OPEN-SOURCE SCRIPT

Stochastic Order Flow Momentum [ScorsoneEnterprises]

628
This indicator implements a stochastic model of order flow using the Ornstein-Uhlenbeck (OU) process, combined with a Kalman filter to smooth momentum signals. It is designed to capture the dynamic momentum of volume delta, representing the net buying or selling pressure per bar, and highlight potential shifts in market direction. The volume delta data is sourced from TradingView’s built-in functionality:
tradingview.com/support/solutions/43000725057-volume-delta/.

For a deeper dive into stochastic processes like the Ornstein-Uhlenbeck model in financial contexts, see these research articles: arxiv.org/html/2412.12458v1 and arxiv.org/pdf/1811.09312.

The SOFM tool aims to reveal the momentum and acceleration of order flow, modeled as a mean-reverting stochastic process. In markets, order flow often oscillates around a baseline, with bursts of buying or selling pressure that eventually fade—similar to how physical systems return to equilibrium. The OU process captures this behavior, while the Kalman filter refines the signal by filtering noise. Parameters theta (mean reversion rate), mu (mean level), and sigma (volatility) are estimated by minimizing a squared-error objective function using gradient descent, ensuring adaptability to real-time market conditions.

How It Works

The script combines a stochastic model with signal processing. Here’s a breakdown of the key components, including the OU equation and supporting functions.

Pine Script®
// Ornstein-Uhlenbeck model for volume delta ou_model(params, v_t, lkb) => theta = clamp(array.get(params, 0), 0.01, 1.0) mu = clamp(array.get(params, 1), -100.0, 100.0) sigma = clamp(array.get(params, 2), 0.01, 100.0) error = 0.0 v_pred = array.new<float>(lkb, 0.0) array.set(v_pred, 0, array.get(v_t, 0)) for i = 1 to lkb - 1 v_prev = array.get(v_pred, i - 1) v_curr = array.get(v_t, i) // Discretized OU: v_t = v_{t-1} + theta * (mu - v_{t-1}) + sigma * noise v_next = v_prev + theta * (mu - v_prev) array.set(v_pred, i, v_next) v_curr_clean = na(v_curr) ? 0 : v_curr v_pred_clean = na(v_next) ? 0 : v_next error := error + math.pow(v_curr_clean - v_pred_clean, 2) error


The ou_model function implements a discretized Ornstein-Uhlenbeck process:
v_t = v_{t-1} + theta (mu - v_{t-1})
The model predicts volume delta (v_t) based on its previous value, adjusted by the mean-reverting term theta (mu - v_{t-1}), with sigma representing the volatility of random shocks (approximated in the Kalman filter).

Parameters Explained

The parameters theta, mu, and sigma represent distinct aspects of order flow dynamics:

Theta:
Definition: The mean reversion rate, controlling how quickly volume delta returns to its mean (mu). Constrained between 0.01 and 1.0 (e.g., clamp(array.get(params, 0), 0.01, 1.0)).
Interpretation: A higher theta indicates faster reversion (short-lived momentum), while a lower theta suggests persistent trends. Initial value is 0.1 in init_params.
In the Code: In ou_model, theta scales the pull toward \mu, influencing the predicted v_t.

Mu:
Definition: The long-term mean of volume delta, representing the equilibrium level of net buying/selling pressure. Constrained between -100.0 and 100.0 (e.g., clamp(array.get(params, 1), -100.0, 100.0)).
Interpretation: A positive mu suggests a bullish bias, while a negative mu indicates bearish pressure. Initial value is 0.0 in init_params.
In the Code: In ou_model, mu is the target level that v_t reverts to over time.

Sigma:
Definition: The volatility of volume delta, capturing the magnitude of random fluctuations. Constrained between 0.01 and 100.0 (e.g., clamp(array.get(params, 2), 0.01, 100.0)).
Interpretation: A higher sigma reflects choppier, noisier order flow, while a lower sigma indicates smoother behavior. Initial value is 0.1 in init_params.
In the Code: In the Kalman filter, sigma contributes to the error term, adjusting the smoothing process.

Summary:

theta: Speed of mean reversion (how fast momentum fades).
mu: Baseline order flow level (bullish or bearish bias).
sigma: Noise level (variability in order flow).

Other Parts of the Script

Clamp
A utility function to constrain parameters, preventing extreme values that could destabilize the model.

ObjectiveFunc

Defines the objective function (sum of squared errors) to minimize during parameter optimization. It compares the OU model’s predicted volume delta to observed data, returning a float to be minimized.

How It Works: Calls ou_model to generate predictions, computes the squared error for each timestep, and sums it. Used in optimization to assess parameter fit.

FiniteDifferenceGradient

Calculates the gradient of the objective function using finite differences. Think of it as finding the "slope" of the error surface for each parameter. It nudges each parameter (theta, mu, sigma) by a small amount (epsilon) and measures the change in error, returning an array of gradients.

Minimize

Performs gradient descent to optimize parameters. It iteratively adjusts theta, mu, and sigma by stepping down the "hill" of the error surface, using the gradients from FiniteDifferenceGradient. Stops when the gradient norm falls below a tolerance (0.001) or after 20 iterations.

Kalman Filter

Smooths the OU-modeled volume delta to extract momentum. It uses the optimized theta, mu, and sigma to predict the next state, then corrects it with observed data via the Kalman gain. The result is a cleaner momentum signal.

Applied

After initializing parameters (theta = 0.1, mu = 0.0, sigma = 0.1), the script optimizes them using volume delta data over the lookback period. The optimized parameters feed into the Kalman filter, producing a smoothed momentum array. The average momentum and its rate of change (acceleration) are calculated, though only momentum is plotted by default.
A rising momentum suggests increasing buying or selling pressure, while a flattening or reversing momentum indicates fading activity. Acceleration (not plotted here) could highlight rapid shifts.

Tool Examples

The SOFM indicator provides a dynamic view of order flow momentum, useful for spotting directional shifts or consolidation.

Low Time Frame Example: On a 5-minute chart of NNQ, a rising momentum above zero with a lookback of 5 might signal building buying pressure, while a drop below zero suggests selling dominance. Crossings of the zero line can mark transitions, though the focus is on trend strength rather than frequent crossovers.

istantanea

High Time Frame Example: On a daily chart of VST, a sustained positive momentum could confirm a bullish trend, while a sharp decline might warn of exhaustion. The mean-reverting nature of the OU process helps filter out noise on longer scales. It doesn’t make the most sense to use this on a high timeframe with what our data is.

istantanea

Choppy Markets: When momentum oscillates near zero, it signals indecision or low conviction, helping traders avoid whipsaws. Larger deviations from zero suggest stronger directional moves to act on, this is on $STT.

istantanea

Inputs
Lookback: Users can set the lookback period (default 5) to adjust the sensitivity of the OU model and Kalman filter. Shorter lookbacks react faster but may be noisier; longer lookbacks smooth more but lag slightly.
The user can also specify the timeframe they want the volume delta from. There is a default way to lower and expand the time frame based on the one we are looking at, but users have the flexibility.

No indicator is 100% accurate, and SOFM is no exception. It’s an estimation tool, blending stochastic modeling with signal processing to provide a leading view of order flow momentum. Use it alongside price action, support/resistance, and your own discretion for best results. I encourage comments and constructive criticism.

Declinazione di responsabilità

Le informazioni ed i contenuti pubblicati non costituiscono in alcun modo una sollecitazione ad investire o ad operare nei mercati finanziari. Non sono inoltre fornite o supportate da TradingView. Maggiori dettagli nelle Condizioni d'uso.