Custom indicator throws nullreference exception on indicatorarea

Created at 23 Aug 2019, 02:44
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
CA

calgodemo

Joined 28.05.2019

Custom indicator throws nullreference exception on indicatorarea
23 Aug 2019, 02:44


Hi everyone,

My bot is calling a custom indicator which draws lines in the indicator area where the MACD crosses. When I execute the bot and it comes to a macd cross, the indicator blows up with a nullreference exception in the indicator code. 

bot:

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class PipnRunBluedottest : Robot
    {
        [Parameter("2nd Macd Indicator TimeFrame", DefaultValue = "Minute15")]
        public TimeFrame SecondaryMacdTimeframe { get; set; }

        public Bluedottest Bdt;
        public IndicatorArea IndicatorArea;
        protected override void OnStart()
        {
            
            Bdt = Indicators.GetIndicator<Bluedottest>(SecondaryMacdTimeframe);
            
            Chart.DrawStaticText("bearish", Bdt.secondary_Macd_bearish.ToString(), VerticalAlignment.Center, HorizontalAlignment.Left, "orange");
        }

        protected override void OnTick()
        {
            // Put your core logic here
        }
        protected override void OnBar()
        {
            int index = MarketSeries.Close.Count - 1;
            Bdt.Calculate(index);
        }
        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}

Indicator:

