How do you know if the current "OnTick" event is going to trigger the "OnBar" event?
How do you know if the current "OnTick" event is going to trigger the "OnBar" event?
20 Apr 2022, 16:45
Hi everyone / @Spotware,
How do you know if the current "OnTick" event is happening just before the "OnBar" event?
The reason I'm asking is because I've encountered this scenario. I have a bot with flags set to determine if a position was entered/increased during the current bar. What happens is when this execution occurs on the tick _before_ the OnBar event, flags get reset and it happens twice in the same bar on the cTrader chart, even though it technically shouldn't. :
20/04/2022 21:22:00.832 | OnTick
20/04/2022 21:22:00.551 | OnTick --> increases position again this bar because flag was reset. Technically it shouldn't because the new bar should have started at 21:22:00.317. Also, cTrader shows both events on the same bar on the chart instead of the two separate bars (the one _before_ the OnBar and the one _after_ the OnBar).
20/04/2022 21:22:00.318 | OnBar --> flag gets reset
20/04/2022 21:22:00.317 | OnTick --> enters position this bar, which is the previous bar. Flag gets set to true. Shouldn't a new bar be opened here before this tick event since
: it's the first tick event after the previous minute during the M1 timeframe?
:
:
:
20/04/2022 21:21:59.410 | OnTick
20/04/2022 21:21:32.504 | OnTick
20/04/2022 21:21:32.348 | OnTick
20/04/2022 21:21:32.239 | cBot "BugBot" was started successfully for NAS100, m1.
This is the pseudo code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
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 BugBot : Robot
{
private bool _enteredPositionThisBar;
/// <summary>
/// OnBar
/// </summary>
protected override void OnBar()
{
Print("OnBar");
_enteredPositionThisBar = false;
}
/// <summary>
/// OnTick
/// </summary>
protected override void OnTick()
{
Print("OnTick");
if (!_enteredPositionThisBar) // && some condition that evaluates to
// true on the "OnTick" just before the "OnBar" event
{
//Enter or increase position size
//Set this flag so we don't do it again this bar
_enteredPositionThisBar = true;
//However, when this occurs on the tick event on the same hour just
//a millisecond before the new bar is opened, we get screwed
}
}
}
}
Replies
firemyst
22 Apr 2022, 04:20
( Updated at: 21 Dec 2023, 09:22 )
RE:
amusleh said:
Hi,
There is no way to know when a tick results on opening of a new bar, you can use a timer to count the remaining time of a bar but that works only for time based bars not for Tick, Renko, and range bars, you have to know the time period of a time frame bar as there is no way for now to know how much is a time based time frame bar time period programmatically.
I recommend you to change the way you designed your bot, instead of using the timer, as it would be not 100% accurate.
cBots OnTick method is called before OnBar, and by a single thread, so they will never be called concurrently.
These types of issues are more related to the way you design your Bot than API limitations.
I don't think you fully understand what I'm trying to describe or I'm not being clear enough.
I do not use a timer in the algorithm. The timings you see in the log statements are from the "Log" tab in cTrader.
I use the "OnTick" and "OnBar" methods with a boolean flag. The code is structured as per my first post.
The bot checked to increase the position size. Since it hadn't already done so that bar, it increased by 0.1 lots, and then set the flag "_enteredPositionThisBar" to true so the bot would not enter another position in the current bar.
That was on the tick called just before the OnBar, but the clock had already ticked over to the next minute, so it should have occurred during the 21.00.00 bar and not the bar opened at 20.59.00.
Then the next bar is opened, and since the flag "_enteredPositionThisBar" was set to false in the "OnBar" method, the bot immediately increased the position size again during the 21.00.00 bar as you can see from the screen capture. Note I do NOT use any asynchronous calls when placing orders.
20/04/2022 20:51:39.729 | cBot "BugBot" was started successfully for NAS100, m1.
20/04/2022 20:51:54.348 | OnTick
:
20/04/2022 21:00:00.775 | OnTick --> it increased the size here, adding 0.1 lots. "_enteredPositionThisBar" set to true.
20/04/2022 21:00:00.909 | OnBar --> "_enteredPositionThisBar" set to false.
20/04/2022 21:01:00.313 | OnTick --> it increased the size again here by 0.1 lots and reset the flag the true.
20/04/2022 21:00:00.418 | OnTick
So because the "OnBar" even occurs _after_ the first tick event in that new bar, it opens a position twice during the same bar when technically it shouldn't since the new bar hadn't been opened yet. With the log above and screen captures below, do you see what I'm saying?
Since boolean flags won't work since tick events for a new bar's timeframe occur _before_ the "OnBar" event actually occurs, and we can't use the Bars.OpenTimes.Count to check if the number of bars have increased (because on the first tick in the new M1 bar, the new bar hasn't been formed yet), would you be able to provide sample code to get around this issue?
Here's what happened. Note the deal map and compare against the logs. cTrader shows BOTH orders being displayed in the same bar even though the first one happened during the tick event _before_ the "OnBar" event:
Thank you.
@firemyst
amusleh
26 Apr 2022, 10:05
Hi,
I did understood your point, what I was trying to explain was there is no way to accurately know when a tick will result in formation of a new bar.
Regarding your issue, you can do something like this:
using cAlgo.API;
using System.Collections.Generic;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class Sample : Robot
{
private readonly Dictionary<int, PositionBarOperation> _positionBarOperations = new Dictionary<int, PositionBarOperation>();
protected override void OnTick()
{
foreach (var position in Positions)
{
PositionBarOperation operation;
// If position ID is inside _positionBarOperations
// Then it means we already executed something for it
if (_positionBarOperations.TryGetValue(position.Id, out operation))
{
// It means the bar is not changed yet
if (operation.BarIndex == Bars.Count)
{
continue;
}
// Bar changed
else
{
operation.BarIndex = Bars.Count;
// Modify, close, etc...
}
}
// Position ID is not inside _positionBarOperations
else
{
operation = new PositionBarOperation
{
Position = position,
BarIndex = Bars.Count
};
_positionBarOperations.Add(position.Id, operation);
// Modify, close, etc...
}
}
}
private class PositionBarOperation
{
public Position Position { get; set; }
public int BarIndex { get; set; }
}
}
}
@amusleh
firemyst
26 Apr 2022, 10:16
RE:
amusleh said:
Hi,
I did understood your point, what I was trying to explain was there is no way to accurately know when a tick will result in formation of a new bar.
Regarding your issue, you can do something like this:
Okay. Cool. Thanks for that and your sample code. I haven't looked at the sample code, but had another question -- with cTrader shouldn't it (or is it already) programmed up to open a new bar regardless of whether or not a tick comes through?
It it takes the timing of a tick to actually open a new bar, then hypothetically bars could open up halfway through their time period, or even not at all.
If it is set to open a new bar regardless of whether a tick or not happens, then the example I provided seems to illustrate a bug where ticks happen before the bar is actually opened.
Thank you.
@firemyst
amusleh
26 Apr 2022, 10:18
RE: RE:
firemyst said:
amusleh said:
Hi,
I did understood your point, what I was trying to explain was there is no way to accurately know when a tick will result in formation of a new bar.
Regarding your issue, you can do something like this:
Okay. Cool. Thanks for that and your sample code. I haven't looked at the sample code, but had another question -- with cTrader shouldn't it (or is it already) programmed up to open a new bar regardless of whether or not a tick comes through?
It it takes the timing of a tick to actually open a new bar, then hypothetically bars could open up halfway through their time period, or even not at all.
If it is set to open a new bar regardless of whether a tick or not happens, then the example I provided seems to illustrate a bug where ticks happen before the bar is actually opened.
Thank you.
Hi,
If there is no tick then there will be no bars, cTrader only creates bars if there are any ticks otherwise it will not form any bar and the OnBar method will not be called.
@amusleh
amusleh
21 Apr 2022, 11:05
Hi,
There is no way to know when a tick results on opening of a new bar, you can use a timer to count the remaining time of a bar but that works only for time based bars not for Tick, Renko, and range bars, you have to know the time period of a time frame bar as there is no way for now to know how much is a time based time frame bar time period programmatically.
I recommend you to change the way you designed your bot, instead of using the timer, as it would be not 100% accurate.
cBots OnTick method is called before OnBar, and by a single thread, so they will never be called concurrently.
These types of issues are more related to the way you design your Bot than API limitations.
@amusleh