Converting single symbol cBot to multi symbol

Created at 01 Apr 2021, 10:24
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!
EY

eynt

Joined 08.05.2020

Converting single symbol cBot to multi symbol
01 Apr 2021, 10:24


I have developed  a cBot which handles a single symbol and uses properties/events such as Bars.LastBar, Symbol.TickSize, OnTick, etc. which refers to the current chart single symbol, Now I want to extend my cBot so it will run the same way only on several symbols, without running it on several charts. How can I accomplish that?

 

Thanks


@eynt
Replies

amusleh
01 Apr 2021, 10:42

Hi,

This sample indicator might help you:

using cAlgo.API;
using cAlgo.API.Internals;
using System;

namespace cAlgo
{
    /// <summary>
    /// This sample indicator shows how to get a symbol data
    /// </summary>
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SymbolSample : Indicator
    {
        private TextBlock _spreadTextBlock;
        private TextBlock _bidTextBlock;
        private TextBlock _askTextBlock;
        private TextBlock _unrealizedGrossProfitTextBlock;
        private TextBlock _unrealizedNetProfitTextBlock;
        private TextBlock _timeTillOpenTextBlock;
        private TextBlock _timeTillCloseTextBlock;
        private TextBlock _isOpenedTextBlock;
        private Symbol _symbol;

        [Parameter("Use Current Symbol", DefaultValue = true)]
        public bool UseCurrentSymbol { get; set; }

        [Parameter("Other Symbol Name", DefaultValue = "GBPUSD")]
        public string OtherSymbolName { get; set; }

        protected override void Initialize()
        {
            var grid = new Grid(23, 2)
            {
                BackgroundColor = Color.Gold,
                Opacity = 0.6,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
            };

            var style = new Style();

            style.Set(ControlProperty.Padding, 1);
            style.Set(ControlProperty.Margin, 2);
            style.Set(ControlProperty.FontWeight, FontWeight.Bold);
            style.Set(ControlProperty.BackgroundColor, Color.Black);

            _symbol = UseCurrentSymbol ? Symbol : Symbols.GetSymbol(OtherSymbolName);

            grid.AddChild(new TextBlock { Text = "Symbol Info", Style = style, HorizontalAlignment = HorizontalAlignment.Center }, 0, 0, 1, 2);

            grid.AddChild(new TextBlock { Text = "Name", Style = style }, 1, 0);
            grid.AddChild(new TextBlock { Text = _symbol.Name, Style = style }, 1, 1);

            grid.AddChild(new TextBlock { Text = "ID", Style = style }, 2, 0);
            grid.AddChild(new TextBlock { Text = _symbol.Id.ToString(), Style = style }, 2, 1);

            grid.AddChild(new TextBlock { Text = "Digits", Style = style }, 3, 0);
            grid.AddChild(new TextBlock { Text = _symbol.Digits.ToString(), Style = style }, 3, 1);

            grid.AddChild(new TextBlock { Text = "Description", Style = style }, 4, 0);
            grid.AddChild(new TextBlock { Text = _symbol.Description, Style = style }, 4, 1);

            grid.AddChild(new TextBlock { Text = "Lot Size", Style = style }, 5, 0);
            grid.AddChild(new TextBlock { Text = _symbol.LotSize.ToString(), Style = style }, 5, 1);

            grid.AddChild(new TextBlock { Text = "Pip Size", Style = style }, 6, 0);
            grid.AddChild(new TextBlock { Text = _symbol.PipSize.ToString(), Style = style }, 6, 1);

            grid.AddChild(new TextBlock { Text = "Pip Value", Style = style }, 7, 0);
            grid.AddChild(new TextBlock { Text = _symbol.PipValue.ToString(), Style = style }, 7, 1);

            grid.AddChild(new TextBlock { Text = "Tick Size", Style = style }, 8, 0);
            grid.AddChild(new TextBlock { Text = _symbol.TickSize.ToString(), Style = style }, 8, 1);

            grid.AddChild(new TextBlock { Text = "Tick Value", Style = style }, 9, 0);
            grid.AddChild(new TextBlock { Text = _symbol.TickValue.ToString(), Style = style }, 9, 1);

            grid.AddChild(new TextBlock { Text = "Volume In Units Max", Style = style }, 10, 0);
            grid.AddChild(new TextBlock { Text = _symbol.VolumeInUnitsMax.ToString(), Style = style }, 10, 1);

            grid.AddChild(new TextBlock { Text = "Volume In Units Min", Style = style }, 11, 0);
            grid.AddChild(new TextBlock { Text = _symbol.VolumeInUnitsMin.ToString(), Style = style }, 11, 1);

            grid.AddChild(new TextBlock { Text = "Volume In Units Step", Style = style }, 12, 0);
            grid.AddChild(new TextBlock { Text = _symbol.VolumeInUnitsStep.ToString(), Style = style }, 12, 1);

            grid.AddChild(new TextBlock { Text = "Ask", Style = style }, 13, 0);

            _askTextBlock = new TextBlock { Text = _symbol.Ask.ToString(), Style = style };

            grid.AddChild(_askTextBlock, 13, 1);

            grid.AddChild(new TextBlock { Text = "Bid", Style = style }, 14, 0);

            _bidTextBlock = new TextBlock { Text = _symbol.Bid.ToString(), Style = style };

            grid.AddChild(_bidTextBlock, 14, 1);

            grid.AddChild(new TextBlock { Text = "Spread", Style = style }, 15, 0);

            _spreadTextBlock = new TextBlock { Text = _symbol.Spread.ToString(), Style = style };

            grid.AddChild(_spreadTextBlock, 15, 1);

            grid.AddChild(new TextBlock { Text = "Unrealized Gross Profit", Style = style }, 16, 0);

            _unrealizedGrossProfitTextBlock = new TextBlock { Text = _symbol.UnrealizedGrossProfit.ToString(), Style = style };

            grid.AddChild(_unrealizedGrossProfitTextBlock, 16, 1);

            grid.AddChild(new TextBlock { Text = "Unrealized Net Profit", Style = style }, 17, 0);

            _unrealizedNetProfitTextBlock = new TextBlock { Text = _symbol.UnrealizedNetProfit.ToString(), Style = style };

            grid.AddChild(_unrealizedNetProfitTextBlock, 17, 1);

            grid.AddChild(new TextBlock { Text = "Time Till Open", Style = style }, 18, 0);

            _timeTillOpenTextBlock = new TextBlock { Text = _symbol.MarketHours.TimeTillOpen().ToString(), Style = style };

            grid.AddChild(_timeTillOpenTextBlock, 18, 1);

            grid.AddChild(new TextBlock { Text = "Time Till Close", Style = style }, 19, 0);

            _timeTillCloseTextBlock = new TextBlock { Text = _symbol.MarketHours.TimeTillClose().ToString(), Style = style };

            grid.AddChild(_timeTillCloseTextBlock, 19, 1);

            grid.AddChild(new TextBlock { Text = "Is Opened", Style = style }, 20, 0);

            _isOpenedTextBlock = new TextBlock { Text = _symbol.MarketHours.IsOpened().ToString(), Style = style };

            grid.AddChild(_isOpenedTextBlock, 20, 1);

            grid.AddChild(new TextBlock { Text = "Trading Sessions #", Style = style }, 21, 0);

            grid.AddChild(new TextBlock { Text = _symbol.MarketHours.Sessions.Count.ToString(), Style = style }, 21, 1);

            grid.AddChild(new TextBlock { Text = "Leverage Tier", Style = style }, 22, 0);

            var leverageTiersStackPanel = new StackPanel
            {
                Orientation = Orientation.Horizontal
            };

            foreach (var leveragTier in _symbol.DynamicLeverage)
            {
                leverageTiersStackPanel.AddChild(new TextBlock { Text = string.Format("Leverage for volume up to {0} is {1}", leveragTier.Volume, leveragTier.Leverage), Style = style });
            }

            grid.AddChild(leverageTiersStackPanel, 22, 1);

            Chart.AddControl(grid);

            _symbol.Tick += Symbol_Tick;

            Timer.Start(TimeSpan.FromSeconds(1));
        }

        private void Symbol_Tick(SymbolTickEventArgs obj)
        {
            _askTextBlock.Text = obj.Symbol.Ask.ToString();
            _bidTextBlock.Text = obj.Symbol.Bid.ToString();
            _spreadTextBlock.Text = obj.Symbol.Spread.ToString();
            _unrealizedGrossProfitTextBlock.Text = obj.Symbol.UnrealizedGrossProfit.ToString();
            _unrealizedNetProfitTextBlock.Text = obj.Symbol.UnrealizedNetProfit.ToString();
        }

        protected override void OnTimer()
        {
            _timeTillOpenTextBlock.Text = _symbol.MarketHours.TimeTillOpen().ToString();
            _timeTillCloseTextBlock.Text = _symbol.MarketHours.TimeTillClose().ToString();
            _isOpenedTextBlock.Text = _symbol.MarketHours.IsOpened().ToString();
        }

        public override void Calculate(int index)
        {
        }
    }
}

