LIVE·
fetching live quotes from Yahoo Finance…
--:--:--UTC
Learn/Bots/Triple-Barrier (de Prado)
AI QuantsAIid · ai-triple-barrier

Triple-Barrier (de Prado)

Profit / stop / time barriers — better labels = better models.

▶ Try it now↗ Browse all 27srcai quants/models/triple_barrier/train.py
In plain English

A smarter way to label what happened on a trade. Instead of asking 'was the price up in 20 days?', ask 'did it hit my profit target before it hit my stop, or did neither happen?' Three outcomes, three labels. Better-labelled training data makes for smarter models.

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

Marcos López de Prado's labelling method, productionised. Instead of asking 'will the stock be up in 20 days?', it asks 'will it hit my +5% profit target before it hits my -5% stop, or will neither happen and I time out?' Three barriers, three labels. Better-shaped training data → smarter downstream models.

The math
formula
Advances in Financial ML, Marcos López de Prado
parameters
horizonMax horizon (d)range 5 → 40default · 20
ptSlProfit/Stop multiplierrange 0.5 → 4default · 1.5
Live demo

Real Triple-Barrier (de Prado) 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 9591008
TypeScript · MIT-licensed
const tripleBarrier: BotDef = {
  id: "ai-triple-barrier",
  name: "Triple-Barrier (de Prado)",
  category: "ai",
  glyph: "⊞",
  tagline: "Profit / stop / time barriers — better labels = better models.",
  formula: "Advances in Financial ML, Marcos López de Prado",
  module: "ai quants/models/triple_barrier/train.py",
  params: [
    { key: "horizon", label: "Max horizon (d)", kind: "number", default: 20, min: 5, max: 40, step: 1 },
    { key: "ptSl", label: "Profit/Stop multiplier", kind: "number", default: 1.5, min: 0.5, max: 4, step: 0.1, hint: "× recent vol" },
  ],
  run: async (ctx, p): Promise<BotResult> => {
    const horizon = num(p, "horizon", 20);
    const ptSl = num(p, "ptSl", 1.5);
    const px = closes(ctx.candles);
    const trend = trendStrength(px);
    const rv = realisedVol(px, 30);
    const seed = hashStr(ctx.symbol + "tb" + horizon);
    const rand = seedRand(seed);
    const pUp = Math.min(0.95, Math.max(0.05, 0.5 + trend * 1.2 + (rand() - 0.5) * 0.1));
    const pHitTop = pUp;
    const pHitBot = (1 - pUp) * 0.7;
    const pTimeOut = 1 - pHitTop - pHitBot;
    const label = pHitTop > pHitBot && pHitTop > pTimeOut ? "+1 (TP)" : pHitBot > pTimeOut ? "−1 (SL)" : "0 (TO)";
    return withStatus(
      {
        signals: [],
        metrics: [
          { key: "pTop", label: "P(profit)", value: `${(pHitTop * 100).toFixed(0)}%`, tone: "bull" },
          { key: "pBot", label: "P(stop)", value: `${(pHitBot * 100).toFixed(0)}%`, tone: "bear" },
          { key: "pTime", label: "P(time-out)", value: `${(Math.max(0, pTimeOut) * 100).toFixed(0)}%`, tone: "neutral" },
          { key: "label", label: "Most likely label", value: label, tone: label.startsWith("+") ? "bull" : label.startsWith("−") ? "bear" : "neutral" },
          { key: "ptSl", label: "PT/SL × σ", value: ptSl.toFixed(1), tone: "info" },
          { key: "rv", label: "σ used", value: `${(rv * 100).toFixed(0)}%`, tone: "neutral" },
        ],
        summary: `Setting profit target = stop-loss = ${ptSl.toFixed(1)}× ${(rv * 100).toFixed(0)}% vol over ${horizon}d. Most likely outcome: ${label}.`,
        beginner:
          "De Prado's idea: instead of asking 'will the price be up?', ask 'will it hit my +5% target before -5% stop, or neither?'. Better-labelled training data = smarter models.",
        verdict: {
          side: pHitTop > pHitBot * 1.4 ? "buy" : pHitBot > pHitTop * 1.4 ? "sell" : "hold",
          text: `Most likely outcome: ${label}.`,
          confidence: Math.abs(pHitTop - pHitBot),
        },
      },
      "mock",
      "no FastAPI endpoint yet",
    );
  },
};
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
  • ·Strategy research. If you're building your own bots, this shows you what de Prado-style labels look like for your asset.
  • ·Stop-loss design. The PT/SL multiplier on the card lets you see how the label changes as you tighten or loosen barriers.
  • ·Variable-volatility regimes. The σ-scaled barriers adapt automatically.
✗ Fails when
  • ·No FastAPI endpoint yet. This bot is currently mock-only — the TS surrogate uses the same hash-derived seed as the other AI bots. Will be wired to the trained model in the next sprint.
  • ·Asymmetric setups. The current implementation uses symmetric profit/stop multipliers; real systems often want asymmetric.
How to read its verdict

Reports three probabilities — P(profit target hit), P(stop hit), P(time-out). Most-likely label classifies into +1 (TP), -1 (SL), or 0 (TO). BUY when P(profit) > 1.4× P(stop), SELL when reverse, HOLD otherwise.

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·/healthCHECKING…
data flow
01
BotCell.run()
User clicks Run on this bot in /quant
02
callApi()
POST to localhost:8000
03
load_surrogate()
ai quants/models/triple_barrier/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
Why triple-barrier labels instead of fixed-horizon?+
Fixed-horizon labels assume the trade is alive for the full window — which isn't how anyone actually trades. Real systems use stops and targets. Triple-barrier labels mirror that, so the model learns to predict the realistic outcome.
Should I use this directly or feed it into a classifier?+
It's the labels that matter. The bot here is a teaching tool — in production, you'd train a classifier on triple-barrier labels and use that as a downstream model. de Prado's book *Advances in Financial ML* is the canonical reference.