Bot not creating pending orders for all instances

Created at 08 Apr 2022, 09:51
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!
WA

waym77

Joined 22.07.2021

Bot not creating pending orders for all instances
08 Apr 2022, 09:51


Hi,

I have a bot that works in backtests and forward tests. The problem is that when I add multiple instances to the bot, the bot only makes pending orders for one of the pairs added.

I do need each instance to communicate with each other regarding volume updates (see PositionsOnClosed and how it uses _PendingOrders.Label), so I am unsure if giving each instance a pair-specific name will break this functionality.

Any advice would be appreciated, thanks!

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.FullAccess)]
    public class DemoBot : Robot
    {
        [Parameter("Name", Group = "Global Settings", DefaultValue = "DemoBot")]
        public string _name { get; set; }

        [Parameter("High/Low Timeframe", Group = "Global Settings", DefaultValue = "Daily")]
        public TimeFrame _hltf { get; set; }

        [Parameter("Take Profit", Group = "Risk", DefaultValue = 15.0, MinValue = 0.1, MaxValue = 1000000.0)]
        public double _takeprofit { get; set; }

        [Parameter("Risk %", Group = "Risk", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _riskpercent { get; set; }

        [Parameter("Stop Loss", Group = "Risk", DefaultValue = 10.0, MinValue = 0.1, MaxValue = 1000000.0)]
        public double _stoploss { get; set; }

        [Parameter("Safety (Pips)", Group = "Risk", DefaultValue = 3.0, MinValue = 0.1, MaxValue = 10000.0)]
        public double _safety { get; set; }

        private Bars _hlbars;
        private double _previoushigh, _previouslow, _volume;
        private bool _todaybuyhappened, _todaysellhappened;

        protected override void OnStart()
        {
            _hlbars = MarketData.GetBars(_hltf);

            _hlbars.BarOpened += _hlbars_BarOpened;
            _safety *= Symbol.PipSize;

            Positions.Closed += PositionsOnClosed;

            _todaybuyhappened = true;
            _todaysellhappened = true;
        }

        private void _hlbars_BarOpened(BarOpenedEventArgs obj)
        {
            _todaybuyhappened = false;
            _todaysellhappened = false;

            foreach (var _PendingOrders in PendingOrders)
            {
                if (_PendingOrders.Label == _name)
                {
                    CancelPendingOrder(_PendingOrders);
                }
            }

            if (_hlbars.OpenPrices.Last(0) > _hlbars.HighPrices.Last(1))
            {
                _todaybuyhappened = true;
            }

            if (_hlbars.OpenPrices.Last(0) < _hlbars.LowPrices.Last(1))
            {
                _todaysellhappened = true;
            }

            _volume = GetVolume();

            _previoushigh = Math.Abs(_hlbars.HighPrices.Last(1) + _safety);
            _previouslow = Math.Abs(_hlbars.LowPrices.Last(1) - _safety);

            if (!_todaybuyhappened)
            {
                PlaceStopOrder(TradeType.Buy, Symbol.Name, _volume, _previoushigh, _name, _stoploss, _takeprofit);
                _todaybuyhappened = true;
            }

            if (!_todaysellhappened)
            {
                PlaceStopOrder(TradeType.Sell, Symbol.Name, _volume, _previouslow, _name, _stoploss, _takeprofit);
                _todaysellhappened = true;
            }


        }

        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            _volume = GetVolume();
            foreach (var _PendingOrders in PendingOrders)
            {
                if (_PendingOrders.Label == _name)
                {
                    if (_PendingOrders.VolumeInUnits != _volume)
                    {
                        _PendingOrders.ModifyVolume(_volume);
                    }
                }
            }
        }

        private double GetVolume()
        {
            double costPerPip = (double)((int)(Symbol.PipValue * 10000000)) / 100;

            double baseNumber = Account.Balance;

            double sizeInLots = Math.Round((baseNumber * _riskpercent / 100) / (_stoploss * costPerPip), 2);

            var result = Symbol.QuantityToVolumeInUnits(sizeInLots);

            if (result > Symbol.VolumeInUnitsMax)
            {
                result = Symbol.VolumeInUnitsMax;
            }
            else if (result < Symbol.VolumeInUnitsMin)
            {
                result = Symbol.VolumeInUnitsMin;
            }
            else if (result % Symbol.VolumeInUnitsStep != 0)
            {
                result = result - (result % Symbol.VolumeInUnitsStep);
            }
            return result;
        }
    }
}

 


