Page 7 of 9

Re: Heikin Ashi Candles, Smoothing the Noise

Posted: Sat Oct 03, 2026 5:48 am
by PTScalper
2. The Updated Success Block (OnTick)

Locate the result handling block in your OnTick method and replace it with this upgraded logic:

Code: Select all

// 4. RESULT HANDLING
if (closeResult.IsSuccessful)
{
    Print($"[Scale-Out Success] 50% partial executed.");
    
    // Purge state and save to JSON
    _scaleOutTargets.Remove(position.Id);
    _lastCloseAttempts.Remove(position.Id);
    SaveState(); 

    // --- BREAKEVEN EXECUTION ---
    if (MoveToBreakeven)
    {
        // 1. Calculate the offset to cover round-trip commissions
        double beOffset = BreakevenExtraPips * Symbol.PipSize;
        double bePrice = position.TradeType == TradeType.Buy 
            ? position.EntryPrice + beOffset 
            : position.EntryPrice - beOffset;

        bePrice = Math.Round(bePrice, Symbol.Digits);

        // 2. Safety Filter: Ensure we never move the stop backwards 
        // if the Heikin Ashi trailing stop is already in deep profit.
        bool isForwardMove = position.TradeType == TradeType.Buy
            ? (position.StopLoss == null || bePrice > position.StopLoss)
            : (position.StopLoss == null || bePrice < position.StopLoss);

        if (isForwardMove)
        {
            // 3. Execute synchronous API modification on the remaining volume
            TradeResult beResult = ModifyPosition(position, bePrice, position.TakeProfit);
            
            if (beResult.IsSuccessful)
                Print($"[Risk Free] Stop Loss moved to breakeven at {bePrice}");
            else
                Print($"[API Error] Failed to set breakeven: {beResult.Error}");
        }
        else
        {
            Print($"[Filter] Breakeven skipped. HA Trailing Stop is already beyond {bePrice}");
        }
    }
}
else
{
    Print($"[API Error] Scale-out failed: {closeResult.Error}. Retrying in {RetryCooldownMs}ms.");
}

Re: Heikin Ashi Candles, Smoothing the Noise

Posted: Sat Oct 03, 2026 5:49 am
by PTScalper
Institutional Guardrails in This Logic

The Commission Offset (BreakevenExtraPips): Moving a stop exactly to position.EntryPrice guarantees a net loss when hit, because you still pay the broker's spread on the exit and commissions on both the entry and exit. Adding a customizable 0.5 to 1.0 pip buffer ensures a true "scratch trade" where you exit flat on your remaining equity.

The isForwardMove Check: Because your OnBar method is independently trailing the stop behind Heikin Ashi wicks, there is a rare edge case where a massive news candle triggers your HA trailing stop to jump past your scale-out target before the tick data registers the RR hit. If you simply fired ModifyPosition(position, position.EntryPrice), the bot would aggressively drag your stop loss backward, exposing you to unnecessary risk.

Shared Object Scope: When ClosePosition executes a partial close, cTrader updates the underlying position object natively. You do not need to hunt for a new Position ID; you simply pass the exact same position reference into ModifyPosition() on the very next line.

Re: Heikin Ashi Candles, Smoothing the Noise

Posted: Sat Oct 03, 2026 5:49 am
by PTScalper
Testing partial close and breakeven logic in cTrader’s Visual Backtester requires specific engine configurations. Because the scale-out and retry mechanisms execute inside OnTick while the trailing stop executes inside OnBar, using standard bar-level backtesting will mask bugs, suppress your cooldown loops, and produce false fills.

Follow this setup to stress-test the logic under realistic, volatile market conditions.

Re: Heikin Ashi Candles, Smoothing the Noise

Posted: Sat Oct 03, 2026 5:50 am
by PTScalper
1. Configure the Backtesting Engine for Tick Precision

Open the Automate tab in cTrader, select your cBot, and click on Backtesting. Set up the testing environment with these parameters:

Data Feed: Set Data strictly to "Tick data from Server (accurate)".

Why: If set to "m1 bars (interpolated)" or "Open prices only", cTrader simulates only 4 ticks per minute or 1 tick per bar. In that mode, your OnTick cooldown logic (RetryCooldownMs = 500) and intrabar touch of the target will not evaluate correctly.

Execution Latency: Click the gear icon (Settings) next to the backtest controls and set Latency to 50 ms – 150 ms.

Why: Live brokers never fill instantly. Introducing artificial latency ensures that price movement between the order dispatch and the broker's response doesn't create invalid order modifications.

Commission & Spread: Under settings, verify that your account type includes standard broker commissions (e.g., $30 per million / $3.00 per lot per side). This verifies whether your BreakevenExtraPips accurately covers the commission deduction on the remaining volume.

Re: Heikin Ashi Candles, Smoothing the Noise

Posted: Sat Oct 03, 2026 5:50 am
by PTScalper
2. Isolate State Persistence During Backtests

