Description
Cbot for automatic trading with many indicators .... optimize your cbot with this parameters ....
with FULL SOURCE CODE
//----------------------------
I HAVE DEVELOP OTHERS POWERFULL TRADING SYSTEMS IF YOU WANT COLLABORATE TO FIND BETTER STRATEGIES YOU CAN CONTACT ME amerigo.stevani @ yahoo.com
AND I HAVE ALSO THE SAME TRADING SYSTEM VERSION WITH HEDGING....
//----------------------------
below some optimizations
Normal PIPS 0; 6
Reverse PIPS -0.2; 6
Ratio Breakout 0; 1
Ratio SLTP 0; 1
Reverse Ratio 0.5; 2
Adx Skip Range: 5; 20
Max Position 1; 5
Quantity Ratio : is a Ratio Factor for volume when there is also the stocastic signal
//----------------------------
Min Range, Max Range.... try in backtesting in the log there is write avg sigma....
- Min Range avg-sigma.
- Max Range avg+sigma
For others parameters use this defaults
five minute ottimization on 2017-2018 eurusd
Optimization Lot 1 eurusd 1M 2017-2019 .....
Example with start balance 1000€ and trading with 0.5 lot in 2 years from 1/1/2017 to 31/12/2018 2450% profit... starting from 1000€ ending with 25496.58€
// -------------------------------------------------------------------------------------------------
//
// RSI Break out
//
//
// -------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
namespace cAlgo
{
public class StatElement
{
public int n;
public double sum;
public double max;
public double min;
public StatElement()
{
n = 0;
sum = 0;
}
public void Add(double v)
{
if (n == 0)
min = max = v;
if (v < min)
min = v;
if (v > max)
max = v;
n++;
sum += v;
}
public double avg
{
get { return sum / (n > 0 ? n : 1); }
}
}
public class StatRecord
{
public Dictionary<string, StatElement> stats;
public StatRecord()
{
stats = new Dictionary<string, StatElement>();
string[] keys =
{
"all",
"stoploss1",
"stoploss2",
"trailing",
"takeprofit"
};
foreach (var s in keys)
stats.Add(s, new StatElement());
}
public void Add(Position p, double TakeProfitPips)
{
var delta = 0.2;
string cat = "";
stats["all"].Add(p.Pips);
if (p.Pips < 0)
cat = "stoploss1";
else if (p.Pips < 2 + delta)
cat = "stoploss2";
else if (p.Pips > TakeProfitPips - delta)
cat = "takeprofit";
else
cat = "trailing";
stats[cat].Add(p.Pips);
}
public override string ToString()
{
var buf = "";
foreach (var s in stats.Keys)
{
var e = stats[s];
buf += String.Format("{0} n:{1} min:{2:0.00} max:{3:0.00} avg:{4:0.00}\r\n", s, e.n, e.min, e.max, e.avg);
}
return buf;
}
}
public class Stats
{
public Dictionary<string, StatRecord> stats;
public Stats()
{
stats = new Dictionary<string, StatRecord>();
}
public void Add(Position p, Symbol s)
{
if (!stats.ContainsKey(p.Comment))
stats.Add(p.Comment, new StatRecord());
double pips = (double)(p.TakeProfit - p.EntryPrice) / s.PipSize;
if (p.TradeType == TradeType.Sell)
pips = -pips;
stats[p.Comment].Add(p, pips);
}
public override string ToString()
{
string buf = "";
foreach (var k in stats.Keys)
{
buf += k + "\r\n";
buf += stats[k].ToString();
}
return buf;
}
}
public class ConditionalOrder
{
public TradeType orderType;
public double entryPrice;
public double stopLoss;
public double takeProfit;
public double volume;
public string remark;
public ConditionalOrder(TradeType theType, double thePrice, double theStop, double theTake, double theVolume, string rem)
{
orderType = theType;
entryPrice = thePrice;
stopLoss = theStop;
takeProfit = theTake;
volume = theVolume;
remark = rem;
}
public bool CanExecute(Symbol symbol)
{
if (orderType == TradeType.Buy)
return symbol.Ask >= entryPrice;
return symbol.Bid <= entryPrice;
}
}
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class RsiBreakout : Robot
{
[Parameter("Rsi Periods", DefaultValue = 14)]
public int RsiPeriods { get; set; }
[Parameter("Adx Periods", DefaultValue = 14)]
public int AdxPeriods { get; set; }
[Parameter("Quantity (Lots)", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
public double Quantity { get; set; }
[Parameter("Quantity Ratio", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
public double QuantityRatio { get; set; }
[Parameter("Stop Loss", DefaultValue = 0, MinValue = 0, Step = 0.1)]
public double StopLoss { get; set; }
[Parameter("Take Profit", DefaultValue = 0, MinValue = 0, Step = 0.1)]
public double TakeProfit { get; set; }
[Parameter("RSI Buy", DefaultValue = 0, MinValue = 0, Step = 1)]
public double RsiBuy { get; set; }
[Parameter("RSI Band", DefaultValue = 0, MinValue = 0, Step = 1)]
public double RsiBand { get; set; }
[Parameter("RSI Sell", DefaultValue = 0, MinValue = 0, Step = 1)]
public double RsiSell { get; set; }
[Parameter("Normal Pips", DefaultValue = 0, MinValue = -2.0, Step = 0.1)]
public double NormalPips { get; set; }
[Parameter("Reverse Pips", DefaultValue = 0, MinValue = -2.0, Step = 0.1)]
public double ReversePips { get; set; }
[Parameter("Ratio Breakout", DefaultValue = 0, MinValue = -1, Step = 0.1)]
public double RatioBreakout { get; set; }
[Parameter("Ratio SLTP", DefaultValue = 0, MinValue = -1, Step = 0.1)]
public double RatioSLTP { get; set; }
[Parameter("Reverse Ratio", DefaultValue = 0, MinValue = 0, Step = 0.1)]
public double ReverseRatio { get; set; }
[Parameter("ADX Threshold", DefaultValue = 25, MinValue = 15, Step = 0.1)]
public double ADXthreshold { get; set; }
[Parameter("FromHour", DefaultValue = 0, MinValue = 0, Step = 1)]
public double FromHour { get; set; }
[Parameter("ToHour", DefaultValue = 0, MinValue = 0, Step = 1)]
public double ToHour { get; set; }
[Parameter("Adx Skip Range", DefaultValue = 0, MinValue = 0, Step = 0.1)]
public double AdxSkip { get; set; }
[Parameter("StopLoss Span", DefaultValue = 0, MinValue = 0, Step = 0.1)]
public double StopLossSpan { get; set; }
[Parameter("Max Positions", DefaultValue = 0, MinValue = 0, Step = 1)]
public double MaxPositions { get; set; }
[Parameter("Range Min", DefaultValue = 0, MinValue = 0, Step = 1)]
public double RangeMin { get; set; }
[Parameter("Range Max", DefaultValue = 0, MinValue = 0, Step = 1)]
public double RangeMax { get; set; }
private const string label = "RsiBreakout";
private RelativeStrengthIndex rsiO;
private ExponentialMovingAverage rsi;
private DirectionalMovementSystem dms;
private StochasticOscillator sto;
private MovingAverage ma;
private ConditionalOrder[] orders = new ConditionalOrder[2];
private MarketSeries serie;
private List<DateTime> skipdate;
private double multiplier;
private Stats stats;
protected override void OnStart()
{
skipdate = new List<DateTime>();
skipdate.Add(new DateTime(2017, 1, 11));
skipdate.Add(new DateTime(2017, 6, 26));
skipdate.Add(new DateTime(2017, 7, 19));
skipdate.Add(new DateTime(2017, 8, 3));
skipdate.Add(new DateTime(2017, 8, 24));
skipdate.Add(new DateTime(2017, 9, 19));
skipdate.Add(new DateTime(2017, 10, 25));
skipdate.Add(new DateTime(2018, 1, 12));
skipdate.Add(new DateTime(2018, 1, 25));
skipdate.Add(new DateTime(2018, 2, 14));
skipdate.Add(new DateTime(2018, 2, 15));
//not over
skipdate.Add(new DateTime(2018, 2, 16));
skipdate.Add(new DateTime(2018, 6, 13));
skipdate.Add(new DateTime(2019, 1, 2));
serie = MarketSeries;
stats = new Stats();
//MarketData.GetSeries(TimeFrame);
rsiO = Indicators.RelativeStrengthIndex(serie.Close, RsiPeriods);
rsi = Indicators.ExponentialMovingAverage(rsiO.Result, (int)(RsiPeriods / 3));
dms = Indicators.DirectionalMovementSystem(AdxPeriods);
ma = Indicators.MovingAverage(serie.Close, RsiPeriods, MovingAverageType.Simple);
sto = Indicators.StochasticOscillator(RsiPeriods, 3, 3, MovingAverageType.Simple);
Positions.Closed += PositionsOnClosed;
orders[0] = null;
orders[1] = null;
multiplier = TakeProfit;
//TakeProfit = StopLoss * TakeProfit;
}
protected override void OnStop()
{
Print("npos {0}", maxpos);
double avg = sumr / countr;
double sigma = Math.Sqrt(sumsq / countr - avg * avg);
Print("maxr {0} avgr {1} minr {2} sigma {3}", maxr, avg, minr, sigma);
Print(stats.ToString());
}
private void PositionsOnClosed(PositionClosedEventArgs args)
{
var position = args.Position;
stats.Add(position, Symbol);
//trailing.Remove (position.Id);
}
private int rsiOrderZone = 0;
private bool flag = false;
private void CleanConditional(int zone = 0)
{
rsiOrderZone = zone;
for (var i = 0; i < orders.Length; i++)
orders[i] = null;
}
private bool SkipDay(DateTime day)
{
for (var i = 0; i < skipdate.Count; i++)
if (skipdate[i] == day)
return true;
return false;
}
private double range = 0;
private double minr = 300, maxr = 0, sumr = 0, countr = 0, sumsq = 0;
private double minPrice, maxPrice;
private void UpdateRange()
{
//range = 10;
//return;
//6
int periods = 30;
var hour = Server.Time.Hour;
if (hour < FromHour || hour > ToHour)
{
return;
}
maxPrice = serie.High.Maximum(periods);
minPrice = serie.Low.Minimum(periods);
range = (maxPrice - minPrice) / Symbol.PipSize / periods;
if (range < minr)
minr = range;
if (range > maxr)
maxr = range;
countr += 1;
sumr += range;
sumsq += range * range;
if (range < RangeMin)
range = RangeMin;
range = RangeMin + (range - RangeMin) / 2;
if (range > RangeMax)
range = RangeMax;
//ChartObjects.DrawText("range", range.ToString(), StaticPosition.TopLeft, Colors.LightBlue);
}
private double AdjRange(double value, double? adj = null)
{
double span = adj == null ? value : (double)(adj * value);
return value + (range - RangeMin) / (RangeMax - RangeMin) * span;
}
private double Pips(double value)
{
return value * Symbol.PipSize;
}
protected override void OnBar()
{
double price = 0;
double entryPrice = 0;
var longPosition = Positions.Find(label, Symbol, TradeType.Buy);
var shortPosition = Positions.Find(label, Symbol, TradeType.Sell);
var hour = Server.Time.Hour;
var isLong = ma.Result.LastValue < serie.Close.LastValue;
/*
var q = from d in skipdate
where d == Server.Time.Date
select d;
*/
var skip = false;
//!q.Any();
skip = SkipDay(Server.Time.Date);
skip = false;
if (skip || (Server.Time.DayOfWeek == DayOfWeek.Friday && hour >= 20))
{
if (!flag && skip)
Print("Close {0}", Server.Time.Date);
CleanConditional();
foreach (var pos in Positions.FindAll(label, Symbol))
pos.Close();
flag = true;
return;
}
flag = false;
if (false)
if (hour > 21)
{
foreach (var pos in Positions.FindAll(label, Symbol))
pos.Close();
}
if (hour < FromHour || hour > ToHour)
{
CleanConditional();
return;
}
UpdateRange();
double midlePrice = (maxPrice + minPrice) / 2;
if (range == RangeMin)
{
CleanConditional();
return;
}
if (rsiOrderZone != 0 && rsi.Result.Last(0) > RsiBuy + RsiBand && rsi.Result.Last(0) < RsiSell - RsiBand)
CleanConditional();
if (rsi.Result.Last(0) > RsiBuy && rsi.Result.Last(0) <= RsiBuy + RsiBand)
{
if (rsiOrderZone == 3)
{
//buy
CleanConditional(1);
//Symbol.Ask < midlePrice &&
if ((dms.ADX.LastValue < ADXthreshold - AdxSkip || (dms.ADX.LastValue > ADXthreshold && dms.DIPlus.LastValue > dms.DIMinus.LastValue)))
{
price = Symbol.Ask;
entryPrice = price + AdjRange(NormalPips * Symbol.PipSize, RatioBreakout);
orders[0] = new ConditionalOrder(TradeType.Buy, entryPrice, AdjRange(StopLoss, RatioSLTP), AdjRange(TakeProfit, RatioSLTP), (sto.PercentD.LastValue < 30 ? QuantityRatio : 1.0) * Quantity, "n buy");
}
}
else if (rsiOrderZone != 1)
CleanConditional();
}
if (rsi.Result.Last(0) < RsiSell && rsi.Result.Last(0) >= RsiSell - RsiBand)
{
//sell
if (rsiOrderZone == 4)
{
CleanConditional(2);
//Symbol.Ask > midlePrice &&
if ((dms.ADX.LastValue < ADXthreshold - AdxSkip || (dms.ADX.LastValue > ADXthreshold && dms.DIPlus.LastValue < dms.DIMinus.LastValue)))
{
price = Symbol.Bid;
entryPrice = price - AdjRange(NormalPips * Symbol.PipSize, RatioBreakout);
orders[0] = new ConditionalOrder(TradeType.Sell, entryPrice, AdjRange(StopLoss, RatioSLTP), AdjRange(TakeProfit, RatioSLTP), (sto.PercentD.LastValue > 70 ? QuantityRatio : 1.0) * Quantity, "n sell");
}
}
else if (rsiOrderZone != 2)
CleanConditional();
}
if (rsiOrderZone < 3 && (rsi.Result.Last(0) <= RsiBuy || rsi.Result.Last(0) >= RsiSell))
{
if (rsi.Result.Last(0) <= RsiBuy)
{
//sell
CleanConditional(3);
//!isLong
//Symbol.Ask < midlePrice &&
if ((dms.ADX.LastValue > ADXthreshold && dms.DIPlus.LastValue < dms.DIMinus.LastValue))
{
price = Symbol.Bid;
entryPrice = price - AdjRange(ReversePips * Symbol.PipSize, RatioBreakout);
orders[1] = new ConditionalOrder(TradeType.Sell, entryPrice, AdjRange(ReverseRatio * StopLoss, RatioSLTP), AdjRange(ReverseRatio * TakeProfit, RatioSLTP), (sto.PercentD.LastValue > 70 ? QuantityRatio : 1.0) * Quantity, "r sell");
}
}
else
{
//buy
CleanConditional(4);
//isLong
//Symbol.Ask > midlePrice &&
if ((dms.ADX.LastValue > ADXthreshold && dms.DIPlus.LastValue > dms.DIMinus.LastValue))
{
price = Symbol.Ask;
entryPrice = price + AdjRange(ReversePips * Symbol.PipSize, RatioBreakout);
orders[1] = new ConditionalOrder(TradeType.Buy, entryPrice, AdjRange(ReverseRatio * StopLoss, RatioSLTP), AdjRange(ReverseRatio * TakeProfit, RatioSLTP), (sto.PercentD.LastValue < 30 ? QuantityRatio : 1.0) * Quantity, "r buy");
}
}
}
}
int maxpos = 0;
protected override void OnTick()
{
//foreach (var position in Positions.FindAll (label, Symbol))
// trailing[position.Id].AdjStopLoss (Symbol, range, mSerie);
var poss = Positions.FindAll(label, Symbol);
var posBuyCount = Positions.FindAll(label, Symbol, TradeType.Buy).Length;
var posSellCount = Positions.FindAll(label, Symbol, TradeType.Sell).Length;
if (poss.Length > maxpos)
maxpos = poss.Length;
if (true)
foreach (Position pos in poss)
if (!pos.HasTrailingStop && pos.Pips > StopLossSpan)
pos.ModifyTrailingStop(true);
if (false)
foreach (Position pos in poss)
{
double midle = 0;
double sl = 0;
if (pos.TradeType == TradeType.Buy)
{
midle = (double)(pos.TakeProfit - pos.EntryPrice) / Symbol.PipSize / multiplier;
sl = pos.EntryPrice + StopLossSpan * Symbol.PipSize;
}
else
{
midle = (double)(pos.EntryPrice - pos.TakeProfit) / Symbol.PipSize / multiplier;
sl = pos.EntryPrice - StopLossSpan * Symbol.PipSize;
}
if (pos.Pips > midle && pos.StopLoss != sl)
{
//pos.ModifyVolume (pos.VolumeInUnits / 2);
pos.ModifyStopLossPrice(sl);
pos.ModifyTrailingStop(true);
//pos.ModifyTakeProfitPrice (null);
//pos.ModifyStopLossPrice(sl);
}
}
int len = orders.Length;
for (int i = 0; i < len; i++)
if (orders[i] != null)
if ((posBuyCount < MaxPositions && orders[i].orderType == TradeType.Buy) || (posSellCount < MaxPositions && orders[i].orderType == TradeType.Sell))
if (orders[i].CanExecute(Symbol))
{
var order = orders[i];
orders[i] = null;
if (false)
{
if (order.orderType == TradeType.Buy)
foreach (var p in Positions.FindAll(label, Symbol, TradeType.Sell))
p.Close();
else
foreach (var p in Positions.FindAll(label, Symbol, TradeType.Buy))
p.Close();
}
TradeResult result = ExecuteMarketOrder(order.orderType, Symbol, VolumeInUnits(order.volume), label, order.stopLoss, order.takeProfit, 0, order.remark);
if (!result.IsSuccessful)
Print("Error: {0}", result.Error);
}
}
private double VolumeInUnits(double quantity)
{
/*
double m = (int)(Account.Balance / 1000);
if (m < 1)
m = 1;
m *= Symbol.QuantityToVolumeInUnits(Quantity);
m = Symbol.NormalizeVolumeInUnits(m, RoundingMode.ToNearest);
Print("{0} {1}", Account.Balance, m);
var volume = m;
*/
//var volume = Symbol.QuantityToVolumeInUnits (Quantity);
var volume = Symbol.QuantityToVolumeInUnits(quantity);
if (volume < Symbol.VolumeInUnitsMin)
volume = Symbol.VolumeInUnitsMin;
if (volume > Symbol.VolumeInUnitsMax)
volume = Symbol.VolumeInUnitsMax;
return volume;
double size = Account.Balance * 30;
size = (int)Symbol.NormalizeVolumeInUnits(size, RoundingMode.Down);
return size;
}
}
}
astevani
Joined on 11.03.2019
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: rsibreakout.algo
- Rating: 5
- Installs: 4239
- Modified: 13/10/2021 09:54
Comments
it would be possible to encode a trailing stop there
Hi,Could someone send me a detailed description of what the settings mean, thank you
Hi Astevani,
need to develop few cBOTS... I know basic programming but for these cBOT need some professional help. I am willing to pay also and not looking for some free service.
Please contact me on skhan.projects@gmail.com
thank you
GoldnOil
The skip days are disabled .... so no day is skipped .... you can try on tick data.....
can someone copy paste this code below and remove the skipped dates in this code so it back tests every tick data instead of skipping the days on the list
Hi Luigi,
you can use 2 years o 3-4 year until ending 2018 for optimization and all the 2019 for back testing ... in this way some systems that i have optimized will win...
i think that 50 of commision and 2 pips of spread are too much... but the systems are working again....
Hi Astevani,
thanks for the bot !
Actually in the last backtest with the suggested parameters , same period, it gives me the same result as yours.
Testing it OutSample it does'nt work which means that the parameters are overfitted.
2 years test is not enough you should test it for minimum 5 years.
Setting the Backtest and Optimization you should put the Commission to 50 and the spread to minimum 2 pips as you should reduce the impact of Slippage on real. With these settings in the same period the result is negative.
I think that this bot in optimization will produce allways overfitted results as there are too many parameters which means that when you backtest it OutSample will produce drastically different results.
during the optimization some days that have spikes, big spikes, let's the optimization process to learn where are the spikes because in that days you earn more. But that spikes don't return in the futures.....
so all parameters are calculates only to get the spikes...
for a good optimization need clean data... the best is clean the data knowing the history of exceptional facts
Ok, There is no particular reason that his days have "weird" results.
For the robot without without source code this can be a real problem because you dont know if you buy a robot with the pair history inside..... so in backtesting and optimization this robots can win many trade only because they have the history of the pair inside and when you use the trading system on real market the robot will fail....
buy a robot without source code and only on backtest is like believe in santa claus...
skipdate = new List<DateTime>();
skipdate.Add(new DateTime(2017, 1, 11));
skipdate.Add(new DateTime(2017, 6, 26));
skipdate.Add(new DateTime(2017, 7, 19));
skipdate.Add(new DateTime(2017, 8, 3));
skipdate.Add(new DateTime(2017, 8, 24));
skipdate.Add(new DateTime(2017, 9, 19));
skipdate.Add(new DateTime(2017, 10, 25));
skipdate.Add(new DateTime(2018, 1, 12));
skipdate.Add(new DateTime(2018, 1, 25));
skipdate.Add(new DateTime(2018, 2, 14));
skipdate.Add(new DateTime(2018, 2, 15));
//not over
skipdate.Add(new DateTime(2018, 2, 16));
skipdate.Add(new DateTime(2018, 6, 13));
skipdate.Add(new DateTime(2019, 1, 2));
This are the days that i skip in the first version of robot for EURUSD.....
For the robot without without source code this can be a real problem because you dont know if you buy a robot with the pair history inside..... so in backtesting and optimization this robots can win many trade only because they have the history of the pair inside and when you use the trading system on real market the robot will fail....
In the first version of the robot, the robot win easy trade in that days. So I try to skip that days in the optimization to make a better optimization. In the source code, now, is disable. So all the days are used. If you want you can check that days and you will see that in that days there is strange volatility.
Hello,
Can you explain this in your code?
-
{
skipdate = new List<DateTime>();
skipdate.Add(new DateTime(2017, 1, 11));
skipdate.Add(new DateTime(2017, 6, 26));
skipdate.Add(new DateTime(2017, 7, 19));
skipdate.Add(new DateTime(2017, 8, 3));
skipdate.Add(new DateTime(2017, 8, 24));
skipdate.Add(new DateTime(2017, 9, 19));
skipdate.Add(new DateTime(2017, 10, 25));
skipdate.Add(new DateTime(2018, 1, 12));
skipdate.Add(new DateTime(2018, 1, 25));
skipdate.Add(new DateTime(2018, 2, 14));
skipdate.Add(new DateTime(2018, 2, 15));
//not over
skipdate.Add(new DateTime(2018, 2, 16));
skipdate.Add(new DateTime(2018, 6, 13));
skipdate.Add(new DateTime(2019, 1, 2));
serie = MarketSeries;
stats = new Stats();
//MarketData.GetSeries(TimeFrame);
rsiO = Indicators.RelativeStrengthIndex(serie.Close, RsiPeriods);
rsi = Indicators.ExponentialMovingAverage(rsiO.Result, (int)(RsiPeriods / 3));
dms = Indicators.DirectionalMovementSystem(AdxPeriods);
ma = Indicators.MovingAverage(serie.Close, RsiPeriods, MovingAverageType.Simple);
sto = Indicators.StochasticOscillator(RsiPeriods, 3, 3, MovingAverageType.Simple);
Positions.Closed += PositionsOnClosed;
orders[0] = null;
orders[1] = null;
multiplier = TakeProfit;
//TakeProfit = StopLoss * TakeProfit;
}
This optimization work no so bad :)
[ChartParameters]
Symbol = EURUSD
Timeframe = m1
[cBotParameters]
RsiPeriods = 9
AdxPeriods = 30
Quantity = 0.5
QuantityRatio = 1.3
StopLoss = 50
TakeProfit = 40
RsiBuy = 32
RsiBand = 10
RsiSell = 72
NormalPips = 2
ReversePips = -0.2
RatioBreakout = 1
RatioSLTP = -0.6
ReverseRatio = 1.5
ADXthreshold = 30
FromHour = 3
ToHour = 15
AdxSkip = 10
StopLossSpan = 15
MaxPositions = 4
RangeMin = 0.1
RangeMax = 0.7
Have you some ideas for an improvement?
Thank you very much. I achieved 100% daily profit with this strategy