Multi-currency backtest
Created at 17 Dec 2019, 13:23
Multi-currency backtest
17 Dec 2019, 13:23
As a test of the new multi-currency backtest functionality, I am writing a robot that calculates the correlation of two instruments.
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
using System.Threading;
using System.Collections.Generic;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None, ScalePrecision = 5, AutoRescale = true)]
public class Correlation : Indicator
{
[Parameter("Master Currency", DefaultValue = "EURUSD")]
public string masterName { get; set; }
[Parameter("Slave Currency", DefaultValue = "AUDUSD")]
public string slaveName { get; set; }
[Parameter("Periods", DefaultValue = 120)]
public int Period { get; set; }
[Output("Correlation", LineColor = "Red")]
public IndicatorDataSeries Result { get; set; }
private Bars masterBars;
private Bars slaveBars;
private Symbol masterSymbol;
private Symbol slaveSymbol;
protected override void Initialize()
{
masterSymbol = Symbols.GetSymbol(masterName);
slaveSymbol = Symbols.GetSymbol(slaveName);
masterBars = MarketData.GetBars(Bars.TimeFrame, masterName);
slaveBars = MarketData.GetBars(Bars.TimeFrame, slaveName);
while (masterBars.Count < Period)
{
var loadedCount = masterBars.LoadMoreHistory();
if (loadedCount == 0)
break;
}
while (slaveBars.Count < Period)
{
var loadedCount = slaveBars.LoadMoreHistory();
if (loadedCount == 0)
break;
}
}
public override void Calculate(int index)
{
if (index < Period + 1)
{
return;
}
double masterSum = 0;
double masterMedian = 0;
double slaveSum = 0;
double slaveMedian = 0;
double upPartSum = 0;
double masterDeltaSqrtSum = 0;
double slaveDeltaSqrtSum = 0;
for (int i = 0; i < Period; i++)
{
masterSum = masterSum + masterBars[index - i].Close;
slaveSum = slaveSum + slaveBars[index - i].Close;
}
masterMedian = masterSum / Period;
slaveMedian = slaveSum / Period;
for (int i = 0; i < Period; i++)
{
upPartSum = upPartSum + (masterBars[index - i].Close - masterMedian) * (slaveBars[index - i].Close - slaveMedian);
masterDeltaSqrtSum = masterDeltaSqrtSum + Math.Pow(masterBars[index - i].Close - masterMedian, 2);
slaveDeltaSqrtSum = slaveDeltaSqrtSum + Math.Pow(slaveBars[index - i].Close - slaveMedian, 2);
}
Result[index] = upPartSum / Math.Sqrt(masterDeltaSqrtSum * slaveDeltaSqrtSum);
}
}
}
On the backtest itself, the indicator does not work.
Replies
PanagiotisCharalampous
17 Dec 2019, 15:44
Hi v,kredov,
The way you handle indices between different data series is wrong. An index in calculate is not the same index in a series retrieved by GetBars(). See below a corrected version
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
using System.Threading;
using System.Collections.Generic;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None, ScalePrecision = 5, AutoRescale = true)]
public class Correlation : Indicator
{
[Parameter("Master Currency", DefaultValue = "EURUSD")]
public string masterName { get; set; }
[Parameter("Slave Currency", DefaultValue = "AUDUSD")]
public string slaveName { get; set; }
[Parameter("Periods", DefaultValue = 120)]
public int Period { get; set; }
[Output("Correlation", LineColor = "Red")]
public IndicatorDataSeries Result { get; set; }
private Bars masterBars;
private Bars slaveBars;
private Symbol masterSymbol;
private Symbol slaveSymbol;
protected override void Initialize()
{
masterSymbol = Symbols.GetSymbol(masterName);
slaveSymbol = Symbols.GetSymbol(slaveName);
masterBars = MarketData.GetBars(Bars.TimeFrame, masterName);
slaveBars = MarketData.GetBars(Bars.TimeFrame, slaveName);
while (masterBars.Count < Period)
{
var loadedCount = masterBars.LoadMoreHistory();
if (loadedCount == 0)
break;
}
while (slaveBars.Count < Period)
{
var loadedCount = slaveBars.LoadMoreHistory();
if (loadedCount == 0)
break;
}
}
public override void Calculate(int index)
{
if (index < Period + 1)
{
return;
}
double masterSum = 0;
double masterMedian = 0;
double slaveSum = 0;
double slaveMedian = 0;
double upPartSum = 0;
double masterDeltaSqrtSum = 0;
double slaveDeltaSqrtSum = 0;
for (int i = 0; i < Period; i++)
{
var masterBarsIndex = masterBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]) - i;
if (!double.IsNaN(masterBarsIndex))
masterSum = masterSum + masterBars[masterBarsIndex].Close;
var slaveBarsIndex = slaveBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]) - i;
if (!double.IsNaN(slaveBarsIndex) && slaveBarsIndex >= 0 && slaveBars.Count > slaveBarsIndex)
slaveSum = slaveBars[slaveBarsIndex].Close;
}
masterMedian = masterSum / Period;
slaveMedian = slaveSum / Period;
for (int i = 0; i < Period; i++)
{
upPartSum = upPartSum + (masterBars[masterBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]) - i].Close - masterMedian) * (slaveBars[slaveBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]) - i].Close - slaveMedian);
masterDeltaSqrtSum = masterDeltaSqrtSum + Math.Pow(masterBars[masterBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]) - i].Close - masterMedian, 2);
slaveDeltaSqrtSum = slaveDeltaSqrtSum + Math.Pow(slaveBars[slaveBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]) - i].Close - slaveMedian, 2);
}
Result[index] = upPartSum / Math.Sqrt(masterDeltaSqrtSum * slaveDeltaSqrtSum);
}
}
}
Best Regards,
Panagiotis
@PanagiotisCharalampous
v.kredov
17 Dec 2019, 13:41 ( Updated at: 21 Dec 2023, 09:21 )
On the live chart, this error often appears when adding an indicator. When the number of indicator values is not equal to the number of tool candles, despite the fact that this behavior always occurs when loading the history of the tool by scrolling the chart back.
@v.kredov