Multi Instrument multi TF

I have a multi-series NinjaTrader strategy.
The strategy only trades on BarsInProgress == 1 and uses its own internally created indicator with Closes[1] and Closes[2].
However, simply changing the host chart (BIP0) to another instrument or timeframe changes the backtest results (mainly exit timing), even though BIP0 is never used in logic.
Is there a way to make such a strategy truly host-chart independent or is this a NinjaTrader engine limitation?
Thank you all in advance!

#region Using declarations
using System;
using NinjaTrader.Cbi;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.NinjaScript.Strategies;
#endregion

namespace NinjaTrader.NinjaScript.Strategies
{
public class MultiBipTestStrategy : Strategy
{
private DummySignalEngine sig;

    protected override void OnStateChange()
    {
        if (State == State.SetDefaults)
        {
            Name = "MultiBipTestStrategy";
            Calculate = Calculate.OnBarClose;
            EntriesPerDirection = 1;
            EntryHandling = EntryHandling.AllEntries;
            IsExitOnSessionCloseStrategy = false;
        }
        else if (State == State.Configure)
        {
            // BIP0 = Host Chart (ignored)
            // BIP1 = Trading timeframe
            // BIP2 = Higher timeframe
            AddDataSeries("6E MAR26", BarsPeriodType.Minute, 15);   // BIP1
            AddDataSeries("6E MAR26", BarsPeriodType.Minute, 120);  // BIP2
        }
        else if (State == State.DataLoaded)
        {
            // Create signal engine on BIP1
            sig = DummySignalEngine(Closes[1]);
            sig.SetHtfSeries(Closes[2]);

            // IMPORTANT: NOT adding to chart
            // AddChartIndicator(sig);  // intentionally NOT used
        }
    }

    protected override void OnBarUpdate()
    {
        // Only process trading series
        if (BarsInProgress != 1)
            return;

        if (sig == null)
            return;

        if (CurrentBars[1] < 50 || CurrentBars[2] < 50)
            return;

        int d = (int)Math.Round(sig[0]);

        if (d == 0)
            return;

        // Exit
        if (d < 0)
            ExitLong("ExitL", "Long");
        if (d > 0)
            ExitShort("ExitS", "Short");

        // Entry
        if (d > 0)
            EnterLong(1, "Long");

        if (d < 0)
            EnterShort(1, "Short");
    }
}

}

#region Using declarations
using System;
using NinjaTrader.NinjaScript;
using NinjaTrader.NinjaScript.Indicators;
using System.Windows.Media;
#endregion

namespace NinjaTrader.NinjaScript.Indicators
{
public class DummySignalEngine : Indicator
{
private ISeries htfClose;
private int internalState = 0;

    public void SetHtfSeries(ISeries<double> htfSeries)
    {
        htfClose = htfSeries;
    }

    protected override void OnStateChange()
    {
        if (State == State.SetDefaults)
        {
            Name = "DummySignalEngine";
            Calculate = Calculate.OnBarClose;
            IsOverlay = false;
            AddPlot(Brushes.Transparent, "Delta");
        }
    }

    protected override void OnBarUpdate()
    {
        // Only calculate on primary input (which is Closes[1] from strategy)
        if (BarsInProgress != 0)
            return;

        Values[0][0] = 0;

        if (htfClose == null)
            return;

        if (CurrentBar < 50 || htfClose.Count < 50)
            return;

        // =========================
        // DUMMY LOGIC (NON-TRADING)
        // =========================

        // Just some deterministic but meaningless state machine
        double a = Input[0];
        double b = htfClose[0];

        int oldState = internalState;
        int newState = internalState;

        if (a > b)
            newState = 1;
        else if (a < b)
            newState = -1;

        int delta = newState - oldState;

        internalState = newState;
        Values[0][0] = delta;
    }
}

}

1 Like