- Learning engine: expand default weights from 3 to all 9 strategies - Learning engine: resolve placeholder strategy_id with DB lookup - Learning engine: pass strategy_sources from trade execution - Trade executor: respect trading:paused Redis flag in RiskManager - Portfolio sync: compute actual daily P&L from day-start snapshot - Portfolio API: cumulative P&L from first snapshot, read pause flag - Portfolio metrics: compute max drawdown and avg hold duration - Add strategy_sources field to TradeExecution schema - Add dev_mode config (TRADING_DEV_MODE) to bypass auth for local dev - Dashboard: VITE_DEV_MODE bypasses ProtectedRoute and 401 redirects - Vite proxy target configurable via VITE_API_TARGET - Add top-level README.md and remaining-work-plan.md - Update CLAUDE.md with correct counts and remove stale TODOs - 404 tests passing Made-with: Cursor
5.9 KiB
Trading Bot — Remaining Work Plan
Created: 2026-02-25 Status: Complete
Overview
This plan addresses all remaining TODOs, placeholders, and incomplete features in the trading bot. Tasks are ordered by dependency — earlier tasks unblock later ones.
Task 1: Learning engine — expand default weights to all 9 strategies
Status: [x] Complete
Files: services/learning_engine/main.py
Problem: _load_strategy_weights() defaults to 3 strategies (momentum, mean_reversion,
news_driven) but the signal generator uses all 9. When Redis has no cached weights, the
learning engine operates on a stale subset.
Fix: Change the default fallback to all 9 strategies with equal weights (~0.111 each),
matching scripts/seed_strategies.py.
Task 2: Portfolio sync — compute actual daily P&L
Status: [x] Complete
Files: services/api_gateway/tasks/portfolio_sync.py
Problem: daily_pnl is hardcoded to 0.0 in _sync_once() (line 60).
Fix: Before inserting the new snapshot, query the most recent prior snapshot for
today. Compute daily_pnl = current_total_value - day_start_total_value. If no prior
snapshot exists for today, the first snapshot's daily_pnl is 0.0.
Task 3: Portfolio API — cumulative P&L from first snapshot
Status: [x] Complete
Files: services/api_gateway/routes/portfolio.py
Problem: total_pnl on line 90 just returns latest.daily_pnl instead of the
cumulative P&L since inception.
Fix: Query the earliest PortfolioSnapshot and compute:
total_pnl = latest.total_value - earliest.total_valuetotal_pnl_pct = total_pnl / earliest.total_value * 100
Task 4: Portfolio API — read trading pause flag from Redis
Status: [x] Complete
Files: services/api_gateway/routes/portfolio.py
Problem: trading_active is hardcoded to True (line 92).
Fix: Read the trading:paused key from Redis (same key used by
services/api_gateway/routes/controls.py). Return trading_active = not paused.
Task 5: Portfolio metrics — compute max drawdown from snapshots
Status: [x] Complete
Files: services/api_gateway/routes/portfolio.py
Problem: max_drawdown is hardcoded to 0.0 (line 170).
Fix: Query all PortfolioSnapshot rows, compute the running peak and maximum
percentage drop from peak. Return as a positive decimal (e.g. 0.12 = 12% drawdown).
Task 6: Portfolio metrics — compute avg hold duration from trade outcomes
Status: [x] Complete
Files: services/api_gateway/routes/portfolio.py
Problem: avg_hold_duration is hardcoded to "0h" (line 172).
Fix: Query TradeOutcome rows, average the hold_duration_seconds column,
and format as a human-readable string (e.g. "4h 30m", "2d 6h").
Task 7: Trade executor — respect the trading pause flag
Status: [x] Complete
Files: services/trade_executor/risk_manager.py
Problem: The controls API sets/clears trading:paused in Redis, but the trade
executor's RiskManager.check_risk() never checks it. Pausing has no effect.
Fix: Accept a Redis client in RiskManager.__init__(). Add a check at the top of
check_risk() that reads trading:paused and rejects with "trading_paused" if set.
Wire the Redis client through from trade_executor/main.py.
Task 8: Learning engine — resolve placeholder strategy_id
Status: [x] Complete
Files: services/learning_engine/main.py
Problem: WeightAdjustment on line 207 uses strategy_id=UUID(int=0) as a
placeholder. This means weight history records can't be linked to the correct strategy.
Fix: On startup, load the strategies table into a name -> UUID lookup dict.
Use this lookup when building WeightAdjustment records. Fall back to UUID(int=0)
only if the strategy name isn't in the DB.
Task 9: Pass strategy_sources from signal through to learning engine
Status: [x] Complete
Files: services/trade_executor/main.py, services/learning_engine/main.py
Problem: TradeExecution doesn't carry strategy_sources. When the learning engine
stores the opening trade (line 136), strategy_sources is always []. This means credit
attribution (evaluator.attribute_credit()) has no strategies to reward.
Fix:
- Add
strategy_sources: list[str] = []to theTradeExecutionschema. - In the trade executor's
process_signal(), copysignal.strategy_sourcesinto the execution message. - In the learning engine, read
trade.strategy_sources(via the extended schema) and store them in the opening trade record.
Task 10: Update CLAUDE.md and add top-level README
Status: [x] Complete
Files: .claude/CLAUDE.md, README.md
Fix:
- Remove "No CI/CD pipeline yet" from Known Issues (Woodpecker exists).
- Update strategy count references (3 → 9) in Project Structure section.
- Update model count (14 → 16 tables).
- Create a concise top-level
README.mdwith: project description, architecture diagram (text), quickstart (docker compose up), dev setup, and test commands.
Execution Order
Tasks are grouped by dependency:
Group A (independent, do first):
- Task 1 (learning engine weights)
- Task 7 (trade executor pause flag)
- Task 9 (strategy_sources passthrough)
Group B (depends on nothing, can parallel with A):
- Task 2 (portfolio sync daily P&L)
- Task 8 (learning engine strategy_id lookup)
Group C (depends on Task 2):
- Task 3 (cumulative P&L API)
- Task 4 (trading_active flag API)
- Task 5 (max drawdown API)
- Task 6 (avg hold duration API)
Group D (after all code changes):
- Task 10 (documentation)
Test Strategy
After each task, run the relevant unit tests:
python -m pytest tests/ -v -m "not integration" --tb=short
Existing tests should continue to pass. New tests may be needed for:
- Task 7: risk manager pause check
- Task 9: strategy_sources in TradeExecution schema