Files
stonks-oracle/infra/migrations/018_autonomous_trading_engine.sql
T
Celes Renata 4ffde8cc06 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
2026-04-15 16:12:22 +00:00

366 lines
14 KiB
SQL

-- Autonomous Trading Engine
-- Adds tables for trading engine configuration, reserve pool management,
-- risk tier history, circuit breakers, trading decisions, stop levels,
-- portfolio snapshots, backtesting, tax lots, earnings calendar,
-- correlation matrix cache, and notifications.
-- ============================================================
-- Trading Engine Configuration
-- ============================================================
CREATE TABLE trading_engine_config (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
enabled BOOLEAN NOT NULL DEFAULT FALSE,
paused BOOLEAN NOT NULL DEFAULT FALSE,
risk_tier VARCHAR(20) NOT NULL DEFAULT 'moderate',
reserve_siphon_pct FLOAT NOT NULL DEFAULT 0.20,
polling_interval_seconds INTEGER NOT NULL DEFAULT 60,
gradual_entry_tranches INTEGER NOT NULL DEFAULT 3,
gradual_entry_threshold_dollars FLOAT NOT NULL DEFAULT 30.0,
gradual_entry_interval_minutes INTEGER NOT NULL DEFAULT 15,
trading_window_start_minutes INTEGER NOT NULL DEFAULT 15,
trading_window_end_minutes INTEGER NOT NULL DEFAULT 15,
max_open_positions INTEGER NOT NULL DEFAULT 10,
circuit_breaker_daily_loss_pct FLOAT NOT NULL DEFAULT 0.05,
circuit_breaker_single_position_loss_pct FLOAT NOT NULL DEFAULT 0.15,
circuit_breaker_ticker_cooldown_hours INTEGER NOT NULL DEFAULT 48,
circuit_breaker_volatility_pause_hours INTEGER NOT NULL DEFAULT 2,
circuit_breaker_stop_loss_hits_threshold INTEGER NOT NULL DEFAULT 3,
circuit_breaker_stop_loss_window_minutes INTEGER NOT NULL DEFAULT 30,
active_pool_minimum FLOAT NOT NULL DEFAULT 100.0,
emergency_drawdown_threshold_pct FLOAT NOT NULL DEFAULT 0.40,
reserve_high_water_pct FLOAT NOT NULL DEFAULT 0.30,
absolute_position_cap FLOAT NOT NULL DEFAULT 50.0,
correlation_reduction_threshold FLOAT NOT NULL DEFAULT 0.5,
correlation_rejection_threshold FLOAT NOT NULL DEFAULT 0.8,
earnings_pre_window_days INTEGER NOT NULL DEFAULT 3,
earnings_post_cooldown_days INTEGER NOT NULL DEFAULT 1,
micro_trading_enabled BOOLEAN NOT NULL DEFAULT FALSE,
micro_trading_interval_seconds INTEGER NOT NULL DEFAULT 300,
micro_trading_allocation_cap_pct FLOAT NOT NULL DEFAULT 0.03,
micro_trading_max_daily INTEGER NOT NULL DEFAULT 10,
micro_trading_max_hold_minutes INTEGER NOT NULL DEFAULT 120,
notification_sms_enabled BOOLEAN NOT NULL DEFAULT FALSE,
notification_email_enabled BOOLEAN NOT NULL DEFAULT FALSE,
notification_phone_number VARCHAR(20),
notification_email_recipient VARCHAR(200),
notification_sns_topic_arn VARCHAR(300),
notification_rate_limit_sms_per_hour INTEGER NOT NULL DEFAULT 10,
notification_rate_limit_email_per_hour INTEGER NOT NULL DEFAULT 20,
notification_daily_summary_time TIME NOT NULL DEFAULT '16:30',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ============================================================
-- Reserve Pool Ledger
-- ============================================================
CREATE TABLE reserve_pool_ledger (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
amount FLOAT NOT NULL,
balance_after FLOAT NOT NULL,
trigger_type VARCHAR(30) NOT NULL,
reference_id UUID,
notes TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT chk_trigger_type CHECK (
trigger_type IN ('profit_siphon', 'emergency_liquidation', 'manual_adjustment', 'initial')
)
);
CREATE INDEX idx_reserve_pool_ledger_created ON reserve_pool_ledger(created_at DESC);
-- ============================================================
-- Risk Tier History
-- ============================================================
CREATE TABLE risk_tier_history (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
previous_tier VARCHAR(20) NOT NULL,
new_tier VARCHAR(20) NOT NULL,
trigger_source VARCHAR(30) NOT NULL,
trigger_metrics JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_risk_tier_history_created ON risk_tier_history(created_at DESC);
-- ============================================================
-- Circuit Breaker Events
-- ============================================================
CREATE TABLE circuit_breaker_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
trigger_type VARCHAR(30) NOT NULL,
threshold_value FLOAT,
actual_value FLOAT,
ticker VARCHAR(20),
cooldown_expires TIMESTAMPTZ,
resolved_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT chk_cb_trigger_type CHECK (
trigger_type IN ('daily_loss', 'single_position', 'volatility', 'manual')
)
);
CREATE INDEX idx_circuit_breaker_events_active ON circuit_breaker_events(created_at DESC)
WHERE resolved_at IS NULL;
-- ============================================================
-- Trading Decisions
-- ============================================================
CREATE TABLE trading_decisions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
recommendation_id UUID REFERENCES recommendations(id),
decision VARCHAR(10) NOT NULL,
skip_reason TEXT,
ticker VARCHAR(20) NOT NULL,
computed_position_size FLOAT,
computed_share_quantity INTEGER,
risk_tier_at_decision VARCHAR(20) NOT NULL,
portfolio_heat_at_decision FLOAT,
active_pool_at_decision FLOAT,
reserve_pool_at_decision FLOAT,
circuit_breaker_status VARCHAR(20) NOT NULL DEFAULT 'inactive',
correlation_check_result JSONB DEFAULT '{}',
sector_exposure_check_result JSONB DEFAULT '{}',
earnings_proximity_flag BOOLEAN NOT NULL DEFAULT FALSE,
is_micro_trade BOOLEAN NOT NULL DEFAULT FALSE,
decision_trace JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_trading_decisions_ticker ON trading_decisions(ticker, created_at DESC);
CREATE INDEX idx_trading_decisions_rec ON trading_decisions(recommendation_id);
CREATE INDEX idx_trading_decisions_decision ON trading_decisions(decision, created_at DESC);
-- ============================================================
-- Position Stop Levels
-- ============================================================
CREATE TABLE position_stop_levels (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ticker VARCHAR(20) NOT NULL,
entry_price FLOAT NOT NULL,
stop_loss_price FLOAT NOT NULL,
take_profit_price FLOAT NOT NULL,
trailing_stop_active BOOLEAN NOT NULL DEFAULT FALSE,
atr_value FLOAT NOT NULL,
atr_multiplier FLOAT NOT NULL,
reward_risk_ratio FLOAT NOT NULL,
signal_confidence FLOAT,
is_micro_trade BOOLEAN NOT NULL DEFAULT FALSE,
active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_position_stop_levels_ticker ON position_stop_levels(ticker) WHERE active = TRUE;
-- ============================================================
-- Portfolio Snapshots
-- ============================================================
CREATE TABLE portfolio_snapshots (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
snapshot_date DATE NOT NULL UNIQUE,
portfolio_value FLOAT NOT NULL,
active_pool FLOAT NOT NULL,
reserve_pool FLOAT NOT NULL,
daily_return FLOAT,
cumulative_return FLOAT,
unrealized_pnl FLOAT,
realized_pnl FLOAT,
win_count INTEGER NOT NULL DEFAULT 0,
loss_count INTEGER NOT NULL DEFAULT 0,
win_rate FLOAT,
sharpe_ratio FLOAT,
max_drawdown FLOAT,
current_drawdown_pct FLOAT,
portfolio_heat FLOAT,
risk_tier VARCHAR(20),
positions JSONB NOT NULL DEFAULT '[]',
metrics JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_portfolio_snapshots_date ON portfolio_snapshots(snapshot_date DESC);
-- ============================================================
-- Backtest Runs
-- ============================================================
CREATE TABLE backtest_runs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
start_date DATE NOT NULL,
end_date DATE NOT NULL,
initial_capital FLOAT NOT NULL,
risk_tier VARCHAR(20) NOT NULL,
config JSONB NOT NULL DEFAULT '{}',
total_return FLOAT,
sharpe_ratio FLOAT,
max_drawdown FLOAT,
win_rate FLOAT,
profit_factor FLOAT,
trade_count INTEGER,
equity_curve JSONB DEFAULT '[]',
status VARCHAR(20) NOT NULL DEFAULT 'running',
completed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ============================================================
-- Backtest Trades
-- ============================================================
CREATE TABLE backtest_trades (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
backtest_id UUID NOT NULL REFERENCES backtest_runs(id) ON DELETE CASCADE,
ticker VARCHAR(20) NOT NULL,
side VARCHAR(10) NOT NULL,
entry_price FLOAT NOT NULL,
exit_price FLOAT,
quantity INTEGER NOT NULL,
pnl FLOAT,
pnl_pct FLOAT,
entry_date DATE NOT NULL,
exit_date DATE,
hold_duration_days INTEGER,
recommendation_id UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_backtest_trades_run ON backtest_trades(backtest_id);
-- ============================================================
-- Tax Lots
-- ============================================================
CREATE TABLE tax_lots (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ticker VARCHAR(20) NOT NULL,
quantity INTEGER NOT NULL,
cost_basis_per_share FLOAT NOT NULL,
acquisition_date DATE NOT NULL,
status VARCHAR(10) NOT NULL DEFAULT 'open',
closed_date DATE,
exit_price FLOAT,
realized_pnl FLOAT,
wash_sale_flag BOOLEAN NOT NULL DEFAULT FALSE,
wash_sale_details TEXT,
order_id UUID REFERENCES orders(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT chk_tax_lot_status CHECK (status IN ('open', 'closed', 'washed'))
);
CREATE INDEX idx_tax_lots_ticker ON tax_lots(ticker, acquisition_date DESC);
CREATE INDEX idx_tax_lots_status ON tax_lots(status) WHERE status = 'open';
-- ============================================================
-- Earnings Calendar
-- ============================================================
CREATE TABLE earnings_calendar (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ticker VARCHAR(20) NOT NULL,
earnings_date DATE NOT NULL,
source VARCHAR(30) NOT NULL DEFAULT 'manual',
confirmed BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(ticker, earnings_date)
);
CREATE INDEX idx_earnings_calendar_date ON earnings_calendar(earnings_date);
CREATE INDEX idx_earnings_calendar_ticker ON earnings_calendar(ticker);
-- ============================================================
-- Correlation Matrix Cache
-- ============================================================
CREATE TABLE correlation_matrix_cache (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ticker_a VARCHAR(20) NOT NULL,
ticker_b VARCHAR(20) NOT NULL,
correlation_coefficient FLOAT NOT NULL,
lookback_days INTEGER NOT NULL DEFAULT 90,
computed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(ticker_a, ticker_b)
);
CREATE INDEX idx_correlation_cache_tickers ON correlation_matrix_cache(ticker_a, ticker_b);
-- ============================================================
-- Notifications
-- ============================================================
CREATE TABLE notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
channel VARCHAR(10) NOT NULL,
event_type VARCHAR(50) NOT NULL,
message TEXT NOT NULL,
delivery_status VARCHAR(20) NOT NULL DEFAULT 'pending',
retry_count INTEGER NOT NULL DEFAULT 0,
error_message TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
delivered_at TIMESTAMPTZ,
CONSTRAINT chk_channel CHECK (channel IN ('sms', 'email')),
CONSTRAINT chk_delivery_status CHECK (
delivery_status IN ('pending', 'delivered', 'failed', 'rate_limited')
)
);
CREATE INDEX idx_notifications_created ON notifications(created_at DESC);
CREATE INDEX idx_notifications_event ON notifications(event_type, created_at DESC);
-- ============================================================
-- Default Data
-- ============================================================
-- Insert default trading engine configuration (moderate tier defaults)
INSERT INTO trading_engine_config (
enabled, paused, risk_tier, reserve_siphon_pct,
polling_interval_seconds, gradual_entry_tranches,
gradual_entry_threshold_dollars, gradual_entry_interval_minutes,
trading_window_start_minutes, trading_window_end_minutes,
max_open_positions,
circuit_breaker_daily_loss_pct, circuit_breaker_single_position_loss_pct,
circuit_breaker_ticker_cooldown_hours, circuit_breaker_volatility_pause_hours,
circuit_breaker_stop_loss_hits_threshold, circuit_breaker_stop_loss_window_minutes,
active_pool_minimum, emergency_drawdown_threshold_pct,
reserve_high_water_pct, absolute_position_cap,
correlation_reduction_threshold, correlation_rejection_threshold,
earnings_pre_window_days, earnings_post_cooldown_days,
micro_trading_enabled, micro_trading_interval_seconds,
micro_trading_allocation_cap_pct, micro_trading_max_daily,
micro_trading_max_hold_minutes,
notification_sms_enabled, notification_email_enabled,
notification_rate_limit_sms_per_hour, notification_rate_limit_email_per_hour,
notification_daily_summary_time
) VALUES (
FALSE, FALSE, 'moderate', 0.20,
60, 3,
30.0, 15,
15, 15,
10,
0.05, 0.15,
48, 2,
3, 30,
100.0, 0.40,
0.30, 50.0,
0.5, 0.8,
3, 1,
FALSE, 300,
0.03, 10,
120,
FALSE, FALSE,
10, 20,
'16:30'
);
-- Insert initial reserve pool ledger entry with zero balance
INSERT INTO reserve_pool_ledger (amount, balance_after, trigger_type, notes)
VALUES (0.0, 0.0, 'initial', 'Initial reserve pool entry');