Please read the API references for more info regarding symbols and bars.


@amusleh

eynt
01 Apr 2021, 10:50

RE:

I will try that, thank you.

Should there by any adjustments in case of running the cBot on a back test?

 


@eynt

amusleh
01 Apr 2021, 11:03

RE: RE:

yuval.ein said:

I will try that, thank you.

Should there by any adjustments in case of running the cBot on a back test?

 

No, just load the symbol and its bars on your cBot OnStart method and you will be able to use it.


@amusleh

eynt
25 Oct 2021, 06:33

RE: RE: RE:

Hello

I have failed converting my code from a single to multi symbol. Perhaps you can attach a code sample of how you converted one of cTrader cBot samples (such as Sample Aligator, Sample Bears Power etc.) from single to multi symbol. An important note: The code must support running on a back test as well the same way (meaning one chart will run several symbols).

Thanks

 


@eynt

amusleh
25 Oct 2021, 09:42

RE: RE: RE: RE:

yuval.ein said:

Hello

I have failed converting my code from a single to multi symbol. Perhaps you can attach a code sample of how you converted one of cTrader cBot samples (such as Sample Aligator, Sample Bears Power etc.) from single to multi symbol. An important note: The code must support running on a back test as well the same way (meaning one chart will run several symbols).

Thanks

 