In the previous step, state persistence was wired to save files directly into AppData/Roaming. If you run a backtest with that code active, two problems occur:

The backtest will read and overwrite the state file used by your live or demo bots.

If you restart a backtest mid-run, it will load remnants of previous simulated trades from your physical drive.

Add a guard in your file initialization using cTrader's RunningMode property to isolate backtest storage:

Code: Select all

private void InitializeStatePersistence()
{
    string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
    
    // Separate backtesting state from live/demo trading
    string modePrefix = RunningMode == RunningMode.VisualBacktesting || RunningMode == RunningMode.SilentBacktesting
        ? "BACKTEST_"
        : "LIVE_";

    _stateFilePath = Path.Combine(appData, $"{modePrefix}{BotLabel}_{SymbolName}_State.json");

    // Automatically wipe backtest cache at the start of a fresh run
    if (RunningMode == RunningMode.VisualBacktesting && File.Exists(_stateFilePath))
    {
        File.Delete(_stateFilePath);
    }
}

Re: Heikin Ashi Candles, Smoothing the Noise

Posted: Sat Oct 03, 2026 5:51 am
by PTScalper
3. Add Visual Markers to the Chart

When running the Visual Backtester at 10x–50x speed, inspecting log lines in real time is impractical. Inject visual chart lines so you can observe the exact moment the target is crossed and the stop moves to breakeven:

Code: Select all

// Place inside OnTick right after setting or moving target/breakeven:
private void UpdateVisualDiagnostics(Position pos, double targetPrice)
{
    if (RunningMode != RunningMode.VisualBacktesting) return;

    // Draw Target Line
    Chart.DrawHorizontalLine("RR_Target", targetPrice, Color.Gold, 2, LineStyle.Dots);

    // Draw Breakeven Threshold
    double bePrice = pos.TradeType == TradeType.Buy 
        ? pos.EntryPrice + (BreakevenExtraPips * Symbol.PipSize) 
        : pos.EntryPrice - (BreakevenExtraPips * Symbol.PipSize);

    Chart.DrawHorizontalLine("BE_Level", bePrice, Color.Cyan, 1, LineStyle.Lines);
}

Re: Heikin Ashi Candles, Smoothing the Noise

Posted: Sat Oct 03, 2026 5:51 am
by PTScalper
When a position is closed or purged, clean up the visual lines:

Code: Select all

Chart.RemoveObject("RR_Target");
Chart.RemoveObject("BE_Level");

Re: Heikin Ashi Candles, Smoothing the Noise

Posted: Sat Oct 03, 2026 5:53 am
by PTScalper
4. High-Volatility Test Scenarios

To verify that the code does not lock up, crash on rounding, or throw API exceptions during liquidity gaps, test across these specific market conditions:

High-Impact News Spike:
Check whether a 40-pip candle in 2 seconds triggers the 50% scale-out without throwing a TechnicalError or volume sizing exception.

Liquidity Gap / Rollover:
Spreads expand 5x–10x. Ensure your MaxSpreadPips filter halts new entries while allowing open trades to exit smoothly.

Aggressive Trend Deceleration
Ensure that when price tags the RR target and immediately retraces violently, the breakeven stop halts the trade at net zero instead of negative equity.

Re: Heikin Ashi Candles, Smoothing the Noise

Posted: Sat Oct 03, 2026 5:54 am
by PTScalper
5. Log & Deal History Audit

After the Visual Backtest finishes, inspect the bottom tabs in cTrader to confirm mechanical execution:

Positions & History Tab:

1.) Filter by your BotLabel.

2.) Find a completed trade that reached the target. You should see two separate Closing Deals under the same trade sequence:

Deal 1: Volume equal to 50% of the original units, marked with a realized profit.

Deal 2: The remaining 50% of the units, closed either by the HA Trailing Stop in deep profit or at your breakeven price.

Events / Journal Tab:

Look for the sequence:

a.) [Attempting Scale-Out] Requesting X units...

b.) [Scale-Out Success] 50% partial executed.

c.) [Risk Free] Stop Loss moved to breakeven at...

Verify there are no unhandled Requote, NoMoney, or BadVolume exceptions.

Verify that if the Heikin Ashi trailing stop had already passed the entry level before the RR target hit, the journal prints [Filter] Breakeven skipped. HA Trailing Stop is already beyond... and preserves your existing stop loss.

Re: Heikin Ashi Candles, Smoothing the Noise

Posted: Sat Oct 03, 2026 5:55 am
by PTScalper
Because cTrader’s backtesting engine rigidly fills orders at the exact historical tick price upon receiving an API command, you cannot pass a "fake" worse price to the ClosePosition method.

To simulate worst-case execution, professional quants use two parallel methods: The Latency Queue (which forces the bot to experience real broker network lag) and The Shadow Ledger (which mathematically calculates a worst-case equity curve).

Here is how to build both into your institutional framework.