institutional-trader/backend/database/optionflowrockerscorer.sql

693 lines
30 KiB
SQL

/* ==================== STOCKS — PANEL2 with price + alert context (Postgres/Supabase) ==================== */
/* Assumptions (as per your schema):
- public."OptionsFlow_monthly" has columns: Symbol, CallPut, Side, Strike, Spot, Premium, Volume, OI,
ExpirationDate, CreatedDate, CreatedTime, StockEtf, Price, etc. (strings/numbers)
- public.prices_intraday_1m(Symbol text, ts timestamptz, open numeric, high numeric, low numeric, close numeric, volume numeric)
- public.prices_daily(Symbol text, "Date" date, close numeric)
- public."AlertStream_monthly" has lowercase columns: "date" text, "timestamp" text, "ticker" text,
"type" text, "message" text, "price" numeric, "volume" numeric
*/
WITH cfg AS (
SELECT
/* <-- adjust these if desired */
(CURRENT_DATE - INTERVAL '1 day')::date AS start_day,
(CURRENT_DATE)::date AS end_day,
0.20::numeric AS tol_pct -- tape-alignment tolerance (pct points)
),
/* 1) FLOW: normalize fields + clean numerics */
base AS (
SELECT
ofm.ctid AS rid, -- stable row identity within a monthly table
ofm.*,
UPPER(TRIM(ofm."Symbol")) AS symbol_norm,
/* cp_norm */
CASE WHEN UPPER(TRIM(ofm."CallPut")) IN ('C','CALL','CALLS','CE') THEN 'CALL'
WHEN UPPER(TRIM(ofm."CallPut")) IN ('P','PUT','PUTS','PE') THEN 'PUT'
END AS cp_norm,
/* side_norm */
CASE
WHEN UPPER(TRIM(ofm."Side")) IN ('A','AA','ASK','BUY','BOT','BTO','AT_ASK') THEN 'BUY'
WHEN UPPER(TRIM(ofm."Side")) IN ('B','BB','BID','SELL','SLD','STO','AT_BID') THEN 'SELL'
ELSE NULL
END AS side_norm,
/* numerics: cast via ::text → regexp_replace → ::numeric so it works whether input is text or numeric */
NULLIF(REGEXP_REPLACE(ofm."Strike"::text, '[\s$,]', '', 'g'),'')::numeric AS strike_num,
NULLIF(REGEXP_REPLACE(ofm."Spot"::text, '[\s$,]', '', 'g'),'')::numeric AS spot_num,
NULLIF(REGEXP_REPLACE(ofm."Premium"::text, '[\s$,]', '', 'g'),'')::numeric AS premium_num,
NULLIF(REGEXP_REPLACE(ofm."Volume"::text, '[\s$,]', '', 'g'),'')::numeric AS vol_num,
NULLIF(REGEXP_REPLACE(ofm."OI"::text, '[\s$,]', '', 'g'),'')::numeric AS oi_num,
/* parse expiration date to DATE (supports YYYY-MM-DD or MM/DD/YYYY) */
CASE
WHEN ofm."ExpirationDate"::text ~ '^\d{4}-\d{2}-\d{2}$' THEN ofm."ExpirationDate"::date
WHEN ofm."ExpirationDate"::text ~ '^\d{1,2}/\d{1,2}/\d{2,4}$' THEN to_date(ofm."ExpirationDate"::text, 'MM/DD/YYYY')
ELSE NULL
END AS exp_date,
/* build FLOW timestamp in local feed time (assume CST = America/Chicago) */
/* Normalize date format first, then parse time */
CASE
WHEN ofm."CreatedTime"::text ~* '(AM|PM)'
THEN CASE
/* Normalize date to YYYY-MM-DD format first */
/* Has seconds: "9:43:09 AM" or "09:43:09 AM" */
WHEN ofm."CreatedTime"::text ~ ':\d{2}:\d{2}\s*(AM|PM)'
THEN COALESCE(
-- Normalize date and parse with normalized format
NULLIF(to_timestamp(
CASE
WHEN ofm."CreatedDate"::text ~ '^\d{4}-\d{2}-\d{2}$'
THEN ofm."CreatedDate"::text
WHEN ofm."CreatedDate"::text ~ '^\d{1,2}/\d{1,2}/\d{4}$'
THEN to_date(ofm."CreatedDate"::text, 'MM/DD/YYYY')::text
ELSE NULL
END || ' ' || btrim(ofm."CreatedTime"::text),
'YYYY-MM-DD HH12:MI:SS AM'), NULL),
-- Fallback: try with MM/DD/YYYY format directly
NULLIF(to_timestamp(ofm."CreatedDate"::text || ' ' || btrim(ofm."CreatedTime"::text), 'MM/DD/YYYY HH12:MI:SS AM'), NULL)
)
/* Has minutes: "9:43 AM" or "09:43 AM" */
WHEN ofm."CreatedTime"::text ~ ':\d{2}\s*(AM|PM)'
THEN COALESCE(
-- Normalize date and parse
NULLIF(to_timestamp(
CASE
WHEN ofm."CreatedDate"::text ~ '^\d{4}-\d{2}-\d{2}$'
THEN ofm."CreatedDate"::text
WHEN ofm."CreatedDate"::text ~ '^\d{1,2}/\d{1,2}/\d{4}$'
THEN to_date(ofm."CreatedDate"::text, 'MM/DD/YYYY')::text
ELSE NULL
END || ' ' || btrim(ofm."CreatedTime"::text),
'YYYY-MM-DD HH12:MI AM'), NULL),
-- Fallback: try with MM/DD/YYYY format directly
NULLIF(to_timestamp(ofm."CreatedDate"::text || ' ' || btrim(ofm."CreatedTime"::text), 'MM/DD/YYYY HH12:MI AM'), NULL),
-- Try with seconds format too
NULLIF(to_timestamp(
CASE
WHEN ofm."CreatedDate"::text ~ '^\d{4}-\d{2}-\d{2}$'
THEN ofm."CreatedDate"::text
WHEN ofm."CreatedDate"::text ~ '^\d{1,2}/\d{1,2}/\d{4}$'
THEN to_date(ofm."CreatedDate"::text, 'MM/DD/YYYY')::text
ELSE NULL
END || ' ' || btrim(ofm."CreatedTime"::text) || ':00',
'YYYY-MM-DD HH12:MI:SS AM'), NULL),
NULLIF(to_timestamp(ofm."CreatedDate"::text || ' ' || btrim(ofm."CreatedTime"::text) || ':00', 'MM/DD/YYYY HH12:MI:SS AM'), NULL)
)
/* Just hour: "9 AM" or "09 AM" - convert to "9:00:00 AM" */
WHEN ofm."CreatedTime"::text ~ '^\d{1,2}\s*(AM|PM)$'
THEN COALESCE(
NULLIF(to_timestamp(
CASE
WHEN ofm."CreatedDate"::text ~ '^\d{4}-\d{2}-\d{2}$'
THEN ofm."CreatedDate"::text
WHEN ofm."CreatedDate"::text ~ '^\d{1,2}/\d{1,2}/\d{4}$'
THEN to_date(ofm."CreatedDate"::text, 'MM/DD/YYYY')::text
ELSE NULL
END || ' ' || REGEXP_REPLACE(btrim(ofm."CreatedTime"::text), '^(\d{1,2})\s*(AM|PM)$', '\1:00:00 \2', 'i'),
'YYYY-MM-DD HH12:MI:SS AM'), NULL),
NULLIF(to_timestamp(ofm."CreatedDate"::text || ' ' || REGEXP_REPLACE(btrim(ofm."CreatedTime"::text), '^(\d{1,2})\s*(AM|PM)$', '\1:00:00 \2', 'i'), 'MM/DD/YYYY HH12:MI:SS AM'), NULL)
)
/* Fallback: try various formats */
ELSE COALESCE(
NULLIF(to_timestamp(
CASE
WHEN ofm."CreatedDate"::text ~ '^\d{4}-\d{2}-\d{2}$'
THEN ofm."CreatedDate"::text
WHEN ofm."CreatedDate"::text ~ '^\d{1,2}/\d{1,2}/\d{4}$'
THEN to_date(ofm."CreatedDate"::text, 'MM/DD/YYYY')::text
ELSE NULL
END || ' ' || btrim(ofm."CreatedTime"::text),
'YYYY-MM-DD HH12:MI AM'), NULL),
NULLIF(to_timestamp(ofm."CreatedDate"::text || ' ' || btrim(ofm."CreatedTime"::text), 'MM/DD/YYYY HH12:MI AM'), NULL)
)
END
-- Non-AM/PM times (24-hour format)
WHEN ofm."CreatedDate"::text ~ '^\d{4}-\d{2}-\d{2}$'
THEN to_timestamp(ofm."CreatedDate"::text || ' ' || btrim(ofm."CreatedTime"::text), 'YYYY-MM-DD HH24:MI:SS')
ELSE to_timestamp(
CASE
WHEN ofm."CreatedDate"::text ~ '^\d{4}-\d{2}-\d{2}$'
THEN ofm."CreatedDate"::text
WHEN ofm."CreatedDate"::text ~ '^\d{1,2}/\d{1,2}/\d{4}$'
THEN to_date(ofm."CreatedDate"::text, 'MM/DD/YYYY')::text
ELSE ofm."CreatedDate"::text
END || ' ' || btrim(ofm."CreatedTime"::text),
'YYYY-MM-DD HH24:MI:SS')
END AS flow_ts_local -- timestamp without time zone (CST clock)
FROM public."OptionsFlow_monthly" ofm
WHERE ofm."Premium" IS NOT NULL
AND btrim(ofm."Premium"::text) <> ''
-- AND ofm."StockEtf" = 'STOCK'
-- AND ofm."Symbol" NOT IN ('TSLA','NVDA') -- your panel excludes these
),
/* 2) Window restriction (CST date window) and compute UTC + DTE */
flow AS (
SELECT
b.*,
(b.flow_ts_local)::date AS flow_date_cst,
/* Convert local CST clock to a real point in time (timestamptz) */
(b.flow_ts_local AT TIME ZONE 'America/Chicago') AS flow_ts_utc,
/* Days to Expiration (DTE) */
CASE
WHEN b.exp_date IS NOT NULL AND (b.flow_ts_local)::date IS NOT NULL
THEN (b.exp_date - (b.flow_ts_local)::date)
ELSE NULL
END AS dte
FROM base b
WHERE (b.flow_ts_local)::date BETWEEN (SELECT start_day FROM cfg) AND (SELECT end_day FROM cfg)
),
/* 3) Direction + moneyness % */
mny AS (
SELECT
f.*,
CASE
WHEN cp_norm='CALL' AND strike_num > spot_num THEN 'OTM'
WHEN cp_norm='CALL' AND strike_num <= spot_num THEN 'ITM'
WHEN cp_norm='PUT' AND strike_num < spot_num THEN 'OTM'
WHEN cp_norm='PUT' AND strike_num >= spot_num THEN 'ITM'
END AS moneyness,
CASE
WHEN (cp_norm='CALL' AND side_norm='BUY') OR (cp_norm='PUT' AND side_norm='SELL') THEN 'BULL'
WHEN (cp_norm='PUT' AND side_norm='BUY') OR (cp_norm='CALL' AND side_norm='SELL') THEN 'BEAR'
ELSE NULL
END AS direction,
/* +mny_pct means ITM depth; -mny_pct means OTM distance */
CASE
WHEN spot_num IS NOT NULL AND spot_num <> 0 AND cp_norm='CALL'
THEN ((spot_num - strike_num) * 100.0) / NULLIF(spot_num,0)
WHEN spot_num IS NOT NULL AND spot_num <> 0 AND cp_norm='PUT'
THEN ((strike_num - spot_num) * 100.0) / NULLIF(spot_num,0)
ELSE NULL
END AS mny_pct
FROM flow f
),
/* 4) Running sums by (exp_date, symbol) — keep your original analytics */
agg AS (
SELECT
m.*,
SUM(CASE WHEN cp_norm='CALL' AND side_norm='BUY' AND moneyness='OTM' THEN premium_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS prem_cb_otm,
SUM(CASE WHEN cp_norm='CALL' AND side_norm='BUY' AND moneyness='ITM' THEN premium_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS prem_cb_itm,
SUM(CASE WHEN cp_norm='CALL' AND side_norm='SELL' AND moneyness='OTM' THEN premium_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS prem_cs_otm,
SUM(CASE WHEN cp_norm='CALL' AND side_norm='SELL' AND moneyness='ITM' THEN premium_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS prem_cs_itm,
SUM(CASE WHEN cp_norm='PUT' AND side_norm='BUY' AND moneyness='OTM' THEN premium_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS prem_pb_otm,
SUM(CASE WHEN cp_norm='PUT' AND side_norm='BUY' AND moneyness='ITM' THEN premium_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS prem_pb_itm,
SUM(CASE WHEN cp_norm='PUT' AND side_norm='SELL' AND moneyness='OTM' THEN premium_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS prem_ps_otm,
SUM(CASE WHEN cp_norm='PUT' AND side_norm='SELL' AND moneyness='ITM' THEN premium_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS prem_ps_itm,
SUM(vol_num) OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS vol_all,
SUM(oi_num) OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS oi_all,
SUM(CASE WHEN (cp_norm='CALL' AND side_norm='BUY') OR (cp_norm='PUT' AND side_norm='SELL') THEN vol_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS bull_vol,
SUM(CASE WHEN (cp_norm='PUT' AND side_norm='BUY') OR (cp_norm='CALL' AND side_norm='SELL') THEN vol_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS bear_vol,
SUM(CASE WHEN (cp_norm='CALL' AND side_norm='BUY') OR (cp_norm='PUT' AND side_norm='SELL') THEN oi_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS bull_oi,
SUM(CASE WHEN (cp_norm='PUT' AND side_norm='BUY') OR (cp_norm='CALL' AND side_norm='SELL') THEN oi_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS bear_oi,
/* OI runs for 💰 badge */
SUM(CASE WHEN cp_norm='CALL' AND side_norm='BUY' AND moneyness='OTM' THEN oi_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS oi_cb_otm,
SUM(CASE WHEN cp_norm='PUT' AND side_norm='BUY' AND moneyness='OTM' THEN oi_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS oi_pb_otm,
/* UNKNOWN SIDE tracking - premium and count for flows where direction is NULL (running sum) */
SUM(CASE WHEN direction IS NULL THEN premium_num ELSE 0 END)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS prem_unknown_sym,
COUNT(*) FILTER (WHERE direction IS NULL)
OVER (PARTITION BY exp_date, symbol_norm ORDER BY flow_ts_utc, rid) AS cnt_unknown_sym,
/* Total premium by symbol/expiration for rule-based rockets (total sum, not running) */
SUM(premium_num) OVER (PARTITION BY exp_date, symbol_norm) AS prem_total_sym,
/* Directional premium totals by symbol/expiration (for rule-based rockets) */
SUM(CASE WHEN direction='BULL' THEN premium_num ELSE 0 END) OVER (PARTITION BY exp_date, symbol_norm) AS prem_bull_sym,
SUM(CASE WHEN direction='BEAR' THEN premium_num ELSE 0 END) OVER (PARTITION BY exp_date, symbol_norm) AS prem_bear_sym,
SUM(1) OVER (PARTITION BY exp_date, symbol_norm, direction ORDER BY flow_ts_utc, rid) AS dir_count
FROM mny m
),
/* 5) Netting + badges (kept from your logic) */
final1 AS (
SELECT
a.*,
(bull_vol - bear_vol) AS net_vol_raw,
(bull_oi - bear_oi ) AS net_oi_raw,
(prem_cb_itm + prem_ps_itm) AS bull_prem_itm,
(prem_cs_itm + prem_pb_itm) AS bear_prem_itm,
(prem_cb_otm + prem_ps_otm) AS otm_bull_raw,
(prem_pb_otm + prem_cs_otm) AS otm_bear_raw,
(prem_cb_itm + prem_ps_itm + prem_cb_otm + prem_ps_otm) AS bull_total,
(prem_cs_itm + prem_pb_itm + prem_cs_otm + prem_pb_otm) AS bear_total
FROM agg a
),
deco AS (
SELECT
f.*,
CASE
WHEN (bull_prem_itm) > (bear_prem_itm) THEN '🟢'
WHEN (bull_prem_itm) < (bear_prem_itm) THEN '🔴'
ELSE ''
END AS badge_round,
(
CASE WHEN (bull_prem_itm) > (bear_prem_itm) AND prem_cb_itm > prem_ps_itm THEN '💎' ELSE '' END
|| CASE WHEN (bull_prem_itm) < (bear_prem_itm) AND prem_pb_itm > prem_cs_itm THEN '💎' ELSE '' END
|| CASE WHEN (bull_prem_itm) > (bear_prem_itm) AND (otm_bull_raw - otm_bear_raw) > 10000 THEN '' ELSE '' END
|| CASE WHEN (bull_prem_itm) < (bear_prem_itm) AND (otm_bear_raw - otm_bull_raw) > 10000 THEN '' ELSE '' END
|| CASE WHEN (bull_prem_itm) > (bear_prem_itm) AND oi_cb_otm > 100000 THEN '💰' ELSE '' END
|| CASE WHEN (bull_prem_itm) < (bear_prem_itm) AND oi_pb_otm > 100000 THEN '💰' ELSE '' END
|| CASE WHEN COALESCE(vol_num,0) > COALESCE(oi_num,0) THEN '' ELSE '' END
) AS badge_more,
CASE
WHEN premium_num > 10000 AND
(
( (bull_prem_itm) > (bear_prem_itm)
AND ( (cp_norm='CALL' AND POSITION('AA' IN UPPER("Side"))>0)
OR (cp_norm='PUT' AND POSITION('BB' IN UPPER("Side"))>0) ) )
OR
( (bull_prem_itm) < (bear_prem_itm)
AND ( (cp_norm='CALL' AND POSITION('BB' IN UPPER("Side"))>0)
OR (cp_norm='PUT' AND POSITION('AA' IN UPPER("Side"))>0) ) )
)
THEN ''
ELSE ''
END AS flash
FROM final1 f
),
rocketize AS (
SELECT
d.*,
CASE WHEN d.badge_round = '🟢' THEN 1 ELSE 0 END AS has_round_green,
CASE WHEN POSITION('💎' IN d.badge_more) > 0 THEN 1 ELSE 0 END AS has_diamond,
CASE WHEN POSITION('' IN d.badge_more) > 0 THEN 1 ELSE 0 END AS has_star,
CASE WHEN POSITION('💰' IN d.badge_more) > 0 THEN 1 ELSE 0 END AS has_money,
CASE WHEN d.flash = '' THEN 1 ELSE 0 END AS has_flash,
CASE WHEN COALESCE(d.vol_num,0) > COALESCE(d.oi_num,0) THEN 1 ELSE 0 END AS has_check,
CASE WHEN d.premium_num > 1000000 THEN 1 ELSE 0 END AS has_fire,
CASE WHEN d.premium_num > 500000 THEN 1 ELSE 0 END AS has_cash,
CASE
WHEN ( d.badge_round = '🟢'
AND POSITION('💎' IN d.badge_more) > 0
AND POSITION('' IN d.badge_more) > 0
AND POSITION('💰' IN d.badge_more) > 0
AND d.flash = ''
AND d.premium_num > 1000000 )
THEN '🚀'
WHEN (COALESCE(d.vol_num,0) > COALESCE(d.oi_num,0))
AND d.flash = ''
AND POSITION('💰' IN d.badge_more) > 0
AND d.premium_num > 500000
THEN '🚀🚀🚀'
WHEN (COALESCE(d.vol_num,0) > COALESCE(d.oi_num,0))
AND d.flash = ''
AND POSITION('💰' IN d.badge_more) > 0
THEN '🚀🚀'
WHEN (COALESCE(d.vol_num,0) > COALESCE(d.oi_num,0))
AND ( d.flash = '' OR d.premium_num > 500000 )
THEN '🚀'
ELSE ''
END AS rocket
FROM deco d
),
/* 6) PRICE CONTEXT (use LATERAL for fast top-1 seeks; convert bar times to CST for session bucketing) */
price_ctx AS (
SELECT
c.rid,
c.symbol_norm,
c.flow_ts_utc,
c.flow_ts_local,
c.flow_date_cst,
/* Session bucket in CST based on flow time */
CASE
WHEN EXTRACT(HOUR FROM c.flow_ts_local)::int BETWEEN 4 AND 9
AND NOT (EXTRACT(HOUR FROM c.flow_ts_local)::int = 9 AND EXTRACT(MINUTE FROM c.flow_ts_local)::int >= 30) THEN 'PRE'
WHEN (EXTRACT(HOUR FROM c.flow_ts_local)::int = 9 AND EXTRACT(MINUTE FROM c.flow_ts_local)::int >= 30)
OR (EXTRACT(HOUR FROM c.flow_ts_local)::int > 9 AND EXTRACT(HOUR FROM c.flow_ts_local)::int < 16) THEN 'RTH'
WHEN EXTRACT(HOUR FROM c.flow_ts_local)::int BETWEEN 16 AND 20 THEN 'POST'
ELSE 'OFF'
END AS session_bucket,
/* last 1m bar <= flow time */
p1.close AS u_close,
p1.high AS u_high,
p1.low AS u_low,
p1.volume AS u_vol_1m,
p1.ts AS u_ts,
/* first RTH bar >= 09:30:00 CST for that flow date */
rth.open AS rth_open,
rth.ts AS rth_ts,
/* prior daily close (CST prior day) */
pd.close AS prior_close,
/* 5m / 15m ago prices */
p5.close AS close_5m_ago,
p15.close AS close_15m_ago
FROM rocketize c
/* nearest <= flow */
LEFT JOIN LATERAL (
SELECT p.close, p.high, p.low, p.volume, p.ts
FROM public.prices_intraday_1m p
WHERE UPPER(p.symbol)=c.symbol_norm
AND p.ts <= c.flow_ts_utc
ORDER BY p.ts DESC
LIMIT 1
) p1 ON TRUE
/* first RTH bar of same CST date (convert bar ts to CST on the fly) */
LEFT JOIN LATERAL (
SELECT p.open, p.ts
FROM public.prices_intraday_1m p
WHERE UPPER(p.symbol)=c.symbol_norm
AND (timezone('America/Chicago', p.ts))::date = c.flow_date_cst
AND (timezone('America/Chicago', p.ts))::time >= time '09:30:00'
ORDER BY p.ts ASC
LIMIT 1
) rth ON TRUE
/* prior close (CST prior calendar day) */
LEFT JOIN LATERAL (
SELECT d.close
FROM public.prices_daily d
WHERE UPPER(d.symbol)=c.symbol_norm
AND d."Date" = c.flow_date_cst - INTERVAL '1 day'
ORDER BY d."Date" DESC
LIMIT 1
) pd ON TRUE
/* 5m ago */
LEFT JOIN LATERAL (
SELECT p.close
FROM public.prices_intraday_1m p
WHERE UPPER(p.symbol)=c.symbol_norm
AND p.ts <= c.flow_ts_utc - INTERVAL '5 minutes'
ORDER BY p.ts DESC
LIMIT 1
) p5 ON TRUE
/* 15m ago */
LEFT JOIN LATERAL (
SELECT p.close
FROM public.prices_intraday_1m p
WHERE UPPER(p.symbol)=c.symbol_norm
AND p.ts <= c.flow_ts_utc - INTERVAL '15 minutes'
ORDER BY p.ts DESC
LIMIT 1
) p15 ON TRUE
),
/* 7) Price features with proper NUMERIC rounding (avoid double-precision round()) */
price_feats AS (
SELECT
px.*,
/* vs prior close is available in all sessions; vs RTH open only valid during/after RTH */
CASE
WHEN px.prior_close IS NOT NULL AND px.u_close IS NOT NULL
THEN ROUND( (((px.u_close - px.prior_close) * 100.0) / NULLIF(px.prior_close,0))::numeric, 2 )
ELSE NULL
END AS pct_vs_prior_close,
CASE
WHEN px.rth_open IS NOT NULL
AND px.u_close IS NOT NULL
AND px.session_bucket = 'RTH'
THEN ROUND( (((px.u_close - px.rth_open) * 100.0) / NULLIF(px.rth_open,0))::numeric, 2 )
ELSE NULL
END AS pct_vs_rth_open,
CASE WHEN px.close_5m_ago IS NOT NULL AND px.u_close IS NOT NULL
THEN ROUND( (((px.u_close - px.close_5m_ago) * 100.0) / NULLIF(px.close_5m_ago,0))::numeric, 2 )
ELSE NULL END AS pct_5m_momo,
CASE WHEN px.close_15m_ago IS NOT NULL AND px.u_close IS NOT NULL
THEN ROUND( (((px.u_close - px.close_15m_ago) * 100.0) / NULLIF(px.close_15m_ago,0))::numeric, 2 )
ELSE NULL END AS pct_15m_momo
FROM price_ctx px
),
/* 8) ALERTS: normalize Date + AM/PM time → CST local ts → UTC; find nearest within ±15m via LATERAL */
alert_nearest AS (
SELECT
c.rid,
a1.near_alert_type,
a1.near_alert_msg,
a1.near_alert_price,
a1.near_alert_volume,
a1.event_ts_utc
FROM rocketize c
LEFT JOIN LATERAL (
SELECT q."type" AS near_alert_type,
q."message" AS near_alert_msg,
q."price" AS near_alert_price,
q."volume" AS near_alert_volume,
q.event_ts_utc
FROM (
SELECT
a."type",
a."message",
a."price",
a."volume",
/* Build local event timestamp (CST clock) from text columns */
CASE
WHEN a."date" ~ '^\d{4}-\d{2}-\d{2}$'
THEN to_timestamp(a."date" || ' ' || btrim(a."timestamp"), 'YYYY-MM-DD HH12:MI AM')
ELSE to_timestamp(a."date" || ' ' || btrim(a."timestamp"), 'MM/DD/YYYY HH12:MI AM')
END AS event_ts_local,
/* Convert to a real point in time (UTC) */
(CASE
WHEN a."date" ~ '^\d{4}-\d{2}-\d{2}$'
THEN to_timestamp(a."date" || ' ' || btrim(a."timestamp"), 'YYYY-MM-DD HH12:MI AM')
ELSE to_timestamp(a."date" || ' ' || btrim(a."timestamp"), 'MM/DD/YYYY HH12:MI AM')
END AT TIME ZONE 'America/Chicago') AS event_ts_utc
FROM public."AlertStream_monthly" a
WHERE UPPER(a."ticker") = c.symbol_norm
) q
WHERE q.event_ts_utc BETWEEN c.flow_ts_utc - INTERVAL '15 minutes'
AND c.flow_ts_utc + INTERVAL '15 minutes'
ORDER BY ABS(EXTRACT(EPOCH FROM (q.event_ts_utc - c.flow_ts_utc))) ASC
LIMIT 1
) a1 ON TRUE
),
/* 9) Enrich + tape-alignment with tolerance + score + Rocket label with [ITM/OTM %] */
flow_enriched AS (
SELECT
r.*,
pf.session_bucket,
pf.pct_vs_prior_close,
pf.pct_vs_rth_open,
pf.pct_5m_momo,
pf.pct_15m_momo,
an.near_alert_type,
an.near_alert_msg,
/* Tape alignment with tolerance band from cfg */
CASE
WHEN pf.session_bucket='PRE' AND pf.pct_vs_prior_close IS NOT NULL THEN
CASE WHEN (r.direction='BULL' AND pf.pct_vs_prior_close >= (SELECT tol_pct FROM cfg))
OR (r.direction='BEAR' AND pf.pct_vs_prior_close <= -(SELECT tol_pct FROM cfg)) THEN 1 ELSE 0 END
WHEN pf.session_bucket='RTH' AND pf.pct_vs_rth_open IS NOT NULL THEN
CASE WHEN (r.direction='BULL' AND pf.pct_vs_rth_open >= (SELECT tol_pct FROM cfg))
OR (r.direction='BEAR' AND pf.pct_vs_rth_open <= -(SELECT tol_pct FROM cfg)) THEN 1 ELSE 0 END
WHEN pf.session_bucket='POST' AND pf.pct_vs_prior_close IS NOT NULL THEN
CASE WHEN (r.direction='BULL' AND pf.pct_vs_prior_close >= (SELECT tol_pct FROM cfg))
OR (r.direction='BEAR' AND pf.pct_vs_prior_close <= -(SELECT tol_pct FROM cfg)) THEN 1 ELSE 0 END
ELSE 0
END AS tape_alignment,
CASE WHEN an.near_alert_type IS NOT NULL THEN 1 ELSE 0 END AS catalyst_flag
FROM rocketize r
LEFT JOIN price_feats pf ON pf.rid = r.rid
LEFT JOIN alert_nearest an ON an.rid = r.rid
),
scored AS (
SELECT
fe.*,
(CASE
WHEN fe.premium_num >= 2000000 THEN 3.0
WHEN fe.premium_num >= 800000 THEN 2.0
WHEN fe.premium_num >= 200000 THEN 1.0
ELSE 0.0
END)
+ 1.5 * CASE
WHEN (fe.bull_total + fe.bear_total) IS NOT NULL AND (fe.bull_total + fe.bear_total) <> 0
THEN (fe.bull_total - fe.bear_total) / NULLIF(ABS(fe.bull_total + fe.bear_total),0)
ELSE 0 END
+ 1.2 * CASE WHEN COALESCE(fe.vol_num,0) > COALESCE(fe.oi_num,0) THEN 1 ELSE 0 END
+ 1.0 * CASE fe.session_bucket WHEN 'RTH' THEN 1 WHEN 'POST' THEN 0.5 WHEN 'PRE' THEN 0.3 ELSE 0 END
+ 1.0 * fe.catalyst_flag
+ 0.8 * CASE
WHEN fe.cp_norm='CALL' AND fe.strike_num > fe.spot_num THEN 1
WHEN fe.cp_norm='PUT' AND fe.strike_num < fe.spot_num THEN 1
ELSE 0 END
+ 0.5 * fe.tape_alignment
AS rocket_score,
/* Rule-based rockets (SQLite style) */
CASE
WHEN fe.premium_num >= 250000
AND ABS(fe.prem_bull_sym - fe.prem_bear_sym) / NULLIF(fe.prem_total_sym, 0) >= 0.6
AND COALESCE(fe.vol_num, 0) > COALESCE(fe.oi_num, 0)
AND fe.tape_alignment = 1
THEN '🚀🚀🚀'
WHEN fe.premium_num >= 150000
AND fe.tape_alignment = 1
THEN '🚀🚀'
WHEN fe.premium_num >= 80000
AND fe.tape_alignment = 1
THEN '🚀'
ELSE NULL
END AS rocket_rule
FROM flow_enriched fe
),
rocket2 AS (
SELECT
s.*,
/* rocket label core - prefer rule-based, fallback to score-based, then original rocket */
COALESCE(
s.rocket_rule,
CASE
WHEN s.rocket_score >= 5.0 THEN '🚀🚀🚀'
WHEN s.rocket_score >= 3.5 THEN '🚀🚀'
WHEN s.rocket_score >= 2.0 THEN '🚀'
ELSE COALESCE(s.rocket, '')
END
) AS rocket_base,
/* append [ITM/OTM %] */
CASE
WHEN s.mny_pct IS NULL THEN
COALESCE(
s.rocket_rule,
CASE
WHEN s.rocket_score >= 5.0 THEN '🚀🚀🚀'
WHEN s.rocket_score >= 3.5 THEN '🚀🚀'
WHEN s.rocket_score >= 2.0 THEN '🚀'
ELSE COALESCE(s.rocket, '')
END
)
ELSE
COALESCE(
s.rocket_rule,
CASE
WHEN s.rocket_score >= 5.0 THEN '🚀🚀🚀'
WHEN s.rocket_score >= 3.5 THEN '🚀🚀'
WHEN s.rocket_score >= 2.0 THEN '🚀'
ELSE COALESCE(s.rocket, '')
END
)
|| ' [' || CASE WHEN s.mny_pct >= 0 THEN 'ITM ' ELSE 'OTM ' END
|| TRIM(TO_CHAR(ABS(s.mny_pct)::numeric, 'FM999990.0')) || '%]'
END AS Rocket_with_mny
FROM scored s
)
/* ==================== FINAL SELECT ==================== */
SELECT
(fe.flow_ts_local)::date AS "CreatedDate",
TO_CHAR(fe.flow_ts_local, 'HH12:MI:SS AM') AS "CreatedTime",
/* Symbol line with session + catalyst + your badges */
(
CASE
WHEN fe.direction = 'BULL' THEN '(' || fe.dir_count || '🟩) '
WHEN fe.direction = 'BEAR' THEN '(' || fe.dir_count || '🟥) '
ELSE ''
END
|| fe."Symbol"
|| ' · ' || COALESCE(fe.session_bucket,'?')
|| CASE WHEN fe.near_alert_type IS NOT NULL THEN '' ELSE '' END
|| CASE WHEN (fe.badge_round || fe.badge_more) <> '' THEN ' ' || fe.badge_round || fe.badge_more ELSE '' END
|| fe.flash
|| CASE
WHEN fe.premium_num > 1000000 THEN ' 🔥'
WHEN fe.premium_num > 500000 THEN ' 💵'
WHEN fe.premium_num > 100000 THEN ' '
ELSE ''
END
) AS "Symbol",
r2.Rocket_with_mny AS "Rocket",
/* NetPremium and Premium abbreviations as before */
CASE
WHEN ABS(fe.bull_total - fe.bear_total) >= 1e6
THEN (CASE WHEN fe.bull_total - fe.bear_total < 0 THEN '-' ELSE '' END)
|| TRIM(TO_CHAR(ABS(fe.bull_total - fe.bear_total)/1e6, 'FM999990.00')) || ' M'
WHEN ABS(fe.bull_total - fe.bear_total) >= 1e3
THEN (CASE WHEN fe.bull_total - fe.bear_total < 0 THEN '-' ELSE '' END)
|| TRIM(TO_CHAR(ROUND(ABS(fe.bull_total - fe.bear_total)/1e3)::numeric, 'FM999990')) || ' K'
ELSE TRIM(TO_CHAR(ROUND(fe.bull_total - fe.bear_total)::numeric, 'FM999990'))
END AS "NetPremium",
CASE
WHEN fe.premium_num IS NULL THEN NULL
WHEN ABS(fe.premium_num) >= 1e6
THEN (CASE WHEN fe.premium_num < 0 THEN '-' ELSE '' END)
|| TRIM(TO_CHAR(ABS(fe.premium_num)/1e6, 'FM999990.00')) || ' M'
WHEN ABS(fe.premium_num) >= 1e3
THEN (CASE WHEN fe.premium_num < 0 THEN '-' ELSE '' END)
|| TRIM(TO_CHAR(ROUND(ABS(fe.premium_num)/1e3)::numeric, 'FM999990')) || ' K'
ELSE TRIM(TO_CHAR(ROUND(fe.premium_num)::numeric, 'FM999990'))
END AS "Premium",
fe."ExpirationDate", fe."Price", fe."CallPut", fe."Side", fe."Strike", fe."Spot", fe."Volume", fe."OI",
/* DTE and unknown-side tracking */
fe.dte AS "DTE",
fe.prem_unknown_sym AS "PremUnknownSym",
fe.cnt_unknown_sym AS "CntUnknownSym",
/* trader-facing context — now meaningful */
fe.pct_vs_prior_close AS "PctVsPriorClose",
fe.pct_vs_rth_open AS "PctVsRthOpen",
fe.pct_5m_momo AS "Pct5m",
fe.pct_15m_momo AS "Pct15m",
/* Tape alignment arrows with tolerance */
CASE
WHEN fe.tape_alignment=1 AND fe.direction='BULL' THEN '↗︎'
WHEN fe.tape_alignment=1 AND fe.direction='BEAR' THEN '↘︎'
ELSE ''
END AS "TapeAlign",
fe.near_alert_type AS "NearAlert"
FROM rocket2 r2
JOIN flow_enriched fe ON fe.rid = r2.rid
WHERE
fe.premium_num > 80000
AND ( fe.badge_round IN ('🟢','🔴')
AND POSITION('💎' IN fe.badge_more)>0
AND POSITION('' IN fe.badge_more)>0 )
AND (
(fe.direction='BULL' AND fe.badge_round='🟢' AND (fe.bull_total - fe.bear_total) > 0)
OR (fe.direction='BEAR' AND fe.badge_round='🔴' AND (fe.bull_total - fe.bear_total) < 0)
)
ORDER BY fe.flow_ts_utc DESC, fe.rid DESC;