234 lines
8.9 KiB
JavaScript
234 lines
8.9 KiB
JavaScript
const AUTONOMY_SCHEMA_VERSION = 2;
|
|
|
|
function initAutonomySchema(db) {
|
|
if (db.dialect === 'postgres') return;
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS autonomy_schema (
|
|
version INTEGER PRIMARY KEY,
|
|
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_jobs (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
job_type TEXT NOT NULL,
|
|
lane TEXT NOT NULL CHECK (lane IN ('live', 'historical', 'maintenance')),
|
|
priority INTEGER NOT NULL DEFAULT 0,
|
|
entity_type TEXT NOT NULL,
|
|
entity_id TEXT NOT NULL,
|
|
idempotency_key TEXT NOT NULL UNIQUE,
|
|
status TEXT NOT NULL DEFAULT 'pending'
|
|
CHECK (status IN ('pending', 'leased', 'complete', 'failed', 'dead_letter')),
|
|
attempts INTEGER NOT NULL DEFAULT 0,
|
|
available_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
leased_by TEXT,
|
|
lease_expires_at TEXT,
|
|
last_error TEXT,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
completed_at TEXT
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_autonomy_jobs_claim
|
|
ON autonomy_jobs(status, lane, priority DESC, available_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_cursors (
|
|
key TEXT PRIMARY KEY,
|
|
value INTEGER NOT NULL DEFAULT 0,
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_proposals (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
event_id INTEGER,
|
|
payload TEXT NOT NULL,
|
|
information_cutoff TEXT NOT NULL,
|
|
coordinator_model TEXT,
|
|
prompt_version TEXT,
|
|
status TEXT NOT NULL DEFAULT 'candidate'
|
|
CHECK (status IN ('candidate', 'accepted', 'rejected', 'superseded')),
|
|
rejection_reason TEXT,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
reviewed_at TEXT
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_instruments (
|
|
symbol TEXT PRIMARY KEY,
|
|
broker TEXT NOT NULL,
|
|
asset_class TEXT NOT NULL DEFAULT 'us_equity',
|
|
active INTEGER NOT NULL DEFAULT 0,
|
|
tradable INTEGER NOT NULL DEFAULT 0,
|
|
shortable INTEGER NOT NULL DEFAULT 0,
|
|
fractionable INTEGER NOT NULL DEFAULT 0,
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_legacy_records (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
source_table TEXT NOT NULL,
|
|
source_id INTEGER NOT NULL,
|
|
payload TEXT NOT NULL,
|
|
calibration_eligible INTEGER NOT NULL DEFAULT 0,
|
|
imported_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
UNIQUE(source_table, source_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_predictions (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
proposal_id INTEGER NOT NULL REFERENCES autonomy_proposals(id),
|
|
event_id INTEGER,
|
|
instrument TEXT NOT NULL,
|
|
direction TEXT NOT NULL CHECK (direction IN ('positive', 'negative')),
|
|
event_type TEXT NOT NULL,
|
|
causal_channel TEXT,
|
|
horizon_days INTEGER NOT NULL,
|
|
information_cutoff TEXT NOT NULL,
|
|
evidence_article_ids TEXT NOT NULL,
|
|
invalidation_condition TEXT,
|
|
learning_eligible INTEGER NOT NULL DEFAULT 0,
|
|
strategy_version TEXT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'open'
|
|
CHECK (status IN ('open', 'resolved', 'unresolvable', 'invalidated')),
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_autonomy_predictions_resolution
|
|
ON autonomy_predictions(status, information_cutoff, instrument);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_outcomes (
|
|
prediction_id INTEGER PRIMARY KEY REFERENCES autonomy_predictions(id),
|
|
price_0 REAL,
|
|
price_horizon REAL,
|
|
benchmark_0 REAL,
|
|
benchmark_horizon REAL,
|
|
excess_return REAL,
|
|
direction_correct INTEGER,
|
|
error_type TEXT,
|
|
evaluated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
notes TEXT
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_calibration_snapshots (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
cohort_key TEXT NOT NULL,
|
|
sample_size INTEGER NOT NULL,
|
|
effective_sample_size REAL NOT NULL,
|
|
directional_probability REAL NOT NULL,
|
|
expected_excess_return REAL,
|
|
lower_return REAL,
|
|
upper_return REAL,
|
|
parent_cohort_key TEXT,
|
|
version TEXT NOT NULL,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_autonomy_calibration_lookup
|
|
ON autonomy_calibration_snapshots(cohort_key, created_at DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_decisions (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
prediction_id INTEGER NOT NULL REFERENCES autonomy_predictions(id),
|
|
action TEXT NOT NULL CHECK (action IN ('BUY', 'SELL', 'HOLD', 'ABSTAIN')),
|
|
calibrated_probability REAL,
|
|
expected_excess_return REAL,
|
|
rationale TEXT NOT NULL,
|
|
strategy_version TEXT NOT NULL,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_order_intents (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
decision_id INTEGER NOT NULL REFERENCES autonomy_decisions(id),
|
|
client_order_id TEXT NOT NULL UNIQUE,
|
|
instrument TEXT NOT NULL,
|
|
side TEXT NOT NULL CHECK (side IN ('buy', 'sell')),
|
|
notional REAL NOT NULL CHECK (notional > 0),
|
|
status TEXT NOT NULL DEFAULT 'shadow'
|
|
CHECK (status IN ('shadow', 'pending', 'submitted', 'filled', 'partially_filled', 'rejected', 'cancelled')),
|
|
broker_order_id TEXT,
|
|
attempts INTEGER NOT NULL DEFAULT 0,
|
|
last_error TEXT,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_broker_events (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
broker TEXT NOT NULL,
|
|
event_type TEXT NOT NULL,
|
|
broker_id TEXT,
|
|
payload TEXT NOT NULL,
|
|
occurred_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
UNIQUE(broker, event_type, broker_id, occurred_at)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_account_snapshots (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
broker TEXT NOT NULL,
|
|
account_id TEXT,
|
|
equity REAL,
|
|
cash REAL,
|
|
buying_power REAL,
|
|
payload TEXT NOT NULL,
|
|
captured_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_position_snapshots (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
broker TEXT NOT NULL,
|
|
instrument TEXT NOT NULL,
|
|
quantity REAL,
|
|
market_value REAL,
|
|
unrealized_pl REAL,
|
|
payload TEXT NOT NULL,
|
|
captured_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
-- Historical replay is a separate evidence path. It deliberately never
|
|
-- writes to autonomy_decisions or order intents.
|
|
CREATE TABLE IF NOT EXISTS autonomy_replay_runs (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
status TEXT NOT NULL DEFAULT 'running'
|
|
CHECK (status IN ('running', 'paused', 'complete', 'superseded', 'failed')),
|
|
start_at TEXT,
|
|
watermark_at TEXT,
|
|
cursor_article_id INTEGER NOT NULL DEFAULT 0,
|
|
cursor_effective_at TEXT,
|
|
processed_articles INTEGER NOT NULL DEFAULT 0,
|
|
strategy_version TEXT NOT NULL,
|
|
prompt_version TEXT NOT NULL,
|
|
coordinator_model TEXT,
|
|
price_provider TEXT NOT NULL DEFAULT 'yahoo',
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
completed_at TEXT,
|
|
last_error TEXT
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_autonomy_replay_runs_active
|
|
ON autonomy_replay_runs(status, cursor_article_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS autonomy_replay_evaluations (
|
|
prediction_id INTEGER PRIMARY KEY REFERENCES autonomy_predictions(id),
|
|
replay_run_id INTEGER NOT NULL REFERENCES autonomy_replay_runs(id),
|
|
snapshot_cutoff TEXT NOT NULL,
|
|
sample_size INTEGER NOT NULL,
|
|
action TEXT NOT NULL CHECK (action IN ('BUY', 'SELL', 'HOLD', 'ABSTAIN')),
|
|
calibrated_probability REAL,
|
|
expected_excess_return REAL,
|
|
rationale TEXT NOT NULL,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
INSERT OR IGNORE INTO autonomy_schema(version) VALUES (${AUTONOMY_SCHEMA_VERSION});
|
|
`);
|
|
for (const statement of [
|
|
'ALTER TABLE autonomy_order_intents ADD COLUMN attempts INTEGER NOT NULL DEFAULT 0',
|
|
'ALTER TABLE autonomy_order_intents ADD COLUMN last_error TEXT',
|
|
'ALTER TABLE autonomy_predictions ADD COLUMN learning_eligible INTEGER NOT NULL DEFAULT 0',
|
|
"ALTER TABLE autonomy_predictions ADD COLUMN origin TEXT NOT NULL DEFAULT 'live'",
|
|
'ALTER TABLE autonomy_predictions ADD COLUMN replay_run_id INTEGER',
|
|
'ALTER TABLE autonomy_replay_runs ADD COLUMN cursor_effective_at TEXT',
|
|
"ALTER TABLE autonomy_calibration_snapshots ADD COLUMN source TEXT NOT NULL DEFAULT 'live'",
|
|
'ALTER TABLE autonomy_calibration_snapshots ADD COLUMN replay_run_id INTEGER',
|
|
]) {
|
|
try { db.exec(statement); } catch (_) {}
|
|
}
|
|
}
|
|
|
|
module.exports = { AUTONOMY_SCHEMA_VERSION, initAutonomySchema };
|