Mechanical intraday backtest for SMH and SOXX using progressive entry, VIX-scaled leverage, and strict end-of-day flat rules.
IBKR Production Trading System
EMA 25/125 Strategy with Dynamic Leverage๐ Overview
Automated trading system for SMH (semiconductor ETF) using EMA crossover strategy with:
- Signal: EMA 25 > EMA 125 = BULL (enter long)
- Leverage: 3.0x - 3.75x based on VIX
- Stop Loss: -2% daily equity
- Entry: 5 minutes before market close (3:55 PM ET)
- Exit: Bear signal or stop loss
โ๏ธ Setup
1. Install Dependencies
pip install ib_insync pandas pytz
2. Configure IBKR TWS
- Open TWS Paper Trading
- Go to: Edit โ Global Configuration โ API โ Settings
- Enable: "Enable ActiveX and Socket Clients"
- Set Port: 7496 (paper) or 7497 (live)
- Add Trusted IP: 127.0.0.1
- Click OK and restart TWS
3. Login to TWS
- Start TWS and login with paper trading credentials
๐ Running the System
Test Mode (Immediate Entry)
python ibkr_production.py
- Enters position immediately
- Good for testing
Production Mode (3:55 PM Entry)
Edit line 241:system.run(test_mode=False) # Change True to False
๐ How It Works
Daily Cycle
| Time | Action | |------|--------| | 9:30 AM | Records day start equity | | Continuous | Monitors -2% stop loss | | 3:55 PM | Enters if BULL signal + no position | | 4:00 PM | Updates EMAs, checks bear exit |
When You Add Money
- System recalculates at 4:00 PM (market close)
- Updates EMAs with today's close price
- Checks signal: BULL or BEAR
- If BULL โ enters position at 3:55 PM next day
- Position sized on new total equity
Stop Loss
- Monitors equity every 5 seconds
- If daily loss โฅ -2% โ exits immediately
- Can re-enter same day at 3:55 PM if BULL signal remains
Leverage Scaling
| VIX Level | Leverage | |-----------|----------| | VIX < 12 | 3.75x | | VIX < 13 | 3.5x | | VIX < 14 | 3.25x | | VIX โฅ 14 | 3.0x |
Note: Paper trading uses default 3.0x (VIX not available)
๐ Console Output
โ
Connected to IBKR Paper Trading (Port 7496)
โ
EMAs Initialized: 25=399.87 | 125=356.11
Signal: BULL
๐
Day Start Equity: $1,001,295.25
โ
ENTERED: 7355 shares @ $408.39 (Leverage: 3.0x)
Status Messages
| Symbol | Meaning | |--------|---------| | โ | Success | | ๐ | Stop loss triggered | | ๐ช | Position exited | | ๐ | Signal changed | | โน๏ธ | System shutdown |
๐ง Configuration
Edit these variables in ibkr_production.py:
# Connection
IBKR_PORT = 7496 # 7496 = paper, 7497 = live
Strategy
EMA_FAST = 25
EMA_SLOW = 125
STOPLOSSPCT = 0.02 # 2%
Leverage
LEV_BASE = 3.0
LEVVIX14 = 3.25
LEVVIX13 = 3.5
LEVVIX12 = 3.75
Timing
ENTRYTIME = dttime(15, 55) # 3:55 PM ET
๐ก๏ธ Safety Features
- -2% Hard Stop - Cannot lose >2% per day (except gaps)
- Bear Exit - Exits when EMA turns bearish
- Auto-reconnect - Handles disconnections
- Position verification - Checks actual IBKR position
- Paper trading default - Safe testing environment
๐ Position Management
Entry Conditions
- โ No current position
- โ EMA 25 > EMA 125 (BULL)
- โ Time = 3:55 PM ET
- โ Valid price available
Exit Conditions
- โ Daily loss โฅ -2% (stop loss)
- โ EMA 25 < EMA 125 (bear signal)
Re-entry
- Can re-enter same day at 3:55 PM if:
๐ Logs & Monitoring
Real-time Monitoring
Watch the console for:- Entry/exit confirmations
- Stop loss triggers
- Signal changes
- Errors
Position Check
# In TWS: Portfolio โ Positions
Should show: SMH shares = script output
๐จ Troubleshooting
"No security definition found"
- Fix: Check symbol and exchange (SMH on ARCA)
"Market data requires subscription"
- Fix: System uses delayed data (automatic)
- 15-minute delay is acceptable for end-of-day strategy
"Cannot convert NaN to integer"
- Fix: Updated script handles this automatically
- Waits for valid price before entering
Position not entering
- Check time (must be 3:55 PM ET in production mode)
- Check signal (EMA 25 must be > EMA 125)
- Check TWS is connected and logged in
๐ Expected Performance
Based on backtest (July 2022 - Jan 2026):
- CAGR: 99.30%
- Max DD: 20.84%
- Sharpe: 1.64
- Trades/Year: 2.8
- Win Rate: 40%
๐ฏ Going Live (Real Money)
Checklist
- โ Test in paper trading for 1 week
- โ Verify all entries/exits working
- โ Confirm stop loss triggers correctly
- โ Check position sizing is correct
Switch to Live
- Change port to 7497
IBKR_PORT = 7497
- Login to TWS Live (not paper)
- Start with small capital (test $10k first)
- Monitor daily for first week
- Gradually increase to full capital
โ ๏ธ Risk Warnings
- Gap Risk: Overnight gaps can exceed -2% stop
- Leverage: 3x amplifies gains AND losses
- Bear Markets: Strategy exits during downtrends (misses upside)
- Slippage: Real executions may differ from backtest
- Technical: System failures, disconnections possible
๐ Emergency Shutdown
To stop the system:
- Press
Ctrl+Cin terminal - System exits gracefully
- Does NOT close position (manual close in TWS if needed)
- Open TWS
- Go to Portfolio โ Positions
- Right-click SMH โ Close Position
๐ Support
Issues?
- Check TWS connection
- Verify API settings
- Check console for error messages
- Ensure market hours (9:30 AM - 4:00 PM ET)
๐ Files
ibkr_production.py- Main trading scriptDEPLOYMENT_GUIDE.md- Setup instructionsREADME.md- This file
Strategy validated. System ready. Trade safe. ๐ฏ