scale bars on multi time frame indicator

Created at 02 Nov 2021, 12:49
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!
notzen's avatar

notzen

Joined 30.01.2017

scale bars on multi time frame indicator
02 Nov 2021, 12:49


Hi,

I try to code an indicator to show ichimoku on multiple time frames ,

the indicators are not in the correct scale so I wonder is there is a method to scale bars in order to make it look consistently .

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

namespace cAlgo
{



    [Cloud("Senkou Span B1", "Senkou Span A1", Opacity = 0.3)]
    [Cloud("Senkou Span B2", "Senkou Span A2", Opacity = 0.3)]
    [Cloud("Senkou Span B3", "Senkou Span A3", Opacity = 0.3)]
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]



    public class Tony_ICH_Fixed : Indicator
    {


        private Bars _baseTimeFrameBars1;
        private Bars _baseTimeFrameBars2;
        private Bars _baseTimeFrameBars3;



        [Parameter("TimeFrame-1", DefaultValue = "Daily", Group = "Time Frame")]
        public TimeFrame BaseTimeFrame1 { get; set; }

        [Parameter("TimeFrame-2", DefaultValue = "Hour4", Group = "Time Frame")]
        public TimeFrame BaseTimeFrame2 { get; set; }

        [Parameter("TimeFrame-3", DefaultValue = "Hour", Group = "Time Frame")]
        public TimeFrame BaseTimeFrame3 { get; set; }
        //--------------------------------------------------------------------------

        [Parameter("Tenkan Sen Periods1", DefaultValue = 9, Group = "Ichimoku")]
        public int TenkanSenPeriods1 { get; set; }

        [Parameter("Kijun Sen Periods1", DefaultValue = 26, Group = "Ichimoku")]
        public int KijunSenPeriods1 { get; set; }

        [Parameter("Senkou Span B Periods1", DefaultValue = 52, Group = "Ichimoku")]
        public int SenkouSpanBPeriods1 { get; set; }

        //-------------------------------------------------------------------------------

        [Parameter("Tenkan Sen Periods2", DefaultValue = 9, Group = "Ichimoku")]
        public int TenkanSenPeriods2 { get; set; }

        [Parameter("Kijun Sen Periods2", DefaultValue = 26, Group = "Ichimoku")]
        public int KijunSenPeriods2 { get; set; }

        [Parameter("Senkou Span B Periods2", DefaultValue = 52, Group = "Ichimoku")]
        public int SenkouSpanBPeriods2 { get; set; }

        //-----------------------------------------------------------------------------

        [Parameter("Tenkan Sen Periods3", DefaultValue = 9, Group = "Ichimoku")]
        public int TenkanSenPeriods3 { get; set; }

        [Parameter("Kijun Sen Periods3", DefaultValue = 26, Group = "Ichimoku")]
        public int KijunSenPeriods3 { get; set; }

        [Parameter("Senkou Span B Periods3", DefaultValue = 52, Group = "Ichimoku")]
        public int SenkouSpanBPeriods3 { get; set; }

        //--------------------------------------------------------------------------------------


        [Parameter("Displacement Chikou 25+current candle 0", DefaultValue = 25, Group = "Ichimoku")]
        public int DisplacementChikou { get; set; }

        [Parameter("DisplacementKumo 25+current candle 0", DefaultValue = 25, Group = "Ichimoku")]
        public int DisplacementKumo { get; set; }


        //-------------------------------------------------------------------------

        [Output("Tenkan Sen", LineColor = "#FF02AFF1")]
        public IndicatorDataSeries TenkanSen1 { get; set; }

        [Output("Kijun Sen", LineColor = "#FFFF6666")]
        public IndicatorDataSeries KijunSen1 { get; set; }

        [Output("Chikou Span", LineColor = "#FFFFFF00")]
        public IndicatorDataSeries ChikouSpan1 { get; set; }

        [Output("Senkou Span B1", LineColor = "#FF808080", LineStyle = LineStyle.Solid)]
        public IndicatorDataSeries SenkouSpanB1 { get; set; }

        [Output("Senkou Span A1", LineColor = "FFCCCCCC", LineStyle = LineStyle.Solid)]
        public IndicatorDataSeries SenkouSpanA1 { get; set; }

//-----------------------------------
        [Output("Tenkan Sen2", LineColor = "#FF02AFF1")]
        public IndicatorDataSeries TenkanSen2 { get; set; }

        [Output("Kijun Sen2", LineColor = "#FFFF6666")]
        public IndicatorDataSeries KijunSen2 { get; set; }

        [Output("Chikou Span2", LineColor = "#FFFFFF00")]
        public IndicatorDataSeries ChikouSpan2 { get; set; }

        [Output("Senkou Span B2", LineColor = "#FF0071C1", LineStyle = LineStyle.Solid)]
        public IndicatorDataSeries SenkouSpanB2 { get; set; }

        [Output("Senkou Span A2", LineColor = "FFFED966", LineStyle = LineStyle.Solid)]
        public IndicatorDataSeries SenkouSpanA2 { get; set; }

        //-----------------------------------

        [Output("Tenkan Sen3", LineColor = "#FF02AFF1")]
        public IndicatorDataSeries TenkanSen3 { get; set; }

        [Output("Kijun Sen3", LineColor = "#FFFF6666")]
        public IndicatorDataSeries KijunSen3 { get; set; }

        [Output("Chikou Span3", LineColor = "#FFFFFF00")]
        public IndicatorDataSeries ChikouSpan3 { get; set; }

        [Output("Senkou Span B3", LineColor = "#FFFF0000", LineStyle = LineStyle.Solid)]
        public IndicatorDataSeries SenkouSpanB3 { get; set; }

        [Output("Senkou Span A3", LineColor = "FF008000", LineStyle = LineStyle.Solid)]
        public IndicatorDataSeries SenkouSpanA3 { get; set; }
        //-----------------------------------


        //[Parameter(DefaultValue = 26)]
        // public int DisplacementChikou { get; set; }

        //[Parameter(DefaultValue = 26)]
        // public int DisplacementKumo { get; set; }




        //[Parameter("Magic Number", DefaultValue = 0)]
        public int mgc = 0;
        public double maxfast1, minfast1, maxmedium1, minmedium1, maxslow1, minslow1;
        public double maxfast2, minfast2, maxmedium2, minmedium2, maxslow2, minslow2;
        public double maxfast3, minfast3, maxmedium3, minmedium3, maxslow3, minslow3;

        private string name;



        protected override void Initialize()
        {

            _baseTimeFrameBars1 = MarketData.GetBars(BaseTimeFrame1);
            _baseTimeFrameBars2 = MarketData.GetBars(BaseTimeFrame2);
            _baseTimeFrameBars3 = MarketData.GetBars(BaseTimeFrame3);



            //DisplacementChikou = KijunSenPeriods - 1;
            // DisplacementKumo = KijunSenPeriods - 1;

            name = "" + mgc.ToString();
        }

        public override void Calculate(int index)
        {
            var index1 = index;
            var index2 = index;
            var index3 = index;
            //Ichimoku 5 lines

            var baseIndex1 = _baseTimeFrameBars1.OpenTimes.GetIndexByTime(Bars.OpenTimes[index1]);
            var baseIndex2 = _baseTimeFrameBars2.OpenTimes.GetIndexByTime(Bars.OpenTimes[index2]);
            var baseIndex3 = _baseTimeFrameBars3.OpenTimes.GetIndexByTime(Bars.OpenTimes[index3]);

            if ((index < TenkanSenPeriods1) || (index < SenkouSpanBPeriods1))
            {
                return;
            }



            maxfast1 = _baseTimeFrameBars1.HighPrices[index1];
            minfast1 = _baseTimeFrameBars1.LowPrices[index1];

            maxmedium1 = _baseTimeFrameBars1.HighPrices[index1];
            minmedium1 = _baseTimeFrameBars1.LowPrices[index1];

            maxslow1 = _baseTimeFrameBars1.HighPrices[index1];
            minslow1 = _baseTimeFrameBars1.LowPrices[index1];

            for (int i = 0; i < TenkanSenPeriods1; i++)
            {
                if (maxfast1 < Bars.HighPrices[index1 - i])
                {
                    maxfast1 = Bars.HighPrices[index1 - i];
                }
                if (minfast1 > Bars.LowPrices[index1 - i])
                {
                    minfast1 = Bars.LowPrices[index1 - i];
                }
            }
            for (int i = 0; i < KijunSenPeriods1; i++)
            {
                if (maxmedium1 < Bars.HighPrices[index1 - i])
                {
                    maxmedium1 = Bars.HighPrices[index1 - i];
                }
                if (minmedium1 > Bars.LowPrices[index1 - i])
                {
                    minmedium1 = Bars.LowPrices[index1 - i];
                }
            }
            for (int i = 0; i < SenkouSpanBPeriods1; i++)
            {
                if (maxslow1 < Bars.HighPrices[index1 - i])
                {
                    maxslow1 = Bars.HighPrices[index1 - i];
                }
                if (minslow1 > Bars.LowPrices[index1 - i])
                {
                    minslow1 = Bars.LowPrices[index1 - i];
                }
            }
            TenkanSen1[index1] = (maxfast1 + minfast1) / 2;
            KijunSen1[index1] = (maxmedium1 + minmedium1) / 2;
            ChikouSpan1[index1 - DisplacementChikou] = Bars.ClosePrices[index1];

            SenkouSpanA1[index + DisplacementKumo] = (TenkanSen1[index1] + KijunSen1[index1]) / 2;
            SenkouSpanB1[index + DisplacementKumo] = (maxslow1 + minslow1) / 2;




            if ((index2 < TenkanSenPeriods2) || (index2 < SenkouSpanBPeriods2))
            {
                return;
            }



            maxfast2 = _baseTimeFrameBars2.HighPrices[index2];
            minfast2 = _baseTimeFrameBars2.LowPrices[index2];

            maxmedium2 = _baseTimeFrameBars2.HighPrices[index2];
            minmedium2 = _baseTimeFrameBars2.LowPrices[index2];

            maxslow2 = _baseTimeFrameBars2.HighPrices[index2];
            minslow2 = _baseTimeFrameBars2.LowPrices[index2];

            for (int i = 0; i < TenkanSenPeriods2; i++)
            {
                if (maxfast2 < Bars.HighPrices[index2 - i])
                {
                    maxfast2 = Bars.HighPrices[index2 - i];
                }
                if (minfast2 > Bars.LowPrices[index2 - i])
                {
                    minfast2 = Bars.LowPrices[index2 - i];
                }
            }
            for (int i = 0; i < KijunSenPeriods2; i++)
            {
                if (maxmedium2 < Bars.HighPrices[index2 - i])
                {
                    maxmedium2 = Bars.HighPrices[index2 - i];
                }
                if (minmedium2 > Bars.LowPrices[index2 - i])
                {
                    minmedium2 = Bars.LowPrices[index2 - i];
                }
            }
            for (int i = 0; i < SenkouSpanBPeriods2; i++)
            {
                if (maxslow2 < Bars.HighPrices[index2 - i])
                {
                    maxslow2 = Bars.HighPrices[index2 - i];
                }
                if (minslow2 > Bars.LowPrices[index2 - i])
                {
                    minslow2 = Bars.LowPrices[index2 - i];
                }
            }
            TenkanSen2[index2] = (maxfast2 + minfast2) / 2;
            KijunSen2[index2] = (maxmedium2 + minmedium2) / 2;
            ChikouSpan2[index2 - DisplacementChikou] = Bars.ClosePrices[index2];

            SenkouSpanA2[index2 + DisplacementKumo] = (TenkanSen2[index2] + KijunSen2[index2]) / 2;
            SenkouSpanB2[index2 + DisplacementKumo] = (maxslow2 + minslow2) / 2;






            if ((index3 < TenkanSenPeriods3) || (index3 < SenkouSpanBPeriods3))
            {
                return;
            }




            maxfast3 = _baseTimeFrameBars3.HighPrices[index3];
            minfast3 = _baseTimeFrameBars3.LowPrices[index3];

            maxmedium3 = _baseTimeFrameBars3.HighPrices[index3];
            minmedium3 = _baseTimeFrameBars3.LowPrices[index3];

            maxslow3 = _baseTimeFrameBars3.HighPrices[index3];
            minslow3 = _baseTimeFrameBars3.LowPrices[index3];

            for (int i = 0; i < TenkanSenPeriods3; i++)
            {
                if (maxfast3 < Bars.HighPrices[index3 - i])
                {
                    maxfast3 = Bars.HighPrices[index3 - i];
                }
                if (minfast3 > Bars.LowPrices[index3 - i])
                {
                    minfast3 = Bars.LowPrices[index3 - i];
                }
            }
            for (int i = 0; i < KijunSenPeriods3; i++)
            {
                if (maxmedium3 < Bars.HighPrices[index3 - i])
                {
                    maxmedium3 = Bars.HighPrices[index3 - i];
                }
                if (minmedium3 > Bars.LowPrices[index3 - i])
                {
                    minmedium3 = Bars.LowPrices[index3 - i];
                }
            }
            for (int i = 0; i < SenkouSpanBPeriods3; i++)
            {
                if (maxslow3 < Bars.HighPrices[index3 - i])
                {
                    maxslow3 = Bars.HighPrices[index3 - i];
                }
                if (minslow3 > Bars.LowPrices[index3 - i])
                {
                    minslow3 = Bars.LowPrices[index3 - i];
                }
            }
            TenkanSen3[index3] = (maxfast3 + minfast3) / 2;
            KijunSen3[index3] = (maxmedium3 + minmedium3) / 2;
            ChikouSpan3[index3 - DisplacementChikou] = Bars.ClosePrices[index3];

            SenkouSpanA3[index3 + DisplacementKumo] = (TenkanSen3[index3] + KijunSen3[index3]) / 2;
            SenkouSpanB3[index3 + DisplacementKumo] = (maxslow3 + minslow3) / 2;

        }

    }
}

 

 


