institutional-trader/backend/database/intradayflow.sql

150 lines
6.1 KiB
SQL

/* --------- PARAMETERS --------- */
WITH params AS (
SELECT
interval '45 minutes' AS lb_flow,
interval '45 minutes' AS lb_px,
interval '30 minutes' AS open_range,
100000::numeric AS big_prem_usd,
0.70::numeric AS pc_ratio_squeeze_cut,
0.80::numeric AS pc_ratio_bull_cut,
0.60::numeric AS short_vol_up_ratio,
0.40::numeric AS short_vol_down_ratio,
0.004::numeric AS up_break_pct,
0.002::numeric AS down_move_pct
),
clock AS (
SELECT (now() AT TIME ZONE 'America/Chicago') AS now_cst
),
/* --------- FLOW AGGREGATION (last lb_flow) --------- */
flow AS (
SELECT
f."Symbol" AS symbol,
SUM(COALESCE(NULLIF(REGEXP_REPLACE(f."Premium"::text, '[\s$,]', '', 'g'),'')::numeric, 0))
FILTER (WHERE UPPER(TRIM(f."CallPut")) IN ('C','CALL','CALLS','CE')
AND UPPER(TRIM(f."Side")) IN ('A','AA','ASK','BUY','BOT','BTO','AT_ASK')
AND COALESCE(NULLIF(REGEXP_REPLACE(f."Premium"::text, '[\s$,]', '', 'g'),'')::numeric, 0) >= (SELECT big_prem_usd FROM params)) AS call_prem,
SUM(COALESCE(NULLIF(REGEXP_REPLACE(f."Premium"::text, '[\s$,]', '', 'g'),'')::numeric, 0))
FILTER (WHERE UPPER(TRIM(f."CallPut")) IN ('P','PUT','PUTS','PE')
AND UPPER(TRIM(f."Side")) IN ('A','AA','ASK','BUY','BOT','BTO','AT_ASK')
AND COALESCE(NULLIF(REGEXP_REPLACE(f."Premium"::text, '[\s$,]', '', 'g'),'')::numeric, 0) >= (SELECT big_prem_usd FROM params)) AS put_prem,
COUNT(*) FILTER (WHERE UPPER(TRIM(f."Side")) IN ('A','AA','ASK','BUY','BOT','BTO','AT_ASK')
AND COALESCE(NULLIF(REGEXP_REPLACE(f."Premium"::text, '[\s$,]', '', 'g'),'')::numeric, 0) >= (SELECT big_prem_usd FROM params)) AS big_trades,
MAX(f."ExpirationDate") FILTER (WHERE UPPER(TRIM(f."Side")) IN ('A','AA','ASK','BUY','BOT','BTO','AT_ASK')) AS last_expiry
FROM public."OptionsFlow_monthly" f
CROSS JOIN clock c
CROSS JOIN params p
WHERE (
CASE
WHEN f."CreatedDate"::text ~ '^\d{4}-\d{2}-\d{2}$'
THEN (to_timestamp(f."CreatedDate"::text || ' ' || btrim(f."CreatedTime"::text), 'YYYY-MM-DD HH12:MI AM') AT TIME ZONE 'America/Chicago')
ELSE (to_timestamp(f."CreatedDate"::text || ' ' || btrim(f."CreatedTime"::text), 'MM/DD/YYYY HH12:MI AM') AT TIME ZONE 'America/Chicago')
END
) >= c.now_cst - p.lb_flow
AND (
CASE
WHEN f."CreatedDate"::text ~ '^\d{4}-\d{2}-\d{2}$'
THEN (to_timestamp(f."CreatedDate"::text || ' ' || btrim(f."CreatedTime"::text), 'YYYY-MM-DD HH12:MI AM') AT TIME ZONE 'America/Chicago')
ELSE (to_timestamp(f."CreatedDate"::text || ' ' || btrim(f."CreatedTime"::text), 'MM/DD/YYYY HH12:MI AM') AT TIME ZONE 'America/Chicago')
END
) < c.now_cst
GROUP BY f."Symbol"
),
/* --------- PRICE STATS (VWAP, ORH/ORL, returns) --------- */
px AS (
SELECT
p.symbol,
MAX(p."timestamp") AS last_ts,
SUM(p.close * p.volume)::numeric / NULLIF(SUM(p.volume),0) AS vwap_lb,
(ARRAY_AGG(p.close ORDER BY p."timestamp" ASC ))[1]::numeric AS start_px,
(ARRAY_AGG(p.close ORDER BY p."timestamp" DESC))[1]::numeric AS last_px,
AVG(p.short_volume_ratio)::numeric AS short_vol_ratio
FROM public.prices_intraday_1m p
CROSS JOIN clock c
CROSS JOIN params pr
WHERE p."timestamp" >= c.now_cst - pr.lb_px
AND p."timestamp" < c.now_cst
GROUP BY p.symbol
),
open_range AS (
SELECT
p.symbol,
MAX(p.high) FILTER (WHERE p."timestamp" >= date_trunc('day', c.now_cst) + time '08:30'
AND p."timestamp" < date_trunc('day', c.now_cst) + time '09:00') AS or_high,
MIN(p.low ) FILTER (WHERE p."timestamp" >= date_trunc('day', c.now_cst) + time '08:30'
AND p."timestamp" < date_trunc('day', c.now_cst) + time '09:00') AS or_low
FROM public.prices_intraday_1m p
CROSS JOIN clock c
GROUP BY p.symbol
),
/* --------- COMBINE --------- */
signals AS (
SELECT
coalesce(f.symbol, px.symbol) AS symbol,
f.call_prem,
f.put_prem,
(f.put_prem / NULLIF(f.call_prem,0))::numeric AS put_call_prem_ratio,
f.big_trades,
f.last_expiry,
px.last_px,
px.vwap_lb,
px.start_px,
((px.last_px - px.start_px) / NULLIF(px.start_px,0))::numeric AS ret_lb,
px.short_vol_ratio,
orr.or_high,
orr.or_low,
CASE WHEN px.last_px > orr.or_high THEN 1 ELSE 0 END AS broke_or_high,
CASE WHEN px.last_px > px.vwap_lb THEN 1 ELSE 0 END AS above_vwap
FROM flow f
FULL OUTER JOIN px ON px.symbol = f.symbol
LEFT JOIN open_range orr ON orr.symbol = COALESCE(f.symbol, px.symbol)
)
/* --------- CLASSIFICATION --------- */
SELECT
s.symbol,
s.last_expiry,
ROUND(COALESCE(s.call_prem,0)::numeric, 0) AS call_prem,
ROUND(COALESCE(s.put_prem,0)::numeric, 0) AS put_prem,
ROUND(100*s.ret_lb, 2) AS ret_lb_pct,
ROUND(100*s.short_vol_ratio, 1) AS short_vol_pct,
s.above_vwap, s.broke_or_high,
CASE
WHEN s.broke_or_high = 1
AND s.above_vwap = 1
AND s.ret_lb >= (SELECT up_break_pct FROM params)
AND (s.put_call_prem_ratio IS NULL OR s.put_call_prem_ratio <= (SELECT pc_ratio_squeeze_cut FROM params))
THEN 'SQUEEZE'
WHEN s.above_vwap = 1
AND s.ret_lb >= (SELECT up_break_pct FROM params)
AND (s.short_vol_ratio IS NULL OR s.short_vol_ratio <= (SELECT short_vol_down_ratio FROM params))
AND (s.put_call_prem_ratio IS NULL OR s.put_call_prem_ratio <= (SELECT pc_ratio_bull_cut FROM params))
THEN 'UNWINDING'
WHEN COALESCE(s.call_prem,0) > COALESCE(s.put_prem,0)
AND s.ret_lb <= -(SELECT down_move_pct FROM params)
AND (s.short_vol_ratio IS NULL OR s.short_vol_ratio >= (SELECT short_vol_up_ratio FROM params))
THEN 'HEDGED SHORTING'
WHEN COALESCE(s.call_prem,0) >= 2*COALESCE(s.put_prem,0)
AND s.ret_lb > -(SELECT down_move_pct FROM params)
THEN 'ACCUMULATION'
ELSE 'NEUTRAL'
END AS phase
FROM signals s
WHERE COALESCE(s.call_prem,0) + COALESCE(s.put_prem,0) > 0
ORDER BY
CASE
WHEN phase='SQUEEZE' THEN 1
WHEN phase='UNWINDING' THEN 2
WHEN phase='HEDGED SHORTING' THEN 3
WHEN phase='ACCUMULATION' THEN 4
ELSE 9
END,
(COALESCE(call_prem,0)+COALESCE(put_prem,0)) DESC;