difference results between optimisation and backtesting

Created at 11 Mar 2019, 05:07
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
AS

astevani

Joined 11.03.2019

difference results between optimisation and backtesting
11 Mar 2019, 05:07


Hi

i am developing a ctrader robot but i am falling in a problem with the results of optimization and backtesting, the two operation show different trading system behavior in optimization and in backtesting, different trades, different gains....

the robot use two timeframes, may be this is the problem.....

can somebody tell me how to fix the problem....

here the bot....

 

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 TrailingStopLossParams {

public Position position;

public bool isTrailing;

public double highestGain;

public double triggerWhenGaining;

public double trailingStopLossDistance;

public double takeProfit;

public double stopLoss;

public Robot robot;

 

public TrailingStopLossParams (Robot theRobot, string theLabel, Symbol symbol, TradeType tradeType, double volume, double theTakeProfit, double theStopLoss) {

robot = theRobot;

isTrailing = false;

highestGain = 0;

takeProfit = theTakeProfit;

stopLoss = theStopLoss;

triggerWhenGaining = takeProfit;

trailingStopLossDistance = takeProfit / 2;

position = robot.ExecuteMarketOrder (tradeType, symbol, volume, theLabel).Position;

 

if (tradeType == TradeType.Buy)

robot.ModifyPosition (position, symbol.Ask - (symbol.PipSize * stopLoss), null);

else

robot.ModifyPosition (position, symbol.Bid + (symbol.PipSize * stopLoss), null);

}

 

public void AdjStopLoss (Symbol symbol, double range, MarketSeries serie, int periods) {

// not used in this context

if (false) {

if (position.TradeType == TradeType.Buy) {

double low = serie.Low.Minimum (periods);

if (low > position.StopLoss && (symbol.Ask > low && (symbol.Ask - low) / symbol.PipSize >= trailingStopLossDistance))

robot.ModifyPosition (position, low, null);

} else {

double high = serie.High.Maximum (periods);

if (high < position.StopLoss && (symbol.Bid < high && (high - symbol.Bid) / symbol.PipSize >= trailingStopLossDistance))

robot.ModifyPosition (position, high, null);

}

}

 

if (!isTrailing && position.Pips >= triggerWhenGaining)

isTrailing = true;

 

if (isTrailing && highestGain < position.Pips) {

if (position.TradeType == TradeType.Buy) {

var newSLprice = symbol.Ask - (symbol.PipSize * trailingStopLossDistance);

if (newSLprice > position.StopLoss)

robot.ModifyPosition (position, newSLprice, null);

} else {

var newSLprice = symbol.Bid + (symbol.PipSize * trailingStopLossDistance);

if (newSLprice < position.StopLoss)

robot.ModifyPosition (position, newSLprice, null);

}

highestGain = position.Pips;

}

}

}

 

