Multi-timeframe robots/indicators

I am trying to use this feature to create Heikin-Ashi indicator with custom timeframe as below. The value of haClose in the HeikinAshiClose series looks correct but I am always getting NaN for haOpen. I am not sure if something like below is supported?

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class TFHeikinAshiIndicator : Indicator
    {
        [Parameter("Heikin-Ashi Timeframe")]
        public TimeFrame HeikinAshiTimeframe { get; set; }

        [Output("Open", Color = Colors.DarkSlateBlue)]
        public IndicatorDataSeries HeikinAshiOpen { get; set; }

        [Output("Close", Color = Colors.SlateBlue)]
        public IndicatorDataSeries HeikinAshiClose { get; set; }

        private MarketSeries heikinAshiSeries;

        protected override void Initialize()
        {
            heikinAshiSeries = MarketData.GetSeries(HeikinAshiTimeframe);
        }

        public override void Calculate(int index)
        {
            int heikinAshiSeriesIndex = GetIndexByDate(heikinAshiSeries, MarketSeries.OpenTime[index]);

            double open = heikinAshiSeries.Open[heikinAshiSeriesIndex];
            double high = heikinAshiSeries.High[heikinAshiSeriesIndex];
            double low = heikinAshiSeries.Low[heikinAshiSeriesIndex];
            double close = heikinAshiSeries.Close[heikinAshiSeriesIndex];

            double haClose = (open + high + low + close) / 4;
            double haOpen;
            if (heikinAshiSeriesIndex != -1)
                haOpen = (HeikinAshiOpen[heikinAshiSeriesIndex - 1] + HeikinAshiClose[heikinAshiSeriesIndex - 1]) / 2;
            else
                haOpen = (open + close) / 2;

            ChartObjects.DrawText("ha", string.Format("heikinAshiSeriesIndex={0} haOpen={1}, haClose={2}", heikinAshiSeriesIndex, haOpen, haClose), StaticPosition.TopLeft, Colors.Red);

            HeikinAshiOpen[heikinAshiSeriesIndex] = haOpen;
            HeikinAshiClose[heikinAshiSeriesIndex] = haClose;
        }

        private int GetIndexByDate(MarketSeries series, DateTime time)
        {
            for (int i = series.Close.Count - 1; i > 0; i--)
            {
                if (time == series.OpenTime[i])
                    return i;
            }
            return -1;
        }
    }
}
TRADERS FIRSTâ„¢ Vote for your favorite features: https://ctrader.com/forum/suggestions
RE: Indicator example: Multi-timeframe moving average

Without plotting the actual moving average lines, how would I just output the numerical value of how far the 100 DAY moving average is from the current price on a one HOUR price chart, plotting just the numerical value in the top left corner of the a one hour price chart, i.e.,

(100 DAY moving average value) - (Current price on a one HOUR chart). With the numerical value output in the top left corner of the one hour chart. When I'm looking at shorter time frame charts like an hour or 15 minute charts, I want to know how far the close is from DAILY moving averages. The code below really only works if you want to know the MAs of shorter timeframes than the chart that you are viewing. I want to know the opposite, i.e, show longer timeframe MAs on shorter timeframe charts.

In this example, we output moving averages with the same period for different timeframes on a single chart:

 

Source code:

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

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC)]
    public class MultiTF_MA : Indicator
    {
        [Parameter(DefaultValue = 50)]
        public int Period { get; set; }

        [Output("MA", Color = Colors.Yellow)]
        public IndicatorDataSeries MA { get; set; }

        [Output("MA5", Color = Colors.Orange)]
        public IndicatorDataSeries MA5 { get; set; }

        [Output("MA10", Color = Colors.Red)]
        public IndicatorDataSeries MA10 { get; set; }

        private MarketSeries series5;
        private MarketSeries series10;

        private MovingAverage ma;
        private MovingAverage ma5;
        private MovingAverage ma10;

        protected override void Initialize()
        {
            series5 = MarketData.GetSeries(TimeFrame.Minute5);
            series10 = MarketData.GetSeries(TimeFrame.Minute10);

            ma = Indicators.MovingAverage(MarketSeries.Close, Period, MovingAverageType.Triangular);
            ma5 = Indicators.MovingAverage(series5.Close, Period, MovingAverageType.Triangular);
            ma10 = Indicators.MovingAverage(series10.Close, Period, MovingAverageType.Triangular);
        }

        public override void Calculate(int index)
        {
            MA[index] = ma.Result[index];

            var index5 = GetIndexByDate(series5, MarketSeries.OpenTime[index]);
            if (index5 != -1)
                MA5[index] = ma5.Result[index5];

            var index10 = GetIndexByDate(series10, MarketSeries.OpenTime[index]);
            if (index10 != -1)
                MA10[index] = ma10.Result[index10];
        }


        private int GetIndexByDate(MarketSeries series, DateTime time)
        {
            for (int i = series.Close.Count - 1; i > 0; i--)
            {
                if (time == series.OpenTime[i])
                    return i;
            }
            return -1;
        }
    }
}
RE:

able to implement this code?
Really needed it

zofoyobis said:

I am trying to use this feature to create Heikin-Ashi indicator with custom timeframe as below. The value of haClose in the HeikinAshiClose series looks correct but I am always getting NaN for haOpen. I am not sure if something like below is supported?

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class TFHeikinAshiIndicator : Indicator
    {
        [Parameter("Heikin-Ashi Timeframe")]
        public TimeFrame HeikinAshiTimeframe { get; set; }

        [Output("Open", Color = Colors.DarkSlateBlue)]
        public IndicatorDataSeries HeikinAshiOpen { get; set; }

        [Output("Close", Color = Colors.SlateBlue)]
        public IndicatorDataSeries HeikinAshiClose { get; set; }

        private MarketSeries heikinAshiSeries;

        protected override void Initialize()
        {
            heikinAshiSeries = MarketData.GetSeries(HeikinAshiTimeframe);
        }

        public override void Calculate(int index)
        {
            int heikinAshiSeriesIndex = GetIndexByDate(heikinAshiSeries, MarketSeries.OpenTime[index]);

            double open = heikinAshiSeries.Open[heikinAshiSeriesIndex];
            double high = heikinAshiSeries.High[heikinAshiSeriesIndex];
            double low = heikinAshiSeries.Low[heikinAshiSeriesIndex];
            double close = heikinAshiSeries.Close[heikinAshiSeriesIndex];

            double haClose = (open + high + low + close) / 4;
            double haOpen;
            if (heikinAshiSeriesIndex != -1)
                haOpen = (HeikinAshiOpen[heikinAshiSeriesIndex - 1] + HeikinAshiClose[heikinAshiSeriesIndex - 1]) / 2;
            else
                haOpen = (open + close) / 2;

            ChartObjects.DrawText("ha", string.Format("heikinAshiSeriesIndex={0} haOpen={1}, haClose={2}", heikinAshiSeriesIndex, haOpen, haClose), StaticPosition.TopLeft, Colors.Red);

            HeikinAshiOpen[heikinAshiSeriesIndex] = haOpen;
            HeikinAshiClose[heikinAshiSeriesIndex] = haClose;
        }

        private int GetIndexByDate(MarketSeries series, DateTime time)
        {
            for (int i = series.Close.Count - 1; i > 0; i--)
            {
                if (time == series.OpenTime[i])
                    return i;
            }
            return -1;
        }
    }
}
RE: Indicator example: Multi-timeframe moving average

cAlgo_Development said:

In this example, we output moving averages with the same period for different timeframes on a single chart:

 

