Status: MERGED FINAL — Panel-reviewed, ready for coding bot Base: Claude Opus 4.6 (complete, unmodified) + unique cherry-picks from DeepSeek V3.1, Gemini 3.1 Pro, GPT-4.1, Grok 4 Fast, Grok 4.1, Sonar Reasoning Pro Primary trading venue: Stock broker (TBD) Scope: Data collection spec — SQLite schema, API endpoints, cadence, storage estimates, implementation checklist, SQL queries Date: 2026-03-15
This spec defines the TA (Technical Analysis) data collection engine for the Stocks Desk. It adapts the existing forex TA engine to equities-specific structure: real volume, session boundaries, gaps, VWAP, earnings catalysts, options flow, institutional positioning, and cross-market signals. The engine feeds the Stocks Desk analyst AIs with structured, schema-enforced data.
Guiding principle: Build in layers. Price + indicators first. Session + gaps second. VWAP + S&R third. Only add external data sources after the core is proven stable.
supertrend_value — current SuperTrend line price levelsupertrend_direction — 1 (bullish) or -1 (bearish)supertrend_flip — boolean, true on the candle where direction changedsupertrend_candles_since_flip — integer, how many candles since last direction changeatr_14 — ATR with period 14 (primary)atr_5 — ATR with period 5 (for short-term volatility)atr_pct — ATR as percentage of closing price (normalizes across price levels)supertrend_distance_pct — (close - supertrend_value) / close * 100CREATE TABLE IF NOT EXISTS candles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
timeframe TEXT NOT NULL, -- '5min','15min','1H','Daily','Weekly'
ts_open INTEGER NOT NULL, -- Unix timestamp, candle open time
ts_close INTEGER NOT NULL,
open REAL NOT NULL,
high REAL NOT NULL,
low REAL NOT NULL,
close REAL NOT NULL,
volume INTEGER NOT NULL,
adjusted_close REAL, -- split/dividend adjusted
session_type TEXT, -- 'premarket','rth','afterhours'
halted INTEGER DEFAULT 0, -- 1 if this candle overlaps a halt
supertrend_value REAL,
supertrend_direction INTEGER,
supertrend_flip INTEGER DEFAULT 0,
supertrend_candles_since_flip INTEGER,
atr_14 REAL,
atr_5 REAL,
atr_pct REAL,
supertrend_distance_pct REAL,
UNIQUE(ticker, timeframe, ts_open)
);
CREATE INDEX IF NOT EXISTS idx_candles_ticker_tf_ts ON candles(ticker, timeframe, ts_open DESC);
CREATE INDEX IF NOT EXISTS idx_candles_session ON candles(ticker, session_type, ts_open DESC);
zigzag_points — JSON array of {ts, price, type: 'HH'|'HL'|'LH'|'LL'} for last 50 ZigZag pivots per timeframetrendline_support — JSON: {slope, intercept, touches, age_candles, slope_raw, slope_pct_per_day, r_squared}trendline_resistance — same schematrendline_break_up — boolean on the candle a resistance TL was brokentrendline_break_down — boolean on the candle a support TL was brokentrendline_break_strength — (break_close - trendline_value) / ATR14All trend line slopes use candle-index as the x-axis (sequential candle numbering, ignoring clock time). Store two slope forms:
slope_raw — price change per candle on native timeframeslope_pct_per_day — percentage change per trading day (1 day = 78×5min = 26×15min = 6.5×1H = 1×Daily candle)When comparing slopes cross-timeframe, use slope_pct_per_day for apples-to-apples comparison. Never compare slope_raw values across timeframes directly.
CREATE TABLE IF NOT EXISTS trendlines (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
timeframe TEXT NOT NULL,
tl_type TEXT NOT NULL, -- 'support' or 'resistance'
anchor_ts_1 INTEGER NOT NULL,
anchor_ts_2 INTEGER NOT NULL,
slope_raw REAL,
slope_pct_per_day REAL,
intercept REAL,
touches INTEGER DEFAULT 2,
age_candles INTEGER,
r_squared REAL,
broken INTEGER DEFAULT 0,
broken_ts INTEGER,
break_strength REAL,
created_ts INTEGER NOT NULL,
updated_ts INTEGER NOT NULL
);
Tracks when multiple signals fire simultaneously. Used for confluence scoring.
event_count — how many distinct signal types fired on this candleevent_types — JSON array of signal type stringsmulti_tf_alignment — boolean: are SuperTrend directions aligned across 3+ timeframes?sr_zone_test — boolean: is price within 0.5 ATR of an active S&R zone?Layer 1 — Divergence Detection (fixed thresholds always)
rsi_divergence_bull_regular — boolean: price lower low, RSI higher lowrsi_divergence_bear_regular — boolean: price higher high, RSI lower highrsi_divergence_bull_hidden — boolean (note: lower predictive value, use cautiously)rsi_divergence_bear_hidden — boolean (lower predictive value)Layer 2 — Overbought/Oversold Labels (adaptive thresholds for confluence scoring only)
rsi_regime_label — 'overbought' | 'oversold' | 'neutral'rsi_adaptive_ob_threshold — current OB threshold in usersi_adaptive_os_threshold — current OS threshold in useStored fields
rsi_14 — raw RSI value (always stored, both layers use this)rsi_divergence_detected — boolean (from Layer 1)rsi_regime_label — text (from Layer 2)macd_line — 12/26 EMA differencemacd_signal — 9 EMA of MACD linemacd_histogram — MACD minus signalmacd_cross_up — boolean: histogram crosses from negative to positivemacd_cross_down — booleanmacd_divergence — boolean: price and MACD histogram divergingstoch_k — %K (14,3)stoch_d — %D signalstoch_cross_up — %K crosses above %D below 20stoch_cross_down — %K crosses below %D above 80adx_14 — trend strength (>25 = trending, <20 = choppy)di_plus — +DIdi_minus — -DIadx_trending — boolean: ADX > 25CREATE TABLE IF NOT EXISTS indicators (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
timeframe TEXT NOT NULL,
ts INTEGER NOT NULL,
rsi_14 REAL,
rsi_regime_label TEXT,
rsi_adaptive_ob_threshold REAL,
rsi_adaptive_os_threshold REAL,
rsi_divergence_detected INTEGER DEFAULT 0,
rsi_divergence_bull_regular INTEGER DEFAULT 0,
rsi_divergence_bear_regular INTEGER DEFAULT 0,
macd_line REAL,
macd_signal REAL,
macd_histogram REAL,
macd_cross_up INTEGER DEFAULT 0,
macd_cross_down INTEGER DEFAULT 0,
macd_divergence INTEGER DEFAULT 0,
stoch_k REAL,
stoch_d REAL,
stoch_cross_up INTEGER DEFAULT 0,
stoch_cross_down INTEGER DEFAULT 0,
adx_14 REAL,
di_plus REAL,
di_minus REAL,
adx_trending INTEGER DEFAULT 0,
bb_upper REAL,
bb_middle REAL,
bb_lower REAL,
bb_width_pct REAL,
bb_squeeze INTEGER DEFAULT 0,
keltner_upper REAL,
keltner_lower REAL,
UNIQUE(ticker, timeframe, ts)
);
Computation optimization — checkpoint system
cumulative_price_volume — sum of (typical_price × volume) from anchor to checkpoint datecumulative_volume — sum of volume from anchor to checkpoint dateFields (intraday, computed per RTH candle)
vwap_daily — cumulative VWAP from 9:30 openvwap_std1_upper / vwap_std1_lower — ±1 standard deviation bandsvwap_std2_upper / vwap_std2_lower — ±2 standard deviation bandsprice_vs_vwap_pct — (close - vwap_daily) / vwap_daily × 100vwap_earnings — VWAP anchored to last earnings date (active for 30 days post-earnings only, then NULL)vwap_52w_high — VWAP anchored to 52-week high datevwap_52w_low — VWAP anchored to 52-week low dateAnchored VWAP checkpoints table
CREATE TABLE IF NOT EXISTS vwap_checkpoints (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
anchor_type TEXT NOT NULL, -- 'earnings','52w_high','52w_low'
anchor_date TEXT NOT NULL, -- YYYY-MM-DD
checkpoint_date TEXT NOT NULL,
cumulative_price_volume REAL NOT NULL,
cumulative_volume REAL NOT NULL,
cumulative_sq_deviation REAL, -- for std dev bands
UNIQUE(ticker, anchor_type, anchor_date, checkpoint_date)
);
Volume curve baseline table
CREATE TABLE IF NOT EXISTS volume_curve_baseline (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
time_bucket_start TEXT NOT NULL, -- HH:MM, 5-min buckets 09:30..15:55
avg_cumulative_volume_20d REAL,
stddev_cumulative_volume_20d REAL,
updated_date TEXT NOT NULL,
UNIQUE(ticker, time_bucket_start)
);
Fields (per candle)
rvol — current cumulative volume / avg_cumulative_volume_20d for this time bucketrvol_zscore — (current_cumulative_volume - avg) / stddevrvol_segment — RVOL broken down by session segment: open (9:30–10:00), morning (10:00–12:00), midday (12:00–14:00), afternoon (14:00–15:00), close (15:00–16:00)Update baseline daily after market close. RVOL computed on-the-fly during RTH by looking up the current time bucket.
Per-session computation
vpoc — Volume Point of Control (bin with highest volume)value_area_high / value_area_low — range containing 70% of total session volume, centered on VPOCvalue_area_width_pct — (VAH - VAL) / VPOC × 100 (narrow = consensus, wide = contested)vpoc_5d, vah_5d, val_5dCREATE TABLE IF NOT EXISTS volume_profile (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
date TEXT NOT NULL, -- YYYY-MM-DD
vpoc REAL,
value_area_high REAL,
value_area_low REAL,
value_area_width_pct REAL,
vpoc_5d REAL,
vah_5d REAL,
val_5d REAL,
created_ts INTEGER NOT NULL,
UNIQUE(ticker, date)
);
VPOC and VAH/VAL feed directly into the S&R Zone Engine as Method 12 (see Section 17).
Tier 0 (v1 — free)
spy_max_pain, qqq_max_pain (calculate from CBOE delayed quotes or Tradier API free tier)spy_put_call_ratio, qqq_put_call_ratio — from CBOE daily PCR (free, cboe.com/us/options/market_statistics/daily/)Tier 1 ($29/month Polygon.io — v2)
max_pain, put_call_ratio, iv_rank, call_wall (strike with max call OI), put_wall (strike with max put OI)Tier 2 ($50–100/month — v3)
Tier 3 (v4+ — internal GEX model)
Options levels table
CREATE TABLE IF NOT EXISTS options_levels (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
snapshot_ts INTEGER NOT NULL,
max_pain REAL,
put_call_ratio REAL,
iv_rank REAL, -- ATM IV vs 252-day history (0-100)
call_wall REAL, -- strike with max call OI
put_wall REAL, -- strike with max put OI
gex REAL, -- Tier 2+ only
gex_flip_price REAL, -- Tier 2+ only
zero_dte_gex REAL, -- Tier 2+ only
data_tier INTEGER DEFAULT 0, -- 0,1,2,3
UNIQUE(ticker, snapshot_ts)
);
SQLite write strategy for options_levels
PRAGMA journal_mode=WALstocks-options.db)Primary grid only for v1. Secondary grid optional for v2.
| Price Range | Primary Grid | Secondary Grid |
|---|---|---|
| Under $25 | $5 | $1 |
| $25–$100 | $25 | $5 |
| $100–$500 | $50 | $10 |
| Over $500 | $100 | $25 |
Store raw S&R levels, not the grid configuration. The grid is a detection method, not a permanent property. When a stock crosses a price tier boundary (e.g., splits from $15 to $7.50), recalculate zones without touching historical zone records.
CREATE TABLE IF NOT EXISTS ticker_config (
ticker TEXT PRIMARY KEY,
sector TEXT,
sector_etf TEXT, -- e.g., 'XLK', 'XLF'
has_options INTEGER DEFAULT 1,
extended_hours_available INTEGER DEFAULT 1,
min_liquidity_threshold REAL, -- minimum avg daily volume
price_tier TEXT, -- 'sub25','25_100','100_500','500plus'
tick_significance_pct REAL, -- $0.01 as % of current price
atr_zone_width_multiplier REAL,
spread_threshold_normal REAL,
min_meaningful_move_pct REAL,
round_number_primary_grid REAL,
round_number_secondary_grid REAL,
data_source TEXT, -- 'polygon','alpaca','yfinance'
data_source_quality INTEGER, -- 1-5 rating
last_updated INTEGER
);
Recalculate price scaler fields whenever a stock crosses a tier boundary. Apply to: S&R zone boundary rounding, ATR buffer calculations, spread z-score baseline, trend line slope normalization.
Confluence fires when multiple independent signals align on the same candle or within the same session.
CREATE TABLE IF NOT EXISTS confluence_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
timeframe TEXT NOT NULL,
ts INTEGER NOT NULL,
event_type TEXT NOT NULL,
direction TEXT NOT NULL, -- 'bullish' or 'bearish'
score INTEGER NOT NULL, -- 0-5 simple count
score_label TEXT NOT NULL, -- 'low','medium','high'
supertrend_aligned INTEGER DEFAULT 0,
vwap_aligned INTEGER DEFAULT 0,
sr_zone_aligned INTEGER DEFAULT 0,
volume_aligned INTEGER DEFAULT 0,
rsi_aligned INTEGER DEFAULT 0,
earnings_proximity_days INTEGER,
halt_involved INTEGER DEFAULT 0,
corporate_action_within_5d INTEGER DEFAULT 0,
outcome_direction TEXT, -- filled post-hoc
outcome_pct REAL,
outcome_candles INTEGER,
brier_score REAL,
UNIQUE(ticker, timeframe, ts, event_type)
);
short_interest_shares — shares sold shortshort_interest_pct_float — short interest / float shares (requires float data — see below)days_to_cover — short_interest / avg_daily_volume_30dshort_interest_change_pct — vs prior reporting period[PANEL: GPT-4.1] Short volume (daily) provides squeeze signals more timely than bi-monthly FINRA short interest. FINRA publishes daily short volume for free at finra.org/finra-data. Fields: daily_short_volume, daily_short_volume_pct (short volume / total volume for that day). This is not the same as short interest (which is the cumulative open short position), but it tracks day-to-day shorting activity in near-real-time.
CREATE TABLE IF NOT EXISTS daily_short_volume (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
date TEXT NOT NULL,
short_volume INTEGER,
total_volume INTEGER,
short_volume_pct REAL,
source TEXT DEFAULT 'finra',
UNIQUE(ticker, date)
);
CREATE TABLE IF NOT EXISTS institutional_positioning (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
date TEXT NOT NULL,
shares_outstanding INTEGER,
float_shares INTEGER,
float_turnover_ratio REAL, -- daily volume / float
float_change_event INTEGER DEFAULT 0, -- 1 if SEC S-3 or 8-K dilution event
float_change_event_type TEXT,
float_change_event_date TEXT,
float_source TEXT, -- 'fmp','sec_edgar','yfinance'
short_interest_shares INTEGER,
short_interest_pct_float REAL,
days_to_cover REAL,
short_interest_change_pct REAL,
short_interest_date TEXT,
insider_net_shares_30d INTEGER, -- net insider buys minus sells (30 days)
insider_cluster_buy INTEGER DEFAULT 0, -- 1 if 3+ insiders bought in 30 days
thirteenf_held_pct REAL, -- % shares held by 13F filers (quarterly context only)
cost_to_borrow_pct REAL, -- annualized CTB rate (if available)
borrow_availability TEXT, -- 'easy','medium','hard','no_data'
UNIQUE(ticker, date)
);
Sources:
[PANEL: DeepSeek V3.1] SEC publishes a daily threshold list of stocks with persistent delivery failures (potential short restriction zone). Being on the threshold list changes price action around squeezes — call walls become more important, put hedges become cheaper. Source: SEC website, free. File: threshold list CSV.
CREATE TABLE IF NOT EXISTS threshold_list (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
date TEXT NOT NULL,
on_threshold_list INTEGER DEFAULT 1,
UNIQUE(ticker, date)
);
CREATE TABLE IF NOT EXISTS insider_transactions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
filed_date TEXT NOT NULL,
transaction_date TEXT NOT NULL,
insider_name TEXT,
insider_title TEXT,
transaction_type TEXT, -- 'buy','sell','option_exercise','auto_plan_sale'
shares INTEGER,
price REAL,
total_value REAL,
auto_plan INTEGER DEFAULT 0, -- 1 if Rule 10b5-1
source TEXT DEFAULT 'openinsider'
);
Dark pool sentiment has been removed from v1. Replace with large_trade_direction derived from time-and-sales data: classify prints > 10,000 shares against NBBO midpoint using the Lee-Ready algorithm (trade at or above ask = buy, at or below bid = sell, at midpoint = neutral). This avoids the FINRA ATS data problem (2-4 week lag, no price info, no directionality).
CREATE TABLE IF NOT EXISTS large_trades (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
ts INTEGER NOT NULL,
price REAL NOT NULL,
shares INTEGER NOT NULL,
direction TEXT, -- 'buy','sell','neutral' (Lee-Ready)
vs_nbbo_midpoint TEXT, -- 'above','below','at'
block_size_atr REAL -- trade size relative to ATR for context
);
spy_correlation_20d — 20-day rolling correlation vs SPYqqq_correlation_20d — vs QQQiwm_correlation_20d — vs IWM (small-cap proxy)sector_etf_correlation_20d — vs the stock's sector ETFbeta_spy_60d — 60-day rolling beta vs SPYrelative_performance_1d — stock return minus SPY return todayrelative_performance_5d — rolling 5-dayrelative_performance_20d — rolling 20-dayTrack top 3 outperforming and bottom 3 underperforming sectors (not all 11 ranks). Binary per sector: outperforming or underperforming vs SPY. Full rotation matrix deferred to v2.
Sector ETF mappings (GICS):
CREATE TABLE IF NOT EXISTS cross_market (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
date TEXT NOT NULL,
spy_correlation_20d REAL,
qqq_correlation_20d REAL,
iwm_correlation_20d REAL,
sector_etf_correlation_20d REAL,
beta_spy_60d REAL,
relative_performance_1d REAL,
relative_performance_5d REAL,
relative_performance_20d REAL,
vix_level REAL,
vix_term_structure TEXT, -- 'contango','backwardation','flat'
yield_10y REAL,
yield_2y REAL,
yield_curve_spread REAL, -- 10Y minus 2Y
spy_circuit_breaker_level_1 REAL, -- SPY prev close * 0.93
spy_circuit_breaker_level_2 REAL, -- SPY prev close * 0.87
spy_circuit_breaker_level_3 REAL, -- SPY prev close * 0.80
circuit_breaker_proximity REAL, -- current SPY / nearest CB level
circuit_breaker_warning INTEGER DEFAULT 0, -- 1 if within 2% of Level 1
sector_outperforming_top3 TEXT, -- JSON array of top 3 sector ETF tickers
sector_underperforming_bottom3 TEXT,
UNIQUE(ticker, date)
);
Circuit breaker fields: calculate daily from SPY's previous close (trivial math). When circuit_breaker_warning = 1, reduce all bullish confluence scores by 3 points — the market is in crash dynamics, bullish signals are unreliable.
rs_vs_spy_pct_1d / _5d / _20d / _60d — stock return minus SPY return for each periodrs_vs_sector_pct_1d / _5d / _20d — stock return minus sector ETF returnrs_rank_universe — rank in tracked stock universe (1 = strongest)rs_rank_sector — rank within sectorrs_trend — 'improving' | 'stable' | 'deteriorating' (based on RS change over 5 days)rs_new_high — boolean: stock made new RS high vs SPY while absolute price did notCREATE TABLE IF NOT EXISTS relative_strength (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
date TEXT NOT NULL,
rs_vs_spy_pct_1d REAL,
rs_vs_spy_pct_5d REAL,
rs_vs_spy_pct_20d REAL,
rs_vs_spy_pct_60d REAL,
rs_vs_sector_pct_1d REAL,
rs_vs_sector_pct_5d REAL,
rs_vs_sector_pct_20d REAL,
rs_rank_universe INTEGER,
rs_rank_sector INTEGER,
rs_trend TEXT,
rs_new_high INTEGER DEFAULT 0,
UNIQUE(ticker, date)
);
Cadence: compute daily after market close. RS ranking requires all tracked stocks to be processed first, then rank.
CREATE TABLE IF NOT EXISTS session_data (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
date TEXT NOT NULL,
premarket_high REAL,
premarket_low REAL,
premarket_open REAL,
premarket_close REAL, -- price at 9:29 AM
premarket_volume INTEGER,
premarket_gap_from_prior_close_pct REAL,
rth_open REAL, -- 9:30 AM first print
rth_high REAL,
rth_low REAL,
rth_close REAL,
rth_volume INTEGER,
opening_range_high REAL, -- first 30-min high
opening_range_low REAL,
opening_range_width_atr REAL,
afterhours_high REAL,
afterhours_low REAL,
afterhours_close REAL, -- last print before 8:00 PM
afterhours_volume INTEGER,
gap_from_prior_close_pct REAL, -- RTH open vs prior RTH close
gap_type TEXT, -- 'earnings','news','technical' (see Section 16)
gap_filled_intraday INTEGER DEFAULT 0,
moc_proxy_volume INTEGER, -- volume 3:45-4:00 PM (MOC imbalance proxy)
moc_proxy_direction TEXT, -- 'up' or 'down' based on 3:45-4:00 PM price
extended_hours_available INTEGER DEFAULT 1,
UNIQUE(ticker, date)
);
For earnings reactions from AMC reporters: earnings_reaction_price = price at 4:15 PM ET; earnings_reaction_range = after-hours high minus after-hours low. For BMO reporters: earnings_reaction_price = price at 9:00 AM ET (30 min before open).
CREATE TABLE IF NOT EXISTS halt_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
halt_time_utc INTEGER NOT NULL,
resume_time_utc INTEGER,
halt_reason_code TEXT, -- T1=news_pending,T2=news_released,LUDP=limit_up_down,M1/M2/M3=circuit_breaker
pre_halt_price REAL,
resume_price REAL,
halt_gap_pct REAL, -- (resume - pre_halt) / pre_halt
halt_duration_seconds INTEGER,
halt_during_sr_zone_test INTEGER DEFAULT 0, -- price within S&R zone when halted
outcome_tagged INTEGER DEFAULT 0 -- any outcome that includes this halt gets halt_involved=1
);
CREATE TABLE IF NOT EXISTS luld_bands (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
ts INTEGER NOT NULL,
upper_band REAL NOT NULL,
lower_band REAL NOT NULL,
UNIQUE(ticker, ts)
);
Sources: NYSE halt feed (nyse.com/trade-halt-current, free CSV), Nasdaq halt feed (nasdaqtrader.com/trader.aspx?id=TradeHalts, free). Poll every 30 seconds during RTH. Flag any candle that overlaps a halt period with halted=1 in the candles table. LULD bands: store as dynamic S&R zones with source='circuit_breaker' and zero decay.
hv_20d — 20-day historical volatility (annualized)hv_60d — 60-day HVhv_percentile_252d — HV percentile vs last 252 trading days (0-100)vol_regime — 'low' (<25th pct) | 'normal' (25-75th) | 'high' (>75th)kaufman_er — Kaufman Efficiency Ratio (0 = choppy, 1 = perfectly trending)bb_squeeze — boolean: Bollinger Band width below Keltner Channel width (volatility compression)vol_expanding — boolean: HV rising for 5+ consecutive daysiv_rank — ATM IV percentile vs 252-day historyiv_percentile — % of days in past year with lower IV than todayiv_skew — put IV minus call IV at same deltaiv_term_structure — front-month vs back-month IV relationshipCREATE TABLE IF NOT EXISTS volatility_regime (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
date TEXT NOT NULL,
hv_20d REAL,
hv_60d REAL,
hv_percentile_252d REAL,
vol_regime TEXT,
kaufman_er REAL,
bb_squeeze INTEGER DEFAULT 0,
vol_expanding INTEGER DEFAULT 0,
iv_rank REAL, -- v2+
iv_percentile REAL, -- v2+
iv_skew REAL, -- v2+
UNIQUE(ticker, date)
);
[PANEL: Opus (aplus)] Store consensus estimates BEFORE earnings. Without them, earnings surprise cannot be calculated.
CREATE TABLE IF NOT EXISTS earnings_estimates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
earnings_date TEXT NOT NULL,
eps_consensus REAL,
eps_high_estimate REAL,
eps_low_estimate REAL,
revenue_consensus REAL,
revenue_high_estimate REAL,
revenue_low_estimate REAL,
num_analysts INTEGER,
estimate_revision_30d REAL, -- change in consensus EPS over 30 days
estimate_revision_direction TEXT, -- 'up','down','flat'
positive_revision_momentum INTEGER DEFAULT 0, -- 3+ months of upward revisions
source TEXT DEFAULT 'fmp',
pulled_date TEXT NOT NULL,
UNIQUE(ticker, earnings_date, pulled_date)
);
Source: Financial Modeling Prep API /analyst-estimates endpoint (free tier). Pull weekly; pull daily in the 5 days before earnings.
CREATE TABLE IF NOT EXISTS earnings_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
earnings_date TEXT NOT NULL,
report_time TEXT NOT NULL, -- 'bmo' (before market open) or 'amc' (after market close)
eps_actual REAL,
eps_consensus REAL,
eps_surprise_pct REAL, -- (actual - consensus) / abs(consensus) * 100
revenue_actual REAL,
revenue_consensus REAL,
revenue_surprise_pct REAL,
implied_move_pct REAL, -- pre-earnings ATM straddle / stock price (v2, needs options)
actual_move_pct REAL, -- gap from prior close
reaction_price REAL, -- 4:15 PM for AMC, 9:00 AM for BMO
reaction_range REAL, -- extended-hours H-L
post_earnings_gap_pct REAL, -- RTH open vs prior RTH close
gap_filled_within_5d INTEGER,
gap_filled_within_20d INTEGER,
price_1d_post REAL, -- for multi-day tail tracking
price_5d_post REAL,
price_10d_post REAL,
price_20d_post REAL, -- 4-week post-earnings drift
historical_beat_rate REAL, -- % of last 8 quarters with positive surprise
historical_avg_move_pct REAL, -- avg absolute move on earnings day (last 8 quarters)
UNIQUE(ticker, earnings_date)
);
[PANEL: Sonar Reasoning Pro] Track the 2-week post-earnings tail — not just the gap. Pattern matters: some stocks gap and hold, others gap and fill, others have a 5-day reaction. Fields price_1d_post through price_20d_post above capture this.
CREATE TABLE IF NOT EXISTS corporate_actions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
action_date TEXT NOT NULL,
action_type TEXT NOT NULL, -- 'secondary_offering','buyback_announcement','buyback_execution','merger_announcement','spinoff','debt_offering','shelf_registration','stock_split','reverse_split','dividend_ex_date','special_dividend'
action_details TEXT, -- JSON: dollar amounts, share counts, terms
price_impact_expected TEXT, -- 'dilutive','accretive','neutral','unknown'
source_filing TEXT, -- SEC filing URL or news source
price_at_announcement REAL,
price_1d_after REAL,
price_5d_after REAL
);
Sources: SEC EDGAR 8-K RSS feed (free, real-time — filter by form type 8-K, parse for offering/buyback/M&A keywords); Financial Modeling Prep corporate actions endpoint (free tier).
Cross-references:
corporate_action_within_5d boolean to all confluence_events and outcome tracking[PANEL: DeepSeek V3.1] Companies are prohibited from repurchasing shares in the ~30 days before earnings. During blackout, mechanical buyback support disappears. Track blackout windows as derived from earnings dates (earnings_date minus 30 days = start of blackout). No external data source needed beyond the earnings calendar.
CREATE TABLE IF NOT EXISTS buyback_blackout (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
blackout_start TEXT NOT NULL,
blackout_end TEXT NOT NULL, -- earnings_date
UNIQUE(ticker, blackout_start)
);
Deferred to v2. Patterns are real but weak (~0.5% edge per pattern) and require years of data to identify reliably. They do not generalize well across market regimes.
Exception: collect the following flags now (zero engineering cost, just derive from dates):
opex_week — boolean: third Friday options expiration weekopex_day — boolean: third Fridayquarter_end — boolean: last 5 trading days of quarter (window dressing flows)santa_rally_window — boolean: last 5 trading days of December + first 2 days of Januaryearnings_season_active — boolean: majority of S&P 500 reporting (approx weeks 2-5 of each quarter)CREATE TABLE IF NOT EXISTS derived_metrics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
date TEXT NOT NULL,
forward_return_1d REAL, -- next day's close vs today's close (filled post-hoc)
forward_return_5d REAL,
forward_return_20d REAL,
gap_adjusted_return_1d REAL, -- accounts for gaps
max_adverse_excursion_5d REAL, -- worst drawdown over next 5 days
max_favorable_excursion_5d REAL, -- best move over next 5 days
brier_score_st_flip REAL, -- prediction accuracy for ST flips on this ticker
brier_score_sr_test REAL, -- prediction accuracy for S&R zone tests
UNIQUE(ticker, date)
);
stocks-core.db — candles, indicators, session_data, trendlinesstocks-levels.db — sr_zones, vwap_checkpoints, volume_profile, luld_bandsstocks-events.db — earnings_events, earnings_estimates, corporate_actions, halt_events, gap_events, confluence_eventsstocks-positioning.db — institutional_positioning, insider_transactions, large_trades, daily_short_volume, threshold_liststocks-options.db — options_levels (rolling 5-day window)stocks-crossmarket.db — cross_market, relative_strength, volatility_regime, volume_curve_baselinePRAGMA journal_mode=WAL;
PRAGMA synchronous=NORMAL;
PRAGMA cache_size=-64000; -- 64MB cache
PRAGMA temp_store=memory;
PRAGMA mmap_size=536870912; -- 512MB mmap
| Data Type | Frequency | Session |
|---|---|---|
| 5min candles | Real-time | RTH + extended |
| 15min, 1H candles | Derived | RTH |
| Daily candles | EOD | RTH |
| VWAP | Real-time (per candle) | RTH |
| RVOL | Per candle (lookup table) | RTH |
| S&R zones | Recalculate every 15min | RTH |
| Options levels (Tier 0) | Daily at 3:45 PM | RTH |
| Options levels (Tier 1+) | Hourly | RTH |
| Short interest | Twice monthly | - |
| Daily short volume | Daily EOD | - |
| Insider transactions | Daily | - |
| Float / shares outstanding | Weekly | - |
| Earnings estimates | Weekly (daily near earnings) | - |
| Halt feed | Every 30 seconds | RTH |
| LULD bands | Every 5 minutes | RTH |
| Corporate actions | Daily (EDGAR RSS) | - |
| Circuit breaker levels | Daily (from SPY prev close) | - |
| Volume profile | Daily EOD | RTH |
| Volume curve baseline | Daily EOD | RTH |
| Relative strength | Daily EOD | - |
| Cross-market | Hourly during RTH + EOD | RTH |
| Table | Est. Rows/Year | Est. Size |
|---|---|---|
| candles (5min RTH) | ~20,000 | ~4MB |
| candles (extended) | ~12,000 | ~2.5MB |
| indicators | ~20,000 | ~5MB |
| volume_curve_baseline | 78 rows | <1MB |
| volume_profile | ~252 | <1MB |
| session_data | ~252 | <1MB |
| earnings_events | ~4 | negligible |
| options_levels (rolling 5d) | ~40 (capped) | negligible |
| Total per stock | - | ~15MB |
For 50 stocks: ~750MB/year. Well within the 15GB disk available. Archive daily candles older than 2 years to compressed JSON.
CREATE TABLE IF NOT EXISTS price_structure (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
timeframe TEXT NOT NULL,
ts INTEGER NOT NULL,
swing_type TEXT, -- 'HH','HL','LH','LL'
swing_price REAL,
prior_swing_price REAL,
trend_structure TEXT, -- 'uptrend','downtrend','ranging'
candle_body_pct REAL, -- (close-open)/range *100 (body as % of H-L range)
candle_type TEXT, -- 'bullish_engulf','bearish_engulf','doji','hammer','shooting_star','inside_bar'
UNIQUE(ticker, timeframe, ts)
);
Phase 1 — at gap creation (real-time)
earnings_gap (earnings within 1 trading day), news_gap (halt preceded the gap — cross-reference halt_events), or technical_gap (no known catalyst)gap_size_atr, gap_direction, gap_vs_trend, gap_open_vs_prior_rangePhase 2 — retrospective (run daily at market close for gaps 1-20 days old)
gap_subtype: 'breakaway' | 'exhaustion' | 'common' | 'continuation' | 'unresolved'gap_subtype_confidence: starts at 0.3 on day 1, increases to 0.7 by day 5 if criteria consistently met, reaches 0.9 by day 10Gap magnetic strength decay
gap_magnetic_strength: starts at 1.0 on gap dayUnfilled gap tracking window
CREATE TABLE IF NOT EXISTS gap_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
gap_date TEXT NOT NULL,
gap_direction TEXT NOT NULL, -- 'up' or 'down'
gap_open REAL,
gap_close REAL, -- prior day's close (bottom of gap for up-gap)
gap_size_pct REAL,
gap_size_atr REAL,
gap_type TEXT, -- phase 1: 'earnings_gap','news_gap','technical_gap'
gap_vs_trend TEXT, -- 'with_trend','counter_trend'
gap_open_vs_prior_range TEXT, -- 'inside','outside'
gap_subtype TEXT, -- phase 2: 'breakaway','exhaustion','common','continuation','unresolved'
gap_subtype_confidence REAL,
gap_magnetic_strength REAL,
filled INTEGER DEFAULT 0,
fill_date TEXT,
fill_days INTEGER,
earnings_event_id INTEGER, -- FK to earnings_events if earnings_gap
halt_event_id INTEGER, -- FK to halt_events if news_gap
corporate_action_within_1d INTEGER DEFAULT 0,
UNIQUE(ticker, gap_date)
);
Asset-class agnostic core from the forex engine, adapted for stocks.
| Method | Description | Base Score | Stocks Adaptation |
|---|---|---|---|
| 1 | Multi-touch horizontal zones | 6 | No change |
| 2 | Fibonacci retracement levels | 5 | Apply to swing moves on Daily/Weekly |
| 3 | Moving average clusters | 4 | SMA 20, 50, 200 on Daily |
| 4 | Pivot points (daily/weekly/monthly) | 3 | RTH data only; remove pre-market pivots |
| 5 | Prior period high/low (daily/weekly/monthly) | 5 | No change |
| 6 | Trendline intersection | 5 | Use candle-index slope convention |
| 7 | Round number grid | 4 | Apply price-tier grid (Section 5) |
| 8 | ZigZag cluster zones | 4 | No change |
| 9 | Gap edges | 5 | Gap top/bottom become S&R levels |
| 10 | Opening range boundaries | 4 | Stocks-specific: 9:30–10:00 AM H/L |
| 11 | VWAP levels | 5 | Daily VWAP + anchored VWAPs |
| 12 | Volume Profile (VPOC + VAH/VAL) | 6/4 | VPOC=6, VAH/VAL=4; composite VPOC bonus +2 |
| 13 | LULD bands / circuit breakers | MAX | Dynamic, zero decay, exchange-enforced |
Removed: Pre-market pivot points (thin volume, noisy, not widely used). Removed: Options-derived S&R zones (Tier 2+ only — not built as permanent S&R in v1). Deferred to v2: Full options method with GEX flip zones.
1 - (0.02 × days_since_last_touch); reset to base score on each new touchatr_zone_width_multiplier)gap_magnetic_strength decay from gap_events tableCREATE TABLE IF NOT EXISTS sr_zones (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
timeframe TEXT NOT NULL,
zone_type TEXT NOT NULL, -- 'support' or 'resistance'
zone_center REAL NOT NULL,
zone_upper REAL NOT NULL,
zone_lower REAL NOT NULL,
composite_score REAL NOT NULL,
contributing_methods TEXT, -- JSON array of method numbers
touch_count INTEGER DEFAULT 1,
first_detected_ts INTEGER,
last_touch_ts INTEGER,
days_since_last_touch INTEGER,
active INTEGER DEFAULT 1,
source TEXT, -- 'multi_touch','fib','ma','pivot','prior_hl','trendline','round_number','zigzag','gap','opening_range','vwap','volume_profile','circuit_breaker'
decay_multiplier REAL DEFAULT 1.0,
luld_static INTEGER DEFAULT 0, -- 1 = LULD band, no decay
UNIQUE(ticker, timeframe, zone_center, zone_type)
);
CREATE INDEX IF NOT EXISTS idx_sr_zones_active ON sr_zones(ticker, timeframe, active, composite_score DESC);
Get top active S&R zones near current price
SELECT *
FROM sr_zones
WHERE ticker = ?
AND timeframe = ?
AND active = 1
AND ABS(zone_center - ?) / ? < 2.0 -- within 2 ATR of current price
ORDER BY composite_score * decay_multiplier DESC
LIMIT 10;
Check if price is inside a zone
SELECT id, zone_type, composite_score, decay_multiplier
FROM sr_zones
WHERE ticker = ?
AND timeframe = ?
AND active = 1
AND ? BETWEEN zone_lower AND zone_upper;
Implement only flags that use data already built in Steps 1–8. Defer flags requiring options/institutional data until those sources are validated.
flag_index_divergence — boolean: stock SuperTrend is bullish while SPY is bearish (or vice versa)flag_session_vol_sr — boolean: price tested an S&R zone during power hour (3–4 PM) with RVOL > 2.0flag_institutional_rs_st — short interest > 15% of float AND RS vs SPY positive AND SuperTrend bullishflag_options_sr_confluence — price at a major S&R zone AND that zone coincides with a call wall or put wallflag_earnings_iv_setup — IV rank > 70 AND earnings within 5 trading days AND historical avg move > 5%flag_short_squeeze — short_interest_pct_float > 20% AND days_to_cover > 5 AND RVOL > 2.0 AND price above prior week's highCREATE TABLE IF NOT EXISTS cross_section_flags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
date TEXT NOT NULL,
flag_index_divergence INTEGER DEFAULT 0,
flag_session_vol_sr INTEGER DEFAULT 0,
flag_institutional_rs_st INTEGER DEFAULT 0,
flag_options_sr_confluence INTEGER DEFAULT 0,
flag_earnings_iv_setup INTEGER DEFAULT 0,
flag_short_squeeze INTEGER DEFAULT 0,
UNIQUE(ticker, date)
);
Not a fundamental analysis engine. One slow-moving backdrop table that feeds one confluence score modifier.
CREATE TABLE IF NOT EXISTS fundamentals (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
date TEXT NOT NULL, -- last update date
pe_ratio_ttm REAL,
pe_ratio_forward REAL,
ps_ratio_ttm REAL,
pb_ratio REAL,
sector_median_pe REAL,
sector_median_ps REAL,
pe_vs_sector REAL, -- stock PE / sector median PE
revenue_growth_yoy REAL,
earnings_growth_yoy REAL,
profit_margin REAL,
UNIQUE(ticker, date)
);
Source: Financial Modeling Prep API free tier (250 req/day). Pull once daily for each stock (30 stocks = 30 requests). Integration: if Mean Reversion Extreme confluence fires AND pe_vs_sector < 0.7, add +1 confluence score. If pe_vs_sector > 2.0, subtract 1. That is the only place fundamentals touch the technical system.
[PANEL: GPT-4.1] Real-time news headlines are a MUST-HAVE. Price-moving news (earnings, M&A, FDA, executive changes, SEC actions) causes major gaps and regime shifts. Without structured news data, sudden moves may be misattributed to technical signals.
[PANEL: Grok 4.1] Analyst upgrades/downgrades and price target changes often cause immediate price reactions due to algorithmic trading responses.
CREATE TABLE IF NOT EXISTS news_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
published_ts INTEGER NOT NULL,
headline TEXT NOT NULL,
source TEXT,
category TEXT, -- 'earnings','analyst_action','ma','regulatory','executive','macro','other'
sentiment_label TEXT, -- 'positive','negative','neutral' (FinBERT or similar)
sentiment_score REAL, -- -1.0 to 1.0
analyst_action TEXT, -- 'upgrade','downgrade','initiation','price_target_raise','price_target_cut' (NULL if not analyst)
analyst_firm TEXT,
price_target_new REAL,
price_target_prior REAL,
price_at_event REAL,
price_1h_after REAL,
price_1d_after REAL
);
CREATE INDEX IF NOT EXISTS idx_news_ticker_ts ON news_events(ticker, published_ts DESC);
Sources: Benzinga (limited free tier), Yahoo Finance headlines RSS (scraping), Finviz RSS, Google Finance news. For sentiment: run free Hugging Face FinBERT model locally — no API cost.
Cadence: poll every 5 minutes during RTH for tracked tickers. Store within 5 minutes of publication.
ticker_config table with price scaler fields| Data | API | Cost | Rate Limit | Notes |
|---|---|---|---|---|
| OHLCV candles | Alpaca API | Free | - | Includes extended hours |
| OHLCV candles (alt) | Polygon.io | $29/month | 5 req/sec | Also covers options Tier 1 |
| Earnings dates + estimates | Financial Modeling Prep | Free | 250 req/day | Also covers float, fundamentals |
| Short interest | FINRA | Free | - | Twice-monthly CSV download |
| Daily short volume | FINRA | Free | - | Daily CSV |
| Insider transactions | OpenInsider.com | Free | 100 req/day | Cleaner than raw EDGAR |
| Halt feed | NYSE | Free | - | nyse.com/trade-halt-current |
| Halt feed (alt) | Nasdaq Trader | Free | - | nasdaqtrader.com/trader.aspx?id=TradeHalts |
| LULD bands | NYSE / Nasdaq | Free | - | Published by exchanges, 5-min updates |
| Threshold list | SEC | Free | - | Daily CSV |
| Corporate actions (8-K) | SEC EDGAR RSS | Free | - | Real-time RSS feed |
| Earnings calendar | FMP or Alpha Vantage | Free | - | Alpha Vantage: 25 req/day for fundamentals |
| CBOE PCR | CBOE | Free | - | cboe.com/us/options/market_statistics/daily/ |
| SPY/QQQ max pain | CBOE delayed | Free | - | 15-min delayed, sufficient for daily calc |
| News headlines | Yahoo Finance RSS | Free | - | Scraping |
| News headlines (alt) | Benzinga | Limited free | - | |
| Sentiment model | FinBERT (HuggingFace) | Free | Local | Run locally, no API cost |
| VIX, yields | Yahoo Finance | Free | - | yfinance library |
| ETF prices (SPY, QQQ, sector) | Same as OHLCV | Free | - | Same pipeline |
| Component | Reusable For |
|---|---|
| VIX + yield curve collection | options_desk, futures_desk, forex_desk, prediction_markets |
| Economic calendar pipeline | forex_desk (already built), futures_desk, crypto_desk, prediction_markets |
| S&R Zone Engine | forex_desk (source), crypto_desk, futures_desk, options_desk |
| Volatility regime classification | forex_desk, crypto_desk, futures_desk, options_desk |
| Confluence scoring framework | All desks (asset-agnostic) |
| SPY/QQQ/IWM price data | options_desk, futures_desk (ES/NQ/RTY), prediction_markets |
| Earnings calendar + corporate events pipeline | options_desk, prediction_markets (earnings outcomes on Kalshi/Polymarket) |
| Relative strength ranking framework | crypto_desk (RS vs BTC), sports_desk (team strength ranking analogy) |
| Session-aware data collection framework | futures_desk (contract rolls), crypto_desk (define 24h sessions) |
| Technical indicator library (SMA, RSI, MACD, ATR, etc.) | All desks — build once, use everywhere |
| News scraping + sentiment infrastructure | crypto_desk, sports_desk, prediction_markets |
| Event outcome tracking (Brier scores, forward returns) | All desks |
| Source | Table | Cadence | Status |
|---|---|---|---|
| Polygon OHLCV (ETF proxies) | ta_futures_ohlcv | 15 min | FLOWING |
| SEC EDGAR (insider, 13F) | sec_* tables (from Stocks desk) | Daily | FLOWING |
| VIX suite | vix_* tables (from Stocks desk) | Intraday | FLOWING |
src/pipeline/ta/plugins/stocks-metrics.ts -- 8 proprietary metricssrc/pipeline/ta/plugins/stocks-overlay.ts -- gap analysis, RVOL, sector lag| Metric | Status | Table |
|---|---|---|
| RVOL (Relative Volume, TOD normalized) | Computing | ta_stocks_metrics |
| Gap Analysis (overnight gap + fill rate) | Computing | ta_stocks_overlay |
| Sector Rotation Velocity | Computing | ta_stocks_metrics |
| VWAP Deviation Regime | Computing | ta_stocks_metrics |
| IAF (Institutional Accumulation Footprint) | Computing | ta_stocks_metrics |
| Sector Lag Detection | Computing | ta_stocks_metrics |
| Dilution Risk Score | Computing | ta_stocks_metrics |
| GVEI (Gamma-Vanna Exposure) | STUBBED -- needs options chain | ta_stocks_metrics_pending |
| DPAS (Dark Pool Accumulation) | STUBBED -- needs dark pool data | ta_stocks_metrics_pending |
| EVCS (Earnings Vol Crush) | STUBBED -- needs earnings IV | ta_stocks_metrics_pending |
| SSPG (Short Squeeze Pressure) | STUBBED -- needs short interest | ta_stocks_metrics_pending |
| PM-SNR (Pre-Market Signal-to-Noise) | STUBBED -- needs pre-market data | ta_stocks_metrics_pending |
| Insider Cluster Score | STUBBED -- needs SEC EDGAR wiring | ta_stocks_metrics_pending |
SPY, QQQ (equity ETFs via Polygon)
| # | Model | Params | Type | In Ensemble | Latency |
|---|---|---|---|---|---|
| 1 | Chronos-T5-Small | 46M | General probabilistic | Yes | ~1s |
| 2 | Chronos-T5-Base | 200M | General probabilistic | Yes | ~3s |
| 3 | Chronos-2 | 120M | General probabilistic (v2) | Yes | ~0.1s |
| 4 | Kronos-mini | 4.1M | Finance OHLCV | Yes | ~0.5s |
| 5 | Kronos-base | 102M | Finance OHLCV | Yes | ~2s |
| 6 | Moirai v1.1 | ~300M | Multivariate | Yes | ~1.7s |
| 7 | TimesFM 2.5 | 200M | General (Google) | Yes | ~0.6s |
| 8 | Lag-Llama | ~10M | Probabilistic | On-demand | ~2s |
Forecasts persisted to ta_model_forecasts with Kronos OHLCV + derived candle shape.
Stubbed: TTM (Python 3.11), FinCast (no weights).
| Module | Table | What It Does |
|---|---|---|
| Dual SuperTrend (10/2+10/3) | ta_supertrend_flips | Flip events, direction, outcomes (2R-6R) |
| RSI crosses (8 pairs, 16 lines) | ta_rsi_crosses | Crossover events, dual stop tracking |
| Pullback monitor (5 methods) | ta_pullback_results | Pullback setups from recent flips |
| S&R Zone Engine (6 methods) | ta_sr_zones + events | Zones scored 0-100+, decay, lifecycle |
| Structure analysis | ta_closed_structure | Candle morphology, trend structure |
| Regime detection | ta_regime | Hurst, autocorrelation, ATR forecast |
| Liquidity sweeps | ta_liquidity_sweeps | Stop-hunt reversals |
| Fair value gaps | ta_fvg | Body gaps + fill tracking |
| Candle patterns (6 types) | ta_candle_patterns | Zone-gated pattern detection |
| RSI divergences (4 types) | ta_divergences | Z-score strength |
| Lead-lag | ta_lead_lag | Cross-instrument correlation |
| Confluence scoring | ta_confluence | -35 to +35 composite |
| Additional signals (5 types) | ta_signals | Composite entry signals |
| Order blocks | ta_sr_zones | Inside S&R engine |
src/pipeline/ta/collector.ts (wired into main.ts Step 9d)src/pipeline/ta/index.ts (barrel export)