291 lines
8.4 KiB
SQL
291 lines
8.4 KiB
SQL
-- =========================================
|
|
-- Extensions (optional but useful)
|
|
-- =========================================
|
|
CREATE EXTENSION IF NOT EXISTS pgcrypto; -- for gen_random_uuid() if you want it later
|
|
|
|
-- =========================================
|
|
-- 1) Identity & Sessions
|
|
-- =========================================
|
|
CREATE TABLE IF NOT EXISTS app_user (
|
|
id TEXT PRIMARY KEY,
|
|
username TEXT NOT NULL UNIQUE,
|
|
password_hash TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS app_session (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
|
|
created_at TIMESTAMPTZ NOT NULL,
|
|
last_seen_at TIMESTAMPTZ,
|
|
expires_at TIMESTAMPTZ NOT NULL
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_app_session_user_id ON app_session(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_app_session_expires_at ON app_session(expires_at);
|
|
|
|
-- =========================================
|
|
-- 2) Broker links + Zerodha auth artifacts
|
|
-- Mirrors: user_brokers.json, zerodha_sessions.json, zerodha_request_tokens.json
|
|
-- =========================================
|
|
|
|
-- Current connected broker record per user (plus "pending" fields)
|
|
CREATE TABLE IF NOT EXISTS user_broker (
|
|
user_id TEXT PRIMARY KEY REFERENCES app_user(id) ON DELETE CASCADE,
|
|
broker TEXT,
|
|
connected BOOLEAN NOT NULL DEFAULT FALSE,
|
|
|
|
access_token TEXT,
|
|
connected_at TIMESTAMPTZ,
|
|
|
|
api_key TEXT,
|
|
user_name TEXT,
|
|
broker_user_id TEXT,
|
|
|
|
-- pending fields (as you described)
|
|
pending_broker TEXT,
|
|
pending_api_key TEXT,
|
|
pending_api_secret TEXT,
|
|
pending_started_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_user_broker_broker ON user_broker(broker);
|
|
CREATE INDEX IF NOT EXISTS idx_user_broker_connected ON user_broker(connected);
|
|
|
|
-- Zerodha session history (can be multiple per user)
|
|
CREATE TABLE IF NOT EXISTS zerodha_session (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
|
|
linked_at TIMESTAMPTZ NOT NULL,
|
|
|
|
api_key TEXT,
|
|
access_token TEXT,
|
|
request_token TEXT,
|
|
|
|
user_name TEXT,
|
|
broker_user_id TEXT
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_zerodha_session_user_id ON zerodha_session(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_zerodha_session_linked_at ON zerodha_session(linked_at);
|
|
|
|
-- Latest/active request token per user (mirrors zerodha_request_tokens.json)
|
|
CREATE TABLE IF NOT EXISTS zerodha_request_token (
|
|
user_id TEXT PRIMARY KEY REFERENCES app_user(id) ON DELETE CASCADE,
|
|
request_token TEXT NOT NULL
|
|
);
|
|
|
|
-- =========================================
|
|
-- 3) Strategy config + engine status
|
|
-- Mirrors: strategy_config.json, engine_status.json
|
|
-- =========================================
|
|
|
|
-- Keep it simple: single-row table (config "current")
|
|
CREATE TABLE IF NOT EXISTS strategy_config (
|
|
id SMALLINT PRIMARY KEY DEFAULT 1,
|
|
strategy TEXT,
|
|
sip_amount NUMERIC,
|
|
|
|
sip_frequency_value INTEGER,
|
|
sip_frequency_unit TEXT,
|
|
|
|
mode TEXT, -- paper/live
|
|
broker TEXT,
|
|
|
|
-- legacy/optional fields
|
|
active BOOLEAN,
|
|
frequency TEXT,
|
|
frequency_days INTEGER,
|
|
unit TEXT,
|
|
next_run TIMESTAMPTZ
|
|
);
|
|
|
|
-- single-row engine status
|
|
CREATE TABLE IF NOT EXISTS engine_status (
|
|
id SMALLINT PRIMARY KEY DEFAULT 1,
|
|
status TEXT NOT NULL,
|
|
last_updated TIMESTAMPTZ NOT NULL
|
|
);
|
|
|
|
-- =========================================
|
|
-- 4) Logs / event streams
|
|
-- Mirrors: strategy_logs.json, engine.log (JSONL)
|
|
-- =========================================
|
|
|
|
-- strategy_logs.json
|
|
CREATE TABLE IF NOT EXISTS strategy_log (
|
|
seq BIGINT PRIMARY KEY,
|
|
ts TIMESTAMPTZ NOT NULL,
|
|
level TEXT,
|
|
category TEXT,
|
|
event TEXT,
|
|
message TEXT,
|
|
run_id TEXT,
|
|
meta JSONB
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_strategy_log_ts ON strategy_log(ts);
|
|
CREATE INDEX IF NOT EXISTS idx_strategy_log_run_id ON strategy_log(run_id);
|
|
CREATE INDEX IF NOT EXISTS idx_strategy_log_event ON strategy_log(event);
|
|
|
|
-- engine.log JSONL
|
|
CREATE TABLE IF NOT EXISTS engine_event (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
ts TIMESTAMPTZ NOT NULL,
|
|
event TEXT,
|
|
data JSONB,
|
|
message TEXT,
|
|
meta JSONB
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_engine_event_ts ON engine_event(ts);
|
|
CREATE INDEX IF NOT EXISTS idx_engine_event_event ON engine_event(event);
|
|
|
|
-- =========================================
|
|
-- 5) Engine state (paper + derived)
|
|
-- Mirrors: state_paper.json, state.json
|
|
-- =========================================
|
|
|
|
-- state_paper.json
|
|
CREATE TABLE IF NOT EXISTS engine_state_paper (
|
|
id SMALLINT PRIMARY KEY DEFAULT 1,
|
|
|
|
initial_cash NUMERIC,
|
|
cash NUMERIC,
|
|
total_invested NUMERIC,
|
|
|
|
nifty_units NUMERIC,
|
|
gold_units NUMERIC,
|
|
|
|
last_sip_ts TIMESTAMPTZ,
|
|
last_run TIMESTAMPTZ,
|
|
|
|
sip_frequency_value INTEGER,
|
|
sip_frequency_unit TEXT
|
|
);
|
|
|
|
-- state.json (lighter)
|
|
CREATE TABLE IF NOT EXISTS engine_state (
|
|
id SMALLINT PRIMARY KEY DEFAULT 1,
|
|
|
|
total_invested NUMERIC,
|
|
nifty_units NUMERIC,
|
|
gold_units NUMERIC,
|
|
|
|
last_sip_ts TIMESTAMPTZ,
|
|
last_run TIMESTAMPTZ
|
|
);
|
|
|
|
-- =========================================
|
|
-- 6) Paper broker (positions, orders, trades, equity curve)
|
|
-- Mirrors: paper_broker.json
|
|
-- =========================================
|
|
|
|
-- overall cash snapshot (paper_broker.json top-level cash)
|
|
CREATE TABLE IF NOT EXISTS paper_broker_account (
|
|
id SMALLINT PRIMARY KEY DEFAULT 1,
|
|
cash NUMERIC NOT NULL
|
|
);
|
|
|
|
-- positions map: symbol -> qty, avg_price, last_price
|
|
CREATE TABLE IF NOT EXISTS paper_position (
|
|
symbol TEXT PRIMARY KEY,
|
|
qty NUMERIC NOT NULL,
|
|
avg_price NUMERIC,
|
|
last_price NUMERIC,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- orders list
|
|
CREATE TABLE IF NOT EXISTS paper_order (
|
|
id TEXT PRIMARY KEY,
|
|
symbol TEXT NOT NULL,
|
|
side TEXT NOT NULL, -- buy/sell
|
|
qty NUMERIC NOT NULL,
|
|
price NUMERIC,
|
|
status TEXT NOT NULL, -- new/filled/cancelled/rejected etc
|
|
timestamp TIMESTAMPTZ NOT NULL
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_paper_order_ts ON paper_order(timestamp);
|
|
CREATE INDEX IF NOT EXISTS idx_paper_order_symbol ON paper_order(symbol);
|
|
CREATE INDEX IF NOT EXISTS idx_paper_order_status ON paper_order(status);
|
|
|
|
-- trades list
|
|
CREATE TABLE IF NOT EXISTS paper_trade (
|
|
id TEXT PRIMARY KEY,
|
|
order_id TEXT REFERENCES paper_order(id) ON DELETE SET NULL,
|
|
symbol TEXT NOT NULL,
|
|
side TEXT NOT NULL,
|
|
qty NUMERIC NOT NULL,
|
|
price NUMERIC NOT NULL,
|
|
timestamp TIMESTAMPTZ NOT NULL
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_paper_trade_ts ON paper_trade(timestamp);
|
|
CREATE INDEX IF NOT EXISTS idx_paper_trade_symbol ON paper_trade(symbol);
|
|
|
|
-- equity_curve list
|
|
CREATE TABLE IF NOT EXISTS paper_equity_curve (
|
|
timestamp TIMESTAMPTZ PRIMARY KEY,
|
|
equity NUMERIC NOT NULL,
|
|
pnl NUMERIC
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_paper_equity_curve_ts ON paper_equity_curve(timestamp);
|
|
|
|
-- =========================================
|
|
-- 7) MTM ledger + event ledger
|
|
-- Mirrors: mtm_ledger.csv, ledger.csv
|
|
-- =========================================
|
|
|
|
CREATE TABLE IF NOT EXISTS mtm_ledger (
|
|
timestamp TIMESTAMPTZ PRIMARY KEY,
|
|
|
|
nifty_units NUMERIC,
|
|
gold_units NUMERIC,
|
|
|
|
nifty_price NUMERIC,
|
|
gold_price NUMERIC,
|
|
|
|
nifty_value NUMERIC,
|
|
gold_value NUMERIC,
|
|
|
|
portfolio_value NUMERIC,
|
|
total_invested NUMERIC,
|
|
pnl NUMERIC
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_mtm_ledger_ts ON mtm_ledger(timestamp);
|
|
|
|
CREATE TABLE IF NOT EXISTS event_ledger (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
timestamp TIMESTAMPTZ NOT NULL,
|
|
event TEXT NOT NULL,
|
|
|
|
nifty_units NUMERIC,
|
|
gold_units NUMERIC,
|
|
|
|
nifty_price NUMERIC,
|
|
gold_price NUMERIC,
|
|
|
|
amount NUMERIC
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_event_ledger_ts ON event_ledger(timestamp);
|
|
CREATE INDEX IF NOT EXISTS idx_event_ledger_event ON event_ledger(event);
|
|
|
|
-- =========================================
|
|
-- 8) Market data cache (History Cache CSVs)
|
|
-- Mirrors: SYMBOL.csv {Date, Close}
|
|
-- =========================================
|
|
|
|
CREATE TABLE IF NOT EXISTS market_close (
|
|
symbol TEXT NOT NULL,
|
|
date DATE NOT NULL,
|
|
close NUMERIC NOT NULL,
|
|
PRIMARY KEY (symbol, date)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_market_close_symbol ON market_close(symbol);
|
|
CREATE INDEX IF NOT EXISTS idx_market_close_date ON market_close(date);
|