Multiple TP

Created at 15 Sep 2023, 21:48
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!
iranava's avatar

iranava

Joined 23.08.2023

Multiple TP
15 Sep 2023, 21:48


Hello
I have this cTrader bot. I want to add TP1, TP2, TP3 and TP4 to it. By determining the amount of a separate lot for each of them. Thank you for helping me. Thank you

This bot is for trading at the time of news release.

 

// -------------------------------------------------------------------------------
//   Opens a buy/sell trade (random, chosen direction, or both directions) seconds before news release.
//   Sets SL and TP. Keeps updating them until the very release.
//   Can set SL to breakeven when unrealized profit = SL.
//   Alternatively, adds ATR based trailing stop.
//   Closes trade after given time period passes.
//   Version 1.09.
//   Copyright 2015-2022, EarnForex.com
//   https://www.earnforex.com/metatrader-expert-advisors/News-Trader/
// -------------------------------------------------------------------------------

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

namespace cAlgo
{
   [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
   public class NewsTrader : Robot
   {
       [Parameter(DefaultValue = 2022, MinValue = 1970)]
       public int Year { get; set; }

       [Parameter(DefaultValue = 4, MinValue = 1, MaxValue = 12)]
       public int Month { get; set; }

       [Parameter(DefaultValue = 26, MinValue = 1, MaxValue = 31)]
       public int Day { get; set; }

       [Parameter(DefaultValue = 0, MinValue = 0, MaxValue = 23)]
       public int Hour { get; set; }

       [Parameter(DefaultValue = 0, MinValue = 0, MaxValue = 59)]
       public int Minute { get; set; }

       [Parameter("Stop-Loss, pips", DefaultValue = 15, MinValue = 0)]
       public int StopLoss { get; set; }

       [Parameter("Take-Profit, pips", DefaultValue = 75, MinValue = 0)]
       public int TakeProfit { get; set; }

       [Parameter(DefaultValue = true)]
       public bool Buy { get; set; }

       [Parameter(DefaultValue = true)]
       public bool Sell { get; set; }

       [Parameter("Randomize Buy/Sell", DefaultValue = false)]
       public bool Rnd { get; set; }

       // Trailing Stop will supersede Breakeven Stop if true.
       [Parameter("Trailing Stop", DefaultValue = false)]
       public bool Trailing { get; set; }

       [Parameter("Breakeven Stop", DefaultValue = false)]
       public bool Breakeven { get; set; }

       [Parameter("Preadjust SL/TP", DefaultValue = false)]
       public bool PreAdjustSLTP { get; set; }

       [Parameter("Seconds Before News", DefaultValue = 10, MinValue = 1)]
       public int SecondsBefore { get; set; }

       [Parameter("Close After Seconds", DefaultValue = 3600, MinValue = 1)]
       public int CloseAfterSeconds { get; set; }

       [Parameter("Use ATR Position Sizing", DefaultValue = false)]
       public bool UseATR { get; set; }

       [Parameter("ATR Period", DefaultValue = 14, MinValue = 1)]
       public int ATR_Period { get; set; }

       [Parameter("ATR Multiplier for SL", DefaultValue = 1, MinValue = 0)]
       public double ATR_Multiplier_SL { get; set; }

       [Parameter("ATR Multiplier for TP", DefaultValue = 5, MinValue = 0)]
       public double ATR_Multiplier_TP { get; set; }

       [Parameter("Volume in Lots", DefaultValue = 0.01, MinValue = 0.01)]
       public double Lots { get; set; }

       [Parameter("Money Management", DefaultValue = true)]
       public bool MM { get; set; }

       [Parameter("Risk, %", DefaultValue = 1, MinValue = 0)]
       public double Risk { get; set; }

       [Parameter("Risk, Money", DefaultValue = 0, MinValue = 0)]
       public double MoneyRisk { get; set; }

       [Parameter("Fixed Balance", DefaultValue = 0, MinValue = 0)]
       public double FixedBalance { get; set; }

       [Parameter("Use Money Instead of %", DefaultValue = false)]
       public bool UseMoneyInsteadOfPercentage { get; set; }

       [Parameter("Use Equity Instead of Balance", DefaultValue = false)]
       public bool UseEquityInsteadOfBalance { get; set; }

       [Parameter("Show Timer", DefaultValue = true)]
       public bool ShowTimer { get; set; }

       [Parameter("Vertical Corner", DefaultValue = VerticalAlignment.Top)]
       public VerticalAlignment CornerVertical { get; set; }

       [Parameter("Horizontal Corner", DefaultValue = HorizontalAlignment.Left)]
       public HorizontalAlignment CornerHorizontal { get; set; }

       [Parameter(DefaultValue = 1)]
       public int Slippage { get; set; }

       [Parameter(DefaultValue = "NewsTrader")]
       public string Commentary { get; set; }

       // Indicator handles
       private AverageTrueRange ATR;

       private DateTime news_time;
       private bool CanTrade = false;

       private double SL, TP;

       private bool HaveLongPosition = false;
       private bool HaveShortPosition = false;

       protected string MyLabel
       {
           get { return string.Format("{0} {1} {2}", Commentary, Symbol.Name, TimeFrame); }
       }

       protected override void OnStart()
       {
           news_time = new DateTime(Year, Month, Day, Hour, Minute, 0);
           double min_lot = Symbol.VolumeInUnitsToQuantity(Symbol.VolumeInUnitsMin);
           double lot_step = Symbol.VolumeInUnitsToQuantity(Symbol.VolumeInUnitsStep);
           Print("Minimum lot: ", min_lot.ToString(), ", lot step: ", lot_step.ToString(), ".");
           if ((Lots < min_lot) && (!MM))
               Print("Lots should not be less than: ", min_lot.ToString(), ".");
           else
               CanTrade = true;

           if (ShowTimer)
           {
               Chart.DrawStaticText("NewsTraderTimer", "", CornerVertical, CornerHorizontal, Color.Red);
               // For smooth updates.
               Timer.Start(TimeSpan.FromMilliseconds(100));
           }

           if (UseATR)
           {
               ATR = Indicators.AverageTrueRange(ATR_Period, MovingAverageType.Simple);
           }

           // If UseATR = false, these values will be used. Otherwise, ATR values will be calculated later.
           SL = StopLoss;
           TP = TakeProfit;
       }

//+------------------------------------------------------------------+
//| Stops timer if needed.                                           |
//+------------------------------------------------------------------+
       protected override void OnStop()
       {
           if (ShowTimer)
           {
               Timer.Stop();
           }
       }

//+------------------------------------------------------------------+
//| Updates text about time left to news or passed after news.       |
//+------------------------------------------------------------------+
       protected override void OnTimer()
       {
           string text;

           TimeSpan difference = Time.Subtract(news_time);

           if (difference <= TimeSpan.FromMilliseconds(0))
               text = "Time to news:" + TimeDistance(difference.Negate());
           else
               text = "Time after news:" + TimeDistance(difference);
           Chart.DrawStaticText("NewsTraderTimer", text + "", CornerVertical, CornerHorizontal, Color.Red);
       }

       protected override void OnTick()
       {
           if (!CanTrade)
               return;

           if (UseATR)
           {
               // Getting the ATR values
               double ATR_value = ATR.Result.LastValue;
               SL = ATR_value * ATR_Multiplier_SL;
               TP = ATR_value * ATR_Multiplier_TP;
               SL /= Symbol.PipSize;
               TP /= Symbol.PipSize;
           }

           // Check what position is currently open
           GetPositionStates();

           // Adjust SL and TP of the current position
           if ((HaveLongPosition) || (HaveShortPosition))
               ControlPosition();
           else
           {
               TimeSpan difference = Time.Subtract(news_time).Negate();
               if ((difference <= TimeSpan.FromSeconds(SecondsBefore)) && (difference > TimeSpan.FromMilliseconds(0)))
               {
                   // Randomize entry.
                   if (Rnd)
                   {
                       Random r = new Random();
                       if (r.Next() % 2 == 1)
                           fBuy();
                       else
                           fSell();
                   }
                   else if ((Buy) && (Sell))
                   {
                       fSell();
                       fBuy();
                   }
                   else if (Buy)
                       fBuy();
                   else if (Sell)
                       fSell();
               }
           }
       }


//+------------------------------------------------------------------+
//| Check what positions are currently open.       |
//+------------------------------------------------------------------+
       private void GetPositionStates()
       {
           foreach (var position in Positions)
           {
               if ((Symbol.Name == position.SymbolName) && (MyLabel == position.Label))
               {
                   if (position.TradeType == TradeType.Sell)
                       HaveShortPosition = true;
                   if (position.TradeType == TradeType.Buy)
                       HaveLongPosition = true;
               }
           }
       }


//+------------------------------------------------------------------+
//| Generic buy.              |
//+------------------------------------------------------------------+
       private void fBuy()
       {
           ExecuteMarketRangeOrder(TradeType.Buy, Symbol.Name, LotsOptimized(), Slippage, Symbol.Ask, MyLabel, SL, TP, Commentary);
       }

//+------------------------------------------------------------------+
//| Generic sell.              |
//+------------------------------------------------------------------+
       private void fSell()
       {
           ExecuteMarketRangeOrder(TradeType.Sell, Symbol.Name, LotsOptimized(), Slippage, Symbol.Bid, MyLabel, SL, TP, Commentary);
       }

//+------------------------------------------------------------------+
//| Add SL/TP, adjust SL/TP, set breakeven, close trade.          |
//+------------------------------------------------------------------+
       private void ControlPosition()
       {
           foreach (var position in Positions)
           {
               if ((Symbol.Name == position.SymbolName) && (MyLabel == position.Label))
               {
                   TimeSpan difference = Time.Subtract(news_time);
                   if ((difference < TimeSpan.FromMilliseconds(0)) && (PreAdjustSLTP))
                   {
                       double new_sl = 0, new_tp = 0;
                       if (position.TradeType == TradeType.Buy)
                       {
                           new_sl = Math.Round(Symbol.Ask - SL * Symbol.PipSize, Symbol.Digits);
                           new_tp = Math.Round(Symbol.Ask + TP * Symbol.PipSize, Symbol.Digits);
                       }
                       else if (position.TradeType == TradeType.Sell)
                       {
                           new_sl = Math.Round(Symbol.Bid + SL * Symbol.PipSize, Symbol.Digits);
                           new_tp = Math.Round(Symbol.Bid - TP * Symbol.PipSize, Symbol.Digits);
                       }
                       if ((new_sl != position.StopLoss) || (new_tp != position.TakeProfit))
                       {
                           Print("Adjusting SL: ", new_sl, " and TP: ", new_tp, ".");
                           ModifyPosition(position, new_sl, new_tp);
                       }
                   }
                   // Check for breakeven or trade time out.
                   else
                   {
                       if ((!Trailing) && (Breakeven) && ((((position.TradeType == TradeType.Buy) && (Symbol.Ask - position.EntryPrice >= SL * Symbol.PipSize)) || ((position.TradeType == TradeType.Sell) && (position.EntryPrice - Symbol.Bid >= SL * Symbol.PipSize)))))
                       {
                           double new_sl = Math.Round(position.EntryPrice, Symbol.Digits);
                           if (new_sl != position.StopLoss)
                           {
                               Print("Moving SL to breakeven: ", new_sl, ".");
                               ModifyPosition(position, new_sl, position.TakeProfit);
                           }
                       }
                       else if ((Trailing) && ((((position.TradeType == TradeType.Buy) && (Symbol.Ask - position.StopLoss >= SL * Symbol.PipSize)) || ((position.TradeType == TradeType.Sell) && (position.StopLoss - Symbol.Bid >= SL * Symbol.PipSize)))))
                       {
                           double new_sl = 0;
                           if (position.TradeType == TradeType.Buy)
                               new_sl = Math.Round(Symbol.Ask - SL * Symbol.PipSize, Symbol.Digits);
                           else if (position.TradeType == TradeType.Sell)
                               new_sl = Math.Round(Symbol.Bid + SL * Symbol.PipSize, Symbol.Digits);
                           if (((position.TradeType == TradeType.Buy) && (new_sl > position.StopLoss)) || ((position.TradeType == TradeType.Sell) && (new_sl < position.StopLoss)))
                           {
                               Print("Moving trailing SL to ", new_sl, ".");
                               ModifyPosition(position, new_sl, position.TakeProfit);
                           }
                       }
                       if (CloseAfterSeconds > 0)
                       {
                           TimeSpan after_difference = Time.Subtract(news_time);
                           if (after_difference >= TimeSpan.FromSeconds(CloseAfterSeconds))
                           {
                               Print("Closing trade by time out.");
                               ClosePosition(position);
                           }
                       }
                   }
               }
           }
       }

//+------------------------------------------------------------------+
//| Format time distance from the number of seconds to normal string |
//| of years, days, hours, minutes, and seconds.       |
//| t - time difference                 |
//| Returns: formatted string.            |
//+------------------------------------------------------------------+
       string TimeDistance(TimeSpan t)
       {
           if ((t < TimeSpan.FromSeconds(1)) && (t > TimeSpan.FromSeconds(1).Negate()))
               return (" 0 seconds");
           string s = "";
           int d = t.Days;
           int h = t.Hours;
           int m = t.Minutes;
           int sec = t.Seconds;

           if (d > 0)
               s += " " + d.ToString() + " day";
           if (d > 1)
               s += "s";

           if (h > 0)
               s += " " + h.ToString() + " hour";
           if (h > 1)
               s += "s";

           if (m > 0)
               s += " " + m.ToString() + " minute";
           if (m > 1)
               s += "s";

           if (sec > 0)
               s += " " + sec.ToString() + " second";
           if (sec > 1)
               s += "s";

           return (s);
       }

//+------------------------------------------------------------------+
//| Calculate position size depending on money management parameters.|
//+------------------------------------------------------------------+
       double LotsOptimized()
       {
           if (!MM)
               return (Symbol.QuantityToVolumeInUnits(Lots));

           double Size, RiskMoney, PositionSize = 0;

           if (Account.Asset.Name == "")
               return (0);

           if (FixedBalance > 0)
           {
               Size = FixedBalance;
           }
           else if (UseEquityInsteadOfBalance)
           {
               Size = Account.Equity;
           }
           else
           {
               Size = Account.Balance;
           }

           if (!UseMoneyInsteadOfPercentage)
               RiskMoney = Size * Risk / 100;
           else
               RiskMoney = MoneyRisk;

           double UnitCost = Symbol.PipValue;

           if ((SL != 0) && (UnitCost != 0))
               PositionSize = (int)Math.Round(RiskMoney / SL / UnitCost);

           Print(PositionSize);

           if (PositionSize < Symbol.VolumeInUnitsMin)
           {
               Print("Calculated position size (" + PositionSize + ") is less than minimum position size (" + Symbol.VolumeInUnitsMin + "). Setting position size to minimum.");
               PositionSize = Symbol.VolumeInUnitsMin;
           }
           else if (PositionSize > Symbol.VolumeInUnitsMax)
           {
               Print("Calculated position size (" + PositionSize + ") is greater than maximum position size (" + Symbol.VolumeInUnitsMax + "). Setting position size to maximum.");
               PositionSize = Symbol.VolumeInUnitsMax;
           }

           double LotStep = Symbol.VolumeInUnitsStep;
           double steps = PositionSize / LotStep;
           if (Math.Floor(steps) < steps)
           {
               Print("Calculated position size (" + PositionSize + ") uses uneven step size. Allowed step size = " + LotStep + ". Setting position size to " + (Math.Floor(steps) * LotStep) + ".");
               PositionSize = Math.Floor(steps) * LotStep;
           }

           return (PositionSize);
       }
   }
}
 


@iranava