use multiple timers and events OnTimer ()

Created at 18 Jul 2020, 19:47
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!
TR

tradermatrix

Joined 24.07.2012

use multiple timers and events OnTimer ()
18 Jul 2020, 19:47


Hello
I would like to use multiple timers and events OnTimer ()
For example, I want a timer to count 100 minutes periods and then trigger an event, and another timer to count minutes and trigger an event at 300 minutes.
In the simple example below, if you operate each indicator independently it works perfectly.
But if the 2 indicators work together, it is always the last timer (Interval MACD int _Interval2) which manages all the events ...
Interval MA int _Interval1: no longer useful.
you will realize this by adding the MA + MACD results with a backtesting for each indicator and then a backtesting together ...

I have the impression that we cannot create several partitions with OnTimer ()
I may also be making a coding error

is there another method to work around the problem.
cordially

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.None)]
    public class EXEMPLEDOUBLETIMER : Robot
    {
        [Parameter("Volume", DefaultValue = 10000)]
        public double volume { get; set; }

        [Parameter("----------MA------------", DefaultValue = "MA")]
        public string Separator1 { get; set; }

        [Parameter("Use MA", DefaultValue = true)]
        public bool UseMA { get; set; }

        [Parameter("Interval (Minut)", DefaultValue = 100)]
        public int _Interval1 { get; set; }

        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("Period", DefaultValue = 125)]
        public int Period { get; set; }

        [Parameter("Moving Average Type", DefaultValue = MovingAverageType.TimeSeries)]
        public MovingAverageType MovingAverageType { get; set; }

        [Parameter("SL ", DefaultValue = 160)]
        public int sl1 { get; set; }

        [Parameter("TP ", DefaultValue = 80)]
        public int tp1 { get; set; }

        [Parameter("----------MACD------------", DefaultValue = "MACD")]
        public string Separator2 { get; set; }

        [Parameter("Use MAcd", DefaultValue = true)]
        public bool UseMACD { get; set; }

        [Parameter("Interval (Minut)", DefaultValue = 300)]
        public int _Interval2 { get; set; }

        [Parameter("MACD LongCycle", DefaultValue = 26, MinValue = 1)]
        public int LongCycle { get; set; }

        [Parameter("MACD ShortCycle", DefaultValue = 12, MinValue = 1)]
        public int ShortCycle { get; set; }

        [Parameter("MACD Period", DefaultValue = 9, MinValue = 1)]
        public int MACDPeriod { get; set; }

        [Parameter("SL ", DefaultValue = 160)]
        public int sl2 { get; set; }

        [Parameter("TP ", DefaultValue = 80)]
        public int tp2 { get; set; }

        private MacdHistogram MACD;

        private MovingAverage MA;

        protected override void OnStart()
        {



            MA = Indicators.MovingAverage(Source, Period, MovingAverageType);

            MACD = Indicators.MacdHistogram(LongCycle, ShortCycle, MACDPeriod);


            TIMER();
            TIMER2();

        }
        private void TIMER()
        {

            if (UseMA)
                Timer.Start(_Interval1 * 60);


        }

        private void TIMER2()
        {

            if (UseMACD)
                Timer.Start(_Interval2 * 60);


        }
        protected override void OnTimer()
        {

            ManagePositions1();
            ManagePositions2();

        }
        protected override void OnTick()
        {



            //   ManagePositions1();
            //   ManagePositions2();
        }

        private void ManagePositions1()
        {
            var cBotPositions = Positions.FindAll("MoVinG");

            if (cBotPositions.Length >= 1)
                return;

            double MA2 = MA.Result[MA.Result.Count - 2];
            int bars = MarketSeries.Close.Count - 1;
            double cl = MarketSeries.Close[bars - 1];




            if (UseMA && MA2 < cl)
            {
                ExecuteMarketOrder(TradeType.Buy, Symbol, volume, "MoVinG", sl1, tp1);

            }
            else if (UseMA && MA2 > cl)
            {
                ExecuteMarketOrder(TradeType.Sell, Symbol, volume, "MoVinG", sl1, tp1);
            }
        }
        private void ManagePositions2()
        {
            var cBotPositions = Positions.FindAll("Macd");

            if (cBotPositions.Length >= 1)
                return;


            if (UseMACD && MACD.Histogram.LastValue > 0.0 && MACD.Signal.IsRising())
            {
                ExecuteMarketOrder(TradeType.Buy, Symbol, volume, "Macd", sl2, tp2);

            }
            else if (UseMACD && MACD.Histogram.LastValue < 0.0 && MACD.Signal.IsFalling())
            {
                ExecuteMarketOrder(TradeType.Sell, Symbol, volume, "Macd", sl2, tp2);
            }
        }



    }
}




 


@tradermatrix
Replies

