TA-Stocks Desk — Final Merged Spec

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


Overview

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.


Section 1 — SuperTrend + ATR (Core Trend Engine)

Fields (per candle, per timeframe)

Parameters

SQLite Table

CREATE 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);

Cadence


Section 2 — Trend Lines + ZigZag

Fields

Slope Convention

All trend line slopes use candle-index as the x-axis (sequential candle numbering, ignoring clock time). Store two slope forms:

When comparing slopes cross-timeframe, use slope_pct_per_day for apples-to-apples comparison. Never compare slope_raw values across timeframes directly.

SQLite Table

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
);

Section 3 — Event Timing Correlation

Tracks when multiple signals fire simultaneously. Used for confluence scoring.

Fields (per candle)


Section 4 — Oscillators: RSI, MACD, Stochastic, ADX

RSI — Two-Layer Architecture (fixes circular dependency)

Layer 1 — Divergence Detection (fixed thresholds always)

Layer 2 — Overbought/Oversold Labels (adaptive thresholds for confluence scoring only)

Stored fields

MACD

Stochastic

ADX

SQLite Table

CREATE 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)
);

Section 5 — Stocks-Specific Levels: VWAP, Options, Round Numbers

VWAP (Daily + Anchored)

Computation optimization — checkpoint system

Fields (intraday, computed per RTH candle)

Anchored 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)
);

Relative Volume (RVOL) — Time-of-Day Normalized

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)

Update baseline daily after market close. RVOL computed on-the-fly during RTH by looking up the current time bucket.

Volume Profile (Market Profile)

Per-session computation

CREATE 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).

Options-Derived Levels — Tiered Implementation

Tier 0 (v1 — free)

Tier 1 ($29/month Polygon.io — v2)

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

Round Number Grid (Simplified)

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.

Price Level Scaler

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.


Section 6 — Confluence Events

Confluence fires when multiple independent signals align on the same candle or within the same session.

Event Types (stocks-adapted)

  1. Trend + Momentum — SuperTrend flip + MACD cross in same direction
  2. VWAP Confluence — price tests VWAP + RSI at key level + volume spike (RVOL > 1.5)
  3. Gap Fill Confluence — price approaches unfilled gap zone + S&R zone present + volume confirms
  4. S&R + Oscillator Extreme — price at S&R zone + RSI in OB/OS territory (adaptive thresholds)

Confluence Score

Confluence table

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)
);

Section 7 — Institutional Positioning + Order Flow

Short Interest

Daily Short Volume (more timely than bi-monthly short interest)

[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)
);

Float + Shares Outstanding

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:

Threshold List / Reg SHO

[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)
);

Insider Transactions

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'
);

Large Trade Direction (replaces dark pool sentiment)

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
);

Section 8 — Cross-Market Signals

Index Correlations

Sector Tracking (Simplified)

Track 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.


Section 9 — Relative Strength Rankings

Fields

CREATE 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.


Section 10 — Session-Specific Tracking

Session Boundaries (US Eastern Time)

Per-Session Fields

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).

Halt Detection + LULD Bands

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.


Section 11 — Volatility Regime Classification

HV-Based (v1 — no options data needed)

IV-Based (v2 — requires options data)

CREATE 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)
);

Section 12 — Earnings + Catalyst Calendar

Earnings Estimates (required for surprise calculation)

[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.

Earnings Events (post-earnings data)

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.

Economic Calendar

Corporate Actions

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:

Buyback Blackout Windows

[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)
);

Section 13 — Seasonal + Time-Based Patterns

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):


Section 14 — Derived Metrics + Forward Returns

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)
);

Section 15 — Data Storage Architecture

Database Files (separate DBs to avoid write contention)

SQLite Configuration (apply to all DB files)

PRAGMA journal_mode=WAL;
PRAGMA synchronous=NORMAL;
PRAGMA cache_size=-64000;    -- 64MB cache
PRAGMA temp_store=memory;
PRAGMA mmap_size=536870912;  -- 512MB mmap

Write Rules

Sampling Frequencies

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

Storage Estimates (per stock, per year)

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.


Section 16 — Closed Period Price Structure

HH/HL/LH/LL Analysis

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)
);

Gap Events + Classification (Two-Phase System)

Phase 1 — at gap creation (real-time)

