Add same-day TSLA intraday strategy (tsladay profile) - #10
Merged
Conversation
New market profile alongside the existing swing config: config/paper_tsladay.env and config/live_tsladay.env (bot/profile.py market "tsladay"), wired into docker-compose.yml (trade-tsladay/paper-tsladay/paper-tsladay-monitor). This is a deliberately different strategy from the spy-market swing config (~1 trade/5-6 weeks, multi-day holds), built because that config doesn't capture TSLA's frequent intraday swings by design: - Bidirectional (ALLOW_SHORTS=true): a position that's always flat by close carries no overnight gap risk, so shorting TSLA's down-legs is as safe as going long its up-legs, and backtests about as profitable (short side actually outperformed: $16.29/30 trades vs long $8.58/25). - Capped at MAX_TRADES_PER_DAY=1: the account is $150 in a cash account, so more than ~1 buy+sell cycle/day risks reusing unsettled (T+1) proceeds and tripping a good-faith violation. This is an account-mechanics constraint the strategy is designed around, not a signal-quality choice. - 15m bars, 2h intraday regime gate (vs the swing config's daily-EMA gate), 09:45-15:30 ET entry window, FLATTEN_BEFORE_CLOSE_MINUTES=15. Backtest: bot/optimize_strategy.py walk-forward grid search fed 15m TSLA bars via yfinance (no Alpaca keys available outside EC2; free intraday history caps at ~60 trading days, so this is a much thinner, single-regime validation than the swing config's 2.9yr one - flagged throughout). Shipped config (65%/70% target/max notional, trimmed down from what the 60-day backtest could have supported as a margin of safety): 55 trades, win rate 53%, PF 2.01 (1.99 under 2x slippage), net +$20.01 (+13.3%) on $150, max drawdown 3.7%, positive in 3 of 4 walk-forward test windows. Full methodology, sizing sweep, and caveats: docs/strategy_tsla_day_2026-08.md. Also fixes a replay/live parity gap this surfaced: bot/research.py::run_replay never simulated ALLOW_OVERNIGHT_HOLDING=false / FLATTEN_BEFORE_CLOSE_MINUTES (only the live loop did, via bot/trade_controls.py::evaluate_session_exit) - every prior backtest had overnight holding enabled so it never mattered. run_replay now calls evaluate_session_exit every bar a position is open. Regression tests in tests/test_research_replay.py. Also made two optimizer knobs configurable that were previously hardcoded for swing-style signals (bot/optimize_strategy.py): ALLOW_SHORTS as a grid dimension (OPT_ALLOW_SHORTS_VALUES) and the trades/day acceptance band (OPT_SCORE_MIN/MAX_TRADES_PER_DAY, OPT_ACCEPT_MIN/MAX_TRADES_PER_DAY) - both default to prior behavior, no change for existing configs. Recommendation: paper only (paper-tsladay) for a real stretch across different market conditions before ever considering live capital, per the doc. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New market profile alongside the existing swing config: config/paper_tsladay.env and config/live_tsladay.env (bot/profile.py market "tsladay"), wired into docker-compose.yml (trade-tsladay/paper-tsladay/paper-tsladay-monitor).
This is a deliberately different strategy from the spy-market swing config (~1 trade/5-6 weeks, multi-day holds), built because that config doesn't capture TSLA's frequent intraday swings by design:
Backtest: bot/optimize_strategy.py walk-forward grid search fed 15m TSLA bars via yfinance (no Alpaca keys available outside EC2; free intraday history caps at ~60 trading days, so this is a much thinner, single-regime validation than the swing config's 2.9yr one - flagged throughout). Shipped config (65%/70% target/max notional, trimmed down from what the 60-day backtest could have supported as a margin of safety): 55 trades, win rate 53%, PF 2.01 (1.99 under 2x slippage), net +$20.01 (+13.3%) on $150, max drawdown 3.7%, positive in 3 of 4 walk-forward test windows. Full methodology, sizing sweep, and caveats: docs/strategy_tsla_day_2026-08.md.
Also fixes a replay/live parity gap this surfaced: bot/research.py::run_replay never simulated ALLOW_OVERNIGHT_HOLDING=false / FLATTEN_BEFORE_CLOSE_MINUTES (only the live loop did, via bot/trade_controls.py::evaluate_session_exit) - every prior backtest had overnight holding enabled so it never mattered. run_replay now calls evaluate_session_exit every bar a position is open. Regression tests in tests/test_research_replay.py. Also made two optimizer knobs configurable that were previously hardcoded for swing-style signals (bot/optimize_strategy.py): ALLOW_SHORTS as a grid dimension (OPT_ALLOW_SHORTS_VALUES) and the trades/day acceptance band (OPT_SCORE_MIN/MAX_TRADES_PER_DAY, OPT_ACCEPT_MIN/MAX_TRADES_PER_DAY) - both default to prior behavior, no change for existing configs.
Recommendation: paper only (paper-tsladay) for a real stretch across different market conditions before ever considering live capital, per the doc.