Skip to content

About

Polars event-study research for ES/NQ intraday futures: MSS, CISD, SMT, RSI/volume divergences, session/momentum/volume filters.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

MSS Research

Polars-based event-study tools for testing whether retail trading features predict near-term market direction:

  • market structure shifts (MSS)
  • change in state of delivery (CISD)
  • ES/NQ smart money technique divergences (SMT)
  • RSI divergences
  • volume divergences
  • MSS break parameters: trade-through vs close-through, momentum, relative volume, short-term vs intermediate-term structure
  • MSS leg context: volume across the impulse leg and direction-aligned RSI momentum across that leg
  • MSS leg momentum comparison: right-leg mean RSI, left-leg mean RSI, and right-minus-left momentum delta
  • MSS leg volume comparison: right-leg relative volume, left-leg relative volume, and right-minus-left volume delta
  • CISD standalone variants: close breaks through the run-start open and the run high/low extreme
  • SMT sweep/fail context: which asset swept, which asset failed, reference/invalidation levels, and sweep depth

Raw data and large generated output tables are intentionally ignored by git. Lightweight matplotlib figures in outputs/figures/ are tracked so the README can show current research snapshots. The core research pipeline uses Polars; plotting still converts to pandas at the matplotlib boundary.

Data

Expected local files:

data/es_1m.parquet
data/nq_1m.parquet

Required columns:

datetime_utc, Open, High, Low, Close, Volume

Leg-based MSS definition

Bullish MSS only counts when price breaks a swing high that is left of the lowest swing-low extremity in the displacement leg. A swing high formed after that low is not eligible as the bullish shift level. Bearish MSS mirrors this: the broken swing low must be left of the highest swing-high extremity.

CISD definition

Bullish CISD anchors on a confirmed short-term swing low with at least three contiguous down-close candles into the swing-low area. Bearish CISD mirrors this at a confirmed short-term swing high with at least three contiguous up-close candles. Up/down close means close-to-close direction.

Each setup emits two standalone CISD variants when a later confirmed bar closes through the setup level:

  • open: bullish breaks above the open of the top candle in the down-close run; bearish breaks below the open of the bottom candle in the up-close run.
  • extreme: bullish breaks above the maximum high of the run; bearish breaks below the minimum low of the run.

CISD event rows include cisd_break_level_type, cisd_anchor_idx, cisd_run_start_idx, cisd_run_end_idx, cisd_run_length, and cisd_break_level.

SMT definition

SMT events compare aligned ES and NQ bars after each instrument's short-term swing points are confirmed.

  • Bullish SMT: one asset trades below its prior swing low while the other asset holds its corresponding prior swing low.
  • Bearish SMT: one asset trades above its prior swing high while the other asset holds its corresponding prior swing high.

The swept asset becomes sweeping_asset; the asset that holds becomes failing_asset. Forward returns are labeled on the sweeping asset, so instrument is set to ES or NQ for the instrument actually swept. SMT rows include reference_price, invalidation_level, smt_swing_idx_sweeper, smt_swing_idx_failing, and sweep_depth.

Time-of-day sessions

Events are bucketed by America/New_York clock time:

  • asia: 18:00-00:00 ET
  • london: 02:00-05:00 ET
  • ny_am: 08:30-12:00 ET
  • ny_pm: 13:30-16:00 ET
  • other: all remaining bars

Run study

PYTHONPATH=src python3 -m mss_research run --data data --out outputs --plots

Useful faster run:

PYTHONPATH=src python3 -m mss_research run --data data --out outputs --timeframes 15min --horizons 5,15,30,60 --bootstrap 100 --plots

For all-timeframe comparisons on memory-limited machines, run each timeframe separately and combine the summary CSVs. Use --bootstrap 0 for fast vectorized Polars summaries when confidence intervals are not needed.

Outputs:

