Using Multiple Custom Indicator
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;
}
}
}
}