AutoTrader is an AI‑driven stock research and trading system for IBKR. It focuses on scanning liquid, lower‑priced stocks, shortlisting candidates, and then selecting buys from that shortlist.
- This project can place real orders if pointed at a live IBKR account. Use Paper Trading until you are fully confident.
- This repository is not financial advice. You are responsible for all trades and risk.
- Trader engine (
main.py): scanning, research, AI decisions, order placement, and audit logging. - FastAPI server (
api_server.py→src/api/app.py): history endpoints backed by the database, plus live endpoints via a dedicated IBKR service thread. - React dashboard (
frontend/): monitoring, settings modal (runtime config), SSE live stream. - Runtime configuration (DB‑backed): update risk limits, markets, and AI strategy prompts without restarting.
- IBKR TWS or IB Gateway running with API access enabled (Paper Trading recommended).
- Python 3.10+.
- Node.js 18+ (for the dashboard).
- An OpenAI‑compatible API (OpenAI, or a compatible provider such as Ollama).
- PostgreSQL (recommended): local install or Docker.
Copy the example file and set your AI provider details:
cp config/secrets.env.example config/secrets.envdocker compose -f docker-compose.postgres.yml up -dpip install -r requirements.txtexport PYTHONPATH="$PYTHONPATH:."
python main.pyexport PYTHONPATH="$PYTHONPATH:."
python api_server.pycd frontend
npm install
npm run devOpen the Vite URL printed in the terminal (usually http://localhost:5173).
AutoTrader is configured from three places (in order):
- Base YAML:
config/config.yaml - Environment variables (for a small set of operational overrides)
- Runtime config (DB‑backed): editable from the dashboard Settings modal, applied at the start of each trader cycle
- Local secrets:
config/secrets.env- This file is for local use and is ignored by
.gitignore. - Create it by copying
config/secrets.env.example.
- This file is for local use and is ignored by
Required (pick one approach):
- OpenAI: set
OPENAI_API_KEY. - OpenAI‑compatible (e.g. Ollama): set
OPENAI_BASE_URL(and optionallyOPENAI_API_KEY; a dummy value is fine for many local providers).
If you want to run locally with Ollama:
- Set in
config/secrets.env:OPENAI_BASE_URL=http://localhost:11434/v1OPENAI_API_KEY=ollama
- Set the model in one place:
ai.modelinconfig/config.yaml(or via the dashboard Settings modal runtime config)
Any other OpenAI‑compatible proxy/provider works the same way: point OPENAI_BASE_URL at it, then change ai.model.
- Recommended: PostgreSQL
- Set
AUTOTRADER_DATABASE_URL(orDATABASE_URL) to apostgresql://...DSN. - The trader writes history; the API reads history and serves it to the dashboard.
- Set
- Fallback: SQLite (
autotrader.db)- Used when no PostgreSQL DSN is configured.
- Not recommended when running trader + API together (SQLite locking under concurrent writer/reader load).
These override a small set of values from config/config.yaml:
- Broker
AUTOTRADER_BROKER_HOSTAUTOTRADER_BROKER_PORTAUTOTRADER_BROKER_CLIENT_ID
- AI
AUTOTRADER_AI_MODEL(default:gpt-4.1-mini)
- Cycle timing
AUTOTRADER_CYCLE_INTERVAL_SECONDS
- PostgreSQL tuning (optional)
AUTOTRADER_PG_CONNECT_TIMEOUT_SECONDSAUTOTRADER_PG_POOL_MINAUTOTRADER_PG_POOL_MAX
Runtime config is stored in the database and applied dynamically. It is designed for:
- Risk/spend limits (e.g. max cash utilisation, per‑currency cash reserve)
- Markets to trade (e.g. US/UK)
- Strategies (select an active strategy; each strategy can override parameters)
- AI strategy prompts:
- shortlist prompt (stage 1)
- buy selection prompt (stage 2)
- position review prompt
- order review prompt
The output schema is enforced in code. The dashboard shows instruction prompts only; you do not manage JSON output formats.
AutoTrader requires TWS or IB Gateway with API access enabled.
- Paper trading ports
- TWS Paper:
7497(default inconfig/config.yaml)
- TWS Paper:
- API settings
- Enable API / socket clients
- Allow connections from localhost
- Client IDs
- Trader uses
broker.client_id(default10) - API uses
broker.client_id + 1000(to avoid collisions) - API is single‑instance (lockfile in
api_server.py)
- Trader uses
This table covers the most commonly adjusted knobs. Anything marked runtime can be changed from the dashboard Settings modal (stored in the DB and applied at the start of each trader cycle).
| Path | Default | Purpose | Runtime? |
|---|---|---|---|
broker.host |
127.0.0.1 |
Where TWS/IB Gateway is running. | No |
broker.port |
7497 |
IBKR API port (paper trading default for TWS). | No |
broker.client_id |
10 |
Trader’s IBKR clientId (API uses +1000). |
No |
ai.model |
gpt-4.1-mini |
Model name used by the trader (OpenAI‑compatible). | Yes |
trading.markets |
["US","UK"] |
Which markets to scan/trade. | Yes |
trading.max_positions |
10 |
Maximum concurrent open positions. | Yes |
trading.max_new_positions_per_cycle |
2 |
Max new entries per scan cycle. | Yes |
trading.risk_per_trade |
0.05 |
Position sizing risk budget as a fraction of equity. | Yes |
trading.max_cash_utilisation |
0.3 |
Upper bound on cash allocation for new trades. | Yes |
trading.cash_budget_tag |
TotalCashValue |
Which IBKR account value to treat as “cash budget”. | Yes |
trading.max_share_price |
20.0 |
Upper price bound for candidates (low‑cost focus). | Yes |
trading.min_share_price |
2.0 |
Lower price bound (avoid very cheap/illiquid names). | Yes |
trading.min_avg_volume |
500000 |
Liquidity filter (avoid thin volume / microcaps). | Yes |
trading.exclude_microcap |
true |
Exclude IBKR trading class SCM to reduce Rule 144 headaches. |
Yes |
trading.volatility_threshold |
0.05 |
Minimum ATR/price ratio for candidates (volatility filter). | Yes |
intraday.enabled |
true |
Enables the intraday scan/trade cycle. | Yes |
intraday.cycle_interval_seconds |
300 |
Time between scan cycles when markets are open. | Yes |
intraday.cycle_interval_seconds_closed |
1800 |
Time between scan cycles when all configured markets are closed. | Yes |
intraday.bar_size |
5 mins |
Bar size for historical data pulls. | No |
intraday.duration |
2 D |
Historical window for indicator calculation. | No |
intraday.use_rth |
true |
Use regular trading hours data. | No |
intraday.stop_atr_multiplier |
2.0 |
Stop distance in ATR multiples. | No |
intraday.take_profit_r |
1.0 |
Take‑profit distance in R multiples of risk. | No |
intraday.flatten_minutes_before_close |
10 |
Avoid new entries close to market close. | Yes |
Run unit tests (no external services required):
pytestRun unit tests with coverage:
pytest --cov=src --cov-report=term-missingRun integration tests (requires real services: PostgreSQL + IBKR Paper + OpenAI key):
pytest -m integrationThere is also a timeout wrapper:
python scripts/run_pytest_with_timeout.py --timeout-seconds 180 -- -q- Trader (
main.py)- Scans candidates
- Runs research + AI decisions
- Places and manages orders
- Writes history/audit records to the database
- API (
api_server.py→src/api/app.py)- History endpoints: database‑backed (stable)
- Live endpoints: IBKR‑backed (no fallbacks; returns 503 if IBKR is unavailable)
- SSE stream:
/api/events/stream
- Dashboard (
frontend/)- Polls history + opens SSE for live event streaming
- Provides the Settings modal to edit runtime config
- Load configuration
- Trader loads
config/config.yaml, applies env overrides, then applies runtime config from the DB.
- Trader loads
- Scan
- The screener queries IBKR scanners and applies basic liquidity filters (min price/volume, optional microcap exclusion).
- Analyse each symbol
- Fetch historical bars from IBKR
- Compute indicators (ATR/RSI/Bollinger) and momentum
- Gather context (news/Reddit/fundamentals when available)
- AI stage 1: shortlist
- AI returns
SHORTLISTorSKIPwith scores and rationale.
- AI returns
- AI stage 2: buy selection
- At the end of the scan, AI selects which symbols to buy from the shortlist (up to the configured max new positions).
- Execution
- Places BUY orders and protective exits (stop‑loss / take‑profit) based on ATR and configured risk knobs.
- Position + order management
- Periodically reviews open positions and may hold/sell/adjust stops/TP.
- Reviews unfilled orders and may keep/cancel/adjust.
- Dashboard shows “IBKR not connected”
- The API and trader are running, but TWS/Gateway is not accepting connections on the configured host/port.
- Live endpoints intentionally return 503 (no silent fallbacks).
- Frontend dev server not reachable on
127.0.0.1- Vite binds to
localhostby default. Usehttp://localhost:5173/.
- Vite binds to
docs/ARCHITECTURE.md: system design and failure modesdocs/RUNBOOK.md: operational runbook (start/stop + debugging)docs/DEVELOPMENT.md: development guide with an AI-first explanation of how the system works
This project is licensed under the Apache License 2.0. See LICENSE.