Using Multiple Custom Indicator

Created at 04 Jun 2020, 14:59
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!
PU

punit.bharadwa

Joined 02.06.2016

Using Multiple Custom Indicator
04 Jun 2020, 14:59


hi,

I am trying to use multiple custom indicators in a bot, but looks like it cannot use more than one. It is most likely something simple that I have overlooked being not great at C#.

But any ideas on how to get this to work?

Aim of the bot of is take the Modified Swing Indicator (downloaded from this forum: https://ctrader.com/algos/indicators/show/1107) and use a LARGE SWING to detect market direction and SMALL SWING for entry.

I attach my Log and then bot & indicator code here:

03/05/2020 22:05:00.000 | Backtesting started
08/05/2020 02:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 02:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 03:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 03:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 04:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 04:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 05:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 05:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 06:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 06:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 07:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 07:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 08:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 08:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 09:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 09:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 10:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 10:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 11:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 11:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 12:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 12:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 13:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 13:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 14:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 14:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 15:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 15:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 16:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 16:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 17:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 17:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 18:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 18:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 19:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 19:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 20:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 20:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
08/05/2020 21:00:00.000 | Using Swing small: False False, 0>0 0>0
08/05/2020 21:00:00.000 | Using Swing large: True False, 1.05769>0 0>1.05769
15/05/2020 00:59:00.000 | Backtesting finished
 

Bot Code:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Test : Robot
    {
        [Parameter("Source", Group = "Mkt Data", DefaultValue = "Close")]
        public DataSeries Source { get; set; }

        [Parameter("Strength", Group = "Mkt Data", DefaultValue = 100)]
        public int BullBear_strength { get; set; }

        [Parameter("cf Strength", Group = "Mkt Data", DefaultValue = 5)]
        public int swing_strength { get; set; }

        [Parameter("Max Trades", Group = "Mkt Data", DefaultValue = 10)]
        public int MaxTrades { get; set; }

        [Parameter("ATR Multiple", Group = "Risk", DefaultValue = 2, MinValue = 0)]
        public double mATR { get; set; }

        [Parameter("Risk (%)", Group = "Risk", DefaultValue = 0.5, MinValue = 0.1)]
        public double Risk_Max { get; set; }

        [Parameter("Max Volume Size", Group = "Risk", DefaultValue = 50000, MinValue = 1000)]
        public double BadVolumeSize { get; set; }

        [Parameter("Use Trailing Stop", Group = "Risk", DefaultValue = false)]
        public bool UseTrailingStop { get; set; }

        public ExponentialMovingAverage ema;
        public AverageTrueRange atr;

        public Swing MktDirection;
        public Swing swing;
        string label = "S";

        protected override void OnStart()
        {

            MktDirection = Indicators.GetIndicator<Swing>(Bars.HighPrices, Bars.LowPrices, BullBear_strength);
            swing = Indicators.GetIndicator<Swing>(Bars.HighPrices, Bars.LowPrices, swing_strength);

            ema = Indicators.ExponentialMovingAverage(Source, 200);
            atr = Indicators.AverageTrueRange(20, MovingAverageType.Exponential);
        }


        protected override void OnBar()
        {

            if (Bars.ClosePrices.Last(1) > MktDirection.SwingLowPlot.Last(1))
            {
                // BULL MKT AND NEW LOW - INCREASE RISK
                Print("Using Swing small: {0} {1}, {2}>{3} {4}>{5}", swing.lastSwingLow > swing.previousSwingLow, swing.lastSwingHigh > swing.lastSwingLow, swing.lastSwingLow, swing.previousSwingLow, swing.lastSwingHigh, swing.lastSwingLow);
                Print("Using Swing large: {0} {1}, {2}>{3} {4}>{5}", MktDirection.lastSwingLow > MktDirection.previousSwingLow, MktDirection.lastSwingHigh > MktDirection.lastSwingLow, MktDirection.lastSwingLow, MktDirection.previousSwingLow, MktDirection.lastSwingHigh, MktDirection.lastSwingLow);
                if (swing.lastSwingLow > swing.previousSwingLow && swing.lastSwingHigh > swing.lastSwingLow)
                {
                    Print("   =============   Buy position   =============   ");
                    string Comment = "BULL_MKT=" + "SWING_LOW=" + "Add";
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000, label, 20, 40, Comment);
                }

            }
            else if (Bars.ClosePrices.Last(1) < MktDirection.SwingHighPlot.Last(1))
            {
                // BEAR MKT AND NEW LOW - INCREASE RISK
                Print("Using Swing small: {0} {1}, {2}>{3} {4}>{5}", swing.previousSwingHigh > swing.lastSwingHigh, swing.lastSwingHigh > swing.lastSwingLow, swing.previousSwingHigh, swing.lastSwingHigh, swing.lastSwingHigh, swing.lastSwingLow);
                Print("Using Swing large: {0} {1}, {2}>{3} {4}>{5}", MktDirection.previousSwingHigh > MktDirection.lastSwingHigh, MktDirection.lastSwingHigh > MktDirection.lastSwingLow, MktDirection.previousSwingHigh, MktDirection.lastSwingHigh, MktDirection.lastSwingHigh, MktDirection.lastSwingLow);
                if (swing.previousSwingHigh > swing.lastSwingHigh && swing.lastSwingHigh > swing.lastSwingLow)
                {
                    Print("   =============   Sell position   =============   ");
                    string Comment = "BEAR_MKT=" + "SWING_HIGH=" + "Add";
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, 10000, label, 20, 40, Comment);
                }

            }
        }


        protected override void OnStop()
        {
            CloseAllPositions(label, TradeType.Sell);
            CloseAllPositions(label, TradeType.Buy);
        }

        // HELPER FUNCTIONS
        private IEnumerable<Position> FilterPositions(string Label, TradeType TradeDirection)
        {
            return Positions.Where(p => p.Label == Label && p.SymbolName == Symbol.Name && p.TradeType == TradeDirection);
        }

        private IEnumerable<PendingOrder> FilteredOrders(string Label, TradeType TradeDirection)
        {
            return PendingOrders.Where(o => o.Label == Label && o.SymbolName == Symbol.Name && o.TradeType == TradeDirection);
        }

        private void CancelAllOrders(string Label, TradeType TradeDirection)
        {
            foreach (var order in FilteredOrders(Label, TradeDirection))
                CancelPendingOrder(order);
        }

        private void CloseAllPositions(string Label, TradeType TradeDirection)
        {
            foreach (var position in FilterPositions(Label, TradeDirection))
                ClosePosition(position);
        }
    }
}