Hi,

Here is the sample martingale cBot that works on two symbols, you must provide the symbol names:

using System;
using cAlgo.API;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SampleMartingalecBot : Robot
    {
        [Parameter("Initial Quantity (Lots)", Group = "Volume", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
        public double InitialQuantity { get; set; }

        [Parameter("Stop Loss", Group = "Protection", DefaultValue = 40)]
        public int StopLoss { get; set; }

        [Parameter("Take Profit", Group = "Protection", DefaultValue = 40)]
        public int TakeProfit { get; set; }

        [Parameter("First Symbol", Group = "Symbols")]
        public string FirstSymbolName { get; set; }

        [Parameter("Second Symbol", Group = "Symbols")]
        public string SecondSymbolName { get; set; }

        private Random random = new Random();

        protected override void OnStart()
        {
            Positions.Closed += OnPositionsClosed;

            var firstSymbol = Symbols.GetSymbol(FirstSymbolName);

            ExecuteOrder(InitialQuantity, firstSymbol, GetRandomTradeType());

            var secondSymbol = Symbols.GetSymbol(SecondSymbolName);

            ExecuteOrder(InitialQuantity, secondSymbol, GetRandomTradeType());
        }

        private void ExecuteOrder(double quantity, Symbol symbol, TradeType tradeType)
        {
            var volumeInUnits = symbol.QuantityToVolumeInUnits(quantity);
            var result = ExecuteMarketOrder(tradeType, symbol.Name, volumeInUnits, "Martingale", StopLoss, TakeProfit);

            if (result.Error == ErrorCode.NoMoney)
                Stop();
        }

        private void OnPositionsClosed(PositionClosedEventArgs args)
        {
            Print("Closed");

            var position = args.Position;

            if (position.Label != "Martingale") return;

            var symbol = Symbols.GetSymbol(args.Position.SymbolName);

            if (position.GrossProfit > 0)
            {
                ExecuteOrder(InitialQuantity, symbol, GetRandomTradeType());
            }
            else
            {
                ExecuteOrder(position.Quantity * 2, symbol, position.TradeType);
            }
        }

        private TradeType GetRandomTradeType()
        {
            return random.Next(2) == 0 ? TradeType.Buy : TradeType.Sell;
        }
    }
}

 


@amusleh

eynt
26 Oct 2021, 00:06

RE: RE: RE: RE: RE:

What if I want to use OnTick for more than one symbol?

 

Thanks


@eynt

firemyst
26 Oct 2021, 05:45

RE: RE: RE: RE: RE: RE:

yuval.ein said:

What if I want to use OnTick for more than one symbol?

 

Thanks

All you have to do is subscribe to the Tick event for each symbol you want.

This thread talks about it for indicators, but it's the same for cBots:

 

Example: Bars.Tick += YourOnTickEventMethod;


@firemyst

eynt
28 Oct 2021, 10:04

RE: RE: RE: RE: RE: RE: RE:

My original single symbol cBot has dozens of private members (strings, integers, etc.). All those members were designed for a single symbol. Now that there are many symbols, each of them should have a different value per symbol. Is there an easy straight forward way to convert all the members from single to multi symbol?

 

Thanks

 


@eynt

firemyst
28 Oct 2021, 10:21

RE: RE: RE: RE: RE: RE: RE: RE:

yuval.ein said:

My original single symbol cBot has dozens of private members (strings, integers, etc.). All those members were designed for a single symbol. Now that there are many symbols, each of them should have a different value per symbol. Is there an easy straight forward way to convert all the members from single to multi symbol?

 

Thanks

 

Yes.

 

Add [] onto the end of them to declare them as arrays.

int[]

double[]

etc etc

[0] is the first symbol's value, [1] is the second symbol's, so on and so forth. Hopefully after that, you won't have to make too many other changes to your code depending on how it's written.


@firemyst