v1.9.20260727a
2026-07-27 · regime integrity + price-context instrumentation
- Regime is now pinned for each option-management pass. The exit thresholds were read once at the top of the function, but the loop awaits on every position — so a Brain refresh completing mid-loop could change the regime while the old thresholds stayed in use. A second account's journal recorded a close at "22 DTE (threshold 28)" alongside regime NEUTRAL, a combination impossible within one consistent tick. The pass now uses a single pinned regime and the journal records which regime was actually applied.
- Fail-safe regime on data failure. When the market-data fetch failed, all four signals were assigned random values and a regime was derived from them, logged as "local HMM fallback" — wording that reads like a model but was
Math.random(). Regime is not cosmetic: it sets the delta target, the IV-rank floor, the profit threshold and the DTE-close threshold, so an invented regime silently changed real trading parameters. The bot now retains the last known regime, marks it stale, and suspends new option entries until live data returns. Exits, stops, breaker closes and all defensive management continue to run.
- 20-day price context recorded in the journal — measurement only. The bot had no per-stock price history at all; every signal was a same-day move on market-wide ETFs, so it could not tell whether an individual name sat high or low within its own recent range. Stock decisions now record the 20-day average, the percentage above or below it, and distance from the 30-day high and low. Nothing reads these values — no entry is gated on them. They are exported in the CSV so the question "did entries above the 20-day average do worse?" can be answered from real trades instead of argued from intuition. Cached once per symbol per day.
- Why measurement rather than a filter: a moving average is a reference line, not a signal. "Only buy below it" is a mean-reversion bet that also turns the bot into one that exclusively averages down; "only buy above it" is a trend bet that would have permitted the ladder that prompted the question. The two are opposite strategies and the data to choose between them does not exist yet.
v1.9.20260726c
2026-07-26 · entry quality guards
- Stale-quote guard on stock buys. A second account placed five stock orders across two days at a byte-identical price, every one of them outside regular hours — the quote was frozen and the bot was sizing real orders against it. Two of those orders came back as broker rejections. Entries now read the trade timestamp from the snapshot and refuse a buy when the last trade is older than the configured limit (default 15 minutes). Options already refused a stale chain feed; stock entries had no equivalent.
- Post-stop re-entry price rule. The 24-hour cooldown prevents immediate whipsaw but expires. That account was stopped out of a name and then bought it back five days later above the entry price that had just failed, across five orders. After a stop-loss the bot now records the failed entry price and refuses to re-buy that underlying above it until the window expires (default 30 days). Buying back below the failed entry is still allowed, since that is a better price than the trade that lost money. Active bars are listed in the Safety tab.
- Bug fix — price fetch failure defaulted to $100. The stock entry path initialised
livePrice to 100 and kept that value if the snapshot threw or returned no trade. A failed fetch therefore sized and priced the order as though the stock cost $100, and the cash check passed against the wrong number. It now aborts the entry and records the reason in the journal.
- Verified by simulation before shipping against the sequences in that account's journal: all five re-buys above the failed entry are refused; a dip below the failed entry is still allowed; the rule expires on schedule; and a live in-session quote passes the freshness check while a prior-day price does not.
- Note: the stale-quote guard will refuse most pre-market and after-hours stock entries, because the last trade is usually hours old at those times. That is the intended behaviour. Both guards apply to stock BUYs only — defensive sells, stops, breaker closes and option management are never blocked — and both are configurable in Safety → ENTRY QUALITY GUARDS.
v1.9.20260726b
2026-07-26 · fixes surfaced by a second account's journal
- The stock concentration cap has never run.
exposureForTicker() was defined only inside openOptionCandidate() and openOptionCandidateElite(). The stock-path cap added in v1.9.20260627b is guarded by typeof exposureForTicker === 'function', which evaluates to false at botTick scope — so the guard silently skipped the whole check on every tick since it shipped. A second account's journal showed one underlying reaching roughly 27% of equity against a 10% cap with no CONCENTRATION record. Now defined globally; the nested copies still shadow it locally with identical behaviour.
- Collateral cap recalibrated for smaller accounts. The 12% per-trade cap shipped in v1.9.20260726a was calibrated against a six-figure account. On a ~$40K account it caps strikes at about $47, which blocks every liquid wheel candidate — the same class of mistake as the entry-DTE floor. New
maxSingleContractPct (25%) lets a single contract through above the sizing target while the portfolio cap still binds. Verified against both account sizes: normal wheel strikes pass, genuine over-concentration is still refused.
- Stock entries now check buying power, not just cash. Cash can look ample while buying power is nearly exhausted by option collateral, producing a broker 403 the bot could have predicted. Two such rejections appear in the second journal on a day with five figures of cash available.
- Confirmed by the second journal, already fixed in v1.9.20260720a / v1.9.20260726a: the DTE open-and-close loop (entries landing at exactly the close threshold, with long runs of duplicate closes on the same contract), and earnings-blackout over-blocking measured against full DTE rather than planned hold.
- Note on settings: churn and safety settings persist in localStorage and survive updates, so shipping new defaults does not change an existing installation. The second account was running a per-ticker daily cap of 5 rather than the current default of 2. Review the Safety tab after updating.
v1.9.20260726a
2026-07-26 · unblock entries, cut drag, real risk units, macro blackout
- Driven by the 07/26 journal. The 07/20 churn fixes worked — zero cycling events after the version switch — but the bot then took no action at all: two thirds of decisions were blocked by the new entry-DTE floor, and the remainder by a chain that arrived without Greeks.
- T1.1 —
targetDTE 30 → 45. Paired with closeAtDTE 21, a 30-DTE entry lived only ~9 days: little theta captured, spread paid on both ends, and an entry window that collided with the close trigger. 45 DTE gives roughly 24 days of hold, the standard wheel parameterization.
- T1.2 — chain is DTE-filtered before strike selection. Previously the selector ran across every expiry and the DTE gate rejected the winner afterwards, abandoning the candidate. On 07/20 the best-delta contract sat one day under the floor while a valid further expiry was never considered. Filtering first means the selector only ever sees qualifying expiries.
- T1.3 — Black-Scholes delta fallback. When a chain arrives with no Greeks populated, delta is now estimated from spot, strike, DTE and IV rather than discarding the candidate. Estimated contracts are flagged in the log.
- T2.1 — marketable limit orders on scheduled closes. Take-profit and DTE closes now submit a limit priced through the touch instead of a market order, so the full spread is not conceded on every exit. Defensive closes (stop-loss, breaker, pre-earnings, rolls) deliberately keep market orders — fill certainty outweighs spread there.
- T3 — option risk caps now measure collateral.
maxTotalPct and perTickerMaxPct summed option market value (the premium) rather than collateral at risk (strike × 100). Measured that way the portfolio cap would need dozens of short puts before binding, and maxPctPerTrade never bound at all because sizing ends in Math.max(1, …) — when the budget was smaller than one contract the floor forced one anyway. New maxCollateralPctPerTrade (12%) and maxTotalCollateralPct (50%) measure collateral directly and reject rather than override.
- T4.1 — earnings blackout measured against planned hold. The check tested earnings against the full DTE even though positions close at
closeAtDTE, so it blocked candidates over earnings the bot would never hold through. It now tests DTE − closeAtDTE. Without this, moving to 45 DTE would have blocked nearly every candidate. preEarningsCloseDays remains the backstop.
- T4.3 — macro event blackout. New Safety-tab panel blocks new option entries within N days (default 2) of FOMC decisions and CPI releases — the market-wide analogue of the earnings blackout. Ships with the 2026 schedule built in and a user-editable date list, since built-in dates go stale.
- Bug fix — the approximate-entry fallback never ran.
openOptionCandidate() referenced an undeclared contract object, so every invocation threw ReferenceError before submission and surfaced only as a generic error. Now uses its actual local variables, and carries the same macro, collateral and churn gates as the elite path.
- Unchanged: every safety layer from June and July — churn gates, cooldowns, concentration cap, kill switch, breaker, no-short guard, PDT protection, cash floor, and full journal instrumentation.
v1.9.20260720a
2026-07-20 · DTE churn loop fixes
- Driven by the 07/17 journal. The bot entered a self-inflicted loop: it sold CSPs on contracts at exactly 21 DTE, the DTE-close logic (threshold 21) immediately bought them back, and the Evaluator re-entered the same contract — ~60 open↔close cycles across two underlyings in one afternoon (189 orders), paying spread and fees each time. A third contract entered at 25 DTE never churned, confirming the mechanism.
- Fix 1: regime-aware entry-DTE floor. New
getMinEntryDTE() = max(minDTE, effective closeAtDTE + 5), where effective closeAtDTE mirrors the manager's regime adjustment (28 in CRASH/BEAR, else 21). Applied in both the elite and fallback entry paths — the bot can no longer open a contract its own closer would immediately kill.
- Fix 2: churn gates now bind option entries. Before any auto-CSP/CC submission (elite and fallback), the bot checks the per-underlying daily cap, total daily cap, and post-close cooldown via
checkChurnPreventionGates(getUnderlying(symbol), 'buy'). Previously these gates were wired only into the stock path. Also, countTotalOrdersToday() now counts option orders against the 10/day total cap (it previously excluded them entirely).
- Fix 3: DTE close hardened. The DTE force-close branch now has the same duplicate-close guard as the other close paths (
isCloseRecent + hasOpenOrderFor + markCloseSubmitted) — it previously had none, and fired repeated closes 30 seconds apart on the same contract (the same double-close family that once created a rogue long put). After a successful DTE close, the underlying enters the post-close cooldown, blocking same-day Evaluator re-entry.
- Net effect: Friday's pattern is structurally impossible on four independent axes — can't enter below closeDTE+5, can't exceed 2 orders/underlying/day or 10 total, can't double-fire the closer, can't re-enter a just-closed underlying for 24h.
- Validation note: the 07/08 fixes were confirmed working in this journal (no stop-loss retry floods, full outcome stamping, earnings blackout active).
v1.9.20260708a
2026-07-08 · stock stop must skip options + retry backoff
- Driven by the 07/08 journal (first full-fidelity export). A long option position tripped the -8% stock stop-loss, and the resulting sell order was rejected by the broker and retried every 30 seconds for two hours — hundreds of rejected orders that consumed half the journal.
- Fix A:
checkStockStops now skips option positions entirely — checks both asset_class === 'us_option' and the OCC symbol pattern (belt and suspenders). Options are managed exclusively by their own logic (2× credit stop, take-profit, DTE force-close, pre-earnings close). Stock stops never touch OCC symbols again.
- Fix B: retry backoff for failed stop-loss closes — after 3 consecutive broker rejections for the same symbol, the bot backs off for 30 minutes and raises a loud
🛑 CHECK THIS POSITION MANUALLY alert instead of hammering the API every tick. A successful close clears the failure counter.
- Journal fidelity validation: the 07/02 fixes are confirmed working in production — zero pending records, every decision stamped with a concrete reason, no after-hours flood, earnings blackout actively skipping entries, and the options-buying-power constraint now visible with exact numbers per tick.
- Note: the rogue long put itself requires manual review in the Alpaca dashboard (position may be real from a duplicate buy-to-close, or a stale cache entry). The DTE force-close path does handle long options and remains a backstop.
v1.9.20260702a
2026-07-02 · journal fidelity (silent exits + ext-hours)
- Driven by the 07/02 journal review. The export showed 96% of records logged during the after-hours session (Evaluator kept picking OPTION every 30s from 4-8 PM ET, when options can't trade) — rotating the entire regular trading day out of the 500-record cap. And 100% of OPTION decisions were "pending" because the option-entry path exits silently at ~24 different points without stamping an outcome.
- Ext-hours journaling gate: during pre/after-market (with EXT-HRS enabled), only actionable STOCK verdicts are journaled and pursued. OPTION and SKIP verdicts outside regular hours are neither journaled nor pursued (throttled log message instead). Regular-session behavior unchanged.
- Catch-all outcome stamp for the option path: every silent exit in
openOptionCandidateElite/openOptionCandidate logs its reason immediately before returning; botTick now captures that most-recent log line and stamps the decision no_action with it. Covers all ~24 exit points (IVR too low, no affordable CSP, wheel cap, stale feed, earnings blackout, per-underlying caps, etc.) without touching each one.
- Submission stamping: a successful elite option submission now stamps the originating Evaluator decision as
submitted (previously only the separate EVENT record was created, leaving the decision pending).
- Stock-path silent exits stamped: duplicate-order guard, insufficient-cash check, and nothing-to-sell now each stamp
no_action with their specific reason.
- Net effect: "pending" should effectively disappear from the journal. Every decision now records what happened and why — including why nothing happened, which was the missing half of the story.
v1.9.20260627d
2026-06-27 · breaker state cleanup
- Bug fix: the Safety tab was showing "BREAKER CB1 ACTIVE" with a trigger date from weeks ago, while simultaneously showing "✓ MANUALLY UNLOCKED". Three coordinated fixes resolve the stale-state problem.
- Fix 1:
resumeFromBreaker() now deletes the breaker state when the user clicks Resume Trading, instead of just flagging unlocked: true. The flag-only approach left the state record alive in localStorage, so the renderer kept treating it as "active" with the original trigger data displayed.
- Fix 2:
getBreakerState() auto-clears any record from a previous trading day (previously only cb3 had this check; cb1 and cb2 records could persist indefinitely). It also defensively clears any record with unlocked: true so the UI never shows a contradictory state.
- Fix 3: on bot startup, the breaker-state cleanup runs automatically — so users with stale records in localStorage (like the historical CB1 from weeks ago) get them cleared on next page load.
- Behavior unchanged for live breaker events: when a current-day breaker fires, all the original protective actions still run (cancel open orders, close breached stocks if cb2+, sticky cb3, etc.). Only the UI/state-management bug is fixed.
v1.9.20260627c
2026-06-27 · changelog policy: no P&L amounts
- Policy change: changelog entries no longer reference specific dollar amounts of realized loss or gain from account history. Configuration values (thresholds, caps, defaults) remain since they document how the bot works, not what the account did.
- Cleaned six prior changelog entries to remove account-specific P&L figures (e.g., MU round-trip damage, CRM churn losses, BAC whipsaw losses, AMZN cash/OBP example values). Replaced with qualitative descriptions that preserve the diagnostic meaning without exposing account history.
- This is a documentation-only change. No behavior modified. All Tier A bug fixes and Tier B default tightenings from v1.9.20260627b remain in effect.
v1.9.20260627b
2026-06-27 · post-mortem fixes (Tier A bugs + Tier B defaults)
- Driven by the 06/25-06/26 post-mortem. Alpaca activity log showed material realized losses from an MU round-trip and CRM put churn within a 90-second window.
- A1 (bug fix): Evaluator loser-bias now gated on
rotationEnabled. The scoring code added +2 to stock score per underperformer regardless of the rotation toggle. This drove the 06/25 mass-liquidation despite rotation being "off." Bias now respects the toggle.
- A2 (bug fix): Underlying-level post-stop cooldown. Cooldown was keyed on exact OCC contract symbol — closing CRM 143 put didn't block CRM 142/144. Now also tracks the underlying ticker; option close blocks ALL options on the same underlying for the cooldown window. New
getUnderlying() helper parses OCC symbols.
- A3 (bug fix): Per-underlying daily order cap for options. Order count was per-exact-symbol — 11 CRM fills across 4 strikes counted as 4 separate symbols. Now counts all options on same underlying together.
- B1 (default):
maxPctPerTrade halved from 5% to 2.5%. Reduces per-order concentration. For a $100K account, each trade now ≤ ~$2,500.
- B2 (new check): Concentration cap on STOCK BUYs. The 10% per-underlying cap existed but was only checked during CSP/CC candidate selection — stock-buy path was missing it. Now any stock BUY that would push the underlying above 10% of equity is refused with a
CONCENTRATION: log line. Records to decision journal as blocked.
- B3 (default): Daily kill switch tightened from -$500 to -$300. Smaller threshold halts the bot earlier in adverse intraday conditions.
- B4 (default): Total daily orders cap reduced from 20 to 10. 18-order MU buying spree wouldn't happen — would hit cap at order 10.
- B5 (default): Per-ticker daily orders cap reduced from 3 to 2. Wheel needs at most open+close per day for one underlying.
- Net effect: the 06/25-06/26 patterns (18-order concentration into a single name + 11-order option churn) are structurally blocked under the new rules. Safety layers are stricter; legitimate wheel activity still possible at much smaller scale.
v1.9.20260627a
2026-06-27 · extend journal to defensive events
- Decision journal now captures defensive actions, not just Evaluator decisions. The 06/26 mystery (positions vanished but journal showed only OPTION/pending records) exposed a real gap: stops, breaker closes, pre-earnings exits, rolls, and other defensive sells all bypass
recordDecision(). This build closes that gap.
- New helper:
recordEvent({event_type, trigger, action, outcome, reason}) creates a structured record for any non-Evaluator event. Records use decision: "EVENT" so they coexist cleanly with existing STOCK/OPTION/SKIP records in DECISIONS array, the CSV export, and the JSON export.
- Six convenience wrappers for the common patterns:
recordStopLossEvent, recordBreakerCloseEvent, recordOptionCloseEvent (handles pre_earnings_close / option_stop / option_tp / option_dte_close), recordRollEvent (legs 1 and 2), recordAutoOptionEntry (handles auto_cc / auto_csp / spread_entry), recordRotationEvent.
- 11 defensive sell paths instrumented: stock stop-loss (success + rejection), circuit-breaker close, pre-earnings close, option 2× credit stop, option take-profit / scale-out, option DTE force-close, rotation sell (when enabled), auto-CC entry, elite auto-CSP entry, roll leg 1 (BTC), roll leg 2 (STO new).
- What you can now answer from the journal: "what closed my positions today" — stop-losses, breaker closes, expiry-forced exits, rolls, all visible. Each record includes the trigger data (P&L%, DTE, breaker level, etc.) so you can see why the bot acted, not just that it acted.
- Unchanged: 500-record cap, localStorage persistence, CSV/JSON export buttons, render stats panel. Existing Evaluator records still produced identically — defensive event records are additive.
- Known limitation: events fired by the broker side (option assignments, expirations) still aren't recorded — those happen in Alpaca, not in the bot's code paths. For those, the Orders tab in Alpaca remains the source of truth.
v1.9.20260610d
2026-06-10 · structured decision journal
- New: Decision Journal — every Evaluator decision is now recorded as a structured record (not just a free-text log line). Each record captures: decision verdict, scores breakdown (stock/option/skip), reasons list, signals (VIXY, SPY, QQQ), regime, cash, options_buying_power, equity, exposure, open positions/options, and downstream outcome.
- Outcome stamping: after each decision, the bot records what actually happened —
submitted, blocked (and which gate blocked it: no-short, cash floor, PDT, churn, kill switch), rejected (with the Alpaca error message), or no_action.
- Export buttons in Safety tab → DECISION JOURNAL: CSV (flat, Excel-friendly) and JSON (full nested structure). Each row covers a full decision with all inputs and outcome — you can pivot on regime, filter by outcome, correlate score thresholds with success rates.
- Persisted to
gus_decisions localStorage. Capped at 500 records (auto-rotates). Survives page reload.
- Live stats panel shows total decisions, breakdown by verdict (STOCK / OPTION / SKIP), breakdown by outcome.
- Use case: after a week of running, export the CSV and ask questions like "what percentage of OPTION decisions actually submitted?", "which signals correlated with the best outcomes?", "did the cash floor block valid trades or only bad ones?"
v1.9.20260610c
2026-06-10 · cash floor
- New: cash floor (ON by default, threshold $0). The bot refuses any stock BUY order whose projected post-order cash would drop below the configured threshold.
- Operates silently — no modal, no automation break. Logs
⛔ CASH FLOOR: SYMBOL BUY refused — would leave cash at $X (floor $Y).
- Why stock BUYs only: option SELL orders (CSPs, CCs) receive credit and increase cash. Option BUY orders only happen during defensive closes (stops, rolls, expiry-forced exits) which must never be blocked or you'd be left with uncovered short positions.
- Configurable in Safety tab → SAFETY CONTROLS → CASH FLOOR. Default $0 (don't go negative). Set to e.g. $500 to keep a cash buffer for fees and assignments.
- Independent of Alpaca's server-side margin check — this is an additional client-side rule for users who want a strict no-margin policy. Alpaca will still reject orders that exceed buying_power as a backstop.
- Settings persist to
gus_cash_floor localStorage.
v1.9.20260610b
2026-06-10 · options buying power fix
- Critical fix: CSP entries were being rejected with "insufficient options buying power" because the bot was reading
ACCOUNT.cash as available funds. Alpaca's cash field doesn't reflect collateral already reserved by existing short options — that's what options_buying_power is for.
- Example: the bot read
cash as available funds, but the true ceiling was options_buying_power (significantly lower). The gap = collateral already locked by an existing CSP that the bot wasn't accounting for.
- New helper
availableOptionsCash() reads ACCOUNT.options_buying_power (Alpaca's purpose-built field for new option positions), takes the min of that and cash to be safe, falls back to cash if the field is missing.
- All 4 option-entry call sites updated to use the new function: openOptionCandidate, openOptionCandidateElite, and 2 outer wrappers.
- Stock entry path UNCHANGED — it still reads raw cash directly, since stocks have different margin rules and use Alpaca's separate
buying_power field via its own path.
v1.9.20260610a
2026-06-10 · better API error messages
- Bug fix: alpacaFetch lumped 401 and 403 together as "Authentication failed — check your API Key" — but 401 = bad credentials while 403 = valid credentials lacking the required permission (e.g. options trading level). The misleading message led people to chase API-key issues when the real problem was account permissions.
- 403 now surfaces Alpaca's actual error message: parses the response body for
message or error field and shows it in the log. Example: Forbidden (403) — options trading level insufficient instead of the generic auth message.
- All 4xx errors now show their actual message from Alpaca's response, not just the HTTP status code.
- 4xx errors no longer fall through to the CORS proxy retry — they're definitive, not CORS-related. Saves a wasted round-trip and prevents the confusing "Connection failed" wrapper around a real Alpaca error.
v1.9.20260526a
2026-05-26 · no-short fix + signal-driven entries
- CRITICAL FIX — bot no longer shorts stock. The stock-entry side (buy/sell) was decided by
Math.random() — an 80/20 coin flip in NEUTRAL regime. ~1 in 5 ticks rolled SELL on a stock not held, opening a naked short (e.g. the AMD short you spotted). Shorting has unlimited risk and has no place in a wheel strategy.
- Ticker selection now signal-driven: instead of a random pick from the universe, the bot now selects the highest-scored Brain pick (score = momentum × 2 + liquidity). Random selection removed.
- Side selection now rule-based: the bot SELLS only positions it already holds long — specifically winners up ≥ +8% (take profit) or losers ≤ -8% (safety exit). Otherwise it BUYS the strongest pick. No coin flip.
- Two hard no-short guards added: (1) a stock SELL is refused outright if the ticker isn't held long; (2) SELL quantity is capped at the actual held share count, so the bot can never oversell into a short.
- Net effect: the bot can only buy stocks or sell stocks it owns. It is now structurally incapable of opening a short stock position.
v1.8.20260509f
2026-05-09 · reword churn prevention
- Churn Prevention panel description reworded to neutral/informational style, matching the rotation toggle update in v1.8.e. Removes specific historical-loss references that had appeared in the live UI.
- Behavior unchanged — cooldown, per-ticker daily cap, and total daily cap all still active with same defaults (24h / 3 per ticker / 20 total).
v1.8.20260509e
2026-05-09 · reword rotation message
- Rotation logic toggle message reworded from warning (with specific dollar loss figure) to neutral informational text.
- Recommendation on default: remains OFF — wheel strategy doesn't use rotation; the toggle takes one click to enable if desired.
- v1.7.20260509a changelog entry also updated to remove the now-stale dollar figure.
v1.8.20260509d
2026-05-09 · light theme pass 2
- Comprehensive coverage of inline color styles that v1.8.c missed. Audit of all hard-coded hex values found ~30+ uncovered patterns.
- Tinted panel backgrounds now mapped to subtle pastels: green-tinted → mint (#ecf7ee), blue-tinted → soft cyan (#eef2fa), purple → lavender (#f5eef5), orange → cream (#fdf7e8), red → pink (#fdecec).
- Border colors: 30+ dark-tinted border patterns mapped to light counterparts (mint, cyan, pink, cream, lavender borders).
- Near-black panel backgrounds (#0a0e0a, #0e0e0e, #0c0c0c, etc.) all now render as white.
- Dashboard hero cards (Equity/Cash/Day P&L): row labels darken to #6a7280, values to #1a1d24 for high contrast.
- Hover states: tbody rows + tabs hover to #f0f4f8 instead of pure-white flash.
- Toast messages (.omsg): proper light backgrounds with status colors (.ok green, .err red).
- Progress bars in trade quality breakdown use darkened accents on white.
- Breaker badge + version chip: light backgrounds with colored text and matching borders.
- Webkit scrollbars: light gray track + thumb instead of jarring dark scrollbars on white.
- Splash logo: opacity 0.85 in light mode (slightly less faded than dark mode's 0.7).
- Dark theme remains the default — only the light variant is affected by these changes.
v1.8.20260509c
2026-05-09 · proper light theme
- Bugfix: the "light theme" shipped in v1.8.a was a lazy CSS
filter: invert() hack. Replaced with a proper data-driven theme using [data-theme="light"] attribute selectors.
- Real color tokens: warm near-white backgrounds (#f7f8fa), near-black text (#1a1d24), darkened accents (green #0a8e3a, red #c41e3a, yellow #b8860b, blue #1969b9) for proper contrast on light backgrounds.
- Panels: white with subtle 1px shadow, light gray borders. Inputs: white backgrounds with focus-green border. Tables: white rows with hover highlight.
- Hard-coded dark hex values throughout the bot (#0a0a0a, #1a1a1a, #bbb, etc.) are auto-overridden via attribute selectors — no per-element refactor needed.
- Logo/images render without inversion (no more weird colors on the splash screen).
- Toggle is the same button (Safety tab → UI / UX FEATURES → Theme).
v1.8.20260509b
2026-05-09 · audit fixes (duplicate functions)
- Bug fix discovered by audit: three duplicate function definitions had been silently overriding each other in the file. Resolved by removing the simpler (later) definitions and keeping the richer (earlier) ones.
- updPBtn (manual order panel button): now uses the version with order-type badge + estimated cost + cash sufficiency indicator (was previously falling back to a simpler version without these features).
- renderPicks (Brain top picks cards): now uses the version with IVR/MOM/LIQ badges per pick (was previously falling back to plain cards without badges).
- enrichPicksWithIVR: duplicate definition removed (was functionally identical, just dead code).
- No behavior regressions: the bot was already running these features via the simpler versions; now the richer UI elements will show. All 22 trading-safety layers and 35 v1.8.a feature wirings verified intact after the fix.
v1.8.20260509a
2026-05-09 · cat 2 + cat 3
- 2.1 Daily Realized-Loss Kill Switch (opt-in, OFF by default): independent of circuit breaker. Halts new entries when today's closed-trade realized loss exceeds threshold (default −$500). Configurable in Safety tab.
- 2.2 Entry-Reason Tagging: every new trade now records an
entry_reason in TRADE_JOURNAL (regime_signal, auto_cc_after_assignment, elite_options_brain, bull_put_spread). Stock entries now also persist to journal (previously only options did). Foundation for future signal-quality analysis.
- 2.4 Wheel vs Churn Breakdown: new Dashboard panel showing closed trades grouped by category (🎯 wheel / 🛡 spread / 📈 stock / ❓ other) with count, P&L, and average per bucket. Warns if stock-bucket count exceeds wheel-bucket count.
- 3.1 Theme toggle (button in Safety tab): page-level light/dark via CSS invert filter. Persists across reload.
- 3.2 Mobile-responsive CSS: media queries at 768px and 480px breakpoints reduce padding, hide topbar logo, stack panels, shrink inputs.
- 3.3 Audible alerts (opt-in): Web Audio API generates short beeps on stops/PDT/kill-switch/breaker events. Pure browser, no external assets.
- 3.4 Tooltips: native HTML
title attributes auto-applied to NLV, DTE, IV, CSP, CC, PDT, ACB, Theta, Delta, IVR, BTC, STO, CB1/CB2/CB3.
- 3.5 PDF Summary export: button in Safety tab opens a printable trade-summary report (use browser's Print > Save as PDF).
- 3.6 Trade Replay: button in Safety tab prompts for a date, opens chronological list of all orders that day in a new tab. Useful for diagnosing churn days like 05/06.
v1.7.20260509b
2026-05-09 · cooldown + per-ticker cap + daily cap
- Post-stop cooldown (24h default): after a stop-loss or breaker-triggered close, the bot blocks re-entry of the same ticker for N hours. Prevents whipsaw: historical analysis showed stop-then-immediate-re-buy patterns generated repeated losses. Persisted in
gus_stop_cooldowns localStorage key.
- Per-ticker daily order cap (3/day default): bot refuses to fire a new stock order if that ticker already has 3+ orders today. Addresses the 14-INTC-orders-on-05/06 fragmentation pattern.
- Total daily order cap (20/day default): bot stops placing stock orders for the day once 20 stock orders have been placed across all tickers. Addresses the ~50-order-day pattern seen on 05/06.
- New CHURN PREVENTION sub-panel in Safety tab → SAFETY CONTROLS, with editable cooldown hours + per-ticker cap + daily cap + live status showing today's order count and active cooldowns.
- All three gates fire BEFORE the order submission, so blocked attempts don't consume the order budget. Log entries:
⛔ CHURN GATE: SYMBOL — reason
- Settings persist to
gus_churn_settings localStorage. Survive page reload.
v1.7.20260509a
2026-05-09 · churn fixes (PDT + rotation + limit)
- PDT protection (ON by default): blocks new entries that would create a 4th day-trade in 5 business days. Prevents Pattern Day Trader flag (90-day account restriction) for accounts under $25K. Auto-disables above threshold.
- Rotation logic disabled by default (
OPT_CONFIG.rotationEnabled = false). Sells losing positions to rotate into higher-scoring picks; not used in pure wheel strategy. Can be re-enabled in Safety tab.
- Limit orders for stock entries (ON by default): BUY orders now use limit price at mid + 0.1% slippage cushion. Saves bid-ask spread on every entry. Falls back to market if no live quote available.
- New SAFETY CONTROLS panel in Safety tab with toggles + live PDT day-trade counter showing recent activity by date.
- All settings persist to localStorage (
gus_safety_controls) across page reloads.
v1.6.20260509d
2026-05-09 · orders buffer to max
- Orders fetch buffer increased from 200 → 500 (the Alpaca API maximum per request)
- Other order endpoints unchanged: FIFO/tax fetch was already at 500; duplicate-check fetch stays at 100 (open orders only, kept small for speed)
v1.6.20260509c
2026-05-09 · orders buffer + date
- Orders fetch buffer increased from 50 → 200 (Alpaca API max is 500; 200 covers ~weeks of activity without overwhelming render)
- Orders table TIME column now shows date + time (MM/DD HH:MM:SS AM/PM) instead of just time, matching the activity log format
v1.6.20260509b
2026-05-09 · logo opacity
- Login/connect screen: splash logo fades to 70% opacity for a more muted look
- (Affects whole logo image — JPEG format can't isolate just the eyes)
v1.6.20260509a
2026-05-09 · merged risk limits
- Merged the two duplicate breaker panels: deleted the OLD "CIRCUIT BREAKERS" panel (which had misleading labels — "Weekly Drawdown", "Monthly Drawdown", etc. all wrote to the same daily threshold).
- New unified risk-limits panel in Safety tab → ⛔ CIRCUIT BREAKER STATUS with 6 properly-implemented controls:
- Daily CB1/CB2/CB3 (−3 / −5 / −10%): existing tiered system
- Weekly limit (−7% default): blocks NEW entries when 7-day rolling drawdown hits threshold. Existing positions managed normally. Uses real date-stamped daily snapshots.
- Monthly limit (−12% default): same mechanism, 30-day window
- Per-trade multiplier (2.0× default): sets
OPTION_STOP_MULT — short option closes if loss reaches Nx the original credit. Already wired into manageOptionPositions().
- Live drawdown displays show current 7-day and 30-day DD with peak date, plus ARMED / BLOCKING badge.
- New
gus_equity_daily localStorage key persists one equity snapshot per trading day (rolling 90-day history) for accurate week/month windows.
- New
gus_limits localStorage key persists weekly/monthly/per-trade settings across page reloads.
- Single SAVE ALL button validates all 6 values together. Validation enforces: daily ordering (CB1 < CB2 < CB3), weekly less severe than monthly, per-trade between 1.2x and 10x.
v1.5.20260509b
2026-05-09 · breaker threshold inputs
- Bugfix: circuit breaker manual threshold entry was broken — the
saveCB() function existed in JS but the input fields and SAVE button were never added to the UI. Hard-coded -3% / -5% / -10% were the only values used.
- New UI in Safety tab → ⛔ CIRCUIT BREAKER STATUS: three input fields (CB1 / CB2 / CB3 in %) + SAVE and RESET DEFAULTS buttons.
- Validation: rejects values outside 0.1–50% range; rejects orderings where CB1 ≥ CB2 ≥ CB3 (escalation must be strictly increasing severity).
- Persistence: saved values persist across page reloads via
gus_cb_thresholds localStorage key. RESET DEFAULTS clears the override.
- UI feedback: green "✓ Saved at HH:MM:SS" message shown for 6 seconds after save; red error if validation fails; activity log records the change.
v1.5.20260509a
2026-05-09 · tiered breaker
- Tiered circuit breaker system: three levels of escalating defensive response.
- CB1 (−3%): cancels all pending orders via Alpaca API, halts new entries. Manual unlock required via "RESUME TRADING" button in Safety tab.
- CB2 (−5%): all of CB1 + closes stock positions that have already breached their per-position stop loss. Short options are NEVER auto-closed (wheel philosophy: let IV crush work).
- CB3 (−10%): all of CB2 + STICKY for the rest of the trading day. Cannot be manually unlocked until next trading day. Designed to prevent revenge-trading on a catastrophic day.
- Durable event log: breaker triggers persist in localStorage (last 50 events) and survive page reloads. Visible in Safety tab → ⛔ CIRCUIT BREAKER STATUS panel → EVENT HISTORY.
- State persistence: if you reload the page while a breaker is active, the bot remembers and stays halted.
- Old behavior removed: the bot will no longer auto-clear the breaker just because daily P&L recovers — explicit user action is now required.
v1.4.20260509a
2026-05-09 · complete export
- Bot vs SPY benchmark panel added to Dashboard. Tracks realized wheel P&L only (excludes unrealized stock appreciation) vs. equivalent SPY return since baseline date.
- Verdict banner: BEATING SPY / TRACKING SPY / LAGGING SPY / INSUFFICIENT DATA. Requires 30+ closed trades before drawing conclusions.
- Time-in-market metric: shows % of equity deployed vs. cash. Warns if <40% (cash drag killing returns).
- Trade quality breakdown: visual bar showing % of closed trades that hit profit-target / time-exit / stop-loss / pre-earnings close. Warns if stop-loss rate exceeds 25%.
- Annualized return calculation for both bot and SPY (rough — uses actual days elapsed × 365).
- SPY baseline auto-set on first run; resettable via "RESET BASELINE" button. Stored in localStorage.
v1.3.20260509b
2026-05-09 · audit
- Audit-only build: verified the existing "BOT vs SPY BENCHMARK" panel on the Dashboard is fully functional (tracks realized wheel P&L vs SPY total return).
- No new code added — panel was already shipped in earlier builds. This entry documents the audit and confirms everything is wired.
v1.3.20260509a
2026-05-09 · 4 priority improvements
- Pre-earnings position closing: short options auto-close 1 day before earnings (configurable via OPT_CONFIG.preEarningsCloseDays, set to 0 to disable). Highest-priority exit trigger — runs before stop-loss, profit-take, and 21-DTE checks.
- Defensive rolling (manual): click any short option in Positions detail modal → "PREVIEW ROLL" button appears for challenged positions. Bot finds further-OTM, longer-DTE candidates and only proceeds if net credit is available (industry rule: never roll for debit). User confirms before execution.
- Wheel position cap: max 10 concurrent active wheels by default (OPT_CONFIG.maxOpenWheels). New entries blocked if cap reached. Counts unique underlyings (stock or short options).
- True Adjusted Cost Basis tracking: position detail modal now shows broker basis vs. ACB-after-premiums-collected, with warning to only sell CCs above adjusted basis to lock in profit. Sourced from TRADE_JOURNAL closed-trade history.
- Standing rule active: every build auto-bumps version + appends changelog entry
v1.1.20260509a
2026-05-09
- Established standing versioning rule: every future build automatically bumps version + appends a new changelog entry
- Restructured changelog modal as append-only history (newest first)
- Topbar logo doubled in size (52px height, max 220px width)
v1.0.20260509
2026-05-09 · initial versioned build
- Earnings refresh button label now reflects active source (Finnhub or fallback)
- Click any position row to see detailed summary (contract details, DTE, P&L, market data, earnings context)
- Version badge added to topbar — click anytime to view this changelog
- Esc key closes modals
Single-file HTML · self-contained · no external dependencies · drop directly onto gusautobot.com