using System;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Bluedottest : Indicator
    {
        [Parameter("2nd Macd Indicator TimeFrame", DefaultValue = "Minute15")]
        public TimeFrame SecondaryMacdTimeframe { get; set; }

        [Output("MACD_current", LineColor = "blue", Thickness = 3)]
        public IndicatorDataSeries Blueline { get; set; }
        [Output("Signal_current", LineColor = "red", Thickness = 1)]
        public IndicatorDataSeries Redline { get; set; }
        [Output("Histogram_current", IsHistogram = true, LineColor = "lightblue", Thickness = 2)]
        public IndicatorDataSeries Histogram { get; set; }
        [Output("MACD", LineColor = "lightgreen", Thickness = 3)]
        public IndicatorDataSeries Greenline { get; set; }
        [Output("Signal", LineColor = "lavender", Thickness = 3)]
        public IndicatorDataSeries Lavenderline { get; set; }
        [Output("Histogram", IsHistogram = true, LineColor = "lightblue", Thickness = 2)]
        public IndicatorDataSeries Histogram2 { get; set; }
        #region indicators
        public MacdCrossOver Macd_current;
        public MarketSeries Series_current;

        public MacdCrossOver Macd_secondary;
        public MarketSeries Series_secondary;
        #endregion
        #region variables
        public int Lastindex;
        public int hcfra; //histogram cross from above
        public int hcfrb; //histogram cross from below

        public List<int> T_List_C;
        public List<int> T_List_S;

        public bool secondary_Macd_bearish; // MACD below Signal on higher TF
        public bool secondary_Macd_bullish; // MACD above Signal on higher TF
        #endregion
        protected override void Initialize()
        {
            // Initialize and create nested indicators
            Macd_current = Indicators.MacdCrossOver(MarketSeries.Close, 26, 12, 9);
            Series_secondary = MarketData.GetSeries(SecondaryMacdTimeframe);
            Macd_secondary = Indicators.MacdCrossOver(Series_secondary.Close, 26, 12, 9);

            hcfra = 0;
            hcfrb = 0;
            T_List_C = new List<int>();
            T_List_S = new List<int>();
            secondary_Macd_bearish = false; // MACD below Signal on higher TF
            secondary_Macd_bullish = false;
        }

        public override void Calculate(int index)
        {
            var index_special = Series_secondary.OpenTime.GetIndexByExactTime(MarketSeries.OpenTime[index]);
            // Calculate value at specified index
            // Result[index] = ...
            Blueline[index] = Macd_current.MACD[index];
            Redline[index] = Macd_current.Signal[index];
            if (index_special != -1)
            {
                Greenline[index] = Macd_secondary.MACD[index_special];
                Lavenderline[index] = Macd_secondary.Signal[index_special];
            }
            if (index > Lastindex)
            {
                OnBarClosed(Lastindex, index_special);
                Lastindex = index;
            }
        }

        public void OnBarClosed(int index, int index_special)
        {
            int HistCrossValue_C = CalcHistZero_C(index);
            if (HistCrossValue_C != 0)
            {
                IndicatorArea.DrawVerticalLine("current_hist_cross" + index.ToString(), index, "orange", 1, LineStyle.DotsRare);
                if(HistCrossValue_C == 1)
                {
                    Calclocalmin_C(hcfrb, hcfra);
                }
            }
            if (index_special != -1)
            {
                if (CalcHistZero_S(index_special) != 0)
                {
                    IndicatorArea.DrawVerticalLine("Second_hist_cross" + index.ToString(), index, "orange", 2, LineStyle.LinesDots);

                }
                if (Macd_secondary.MACD[index_special] > Macd_secondary.Signal[index_special])
                {
                    secondary_Macd_bullish = true;
                    secondary_Macd_bearish = false;
                }
                if (Macd_secondary.MACD[index_special] < Macd_secondary.Signal[index_special])
                {
                    secondary_Macd_bearish = true;
                    secondary_Macd_bullish = false;
                }

            }

        }

        private void Calclocalmin_C(int hcfrb, int hcfra)
        {
            int period = (MarketSeries.Close.Count - 1) - hcfrb;
            int minimum = hcfrb;
            for(int index = hcfrb; index > hcfra; index--)
            {
                if (Macd_current.MACD[index] < Macd_current.MACD[minimum]) minimum = index;
            }
            IndicatorArea.DrawVerticalLine("current_local_min" + minimum.ToString(), minimum, "red", 1, LineStyle.DotsRare);
            T_List_C.Add(minimum);
        }

        public int CalcHistZero_C(int index)
        {
            //current index is Marketseries...Count -1, we want to know if ..Count-2 and ..Count-3 have different signs for histogram value
            if (Macd_current.Histogram[index] < 0 && Macd_current.Histogram[index - 1] > 0)
            {
                //here we have the macd line crossing the signal line from above (falling)
                hcfra = index;
                return -1;

            }
            if (Macd_current.Histogram[index] > 0 && Macd_current.Histogram[index - 1] < 0)
            {
                //here we have the macd line crossing the signal line from below (rising)
                hcfrb = index;
                return 1;
            }

            return 0;
        }
        public int CalcHistZero_S(int index)
        {
            //current index is Marketseries...Count -1, we want to know if ..Count-2 and ..Count-3 have different signs for histogram value
            if (Macd_secondary.Histogram[index] < 0 && Macd_secondary.Histogram[index - 1] > 0)
            {
                return 1;
            }
            if (Macd_secondary.Histogram[index] > 0 && Macd_secondary.Histogram[index - 1] < 0)
            {
                return 1;
            }

            return 0;
        }
    }
}

IndicatorArea.DrawVerticalLine("current_hist_cross" + index.ToString(), index, "orange", 1, LineStyle.DotsRare); Is what blows up on me.

 

Thanks!

CaD


@calgodemo
Replies

srubtsov
23 Aug 2019, 15:35

Hi,

It happens because of an indicator in a cBot doesn't create `IndicatorArea`. Create an indicator in a cBot doesn't equal to add indicator on the chart. You have several ways to solve the problem, for example: Check `IndicatorArea` on null and doesn't draw anything. Or if possible to use `Chart` use method:

private ChartArea GetChartArea()
{
    if (IndicatorArea == null) return Chart;
    return IndicatorArea;
}

 


@srubtsov

calgodemo
23 Aug 2019, 23:26

Thanks srubtsov - I used the null check and that works. 

CaD


@calgodemo