outputs/all_events.parquet
outputs/summary.csv
outputs/figures/*.png

Current graphs

These figures are generated from the current local summary output and committed because they are small. Recreate them with the plots command below.

Figures were regenerated on 2026-09-29 from all three timeframes (1min, 5min, 15min; --bootstrap 0), after two labeling fixes. They include SMT.

Labeling fixes (2026-09-29) — figures before this date are not comparable:

  1. Divergence look-ahead removed. RSI/volume divergence events used to fire on the swing bar, but a k=1 swing is only confirmed one bar later. Forward returns therefore included the confirming bar, which by construction moves in the signal direction, and divergences plotted at 55–62% win rate. Divergence events now fire on the confirmation bar (event_idx = swing_*_available_idx, with the swing kept in divergence_swing_idx). Divergence win rates are now 49.4–50.8%, and means are −1.1 to +0.3 bp. Every earlier divergence result was an artifact of the look-ahead.
  2. Flat outcomes excluded from win rate. win used to be aligned_return > 0, so flat outcomes (6–10% of 1min 5-bar returns) counted as losses and pushed everything below 50%. A flat outcome now gets win = null and is excluded from win_rate, so 50% is the no-edge baseline. n and the return statistics still include flat outcomes.

Headline win rates after the fixes (all event types; the full table is written to outputs/headline_stats.csv):

Event 1min (5 / 60 bars) 5min (5 / 60) 15min (5 / 60) Mean aligned return, bp (range over all cells)
MSS 47.9 / 49.1 48.6 / 49.8 48.9 / 50.0 −0.17 to +0.65
CISD 47.3 / 49.1 48.5 / 49.9 48.7 / 49.7 −0.50 to +0.40
SMT 51.8 / 50.8 50.6 / 49.8 50.5 / 49.5 −0.93 to +0.19
RSI divergence 50.6 / 50.3 50.8 / 49.9 50.1 / 49.4 −0.91 to +0.31
Volume divergence 50.4 / 50.0 50.7 / 49.9 50.7 / 49.4 −1.06 to +0.10

SMT in detail (fixed-horizon, labeled on the sweeping asset):

Timeframe SMT rows Win % (5 / 15 / 30 / 60 bars) Mean aligned bp (5 / 15 / 30 / 60)
1min 141,382 51.8 / 51.4 / 51.0 / 50.8 +0.06 / +0.14 / +0.19 / +0.12
5min 30,819 50.6 / 50.2 / 50.1 / 49.8 −0.30 / −0.51 / −0.50 / −0.69
15min 11,078 50.5 / 49.7 / 50.3 / 49.5 −0.62 / −0.93 / −0.62 / −0.62

A few things worth a look, all point estimates and none tested:

  • MSS and CISD sit at 47–49% at short horizons, even with flat outcomes excluded, and converge toward 50% with horizon. Both fire on a bar that closes or trades through a level, so this may be short-term reversal or bid-ask bounce off the break bar's close rather than anything structural.
  • 1min SMT with ES sweeping is the highest cell, at about 52% for 5 bars. The mean return is +0.06 bp, so the win-rate tilt is not carrying any meaningful return.

The 15min SMT count moved from 10,770 (May run) to 11,078 because the data parquets were updated on 2026-07-18. SMT's largest same-bar overlap is with MSS: 15min phi≈0.097 (4,424 overlaps), 5min phi≈0.080, 1min phi≈0.073. Its overlap with divergences is now about 0 (phi −0.03 to −0.01), because divergence events moved to the confirmation bar.

Statistical caveats — read before quoting any of these numbers:

  • No intervals. The run used --bootstrap 0, so none of these point estimates have confidence intervals. Nothing here rejects, or establishes the absence of, a directional effect. Win rates near 50% are a statement about this sample, not evidence of "no edge". Claiming absence would need an equivalence test against a stated minimum effect, or a minimum detectable effect that excludes it.
  • Nominal n overstates information. SMT rows are not independent: ES and NQ rows fire on the same bars, SMT heavily co-occurs with MSS, and 15–60 bar forward windows overlap between nearby events. Effective n is materially smaller. Any interval should use a block/cluster bootstrap (e.g. by session day), not the row-level bootstrap.
  • The labels are a proxy for the SMT trade. Returns are fixed-horizon closes on the sweeping asset. The computed invalidation_level is not used as a stop, there is no target, and labeling the sweeping asset (rather than the asset that held) is a design choice, not part of the SMT definition. The win rates above describe fixed-horizon drift after the event, not the outcome of an SMT trade with a stop at invalidation.
Top-level event comparisons

Win rate by event type

What it shows: weighted win rate by forward horizon for each event family. A win means the forward return was positive after aligning to event direction; flat outcomes are excluded.

How to read: the dashed 50% line is the no-edge baseline (flat outcomes are excluded from win rate). Lines consistently above it would indicate a directional tendency, subject to the caveats above.

Current read: all families sit within about ±3 points of 50%. MSS/CISD are below 50% at short horizons and SMT (ES sweeps) is slightly above. Without intervals and an effective-n correction, this neither shows nor rules out a standalone directional effect.

Win rate by event type

Mean aligned return by event type

What it shows: average forward return after multiplying by event direction. Positive means favorable to the signal direction.

How to read: the dashed zero line is no-edge baseline. Larger positive values imply favorable average drift.

Current read: point-estimate means are close to zero and small relative to intraday return dispersion; no intervals yet.

Mean aligned return by event type

Sample size by event type

What it shows: how many event rows contribute to each event-family aggregate.

How to read: small event families are more fragile; large event families dominate weighted charts.

Current read: MSS/CISD/volume-divergence dominate sample size; SMT is meaningful but smaller.

Sample size by event type

Timeframe and horizon comparisons

Win rate by timeframe and event type

What it shows: event-family win rates split by timeframe and forward horizon.

How to read: robust effects should persist across horizons and preferably across timeframes.

Current read: no event family shows a visibly stable above-50% pattern across horizons in point estimate; this is unresolved, not a negative result.

Win rate by timeframe and event type

Mean aligned return by timeframe and event type

What it shows: average event-direction return by timeframe and horizon.

How to read: positive values mean favorable drift after the event; negative values mean adverse drift.

Current read: averages remain near zero at every timeframe in point estimate; no timeframe stands out, but no intervals have been computed.

Mean aligned return by timeframe and event type

P75 aligned return by timeframe and event type

What it shows: upper-quartile favorable return by timeframe and horizon.

How to read: high P75 with weak mean/win rate suggests events may mark volatility/opportunity rather than direction.

Current read: P75 is more informative as a volatility/activity marker than as standalone prediction.

P75 aligned return by timeframe and event type

Same-bar event overlap / Pearson phi correlation

Event-type correlation by timeframe, including SMT

What it shows: same-bar binary Pearson phi correlation between event families: CISD, MSS, SMT, RSI divergence, and volume divergence.

How to read: positive values mean two event types often occur on the same instrument/bar more than chance; negative values mean they avoid each other. The diagonal is blank because self-correlation is not the research question.

Current read: SMT's strongest same-bar relationship is with MSS at every timeframe (15min phi≈0.097, 5min phi≈0.080), which makes sense because both are sweep/structure concepts.

Event-type correlation by timeframe, including SMT

Distribution / tail-shape charts

MSS aligned-return distribution

What it shows: MSS mean aligned return with P25–P75 band by horizon and MSS subtype.

How to read: a useful directional signal should have mean and quartile band shifted above zero.

Current read: MSS distributions broadly straddle zero, consistent with MSS marking activity more than direction.

MSS aligned return distribution

CISD aligned-return distribution

What it shows: CISD mean aligned return with P25–P75 band, split by open and extreme break-level variants.

How to read: compare whether the stricter/extreme level changes the return distribution.

Current read: CISD variants need filtering; standalone distributions are not clearly directional.

CISD aligned return distribution

CISD P75 aligned return by timeframe

What it shows: upper-quartile CISD return by timeframe and break-level type.

How to read: useful for asking whether CISD creates favorable excursion potential even if mean/win rate are weak.

Current read: P75 is better treated as opportunity/volatility context than as a complete entry rule.

CISD P75 aligned return by timeframe

Break-candle context charts

Win rate by momentum bucket

What it shows: win rate by break-candle body size relative to rolling median range.

How to read: high momentum means the break candle body was large relative to recent range.

Current read: break-candle momentum alone has not produced a strong directional filter.

Win rate by momentum bucket

Win rate by relative volume bucket

What it shows: win rate by break-candle volume relative to rolling median volume.

How to read: tests whether above/below-normal volume changes directional outcomes.

Current read: relative volume is more promising as context than as a standalone signal.

Win rate by relative volume bucket

MSS leg context charts

Win rate by MSS leg RSI momentum bucket

What it shows: MSS win rate by strongest direction-aligned RSI value during the shift leg.

How to read: higher bucket means stronger directional RSI during the leg into the break.

Current read: right-leg momentum is useful context to inspect, but not enough alone.

Win rate by MSS leg RSI momentum bucket

Win rate by right-leg mean RSI bucket

What it shows: MSS win rate by average direction-aligned RSI across the right leg.

How to read: mean RSI smooths the leg momentum rather than taking only the extreme.

Current read: helps separate persistent leg strength from one-bar spike effects.

Win rate by right-leg mean RSI bucket

Win rate by right-vs-left leg RSI momentum delta

What it shows: MSS win rate by whether the shift leg has stronger/weaker mean aligned RSI than the prior leg.

How to read: strengthening means right-leg RSI momentum exceeded prior-leg momentum by more than 5 points.

Current read: tests the “displacement should strengthen” idea; still needs conjunction with other filters.

Win rate by right-vs-left leg RSI momentum delta

Win rate by MSS leg volume bucket

What it shows: MSS win rate by right-leg relative volume.

How to read: high means the displacement leg traded above baseline volume after length normalization.

Current read: volume may describe regime/participation more than direct direction.

Win rate by MSS leg volume bucket

Win rate by right-vs-left leg relative volume delta

What it shows: MSS win rate by whether right-leg relative volume expanded or contracted versus the prior leg.

How to read: expanding means the shift leg had materially higher relative volume than the prior leg.

Current read: useful for testing accumulation/distribution-style hypotheses, but not standalone edge yet.

Win rate by right-vs-left leg relative volume delta

CISD and session context charts

Win rate by CISD break level type

What it shows: CISD win rate split by open and extreme setup levels.

How to read: compares loose vs stricter CISD confirmation definitions.

Current read: neither variant should be treated as a standalone directional rule without additional filters.

Win rate by CISD break level type

Win rate by time-of-day session

What it shows: win rate by New York session bucket: Asia, London, NY AM, NY PM, other.

How to read: identifies whether event directionality varies by liquidity/time regime.

Current read: session remains an important context filter candidate.

Win rate by time-of-day session

Win rate by session and MSS leg volume

What it shows: MSS win-rate heatmap crossing session with right-leg volume bucket.

How to read: look for localized pockets where time-of-day and participation agree.

Current read: most useful for hypothesis generation; needs sample-size checks before trusting pockets.

Win rate by session and MSS leg volume

Create graphs from existing summary

PYTHONPATH=src python3 -m mss_research plots --summary outputs/summary.csv --out outputs/figures

Graphs include win rate, mean aligned return, timeframe-by-event comparisons, same-bar event-type correlation heatmaps for CISD/MSS/SMT/RSI-divergence/volume-divergence, P75 aligned-return comparisons, MSS and CISD P25/mean/P75 aligned-return distributions, sample size, break-candle momentum/volume buckets, MSS-leg RSI/volume buckets, right-leg mean RSI, right-vs-left RSI delta, right-vs-left relative-volume delta, CISD break-level type, time-of-day sessions, and session-by-leg-volume heatmaps.

Tests

python3 -m pytest -q

About

Polars event-study research for ES/NQ intraday futures: MSS, CISD, SMT, RSI/volume divergences, session/momentum/volume filters.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages