Skip to main content

pyvsmc

Python Version License: MIT PyPI version Tests Type Checked Ruff

High-performance NumPy/Numba market-structure engine for Smart Money Concepts (SMC).

pyvsmc provides NumPy/Numba + Polars implementations of SMC/ICT concepts — Fair Value Gaps, fractal swings, BOS/CHOCH, Order Blocks, Liquidity sweeps, Premium/Discount & OTE — with appropriate data structures and low asymptotic complexity.

Architecture: NumPy for bulk transforms, Numba njit(cache=True) for stateful/first-passage scans, Polars for DataFrame integration. Not “zero loops” — correctness and complexity first.


Features

Module Concept Key Function
fvg Fair Value Gap / Imbalance + CE 50% + IFVG detect_fvg()
swings Fractal Swing Highs & Lows detect_swings()
structure BOS & CHOCH (first-cross, break_mode) detect_structure()
order_blocks Order Block + zone_mode + breaker detect_order_blocks()
liquidity Equal highs/lows (swing-based) + sweeps detect_liquidity()
zones Premium/Discount + OTE 0.618/0.705/0.786 detect_zones()
polars_ext Polars .smc namespace df.smc.add_all()
  • Correctness: Strict mypy, NaN-aware, first-cross BOS, CE50/full/inverted tracking.
  • Polars: pl.DataFrame.smc.* + add_smc_columns(); fvg/swings have native LazyFrame expr, other modules fallback honest collect() (documented).
  • Tested: 92 tests covering empty, flat, NaN, dense gaps, mitigation, EQH/EQL, OTE, LazyFrame.

Installation

pip install pyvsmc

With Polars (recommended):

pip install "pyvsmc[dev]"   # includes polars, pytest, ruff, mypy, numba
# or
pip install pyvsmc polars numba

From source:

git clone https://github.com/Khaymat/pyvsmc
cd pyvsmc
pip install -e ".[dev]"

Requirements: Python >=3.10, numpy>=1.24.0, polars>=0.20.0 (optional), numba>=0.56 (optional, for JIT).


Quickstart

NumPy API

import numpy as np
import pyvsmc as smc

high  = np.array([10.0, 11.2, 10.8, 12.5, 11.0, 13.0])
low   = np.array([ 9.5,  9.8, 10.0, 11.8, 10.5, 12.2])
close = np.array([10.0, 10.5, 10.2, 12.2, 11.1, 12.8])
open_ = np.array([ 9.8, 10.0, 10.4, 11.0, 11.5, 12.0])

# 1. FVG + CE/IFVG
fvg = smc.detect_fvg(high, low, close=close, compute_mitigation=True)
print(fvg.bullish, fvg.ce_level, fvg.mitigated_50, fvg.inverted)

# 2. Swings
swings = smc.detect_swings(high, low, window_size=2)

# 3. Structure — break_mode close/wick/both, first-cross
structure = smc.detect_structure(high, low, close, window_size=2, break_mode="close")
print(structure.bos_bullish, structure.trend)

# 4. Order Blocks — zone_mode full/body/mean_threshold + breaker
obs = smc.detect_order_blocks(open_, high, low, close, lookback=5, zone_mode="body", compute_mitigation=True)
print(obs.bullish_ob, obs.is_breaker)

# 5. Liquidity + Zones
liq = smc.detect_liquidity(high, low, close, equal_threshold=0.001)
zones = smc.detect_zones(high, low, close)
print(liq.equal_swing_high, liq.sweep_high, zones.in_ote)

Polars API

import polars as pl
import pyvsmc  # registers .smc namespace

df = pl.DataFrame({"open": open_, "high": high, "low": low, "close": close})

# Eager
from pyvsmc.polars_ext import add_smc_columns
df = add_smc_columns(df, window_size=2, fvg_mitigation=True)
# Lazy (fvg/swings native, others collect fallback)
ldf = df.lazy()
ldf = ldf.pipe(lambda d: pyvsmc.fvg_polars(d))  # native expr