Swing Indicator code:

#region Using declarations
using System;
using System.Collections;
using cAlgo.API;
#endregion

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Swing : Indicator
    {
        #region Properties
        [Parameter("High source")]
        public DataSeries High { get; set; }

        [Parameter("Low source")]
        public DataSeries Low { get; set; }

        [Parameter("Strength", DefaultValue = 5, MinValue = 1)]
        public int strength { get; set; }

        [Output("Swing high", LineColor = "Green", Thickness = 4, PlotType = PlotType.Points)]
        public IndicatorDataSeries SwingHighPlot { get; set; }

        [Output("Swing low", LineColor = "Orange", Thickness = 4, PlotType = PlotType.Points)]
        public IndicatorDataSeries SwingLowPlot { get; set; }
        #endregion

        #region Variables
        private double currentSwingHigh, currentSwingLow;
        public double previousSwingHigh, previousSwingLow;
        public double lastSwingHigh, lastSwingLow;
        private int CurrentBar, Count;
        private int saveCurrentBar = -1;
        private ArrayList lastHighCache, lastLowCache;
        private IndicatorDataSeries swingHighSeries, swingHighSwings, swingLowSeries, swingLowSwings;
        #endregion

        protected override void Initialize()
        {
            lastHighCache = new ArrayList();
            lastLowCache = new ArrayList();

            swingHighSeries = CreateDataSeries();
            swingHighSwings = CreateDataSeries();
            swingLowSeries = CreateDataSeries();
            swingLowSwings = CreateDataSeries();
        }

        public override void Calculate(int index)
        {
            CurrentBar = index;
            Count = High.Count;

            if (saveCurrentBar != CurrentBar)
            {
                swingHighSwings[index] = double.NaN;
                swingLowSwings[index] = double.NaN;
                swingHighSeries[index] = double.NaN;
                swingLowSeries[index] = double.NaN;
                lastHighCache.Add(High.Last(0));

                if (lastHighCache.Count > (2 * strength) + 1)
                    lastHighCache.RemoveAt(0);
                lastLowCache.Add(Low.Last(0));
                if (lastLowCache.Count > (2 * strength) + 1)
                    lastLowCache.RemoveAt(0);

                if (lastHighCache.Count == (2 * strength) + 1)
                {
                    bool isSwingHigh = true;
                    double swingHighCandidate = (double)lastHighCache[strength];
                    for (int i = 0; i < strength; i++)
                        if ((double)lastHighCache[i] >= swingHighCandidate - double.Epsilon)
                            isSwingHigh = false;

                    for (int i = strength + 1; i < lastHighCache.Count; i++)
                        if ((double)lastHighCache[i] > swingHighCandidate - double.Epsilon)
                            isSwingHigh = false;

                    if (isSwingHigh)
                    {
                        previousSwingHigh = lastSwingHigh;
                        lastSwingHigh = swingHighCandidate;
                    }

                    if (isSwingHigh)
                    {
                        currentSwingHigh = swingHighCandidate;
                        for (int i = 0; i <= strength; i++)
                            SwingHighPlot[index - i] = currentSwingHigh;
                    }
                    else
                        SwingHighPlot[index] = double.NaN;
                }

                if (lastLowCache.Count == (2 * strength) + 1)
                {
                    bool isSwingLow = true;
                    double swingLowCandidate = (double)lastLowCache[strength];
                    for (int i = 0; i < strength; i++)
                        if ((double)lastLowCache[i] <= swingLowCandidate + double.Epsilon)
                            isSwingLow = false;

                    for (int i = strength + 1; i < lastLowCache.Count; i++)
                        if ((double)lastLowCache[i] < swingLowCandidate + double.Epsilon)
                            isSwingLow = false;

                    if (isSwingLow)
                    {
                        previousSwingLow = lastSwingLow;
                        lastSwingLow = swingLowCandidate;
                    }

                    if (isSwingLow)
                    {
                        currentSwingLow = swingLowCandidate;
                        for (int i = 0; i <= strength; i++)
                            SwingLowPlot[index - i] = currentSwingLow;
                    }
                    else
                        SwingLowPlot[index] = double.NaN;


                }

                saveCurrentBar = CurrentBar;
            }
            else
            {
                if (High.Last(0) > High.Last(strength) && swingHighSwings.Last(strength) > 0.0)
                {
                    swingHighSwings[index - strength] = 0.0;
                    for (int i = 0; i <= strength; i++)
                        SwingHighPlot[index - i] = double.NaN;
                }
                else if (High.Last(0) > High.Last(strength) && currentSwingHigh != 0.0)
                {
                    SwingHighPlot[index] = double.NaN;
                }
                else if (High.Last(0) <= currentSwingHigh)
                    SwingHighPlot[index] = currentSwingHigh;

                if (Low.Last(0) < Low.Last(strength) && swingLowSwings.Last(strength) > 0.0)
                {
                    swingLowSwings[index - strength] = 0.0;
                    for (int i = 0; i <= strength; i++)
                        SwingLowPlot[index - i] = double.NaN;
                    currentSwingLow = double.NaN;
                }
                else if (Low.Last(0) < Low.Last(strength) && currentSwingLow != double.NaN)
                {
                    SwingLowPlot[index] = double.NaN;
                    currentSwingLow = double.NaN;
                }
                else if (Low.Last(0) >= currentSwingLow)
                    SwingLowPlot[index] = currentSwingLow;
            }
        }
    }
}


@punit.bharadwa