Good Project But so slow
Good Project But so slow
12 Dec 2023, 21:43
Hello, I have developed this indicator, and I would like to know if there is a different way that consumes fewer resources to increase speed. (trendline issue)
All the code here :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class STOCHALLINONELoadMore : Indicator
{
//[Parameter("Nbrs Stoch Load ", DefaultValue = 28, Group = " Ribbon/BarsColors Setting")]
//public int NbrsStochLoad { get; set; }
[Parameter("Percent K", DefaultValue = 9, Group = "Stoch Setting")]
public int PeriodK { get; set; }
[Parameter("Percent K", DefaultValue = 3, Group = "Stoch Setting")]
public int PeriodD { get; set; }
[Parameter("Percent K", DefaultValue = 9, Group = "Stoch Setting")]
public int KSlowing { get; set; }
[Parameter("Nbrs Stoch Load", DefaultValue = 25, Group = "Nbrs Load")]
public int StochLoad { get; set; }
[Parameter("Periods Multi STOCH ", DefaultValue = 1.1, Group = "Nbrs Load")]
public double PeriodsMulti { get; set; }
[Parameter("Extra Level", DefaultValue = 80, Group = "Extra Level")]
public int HighLevel { get; set; }
[Parameter("Extra Level", DefaultValue = 20, Group = "Extra Level")]
public int LowLevel { get; set; }
[Output("Result", PlotType = PlotType.Line, LineColor = "Green", Thickness = 1)]
public IndicatorDataSeries Result { get; set; }
[Output("Signal", PlotType = PlotType.Line, LineColor = "Red", Thickness = 1)]
public IndicatorDataSeries Signal { get; set; }
private StochasticOscillator[] stoch;
private IndicatorDataSeries[] resK, resD;
public IndicatorDataSeries totalLoad;
private int[] periodsStoch;
private double resIndicatorK, resIndicatorD, load;
protected override void Initialize()
{
resK = new IndicatorDataSeries[StochLoad];
resD = new IndicatorDataSeries[StochLoad];
stoch = new StochasticOscillator[StochLoad];
periodsStoch = new int[StochLoad];
totalLoad = CreateDataSeries();
resIndicatorK = 0.00;
resIndicatorD = 0.00;
load = 100 / StochLoad;
for (int i = 0; i < resK.Length; i++)
{
periodsStoch[i] = (int)(Math.Round(Math.Pow(PeriodsMulti, i) * PeriodK));
resK[i] = CreateDataSeries();
resD[i] = CreateDataSeries();
stoch[i] = Indicators.StochasticOscillator(Bars, periodsStoch[i], PeriodD, KSlowing, MovingAverageType.Simple);
}
}
public override void Calculate(int index)
{
resIndicatorK = 0.00;
resIndicatorD = 0.00;
for (int i = 0; i < resK.Length; i++)
{
resK[i][index] = stoch[i].PercentK[index];
resD[i][index] = stoch[i].PercentD[index];
if (!double.IsNaN(resK[i][index]))
{
if (resK[i][index] >= 80)
{
if (IndicatorArea.FindObject("stoch" + i + index) != null)
IndicatorArea.RemoveObject("stoch" + i + index);
IndicatorArea.DrawTrendLine("stoch" + i + index, index, i * load, index - 1, i * load, Color.FromArgb(100, "8901FF01"), 5, LineStyle.DotsVeryRare);
}
else if (resK[i][index] < 80 && resK[i][index] >= 50)
{
if (IndicatorArea.FindObject("stoch" + i + index) != null)
IndicatorArea.RemoveObject("stoch" + i + index);
IndicatorArea.DrawTrendLine("stoch" + i + index, index, i * load, index - 1, i * load, Color.FromArgb(100,"8C02AFF1"), 5, LineStyle.DotsVeryRare);
}
else if (resK[i][index] < 50 && resK[i][index] >= 20)
{
if (IndicatorArea.FindObject("stoch" + i + index) != null)
IndicatorArea.RemoveObject("stoch" + i + index);
IndicatorArea.DrawTrendLine("stoch" + i + index, index, i * load, index - 1, i * load, Color.FromArgb(100,"A3FF6000"), 5, LineStyle.DotsVeryRare);
}
else if (resK[i][index] < 20)
{
if (IndicatorArea.FindObject("stoch" + i + index) != null)
IndicatorArea.RemoveObject("stoch" + i + index);
IndicatorArea.DrawTrendLine("stoch" + i + index, index, i * load, index - 1, i * load, Color.FromArgb(100,"A3FF6000"), 5, LineStyle.DotsVeryRare);
}
resIndicatorK += resK[i][index];
resIndicatorD += resD[i][index];
}
}
if (index == periodsStoch[resK.Length - 1])
IndicatorArea.DrawVerticalLine("StartIndicator" + index, index, "8901FF01", 5, LineStyle.DotsVeryRare);
Result[index] = (resIndicatorK / StochLoad);
Signal[index] = (resIndicatorD / StochLoad);
}
}
}
Replies
YesOrNot
16 Dec 2023, 09:38
RE: Limit the calculation to recent Bars only
MehranM said:
You can limit the calculation to recent bars to make it feasible. Here is the code I suggest:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class STOCHALLINONELoadMore : Indicator
{
//[Parameter("Nbrs Stoch Load ", DefaultValue = 28, Group = " Ribbon/BarsColors Setting")]
//public int NbrsStochLoad { get; set; }
[Parameter("Percent K", DefaultValue = 9, Group = "Stoch Setting")]
public int PeriodK { get; set; }
[Parameter("Percent K", DefaultValue = 3, Group = "Stoch Setting")]
public int PeriodD { get; set; }
[Parameter("Percent K", DefaultValue = 9, Group = "Stoch Setting")]
public int KSlowing { get; set; }
[Parameter("Nbrs Stoch Load", DefaultValue = 25, Group = "Nbrs Load")]
public int StochLoad { get; set; }
[Parameter("Periods Multi STOCH ", DefaultValue = 1.1, Group = "Nbrs Load")]
public double PeriodsMulti { get; set; }
[Parameter("Extra Level", DefaultValue = 80, Group = "Extra Level")]
public int HighLevel { get; set; }
[Parameter("Extra Level", DefaultValue = 20, Group = "Extra Level")]
public int LowLevel { get; set; }
[Output("Result", PlotType = PlotType.Line, LineColor = "Green", Thickness = 1)]
public IndicatorDataSeries Result { get; set; }
[Output("Signal", PlotType = PlotType.Line, LineColor = "Red", Thickness = 1)]
public IndicatorDataSeries Signal { get; set; }
[Parameter("Extend Calculation", DefaultValue = 10)]
public int ExtendCalculation { get; set; }
private StochasticOscillator[] stoch;
private IndicatorDataSeries[] resK, resD;
public IndicatorDataSeries totalLoad;
private int[] periodsStoch;
private double resIndicatorK, resIndicatorD, load;
protected override void Initialize()
{
resK = new IndicatorDataSeries[StochLoad];
resD = new IndicatorDataSeries[StochLoad];
stoch = new StochasticOscillator[StochLoad];
periodsStoch = new int[StochLoad];
totalLoad = CreateDataSeries();
resIndicatorK = 0.00;
resIndicatorD = 0.00;
load = 100 / StochLoad;
for (int i = 0; i < resK.Length; i++)
{
periodsStoch[i] = (int)(Math.Round(Math.Pow(PeriodsMulti, i) * PeriodK));
resK[i] = CreateDataSeries();
resD[i] = CreateDataSeries();
stoch[i] = Indicators.StochasticOscillator(Bars, periodsStoch[i], PeriodD, KSlowing, MovingAverageType.Simple);
}
}
public override void Calculate(int index)
{
if (index > Chart.FirstVisibleBarIndex - ExtendCalculation || ExtendCalculation >= 1000)
{
resIndicatorK = 0.00;
resIndicatorD = 0.00;
for (int i = 0; i < resK.Length; i++)
{
resK[i][index] = stoch[i].PercentK[index];
resD[i][index] = stoch[i].PercentD[index];
if (!double.IsNaN(resK[i][index]))
{
if (resK[i][index] >= 80)
{
if (IndicatorArea.FindObject("stoch" + i + index) != null)
IndicatorArea.RemoveObject("stoch" + i + index);
IndicatorArea.DrawTrendLine("stoch" + i + index, index, i * load, index - 1, i * load, Color.FromArgb(100, "8901FF01"), 5, LineStyle.DotsVeryRare);
}
else if (resK[i][index] < 80 && resK[i][index] >= 50)
{
if (IndicatorArea.FindObject("stoch" + i + index) != null)
IndicatorArea.RemoveObject("stoch" + i + index);
IndicatorArea.DrawTrendLine("stoch" + i + index, index, i * load, index - 1, i * load, Color.FromArgb(100, "8C02AFF1"), 5, LineStyle.DotsVeryRare);
}
else if (resK[i][index] < 50 && resK[i][index] >= 20)
{
if (IndicatorArea.FindObject("stoch" + i + index) != null)
IndicatorArea.RemoveObject("stoch" + i + index);
IndicatorArea.DrawTrendLine("stoch" + i + index, index, i * load, index - 1, i * load, Color.FromArgb(100, "A3FF6000"), 5, LineStyle.DotsVeryRare);
}
else if (resK[i][index] < 20)
{
if (IndicatorArea.FindObject("stoch" + i + index) != null)
IndicatorArea.RemoveObject("stoch" + i + index);
IndicatorArea.DrawTrendLine("stoch" + i + index, index, i * load, index - 1, i * load, Color.FromArgb(100, "A3FF6000"), 5, LineStyle.DotsVeryRare);
}
resIndicatorK += resK[i][index];
resIndicatorD += resD[i][index];
}
}
if (index == periodsStoch[resK.Length - 1])
IndicatorArea.DrawVerticalLine("StartIndicator" + index, index, "8901FF01", 5, LineStyle.DotsVeryRare);
Result[index] = (resIndicatorK / StochLoad);
Signal[index] = (resIndicatorD / StochLoad);
}
}
}
}
Thx for response but the objective et to have the all data in 1 sec… (1000 indicator load)
firemyst
27 Dec 2023, 12:21
Here are some tips to get you started
Looking at the code, I see a lot of repetitive stuff that you should eliminate to reduce CPU and memory operations.
For starters:
1) you have "i * load" all over the place. That wastes at least 3 CPU cycles to reference i, reference load, and then do the multiplication. Do "i * load" ONCE at the start of the loop, save it into a local variable (that will be saved in faster memory access), and use that throughout.
2) same thing with "index - 1". Create a local variable int indexMinus1 and assign "index - 1" to it. Then use that local variable everywhere instead of having the calculation repeated over and over and over
3) Color.FromArgb(100, "A3FF6000"). Again geezsus. Set the color once in a local variable and reference that where needed instead of having the system to call that function over and over and over.
4) "stoch" + i + index : strings are immutable objects. Every time you do this, the CPU has to waste cycles creating a new string object in memory, storing it in memory, and then referencing it. Create another local variable, set it once, and then reference it throughout code. Ex: string strIdentifier = "stoch" + i + index; There. It's done once, and you've just freed up not only constant memory operations but also multiple CPU cycles.
@firemyst
YesOrNot
07 Jan 2024, 02:35
RE: Here are some tips to get you started
firemyst said:
Looking at the code, I see a lot of repetitive stuff that you should eliminate to reduce CPU and memory operations.
For starters:
1) you have "i * load" all over the place. That wastes at least 3 CPU cycles to reference i, reference load, and then do the multiplication. Do "i * load" ONCE at the start of the loop, save it into a local variable (that will be saved in faster memory access), and use that throughout.
2) same thing with "index - 1". Create a local variable int indexMinus1 and assign "index - 1" to it. Then use that local variable everywhere instead of having the calculation repeated over and over and over
3) Color.FromArgb(100, "A3FF6000"). Again geezsus. Set the color once in a local variable and reference that where needed instead of having the system to call that function over and over and over.
4) "stoch" + i + index : strings are immutable objects. Every time you do this, the CPU has to waste cycles creating a new string object in memory, storing it in memory, and then referencing it. Create another local variable, set it once, and then reference it throughout code. Ex: string strIdentifier = "stoch" + i + index; There. It's done once, and you've just freed up not only constant memory operations but also multiple CPU cycles.
Hi Hi! Thanks for the help. I just made it, but it doesn't deserve. I think the problem is plotting points, not the memory operations…
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class STOCHALLINONELoadMore : Indicator
{
//[Parameter("Nbrs Stoch Load ", DefaultValue = 28, Group = " Ribbon/BarsColors Setting")]
//public int NbrsStochLoad { get; set; }
[Parameter("Percent K", DefaultValue = 9, Group = "Stoch Setting")]
public int PeriodK { get; set; }
[Parameter("Percent K", DefaultValue = 3, Group = "Stoch Setting")]
public int PeriodD { get; set; }
[Parameter("Percent K", DefaultValue = 9, Group = "Stoch Setting")]
public int KSlowing { get; set; }
[Parameter("Nbrs Stoch Load", DefaultValue = 25, Group = "Nbrs Load")]
public int StochLoad { get; set; }
[Parameter("Periods Multi STOCH ", DefaultValue = 1.1, Group = "Nbrs Load")]
public double PeriodsMulti { get; set; }
[Parameter("Extra Level", DefaultValue = 80, Group = "Extra Level")]
public int HighLevel { get; set; }
[Parameter("Extra Level", DefaultValue = 20, Group = "Extra Level")]
public int LowLevel { get; set; }
[Output("Result", PlotType = PlotType.Line, LineColor = "Green", Thickness = 1)]
public IndicatorDataSeries Result { get; set; }
[Output("Signal", PlotType = PlotType.Line, LineColor = "Red", Thickness = 1)]
public IndicatorDataSeries Signal { get; set; }
private StochasticOscillator[] stoch;
private IndicatorDataSeries[] resK, resD;
public IndicatorDataSeries totalLoad;
private int[] periodsStoch;
private double resIndicatorK, resIndicatorD, load;
private Color colohigh, colomhigh, cololow, colomlow;
protected override void Initialize()
{
resK = new IndicatorDataSeries[StochLoad];
resD = new IndicatorDataSeries[StochLoad];
stoch = new StochasticOscillator[StochLoad];
periodsStoch = new int[StochLoad];
totalLoad = CreateDataSeries();
colohigh = Color.FromArgb(100, "8901FF01");
colomhigh = Color.FromArgb(100, "8C02AFF1");
cololow = Color.FromArgb(100, "A3FF6000");
colomlow = Color.FromArgb(100, "A3FF6000");
resIndicatorK = 0.00;
resIndicatorD = 0.00;
load = 100 / StochLoad;
for (int i = 0; i < resK.Length; i++)
{
periodsStoch[i] = (int)(Math.Round(Math.Pow(PeriodsMulti, i) * PeriodK));
resK[i] = CreateDataSeries();
resD[i] = CreateDataSeries();
stoch[i] = Indicators.StochasticOscillator(Bars, periodsStoch[i], PeriodD, KSlowing, MovingAverageType.Simple);
}
}
public override void Calculate(int index)
{
resIndicatorK = 0.00;
resIndicatorD = 0.00;
int indiM1 = index - 1;
for (int i = 0; i < resK.Length; i++)
{
string obj = "stoch" + i + index;
double iLoad = i * load;
resK[i][index] = stoch[i].PercentK[index];
resD[i][index] = stoch[i].PercentD[index];
if (!double.IsNaN(resK[i][index]))
{
if (resK[i][index] >= 80)
{
if (IndicatorArea.FindObject(obj) != null)
IndicatorArea.RemoveObject(obj);
IndicatorArea.DrawTrendLine(obj, index, iLoad, indiM1, iLoad, colohigh, 5, LineStyle.DotsVeryRare);
}
else if (resK[i][index] < 80 && resK[i][index] >= 50)
{
if (IndicatorArea.FindObject(obj) != null)
IndicatorArea.RemoveObject(obj);
IndicatorArea.DrawTrendLine(obj, index, iLoad, indiM1, iLoad, colomhigh, 5, LineStyle.DotsVeryRare);
}
else if (resK[i][index] < 50 && resK[i][index] >= 20)
{
if (IndicatorArea.FindObject(obj) != null)
IndicatorArea.RemoveObject(obj);
IndicatorArea.DrawTrendLine(obj, index, iLoad, indiM1, iLoad, cololow, 5, LineStyle.DotsVeryRare);
}
else if (resK[i][index] < 20)
{
if (IndicatorArea.FindObject(obj) != null)
IndicatorArea.RemoveObject(obj);
IndicatorArea.DrawTrendLine(obj, index, iLoad, indiM1, iLoad, colomlow, 5, LineStyle.DotsVeryRare);
}
resIndicatorK += resK[i][index];
resIndicatorD += resD[i][index];
}
}
if (index == periodsStoch[resK.Length - 1])
IndicatorArea.DrawVerticalLine("StartIndicator" + index, index, colohigh, 5, LineStyle.DotsVeryRare);
Result[index] = (resIndicatorK / StochLoad);
Signal[index] = (resIndicatorD / StochLoad);
}
}
}
firemyst
07 Jan 2024, 02:52
RE: RE: Here are some tips to get you started
YesOrNot said:
Hi Hi! Thanks for the help. I just made it, but it doesn't deserve. I think the problem is plotting points, not the memory operations…
Great to see the big code improvements!
That's just the start as I said.
cTrader wasn't built well enough to handle all the custom drawn objects like other trading platforms.
What I've done as a work around is included parameters in my indicators to state how far back I want items drawn:
[Parameter("Num of Bars Back to Analyze", Group = "Misc", DefaultValue = 500, MinValue = 1)]
public int NumBarsBackToAnalyze { get; set; }
Then what I do is every time a new bar is formed, I programmatically remove all the custom drawn objects that are more than “NumBarsBackToAnalyze
”.
So in the example above, when a new bar is formed, if I have any custom drawn objects on the chart more than 500 bars ago, I delete them.
It's a rolling process, keeps cTrader somewhat responsive. However, because it's a heavy burden, I only do it once every time a new bar is formed – it's a waste of resources to do it every tick.
@firemyst
MehranM
13 Dec 2023, 12:21 ( Updated at: 14 Dec 2023, 06:43 )
Limit the calculation to recent Bars only
You can limit the calculation to recent bars to make it feasible. Here is the code I suggest:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class STOCHALLINONELoadMore : Indicator
{
//[Parameter("Nbrs Stoch Load ", DefaultValue = 28, Group = " Ribbon/BarsColors Setting")]
//public int NbrsStochLoad { get; set; }
[Parameter("Percent K", DefaultValue = 9, Group = "Stoch Setting")]
public int PeriodK { get; set; }
[Parameter("Percent K", DefaultValue = 3, Group = "Stoch Setting")]
public int PeriodD { get; set; }
[Parameter("Percent K", DefaultValue = 9, Group = "Stoch Setting")]
public int KSlowing { get; set; }
[Parameter("Nbrs Stoch Load", DefaultValue = 25, Group = "Nbrs Load")]
public int StochLoad { get; set; }
[Parameter("Periods Multi STOCH ", DefaultValue = 1.1, Group = "Nbrs Load")]
public double PeriodsMulti { get; set; }
[Parameter("Extra Level", DefaultValue = 80, Group = "Extra Level")]
public int HighLevel { get; set; }
[Parameter("Extra Level", DefaultValue = 20, Group = "Extra Level")]
public int LowLevel { get; set; }
[Output("Result", PlotType = PlotType.Line, LineColor = "Green", Thickness = 1)]
public IndicatorDataSeries Result { get; set; }
[Output("Signal", PlotType = PlotType.Line, LineColor = "Red", Thickness = 1)]
public IndicatorDataSeries Signal { get; set; }
[Parameter("Extend Calculation", DefaultValue = 10)]
public int ExtendCalculation { get; set; }
private StochasticOscillator[] stoch;
private IndicatorDataSeries[] resK, resD;
public IndicatorDataSeries totalLoad;
private int[] periodsStoch;
private double resIndicatorK, resIndicatorD, load;
protected override void Initialize()
{
resK = new IndicatorDataSeries[StochLoad];
resD = new IndicatorDataSeries[StochLoad];
stoch = new StochasticOscillator[StochLoad];
periodsStoch = new int[StochLoad];
totalLoad = CreateDataSeries();
resIndicatorK = 0.00;
resIndicatorD = 0.00;
load = 100 / StochLoad;
for (int i = 0; i < resK.Length; i++)
{
periodsStoch[i] = (int)(Math.Round(Math.Pow(PeriodsMulti, i) * PeriodK));
resK[i] = CreateDataSeries();
resD[i] = CreateDataSeries();
stoch[i] = Indicators.StochasticOscillator(Bars, periodsStoch[i], PeriodD, KSlowing, MovingAverageType.Simple);
}
}
public override void Calculate(int index)
{
if (index > Chart.FirstVisibleBarIndex - ExtendCalculation || ExtendCalculation >= 1000)
{
resIndicatorK = 0.00;
resIndicatorD = 0.00;
for (int i = 0; i < resK.Length; i++)
{
resK[i][index] = stoch[i].PercentK[index];
resD[i][index] = stoch[i].PercentD[index];
if (!double.IsNaN(resK[i][index]))
{
if (resK[i][index] >= 80)
{
if (IndicatorArea.FindObject("stoch" + i + index) != null)
IndicatorArea.RemoveObject("stoch" + i + index);
IndicatorArea.DrawTrendLine("stoch" + i + index, index, i * load, index - 1, i * load, Color.FromArgb(100, "8901FF01"), 5, LineStyle.DotsVeryRare);
}
else if (resK[i][index] < 80 && resK[i][index] >= 50)
{
if (IndicatorArea.FindObject("stoch" + i + index) != null)
IndicatorArea.RemoveObject("stoch" + i + index);
IndicatorArea.DrawTrendLine("stoch" + i + index, index, i * load, index - 1, i * load, Color.FromArgb(100, "8C02AFF1"), 5, LineStyle.DotsVeryRare);
}
else if (resK[i][index] < 50 && resK[i][index] >= 20)
{
if (IndicatorArea.FindObject("stoch" + i + index) != null)
IndicatorArea.RemoveObject("stoch" + i + index);
IndicatorArea.DrawTrendLine("stoch" + i + index, index, i * load, index - 1, i * load, Color.FromArgb(100, "A3FF6000"), 5, LineStyle.DotsVeryRare);
}
else if (resK[i][index] < 20)
{
if (IndicatorArea.FindObject("stoch" + i + index) != null)
IndicatorArea.RemoveObject("stoch" + i + index);
IndicatorArea.DrawTrendLine("stoch" + i + index, index, i * load, index - 1, i * load, Color.FromArgb(100, "A3FF6000"), 5, LineStyle.DotsVeryRare);
}
resIndicatorK += resK[i][index];
resIndicatorD += resD[i][index];
}
}
if (index == periodsStoch[resK.Length - 1])
IndicatorArea.DrawVerticalLine("StartIndicator" + index, index, "8901FF01", 5, LineStyle.DotsVeryRare);
Result[index] = (resIndicatorK / StochLoad);
Signal[index] = (resIndicatorD / StochLoad);
}
}
}
}
@MehranM