PanagiotisCharalampous
20 Jul 2020, 09:10

Hi tradermatrix,

At the moment you can only have one instance of the Timer. You will need to implement your logic with this limitation in mind.

Best Regards,

Panagiotis 

Join us on Telegram

 


@PanagiotisCharalampous

tradermatrix
20 Jul 2020, 15:11

RE:

PanagiotisCharalampous said:

Hi tradermatrix,

At the moment you can only have one instance of the Timer. You will need to implement your logic with this limitation in mind.

Best Regards,

Panagiotis 

Join us on Telegram

Hi Panagiotis
Thank you for your reply.
It is a shame because for example I have a robot with 14 different strategies and I am therefore obliged to keep the same deadlines for all instances.
I even think that if the timer is open on a robot, it also intervenes on another robot in operation.
The "OnTimer ()" timer should be associated with the label, this would create several instances of different timers ...

otherwise the method "System.Threading.Thread.Sleep (60000 * _Interval1);" is very easy to use and works on as many desired instances but is still not compatible with backtesting or optimization.
cordially

 


@tradermatrix

PanagiotisCharalampous
20 Jul 2020, 15:14

Hi tradermatrix,

I do not see why you cannot implement different checks with a single timer event, one for every strategy. It needs some coding but its achievable. 

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

tradermatrix
20 Jul 2020, 16:08

RE:

PanagiotisCharalampous said:

Hi tradermatrix,

I do not see why you cannot implement different checks with a single timer event, one for every strategy. It needs some coding but its achievable. 

Best Regards,

Panagiotis 

Join us on Telegram

Thank you for your reply.
so I am making a mistake.
Do you have a sample code to share?


@tradermatrix

PanagiotisCharalampous
20 Jul 2020, 16:21

Hi tradermatrix,

