Timed position close issue

victor.major since: 20 Nov 2019;

  03 May 2021, 10:37
Timed position close issue

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.

amusleh's avatar

amusleh since: 01 Mar 2021;

  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);
                }
            }
        }
    }
}
Community Developer | Spotware

victor.major since: 20 Nov 2019;

  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);
                }
            }
        }
    }
}
amusleh's avatar

amusleh since: 01 Mar 2021;

  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.

Community Developer | Spotware