Category Other  Published on 15/11/2023

MULTISYMBOL CBOT BETA

Description

ATTENTION, THIS CBOT IS NOT INTENDED TO BE USED AS-IS; IT IS A BETA TEST VERSION.

This robot demonstrates the use of a multisymbol robot with cTrader. It is intended for educational purposes.(Bugs possible) For use it take the indicator here : https://ctrader.com/algos/indicators/show/3757

Example of optimization for the dates from 14/10/2023 to 14/11/2023 on the EURUSD 1h. (+95% Without : monney management, correlation, symbol analysis etc…)

Contact me on Telegram for collaborative work: https://t.me/nimi012

 


// Version 1.0

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

namespace cAlgo.Robots
{
    //Set time zone to Eastern Standard Time EP9-Best time to trade
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class MultiSymbolTGR : Robot
    {
        //Create Parameters EP10-Functions and Parameters
        [Parameter("Update Method", DefaultValue = UpdateMethodType.OnBar, Group = "============================================================================\nBASE SETTING\n============================================================================")]
        public UpdateMethodType UpdateMethod { get; set; }
        public enum UpdateMethodType
        {
            OnBar,
            OnTick
        }

        [Parameter("Trade Start Hour", DefaultValue = 1, Group = "Open Management")]
        public int StartHour { get; set; }
        [Parameter("Trade End Hour", DefaultValue = 23, Group = "Open Management")]
        public int EndHour { get; set; }

        [Parameter("Symbol Selection Method", DefaultValue = SymbolSelectionMethodType.WatchList, Group = "Symbol Management")]
        public SymbolSelectionMethodType SymbolSelectionMethod { get; set; }
        public enum SymbolSelectionMethodType
        {
            CurrentChart,
            SymbolList,
            WatchList
        }

        [Parameter("Symbol List", DefaultValue = "USDHUF USDCZK NOKSEK NOKJPY EURZAR EURCZK USDPLN EURNOK USDSEK NZDCAD CHFJPY GBPJPY EURJPY NZDUSD GBPCHF GBPAUD EURCHF AUDCAD GBPUSD", Group = "Symbol Management")]
        public string TradedSymbols { get; set; }
        [Parameter("Watchlist Name", DefaultValue = "Good Spread", Group = "Symbol Management")]
        public string WatchlistName { get; set; }

        [Parameter("Fix Trade Amount", DefaultValue = false, Group = "============================================================================\nMONNEY MANAGEMENT\n============================================================================")]
        public bool FixTradeAmount { get; set; }
        [Parameter("Max Risk %", DefaultValue = 1.9, Group = "============================================================================\nMONNEY MANAGEMENT\n============================================================================")]
        public double MaxRiskPct { get; set; }
        [Parameter("Max Spread (in Pips)", DefaultValue = 3.1, MinValue = 0.1, Group = "============================================================================\nMONNEY MANAGEMENT\n============================================================================")]
        public double MaxSpred { get; set; }
        [Parameter("Min Bars after Close", DefaultValue = 21, Group = "============================================================================\nMONNEY MANAGEMENT\n============================================================================")]
        public int MinBarsAfterClose { get; set; }

        [Parameter("Martingale Mode", DefaultValue = MartingaleModeType.Standard, Group = "Martingale Management")]
        public MartingaleModeType MartingaleMode { get; set; }
        public enum MartingaleModeType
        {
            None,
            Standard,
            DrawDown
        }
        [Parameter("Martingale Increase Step", DefaultValue = 3, Group = "Martingale Management")]
        public double MartingaleIncrease { get; set; }
        [Parameter("Max Martingale Steps", DefaultValue = 2, Group = "Martingale Management")]
        public int MartingaleMaxSteps { get; set; }
        [Parameter("Martingale Break-Even ±Range [pips]", DefaultValue = 5, MinValue = 0.0, Group = "Martingale Management")]
        public double MartingaleBreakevenRange { get; set; }

        [Parameter("Pips Confirmation", DefaultValue = 1.2, Group = "============================================================================\nOPEN TYPE\n============================================================================")]
        public double PipsConfirmation { get; set; }
        [Parameter("Tp Factor", DefaultValue = 4, Group = "============================================================================\nOPEN TYPE\n============================================================================")]
        public double TpFactor { get; set; }

        [Parameter("TP Method", DefaultValue = TPMethodeType.None, Group = "Exit Management")]
        public TPMethodeType TPMethode { get; set; }
        public enum TPMethodeType
        {
            None
        }
        [Parameter("TSL on Start", DefaultValue = false, Group = "Exit")]
        public bool TSLOnStart { get; set; }
        [Parameter("Check on Tick", DefaultValue = false, Group = "Exit")]
        public bool CheckOnTick { get; set; }

        [Parameter("Level Buy", DefaultValue = 1, Group = "TGR")]
        public double LevelBuy { get; set; }
        [Parameter("Level Sell", DefaultValue = 88, Group = "TGR")]
        public double LevelSell { get; set; }
        [Parameter("Over Buy", DefaultValue = 110, Group = "TGR")]
        public double OverBuy { get; set; }
        [Parameter("Over Sell", DefaultValue = 5, Group = "TGR")]
        public double OverSell { get; set; }
        [Parameter("Over(Buy/Sell) In Look Back", DefaultValue = false, Group = "TGR")]
        public bool InLookBack { get; set; }
        [Parameter("Over(Buy/Sell) LookBack", DefaultValue = 150, Group = "TGR")]
        public int OverBuySellLookBack { get; set; }

        ///////////////////////////////////////////////
        [Parameter("Indicator Type", DefaultValue = ATGRBARSv3.EnumIndicatorType.Over_Buy_Sell, Group = " TGR Setting")]
        public ATGRBARSv3.EnumIndicatorType IndicatorType { get; set; }

        [Parameter("Initial Periods", DefaultValue = 17, Group = "Initialization")]
        public int Periods { get; set; }
        [Parameter("Sources Bars", DefaultValue = ATGRBARSv3.EnumSourcesBars.High_And_Low, Group = "Initialization")]
        public ATGRBARSv3.EnumSourcesBars SourcesBars { get; set; }

        [Parameter("Sources Over(Buy/Sell)", DefaultValue = ATGRBARSv3.EnumSourcesOverBuySell.Median_Price, Group = "Initialization")]
        public ATGRBARSv3.EnumSourcesOverBuySell SourcesOverBuySell { get; set; }

        [Parameter("Nbrs Indicator Load  ", DefaultValue = 10, Group = "LoadCount")]
        public int NbrsLoad { get; set; }
        [Parameter("Periods Multiplicator ", DefaultValue = 1.418, Group = "LoadCount")]
        public double PeriodsMultiTgr { get; set; }

        [Parameter("Smooth Sensibility Over(Buy/Sell) ", DefaultValue = 2, Group = "  Over(Buy/Sell")]
        public int SensibilityOverBuySell { get; set; }
        [Parameter("Smooth Result", DefaultValue = 13, Group = "  Over(Buy/Sell")]
        public int Smooth { get; set; }
        [Parameter("Smooth Type", DefaultValue = MovingAverageType.Weighted, Group = "  Over(Buy/Sell")]
        public MovingAverageType SmoothType { get; set; }

        [Parameter("Period Signal Result", DefaultValue = 34, Group = "Signal")]
        public int PeriodSignalResult { get; set; }
        [Parameter("MaType Signal Result", DefaultValue = MovingAverageType.Weighted, Group = "Signal")]
        public MovingAverageType MaTypeSignalResult { get; set; }

        [Parameter("Period Histo 1", DefaultValue = 2, Group = "Histogram")]
        public int PeriodS1 { get; set; }
        [Parameter("MaType Histo 1", DefaultValue = MovingAverageType.Exponential, Group = "Histogram")]
        public MovingAverageType MaTypeS1 { get; set; }

        [Parameter("Period Histo 2", DefaultValue = 114, Group = "Histogram")]
        public int PeriodS2 { get; set; }
        [Parameter("MaType Histo 2", DefaultValue = MovingAverageType.Weighted, Group = "Histogram")]
        public MovingAverageType MaTypeS2 { get; set; }

        //Create indicator variables EP5-ATR
        private ATGRBARSv3[] tgr;
        private AverageTrueRange[] atr;
        private DonchianChannel[] dcn;

        private string botName;
        private double initialBalance;
        private List<double>[] drawdown;
        private Symbol[] TradeList;
        private int barsBack;
        private DateTime startTime;
        private int[] lastLongCloseIndex;
        private int[] lastShortCloseIndex;
        private bool[] longSlLevelReached;
        private bool[] shortSlLevelReached;
        private int[] martingaleStep;
        private double peak;
        private DateTime[] LookBackOverBuy, LookBackOverSell;

        protected override void OnStart()
        {
            if (SymbolSelectionMethod == SymbolSelectionMethodType.WatchList)
            {
                // Get the trade list from the watchlist provided by the user
                foreach (Watchlist w in Watchlists)
                {
                    if (w.Name == WatchlistName)
                    {
                        TradeList = Symbols.GetSymbols(w.SymbolNames.ToArray());
                    }
                }
            }
            else if (SymbolSelectionMethod == SymbolSelectionMethodType.SymbolList)
            {
                // Get the trade list from the sysmbol list provided by the user
                string[] SymbolList = TradedSymbols.Split(' ');

                TradeList = Symbols.GetSymbols(SymbolList);
            }
            else
            {
                TradeList = new Symbol[1];
                TradeList[0] = Symbol;
            }

            // Get all available symbols
            //TradeList = new Symbol[Symbols.Count];

            tgr = new ATGRBARSv3[TradeList.Length];
            atr = new AverageTrueRange[TradeList.Length];
            dcn = new DonchianChannel[TradeList.Length];

            drawdown = new List<double>[TradeList.Length + 1].Select(item => new List<double>()).ToArray();

            lastLongCloseIndex = new int[TradeList.Length];
            lastShortCloseIndex = new int[TradeList.Length];
            longSlLevelReached = new bool[TradeList.Length];
            shortSlLevelReached = new bool[TradeList.Length];
            martingaleStep = new int[TradeList.Length];

            LookBackOverBuy = new DateTime[TradeList.Length];
            LookBackOverSell = new DateTime[TradeList.Length];

            // We subscribe to the bar event for each symbol for the current timeframe

            Print("{0} traded symbols: ", TradeList.Length);
            peak = Account.Balance;
            int i = 0;
            foreach (var symbol in TradeList)
            {
                Print(symbol.Name);

                var bars = MarketData.GetBars(TimeFrame, symbol.Name);

                if (UpdateMethod == UpdateMethodType.OnTick)
                {
                    bars.Tick += OnBarTick;
                    barsBack = 0;
                }

                else if (UpdateMethod == UpdateMethodType.OnBar)
                {
                    bars.BarOpened += OnBarOpened;
                    barsBack = 1;

                    if (CheckOnTick)
                    {
                        bars.Tick += OnBarTick;
                    }
                }
                //Load indicators on start up EP5-ATR
                tgr[i] = Indicators.GetIndicator<ATGRBARSv3>(bars, IndicatorType, Periods, SourcesBars, SourcesOverBuySell, NbrsLoad, PeriodsMultiTgr, SensibilityOverBuySell, Smooth, SmoothType, PeriodSignalResult, MaTypeSignalResult, PeriodS1, MaTypeS1, PeriodS2, MaTypeS2,
                0, 0, 0, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
                Print(1);

                atr[i] = Indicators.AverageTrueRange(bars, 150, MovingAverageType.Simple);
                dcn[i] = Indicators.DonchianChannel(bars, 5);

                drawdown[i].Add(0.0);

                lastLongCloseIndex[i] = 0;
                lastShortCloseIndex[i] = 0;
                longSlLevelReached[i] = false;
                shortSlLevelReached[i] = false;
                martingaleStep[i] = 0;
                LookBackOverBuy[i] = bars.OpenTimes.Last(150 + 2);
                LookBackOverSell[i] = bars.OpenTimes.Last(150 + 2);

                i++;
                Print(symbol.CommissionType + "   " + symbol.Commission);
            }
            drawdown[TradeList.Length].Add(0.0);
            //subscribe to position close event - to move stoploss to Breakeven for the 2nd Trade
            Positions.Closed += OnPositionClosed;
            //Get Name of Bot and Currency pair of current instance EP15-Deploy
            botName = GetType().ToString();
            initialBalance = Account.Balance;
            startTime = DateTime.Now;


        }

        private void OnBarTick(BarsTickEventArgs obj)
        {
            if (CheckTradeConditions(obj.Bars, botName) && UpdateMethod == UpdateMethodType.OnTick)
            {
                DoEntry(obj.Bars);
            }

            if (CheckExitConditions(obj.Bars, botName))
            {
                DoExit(obj.Bars);
            }
        }
        private void OnBarOpened(BarOpenedEventArgs obj)
        {
            if (UpdateMethod == UpdateMethodType.OnBar)
            {
                if (CheckTradeConditions(obj.Bars, botName))
                {
                    DoEntry(obj.Bars);
                }

                if (!CheckOnTick && CheckExitConditions(obj.Bars, botName))
                {
                    DoExit(obj.Bars);
                }
            }
        }
        private void DoEntry(Bars bars)
        {
            if (Monitor.TryEnter(this))
            {
                try
                {
                    int symbolIndex = Array.FindIndex(TradeList, x => x.Name == bars.SymbolName);
                    Symbol symbol = Array.Find(TradeList, x => x.Name == bars.SymbolName);
                    if (symbol != null)
                    {
                        // Put your core logic here EP7-MACD and EP8-Custom Indicators
                        var ClosePrice = bars.ClosePrices.Last(barsBack);
                        var PrevClosePrice = bars.ClosePrices.Last(barsBack + 1);
                        var Prev2ClosePrice = bars.ClosePrices.Last(barsBack + 2);
                        var LowPrice = bars.LowPrices.Last(barsBack);
                        var PrevLowPrice = bars.LowPrices.Last(barsBack + 1);
                        var HighPrice = bars.HighPrices.Last(barsBack);
                        var PrevHighPrice = bars.HighPrices.Last(barsBack + 1);

                        //Check for Entry Signal
                        {
                            var BuyTriggerR1 = tgr[symbolIndex].HistolUp.Last(0) > 0;
                            var SellTriggerS1 = tgr[symbolIndex].HistoDown.Last(0) < 0;

                            if (BuyTriggerR1)
                            {
                                Open(TradeType.Buy, bars, GetSl(bars, TradeType.Buy), (GetSl(bars, TradeType.Buy) * TpFactor), botName);
                            }

                            if (SellTriggerS1)
                            {
                                Open(TradeType.Sell, bars, GetSl(bars, TradeType.Sell), (GetSl(bars, TradeType.Sell) * TpFactor), botName);
                            }
                        }
                    }
                }
                finally
                {
                    Monitor.Exit(this);
                }
            }
        }
        private void DoExit(Bars bars)
        {
            if (Monitor.TryEnter(this))
            {
                try
                {
                    int symbolIndex = Array.FindIndex(TradeList, x => x.Name == bars.SymbolName);
                    Symbol symbol = TradeList[symbolIndex];
                    if (symbol != null)
                    {
                        var ClosePrice = bars.ClosePrices.Last(barsBack);
                        var LowPrice = bars.LowPrices.Last(barsBack);
                        var HighPrice = bars.HighPrices.Last(barsBack);

                        //Check for Exit Signal

                    }
                }
                finally
                {
                    Monitor.Exit(this);
                }
            }
        }

        //Function after position is closed to move SL to Brakeven
        private bool CheckTradeConditions(Bars bars, string Label)
        {
            //Check trade entry time (EP9-Best time to trade) and there's no existing position before entering a trade
            int symbolIndex = Array.FindIndex(TradeList, x => x.Name == bars.SymbolName);
            Symbol symbol = TradeList[symbolIndex];

            return (Positions.FindAll(Label, symbol.Name).Length == 0 && PendingOrders.Where(x => x.Label == Label && x.SymbolName == symbol.Name).Count() == 0 && symbol.Spread < MaxSpred * symbol.PipSize && Server.Time.Hour >= StartHour && Server.Time.Hour < EndHour);
        }
        private bool CheckExitConditions(Bars bars, string Label)
        {
            //Check there's an existing position
            return (Positions.FindAll(Label, bars.SymbolName).Length > 0 || PendingOrders.Where(x => x.Label == Label && x.SymbolName == bars.SymbolName).Count() > 0);
        }
        //Function for opening a new trade - EP10-Functions and Parameters
        private void Open(TradeType TradeType, Bars bars, double? SLpips, double? TPpips, string Label)
        {
            int symbolIndex = Array.FindIndex(TradeList, x => x.Name == bars.SymbolName);
            Symbol symbol = TradeList[symbolIndex];
            if (Positions.FindAll(Label, symbol.Name, TradeType).Length == 0)
            {
                int index = bars.Count - 1;
                if ((TradeType == TradeType.Buy && index - lastLongCloseIndex[symbolIndex] >= MinBarsAfterClose) || (TradeType == TradeType.Sell && index - lastShortCloseIndex[symbolIndex] >= MinBarsAfterClose))
                {

                    //Calculate trade amount based on ATR - EP6-Money Management
                    TradeResult result;
                    var TradeAmount = ((FixTradeAmount ? initialBalance : Account.Equity) * MaxRiskPct) / (100.0 * (double)SLpips * symbol.PipValue);
                    if (Positions.FindAll(Label, symbol.Name, TradeType).Length == 0)
                    {
                        if (TPMethode == TPMethodeType.None)
                        {
                            TradeAmount = Symbol.NormalizeVolumeInUnits(TradeAmount * Math.Pow(MartingaleIncrease, martingaleStep[symbolIndex]), RoundingMode.Down);
                            result = ExecuteMarketOrder(TradeType, symbol.Name, TradeAmount, Label, SLpips, TPpips, null, TSLOnStart);
                        }
                        else
                        {
                            TradeAmount = Symbol.NormalizeVolumeInUnits(TradeAmount * Math.Pow(MartingaleIncrease, martingaleStep[symbolIndex]), RoundingMode.Down);
                            result = ExecuteMarketOrder(TradeType, symbol.Name, TradeAmount, Label, SLpips, null, null, TSLOnStart);
                            if (!result.IsSuccessful)
                            {
                                Print("Could not execute order: {0}", result.Error);
                            }
                            //result = ExecuteMarketOrder(TradeType, symbol.Name, TradeAmount, Label, SLpips, TPpips, null, TSLOnStart);
                        }
                        if (!result.IsSuccessful)
                        {
                            Print("Could not execute order: {0}", result.Error);
                        }
                        if (TradeType == TradeType.Buy)
                        {
                            longSlLevelReached[symbolIndex] = false;
                        }
                        else
                        {
                            shortSlLevelReached[symbolIndex] = false;
                        }
                        foreach (var position in Positions.FindAll(Label, symbol.Name, TradeType))
                        {
                            if (position.StopLoss == null)
                            {
                                Close(TradeType, bars.SymbolName, Label);
                                Print("No SL defined!");
                                break;
                            }
                        }
                        foreach (var order in PendingOrders.Where(x => x.Label == Label && x.SymbolName == symbol.Name && x.TradeType == TradeType))
                        {
                            if (order.StopLoss == null)
                            {
                                Close(TradeType, bars.SymbolName, Label);
                                Print("No SL defined!");
                                break;
                            }
                        }
                    }
                }
            }
        }
        //Function for closing trades - EP10-Functions and Parameters
        private void Close(TradeType TradeType, string symbolName, string Label)
        {
            if (symbolName != "")
            {
                foreach (var position in Positions.FindAll(Label, symbolName, TradeType))
                    ClosePosition(position);

                foreach (var order in PendingOrders.Where(x => x.Label == Label && x.SymbolName == symbolName && x.TradeType == TradeType))
                    CancelPendingOrder(order);
            }
            else
            {
                foreach (var symbol in TradeList)
                {
                    foreach (var position in Positions.FindAll(Label, symbol.Name, TradeType))
                        ClosePosition(position);

                    foreach (var order in PendingOrders.Where(x => x.Label == Label && x.SymbolName == symbol.Name && x.TradeType == TradeType))
                        CancelPendingOrder(order);
                }
            }
        }
        protected override void OnStop()
        {
            var stopTime = DateTime.Now;
            Print("Execution time: {0}", stopTime - startTime);

            // Close all positions except in real-time (for better results in backtesting or optimization)
            if (RunningMode != RunningMode.RealTime)
            {
                Close(TradeType.Buy, "", botName);
                Close(TradeType.Sell, "", botName);
            }

            // Print more details of individual results per symbol
            if ((RunningMode == RunningMode.SilentBacktesting || RunningMode == RunningMode.VisualBacktesting) && History.Count > 0)
            {
                double totalProfit = 0.0;
                foreach (var sym in TradeList)
                {
                    int lostBull = 0;
                    int lostBear = 0;
                    int wonBull = 0;
                    int wonBear = 0;
                    double wonPips = 0.0;
                    double lostPips = 0.0;
                    double profit = 0.0;
                    foreach (var hist in History.Where(x => x.Label == botName && x.SymbolName == sym.Name))
                    {
                        profit += hist.NetProfit;
                        if (hist.Pips >= 0)
                        {
                            wonPips += hist.Pips;
                            if (hist.TradeType == TradeType.Buy)
                            {
                                wonBull++;
                            }
                            else
                            {
                                wonBear++;
                            }
                        }
                        else
                        {
                            lostPips += hist.Pips;
                            if (hist.TradeType == TradeType.Buy)
                            {
                                lostBull++;
                            }
                            else
                            {
                                lostBear++;
                            }
                        }
                    }
                    Print("Symbol {0} results: {1} trades (+{2}, -{3} => {4}%), {5} net pips (+{6}, {7}), {8}{9} net profit with max {10}% balance drawdown", sym.Name, wonBull + lostBull + wonBear + lostBear, wonBull + wonBear, lostBull + lostBear, (100.0 * (wonBull + wonBear) / (wonBull + lostBull + wonBear + lostBear)).ToString("0.00"), (wonPips + lostPips).ToString("0.0"), wonPips.ToString("0.0"), lostPips.ToString("0.0"), profit.ToString("0.00"),
                    Account.Asset.Name, GetDrawDown(Array.FindIndex(TradeList, x => x.Name == sym.Name)).ToString("0.0"));
                    Print("{0} buy trades: {1} won, {2} lost => {3}%", wonBull + lostBull, wonBull, lostBull, (100.0 * wonBull / (wonBull + lostBull)).ToString("0.00"));
                    Print("{0} sell trades: {1} won, {2} lost => {3}%", wonBear + lostBear, wonBear, lostBear, (100.0 * wonBear / (wonBear + lostBear)).ToString("0.00"));

                    totalProfit += profit;
                }

                Print("Total net profit: {0}{1} = {2}% gain with max {3}% balance drawdown", totalProfit.ToString("0"), Account.Asset.Name, (100.0 * totalProfit / initialBalance).ToString("0"), GetDrawDown(TradeList.Length).ToString("0.0"));

                Print("K-Ratio: " + GetKRatio().ToString("0.00"));
            }
        }

        /////////////////////////////////////////////////////// On position Close + Management Martingale /////////////////////////////////////////////////////
        private void OnPositionClosed(PositionClosedEventArgs args)
        {
            int symbolIndex = Array.FindIndex(TradeList, x => x.Name == args.Position.SymbolName);

            if (args.Position.TradeType == TradeType.Buy)
            {
                lastLongCloseIndex[symbolIndex] = atr[symbolIndex].Result.Count + 1;
            }
            else if (args.Position.TradeType == TradeType.Sell)
            {
                lastShortCloseIndex[symbolIndex] = atr[symbolIndex].Result.Count + 1;
            }

            // Close(args.Position.TradeType, args.Position.SymbolName, args.Position.Label);
            if (args.Position.Label == botName && args.Position.SymbolName == SymbolName)
            {
                if (MartingaleMode == MartingaleModeType.None)
                {
                    martingaleStep[symbolIndex] = 0;
                }
                else if (MartingaleMode == MartingaleModeType.DrawDown)
                {
                    double dd = GetDrawDown(symbolIndex);
                    if (dd > 0 && martingaleStep[symbolIndex] < MartingaleMaxSteps)
                    {
                        martingaleStep[symbolIndex]++;
                    }
                    else
                    {
                        martingaleStep[symbolIndex] = 0;
                    }
                }
                else if (MartingaleMode == MartingaleModeType.Standard)
                {
                    if (args.Position.Pips < -MartingaleBreakevenRange && martingaleStep[symbolIndex] < MartingaleMaxSteps)
                    {
                        martingaleStep[symbolIndex]++;
                    }
                    else if (args.Position.Pips > MartingaleBreakevenRange || martingaleStep[symbolIndex] >= MartingaleMaxSteps)
                    {
                        martingaleStep[symbolIndex] = 0;
                    }

                }
            }
            // Total Drawdown
            CalcDrawDown(TradeList.Length, args.Position.NetProfit, History.Where(x => x.PositionId == args.Position.Id).First().Balance);
            // Drawdown per Symbol
            CalcDrawDown(Array.FindIndex(TradeList, x => x.Name == args.Position.SymbolName), args.Position.NetProfit, History.Where(x => x.PositionId == args.Position.Id).First().Balance);
        }

        //Martingal function
        private void CalcDrawDown(int index, double gain, double balance)
        {
            drawdown[index].Add(drawdown[index][drawdown[index].Count - 1] + gain / balance * 100.0);
        }
        private double GetDrawDown(int index)
        {

            double maxDD = 0.0;

            double dd = drawdown[index].Last();
            double peak = drawdown[index].Max();

            foreach (double c in drawdown[index])
            {
                peak = Math.Max(peak, dd);
                maxDD = Math.Max(peak - dd, maxDD);
            }

            return maxDD;
        }
        //////////////////////////////////////////////////// Enter Special function /////////////////////////////////////////////////////////////
        private DateTime GetOverBuy(Bars bars)
        {
            int symbolIndex = Array.FindIndex(TradeList, x => x.Name == bars.SymbolName);
            Symbol symbol = TradeList[symbolIndex];
            var prevOverBuy = bars.OpenTimes.Last(OverBuySellLookBack + 2);

            for (int i = 3; i < OverBuySellLookBack; i++)
            {
                if ((tgr[symbolIndex].Result.Last(i) >= OverBuy) /*&& (prevResult < OverBuyEnterLevelEnter)*/)
                {
                    prevOverBuy = bars.OpenTimes.Last(i);
                    LookBackOverBuy[symbolIndex] = LookBackOverBuy[symbolIndex] > prevOverBuy ? LookBackOverBuy[symbolIndex] : prevOverBuy;
                }
            }
            return LookBackOverBuy[symbolIndex];
        }
        private DateTime GetOverSell(Bars bars)
        {
            int symbolIndex = Array.FindIndex(TradeList, x => x.Name == bars.SymbolName);
            Symbol symbol = TradeList[symbolIndex];

            var prevOverSell = bars.OpenTimes.Last(OverBuySellLookBack + 2);
            for (int i = 3; i < OverBuySellLookBack; i++)
            {
                if (tgr[symbolIndex].Result.Last(i) <= OverSell)
                {
                    prevOverSell = bars.OpenTimes.Last(i);
                    LookBackOverSell[symbolIndex] = LookBackOverSell[symbolIndex] > prevOverSell ? LookBackOverSell[symbolIndex] : prevOverSell;
                }
            }
            return LookBackOverSell[symbolIndex];
        }
        private bool GetTooBigBar(Bars bars)
        {
            int symbolIndex = Array.FindIndex(TradeList, x => x.Name == bars.SymbolName);
            Symbol symbol = TradeList[symbolIndex];

            double atrSize = atr[symbolIndex].Result.Last(2) * 2;
            double barSize = Math.Abs(Bars.OpenPrices.Last(1) - Bars.ClosePrices.Last(1));
            bool result = false;

            if (barSize < atrSize)
            {
                result = true;
            }
            else if (barSize >= atrSize)
            {
                result = false;
            }
            else
            {
                result = true;
            }

            return result;
        }

        private bool GetConfirmationEnterBarsBuy(Bars bars, TradeType tradeType)
        {
            int symbolIndex = Array.FindIndex(TradeList, x => x.Name == bars.SymbolName);
            Symbol symbol = TradeList[symbolIndex];
            var result = false;

            if (tradeType == TradeType.Buy)
            {
                if (bars.ClosePrices.Last(1) > bars.OpenPrices.Last(1) && symbol.Bid > (bars.HighPrices.Last(1) + (PipsConfirmation / symbol.PipSize)))
                {
                    result = true;
                }

                else if (bars.ClosePrices.Last(1) < bars.OpenPrices.Last(1) && symbol.Bid > (bars.OpenPrices.Last(1) + (PipsConfirmation / symbol.PipSize)))
                {
                    result = true;
                }
                else
                {
                    result = false;
                }
            }
            if (tradeType == TradeType.Sell)
            {
                if (bars.ClosePrices.Last(1) > bars.OpenPrices.Last(1) && symbol.Ask < (bars.OpenPrices.Last(1) - (PipsConfirmation / symbol.PipSize)))
                {
                    result = true;
                }

                else if (bars.ClosePrices.Last(1) < bars.OpenPrices.Last(1) && symbol.Ask < (bars.LowPrices.Last(1) - (PipsConfirmation / symbol.PipSize)))
                {
                    result = true;
                }
                else
                {
                    result = false;
                }
            }
            return result;
        }
        /////////////////////////////////////////////////////////////////// monney management ////////////////////////////////////////////////////////////////
        private double GetSl(Bars bars, TradeType tradeType)
        {
            int symbolIndex = Array.FindIndex(TradeList, x => x.Name == bars.SymbolName);
            Symbol symbol = TradeList[symbolIndex];

            if (tradeType == TradeType.Buy)
                return (symbol.Ask - dcn[symbolIndex].Bottom.Last(0)) / symbol.PipSize;

            else if (tradeType == TradeType.Sell)
                return (dcn[symbolIndex].Top.Last(0) - symbol.Bid) / symbol.PipSize;
            else
                return 0;
        }

        private double GetTp(Bars bars, TradeType tradeType)
        {
            int symbolIndex = Array.FindIndex(TradeList, x => x.Name == bars.SymbolName);
            Symbol symbol = TradeList[symbolIndex];

            if (tradeType == TradeType.Buy)
                return (symbol.Bid - dcn[symbolIndex].Bottom.Last(0)) / symbol.PipSize + symbol.Spread;

            else if (tradeType == TradeType.Sell)
                return (dcn[symbolIndex].Top.Last(0) - symbol.Ask) / symbol.PipSize + symbol.Spread;
            else
                return 0;
        }

        /////////////////////////////////////////////// Optimisation ////////////////////////////////////////////////////////////
        private double GetKRatio()
        {
            double balance = initialBalance;
            double log_balance = 0;
            int size = History.Count + 1;
            double[] log_profit = new double[size];
            log_profit[0] = 0.0;
            int count = 1;

            double x_sum = 0;
            double y_sum = 0;

            foreach (var ticket in History)
            {
                log_balance += Math.Log((balance + ticket.NetProfit) / balance);
                balance += ticket.NetProfit;
                log_profit[count] = log_balance;

                x_sum += count;
                y_sum += log_balance;
                count++;
            }

            double x_mean = x_sum / size;
            double y_mean = y_sum / size;

            double slope_numerator = 0;
            double slope_denominator = 0;
            double x_sqr = 0;
            double y_sqr = 0;

            for (int i = 0; i < size; i++)
            {
                slope_numerator += (i - x_mean) * (log_profit[i] - y_mean);
                slope_denominator += Math.Pow(i - x_mean, 2);

                y_sqr += Math.Pow(log_profit[i] - y_mean, 2);
                x_sqr += Math.Pow(i - x_mean, 2);
            }

            double slope = slope_numerator / slope_denominator;
            double std_err = Math.Sqrt((y_sqr - (Math.Pow(slope_numerator, 2) / x_sqr)) / ((size - 2) * x_sqr));

            return slope / std_err;
        }
        protected override double GetFitness(GetFitnessArgs args)
        {
            return GetKRatio();
        }
    }
}


YE
YesOrNot

Joined on 10.10.2022 Blocked

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: MultiSymbol TGR.algo
  • Rating: 0
  • Installs: 300
Comments
Log in to add a comment.
No comments found.