693 lines
30 KiB
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;
|