CRITICAL FIXES (would have prevented the $194K crisis):
1. HARD MAX SHORT POSITION CAP (safety.py + executor.py)
- new config: max_short_positions=4 (hard limit)
- new config: max_total_positions=8 (hard limit)
- executor now queries broker.get_positions() for AUTHORITATIVE count
- BEFORE opening any short, checks broker directly (not just store)
- validate_trade() now accepts broker_positions and blocks at hard cap
- This directly prevents the 13-shorts scenario
2. YESTERDAY-CLOSE DRAWDC OWN CIRCUIT BREAKER (safety.py)
- new config: yesterday_close_drawdown_limit=3%
- new config: yesterday_close_drawdown_reduction=50%
- Separate from peak-equity tracking (which is too slow)
- At $194K from $200K initial = 3% → fires IMMEDIATELY, cuts 50% of positions
- Tested: check_yesterday_close_drawdown($194K) → triggers with 50% reduction
3. PER-POSITION STOP LOSS DEFAULTS (safety.py + executor.py)
- new config: stop_loss_default_pct_long=1.0%, short=1.5%
- new config: stop_loss_max_pct=3.0% (never wider than this)
- new config: take_profit_default_pct=2.0%
- NEW: get_default_stop_loss() + get_default_take_profit() methods
- executor.execute_signal() now ALWAYS sets stop loss (even if GA provides None)
- Previously stops were often None → exits never triggered
- Tested: get_default_stop_loss($100, 'short') = $101.50 ✓
4. BROKER/STORE SYNC VALIDATION (safety.py + main_auto.py)
- new: validate_broker_position_count() detects discrepancies
- new: _trade_symbol() now passes combined_equity to executor
- new: _trading_cycle() validates broker vs store BEFORE evaluating new trades
- Logs warning when broker has positions not tracked in store
- Blocks new trades if broker position count already at hard cap
5. CRISIS MODE: 10+ LOSING POSITIONS (executor.py check_exits)
- If 8+ of 10+ positions are losing money → force reduce 50% of ALL positions
- Catches cascading blowups before drawdown thresholds are hit
- Logs CRITICAL warning when triggered
6. DEFAULT STOP LOSS ENFORCEMENT (executor.py)
- _enforce_stop_loss_tightness() was overriding None stops to None
- Now executor ALWAYS applies safety defaults if GA provides no stop
- Every new position gets a stop loss on entry
Config changes (auto_config.json):
- Added max_short_positions, max_total_positions
- Added stop_loss_default_pct_long/short, take_profit_default_pct
- Added stop_loss_atr_multiplier, stop_loss_max_pct
- Added yesterday_close_drawdown_limit=3%, yesterday_close_drawdown_reduction=50%
HOW THIS WOULD HAVE HELPED THE $194,940 PORTFOLIO:
- At $194,940 from $200K = 2.53% drawdown from initial
- If yesterday closed at $200K: 2.53% < 3% limit → NOT triggered
- But at open today if equity dropped to $194,000 → 3.00% → TRIGGERS IMMEDIATELY
- Hard cap at 4 shorts: after 4 shorts, executor blocks action 5/6
- Stop losses: each of the 4 shorts would have had 1.5% stop → 2 shorts would
have been stopped out before they lost further, limiting damage
- Crisis mode: if 8 positions were losing, 50% of all positions closed
- Portfolio equity now sums both brokers instead of showing Alpaca only
- Total P&L was showing -$100k because OANDA equity was missing
- Set initial_capital to $200k (Alpaca $100k + OANDA $100k)
- Set target_capital to $250k
- Label forex positions as "units" instead of "shares"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Switch to oil stocks (USO, XLE, OXY, CVX, XOM, SLB, HAL, DVN, MPC, VLO)
- Add JPY/USD forex pairs for Japan targeting
- 7-action RL space: long, short, close (was 5 long-only actions)
- Bollinger Band mean-reversion scalp entries both directions
- 5-minute candles with 60-second cycles for scalping
- 35 features (added VWAP, fast RSI, fast ROC for scalping)
- Short position support in backtest, executor, and RL environment
- GA tuned for scalping: tighter SL/TP, shorter hold times
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>