Files
stonks-oracle/infra/migrations/018_autonomous_trading_engine.sql
T

369 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)
-- Use a singleton pattern: only insert if no rows exist
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
)
SELECT
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'
WHERE NOT EXISTS (SELECT 1 FROM trading_engine_config);
-- Insert initial reserve pool ledger entry with zero balance (only if empty)
INSERT INTO reserve_pool_ledger (amount, balance_after, trigger_type, notes)
SELECT 0.0, 0.0, 'initial', 'Initial reserve pool entry'
WHERE NOT EXISTS (SELECT 1 FROM reserve_pool_ledger);