Nasty bug in optimization

Created at 30 Mar 2019, 10:37
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!
alexander.n.fedorov's avatar

alexander.n.fedorov

Joined 02.01.2018

Nasty bug in optimization
30 Mar 2019, 10:37


Dear Panagiotis!

There must be sum bug in optimizations.

I will put three charts here and a zip of the bot 

Optimization and backtesting show complitely different results, even thou all the condititons according to "apply

"

 


@alexander.n.fedorov
Replies

alexander.n.fedorov
30 Mar 2019, 10:44 ( Updated at: 21 Dec 2023, 09:21 )

RE:

alexander.n.fedorov said:

Dear Panagiotis!

There must be sum bug in optimizations.

I will put three charts here and a zip of the bot 

Optimization and backtesting show complitely different results, even thou all the condititons according to "apply

"

 

in both cases parameteres are the same, 1 minuter data,dates are the same, only one timeframe

What is interesting, sometimes it repeats perfectly

Sometimes -  nothing in common.


using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.RussianStandardTime, AccessRights = AccessRights.None)]
    public class VolatilityBreakout4 : Robot
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("Risk", MaxValue = 10, MinValue = 0.5, DefaultValue = 1)]
        public double Risk { get; set; }

        [Parameter("Squeeze bars number", MaxValue = 180, MinValue = 5, Step = 1, DefaultValue = 20)]
        public int SqueezeBarsNumber { get; set; }

        [Parameter("Squeeze in pips", MaxValue = 300, MinValue = 1, Step = 0.1, DefaultValue = 20)]
        public double Squeeze { get; set; }

        [Parameter("TP multiple", MaxValue = 8, MinValue = 1, Step = 0.1, DefaultValue = 2)]
        public double TpMultiple { get; set; }

        [Parameter("Close Trade Hour", DefaultValue = 23)]
        public int CloseTradesHour { get; set; }

        [Parameter("Close Trade Minute", DefaultValue = 30)]
        public int CloseTradesMinute { get; set; }

        [Parameter("Open Trade Hour", DefaultValue = 2)]
        public int OpenTradesHour { get; set; }

        private string instance;
        private MarketSeries ms;
        private double range, high, low, volume, barsRange, SL, TP, minVolume, risk;
        private int pipDigits, n;
        private DateTime squeezeFirstBarTime, squeezeLastBarTime;
        private TimeSpan ts;

        protected override void OnStart()
        {
            instance = ToString() + ", " + Symbol.Code + ", " + TimeFrame + ", " + Account.BrokerName + ", " + Account.Number;
            range = Squeeze * Symbol.PipSize;
            ms = MarketData.GetSeries(TimeFrame);
            minVolume = Symbol.VolumeInUnitsMin;
            ts = CandleOpenTime(0) - CandleOpenTime(2);
            risk = Risk * 0.01;
            pipDigits = Symbol.Digits - (int)Math.Log10(1 / Symbol.PipSize);
            Positions.Opened += Positions_Opened;
            Positions.Closed += PositionsOnClosed;
            squeezeFirstBarTime = CandleOpenTime(2 + SqueezeBarsNumber);
            squeezeLastBarTime = CandleOpenTime(2);
        }

        protected override void OnBar()
        {
            if ((CandleOpenTime(0).Hour >= CloseTradesHour && CandleOpenTime(0).Minute >= CloseTradesMinute) || CandleOpenTime(0).Hour < OpenTradesHour)
            {
                return;
            }
            squeezeFirstBarTime = CandleOpenTime(1 + SqueezeBarsNumber);
            squeezeLastBarTime = CandleOpenTime(1);
            high = CandleHigh(1);
            low = CandleLow(1);
            barsRange = CandleClose(1) > (1) ? MarketSeries.Close.Last(1) - MarketSeries.Open.Last(1) : MarketSeries.Open.Last(1) - MarketSeries.Close.Last(1);
            for (int i = 0; i < SqueezeBarsNumber; i++)
            {
                high = CandleHigh(i + 1) > high ? CandleHigh(i + 1) : high;
                low = CandleLow(i + 1) < low ? CandleLow(i + 1) : low;
                barsRange = high - low;
            }
            //Chart.RemoveAllObjects();
            //Chart.DrawTrendLine("sHigh", squeezeFirstBarTime, high, squeezeLastBarTime, high, Color.Aqua, 1, LineStyle.Solid);
            //Chart.DrawTrendLine("sLow", squeezeFirstBarTime, low, squeezeLastBarTime, low, Color.Red, 1, LineStyle.Solid);
            //double barRangePips = Math.Round(barsRange / Symbol.PipSize, 1);
            //string text = "Squeeze = " + Squeeze + " , barRange = " + barRangePips;
            //Chart.DrawStaticText("Current range", text, VerticalAlignment.Bottom, HorizontalAlignment.Right, Color.Aquamarine);

            var position = Positions.Find(instance);
            if (position != null)
            {
                return;
            }
            n = 0;
            foreach (var order in PendingOrders)
            {
                if (order.Label == instance)
                {
                    n = n + 1;
                }
            }
            if (position == null)
            {
                if (n == 0)
                {
                    if (high - low < range)
                    {
                        double longPrice = high;
                        double shortPrice = low;
                        SL = (high - low) / Symbol.PipSize;
                        volume = Math.Floor(((Account.Equity * risk) / SL) / Symbol.PipValue / minVolume) * minVolume;
                        SL = Math.Round(SL, pipDigits, MidpointRounding.AwayFromZero);
                        TP = SL * TpMultiple;
                        PlaceStopOrder(TradeType.Buy, Symbol, volume, longPrice, instance, SL, TP);
                        PlaceStopOrder(TradeType.Sell, Symbol, volume, shortPrice, instance, SL, TP);
                    }
                }

            }
        }
        private void Positions_Opened(PositionOpenedEventArgs args)
        {
            var position = args.Position;
            if (position.Label == instance)
            {
                foreach (var order in PendingOrders)
                {
                    if (order.Label == instance)
                        CancelPendingOrder(order);
                }
            }

        }
        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            var position = args.Position;

            if (args.Reason == PositionCloseReason.TakeProfit)
            {
                //if (Server.Time - position.EntryTime < ts)
                //{
                //    ExecuteMarketOrder(position.TradeType, Symbol, volume, instance, SL, SL);
                //}
                ////    foreach (var order in PendingOrders)
                //    {
                //        if (order.Label == instance)
                //            CancelPendingOrder(order);
                //    }
                //}

            }
        }
        #region Candles Processing
        #region Candle Type
        private bool CandleTypeBullish(int k)
        {
            if (ms.Open.Last(k) > ms.Close.Last(k))
            {
                return false;
            }
            return true;
        }
        #endregion

        #region Candle Range(int k)
        private double CandleRange(int k)
        {
            return ms.High.Last(k) - ms.Low.Last(k);
        }
        #endregion

        #region Candle body bottom
        private double CandleBodyBottom(int k)
        {
            return (ms.Open.Last(k) < ms.Close.Last(k)) ? ms.Open.Last(k) : ms.Close.Last(k);
        }
        #endregion

        #region Candle body Top
        private double CandleBodyTop(int k)
        {
            return (ms.Open.Last(k) > ms.Close.Last(k)) ? ms.Open.Last(k) : ms.Close.Last(k);
        }
        #endregion

        #region Candle high
        private double CandleHigh(int k)
        {
            return ms.High.Last(k);
        }
        #endregion

        #region Candle low
        private double CandleLow(int k)
        {
            return ms.Low.Last(k);
        }
        #endregion

        #region Candle body
        private double CandleBody(int k)
        {
            return Math.Abs((ms.Open.Last(k) - ms.Close.Last(k)));
        }
        #endregion

        #region Candle Close
        private double CandleClose(int k)
        {
            if (CandleTypeBullish(k))
            {
                return CandleBodyTop(k);
            }
            return CandleBodyBottom(k);
        }
        #endregion

        #region Candle Open
        private double CandleOpen(int k)
        {
            if (CandleTypeBullish(k))
            {
                return CandleBodyBottom(k);
            }
            return CandleBodyTop(k);
        }

        #endregion

        #region Candle Sinus
        private double CandleSinus(int k)
        {
            return Math.Abs((ms.Open.Last(k) - ms.Close.Last(k))) / CandleRange(k) * (ms.Close.Last(k) > ms.Open.Last(k) ? 1 : -1);
        }
        #endregion

        #region Trend Angle
        private double TrendAngle(int CandlesInTrend)
        {
            double absBody = 0;
            double bodiesRange = 0;
            for (int i = 0; i <= CandlesInTrend; i++)
            {
                if (CandleTypeBullish(i))
                {
                    bodiesRange = bodiesRange + CandleBody(i);
                }
                if (!CandleTypeBullish(i))
                {
                    bodiesRange = bodiesRange - CandleBody(i);
                }
                absBody = absBody + CandleBody(i);
            }
            var trendSinus = bodiesRange / absBody;
            return Math.Asin(trendSinus) * 180 / Math.PI;
        }
        #endregion

        #region Candle OpenTime
        private DateTime CandleOpenTime(int k)
        {
            return ms.OpenTime.Last(k);
        }
        #endregion

        #region No k Candles on the left High
        private bool NoLeftCandlesHigh(int k)
        {
            for (int i = 1; i < k; i++)
            {
                if (CandleHigh(1) > CandleLow(1 + i) && CandleHigh(1) < CandleHigh(1 + i))
                {
                    return false;
                }
                if (CandleHigh(1) < CandleLow(1 + i) || CandleHigh(1) > CandleHigh(1 + i))
                {
                    continue;
                }
            }
            return true;
        }
        #endregion
        #region No k Candles on the left Low
        private bool NoLeftCandlesLow(int k)
        {
            for (int i = 1; i < k; i++)
            {
                if (CandleLow(1) < CandleHigh(1 + i) && CandleLow(1) > CandleLow(1 + i))
                {
                    return false;
                }
                if (CandleLow(1) < CandleHigh(1 + i) || CandleLow(1) > CandleLow(1 + i))
                {
                    continue;
                }
            }
            return true;
        }
        #endregion
        #endregion
    }
}

 


