I had hoped that this one would be simple, but having simplified it and stripped out all executions, it has seemingly proved not to be.
The idea is to backtest a strategy that relies on Daily bars, but use one-minute bars for execution for more accurate results. One-minute bars would be BarsArray[0], and any other data series would be BarsArray[1] and so forth. NT8 seems to require some extra validation to make sure that enough bars have elapsed to populate all the variables, such as previous closes and indicator values.
If I were just using BarsArray[0], I could add the "if(CurrentBar < 1) return;" snippet and be done, but as soon as I start using any other data series, that seems to stop working. My workaround for this was to try to set that required value dynamically as is illustrated in the code below, but this has some unexpected results.
To the point of this post: for Daily bars, there is a 6 month wait time before the strategy can even execute, and then the 2:00:00PM bar does not qualify for execution every single day. What that means is that BarsInProgress is NEVER 1 for Daily bars.
Obviously my dynamic approach isn't working, but the simple approach isn't working either. What should my code look like to permanently resolve that pesky index out-of-range error?
Thank you.
#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion
namespace NinjaTrader.NinjaScript.Strategies
{
public class A_Test : Strategy
{
#region Variables
private int chartPeriod1 = 1;
private int chartPeriod2 = 60;
//Prevent crash in OnBarUpdate
private string longestCPType = "Day";
private int minutesInDay = 1440; //If daily bars used, this is a multiplier for the number of minutes in a day to use.
private int chartLookback = 2; //1 for no previous bars considered, 2 for looking at previous bar, etc.
private int valBar = 0;
#endregion
protected override void OnStateChange()
{
if (State == State.Configure)
{
AddDataSeries(BarsPeriodType.Day, chartPeriod1); //BarsArray[1]
AddDataSeries(BarsPeriodType.Minute, chartPeriod2); //BarsArray[2]
Calculate = Calculate.OnBarClose;
TraceOrders = false;
RealtimeErrorHandling = RealtimeErrorHandling.IgnoreAllErrors;
}
}
protected override void OnBarUpdate()
{
//Set valBar dynamically to prevent OBU crash
if (longestCPType == "Minute")
{
valBar = chartPeriod2 * chartLookback;
}
else
{
if (longestCPType == "Day")
{
valBar = chartLookback * minutesInDay;
}
else
{
valBar = 1;
}
}
//Print to check datetime of error. Extremely long wait time if trying to use Daily data (about 6 months). AND THEN this triggers every day at 2:00:00PM - market close - meaning BIP is never 1.
if (CurrentBar < valBar)
{
Print(Time[0] + " cb<vb");
}
if (CurrentBar < valBar) return;
if (BarsInProgress == 1)
{
Print(Time[0] + " BIP=1");
}
if (BarsInProgress == 2)
{
Print(Time[0] + " BIP=2");
}
//If valBar set to 1, this crashes. If valBar set dynamically (longestCPType code above) error message:
//Strategy 'A_Test': Error on calling 'OnBarUpdate' method on bar 1: You are accessing an index with a value that is invalid since it is out-of-range. I.E. accessing a series [barsAgo] with a value of 5 when there are only 4 bars on the chart.
double testClose = Closes[1][0];
double testPastClose = Closes[1][1];
}
}
}
Comment