institutional-trader/backend/database/intradayoptionfactors.sql

200 lines
8.8 KiB
SQL
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

WITH
-- 1⃣ Daily close with previous close and daily % change
daily_prev AS (
SELECT
UPPER(Ticker) AS symbol,
CAST(dt AS date) AS trade_date,
close::numeric AS close,
LAG(close) OVER (PARTITION BY Ticker ORDER BY dt) AS prev_close,
100.0 * (close - LAG(close) OVER (PARTITION BY Ticker ORDER BY dt))
/ NULLIF(LAG(close) OVER (PARTITION BY Ticker ORDER BY dt), 0) AS daily_pct_change,
CASE WHEN close >= LAG(close) OVER (PARTITION BY Ticker ORDER BY dt)
THEN 'UP' ELSE 'DOWN' END AS daily_direction
FROM price_daily
),
-- 2⃣ Intraday prices joined with prior close and session tagging
minute_enriched AS (
SELECT
UPPER(m.Ticker) AS symbol,
(m.ts AT TIME ZONE 'America/New_York') AS ts_et,
CAST(m.ts AT TIME ZONE 'America/New_York' AS date) AS trade_date,
m.close::numeric AS close,
dp.prev_close,
100.0 * (m.close - dp.prev_close) / NULLIF(dp.prev_close,0) AS pct_from_prev_close,
CASE
WHEN CAST(m.ts AT TIME ZONE 'America/New_York' AS time) < TIME '09:30' THEN 'PRE'
WHEN CAST(m.ts AT TIME ZONE 'America/New_York' AS time) >= TIME '16:00' THEN 'POST'
ELSE 'RTH'
END AS session
FROM price_1m m
JOIN daily_prev dp
ON dp.symbol = UPPER(m.Ticker)
AND dp.trade_date = CAST(m.ts AT TIME ZONE 'America/New_York' AS date)
WHERE dp.prev_close IS NOT NULL
),
-- 3⃣ First ±3% cross per day
first_cross AS (
SELECT DISTINCT ON (symbol, trade_date)
symbol,
trade_date,
ts_et AS first_cross_ts,
CASE WHEN pct_from_prev_close >= 3 THEN 'UP' ELSE 'DOWN' END AS first_cross_direction,
pct_from_prev_close AS first_cross_pct,
session AS first_cross_session
FROM minute_enriched
WHERE ABS(pct_from_prev_close) >= 3
ORDER BY symbol, trade_date, ts_et
),
-- 4⃣ Session peaks
session_peaks AS (
SELECT
symbol, trade_date,
MAX(ABS(pct_from_prev_close)) FILTER (WHERE session='PRE') AS max_abs_pct_pre,
MAX(ABS(pct_from_prev_close)) FILTER (WHERE session='RTH') AS max_abs_pct_rth,
MAX(ABS(pct_from_prev_close)) FILTER (WHERE session='POST') AS max_abs_pct_post
FROM minute_enriched
GROUP BY symbol, trade_date
),
-- 5⃣ AlertStream aggregation
alerts_pre AS (
SELECT
UPPER(a."Ticker") AS symbol,
a."Timestamp"::timestamp AS alert_ts_raw,
a."Type",
a."Message"
FROM public."AlertStream_monthly" a
),
alert_agg AS (
SELECT
symbol,
CAST(alert_ts_raw AT TIME ZONE 'America/New_York' AS date) AS trade_date,
COUNT(*) AS alert_count,
SUM(CASE WHEN "Type" ILIKE '%AnnualHigh%' THEN 1 ELSE 0 END) AS alert_52w_high,
SUM(CASE WHEN "Type" ILIKE '%AnnualLow%' THEN 1 ELSE 0 END) AS alert_52w_low,
SUM(CASE WHEN "Type" ILIKE '%PriceSpike%' THEN 1 ELSE 0 END) AS alert_price_spike,
SUM(CASE WHEN "Type" ILIKE '%DarkPool%' THEN 1 ELSE 0 END) AS alert_darkpool,
SUM(CASE WHEN "Type" ILIKE '%Block%' THEN 1 ELSE 0 END) AS alert_block,
SUM(CASE WHEN "Type" ILIKE '%Halt%' THEN 1 ELSE 0 END) AS alert_halt,
SUM(CASE WHEN "Type" ILIKE '%Options%' THEN 1 ELSE 0 END) AS alert_options,
SUM(CASE WHEN "Message" ~* '(earn(ing|ings|ed|s)|\\bEPS\\b|guidance)' THEN 1 ELSE 0 END) AS news_earnings,
SUM(CASE WHEN "Message" ~* '(merger|acquir|M&A|takeover)' THEN 1 ELSE 0 END) AS news_mergers,
SUM(CASE WHEN "Message" ~* '\\b(FDA|PDUFA)\\b|trial|phase\\s?(1|2|3)|endpoint' THEN 1 ELSE 0 END) AS news_fda,
SUM(CASE WHEN "Message" ~* '(buyback|repurchase|\\bASR\\b)' THEN 1 ELSE 0 END) AS news_buyback,
SUM(CASE WHEN "Message" ~* 'dividend|ex[- ]?div' THEN 1 ELSE 0 END) AS news_dividend,
SUM(CASE WHEN "Message" ~* '(^|\\W)split(\\W|$)|reverse\\s+split' THEN 1 ELSE 0 END) AS news_split,
SUM(CASE WHEN "Message" ~* '(contract|award|supplier|customer)' THEN 1 ELSE 0 END) AS news_contract,
SUM(CASE WHEN "Message" ~* '(8-K|10-Q|10-K|S-1|\\bSEC\\b)' THEN 1 ELSE 0 END) AS news_sec,
SUM(CASE WHEN "Message" ~* '(upgrade|raised\\s+to|target\\s+raise)' THEN 1 ELSE 0 END) AS news_rating_up,
SUM(CASE WHEN "Message" ~* '(downgrade|lowered\\s+to|target\\s+cut)' THEN 1 ELSE 0 END) AS news_rating_dn
FROM alerts_pre
GROUP BY 1,2
),
-- 6⃣ OptionsFlow aggregation
options_pre AS (
SELECT
UPPER(o."Symbol") AS symbol,
to_timestamp(o."CreatedDate" || ' ' || o."CreatedTime", 'MM/DD/YYYY HH12:MI:SS AM') AS opt_ts_raw,
o.*
FROM public."OptionsFlow_monthly" o
),
options_agg AS (
SELECT
symbol,
CAST(opt_ts_raw AT TIME ZONE 'America/New_York' AS date) AS trade_date,
COUNT(*) AS opt_trades,
SUM(COALESCE("Premium", "Price"*"Volume"*100.0)) AS opt_notional_total,
SUM(CASE
WHEN ("Color" ILIKE '%BULL%')
OR (UPPER("CallPut")='CALL' AND UPPER("Side") IN ('B','BUY'))
OR (UPPER("CallPut")='PUT' AND UPPER("Side") IN ('S','SELL'))
THEN COALESCE("Premium","Price"*"Volume"*100.0)
ELSE 0 END) AS opt_notional_bull,
SUM(CASE
WHEN ("Color" ILIKE '%BEAR%')
OR (UPPER("CallPut")='PUT' AND UPPER("Side") IN ('B','BUY'))
OR (UPPER("CallPut")='CALL' AND UPPER("Side") IN ('S','SELL'))
THEN COALESCE("Premium","Price"*"Volume"*100.0)
ELSE 0 END) AS opt_notional_bear,
SUM(CASE WHEN UPPER("Type") LIKE '%SWEEP%' THEN 1 ELSE 0 END) AS opt_sweep_count,
SUM(CASE WHEN UPPER("Type") LIKE '%BLOCK%' THEN 1 ELSE 0 END) AS opt_block_count,
SUM(CASE WHEN COALESCE("Uoa",'F') ILIKE 'T' THEN 1 ELSE 0 END) AS opt_uoa_count,
AVG(NULLIF("Dte",0)) AS opt_avg_dte,
AVG(NULLIF("ImpliedVolatility",0)) AS opt_avg_iv,
SUM(CASE WHEN UPPER("CallPut")='CALL' THEN 1 ELSE 0 END) AS opt_call_trades,
SUM(CASE WHEN UPPER("CallPut")='PUT' THEN 1 ELSE 0 END) AS opt_put_trades
FROM options_pre
GROUP BY 1,2
),
-- 7⃣ Combine everything
final AS (
SELECT
dp.symbol,
dp.trade_date,
dp.prev_close,
dp.close,
dp.daily_pct_change,
dp.daily_direction,
fc.first_cross_ts,
fc.first_cross_direction,
fc.first_cross_pct,
fc.first_cross_session,
sp.max_abs_pct_pre,
sp.max_abs_pct_rth,
sp.max_abs_pct_post,
COALESCE(al.alert_count,0) AS alert_count,
COALESCE(al.alert_52w_high,0) AS alert_52w_high,
COALESCE(al.alert_52w_low,0) AS alert_52w_low,
COALESCE(al.alert_price_spike,0) AS alert_price_spike,
COALESCE(al.alert_darkpool,0) AS alert_darkpool,
COALESCE(al.alert_block,0) AS alert_block,
COALESCE(al.alert_halt,0) AS alert_halt,
COALESCE(al.alert_options,0) AS alert_options,
COALESCE(al.news_earnings,0) AS news_earnings,
COALESCE(al.news_mergers,0) AS news_mergers,
COALESCE(al.news_fda,0) AS news_fda,
COALESCE(al.news_buyback,0) AS news_buyback,
COALESCE(al.news_dividend,0) AS news_dividend,
COALESCE(al.news_split,0) AS news_split,
COALESCE(al.news_contract,0) AS news_contract,
COALESCE(al.news_sec,0) AS news_sec,
COALESCE(al.news_rating_up,0) AS news_rating_up,
COALESCE(al.news_rating_dn,0) AS news_rating_dn,
COALESCE(op.opt_trades,0) AS opt_trades,
COALESCE(op.opt_notional_total,0) AS opt_notional_total,
COALESCE(op.opt_notional_bull,0) AS opt_notional_bull,
COALESCE(op.opt_notional_bear,0) AS opt_notional_bear,
COALESCE(op.opt_sweep_count,0) AS opt_sweep_count,
COALESCE(op.opt_block_count,0) AS opt_block_count,
COALESCE(op.opt_uoa_count,0) AS opt_uoa_count,
CASE WHEN COALESCE(al.news_earnings,0)
+COALESCE(al.news_mergers,0)
+COALESCE(al.news_fda,0)
+COALESCE(al.news_buyback,0)
+COALESCE(al.news_dividend,0)
+COALESCE(al.news_split,0)
+COALESCE(al.news_contract,0)
+COALESCE(al.news_sec,0)
+COALESCE(al.news_rating_up,0)
+COALESCE(al.news_rating_dn,0) > 0 THEN 1 ELSE 0 END AS clue_news,
CASE WHEN COALESCE(op.opt_notional_bull,0) > COALESCE(op.opt_notional_bear,0) THEN 1 ELSE 0 END AS clue_options_bullish,
CASE WHEN COALESCE(op.opt_notional_bear,0) > COALESCE(op.opt_notional_bull,0) THEN 1 ELSE 0 END AS clue_options_bearish,
CASE WHEN COALESCE(al.alert_halt,0)>0 OR COALESCE(al.alert_price_spike,0)>0 THEN 1 ELSE 0 END AS clue_halt_or_spike,
CASE WHEN COALESCE(al.alert_52w_high,0)>0 OR COALESCE(al.alert_52w_low,0)>0 THEN 1 ELSE 0 END AS clue_52w_extreme,
CASE WHEN COALESCE(al.alert_darkpool,0)>0 OR COALESCE(al.alert_block,0)>0 OR COALESCE(op.opt_block_count,0)>0 THEN 1 ELSE 0 END AS clue_darkpool_block,
CASE WHEN COALESCE(op.opt_uoa_count,0)>0 THEN 1 ELSE 0 END AS clue_uoa
FROM daily_prev dp
LEFT JOIN first_cross fc ON fc.symbol=dp.symbol AND fc.trade_date=dp.trade_date
LEFT JOIN session_peaks sp ON sp.symbol=dp.symbol AND sp.trade_date=dp.trade_date
LEFT JOIN alert_agg al ON al.symbol=dp.symbol AND al.trade_date=dp.trade_date
LEFT JOIN options_agg op ON op.symbol=dp.symbol AND op.trade_date=dp.trade_date
)
SELECT *
FROM final
ORDER BY trade_date DESC, symbol;