DreamzFX Position Manager (Opposite direction)

Created at 02 Dec 2020, 14:47
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!
BO

Bounce

Joined 26.11.2020

DreamzFX Position Manager (Opposite direction)
02 Dec 2020, 14:47


Adding a opposite direction

Hi there,

Is anyone able to fix this? 

I would like to add 1 thing to this cbot.
I want the bot to open a position in the opposite direction as soon as a SL is triggered.

The rest of the bot is very nice with the jumping Trailing Stop and everything.

My programming skills are second to non.

Please help a brother out.

 

Source Code:

/*
  DreamzFX Position Manager
  Version: 1.0.2
*/

using System;
using System.Threading;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
using System.Collections.Generic;
using System.IO;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FileSystem)]
    public class TradingHelper : Robot
    {
        [Parameter("StopLoss Initial", DefaultValue = 0, MinValue = 0)]
        public int StopLoss_Initial { get; set; }

        [Parameter("Take Profit Initial", DefaultValue = 0, MinValue = 0)]
        public int TakeProfit_Initial { get; set; }

        [Parameter("BreakEven After", DefaultValue = 0, MinValue = 0)]
        public int BreakEven_After { get; set; }

        [Parameter("BreakEven Profit Pips", DefaultValue = 2, MinValue = 0)]
        public int BreakEven_Profit { get; set; }

        [Parameter("BreakEven2 After", DefaultValue = 0, MinValue = 0)]
        public int BreakEven2_After { get; set; }

        [Parameter("BreakEven2 Profit Pips", DefaultValue = 0, MinValue = 0)]
        public int BreakEven2_Profit { get; set; }

        [Parameter("Jumping StopLoss", DefaultValue = 0, MinValue = 0)]
        public int Jumping_Stop { get; set; }

        [Parameter("Jumping Stop Distance", DefaultValue = 0, MinValue = 0)]
        public int Jumping_Distance { get; set; }

        [Parameter("Take Profit 1", DefaultValue = 0, MinValue = 0)]
        public int TakeProfit_1 { get; set; }

        [Parameter("Manage This Pair Only", DefaultValue = true)]
        public bool ManageThisPairOnly { get; set; }

        [Parameter("Manage By Comment", DefaultValue = false)]
        public bool ManageByComment { get; set; }

        [Parameter("Comment to Manage", DefaultValue = null)]
        public string ManagedComment { get; set; }

        [Parameter("Ignore Comment", DefaultValue = false)]
        public bool IgnoreByComment { get; set; }

        [Parameter("Comment to Ignore", DefaultValue = null)]
        public string IgnoredComment { get; set; }

        [Parameter("Manage by (0-both 1-buy 2-sell)", DefaultValue = 0)]
        public int Trade_Type { get; set; }

        /* Variables */
        private double last = 0;
        private int ticks = 10;
        public int i;
        public double Bid, Ask;
        public Symbol symbol;
        public List<int> Partial_Positions = new List<int>();
        TradeResult result;
        string FileName = "PosManager_Partials.txt";

        protected override void OnStart()
        {
            // Validate Parameters
            CheckParameters();

            // If running in Backtester, open a couple of positions
            if (IsBacktesting)
            {
                ExecuteMarketOrder(TradeType.Buy, Symbol, 2000, null, 0, 0, 0, "test");
                ExecuteMarketOrder(TradeType.Sell, Symbol, 2000);
            }
            Positions.Opened += OnPositionsOpened;
            Positions.Closed += OnPositionsClosed;
            FileRead();
            Timer.Start(1);
        }

        public void FileRead()
        {
            if (!File.Exists(FileName))
                File.Create(FileName);
            else
            {
                // Dump "FileName" into array
                string[] Ids = System.IO.File.ReadAllLines(FileName);

                File.Delete(FileName);

                StreamWriter _fileWriter;
                _fileWriter = File.AppendText(FileName);
                _fileWriter.AutoFlush = true;

                // Check which Positions from the File are Still active
                foreach (Position position in Positions)
                    foreach (string Id in Ids)
                        if (position.Id == Convert.ToInt32(Id))
                        {
                            // If the Position Exists, Add it to the Partial_Positions list and to the file
                            Partial_Positions.Add(Convert.ToInt32(Id));
                            _fileWriter.WriteLine(Id);
                            break;
                        }
                _fileWriter.Close();
            }
            for (i = 0; i < Partial_Positions.Count; i++)
                Print(Partial_Positions[i]);
        }

        protected override void OnTimer()
        {
            ticks = 0;
            OnTick();
        }

        private void OnPositionsOpened(PositionOpenedEventArgs args)
        {
            if (args.Position.SymbolCode == Symbol.Code)
            {
                ticks = 0;
                OnTick();
            }
        }

        private void OnPositionsClosed(PositionClosedEventArgs args)
        {
            // If position being closed is in the Partial_Positions list, remove it from the list
            for (i = 0; i < Partial_Positions.Count; i++)
                if (Partial_Positions[i] == args.Position.Id)
                    Partial_Positions.RemoveAt(i);
        }

        protected override void OnTick()
        {
            if (Monitor.TryEnter(this))
            {
                try
                {
                    DoWork();
                } finally
                {
                    Monitor.Exit(this);
                }
            }
        }

        // Main function to process positions
        private void DoWork()
        {
            if (--ticks > 0 && Math.Abs(last - MarketSeries.Close.LastValue) < Symbol.PipSize / 2)
                return;

            RefreshData();

            ticks = 10;
            last = MarketSeries.Close.LastValue;

            foreach (Position position in Positions)
            {
                if (!ManageThisPosition(position))
                    continue;

                symbol = MarketData.GetSymbol(position.SymbolCode);
                Bid = symbol.Bid;
                Ask = symbol.Ask;

                // Set initial stops if necessary
                if ((StopLoss_Initial > 0 && position.StopLoss == null) || (TakeProfit_Initial > 0 && position.TakeProfit == null))
                    SetStops(position);

                // BreakEven
                if (BreakEven_After > 0 && position.Pips >= BreakEven_After)
                    BreakEven(position, BreakEven_Profit);

                // BreakEven2
                if (BreakEven2_After > 0 && position.Pips >= BreakEven2_After)
                    BreakEven(position, BreakEven2_Profit);

                // Partial Closure at Take Profit 1
                if (TakeProfit_1 > 0)
                    TakeProfit1(position);

                // Jumping StopLoss. SL jumps every X pips. Also keeps a distance of Y pips below market price before setting a new SL
                // Only triggers if we're in profit
                if (Jumping_Stop > 0 && position.Pips >= Jumping_Stop + Jumping_Distance && position.Pips >= 0)
                    JumpingStop(position);
            }
        }

        // Basic Parameter Check
        private void CheckParameters()
        {
            string msg = null;
            if (BreakEven_After != 0 && BreakEven_After < BreakEven_Profit)
            {
                msg = "ERROR: 'BreakEven_After' value should be greater than 'BreakEven_Profit";
                Print(msg);
            }
            if (BreakEven2_After != 0 && BreakEven2_After < BreakEven2_Profit)
            {
                msg = "ERROR: 'BreakEven2_After' value should be greater than 'BreakEven2_Profit";
                Print(msg);
            }

            if (msg != null)
                Stop();
        }

        // Returns rounded number
        private double RND(double p)
        {
            return Math.Round(p, Symbol.Digits);
        }

        // Test if position fits the rules to be managed
        private bool ManageThisPosition(Position position)
        {
            // Check if position matches the current chart
            if (ManageThisPairOnly && position.SymbolCode != Symbol.Code)
                return false;

            // If "ManageByComment" is set to true, check if comment matches
            if (ManageByComment && position.Comment != ManagedComment)
                return false;

            // Check if position comment is to be ignored
            if (IgnoreByComment && position.Comment == IgnoredComment)
                return false;

            return true;
        }

        // Set initial StopLoss and TakeProfit
        private void SetStops(Position position)
        {
            double? NewSL = position.StopLoss;
            double? NewTP = position.TakeProfit;

            if (StopLoss_Initial > 0 && position.StopLoss == null)
            {
                // Manually close position if it's too late to set a SL
                if (position.Pips <= StopLoss_Initial * (-1))
                {
                    ClosePosition(position);
                    return;
                }

                if (position.TradeType == TradeType.Buy)
                    NewSL = RND(position.EntryPrice - StopLoss_Initial * symbol.PipSize);
                else
                    NewSL = RND(position.EntryPrice + StopLoss_Initial * symbol.PipSize);
            }

            if (TakeProfit_Initial > 0 && position.TakeProfit == null)
            {
                // Manually close position if it's too late to set a TP
                if (position.Pips >= TakeProfit_Initial)
                {
                    ClosePosition(position);
                    return;
                }

                if (position.TradeType == TradeType.Buy)
                    NewTP = RND(position.EntryPrice + TakeProfit_Initial * symbol.PipSize);
                else
                    NewTP = RND(position.EntryPrice - TakeProfit_Initial * symbol.PipSize);
            }


            result = ModifyPosition(position, NewSL, NewTP);
            if (!result.IsSuccessful)
                Print("ERROR: Setting Stops!", result.Error);
        }

        // Set a BreakEven sl at "BreakEven_Profit" after reaching "BreakEven_After"
        private void BreakEven(Position position, double BE_Profit)
        {
            double BE_Price;
            if (position.TradeType == TradeType.Buy)
            {
                BE_Price = RND(position.EntryPrice + BE_Profit * symbol.PipSize);
                if (!(position.StopLoss >= BE_Price) && BE_Price < Bid)
                {
                    result = ModifyPosition(position, BE_Price, position.TakeProfit);
                    if (!result.IsSuccessful)
                        Print("ERROR: Setting BreakEven!", result.Error);
                }
            }
            else
            {
                BE_Price = RND(position.EntryPrice - BE_Profit * symbol.PipSize);
                if (!(position.StopLoss <= BE_Price) && BE_Price > Ask)
                {
                    result = ModifyPosition(position, BE_Price, position.TakeProfit);
                    if (!result.IsSuccessful)
                        Print("ERROR: Setting BreakEven!", result.Error);
                }
            }
        }

        // Jumping StopLoss
        private void JumpingStop(Position position)
        {
            double Max = position.Pips - Jumping_Distance;
            double NewJump = Max - (Max % Jumping_Stop);
            double NewSL;

            if (position.TradeType == TradeType.Buy)
            {
                NewSL = position.EntryPrice + NewJump * symbol.PipSize;
                if (NewSL <= position.StopLoss)
                    return;
            }
            else
            {
                NewSL = position.EntryPrice - NewJump * symbol.PipSize;
                if (NewSL >= position.StopLoss)
                    return;
            }
            result = ModifyPosition(position, NewSL, position.TakeProfit);
            if (!result.IsSuccessful)
                Print("ERROR: Setting Jumping Stop!", result.Error);
        }

        // Close half the position when "Take_Profit_1" is reached
        private void TakeProfit1(Position position)
        {
            if (position.Pips >= TakeProfit_1)
            {
                long Close_Lots = Symbol.NormalizeVolume(position.Volume / 2);

                for (i = 0; i < Partial_Positions.Count; i++)
                    if (Partial_Positions[i] == position.Id)
                        return;
                // Make sure the position is divisible (not 0.01 lots)
                if (Close_Lots != position.Volume)
                {
                    result = ClosePosition(position, Close_Lots);
                    if (!result.IsSuccessful)
                        Print("ERROR: Closing Half Position!", result.Error);
                    else
                    {
                        Partial_Positions.Add(position.Id);
                        using (System.IO.StreamWriter file = new System.IO.StreamWriter(FileName, true))
                            file.WriteLine(position.Id);
                    }
                }
            }
        }

        protected override void OnStop()
        {
        }
    }
}


@Bounce