@alexander.n.fedorov

alexander.n.fedorov
30 Mar 2019, 10:50 ( Updated at: 21 Dec 2023, 09:21 )

RE: RE:

alexander.n.fedorov said:

alexander.n.fedorov said:

Dear Panagiotis!

There must be sum bug in optimizations.

I will put three charts here and a zip of the bot 

Optimization and backtesting show complitely different results, even thou all the condititons according to "apply

"

 

in both cases parameteres are the same, 1 minuter data,dates are the same, only one timeframe

What is interesting, sometimes it repeats perfectly

Sometimes -  nothing in common.


using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.RussianStandardTime, AccessRights = AccessRights.None)]
    public class VolatilityBreakout4 : Robot
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("Risk", MaxValue = 10, MinValue = 0.5, DefaultValue = 1)]
        public double Risk { get; set; }

        [Parameter("Squeeze bars number", MaxValue = 180, MinValue = 5, Step = 1, DefaultValue = 20)]
        public int SqueezeBarsNumber { get; set; }

        [Parameter("Squeeze in pips", MaxValue = 300, MinValue = 1, Step = 0.1, DefaultValue = 20)]
        public double Squeeze { get; set; }

        [Parameter("TP multiple", MaxValue = 8, MinValue = 1, Step = 0.1, DefaultValue = 2)]
        public double TpMultiple { get; set; }

        [Parameter("Close Trade Hour", DefaultValue = 23)]
        public int CloseTradesHour { get; set; }

        [Parameter("Close Trade Minute", DefaultValue = 30)]
        public int CloseTradesMinute { get; set; }

        [Parameter("Open Trade Hour", DefaultValue = 2)]
        public int OpenTradesHour { get; set; }

        private string instance;
        private MarketSeries ms;
        private double range, high, low, volume, barsRange, SL, TP, minVolume, risk;
        private int pipDigits, n;
        private DateTime squeezeFirstBarTime, squeezeLastBarTime;
        private TimeSpan ts;

        protected override void OnStart()
        {
            instance = ToString() + ", " + Symbol.Code + ", " + TimeFrame + ", " + Account.BrokerName + ", " + Account.Number;
            range = Squeeze * Symbol.PipSize;
            ms = MarketData.GetSeries(TimeFrame);
            minVolume = Symbol.VolumeInUnitsMin;
            ts = CandleOpenTime(0) - CandleOpenTime(2);
            risk = Risk * 0.01;
            pipDigits = Symbol.Digits - (int)Math.Log10(1 / Symbol.PipSize);
            Positions.Opened += Positions_Opened;
            Positions.Closed += PositionsOnClosed;
            squeezeFirstBarTime = CandleOpenTime(2 + SqueezeBarsNumber);
            squeezeLastBarTime = CandleOpenTime(2);
        }

        protected override void OnBar()
        {
            if ((CandleOpenTime(0).Hour >= CloseTradesHour && CandleOpenTime(0).Minute >= CloseTradesMinute) || CandleOpenTime(0).Hour < OpenTradesHour)
            {
                return;
            }
            squeezeFirstBarTime = CandleOpenTime(1 + SqueezeBarsNumber);
            squeezeLastBarTime = CandleOpenTime(1);
            high = CandleHigh(1);
            low = CandleLow(1);
            barsRange = CandleClose(1) > (1) ? MarketSeries.Close.Last(1) - MarketSeries.Open.Last(1) : MarketSeries.Open.Last(1) - MarketSeries.Close.Last(1);
            for (int i = 0; i < SqueezeBarsNumber; i++)
            {
                high = CandleHigh(i + 1) > high ? CandleHigh(i + 1) : high;
                low = CandleLow(i + 1) < low ? CandleLow(i + 1) : low;
                barsRange = high - low;
            }
            //Chart.RemoveAllObjects();
            //Chart.DrawTrendLine("sHigh", squeezeFirstBarTime, high, squeezeLastBarTime, high, Color.Aqua, 1, LineStyle.Solid);
            //Chart.DrawTrendLine("sLow", squeezeFirstBarTime, low, squeezeLastBarTime, low, Color.Red, 1, LineStyle.Solid);
            //double barRangePips = Math.Round(barsRange / Symbol.PipSize, 1);
            //string text = "Squeeze = " + Squeeze + " , barRange = " + barRangePips;
            //Chart.DrawStaticText("Current range", text, VerticalAlignment.Bottom, HorizontalAlignment.Right, Color.Aquamarine);

            var position = Positions.Find(instance);
            if (position != null)
            {
                return;
            }
            n = 0;
            foreach (var order in PendingOrders)
            {
                if (order.Label == instance)
                {
                    n = n + 1;
                }
            }
            if (position == null)
            {
                if (n == 0)
                {
                    if (high - low < range)
                    {
                        double longPrice = high;
                        double shortPrice = low;
                        SL = (high - low) / Symbol.PipSize;
                        volume = Math.Floor(((Account.Equity * risk) / SL) / Symbol.PipValue / minVolume) * minVolume;
                        SL = Math.Round(SL, pipDigits, MidpointRounding.AwayFromZero);
                        TP = SL * TpMultiple;
                        PlaceStopOrder(TradeType.Buy, Symbol, volume, longPrice, instance, SL, TP);
                        PlaceStopOrder(TradeType.Sell, Symbol, volume, shortPrice, instance, SL, TP);
                    }
                }

            }
        }
        private void Positions_Opened(PositionOpenedEventArgs args)
        {
            var position = args.Position;
            if (position.Label == instance)
            {
                foreach (var order in PendingOrders)
                {
                    if (order.Label == instance)
                        CancelPendingOrder(order);
                }
            }

        }
        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            var position = args.Position;

            if (args.Reason == PositionCloseReason.TakeProfit)
            {
                //if (Server.Time - position.EntryTime < ts)
                //{
                //    ExecuteMarketOrder(position.TradeType, Symbol, volume, instance, SL, SL);
                //}
                ////    foreach (var order in PendingOrders)
                //    {
                //        if (order.Label == instance)
                //            CancelPendingOrder(order);
                //    }
                //}

            }
        }
        #region Candles Processing
        #region Candle Type
        private bool CandleTypeBullish(int k)
        {
            if (ms.Open.Last(k) > ms.Close.Last(k))
            {
                return false;
            }
            return true;
        }
        #endregion

        #region Candle Range(int k)
        private double CandleRange(int k)
        {
            return ms.High.Last(k) - ms.Low.Last(k);
        }
        #endregion

        #region Candle body bottom
        private double CandleBodyBottom(int k)
        {
            return (ms.Open.Last(k) < ms.Close.Last(k)) ? ms.Open.Last(k) : ms.Close.Last(k);
        }
        #endregion

        #region Candle body Top
        private double CandleBodyTop(int k)
        {
            return (ms.Open.Last(k) > ms.Close.Last(k)) ? ms.Open.Last(k) : ms.Close.Last(k);
        }
        #endregion

        #region Candle high
        private double CandleHigh(int k)
        {
            return ms.High.Last(k);
        }
        #endregion

        #region Candle low
        private double CandleLow(int k)
        {
            return ms.Low.Last(k);
        }
        #endregion

        #region Candle body
        private double CandleBody(int k)
        {
            return Math.Abs((ms.Open.Last(k) - ms.Close.Last(k)));
        }
        #endregion

        #region Candle Close
        private double CandleClose(int k)
        {
            if (CandleTypeBullish(k))
            {
                return CandleBodyTop(k);
            }
            return CandleBodyBottom(k);
        }
        #endregion

        #region Candle Open
        private double CandleOpen(int k)
        {
            if (CandleTypeBullish(k))
            {
                return CandleBodyBottom(k);
            }
            return CandleBodyTop(k);
        }

        #endregion

        #region Candle Sinus
        private double CandleSinus(int k)
        {
            return Math.Abs((ms.Open.Last(k) - ms.Close.Last(k))) / CandleRange(k) * (ms.Close.Last(k) > ms.Open.Last(k) ? 1 : -1);
        }
        #endregion

        #region Trend Angle
        private double TrendAngle(int CandlesInTrend)
        {
            double absBody = 0;
            double bodiesRange = 0;
            for (int i = 0; i <= CandlesInTrend; i++)
            {
                if (CandleTypeBullish(i))
                {
                    bodiesRange = bodiesRange + CandleBody(i);
                }
                if (!CandleTypeBullish(i))
                {
                    bodiesRange = bodiesRange - CandleBody(i);
                }
                absBody = absBody + CandleBody(i);
            }
            var trendSinus = bodiesRange / absBody;
            return Math.Asin(trendSinus) * 180 / Math.PI;
        }
        #endregion

        #region Candle OpenTime
        private DateTime CandleOpenTime(int k)
        {
            return ms.OpenTime.Last(k);
        }
        #endregion

        #region No k Candles on the left High
        private bool NoLeftCandlesHigh(int k)
        {
            for (int i = 1; i < k; i++)
            {
                if (CandleHigh(1) > CandleLow(1 + i) && CandleHigh(1) < CandleHigh(1 + i))
                {
                    return false;
                }
                if (CandleHigh(1) < CandleLow(1 + i) || CandleHigh(1) > CandleHigh(1 + i))
                {
                    continue;
                }
            }
            return true;
        }
        #endregion
        #region No k Candles on the left Low
        private bool NoLeftCandlesLow(int k)
        {
            for (int i = 1; i < k; i++)
            {
                if (CandleLow(1) < CandleHigh(1 + i) && CandleLow(1) > CandleLow(1 + i))
                {
                    return false;
                }
                if (CandleLow(1) < CandleHigh(1 + i) || CandleLow(1) > CandleLow(1 + i))
                {
                    continue;
                }
            }
            return true;
        }
        #endregion
        #endregion
    }
}

 

