6-Model Consensus
All AI quants vote. Tier emerges from agreement, not opinion.
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.
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.
binary + magnitude + +macro + sequence + transformer + quantile
Real 6-Model Consensus bot, running on real Yahoo data when the symbol is available. Drag the params — the bot re-runs instantly.
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.
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,
},
};
},
},
);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.
- Copy the whole block above.
- On /quant, click + Import your bot in the bot library.
- Paste, hit save. It hot-loads into your workspace.
- Edit any param defaults or logic to your taste — it's now yours.
- ·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.
- ·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.
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%.
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.
cd "ai quants" && uvicorn serve:app --reload --port 8000Why does the consensus give the same answer for AAPL and TSLA?+
What's the historical accuracy?+
Can I use this for day trades?+
Will the stock be up or down 20 days from now? GBM ensemble vote.
Predicts the size of the next 20-day move, not just the sign.
Honest confidence interval — not just a point prediction.
Attention over a full year of OHLCV. Spots seasonality + regime.