# Namespace — fvg/swings have native LazyFrame support; other modules use eager fallback
df = pl.DataFrame({"open": open_, "high": high, "low": low, "close": close})
df = df.smc.add_all(window_size=2, include_liquidity=True)
df = df.smc.fvg(min_gap_size=0.5)
df = df.smc.swings(window_size=2)
df = df.smc.structure(window_size=2)
df = df.smc.order_blocks(lookback=5)
df = df.smc.liquidity(equal_threshold=0.001)
df = df.smc.zones(eq_threshold=0.02)

API Reference

detect_fvg(high, low, min_gap_size=None, min_gap_size_pct=None, *, compute_mitigation=False, close=None)

Bullish Low[i] > High[i-2] [High[i-2], Low[i]], Bearish High[i] < Low[i-2]. Returns FVGResult with bullish/bearish, bullish_upper/lower, ce_level, gap_size, mitigated/mitigated_50/mitigated_full/inverted + indices. close enables IFVG.

detect_swings(high, low, window_size=2, tie="all")

High[i]==max(window), Low[i]==min(window). tie="all" (current default, legacy — every equal extremum), "first" (one deterministic per plateau, flat →0), "strict" (unique). Returns SwingResult.

detect_structure(high, low, close, window_size=2, *, break_mode="close", tie="all", swing_high=None, swing_low=None)

break_mode="close"|"wick"|"both", first-cross, tie forwarded when swings computed internally. If swing_high/swing_low supplied (both or neither, else ValueError), they are used verbatim and window_size/tie are ignored for swing generation.

detect_order_blocks(open_, high, low, close, *, lookback=10, zone_mode="full", compute_mitigation=False, tie="all", break_mode="close")

zone_mode="full"|"body"|"mean_threshold", tie forwarded to structure/swings, break_mode forwarded. Returns bullish_ob/bearish_ob, ob_high/low, mitigated/is_breaker.

detect_liquidity(high, low, close, *, equal_threshold=0.001, sweep_lookback=20, window_size=2, tie="all", swing_high=None, swing_low=None)

tie and optional swing_high/swing_low injection (both or neither). Returns equal_high/low + equal_swing_high/low (EQH/EQL), sweep_high/low.

detect_zones(high, low, close, window_size=2, eq_threshold=0.02, tie="all", swing_high=None, swing_low=None)

tie and optional swing injection as above. Returns premium/discount/equilibrium, range_high/low, ote_high/low/705, in_ote.

All have *_polars variants (swings_polars, structure_polars with break_mode/tie, liquidity_polars/zones_polars with tie, order_blocks_polars with zone_mode/tie/break_mode). add_smc_columns exposes tie, structure_break_mode, ob_zone_mode/ob_tie (defaults preserve 0.3.x).


Testing

pip install -e ".[dev]"
pytest -v
pytest --cov=pyvsmc --cov-report=term-missing

Run type checks and lint:

mypy src/pyvsmc
ruff check src/pyvsmc tests

Project Structure

pyvsmc/
├── pyproject.toml
├── README.md
├── src/pyvsmc/
│   ├── __init__.py
│   ├── py.typed
│   ├── fvg.py
│   ├── swings.py
│   ├── structure.py
│   ├── order_blocks.py
│   ├── liquidity.py
│   ├── zones.py
│   └── polars_ext.py
├── src/pysmc/          # shim deprecated → pyvsmc
├── benchmarks/
│   ├── bench.py
│   └── results.json
└── tests/
    ├── test_fvg.py + test_fvg_regression.py
    ├── test_swings.py
    ├── test_structure.py
    ├── test_order_blocks.py
    ├── test_liquidity.py
    ├── test_zones.py
    └── test_polars_ext.py

Performance & Complexity

Benchmark 0.3.2 (synthetic OHLC random, window_size=2, 3 runs median, tracemalloc peak):