I think Spotware have to do smth about it, otherwise the whole idea of cTrader Algos is becoming useless

Regadrs

 

Alexander

 


@alexander.n.fedorov

alexander.n.fedorov
30 Mar 2019, 10:57 ( Updated at: 21 Dec 2023, 09:21 )

RE: RE: RE:

alexander.n.fedorov said:

alexander.n.fedorov said:

alexander.n.fedorov said:

Dear Panagiotis!

There must be sum bug in optimizations.

I will put three charts here and a zip of the bot 

Optimization and backtesting show complitely different results, even thou all the condititons according to "apply

"

 

in both cases parameteres are the same, 1 minuter data,dates are the same, only one timeframe

What is interesting, sometimes it repeats perfectly

Sometimes -  nothing in common.


using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.RussianStandardTime, AccessRights = AccessRights.None)]
    public class VolatilityBreakout4 : Robot
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("Risk", MaxValue = 10, MinValue = 0.5, DefaultValue = 1)]
        public double Risk { get; set; }

        [Parameter("Squeeze bars number", MaxValue = 180, MinValue = 5, Step = 1, DefaultValue = 20)]
        public int SqueezeBarsNumber { get; set; }

        [Parameter("Squeeze in pips", MaxValue = 300, MinValue = 1, Step = 0.1, DefaultValue = 20)]
        public double Squeeze { get; set; }

        [Parameter("TP multiple", MaxValue = 8, MinValue = 1, Step = 0.1, DefaultValue = 2)]
        public double TpMultiple { get; set; }

        [Parameter("Close Trade Hour", DefaultValue = 23)]
        public int CloseTradesHour { get; set; }

        [Parameter("Close Trade Minute", DefaultValue = 30)]
        public int CloseTradesMinute { get; set; }

        [Parameter("Open Trade Hour", DefaultValue = 2)]
        public int OpenTradesHour { get; set; }

        private string instance;
        private MarketSeries ms;
        private double range, high, low, volume, barsRange, SL, TP, minVolume, risk;
        private int pipDigits, n;
        private DateTime squeezeFirstBarTime, squeezeLastBarTime;
        private TimeSpan ts;

        protected override void OnStart()
        {
            instance = ToString() + ", " + Symbol.Code + ", " + TimeFrame + ", " + Account.BrokerName + ", " + Account.Number;
            range = Squeeze * Symbol.PipSize;
            ms = MarketData.GetSeries(TimeFrame);
            minVolume = Symbol.VolumeInUnitsMin;
            ts = CandleOpenTime(0) - CandleOpenTime(2);
            risk = Risk * 0.01;
            pipDigits = Symbol.Digits - (int)Math.Log10(1 / Symbol.PipSize);
            Positions.Opened += Positions_Opened;
            Positions.Closed += PositionsOnClosed;
            squeezeFirstBarTime = CandleOpenTime(2 + SqueezeBarsNumber);
            squeezeLastBarTime = CandleOpenTime(2);
        }

        protected override void OnBar()
        {
            if ((CandleOpenTime(0).Hour >= CloseTradesHour && CandleOpenTime(0).Minute >= CloseTradesMinute) || CandleOpenTime(0).Hour < OpenTradesHour)
            {
                return;
            }
            squeezeFirstBarTime = CandleOpenTime(1 + SqueezeBarsNumber);
            squeezeLastBarTime = CandleOpenTime(1);
            high = CandleHigh(1);
            low = CandleLow(1);
            barsRange = CandleClose(1) > (1) ? MarketSeries.Close.Last(1) - MarketSeries.Open.Last(1) : MarketSeries.Open.Last(1) - MarketSeries.Close.Last(1);
            for (int i = 0; i < SqueezeBarsNumber; i++)
            {
                high = CandleHigh(i + 1) > high ? CandleHigh(i + 1) : high;
                low = CandleLow(i + 1) < low ? CandleLow(i + 1) : low;
                barsRange = high - low;
            }
            //Chart.RemoveAllObjects();
            //Chart.DrawTrendLine("sHigh", squeezeFirstBarTime, high, squeezeLastBarTime, high, Color.Aqua, 1, LineStyle.Solid);
            //Chart.DrawTrendLine("sLow", squeezeFirstBarTime, low, squeezeLastBarTime, low, Color.Red, 1, LineStyle.Solid);
            //double barRangePips = Math.Round(barsRange / Symbol.PipSize, 1);
            //string text = "Squeeze = " + Squeeze + " , barRange = " + barRangePips;
            //Chart.DrawStaticText("Current range", text, VerticalAlignment.Bottom, HorizontalAlignment.Right, Color.Aquamarine);

            var position = Positions.Find(instance);
            if (position != null)
            {
                return;
            }
            n = 0;
            foreach (var order in PendingOrders)
            {
                if (order.Label == instance)
                {
                    n = n + 1;
                }
            }
            if (position == null)
            {
                if (n == 0)
                {
                    if (high - low < range)
                    {
                        double longPrice = high;
                        double shortPrice = low;
                        SL = (high - low) / Symbol.PipSize;
                        volume = Math.Floor(((Account.Equity * risk) / SL) / Symbol.PipValue / minVolume) * minVolume;
                        SL = Math.Round(SL, pipDigits, MidpointRounding.AwayFromZero);
                        TP = SL * TpMultiple;
                        PlaceStopOrder(TradeType.Buy, Symbol, volume, longPrice, instance, SL, TP);
                        PlaceStopOrder(TradeType.Sell, Symbol, volume, shortPrice, instance, SL, TP);
                    }
                }

            }
        }
        private void Positions_Opened(PositionOpenedEventArgs args)
        {
            var position = args.Position;
            if (position.Label == instance)
            {
                foreach (var order in PendingOrders)
                {
                    if (order.Label == instance)
                        CancelPendingOrder(order);
                }
            }

        }
        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            var position = args.Position;

            if (args.Reason == PositionCloseReason.TakeProfit)
            {
                //if (Server.Time - position.EntryTime < ts)
                //{
                //    ExecuteMarketOrder(position.TradeType, Symbol, volume, instance, SL, SL);
                //}
                ////    foreach (var order in PendingOrders)
                //    {
                //        if (order.Label == instance)
                //            CancelPendingOrder(order);
                //    }
                //}

            }
        }
        #region Candles Processing
        #region Candle Type
        private bool CandleTypeBullish(int k)
        {
            if (ms.Open.Last(k) > ms.Close.Last(k))
            {
                return false;
            }
            return true;
        }
        #endregion

        #region Candle Range(int k)
        private double CandleRange(int k)
        {
            return ms.High.Last(k) - ms.Low.Last(k);
        }
        #endregion

        #region Candle body bottom
        private double CandleBodyBottom(int k)
        {
            return (ms.Open.Last(k) < ms.Close.Last(k)) ? ms.Open.Last(k) : ms.Close.Last(k);
        }
        #endregion

        #region Candle body Top
        private double CandleBodyTop(int k)
        {
            return (ms.Open.Last(k) > ms.Close.Last(k)) ? ms.Open.Last(k) : ms.Close.Last(k);
        }
        #endregion

        #region Candle high
        private double CandleHigh(int k)
        {
            return ms.High.Last(k);
        }
        #endregion

        #region Candle low
        private double CandleLow(int k)
        {
            return ms.Low.Last(k);
        }
        #endregion

        #region Candle body
        private double CandleBody(int k)
        {
            return Math.Abs((ms.Open.Last(k) - ms.Close.Last(k)));
        }
        #endregion

        #region Candle Close
        private double CandleClose(int k)
        {
            if (CandleTypeBullish(k))
            {
                return CandleBodyTop(k);
            }
            return CandleBodyBottom(k);
        }
        #endregion

        #region Candle Open
        private double CandleOpen(int k)
        {
            if (CandleTypeBullish(k))
            {
                return CandleBodyBottom(k);
            }
            return CandleBodyTop(k);
        }

        #endregion

        #region Candle Sinus
        private double CandleSinus(int k)
        {
            return Math.Abs((ms.Open.Last(k) - ms.Close.Last(k))) / CandleRange(k) * (ms.Close.Last(k) > ms.Open.Last(k) ? 1 : -1);
        }
        #endregion

        #region Trend Angle
        private double TrendAngle(int CandlesInTrend)
        {
            double absBody = 0;
            double bodiesRange = 0;
            for (int i = 0; i <= CandlesInTrend; i++)
            {
                if (CandleTypeBullish(i))
                {
                    bodiesRange = bodiesRange + CandleBody(i);
                }
                if (!CandleTypeBullish(i))
                {
                    bodiesRange = bodiesRange - CandleBody(i);
                }
                absBody = absBody + CandleBody(i);
            }
            var trendSinus = bodiesRange / absBody;
            return Math.Asin(trendSinus) * 180 / Math.PI;
        }
        #endregion

        #region Candle OpenTime
        private DateTime CandleOpenTime(int k)
        {
            return ms.OpenTime.Last(k);
        }
        #endregion

        #region No k Candles on the left High
        private bool NoLeftCandlesHigh(int k)
        {
            for (int i = 1; i < k; i++)
            {
                if (CandleHigh(1) > CandleLow(1 + i) && CandleHigh(1) < CandleHigh(1 + i))
                {
                    return false;
                }
                if (CandleHigh(1) < CandleLow(1 + i) || CandleHigh(1) > CandleHigh(1 + i))
                {
                    continue;
                }
            }
            return true;
        }
        #endregion
        #region No k Candles on the left Low
        private bool NoLeftCandlesLow(int k)
        {
            for (int i = 1; i < k; i++)
            {
                if (CandleLow(1) < CandleHigh(1 + i) && CandleLow(1) > CandleLow(1 + i))
                {
                    return false;
                }
                if (CandleLow(1) < CandleHigh(1 + i) || CandleLow(1) > CandleLow(1 + i))
                {
                    continue;
                }
            }
            return true;
        }
        #endregion
        #endregion
    }
}

 

I think Spotware have to do smth about it, otherwise the whole idea of cTrader Algos is becoming useless

Regadrs

 

Alexander

 

P.S. What is interesting, this effect appeared just recently. Before my previous mail  everything worked allright. May it is one of the constant upgrades?

 


@alexander.n.fedorov

alexander.n.fedorov
30 Mar 2019, 11:18

I just tryied to do optimization on tick data. Result is the same. Optimization and the backtest -  absolutely different results

 


@alexander.n.fedorov

tradermatrix
30 Mar 2019, 15:52

Hi
I think the problem is here;
SL = Math.Round(SL, pipDigits, MidpointRounding.AwayFromZero);
I just replaced ("MidpointRounding.AwayFromZero") with 0 and it works
 SL = Math.Round(SL, pipDigits, 0);
  TP = SL * TpMultiple;
                        PlaceStopOrder(TradeType.Buy, Symbol, volume, longPrice, instance, SL, TP);
                        PlaceStopOrder(TradeType.Sell, Symbol, volume, shortPrice, instance, SL, TP);

cordially


@tradermatrix

alexander.n.fedorov
31 Mar 2019, 10:30

RE:

tradermatrix said:

Hi
I think the problem is here;
SL = Math.Round(SL, pipDigits, MidpointRounding.AwayFromZero);
I just replaced ("MidpointRounding.AwayFromZero") with 0 and it works
 SL = Math.Round(SL, pipDigits, 0);
  TP = SL * TpMultiple;
                        PlaceStopOrder(TradeType.Buy, Symbol, volume, longPrice, instance, SL, TP);
                        PlaceStopOrder(TradeType.Sell, Symbol, volume, shortPrice, instance, SL, TP);

