LIVE·
fetching live quotes from Yahoo Finance…
--:--:--UTC
Learn/Bots/6-Model Consensus
AI QuantsAIid · ai-consensus

6-Model Consensus

All AI quants vote. Tier emerges from agreement, not opinion.

▶ Try it now↗ Browse all 27srcai quants/models/best_consensus/build.pyapi/api/consensus
In plain English

Six different AI judges look at the same stock and each one votes 'up' or 'down' for the next month. If 5 or 6 of them agree, that's a strong signal worth taking seriously. If they're split 3-3, the market is genuinely confused and the smart move is to do nothing. The card shows you who voted and how confident the group is.

No jargon. Just what this bot does.
The longer version

Six AI models look at the same stock and vote on direction. The card shows you their tally, the agreement tier, and the historical accuracy band that tier earns out-of-sample. The single most useful AI bot in the workbench — when you see ULTRA tier, you've got something real.

The math
formula
binary + magnitude + +macro + sequence + transformer + quantile
Live demo

Real 6-Model Consensus 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 10231114
TypeScript · MIT-licensed
const consensus: BotDef = aiBot<DirReq, ConsRes>(
  {
    id: "ai-consensus",
    name: "6-Model Consensus",
    category: "ai",
    glyph: "⌬",
    tagline: "All AI quants vote. Tier emerges from agreement, not opinion.",
    formula: "binary + magnitude + +macro + sequence + transformer + quantile",
    endpoint: "/api/consensus",
    module: "ai quants/models/best_consensus/build.py",
    params: [],
  },
  {
    request: dirRequest,
    build: (data) => {
      const c = data.consensus;
      return {
        signals: [],
        metrics: [
          { key: "dir", label: "Consensus direction", value: c.direction.toUpperCase(), tone: c.direction === "up" ? "bull" : c.direction === "down" ? "bear" : "neutral" },
          { key: "agree", label: "Agree", value: `${c.agree_count} / ${c.n_models}`, tone: c.agree_count >= c.n_models - 1 ? "bull" : "neutral" },
          { key: "tier", label: "Tier", value: c.tier.toUpperCase(), tone: c.tier === "ultra" ? "bull" : c.tier === "high" ? "info" : "neutral" },
          { key: "acc", label: "Expected acc band", value: c.expected_accuracy_band, tone: "info" },
          { key: "mag", label: "Avg magnitude", value: `${(c.avg_magnitude * 100).toFixed(2)}%`, tone: "info" },
        ],
        summary: `Real-model consensus on ${data.ticker}: ${c.agree_count}/${c.n_models} agree → ${c.direction.toUpperCase()} (${c.tier} tier). Accuracy band: ${c.expected_accuracy_band}.`,
        beginner:
          "Six different AI models look at the same stock and vote. When 5 or 6 agree, the trade is much higher quality. When they're split, the market is genuinely confused.",
        verdict: {
          side: c.direction === "up" ? "buy" : c.direction === "down" ? "sell" : "hold",
          text: c.direction === "split"
            ? `Models split — no edge.`
            : `${c.tier.toUpperCase()} consensus — ${c.agree_count}/${c.n_models} say ${c.direction.toUpperCase()}.`,
          confidence: c.tier === "ultra" ? 0.95 : c.tier === "high" ? 0.78 : c.tier === "medium" ? 0.55 : 0.3,
        },
      };
    },
    mock: (ctx) => {
      const px = closes(ctx.candles);
      const trend = trendStrength(px);
      const rv = realisedVol(px);
      const seed = hashStr(ctx.symbol + "consensus");
      const rand = seedRand(seed);
      const models = [
        { name: "binary GBM", p: 0.5 + trend * 1.4 + (rand() - 0.5) * 0.15 },
        { name: "magnitude", p: 0.5 + trend * 1.1 + (rand() - 0.5) * 0.18 },
        { name: "+macro", p: 0.5 + trend * 1.0 - (rv - 0.25) * 0.6 + (rand() - 0.5) * 0.14 },
        { name: "sequence CNN", p: 0.5 + trend * 0.9 + (rand() - 0.5) * 0.20 },
        { name: "transformer", p: 0.5 + trend * 1.2 - (rv - 0.25) * 0.4 + (rand() - 0.5) * 0.14 },
        { name: "quantile", p: 0.5 + trend * 0.8 + (rand() - 0.5) * 0.16 },
      ].map((m) => ({ ...m, p: Math.min(0.97, Math.max(0.03, m.p)), vote: (m.p > 0.5 ? 1 : -1) as 1 | -1 }));
      const upVotes = models.filter((m) => m.vote === 1).length;
      const downVotes = 6 - upVotes;
      const dir = upVotes >= 5 ? "up" : downVotes >= 5 ? "down" : "split";
      const agree = Math.max(upVotes, downVotes);
      const avgMag = Math.abs(trend) * 0.6;
      const tier = agree === 6 && avgMag > 0.04 ? "ultra" : agree >= 5 ? "high" : agree >= 4 ? "medium" : "low";
      const accBand = tier === "ultra" ? "65–77%" : tier === "high" ? "60–66%" : tier === "medium" ? "55–60%" : "≤55%";
      const signals: Signal[] = [];
      return {
        signals,
        metrics: [
          { key: "dir", label: "Consensus direction", value: dir.toUpperCase(), tone: dir === "up" ? "bull" : dir === "down" ? "bear" : "neutral" },
          { key: "agree", label: "Agree", value: `${agree} / 6`, tone: agree >= 5 ? "bull" : "neutral" },
          { key: "tier", label: "Tier", value: tier.toUpperCase(), tone: tier === "ultra" ? "bull" : tier === "high" ? "info" : "neutral" },
          { key: "acc", label: "Expected acc band", value: accBand, tone: "info" },
        ],
        pane: {
          kind: "histogram",
          series: [{
            values: models.map((m) => m.p - 0.5),
            color: "var(--bear)",
            label: "P(up) − 0.5 per model",
          }],
          refLines: [{ value: 0, color: "var(--fg-faint)" }],
          height: 100,
        },
        summary:
          `Models voting UP: ${upVotes}/6 — ${tier.toUpperCase()} consensus. ` +
          models.map((m) => `${m.name} ${(m.p * 100).toFixed(0)}%${m.vote === 1 ? "↑" : "↓"}`).join(" · "),
        beginner: "Six models vote on direction. 5–6 agreeing = high quality. Split = sit out.",
        verdict: {
          side: dir === "up" ? "buy" : dir === "down" ? "sell" : "hold",
          text: dir === "split"
            ? `Models split ${upVotes}↑ / ${downVotes}↓ — no edge.`
            : `${tier.toUpperCase()} consensus — ${agree}/6 say ${dir.toUpperCase()}. Historical acc band: ${accBand}.`,
          confidence: tier === "ultra" ? 0.95 : tier === "high" ? 0.78 : tier === "medium" ? 0.55 : 0.3,
        },
      };
    },
  },
);
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
  • ·Liquid US large-caps (AAPL, NVDA, AMZN, SPY) where macro context is rich and per-asset training data is plentiful.
  • ·Stable volatility regimes — the models were trained on bands, not regime shifts.
  • ·Multi-week horizons (20-day default). Same-day or next-day prediction is much noisier.
  • ·When ≥5 of 6 models agree. The agreement is the signal; opinion alone is cheap.
✗ Fails when
  • ·Regime breaks. COVID-era March 2020, the 2022 rate cycle, post-earnings gaps — the ensemble was fit on smoother periods.
  • ·Tickers Yahoo doesn't have rich data for. The Python side needs ≥250 historical bars to build features.
  • ·Crypto and FX. The training basket is US equities; out-of-distribution.
  • ·Split votes. When 3-3 or 4-2, the consensus number is essentially noise — the bot will say SPLIT and that's the right answer.
How to read its verdict

BUY/SELL only fire when ≥5 models lean the same way AND the average expected magnitude clears 4%. Otherwise it's HOLD. The confidence number is the agreement fraction × the magnitude clearing. ULTRA tier maps to ~65–77% historical accuracy, HIGH to 60–66%, MEDIUM to 55–60%, LOW to ≤55%.

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.

FastAPI·http://localhost:8000·/api/consensusCHECKING…
data flow
01
BotCell.run()
User clicks Run on this bot in /quant
02
callApi()
POST to localhost:8000/api/consensus
03
load_surrogate()
ai quants/models/best_consensus/build.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
Why does the consensus give the same answer for AAPL and TSLA?+
If you see Source: Mock on the card, the FastAPI service is offline and you're getting a deterministic seeded fallback that depends only on the synthetic chart. Start uvicorn (cd "ai quants" && uvicorn serve:app --port 8000) and refresh — Source flips to Python NN and AAPL/TSLA each get their own real predictions.
What's the historical accuracy?+
Embargoed walk-forward CV on US large caps: ULTRA tier (6/6 agree + |magnitude| > 4%) lands ~65–77%; HIGH tier (≥5 agree) lands 60–66%; MEDIUM (≥4) lands 55–60%; below that it's not tradeable. These bands are conservative — production models tend to drift down 2-4 pts when the regime shifts.
Can I use this for day trades?+
No. The horizon is 20 trading days. Models trained on monthly windows have terrible variance on intraday calls. For day trading, the 1D CNN bot is closer (60-bar lookback) but still not really designed for sub-day.