n swings fvg fvg+mit struct OB liquidity zones polars eager
1k 0.79ms 1.16ms 1.96ms 17.5ms* 19.6ms 11ms 1.79ms 58ms
10k 2.57ms 1.90ms 2.40ms 19.7ms* 28.8ms 154ms 4.5ms 206ms
100k 23ms 8.4ms 19ms 47ms 74ms 1306ms 39ms 1452ms

* struct cold JIT ~15ms, warm 47ms/100k

Typical random-data speedup (preserved): 0.3.1 fvg_mit 963ms → 0.3.2 16ms at 100k57× faster for d small. Pathological g=Θ(n), d=Θ(n) (all gaps mitigate at last bar, see benchmarks/bench_adversarial.py) remains worst O(g·n)=Θ(n²)10k 0.41s → 40k 6.5s → 80k 31s, same as 0.3.1 family.

Complexity (corrected):

  • swings O(n), fvg w/o mit O(n) (bulk), fvg existence flags O(n) via NaN-safe reverse-cum, fvg first-index O(n + g·d) avg/practical, worst O(g·n) Θ(n²) when g=Θ(n) and d=Θ(n).
  • structure O(n) Numba cache=True (top-level), OB O(m·L) bounded L=lookback, liquidity EQH O(s) diff.

Limitations: fvg mit worst Θ(n²) — avoid compute_mitigation=True on 500k+ dense adversarial gaps; for typical random gaps it's ~16ms/100k. polars Lazy for fvg/swings native (shift/rolling_max), others fallback honest collect()->eager->lazy; order_blocks many impulses → lookback bound.


Financial & Legal Disclaimer

IMPORTANT — PLEASE READ CAREFULLY

pyvsmc is an open-source analytics and research library. It is provided solely for educational, informational, and research purposes.

  • Not Financial Advice. Nothing in this library, its documentation, examples, or outputs constitutes financial, investment, trading, or other professional advice.
  • No Warranty of Accuracy or Fitness. SMC are interpretive frameworks.
  • Use at Your Own Risk. Trading involves substantial risk of loss.
  • No Liability. Authors disclaim all liability.
  • Do Your Own Research (DYOR).

License

MIT License — see LICENSE for details.

Copyright (c) 2026 pyvsmc contributors.


Contributing

Issues and pull requests are welcome. Please run ruff, mypy, and pytest before submitting.

Acknowledgements

Built with NumPy, Numba and Polars. SMC concepts as described by the broader ICT / Smart Money community.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyvsmc-0.3.7.tar.gz (53.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyvsmc-0.3.7-py3-none-any.whl (40.7 kB view details)

Uploaded Python 3

File details

Details for the file pyvsmc-0.3.7.tar.gz.

File metadata

  • Download URL: pyvsmc-0.3.7.tar.gz
  • Upload date:
  • Size: 53.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.5

File hashes

Hashes for pyvsmc-0.3.7.tar.gz
Algorithm Hash digest
SHA256 caf0ecc5a2dc7a70015c39c4993d1a01a989ec359e8085830ecbd1673c4461d9
MD5 f0f77caadce4b0c44c9bd826b220d79e
BLAKE2b-256 1ba169bce7167e0590dd56a43b631bab0758007f71673a75c03e7d90feddad53

See more details on using hashes here.

File details

Details for the file pyvsmc-0.3.7-py3-none-any.whl.

File metadata

  • Download URL: pyvsmc-0.3.7-py3-none-any.whl
  • Upload date:
  • Size: 40.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.5

File hashes

Hashes for pyvsmc-0.3.7-py3-none-any.whl
Algorithm Hash digest
SHA256 99b9e195a4adb55acfaab5fb22af1cd5c4c3a97debfe55ae230c8d52df673bee
MD5 4e352d577d16944c34be7a478a0c6553
BLAKE2b-256 54601ea29ad8f5500e9c4164142c27b9b96788bc81b39c766eb55fbe6ba18cac

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.3.7 This release

2 files

0.3.6

2 files

0.3.5

2 files

0.3.4

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page