Soliton Wave Momentum For ThinkOrSwim

whoDAT

Active member
Plus
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.

Screenshot 2026-08-21 214109.png


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:

  1. Non-Linear Wave Energy (U_pulse):
    Calculates directional displacement weighted non-linearly by volume density.
    Screenshot 2026-08-21 213250.png


  2. Wave Dispersion Envelope (D):
    Measures background noise and energy variance over a rolling window (N).
    Screenshot 2026-08-21 213308.png


  3. Soliton Condition Ratio (S):
    Measures the signal-to-noise ratio of non-linear steepening relative to dispersion.
    Screenshot 2026-08-21 213323.png
When S is greater than the threshold, the system declares a Soliton Propagation State. The sign of U determines the directional vector U > 0 => Bullish or U < 0 => Bearish.

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 VariableFunctionEffect on Strategy Performance
wave_lookbackRolling 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_thresholdThe 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_barsMandatory 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:

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
1084 Online
Create Post

Similar threads

Similar threads

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top