A self-improving, fully automated US equity swing-trading bot that connects to Interactive Brokers, scores a curated stock universe using technical + sentiment signals, places bracket orders with automatic stop-loss/take-profit, and learns from its own trade history to improve over time.
- Multi-signal scoring engine — RSI, MACD, Bollinger Bands, EMA trend, volume surge, and live news sentiment are combined into a single composite score per stock
- Self-improving optimizer — every 7 trading days the bot analyses which signals correlated most with profitable trades and re-weights them automatically
- Broker-managed risk — bracket orders (market buy + limit take-profit + stop sell) are submitted to Interactive Brokers so SL/TP are enforced server-side even if the bot is offline
- Comprehensive risk controls — drawdown halt, PDT protection, sector concentration limits, per-trade position sizing
- Live dashboard — Streamlit app with equity curve, open positions, trade history, signal weights, news sentiment feed, and optimizer history
- Zero paid data feeds — market data via yfinance (Yahoo Finance), news sentiment via VADER NLP — no API keys required
09:00 AM ET ─── Pre-market scan
│
├─ Fetch 60 days OHLCV for all 33 symbols (yfinance)
├─ Compute 5 technical signals per symbol
├─ Fetch Yahoo Finance headlines → VADER sentiment score
├─ Weighted composite score (0–1 scale)
├─ Check exit conditions on open positions
└─ Queue top-scoring buy candidates (score ≥ 0.60)
09:30 AM ET ─── Market opens
└─ Submit bracket orders for candidates via IB API
├─ Parent: MARKET BUY
├─ Take-profit: LIMIT SELL (+8%)
└─ Stop-loss: STOP SELL (-2%)
09:30–4:00PM ─── IB manages SL/TP server-side (no bot action needed)
04:15 PM ET ─── Market close routine
├─ Save daily portfolio snapshot
├─ Run optimizer (if 7-day interval elapsed)
└─ Log performance summary
trading-bot/
├── config/
│ ├── settings.py # All tunable constants — capital, risk, thresholds
│ └── universe.py # 33-stock curated universe (S&P 500 blue chips + tech)
│
├── data/
│ ├── market_data.py # yfinance OHLCV bars + live price quotes
│ └── news_data.py # Yahoo Finance headlines + VADER sentiment scoring
│
├── strategy/
│ ├── signals.py # RSI, MACD, Bollinger Bands, EMA trend, volume surge
│ ├── composite.py # Weighted scorer — combines all signals into one score
│ └── optimizer.py # Self-improvement engine — tunes weights from trade history
│
├── execution/
│ ├── broker.py # Interactive Brokers (ib_insync) — orders, positions, account
│ └── risk.py # Risk manager — position sizing, drawdown halt, PDT guard
│
├── storage/
│ └── database.py # SQLite via SQLAlchemy — trades, snapshots, optimizer log
│
├── dashboard/
│ └── app.py # Streamlit dashboard — equity curve, positions, news, weights
│
├── main.py # Orchestrator + APScheduler — runs the full daily loop
├── scan_now.py # Manual trigger — run a scan outside of scheduled hours
├── requirements.txt
├── .env.example # Environment variable template
└── SETUP.md # Full setup guide
| Signal | Weight (default) | Description |
|---|---|---|
| RSI | 20% | RSI < 30 → oversold buy signal; RSI > 70 → overbought sell signal |
| MACD | 20% | Histogram crossover; normalised by 20-day rolling std for scale-invariance |
| Bollinger Bands | 15% | %B position — price near lower band = buy, near upper = sell |
| Volume Surge | 15% | Above-average volume confirming the direction of a price move |
| EMA Trend | 15% | 10-day EMA vs 50-day EMA spread — rewards confirmed uptrends |
| News Sentiment | 15% | VADER NLP on Yahoo Finance headlines; finance-tuned lexicon |
Weights are adjusted automatically by the optimizer after each 7-day cycle based on which signals actually correlated with profitable trades.
| Control | Value | Notes |
|---|---|---|
| Stop-loss | −2% | Per position; enforced server-side by IB |
| Take-profit | +8% | Per position; 4:1 reward-to-risk ratio |
| Max drawdown halt | −15% | All trading suspended until manually reset |
| Max position size | 10% | No single stock > 10% of portfolio |
| Max risk per trade | 2% | Position sized so a stop-loss costs at most 2% of portfolio |
| PDT protection | 3 day-trades / 5 sessions | Enforced if account is under $25k USD |
| Sector concentration | 35% | No single sector > 35% of portfolio |
| Max open positions | 5 | Keeps portfolio focused; preserves PDT headroom |
33 large-cap, high-liquidity stocks selected for tight spreads, strong news coverage, and sector diversification:
Technology: AAPL, MSFT, GOOGL, AMZN, META, NVDA, TSM, AVGO, ORCL, CRM, ADBE, AMD, INTC, QCOM, NOW, SNOW, PLTR, NET
Financials: JPM, BAC, GS, V, MA, BRK.B
Healthcare: JNJ, UNH, PFE
Energy: XOM, CVX
Consumer: HD, MCD, KO, WMT
| Layer | Library |
|---|---|
| Broker / Order execution | ib_insync → Interactive Brokers API |
| Market data | yfinance (Yahoo Finance — free) |
| Technical indicators | ta |
| News sentiment | vaderSentiment + NLTK |
| Data processing | pandas, numpy |
| Storage | SQLite via SQLAlchemy |
| Scheduling | APScheduler |
| Dashboard | Streamlit + Plotly |
| Logging | Loguru |
| Retry logic | Tenacity |
- Python 3.11+
- An Interactive Brokers account (paper or live)
- IB Gateway or TWS running locally with the API enabled
# 1. Clone the repo
git clone https://github.com/your-username/trading-bot.git
cd trading-bot
# 2. Create and activate a virtual environment
python3 -m venv .venv
source .venv/bin/activate
# 3. Install dependencies
pip install -r requirements.txt
# 4. Configure environment variables
cp .env.example .env
# Edit .env with your IB connection details and capital
# 5. Start the bot (IB Gateway/TWS must already be running)
python main.py
# 6. Start the dashboard (separate terminal)
streamlit run dashboard/app.py
# Open http://localhost:8501See SETUP.md for the full step-by-step guide including IB Gateway configuration, API permissions, and switching from paper to live trading.
The Streamlit dashboard (port 8501) provides:
- Overview — portfolio value, total return, today's P&L, win rate, equity curve
- Positions — open trades with entry price, stop-loss, take-profit levels
- Trade History — full closed-trade log with P&L breakdown and hold times
- Strategy — current signal weights visualised as a bar chart + signal reference
- News Sentiment — live VADER scores for held symbols with headline links
- Optimizer — Sharpe ratio history and signal weight evolution over time
The bot self-manages via APScheduler — run python main.py once and leave it:
| Job | Schedule |
|---|---|
| Pre-market scan | 9:00 AM ET, Mon–Fri |
| Market close routine | 4:15 PM ET, Mon–Fri |
| Heartbeat / position check | Every 30 min, 9:00–15:30 ET |
This project is for educational and personal use only. It is not financial advice. Trading stocks involves significant risk of loss. Always start with paper trading and never risk money you cannot afford to lose.