The Soliton Wave Non-Linear Momentum Engine translates non-linear wave mechanics—originally developed to model solitary waves in hydrodynamics and plasma physics—into a quantitative regime-detection framework for financial markets.
By evaluating market momentum through the Korteweg–de Vries (KdV) differential framework, the study separates ordinary, self-dissipating noise from rare, high-conviction institutional sweeps. Applied to the E-mini S&P 500 (/ES) on a 1-Hour chart, the model isolates structural directional expansion, allowing traders to enter early in momentum pulses that resist immediate mean-reversion.
When non-linear steepening exactly balances dispersion, a Soliton wave forms—a single, localized pulse that propagates over long distances without losing its amplitude, shape, or speed.
By evaluating market momentum through the Korteweg–de Vries (KdV) differential framework, the study separates ordinary, self-dissipating noise from rare, high-conviction institutional sweeps. Applied to the E-mini S&P 500 (/ES) on a 1-Hour chart, the model isolates structural directional expansion, allowing traders to enter early in momentum pulses that resist immediate mean-reversion.
Conceptual Framework & Physics Analogy
In physical fluid systems, standard waves dissipate as they travel due to dispersion (u_xxx), where different frequency components travel at different speeds and break apart the wave packet. However, under specific conditions, non-linear steepening (u * u_x) occurs, causing the wave front to sharpen.When non-linear steepening exactly balances dispersion, a Soliton wave forms—a single, localized pulse that propagates over long distances without losing its amplitude, shape, or speed.
- Non-Linear Steepening (u * u_x): Represents aggressive market orders sweeping through passive book depth. Directional displacement scales exponentially when accompanied by heavy volume flux.
- Dispersion (u_xxx): Represents market friction, choppy two-way trading, and liquidity absorption that causes most price moves to stall and mean-revert.
- The Soliton State: When non-linear directional energy overwhelms background dispersion, the price move behaves like a solitary wave. Rather than fading, price continues in the impulse direction.
Mathematical Mapping
The engine quantifies these physical forces using three core equations:- Non-Linear Wave Energy (U_pulse):
Calculates directional displacement weighted non-linearly by volume density.
- Wave Dispersion Envelope (D):
Measures background noise and energy variance over a rolling window (N).
- Soliton Condition Ratio (S):
Measures the signal-to-noise ratio of non-linear steepening relative to dispersion.
Model Inputs & Calibration for /ES (1-Hour)
On the 1-Hour /ES chart, institutional accumulation and distribution take time to clear passive order liquidity. The inputs control wave sensitivity and structural execution:| Input Variable | Function | Effect on Strategy Performance |
| wave_lookback | Rolling bar window used to calculate background dispersion ($\mathcal{D}$). | Lower (10–15): Makes model hyper-sensitive to short-term bursts; increases trade frequency. Higher (20–30): Establishes a broader baseline; filters out intra-session spikes to isolate multi-session trends. |
| soliton_threshold | The minimum Soliton Ratio ($\mathcal{S}$) required to trigger a trade. | Lower (1.5): Captures earlier entries but risks entering standard breakout noise. Higher (2.0–2.5): Restricts entries to true institutional sweeps, driving up win rate at the expense of trade count. |
| min_cooldown_bars | Mandatory bar lockout following a triggered signal. | Prevents over-trading during prolonged impulse legs. On /ES 1-Hour, setting this between 12 and 24 ensures the model trades distinct wave packets rather than chasing the same move. |
The Quantitative Profit Engine & Non-Repainting Architecture
The backtest engine integrated within this study enforces strict real-world execution rules to guarantee historical accuracy without forward-looking bias.1. Non-Repainting Execution
ThinkScript signals often suffer from repainting when code evaluates intra-bar close prices or allows state variables to update bidirectionally. This model uses single-direction recursive logic (rec variables) evaluated using top-down execution:- Signals are calculated on bar close.
- Trade execution (tradeState) occurs on the Open of the following bar (open).
- Once a signal locks in, historical arrows, entry bubbles, and state variables never shift or disappear on chart refresh.
2. Futures-Native Point & Tick Valuation
The engine dynamically reads instrument parameters via TickSize() and TickValue(). For /ES, where 1 point = 4 ticks ($12.50/tick or $50/point), the engine translates dollar inputs directly into precise point targets:- Take_Profit_Dollars = Adjust downwards if you want to take profits more quickly.
- Stop_Loss_Dollars = Adjust downwards to limit your loss on each trade.
3. State-Locked Position Tracking
The profit engine maintains a continuous state machine:- Position Lock: Ignores secondary raw triggers while a trade is active (pos != 0), ensuring profit targets and stop losses are evaluated clean of signal noise.
- Realistic Slippage & Fees: Every completed trade subtracts Trade_Commission ($4.50 round-turn default) from net results, delivering realistic expectancy metrics across Long Win %, Short Win %, and Net Profit/Loss labels.
Code:# SOLITON WAVE NON-LINEAR MOMENTUM ENGINE # Non-Linear Wave Mechanics: Soliton Pulse vs. Dispersion Balance # by whoDAT 8/2026 declare upper; # --- Inputs: Soliton Engine --- input wave_lookback = 20; # Period to compute dispersion envelope input soliton_threshold = 1.9; # Ratio where non-linear momentum overrides dispersion input min_cooldown_bars = 15; # Lockout window between wave packets # --- Inputs: Profit Engine --- input Take_Profit_Dollars = 10000.0; input Stop_Loss_Dollars = 10000.0; input Trade_Commission = 4.50; # Round-turn futures commission input ShowProfitBubbles = yes; input ShowDebugBubbles = no; input Display_Mode = {default "Dollars", "Pips"}; # --- 1. SAFE ACCUMULATION GATE --- def isReady = BarNumber() > wave_lookback + min_cooldown_bars; # --- 2. NON-LINEAR WAVE METRICS (KdV Equivalence) --- # Non-Linear Steepening (u * u_x): Directional price displacement scaled by volume density def bar_displacement = close - open; def vol_factor = Log(1 + Volume); def nonlinear_energy = bar_displacement * vol_factor; # Wave Dispersion (u_xxx): Variance/noise of energy over lookback window def dispersion = StDev(nonlinear_energy, wave_lookback); # Soliton Condition (S = |Energy| / Dispersion) def soliton_ratio = if dispersion > 0 then AbsValue(nonlinear_energy) / dispersion else 0; # --- 3. SOLITON PULSE SIGNALS --- def is_soliton_pulse = isReady and (soliton_ratio >= soliton_threshold); # Directional Vector of the Soliton def pulse_dir = Sign(nonlinear_energy); def raw_buy_trigger = is_soliton_pulse and pulse_dir > 0; def raw_sell_trigger = is_soliton_pulse and pulse_dir < 0; rec bars_since_last_signal; def LongSignalRaw = if !isReady or bars_since_last_signal[1] < min_cooldown_bars then no else raw_buy_trigger; def ShortSignalRaw = if !isReady or bars_since_last_signal[1] < min_cooldown_bars then no else raw_sell_trigger; rec lastSignalDir = CompoundValue(1, if !isReady then 0 else if LongSignalRaw then 1 else if ShortSignalRaw then -1 else lastSignalDir[1], 0); def LongSignal = isReady and LongSignalRaw and lastSignalDir[1] != 1; def ShortSignal = isReady and ShortSignalRaw and lastSignalDir[1] != -1; bars_since_last_signal = CompoundValue(1, if LongSignal or ShortSignal then 0 else bars_since_last_signal[1] + 1, 999); # --- 4. QUANTITATIVE PROFIT ENGINE CORE --- def ts = if !IsNaN(TickSize()) and TickSize() > 0 then TickSize() else 0.001; def tv = if !IsNaN(TickValue()) and TickValue() > 0 then TickValue() else 1.0; def pipSize = if ts == 0.00001 then 0.0001 else if ts == 0.001 then 0.01 else ts; def pv = tv * (pipSize / ts); def pointsToProfit = Take_Profit_Dollars / (tv / ts); def pointsToLoss = Stop_Loss_Dollars / (tv / ts); rec tradeState = CompoundValue(1, if !isReady then 0 else if tradeState[1] == 0 then ( if LongSignal[1] then open else if ShortSignal[1] then -open else 0 ) else if tradeState[1] > 0 then ( if ShortSignal or (high - tradeState[1]) >= pointsToProfit or (tradeState[1] - low) >= pointsToLoss then 0 else tradeState[1] ) else ( if LongSignal or (AbsValue(tradeState[1]) - low) >= pointsToProfit or (high - AbsValue(tradeState[1])) >= pointsToLoss then 0 else tradeState[1] ), 0); def pos = Sign(tradeState); def longExit = isReady and tradeState[1] > 0 and tradeState == 0; def shortExit = isReady and tradeState[1] < 0 and tradeState == 0; def tradeClosed = longExit or shortExit; rec entryPrice = CompoundValue(1, if !isReady then 0 else if (tradeState crosses above 0 or tradeState crosses below 0) then open else entryPrice[1], 0); def exitPrice = if !tradeClosed then close else if longExit then ( if ShortSignal then close else if (high - entryPrice[1]) >= pointsToProfit then entryPrice[1] + pointsToProfit else entryPrice[1] - pointsToLoss ) else ( if LongSignal then close else if (entryPrice[1] - low) >= pointsToProfit then entryPrice[1] - pointsToProfit else entryPrice[1] + pointsToLoss ); def longResult = if longExit and !IsNaN(entryPrice) and !IsNaN(exitPrice) then (exitPrice - entryPrice) / pipSize * pv - Trade_Commission else 0; def shortResult = if shortExit and !IsNaN(entryPrice) and !IsNaN(exitPrice) then (entryPrice - exitPrice) / pipSize * pv - Trade_Commission else 0; def currentTradeResult = longResult + shortResult; rec totalPnl = if IsNaN(totalPnl[1]) then 0 else totalPnl[1] + currentTradeResult; rec tradeCount = if IsNaN(tradeCount[1]) then 0 else tradeCount[1] + (if tradeClosed then 1 else 0); rec pLong = if IsNaN(pLong[1]) then 0 else pLong[1] + longResult; rec cLong = if IsNaN(cLong[1]) then 0 else cLong[1] + (if longExit then 1 else 0); rec wLong = if IsNaN(wLong[1]) then 0 else wLong[1] + (if longExit and longResult > 0 then 1 else 0); rec pShort = if IsNaN(pShort[1]) then 0 else pShort[1] + shortResult; rec cShort = if IsNaN(cShort[1]) then 0 else cShort[1] + (if shortExit then 1 else 0); rec wShort = if IsNaN(wShort[1]) then 0 else wShort[1] + (if shortExit and shortResult > 0 then 1 else 0); rec mWin = if IsNaN(mWin[1]) then 0 else if currentTradeResult > mWin[1] then currentTradeResult else mWin[1]; rec mLoss = if IsNaN(mLoss[1]) then 0 else if currentTradeResult < mLoss[1] then currentTradeResult else mLoss[1]; def wrL = if cLong > 0 then (wLong / cLong) * 100 else 0; def wrS = if cShort > 0 then (wShort / cShort) * 100 else 0; def isPips = Display_Mode == Display_Mode."Pips"; # --- 5. CHART DASHBOARD & LABELS --- AddLabel(yes, "Trades: " + tradeCount + " | Net: " + (if isPips then Round(totalPnl,1) + " P" else AsDollars(totalPnl)), if totalPnl >= 0 then Color.GREEN else Color.RED, Location.BOTTOM_LEFT); AddLabel(cLong > 0, "Long Win: " + Round(wrL,1) + "%", Color.CYAN, Location.BOTTOM_LEFT); AddLabel(cShort > 0, "Short Win: " + Round(wrS,1) + "%", Color.ORANGE, Location.BOTTOM_LEFT); AddLabel(yes, "L Profit: " + (if isPips then Round(pLong,1)+" P" else AsDollars(pLong)), Color.CYAN, Location.BOTTOM_LEFT); AddLabel(yes, "S Profit: " + (if isPips then Round(pShort,1)+" P" else AsDollars(pShort)), Color.ORANGE, Location.BOTTOM_LEFT); AddLabel(tradeCount > 0, "Max Win: " + (if isPips then Round(mWin,1)+" P" else AsDollars(mWin)) + " | Max Loss: " + (if isPips then Round(mLoss,1)+" P" else AsDollars(mLoss)), Color.GRAY, Location.BOTTOM_LEFT); AddLabel(pos == 1, " . . WAVE STATE: SOLITON PROPAGATION LONG ", Color.LIGHT_GREEN); AddLabel(pos == -1, " . . WAVE STATE: SOLITON PROPAGATION SHORT ", Color.LIGHT_RED); AddLabel(pos == 0, " . . WAVE STATE: DISPERSIVE NOISE / BALANCED ", Color.GRAY); # --- 6. EXECUTION SIGNALS & PRICE CHART VISUALS --- plot UpArrow = if LongSignal then low - (ts*10) else Double.NaN; UpArrow.SetPaintingStrategy(PaintingStrategy.ARROW_UP); UpArrow.SetDefaultColor(Color.CYAN); UpArrow.SetLineWeight(3); plot DownArrow = if ShortSignal then high + (ts*10) else Double.NaN; DownArrow.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN); DownArrow.SetDefaultColor(Color.ORANGE); DownArrow.SetLineWeight(3); AssignPriceColor(if pos == 1 then Color.CYAN else if pos == -1 then Color.ORANGE else Color.CURRENT); # --- 7. TRANSACTION BUBBLES --- def showBubble = tradeClosed and !IsNaN(currentTradeResult); AddChartBubble(ShowDebugBubbles and showBubble, high, "Type: " + (if longExit then "LONG" else "SHORT") + "\nIn: " + Round(entryPrice, 5) + "\nOut: " + Round(exitPrice, 5) + "\nResult: " + (if isPips then Round(currentTradeResult,1) + "P" else AsDollars(currentTradeResult)), Color.GRAY, no); AddChartBubble(ShowProfitBubbles and showBubble, low, (if isPips then Round(currentTradeResult,1) + " P" else AsDollars(currentTradeResult)), if currentTradeResult >= 0 then Color.GREEN else Color.RED, yes);
Last edited by a moderator: