LIVE
connecting to the live quote stream…
--:--:--UTC
Learn/Bots/Transformer (252d)
AI QuantsAI
ϟ

Transformer (252d)

Attention over a full year of OHLCV. Spots seasonality + regime.

⟢In plain English

The same kind of AI that powers ChatGPT — but instead of reading words, this one reads a whole year of price data. It learns to focus on the important days (earnings, big drops, regime shifts) and uses them to guess the next month's move.

A Transformer encoder — same architecture that made ChatGPT work — but fed a year of OHLCV data instead of text tokens. It learns to attend to the right days: earnings prints, vol spikes, regime changes. Predicts the next 20-day return purely from raw price/volume shape. No hand-engineered features.

⟢The math
formula
TransformerEncoder · 4 heads · 2 layers · 252 lookback
parameters
lookbackLookback (bars)range 60 → 504default · 252
⟢Live demo

Real Transformer (252d) bot, running on real Yahoo data when the symbol is available. Drag the params — the bot re-runs instantly.

symbolloading…
loading AMZN bars…
⟢Source code · public

This is the actual code the bot runs — not a re-explanation, not a simplified version. Whatever ships here is what executes when you press Run All in the workbench. Read it, copy it, fork it, build a better one.

●lib/quant/ai-bots.ts·lines 854–924
TypeScript · MIT-licensed
const transformerSeq: BotDef = aiBot<DirReq, SeqRes>(
  {
    id: "ai-transformer",
    name: "Transformer (252d)",
    category: "ai",
    glyph: "ϟ",
    tagline: "Attention over a full year of OHLCV. Spots seasonality + regime.",
    formula: "TransformerEncoder · 4 heads · 2 layers · 252 lookback",
    endpoint: "/api/transformer",
    module: "ai quants/models/transformer/train.py",
    params: [
      { key: "lookback", label: "Lookback (bars)", kind: "number", default: 252, min: 60, max: 504, step: 1 },
    ],
  },
  {
    request: dirRequest,
    // Free tier: run the real transformer on the user's machine (onnxruntime-web).
    deviceSource: "device-transformer",
    device: async (ctx) => {
      const res = await runTransformer(ctx.symbol.toUpperCase());
      return res
        ? { expected_return: res.expectedReturn, direction: res.direction, horizon_days: 20 }
        : null;
    },
    build: (data) => {
      const pred = data.expected_return;
      return {
        signals: [],
        metrics: [
          { key: "pred", label: "20d return", value: `${(pred * 100).toFixed(2)}%`, tone: pred > 0 ? "bull" : "bear" },
          { key: "dir", label: "Direction", value: data.direction.toUpperCase(), tone: data.direction === "up" ? "bull" : "bear" },
          { key: "lookback", label: "Window", value: "252d" },
          { key: "model", label: "Architecture", value: "TransformerEncoder · 4 heads · 2 layers", tone: "info" },
        ],
        summary: `Transformer attends over 252 days. Predicts ${(pred * 100).toFixed(2)}% over the next 20d.`,
        beginner:
          "Same architecture that powers ChatGPT, applied to a year of price data. Attention focuses on the right days — earnings, vol spikes, regime changes.",
        verdict: {
          side: pred > 0.015 ? "buy" : pred < -0.015 ? "sell" : "hold",
          text: `Transformer expects ${(pred * 100).toFixed(2)}% in 20d.`,
          confidence: Math.min(1, Math.abs(pred) * 15),
        },
      };
    },
    mock: (ctx, p) => {
      const lookback = num(p, "lookback", 252);
      const px = closes(ctx.candles);
      const trend = trendStrength(px);
      const rv = realisedVol(px, 60);
      const seed = hashStr(ctx.symbol + "txr" + lookback);
      const rand = seedRand(seed);
      const pred = trend * 0.7 - (rv - 0.25) * 0.08 + (rand() - 0.5) * 0.025;
      return {
        signals: [],
        metrics: [
          { key: "pred", label: "20d return", value: `${(pred * 100).toFixed(2)}%`, tone: pred > 0 ? "bull" : "bear" },
          { key: "dir", label: "Direction", value: pred > 0 ? "UP" : "DOWN", tone: pred > 0 ? "bull" : "bear" },
          { key: "lookback", label: "Window", value: `${lookback}d` },
          { key: "regime", label: "Vol regime", value: rv > 0.3 ? "high" : "low", tone: rv > 0.3 ? "warn" : "neutral" },
        ],
        summary: `Transformer (TS mock) expects ${(pred * 100).toFixed(2)}% in 20d, vol regime ${(rv * 100).toFixed(0)}%.`,
        beginner: "Attention over a year of OHLCV. The Python model is the real one.",
        verdict: {
          side: pred > 0.015 ? "buy" : pred < -0.015 ? "sell" : "hold",
          text: `Transformer expects ${(pred * 100).toFixed(2)}% in 20d.`,
          confidence: Math.min(1, Math.abs(pred) * 15),
        },
      };
    },
  },
);
what each piece means
  • id — unique key the workbench uses to find the bot.
  • params — the sliders + inputs you see on the cell.
  • run(ctx, p) — the function that gets called with candles + your params and returns the verdict.
  • verdict — the BUY / SELL / HOLD pill at the top of the cell.
  • metrics — the small stat boxes shown in the cell body.
