200 lines
8.8 KiB
SQL
200 lines
8.8 KiB
SQL
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;
|