Error on calling 'OnStateChange' method: Object reference not set to an instance of an object

Hi,

I have been working on making a strategy out of an indicator I have developed. When the strategy is applied to the chart I do not see any error or message in the log, and the strategy operates as intended.

The issue is when I go to backtest the strategy, I receive:
Error on calling ‘OnStateChange’ method: Object reference not set to an instance of an object

I’ve tried to troubleshoot the issue but I am stumped. I’ve attached the code from namespace through OnStateChange() below.

namespace NinjaTrader.NinjaScript.Strategies
{
// Enum to choose trade direction
public enum TradeDirection
{
LongOnly, // Only allow long entries
ShortOnly, // Only allow short entries
Both // Allow both long and short entries
}

// Main strategy class

public class SwingTrader101 : Strategy
{
// === SWING POINT STORAGE ===
private List allSwingHighs = new(); // Stores all detected swing highs
private List allSwingHighBars = new(); // Bar indices for swing highs
private List allSwingLows = new(); // Stores all detected swing lows
private List allSwingLowBars = new(); // Bar indices for swing lows

  private List<double> swingHighs = new();          // Filtered valid swing highs
  private List<int> swingHighBars = new();          // Bar indices for filtered swing highs
  private List<double> swingLows = new();           // Filtered valid swing lows
  private List<int> swingLowBars = new();           // Bar indices for filtered swing lows

  // === TRACK USED ENTRY PRICES ===
  private HashSet<double> usedLongPrices = new();   // Tracks which long levels have been used
  private HashSet<double> usedShortPrices = new();  // Tracks which short levels have been used

  // === RISK & SIZING ===
  private int EntryCount;                           // Number of filled entries
  private double TotalContracts;                    // Cumulative contracts filled
  private double[] SizeLevels = new double[8];      // Position size for each scale-in level

  // === SWING SETTINGS ===
  private double minDistanceTicks;                  // Minimum distance between swing points
  private int maxSwings;                            // Maximum swing levels to store/draw
  
  private SMMA SMMA4;								  // SMMA 4 period for entry filtering

  // ========================
  //     STATE LOGIC
  // ========================
  protected override void OnStateChange()
  {
      // Check if we are in the 'SetDefaults' stage
      if (State == State.SetDefaults)
      {
          Name = "SwingTrader101";                          // Set the strategy name
          Calculate = Calculate.OnBarClose;                 // Strategy calculates once per bar (not on each tick)
          EntriesPerDirection = 8;                          // Allow up to 8 entries in the same direction
          EntryHandling = EntryHandling.AllEntries;         // Allow multiple entries without merging
          IsExitOnSessionCloseStrategy = true;              // Exit all trades before session close
          ExitOnSessionCloseSeconds = 30;                   // Time before close to exit trades
          StartBehavior = StartBehavior.WaitUntilFlat;      // Start strategy only when flat
          TimeInForce = TimeInForce.Gtc;                    // Orders remain active until filled or cancelled
          BarsRequiredToTrade = 51;                         // Number of bars to wait before the strategy starts trading
  
          // === USER PARAMETERS (default values) ===
          MyT = 15;                                          // Profit target in ticks
          MySt = 100;                                        // Stop loss in dollars
          InitalSize = 1;                                    // Initial contract size per entry
          MaxContracts = 150;                                // Maximum number of total contracts allowed
          SizeFactor = 1.0;                                  // Scale factor for position sizing (no scaling here)
          StartTime = 83000;                                 // Trading session start time (HHMMSS format)
          EndTime = 180000;                                  // Trading session end time (HHMMSS format)
          DirectionMode = TradeDirection.Both;               // Allow both long and short trades
          MaxEntries = 8;                                    // Max number of scale-in entries allowed
  		SwingOffset = 0; 								   // Default is 0 (no offset), user can change this
      }
      // Configuration state runs once after SetDefaults and before DataLoaded
      else if (State == State.Configure)
      {
          minDistanceTicks = 20 * TickSize;                  // Minimum distance between swing points, in price
          maxSwings = 10;   								   // Maximum number of swings to store and draw
  		
  		SMMA4 = SMMA(Close, 4);
  		
  		SizeLevels = new double[8];						   // Loop to set up size scaling levels for 8 possible entries
  		for (int i = 0; i < 8; i++)
  			SizeLevels[i] = Math.Min(300, Math.Round(InitalSize * Math.Pow(SizeFactor, i))); // Scaled size capped at 300
      }
      // This block runs after data is fully loaded and ready
      else if (State == State.DataLoaded)
      {
          SetProfitTarget("", CalculationMode.Ticks, MyT);   // Set profit target for each trade
          if (MySt > 0)
              SetStopLoss("", CalculationMode.Currency, MySt, true); // Set stop loss if > 0 (in $)
      }
  }

Try putting SMMA4 = SMMA(Close, 4); in the State.DataLoaded. One way to help is to use Visual Studio. If you have it running while debugging, it should break in Visual Studio so you can identify what is breaking. https://ninjatrader.com/support/helpguides/nt8/NT%20HelpGuide%20English.html?visual_studio_debugging.htm

You’re accessing TickSize too early, it’s not ready.

https://ninjatrader.com/fr/support/helpguides/nt8/NT%20HelpGuide%20English.html?ticksize.htm

" Warning: This property should NOT be accessed during State.SetDefaults from within the OnStateChange() method, all bars series would be guaranteed to have loaded in State.DataLoaded"

In General it looks like a lot of your code could be moved to State.DataLoaded.

1 Like

Thank you for the tip, I did not know I could debug in vs

Thank you, this was the issue!