@waym77
Replies

amusleh
08 Apr 2022, 10:40

Hi,

You can separate each instance orders by using the Symbol name, example:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class DemoBot : Robot
    {
        [Parameter("Name", Group = "Global Settings", DefaultValue = "DemoBot")]
        public string _name { get; set; }

        [Parameter("High/Low Timeframe", Group = "Global Settings", DefaultValue = "Daily")]
        public TimeFrame _hltf { get; set; }

        [Parameter("Take Profit", Group = "Risk", DefaultValue = 15.0, MinValue = 0.1, MaxValue = 1000000.0)]
        public double _takeprofit { get; set; }

        [Parameter("Risk %", Group = "Risk", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _riskpercent { get; set; }

        [Parameter("Stop Loss", Group = "Risk", DefaultValue = 10.0, MinValue = 0.1, MaxValue = 1000000.0)]
        public double _stoploss { get; set; }

        [Parameter("Safety (Pips)", Group = "Risk", DefaultValue = 3.0, MinValue = 0.1, MaxValue = 10000.0)]
        public double _safety { get; set; }

        private Bars _hlbars;
        private double _previoushigh, _previouslow, _volume;
        private bool _todaybuyhappened, _todaysellhappened;

        public IEnumerable<PendingOrder> BotPendingOrders
        {
            get
            {
                return PendingOrders.Where(order => order.SymbolName.Equals(SymbolName, StringComparison.Ordinal) && order.Label.Equals(_name, StringComparison.Ordinal));
            }
        }

        protected override void OnStart()
        {
            _hlbars = MarketData.GetBars(_hltf);

            _hlbars.BarOpened += _hlbars_BarOpened;
            _safety *= Symbol.PipSize;

            Positions.Closed += PositionsOnClosed;

            _todaybuyhappened = true;
            _todaysellhappened = true;
        }

        private void _hlbars_BarOpened(BarOpenedEventArgs obj)
        {
            _todaybuyhappened = false;
            _todaysellhappened = false;

            foreach (var _PendingOrders in BotPendingOrders)
            {
                CancelPendingOrder(_PendingOrders);
            }

            if (_hlbars.OpenPrices.Last(0) > _hlbars.HighPrices.Last(1))
            {
                _todaybuyhappened = true;
            }

            if (_hlbars.OpenPrices.Last(0) < _hlbars.LowPrices.Last(1))
            {
                _todaysellhappened = true;
            }

            _volume = GetVolume();

            _previoushigh = Math.Abs(_hlbars.HighPrices.Last(1) + _safety);
            _previouslow = Math.Abs(_hlbars.LowPrices.Last(1) - _safety);

            if (!_todaybuyhappened)
            {
                PlaceStopOrder(TradeType.Buy, Symbol.Name, _volume, _previoushigh, _name, _stoploss, _takeprofit);
                _todaybuyhappened = true;
            }

            if (!_todaysellhappened)
            {
                PlaceStopOrder(TradeType.Sell, Symbol.Name, _volume, _previouslow, _name, _stoploss, _takeprofit);
                _todaysellhappened = true;
            }
        }

        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            _volume = GetVolume();

            foreach (var _PendingOrders in BotPendingOrders)
            {
                if (_PendingOrders.VolumeInUnits != _volume)
                {
                    _PendingOrders.ModifyVolume(_volume);
                }
            }
        }

        private double GetVolume()
        {
            double costPerPip = (double)((int)(Symbol.PipValue * 10000000)) / 100;

            double baseNumber = Account.Balance;

            double sizeInLots = Math.Round((baseNumber * _riskpercent / 100) / (_stoploss * costPerPip), 2);

            var result = Symbol.QuantityToVolumeInUnits(sizeInLots);

            if (result > Symbol.VolumeInUnitsMax)
            {
                result = Symbol.VolumeInUnitsMax;
            }
            else if (result < Symbol.VolumeInUnitsMin)
            {
                result = Symbol.VolumeInUnitsMin;
            }
            else if (result % Symbol.VolumeInUnitsStep != 0)
            {
                result = result - (result % Symbol.VolumeInUnitsStep);
            }
            return result;
        }
    }
}

The BotPendingOrders enumerable will give you only those orders that are from same symbol and with same Label.