cordially

Thank you. Let me try

Also before I tryied I wannted to say it is not working on tick either


@alexander.n.fedorov

alexander.n.fedorov
31 Mar 2019, 10:43 ( Updated at: 21 Dec 2023, 09:21 )

I tryied, I changed to "0"

the results 

 

 

 

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.RussianStandardTime, AccessRights = AccessRights.FullAccess)]
    public class VolatilityBreakout4 : Robot
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("Risk", MaxValue = 10, MinValue = 0.5, DefaultValue = 1)]
        public double Risk { get; set; }

        [Parameter("Squeeze bars number", MaxValue = 180, MinValue = 5, Step = 1, DefaultValue = 20)]
        public int SqueezeBarsNumber { get; set; }

        [Parameter("Squeeze in pips", MaxValue = 300, MinValue = 1, Step = 0.1, DefaultValue = 20)]
        public double Squeeze { get; set; }

        [Parameter("TP multiple", MaxValue = 8, MinValue = 1, Step = 0.1, DefaultValue = 2)]
        public double TpMultiple { get; set; }

        [Parameter("Close on Profit %", Step = 0.1, DefaultValue = 4.0)]
        public double CloseOnProfit { get; set; }

        [Parameter("Close Trade Hour", DefaultValue = 23)]
        public int CloseTradesHour { get; set; }

        [Parameter("Close Trade Minute", DefaultValue = 30)]
        public int CloseTradesMinute { get; set; }

        [Parameter("Open Trade Hour", DefaultValue = 2)]
        public int OpenTradesHour { get; set; }

        private string instance;
        private MarketSeries ms;
        private double range, high, low, volume, barsRange, SL, TP, minVolume, risk, longPrice;
        private double shortPrice, closeOnProfit;
        private int pipDigits, n;
        private DateTime squeezeFirstBarTime, squeezeLastBarTime;

        protected override void OnStart()
        {
            instance = ToString() + ", " + Symbol.Code + ", " + TimeFrame + ", " + Account.BrokerName + ", " + Account.Number;
            range = Squeeze * Symbol.PipSize;
            ms = MarketData.GetSeries(TimeFrame);
            minVolume = Symbol.VolumeInUnitsMin;
            risk = Risk * 0.01;
            closeOnProfit = CloseOnProfit * 0.01;
            pipDigits = Symbol.Digits - (int)Math.Log10(1 / Symbol.PipSize);
            Positions.Opened += Positions_Opened;
            Positions.Closed += PositionsOnClosed;
            squeezeFirstBarTime = CandleOpenTime(2 + SqueezeBarsNumber);
            squeezeLastBarTime = CandleOpenTime(2);
        }

        protected override void OnBar()
        {
            var position = Positions.Find(instance);
            var spread = Symbol.Spread / Symbol.PipSize;
            if (position == null)
            {
                if (spread > 2)
                {
                    return;
                }
                if ((CandleOpenTime(0).Hour >= CloseTradesHour && CandleOpenTime(0).Minute >= CloseTradesMinute) || CandleOpenTime(0).Hour < OpenTradesHour)
                {
                    return;
                }
                squeezeFirstBarTime = CandleOpenTime(1 + SqueezeBarsNumber);
                squeezeLastBarTime = CandleOpenTime(1);
                high = CandleHigh(1);
                low = CandleLow(1);
                barsRange = CandleClose(1) > (1) ? MarketSeries.Close.Last(1) - MarketSeries.Open.Last(1) : MarketSeries.Open.Last(1) - MarketSeries.Close.Last(1);
                for (int i = 0; i < SqueezeBarsNumber; i++)
                {
                    high = CandleHigh(i + 1) > high ? CandleHigh(i + 1) : high;
                    low = CandleLow(i + 1) < low ? CandleLow(i + 1) : low;
                    barsRange = high - low;
                }
                //Chart.RemoveAllObjects();
                //Chart.DrawTrendLine("sHigh", squeezeFirstBarTime, high, squeezeLastBarTime, high, Color.Aqua, 1, LineStyle.Solid);
                //Chart.DrawTrendLine("sLow", squeezeFirstBarTime, low, squeezeLastBarTime, low, Color.Red, 1, LineStyle.Solid);
                //double barRangePips = Math.Round(barsRange / Symbol.PipSize, 1);
                //string text = "Squeeze = " + Squeeze + " , barRange = " + barRangePips;
                //Chart.DrawStaticText("Current range", text, VerticalAlignment.Bottom, HorizontalAlignment.Right, Color.Aquamarine);


                n = 0;
                foreach (var order in PendingOrders)
                {
                    if (order.Label == instance)
                    {
                        n = n + 1;
                    }
                }
                if (n == 0)
                {
                    if (high - low < range)
                    {
                        {
                            longPrice = high;
                            shortPrice = low;
                            SL = (high - low) / Symbol.PipSize + 1;
                            volume = Math.Floor(((Account.Equity * risk) / SL) / Symbol.PipValue / minVolume) * minVolume;
                            SL = Math.Round(SL, pipDigits, 0);
                            TP = Math.Round(SL * TpMultiple, pipDigits, 0);
                            PlaceStopOrder(TradeType.Buy, Symbol, volume, longPrice, instance, null, TP);
                            PlaceStopOrder(TradeType.Sell, Symbol, volume, shortPrice, instance, null, TP);
                            //Chart.DrawHorizontalLine(longPrice.ToString(), longPrice - SL * Symbol.PipSize, Color.Crimson, 1, LineStyle.DotsRare);
                            //Chart.DrawHorizontalLine(shortPrice.ToString(), shortPrice + SL * Symbol.PipSize, Color.Crimson, 1, LineStyle.DotsRare);
                        }
                    }
                }
            }
            if (position != null)
            {
                if (spread > 2)
                {
                    return;
                }
                if (position.TradeType == TradeType.Buy)
                {
                    if (CandleClose(1) < position.EntryPrice - SL * Symbol.PipSize)
                    {
                        ClosePosition(position);
                        //Chart.RemoveAllObjects();
                    }
                }
                if (position.TradeType == TradeType.Sell)
                {
                    if (CandleClose(1) > position.EntryPrice + SL * Symbol.PipSize)
                    {

                        ClosePosition(position);
                        //Chart.RemoveAllObjects();
                    }
                }
            }
        }
        protected override void OnTick()
        {
            if (Account.UnrealizedNetProfit > Account.Balance * closeOnProfit)
                foreach (var position in Positions)
                {
                    ClosePositionAsync(position);
                }
        }
        private void Positions_Opened(PositionOpenedEventArgs args)
        {
            var position = args.Position;
            if (position.Label == instance)
            {
                foreach (var order in PendingOrders)
                {
                    if (order.Label == instance)
                        CancelPendingOrder(order);
                }
                if (position.TradeType == TradeType.Buy)
                {
                    //Chart.RemoveObject(shortPrice.ToString());
                }
                if (position.TradeType == TradeType.Sell)
                {
                    //Chart.RemoveObject(longPrice.ToString());
                }
            }

        }
        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            var position = args.Position;

            if (args.Reason == PositionCloseReason.TakeProfit)
            {
                //
            }
        }
        #region Candles Processing
        #region Candle Type
        private bool CandleTypeBullish(int k)
        {
            if (ms.Open.Last(k) > ms.Close.Last(k))
            {
                return false;
            }
            return true;
        }
        #endregion

        #region Candle Range(int k)
        private double CandleRange(int k)
        {
            return ms.High.Last(k) - ms.Low.Last(k);
        }
        #endregion

        #region Candle body bottom
        private double CandleBodyBottom(int k)
        {
            return (ms.Open.Last(k) < ms.Close.Last(k)) ? ms.Open.Last(k) : ms.Close.Last(k);
        }
        #endregion

        #region Candle body Top
        private double CandleBodyTop(int k)
        {
            return (ms.Open.Last(k) > ms.Close.Last(k)) ? ms.Open.Last(k) : ms.Close.Last(k);
        }
        #endregion

        #region Candle high
        private double CandleHigh(int k)
        {
            return ms.High.Last(k);
        }
        #endregion

        #region Candle low
        private double CandleLow(int k)
        {
            return ms.Low.Last(k);
        }
        #endregion

        #region Candle body
        private double CandleBody(int k)
        {
            return Math.Abs((ms.Open.Last(k) - ms.Close.Last(k)));
        }
        #endregion

        #region Candle Close
        private double CandleClose(int k)
        {
            if (CandleTypeBullish(k))
            {
                return CandleBodyTop(k);
            }
            return CandleBodyBottom(k);
        }
        #endregion

        #region Candle Open
        private double CandleOpen(int k)
        {
            if (CandleTypeBullish(k))
            {
                return CandleBodyBottom(k);
            }
            return CandleBodyTop(k);
        }

        #endregion

        #region Candle Sinus
        private double CandleSinus(int k)
        {
            return Math.Abs((ms.Open.Last(k) - ms.Close.Last(k))) / CandleRange(k) * (ms.Close.Last(k) > ms.Open.Last(k) ? 1 : -1);
        }
        #endregion

        #region Trend Angle
        private double TrendAngle(int CandlesInTrend)
        {
            double absBody = 0;
            double bodiesRange = 0;
            for (int i = 0; i <= CandlesInTrend; i++)
            {
                if (CandleTypeBullish(i))
                {
                    bodiesRange = bodiesRange + CandleBody(i);
                }
                if (!CandleTypeBullish(i))
                {
                    bodiesRange = bodiesRange - CandleBody(i);
                }
                absBody = absBody + CandleBody(i);
            }
            var trendSinus = bodiesRange / absBody;
            return Math.Asin(trendSinus) * 180 / Math.PI;
        }
        #endregion

        #region Candle OpenTime
        private DateTime CandleOpenTime(int k)
        {
            return ms.OpenTime.Last(k);
        }
        #endregion

        #region No k Candles on the left High
        private bool NoLeftCandlesHigh(int k)
        {
            for (int i = 1; i < k; i++)
            {
                if (CandleHigh(1) > CandleLow(1 + i) && CandleHigh(1) < CandleHigh(1 + i))
                {
                    return false;
                }
                if (CandleHigh(1) < CandleLow(1 + i) || CandleHigh(1) > CandleHigh(1 + i))
                {
                    continue;
                }
            }
            return true;
        }
        #endregion
        #region No k Candles on the left Low
        private bool NoLeftCandlesLow(int k)
        {
            for (int i = 1; i < k; i++)
            {
                if (CandleLow(1) < CandleHigh(1 + i) && CandleLow(1) > CandleLow(1 + i))
                {
                    return false;
                }
                if (CandleLow(1) < CandleHigh(1 + i) || CandleLow(1) > CandleLow(1 + i))
                {
                    continue;
                }
            }
            return true;
        }
        #endregion
        #endregion
    }
}

