Referencing data from custom indicator
Referencing data from custom indicator
27 Mar 2021, 20:37
Dear all,
I'm using a custom indicator (Connor's RSI). The plotted indicator is correct. But when I retrieve the indicator's (Result[index]) previous bar values through crsi.Result.Last(n) I never get the same value as that for the plotted indicator. Am I missing something? I can share code if necessary.
Thanks,
Sameh
Replies
findsameh
28 Mar 2021, 14:51
RE:
Dear Ahmad,
Neither index-1 nor Last(1) work, both return numbers not matching any of the correct results. Below is the CRSI indicator code, followed by a simple bot to retrieve the results.
using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using System.Linq;
using System.Collections.Generic;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class ConnorsCRSI11 : Indicator
{
[Output("Main", Color = Colors.Orange)]
public IndicatorDataSeries Result { get; set; }
[Parameter(DefaultValue = 3.0)]
public int rsiPeriods { get; set; }
[Parameter(DefaultValue = 2.0)]
public int streakPeriods { get; set; }
[Parameter(DefaultValue = 100.0)]
public int rocPeriods { get; set; }
public RelativeStrengthIndex rsi;
public int streak;
public double avgGain1;
public double avgLoss1;
public double avgGain;
public double avgLoss;
public double rsiStreakValue = 0;
public List<double> listOfAvgGain = new List<double>();
public List<double> listOfAvgLoss = new List<double>();
public List<double> listOfGain = new List<double>();
public List<double> listOfLoss = new List<double>();
public List<int> listOfStreaks = new List<int>();
public int startIndex;
public double percentRank = 0.0;
protected override void Initialize()
{
rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, rsiPeriods);
startIndex = 1;
}
public override void Calculate(int index)
{
UpDownStreak(streakPeriods, index + 1);
RsiStreak(streakPeriods, index);
Roc(rocPeriods, index);
Result[index] = (rsiStreakValue + rsi.Result.LastValue + percentRank) / 3;
}
// crsi calculations
public void Roc(double periods, int index)
{
var countRocDn = 0;
var prevDayRoc = 0.0;
var todayRoc = (Bars.ClosePrices[index] - Bars.ClosePrices[index - 1]) / Bars.ClosePrices[index - 1];
for (int i = 1; i <= periods; i++)
{
prevDayRoc = (Bars.ClosePrices[index - i] - Bars.ClosePrices[index - i - 1]) / Bars.ClosePrices[index - i - 1];
if (todayRoc > prevDayRoc)
countRocDn++;
}
percentRank = (countRocDn / periods) * 100;
}
public void UpDownStreak(int periods, int index)
{
int countUp = 0;
int countDn = 0;
int countEqual = 0;
for (int i = 1; i < 100; i++)
if (Bars.ClosePrices[index - i] > Bars.ClosePrices[index - i - 1])
{
countUp++;
continue;
}
else
break;
for (int i = 1; i < 100; i++)
if (Bars.ClosePrices[index - i] < Bars.ClosePrices[index - i - 1])
{
countDn++;
continue;
}
else
break;
for (int i = 1; i < 100; i++)
if (Bars.ClosePrices[index - i] == Bars.ClosePrices[index - i - 1])
{
countEqual++;
continue;
}
else
break;
if (countUp > countDn && countUp > countEqual)
{
streak = countUp;
listOfStreaks.Add(countUp);
}
else if (countDn > countUp && countDn > countEqual)
{
streak = -countDn;
listOfStreaks.Add(-countDn);
}
else if (countEqual > countUp && countEqual > countDn)
{
streak = 0;
listOfStreaks.Add(0);
}
if (listOfStreaks.Count > periods)
listOfStreaks.RemoveAt(0);
}
public void RsiStreak(int periods, int index)
{
if (listOfStreaks.Count < periods)
return;
double changeValue = 0;
double rs = 0;
List<double> listOfChangeValues = new List<double>();
for (int i = 0; i < periods - 1; i++)
{
changeValue = listOfStreaks[i + 1] - listOfStreaks[i];
if (changeValue > 0)
{
listOfGain.Add(changeValue);
listOfLoss.Add(0);
}
else
{
listOfLoss.Add(Math.Abs(changeValue));
listOfGain.Add(0);
}
}
if (1 == startIndex)
{
avgGain1 = listOfGain.Average();
avgLoss1 = listOfLoss.Average();
listOfAvgGain.Add(avgGain1);
listOfAvgLoss.Add(avgLoss1);
}
else
{
avgGain = ((listOfAvgGain[listOfAvgGain.Count - 1] * (periods - 1)) + listOfGain[listOfGain.Count - 1]) / periods;
avgLoss = ((listOfAvgLoss[listOfAvgLoss.Count - 1] * (periods - 1)) + listOfLoss[listOfLoss.Count - 1]) / periods;
listOfAvgGain.Add(avgGain);
listOfAvgLoss.Add(avgLoss);
}
if (1 == startIndex)
{
startIndex = 2;
rs = avgGain1 / avgLoss1;
if (avgLoss1 == 0)
rsiStreakValue = 100;
else
rsiStreakValue = 100 - (100 / (1 + rs));
}
else
{
rs = avgGain / avgLoss;
if (avgLoss == 0)
rsiStreakValue = 100;
else
rsiStreakValue = 100 - (100 / (1 + rs));
}
if (listOfLoss.Count >= periods)
listOfLoss.RemoveAt(0);
if (listOfGain.Count >= periods)
listOfGain.RemoveAt(0);
if (listOfAvgGain.Count >= periods)
listOfAvgGain.RemoveAt(0);
if (listOfAvgLoss.Count >= periods)
listOfAvgLoss.RemoveAt(0);
if (listOfStreaks.Count >= periods)
listOfStreaks.RemoveAt(0);
}
}
}
===========
Bot to retrieve results:
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class cBotNew : Robot
{
[Parameter("RSI periods", Group = "CRSI", DefaultValue = 3.0, MinValue = 1)]
public int rsiPeriods { get; set; }
[Parameter("Up/down streak periods", Group = "CRSI", DefaultValue = 2.0, MinValue = 1)]
public int streakPeriods { get; set; }
[Parameter("Rate of change periods", Group = "CRSI", DefaultValue = 100.0, MinValue = 2)]
public int rocPeriods { get; set; }
public ConnorsCRSI11 crsi;
protected override void OnStart()
{
crsi = Indicators.GetIndicator<ConnorsCRSI11>(rsiPeriods, streakPeriods, rocPeriods);
}
protected override void OnBar()
{
Print(crsi.Result.Last(1));
}
}
}
===========
Thanks,
Sameh
@findsameh
amusleh
29 Mar 2021, 11:45
I changed the lists to IndicatorDataSeries and now the results are matching, the indicator might be changed so please modify it if something is changed related to indicator formula.
using cAlgo.API;
using cAlgo.API.Indicators;
using System;
using System.Linq;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class ConnorsCRSI11 : Indicator
{
private IndicatorDataSeries listOfAvgGain;
private IndicatorDataSeries listOfAvgLoss;
private IndicatorDataSeries listOfGain;
private IndicatorDataSeries listOfLoss;
private IndicatorDataSeries listOfStreaks;
[Output("Main", Color = Colors.Orange, IsHistogram = true, PlotType = PlotType.Histogram)]
public IndicatorDataSeries Result { get; set; }
[Parameter(DefaultValue = 3.0)]
public int rsiPeriods { get; set; }
[Parameter(DefaultValue = 2.0)]
public int streakPeriods { get; set; }
[Parameter(DefaultValue = 100.0)]
public int rocPeriods { get; set; }
public RelativeStrengthIndex rsi;
public int streak;
public double avgGain1;
public double avgLoss1;
public double avgGain;
public double avgLoss;
public int startIndex;
public double percentRank = 0.0;
protected override void Initialize()
{
listOfAvgGain = CreateDataSeries();
listOfAvgLoss = CreateDataSeries();
listOfGain = CreateDataSeries();
listOfLoss = CreateDataSeries();
listOfStreaks = CreateDataSeries();
rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, rsiPeriods);
startIndex = 1;
}
public override void Calculate(int index)
{
if (index <= rocPeriods) return;
UpDownStreak(streakPeriods, index);
var rsiStreakValue = GetRsiStreak(streakPeriods, index);
Roc(rocPeriods, index);
Result[index] = (rsiStreakValue + rsi.Result[index] + percentRank) / 3;
}
// crsi calculations
public void Roc(double periods, int index)
{
var countRocDn = 0;
var prevDayRoc = 0.0;
var todayRoc = (Bars.ClosePrices[index] - Bars.ClosePrices[index - 1]) / Bars.ClosePrices[index - 1];
for (int i = 1; i <= periods; i++)
{
prevDayRoc = (Bars.ClosePrices[index - i] - Bars.ClosePrices[index - i - 1]) / Bars.ClosePrices[index - i - 1];
if (todayRoc > prevDayRoc)
countRocDn++;
}
percentRank = (countRocDn / periods) * 100;
}
public void UpDownStreak(int periods, int index)
{
int countUp = 0;
int countDn = 0;
int countEqual = 0;
for (int i = 1; i < 100; i++)
if (Bars.ClosePrices[index - i] > Bars.ClosePrices[index - i - 1])
{
countUp++;
continue;
}
else
break;
for (int i = 1; i < 100; i++)
if (Bars.ClosePrices[index - i] < Bars.ClosePrices[index - i - 1])
{
countDn++;
continue;
}
else
break;
for (int i = 1; i < 100; i++)
if (Bars.ClosePrices[index - i] == Bars.ClosePrices[index - i - 1])
{
countEqual++;
continue;
}
else
break;
if (countUp > countDn && countUp > countEqual)
{
streak = countUp;
listOfStreaks[index] = countUp;
}
else if (countDn > countUp && countDn > countEqual)
{
streak = -countDn;
listOfStreaks[index] = -countDn;
}
else if (countEqual > countUp && countEqual > countDn)
{
streak = 0;
listOfStreaks[index] = 0;
}
}
public double GetRsiStreak(int periods, int index)
{
if (listOfStreaks.Count < periods)
return 0;
double changeValue;
double rs;
double result;
for (int i = index; i > index - periods; i--)
{
changeValue = listOfStreaks[i - 1] - listOfStreaks[i];
listOfLoss[index] = 0;
listOfGain[index] = 0;
if (double.IsNaN(changeValue)) continue;
if (changeValue > 0)
{
listOfGain[index] = changeValue;
}
else
{
listOfLoss[index] = Math.Abs(changeValue);
}
}
if (1 == startIndex)
{
avgGain1 = listOfGain.Average();
avgLoss1 = listOfLoss.Average();
listOfAvgGain[index] = double.IsNaN(avgGain1) ? 0 : avgGain1;
listOfAvgLoss[index] = double.IsNaN(avgLoss1) ? 0 : avgLoss1;
}
else
{
avgGain = ((listOfAvgGain[index - 1] * (periods - 1)) + listOfGain[index]) / periods;
avgLoss = ((listOfAvgLoss[index - 1] * (periods - 1)) + listOfLoss[index]) / periods;
listOfAvgGain[index] = avgGain;
listOfAvgLoss[index] = avgLoss;
}
if (1 == startIndex)
{
startIndex = 2;
rs = avgGain1 / avgLoss1;
if (avgLoss1 == 0)
result = 100;
else
result = 100 - (100 / (1 + rs));
}
else
{
rs = avgGain / avgLoss;
if (avgLoss == 0)
result = 100;
else
result = 100 - (100 / (1 + rs));
}
return result;
}
}
}
using cAlgo.API;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class cBotNew : Robot
{
[Parameter("RSI periods", Group = "CRSI", DefaultValue = 3.0, MinValue = 1)]
public int rsiPeriods { get; set; }
[Parameter("Up/down streak periods", Group = "CRSI", DefaultValue = 2.0, MinValue = 1)]
public int streakPeriods { get; set; }
[Parameter("Rate of change periods", Group = "CRSI", DefaultValue = 100.0, MinValue = 2)]
public int rocPeriods { get; set; }
public ConnorsCRSI11 crsi;
protected override void OnStart()
{
crsi = Indicators.GetIndicator<ConnorsCRSI11>(rsiPeriods, streakPeriods, rocPeriods);
}
protected override void OnBar()
{
var index = Bars.Count - 2;
Print(crsi.Result[index], " | ", Bars.OpenTimes[index].ToString("R"));
}
}
}
@amusleh
findsameh
30 Mar 2021, 22:05
RE:
Hello Ahmad,
Thanks for the suggestion. But with your suggested solution if you compare the result through the indicator code (Result[index]) and compare it to the result through the bot (crsi.Result[index]), you'd find that both values still don't match.
And I'm not sure why I'd need to change the indicator code to retrieve a value from indicator to bot, knowing the indicator already produces the correct values for CRSI.
Sameh
@findsameh
amusleh
31 Mar 2021, 09:16
RE: RE:
findsameh said:
Hello Ahmad,
Thanks for the suggestion. But with your suggested solution if you compare the result through the indicator code (Result[index]) and compare it to the result through the bot (crsi.Result[index]), you'd find that both values still don't match.
And I'm not sure why I'd need to change the indicator code to retrieve a value from indicator to bot, knowing the indicator already produces the correct values for CRSI.
Sameh
There was some issues in your indicator code, that causes issues when you use it on a cBot, like using invalid bar index.
I checked the indicator and cBot I posted and the results does match on backtest for EURUSD on Spotware cTrader beta.
@amusleh
findsameh
31 Mar 2021, 12:14
RE: RE: RE:
amusleh said:
findsameh said:
Hello Ahmad,
Thanks for the suggestion. But with your suggested solution if you compare the result through the indicator code (Result[index]) and compare it to the result through the bot (crsi.Result[index]), you'd find that both values still don't match.
And I'm not sure why I'd need to change the indicator code to retrieve a value from indicator to bot, knowing the indicator already produces the correct values for CRSI.
Sameh
There was some issues in your indicator code, that causes issues when you use it on a cBot, like using invalid bar index.
I checked the indicator and cBot I posted and the results does match on backtest for EURUSD on Spotware cTrader beta.
Apologies, my mistake ... they do match. Thanks a lot.
Sameh
@findsameh
amusleh
28 Mar 2021, 11:13
Hi,
To get the previous completed value on a data series you must use index -1 or Last(1).
If that didn't solved the issue please post the code and we will help you.
@amusleh