Converting Indicator to .NET 6 - ArgumentOutOfRangeException
Converting Indicator to .NET 6 - ArgumentOutOfRangeException
24 Jul 2022, 10:32
Hi
As stated in the subject, I'm getting the following error:
24/07/2022 08:15:11.807 | Indicator instance [Moving Average Slope, GBPUSD, t250] crashed with error "Crashed in Calculate with ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: y2. Actual value was: NaN."
I'm not getting any errors or warnings presented in VS2022 and it builds successfully from within VS and cTrader. I get the above error when trying to load the indicator on the chart. Works fine in cTrader 4.1. I don't have a parameter named 'y2' so I don't know what it's referring to.
I created a new Indicator in cTrader 4.3.9 and copied my cAlgo namespace from the previous indicator.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class MovingAverageSlope : Indicator
{
// Define parameters
[Parameter("Type:", DefaultValue = MovingAverageType.Exponential)]
public MovingAverageType maType { get; set; }
[Parameter("Periods", DefaultValue = 20, MinValue = 2, Step = 1)]
public int maPeriod { get; set; }
[Parameter("Show Slope:", DefaultValue = true)]
public bool slopeShow { get; set; }
[Parameter("Slope Length:", DefaultValue = 10, MinValue = 5, Step = 1)]
public int slopePeriod { get; set; }
[Parameter("Timeframe:", DefaultValue = "t250")]
public TimeFrame maTimeFrame { get; set; }
[Parameter("Smoothing:", DefaultValue = true)]
public bool maSmoothing { get; set; }
[Parameter("Show Info:", DefaultValue = true)]
public bool infoShow { get; set; }
[Output("Close", LineColor = "#FFFF00C5")]
public IndicatorDataSeries maCloseLine { get; set; }
[Output("Slope", LineColor = "#FFFFFF01")]
public IndicatorDataSeries slopeLine { get; set; }
// Instantiate indicator objects
private Bars priceBars;
private int maTimeIndex;
private MovingAverage maClose;
// Instatiate information panels
private StackPanel maPanel;
private StackPanel trendPanel;
private TextBlock[] maTextBlock = new TextBlock[3];
private TextBlock[] trendTextBlock = new TextBlock[2];
// Define the start and end of the period of time that trades are allowed to be entered
TimeSpan tradingStart = new TimeSpan(7, 0, 0);
TimeSpan tradingEnd = new TimeSpan(11, 0, 0);
protected override void Initialize()
{
// Get candle data and create moving average
priceBars = MarketData.GetBars(maTimeFrame);
maClose = Indicators.MovingAverage(priceBars.ClosePrices, maPeriod, maType);
// Create primary slope information panel
maPanel = new StackPanel
{
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Top,
BackgroundColor = Color.Black,
Margin = 5
};
// Add slope text blocks to primary information panel
for (int i = 0; i < maTextBlock.Count(); i++)
{
maTextBlock[i] = new TextBlock
{
Text = "",
HorizontalAlignment = HorizontalAlignment.Right,
ForegroundColor = Color.White
};
maPanel.AddChild(maTextBlock[i]);
}
Chart.AddControl(maPanel);
// Create secondary information panel
trendPanel = new StackPanel
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Bottom,
BackgroundColor = Color.Black,
Margin = 5
};
//Add text blocks to secondary information panel
for (int i = 0; i < trendTextBlock.Count(); i++)
{
trendTextBlock[i] = new TextBlock
{
Text = "",
ForegroundColor = Color.White,
HorizontalAlignment = HorizontalAlignment.Center
};
trendPanel.AddChild(trendTextBlock[i]);
}
Chart.AddControl(trendPanel);
}
public override void Calculate(int index)
{
// Smooth moving average
maTimeIndex = GetIndexByDate(priceBars, Bars.OpenTimes[index]);
if (maTimeIndex != -1)
{
maCloseLine[index] = maClose.Result[maTimeIndex];
}
if (slopeShow == true)
{
DisplayMASlope(maClose.Result.Last(0), maClose.Result.Last(slopePeriod), slopePeriod);
}
}
private int GetIndexByDate(Bars barData, DateTime time)
{
//
for (int i = barData.ClosePrices.Count - 1; i > 0; i--)
{
if (barData.OpenTimes[i] == time)
return i;
}
return -1;
}
public void DisplayMASlope(double currentMAClose, double pastMAClose, int period)
{
// Calculate slope
double slope = Math.Round(((currentMAClose - pastMAClose) * 10000) / period, 5);
if (infoShow == true)
{
maTextBlock[0].Text = String.Format("Slope {0}", slope);
trendTextBlock[1].Text = "It's better to miss one than to lose one!";
trendTextBlock[1].ForegroundColor = Color.Yellow;
if (slope >= 0.3)
{
// UPTREND information panel text
string directionText = "Long Positions Only!";
Color directionTextColor = Color.LimeGreen;
string strategyText = "Buy at moving average or Stochastic 'oversold'";
Color strategyTextColor = Color.Yellow;
maTextBlock[1].Text = directionText;
maTextBlock[1].ForegroundColor = directionTextColor;
trendTextBlock[0].Text = directionText;
trendTextBlock[0].ForegroundColor = directionTextColor;
maTextBlock[2].Text = strategyText;
maTextBlock[2].ForegroundColor = strategyTextColor;
}
else if (slope <= -0.3)
{
// DOWNTREND information panel text
string directionText = "Short Positions Only!";
Color directionTextColor = Color.Red;
string strategyText = "Sell at moving average or Stochastic 'overbought'";
Color strategyTextColor = Color.Yellow;
maTextBlock[1].Text = directionText;
maTextBlock[1].ForegroundColor = directionTextColor;
trendTextBlock[0].Text = directionText;
trendTextBlock[0].ForegroundColor = directionTextColor;
maTextBlock[2].Text = strategyText;
maTextBlock[2].ForegroundColor = strategyTextColor;
}
else
{
// SIDEWAYS information panel text
string directionText = "Sideways Range";
Color directionTextColor = Color.White;
string strategyText = "Trade Stochastic 'overbought' and 'oversold' levels";
Color strategyTextColor = Color.Yellow;
maTextBlock[1].Text = directionText;
maTextBlock[1].ForegroundColor = directionTextColor;
trendTextBlock[0].Text = directionText;
trendTextBlock[0].ForegroundColor = directionTextColor;
maTextBlock[2].Text = strategyText;
maTextBlock[2].ForegroundColor = strategyTextColor;
}
}
// Draw slope onto moving average
Chart.DrawTrendLine("Slope", priceBars.OpenTimes.Last(0), currentMAClose, priceBars.OpenTimes.Last(period), pastMAClose, Color.Yellow, 1, LineStyle.Lines);
}
}
}
EDIT:
Just did a bit more of a test. I'm getting the same result if I use my original .NET 4 project but change the Target Framework to .NET 6.
I have 2 charts open: the t250 and t50. I can add the indicator to the t50 chart without a problem. When adding it to the t250 chart I get the error. If I close my t250 chart and duplicate my t50 chart with the indicator already loaded on the chart, then change the timeframe to t250, it crashes my indicator again. However, I can add it to the t250 chart if I change my indicator to get the t500 bars.
It seems to crash if I'm using the indicator is using the same timeframe as the chart.