[Robot (TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]

public class AmeReverse_2 : Robot {

[Parameter ("Vol Period", DefaultValue = 14)]

public int VolPeriod { get; set; }

 

[Parameter ("Quantity (Lots)", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]

public double Quantity { get; set; }

 

[Parameter ("Long Stop Loss Reverse", DefaultValue = 0, MinValue = 0, Step = 0.1)]

public double LongReverseStopLoss { get; set; }

 

[Parameter ("Long Take Profit Reverse", DefaultValue = 0, MinValue = 0, Step = 0.1)]

public double LongReverseTakeProfit { get; set; }

 

[Parameter ("Long Stop Loss", DefaultValue = 0, MinValue = 0, Step = 0.1)]

public double LongNormalStopLoss { get; set; }

 

[Parameter ("Long Take Profit", DefaultValue = 0, MinValue = 0, Step = 0.1)]

public double LongNormalTakeProfit { get; set; }

 

[Parameter ("Short Stop Loss Reverse", DefaultValue = 0, MinValue = 0, Step = 0.1)]

public double ShortReverseStopLoss { get; set; }

 

[Parameter ("Short Take Profit Reverse", DefaultValue = 0, MinValue = 0, Step = 0.1)]

public double ShortReverseTakeProfit { get; set; }

 

[Parameter ("Short Stop Loss", DefaultValue = 0, MinValue = 0, Step = 0.1)]

public double ShortNormalStopLoss { get; set; }

 

[Parameter ("Short Take Profit", DefaultValue = 0, MinValue = 0, Step = 0.1)]

public double ShortNormalTakeProfit { get; set; }

 

[Parameter ("Thresold Red", DefaultValue = 0, MinValue = 0, Step = 0.1)]

public double ThresoldRed { get; set; }

 

[Parameter ("Thresold Green", DefaultValue = 0, MinValue = 0, Step = 0.1)]

public double ThresoldGreen { get; set; }

 

[Parameter ("Search Deep", DefaultValue = 30, MinValue = 6, Step = 1)]

public int SearchDeep { get; set; }

 

[Parameter ("Long RSI Buy", DefaultValue = 30, MinValue = 10, Step = 0.5)]

public double LongRsiBuy { get; set; }

 

[Parameter ("Long RSI Sell", DefaultValue = 70, MinValue = 60, Step = 0.5)]

public double LongRsiSell { get; set; }

 

[Parameter ("Short RSI Buy", DefaultValue = 30, MinValue = 10, Step = 0.5)]

public double ShortRsiBuy { get; set; }

 

[Parameter ("Short RSI Sell", DefaultValue = 70, MinValue = 60, Step = 0.5)]

public double ShortRsiSell { get; set; }

 

[Parameter ("Volatility Ratio", DefaultValue = 0.5, MinValue = 0.2, Step = 0.1)]

public double VolatilityRatio { get; set; }

 

[Parameter ("MA Long Periods", DefaultValue = 24, MinValue = 12, Step = 1)]

public int MALongPeriods { get; set; }

 

[Parameter ("AdjStopLossPeriods", DefaultValue = 10, MinValue = 4, Step = 1)]

public int AdjStopLossPeriods { get; set; }

 

private const string label = "Reverse2";

private MovingAverage mMaLong;

private MovingAverage mMaShort;

private MovingAverage mMaLong2;

private MovingAverage mMaShort2;

private RelativeStrengthIndex mRsi;

private int forcedClosed = 0;

private double forsedClosedPL = 0.0;

private Dictionary<int, TrailingStopLossParams> trailing;

private int sameTime = 0;

private MarketSeries mSerie;

private double range = 0;

private MarketSeries mMonthly;

protected override void OnStart () {

mMonthly = MarketData.GetSeries (TimeFrame.Monthly);

mMaShort = Indicators.MovingAverage (mMonthly.Close, 6, MovingAverageType.Simple);

mMaLong = Indicators.MovingAverage (mMonthly.Close, 12, MovingAverageType.Exponential);

mSerie = MarketData.GetSeries (TimeFrame.Minute3);

mMaShort2 = Indicators.MovingAverage (mSerie.Close, 6, MovingAverageType.Simple);

mMaLong2 = Indicators.MovingAverage (mSerie.Close, MALongPeriods, MovingAverageType.Exponential);

trailing = new Dictionary<int, TrailingStopLossParams> ();

mRsi = Indicators.RelativeStrengthIndex (mSerie.Close, VolPeriod);

Positions.Closed += PositionsOnClosed;

UpdateRange ();

}

 

protected override void OnStop () {

Print ("sameTime max:{0}", sameTime);

Print ("#{0}, ${1}", forcedClosed, forsedClosedPL);

}

 

private void PositionsOnClosed (PositionClosedEventArgs args) {

var position = args.Position;

trailing.Remove (position.Id);

}

private void UpdateRange () {

range = (mSerie.High.Maximum (20) - mSerie.Low.Minimum (20)) / Symbol.PipSize;

//ChartObjects.DrawText("range", range.ToString(), StaticPosition.TopLeft, Colors.LightBlue);

}

 

protected override void OnBar () {

UpdateRange ();

 

var longPosition = Positions.Find (label, Symbol, TradeType.Buy);

var shortPosition = Positions.Find (label, Symbol, TradeType.Sell);

 

var currentHours = Server.Time.TimeOfDay.TotalHours;

//bool tradeTime = StartTime < StopTime ? currentHours > StartTime && currentHours < StopTime : currentHours < StopTime || currentHours > StartTime;

bool pastNine = currentHours > 21.0;

 

if (Server.Time.DayOfWeek == DayOfWeek.Friday && pastNine) {

foreach (var pos in Positions.FindAll (label, Symbol))

ClosePosition (pos);

 

return;

}

 

//Print("{0}", mPips.Result.Last(0), VolatilityRatio);

 

if (range < VolatilityRatio)

return;

 

//if(longPosition!=null || shortPosition!=null)

// return;

bool buySignal = mMaLong.Result.Last (0) < mMaShort.Result.Last (0);

bool buySignal2 = mMaLong2.Result.Last (0) < mMaShort2.Result.Last (0);

bool sellSignal = !buySignal;

double RsiBuy = buySignal ? LongRsiBuy : ShortRsiBuy;

double RsiSell = buySignal ? LongRsiSell : ShortRsiSell;

bool rsiBuySignal = mRsi.Result.Last (1) < RsiBuy && mRsi.Result.Last (0) >= RsiBuy;

bool rsiSellSignal = mRsi.Result.Last (1) > RsiSell && mRsi.Result.Last (0) <= RsiSell;

 

//if (mRsi.Result.Last(0) > RsiBuy && mRsi.Result.Last(0) < RsiSell)

{

//return;

//buySignal = false;

//sellSignal = false;

}

// DownUpPattern(SourceSeries, TradeType.Buy) &&

//if (mRsi.Result.Last(1)<RsiBuy && mRsi.Result.Last(0)>=RsiBuy)

//if(rsiBuySignal)

if (DownUpPattern (TradeType.Buy) && mRsi.Result.Last (0) < RsiBuy) {

if (shortPosition != null) {

forcedClosed++;

forsedClosedPL += shortPosition.Pips;

ClosePosition (shortPosition);

}

 

if (longPosition == null) {

var stopLoss = buySignal ? (buySignal2 ? LongNormalStopLoss : LongReverseStopLoss ):(buySignal2 ? ShortNormalStopLoss : ShortReverseStopLoss );

var takeProfit = buySignal ? (buySignal2 ? LongNormalTakeProfit : LongReverseTakeProfit ):(buySignal2 ? ShortNormalTakeProfit : ShortReverseTakeProfit );

var tslp = new TrailingStopLossParams (this, label, Symbol, TradeType.Buy, VolumeInUnits, takeProfit * range, stopLoss * range);

trailing.Add (tslp.position.Id, tslp);

}

}

//DownUpPattern(SourceSeries, TradeType.Sell) &&

//if (mRsi.Result.Last(1)>RsiSell && mRsi.Result.Last(0)<=RsiSell )

//if(rsiSellSignal)

if (DownUpPattern (TradeType.Sell) && mRsi.Result.Last (0) > RsiSell) {

if (longPosition != null) {

forcedClosed++;

forsedClosedPL += longPosition.Pips;

ClosePosition (longPosition);

}

 

if (shortPosition == null) {

var stopLoss = !buySignal ? (!buySignal2 ? LongNormalStopLoss : LongReverseStopLoss ):(!buySignal2 ? ShortNormalStopLoss : ShortReverseStopLoss );

var takeProfit = !buySignal ? (!buySignal2 ? LongNormalTakeProfit : LongReverseTakeProfit ):(!buySignal2 ? ShortNormalTakeProfit : ShortReverseTakeProfit );

var tslp = new TrailingStopLossParams (this, label, Symbol, TradeType.Sell, VolumeInUnits, takeProfit * range, stopLoss * range);

trailing.Add (tslp.position.Id, tslp);

}

}

}

 

protected override void OnTick () {

if (trailing.Count () > sameTime)

sameTime = trailing.Count ();

 

foreach (var position in Positions.FindAll (label, Symbol))

trailing[position.Id].AdjStopLoss (Symbol, range, mSerie, AdjStopLossPeriods);

}

 

private double VolumeInUnits {

//return Symbol.QuantityToVolumeInUnits(Quantity);

get {

return Symbol.QuantityToVolumeInUnits (Quantity);

double size = Account.Balance * 30;

size = (int) Symbol.NormalizeVolumeInUnits (size, RoundingMode.Down);

return size;

}

}

 

private bool DownUpPattern (TradeType type) {

//bool step0 = CandleRed(series, type, 2);

bool step0 = true;

//bool step1 = step0 && CandleRed(series, type, 1) && CandleGreen(series, type, 0);

bool step1 = step0 && CandleGreen (type, 0);

//bool step2 = (-CandleValue( type, 2) - CandleValue( type, 1)) / Symbol.PipValue > ThresoldRed;

//< 2 * CandleValue( type, 0) / Symbol.PipValue;

//bool step2 = -CandleValue(series, type, 1) > ThresoldRed;

//bool step3 = CandleValue(series, type, 0) > ThresoldGreen;

//return step1 && step2 && step3;

 

bool step2 = CandleValue (type, 0) > range * (type == TradeType.Buy ? ThresoldGreen : ThresoldRed);

return step1 && step2;

}

 

private bool CandleRed (TradeType type, int index) {

return CandleValue (type, index) < 0;

}

 

private bool CandleGreen (TradeType type, int index) {

return CandleValue (type, index) > 0;

}

 

private double CandleValue (TradeType type, int index) {

 

return (mSerie.Close.Last (index) - mSerie.Open.Last (index + 1)) / (type == TradeType.Buy ? Symbol.PipSize : -Symbol.PipSize);

}

}

}

 


@astevani
Replies

astevani
11 Mar 2019, 07:51 ( Updated at: 21 Dec 2023, 09:21 )

results of optimisation and backtesting

here the results of optimisation and backtesting with the same parameters 


@astevani

PanagiotisCharalampous
12 Mar 2019, 12:21

Hi astevani,

This is a known issue. Please read more here.

Best Regards,

Panagiotis


@PanagiotisCharalampous

astevani
12 Mar 2019, 15:41

RE:

Panagiotis Charalampous said:

Hi astevani,

This is a known issue. Please read more here.

Best Regards,

Panagiotis

I would like to know if there is a work around?

best regards

 


@astevani

dave.anderson.consulting
25 Aug 2023, 14:09 ( Updated at: 26 Aug 2023, 14:48 )

No there isn't any workaround for this bug  :-(

No there isn't any fix for this bug even on cTrader version 4.8.23 in 2023 :-(

Even after 4 years!

See originally reported bug in 2019: https://ctrader.com/forum/cbot-support/15410

 


@dave.anderson.consulting

PanagiotisChar
26 Aug 2023, 14:58 ( Updated at: 26 Aug 2023, 15:00 )

RE: difference results between optimisation and backtesting

dave.anderson.consulting said: 

No there isn't any workaround for this bug  :-(

No there isn't any fix for this bug even on cTrader version 4.8.23 in 2023 :-(

Even after 4 years!

See originally reported bug in 2019: https://ctrader.com/forum/cbot-support/15410

 

Hi there,

The same symptom does not mean that it has the same cause. Better share cBot code and exact steps to reproduce.

Aieden Technologies

Need help? Join us on Telegram


@PanagiotisChar