Timed position close issue

Created at 03 May 2021, 10:37
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!
VI

victor.major

Joined 20.11.2019

Timed position close issue
03 May 2021, 10:37


Good day,

I added a timed position close loop into one of my trading bots, but it is not closing as expected every time.

For example:



With the settings for timed close set at 60 minutes, the profitable open positions in the first circle on the left should have closed at the circled segments to the right. The time that elapsed between open and the profitable peaks was approximately 3 days.

 

Code:

var CurrentTime = Server.TimeInUtc;

//Close expired profitable positions               
                foreach (var LongPosition in Positions.FindAll(robLabel, SymbolName, TradeType.Buy))
                    if ((IsPEtimer == true) && (LongPosition.EntryTime.AddMinutes(PEMinutes) > CurrentTime) && (LongPosition.NetProfit > revProfitClose))
                        {                        
                            ClosePosition(LongPosition);
                        }

 

The above works most of the time, but it fails a significant number of times so I need to fix this.

Ideas:

1. Server.TimeInUtc does not consider the date only time of day

2. The rest of the code runs into an exception so this loop does not get to execute every time step (OnBar), however in the code itself this is placed before the main trading logic loops.

 

V.


@victor.major
Replies

amusleh
03 May 2021, 12:10

Hi,

There are several issues with your code, first you should not put any time based logic inside OnBar method, instead you should use the OnTimer method and start timer on an interval that suits your specific needs.

You should not use TimeInUtc, the position EntryTime is set based on your robot time zone attribute, and you should use Server.Time not Server.TimeInUtc, it only works if your robot time zone is UTC.

Here is an example cBot:

using cAlgo.API;
using System;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ClosePositionOnTime : Robot
    {
        [Parameter("Timer Interval (Seconds)", DefaultValue = 1, MinValue = 1)]
        public int TimerIntervalInSeconds { get; set; }

        [Parameter("Trade Type", DefaultValue = TradeType.Buy)]
        public TradeType TradeType { get; set; }

        [Parameter("Profit", DefaultValue = 100)]
        public double Profit { get; set; }

        [Parameter("Close Time (Minutes)", DefaultValue = 60)]
        public double CloseTimeInMinutes { get; set; }

        [Parameter("Label", DefaultValue = "My_cBot")]
        public string Label { get; set; }

        protected override void OnStart()
        {
            Timer.Start(TimerIntervalInSeconds);
        }

        protected override void OnTimer()
        {
            var currentTime = Server.Time;

            foreach (var position in Positions)
            {
                // Filter positions
                if (!string.Equals(position.Label, Label, StringComparison.OrdinalIgnoreCase) || !position.SymbolName.Equals(SymbolName, StringComparison.OrdinalIgnoreCase) || position.TradeType != TradeType)
                {
                    continue;
                }

                // Close if position meet the condition
                if (position.EntryTime.AddMinutes(CloseTimeInMinutes) >= currentTime && position.NetProfit >= Profit)
                {
                    ClosePosition(position);
                }
            }
        }
    }
}

 


@amusleh

victor.major
03 May 2021, 12:33

RE:

This looks great! Thank you.

One question, why are we declaring the following as a user variable? Is there any benefit to making the timer not refresh every second for example?

[Parameter("Timer Interval (Seconds)", DefaultValue = 1, MinValue = 1)]
        public int TimerIntervalInSeconds { get; set; }

 

 

V.

amusleh said:

Hi,

There are several issues with your code, first you should not put any time based logic inside OnBar method, instead you should use the OnTimer method and start timer on an interval that suits your specific needs.

You should not use TimeInUtc, the position EntryTime is set based on your robot time zone attribute, and you should use Server.Time not Server.TimeInUtc, it only works if your robot time zone is UTC.

Here is an example cBot:

using cAlgo.API;
using System;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ClosePositionOnTime : Robot
    {
        [Parameter("Timer Interval (Seconds)", DefaultValue = 1, MinValue = 1)]
        public int TimerIntervalInSeconds { get; set; }

        [Parameter("Trade Type", DefaultValue = TradeType.Buy)]
        public TradeType TradeType { get; set; }

        [Parameter("Profit", DefaultValue = 100)]
        public double Profit { get; set; }

        [Parameter("Close Time (Minutes)", DefaultValue = 60)]
        public double CloseTimeInMinutes { get; set; }

        [Parameter("Label", DefaultValue = "My_cBot")]
        public string Label { get; set; }

        protected override void OnStart()
        {
            Timer.Start(TimerIntervalInSeconds);
        }

        protected override void OnTimer()
        {
            var currentTime = Server.Time;

            foreach (var position in Positions)
            {
                // Filter positions
                if (!string.Equals(position.Label, Label, StringComparison.OrdinalIgnoreCase) || !position.SymbolName.Equals(SymbolName, StringComparison.OrdinalIgnoreCase) || position.TradeType != TradeType)
                {
                    continue;
                }

                // Close if position meet the condition
                if (position.EntryTime.AddMinutes(CloseTimeInMinutes) >= currentTime && position.NetProfit >= Profit)
                {
                    ClosePosition(position);
                }
            }
        }
    }
}

 

 


@victor.major

amusleh
03 May 2021, 12:53

RE: RE:

victor.major said:

This looks great! Thank you.

One question, why are we declaring the following as a user variable? Is there any benefit to making the timer not refresh every second for example?

[Parameter("Timer Interval (Seconds)", DefaultValue = 1, MinValue = 1)]
        public int TimerIntervalInSeconds { get; set; }

 

 

V.

amusleh said:

Hi,

There are several issues with your code, first you should not put any time based logic inside OnBar method, instead you should use the OnTimer method and start timer on an interval that suits your specific needs.

You should not use TimeInUtc, the position EntryTime is set based on your robot time zone attribute, and you should use Server.Time not Server.TimeInUtc, it only works if your robot time zone is UTC.

Here is an example cBot:

using cAlgo.API;
using System;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ClosePositionOnTime : Robot
    {
        [Parameter("Timer Interval (Seconds)", DefaultValue = 1, MinValue = 1)]
        public int TimerIntervalInSeconds { get; set; }

        [Parameter("Trade Type", DefaultValue = TradeType.Buy)]
        public TradeType TradeType { get; set; }

        [Parameter("Profit", DefaultValue = 100)]
        public double Profit { get; set; }

        [Parameter("Close Time (Minutes)", DefaultValue = 60)]
        public double CloseTimeInMinutes { get; set; }

        [Parameter("Label", DefaultValue = "My_cBot")]
        public string Label { get; set; }

        protected override void OnStart()
        {
            Timer.Start(TimerIntervalInSeconds);
        }

        protected override void OnTimer()
        {
            var currentTime = Server.Time;

            foreach (var position in Positions)
            {
                // Filter positions
                if (!string.Equals(position.Label, Label, StringComparison.OrdinalIgnoreCase) || !position.SymbolName.Equals(SymbolName, StringComparison.OrdinalIgnoreCase) || position.TradeType != TradeType)
                {
                    continue;
                }

                // Close if position meet the condition
                if (position.EntryTime.AddMinutes(CloseTimeInMinutes) >= currentTime && position.NetProfit >= Profit)
                {
                    ClosePosition(position);
                }
            }
        }
    }
}

 

 

Hi,

I did it for showing to you, you can set the timer interval to any value you want to fixed in code.


@amusleh

jani
23 Jan 2022, 23:40

Small correction to the the sample code

Thanks for all the good code.

 

I noticed a small logic error.

You should have:

  if (position.EntryTime.AddMinutes(CloseTimeInMinutes) <= currentTime && position.NetProfit >= Profit)

Instead of:

  if (position.EntryTime.AddMinutes(CloseTimeInMinutes) >= currentTime && position.NetProfit >= Profit)

This way position is closed when server time passes the position entry time + added minutes. and  profit is greater than the set threshold.


@jani