Notes · The cage · June 2026

I let Claude write a trading bot, then put it in a cage.

An LLM will happily generate a trading bot with no position caps, no loss limits, and no idea what a market hour is. We ran one against a pre-trade gate on June 12, 2026, and kept the receipts — every block below carries its real trace ID.

TITAN DIAGNOSTIC SYSTEMS · CHICAGO · JUNE 2026
§ 1 · The bot Claude wrote

The prompt was the one people actually type: “Write me a Python momentum bot for Alpaca that buys breakouts.” This is representative of what comes back. It looks clean and it runs. The annotations mark what is genuinely missing, and only that:

import alpaca_trade_api as tradeapi

api = tradeapi.REST(KEY, SECRET, BASE_URL)

def check_breakout(symbol):
    bars = api.get_bars(symbol, "5Min", limit=20).df
    high_20 = bars["high"][:-1].max()
    last = bars["close"].iloc[-1]
    return last > high_20            ← fires on every 5-min bar that qualifies — no cooldown,
                                        no daily cap, nothing stops a re-entry seconds after a loss
def position_size(symbol, price):
    account = api.get_account()
    budget = float(account.buying_power) * 0.25
    return int(budget // price)      ← 25% of buying power per trade, no absolute cap,
                                        no daily-loss circuit breaker anywhere in the file
def run(symbols):
    while True:
        for sym in symbols:
            if check_breakout(sym):
                qty = position_size(sym, get_price(sym))
                api.submit_order(symbol=sym, qty=qty,
                                 side="buy", type="market",
                                 time_in_force="day")  ← straight to the broker. market order,
                                        market-hours unaware, no duplicate guard
        time.sleep(60)

To be fair to the model: nothing here is wrong, exactly. It is a momentum bot that buys breakouts, as requested. The problem is what isn’t there — and that an LLM under instruction to “fix” a losing strategy will edit this file, including any risk checks you asked it to add earlier. Safety that lives in the same file as the strategy is safety the next prompt can remove.

§ 2 · The cage, one line

The cage is a change of address. The bot stops POSTing orders to the broker and starts POSTing signals to Titan:

- api.submit_order(symbol=sym, qty=qty, side="buy", type="market", ...)
+ requests.post("https://www.titandiagnostics.io/api/public/v1/signal",
+     headers={"X-Titan-Agent-Key": TITAN_KEY},
+     json={"symbol": sym, "side": "BUY", "close": price, "atr": atr})

Something is missing from that request, and it’s the dangerous part: there is no quantity field. The public signal schema accepts symbol, side, price, ATR — intent, not size. Sizing is computed inside the gate from limits the operator set, so the bot’s 25%-of-buying-power idea has no way to express itself. The first thing the cage takes away from the bot is the ability to say how much.

The other 26 safety checks now run on Titan’s infrastructure, between the signal and the broker. The bot’s code — and the LLM that wrote it, and every future prompt that edits it — cannot reach them.

§ 3 · First contact — live, June 12

We ran the caged bot’s signal pattern against a sandbox account (30-minute buy cooldown, 3-trade daily cap) during market hours on June 12, 2026, with real IEX quotes pushed for every symbol. Six signals; here is what the cage decided. First, the part people forget a gate does — it lets good signals through:

Twenty seconds later the bot saw another qualifying bar on the same symbol and did what its loop does — fired again. This is the revenge-trade shape, mechanized:

Then the bot’s idea of a price met reality. It signaled GOOG at a level 50% above the live market — the kind of number a stale data frame or a hallucinated calculation produces:

Two more clean breakouts forwarded (AMD, MSFT — traces 5056b87b… and 16b5d885…). Then the bot found a fourth:

§ 4 · Changing the rules, with a witness

Suppose the day-cap of three feels too tight and you — or the LLM you asked to “optimize” the setup — want to raise it to ten. With safety inside the bot’s file, that edit just happens. With the cage, a proposed change can be replayed against the bot’s own recorded signals first. We did exactly that, live, with the signals above:

§ 5 · The honest close

Titan didn’t make this bot good. The strategy is still naive. What Titan did: capped the blow-up, blocked the duplicates and the revenge entry, and produced a receipt for every decision that I can’t edit afterward.

Every trace ID on this page is real and was created through the live application on June 12, 2026. Forwarded decisions are hash-chained, with daily commitments anchored to Bitcoin — verify one yourself, in your browser.

What Titan does not claim

Titan proves what your strategy said, when it said it, and what the safety checks decided. It does not prove you made money.

Titan caps the blow-up. It does not make your strategy good. Titan does not manage open-position risk after a fill, does not hold funds, does not store broker credentials, and does not submit orders — execution stays in your hands, on your machine. Works with Alpaca today.