System Init
0%
LOADING_ASSETSv2.0.26
blogs/membangun-pyvsmc-vectorized-smart-money-concepts
//Khay
Baca Bahasa Indonesia

Deconstructing the Loop Paradox: Architecture Notes on pyvsmc

PythonTradingQuantNumPyPolarsData ScienceAlgorithms

I often reflect on why modern quantitative architectures still treat financial time-series as sequential queues of rows to be evaluated one candle at a time. Iterating row by row with procedural loops is not merely slow; it is a conceptual mismatch with contiguous discrete memory layouts.

When scanning hundreds of thousands of market candles for Smart Money Concepts (SMC) patterns like Fair Value Gaps, Fractal Swings, and Order Blocks, latency is rarely a language limitation. It is a memory architecture problem.

To solve this, I designed pyvsmc (Python Vectorized Smart Money Concepts). The core philosophy is absolute: eliminate sequential time-series loops from the Python interpreter and delegate all tensor evaluations to SIMD-accelerated linear algebra in C and Rust.

The package is available on PyPI:

pip install pyvsmc

Full source code and documentation can be examined on GitHub at Khaymat/pyvsmc and on PyPI at pypi.org/project/pyvsmc.


The Core Problem: Why Iterative Bar Looping Is an Anti-Pattern

Human perception views price charts as historical narratives: yesterday transitions into today, which transitions into tomorrow. Hardware, however, recognizes no narrative. It only sees contiguous blocks of float64 arrays in RAM.

Procedural iteration via for i in range(len(prices)) forces the CPython interpreter to execute dynamic type checks, stack allocations, and pointer dereferences on every single row.

Across a dataset of n=100,000n = 100,000 bars, searching forward for future zone mitigations degrades the routine into quadratic complexity O(n2)\mathcal{O}(n^2):

Total Comparisonsn(n1)25×109 operations\text{Total Comparisons} \approx \frac{n(n-1)}{2} \approx 5 \times 10^9 \text{ operations}

Executing 5 billion CPU cycles for an operation that can be solved in a single linear pass is fundamentally inefficient.


Mathematical Formulation in pyvsmc

1. Fair Value Gaps and Asymptotic Reduction to O(n)

A Fair Value Gap (FVG) represents a 3-candle structural liquidity void across indices i2,i1,ii-2, i-1, i:

Bullish FVG: Low[i]>High[i2]Low[i] > High[i-2] Imbalance interval: [High[i2],Low[i]][High[i-2], Low[i]].

Bearish FVG: High[i]<Low[i2]High[i] < Low[i-2] Imbalance interval: [High[i],Low[i2]][High[i], Low[i-2]].

Detecting the gap interval requires straightforward shifted array slicing without Python loops:

import numpy as np

bullish_fvg = low[2:] > high[:-2]
bearish_fvg = high[2:] < low[:-2]

The deeper challenge lies in mitigation verification: tracking whether future candles (j>ij > i) violate the gap boundary.

Instead of scanning each subset min(Low[i+1:n])\min(Low[i+1 : n]) sequentially, I formulated the evaluation using a Reverse Cumulative Extrema scan:

RevCumMin(Low)k=minjkLow[j]\text{RevCumMin}(Low)_k = \min_{j \ge k} Low[j]

By reversing the array, running a cumulative minimum, and reversing the output, future bounds are computed in a single linear O(n)\mathcal{O}(n) sweep:

# Compute future lower bounds in linear O(n) time
rev_cummin_low = np.minimum.accumulate(low[::-1])[::-1]

# Simultaneous vector mitigation mask
mitigated_mask = rev_cummin_low[i + 1] <= bullish_upper[i]

Complexity immediately drops from 5×1095 \times 10^9 operations to linear vector instructions evaluated in milliseconds.


2. Fractal Swings via Zero-Copy Strided Windows

To isolate fractal pivot points across window radius NN:

SwingHigh[i]    High[i]=max{High[iN],,High[i+N]}SwingHigh[i] \iff High[i] = \max \{ High[i-N], \dots, High[i+N] \} SwingLow[i]    Low[i]=min{Low[iN],,Low[i+N]}SwingLow[i] \iff Low[i] = \min \{ Low[i-N], \dots, Low[i+N] \}

Rather than allocating iterative sub-arrays, pyvsmc employs strided memory manipulation via sliding_window_view. This yields a virtual 2D view of shape (n2N,2N+1)(n - 2N, 2N + 1) with zero RAM duplication:

from numpy.lib.stride_tricks import sliding_window_view

windows = sliding_window_view(high, window_shape=2 * N + 1)
is_swing_high = high[N:-N] == np.max(windows, axis=1)

3. Polars Native Integration

To support large-scale quantitative data pipelines, pyvsmc exposes an Arrow-native .smc namespace:

import polars as pl
import pyvsmc

df = pl.read_parquet("market_ticks.parquet")
df_smc = df.smc.add_all(window_size=2, ob_lookback=10)

Concluding Thoughts

Computational efficiency is not merely an optimization benchmark; it is an architectural discipline. Removing redundant interpreter overhead allows mathematical models to execute as intended by the underlying hardware.

pyvsmc is open-source under the MIT license on GitHub and PyPI.