Category Trend  Published on 22/09/2021

C-3PO (Unimate)

Description

C-3PO (Unimate) -  A simple yet effective short-term trading Breakout Strategy. This Robot serves as a template for your own strategy. make it your Own. Good Luck!

  • Easy to use and supervise
  • Fully configurable settings
  • Customizable SL, TP, Break-Even, Trailing-Stop, and Scale Out Trades
  • Built-in money management

 


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 Unimate : Robot
    {

        [Parameter("Instance Name", DefaultValue = "Trend cBot")]
        public string PositionId { get; set; }

        [Parameter("Percentage Risk Model?", Group = "Volume", DefaultValue = true)]
        public bool volPercentBool { get; set; }

        [Parameter("Risk %", Group = "Volume", DefaultValue = 1.5, MinValue = 1, MaxValue = 10)]
        public double volPercent { get; set; }

        [Parameter("Quantity", Group = "Volume", DefaultValue = 2000, MinValue = 1000, Step = 1000)]
        public int volQty { get; set; }

        [Parameter("User ATR for Protection?", Group = "Protection", DefaultValue = true)]
        public bool ATR_Protection { get; set; }

        [Parameter("StopLoss (*ATR)", Group = "Protection", DefaultValue = 2.5, Step = 0.1, MinValue = 0, MaxValue = 100)]
        public double StopLoss_ATR { get; set; }

        [Parameter("TakeProfit (*ATR)", Group = "Protection", DefaultValue = 10.0, Step = 0.1, MinValue = 0, MaxValue = 100)]
        public double TakeProfit_ATR { get; set; }

        [Parameter("Stop Loss (pips)", Group = "Protection", DefaultValue = 25, MinValue = 1)]
        public int StopLoss_Pips { get; set; }

        [Parameter("Take Profit (pips)", Group = "Protection", DefaultValue = 100, MinValue = 1)]
        public int TakeProfit_Pips { get; set; }

        [Parameter("Use Exit Strategy?", Group = "Protection", DefaultValue = true)]
        public bool ExitStrategy { get; set; }

        [Parameter("MA (Fast)", Group = "Indicators", DefaultValue = 9)]
        public int FastPeriods { get; set; }

        [Parameter("MA (Slow)", Group = "Indicators", DefaultValue = 50)]
        public int SlowPeriods { get; set; }

        [Parameter("MA (Type)", Group = "Indicators")]
        public MovingAverageType MAType { get; set; }

        [Parameter("MA (Source)", Group = "Indicators")]
        public DataSeries SourceSeries { get; set; }

        [Parameter("RSI (Periods)", Group = "Indicators", DefaultValue = 9)]
        public int Periods { get; set; }

        [Parameter("RSI (Source)", Group = "Indicators")]
        public DataSeries Source { get; set; }

        [Parameter("RSI (OverBought)", Group = "Indicators", DefaultValue = 68, MinValue = 65, MaxValue = 100)]
        public double OverBought { get; set; }

        [Parameter("RSI (OverSold)", Group = "Indicators", DefaultValue = 32, MinValue = 0, MaxValue = 35)]
        public double OverSold { get; set; }

        [Parameter("ADX (Period)", Group = "Indicators", DefaultValue = 9)]
        public int Period { get; set; }

        [Parameter("ADX (Threshold)", Group = "Indicators", DefaultValue = 21)]
        public int Threshold { get; set; }

        [Parameter("Enabled", Group = "Break Even", DefaultValue = true)]
        public bool BreakEvenEnabled { get; set; }

        [Parameter("Trigger (*ATR)", Group = "Break Even", DefaultValue = 2.5, Step = 0.1, MinValue = 1, MaxValue = 10)]
        public double Trigger_ATR { get; set; }

        [Parameter("Trigger Pips", Group = "Break Even", DefaultValue = 25, MinValue = 1)]
        public double Trigger_Pips { get; set; }

        [Parameter("Add Pips", Group = "Break Even", DefaultValue = 2.0, MinValue = 0.0)]
        public double AddPips { get; set; }

        [Parameter("OnTick", Group = "Break Even", DefaultValue = false)]
        public bool OnTickBreakEvenEnabled { get; set; }

        [Parameter("Enabled", Group = "Tralling Stop", DefaultValue = true)]
        public bool TrallingStopEnabled { get; set; }

        [Parameter("Tralling Stop (*ATR)", Group = "Tralling Stop", DefaultValue = 3.0)]
        public int TrallingStop_ATR { get; set; }

        [Parameter("Tralling Stop (pips)", Group = "Tralling Stop", DefaultValue = 30.0)]
        public int TrallingStop_Pips { get; set; }

        [Parameter("OnTick", Group = "Tralling Stop", DefaultValue = false)]
        public bool OnTickTrallingStopEnabled { get; set; }

        [Parameter("Only Show", Group = "Take Profit", DefaultValue = false)]
        public bool onlyShowEnabled = false;

        [Parameter("Enabled", Group = "Take Profit 1", DefaultValue = true)]
        public bool TakeProfit1Enabled { get; set; }

        [Parameter("*ATR", Group = "Take Profit 1", DefaultValue = 2.5)]
        public double TakeProfit1_ATR { get; set; }

        [Parameter("Pips", Group = "Take Profit 1", DefaultValue = 25)]
        public double TakeProfit1_Pips { get; set; }

        [Parameter("Volume", Group = "Take Profit 1", DefaultValue = 1000)]
        public int TakeProfit1Volume { get; set; }

        [Parameter("Enabled", Group = "Take Profit 2", DefaultValue = false)]
        public bool TakeProfit2Enabled { get; set; }

        [Parameter("*ATR", Group = "Take Profit 2", DefaultValue = 5.0)]
        public double TakeProfit2_ATR { get; set; }

        [Parameter("Pips", Group = "Take Profit 2", DefaultValue = 50)]
        public double TakeProfit2_Pips { get; set; }

        [Parameter("Volume", Group = "Take Profit 2", DefaultValue = 1000)]
        public int TakeProfit2Volume { get; set; }

        [Parameter("Enabled", Group = "Take Profit 3", DefaultValue = false)]
        public bool TakeProfit3Enabled { get; set; }

        [Parameter("*ATR", Group = "Take Profit 3", DefaultValue = 7.5)]
        public double TakeProfit3_ATR { get; set; }

        [Parameter("Pips", Group = "Take Profit 3", DefaultValue = 75)]
        public double TakeProfit3_Pips { get; set; }

        [Parameter("Volume", Group = "Take Profit 3", DefaultValue = 1000)]
        public int TakeProfit3Volume { get; set; }

        [Parameter("Enabled", Group = "Take Profit 4", DefaultValue = false)]
        public bool TakeProfit4Enabled { get; set; }

        [Parameter("*ATR", Group = "Take Profit 4", DefaultValue = 10.0)]
        public double TakeProfit4_ATR { get; set; }

        [Parameter("Pips", Group = "Take Profit 4", DefaultValue = 100)]
        public double TakeProfit4_Pips { get; set; }

        [Parameter("Volume", Group = "Take Profit 4", DefaultValue = 1000)]
        public int TakeProfit4Volume { get; set; }

        [Parameter("Max Allowable Spread", Group = "Filter", DefaultValue = 2.0, MinValue = 0.1, MaxValue = 100.0, Step = 0.1)]
        public double MaxSpread { get; set; }

        [Parameter("Allowable Slippage", Group = "Filter", DefaultValue = 3.0, MinValue = 0.5, Step = 0.1)]
        public double Slippage { get; set; }

        [Parameter("Comment", Group = "Filter", DefaultValue = "Unimate")]
        public string Comment { get; set; }

        private AverageTrueRange ATR;
        private MovingAverage PAC_hi;
        private MovingAverage PAC_low;
        private MovingAverage slowMa;
        private RelativeStrengthIndex RSI;
        private DirectionalMovementSystem _dms;
        private TakeProfitLevel[] _levels;
        private bool entrar = true;
        private SymbolInfo _symbolInfo;
        private double SPREAD;
        private int VolumeInUnits;
        private double Stop_Loss;
        private double Take_Profit;
        private double Break_Even;
        private double Tralling_Stop;
        private double Scale_Out1;
        private double Scale_Out2;
        private double Scale_Out3;
        private double Scale_Out4;

        #region Calculate Volume
        private int CalculateVolume(double stopLossPips)
        {
            int result;
            switch (volPercentBool)
            {
                case true:
                    double costPerPip = (double)((int)(Symbol.PipValue * 10000000)) / 100;
                    double posSizeForRisk = (Account.Balance * volPercent / 100) / (stopLossPips * costPerPip);
                    double posSizeToVol = (Math.Round(posSizeForRisk, 2) * 100000);
                    Print("Cost per Pip: $ {0},   ||   Position Size (Lot): {1},   ||   Position Size (Unit): {2}", costPerPip, Math.Round(posSizeForRisk, 2), posSizeToVol);
                    result = (int)Symbol.NormalizeVolumeInUnits(posSizeToVol, RoundingMode.ToNearest);
                    result = result > 150000 ? 150000 : result;
                    result = result <= 1000 ? 2000 : result;
                    Print("{0}% of Account Balance used for Volume!   ||   Volume equals {1}", volPercent, result);
                    break;
                default:
                    result = volQty;
                    Print("Volume Quantity Used! Volume equals {0}", result);
                    break;
            }
            return result;
        }
        #endregion

        /// This is called when the robot first starts, it is only called once.
        protected override void OnStart()
        {
            ATR = Indicators.AverageTrueRange(14, MovingAverageType.Exponential);
            PAC_hi = Indicators.MovingAverage(Bars.HighPrices, FastPeriods, MAType);
            PAC_low = Indicators.MovingAverage(Bars.LowPrices, FastPeriods, MAType);
            slowMa = Indicators.MovingAverage(SourceSeries, SlowPeriods, MAType);
            RSI = Indicators.RelativeStrengthIndex(Source, Periods);
            _dms = Indicators.DirectionalMovementSystem(Period);

            SPREAD = (double)((int)Math.Round(Symbol.Spread / Symbol.PipSize, 5));


            if (ATR_Protection)
            {
                Stop_Loss = (double)((int)Math.Round((ATR.Result.Last(1)) * StopLoss_ATR / Symbol.PipSize, 5));
                Take_Profit = (double)((int)Math.Round((ATR.Result.Last(1)) * TakeProfit_ATR / Symbol.PipSize, 5));
                Break_Even = (double)((int)Math.Round((ATR.Result.Last(1)) * Trigger_ATR / Symbol.PipSize, 5));
                Tralling_Stop = (double)((int)Math.Round((ATR.Result.Last(1)) * TrallingStop_ATR / Symbol.PipSize, 5));
                Scale_Out1 = (double)((int)Math.Round((ATR.Result.Last(1)) * TakeProfit1_ATR / Symbol.PipSize, 5));
                Scale_Out2 = (double)((int)Math.Round((ATR.Result.Last(1)) * TakeProfit2_ATR / Symbol.PipSize, 5));
                Scale_Out3 = (double)((int)Math.Round((ATR.Result.Last(1)) * TakeProfit3_ATR / Symbol.PipSize, 5));
                Scale_Out4 = (double)((int)Math.Round((ATR.Result.Last(1)) * TakeProfit4_ATR / Symbol.PipSize, 5));
            }
            else if (!ATR_Protection)
            {
                Stop_Loss = StopLoss_Pips;
                Take_Profit = TakeProfit_Pips;
                Break_Even = Trigger_Pips;
                Tralling_Stop = TrallingStop_Pips;
                Scale_Out1 = TakeProfit1_Pips;
                Scale_Out2 = TakeProfit2_Pips;
                Scale_Out3 = TakeProfit3_Pips;
                Scale_Out4 = TakeProfit4_Pips;
            }
            VolumeInUnits = CalculateVolume(Stop_Loss);
            // Subscribe to the Trade Closing event
            Positions.Closed += OnPositionsClosed;
        }
        /// This event handler is called every tick or every time the price changes for the symbol.
        protected override void OnTick()
        {
            var longPosition = Positions.Find(PositionId, SymbolName, TradeType.Buy);
            var shortPosition = Positions.Find(PositionId, SymbolName, TradeType.Sell);
            var Open = Bars.OpenPrices.Last(1);
            var Close = Bars.ClosePrices.Last(1);
            var Range = Bars.HighPrices.Last(1) - Bars.LowPrices.Last(1);
            var GreenBar = Bars.ClosePrices.Last(1) - Bars.OpenPrices.Last(1);
            var RedBar = Bars.OpenPrices.Last(1) - Bars.ClosePrices.Last(1);
            var PAC_High = PAC_hi.Result.Last(1);
            var PAC_Low = PAC_low.Result.Last(1);
            var Trend = slowMa.Result.Last(1);
            var Rsi = RSI.Result.Last(1);
            var ADX = _dms.ADX.LastValue;
            var DIPlus = _dms.DIPlus.Last(1);
            var DIMinus = _dms.DIMinus.Last(1);

            if ((GreenBar / Range) >= 0.65 && Close > PAC_High && Open < PAC_High && PAC_Low >= Trend && Rsi >= 50 && Rsi < OverBought && ADX >= Threshold && DIPlus > DIMinus && SPREAD <= MaxSpread && longPosition == null)
            {
                if (shortPosition != null)
                    ClosePosition(shortPosition);
                ExecuteMarketRangeOrder(TradeType.Buy, this.Symbol.Name, VolumeInUnits, Slippage, Symbol.Bid, PositionId.ToString(), Stop_Loss, Take_Profit, Comment);
                if (LastResult.IsSuccessful)
                    Print("PID: [ {0} ] Open {1} {2}    ||   Volume: {3}    ||   Spread: {4}   ||   Stoploss: {5}   ||   TakeProfit: {6}   ||   {7} {8}:{9}:{10}", LastResult.Position.Id, "Long Position for ", SymbolName, LastResult.Position.VolumeInUnits, SPREAD, Stop_Loss, Take_Profit, Server.Time.DayOfWeek, Server.Time.Hour,
                    Server.Time.Minute, Server.Time.Second);
            }
            else if ((RedBar / Range) >= 0.65 && Close < PAC_Low && Open > PAC_Low && PAC_High <= Trend && Rsi <= 50 && Rsi > OverSold && ADX >= Threshold && DIPlus < DIMinus && SPREAD <= MaxSpread && shortPosition == null)
            {
                if (longPosition != null)
                    ClosePosition(longPosition);
                ExecuteMarketRangeOrder(TradeType.Sell, this.Symbol.Name, VolumeInUnits, Slippage, Symbol.Bid, PositionId.ToString(), Stop_Loss, Take_Profit, Comment);
                if (LastResult.IsSuccessful)
                    Print("PID: [ {0} ] Open {1} {2}    ||   Volume: {3}    ||   Spread: {4}   ||   Stoploss: {5}   ||   TakeProfit: {6}   ||   {7} {8}:{9}:{10}", LastResult.Position.Id, "Short Position for ", SymbolName, LastResult.Position.VolumeInUnits, SPREAD, Stop_Loss, Take_Profit, Server.Time.DayOfWeek, Server.Time.Hour,
                    Server.Time.Minute, Server.Time.Second);

            }
            if (Close > PAC_High || ((GreenBar / Range) >= 0.75 && Close > PAC_Low))
            {
                if (ExitStrategy && shortPosition != null)
                    ClosePosition(shortPosition);
            }

            else if (Close < PAC_Low || ((RedBar / Range) >= 0.75 && Close < PAC_High))
            {

                if (ExitStrategy && longPosition != null)
                    ClosePosition(longPosition);
            }
            var position = Positions.Find(PositionId);
            if (position != null && entrar)
            {
                _symbolInfo = Symbols.GetSymbolInfo(position.SymbolName);
                _levels = GetTakeProfitLevels();
                ValidateLevels(position);
                entrar = false;
            }

            if (position == null)
            {
                entrar = true;
            }

            profit123();


            if (TrallingStopEnabled && OnTickTrallingStopEnabled)
            {
                TrallingStop();
            }

            if (BreakEvenEnabled && OnTickBreakEvenEnabled)
            {
                BreakEvenIfNeeded();
            }
        }

        /// a handler that is called on stopping the cBot.
        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }

        /// a special Robot class member that handles situations with errors.
        protected override void OnError(Error error)
        {
            Print("Error Code {0}", error.Code);
        }

        /// a special event handler that is called each time a new bar is drawn on chart.
        /// if you want your robot to act only when the previous bar is closed, this standard handler is where you put your main trading code.
        protected override void OnBar()
        {
            if (BreakEvenEnabled && OnTickBreakEvenEnabled == false)
            {
                BreakEvenIfNeeded();
            }

            if (TrallingStopEnabled && OnTickTrallingStopEnabled == false)
            {
                TrallingStop();
            }
        }

        protected void profit123()
        {
            var position = Positions.Find(PositionId);
            if (position != null)
            {

                var reachedLevels = _levels.Where(level => level.IsEnabled && !level.IsTriggered && level.Pips <= position.Pips);

                foreach (var reachedLevel in reachedLevels)
                {
                    reachedLevel.MarkAsTriggered();

                    Print("PID: [ {0} ] Scale Out {1}   ||   {2}  is reached.  ||   Gain/Loss {3} Pips / $ {4}   ||   {5} {6}:{7}:{8}", LastResult.Position.Id, SymbolName, reachedLevel.Name, LastResult.Position.Pips, LastResult.Position.NetProfit, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
                    var volumeToClose = Math.Min(reachedLevel.Volume, position.VolumeInUnits);

                    if (position.TradeType == TradeType.Buy)
                    {
                        Chart.DrawIcon("poMarker1" + Bars.OpenTimes.Last(0).ToString() + "" + reachedLevel.Pips, ChartIconType.Square, Bars.OpenTimes.LastValue, Bars.LowPrices.Last(0) - (reachedLevel.Pips * Symbol.PipSize), reachedLevel.mColor);
                    }
                    else
                    {
                        Chart.DrawIcon("poMarker1" + Bars.OpenTimes.Last(0).ToString() + "" + reachedLevel.Pips, ChartIconType.Square, Bars.OpenTimes.LastValue, Bars.HighPrices.Last(0) + (reachedLevel.Pips * Symbol.PipSize), reachedLevel.mColor);
                    }

                    if (onlyShowEnabled == false)
                    {
                        ClosePosition(position, volumeToClose);
                    }
                }
            }
        }

        protected void TrallingStop()
        {
            var position = Positions.Find(PositionId);
            if (position != null)
            {
                if (position.TradeType == TradeType.Sell)
                {
                    double? stopLossPrice = Symbol.Bid + Tralling_Stop * Symbol.PipSize;
                    if (Tralling_Stop != 0 && stopLossPrice < position.StopLoss && stopLossPrice < position.EntryPrice)
                        if (stopLossPrice - Symbol.Bid > 0)
                        {
                            ModifyPosition(position, stopLossPrice, position.TakeProfit);
                            Print("PID: [ {0} ] Trailing {1}   ||   New StopLoss: {2}   ||   {3} {4}:{5}:{6}", LastResult.Position.Id, SymbolName, LastResult.Position.StopLoss, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
                        }
                }
                else
                {
                    double stopLossPrice = Symbol.Ask - Tralling_Stop * Symbol.PipSize;
                    if (Tralling_Stop != 0 && stopLossPrice > position.StopLoss && stopLossPrice > position.EntryPrice)
                        if (stopLossPrice - Symbol.Ask < 0)
                        {
                            ModifyPosition(position, stopLossPrice, position.TakeProfit);
                            Print("PID: [ {0} ] Trailing {1}   ||   New StopLoss: {2}   ||   {3} {4}:{5}:{6}", LastResult.Position.Id, SymbolName, LastResult.Position.StopLoss, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
                        }
                }
            }
        }
        private void OnPositionsClosed(PositionClosedEventArgs args)
        {
            // check if the position has been closed due to stoploss or takeprofit or any other(stop out etc)
            if (args.Reason == PositionCloseReason.StopLoss)
            {
                Print("PID: [ {0} ] Stoploss Hit {1}   ||   Gain/Loss {2}Pips / $ {3}   ||   Spread:{4}   ||   {5} {6}:{7}:{8} ", LastResult.Position.Id, SymbolName, LastResult.Position.Pips, LastResult.Position.NetProfit, SPREAD, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
            }
            else if (args.Reason == PositionCloseReason.TakeProfit)
            {
                Print("PID: [ {0} ] Take Profit Hit {1}   ||   Gain/Loss {2}Pips / $ {3}   ||   Spread:{4}   ||   {5} {6}:{7}:{8}", LastResult.Position.Id, SymbolName, LastResult.Position.Pips, LastResult.Position.NetProfit, SPREAD, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
            }
            else if (args.Reason == PositionCloseReason.Closed)
            {
                Print("PID: [ {0} ] Exit Trade {1}   ||   Gain/Loss {2}Pips / $ {3}   ||   Spread:{4}   ||   {5} {6}:{7}:{8}", LastResult.Position.Id, SymbolName, LastResult.Position.Pips, LastResult.Position.NetProfit, SPREAD, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
            }
            else if (args.Reason == PositionCloseReason.StopOut)
            {
                Print("PID: [ {0} ] StopOut {1}   ||   Gain/Loss {2}Pips / $ {3}   ||   Spread:{4}   ||   {5} {6}:{7}:{8}", LastResult.Position.Id, SymbolName, LastResult.Position.Pips, LastResult.Position.NetProfit, SPREAD, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
            }
        }

        private void ValidateLevels(Position position)
        {
            MakeSureAnyLevelEnabled();
            ValidateTotalVolume(position);
            ValidateReachedLevels(position);
            ValidateVolumes();
        }

        private void ValidateVolumes()
        {
            var enabledLevels = _levels.Where(level => level.IsEnabled);
            foreach (var level in enabledLevels)
            {
                if (level.Volume < _symbolInfo.VolumeInUnitsMin)
                    PrintErrorAndStop("Volume for " + _symbolInfo.Name + " cannot be less than " + _symbolInfo.VolumeInUnitsMin);
                if (level.Volume > _symbolInfo.VolumeInUnitsMax)
                    PrintErrorAndStop("Volume for " + _symbolInfo.Name + " cannot be greater than " + _symbolInfo.VolumeInUnitsMax);
                if (level.Volume % _symbolInfo.VolumeInUnitsMin != 0)
                    PrintErrorAndStop("Volume " + level.Volume + " is invalid");
            }
        }

        private void ValidateReachedLevels(Position position)
        {
            var reachedLevel = _levels.FirstOrDefault(l => l.Pips <= position.Pips);
            if (reachedLevel != null)
                PrintErrorAndStop("Level " + reachedLevel.Name + " is already reached. The amount of Pips must be more than the amount of Pips that the Position is already gaining");
        }

        private void MakeSureAnyLevelEnabled()
        {
            if (_levels.All(level => !level.IsEnabled))
                PrintErrorAndStop("You have to enable at least one \"Take Profit\" in cBot Parameters");
        }

        private void ValidateTotalVolume(Position position)
        {
            var totalVolume = _levels.Where(level => level.IsEnabled).Sum(level => level.Volume);

            if (totalVolume > position.VolumeInUnits)
                PrintErrorAndStop("The sum of all Take Profit respective volumes cannot be larger than the Position's volume");
        }

        private TakeProfitLevel[] GetTakeProfitLevels()
        {
            return new[] 
            {
                new TakeProfitLevel("Take Profit 1", TakeProfit1Enabled, Scale_Out1, TakeProfit1Volume, Color.LightBlue),
                new TakeProfitLevel("Take Profit 2", TakeProfit2Enabled, Scale_Out2, TakeProfit2Volume, Color.SkyBlue),
                new TakeProfitLevel("Take Profit 3", TakeProfit3Enabled, Scale_Out3, TakeProfit3Volume, Color.MidnightBlue),
                new TakeProfitLevel("Take Profit 4", TakeProfit4Enabled, Scale_Out4, TakeProfit4Volume, Color.Blue)
            };
        }
        private void PrintErrorAndStop(string errorMessage)
        {
            Print(errorMessage);
            //  Stop();

            // throw new Exception(errorMessage);
        }
        /// Call custom class method to move StopLoss to BreakEven
        private void BreakEvenIfNeeded()
        {
            var position = Positions.Find(PositionId);
            if (position == null)
                return;

            if (position.Pips < Break_Even)
                return;

            var desiredNetProfitInDepositAsset = AddPips * _symbolInfo.PipValue * position.VolumeInUnits;
            var desiredGrossProfitInDepositAsset = desiredNetProfitInDepositAsset - position.Commissions * 2 - position.Swap;
            var quoteToDepositRate = _symbolInfo.PipValue / _symbolInfo.PipSize;
            var priceDifference = desiredGrossProfitInDepositAsset / (position.VolumeInUnits * quoteToDepositRate);

            var priceAdjustment = GetPriceAdjustmentByTradeType(position.TradeType, priceDifference);
            var breakEvenLevel = position.EntryPrice + priceAdjustment;
            var roundedBreakEvenLevel = RoundPrice(breakEvenLevel, position.TradeType);


            if (position.TradeType == TradeType.Sell && position.StopLoss < position.EntryPrice)
                return;

            if (position.TradeType == TradeType.Buy && position.StopLoss > position.EntryPrice)
                return;

            ModifyPosition(position, roundedBreakEvenLevel, position.TakeProfit);

            Print("PID: [ {0} ] Break Even {1}  ||   ({2}  -  {3})   || {4} {5}:{6}:{7}", LastResult.Position.Id, SymbolName, roundedBreakEvenLevel, position.StopLoss, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);

        }

        private double RoundPrice(double price, TradeType tradeType)
        {
            var multiplier = Math.Pow(10, _symbolInfo.Digits);

            if (tradeType == TradeType.Buy)
                return Math.Ceiling(price * multiplier) / multiplier;

            return Math.Floor(price * multiplier) / multiplier;
        }

        private static double GetPriceAdjustmentByTradeType(TradeType tradeType, double priceDifference)
        {
            if (tradeType == TradeType.Buy)
                return priceDifference;

            return -priceDifference;
        }
    }


    internal class TakeProfitLevel
    {
        public string Name { get; private set; }

        public bool IsEnabled { get; private set; }

        public double Pips { get; private set; }

        public int Volume { get; private set; }

        public bool IsTriggered { get; private set; }

        public Color mColor;

        public TakeProfitLevel(string name, bool isEnabled, double pips, int volume, Color c)
        {
            Name = name;
            IsEnabled = isEnabled;
            Pips = pips;
            Volume = volume;
            mColor = c;
        }

        public void MarkAsTriggered()
        {
            IsTriggered = true;
        }
    }
}


TR
traderfxmaster007

Joined on 09.07.2019

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: C-3PO (Unimate).algo
  • Rating: 5
  • Installs: 2186
  • Modified: 13/10/2021 09:54
Comments
Log in to add a comment.
angler's avatar
angler · 7 months ago

非常好,感谢你

RI

Thanks for the bot, really nice.