It depends on what are you trying to achieve. In principle, you can set your timer to a fast interval e.g. one second, and then implement time checks on custom intervals. See an example below

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.None)]
    public class NewcBot : Robot
    {
        [Parameter(DefaultValue = 30)]
        public int Interval1 { get; set; }

        [Parameter(DefaultValue = 50)]
        public int Interval2 { get; set; }

        DateTime _interval1;
        DateTime _interval2;

        protected override void OnStart()
        {
            _interval1 = Server.Time;
            _interval2 = Server.Time;
            Timer.TimerTick += Timer_TimerTick;
            Timer.Start(1);
        }

        private void Timer_TimerTick()
        {
            if (_interval1.AddSeconds(Interval1) < Server.Time)
            {
                Print("Interval 1 Triggered");
                _interval1 = Server.Time;
            }
            if (_interval2.AddSeconds(Interval2) < Server.Time)
            {
                Print("Interval 2 Triggered");
                _interval2 = Server.Time;
            }
        }

        protected override void OnTick()
        {
            // Put your core logic here
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

tradermatrix
20 Jul 2020, 17:43

RE:

Thank you for your precious help, I will experiment your method and look for a solution to adapt it to my needs.
Best Regards,

 


@tradermatrix

Obiriec
28 Jul 2023, 16:00 ( Updated at: 28 Jul 2023, 16:06 )

RE: use multiple timers and events OnTimer ()

PanagiotisCharalampous said: 

Hi tradermatrix,

It depends on what are you trying to achieve. In principle, you can set your timer to a fast interval e.g. one second, and then implement time checks on custom intervals. See an example below

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.None)]    public class NewcBot : Robot    {        [Parameter(DefaultValue = 30)]        public int Interval1 { get; set; }        [Parameter(DefaultValue = 50)]        public int Interval2 { get; set; }        DateTime _interval1;        DateTime _interval2;        protected override void OnStart()        {            _interval1 = Server.Time;            _interval2 = Server.Time;            Timer.TimerTick += Timer_TimerTick;            Timer.Start(1);        }        private void Timer_TimerTick()        {            if (_interval1.AddSeconds(Interval1) < Server.Time)            {                Print("Interval 1 Triggered");                _interval1 = Server.Time;            }            if (_interval2.AddSeconds(Interval2) < Server.Time)            {                Print("Interval 2 Triggered");                _interval2 = Server.Time;            }        }        protected override void OnTick()        {            // Put your core logic here        }        protected override void OnStop()        {            // Put your deinitialization logic here        }    }}

Best Regards,

Panagiotis 

Join us on Telegram

Good evening, I have a request similar to this user's post:
I programmed a cBot that works on a single instance of cTrader simultaneously on all 28 Forex pairs.
The cBot is able to recognize if there are "correlated" pairs to avoid having to open multiple operations, for example: if a EURUSD operation is already open, it will no longer open operations on all pairs that contain EUR or USD.
This logic works well but only if there is already an open trade.
When there is no operation open, it happens that, if the opening conditions occur simultaneously, the various instances of the cBot open the first operation and very often the presence of pairs that should not have been opened is seen.
I tried inserting a timer inside the code that sets the seconds of delay depending on the pair it's running on taking the value from a list but unfortunately I can't get the result I want because the timer doesn't make the requested pause but it loops in just one tick.
This must be done "OnBar" every time.
I may have some suggestions or correction of the code that I report in the attachment.

This is a part of code:

…..
 var Loop = 0;

           string AUDCAD = "AUDCAD";
           string AUDCHF = "AUDCHF";
           string AUDJPY = "AUDJPY";
           string AUDNZD = "AUDNZD";
           string AUDUSD = "AUDUSD";
           string CADCHF = "CADCHF";
           string CADJPY = "CADJPY";
           string CHFJPY = "CHFJPY";
           string EURAUD = "EURAUD";
           string EURCAD = "EURCAD";
           string EURCHF = "EURCHF";
           string EURGBP = "EURGBP";
           string EURJPY = "EURJPY";
           string EURNZD = "EURNZD";
           string EURUSD = "EURUSD";
           string GBPAUD = "GBPAUD";
           string GBPCAD = "GBPCAD";
           string GBPCHF = "GBPCHF";
           string GBPJPY = "GBPJPY";
           string GBPNZD = "GBPNZD";
           string GBPUSD = "GBPUSD";
           string NZDCAD = "NZDCAD";
           string NZDCHF = "NZDCHF";
           string NZDJPY = "NZDJPY";
           string NZDUSD = "NZDUSD";
           string USDCAD = "USDCAD";
           string USDCHF = "USDCHF";
           string USDJPY = "USDJPY";

           if (Symbol.Name.Contains(AUDCAD))
           {
               Loop = 7;
           }
           if (Symbol.Name.Contains(AUDCHF))
           {
               Loop = 11;
           }
           if (Symbol.Name.Contains(AUDJPY))
           {
               Loop = 13;
           }
           if (Symbol.Name.Contains(AUDNZD))
           {
               Loop = 17;
           }
           if (Symbol.Name.Contains(AUDUSD))
           {
               Loop = 19;
           }
           if (Symbol.Name.Contains(CADCHF))
           {
               Loop = 23;
           }
           if (Symbol.Name.Contains(CADJPY))
           {
               Loop = 29;
           }
           if (Symbol.Name.Contains(CHFJPY))
           {
               Loop = 31;
           }
           if (Symbol.Name.Contains(EURAUD))
           {
               Loop = 37;
           }
           if (Symbol.Name.Contains(EURCAD))
           {
               Loop = 41;
           }
           if (Symbol.Name.Contains(EURCHF))
           {
               Loop = 43;
           }
           if (Symbol.Name.Contains(EURGBP))
           {
               Loop = 47;
           }
           if (Symbol.Name.Contains(EURJPY))
           {
               Loop = 53;
           }
           if (Symbol.Name.Contains(EURNZD))
           {
               Loop = 59;
           }
           if (Symbol.Name.Contains(EURUSD))
           {
               Loop = 61;
           }
           if (Symbol.Name.Contains(GBPAUD))
           {
               Loop = 67;
           }
           if (Symbol.Name.Contains(GBPCAD))
           {
               Loop = 71;
           }
           if (Symbol.Name.Contains(GBPCHF))
           {
               Loop = 73;
           }
           if (Symbol.Name.Contains(GBPJPY))
           {
               Loop = 79;
           }
           if (Symbol.Name.Contains(GBPNZD))
           {
               Loop = 83;
           }
           if (Symbol.Name.Contains(GBPUSD))
           {
               Loop = 89;
           }
           if (Symbol.Name.Contains(NZDCAD))
           {
               Loop = 97;
           }
           if (Symbol.Name.Contains(NZDCHF))
           {
               Loop = 101;
           }
           if (Symbol.Name.Contains(NZDJPY))
           {
               Loop = 103;
           }
           if (Symbol.Name.Contains(NZDUSD))
           {
               Loop = 107;
           }
           if (Symbol.Name.Contains(USDCAD))
           {
               Loop = 109;
           }
           if (Symbol.Name.Contains(USDCHF))
           {
               Loop = 113;
           }
           if (Symbol.Name.Contains(USDJPY))
           {
               Loop = 127;
           }

           var Account_Positions = Positions.Count;

           Timer.Start(Loop);

           for (int i = 0; i < Loop; i++)
           {
               Print("Loop n.: " + Loop + " >> " + i + "");
           }
           Timer.Stop();

…….

 

Once the cBot has "entered" the Loop, it should remain still for the set time but instead immediately exits and executes the rest of the code.

Surely I made a mistake in setting this part of the code but despite trying to write it in another way, I still can't find the solution!


@Obiriec