Multi-timeframe trading and one buy/one sell per period
            
                 09 Mar 2022, 13:15
            
                    
Hi, I am building a basic EA to test multi-timeframe trading, and I am having some trouble in that bot does not create any trades.
The bot needs to buy when Bull Price > Previous Period High (Bull Price = Price + Safety in Pips)
And sell when Bear Price < Previous Period Low open sell (Bear Price = Price - Safety in Pips)
Additionally, one of each (buy or sell) is allowed per trading day.
Here I have attached the code I am having problems with:
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 AFFS : Robot
    {
        [Parameter("Name", DefaultValue = "AFFS")]
        public string _name { get; set; }
        [Parameter("Start Hour", DefaultValue = 6.0)]
        public double _starttime { get; set; }
        [Parameter("Stop Hour", DefaultValue = 18.0)]
        public double _stoptime { get; set; }
        [Parameter("Max Lots", DefaultValue = 100.0, MinValue = 0.01, MaxValue = 1000.0)]
        public double _maxlots { get; set; }
        [Parameter("Starting Risk (%)", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0)]
        public double _startingrisk { get; set; }
        [Parameter("Risk Step (%)", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0)]
        public double _riskstep { get; set; }
        [Parameter("Take Profit", DefaultValue = 5.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _takeprofit { get; set; }
        [Parameter("Stop Loss", DefaultValue = 10.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _stoploss { get; set; }
        [Parameter("Safety (Pips)", DefaultValue = 3.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _safety { get; set; }
        [Parameter("High/Low Timeframe", DefaultValue = "Daily")]
        public TimeFrame _hltf { get; set; }
        private Bars _hlbars;
        private double _bullprice, _bearprice, _previoushigh, _previouslow, _maxunits, _activerisk;
        private bool _todaybuy, _todaysell;
        protected override void OnStart()
        {
            _hlbars = MarketData.GetBars(_hltf);
        }
        protected override void OnBar()
        {
            var _currenthours = Server.Time.TimeOfDay.TotalHours;
            bool _tradetime = _starttime < _stoptime ? _currenthours > _starttime && _currenthours < _stoptime : _currenthours < _stoptime || _currenthours > _starttime;
            _activerisk = GetRisk();
            var _volume = GetVolume();
            _maxunits = Symbol.QuantityToVolumeInUnits(_maxlots);
            if (_volume > _maxunits)
            {
                _volume = _maxunits;
            }
            _previoushigh = _hlbars.HighPrices.Last(1);
            _previouslow = _hlbars.LowPrices.Last(1);
            _bullprice = Symbol.Ask + (_safety / Symbol.PipValue);
            _bearprice = Symbol.Bid - (_safety / Symbol.PipValue);
            if (_tradetime && !_todaybuy)
            {
                if (_bullprice > _previoushigh)
                {
                    ExecuteMarketOrder(TradeType.Buy, Symbol.Name, _volume, _name, _stoploss, _takeprofit);
                    _todaybuy = true;
                }
            }
            if (!_tradetime && _todaybuy)
            {
                _todaybuy = false;
            }
            if (_tradetime && !_todaysell)
            {
                if (_bearprice < _previouslow)
                {
                    ExecuteMarketOrder(TradeType.Sell, Symbol.Name, _volume, _name, _stoploss, _takeprofit);
                    _todaysell = true;
                }
            }
            if (!_tradetime && _todaysell)
            {
                _todaysell = false;
            }
        }
        private double GetRisk()
        {
            double _result = 0.0;
            double _maxrisk = 10.0;
            var _lastposition = History.FindLast(_name);
            bool _win = _lastposition.NetProfit > 0.0 ? true : false;
            if (_win && _activerisk < _maxrisk)
            {
                _result = _activerisk + _riskstep;
            }
            else if (!_win)
            {
                _result = _startingrisk;
            }
            return _result;
        }
        private double GetVolume()
        {
            double costPerPip = (double)((int)(Symbol.PipValue * 10000000)) / 100;
            double baseNumber = Account.Balance;
            double sizeInLots = Math.Round((baseNumber * _activerisk / 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;
        }
    }
}
Replies
                     wmclennan77
                     10 Mar 2022, 13:25
                                    
RE:
amusleh said:
Hi,
Try this:
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 AFFS : Robot { [Parameter("Name", DefaultValue = "AFFS")] public string _name { get; set; } [Parameter("Start Hour", DefaultValue = 6.0)] public double _starttime { get; set; } [Parameter("Stop Hour", DefaultValue = 18.0)] public double _stoptime { get; set; } [Parameter("Max Lots", DefaultValue = 100.0, MinValue = 0.01, MaxValue = 1000.0)] public double _maxlots { get; set; } [Parameter("Starting Risk (%)", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0)] public double _startingrisk { get; set; } [Parameter("Risk Step (%)", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0)] public double _riskstep { get; set; } [Parameter("Take Profit", DefaultValue = 5.0, MinValue = 0.1, MaxValue = 100.0)] public double _takeprofit { get; set; } [Parameter("Stop Loss", DefaultValue = 10.0, MinValue = 0.1, MaxValue = 100.0)] public double _stoploss { get; set; } [Parameter("Safety (Pips)", DefaultValue = 3.0, MinValue = 0.1, MaxValue = 100.0)] public double _safety { get; set; } [Parameter("High/Low Timeframe", DefaultValue = "Daily")] public TimeFrame _hltf { get; set; } private Bars _hlbars; private double _bullprice, _bearprice, _previoushigh, _previouslow, _maxunits, _activerisk; private bool _todaybuy, _todaysell; protected override void OnStart() { _hlbars = MarketData.GetBars(_hltf); _safety *= Symbol.PipSize; } protected override void OnBar() { var _currenthours = Server.Time.TimeOfDay.TotalHours; bool _tradetime = _starttime < _stoptime ? _currenthours > _starttime && _currenthours < _stoptime : _currenthours < _stoptime || _currenthours > _starttime; _activerisk = GetRisk(); var _volume = GetVolume(); _maxunits = Symbol.QuantityToVolumeInUnits(_maxlots); if (_volume > _maxunits) { _volume = _maxunits; } _previoushigh = _hlbars.HighPrices.Last(1); _previouslow = _hlbars.LowPrices.Last(1); _bullprice = Symbol.Ask + _safety; _bearprice = Symbol.Bid - _safety; if (_tradetime && !_todaybuy) { if (_bullprice > _previoushigh) { ExecuteMarketOrder(TradeType.Buy, Symbol.Name, _volume, _name, _stoploss, _takeprofit); _todaybuy = true; } } if (!_tradetime && _todaybuy) { _todaybuy = false; } if (_tradetime && !_todaysell) { if (_bearprice < _previouslow) { ExecuteMarketOrder(TradeType.Sell, Symbol.Name, _volume, _name, _stoploss, _takeprofit); _todaysell = true; } } if (!_tradetime && _todaysell) { _todaysell = false; } } private double GetRisk() { double _result = 0.0; double _maxrisk = 10.0; var _lastposition = History.FindLast(_name); bool _win = _lastposition != null && _lastposition.NetProfit > 0.0 ? true : false; if (_win && _activerisk < _maxrisk) { _result = _activerisk + _riskstep; } else if (!_win) { _result = _startingrisk; } return _result; } private double GetVolume() { double costPerPip = (double)((int)(Symbol.PipValue * 10000000)) / 100; double baseNumber = Account.Balance; double sizeInLots = Math.Round((baseNumber * _activerisk / 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; } } }
Hi amusleh,
Thanks, works perfectly!
@wmclennan77
                     wmclennan77
                     11 Mar 2022, 11:42
                                    
RE:
amusleh said:
Hi,
Try this:
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 AFFS : Robot { [Parameter("Name", DefaultValue = "AFFS")] public string _name { get; set; } [Parameter("Start Hour", DefaultValue = 6.0)] public double _starttime { get; set; } [Parameter("Stop Hour", DefaultValue = 18.0)] public double _stoptime { get; set; } [Parameter("Max Lots", DefaultValue = 100.0, MinValue = 0.01, MaxValue = 1000.0)] public double _maxlots { get; set; } [Parameter("Starting Risk (%)", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0)] public double _startingrisk { get; set; } [Parameter("Risk Step (%)", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0)] public double _riskstep { get; set; } [Parameter("Take Profit", DefaultValue = 5.0, MinValue = 0.1, MaxValue = 100.0)] public double _takeprofit { get; set; } [Parameter("Stop Loss", DefaultValue = 10.0, MinValue = 0.1, MaxValue = 100.0)] public double _stoploss { get; set; } [Parameter("Safety (Pips)", DefaultValue = 3.0, MinValue = 0.1, MaxValue = 100.0)] public double _safety { get; set; } [Parameter("High/Low Timeframe", DefaultValue = "Daily")] public TimeFrame _hltf { get; set; } private Bars _hlbars; private double _bullprice, _bearprice, _previoushigh, _previouslow, _maxunits, _activerisk; private bool _todaybuy, _todaysell; protected override void OnStart() { _hlbars = MarketData.GetBars(_hltf); _safety *= Symbol.PipSize; } protected override void OnBar() { var _currenthours = Server.Time.TimeOfDay.TotalHours; bool _tradetime = _starttime < _stoptime ? _currenthours > _starttime && _currenthours < _stoptime : _currenthours < _stoptime || _currenthours > _starttime; _activerisk = GetRisk(); var _volume = GetVolume(); _maxunits = Symbol.QuantityToVolumeInUnits(_maxlots); if (_volume > _maxunits) { _volume = _maxunits; } _previoushigh = _hlbars.HighPrices.Last(1); _previouslow = _hlbars.LowPrices.Last(1); _bullprice = Symbol.Ask + _safety; _bearprice = Symbol.Bid - _safety; if (_tradetime && !_todaybuy) { if (_bullprice > _previoushigh) { ExecuteMarketOrder(TradeType.Buy, Symbol.Name, _volume, _name, _stoploss, _takeprofit); _todaybuy = true; } } if (!_tradetime && _todaybuy) { _todaybuy = false; } if (_tradetime && !_todaysell) { if (_bearprice < _previouslow) { ExecuteMarketOrder(TradeType.Sell, Symbol.Name, _volume, _name, _stoploss, _takeprofit); _todaysell = true; } } if (!_tradetime && _todaysell) { _todaysell = false; } } private double GetRisk() { double _result = 0.0; double _maxrisk = 10.0; var _lastposition = History.FindLast(_name); bool _win = _lastposition != null && _lastposition.NetProfit > 0.0 ? true : false; if (_win && _activerisk < _maxrisk) { _result = _activerisk + _riskstep; } else if (!_win) { _result = _startingrisk; } return _result; } private double GetVolume() { double costPerPip = (double)((int)(Symbol.PipValue * 10000000)) / 100; double baseNumber = Account.Balance; double sizeInLots = Math.Round((baseNumber * _activerisk / 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; } } }
Hi amusleh,
I have one more issue if you can help me.
In the bot above, is there any way to check in the OnStart if:
In the _hlbars period,  the one entry for the day has already happened? If so, the bot cannot trade until the next period.
For example, if HL is set to daily and I start the bot at 2 PM and today's entry happened at 1 PM, I don't want the bot to trade until the next day.
What is happening now is when I initialize the bot, the logic sees that the current price is higher than the previous high, and makes a buy immediately. This is wrong since the ideal entry has passed.
Any help would be greatly appreciated, thanks.
@wmclennan77
                     amusleh
                     14 Mar 2022, 08:58
                                    
Hi,
You can use the loaded Bars BarOpened event instead of Bot OnBar method, ex:
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 AFFS : Robot
    {
        [Parameter("Name", DefaultValue = "AFFS")]
        public string _name { get; set; }
        [Parameter("Start Hour", DefaultValue = 6.0)]
        public double _starttime { get; set; }
        [Parameter("Stop Hour", DefaultValue = 18.0)]
        public double _stoptime { get; set; }
        [Parameter("Max Lots", DefaultValue = 100.0, MinValue = 0.01, MaxValue = 1000.0)]
        public double _maxlots { get; set; }
        [Parameter("Starting Risk (%)", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0)]
        public double _startingrisk { get; set; }
        [Parameter("Risk Step (%)", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0)]
        public double _riskstep { get; set; }
        [Parameter("Take Profit", DefaultValue = 5.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _takeprofit { get; set; }
        [Parameter("Stop Loss", DefaultValue = 10.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _stoploss { get; set; }
        [Parameter("Safety (Pips)", DefaultValue = 3.0, MinValue = 0.1, MaxValue = 100.0)]
        public double _safety { get; set; }
        [Parameter("High/Low Timeframe", DefaultValue = "Daily")]
        public TimeFrame _hltf { get; set; }
        private Bars _hlbars;
        private double _bullprice, _bearprice, _previoushigh, _previouslow, _maxunits, _activerisk;
        private bool _todaybuy, _todaysell;
        protected override void OnStart()
        {
            _hlbars = MarketData.GetBars(_hltf);
            _hlbars.BarOpened += _hlbars_BarOpened;
            _safety *= Symbol.PipSize;
        }
        private void _hlbars_BarOpened(BarOpenedEventArgs obj)
        {
            var _currenthours = Server.Time.TimeOfDay.TotalHours;
            bool _tradetime = _starttime < _stoptime ? _currenthours > _starttime && _currenthours < _stoptime : _currenthours < _stoptime || _currenthours > _starttime;
            _activerisk = GetRisk();
            var _volume = GetVolume();
            _maxunits = Symbol.QuantityToVolumeInUnits(_maxlots);
            if (_volume > _maxunits)
            {
                _volume = _maxunits;
            }
            _previoushigh = _hlbars.HighPrices.Last(1);
            _previouslow = _hlbars.LowPrices.Last(1);
            _bullprice = Symbol.Ask + _safety;
            _bearprice = Symbol.Bid - _safety;
            if (_tradetime && !_todaybuy)
            {
                if (_bullprice > _previoushigh)
                {
                    ExecuteMarketOrder(TradeType.Buy, Symbol.Name, _volume, _name, _stoploss, _takeprofit);
                    _todaybuy = true;
                }
            }
            if (!_tradetime && _todaybuy)
            {
                _todaybuy = false;
            }
            if (_tradetime && !_todaysell)
            {
                if (_bearprice < _previouslow)
                {
                    ExecuteMarketOrder(TradeType.Sell, Symbol.Name, _volume, _name, _stoploss, _takeprofit);
                    _todaysell = true;
                }
            }
            if (!_tradetime && _todaysell)
            {
                _todaysell = false;
            }
        }
        private double GetRisk()
        {
            double _result = 0.0;
            double _maxrisk = 10.0;
            var _lastposition = History.FindLast(_name);
            bool _win = _lastposition != null && _lastposition.NetProfit > 0.0 ? true : false;
            if (_win && _activerisk < _maxrisk)
            {
                _result = _activerisk + _riskstep;
            }
            else if (!_win)
            {
                _result = _startingrisk;
            }
            return _result;
        }
        private double GetVolume()
        {
            double costPerPip = (double)((int)(Symbol.PipValue * 10000000)) / 100;
            double baseNumber = Account.Balance;
            double sizeInLots = Math.Round((baseNumber * _activerisk / 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;
        }
    }
}
This way the execution logic will be executed only once per bar based on your selected time frame.
@amusleh

amusleh
10 Mar 2022, 10:16
Hi,
Try this:
@amusleh