@amusleh

waym77
11 Apr 2022, 07:25

RE:

amusleh said:

Hi,

You can separate each instance orders by using the Symbol name, example:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class DemoBot : Robot
    {
        [Parameter("Name", Group = "Global Settings", DefaultValue = "DemoBot")]
        public string _name { get; set; }

        [Parameter("High/Low Timeframe", Group = "Global Settings", DefaultValue = "Daily")]
        public TimeFrame _hltf { get; set; }

        [Parameter("Take Profit", Group = "Risk", DefaultValue = 15.0, MinValue = 0.1, MaxValue = 1000000.0)]
        public double _takeprofit { get; set; }

        [Parameter("Risk %", Group = "Risk", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _riskpercent { get; set; }

        [Parameter("Stop Loss", Group = "Risk", DefaultValue = 10.0, MinValue = 0.1, MaxValue = 1000000.0)]
        public double _stoploss { get; set; }

        [Parameter("Safety (Pips)", Group = "Risk", DefaultValue = 3.0, MinValue = 0.1, MaxValue = 10000.0)]
        public double _safety { get; set; }

        private Bars _hlbars;
        private double _previoushigh, _previouslow, _volume;
        private bool _todaybuyhappened, _todaysellhappened;

        public IEnumerable<PendingOrder> BotPendingOrders
        {
            get
            {
                return PendingOrders.Where(order => order.SymbolName.Equals(SymbolName, StringComparison.Ordinal) && order.Label.Equals(_name, StringComparison.Ordinal));
            }
        }

        protected override void OnStart()
        {
            _hlbars = MarketData.GetBars(_hltf);

            _hlbars.BarOpened += _hlbars_BarOpened;
            _safety *= Symbol.PipSize;

            Positions.Closed += PositionsOnClosed;

            _todaybuyhappened = true;
            _todaysellhappened = true;
        }

        private void _hlbars_BarOpened(BarOpenedEventArgs obj)
        {
            _todaybuyhappened = false;
            _todaysellhappened = false;

            foreach (var _PendingOrders in BotPendingOrders)
            {
                CancelPendingOrder(_PendingOrders);
            }

            if (_hlbars.OpenPrices.Last(0) > _hlbars.HighPrices.Last(1))
            {
                _todaybuyhappened = true;
            }

            if (_hlbars.OpenPrices.Last(0) < _hlbars.LowPrices.Last(1))
            {
                _todaysellhappened = true;
            }

            _volume = GetVolume();

            _previoushigh = Math.Abs(_hlbars.HighPrices.Last(1) + _safety);
            _previouslow = Math.Abs(_hlbars.LowPrices.Last(1) - _safety);

            if (!_todaybuyhappened)
            {
                PlaceStopOrder(TradeType.Buy, Symbol.Name, _volume, _previoushigh, _name, _stoploss, _takeprofit);
                _todaybuyhappened = true;
            }

            if (!_todaysellhappened)
            {
                PlaceStopOrder(TradeType.Sell, Symbol.Name, _volume, _previouslow, _name, _stoploss, _takeprofit);
                _todaysellhappened = true;
            }
        }

        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            _volume = GetVolume();

            foreach (var _PendingOrders in BotPendingOrders)
            {
                if (_PendingOrders.VolumeInUnits != _volume)
                {
                    _PendingOrders.ModifyVolume(_volume);
                }
            }
        }

        private double GetVolume()
        {
            double costPerPip = (double)((int)(Symbol.PipValue * 10000000)) / 100;

            double baseNumber = Account.Balance;

            double sizeInLots = Math.Round((baseNumber * _riskpercent / 100) / (_stoploss * costPerPip), 2);

            var result = Symbol.QuantityToVolumeInUnits(sizeInLots);

            if (result > Symbol.VolumeInUnitsMax)
            {
                result = Symbol.VolumeInUnitsMax;
            }
            else if (result < Symbol.VolumeInUnitsMin)
            {
                result = Symbol.VolumeInUnitsMin;
            }
            else if (result % Symbol.VolumeInUnitsStep != 0)
            {
                result = result - (result % Symbol.VolumeInUnitsStep);
            }
            return result;
        }
    }
}

The BotPendingOrders enumerable will give you only those orders that are from same symbol and with same Label.

Hi, this works perfectly, thanks! 


@waym77