LAZY LOADING REVISITED ....
LAZY LOADING REVISITED ....
22 Feb 2022, 15:49
For quite a long time now, I've tried to solve this problem with 'lazy loading', that is said from some in the community to be an easy one.
I have constructed a really easy code to alternate between a sell (SELL) and a liquidation (LIQ) signal from an Indicator. But the Robot then clusters them together in blocks instead of alternating in-between them, as can be seen far below.
I hereby submit the codes for both programs and hope to receive "the easy" solution, after weeks of trials to try to overcome these 'basics'.
It would be extremely helpful if i could get clear guidance to this issue and maybe it should be included in your guide for programming, since I believe that a lot of traders have been stuck with this issue for hundreds of hours, needlessly.
Sincerely,
Björn Bernau
**********************
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SELL_LIQ : Indicator
{
//// SELL SIGNAL ////
[Output("sell_ONE", PlotType = PlotType.Points, LineColor = "#B511F7", Thickness = 4)]
public IndicatorDataSeries sell_ONE { get; set; }
[Output("liq_ONE", PlotType = PlotType.Points, LineColor = "#FF7CFC00", Thickness = 4)]
public IndicatorDataSeries liq_ONE { get; set; }
//// BOLLINGER ////
[Parameter("Source")]
public DataSeries Source { get; set; }
[Parameter("BandPeriods", DefaultValue = 16)]
public int BandPeriod { get; set; }
[Parameter("Std", DefaultValue = 1.6)]
public double std { get; set; }
[Parameter("MAType")]
public MovingAverageType MAType { get; set; }
private BollingerBands boll;
protected override void Initialize()
{
boll = Indicators.BollingerBands(Source, BandPeriod, std, MAType);
}
int HIGHstartCountIndexZERO = 0;
double d = double.NaN;
public override void Calculate(int index)
{
liquidator(index);
}
private void liquidator(int index)
{
var high = 0;
double high0 = Bars.HighPrices[index - 0];
double high1 = Bars.HighPrices[index - 1];
double high2 = Bars.HighPrices[index - 2];
double high3 = Bars.HighPrices[index - 3];
double high4 = Bars.HighPrices[index - 4];
double close0 = Bars.ClosePrices[index - 0];
var BBT2 = boll.Top[index - 2];
if (high4 <= high2)
if (high3 <= high2)
if (high2 > BBT2)
if (high2 >= high1)
if (high2 >= close0)
{
high = 1;
}
if (high == 1)
{
HIGHstartCountIndexZERO += 1;
}
if (high == 0)
{
sell_ONE[index - 0] = d;
}
if (high == 0)
{
liq_ONE[index - 0] = d;
}
if (high == 1)
if (HIGHstartCountIndexZERO % 2 != 0)
{
sell_ONE[index - 0] = Bars.HighPrices[index - 0];
}
if (high == 1)
if (HIGHstartCountIndexZERO % 2 == 0)
{
liq_ONE[index - 0] = Bars.HighPrices[index - 0];
}
}
}
}
**************
namespace cAlgo
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SELL_LIQ_220220 : Robot
{
////////////////////////////////////
///// TRADING PARAMETERS //////
////////////////////////////////////
[Parameter("Volume", DefaultValue = 1000)]
public int Volume { get; set; }
[Parameter("StopLoss", DefaultValue = 50)]
public int StopLoss { get; set; }
[Parameter("LIMIT", DefaultValue = 200)]
public int LIMIT { get; set; }
////////////////////////////
//// INITIAL PARAM ////
[Parameter("Source")]
public DataSeries Source { get; set; }
[Parameter("BandPeriods", DefaultValue = 16)]
public int BandPeriod { get; set; }
[Parameter("Std", DefaultValue = 1.6)]
public double std { get; set; }
[Parameter("MAType")]
public MovingAverageType MAType { get; set; }
//////////////////////////////
//// LITTERALS ////
[Parameter("littFACTOR", DefaultValue = 5)]
public double littFACTOR { get; set; }
private SELL_LIQ S2;
protected override void OnStart()
{
S2 = Indicators.GetIndicator<SELL_LIQ>(Source, BandPeriod, std, MAType);
}
protected override void OnBar()
{
var a = S2.sell_ONE.Last(0);
var b = S2.liq_ONE.Last(0);
if (!double.IsNaN(S2.sell_ONE.Last(0)) == true)
{
Print("SELL ", Bars.Count, " ", S2.sell_ONE);
}
if (!double.IsNaN(S2.liq_ONE.Last(0)) == true)
{
Print("LIQ ", Bars.Count, " ", S2.liq_ONE);
}
}
}
}
BLOCK-wise clustering of results
22/02/2022 00:59:00.000 | Backtesting finished
21/02/2022 11:00:00.000 | LIQ 639 IndicatorDataSeries (Count: 639, LastValue: 1,13634)
21/02/2022 06:00:00.000 | LIQ 634 IndicatorDataSeries (Count: 634, LastValue: 1,13621)
18/02/2022 12:00:00.000 | LIQ 616 IndicatorDataSeries (Count: 616, LastValue: 1,13611)
16/02/2022 22:00:00.000 | LIQ 578 IndicatorDataSeries (Count: 578, LastValue: 1,13821)
16/02/2022 11:00:00.000 | LIQ 567 IndicatorDataSeries (Count: 567, LastValue: 1,13775)
15/02/2022 19:00:00.000 | LIQ 551 IndicatorDataSeries (Count: 551, LastValue: 1,13586)
15/02/2022 16:00:00.000 | LIQ 548 IndicatorDataSeries (Count: 548, LastValue: 1,1322)
15/02/2022 13:00:00.000 | LIQ 545 IndicatorDataSeries (Count: 545, LastValue: 1,13459)
11/02/2022 19:00:00.000 | LIQ 503 IndicatorDataSeries (Count: 503, LastValue: 1,13966)
11/02/2022 16:00:00.000 | LIQ 500 IndicatorDataSeries (Count: 500, LastValue: 1,13888)
10/02/2022 19:00:00.000 | LIQ 479 IndicatorDataSeries (Count: 479, LastValue: 1,14645)
10/02/2022 16:00:00.000 | SELL 476 IndicatorDataSeries (Count: 476, LastValue: 1,14074)
10/02/2022 12:00:00.000 | SELL 472 IndicatorDataSeries (Count: 472, LastValue: 1,14359)
09/02/2022 20:00:00.000 | SELL 456 IndicatorDataSeries (Count: 456, LastValue: 1,14326)
09/02/2022 16:00:00.000 | SELL 452 IndicatorDataSeries (Count: 452, LastValue: 1,14317)
09/02/2022 13:00:00.000 | SELL 449 IndicatorDataSeries (Count: 449, LastValue: 1,14295)
09/02/2022 06:00:00.000 | SELL 442 IndicatorDataSeries (Count: 442, LastValue: 1,14269)
07/02/2022 19:00:00.000 | SELL 407 IndicatorDataSeries (Count: 407, LastValue: 1,14186)
07/02/2022 15:00:00.000 | SELL 403 IndicatorDataSeries (Count: 403, LastValue: 1,14398)
04/02/2022 14:00:00.000 | SELL 378 IndicatorDataSeries (Count: 378, LastValue: 1,14655)
04/02/2022 10:00:00.000 | SELL 374 IndicatorDataSeries (Count: 374, LastValue: 1,14602)
03/02/2022 19:00:00.000 | SELL 359 IndicatorDataSeries (Count: 359, LastValue: 1,14436)
02/02/2022 16:00:00.000 | SELL 332 IndicatorDataSeries (Count: 332, LastValue: 1,13048)
01/02/2022 14:00:00.000 | SELL 306 IndicatorDataSeries (Count: 306, LastValue: 1,12617)
01/02/2022 11:00:00.000 | SELL 303 IndicatorDataSeries (Count: 303, LastValue: 1,12614)
31/01/2022 22:00:00.000 | SELL 290 IndicatorDataSeries (Count: 290, LastValue: 1,12354)
31/01/2022 18:00:00.000 | LIQ 286 IndicatorDataSeries (Count: 286, LastValue: 1,12101)
31/01/2022 11:00:00.000 | LIQ 279 IndicatorDataSeries (Count: 279, LastValue: 1,11747)
28/01/2022 17:00:00.000 | LIQ 261 IndicatorDataSeries (Count: 261, LastValue: 1,11643)
24/01/2022 21:00:00.000 | LIQ 169 IndicatorDataSeries (Count: 169, LastValue: 1,13198)
21/01/2022 17:00:00.000 | LIQ 141 IndicatorDataSeries (Count: 141, LastValue: 1,1346)
21/01/2022 12:00:00.000 | LIQ 136 IndicatorDataSeries (Count: 136, LastValue: 1,13391)
21/01/2022 01:00:00.000 | Backtesting started
Replies
BJORNBERNAU
25 Feb 2022, 12:01
( Updated at: 21 Dec 2023, 09:22 )
RE:
PanagiotisCharalampous said:
Hi Bjorn,
Your problem has nothing to do with lazy loading. Instead this happens because of a poorly programmed indicator. You problem is here.
if (high == 1) { HIGHstartCountIndexZERO += 1; }
You cannot do this since the Calculate is called many times during a current candle's life. It is clearly described here. This variable will just produce nonsense. What you actually need to do is to keep the state of the last selection. Here is a very rough solution. The code is still poor but I do not have the time to rewrite the entire indicator. It's just an example of how you need to handle this
if (Bars.OpenTimes[index] != _lastBarOpenTime) { _lastBarOpenTime = Bars.OpenTimes[index]; if (!double.IsNaN(sell_ONE.Last(1))) { isBuy = true; } if (!double.IsNaN(liq_ONE.Last(1))) { isBuy = false; } }
Here is the full source code
using cAlgo.API; using cAlgo.API.Indicators; using System; namespace cAlgo { [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class SELL_LIQ : Indicator { //// SELL SIGNAL //// [Output("sell_ONE", PlotType = PlotType.Points, LineColor = "#B511F7", Thickness = 4)] public IndicatorDataSeries sell_ONE { get; set; } [Output("liq_ONE", PlotType = PlotType.Points, LineColor = "#FF7CFC00", Thickness = 4)] public IndicatorDataSeries liq_ONE { get; set; } //// BOLLINGER //// [Parameter("Source")] public DataSeries Source { get; set; } [Parameter("BandPeriods", DefaultValue = 16)] public int BandPeriod { get; set; } [Parameter("Std", DefaultValue = 1.6)] public double std { get; set; } [Parameter("MAType")] public MovingAverageType MAType { get; set; } private BollingerBands boll; private bool isBuy; protected override void Initialize() { boll = Indicators.BollingerBands(Source, BandPeriod, std, MAType); } private int HIGHstartCountIndexZERO = 0; private double d = double.NaN; private DateTime _lastBarOpenTime; public override void Calculate(int index) { liquidator(index); } private void liquidator(int index) { if (Bars.OpenTimes[index] != _lastBarOpenTime) { _lastBarOpenTime = Bars.OpenTimes[index]; if (!double.IsNaN(sell_ONE.Last(1))) { isBuy = true; } if (!double.IsNaN(liq_ONE.Last(1))) { isBuy = false; } } var high = 0; double high0 = Bars.HighPrices[index - 0]; double high1 = Bars.HighPrices[index - 1]; double high2 = Bars.HighPrices[index - 2]; double high3 = Bars.HighPrices[index - 3]; double high4 = Bars.HighPrices[index - 4]; double close0 = Bars.ClosePrices[index - 0]; var BBT2 = boll.Top[index - 2]; if (high4 <= high2) if (high3 <= high2) if (high2 > BBT2) if (high2 >= high1) if (high2 >= close0) { high = 1; } if (high == 0) { sell_ONE[index - 0] = d; } if (high == 0) { liq_ONE[index - 0] = d; } if (high == 1) if (!isBuy) { sell_ONE[index - 0] = Bars.HighPrices[index - 0]; } if (high == 1) if (isBuy) { liq_ONE[index - 0] = Bars.HighPrices[index - 0]; } } } }
and here are the results
Best Regards,
Panagiotis
No go, I'm sorry to say.
The code you've revised gives the exact same result.
Liquidation, despite no liquidation signal.
Here is again the indicator and robot code, so we there is no doubt.
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class sell_liq_panaBASE : Indicator
{
/////////////////////////////////////////////
/////////////////////////////////////////////
/////////////////////////////////////////////
/////////////////////////////////////////////
/////////////////////////////////////////////
////////////// 22-02-25 /////////////////
/////////////////////////////////////////////
/////////////////////////////////////////////
/////////////////////////////////////////////
/////////////////////////////////////////////
/////////////////////////////////////////////
//// SELL SIGNAL ////
[Output("sell_ONE", PlotType = PlotType.Points, LineColor = "#B511F7", Thickness = 4)]
public IndicatorDataSeries sell_ONE { get; set; }
[Output("liq_ONE", PlotType = PlotType.Points, LineColor = "#FF7CFC00", Thickness = 4)]
public IndicatorDataSeries liq_ONE { get; set; }
//// BOLLINGER ////
[Parameter("Source")]
public DataSeries Source { get; set; }
[Parameter("BandPeriods", DefaultValue = 16)]
public int BandPeriod { get; set; }
[Parameter("Std", DefaultValue = 1.6)]
public double std { get; set; }
[Parameter("MAType")]
public MovingAverageType MAType { get; set; }
private BollingerBands boll;
private bool isBuy;
protected override void Initialize()
{
boll = Indicators.BollingerBands(Source, BandPeriod, std, MAType);
}
// private int HIGHstartCountIndexZERO = 0;
private double d = double.NaN;
private DateTime _lastBarOpenTime;
public override void Calculate(int index)
{
liquidator(index);
}
private void liquidator(int index)
{
if (Bars.OpenTimes[index] != _lastBarOpenTime)
{
_lastBarOpenTime = Bars.OpenTimes[index];
if (!double.IsNaN(sell_ONE.Last(1)))
{
isBuy = true;
}
if (!double.IsNaN(liq_ONE.Last(1)))
{
isBuy = false;
}
}
var high = 0;
double high0 = Bars.HighPrices[index - 0];
double high1 = Bars.HighPrices[index - 1];
double high2 = Bars.HighPrices[index - 2];
double high3 = Bars.HighPrices[index - 3];
double high4 = Bars.HighPrices[index - 4];
double close0 = Bars.ClosePrices[index - 0];
var BBT2 = boll.Top[index - 2];
if (high4 <= high2)
if (high3 <= high2)
if (high2 > BBT2)
if (high2 >= high1)
if (high2 >= close0)
{
high = 1;
}
if (high == 0)
{
sell_ONE[index - 0] = d;
}
if (high == 0)
{
liq_ONE[index - 0] = d;
}
if (high == 1)
if (!isBuy)
{
sell_ONE[index - 0] = Bars.HighPrices[index - 0];
}
if (high == 1)
if (isBuy)
{
liq_ONE[index - 0] = Bars.HighPrices[index - 0];
}
}
}
}
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
namespace cAlgo
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SELL_LIQ_220225_REALpana : Robot
{
////////////////////////////////////
///// TRADING PARAMETERS //////
////////////////////////////////////
[Parameter("Volume", DefaultValue = 1000)]
public int Volume { get; set; }
[Parameter("StopLoss", DefaultValue = 50)]
public int StopLoss { get; set; }
[Parameter("LIMIT", DefaultValue = 200)]
public int LIMIT { get; set; }
////////////////////////////
//// INITIAL PARAM ////
[Parameter("Source")]
public DataSeries Source { get; set; }
[Parameter("BandPeriods", DefaultValue = 16)]
public int BandPeriod { get; set; }
[Parameter("Std", DefaultValue = 1.6)]
public double std { get; set; }
[Parameter("MAType")]
public MovingAverageType MAType { get; set; }
//////////////////////////////
//// LITTERALS ////
[Parameter("littFACTOR", DefaultValue = 5)]
public double littFACTOR { get; set; }
private sell_liq_panaBASE S2;
protected override void OnStart()
{
S2 = Indicators.GetIndicator<sell_liq_panaBASE>(Source, BandPeriod, std, MAType);
}
double d = double.NaN;
int m = 0;
int n = 0;
protected override void OnBar()
{
var a = S2.sell_ONE.Last(1);
var b = S2.liq_ONE.Last(1);
// m += 1;
// string POS = "sell_pos " + m;
if (!double.IsNaN(S2.sell_ONE.Last(1)) == true)
{
m += 1;
string POS = "sell_pos " + m;
ExecuteMarketOrder(TradeType.Sell, Symbol.Name, 1000, POS, StopLoss, LIMIT);
Print("SELL ", Bars.Count, " ", S2.sell_ONE, " ", POS);
}
// var POS = Positions.FindAll(posit);
if (!double.IsNaN(S2.liq_ONE.Last(1)) == true)
foreach (var position in Positions)
{
n += 1;
string LIQ = "liq " + n;
ClosePosition(position);
Print("LIQ ", Bars.Count, " ", S2.liq_ONE, " ", LIQ);
}
}
}
}
@BJORNBERNAU
PanagiotisCharalampous
25 Feb 2022, 13:09
Hi Björn,
Which position is this? Dates are not visible. Also did you notice that you use a stop loss in your code?
Best Regards,
Panagiotis
Join us on Telegram and Facebook
@PanagiotisCharalampous
BJORNBERNAU
25 Feb 2022, 14:17
RE:
PanagiotisCharalampous said:
Hi Björn,
Which position is this? Dates are not visible. Also did you notice that you use a stop loss in your code?
Best Regards,
Panagiotis
17 o'clock 31 jan 2022.
It now seems to work.
Yes, you're right. I missed the 50 stoploss. It works!
Thank you for this clear guidance, I wish you a nice weekend!
@BJORNBERNAU
PanagiotisCharalampous
22 Feb 2022, 17:20
Hi Bjorn,
Your problem has nothing to do with lazy loading. Instead this happens because of a poorly programmed indicator. You problem is here.
You cannot do this since the Calculate is called many times during a current candle's life. It is clearly described here. This variable will just produce nonsense. What you actually need to do is to keep the state of the last selection. Here is a very rough solution. The code is still poor but I do not have the time to rewrite the entire indicator. It's just an example of how you need to handle this
Here is the full source code
and here are the results
Best Regards,
Panagiotis
Join us on Telegram and Facebook
@PanagiotisCharalampous