Assistance with custom indicator when referencing - Error MSB4006 There is a circular dependency in the target dependency graph

Created at 04 Jan 2025, 13:36
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!
MA

masedir

Joined 27.12.2024

Assistance with custom indicator when referencing - Error MSB4006 There is a circular dependency in the target dependency graph
04 Jan 2025, 13:36


Good day

I need assistance with a custom indicator error MSB4006; the indicator displays data correctly but when referencing it from a cBot, it generates an error when building the bot. The indicator is an NRTR Channel indicator. 

 

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NRTRChannel : Indicator
    {
        [Parameter("ATR Period", DefaultValue = 40)]
        public int ATRPeriod { get; set; }

        [Parameter("ATR Multiplier", DefaultValue = 2.0)]
        public double ATRMultiplier { get; set; }

        [Parameter("Show Price Labels", DefaultValue = true)]
        public bool ShowLabels { get; set; }

        [Output("longResistance", LineColor = "DeepSkyBlue", PlotType = PlotType.DiscontinuousLine, LineStyle = LineStyle.Dots, Thickness = 2)]
        public IndicatorDataSeries CeilingBuffer { get; set; }

        [Output("longSupport", LineColor = "DeepSkyBlue", PlotType = PlotType.DiscontinuousLine, LineStyle = LineStyle.Dots, Thickness = 2)]
        public IndicatorDataSeries BuyBuffer { get; set; }

        [Output("shortSupport", LineColor = "LightSalmon", PlotType = PlotType.DiscontinuousLine, LineStyle = LineStyle.Dots, Thickness = 2)]
        public IndicatorDataSeries SellBuffer { get; set; }

        [Output("shortResistance", LineColor = "LightSalmon", PlotType = PlotType.DiscontinuousLine, LineStyle = LineStyle.Dots, Thickness = 2)]
        public IndicatorDataSeries FloorBuffer { get; set; }

        private IndicatorDataSeries trendBuffer;
        private AverageTrueRange atr;
        private const int UP_TREND = 1;
        private const int DOWN_TREND = -1;

        protected override void Initialize()
        {
            trendBuffer = CreateDataSeries();
            atr = Indicators.AverageTrueRange(ATRPeriod, MovingAverageType.Simple);
        }

        public override void Calculate(int index)
        {
            if (index <= ATRPeriod)
                return;

            if (index == ATRPeriod + 1)
            {
                if (Bars.ClosePrices[index] > Bars.LowPrices[index])
                {
                    trendBuffer[index] = UP_TREND;
                    CeilingBuffer[index] = Bars.ClosePrices[index];
                    BuyBuffer[index] = Bars.ClosePrices[index] - ATRMultiplier * atr.Result[index];
                }
                else
                {
                    trendBuffer[index] = DOWN_TREND;
                    FloorBuffer[index] = Bars.ClosePrices[index];
                    SellBuffer[index] = Bars.ClosePrices[index] + ATRMultiplier * atr.Result[index];
                }
                return;
            }

            if (trendBuffer[index - 1] > 0)
            {
                if (Bars.LowPrices[index] > CeilingBuffer[index - 1])
                {
                    CeilingBuffer[index] = Bars.ClosePrices[index];
                    FloorBuffer[index] = double.NaN;
                    BuyBuffer[index] = Bars.ClosePrices[index] - ATRMultiplier * atr.Result[index];
                    SellBuffer[index] = double.NaN;
                    trendBuffer[index] = UP_TREND;
                }
                else if (Bars.ClosePrices[index] < BuyBuffer[index - 1])
                {
                    trendBuffer[index] = DOWN_TREND;
                    FloorBuffer[index] = Bars.ClosePrices[index];
                    SellBuffer[index] = Bars.ClosePrices[index] + ATRMultiplier * atr.Result[index];
                    CeilingBuffer[index] = double.NaN;
                    BuyBuffer[index] = double.NaN;
                }
                else
                {
                    CopyPreviousValues(index);
                }
            }
            else
            {
                if (Bars.HighPrices[index] < FloorBuffer[index - 1])
                {
                    FloorBuffer[index] = Bars.ClosePrices[index];
                    CeilingBuffer[index] = double.NaN;
                    SellBuffer[index] = Bars.ClosePrices[index] + ATRMultiplier * atr.Result[index];
                    BuyBuffer[index] = double.NaN;
                    trendBuffer[index] = DOWN_TREND;
                }
                else if (Bars.ClosePrices[index] > SellBuffer[index - 1])
                {
                    trendBuffer[index] = UP_TREND;
                    CeilingBuffer[index] = Bars.ClosePrices[index];
                    BuyBuffer[index] = Bars.ClosePrices[index] - ATRMultiplier * atr.Result[index];
                    FloorBuffer[index] = double.NaN;
                    SellBuffer[index] = double.NaN;
                }
                else
                {
                    CopyPreviousValues(index);
                }
            }

            if (ShowLabels && index == Bars.ClosePrices.Count - 1)
            {
                ShowPriceLevels(index);
            }
        }

        private void CopyPreviousValues(int index)
        {
            SellBuffer[index] = SellBuffer[index - 1];
            BuyBuffer[index] = BuyBuffer[index - 1];
            CeilingBuffer[index] = CeilingBuffer[index - 1];
            FloorBuffer[index] = FloorBuffer[index - 1];
            trendBuffer[index] = trendBuffer[index - 1];
        }

        private void ShowPriceLevels(int index)
        {
            var existingLabels = Chart.Objects.Where(obj => obj.Name.StartsWith("NRTR_"));
            foreach (var label in existingLabels)
            {
                Chart.RemoveObject(label.Name);
            }

            cAlgo.API.Color color;
            double upperLevel, lowerLevel;

            if (trendBuffer[index] == UP_TREND)
            {
                color = cAlgo.API.Color.DeepSkyBlue;
                upperLevel = CeilingBuffer[index];
                lowerLevel = BuyBuffer[index];
            }
            else
            {
                color = cAlgo.API.Color.LightSalmon;
                upperLevel = SellBuffer[index];
                lowerLevel = FloorBuffer[index];
            }

            if (!double.IsNaN(upperLevel))
            {
                var upperText = Chart.DrawText(
                    "NRTR_Res_" + index,
                    upperLevel.ToString("F5"),
                    index,
                    upperLevel,
                    color
                );
                upperText.VerticalAlignment = VerticalAlignment.Center;
                upperText.HorizontalAlignment = HorizontalAlignment.Right;
            }

            if (!double.IsNaN(lowerLevel))
            {
                var lowerText = Chart.DrawText(
                    "NRTR_Sup_" + index,
                    lowerLevel.ToString("F5"),
                    index,
                    lowerLevel,
                    color
                );
                lowerText.VerticalAlignment = VerticalAlignment.Center;
                lowerText.HorizontalAlignment = HorizontalAlignment.Right;
            }
        }
    }
}

@masedir