Multisymbol, different result depending on the instance

Created at 22 Jan 2025, 19:21
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!
KH

khlopez

Joined 13.04.2023

Multisymbol, different result depending on the instance
22 Jan 2025, 19:21


Hello everyone,

 

I built a code that works in several pairs, although some adjustments must be done in each of them. When run in different instances, it works very well, but when I tried to fix it so that it can be run in one instance for all the currencies, it gave me different results depending on the instance (e.g. if I execute the bot in the EURUSD instance, I get a result, and if I execute it in the GBPUSD instance, I get a different one. The same exact code).

Could you please help me fix it so that I get the same result no matter the instance I run it in?

I’m very far from being an expert in coding, but I think the issue may be somewhere in the conditions included in the Bars_BarOpened method, because I just try to put a simple ExecuteMarketOrder for every pair, it works fine:

using System;
using System.Linq;
using System.Text;
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 MultisymbolBacktesting : Robot
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }
        public Symbol[] MySymbols;
        private ExponentialMovingAverage EMA20;
        [Parameter("Seguridad SL 1", DefaultValue = 5)]
        public int SeguridadSL1 { get; set; }
        [Parameter("Seguridad SL 2", DefaultValue = 3)]
        public int SeguridadSL2 { get; set; }
        [Parameter("Seguridad TP 1", DefaultValue = 3)]
        public int SeguridadTP1 { get; set; }
        [Parameter("Seguridad TP 2", DefaultValue = 2)]
        public int SeguridadTP2 { get; set; }

        protected override void OnStart()
        {
            // We get a symbol array for the following for symbols
            MySymbols = Symbols.GetSymbols("EURUSD", "GBPUSD");
            
            // We subscribe to the bar event for each symbol for the current timeframe
            foreach (var symbol in MySymbols)
            {
                var bars = MarketData.GetBars(TimeFrame, symbol.Name);
                bars.BarOpened += Bars_BarOpened;
            }
            
        }   

        private void Bars_BarOpened(BarOpenedEventArgs obj)
        {
            int countPositionsEURUSD = 0;
            int countPositionsGBPUSD = 0;
            int countLabelLiquidez = 0; //Type of entry
            int countLabelFuerte = 0; //Type of entry
            int countLabelEnvolvente = 0; //Type of entry
            int countLabelPinAlcista = 0; //Type of entry
            foreach (var position in Positions)
            {
                if (position.SymbolName == "EURUSD")
                {
                    countPositionsEURUSD++;
                    if (countPositionsEURUSD > 5)
                        return;
                    if (position.Label == "Liquidez y vela fuerte")
                    {
                        countLabelLiquidez++;
                        if (countLabelLiquidez > 0)
                            return;
                    }
                    else if (position.Label == "Envolvente o doble suelo")
                    {
                        countLabelEnvolvente++;
                        if (countLabelEnvolvente > 0)
                            return;
                    }
                    else if (position.Label == "Vela Fuerte")
                    {
                        countLabelFuerte++;
                        if (countLabelFuerte > 0)
                            return;
                    }
                    else if (position.Label == "Pinbar alcista")
                    {
                        countLabelPinAlcista++;
                        if (countLabelPinAlcista > 0)
                            return;
                    }
                }
                else if (position.SymbolName == "GBPUSD")
                {
                    countPositionsGBPUSD++;
                    if (countPositionsGBPUSD > 5)
                        return;
                    if (position.Label == "Liquidez y vela fuerte")
                    {
                        countLabelLiquidez++;
                        if (countLabelLiquidez > 0)
                            return;
                    }
                    else if (position.Label == "Envolvente o doble suelo")
                    {
                        countLabelEnvolvente++;
                        if (countLabelEnvolvente > 0)
                            return;
                    }
                    else if (position.Label == "Vela Fuerte")
                    {
                        countLabelFuerte++;
                        if (countLabelFuerte > 0)
                            return;
                    }
                    else if (position.Label == "Pinbar alcista")
                    {
                        countLabelPinAlcista++;
                        if (countLabelPinAlcista > 0)
                            return;
                    }
                }
            }
            switch (obj.Bars.SymbolName)
            {
                case "EURUSD": 
                    AnalyzeEURUSD(obj);
                    break;

                case "GBPUSD":
                    AnalyzeGBPUSD(obj);
                    break;
            }
        }

private void AnalyzeEURUSD(BarOpenedEventArgs obj)
//Conditions and execute orders for the EURUSD

private void AnalyzeGBPUSD(BarOpenedEventArgs obj)
//Conditions and execute orders for the EURUSD
    }
}

 

Thank you very much for your help, and regards.


@khlopez
Replies

firemyst
24 Jan 2025, 01:49

I believe with the event listeners, they will only work for the current running instance. That's it.

So if you have your bot under AUDUSD for example, it will only respond when bars are opened for AUDUSD.

Your code is only getting the information for the current symbol instance the bot is running under.

Thus, you need to change your code to handle multiple symbols. Example guidance below:

// We get a symbol array for the following for symbols
MySymbols = Symbols.GetSymbols("EURUSD", "GBPUSD");

//You need to get the bars data for each symbol now
Bars[] SymbolBars = new Bars[MySymbols.Length];

//You need create a variable array to keep track of the symbol's current index
int[] Indexes = new int[MySymbols.Length];

//You need create a variable array to keep track of when a new bar is opened
int[] _previousIndexes = new int[MySymbols.Length];

//Loop to initialize all the data
for (int x = 0; x < MySymbols.Length; x++)
{
	//get the bars data for each symbol
	SymbolBars[x] = MarketData.GetBars(<the time frame you want>, MySymbols[x]);

	//define your onTick method in your code that every symbol will use to check for ticks
	MySymbols[x].Tick += OnTickEventMethod;

	//Initialize all these
	Indexes[x] = 0;
	_previousIndexes[x] = 0;
}



//You need to define and write your OnTickEventMethod 
private void OnTickEventMethod(SymbolTickEventArgs stea)
{
	//Get the symbol the tick event came from
	int x = Array.FindIndex(MySymbols, element => element == stea.SymbolName);

	//Skip any bar symbols that may not have loaded yet.
	if (SymbolBars[x] == null)
		return;
	else
 	{
		Indexes[x] = SymbolBars[x].ClosePrices.Count - 1;

		//check if a new bar has formed
     		if (Indexes[x] > _previousIndexes[x])
     		{
			//we have a new bar
			//write your onBar logic here

			//update our bar trackers
			_previousIndexes[x] = Indexes[x];
		}

		//from here down is where you would put your normal tick event code

		//if you want anything for the specific symbol, you have to reference it through the arrays and create arrays for your variables.
		//For example, you can't do this any more:
		//countLabelFuerte++

		//You need to make it an array as well and do this because you only want to increase the counter for the specific symbol,
		//not across all symbols:
		countLabelFuerte[x]++;

		//Welcome to the big leagues :-)

		//If you're a beginning programmer, what I would suggest you do is get your bot working as you want it for one
		//symbol only. And then when it's working to your satisfaction, convert everything to arrays to handle multiple symbols
		//under one bot instance.

	}
}

@firemyst