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 lowsprivate 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 $) } }