Files
Chan/ChanMacro/database.py
T

225 lines
7.6 KiB
Python

"""
database.py — SQLite schema initialization and connection management.
"""
import sqlite3
import os
from pathlib import Path
SCHEMA = """
-- ═══════════════════════════════════════════════
-- L0: Raw data tables
-- ═══════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS ohlcv_daily (
date TEXT NOT NULL,
symbol TEXT NOT NULL DEFAULT 'BTC/USDT:USDT',
open REAL,
high REAL,
low REAL,
close REAL,
volume REAL,
ema20 REAL,
ema60 REAL,
ema120 REAL,
atr_14 REAL,
bb_width REAL,
adx_14 REAL,
PRIMARY KEY (date, symbol)
);
CREATE TABLE IF NOT EXISTS breadth_daily (
date TEXT PRIMARY KEY,
total_tracked INTEGER DEFAULT 50,
advance_top50 INTEGER DEFAULT 0,
decline_top50 INTEGER DEFAULT 0,
above_ema20_top50 INTEGER DEFAULT 0,
new_highs_20d_top50 INTEGER DEFAULT 0,
btc_dominance REAL,
advance_top20 INTEGER DEFAULT 0,
advance_top30 INTEGER DEFAULT 0,
above_ema20_top20 INTEGER DEFAULT 0,
above_ema20_top30 INTEGER DEFAULT 0,
new_highs_20d_top20 INTEGER DEFAULT 0,
new_highs_20d_top30 INTEGER DEFAULT 0,
fetched_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS derivatives (
date TEXT NOT NULL,
symbol TEXT NOT NULL DEFAULT 'BTC/USDT:USDT',
funding_rate REAL,
open_interest REAL,
oi_24h_change_pct REAL,
long_liquidations REAL,
short_liquidations REAL,
basis_annualised_pct REAL,
source TEXT DEFAULT 'binance',
fetched_at TEXT DEFAULT (datetime('now')),
PRIMARY KEY (date, symbol)
);
CREATE TABLE IF NOT EXISTS etf_flow (
date TEXT NOT NULL,
product TEXT NOT NULL,
net_flow_million REAL NOT NULL,
price REAL,
source TEXT DEFAULT 'farside',
fetched_at TEXT DEFAULT (datetime('now')),
PRIMARY KEY (date, product)
);
CREATE TABLE IF NOT EXISTS stablecoin_supply (
date TEXT NOT NULL,
token TEXT NOT NULL,
chain TEXT NOT NULL DEFAULT 'all',
supply REAL NOT NULL,
source TEXT DEFAULT 'defillama',
fetched_at TEXT DEFAULT (datetime('now')),
PRIMARY KEY (date, token, chain)
);
-- ═══════════════════════════════════════════════
-- L3: Regime history
-- ═══════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS regime_history (
date TEXT PRIMARY KEY,
regime TEXT NOT NULL,
confidence REAL,
regime_version TEXT NOT NULL DEFAULT 'v1_price_breadth_vol',
maturity_score REAL DEFAULT 50.0,
all_scores_json TEXT DEFAULT '{}',
prior_regime TEXT,
confirmation_days INTEGER DEFAULT 1,
created_at TEXT DEFAULT (datetime('now'))
);
-- ═══════════════════════════════════════════════
-- ★ signal_features — THE moat
-- ═══════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS signal_features (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date TEXT NOT NULL,
signal_type TEXT NOT NULL,
signal_version TEXT NOT NULL DEFAULT 'b3_v1',
symbol TEXT DEFAULT 'BTC/USDT:USDT',
-- ★★ Version control (most important fields)
regime_version TEXT NOT NULL DEFAULT 'v1_price_breadth_vol',
signal_grade TEXT,
signal_strength REAL,
-- Market State Vector snapshot
regime TEXT NOT NULL,
regime_confidence REAL,
regime_maturity_score REAL DEFAULT 50.0,
market_state_hash TEXT,
state_embedding TEXT DEFAULT '[]',
breadth_top20 REAL,
breadth_top30 REAL,
breadth_top50 REAL,
breadth_bucket TEXT,
breadth_divergence REAL,
oi_state TEXT,
volatility_regime TEXT,
price_structure_score REAL,
-- Chan context (V5+)
chan_trend_direction TEXT,
chan_pivot_count INTEGER,
chan_divergence_type TEXT,
-- Outcomes
entry_price REAL,
result_1d REAL,
result_3d REAL,
result_5d REAL,
result_7d REAL,
result_14d REAL,
max_favorable_excursion REAL,
max_adverse_excursion REAL,
is_win_7d INTEGER,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE INDEX IF NOT EXISTS idx_sf_regime ON signal_features(regime);
CREATE INDEX IF NOT EXISTS idx_sf_signal ON signal_features(signal_type);
CREATE INDEX IF NOT EXISTS idx_sf_oi_state ON signal_features(oi_state);
CREATE INDEX IF NOT EXISTS idx_sf_date ON signal_features(date);
CREATE INDEX IF NOT EXISTS idx_sf_state_hash ON signal_features(market_state_hash);
CREATE INDEX IF NOT EXISTS idx_sf_regime_version ON signal_features(regime_version);
CREATE INDEX IF NOT EXISTS idx_sf_signal_version ON signal_features(signal_version);
-- ═══════════════════════════════════════════════
-- Expectancy cache (raw counts, NOT posteriors)
-- ═══════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS expectancy_cache (
state_hash TEXT NOT NULL,
signal_type TEXT NOT NULL,
wins_weighted REAL DEFAULT 0,
losses_weighted REAL DEFAULT 0,
sum_return_7d REAL DEFAULT 0,
sum_return_sq_7d REAL DEFAULT 0,
effective_samples REAL DEFAULT 0,
sufficiency TEXT DEFAULT 'INSUFFICIENT',
updated_at TEXT DEFAULT (datetime('now')),
PRIMARY KEY (state_hash, signal_type)
);
-- ═══════════════════════════════════════════════
-- Similarity outcome (KNN weight learning, Phase D)
-- ═══════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS similarity_outcome (
id INTEGER PRIMARY KEY AUTOINCREMENT,
state_a_hash TEXT,
state_b_hash TEXT,
distance REAL,
actual_return_gap REAL,
dimension_weights_json TEXT DEFAULT '{}',
created_at TEXT DEFAULT (datetime('now'))
);
-- ═══════════════════════════════════════════════
-- chan_context — Chan theory integration (V1 empty)
-- ═══════════════════════════════════════════════
CREATE TABLE IF NOT EXISTS chan_context (
date TEXT NOT NULL,
timeframe TEXT NOT NULL DEFAULT '1d',
trend_direction TEXT,
trend_strength REAL,
pivot_count INTEGER,
pivot_level TEXT,
signal_type TEXT,
signal_strength REAL,
divergence_type TEXT,
chan_structure_score REAL,
alignment_score REAL,
raw_context_json TEXT DEFAULT '{}',
PRIMARY KEY (date, timeframe)
);
"""
def init_db(db_path: str = "data/macro.db") -> sqlite3.Connection:
"""Initialize database: create directory and all tables."""
Path(db_path).parent.mkdir(parents=True, exist_ok=True)
conn = sqlite3.connect(db_path)
conn.executescript(SCHEMA)
conn.commit()
return conn
def get_connection(db_path: str = "data/macro.db") -> sqlite3.Connection:
"""Get a database connection. Creates tables if first run."""
if not os.path.exists(db_path):
return init_db(db_path)
conn = sqlite3.connect(db_path)
conn.row_factory = sqlite3.Row
return conn