Category Trend  Published on 21/09/2022

Breakout Trend Bot

Description

By ForexCove. The Breakout Trend Bot trades in the direction of trend. Pending orders are placed x-pips above or below previous highest high or lowest low, and if market shows strength in the predicted direction, the trade is taken.

You can configure desired trend strength with built in ADX filter, and even let TP and SL targets be defined by ATR.

 To download a sample config file, visit this link HERE


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.UTC, AccessRights = AccessRights.None)]
    public class Breakout_cBot : Robot
    {

        [Parameter(DefaultValue = "Breakout_cBot")]
        public string cBotLabel { get; set; }

        [Parameter("Lot Size", DefaultValue = 0.1, MinValue = 0.01, Step = 0.01)]
        public double LotSize { get; set; }

        [Parameter("Enable Martingale", DefaultValue = false)]
        public bool EnableMartingale { get; set; }

        [Parameter("Max trade size:", DefaultValue = 0.8, MinValue = 0.01, Step = 0.01)]
        public double MaxTradeSize { get; set; }

        [Parameter("Martingale Multiplier:", DefaultValue = 2.0)]
        public double MartingaleMultiplier { get; set; }

        [Parameter("StopLoss in pips", DefaultValue = 20.0)]
        public double StopLoss { get; set; }

        [Parameter("TakeProfit in pips", DefaultValue = 20.0)]
        public double TakeProfit { get; set; }

        [Parameter("MA Type", DefaultValue = MovingAverageType.Exponential)]
        public MovingAverageType MAType { get; set; }

        [Parameter("MA Period", DefaultValue = 14)]
        public int MAPeriod { get; set; }

        [Parameter("Offsetfrom Highest/lowest pricee in pips", DefaultValue = 3.0)]
        public double OffsetHL { get; set; }

        [Parameter("Adjust Initial Volume  (true/false)", DefaultValue = true)]
        public bool ParamAdjustInitialVolume { get; set; }

        [Parameter("Initial Volume Adjustment", DefaultValue = 40, Step = 1)]
        public double ParamVolumeAdjustment { get; set; }

        [Parameter("Include trading hours", DefaultValue = true)]
        public bool UseTradingHours { get; set; }

        [Parameter("Trading Start Hour:0-23", DefaultValue = 8, MinValue = 0, MaxValue = 23, Step = 1)]
        public int StartTimeHour { get; set; }

        [Parameter("Trading Start Minute:0-59", DefaultValue = 0, MinValue = 0, MaxValue = 59, Step = 1)]
        public int StartTimeMinute { get; set; }

        [Parameter("Trading End Hour:0-23", DefaultValue = 22, MinValue = 0, MaxValue = 23, Step = 1)]
        public int EndTimeHour { get; set; }

        [Parameter("Trading End Minute:0-59", DefaultValue = 0, MinValue = 0, MaxValue = 59, Step = 1)]
        public int EndTimeMinute { get; set; }

        [Parameter("Use ADX", DefaultValue = true)]
        public bool UseADX { get; set; }

        [Parameter("ADX Level", DefaultValue = 25)]
        public int ADXLevel { get; set; }

        [Parameter("ADX Period", DefaultValue = 14)]
        public int ADXPeriod { get; set; }

        [Parameter("Dynamic TP/SL - Yes/No:", Group = ("Dynamic TP/SL"), DefaultValue = true)]
        public bool DynamicTPSL { get; set; }

        [Parameter("ATR periods:", Group = ("Dynamic TP/SL"), DefaultValue = 14)]
        public int ATR_Periods { get; set; }

        [Parameter("MA Type", Group = ("Dynamic TP/SL"), DefaultValue = MovingAverageType.Simple)]
        public MovingAverageType ATR_MAType { get; set; }

        [Parameter("ATR TP Multiplier:", Group = ("Dynamic TP/SL"), DefaultValue = 300.0)]
        public double ATR_TP_Multiplier { get; set; }

        [Parameter("ATR SL Multiplier:", Group = ("Dynamic TP/SL"), DefaultValue = 200.0)]
        public double ATR_SL_Multiplier { get; set; }


        private MovingAverage MA;
        private int SignalBar;
        private double currentLotSize;
        private DateTime StartTimeHour_;
        private DateTime EndTimeHour_;
        private DateTime StartTimeMinute_;
        private DateTime EndTimeMinute_;
        private DirectionalMovementSystem dms_;

        private AverageTrueRange ATR_;


        protected override void OnStart()
        {
            MA = Indicators.MovingAverage(Bars.ClosePrices, MAPeriod, MAType);
            SignalBar = 1;
            currentLotSize = GetInitialLots(Account.Balance, ParamVolumeAdjustment);

            if (EnableMartingale == true)
                Positions.Closed += OnPositionsClosed;

            StartTimeHour_ = Server.Time.Date.AddHours(StartTimeHour);
            EndTimeHour_ = Server.Time.Date.AddHours(EndTimeHour);
            StartTimeMinute_ = Server.Time.Date.AddMinutes(StartTimeMinute);
            EndTimeMinute_ = Server.Time.Date.AddMinutes(EndTimeMinute);

            dms_ = Indicators.DirectionalMovementSystem(ADXPeriod);

            if (DynamicTPSL == true)
            {
                ATR_ = Indicators.AverageTrueRange(ATR_Periods, ATR_MAType);
            }

        }

        protected override void OnTick()
        {

        }

        protected override void OnBar()
        {
            if ((UseTradingHours == true && IsTradingHours() == true) || (UseTradingHours == false))
            {

                if (Positions.FindAll(cBotLabel, Symbol.Name).Length == 0 && (UseADX == false || (UseADX == true && CheckADX() == true)))
                {
                    if (Bars.ClosePrices.Last(SignalBar) > MA.Result.Last(SignalBar))
                    {
                        if (Bars.ClosePrices.Last(SignalBar) < Bars.OpenPrices.Last(SignalBar))
                        {
                            if (getPendingOrdersQuantity() == 0)
                                OpenStopOrder((Bars.HighPrices.Last(SignalBar) + OffsetHL * Symbol.PipSize), TradeType.Buy, currentLotSize);
                            else
                            {
                                double dNewOpenPrice = Bars.HighPrices.Last(SignalBar) + OffsetHL * Symbol.PipSize;
                                tryModifyStopOrder(TradeType.Buy, dNewOpenPrice);
                            }
                        }
                        else if (Bars.ClosePrices.Last(SignalBar) > Bars.OpenPrices.Last(SignalBar))
                        {
                            if (Bars.OpenPrices.Last(SignalBar) < MA.Result.Last(SignalBar) && getPendingOrdersQuantity() > 0)
                                cancelStopOrder(TradeType.Sell);
                        }
                    }
                    else if (Bars.ClosePrices.Last(SignalBar) < MA.Result.Last(SignalBar))
                    {
                        if (Bars.ClosePrices.Last(SignalBar) < Bars.OpenPrices.Last(SignalBar))
                        {
                            if (Bars.OpenPrices.Last(SignalBar) > MA.Result.Last(SignalBar) && getPendingOrdersQuantity() > 0)
                                cancelStopOrder(TradeType.Buy);
                        }
                        else if (Bars.ClosePrices.Last(SignalBar) > Bars.OpenPrices.Last(SignalBar))
                        {
                            if (getPendingOrdersQuantity() == 0)
                                OpenStopOrder((Bars.LowPrices.Last(SignalBar) - OffsetHL * Symbol.PipSize), TradeType.Sell, currentLotSize);
                            else
                            {
                                double dNewOpenPrice = Bars.LowPrices.Last(SignalBar) - OffsetHL * Symbol.PipSize;
                                tryModifyStopOrder(TradeType.Sell, dNewOpenPrice);
                            }
                        }
                    }
                }
            }
        }

        private int getPendingOrdersQuantity()
        {
            int count = 0;
            foreach (var order in PendingOrders)
            {
                if (order.Label == cBotLabel)
                {
                    count++;
                }
            }
            return count;
        }

        private void OpenStopOrder(double dOpenPrice, TradeType tradeType, double dLots)
        {
            var volumeInUnits = Symbol.QuantityToVolumeInUnits(dLots);
            volumeInUnits = Symbol.NormalizeVolumeInUnits(volumeInUnits, RoundingMode.Down);

            double? TakeProfitPips = TakeProfit;
            double? StopLossPips = StopLoss;

            if (DynamicTPSL == true)
            {
                TakeProfitPips = ATR_.Result.LastValue * ATR_TP_Multiplier;
                StopLossPips = ATR_.Result.LastValue * ATR_SL_Multiplier;
            }

            var result = PlaceStopOrder(tradeType, Symbol.Name, volumeInUnits, dOpenPrice, cBotLabel, StopLossPips, TakeProfitPips);
            if (!result.IsSuccessful)
            {
                Print("Placing Stop Order Error: {0}", result.Error.Value);
                OnStop();
            }
        }

        private void tryModifyStopOrder(TradeType tradeType, double dNewOpenPrice)
        {
            foreach (var order in PendingOrders)
            {
                if (order.SymbolName == Symbol.Name && order.Label == cBotLabel && order.TradeType == tradeType)
                {
                    if ((order.TradeType == TradeType.Buy && order.TargetPrice > dNewOpenPrice) || (order.TradeType == TradeType.Sell && order.TargetPrice < dNewOpenPrice))
                        ModifyPendingOrder(order, dNewOpenPrice, order.StopLossPips, order.TakeProfitPips, order.ExpirationTime);
                }
            }
        }

        private void cancelStopOrder(TradeType tradeType)
        {
            foreach (var order in PendingOrders)
            {
                if (order.SymbolName == Symbol.Name && order.Label == cBotLabel && order.TradeType == tradeType)
                {
                    CancelPendingOrder(order);
                }
            }
        }

        void OnPositionsClosed(PositionClosedEventArgs obj)
        {
            Position closedPosition = obj.Position;
            if (closedPosition.SymbolName == Symbol.Name && closedPosition.Label == cBotLabel)
            {
                if (closedPosition.NetProfit < 0.0)
                {
                    currentLotSize = Math.Min(Math.Round((currentLotSize * MartingaleMultiplier), 2), MaxTradeSize);
                }
                else
                    currentLotSize = GetInitialLots(Account.Balance, ParamVolumeAdjustment);
            }
        }

        protected double GetInitialLots(double balance, double adjustment)
        {
            if (ParamAdjustInitialVolume == true)
            {
                double volumeDouble = balance * adjustment / 100;
                double volumeLong = Symbol.NormalizeVolumeInUnits(volumeDouble, RoundingMode.Down);
                volumeLong = Math.Max(volumeLong, Symbol.VolumeInUnitsMin);
                volumeLong = Symbol.VolumeInUnitsToQuantity(volumeLong);
                return volumeLong;
            }
            else
            {
                return LotSize;
            }
        }

        private bool IsTradingHours()
        {
            var currentTimeHour = Server.Time.TimeOfDay.Hours;
            var currentTimeMinute = Server.Time.TimeOfDay.Minutes;
            if ((StartTimeHour_.Hour < currentTimeHour && EndTimeHour_.Hour > currentTimeHour) || (StartTimeHour_.Hour == currentTimeHour && StartTimeMinute_.Minute <= currentTimeMinute) || (EndTimeHour_.Hour == currentTimeHour && EndTimeMinute_.Minute >= currentTimeMinute))
                return true;

            return false;

        }

        private bool CheckADX()
        {
            if (dms_.ADX.Last(SignalBar) > ADXLevel)
                return true;

            return false;

        }

        protected override void OnStop()
        {
            Stop();
        }
    }
}


CT
ctid1731325

Joined on 10.01.2020 Blocked

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: Breakout_v1_1_2_cBot.algo
  • Rating: 5
  • Installs: 1947
Comments
Log in to add a comment.
LU
lucashenry0988 · 1 year ago

I must say that you are doing a very nice job here on this fantastic blog. just keep it on, you are good. I think you know about wholesale yellow corn suppliers In china. It will help you to start a business

NI
nielsen · 1 year ago

Very interesting with the pending orders. Congrats!