@notzen
Replies

amusleh
03 Nov 2021, 08:26

Hi,

I tested your code and something is wrong on it, because some of the outputs doesn't continue to the last bar.

Instead of using multiple time frames on a single indicator which makes debugging much harder for you I recommend you to use only one single time frame.

Develop an Ichimoku indicator that get just one time frame and then you can use three instance of that indicator for multiple time frames.

Regarding scaling, Ichimoku lines mostly follow the price and you should not have any scaling issue, the scaling issue occurs if your indicator lines are very far away from price series.


@amusleh

notzen
03 Nov 2021, 10:22

RE:

Hi ,

thanks for your feedback

the base code is this ,

unfortunately even using more instances the result is the same , except the scaling, I am not sure if there is anything else wrong . 

the indicator itself work ok and show ichimoku correctly and fix the wrong displacement in the built-in indicator (it is 26 candle from the current so candle 0 not candle 1...about that I wonder is the other lines use calculation from candle 1 or 0 as it should be start from current always in ichimoku because Japaneses count from 1 not 0...)

 

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

namespace cAlgo
{



    [Cloud("Senkou Span B", "Senkou Span A", Opacity = 0.2)]

    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]



    public class Tony_ICH_Fixed : Indicator
    {


        private Bars _baseTimeFrameBars;



        [Parameter("TimeFrame-1", DefaultValue = "Daily", Group = "Time Frame")]
        public TimeFrame BaseTimeFrame { get; set; }

        [Parameter("Tenkan Sen Periods", DefaultValue = 9, Group = "Ichimoku")]
        public int TenkanSenPeriods { get; set; }

        [Parameter("Kijun Sen Periods", DefaultValue = 26, Group = "Ichimoku")]
        public int KijunSenPeriods { get; set; }

        [Parameter("Senkou Span B Periods", DefaultValue = 52, Group = "Ichimoku")]
        public int SenkouSpanBPeriods { get; set; }

        [Parameter("Displacement Chikou 25+current candle 0", DefaultValue = 25, Group = "Ichimoku")]
        public int DisplacementChikou { get; set; }

        [Parameter("DisplacementKumo 25+current candle 0", DefaultValue = 25, Group = "Ichimoku")]
        public int DisplacementKumo { get; set; }


        //------------------------

        [Output("Tenkan Sen", LineColor = "#FF02AFF1")]
        public IndicatorDataSeries TenkanSen { get; set; }

        [Output("Kijun Sen", LineColor = "#FFFF6666")]
        public IndicatorDataSeries KijunSen { get; set; }

        [Output("Chikou Span", LineColor = "#FFFFFF00")]
        public IndicatorDataSeries ChikouSpan { get; set; }

        [Output("Senkou Span B", LineColor = "#FFFF0000", LineStyle = LineStyle.Solid)]
        public IndicatorDataSeries SenkouSpanB { get; set; }

        [Output("Senkou Span A", LineColor = "FF008000", LineStyle = LineStyle.Solid)]
        public IndicatorDataSeries SenkouSpanA { get; set; }




        //[Parameter("Magic Number", DefaultValue = 0)]
        public int mgc = 0;
        public double maxfast, minfast, maxmedium, minmedium, maxslow, minslow;






        protected override void Initialize()
        {

            _baseTimeFrameBars = MarketData.GetBars(BaseTimeFrame);



        }

        public override void Calculate(int index)
        {


            //Ichimoku 5 lines

            var baseIndex = _baseTimeFrameBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);

            if ((baseIndex < TenkanSenPeriods) || (baseIndex < SenkouSpanBPeriods))
            {
                return;
            }

            maxfast = _baseTimeFrameBars.HighPrices[baseIndex];
            minfast = _baseTimeFrameBars.LowPrices[baseIndex];

            maxmedium = _baseTimeFrameBars.HighPrices[baseIndex];
            minmedium = _baseTimeFrameBars.LowPrices[baseIndex];

            maxslow = _baseTimeFrameBars.HighPrices[baseIndex];
            minslow = _baseTimeFrameBars.LowPrices[baseIndex];

            for (int i = 0; i < TenkanSenPeriods; i++)
            {
                if (maxfast < Bars.HighPrices[baseIndex - i])
                {
                    maxfast = Bars.HighPrices[baseIndex - i];
                }
                if (minfast > Bars.LowPrices[baseIndex - i])
                {
                    minfast = Bars.LowPrices[baseIndex - i];
                }
            }
            for (int i = 0; i < KijunSenPeriods; i++)
            {
                if (maxmedium < Bars.HighPrices[baseIndex - i])
                {
                    maxmedium = Bars.HighPrices[baseIndex - i];
                }
                if (minmedium > Bars.LowPrices[baseIndex - i])
                {
                    minmedium = Bars.LowPrices[baseIndex - i];
                }
            }
            for (int i = 0; i < SenkouSpanBPeriods; i++)
            {
                if (maxslow < Bars.HighPrices[baseIndex - i])
                {
                    maxslow = Bars.HighPrices[baseIndex - i];
                }
                if (minslow > Bars.LowPrices[baseIndex - i])
                {
                    minslow = Bars.LowPrices[baseIndex - i];
                }
            }
            TenkanSen[baseIndex] = (maxfast + minfast) / 2;
            KijunSen[baseIndex] = (maxmedium + minmedium) / 2;
            ChikouSpan[baseIndex - DisplacementChikou] = Bars.ClosePrices[baseIndex];

            SenkouSpanA[baseIndex + DisplacementKumo] = (TenkanSen[baseIndex] + KijunSen[baseIndex]) / 2;
            SenkouSpanB[baseIndex + DisplacementKumo] = (maxslow + minslow) / 2;





        }

    }
}

 

amusleh said:

Hi,

I tested your code and something is wrong on it, because some of the outputs doesn't continue to the last bar.

Instead of using multiple time frames on a single indicator which makes debugging much harder for you I recommend you to use only one single time frame.

Develop an Ichimoku indicator that get just one time frame and then you can use three instance of that indicator for multiple time frames.

Regarding scaling, Ichimoku lines mostly follow the price and you should not have any scaling issue, the scaling issue occurs if your indicator lines are very far away from price series.

 


@notzen

amusleh
04 Nov 2021, 08:03 ( Updated at: 04 Nov 2021, 08:04 )

Hi,

Your code has several issues, please fix the issues first then we will see if there is any scaling issue or not.

You are using the baseIndex for Bars, the baseIndex is for other time frame, you can't use it for Bars which is from current chart time frame.

For setting indicator outputs you are again using baseIndex, which is not correct, you have to use index for setting outputs not baseIndex.

Use the baseIndex only for getting the other time frame data, not for outputs of current chart time frame Bars.


@amusleh