feat: autonomous trading engine — full implementation

- Database migration 018 with 13 tables for trading engine state
- Trading engine service (services/trading/) with 12 pure computation modules:
  position sizer, stop-loss manager, reserve pool, circuit breaker,
  risk tier controller, correlation matrix, tax lots, trading window,
  gradual entry, notifications, micro-trading, backtester
- Core TradingEngine with pre-trade evaluation pipeline and integration wiring
- FastAPI HTTP service with 14 endpoints (health, config, decisions, metrics, backtest)
- Performance tracker with Sharpe ratio, drawdown, profit factor computation
- 194 Python tests (165 property-based + 29 integration)
- Frontend: 13 TanStack Query hooks, 7 dashboard panels, tabbed Trading Engine page
- Helm chart entry, network policy, nginx proxy, ingress for trading-engine
- Shared infrastructure: enums, Redis keys, TradingConfig in AppConfig
This commit is contained in:
Celes Renata
2026-04-15 16:12:22 +00:00
parent da86132f0c
commit 4ffde8cc06
58 changed files with 14168 additions and 1 deletions
@@ -0,0 +1 @@
{"specId": "3e745894-9abc-49ff-97cc-c921f436bb32", "workflowType": "requirements-first", "specType": "feature"}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,308 @@
# Requirements Document — Autonomous Trading Engine
## Introduction
This feature adds a fully autonomous trading engine to the Stonks Oracle platform. The engine consumes recommendations produced by the existing three-layer signal aggregation pipeline (company-specific, macro, competitive), applies confidence-based position sizing, reserve pool management, dynamic stop-loss/take-profit levels, and portfolio rebalancing logic, then executes trades through the existing Alpaca broker adapter.
The system is designed for a developer who wants to allocate $500 in paper trading capital and let the engine operate without manual intervention. Day-to-day decisions — what to buy, how much, when to exit — are made autonomously based on signal confidence, risk tier configuration, and portfolio state. The architecture supports switching from paper to live trading with minimal changes.
The engine builds on existing infrastructure rather than replacing it. The recommendation engine already produces buy/sell/hold/watch signals with confidence scores and position sizing guidance. The broker service already submits orders to Alpaca with idempotency and risk evaluation. The risk engine already enforces position limits, sector exposure, and daily loss controls. This feature layers autonomous decision-making, reserve pool management, adaptive market response, circuit breakers, and performance tracking on top of that foundation.
Key design principles:
- **Fail-safe**: circuit breakers halt trading on abnormal losses; reserve pool is untouchable by normal trading
- **Transparent**: every decision is traced from signal through sizing through execution
- **Incremental**: positions are built gradually, not all-at-once
- **Adaptive**: risk tier auto-adjusts based on recent performance and reserve pool health
## Glossary
- **Trading_Engine**: The autonomous service that polls for actionable recommendations, computes position sizes, manages the reserve pool, enforces circuit breakers, and submits orders to the Broker_Service.
- **Reserve_Pool**: A cash reserve automatically funded by siphoning a configurable percentage of realized profits. The Reserve_Pool is not available for normal trading and acts as a safety net for the portfolio.
- **Active_Pool**: The portion of portfolio capital available for trading, equal to total portfolio value minus the Reserve_Pool balance.
- **Risk_Tier**: A named configuration preset (conservative, moderate, aggressive) that controls confidence thresholds, position sizing multipliers, stop-loss widths, and take-profit targets.
- **Risk_Tier_Controller**: The component that evaluates recent performance metrics and Reserve_Pool size to automatically adjust the active Risk_Tier.
- **Circuit_Breaker**: A safety mechanism that halts all trading when portfolio losses exceed configurable thresholds within a time window, or when abnormal market conditions are detected.
- **Position_Sizer**: The component that computes the dollar amount and share quantity for a trade based on signal confidence, Risk_Tier parameters, Active_Pool size, correlation constraints, and sector exposure limits.
- **Stop_Loss_Manager**: The component that computes and maintains dynamic stop-loss and take-profit levels for each open position based on volatility and signal strength.
- **Portfolio_Rebalancer**: The component that periodically evaluates portfolio concentration and generates rebalancing orders when sector or single-stock exposure exceeds configurable limits.
- **Performance_Tracker**: The component that computes and persists real-time portfolio metrics including P&L, win/loss ratio, Sharpe ratio, max drawdown, and per-trade statistics.
- **Backtester**: The component that replays historical recommendation and market data to simulate how the trading strategy would have performed, producing the same metrics as the Performance_Tracker.
- **Portfolio_Heat**: The total risk across all open positions, computed as the sum of each position's value multiplied by its stop-loss distance percentage. Portfolio_Heat must not exceed a configurable threshold of the Active_Pool.
- **Correlation_Matrix**: A precomputed matrix of price correlation coefficients between tracked companies, used to prevent over-concentration in correlated positions.
- **Earnings_Calendar**: A schedule of upcoming earnings report dates for tracked companies, used to reduce position sizes before earnings and adjust after results.
- **Trading_Window**: The allowed time range for order submission, excluding the first and last 15 minutes of market hours to avoid high-volatility open/close periods.
- **Gradual_Entry**: The strategy of scaling into a position over multiple smaller orders rather than a single large order, reducing market impact and allowing the engine to abort if conditions change.
- **Tax_Lot**: A record of the purchase date, quantity, and cost basis for a specific acquisition of shares, used for tax-loss harvesting awareness and wash sale detection.
- **Notification_Service**: The component that sends alerts to the operator via SMS (AWS SNS) and email (Gmail API) for critical events such as circuit breaker triggers, risk tier changes, large trades, and daily performance summaries.
- **Micro_Trading_Mode**: An optional operating mode where the Trading_Engine evaluates and acts on intraday and short-window trend signals (5-minute and 15-minute intervals) in addition to the standard daily/weekly recommendation cycle, enabling faster position turnover for short-term opportunities.
- **Broker_Service**: The existing service (services/adapters/broker_service.py) that processes order requests through risk evaluation and submits them to Alpaca.
- **Recommendation_Engine**: The existing service (services/recommendation/) that produces buy/sell/hold/watch signals with confidence scores from trend data.
- **Aggregation_Engine**: The existing service (services/aggregation/) that computes trend summaries from all three signal layers.
## Requirements
### Requirement 1: Autonomous Decision Loop
**User Story:** As a developer with $500 in paper trading capital, I want the system to automatically evaluate recommendations and execute trades without my intervention, so that I can let it run and check results periodically.
#### Acceptance Criteria
1. THE Trading_Engine SHALL run a continuous decision loop that polls for new actionable recommendations (action = buy or sell, mode = paper_eligible or live_eligible) at a configurable interval (default: 60 seconds).
2. WHEN the Trading_Engine finds an actionable recommendation, THE Trading_Engine SHALL evaluate the recommendation against the current portfolio state, Risk_Tier parameters, circuit breaker status, and Trading_Window constraints before deciding whether to act.
3. WHEN the Trading_Engine decides to act on a recommendation, THE Trading_Engine SHALL compute the position size via the Position_Sizer, generate an order job, and submit it to the existing Broker_Service queue for execution.
4. WHEN the Trading_Engine decides not to act on a recommendation, THE Trading_Engine SHALL persist a decision record with the skip reason (circuit breaker active, outside Trading_Window, insufficient confidence, position limit reached, or insufficient Active_Pool funds).
5. THE Trading_Engine SHALL process each recommendation at most once, using the recommendation ID as a deduplication key persisted in Redis with a configurable TTL (default: 24 hours).
6. WHEN the Trading_Engine starts, THE Trading_Engine SHALL load the current portfolio state from the Broker_Service (positions, account balance) and the active Risk_Tier configuration from PostgreSQL before entering the decision loop.
7. THE Trading_Engine SHALL expose a health endpoint at `/health` and a readiness endpoint at `/ready` that reports whether the engine has successfully loaded portfolio state and is actively polling.
### Requirement 2: Confidence-Based Position Sizing
**User Story:** As a developer, I want position sizes to scale with signal confidence so that high-confidence signals get larger allocations and the system never risks too much on a single trade.
#### Acceptance Criteria
1. WHEN the Position_Sizer computes a trade size, THE Position_Sizer SHALL scale the allocation as a percentage of the Active_Pool using the formula: `base_allocation_pct * (confidence / confidence_threshold) * risk_tier_multiplier`, clamped to the Risk_Tier's max_position_pct.
2. WHEN the signal confidence is below the Risk_Tier's minimum confidence threshold, THE Position_Sizer SHALL return a zero allocation and the Trading_Engine SHALL skip the trade.
3. THE Position_Sizer SHALL enforce that no single position exceeds a configurable maximum percentage of the Active_Pool (default: 10% for moderate tier).
4. THE Position_Sizer SHALL enforce that the total dollar value of any single position does not exceed a configurable absolute cap (default: $50 for a $500 portfolio, scaling with portfolio size).
5. WHEN computing position size, THE Position_Sizer SHALL check the Correlation_Matrix and reduce the allocation if the portfolio already holds positions with a correlation coefficient above 0.7 to the candidate stock.
6. WHEN computing position size, THE Position_Sizer SHALL check sector exposure and reduce the allocation if adding the position would cause the sector to exceed the configurable sector exposure limit (default: 30% of Active_Pool).
7. THE Position_Sizer SHALL round the computed share quantity down to whole shares and reject orders where the resulting quantity is zero.
### Requirement 3: Reserve Pool Management
**User Story:** As a developer, I want a portion of profits automatically set aside into a reserve that normal trading cannot touch, so that the portfolio has a safety net that grows over time.
#### Acceptance Criteria
1. WHEN a position is closed with a realized profit, THE Trading_Engine SHALL transfer a configurable percentage of the profit (default: 20%) into the Reserve_Pool.
2. THE Trading_Engine SHALL persist the Reserve_Pool balance in PostgreSQL and update it on every profit siphon event, with a full audit trail of deposits and withdrawals.
3. THE Trading_Engine SHALL compute the Active_Pool as: `total_portfolio_value - reserve_pool_balance`, and all position sizing and risk calculations SHALL use the Active_Pool rather than the total portfolio value.
4. WHEN the Reserve_Pool balance exceeds a configurable high-water mark percentage of the total portfolio (default: 30%), THE Risk_Tier_Controller SHALL consider this a signal to increase risk tolerance (shift toward a more aggressive tier).
5. WHEN the Active_Pool drops below a configurable minimum threshold (default: $100), THE Trading_Engine SHALL halt new position entries and only allow position exits until the Active_Pool recovers.
6. IF the portfolio experiences a drawdown exceeding a configurable emergency threshold (default: 40% of initial capital), THEN THE Trading_Engine SHALL liquidate the Reserve_Pool into the Active_Pool to provide emergency capital, log the event, and shift to the conservative Risk_Tier.
7. THE Reserve_Pool balance SHALL be visible on the dashboard and included in all portfolio summary API responses.
### Requirement 4: Dynamic Stop-Loss and Take-Profit
**User Story:** As a developer, I want every position to have automatic exit levels that adapt to market volatility and signal strength, so that losses are cut and profits are captured without manual monitoring.
#### Acceptance Criteria
1. WHEN the Trading_Engine opens a new position, THE Stop_Loss_Manager SHALL compute an initial stop-loss price based on the stock's recent volatility (ATR — Average True Range over 14 periods) and the Risk_Tier's stop-loss multiplier: `entry_price - (ATR * stop_loss_atr_multiplier)` for long positions.
2. WHEN the Trading_Engine opens a new position, THE Stop_Loss_Manager SHALL compute an initial take-profit price using the Risk_Tier's reward-to-risk ratio: `entry_price + (stop_distance * reward_risk_ratio)`.
3. WHILE a position is open, THE Stop_Loss_Manager SHALL re-evaluate stop-loss and take-profit levels at a configurable interval (default: every 5 minutes during market hours) and adjust them if volatility or signal conditions have materially changed.
4. WHEN a position's current price crosses the stop-loss level, THE Trading_Engine SHALL submit a market sell order to the Broker_Service immediately, without waiting for the next decision loop cycle.
5. WHEN a position's current price crosses the take-profit level, THE Trading_Engine SHALL submit a market sell order to the Broker_Service immediately.
6. WHEN a position has moved favorably by more than 50% of the take-profit distance, THE Stop_Loss_Manager SHALL implement a trailing stop by moving the stop-loss to breakeven (entry price) to lock in a risk-free position.
7. THE Stop_Loss_Manager SHALL persist all stop-loss and take-profit levels and adjustments in PostgreSQL with timestamps for audit trail purposes.
8. IF the Trading_Engine cannot fetch current price data for a position, THEN THE Trading_Engine SHALL use the last known price and log a warning, and if price data is unavailable for more than 15 minutes during market hours, THE Trading_Engine SHALL close the position as a safety measure.
### Requirement 5: Risk Tier Configuration and Auto-Adjustment
**User Story:** As a developer, I want configurable risk tiers that auto-adjust based on how the system is performing, so that the engine takes less risk after losses and more risk when it is doing well.
#### Acceptance Criteria
1. THE Trading_Engine SHALL support three named Risk_Tiers with the following default parameters:
- **Conservative**: min_confidence = 0.75, max_position_pct = 0.05, stop_loss_atr_multiplier = 1.5, reward_risk_ratio = 2.0, max_sector_pct = 0.20, max_portfolio_heat = 0.10
- **Moderate**: min_confidence = 0.55, max_position_pct = 0.10, stop_loss_atr_multiplier = 2.0, reward_risk_ratio = 1.5, max_sector_pct = 0.30, max_portfolio_heat = 0.20
- **Aggressive**: min_confidence = 0.40, max_position_pct = 0.15, stop_loss_atr_multiplier = 2.5, reward_risk_ratio = 1.2, max_sector_pct = 0.40, max_portfolio_heat = 0.30
2. THE Risk_Tier_Controller SHALL evaluate the active Risk_Tier at a configurable interval (default: daily at market close) based on: trailing 30-day win rate, trailing 30-day Sharpe ratio, current drawdown from peak portfolio value, and Reserve_Pool size relative to total portfolio.
3. WHEN the trailing 30-day win rate drops below 40% or the current drawdown exceeds 15%, THE Risk_Tier_Controller SHALL downgrade the Risk_Tier by one level (aggressive → moderate, moderate → conservative).
4. WHEN the trailing 30-day win rate exceeds 55% and the Reserve_Pool exceeds 20% of total portfolio value and the current drawdown is below 5%, THE Risk_Tier_Controller SHALL upgrade the Risk_Tier by one level (conservative → moderate, moderate → aggressive).
5. WHEN the Risk_Tier_Controller changes the active Risk_Tier, THE Risk_Tier_Controller SHALL persist the change in PostgreSQL with the previous tier, new tier, and the metrics that triggered the change, and log the event.
6. THE Risk_Tier configuration SHALL be stored in PostgreSQL and editable through the API, allowing operators to override the auto-adjustment and manually set a tier.
### Requirement 6: Circuit Breakers
**User Story:** As a developer, I want automatic safety stops that halt all trading if things go badly wrong, so that a bad day or a flash crash does not wipe out the portfolio.
#### Acceptance Criteria
1. WHEN the portfolio value drops by more than a configurable daily loss percentage (default: 5%) within a single trading day, THE Circuit_Breaker SHALL halt all new order submissions and log the event with the loss amount and percentage.
2. WHEN a single position loses more than a configurable percentage of its entry value (default: 15%), THE Circuit_Breaker SHALL immediately close the position via a market sell order and prevent the Trading_Engine from re-entering the same ticker for a configurable cooldown period (default: 48 hours).
3. WHEN the Circuit_Breaker detects extreme market volatility (VIX equivalent proxy exceeding a configurable threshold, or more than 3 positions hitting stop-losses within a 30-minute window), THE Circuit_Breaker SHALL pause all trading for a configurable duration (default: 2 hours) and log the trigger condition.
4. WHEN a Circuit_Breaker is triggered, THE Trading_Engine SHALL send a notification to a configurable alert channel (Redis pub/sub event) and record the circuit breaker event in PostgreSQL with the trigger type, threshold, actual value, and timestamp.
5. WHEN a Circuit_Breaker cooldown expires, THE Trading_Engine SHALL resume normal operation automatically and log the resumption.
6. THE Circuit_Breaker status (active/inactive, trigger reason, cooldown remaining) SHALL be queryable through the API and visible on the dashboard.
### Requirement 7: Adaptive Market Response
**User Story:** As a developer, I want the system to react to sudden market changes in real-time rather than waiting for the next scheduled cycle, so that positions are protected during volatile events.
#### Acceptance Criteria
1. WHEN a new high-severity macro event (severity = high or critical) is classified by the existing macro classification pipeline, THE Trading_Engine SHALL trigger an immediate portfolio re-evaluation cycle outside the normal polling interval.
2. WHEN an immediate re-evaluation is triggered, THE Trading_Engine SHALL re-check all open positions against updated stop-loss levels, tighten stops by a configurable factor (default: 0.5x normal ATR multiplier) for the duration of the event, and evaluate whether any positions should be closed.
3. WHEN a tracked stock's price moves more than a configurable percentage (default: 5%) within a 15-minute window, THE Trading_Engine SHALL trigger an immediate re-evaluation for that specific position.
4. WHILE a high-severity macro event is active (within its estimated_duration window), THE Trading_Engine SHALL increase the polling frequency for stop-loss checks from the default interval to a configurable fast interval (default: every 60 seconds).
5. WHEN the Trading_Engine detects that multiple positions are simultaneously declining (more than 50% of open positions with negative unrealized P&L exceeding 2%), THE Trading_Engine SHALL reduce new position entries to zero and focus exclusively on managing existing positions until conditions stabilize.
### Requirement 8: Portfolio Rebalancing
**User Story:** As a developer, I want the system to periodically rebalance the portfolio to avoid over-concentration in any single stock or sector, so that diversification is maintained automatically.
#### Acceptance Criteria
1. THE Portfolio_Rebalancer SHALL run at a configurable interval (default: weekly, at market open on Monday) and evaluate the current portfolio against sector exposure limits and single-stock concentration limits defined by the active Risk_Tier.
2. WHEN a single stock position exceeds the Risk_Tier's max_position_pct of the Active_Pool, THE Portfolio_Rebalancer SHALL generate a partial sell order to bring the position back within limits.
3. WHEN a sector's total exposure exceeds the Risk_Tier's max_sector_pct of the Active_Pool, THE Portfolio_Rebalancer SHALL generate sell orders for the lowest-confidence positions in that sector to bring exposure within limits.
4. THE Portfolio_Rebalancer SHALL enforce a configurable maximum number of open positions (default: 10) and prevent new entries when the limit is reached, prioritizing higher-confidence opportunities over existing lower-confidence positions.
5. WHEN the Portfolio_Rebalancer generates rebalancing orders, THE Portfolio_Rebalancer SHALL submit them through the normal Broker_Service queue with a `rebalance` tag in the decision trace, and persist the rebalancing rationale in PostgreSQL.
6. THE Portfolio_Rebalancer SHALL respect the Trading_Window constraints and Circuit_Breaker status — rebalancing orders are not submitted outside market hours or when a circuit breaker is active.
### Requirement 9: Sector Diversification and Correlation Awareness
**User Story:** As a developer, I want the system to enforce diversification rules so that the portfolio is not over-exposed to a single sector or to stocks that move together.
#### Acceptance Criteria
1. THE Position_Sizer SHALL maintain a Correlation_Matrix computed from the trailing 90-day price history of all tracked companies, refreshed daily.
2. WHEN the Position_Sizer evaluates a new trade, THE Position_Sizer SHALL compute the weighted average correlation between the candidate stock and all existing portfolio positions, and reduce the allocation proportionally when the average correlation exceeds 0.5.
3. WHEN the weighted average correlation between a candidate stock and the existing portfolio exceeds 0.8, THE Position_Sizer SHALL reject the trade entirely and log the rejection reason.
4. THE Position_Sizer SHALL track sector exposure as the sum of market values of all positions in each sector, using the sector field from the companies table.
5. WHEN the portfolio holds positions in fewer than 3 sectors, THE Position_Sizer SHALL apply a diversification bonus (1.2x allocation multiplier) to trades in under-represented sectors to encourage diversification.
### Requirement 10: Earnings Calendar Awareness
**User Story:** As a developer, I want the system to reduce risk around earnings announcements because earnings are high-volatility events that can move stocks unpredictably.
#### Acceptance Criteria
1. THE Trading_Engine SHALL maintain an Earnings_Calendar table in PostgreSQL containing the next known earnings date for each tracked company, populated from market data or manual entry.
2. WHEN a tracked company's earnings date is within a configurable pre-earnings window (default: 3 trading days), THE Position_Sizer SHALL reduce the maximum position size for that company by 50% and THE Stop_Loss_Manager SHALL tighten stop-losses by a configurable factor (default: 0.7x normal ATR multiplier).
3. WHEN a tracked company's earnings date is within 1 trading day, THE Trading_Engine SHALL not open new positions in that company and SHALL flag existing positions for manual review via a dashboard alert.
4. WHEN a tracked company reports earnings and the result is reflected in the next recommendation cycle, THE Trading_Engine SHALL resume normal position sizing for that company after a configurable post-earnings cooldown (default: 1 trading day).
### Requirement 11: Trading Window and Gradual Entry
**User Story:** As a developer, I want the system to avoid trading during the volatile open and close periods and to scale into positions gradually rather than all at once.
#### Acceptance Criteria
1. THE Trading_Engine SHALL only submit new orders during the Trading_Window: market hours excluding the first 15 minutes after open (9:45 AM ET) and the last 15 minutes before close (3:45 PM ET).
2. WHEN the Trading_Engine is outside the Trading_Window, THE Trading_Engine SHALL queue pending decisions and execute them when the window reopens, unless the recommendation has expired or conditions have changed.
3. WHEN the Position_Sizer computes a position size exceeding a configurable gradual entry threshold (default: $30 or 5% of Active_Pool, whichever is smaller), THE Trading_Engine SHALL split the order into multiple tranches (default: 3 tranches) submitted at configurable intervals (default: 15 minutes apart).
4. WHEN executing a Gradual_Entry, THE Trading_Engine SHALL re-evaluate the recommendation confidence and price conditions before submitting each subsequent tranche, and cancel remaining tranches if conditions have deteriorated.
5. WHEN executing a Gradual_Entry, THE Trading_Engine SHALL link all tranches to the same parent decision record so that the full entry sequence is traceable.
### Requirement 12: Tax-Loss Harvesting Awareness
**User Story:** As a developer, I want the system to track cost basis and flag wash sale risks so that I have visibility into tax implications even during paper trading.
#### Acceptance Criteria
1. THE Trading_Engine SHALL maintain Tax_Lot records in PostgreSQL for every position entry, recording the acquisition date, quantity, cost basis per share, and current status (open, closed, washed).
2. WHEN the Trading_Engine closes a position at a loss, THE Trading_Engine SHALL check whether the same ticker was purchased within the preceding 30 days or will be purchased within the following 30 days (based on pending recommendations), and flag the trade as a potential wash sale.
3. WHEN a potential wash sale is detected, THE Trading_Engine SHALL log the event, tag the Tax_Lot record, and include the wash sale flag in the trade's decision trace.
4. THE Performance_Tracker SHALL compute realized gains and losses using the Tax_Lot cost basis (FIFO method) and include a tax-adjusted P&L alongside the raw P&L in portfolio metrics.
### Requirement 13: Portfolio Heat Management
**User Story:** As a developer, I want the system to limit the total risk across all positions so that even if every stop-loss is hit simultaneously, the portfolio loss is bounded.
#### Acceptance Criteria
1. THE Position_Sizer SHALL compute Portfolio_Heat as the sum across all open positions of: `position_value * (entry_price - stop_loss_price) / entry_price`.
2. WHEN the current Portfolio_Heat exceeds the Risk_Tier's max_portfolio_heat percentage of the Active_Pool, THE Position_Sizer SHALL reject new position entries until existing positions are closed or stop-losses are tightened to reduce heat.
3. WHEN the Portfolio_Heat exceeds 80% of the max_portfolio_heat threshold, THE Stop_Loss_Manager SHALL proactively tighten stop-losses on the lowest-confidence positions to reduce overall heat.
4. THE Portfolio_Heat value SHALL be computed and persisted at every decision loop iteration and be queryable through the API and visible on the dashboard.
### Requirement 14: Performance Tracking and Metrics
**User Story:** As a developer, I want real-time performance metrics and dashboards so that I can see how the autonomous engine is performing at a glance.
#### Acceptance Criteria
1. THE Performance_Tracker SHALL compute and persist the following metrics at a configurable interval (default: every 5 minutes during market hours): total portfolio value, Active_Pool value, Reserve_Pool balance, unrealized P&L, realized P&L, daily P&L, win count, loss count, win rate, average win amount, average loss amount, profit factor, Sharpe ratio (annualized, using daily returns over trailing 30 days), max drawdown (from peak portfolio value), and current drawdown percentage.
2. THE Performance_Tracker SHALL compute per-trade metrics for every closed position: entry price, exit price, hold duration, P&L amount, P&L percentage, and the recommendation ID that triggered the trade.
3. THE Performance_Tracker SHALL persist daily portfolio snapshots in PostgreSQL containing end-of-day portfolio value, daily return, cumulative return, and all positions with their unrealized P&L.
4. THE Dashboard SHALL display a trading engine overview panel showing: current Risk_Tier, Circuit_Breaker status, Active_Pool and Reserve_Pool balances, Portfolio_Heat gauge, and the last 24 hours of P&L.
5. THE Dashboard SHALL display a portfolio composition panel showing: current positions with entry price, current price, unrealized P&L, stop-loss level, take-profit level, and sector allocation pie chart.
6. THE Dashboard SHALL display a trade history panel showing: completed trades with entry/exit prices, P&L, hold duration, and the recommendation thesis that triggered each trade.
7. THE Dashboard SHALL display a performance chart panel showing: cumulative P&L over time, daily returns bar chart, and drawdown chart, using the existing Recharts library.
### Requirement 15: Backtesting
**User Story:** As a developer, I want to backtest the trading strategy against historical data already in the database before risking real money, so that I can validate the approach.
#### Acceptance Criteria
1. THE Backtester SHALL accept a date range, initial capital amount, and Risk_Tier configuration as inputs, and replay historical recommendations from the recommendations table within that date range.
2. WHEN replaying historical recommendations, THE Backtester SHALL simulate the Trading_Engine's decision logic (position sizing, stop-loss/take-profit, circuit breakers, reserve pool, rebalancing) using historical price data from the market data tables.
3. THE Backtester SHALL produce the same set of metrics as the Performance_Tracker (total return, Sharpe ratio, max drawdown, win rate, profit factor, trade count) for the simulated period.
4. THE Backtester SHALL persist backtest results in PostgreSQL with a unique backtest_id, the configuration used, and the full trade log, so that results can be compared across different configurations.
5. THE Backtester SHALL be invocable through the API at `POST /api/trading/backtest` with the date range, capital, and risk tier parameters, and return the backtest_id for result retrieval.
6. THE Dashboard SHALL display a backtesting panel where the operator can configure and launch backtests, and view results including the equity curve, trade log, and summary metrics.
### Requirement 16: Trading Engine Configuration and Control
**User Story:** As a developer, I want to configure, start, stop, and monitor the trading engine through the API and dashboard, so that I have full control over autonomous operation.
#### Acceptance Criteria
1. THE Trading_Engine SHALL be configurable through a trading_engine_config table in PostgreSQL containing: enabled (boolean), risk_tier (conservative/moderate/aggressive), reserve_siphon_pct, polling_interval_seconds, gradual_entry_tranches, and all circuit breaker thresholds.
2. THE API SHALL expose a `GET /api/trading/status` endpoint returning the current engine state: enabled/disabled, active Risk_Tier, Circuit_Breaker status, Active_Pool balance, Reserve_Pool balance, Portfolio_Heat, open position count, and last decision timestamp.
3. THE API SHALL expose a `PUT /api/trading/config` endpoint allowing operators to update engine configuration, with changes taking effect on the next decision loop iteration.
4. THE API SHALL expose a `POST /api/trading/pause` and `POST /api/trading/resume` endpoint to temporarily halt and resume autonomous trading without changing the enabled configuration.
5. THE Dashboard SHALL display a trading engine control panel with start/pause/resume controls, Risk_Tier selector, and real-time engine status indicators.
6. WHEN the Trading_Engine configuration changes, THE Trading_Engine SHALL record an audit event with the previous configuration, new configuration, and the source of the change (operator or auto-adjustment).
### Requirement 17: Decision Audit Trail
**User Story:** As a developer, I want a complete audit trail of every decision the trading engine makes, so that I can understand why it took or skipped every trade.
#### Acceptance Criteria
1. WHEN the Trading_Engine evaluates a recommendation, THE Trading_Engine SHALL persist a trading_decision record containing: recommendation_id, decision (act or skip), skip_reason (if skipped), computed_position_size, risk_tier_at_decision, portfolio_heat_at_decision, active_pool_at_decision, reserve_pool_at_decision, circuit_breaker_status, correlation_check_result, sector_exposure_check_result, earnings_proximity_flag, and timestamp.
2. WHEN the Trading_Engine submits an order, THE Trading_Engine SHALL include the trading_decision_id in the order job payload so that the existing Broker_Service decision_trace links back to the autonomous engine's reasoning.
3. THE API SHALL expose a `GET /api/trading/decisions` endpoint returning recent trading decisions with pagination, filterable by ticker, decision type (act/skip), and date range.
4. THE Dashboard SHALL display a decision log panel showing recent decisions with expandable detail showing the full reasoning chain from recommendation through position sizing through execution.
### Requirement 18: Trading Engine Storage
**User Story:** As a data engineer, I want all trading engine state persisted in PostgreSQL with appropriate schemas, so that the engine can recover from restarts and data is available for analysis.
#### Acceptance Criteria
1. THE System SHALL create a database migration adding tables for: trading_engine_config, reserve_pool_ledger, risk_tier_history, circuit_breaker_events, trading_decisions, position_stop_levels, portfolio_snapshots, backtest_runs, backtest_trades, tax_lots, earnings_calendar, and correlation_matrix_cache.
2. THE reserve_pool_ledger table SHALL record every deposit and withdrawal with amount, balance_after, trigger (profit_siphon, emergency_liquidation, manual_adjustment), and timestamp.
3. THE position_stop_levels table SHALL record every stop-loss and take-profit level and adjustment for every open position, with the computation inputs (ATR value, multiplier, signal confidence) for reproducibility.
4. THE portfolio_snapshots table SHALL store daily end-of-day snapshots with portfolio value, active pool, reserve pool, positions JSON, and all computed metrics.
5. WHEN the Trading_Engine restarts, THE Trading_Engine SHALL reconstruct its state from PostgreSQL (open positions, reserve pool balance, active risk tier, circuit breaker status) and resume operation without data loss.
### Requirement 19: Notification System
**User Story:** As a developer who is not watching the dashboard all day, I want the system to send me text messages and emails for critical events, so that I know immediately when something important happens.
#### Acceptance Criteria
1. THE Notification_Service SHALL support two delivery channels: SMS via AWS SNS and email via the Gmail API, each independently configurable and toggleable.
2. THE Notification_Service SHALL send an immediate notification WHEN any of the following events occur: a Circuit_Breaker is triggered, a Circuit_Breaker cooldown expires and trading resumes, the Risk_Tier_Controller changes the active Risk_Tier, the Reserve_Pool receives an emergency liquidation, or a single trade P&L exceeds a configurable threshold (default: 5% of Active_Pool).
3. THE Notification_Service SHALL send a daily performance summary notification at a configurable time (default: 30 minutes after market close) containing: daily P&L, total portfolio value, Active_Pool and Reserve_Pool balances, number of trades executed, current Risk_Tier, and any open circuit breaker status.
4. THE Notification_Service SHALL send a weekly performance digest containing: weekly P&L, win/loss count, Sharpe ratio, max drawdown, top winning and losing trades, and Risk_Tier changes during the week.
5. WHEN configuring SMS notifications, THE Notification_Service SHALL use AWS SNS with a configurable SNS topic ARN and phone number, authenticating via AWS credentials (access key and secret key) stored as environment variables or Kubernetes secrets.
6. WHEN configuring email notifications, THE Notification_Service SHALL use the Gmail API with OAuth2 credentials (client ID, client secret, refresh token) stored as environment variables or Kubernetes secrets, sending from a configurable sender address to a configurable recipient address.
7. THE Notification_Service SHALL implement rate limiting (default: maximum 10 SMS and 20 emails per hour) to prevent notification storms during volatile market conditions.
8. THE Notification_Service SHALL persist all sent notifications in PostgreSQL with the channel, event type, message content, delivery status, and timestamp for audit purposes.
9. THE API SHALL expose a `GET /api/trading/notifications/config` and `PUT /api/trading/notifications/config` endpoint for viewing and updating notification preferences (channels enabled, phone number, email address, event types, rate limits).
10. THE Dashboard SHALL display a notification preferences panel where the operator can configure which events trigger notifications, select delivery channels, and view recent notification history.
11. IF a notification delivery fails (SNS publish error or Gmail API error), THEN THE Notification_Service SHALL retry up to 3 times with exponential backoff and log the failure, but SHALL NOT block or delay trading operations.
### Requirement 20: Micro-Trading Mode
**User Story:** As a developer, I want the option to enable faster trading cycles that evaluate short-term signals on 5-minute and 15-minute intervals, so that the engine can capture intraday opportunities without being limited to daily recommendation cycles.
#### Acceptance Criteria
1. THE Trading_Engine SHALL support an optional Micro_Trading_Mode that, when enabled, polls for intraday trend window signals (intraday and 1d windows) at a configurable fast interval (default: every 5 minutes during market hours) in addition to the standard recommendation polling.
2. WHEN Micro_Trading_Mode is enabled, THE Trading_Engine SHALL evaluate intraday trend summaries from the Aggregation_Engine and generate micro-trade decisions for signals that meet the active Risk_Tier's confidence threshold.
3. WHEN Micro_Trading_Mode generates a trade, THE Position_Sizer SHALL apply a configurable micro-trade allocation cap (default: 3% of Active_Pool per micro-trade) that is lower than the standard position sizing cap, limiting the risk of any single short-term trade.
4. WHEN Micro_Trading_Mode is enabled, THE Trading_Engine SHALL enforce a configurable maximum number of micro-trades per day (default: 10) to prevent excessive trading and commission accumulation.
5. WHEN Micro_Trading_Mode is enabled, THE Stop_Loss_Manager SHALL use tighter stop-loss and take-profit levels for micro-trade positions: stop-loss at 1.0x ATR (instead of the standard tier multiplier) and take-profit at 1.5x the stop distance.
6. WHEN a micro-trade position has been open for longer than a configurable maximum hold duration (default: 2 hours), THE Trading_Engine SHALL close the position at market price regardless of P&L, to prevent short-term trades from becoming unintended long-term holds.
7. THE Trading_Engine SHALL track micro-trade performance metrics separately from standard trade metrics, including: micro-trade win rate, average micro-trade P&L, micro-trade count per day, and micro-trade contribution to total portfolio P&L.
8. THE Micro_Trading_Mode SHALL be toggleable through the trading_engine_config table and the API, independently of the main Trading_Engine enabled state.
9. THE Dashboard SHALL display a micro-trading panel showing: micro-trade mode status (enabled/disabled), today's micro-trade count and P&L, active micro-trade positions, and micro-trade performance metrics over the trailing 7 days.
10. WHEN Micro_Trading_Mode is enabled, THE Trading_Engine SHALL respect all existing constraints (Trading_Window, Circuit_Breakers, Portfolio_Heat limits, correlation checks) and apply them to micro-trades with the same rigor as standard trades.
@@ -0,0 +1,656 @@
# Implementation Plan: Autonomous Trading Engine
## Overview
This plan implements a fully autonomous trading engine as a new service (`services/trading/`) that consumes recommendations from the existing three-layer signal aggregation pipeline, applies confidence-based position sizing with reserve pool management, enforces dynamic stop-loss/take-profit levels, manages circuit breakers, and submits orders through the existing Broker Service queue. The implementation extends existing services (broker_service, recommendation, risk engine, query API, dashboard) without replacing them. Tasks are ordered so each step builds on the previous, with property-based tests validating core computation logic early.
## Tasks
- [x] 1. Database migration and shared infrastructure
- [x] 1.1 Create PostgreSQL migration `infra/migrations/018_autonomous_trading_engine.sql`
- Add `trading_engine_config` table with all configuration fields (enabled, paused, risk_tier, reserve_siphon_pct, polling intervals, gradual entry params, circuit breaker thresholds, active pool minimum, emergency drawdown threshold, correlation thresholds, earnings windows, micro-trading params, notification settings, timestamps)
- Add `reserve_pool_ledger` table with amount, balance_after, trigger_type (profit_siphon, emergency_liquidation, manual_adjustment, initial), reference_id, notes, created_at; index on created_at DESC
- Add `risk_tier_history` table with previous_tier, new_tier, trigger_source, trigger_metrics JSONB, created_at; index on created_at DESC
- Add `circuit_breaker_events` table with trigger_type (daily_loss, single_position, volatility, manual), threshold_value, actual_value, ticker, cooldown_expires, resolved_at, created_at; partial index on active (unresolved) events
- Add `trading_decisions` table with recommendation_id FK, decision, skip_reason, ticker, computed_position_size, computed_share_quantity, risk_tier_at_decision, portfolio_heat_at_decision, active_pool_at_decision, reserve_pool_at_decision, circuit_breaker_status, correlation_check_result JSONB, sector_exposure_check_result JSONB, earnings_proximity_flag, is_micro_trade, decision_trace JSONB, created_at; indexes on ticker, recommendation_id, decision
- Add `position_stop_levels` table with ticker, entry_price, stop_loss_price, take_profit_price, trailing_stop_active, atr_value, atr_multiplier, reward_risk_ratio, signal_confidence, is_micro_trade, active, timestamps; partial index on active positions
- Add `portfolio_snapshots` table with snapshot_date (UNIQUE), portfolio_value, active_pool, reserve_pool, daily_return, cumulative_return, unrealized_pnl, realized_pnl, win/loss counts, win_rate, sharpe_ratio, max_drawdown, current_drawdown_pct, portfolio_heat, risk_tier, positions JSONB, metrics JSONB, created_at; index on snapshot_date DESC
- Add `backtest_runs` table with start_date, end_date, initial_capital, risk_tier, config JSONB, result metrics, equity_curve JSONB, status, completed_at, created_at
- Add `backtest_trades` table with backtest_id FK (CASCADE), ticker, side, entry/exit prices, quantity, pnl, dates, hold_duration_days, recommendation_id; index on backtest_id
- Add `tax_lots` table with ticker, quantity, cost_basis_per_share, acquisition_date, status (open/closed/washed), closed_date, exit_price, realized_pnl, wash_sale_flag, wash_sale_details, order_id FK; indexes on ticker and open status
- Add `earnings_calendar` table with ticker, earnings_date, source, confirmed, timestamps; UNIQUE on (ticker, earnings_date); indexes on date and ticker
- Add `correlation_matrix_cache` table with ticker_a, ticker_b, correlation_coefficient, lookback_days, computed_at; UNIQUE on (ticker_a, ticker_b)
- Add `notifications` table with channel (sms/email), event_type, message, delivery_status (pending/delivered/failed/rate_limited), retry_count, error_message, created_at, delivered_at; indexes on created_at and event_type
- Insert default trading_engine_config row with moderate tier defaults
- Insert initial reserve_pool_ledger entry with balance 0.0 and trigger_type 'initial'
- _Requirements: 18.1, 18.2, 18.3, 18.4, 16.1_
- [x] 1.2 Add new Pydantic schemas and enums to `services/shared/schemas.py`
- Add `TradingDecisionType` enum (act, skip)
- Add `CircuitBreakerTriggerType` enum (daily_loss, single_position, volatility, manual)
- Add `ReservePoolTriggerType` enum (profit_siphon, emergency_liquidation, manual_adjustment, initial)
- Add `NotificationChannel` enum (sms, email)
- Add `RiskTierName` enum (conservative, moderate, aggressive)
- _Requirements: 5.1, 6.1, 3.1, 19.1_
- [x] 1.3 Add trading-related Redis keys to `services/shared/redis_keys.py`
- Add `QUEUE_TRADING_DECISIONS = "trading_decisions"` queue name
- Add `TRADING_DEDUPE_PREFIX` for recommendation deduplication (`stonks:dedupe:trading`)
- Add `TRADING_CB_PREFIX` for circuit breaker state (`stonks:trading:circuit_breaker`)
- Add `TRADING_NOTIFICATION_RATE` for notification rate limiting (`stonks:trading:notification_rate`)
- _Requirements: 1.5, 6.4, 19.7_
- [x] 1.4 Add `TradingConfig` dataclass to `services/shared/config.py`
- Add `TradingConfig` with fields: enabled, risk_tier, reserve_siphon_pct, polling_interval_seconds, stop_loss_check_interval_seconds, fast_stop_loss_interval_seconds, gradual_entry_tranches, gradual_entry_threshold_dollars, absolute_position_cap, active_pool_minimum, emergency_drawdown_threshold_pct, reserve_high_water_pct, micro_trading_enabled, micro_trading_interval_seconds, micro_trading_allocation_cap_pct, micro_trading_max_daily, micro_trading_max_hold_minutes, sns_topic_arn, sns_phone_number, gmail_sender, gmail_recipient
- Add `trading: TradingConfig` field to `AppConfig` with env var loading in `load_config()`
- _Requirements: 16.1, 20.1, 19.5, 19.6_
- [x] 2. Checkpoint — Ensure migration and shared schemas are consistent
- Ensure all tests pass, ask the user if questions arise.
- [x] 3. Core data models and risk tier configuration
- [x] 3.1 Create `services/trading/__init__.py` and `services/trading/models.py`
- Create the `services/trading/` package directory
- Define `RiskTierConfig` dataclass with fields: name, min_confidence, max_position_pct, stop_loss_atr_multiplier, reward_risk_ratio, max_sector_pct, max_portfolio_heat
- Define `RISK_TIER_DEFAULTS` dict mapping conservative/moderate/aggressive to their default `RiskTierConfig` instances per the design specification
- Define `PortfolioState` dataclass with fields: positions (list), total_value, cash, active_pool, reserve_pool, sector_exposure (dict), portfolio_heat, open_position_count
- Define `TradingDecision` dataclass with all fields matching the `trading_decisions` table schema
- Define `PositionSizeResult` dataclass with dollar_amount, share_quantity, allocation_pct, adjustments list, rejected flag, rejection_reason
- Define `StopLevels` dataclass with stop_loss_price, take_profit_price, trailing_stop_active, atr_value, atr_multiplier, reward_risk_ratio, last_updated
- Define `OpenPosition` dataclass with ticker, quantity, entry_price, current_price, unrealized_pnl, market_value, sector, stop_loss_price, take_profit_price, signal_confidence, is_micro_trade
- Define `ClosedTrade` dataclass with ticker, entry_price, exit_price, quantity, pnl, pnl_pct, hold_duration, recommendation_id, is_micro_trade
- Define `PerformanceMetrics` dataclass with all fields from the design (total_portfolio_value through computed_at)
- Define `CircuitBreakerState` dataclass with active, trigger_type, triggered_at, cooldown_expires, ticker_cooldowns dict
- Define `ReservePoolState` dataclass with balance, total_deposits, total_withdrawals, last_updated
- Define `StopTrigger` dataclass with ticker, trigger_type (stop_loss/take_profit), current_price, trigger_price
- _Requirements: 5.1, 1.2, 2.1, 4.1, 6.1, 3.1, 13.1, 14.1_
- [x] 3.2 Write property test for risk tier default parameters
- **Property 29 (partial): Persistence round-trip for risk tier configs**
- Verify all three tier defaults have valid parameter ranges (min_confidence in [0,1], max_position_pct in (0,1], etc.)
- Verify conservative < moderate < aggressive for min_confidence thresholds (inverse) and position limits
- **Validates: Requirements 5.1**
- [x] 4. Position Sizer implementation
- [x] 4.1 Implement `services/trading/position_sizer.py`
- Implement `PositionSizer` class with `compute()` method accepting confidence, ticker, sector, current_price, active_pool, risk_tier, portfolio_state, correlation_matrix, earnings_calendar
- Implement sizing formula: `raw_pct = base_allocation_pct * (confidence / min_confidence) * multiplier`, clamped to max_position_pct, then dollar_amount = active_pool * clamped_pct, clamped to absolute_position_cap
- Implement confidence gate: reject when confidence < risk_tier.min_confidence
- Implement correlation reduction: compute weighted average correlation with existing positions; reduce proportionally when avg > 0.5; reject entirely when avg > 0.8
- Implement sector exposure reduction: reduce allocation if adding position would push sector above max_sector_pct
- Implement diversification bonus: 1.2x multiplier for under-represented sectors when portfolio holds < 3 sectors
- Implement earnings proximity: reduce by 50% within 3 trading days; reject within 1 trading day
- Implement portfolio heat check: reject if current heat + new position heat exceeds max_portfolio_heat
- Implement active pool minimum: reject new entries when Active Pool < configured minimum ($100 default)
- Implement absolute cap enforcement and share rounding (round down to whole shares, reject if quantity = 0)
- _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 9.2, 9.3, 9.4, 9.5, 10.2, 10.3, 13.1, 13.2, 3.5_
- [x] 4.2 Write property test for position sizing formula and invariants
- **Property 1: Position sizing formula and invariants**
- Generate random confidence values, Active Pool balances, stock prices, and RiskTierConfig objects
- Verify zero allocation when confidence < min_confidence
- Verify allocation never exceeds max_position_pct or absolute_position_cap
- Verify share quantity is rounded down to whole shares
- Verify rejection when rounded quantity is zero
- **Validates: Requirements 2.1, 2.2, 2.3, 2.4, 2.7**
- [x] 4.3 Write property test for correlation-based allocation adjustment
- **Property 2: Correlation-based allocation adjustment**
- Generate random correlation matrices and portfolio positions
- Verify allocation reduced when weighted avg correlation > 0.5
- Verify trade rejected when weighted avg correlation > 0.8
- Verify allocation unchanged when weighted avg correlation <= 0.5
- Verify monotonic non-increase: higher correlation → lower or equal allocation
- **Validates: Requirements 2.5, 9.2, 9.3**
- [x] 4.4 Write property test for sector exposure enforcement
- **Property 3: Sector exposure computation and enforcement**
- Generate random portfolios with sector labels
- Verify sector exposure equals sum of market values per sector
- Verify allocation reduced when adding position would exceed max_sector_pct
- **Validates: Requirements 2.6, 9.4**
- [x] 4.5 Write property test for diversification bonus
- **Property 4: Diversification bonus for under-represented sectors**
- Generate portfolios with varying sector counts
- Verify 1.2x bonus applied when portfolio has < 3 sectors and trade is in new sector
- Verify no bonus when portfolio has >= 3 sectors
- **Validates: Requirements 9.5**
- [x] 4.6 Write property test for Active Pool computation
- **Property 5: Active Pool computation invariant**
- Generate random total_portfolio_value and reserve_pool_balance
- Verify Active Pool = total_portfolio_value - reserve_pool_balance
- **Validates: Requirements 3.3**
- [x] 4.7 Write property test for earnings proximity adjustments
- **Property 19: Earnings proximity adjustments**
- Generate random earnings dates relative to current date
- Verify 50% reduction within 3 trading days
- Verify rejection within 1 trading day
- Verify normal sizing outside earnings window
- **Validates: Requirements 10.2, 10.3**
- [x] 4.8 Write property test for portfolio heat computation and enforcement
- **Property 24: Portfolio heat computation and threshold enforcement**
- Generate random open positions with entry prices and stop-loss levels
- Verify heat = sum of position_value * (entry_price - stop_loss_price) / entry_price
- Verify new entries rejected when heat exceeds max_portfolio_heat
- **Validates: Requirements 13.1, 13.2**
- [x] 4.9 Write property test for Active Pool minimum halts entries
- **Property 7: Active Pool minimum halts new entries but allows exits**
- Generate portfolio states with Active Pool below and above minimum
- Verify buy orders rejected when Active Pool < minimum
- Verify sell orders allowed regardless of Active Pool
- **Validates: Requirements 3.5**
- [x] 5. Checkpoint — Ensure position sizer logic and property tests pass
- Ensure all tests pass, ask the user if questions arise.
- [x] 6. Stop-Loss Manager implementation
- [x] 6.1 Implement `services/trading/stop_loss_manager.py`
- Implement `StopLossManager` class with `compute_initial_levels()` method: stop_loss = entry_price - (ATR * stop_loss_atr_multiplier), take_profit = entry_price + (stop_distance * reward_risk_ratio)
- Implement `re_evaluate_levels()` method: adjust if ATR changed > 10% or signal conditions changed; respect configurable interval (default 5 min)
- Implement `check_price_crossings()` method: return list of StopTrigger for positions where current price <= stop_loss or >= take_profit
- Implement trailing stop logic: when price moves favorably by > 50% of take-profit distance, move stop-loss to entry price (breakeven)
- Implement earnings proximity tightening: 0.7x ATR multiplier when earnings within 3 trading days
- Implement high-severity event tightening: 0.5x normal ATR multiplier during active macro events
- Implement proactive heat tightening: tighten stops on lowest-confidence positions when heat > 80% of max
- Implement price data unavailability safety: close position if price unavailable > 15 minutes during market hours
- Persist all stop levels and adjustments to `position_stop_levels` table
- _Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 7.2, 10.2, 13.3_
- [x] 6.2 Write property test for stop-loss and take-profit initial computation
- **Property 9: Stop-loss and take-profit initial computation**
- Generate random entry prices, ATR values, and RiskTierConfig objects
- Verify stop-loss = entry_price - (ATR * multiplier) and always below entry
- Verify take-profit = entry_price + (stop_distance * reward_risk_ratio) and always above entry
- **Validates: Requirements 4.1, 4.2**
- [x] 6.3 Write property test for price crossing triggers
- **Property 10: Price crossing triggers immediate sell**
- Generate random positions with stop/take-profit levels and current prices
- Verify sell triggered when price <= stop_loss or >= take_profit
- Verify no trigger when price is between stop_loss and take_profit
- **Validates: Requirements 4.4, 4.5**
- [x] 6.4 Write property test for trailing stop activation
- **Property 11: Trailing stop activation at 50% of take-profit distance**
- Generate random positions with varying favorable price moves
- Verify trailing stop activates (stop moves to entry) when move > 50% of TP distance
- Verify trailing stop does not activate when move <= 50%
- **Validates: Requirements 4.6**
- [x] 6.5 Write property test for stop tightening during high-severity events
- **Property 15: Stop tightening during high-severity events**
- Generate random positions and ATR values
- Verify tightened stop uses 0.5x normal multiplier
- Verify tightened stop is closer to current price than normal stop
- **Validates: Requirements 7.2**
- [x] 6.6 Write property test for proactive stop tightening at 80% heat
- **Property 25: Proactive stop tightening at 80% heat threshold**
- Generate portfolios with heat near the threshold
- Verify lowest-confidence positions get stops tightened first
- **Validates: Requirements 13.3**
- [x] 7. Reserve Pool Controller implementation
- [x] 7.1 Implement `services/trading/reserve_pool.py`
- Implement `ReservePoolController` class with `siphon_profit()` method: transfer configured percentage of realized profit to reserve, persist to `reserve_pool_ledger`
- Implement `emergency_liquidate()` method: release entire reserve into active pool, log event, persist to ledger
- Implement `compute_active_pool()` method: total_portfolio_value - reserve_pool_balance
- Implement `get_state()` method: load current balance and history from PostgreSQL
- Implement high-water mark detection: signal when reserve > 30% of total portfolio
- _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7_
- [x] 7.2 Write property test for reserve pool siphon computation
- **Property 6: Reserve pool siphon computation**
- Generate random realized profit amounts and siphon percentages
- Verify transferred amount = realized_profit * siphon_pct
- Verify balance_after = previous_balance + transferred_amount
- **Validates: Requirements 3.1, 3.2**
- [x] 7.3 Write property test for emergency drawdown triggers reserve liquidation
- **Property 8: Emergency drawdown triggers reserve liquidation**
- Generate portfolio states with drawdowns above and below emergency threshold
- Verify reserve liquidated into active pool when drawdown exceeds threshold
- Verify risk tier set to conservative after emergency liquidation
- **Validates: Requirements 3.6**
- [x] 8. Circuit Breaker implementation
- [x] 8.1 Implement `services/trading/circuit_breaker.py`
- Implement `CircuitBreaker` class with `check_daily_loss()`: activate when portfolio drops > configured daily_loss_pct
- Implement `check_single_position()`: close position and apply ticker cooldown when loss > configured single_position_loss_pct
- Implement `check_volatility()`: pause trading when 3+ positions hit stop-losses within 30-minute window
- Implement `is_ticker_cooled_down()`: check per-ticker re-entry cooldowns
- Implement `is_active()`: return whether any circuit breaker is currently active
- Implement cooldown expiry: auto-resolve when current time > triggered_at + cooldown_duration
- Persist all circuit breaker events to `circuit_breaker_events` table
- Store active state in Redis for fast lookup
- _Requirements: 6.1, 6.2, 6.3, 6.4, 6.5, 6.6_
- [x] 8.2 Write property test for circuit breaker activation
- **Property 13: Circuit breaker activation**
- Generate random portfolio states with varying daily losses, position losses, and stop-loss hit sequences
- Verify daily_loss trigger when loss > threshold
- Verify single_position trigger and ticker cooldown when position loss > threshold
- Verify volatility trigger when 3+ stop-losses within 30 minutes
- Verify all new orders rejected when any circuit breaker is active
- **Validates: Requirements 6.1, 6.2, 6.3**
- [x] 8.3 Write property test for circuit breaker cooldown expiry
- **Property 14: Circuit breaker cooldown expiry**
- Generate circuit breaker events with varying cooldown durations and current times
- Verify transition from active to resolved when time > triggered_at + cooldown
- Verify remains active before expiry
- **Validates: Requirements 6.5**
- [x] 9. Risk Tier Controller implementation
- [x] 9.1 Implement `services/trading/risk_tier_controller.py`
- Implement `RiskTierController` class with `evaluate()` method accepting PerformanceMetrics and reserve_pct
- Implement downgrade logic: downgrade one level when trailing 30-day win rate < 40% OR current drawdown > 15%
- Implement upgrade logic: upgrade one level when win rate > 55% AND reserve > 20% of total AND drawdown < 5%
- Implement tier bounds: never go below conservative or above aggressive
- Persist tier changes to `risk_tier_history` table with previous tier, new tier, and trigger metrics
- _Requirements: 5.2, 5.3, 5.4, 5.5, 5.6_
- [x] 9.2 Write property test for risk tier auto-adjustment conditions
- **Property 12: Risk tier auto-adjustment conditions**
- Generate random performance metrics (win rate, drawdown, reserve percentage)
- Verify downgrade when win rate < 40% OR drawdown > 15%
- Verify upgrade when win rate > 55% AND reserve > 20% AND drawdown < 5%
- Verify no change when neither condition met
- Verify tier never goes below conservative or above aggressive
- **Validates: Requirements 5.3, 5.4**
- [x] 10. Checkpoint — Ensure core components and property tests pass
- Ensure all tests pass, ask the user if questions arise.
- [x] 11. Correlation Matrix and Tax Lot Tracker
- [x] 11.1 Implement `services/trading/correlation.py`
- Implement `CorrelationMatrix` class with `refresh()` method: compute trailing 90-day price correlations from market data tables, persist to `correlation_matrix_cache` table
- Implement `get_correlation()` method: return coefficient for a ticker pair, 0.0 if unknown
- Implement `get_portfolio_correlation()` method: weighted average correlation between candidate and existing positions
- Cache in-memory after refresh; schedule daily refresh
- _Requirements: 9.1, 9.2, 9.3_
- [x] 11.2 Implement `services/trading/tax_lots.py`
- Implement `TaxLotTracker` class with `record_entry()` method: create tax lot record in PostgreSQL
- Implement `close_lots_fifo()` method: close lots in FIFO order, compute realized P&L per lot
- Implement `check_wash_sale()` method: check 30-day window before and after for same-ticker purchases
- Persist wash sale flags and details to tax_lots table
- _Requirements: 12.1, 12.2, 12.3, 12.4_
- [x] 11.3 Write property test for tax lot FIFO ordering
- **Property 22: Tax lot FIFO ordering**
- Generate random sequences of buy/sell transactions for the same ticker
- Verify lots closed in FIFO order (earliest acquired first)
- Verify realized P&L = (exit_price - cost_basis_per_share) * quantity per lot
- **Validates: Requirements 12.4**
- [x] 11.4 Write property test for wash sale detection
- **Property 23: Wash sale detection within 30-day window**
- Generate random loss-closing dates and purchase dates
- Verify wash sale flagged when same ticker purchased within 30 days before or after loss
- Verify no flag when purchases are outside the 30-day window
- **Validates: Requirements 12.2, 12.3**
- [x] 12. Trading Window and Gradual Entry logic
- [x] 12.1 Implement `services/trading/trading_window.py`
- Implement `is_within_trading_window()` function: return True if timestamp is between 9:45 AM ET and 3:45 PM ET on a market day
- Implement `next_window_open()` function: return the next timestamp when the trading window opens
- Implement `is_market_open()` function: check if current time is during US market hours (9:30 AM - 4:00 PM ET)
- _Requirements: 11.1, 11.2_
- [x] 12.2 Implement gradual entry logic in `services/trading/gradual_entry.py`
- Implement `should_use_gradual_entry()`: return True when position size exceeds min($30, 5% of Active Pool)
- Implement `split_into_tranches()`: split order into configured number of tranches (default 3) of approximately equal size
- Implement `GradualEntryManager` class to track pending tranches, re-evaluate before each submission, cancel remaining if conditions deteriorate
- Link all tranches to the same parent trading decision ID
- _Requirements: 11.3, 11.4, 11.5_
- [x] 12.3 Write property test for trading window determination
- **Property 20: Trading window determination**
- Generate random timestamps across US market hours
- Verify within-window classification for 9:45 AM - 3:45 PM ET
- Verify outside-window classification for all other times
- **Validates: Requirements 11.1**
- [x] 12.4 Write property test for gradual entry tranche splitting
- **Property 21: Gradual entry tranche splitting**
- Generate random position sizes above and below the threshold
- Verify splitting into configured number of tranches when above threshold
- Verify all tranches reference the same parent decision ID
- Verify tranche sizes are approximately equal
- **Validates: Requirements 11.3, 11.5**
- [x] 13. Autonomous Decision Loop (core engine)
- [x] 13.1 Implement `services/trading/engine.py`
- Implement `TradingEngine` class with `__init__()` accepting asyncpg.Pool, aioredis.Redis, and TradingEngineConfig
- Implement `start()` method: load portfolio state from Broker Service (positions, account balance), load active risk tier from PostgreSQL, load reserve pool balance, load circuit breaker status, load open stop levels, enter decision loop
- Implement `stop()` method: graceful shutdown — cancel pending tranches, persist state
- Implement `decision_loop()` method: poll recommendations at configured interval, evaluate each, size positions, submit orders
- Implement `poll_recommendations()` method: fetch from `recommendations` table where action IN (buy, sell) AND mode IN (paper_eligible, live_eligible) AND generated_at > last_poll_timestamp, ordered by confidence DESC
- Implement recommendation deduplication: check Redis key `stonks:dedupe:trading:{recommendation_id}` with 24h TTL, mark before evaluation
- Implement `evaluate_recommendation()` method: run all pre-trade checks (circuit breaker, trading window, risk tier confidence, portfolio heat, sector exposure, correlation, earnings proximity) and produce a TradingDecision record
- Implement `execute_decision()` method: generate order job payload matching existing broker queue schema, push to `stonks:queue:broker_orders`, handle gradual entry for large positions
- Persist every decision (act or skip) to `trading_decisions` table with full reasoning chain
- Implement adaptive market response: trigger immediate re-evaluation on high-severity macro events, tighten stops during events, increase polling frequency
- Implement rapid price move detection: re-evaluate position when price moves > 5% in 15 minutes
- Implement multiple declining positions halt: stop new entries when > 50% of positions have > 2% negative unrealized P&L
- _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 7.1, 7.2, 7.3, 7.4, 7.5, 17.1, 17.2_
- [x] 13.2 Write property test for recommendation deduplication
- **Property 27: Recommendation deduplication (idempotence)**
- Generate random recommendation IDs and process them twice
- Verify second processing is a no-op (no new decision record, no order submitted)
- **Validates: Requirements 1.5**
- [x] 13.3 Write property test for trading decision record completeness
- **Property 28: Trading decision record completeness and traceability**
- Generate random recommendations and evaluate them
- Verify all required fields present in the persisted decision record
- Verify "act" decisions include order job with trading_decision_id
- **Validates: Requirements 1.4, 17.1, 17.2**
- [x] 13.4 Write property test for multiple declining positions halts entries
- **Property 16: Multiple declining positions halts new entries**
- Generate portfolio states with varying percentages of declining positions
- Verify new entries halted when > 50% of positions have > 2% negative unrealized P&L
- Verify entries allowed when <= 50% are declining
- **Validates: Requirements 7.5**
- [x] 13.5 Write property test for maximum open positions enforcement
- **Property 18: Maximum open positions enforcement**
- Generate portfolio states at and below the max position limit
- Verify new entries rejected at the limit
- Verify portfolio never exceeds the configured maximum
- **Validates: Requirements 8.4**
- [x] 14. Checkpoint — Ensure decision loop and core engine tests pass
- Ensure all tests pass, ask the user if questions arise.
- [x] 15. Portfolio Rebalancer and Performance Tracker
- [x] 15.1 Implement `services/trading/rebalancer.py`
- Implement `PortfolioRebalancer` class with `evaluate()` method accepting positions, risk_tier, and active_pool
- Generate partial sell orders when single stock exceeds max_position_pct
- Generate sell orders for lowest-confidence positions when sector exceeds max_sector_pct
- Enforce maximum open positions limit (default 10)
- Submit rebalancing orders through normal broker queue with `rebalance` tag in decision trace
- Respect trading window and circuit breaker status
- Schedule: weekly at market open on Monday (configurable)
- _Requirements: 8.1, 8.2, 8.3, 8.4, 8.5, 8.6_
- [x] 15.2 Write property test for portfolio rebalancing sell orders
- **Property 17: Portfolio rebalancing generates correct sell orders**
- Generate portfolios with over-concentrated positions and sectors
- Verify sell orders generated to bring positions within limits
- Verify lowest-confidence positions targeted first for sector rebalancing
- **Validates: Requirements 8.2, 8.3**
- [x] 15.3 Implement `services/trading/performance_tracker.py`
- Implement `PerformanceTracker` class with `compute_metrics()` method: compute all PerformanceMetrics fields (total portfolio value, active/reserve pool, unrealized/realized P&L, daily P&L, win/loss counts, win rate, avg win/loss, profit factor, Sharpe ratio, max drawdown, current drawdown, portfolio heat)
- Implement Sharpe ratio: `(mean_daily_return / std_daily_return) * sqrt(252)` using trailing 30-day daily returns
- Implement `record_trade()` method: persist per-trade metrics (entry/exit price, hold duration, P&L, recommendation ID)
- Implement `persist_daily_snapshot()` method: save end-of-day snapshot to `portfolio_snapshots` table
- Compute metrics every 5 minutes during market hours
- Track micro-trade metrics separately from standard trade metrics
- _Requirements: 14.1, 14.2, 14.3, 20.7_
- [x] 15.4 Write property test for performance metrics computation
- **Property 26: Performance metrics computation**
- Generate random sets of closed trades with entry/exit prices and hold durations
- Verify win_rate = wins / total_trades
- Verify profit_factor = gross_profits / gross_losses (infinity if no losses)
- Verify Sharpe ratio formula consistency
- **Validates: Requirements 14.1, 14.2**
- [x] 15.5 Write property test for micro-trade metrics tracked separately
- **Property 33: Micro-trade metrics tracked separately**
- Generate mixed sets of standard and micro-trades
- Verify micro-trade metrics computed independently
- Verify standard trade metrics not contaminated by micro-trades
- **Validates: Requirements 20.7**
- [x] 16. Notification Service implementation
- [x] 16.1 Implement `services/trading/notifications.py`
- Implement `NotificationService` class with `send_alert()` method: send via all enabled channels (SMS via AWS SNS, email via Gmail API)
- Implement `send_daily_summary()` method: format and send daily performance summary at configurable time (default 16:30)
- Implement `send_weekly_digest()` method: format and send weekly performance digest
- Implement rate limiting: max 10 SMS/hour, 20 emails/hour (configurable), using Redis counters with hourly TTL
- Implement retry logic: up to 3 retries with exponential backoff on delivery failure
- Persist all notifications to `notifications` table with channel, event_type, message, delivery_status, timestamp
- Support event types: circuit_breaker_triggered, circuit_breaker_resumed, risk_tier_changed, emergency_liquidation, large_trade_pnl, daily_summary, weekly_digest
- Notifications run in separate asyncio tasks — never block trading operations
- _Requirements: 19.1, 19.2, 19.3, 19.4, 19.5, 19.6, 19.7, 19.8, 19.11_
- [x] 16.2 Write property test for notification rate limiting
- **Property 30: Notification rate limiting**
- Generate random sequences of notification requests within a one-hour window
- Verify at most 10 SMS and 20 emails delivered per hour
- Verify excess notifications marked as 'rate_limited'
- **Validates: Requirements 19.7**
- [x] 17. Micro-Trading Module
- [x] 17.1 Implement `services/trading/micro_trading.py`
- Implement `MicroTradingModule` class with `poll_intraday_signals()` method: fetch intraday and 1d trend window signals from aggregation engine
- Implement `evaluate_micro_trade()` method: evaluate signal against risk tier confidence threshold, apply micro-trade allocation cap (3% of Active Pool)
- Enforce daily micro-trade limit (default 10)
- Use tighter stop-loss (1.0x ATR) and take-profit (1.5x stop distance)
- Implement auto-close after max hold duration (default 2 hours)
- Respect all existing constraints (trading window, circuit breakers, portfolio heat, correlation, sector exposure, earnings)
- Toggleable independently via trading_engine_config
- _Requirements: 20.1, 20.2, 20.3, 20.4, 20.5, 20.6, 20.8, 20.10_
- [x] 17.2 Write property test for micro-trade parameter constraints
- **Property 31: Micro-trade parameter constraints**
- Generate random micro-trade scenarios
- Verify allocation does not exceed micro_trading_allocation_cap_pct
- Verify stop-loss at 1.0x ATR, take-profit at 1.5x stop distance
- Verify daily count does not exceed configured maximum
- **Validates: Requirements 20.3, 20.4, 20.5**
- [x] 17.3 Write property test for micro-trade auto-close
- **Property 32: Micro-trade auto-close after max hold duration**
- Generate micro-trade positions with varying hold durations
- Verify positions closed at market price when hold exceeds max duration
- **Validates: Requirements 20.6**
- [x] 17.4 Write property test for micro-trades respect all constraints
- **Property 34: Micro-trades respect all existing constraints**
- Generate micro-trade evaluations with various constraint violations
- Verify trading window, circuit breakers, portfolio heat, correlation, sector exposure, and earnings rules all enforced
- **Validates: Requirements 20.10**
- [x] 18. Checkpoint — Ensure all trading logic and property tests pass
- Ensure all tests pass, ask the user if questions arise.
- [x] 19. Backtester implementation
- [x] 19.1 Implement `services/trading/backtester.py`
- Implement `Backtester` class with `run()` method accepting BacktestConfig (start_date, end_date, initial_capital, risk_tier)
- Replay historical recommendations from `recommendations` table within date range
- Simulate full decision logic: position sizing, stop-loss/take-profit, circuit breakers, reserve pool, rebalancing
- Use historical price data from market data tables for simulation
- Produce BacktestResult with total_return, sharpe_ratio, max_drawdown, win_rate, profit_factor, trade_count, trade_log, equity_curve
- Persist results to `backtest_runs` and `backtest_trades` tables with unique backtest_id
- Handle missing historical data gracefully (skip dates, note gaps)
- Persist partial results with status 'failed' on mid-run errors
- _Requirements: 15.1, 15.2, 15.3, 15.4_
- [x] 19.2 Write property test for backtester produces equivalent metrics
- **Property 36: Backtester produces equivalent metrics**
- Generate random sets of historical trades
- Verify backtester metric computation matches performance tracker for same trade data
- **Validates: Requirements 15.3**
- [x] 20. Trading Engine FastAPI HTTP Service
- [x] 20.1 Implement `services/trading/app.py`
- Create FastAPI application with lifespan handler that starts/stops the TradingEngine
- Implement `GET /health` liveness probe endpoint
- Implement `GET /ready` readiness probe: return healthy when portfolio loaded and loop active
- Implement `GET /api/trading/status` endpoint: return engine state (enabled, risk tier, circuit breaker status, active/reserve pool, portfolio heat, open positions, last decision timestamp)
- Implement `PUT /api/trading/config` endpoint: update trading_engine_config, record audit event with previous/new config and change source
- Implement `POST /api/trading/pause` and `POST /api/trading/resume` endpoints
- Implement `GET /api/trading/decisions` endpoint: paginated, filterable by ticker, decision type, date range
- Implement `GET /api/trading/metrics` endpoint: current performance metrics
- Implement `GET /api/trading/metrics/history` endpoint: historical daily snapshots
- Implement `POST /api/trading/backtest` endpoint: launch backtest, return backtest_id
- Implement `GET /api/trading/backtest/{id}` endpoint: retrieve backtest results
- Implement `GET /api/trading/notifications/config` and `PUT /api/trading/notifications/config` endpoints
- Implement `GET /api/trading/notifications/history` endpoint: recent notifications
- _Requirements: 1.7, 5.6, 6.6, 15.5, 16.2, 16.3, 16.4, 17.3, 19.9_
- [x] 20.2 Write property test for configuration change audit trail
- **Property 35: Configuration change audit trail**
- Generate random configuration changes via API
- Verify audit event persisted with previous config, new config, and change source
- **Validates: Requirements 16.6**
- [x] 20.3 Write property test for persistence round-trip
- **Property 29: Persistence round-trip for trading engine state**
- Generate random trading engine config, reserve pool entries, risk tier history, circuit breaker events, portfolio snapshots, and backtest results
- Verify persist-then-read produces equivalent objects with all fields preserved
- **Validates: Requirements 3.2, 4.7, 5.5, 6.4, 14.3, 15.4, 16.1**
- [x] 21. Checkpoint — Ensure API endpoints and backtester work correctly
- Ensure all tests pass, ask the user if questions arise.
- [x] 22. Kubernetes deployment and infrastructure
- [x] 22.1 Add trading-engine service to Helm chart `infra/helm/stonks-oracle/values.yaml`
- Add `tradingEngine` entry under `services:` with: replicas 1, image trading-engine, command `uvicorn services.trading.app:app --host 0.0.0.0 --port 8000`, tier trading, port 8000, secrets [stonks-core-secrets, stonks-broker-secrets], resources (requests: 100m CPU / 256Mi memory, limits: 500m CPU / 512Mi memory), readiness probe on /ready port 8000, liveness probe on /health port 8000
- _Requirements: 1.7, 16.1_
- [x] 22.2 Add network policy for trading-engine
- Allow ingress from query-api, dashboard, and kube-system (Traefik) on port 8000
- Allow egress to PostgreSQL, Redis, and external services (SNS, Gmail API)
- _Requirements: 16.2_
- [x] 22.3 Add `/trading/` proxy route to dashboard nginx.conf
- Add `location /trading/ { proxy_pass http://trading-engine:8000/; }` to `frontend/nginx.conf`
- _Requirements: 14.4, 16.5_
- [x] 22.4 Add trading-engine ingress if external access needed
- Add ingress host entry for trading engine API (e.g., `stonks-trading.celestium.life`) to values.yaml if direct external access is desired, or rely on dashboard proxy
- _Requirements: 16.2_
- [x] 23. Dashboard frontend — Trading Engine panels
- [x] 23.1 Add trading API client hooks to `frontend/src/api/`
- Add `useTradingStatus()` hook: fetch `GET /trading/api/trading/status`
- Add `useTradingDecisions()` hook: fetch `GET /trading/api/trading/decisions` with pagination and filters
- Add `useTradingMetrics()` hook: fetch `GET /trading/api/trading/metrics`
- Add `useTradingMetricsHistory()` hook: fetch `GET /trading/api/trading/metrics/history`
- Add `useTradingConfig()` and `useUpdateTradingConfig()` hooks for config read/write
- Add `usePauseTradingEngine()` and `useResumeTradingEngine()` mutation hooks
- Add `useBacktestLaunch()` and `useBacktestResult()` hooks
- Add `useNotificationConfig()`, `useUpdateNotificationConfig()`, and `useNotificationHistory()` hooks
- _Requirements: 14.4, 14.5, 14.6, 14.7, 15.6, 16.5, 17.4, 19.10, 20.9_
- [x] 23.2 Implement Trading Engine overview panel component
- Display current Risk Tier, Circuit Breaker status (active/inactive with trigger reason and cooldown remaining), Active Pool and Reserve Pool balances, Portfolio Heat gauge, last 24h P&L summary
- Include start/pause/resume controls and Risk Tier selector dropdown
- Use TanStack Query for data fetching with auto-refresh
- _Requirements: 14.4, 16.5, 6.6_
- [x] 23.3 Implement Portfolio Composition panel component
- Display current positions table: ticker, entry price, current price, unrealized P&L, stop-loss level, take-profit level, sector
- Display sector allocation pie chart using Recharts
- _Requirements: 14.5_
- [x] 23.4 Implement Trade History panel component
- Display completed trades table: entry/exit prices, P&L amount and percentage, hold duration, recommendation thesis
- Support pagination and filtering by ticker and date range
- _Requirements: 14.6, 17.4_
- [x] 23.5 Implement Performance Charts panel component
- Display cumulative P&L line chart over time using Recharts
- Display daily returns bar chart using Recharts
- Display drawdown chart using Recharts
- _Requirements: 14.7_
- [x] 23.6 Implement Backtesting panel component
- Display backtest configuration form: date range picker, initial capital input, risk tier selector
- Display backtest results: equity curve chart, trade log table, summary metrics (total return, Sharpe, max drawdown, win rate, profit factor)
- Support launching new backtests and viewing historical results
- _Requirements: 15.6_
- [x] 23.7 Implement Micro-Trading panel component
- Display micro-trade mode status toggle (enabled/disabled)
- Display today's micro-trade count and P&L
- Display active micro-trade positions table
- Display micro-trade performance metrics over trailing 7 days
- _Requirements: 20.9_
- [x] 23.8 Implement Notification Preferences panel component
- Display notification channel toggles (SMS, email) with phone number and email address inputs
- Display event type selection checkboxes
- Display rate limit configuration
- Display recent notification history table
- _Requirements: 19.10_
- [x] 23.9 Wire trading panels into dashboard routing
- Add Trading page route to TanStack Router configuration
- Add navigation link to the dashboard sidebar/header
- Compose all trading panels (overview, portfolio, trade history, performance, backtesting, micro-trading, notifications) into the Trading page layout
- _Requirements: 14.4, 16.5_
- [x] 24. Checkpoint — Ensure frontend builds and all tests pass
- Ensure all tests pass, ask the user if questions arise.
- [x] 25. Integration wiring and final validation
- [x] 25.1 Wire stop-loss price crossing detection into the decision loop
- Connect `StopLossManager.check_price_crossings()` to run at the configured interval (5 min default, 60s during high-severity events)
- Generate immediate sell orders for triggered positions and submit to broker queue
- Handle price data unavailability (close position after 15 min without data)
- _Requirements: 4.3, 4.4, 4.5, 4.8, 7.4_
- [x] 25.2 Wire reserve pool siphoning to position close events
- Detect profitable position closes from broker service fill events
- Call `ReservePoolController.siphon_profit()` with realized profit
- Trigger notification for large trade P&L events
- _Requirements: 3.1, 19.2_
- [x] 25.3 Wire risk tier evaluation to daily market close schedule
- Schedule `RiskTierController.evaluate()` at market close
- Trigger notification on tier changes
- _Requirements: 5.2, 19.2_
- [x] 25.4 Wire portfolio rebalancer to weekly schedule
- Schedule `PortfolioRebalancer.evaluate()` weekly at Monday market open
- Submit rebalancing orders through broker queue
- _Requirements: 8.1, 8.5_
- [x] 25.5 Wire notification service to all critical events
- Connect circuit breaker triggers/resumes, risk tier changes, emergency liquidation, large trade P&L to notification dispatch
- Schedule daily summary at configured time (default 16:30)
- Schedule weekly digest
- _Requirements: 19.2, 19.3, 19.4_
- [x] 25.6 Wire micro-trading module into the decision loop
- Start micro-trading polling when enabled in config
- Route micro-trade decisions through the same order submission pipeline
- Track micro-trade metrics separately in performance tracker
- _Requirements: 20.1, 20.2, 20.7_
- [x] 25.7 Write integration tests for end-to-end decision flow
- Test full cycle: recommendation → evaluation → position sizing → order submission to broker queue
- Test stop-loss crossing → immediate sell order
- Test reserve pool siphoning on profitable close
- Test circuit breaker trigger → halt → cooldown → resume
- Test engine startup state reconstruction from PostgreSQL
- _Requirements: 1.1, 1.2, 1.3, 3.1, 4.4, 6.1, 6.5, 18.5_
- [x] 26. Final checkpoint — Ensure all tests pass
- Ensure all tests pass, ask the user if questions arise.
## Notes
- Tasks marked with `*` are optional and can be skipped for faster MVP
- Each task references specific requirements for traceability
- Checkpoints ensure incremental validation after each major component
- Property tests validate the 36 correctness properties defined in the design document
- The trading engine is a NEW service at `services/trading/` — it does not replace existing services
- All order submission goes through the existing `stonks:queue:broker_orders` Redis queue consumed by the Broker Service
- Migration number 018 is the next available migration slot
- Frontend components use the existing React 19 + TypeScript + Tailwind + TanStack + Recharts stack
- Dashboard proxy needs `/trading/``trading-engine:8000` added to nginx.conf