Problem with custom library
Problem with custom library
10 Mar 2024, 20:53
I want to build a library to consolidate some of my custom indicators. I am using VS 2022 and cTrader version 4.8.30.213183. I was able to construct the library and I added the reference to the cBot. I was able to build/compile the cBot and the Library in VS 2022 just fine. But when I tried to backtest the cBot I got an error message in cTrader Automate Build:
However, VS 2022 seems to build the code fine as I get:
1>C:\Users\janiv\OneDrive\Documents\cAlgo\CustomLibraries\CustomIndicatorLibrary\CustomIndicatorLibrary\Class1.cs(40,41,40,50): warning CS8618: Non-nullable field 'trueRange' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
1>C:\Users\janiv\OneDrive\Documents\cAlgo\CustomLibraries\CustomIndicatorLibrary\CustomIndicatorLibrary\Class1.cs(41,41,41,44): warning CS8618: Non-nullable field 'atr' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
1>CustomIndicatorLibrary -> C:\Users\janiv\OneDrive\Documents\cAlgo\CustomLibraries\CustomIndicatorLibrary\CustomIndicatorLibrary\bin\Debug\net6.0\CustomIndicatorLibrary.dll
1>Done building project "CustomIndicatorLibrary.csproj".
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
========== Rebuild started at 10:32 PM and took 00,563 seconds ==========
I got some warnings but the build went through fine.
cBot code:
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
using System.Threading;
using CustomIndicatorLibrary;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class AAATestBotMAcross : Robot
{
[Parameter(DefaultValue = "SuperTrendReference_cBot")]
public string cBotLabel { get; set; }
[Parameter("Trade Volume:", DefaultValue = 1000)]
public int Volume { get; set; }
[Parameter("Fast SMA Period", DefaultValue = 9)]
public int FastSMAPeriod { get; set; }
[Parameter("Slow SMA Period", DefaultValue = 21)]
public int SlowSMAPeriod { get; set; }
[Parameter("KAMA Period", DefaultValue = 10)]
public int KaMaPeriod { get; set; }
[Parameter("Take Profit (pips):", DefaultValue = 50.0)]
public double TakeProfit { get; set; }
[Parameter("Stop Loss (pips):", DefaultValue = 50.0)]
public double StopLoss { get; set; }
private MovingAverage fastSMA;
private MovingAverage slowSMA;
private CustomIndicatorLibrary.Class1.KAMA KAMA_;
protected override void OnStart()
{
fastSMA = Indicators.MovingAverage(Bars.ClosePrices, FastSMAPeriod, MovingAverageType.Simple);
slowSMA = Indicators.MovingAverage(Bars.ClosePrices, SlowSMAPeriod, MovingAverageType.Simple);
// Create an instance of the CustomKAMA indicator
KAMA_ = Indicators.GetIndicator<CustomIndicatorLibrary.Class1.KAMA>(
Symbol.Name,
TimeFrame,
new CustomIndicatorLibrary.Class1.KAMA.Parameters
{
Source = Bars.ClosePrices,
Period = KaMaPeriod,
Fast = 2,
Slow = 30,
ATRPeriod = 14,
BufferFactor = 1
});
}
protected override void OnBar()
{
var currentFastSMA = fastSMA.Result.LastValue;
var currentSlowSMA = slowSMA.Result.LastValue;
var previousFastSMA = fastSMA.Result.Last(1);
var previousSlowSMA = slowSMA.Result.Last(1);
// Check for a crossover
if (currentFastSMA > currentSlowSMA && previousFastSMA <= previousSlowSMA)
{
ExecuteMarketOrder(TradeType.Buy, SymbolName, Volume, "SMA Crossover - Buy", StopLoss, TakeProfit);
}
else if (currentFastSMA < currentSlowSMA && previousFastSMA >= previousSlowSMA)
{
ExecuteMarketOrder(TradeType.Sell, SymbolName, Volume, "SMA Crossover - Sell", StopLoss, TakeProfit);
}
}
private void OpenMarketOrder(TradeType tradeType, double dLots, double takeProfit, double stopLoss)
{
var volumeInUnits = Symbol.QuantityToVolumeInUnits(dLots);
volumeInUnits = Symbol.NormalizeVolumeInUnits(volumeInUnits, RoundingMode.Down);
var result = ExecuteMarketOrder(tradeType, Symbol.Name, volumeInUnits, cBotLabel, takeProfit, stopLoss);
if (!result.IsSuccessful)
{
Print("Execute Market Order Error: {0}", result.Error.Value);
OnStop();
}
}
private int CalculatePositionsQnty(TradeType tradeType)
{
return Positions.FindAll(cBotLabel, Symbol.Name, tradeType).Length;
}
private void CloseAllPositions(TradeType tradeType)
{
foreach (var position in Positions.FindAll(cBotLabel, Symbol.Name, tradeType))
{
var result = ClosePosition(position);
if (!result.IsSuccessful)
{
Print("Closing market order error: {0}", result.Error);
}
}
}
}
}
library code:
using System;
using cAlgo.API;
using cAlgo.API.Indicators;
namespace CustomIndicatorLibrary
{
public class Class1
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class KAMA : Indicator
{
[Parameter()]
public DataSeries Source { get; set; }
[Parameter("KAMA Period", DefaultValue = 10)]
public int Period { get; set; }
[Parameter("Fast MA", DefaultValue = 2)]
public double Fast { get; set; }
[Parameter("Slow MA", DefaultValue = 30)]
public int Slow { get; set; }
[Parameter("ATR Period", DefaultValue = 14)]
public int ATRPeriod { get; set; }
[Parameter("Buffer Factor", DefaultValue = 1)]
public double BufferFactor { get; set; }
[Output("KAMA", PlotType = PlotType.Line, LineColor = "Lime", Thickness = 2)]
public IndicatorDataSeries Kama { get; set; }
[Output("Up Buffer", PlotType = PlotType.Line, LineColor = "White", Thickness = 1, LineStyle = LineStyle.Lines)]
public IndicatorDataSeries UpBuff { get; set; }
[Output("Down Buffer", PlotType = PlotType.Line, LineColor = "White", Thickness = 1, LineStyle = LineStyle.Lines)]
public IndicatorDataSeries DownBuff { get; set; }
private IndicatorDataSeries diff;
private IndicatorDataSeries trueRange;
private IndicatorDataSeries atr;
double fastd;
double slowd;
protected override void Initialize()
{
diff = CreateDataSeries();
trueRange = CreateDataSeries();
atr = CreateDataSeries();
fastd = 2.0 / (Fast + 1);
slowd = 2.0 / (Slow + 1);
}
public override void Calculate(int index)
{
if (index >= 1)
{
diff[index] = Math.Abs(Source[index] - Source[index - 1]);
trueRange[index] = Math.Max(Math.Max(Bars.HighPrices[index] - Bars.LowPrices[index], Math.Abs(Bars.HighPrices[index] - Bars.ClosePrices[index - 1])), Math.Abs(Bars.LowPrices[index] - Bars.ClosePrices[index - 1]));
// Simple Moving Average for ATR
if (index >= ATRPeriod)
{
double atrSum = 0;
for (int i = index - ATRPeriod + 1; i <= index; i++)
{
atrSum += trueRange[i];
}
atr[index] = atrSum / ATRPeriod;
}
}
if (index < Period)
{
Kama[index] = Source[index];
return;
}
double signal = Math.Abs(Source[index] - Source[index - Period]);
double noise = 0.0;
for (int i = index - Period + 1; i <= index; i++)
{
noise += diff[i];
}
if (noise == 0)
{
Kama[index] = Kama[index - 1];
}
else
{
double smoothingFactor = Math.Pow(((signal / noise) * (fastd - slowd) + slowd), 2);
Kama[index] = Kama[index - 1] + smoothingFactor * (Source[index] - Kama[index - 1]);
}
if (index >= ATRPeriod)
{
UpBuff[index] = Kama[index] + atr[index] * BufferFactor;
DownBuff[index] = Kama[index] - atr[index] * BufferFactor;
}
}
}
}
}
cBot references should be just fine:
Could someone help me with this issue?
jani
10 Mar 2024, 22:43
Sorry could not find the way to delete this thread. I solved the issue already. It was a problem with:
just needed to remove the "Parameters" and simplify the syntax
@jani