Phase 2 — retrospective (run daily at market close for gaps 1-20 days old)

Gap magnetic strength decay

Unfilled 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)
);

Section 17 — S&R Zone Engine

Asset-class agnostic core from the forex engine, adapted for stocks.

Detection Methods

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.

Zone Scoring, Decay, and Clustering

CREATE 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);

Key SQL Queries

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;

Section 18 — Cross-Section Intelligence Flags

Implement only flags that use data already built in Steps 1–8. Defer flags requiring options/institutional data until those sources are validated.

Flag 18.2 — Index vs Stock Direction (v1)

Flag 18.7 — Session + Volume + S&R (v1)

Flag 18.1 — Institutional + RS + ST (v2, after short interest validated)

Flag 18.3 — Options + S&R Confluence (v2, after Tier 1 options built)

Flag 18.5 — Earnings Volatility Setup (v2)

Flag 18.6 — Short Squeeze Proximity (v2)

CREATE 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)
);

Section 19 — Future Additions (Tiered)

Tier 1 (v2 — next build phase)

Tier 2 (v3)

Deferred Indefinitely (remove from v1 scope)


Section 20 — Fundamental Valuation Context (light touch)

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.


Section 21 — Real-Time News Headlines (Catalyst Awareness)

[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.


Implementation Checklist

Phase 1 — Foundation (1–2 weeks)

Phase 2 — Sessions + Gaps (3–5 days)

Phase 3 — VWAP + Volume Profile (2–3 days)

Phase 4 — S&R Zone Engine (1–2 weeks)

Phase 5 — Cross-Market + Relative Strength (3–5 days)

Phase 6 — Relative Strength + Confluence (2–3 days)

Phase 7 — Earnings + Catalysts (3–5 days)

Phase 8 — Volatility Regime (2–3 days)

Phase 9 — Trend Lines + ZigZag + Divergences (1–2 weeks)

Phase 10 — Price Structure + Full Gap Classification (1 week)

Phase 11 — Short Interest + Insiders (3–5 days)

Phase 12 — Seasonal + News + Fundamentals (3–5 days)

Phase 13 — Options (Tier 0, v1)

Phase 14 — Cross-Section Flags + Backtesting

Phase 15 — Options Tier 1 (v2, separate project)


API Endpoints Reference

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

Cross-Desk Reusability

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

Notes for Coding Bot

  1. Start with Phase 1. Do not skip ahead. Every other phase depends on clean candle data.
  2. Use Alpaca API first (free, includes extended hours). Switch to Polygon.io only if rate limits become a constraint.
  3. SQLite WAL mode is mandatory. Enable it on every DB file before any writes.
  4. Use separate DB files for different data categories to avoid write contention.
  5. Never write row-by-row. Always batch into transactions.
  6. The price level scaler must be applied everywhere: S&R zone widths, ATR buffers, spread thresholds. A $3 stock and a $300 stock are not the same.
  7. Gap classification is two-phase. Do not try to classify breakaway/exhaustion at creation time. Assign 'unclassified' at creation, reclassify daily.
  8. RSI divergence detection uses fixed 70/30. Adaptive thresholds are only for confluence labels, not divergence detection.
  9. RVOL requires the volume_curve_baseline table. Build it before computing RVOL.
  10. Options data is Tier 0 (SPY/QQQ max pain only) in v1. Do not attempt per-stock options collection in v1.
  11. Halt detection is not optional. Without it, outcome tracking is poisoned by halt-driven moves attributed to technical signals.
  12. The ticker_config table is the master configuration. Populate it before starting data collection for any stock.
  13. Stock broker (TBD) will be the primary execution venue. When the broker is selected, verify which data endpoints their API exposes (many brokers include real-time Level 1, some expose Level 2, a few expose options chains). Update the API endpoints table accordingly before Phase 13.

Build Status (Updated 2026-03-29)

Data Sources

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

Code

Proprietary Metrics

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

Instruments

SPY, QQQ (equity ETFs via Polygon)

What's NOT Built Yet

Foundation Models (shared sidecar, port 5050, systemd auto-restart)

# 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).

Shared Core (all desks, computed every 15 min per instrument)

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

Pipeline Wiring

Source: ~/edgeclaw/results/spec-panel/ta-stocks/spec-final.md