Source code:

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

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC)]
    public class MultiTF_MA : Indicator
    {
        [Parameter(DefaultValue = 50)]
        public int Period { get; set; }

        [Output("MA", Color = Colors.Yellow)]
        public IndicatorDataSeries MA { get; set; }

        [Output("MA5", Color = Colors.Orange)]
        public IndicatorDataSeries MA5 { get; set; }

        [Output("MA10", Color = Colors.Red)]
        public IndicatorDataSeries MA10 { get; set; }

        private MarketSeries series5;
        private MarketSeries series10;

        private MovingAverage ma;
        private MovingAverage ma5;
        private MovingAverage ma10;

        protected override void Initialize()
        {
            series5 = MarketData.GetSeries(TimeFrame.Minute5);
            series10 = MarketData.GetSeries(TimeFrame.Minute10);

            ma = Indicators.MovingAverage(MarketSeries.Close, Period, MovingAverageType.Triangular);
            ma5 = Indicators.MovingAverage(series5.Close, Period, MovingAverageType.Triangular);
            ma10 = Indicators.MovingAverage(series10.Close, Period, MovingAverageType.Triangular);
        }

        public override void Calculate(int index)
        {
            MA[index] = ma.Result[index];

            var index5 = GetIndexByDate(series5, MarketSeries.OpenTime[index]);
            if (index5 != -1)
                MA5[index] = ma5.Result[index5];

            var index10 = GetIndexByDate(series10, MarketSeries.OpenTime[index]);
            if (index10 != -1)
                MA10[index] = ma10.Result[index10];
        }


        private int GetIndexByDate(MarketSeries series, DateTime time)
        {
            for (int i = series.Close.Count - 1; i > 0; i--)
            {
                if (time == series.OpenTime[i])
                    return i;
            }
            return -1;
        }
    }
}

A modification to the above example that solves missing values when attaching indicator to chart of lower time frame than the M5: the index function returns a match,or the closest previous value in higher time frame series.

//modified GetIndexByDate() from ctdn example

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

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC)]
    public class MultiTF_MA : Indicator
    {
        [Parameter(DefaultValue = 50)]
        public int Period { get; set; }
        
        [Output("MA", Color = Colors.Yellow)]
        public IndicatorDataSeries MA { get; set; }

        [Output("MA5", Color = Colors.Orange)]
        public IndicatorDataSeries MA5 { get; set; }

        [Output("MA10", Color = Colors.Red)]
        public IndicatorDataSeries MA10 { get; set; }

        private MarketSeries series5;
        private MarketSeries series10;

        private MovingAverage ma;
        private MovingAverage ma5;
        private MovingAverage ma10;

        protected override void Initialize()
        {
            series5 = MarketData.GetSeries(TimeFrame.Minute5);
            series10 = MarketData.GetSeries(TimeFrame.Minute10);

            ma = Indicators.MovingAverage(MarketSeries.Close, Period, MovingAverageType.Triangular);
            ma5 = Indicators.MovingAverage(series5.Close, Period, MovingAverageType.Triangular);
            ma10 = Indicators.MovingAverage(series10.Close, Period, MovingAverageType.Triangular);
        }

        public override void Calculate(int index)
        {
            MA[index] = ma.Result[index];

            //var index5 = GetIndexByDate(series5, MarketSeries.OpenTime[index]);
            var index5 = GetIndexByTime(series5, MarketSeries.OpenTime[index]); 
            if (index5 != -1)
                MA5[index] = ma5.Result[index5];

            //var index10 = GetIndexByDate(series10, MarketSeries.OpenTime[index]);
            var index10 = GetIndexByTime(series10, MarketSeries.OpenTime[index]);
            if (index10 != -1)
                MA10[index] = ma10.Result[index10];
        }


        private int GetIndexByDate(MarketSeries series, DateTime time)
        {
            for (int i = series.Close.Count - 1; i > 0; i--)
            {
                if (time == series.OpenTime[i])
                    return i;
            }
            return -1;
        }

        private int GetIndexByTime(MarketSeries searchSeries, DateTime desiredTime)
        {
            Print("desired time=" + desiredTime.ToString());
            //loop over time series backwards till closest match found
            for (int i = searchSeries.Close.Count - 1; i > 0; i--)
            {
                if (desiredTime == searchSeries.OpenTime[i])
                {
                    return i;
                }
                else if (searchSeries.OpenTime[i] < desiredTime) return i; //return last value prev. to desired
                
            }
            return -1;
        }
    }
}