What changed and why
Every strategy and safety change to the bot since the first line of code, newest first. For each one: the issue we saw, what changed, the reason, and the idea behind it. Live trading on a real account began July 2, 2026; entries that touched real money say so.
70 changes, May 27, 2026 to September 13, 2026
The strategy itself is on the methodology page and every adjustable control is in the settings reference. Nothing here is investment advice, no result is guaranteed, and options trading carries substantial risk of loss.
2026-09-13: directional trades take the early win, bearish bets paused
- Issue. We reviewed every trade since launch. The directional lane’s winners peaked within one to three days and then faded; four trades that were up 34 to 78% of the premium paid rode all the way back to the 50% stop. Bearish directional bets lost 9 of 11 on the live account. Single-stock condors at moderate volatility lost every time while ETF condors made money.
- What changed. A directional trade now closes when it is up 30% of the premium paid, the mirror of the 50% stop. Bearish directional structures are off on the live account (they keep running in the sandbox so we keep measuring them). Single stocks need a volatility rank of 70 or higher to qualify for a condor; ETFs keep the lower bar. A reporting bug that understated fees on the dashboard is fixed. The rebuilt earnings engine (see 2026-08-27) is back on for the live account as of September 9; its first live trade gets a same-day review.
- Reason. Our own ledger: 25 stop-outs with zero winners, most of them never profitable at any point, the rest profitable early and given back. tastylive’s research supports the index and ETF core and says nothing that supports a bearish single-stock lane in a rising market.
- Idea. Trade the part of the book that has paid, take the win the market hands you, and let the sandbox keep testing the rest.
2026-09-10: exits no longer fire on the first bad quote after the open
- Issue. A long MDT call was sold seven minutes after the open at the bid, on a quote 70 cents wide. At the true midpoint the position was down 37%, under the 50% exit rule. The bot had taken the broker’s mark, which had collapsed to the bid on a lopsided early book, and fired the rule on it. Three earlier exits had the same shape.
- What changed. The 50% premium stop now waits out the first 15 minutes after the open and skips any quote that is more than 30% wide, like every other profit-and-loss exit. The bot prices off the live bid and ask midpoint when it has both sides, and falls back to the broker’s mark only when it does not. Every exit now records the bid, ask, and both marks it saw.
- Reason. A profit-and-loss rule is not an emergency. The emergency list is for assignments and expiration day. Widest quotes of the day are the first minutes; reading a loss off them sells at the worst price for no reason.
- Idea. Measure first, act second. Every rule fires on a number, so the number has to be a fair one before the rule is allowed to see it.
2026-09-10: put spreads can now use a disaster wing (sandbox first)
- Issue. The tastytrade short put is one of the highest-probability trades there is, but a naked put on a $15,000 account cannot keep a fixed loss cap.
- What changed. A new way to build the bull put spread: sell the one standard deviation put, buy a far-out 5-delta put as a disaster wing, then pull the wing in until the max loss fits the per-trade cap. Running in the sandbox next to the condors before any live account sees it.
- Reason. tastylive’s 14-year study: the 5-delta wing keeps 83 to 85% of the naked put’s profit, cuts the worst loss by 31%, cuts buying power by about 90%, and leaves the win rate unchanged.
- Idea. Get the behavior of the naked put with the loss cap of a spread.
2026-09-09: three new entry checks, and the put spread can compete
- Issue. Live single-stock condors entered at moderate volatility lost every time, while the same condors on ETFs made money. The wings were too narrow for expensive stocks, and the volatility check was the weakest version of the test.
- What changed. Individual stocks now need a higher volatility rank than ETFs. A condor on a single stock is skipped when the wing is too narrow for the stock’s price. Implied volatility must sit at least 3 points above realized. The bull put spread can compete with the condor without a directional signal, capped at two open per account. All of it is visible on the dashboard as “active gates”.
- Reason. tastylive’s wing-width study, expected-move study, and their own guidance that the volatility risk premium is the edge. Plus 48 live trades of our own data.
- Idea. Trade the same rules, on fewer wrong names.
2026-09-09: defense turned on, book sized down, long options off
- Issue. Tested condors sat unmanaged for a week with time left. The buying-power ceiling had been lifted to 95%. Outright long calls and puts had never once closed a winner under the 50% stop.
- What changed. The bot now rolls the untested side of a tested condor for credit, tastylive’s primary defense. The buying-power ceiling is back to 50%. Outright long options are off on the live account; debit spreads stay.
- Reason. tastylive’s data: rolling the untested side wins 78% of the time versus 36% for exiting at the breach. Their allocation guidance is 25 to 50% of buying power.
- Idea. Defend the trade, size the book, drop what does not pay.
2026-08-27: earnings trades rebuilt
- Issue. Seven live earnings condors lost $850. Every loss was a print that blew through the implied move on a short strike placed inside it.
- What changed. Strikes now sit at the further of the 16-delta strike and 1.3 times the implied move, wings are twice as wide, the credit must be at least a third of the wing, names with beta above 1.3 or an implied move over 8% are skipped, and the trade uses an expiry a week past the report so it can be defended. Off on the live account until the sandbox proves it.
- Reason. Our own seven trades and the implied-move history of names like CRWD and META, which beat their implied move more often than not.
- Idea. Skipping expensive prints is the edge.
2026-08-20: live account loosened only where the log proved it was stuck
- Issue. Robin asked how to get the live account trading more. The decision log for 8/17 to 8/20 showed both accounts entering at about the same rate, 8 entries each since 8/10. What differed was which gate was binding. Live skipped SPY 65 times because a 10-wide SPY condor risked $722 to $726 against a $700 per-trade cap. The directional lane sat pinned at its count cap of 4 all day on 8/19. Live’s entry window was about 20 minutes a day shorter than the sandbox’s.
- What changed. On the live account only: the per-trade cap moved from $700 to $750, the directional position count cap from 4 to 6, and the entry window now opens 15 minutes after the bell (was 30) and closes 10 minutes before the close (was 15). Spread width was briefly set to 5 and put back to 10 the same afternoon. Live money.
- Reason. Each change targets a gate the log proved was binding. The count cap release showed up within two minutes: live opened AMZN after taking no entries all morning. Width stays 10 because 5-wides were less profitable in earlier live trading and the 10-wide choice was made deliberately on 2026-07-24. Six closed 10-wide trades across both accounts, pointing in opposite directions, is noise; the width question needs about 15 closes per account before it means anything.
- Idea. Measure which gate is actually blocking before touching anything, then touch only that gate.
2026-08-15: entry orders give up in 90 seconds, live gates match the sandbox
- Issue. A resting entry order that did not fill sat for 30 minutes before the bot gave up. Filled entries averaged 68 seconds of life; cancelled ones sat 35 minutes. Nothing fills late, and each dead order held its symbol, a position slot and its buying power for about six cycles. Separately, the live account’s structure-quality floor was scored in a way that rejected about 96% of built structures, and its volatility-rank floor of 50 produced only 5 candidates on 8/14 against the sandbox’s 26 at a floor of 30.
- What changed. Entry orders now abort after 90 seconds if unfilled, using the same watcher that already handled exits. On the live account the quality floor now gates on the plain credit-to-width ratio, the sandbox’s setting, and the minimum volatility rank drops from 50 to 30. Directional news bias is limited to symbols the bot actually scans, which removed about 14,000 dead candidate evaluations a day and changes no outcome. Live money.
- Reason. The 50 floor was Robin’s deliberate risk-reduction setting from 2026-07-24; it was flipped with a data-backed reason and his explicit approval. Raising the directional engine’s cap was investigated and rejected: live directional is minus $541 over 15 trades (40% win rate) against the sandbox’s plus $765 over 12 (75%), and the gap is explained by the already-fixed CRWV bug, the sandbox’s idealized mid fills, and live hitting its directional allocation cap 454 times since 8/1. That engine is deliberately the smallest slice.
- Idea. A wider funnel only helps once the leak at the bottom is fixed. The 90-second abort is the leak.
2026-08-11: exits walk to the real bid and ask, breakers ignore open drawdown
- Issue. Two YouTube pitches (a pre-earnings straddle and five premium-selling lessons) were reviewed and dismissed, but asking what this bot would have done on 5 August 2024 turned up defects that had nothing to do with either video. The limit walk on an urgent exit was bounded off a multiple of the mid, so a bad quote could concede up to twice an already bad price. The daily and weekly loss breakers skipped any position whose latest mark was blank, which happens exactly when quotes are implausible, so they under-counted on the worst days. An opportunistic exit could fire into a quote blown out to 30% wide or more.
- What changed. Orders now carry the real bid and ask, and an exit walk stops at the touch or the old bound, whichever is tighter. Opportunistic exits such as the profit target are deferred while the widest leg is more than 30% wide; defensive and must-fill exits are exempt, so nothing can be stranded. The breakers walk back to the last good mark. Net vega is now measured every cycle but gates nothing. At Robin’s call the loss breakers count realized losses only.
- Reason. An unrealized swing from a volatility spike should not latch the weekly breaker for seven days on marks that recover in 48 hours. Volatility stress belongs to the risk-off halt and the VIX kill switch, which read the market instead of our own marks. Live net vega measured minus $23 per vol point on a $19,691 account, so a 20-point VIX spike costs roughly $470, small because everything is defined risk at one lot.
- Idea. Concede to the market’s real price, never to a synthetic one, and let the breakers count money that is actually gone.
2026-08-07: entry orders concede toward the touch, mega-caps no longer called illiquid
- Issue. Every live entry order, all 50 on the live account, was submitted at the mid and never repriced. It rested at one price until the 30-minute sweep killed it. Fill rate tracked spread width exactly: 89% on one-leg orders, 57% on two-leg verticals, 50% on four-leg condors. Overall the live account was filling 53% of its entries while the sandbox filled 100% at mid; live was not entering less, it was filling less. Separately, the directional lane’s liquidity check lumped “no data” together with “too wide,” and a stale cached spread condemned GOOGL (cached at 20% wide, live at 6 to 7%) while names like RTX and LMT were logged illiquid without ever being measured.
- What changed. Entry orders now go out at a price part way from the mid toward the touch (the ask for a buy leg, the bid for a sell leg), enabled at the halfway point on both accounts the same day. The concession never pays beyond the touch, and the true mid is still recorded so slippage stays honest. Known-liquid names skip the cached check and are tested against the live chain at entry; symbols with no data get their own skip reason. Live money.
- Reason. The price at submit was the whole story: filled orders lived 68 seconds, cancelled ones 35 minutes. This is not a loosening. XOM, genuinely 35% wide, still dies one stage later on real quotes. By 8/10 and 8/11 the entry abort count had gone to zero on both days, on four fills, real but not yet conclusive.
- Idea. Pay a known, visible fraction of the spread to get filled, and measure liquidity on the quotes we are about to trade.
2026-08-07: an instrument the broker refuses is not retried every cycle
- Issue. The sandbox tried the same GLD call strike 12 times in one morning. The broker rejected it as unsupported each time, the bot kept no memory of the answer, and the picker re-selected the same dead strike every cycle, burning a candidate slot and a broker round trip forever.
- What changed. A symbol the broker refuses for an instrument-level reason sits out 24 hours on that account. Transient rejections (margin check, empty response, rate limit, timeout) stay retryable.
- Reason. A margin failure clears the moment a position closes; treating it as permanent would be a self-inflicted day-long outage, so only the truly permanent classes are held out. A sandbox rejection never gates the live account.
- Idea. Record the broker’s answer instead of guessing it.
2026-08-06: index funds counted together, and the next entry blocker named
- Issue. QQQ, TQQQ and SQQQ were bucketed as Technology. The sandbox book read as two Broad Market plus two Technology, which looked diversified. It was four index products, essentially one leveraged beta bet. With the sector data fixed the day before, the live log also showed the next blocker: a well-built ADM condor with 1.725 of credit on 8.275 of width was rejected by the quality floor, because that floor was being scored against probability of profit as well as credit.
- What changed. The three Nasdaq-100 funds move to the Broad Market bucket and the three open positions were relabeled so the cap sees them. ARKK was pinned to Technology by hand, since it is an actively managed thematic fund, not an index. The quality floor was deliberately not changed; the bot now logs the score, ratio and probability for every attempt so the floor can be set from a week of real data instead of guessed.
- Reason. The Nasdaq-100 is a broad index that happens to be tech-weighted. The old label overstated tech concentration and hid the real correlation between QQQ, SPY and IWM. The live account moved from Technology 3 of 3 full to Broad Market 3 of 3 full (IWM, QQQ, SPY).
- Idea. A concentration cap only works when the labels reflect what actually moves together.
2026-08-05: the sector cap finally has sector data
- Issue. The maximum-positions-per-sector cap had never resolved a sector for a single stock: 83 of 93 positions ever had no sector, and the only 7 that did were hand-mapped ETFs. Every single stock fell into one shared “unknown” bucket, so on the live account AAPL, RIVN and T filled it at 3 and the bot could not open a fourth single-stock position in any sector. It was the top actionable skip on every engine, 2,602 skips in five days across 145 symbols. Not money (53% of allocation in use) and not counts (7 of 15 slots).
- What changed. Symbols are classified into a fixed sector list from the company’s published name, stored once, and a hand correction is never overwritten by the classifier. Open positions are bucketed the same way. The cap itself was not raised.
- Reason. Fix the data, do not loosen the control; it is the only correlation gate the bot has. The classifier can only restrict an entry by routing a symbol into a bucket; it can never authorize or size a trade. Verified on 15 live names, including one it correctly declined to classify. Technology stays capped afterward (AAPL, QQQ, SMH), and every other sector opens up.
- Idea. A cap that reads bad data is not a cap.
2026-08-04: first honest read of the live ledger
- Issue. The first expectancy report showed the live account at minus $832 net over 21 trades, minus $40 per trade. Read at face value that says the strategy loses money.
- What changed. Nothing in the bot. No engine toggled, no gate relaxed, no threshold moved. The report and the underlying trades were written up so the loss is explained rather than averaged.
- Reason. $1,078 of that loss sits in two clusters. Three bearish put pairs (CRWV minus $505, NVDA minus $54, AMZN minus $52) all opened on 2026-07-07 at 17 days to expiration, a window only reachable through the swing band, on the day a per-account swing-off setting silently failed to hold. That was a bug, fixed 2026-07-08, and it cost real money. Two earnings condors (NFLX minus $256, TSM minus $211) had short strikes placed inside the implied move, a gap fixed 2026-08-01. The other 16 trades net plus $246. The core mechanical engine is minus $8.40 per trade over five trades: flat, and five trades is nothing.
- Idea. Excluding losers after the fact is how people fool themselves, so the defense is that both clusters were documented open bugs before the report ran. The earnings engine gets judged on 10 post-fix trades, not on 5.
2026-08-03: a hand-placed position no longer blocks debit spreads, buying power ceiling raised
- Issue. XLU, HOOD and NOW opened in the sandbox but never on the live account. The manual-leg collision check only recognized credit-spread geometry, so any bull call or bear put spread read as uncovered, and Robin’s hand-placed QQQ put spread armed the check for every symbol. HOOD was blocked for three hours while the sandbox filled it. Separately, the buying-power ceiling required 65% of net liquidation free, with hand-held positions counting against it, and the live account could open nothing.
- What changed. A same-type long anywhere in the proposal now counts as cover, in both wing geometries. Robin raised the ceiling so the account keeps 5% free instead of 65%. Live money.
- Reason. Both wing shapes cap risk; the check had only been taught one. The ceiling was Robin’s knob call.
- Idea. A safety check has to understand every structure the bot can build.
2026-08-03: the volatility premium gate had been rejecting everything
- Issue. Since it was switched on 2026-07-26, the gate that requires implied volatility above realized had been subtracting a percentage from a decimal fraction, so every symbol with data came out negative. Daily mechanical candidates fell from 157 to about 20 the day it went on. The only names still entering the premium engines were ones the data feed did not cover. Also, when the top-ranked structure failed its own liquidity or risk check, the bot gave up on the symbol instead of trying the runner-up.
- What changed. The gate reads the data vendor’s own matched difference. When a structure fails a structure-specific gate (leg liquidity, manual-leg collision, per-trade risk cap), the bot walks down the ranking and takes the first structure that passes. Portfolio-level caps do not retry cheaper structures.
- Reason. The gate’s logic was right; its input was garbage. The fallback was Robin’s request; auto-downsizing into a nearly full account was left as something an operator opts into rather than inherits.
- Idea. A rule can only be as good as the number it reads.
2026-08-02: a position you close by hand is booked from the broker’s record
- Issue. When a position vanished from the broker because the operator closed it in tastytrade, the bot froze it as needing attention and its profit or loss never reached the ledger until someone rebuilt it by hand. That had happened once, for an AMZN position on 2026-08-01, whose entire outcome had been missing.
- What changed. The bot asks the broker for the account’s transaction history, matches the position’s exact contracts and quantity against the closing fills, and books the real closing price and fees. A push notification reports the result. Any partial or ambiguous match books nothing and falls back to the freeze.
- Reason. Robin’s call: if it was closed in tastytrade it was to get out, so resolve it immediately. Matching on contract identity is stronger than any order tag, because a hand-placed close carries no tag.
- Idea. When unsure, ask the broker. When still unsure, refuse to guess.
2026-08-02: buying power ceiling enforced and a beta-weighted delta gate at entry
- Issue. The buying-power ceiling existed as a setting but was never enforced. Nothing at entry consulted the portfolio’s beta-weighted delta. Days to expiration were computed from the server’s date instead of the exchange’s, which on a cloud host makes every count a day short after 8 pm Eastern. The allocation cap was computed three different ways, and the dashboard showed “uncapped” in exactly the state where the bot enforces $0 and takes no trades.
- What changed. A broker-wide buying-power ceiling (35% at launch) is enforced against the broker’s own remaining buying power, so hand-held positions count. A new entry is rejected when it would push beta-weighted portfolio delta further outside a band of 1% of net liquidation. Expiry math uses the exchange date. The picker no longer crashes or mis-ranks on an unpriceable proposal. Six more settings where a global value silently beat a per-account override were fixed.
- Reason. The band shipped at 1% rather than tastytrade’s 0.1% because at 0.1% a single one-lot 20-delta short already exceeds it on this account size. A per-trade cap as a percent of net liquidation was parked: 5% of $12,460 is $623, which would reject every 10-wide condor, the structure chosen for more credit and wider breakevens.
- Idea. Every ceiling in the settings should be a ceiling the bot actually checks.
2026-08-02: six execution and accounting fixes on live-money paths
- Issue. A validation pass found nothing actively losing money and six defects one ordinary event away from firing. The limit walk assumed a close always costs money, so a close that collects a credit (closing any net-long position, worst case selling assigned stock) would jump to twice the mid on its first walk and pin there unfillable. A broker zero on a fill price could book a condor’s credit 100 times too light and trip the 50% stop on a healthy position. Global directional settings beat per-account ones, the exact mechanism behind the CRWV loss. The directional earnings exit and the 50% premium stop were opportunistic and could fail to fill on the last cycle before a report. Fees were stamped on orders but never reached profit and loss.
- What changed. Credit-collecting closes floor at 75% of the mid; debit closes cap at twice the mid. Per-account directional settings win. Both deadline exits are must-fill. Trades carry summed open and close fees, and the dashboard shows net of fees next to gross. Stale global trend-band rows still at 30 to 45 days were corrected to the 45 to 60 day band. Live money.
- Reason. The 75% floor is deliberately asymmetric with the 2x debit cap: failing to buy back a short leaves width-sized risk open, while failing to sell a long only risks what the long is still worth. tastytrade has no rule here, so this is bot policy filling a gap. The must-fill promotion shipped after the sign fix on purpose; reversed, it would have routed the exits that most need to fill straight into the pin.
- Idea. The exits that matter most must be the ones that cannot get stuck.
2026-08-02: directional lane rebuilt to Payne’s plans
- Issue. The directional engine had drifted from its source. Swing trades took profit at 40% of premium against a 50% stop, a negative-expectancy pairing invented in June. The half-time rule harvested any winner at half time and rode losers to the stop, the opposite of Payne’s rule. Nothing kept a long-premium trade from holding through an earnings report.
- What changed. Directional entries are skipped within 14 days of earnings, and any directional position whose report falls inside its remaining life closes the day before the announcement, regardless of profit or loss. Swing plan: enter 21 to 35 days out (was 7 to 21), take profit at 100% of premium (was 40%), and at half the trade’s life anything below 50% profit exits, laggards and losers alike. Trend plan: enter 45 to 60 days out (was 30 to 45), manage at 30 days left (was 21), uncapped singles take profit at a 70% return, capped debit spreads keep 82% of max gain. The 50% premium stop is Payne’s own number and is unchanged.
- Reason. Every default traces to one of Payne’s eight plan sheets. Long premium never holds through the volatility crush. The three open swing positions at the time were assessed under the new rules: none exited on restart, and each reaches its pace check around 2026-08-07.
- Idea. Payne governs the directional engine; tastytrade governs everything else.
2026-08-01: earnings strikes moved out, directional volatility ceiling restored, catalyst close calmed
- Issue. A 26-agent validation of the bot against tastytrade doctrine found the core loop (50% target, 21-day exit, credit-only rolls, entry pricing) faithful, and four defects. Every earnings condor on both accounts had entered with shorts at 0.55 to 0.71 of the implied move, inside the priced move on a binary event, at 37 to 42% probability of profit. The directional lane’s volatility-rank ceiling of 60 had been silently disabled by a blank setting, so longs were bought at ranks of 66 to 92 (NFLX at 90.7 lost $169). The catalyst close arm fired at 0.30 delta, so shorts entered at 0.20 to 0.30 could be closed for merely wiggling (TSM closed for minus $59 at 0.32 delta; marks then reverted $48.50 the other way).
- What changed. Earnings short strikes move from 30 delta to 20 delta. The 60 ceiling is back. The catalyst arm only accelerates once the strike is genuinely tested, at 0.45 delta. The broker’s commissions and regulatory fees are recorded on every order, live and paper. The live ledger was repaired: an AMZN position from the 2026-07-07 incident had no trade row at all and was rebuilt from broker history at minus $52. True live gross since launch: minus $813 over 20 trades. Live money.
- Reason. The live-versus-sandbox gap (minus $761 versus plus $900) decomposes into two already-fixed bugs, the defects above, about $63 of chase cost, and unbooked fees. Execution explains less than 10%. The sandbox number is a zero-friction upper bound: mid fills, no fees, no entry aborts against live’s 43%.
- Idea. Validate against the doctrine you claim to follow, then fix what does not match.
2026-08-01: directional count cap 2 to 4, mechanical engine starved by the regime
- Issue. Entries stopped. The live account’s last cycle on Friday had 17 candidates and 0 entries: 16 were directional and blocked by a count cap of 2 (F and RIVN open), and the one mechanical candidate was correctly rejected at negative expected value.
- What changed. Directional count cap raised from 2 to 4 on both accounts. The mechanical volatility floor of 50 was left alone.
- Reason. With VIX at 16.1 the entire scanned universe had 13 symbols above a volatility rank of 30 on 2026-07-31 and not one liquid large cap. Lowering the floor to 38 would have added only small caps.
- Idea. Do not buy illiquid names to manufacture activity. Wait for volatility.
2026-07-29: market data now comes from the live session
- Issue. Chains and marks were fetched through the sandbox environment, which measured 8 to 25 times slower than live on two different connections, with thinner chains and no streaming quotes for the live account’s real contracts. Every chain fetch timed out, so the bot had produced zero entry candidates since 2026-07-24 and cycles ran about 12 minutes.
- What changed. Chains, marks and VIX come from the live login whenever one exists, with the sandbox as the fallback. Order execution is untouched: each account still trades through its own session. Concurrency was cut to 8 after the live API throttled the first fan-out, with retries.
- Reason. The first live-data cycle evaluated 119 candidates and fetched an eight-symbol chain batch in 1.4 seconds, every skip a real strategy gate.
- Idea. Rehearse order shapes in the sandbox; read prices from the real market.
2026-07-29: rolls never widen, one-order rolls, and the tastytrade defense ladder
- Issue. On 2026-07-28 rolls on EWY, SMH and DRAM silently doubled defined risk from 5-wide to 10-wide, because the roll rebuilt at the current default width while the stored max loss never updated (SMH showed $210 against about $705 real). A two-phase roll on EWY closed the old side and abandoned the new one with no notification; it was closed by hand for minus $45. The primary tastytrade defense, rolling the untested side in, was unreachable in the live path.
- What changed. Rolls hold the position’s own width, are refused if wider, and re-check the per-trade cap. Any roll that fits in four legs goes out as one net-credit order that fills whole or touches nothing, with strict validation so a stale closing leg can never be converted into an opening leg. The defense ladder is now: a confirmed catalyst closes at any time to expiration; tested with ample time, roll the quiet untested side (15 delta or less) in for credit; tested near expiry, roll out in time, or close if that cannot be done for credit. The new untested short can never cross the tested strike (at most an iron fly). The old same-expiry widen roll was retired. The roll-the-untested-side switch stays off until the first live one-order roll is observed end to end; until then a tested position with ample time holds.
- Reason. Rehearsed the same morning in the sandbox: a mixed-action four-leg roll filled as one unit. Live money on the width guard.
- Idea. Defense should never add risk, and a roll should be one order, not two hopes.
2026-07-26: volatility premium gate on, liquidity rating floor, news veto gets its own switch
- Issue. One news toggle armed both the offensive news-entry path and the defensive stand-aside veto. The universe carried price, volume and weeklys floors that nothing consumed. Premium engines had no check that implied volatility actually exceeded realized.
- What changed. The veto has its own switch, off by default. Candidates below a liquidity rating of 3 on tastytrade’s 1 to 5 scale are rejected, including known-liquid names; a missing rating passes. The volatility premium gate is on: premium entries decline when 30-day implied is below 30-day realized, directional exempt. The dead floors were deleted. (The gate’s input turned out to be in mismatched units; see 2026-08-03.)
- Reason. Robin: a $20 stock is fine, thinly traded options are not.
- Idea. Gate on the risk that actually bites.
2026-07-26: stored credentials encrypted at rest
- Issue. Broker secrets, refresh tokens and API keys sat in the settings table in plain text. Anyone with database access had a usable credential.
- What changed. Secret settings are encrypted row by row with a key held outside the database. Existing plaintext rows were encrypted in place once. A missing or wrong key fails loudly instead of returning an empty credential.
- Reason. The hosted database already encrypts storage and enforces TLS; this is the layer that survives a leaked database login.
- Idea. Database access alone should never yield a usable credential.
2026-07-24: mechanical engine moves to 20 delta, 10-wide wings, volatility rank 50, $700 cap
- Issue. A review against Tom Sosnoff’s “11 boring strategies” and tastytrade’s 10-year condor-versus-strangle research found the execution layer mature and the mechanical engine running the weakest premium configuration: condors at low volatility rank, 30-delta shorts, 5-wide wings.
- What changed. Mechanical entries need a volatility rank of 50 (was 30), short strikes sit at 20 delta (was 30), wings are 10 wide (was 5), and the per-trade cap is $700 (was $300), raised with the width so a 10-wide at one-third-width credit is not blocked. Width and rank are editable from the dashboard; width is constrained to $5 steps from 5 to 20. Shipped live the same day with Robin’s approval. The sandbox account was set to the old configuration as a control, so live versus sandbox is a forward A/B.
- Reason. A 20-delta, 10-wide condor approximates the short strangle, the study’s winner, while staying defined risk and IRA compatible. Accepted consequence: about 3 chunkier positions instead of 6. Earnings, contraction and directional floors are untouched. The earnings engine stays on despite a live record of minus $343, with the decision deferred to a backtest.
- Idea. Sell the expected move with wings wide enough to keep the premium edge.
2026-07-24: two safety knobs that gated nothing now gate, plus a pre-entry news veto
- Issue. An audit of the settings found two that read as safety controls and did nothing. The roll-undefined-risk switch never gated, so turning it off would not have closed a breached strangle. The naked earnings delta of 16 was never read: an opted-in naked earnings entry would have built at 30 delta, about twice as close to the money. The news toggle was an end-to-end no-op.
- What changed. Both knobs work. Off now closes a breached undefined-risk position instead of rolling it; naked builders read 16 delta. A pre-entry news veto exists: fresh, high-confidence company news vetoes a new premium entry on that symbol in either direction. Off by default. Defaults for all three preserve live behavior.
- Reason. Both knobs had to work before any undefined-risk structure goes live. A condor is short both ways, so strong fresh news either way is uncompensated event risk.
- Idea. A knob that does not gate is worse than no knob.
2026-07-23: sector cap 2 to 3, country funds get their own bucket
- Issue. The live book (SMH, EWY, IWM, SPY, INTC) filled both its sector buckets at a cap of 2 and stopped entering. EWY and INTC both sat in the shared unknown bucket, competing for room against unrelated names.
- What changed. Maximum positions per sector raised to 3 at Robin’s request and made editable from the dashboard, globally and per account. Country and regional funds (EWY, EWZ, EEM, FXI and the like) get an “International” bucket.
- Reason. Diagnosed from why the live account was not entering.
- Idea. Buckets should reflect what is correlated, and the cap should be a dial, not a code edit.
2026-07-23: a fill that lands during a cancel no longer freezes the position
- Issue. Live QQQ delta-defense close. The walk cancelled the first order at 2.53 and replaced it at 2.58, which filled at 2.55 within a second. The broker’s cancel event for the old order arrived first and set the position back to open; the fill then landed against an open position, and the booking layer, correctly refusing to guess, froze it. Database said open, broker was flat.
- What changed. A cancelled close no longer reopens the position while a replacement close is live, and the walk re-asserts the closing state after placing a replacement. Both event orderings are covered. The position was booked by hand from the real fill at plus $22. Live money.
- Reason. The fail-closed refusal did its job; the fix targets the two writers that created the contradiction.
- Idea. Never book against a state you cannot trust, and never let a race create that state.
2026-07-19: per-trade cap becomes a flat dollar figure
- Issue. The overnight batch enforced the per-trade risk cap as 2% of net liquidation, which at the live account’s size came to about $252 and would have skipped every standard $300-risk 5-wide condor.
- What changed. The cap has two modes: a flat dollar figure (the default, $300) or a percent of net liquidation. Settable per account from the dashboard. Zero means uncapped. A wing may still resolve at most 1.5 times the intended width.
- Reason. Robin’s explicit request so the standard trade is not blocked.
- Idea. Size the cap to the structure you actually trade.
2026-07-19: overnight review batch, 16 fixes and three dials shipped off
- Issue. A full-model review on 2026-07-17 produced 18 confirmed findings. The roll credit gate used a flat 25-cent buffer and approved rolls that lost money after fees. Cooldowns were shared across accounts, so sandbox activity could block a live entry or suppress a live defensive close. After a roll the profit target read the stale entry envelope. A pair spread’s debit-side short read as “tested” at entry. A one-day 8% gap early in a 45-day position barely registered as a catalyst. The sector cap could not see a live MU plus SMH book. The allocation cap could resolve to “uncapped” when no net liquidation was available.
- What changed. Rolls must clear 60 cents per leg plus a buffer, about $2.65 of net credit for a four-leg roll. Cooldowns and news dedup are per account. Rolls recompute max profit and max loss. Only the credit side of a pair defines tested. The move ratio is scaled by time elapsed. A ladder news shift must be under 24 hours old, postdate entry, and oppose the tested side. An armed expiry-day flatten beats a mid-confidence news reduce, and a flatten blocked twice by missing marks pages the operator. Per-trade risk is enforced at entry. Contraction requires fresh spike data. The allocation cap fails closed to $0. The risk-off day-open baseline seeds from the prior close after a restart. Three dials shipped with defaults that preserve behavior: the quality-floor mode, whether breakers count unrealized loss, and the volatility premium gate.
- Reason. All from the 2026-07-17 review. The same read found the earnings engine’s 1 to 3 day trades net minus $343 over five trades, flagged as a blocker for that engine.
- Idea. Model real friction, keep accounts from bleeding into each other, and fail closed when a number is missing.
2026-07-17: a manual close on the live account never reached the broker
- Issue. Robin clicked Close on the live SPY condor. The dashboard marked it closed with plus $19 realized; SPY stayed open at tastytrade. The manual close had booked directly in the database at the last mark for every account, with no broker order and no live check. It was the first manual close ever clicked on a live position, so it had never surfaced. Caught within minutes and the database repaired so broker and ledger agreed.
- What changed. On a live account, Close now sets a request the trading loop picks up and executes through the real close path: a real order, the limit walk, booked from the actual fill. Market-closed and data-quality deferrals apply, and the request stands until executed. The dashboard shows a closing state while it is pending. Paper accounts keep the instant booking.
- Reason. Live money. A close that exists only in our database is not a close.
- Idea. Every close on a live account is a broker order, including the ones a human clicks.
2026-07-15: broker login problems now heal themselves and raise a flag when they do not
- Issue. The sandbox account silently stopped being managed at about 1:50 AM ET. One transient failure while looking up the account after login left that login half set up, and the bot then skipped it on every later attempt without logging an error. The account showed as healthy while nothing managed its positions, and only a full restart would have fixed it. Two days earlier a separate bug aborted the live account’s management pass on any cycle where a candidate trade collided with one of the operator’s manual holdings; the collision was handled correctly, but writing the note about it crashed the cycle.
- What changed. A half-initialized login is retried instead of skipped, and every cycle re-checks that each trading-enabled account is present, so a blip recovers on the next cycle with no restart and no noise. If a login stays down, a red banner on the dashboard tells you to re-paste your token and a push alert goes out; a live account with open positions going down is sent at high priority. A credential-type error escalates on the first failure; a network blip gets two cycles. A benign sandbox quirk tripped the new banner the same morning, so the check was narrowed to the one test that proves an account is usable. The manual-holding crash is fixed, and a note-writing problem can never again stop a cycle. Same day: the daily auto-screener had been skipping its refresh for about 24 hours after every reboot, now fixed, and the dashboard’s cap and buying-power panels now show the per-account cap the bot actually enforces (on the live account, $3,000, not the $5,000 global figure they had displayed).
- Reason. Unmanaged positions with no alarm is the worst failure mode a bot can have. Enforcement was correct throughout; detection and display were not.
- Idea. Retry quietly, then alarm loudly.
2026-07-11: favorable news no longer closes a directional trade
- Issue. The news gate decides whether a headline opposes a position. Four directional structures (bull call spread, bear put spread, long call, long put) were never registered with a direction, so the gate treated them like iron condors, where news in either direction counts as a threat. A winning bull call spread could have been closed by a high-confidence bullish headline. Checked against the ledger: it never fired on a real trade. The only news-gate exit ever recorded (NVDA, July 8) was on a correctly mapped structure. Two open sandbox positions were exposed at the time; no live money.
- What changed. The four structures now carry their direction. Opposing news still closes them. Favorable news does not. A guard now checks that every buildable structure has a direction so a fifth cannot slip through the same way.
- Reason. Found during an audit prompted by a question about whether the news gate exits condors at all.
- Idea. The gate protects a thesis. It should not cut a trade on news that confirms it.
2026-07-09: a swing-mode setting that never saved, a CRWV loss, and screener controls
- Issue. On the dashboard, the directional engine’s swing-mode toggle looked like it saved per account but never did; every click snapped back on the next refresh. Meanwhile the live account had entered CRWV on July 7 at 17 days to expiration, a duration only reachable through the swing window, while the intent was to have swing mode off on that account. That position stopped out on July 9 at an 82% loss of the premium paid, $505 of real money, under the standard 50% premium stop that a short-dated entry is far more exposed to.
- What changed. The per-account save for swing mode was fixed the night of July 8, so the setting sticks to the account it was set on. The auto- screener’s five tuning knobs (minimum IV rank, minimum liquidity rating, list size, refresh interval, and which tastytrade watchlists feed it) are now editable from the dashboard with no restart. The default watchlist set grew from five to eight, adding S&P 500, tasty Fast Movers, and tasty Earnings, each tested live before being added. A per-account news-trigger toggle that returned a server error is also fixed, though the news-trigger entry path itself is not wired to anything yet, so that toggle does nothing either way for now.
- Reason. The setting that should have kept the live account out of a short-dated directional trade was not being written anywhere.
- Idea. A setting that appears to save but does not is worse than no setting.
2026-07-08: a tested condor with time left is now rolled, not closed
- Issue. The defense rule closed a defined-risk position the moment the tested short strike’s delta reached 0.45, with no regard for time left. Five mechanical positions were closed this way at 44 to 50 days to expiration, none ever rolled: MRVL (-$62.50), ADBE (-$27), SMH (-$22), CRM (-$29), BABA (+$12), all entered at 50 to 53 days and closed one to nine days later. Separately, the catalyst check inside that rule (how far the stock has moved relative to its implied move at entry) had never once had data: the underlying’s price at entry was never recorded on any of the 37 positions ever opened, so the check silently fell back to delta alone.
- What changed. For defined-risk positions, a delta reading alone closes the trade only inside 21 days to expiration. With more time and no catalyst, the bot buys back the tested spread and re-sells it further out of the money at the same expiration, for a net credit, subject to the same fee buffer and roll limit as other rolls, and skipped if earnings land before expiration. If no credit roll exists, the position is held rather than closed, and the hold is logged so the patience is visible. A confirmed catalyst (an abnormal move against the implied move with the tested delta at or above 0.30) still closes at any duration. The underlying’s price and implied move at entry are now recorded on every new position, so the catalyst check has data going forward; existing positions keep the delta-only fallback.
- Reason. tastytrade’s guidance is to roll a tested side while there is time. The rule was contradicting the bot’s own stated patience for defined-risk trades.
- Idea. Time is the defense. Do not spend it on the first bad delta reading.
2026-07-08: live positions priced from the broker’s marks, and garbage quotes thrown out
- Issue. The bot priced open positions from raw bid/ask midpoints on the data feed, which ran about $1 per share low on wide books. Measured at the same instant: an NVDA package priced at 3.62 against the broker’s 4.80 mark, so the dashboard read -$128.50 against roughly -$11; CRWV read -$235 against -$132.50. Those marks feed the profit, stop, and defense rules, not just the display. Overnight, a live MU condor got quotes that netted to an impossible negative cost to close, so the dashboard showed +$345.50 against the broker’s roughly +$69 and the bot logged “125% of max profit” close intents all night. Only the market-closed deferral kept it from firing, and a manual close from the dashboard would have booked at that garbage number. A live NVDA close had also booked its 4.04 limit instead of the real 4.37 fill, so the ledger said -$87 when the truth was -$54.
- What changed. On live accounts the broker’s own per-leg marks now take precedence over feed midpoints; any leg the broker does not mark keeps the feed value, and deltas still come from the feed. Outside market hours a computed mark is never trusted. During hours, a mark that implies a profit or loss outside the structure’s possible range (plus a small allowance for noise) is discarded and recorded as rejected. The dashboard and the manual close button use the newest plausible mark and refuse to close if none exists. When a fill event arrives with incomplete per-leg data the bot now re-reads the order at the broker and books the real netted price; the NVDA rows were repaired. The trade ledger now records which rule closed each trade. And every full close is followed for five trading days, recording whether the exit saved money against holding, so exit rules can be judged on data rather than one anecdote.
- Reason. Every exit rule fires on a number, and the number was wrong in two different ways.
- Idea. Price the position the way the broker prices it, and throw out any quote that cannot be a price.
2026-07-07: entry orders are checked before they are sent, and verified after
- Issue. Two live incidents. The allocation and per-engine budget checks ran after the order was submitted, so a candidate that exceeded its budget filled first and was aborted afterward: CRWV (about $1,114 of buying power) and NVDA (about $998) both blew through the directional engine’s $450 budget and were stranded awaiting attention despite clean fills. On another entry the broker returned an empty response, the bot treated the order as failed, and the order filled two minutes later on a position the bot believed dead (AAPL, AMZN). Bot orders were also never being tagged as bot-owned, a loss from an earlier library upgrade that had made the reconciler’s ownership check dead code.
- What changed. Defined-risk trades are checked against the allocation cap and engine budget before anything is sent; undefined-risk trades get a no-side-effect validation first. If an order still lands over budget, the bot tries to cancel, and if the fill wins it books a normal managed position and raises an alert. After a submit error, the bot lists today’s orders at the broker and matches the exact legs before deciding; if the order exists or the lookup fails, the position is frozen for attention rather than assumed dead. Every bot order carries the bot’s tag again.
- Reason. Real orders exposed ordering assumptions that paper trading never tested.
- Idea. Decide before you send. After you send, verify before you conclude.
2026-07-07: three live-money fixes, plus push notifications
- Issue. Every swing-mode directional entry was being closed on its first evaluation because the standard 21-day exit backstop equaled the top of the 7 to 21 day swing window. This fired live on NVDA (13 days) and CRWV (17 days). The daily and weekly loss breakers looked up marks by symbol, so two open positions on one underlying fed one position’s mark into the other’s total. Three-leg funded-pair fills booked at the long put’s price alone, dropping the funding spread’s credit: CRWV booked -$715 (true -$615) and NVDA -$600 (true -$491), an error too small and sign-correct for the size guards to catch.
- What changed. Swing trades have their own five-day exit backstop. Breaker math and the dashboard’s marks are scoped per position, not per symbol. A fill snapshot with incomplete per-leg data is anchored to the order’s limit, the worst case for a marketable limit, and the affected rows were corrected from the broker’s records. Pushover push notifications were added alongside SMS: each user supplies their own free Pushover keys, stored in the bot’s settings and never shown in any response, with per-event switches and a test button. Notification settings are global, and a bug that silently dropped them when an account was selected is fixed.
- Reason. Each was a live-only data shape that no sandbox fill had ever produced.
- Idea. Assume the broker’s event is incomplete until every leg says otherwise.
2026-07-06: earnings trades now enter close to the report
- Issue. The earnings engine was entering 7 to 13 days before the report (NFLX was the case). The only timing control was the expiration window’s seven-day floor, which forced the nearest post-report expiration to be at least a week out, which in turn forced early entry.
- What changed. A real timing gate: the engine enters only when the report is within three days. The expiration window is now 1 to 14 days and only bounds the resulting expiry. Naked earnings structures are a per-symbol opt-in (default off for every name) instead of an engine-wide switch; other engines are unaffected. Both are editable from the dashboard, globally or per account.
- Reason. Entering a week early holds the trade through days of movement that have nothing to do with the earnings premium the engine exists to sell.
- Idea. Sell the crush, not the run-up. Open question left on the table: whether one to three day entries price well enough to clear the 25% credit-to-risk floor. To be measured.
2026-07-06: fills book at the real per-leg price, and the loop stays up when code changes
- Issue. A newly opened live NFLX iron condor showed -$250 on the dashboard while tastytrade had it down about $2. The broker library’s average-fill figure had produced a per-contract value of -$52, a debit on a credit trade with a $198 limit, small enough and wrong-signed enough to slip past the size guard. Deeper: every live fill had been booked at the limit price, never at what actually filled (which is why every fill showed zero slippage), because that average was unreliable and the true per-leg fills sat unused. Same day, the live server was found running with an auto-reload flag: any code or doc edit restarted it and left the trading loop stopped. The live positions (NFLX, EWY, SMH, MU) went unmanaged from about 10:28 to 17:00 ET. No harm found; MU was at about 32% of its 50% target, and the catch-up cycle had nothing to close.
- What changed. The signed net of the actual per-leg fills is now the fill price whenever every leg reports one. An open whose fill lands on the wrong side of its own limit is corrected. The NFLX row was repaired to +$198. The server was relaunched without auto-reload; the standing rule is never to run the live bot that way and to use the dashboard restart button instead.
- Reason. Robin asked why we book a proxy at all when the exact executed prices are available.
- Idea. The broker’s fills are the source of truth. Earlier live positions booked at their limits can be reconciled against real fills if exact cost basis matters.
2026-07-02: first real trades, and the bug found on the way
- Issue. Robin flipped the Individual account to live. The dashboard showed MU and SMH iron condors, but neither order reached tastytrade. The bot cached each account’s paper-or-live flag at login and never re-read it, so the loop kept simulating orders for an account that was now live. The trading-enabled flag was already re-read every cycle; the paper flag was the one that stayed stale.
- What changed. The paper-or-live flag is re-read at the top of every cycle, a fill listener is started for any account that just went live, and the dashboard toggles apply immediately rather than on the next cycle. The two phantom positions and their simulated orders were removed. After a clean restart, the first three real fills landed on the live account. The review documents were updated to say plainly what that proved (live order submission and fill handling) and what still had no live reps (stale-order cancel, a real close or roll, the reconciler, resting orders, the dividend check).
- Reason. The flag that separates simulated from real orders must be as fresh as the flag that allows trading at all.
- Idea. One small account, watched closely, before anything scales.
2026-07-02: six findings from an outside review, plus caps and cancels that now work
- Issue. An outside adversarial review said no-go for scaling up until six issues were fixed; all six were verified real. The broker’s “partially removed” status (partial fill, remainder cancelled) was left in a working state, so the filled part was neither booked nor flagged for up to 30 minutes. A configured probability-of-profit floor let a candidate with missing deltas through. News-triggered entries skipped the IV rank floor entirely; the floor of 20 had been in the config since the start and was never read. Daily equity snapshots from different accounts overwrote each other. News-trigger cooldowns and the broker order lookup were not scoped per account. Separately: per-account per-engine position-count and allocation caps never saved or applied (Robin set mechanical to two on the Individual account and it reverted), and an unfilled entry order looked identical to a filled position with no way to cancel it.
- What changed. A partial-then-cancelled fill books the filled portion and flags the position in one step. A probability floor with no delta data rejects the candidate. News-triggered entries enforce the IV rank floor (missing rank fails closed) and carry the real rank. Equity snapshots, news-trigger gates, and order lookups are scoped per account; a fill that matches another account’s order is logged and never booked. Per-account engine caps now save, display, and bind at trade time, with the account override winning over the global setting. An unfilled entry shows a “working, unfilled” badge with a cancel button, and a cancelled entry no longer lingers as a phantom open position.
- Reason. Outside eyes on the fill path before real size.
- Idea. Missing data is a rejection, not a waiver.
2026-07-01: four silent failures found on a live day
- Issue. Every symbol was being rejected for lacking an expiration in its window, including ABBV’s real August 21 expiry at 51 days. A fresh session fetched the chain fine; the bot’s 40-minute-old session returned nothing for every symbol and logged no error, and a restart went from zero candidates to 64 on the next cycle. The real cause: the scanner fired about 500 requests at once across a roughly 250-name universe against a connection pool capped at 100, so everything past the cap timed out and looked like a data failure. The position-mark fetch had also failed completely (40 expected, 0 received) for 11 straight cycles over about 57 minutes, so close actions were skipped across 10 open positions, and the safety net meant to force a session refresh after two such cycles never fired because a later, unrelated fetch overwrote its input. And the news classifier had been dead since the move to the new database: every new article was stored but never queued for classification, so only the startup sweep ever classified anything.
- What changed. Scanner requests are limited to 24 in flight. Chain fetch failures are logged instead of swallowed, and two straight cycles of zero chain coverage force a session refresh, the same recovery the marks path already had. The marks safety net now reads only the fetch it is meant to watch. The classifier insert is fixed, so real-time news classification, which feeds the news gate and news bias, works again. A timing bug that could delay the first proactive token refresh by up to 20 hours after a start is fixed too.
- Reason. Each failure was invisible: no exception, no halt, just an empty result treated as a fact.
- Idea. Empty is not the same as none. Log it, count it, recover from it.
2026-06-30: rolls book real fills, sessions heal overnight, and IRAs cannot go naked
- Issue. A live roll folded the planned cash flow into cost basis instead of the actual fill, so every rolled position would carry a basis off by the roll’s slippage, either triggering the profit target early or understating a loss. Data-feed marks were dropping to nothing overnight and needed a manual restart: broker tokens last about 24 hours and were never refreshed, and the failures were swallowed silently. The account-type gate looked up the raw label from the broker, so a live account stored as “Traditional IRA” fell through to the permissive margin default and would have been allowed a short strangle or naked put at entry.
- What changed. Roll cost basis now sums the actual fill prices of the close and open orders, falling back to the plan only if a fill price is missing, and loudly. Sessions refresh proactively every 20 hours and reactively after two cycles of zero mark coverage. Account types are normalized before lookup: any IRA, Roth, 401k, HSA, custodial, or similar label resolves to its defined-risk-only set, and a taxable account that is cash-only is treated as cash; unknown labels default to margin. Custodial accounts are capped at five contracts per position. The directional engine gained a default IV rank ceiling of 60, and per-engine buying-power and position-count caps, contracts per directional entry, and the bias thresholds became dashboard settings.
- Reason. Three separate ways the live account could drift from what the operator believed was enforced.
- Idea. The broker’s label is not the rule. The rule is what the label maps to.
2026-06-29: a wrong fill price closed three sandbox positions within minutes
- Issue. For multi-leg orders the broker library’s average fill figure returned the unsigned sum of all leg prices, about $29.40 per share for a condor whose real net credit was $2.78. A guard existed but needed a field that is absent on live fill events, so it never ran. The stored credit was five to ten times too large, the profit target saw a 963% gain immediately, and QQQ, SMH, and MRVL were each opened and closed within one to four minutes.
- What changed. A second guard reads the order’s own limit price from the bot’s records and corrects any fill above three times the limit. The next day it was tightened to 1.5 times after DRAM (2.33x) and CRM (1.96x) slipped past the looser bar. The three closed trades stay in the ledger with inflated but offsetting figures.
- Reason. Real fills should land within about 10% of the limit; anything far beyond that is a data artifact, not a price.
- Idea. Trust the limit you sent over a number you did not compute.
2026-06-25: a vanished position, a fake loss, and a VIX switch that never had data
- Issue. The sandbox wipes all positions every 24 hours. MU’s legs vanished from the broker on June 24; the reconciler noticed but only alerted, leaving the position open. The bot kept managing a ghost, fired a close, the broker rejected it, and the close booked a debit of $835 on a spread only $499.50 wide: a fake loss of $668 that pushed day P/L to -$644.50 and tripped the daily loss breaker. The halt was real; its cause was fiction. The day before, a QQQ close had booked a per-share debit of 23.73 (the non-netted sum of the legs) against a true 2.77, showing -$2,099.50 on a near-breakeven trade, and a stalled data connection could hang a cycle forever with no timeout. Also: the VIX kill switch had read “unknown” on every cycle since it was built, because VIX is a cash index with no bid or ask and the fetch listened only for quotes.
- What changed. A position that vanishes at the broker is frozen for operator attention rather than managed or auto-closed, and is never booked at $0. A close fill larger than 1.2 times the structure’s width is refused and flagged instead of booked. A close fill more than three times the order’s limit is corrected to the limit. Every data connection and chain fetch has a timeout, with a whole-cycle backstop. VIX is read from the last trade price first. The next day the loop was also made to resume automatically after any restart in whatever state, running or stopped, the operator last chose.
- Reason. A safety halt fired on a number that could not be true. In live trading, a vanished position before expiration is a real anomaly and deserves a freeze, not silent management.
- Idea. Never book what the broker did not do.
2026-06-23: mechanical window widened to 30 to 65 days
- Issue. The 30 to 45 day window almost always landed on a weekly expiration, because the monthly (third Friday) cycle sits inside 30 to 45 days for only 7 to 10 days a month.
- What changed. The mechanical engine’s window is now 30 to 65 days to expiration. The 21-day management exit is unchanged; a 65-day entry still exits at 21 days.
- Reason. Keeps a monthly expiration in range about three weeks a month, matching the monthly preference added June 18, with headroom around the cycle.
- Idea. Trade the monthlies the way the research assumes.
2026-06-23: live fill accounting fixed before real money, with a backup path for missed fills
- Issue. Outside reviewers flagged that the broker library reports a net fill price that is negative for a credit and positive for a debit, the inverse of the bot’s convention. The bot passed it through unchanged, so on a real fill a credit open would have booked a negative credit and every realized P/L would have been inverted. It was latent only because sandbox market orders return zero for that figure. The zero-case fallback had its own bug: it averaged leg prices instead of netting them, booking a $167 MU put spread in the sandbox as about $4,610 of credit, which breaks every rule that reads credit. And if the fill stream dropped mid-session, fills on accepted orders sat unbooked until a restart, risking a double entry or an unmanaged position.
- What changed. The sign is flipped once at the boundary with the broker library. The fallback nets legs by direction and divides by the contract count. A loud check fires if a close ever books a negative debit. Each cycle re-polls any order accepted more than five minutes ago and routes its real status through the same handler the stream uses. A roll whose open order timed out is re-checked at the broker after the cancel, so a fill that beat the cancel is booked, not stranded.
- Reason. Two of these would have corrupted the very first live fill.
- Idea. The stream is primary; the poll is the net under it.
2026-06-22: three fill bugs that would have hit the first live order
- Issue. A one-contract iron condor has four legs, and the fill handler summed them to report four contracts filled against an order for one, so the position never booked. Fill prices arrived per share but were stored as if per contract, so credits and debits would have been recorded about 100 times too small against per-contract marks. And if the bot cancelled a close order to re-price it and then could not place the replacement, the position was left in a “closing” state that nothing manages.
- What changed. Filled quantity is the largest per-leg count, since all legs of a combo fill together. Prices are converted to per contract once, at the boundary with the broker library. A failed re-price freezes the position for operator attention with a halt note instead of leaving it silently unmanaged. Slippage is measured in consistent units. News-triggered entries were also switched off by default and given a dashboard toggle.
- Reason. Every one of these hit the default structure on entry and close the moment paper mode came off.
- Idea. Paper trading cannot test the fill path. Adversarial review can.
2026-06-18: monthly expirations preferred, and the entry window is adjustable
- Issue. Within the mechanical engine’s window the bot chose among all expirations, weekly or monthly. The 30-minute wait after the open and the 15-minute cutoff before the close were fixed constants. A broker fill event carrying a zero price could write a zero credit on a new position.
- What changed. When a third-Friday monthly exists in the window, the mechanical engine picks from monthlies; otherwise it falls back to the full list. Earnings and contraction engines are unaffected. The after-open wait and before-close cutoff are dashboard settings, global or per account. A zero fill price falls back to the order’s limit with a warning.
- Reason. Monthlies carry the liquidity and the research behind the 45-day entry.
- Idea. Default to the expiration the strategy was built on.
2026-06-17: clear a halt once, and the bot stops crashing every cycle
- Issue. The dashboard’s Clear Halt button cleared the halt reason, but the VIX, macro-event, daily-loss, and weekly-loss gates re-evaluated every cycle and re-fired immediately. Separately, the database dropped idle connections after a timeout and the bot had no reconnect path, so it crashed on every cycle until restarted.
- What changed. Clear Halt writes a same-day override for all four gates. The override expires at midnight ET, so a cleared halt stays cleared for the rest of that day and re-arms on its own. It does not touch open positions. The button now appears inside the halted gate itself, not only in the top banner. Database calls retry once after a reconnect. The macro halt uses the cycle’s own date rather than the wall clock.
- Reason. An operator who has judged a halt and cleared it should not have to clear it again five minutes later.
- Idea. Overrides are dated, not permanent.
2026-06-16: live close safety, SMS alerts, and a manual close button
- Issue. Three live-only paths could mark a position closed or reduced in the bot’s records while it stayed open at the broker: a close whose order could not be built or was refused, a calendar-roll fallback that closed directly without an order, and a reduce order that was never placed. The stale-order cleanup and the price walk also cancelled orders locally without confirming at the broker, so a fill arriving after the local cancel would be ignored and the position stranded. There was no way to close a position by hand from the dashboard and no notifications of any kind.
- What changed. A refused defensive close leaves the position open and retries next cycle; a refused reduce freezes the position for attention; the roll fallback submits a real close order. Before cancelling, the bot fetches the order’s status at the broker and re-confirms after; a fill that beats the cancel is booked, and an unconfirmed cancel waits a cycle. A late fill on a locally cancelled order is booked and flagged rather than dropped. Twilio SMS notifications for entries, exits, and halts (one halt text per account per reason per day), off until enabled. A Close button on each open position with a confirm step, plus a full activity log tab.
- Reason. The bot’s records must never claim a state the broker does not hold.
- Idea. Confirm with the broker before believing your own cancel.
2026-06-15: the bot respects your manual positions, and the expiration profit pull needs 25%
- Issue. The bot had no knowledge of options you hold manually in the same account. A proposed short strike that collided with a manual holding could go in blind. Positions frozen for attention had no way to be resolved from the dashboard. The expiration-day profit pull fired on any profit at all.
- What changed. Before entry the bot reads your non-bot holdings and declines any short leg that is not covered, either by the trade’s own long or by a manual long of the same type at or beyond that strike. Defined-risk structures cover themselves, so a normal condor or spread is never blocked. Live accounts only; if there is no broker data, nothing is blocked. Frozen positions show a badge and a Resolve button. The expiration profit pull now requires at least 25% of max profit captured, adjustable.
- Reason. Your manual book and the bot’s book share one account and one margin.
- Idea. Never propose a short that nothing you hold covers.
2026-06-13: circuit breakers use the broker’s real net liquidation value
- Issue. The daily and weekly loss breakers compared losses against a manually typed account value. And the account fill stream was importing a class that does not exist in the current broker library, so every reconnect attempt crashed and fill events would have been permanently silenced on any live account.
- What changed. Each cycle fetches net liquidating value from the broker, stores it per account, and feeds it to the breakers; the manual value is the fallback. The fill stream uses the correct library class and event type, and a permanent library gap stops the reconnect loop with one warning instead of retrying forever. A per-login authentication badge (green, or red with the error) was added the day before.
- Reason. A breaker sized against a stale number is not a breaker.
- Idea. Live numbers for live gates.
2026-06-09: every setting is truly per account
- Issue. With a specific account selected, changing structures, engines, the entries-paused switch, max allocation dollars, account value, entries per cycle, or the known-liquid list wrote to the global settings and changed every account. The day before, engine and structure toggles saved with an account selected were silently dropped and reverted to all-on.
- What changed. Each of those settings persists as a per-account override, and the trading loop reads the override at cycle time, with the account value winning over the global one. The allocation cap honors per-account dollars, account value, and percent.
- Reason. Two accounts with different risk tolerances need different rules, and the dashboard implied they already had them.
- Idea. What the settings page shows for an account is what the bot runs for that account.
2026-06-08: three hair-triggers tightened, and the contraction engine’s spike check turned on
- Issue. The VIX-collapse exit could harvest a position at 0% profit on any five-point VIX drop. The roll gate accepted a roll earning $0.01 per contract, a guaranteed loss after commissions. The implied-move defense could close a healthy condor on an abnormal move even with both short strikes far out of the money. And the contraction engine’s requirement that IV rank had jumped at least 20 points recently was never evaluated, because the jump was never computed, so high-IV plateaus passed as fresh spikes.
- What changed. The VIX-collapse exit needs at least 25% of max profit. A roll must net more than $0.25 per contract or the bot closes instead. The implied-move defense also requires the tested short’s delta at or above 0.30. IV rank history is kept per symbol, pruned to 40 days, and the jump is measured against the reading from about seven days earlier; with no history old enough, the check passes. A transient timeout on the market-metrics feed no longer aborts the whole cycle.
- Reason. Each trigger was firing on a condition that carried no edge.
- Idea. A rule should need a reason, not just a number crossing zero.
2026-06-07: swing mode for directional trades
- Issue. The directional engine had a swing-mode toggle that did nothing.
- What changed. With swing mode on, directional entries use a 7 to 21 day window instead of 30 to 45, buy an at-the-money long (about 0.50 delta) instead of the 0.68-delta in-the-money strike, target 40% instead of 82%, and exit early once half the original days have elapsed if the trade is profitable. With it off, nothing changes. Known tension at build time: the standard 21-day exit backstop equals the top of the swing window, so a fresh swing entry could be closed at once; that was fixed July 7.
- Reason. Shorter, faster directional bets are a different plan from 45-day trend trades and needed their own rules.
- Idea. One engine, two tempos.
2026-06-07: must-fill orders walk their price, and condor rolls open in two orders
- Issue. A limit order that did not fill just sat. For a defensive close that is a live risk. Iron condor rolls tried to open all four new legs in one order, at the broker’s four-leg cap.
- What changed. Closes for defensive rules (assignment cleanup, news gate, delta defense, expiration flatten, assignment risk) are tagged must-fill: every 30 seconds the bot cancels and re-submits one tick ($0.05) worse, up to a cap of twice the mid. Opportunistic orders (profit targets, reduces, roll legs) are cancelled after 90 seconds. All three intervals are settings. Roll opens on a condor go as two two-leg orders, put side then call side, with the new legs booked only after both fill; if the second fails or times out, the roll is flagged half-rolled for attention. Slippage against the mid is recorded on every fill and shown on the dashboard, and beta is fetched live for beta-weighted delta.
- Reason. A defensive exit that never fills is not a defense. A missed roll is safer than an un-closed spread, so roll legs stay opportunistic.
- Idea. Pay up when you must, walk away when you can.
2026-06-04: in live mode, the fill is the only thing that books a position
- Issue. The bot booked positions, closes, and rolls the moment it decided to act, before the broker filled anything. In paper mode that is fine. With real orders it means the ledger describes intent, not reality: a rejected open would still create a position, a close would book at the mark rather than the fill, and a reduce never sent an order at all. A vanished position could be closed at $0.
- What changed. Each position moves through explicit states (pending open, open, closing, reducing, rolling, closed, aborted, needs attention). In live mode a broker fill is the sole event that books an open, close, or reduce, at the actual price. A partial fill of a multi-leg structure freezes the position for attention rather than silently resizing. Live rolls run in two phases: close first, then the pre-planned open only after the close fill is confirmed, with a timeout that flags a half-rolled position. On startup the bot resolves any orders and mid-flight rolls whose fills arrived while it was down, and refuses to start if the broker cannot be reached. The next day the remaining uncertain paths were closed: a fill with no matching position raises an alarm, the position record is created before the order is sent so no live order can exist without a home, a failed status lookup during recovery halts rather than reading as “still working”, and a bookkeeping failure rolls back the whole fill. Paper behavior did not change.
- Reason. Two independent reviews converged on the same thesis: the bot booked on intent while the order layer was designed to book on fills.
- Idea. Reality is what filled.
2026-06-04: loss breakers scoped per account, and the liquidity gate stopped rejecting almost everything
- Issue. The daily and weekly loss breakers had no account filter, so one account’s drawdown counted against another account’s value and could trip its breaker. The liquidity screen failed closed when it had no open-interest or spread data, and that data was never being populated, so every name outside the 24-symbol known-liquid list was dropped every cycle (1,168 rejections across 59 symbols in one cycle); only mega-caps ever traded.
- What changed. Breakers, P/L windows, and management decisions are scoped to the account being cycled. The liquidity screen passes when it has no data, a measured spread that is too wide still rejects, and the real check moved to entry time, where the proposed legs’ actual bid and ask are read from the just-fetched chain and any leg wider than the limit is skipped. A spread probe on the roughly 30-delta strikes now runs during the scan. The two defense triggers (tested delta 0.45, implied-move ratio 1.5) became dashboard settings. The pattern-day-trader counter was removed.
- Reason. One gate was too coarse, the other too strict, and neither was doing what its own comments said.
- Idea. Reject on evidence, not on the absence of evidence.
2026-06-03: the news gate will not close a condor on news the market is ignoring
- Issue. An MSFT iron condor was reduced on bullish news at 0.75 confidence while the stock was falling. A condor is threatened by a move toward either wing, so the gate treats any directional headline as a threat, and the price-agreement check added the day before could not run because the position predated the recorded entry price. Separately, the risk-off halt’s index-drop arm was inert, and opportunistic exits could fire in the first minutes after the open on thin quotes.
- What changed. When the entry price is unknown, a neutral structure declines to act on news; directional structures still act, because the gate already requires the news to oppose their thesis. The index-drop arm is live: an intraday drop of 1.5% or more in the configured index halts new premium entries. Opportunistic exits (profit target, morning-after, fast exit, VIX collapse, IV normalized) wait 15 minutes after the open; defensive closes fire immediately. The account fill stream runs as a background task with reconnect, and the reconciler was wired to act on vanished positions (later changed to a freeze; see June 25).
- Reason. A headline is not a move. The gate needs both.
- Idea. Confirm with price before acting on words.
2026-06-02: news gate guards, news-driven entries, and a profit ladder (off by default)
- Issue. The news gate could act on a headline older than the position, exit a position in the same cycle it entered, or fire on news the stock had not moved on. There was no way to enter on strong news through the contraction engine, and no way to take profit in stages.
- What changed. Three guards: news received before the position opened is ignored; no news exit inside the first 15 minutes; the underlying must have moved at least 5% in the news direction since entry (raised from 2%). Both thresholds are dashboard settings. The contraction engine can enter on a high-confidence directional headline using a one-sided credit spread in the news direction, with a 25% profit target and a morning-after close if profitable; off by default. A three-step profit ladder (close a quarter at 25% of max profit, half the remainder at 50%, the rest at 75%) is available per premium engine; off by default. Portfolio Greeks (net and beta-weighted delta, theta, vega, gamma, and a -5% stress figure) are computed each cycle and shown on the dashboard.
- Reason. The first live-style news exits showed the gate needed context, not just sentiment.
- Idea. New behaviors ship off and earn their way on.
2026-06-02: real order plumbing, and one account can no longer touch another’s positions
- Issue. The order and roll state machines existed but nothing persisted orders, routed broker events, cancelled stale orders, reconciled against the broker, handled rate limits, or gated live submission. And the management pass read every open position regardless of account, so account A’s cycle could manage and close account B’s positions.
- What changed. Every order is persisted; broker fill, reject, and cancel events update it. Orders working past a threshold are cancelled at the start of each cycle (a stale roll leg flags the roll half-rolled with an alert). The reconciler diffs broker holdings against the bot’s, writes any assignment stock leg so the assignment rule can fire, and surfaces manual trades without managing them. Rate-limit responses get exponential backoff; exhaustion marks the order rate-limited with an alert. No live order is submitted unless trading is enabled for that exact account; an unknown account is blocked. Management is scoped to the account being cycled.
- Reason. Paper mode stayed on throughout; this is the wiring so that turning it off later is not a leap.
- Idea. Build the live path while it still cannot hurt you.
2026-06-01: the same headline fired 22 times, and the earnings floor moved to 7 days
- Issue. An MU position had the same bullish article trigger a news reduce 22 times over more than 10 hours, overnight and on a Sunday, before it finally closed. The gate ran while the market was closed on stale marks, and the 15-minute cooldown kept resetting across cycles and restarts. The earnings engine’s three-day expiration floor was too tight for a four-leg structure; spreads eat the credit under seven days.
- What changed. The news gate skips outside regular hours and will not act twice on the same article. The earnings expiration floor moved from 3 to 7 days (reworked again July 6). Per-account overrides expanded to engine on and off, directional structures, vertical rolls, and probability floors. Imported live accounts that had been mislabeled as sandbox were corrected.
- Reason. A rule that fires on the same input every 18 minutes is a loop, not a decision.
- Idea. Act once per fact.
2026-05-31: multiple accounts, account-type rules, and a debit order that was going out as a credit
- Issue. The bot ran one account. Under the broker library upgrade, a debit structure’s order was built with a positive price and a debit flag the newer library silently ignores, so a debit order would have been submitted as a credit order.
- What changed. Multi-account support: one session per tastytrade login, any number of account numbers under it, each with its own paper-or-live flag, trading-enabled switch, allocation, and settings overrides. Account types (IRA variants, 401k, cash, margin, custodial) carry hard restrictions. Account history can be reset per account with a typed confirmation. Sandbox and live broker secrets are separate. Order prices are signed, so credit and debit route correctly. Broker login moved to OAuth refresh tokens. Accounts can be imported from a live session with paper mode on and trading off as the defaults.
- Reason. Isolation first: a customer’s book, settings, and risk limits must never bleed into another account.
- Idea. Every account is its own bot.
2026-05-30: the directional engine gets its own structures, exits, and IV band
- Issue. The premium engines profit from a quiet range. There was no offensive lane, and a review found the directional pair variants entered ungated because their max loss was never priced.
- What changed. Four directional structures: bull call spread and bear put spread (buy about 0.68 delta in the money, sell further out), and outright long call or put. Credit-funded pairs are preferred (1.2x score bonus), then debit spreads, then outright longs (0.8x penalty); a funded pair may enter as a small net debit up to 15% of its risk. Directional exits: take profit at 82% of max for defined-risk (return on risk for uncapped), close when the long leg’s delta reaches 0.87, stop at a 50% loss of premium paid, and a 21-day backstop. Its own IV rank band: floor 30, optional ceiling. The reward-to-risk gate fails closed if max loss cannot be priced. The ex-dividend early-assignment check is live: an in-the-money short call inside the dividend window whose dividend exceeds its remaining extrinsic is pulled. Live rolls are modeled as close-then-open with the open gated on the close fill. Per-engine scorecards on the overview. Vertical rolls default off. A contraction position that is tested (delta at or above 0.45) no longer closes under the IV-normalized rule. Probability-of-profit floors are wired per engine but ship disabled, because the bot’s measure is conservative and a tastytrade-style 0.70 floor would block the default condor. The directional engine stays off by default and paper-only.
- Reason. Two outside reviews of the plan, plus Payne’s directional trading rules.
- Idea. Let the market pay for the bet: a credit spread funds the directional leg.
2026-05-29: five bugs from the third review
- Issue. The directional engine had never opened a trade: its settings were missing from the structure picker’s map, so every candidate returned early, invisible because the only test checked for a decision tag that a skip also carries. The contraction engine’s 16-delta short strike was never used; every builder hard-coded the mechanical 30 delta. The news gate matched symbols by substring, so a headline about AAPL could hit a position in AA. A broker fill event arriving out of order could downgrade a recorded fill. The single-long directional variants had no working profit exit.
- What changed. All five fixed and pinned with tests. Builders read the driving engine’s own delta and width (mechanical 30, contraction 16, earnings 30). Symbol matching is exact. Filled quantity can never regress. Uncapped structures take profit on a return-on-risk basis.
- Reason. Each was a rule that existed on paper and not in the code.
- Idea. A rule that never fires is indistinguishable from no rule. Test that it fires.
2026-05-27: the rulebook as it stood at the first review
- Issue. The original plan had drifted from what the code did, so the strategy document was rewritten to describe the bot as built.
- What changed. The recorded rules. News flows through a classifier and drives defensive action on a confidence ladder (0.60 flag, 0.75 reduce by half, 0.90 close), with a 15-minute per-symbol cooldown and a brake that refuses a reduce when the loss exceeds twice the credit; news bias is a recency-weighted vote with a 12-hour half-life; strong news adds a name to the scan list for 48 hours. The structure picker scores every eligible defined-risk structure by credit divided by max loss and requires at least 0.25 (a third of the width as credit). Risk: at most three new entries per cycle and 20 open positions; cooldowns after an exit by rule (two hours after a profit target, 72 hours after a stop or a news close, seven days after an earnings exit); a VIX kill switch at 35, with an unknown VIX never halting; an entry pause on scheduled FOMC and CPI dates; a VIX-collapse exit when VIX has fallen five points since entry and the trade is profitable; daily and weekly loss breakers; entries only in regular hours with a 30-minute warm-up and 15-minute cool-down; and re-entry in a symbol only after the prior position exits. The earnings window widened from 1 to 7 days to 3 to 14. The loop runs every five minutes. If mark coverage collapses, closes are deferred that cycle and re-decided on fresh data.
- Reason. A customer should be able to read the rules the bot actually runs.
- Idea. The document follows the code, not the other way around.