150 lines
6.1 KiB
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;
|