use this code yourself
  1. Copy the whole block above.
  2. On /quant, click + Import your bot in the bot library.
  3. Paste, hit save. It hot-loads into your workspace.
  4. Edit any param defaults or logic to your taste — it's now yours.
⟢Specialty · when it shines, when it fails
✓ Shines when
  • ·Long-horizon patterns: seasonality, regime detection, post-earnings drift. The 252-day window covers a full annual cycle.
  • ·Names with rich price history and multiple regime episodes (SPY, AAPL, JPM). The attention learns which past contexts are similar to today's.
  • ·When you don't trust hand-crafted features. The model learns its own representations end-to-end.
✗ Fails when
  • ·Small data regimes. Transformers need lots of examples — small caps with patchy history struggle.
  • ·Out-of-distribution market structure. Crypto's 24/7 trading and crypto-native cycles are not in the training set.
  • ·Latency-sensitive use cases. A forward pass on a 252-day sequence is fast on GPU, slower on CPU; the bot is ~50ms in our setup.
⟢How to read its verdict

BUY when expected return > +1.5%, SELL when < -1.5%, HOLD in between. Confidence scales with |pred|. The 'vol regime' chip on the card is a useful sanity check: in high-vol regimes the model under-bets, which is the right behavior.

⟢Python service

This bot tries to call the FastAPI service first. When it's up, you get real model output. When it's down, the bot transparently falls back to a deterministic TS surrogate.

srcai quants/models/transformer/train.pyapi/api/transformer
FastAPI··/api/transformerCHECKING…
How the request flows+
01
BotCell.run()
User clicks Run on this bot in /quant
02
callApi()
POST to localhost:8000/api/transformer
03
load_surrogate()
ai quants/models/transformer/train.py
04
predict()
Forward pass on the inputs you provided
05
BotResult
JSON returned, card flips green Source: Python NN
spin it upcd "ai quants" && uvicorn serve:app --reload --port 8000
⟢FAQ
What makes this different from the 1D CNN?+
CNN sees 60 bars; this sees 252. CNN learns local patterns (cup-and-handle, breakouts); this learns global context (where in the cycle are we?). They complement each other — that's why both feed into the 6-Model Consensus.
Why a Transformer for 252 numbers?+
Self-attention scales O(n²) with sequence length, which is fine at 252. The point isn't size — it's that attention learns which past days matter for predicting the next move. A linear model can't tell you 'today resembles April 2018'; this can.