I commented the charts. Charts do not work on optimization. 

I also introduced the OnTick logic, as it may improve the working with portfolio

But the poin is that about a month ago everthing was working perfectly

Now -  not 

during this time there were some updates on the software. Could that be the reason?

Regards, 

Alexander


@alexander.n.fedorov

alexander.n.fedorov
31 Mar 2019, 11:37 ( Updated at: 21 Dec 2023, 09:21 )

I put two charts. Both have the same parameters, both OnTick , same period

first, optimization

 

Second  - Backtesting

 

 

As you can see, they are quite different

????

 


@alexander.n.fedorov

alexander.n.fedorov
31 Mar 2019, 11:39 ( Updated at: 21 Dec 2023, 09:21 )

Sorry , the second one was wrong 

the correct one is this:

 


@alexander.n.fedorov

tradermatrix
31 Mar 2019, 11:57

Hello

I downloaded the last code you tested ... and at home it works in bar mode and tick mode .. no difference between backesting and optimization

I think the cause is an update ..

I downloaded last upgrade to a newer version of .Net framework.

can be a try ...

https://dotnet.microsoft.com/download/dotnet-framework/net472


@tradermatrix

alexander.n.fedorov
31 Mar 2019, 13:05

Hi!

Because I am quite new to the programming in C# I do not quite understand what shall I do with the link?

Shall I just down load the runtime? I am using Visual Studio for writing a code

Regards

 

Alexander


@alexander.n.fedorov

alexander.n.fedorov
31 Mar 2019, 13:21

Hi, TraDerMaTrix

I really appreciate your concern. I downloaded and installed the the developer pack

But results are the same

May be you could be very kind and call my Skype number:

alexander.n.fedorov

Regards,

 

Alexander

 


@alexander.n.fedorov

alexander.n.fedorov
31 Mar 2019, 13:56

Hi, TraDerMaTrix

 

I installed the developer pack per your link on a VPS server (dedicated, very good) and on my notebook

Rebuilt the code

Tryid it again on both machines

It is not working. It gives different results

Can you help? You look like you know whay you are doing

 

Regards,

 

Alexander


@alexander.n.fedorov

alexander.n.fedorov
31 Mar 2019, 18:10

There is very interesting thing I discovered.

If TimeFrame is included into optimization of this algo, then I have all the problems

If I use only one TimeFrame - no problem!

It must be a bug

 


@alexander.n.fedorov

PanagiotisCharalampous
02 Apr 2019, 11:37

Hi Sasha,

It should be the same issue we discussed here.

Best Regards,

Panagiotis


@PanagiotisCharalampous