The flip-book. Buy right, fixed budget, sell on schedule. Get in, capture the spread, get out.
Operating Manual · Rev. LC-2606-BTrack B does not predict. It finds a dated, repricing catalyst, structures a trade around it with the stop set before entry, and exits on schedule — win or lose. The edge is not foresight; it is mechanical consistency at scale, with the AI doing the scanning and the discipline-enforcement that human emotion erodes.
Three things must be true before a single share is bought: a catalyst with a date, a trigger that is a price and not a feeling, and an invalidation written down before the entry. The target clears a 2:1 minimum or the setup dies. Everything below is the machine that enforces those four facts.
The system splits along a single fault line: the model does what it is good at — searching for dated catalysts and reading levels — and deterministic code does everything that enforces the rules. Because the model never performs the sizing math, it cannot widen a stop to save a thesis or oversize a position. Rules are code, not suggestions.
The layer above every trade gate. Before the scanner hunts a single catalyst, it reads market state and resolves one of three regimes — and that verdict scales the whole book's gross exposure. This is the discipline a confident trader most often abandons: position size indexed to the tape, not to how sure you feel.
These limits live in sizer.py and fire regardless of what any setup "wants." A sub-2:1 trade, an inverted stop, an over-heated book — all rejected at the door.
| Control | Limit | Enforcement |
|---|---|---|
| Regime gate | ×1 / ×0.5 / ×0 | Full / half / sit-out scales gross exposure before any trade is sized. Sit-out halts the scan. |
| Per-trade risk | ≤ 1.0% | Position size = (capital × 0.01) ÷ stop distance. Floored to whole shares. Regime multiplier then scales it. |
| Reward-to-risk | ≥ 2.0 : 1 | Computed from trigger / stop / target. Below 2:1 → rejected, reason logged. |
| Invalidation | pre-set | Must sit on the correct side of the trigger. Never widened to hold a loser. |
| Dated catalyst | required | No date, no trade. "Looks bullish" is auto-rejected. |
| Correlation cap | ≤ 2.0% | Combined risk per group (energy, biotech…) capped; excess names dropped. |
| Portfolio heat | ≤ 4% / 2% | Total open risk across the book — 4% in full size, 2% in half. New entries blocked past the ceiling. |
| Concurrent | ≤ 5 | Max open positions; lowest-conviction surplus trimmed. |
Every approved setup resolves to this. Entry is four fields written before the trade; the rest is computed. This is the unit the scanner produces and the unit you act on.
Entry sets the size; this is what happens after. The two directions are not symmetric. Scaling out is the standing discipline — it turns a winner into a no-risk trade and refuses to let a catalyst trade drift into a momentum bet. Scaling in is the exception, hedged by four gates, because uncontrolled adding is the single fastest way to blow through the 1% rule without noticing.
| Window (ET) | Action | Agent |
|---|---|---|
| pre-06:30 | Regime check first (SPX/VIX/ADX), then overnight scan: catalysts, macro, gaps. Agent drafts watchlist + four-field cards at the regime's size. | regime · scan |
| 08:00–09:00 | Review cards, approve or reject. Brackets staged with R:R and sizing shown. | draft |
| 09:30–09:45 | Observe the open. No entries. Agent flags abnormal volume and gaps. | watch |
| 09:45–11:00 | Prime entry window. Trigger fires → confirm live price in ToS → click. | monitor |
| 11:00–14:00 | Manage open risk through the midday lull. Agent watches stops, targets, news. | manage |
| 14:00–15:30 | Second window + scale management. ① trim 50% at 2:1, stop to breakeven; ② trail the runner. Add-on only if FULL regime + original risk locked. | scale |
| 15:30–16:00 | No new entries. Flatten time-stops and catalyst-resolved trades. | close |
| post-close | Journal every fill, R multiple, adherence score. Agent auto-logs and flags violations. | journal |
The five prompts that drive the search-driven agent. Fire Prompt 4 each morning to run the whole scan; the others are the stages it chains, kept separate so you can run, edit, or debug any one. Tap copy to lift any prompt to your clipboard. Replace [FILL IN] with your Track B capital before first use.
You are the Track B Alpha Scanner — a mechanical catalyst-trade screener for a flip-book trading system. You do NOT predict direction from feeling; you find DATED, repricing catalysts and structure each into a trade with a stop set before entry. HARD RULES (never violate, never rationalize around): - Every price, catalyst date, and figure you state MUST come from a live search result you ran this session. If you cannot ground a field with a search, write "UNVERIFIED — do not trade" and do not fill it in from memory. - Per-trade risk <= 1% of trading capital. Capital = $[FILL IN]. - Minimum reward-to-risk = 2:1. Any setup below 2:1 is REJECTED, no exceptions. - The invalidation (stop) is set BEFORE entry and is mechanical. You never widen a stop to keep a thesis alive. - A trade needs a DATED catalyst: a specific event with a date or tight window. "It looks bullish" is not a catalyst and is auto-rejected. - REGIME FIRST: before hunting catalysts, report current market state (SPX vs 50d/200d MA, VIX, ADX, consecutive 2%+ down days). Track B gross exposure scales with regime, not conviction — full size / half size / sit out. In a sit-out regime there are NO new entries. - Correlated concurrent exposure is capped: flag when two or more candidates share a driver (e.g., two oil names, two biotech binaries). OUTPUT DISCIPLINE: - Conclusion first, reasoning second. - Every candidate gets the four written fields: Catalyst, Trigger, Invalidation, Target — plus computed R:R, position size, and the source links used. - If a setup fails any gate, say WHY in one line and move on. Do not pad.
TASK: Find dated catalysts in the next 1–10 trading days that could reprice liquid US equities/ETFs in my universe. STEP 0 — REGIME READINGS (do this first): Search and report current market state for the regime filter: - "S&P 500 today" → SPX last - "S&P 500 50 day 200 day moving average" → SPX 50d & 200d MA - "VIX today" → VIX last - "S&P 500 ADX" → trend strength (if available) - Count consecutive recent sessions closing <= -2% Report each as a number with a source. (The engine classifies full / half / sit-out from these — you just supply the grounded readings.) UNIVERSE FOCUS (priority order): 1. Oil & energy macro: OPEC+ meetings, EIA inventory, Hormuz/Iran/Russia supply headlines, refinery outages. Names: USO, XLE, XOM, CVX, OXY, SLB. 2. Biotech binaries: PDUFA dates, Phase 2/3 readouts, FDA AdComm. Names: XBI, plus single-name catalysts you surface. 3. Index/macro events: CPI, PCE, FOMC, jobs report, major mega-cap earnings. 4. Single-name earnings with known dates in the window. FOR EACH catalyst, SEARCH and report: - Symbol(s) affected - Catalyst description - Exact date/time (or window) — cite the source - Expected repricing direction & rough magnitude IF the source implies one - Correlation group (energy / biotech / index / semis / etc.) SEARCHES TO RUN (adapt as needed): - "OPEC meeting [current month year] date" - "EIA crude oil inventory report schedule [this week]" - "FDA PDUFA dates [current month year]" - "economic calendar [this week]" (CPI, FOMC, jobs) - "[ticker] earnings date [current quarter]" - Any live geopolitical oil headlines from the last 48 hours OUTPUT: a table of 8–15 dated catalysts, most-imminent first, each with a source link. Reject and exclude anything you cannot date from a search.
TASK: For each catalyst candidate from Prompt 1, search current price + recent range and define a MECHANICAL trigger and invalidation. No feelings — specific prices only. FOR EACH SYMBOL, SEARCH: - "[ticker] stock price today" - "[ticker] stock 52 week high low" / recent support-resistance levels - "[ticker] average volume" - Recent daily range / key levels (prior day high/low, round numbers, VWAP if available) THEN DEFINE: - TRIGGER: the specific price or signal that confirms entry (e.g., "break above $X on volume > 1.5x avg" or "reclaim of $Y"). Must be a number. - INVALIDATION (STOP): the price that proves the setup wrong. Set it at a structural level (below support / above resistance for shorts), NOT an arbitrary %. State the dollar distance from trigger to stop. - LIQUIDITY CHECK: confirm avg volume > 2M and price > $10. If it fails, REJECT. OUTPUT per symbol: Trigger price | Stop price | Stop distance ($) | liquidity pass/fail | sources.
TASK: For each surviving candidate, set the target, run the 2:1 gate, size the position, check the caps, and assemble the final four-field card.
INPUTS: trigger, stop, stop-distance from Prompt 2. Capital = $[FILL IN].
COMPUTE:
1. TARGET: nearest meaningful resistance/objective from the catalyst thesis. Reward = |target − trigger|. Risk = |trigger − stop|.
2. R:R = reward / risk. IF R:R < 2.0 → REJECT (state the ratio, move on).
3. POSITION SIZE:
dollar_risk = capital × 0.01
shares = floor(dollar_risk / risk_per_share)
position_value = shares × trigger
Report shares, position value, and exact $ at risk.
4. CORRELATION CHECK: list each candidate's group. If 2+ survivors share a group, flag it and cap combined risk at 2% (halve size or pick one).
5. HEAT CHECK: sum $ at risk across all proposed trades. If > 4% of capital, flag and trim the lowest-conviction trades.
OUTPUT — one card per surviving trade, ranked by R:R (highest first):
━━━ [TICKER] — [LONG/SHORT] ━━━
Catalyst: [what reprices it, and by when — with date]
Trigger: [specific price / signal]
Invalidation: [stop price — set before entry]
Target: [price] — R:R = [x.x : 1]
Size: [N] shares · $[value] · $[risk] at risk ([0.x]% of capital)
Scale-out: ① at [2:1 price] trim 50% → stop to breakeven
② trail runner on prior-bar low / 1×ATR
③ catalyst resolves → flat remainder, win or lose
Group: [correlation group] | Heat after add: [x.x]%
Window: [catalyst date] · enter only [09:45–11:00 or 14:00–15:30 ET]
Sources: [links]
─────────────────────────────
STATUS: APPROVED FOR REVIEW / REJECTED ([reason])
End with a portfolio summary: total trades, total heat %, any correlation flags, and the single highest-conviction trade of the day.
Run the full Track B Alpha scan now. Trading capital = $[FILL IN]. Execute in order, using live web search at every step: 0. REGIME FILTER — search current market state (SPX last, SPX 50d & 200d MA, VIX, ADX, consecutive 2%+ down days), each grounded in a source. Resolve the regime: FULL (SPX>50d & 50d>200d, VIX<=20, ATR-trend>0.5% — 2 of 3) → full size; MIXED/choppy (VIX 20–28, ADX<20) → half size; STRESS (VIX 28–45, SPX<200d, or consecutive 2%+ down days) → SIT OUT. If SIT OUT: stop here, report "no new Track B entries, manage existing to stops only," and do not hunt catalysts. 1. CATALYST DISCOVERY — search for all dated catalysts in the next 10 trading days across oil/energy, biotech binaries, index/macro events, and mega-cap earnings. Date every one from a source. 2. TECHNICAL CHECK — for each, search current price/volume/levels and set a numeric trigger + structural stop. Reject illiquid names. 3. GATE & SIZE — set targets, compute R:R, reject anything < 2:1, size each to <=1% risk, APPLY the regime multiplier (×1 full / ×0.5 half), check correlation (<=2% per group, scaled) and heat (<=4% full / <=2% half). 4. DELIVER — ranked four-field cards (Catalyst/Trigger/Invalidation/Target) with size, R:R, sources, and APPROVED/REJECTED status. Conclusion first. Reminders: regime before catalysts. Never fill a price or date from memory — search it. Never widen a stop. Never approve a sub-2:1 setup. Flag correlated clusters. I execute manually in ThinkorSwim; you draft, I click. Finish with: the regime verdict and why, today's single best trade, the day's total heat, and what to watch for invalidation before the open.
Track B-2 is not Track B with the catalyst removed. It's a separate system with its own edge, its own math, and its own risk logic. Build it as a sibling, never let it bleed into B's gates — the moment a bare breakout gets called a "catalyst," both systems lose their meaning. Here is what makes B-2 a different animal.
| Track B · Alpha | Track B-2 · Trend | |
|---|---|---|
| Edge from | Dated catalyst repricing | Trend persistence + payoff skew |
| Entry needs | A catalyst with a date | A breakout + trend filter (200d, MA stack, RS) |
| Win rate | Moderate; 2:1 carries it | Low (~35–45%) — by design |
| Exit | Fixed: 2:1, or on the event | No fixed target. Chandelier trail; let it run |
| Selection | Few, hand-judged catalysts | Breadth — every qualifying breakout, ranked by RS |
| Risk/trade | 1% | 0.5% (more positions, lower hit rate) |
| Regime lens | VIX-led (orderly vol?) | ADX/MA-led (actually trending?) |
| Stands down when | VIX 28–45, SPX < 200d | Chop — ADX < 18, even if VIX is calm |
| Engine | sizer.py · regime.py | sizer_b2.py · regime_b2.py |
def size_one_b2(c, capital):
# Initial stop is ATR-based, NOT a structural catalyst stop:
initial_stop = c.breakout_level - 2.0 * c.atr # long
risk_per_share = c.breakout_level - initial_stop
trend_ok = c.above_200d and c.ma_stack_ok # the catalyst-replacement
# Exit is a TRAIL, never a target — this is the whole point:
trail = "chandelier: highest-high − 3×ATR, exit when hit"
# Gates: trend filter, liquidity, valid ATR stop, and >=3R *room*
# (room is a SETUP-QUALITY filter, NOT a profit target — upside uncapped):
if not trend_ok: return reject("fails trend filter")
if potential_r < 3.0: return reject("too cramped to run")
shares = floor(capital * 0.005 / risk_per_share) # 0.5% — smaller than B
return approve(shares, trail) # let the winner run
# build_book_b2() ranks by RELATIVE STRENGTH, not R:R — there is no R:R here.
# regime_b2 stands the whole sleeve down in CHOP (ADX < 18), the breakout-killer,
# even when VIX is calm. That is the opposite reflex from Track B.
Run it as its own sleeve with its own capital line: build_book_b2(candidates, capital, regime_multiplier, heat_cap). Same deterministic discipline as B — model proposes breakouts from a screen, code enforces the trend filter, the 0.5% size, and the chandelier exit. It shares the regime readings with B but reads them through a trend lens, so one morning scan can feed both sleeves.
Three prompts that drive the breakout screener — a technical screen, not a catalyst hunt. Fire B-2 Prompt 2 each morning; the others are its standing role and the screen stage it chains. Replace [FILL IN] with the B-2 sleeve capital. run_scan_b2.py already wires all three together.
You are the Track B-2 Trend Scanner — a mechanical breakout SCREENER for a trend-following sleeve. This is NOT catalyst trading. You do not look for events or news. You screen price action for breakouts in confirmed uptrends. WHAT YOU ARE LOOKING FOR (the screen): - Liquid US equities/ETFs making a FRESH BREAKOUT: a new 20-day high (or 55-day Donchian breakout, or a clean break of a multi-week consolidation/channel). - In a confirmed UPTREND: price above the 200-day MA, and 50d > 200d (MA stack). - With strong RELATIVE STRENGTH: leaders, ideally top ~20% vs the market. - Liquid: price > $10 and average daily volume > 2,000,000 shares. HARD RULES (never violate, never rationalize): - Every price, level, ATR, volume, and RS read MUST come from a live search this session. Never fill a number from memory. If you can't ground a field, drop that candidate. - You do NOT set a profit target. Track B-2 has NO fixed target — winners run on a trailing stop. Do not propose one. The engine sets the ATR stop and chandelier trail. - You do NOT compute position size, the stop, R-multiples, correlation, heat, or the regime. A deterministic engine does all of that and will reject anything that fails a gate or stand the whole sleeve down in a choppy tape. - A bare breakout with NO trend behind it (below 200d, weak RS) is rejected — that is the chop that kills this strategy. Quality over quantity. OUTPUT DISCIPLINE: conclusion first. Report market-state readings for the trend regime, then the screened breakout candidates. If a name fails the trend filter, drop it in one line.
TASK: Screen for liquid breakouts in confirmed uptrends with strong relative strength. This is a TECHNICAL screen — no catalysts, no news. STEP 0 — TREND REGIME READINGS (do this first): Search and report, each with a source: - "S&P 500 today" → SPX last - "S&P 500 50 day 200 day moving average" → SPX 50d & 200d - "VIX today" → VIX - "S&P 500 ADX today" → ADX (the key one — B-2 stands down in chop) - Count consecutive recent sessions closing <= -2% STEP 1 — SCREEN for breakout candidates: - "stocks making new 20 day highs today" - "stocks breaking out today high volume" - "relative strength leaders stocks this week" - "52 week high stocks today liquid" STEP 2 — Per candidate, confirm and read: - "[ticker] stock price today" → price + the breakout level - "[ticker] 200 day moving average" → above 200d? 50d > 200d? - "[ticker] ATR" → current ATR (the engine uses this for stop + trail) - "[ticker] average volume" → must be > 2M; price > $10 - relative-strength rank (top ~20% preferred) - a nearby measured-move / prior-resistance objective (for the engine's >=3R ROOM check — this is setup quality, NOT a target you trade to) REJECT: anything below the 200d, weak RS, illiquid, or with no clean breakout level. A bare breakout with no trend is chop — drop it. OUTPUT per name: ticker | setup | breakout level | ATR | price | above_200d | 50d>200d | RS rank | measured move | avg volume | sources. Do NOT set a stop, size, or target — the engine does that.
Run the Track B-2 trend/breakout screen now. Sleeve capital = $[FILL IN]. Execute in order, using live web search at every step: 0. TREND REGIME — search SPX last, SPX 50d & 200d MA, VIX, ADX, consecutive 2%+ down days, each from a source. Resolve: TREND_ON (SPX>50d>200d AND ADX>=25) → full; WEAK (trend present, ADX<25) → half size; TREND_OFF (ADX<18 choppy, OR SPX<200d, OR consecutive 2%+ down days, OR VIX>35) → STAND DOWN. If TREND_OFF: stop here, report "no new B-2 breakouts — chop manufactures false breakouts," and do not screen. 1. SCREEN — find liquid names making fresh breakouts (new 20-day highs, Donchian, channel breaks) in confirmed uptrends (above 200d, 50d>200d) with strong relative strength (top ~20%). Ground every level, ATR, volume, RS from search. 2. CONFIRM — per name, read price, breakout level, ATR, 200d position, avg volume, RS, and a measured-move objective. Reject anything below 200d, weak RS, or illiquid. 3. DELIVER — a list of breakout candidates with their levels and ATR. Set NO targets and NO sizes — the engine sizes to 0.5%, sets the ATR stop, and applies the chandelier trail. Reminders: this is a technical screen, not a catalyst hunt. Never set a profit target — winners run on the trail. Never fill a number from memory. Stand down in chop even if VIX is calm. I execute manually in ThinkorSwim; you draft, I click. Finish with: the trend-regime verdict and why, the strongest-RS breakout of the day, and a note that most of these will fail small while a few run.
The prompts find trades; this code decides whether they live. regime.py classifies the tape and sets the gross multiplier; the model proposes trigger / stop / target as JSON; build_portfolio() computes R:R, sizes to 1%, applies the regime scale, enforces the correlation and heat caps, and rejects the rest. Scale-out prints on every card; size_add_on() gates any pyramiding. Reference excerpt — the full regime.py, sizer.py and run_scan.py ship as separate files.
def classify(s): # s = today's market-state readings
# SIT_OUT trips — any one forces sit-out (the hard stops):
if s.spx < s.spx_200d: return SIT_OUT # below the 200d
if 28 <= s.vix <= 45: return SIT_OUT # stress band
if s.consec_down_days_2pct >= 2: return SIT_OUT # cascade
# FULL — need 2 of 3:
trend = s.spx > s.spx_50d and s.spx_50d > s.spx_200d
calm = s.vix <= 20
atr = s.atr_trend_pct and s.atr_trend_pct > 0.5
if (trend + calm + atr) >= 2: return FULL # ×1.0, heat 4%
return HALF # ×0.5, heat 2%
# The multiplier scales every position build_portfolio() produces:
# FULL -> shares as-is (1% per trade, 4% heat)
# HALF -> shares × 0.5 (~0.5% per trade, 2% heat)
# SIT_OUT -> zero new entries; manage existing to stops only
#
# Daily reading. Set pre-market, held for the session. A midday VIX
# spike does NOT re-gate trades already on — their stops govern them.
def size_one(c, capital):
risk_per_share = (c.trigger - c.stop) if c.direction == "LONG" \
else (c.stop - c.trigger)
reward = (c.target - c.trigger) if c.direction == "LONG" \
else (c.trigger - c.target)
rr = reward / risk_per_share if risk_per_share > 0 else -1
# Gate 1 — stop on correct side of trigger
if risk_per_share <= 0:
return reject("stop on wrong side of trigger")
# Gate 2 — dated catalyst present
if not c.catalyst_date.strip():
return reject("no dated catalyst")
# Gate 3 — 2:1 reward-to-risk
if rr < 2.0:
return reject(f"R:R {rr:.2f} below 2:1 minimum")
dollar_risk = capital * 0.01 # <= 1% — hard ceiling
shares = floor(dollar_risk / risk_per_share)
if shares < 1:
return reject("stop too wide — <1 share fits the 1% budget")
return approve(shares, shares * c.trigger, shares * risk_per_share)
# build_portfolio() then enforces, in order:
# • correlation cap — combined risk per group <= 2% of capital
# • portfolio heat — total open risk <= 4% of capital
# • max concurrent — <= 5 positions, lowest-conviction trimmed
#
# The model never runs this arithmetic, so it cannot widen a stop
# or oversize a position. Rules are code, not suggestions.
def size_add_on(a, capital):
# An add-on is a NEW, independently risk-counted tranche —
# never "more onto the winner." All four gates must hold:
# 1 — regime must be FULL (no adding in half-size / sit-out)
if a.regime != "FULL":
return reject(f"add-on forbidden in {a.regime} regime")
# 2 — original position's risk already locked (stop at breakeven)
orig_locked = a.orig_stop_now >= a.orig_entry # long
if not orig_locked:
return reject("lock the first tranche before adding")
# gate — valid stop and 2:1 on the add itself
if risk_per_share <= 0: return reject("stop wrong side")
if rr < 2.0: return reject("add-on below 2:1")
# 3 — the add-on's OWN risk <= 1%, sized alone
shares = floor(capital * 0.01 / risk_per_share)
# 4 — group risk after the add stays <= 2% (correlation cap)
if a.group_risk_used + shares*risk_per_share > capital*0.02:
return reject("add-on breaches 2% group cap")
return approve(shares) # a fresh sub-position, fully gated
# Because the original stop is at breakeven, its live risk is ~0 —
# so the add-on almost always has room under the group cap. The
# discipline isn't "can I add?" — it's "is the first tranche safe yet?"