Announcement
Collapse
No announcement yet.
Partner 728x90
Collapse
NinjaTrader
Calculate OnBarClose when OnPriceChange selected.
Collapse
X
-
No, my friend, I'm not missing the return. Yes, you're right this means double print. According to different scenarios you want to add again.Originally posted by bltdavid View Post
You're missing a return inside your IsFirstTickOfBar, right?
For example, if you have a custom series inside your strategy and you want to calculate the current value only on bar close and all other trading logic will be processed tick by tick.
So you don't want to use return. Something like this;
if (IsFirstTickOfBar)
{
Do some calculations because the current bar closed right now...
Below we'll use updated values until the next bar close so don't use return
}
if (Position.MarketPosition == MarketPosition.Flat)
{
Use updated values for trade logic...
}
Also thank you so much for your tips. They are very valuable and useful.
Leave a comment:
-
You're missing a return inside your IsFirstTickOfBar, right?Originally posted by aytacasan View PostCode:if (IsFirstTickOfBar) { var barsAgo = (Calculate == Calculate.OnBarClose || State == State.Historical) ? 0 : 1; if (DateTime.Now >= Time[barsAgo]) { var currentBar = CurrentBar - barsAgo; Print(string.Format("OnBarClose {0} {1} {2} {3} {4} {5}", currentBar.ToString("0000"), Time[barsAgo].ToString("yyyyMMdd HH:mm"), Open[barsAgo].ToString("0.00"), High[barsAgo].ToString("0.00"), Low[barsAgo].ToString("0.00"), Close[barsAgo].ToString("0.00"))); } return; // [COLOR=#e74c3c]<-- you're missing this, right?[/COLOR] }
I mean, for that piece of code, without the return, you're gonna have
double prints on the first tick of every bar, right?
Mind if I make some more coding suggestions?
Let's make your code a bit easier to read, and easier to write.
[I know this is very subjective, but you may find some useful nuggets here.]
-=o=-
TIP #1
I like to make these three methods available for every Indicator and Strategy,
The important one here is FormatPrice -- it will show the correct numberCode:public double RoundToTickSize(double Price) { return Instrument.MasterInstrument.RoundToTickSize(Price) ; } public string FormatPrice(double Price) { return Instrument.MasterInstrument.FormatPrice(RoundToTic kSize(Price)); } public int ComparePrice(double Price1, double Price2) { return Instrument.MasterInstrument.Compare(Price1, Price2); }
of decimals (or fractionals, in the case of Treasury bonds), so your code
becomes insulated form the TickSize of the instrument.
Now your first Print becomes,
-=o=-Code:Print(string.Format("OnBarClose {0} {1} {2} {3} {4} {5}", currentBar.ToString("0000"), Time[barsAgo].ToString("yyyyMMdd HH:mm"), FormatPrice(Open[barsAgo]), FormatPrice(High[barsAgo]), FormatPrice(Low[barsAgo]), FormatPrice(Close[barsAgo])));
TIP #2
I would suggest that typing currentBar.ToString("0000") is a bit
too much typing, I mean, my fingers get achy just looking at that ... lol ...
Try moving that format specification inside the string.Format itself, like this,
That helps to make the code a little bit cleaner and easier to read.Code:Print(string.Format("OnBarClose [B][COLOR=#e74c3c]{0:0000}[/COLOR][/B] {1} {2} {3} {4} {5}", currentBar, Time[barsAgo].ToString("yyyyMMdd HH:mm"), FormatPrice(Open[barsAgo]), FormatPrice(High[barsAgo]), FormatPrice(Low[barsAgo]), FormatPrice(Close[barsAgo])));
-=o=-
TIP #3
I predict that you use Print(string.Format(....)) a lot, which is
a very good thing. This next tip helps to make that a little bit easier.
I like to make this method available to every Indicator and Strategy,
Your Print easily becomes a PrintString, like this,Code:public void PrintString(string format, params object[] args) { Print(string.Format(format, args)); }
Big deal, you say, small savings in typing, who cares, it's just a personalCode:PrintString("OnBarClose [B][COLOR=#e74c3c]{0:0000}[/COLOR][/B] {1} {2} {3} {4} {5}", currentBar, Time[barsAgo].ToString("yyyyMMdd HH:mm"), FormatPrice(Open[barsAgo]), FormatPrice(High[barsAgo]), FormatPrice(Low[barsAgo]), FormatPrice(Close[barsAgo]));
matter of taste and style. Sure, but there are benefits to this approach.
What are those benefits?
1. What if you want to turn off all your debugging output?
PrintString allows you to setup a single global variable, which can
later become your primary knob to disable that debugging output quickly
and easily, like this,
2. What if you want to use PrintString everywhere?Code:public void PrintString(string format, params object[] args) { if (IsDebugging) Print(string.Format(format, args)); }
Well, you can wrap that other long output method easily, like this,
I've found PrintString to be a nice little method that encapsulates all myCode:public void PrintString(string format, params object[] args) { NinjaTrader.Code.Output.Process(string.Format(format, args), PrintTo.OutputTab1); }
printing to the output window.
-=o=-
TIP #4
FormatPrice can be used with FormatPriceMarker to make all your
Treasury bond charts more consistent and a little easier to use.
Study the technique here.
Leave a comment:
-
Hi David,Originally posted by bltdavid View Post
Yeah, you've discovered something else, and that is the Historical -> RealTime transition
doesn't seem so clean.
Although the support team does not comment on this issue, I think the most correct approach should be as follows.
Below code, you can execute commands for only each closed bar or for only each tick, or for both situations.
Thanks for your helps.
Code:if (IsFirstTickOfBar) { var barsAgo = (Calculate == Calculate.OnBarClose || State == State.Historical) ? 0 : 1; if (DateTime.Now >= Time[barsAgo]) { var currentBar = CurrentBar - barsAgo; Print(string.Format("OnBarClose {0} {1} {2} {3} {4} {5}", currentBar.ToString("0000"), Time[barsAgo].ToString("yyyyMMdd HH:mm"), Open[barsAgo].ToString("0.00"), High[barsAgo].ToString("0.00"), Low[barsAgo].ToString("0.00"), Close[barsAgo].ToString("0.00"))); } } Print(string.Format("OnEachTick {0} {1} {2} {3} {4} {5}", CurrentBar.ToString("0000"), Time[0].ToString("yyyyMMdd HH:mm"), Open[0].ToString("0.00"), High[0].ToString("0.00"), Low[0].ToString("0.00"), Close[0].ToString("0.00")));
Leave a comment:
-
Yeah, you've discovered something else, and that is the Historical -> RealTime transitionOriginally posted by aytacasan View PostPlease look at the attachments. One is with doing Time check other is not.
Without time check "HT 2523 20211210 03:00 50520.94 50844.86 47323.23 47884.41" output line working something historical but actually it's not historical in my logic because its current-day bar and isn't closed yet. Also, be careful about the recurrence of the 2523 bar number.
About time zone. Yes, I'm talking about NT's settings. This setting effecting all of your data related to time. For example time series on your chart, time series on your script, etc.
I'll study the sample code that you mentioned very next post.
doesn't seem so clean. That is, in my experience with NT7, I found that sometimes the
CurrentBar for the very last Historical bar is 're-used' for the very first RealTime bar, but
this only happened with CalculateOnBarClose=False, which is equivalent to OnEachTick
in NT8. I think the term 'fake bar' was previously used to describe this phenomenon.
Also, see the edits in my post #6 to understand why Time[0] is a constant value for each
call to OnBarUpdate. I discuss why, even after the transition from Historical to RealTime,
each tick for CurrentBar=2523 shows the same Time[0] value. Did you notice that?
So why is that? Quick answer: Because your using OnEachTick/OnPriceChange, and
because the primary bar series is time-based.Last edited by bltdavid; 12-10-2021, 08:35 PM.
Leave a comment:
-
Please look at the attachments. One is with doing Time check other is not.Originally posted by bltdavid View Post
Looks good, but why the code in red above?
Without time check "HT 2523 20211210 03:00 50520.94 50844.86 47323.23 47884.41" output line working something historical but actually it's not historical in my logic because its current-day bar and isn't closed yet. Also, be careful about the recurrence of the 2523 bar number.
About time zone. Yes, I'm talking about NT's settings. This setting effecting all of your data related to time. For example time series on your chart, time series on your script, etc.
I'll study the sample code that you mentioned very next post.
Thanks,
AA
Leave a comment:
-
Sounds like we're talking about the code for a strategy.Originally posted by aytacasan View PostMaybe we can talk about a more specific sample.
Let say we have an indicator that must calculate only on bar close.
And we write a strategy that uses this indicator for entry/exit conditions.
Also want to use trailing stop for open positions and need tick by tick data.
First set strategy's calculate on each tick than in our OnBarUpdate;
You're asking about a very common scenario.
Study this sample.Last edited by bltdavid; 12-09-2021, 02:34 PM.
Leave a comment:
-
Looks good, but why the code in red above?Originally posted by aytacasan View Post
So David below code is the right solution? What do you think about it?
Also above code when my computer and ninja use different time zone settings, is it continue working?Code:protected override void OnBarUpdate() { //Add your custom strategy logic here. if (IsFirstTickOfBar) { var barsAgo = (Calculate == Calculate.OnBarClose || State == State.Historical) ? 0 : 1; [COLOR=#e74c3c] if (DateTime.Now < Time[barsAgo]) return;[/COLOR] Print(string.Format("{0} {1} {2} {3} {4} {5}", CurrentBar.ToString("0000"), Time[barsAgo].ToString("yyyyMMdd HH:mm"), Open[barsAgo].ToString("0.##"), High[barsAgo].ToString("0.##"), Low[barsAgo].ToString("0.##"), Close[barsAgo].ToString("0.##"))); return; } }
As to your second question,
The timezone setting of your PC vs the exchange time zone
doesn't matter. So, yes, it will continue working.
Do you mean the NT8 setting in Options -> General where you
can tell NinjaTrader the time zone? Same thing, it doesn't
matter.
By default,
The timestamp values stored the Time series are always
adjusted and saved as local time -- meaning the time values
you see are end times of each bar automatically normalized
to the time zone of your local computer.
However, if you change the time zone in Options -> General,
the timestamp values stored in the Time series are normalized
to the time zone setting you specified.
[EDIT: I presume that the Time series is always normalized to
the time zone setting in General -> Options. It's just that this
setting defaults to your computer's time zone, and 99 out of
100 people probably never change it.]
NT Support can correct me if I'm wrong.
Leave a comment:
-
Maybe we can talk about a more specific sample.Originally posted by bltdavid View PostTime[0] has nothing to do with the session.
Let say we have an indicator that must calculate only on bar close.
And we write a strategy that uses this indicator for entry/exit conditions.
Also want to use trailing stop for open positions and need tick by tick data.
First set strategy's calculate on each tick than in our OnBarUpdate;
if (IsFirstTickOfBar)
{
if (this is not most recent and so not yet closed bar)
{
Do indicator calculations...
if (We don't have a position and conditions are met for a new position)
{
Open new position...
}
}
}
if (We have a position)
{
Trail stop...
}
Leave a comment:
-
So David below code is the right solution? What do you think about it?Originally posted by bltdavid View PostTime[0] has nothing to do with the session.
That is not how it is defined.
Time is a Series that contains the 'end time' of each bar,
and is defined that way for all time frames and all bar types.
If the end time of the bar happens to be same time as the
end time of the session, well, that's just coincidental.
When using OnBarClose,
Time[0] is close timestamp of the most recently closed bar
Time[1] is close timestamp of the next recently closed bar
When using OnEachTick/OnPriceChange,
Time[0] is current timestamp of the active bar being built
Time[1] is close timestamp of the most recently closed bar
Time[2] is close timestamp of the next recently closed bar
The above statements are true & consistent and stay constant, regardless of
the time frame or underlying bar type.
Also above code when my computer and ninja use different time zone settings, is it continue working?Code:protected override void OnBarUpdate() { //Add your custom strategy logic here. if (IsFirstTickOfBar) { var barsAgo = (Calculate == Calculate.OnBarClose || State == State.Historical) ? 0 : 1; if (DateTime.Now < Time[barsAgo]) return; Print(string.Format("{0} {1} {2} {3} {4} {5}", CurrentBar.ToString("0000"), Time[barsAgo].ToString("yyyyMMdd HH:mm"), Open[barsAgo].ToString("0.##"), High[barsAgo].ToString("0.##"), Low[barsAgo].ToString("0.##"), Close[barsAgo].ToString("0.##"))); return; } }
Thanks,
AALast edited by aytacasan; 12-09-2021, 12:51 PM.
Leave a comment:
-
Time[0] has nothing to do with the session.
That is not how it is defined.
Time is a Series that contains the 'end time' of each bar,
and is defined that way for all time frames and all bar types.
If the end time of the bar happens to be same time as the
end time of the session, well, that's just coincidental.
When using OnBarClose,
Time[0] is close timestamp of the most recently closed bar
Time[1] is close timestamp of the next recently closed bar
When using OnEachTick/OnPriceChange,
Time[0] is current(*) timestamp of the active bar being built
Time[1] is close timestamp of the most recently closed bar
Time[2] is close timestamp of the next recently closed bar
The above statements are true & consistent and stay constant, regardless of
the time frame or underlying bar type.
EDIT:
The "current" timestamp is a rather fuzzy definition. For time based bar series
using OnEachTick/OnPriceChange, Time[0] is the active bar's projected end time.
And, once set for a particular bar, Time[0] will keep the same projected end time
for each call to OnBarUpdate -- that is, Time[0] stays constant and will not change
until that bar closes, which occurs on the first tick of the next bar.
(Naturally, after the bar closes, the new Time[0] value for the next bar is the projected
end time of that next bar. Remember, for time-based bar series, the new 'projected
end time' is calculated on the first tick of the new bar. That means Time[0] will always
reflect the correct projected end time of the bar, starting on the bar's very first tick.)
Non-time based bars, such as Renko and Range, aren't so fuzzy. The time value
in these bars is very straight forward. The Time[0] value is the timestamp of the
real-time incoming tick exactly as it was received from the data provider. So, for
these bars, Time[0] is always (er, I mean, usually) a different value. I wanted to
say 'always different', but in a highly volatile fast-moving market, many multiple
ticks could easily have the same Time[0] value.
To understand the 'constant' nature of the Time series, you need to understand the
underlying base time period the bar series is built upon. That is, whether a bar series
is time-based or tick-based is defined by the bar series itself. Start by studying the
help page titled How Bars Are Built.
After that, to really master the subject, study How Bars Data is Referenced.Last edited by bltdavid; 12-10-2021, 08:32 PM. Reason: Added edits to discuss 'current timestamp' for time-based vs tick-based bar series
- Likes 1
Leave a comment:
-
Hi David,Originally posted by bltdavid View Post
When using OnBarClose,
Close[0] is close price of the most recently closed bar <-- you want this
Close[1] is close price of the next recently closed bar
When using OnEachTick/OnPriceChange,
Close[0] is current close price of the active bar being built
Close[1] is close price of the most recently closed bar <-- you want this
Close[2] is close price of the next recently closed bar
Woah woah woah ... did you See that?
The meaning of Close[0] vs Close[1] has completely changed
based upon the value of the Calculate setting.
When using OnEachTick/OnPriceChange, all the BarsAgo
index values get shifted by 1, so that [0] is freed up to store
the current values of the active bar being built.
This is a big deal.
It bites people who are doing precisely what you're trying to do.
[That is, access values from the most recently closed bar.]
So, what can you do about that?
[Many times, you won't care. For ex, take a look at @EMA.cs,
or @CCI.cs, or any standard indicator -- most of them don't care
about Calculate and just use Close[0], etc -- but yet they still work
regardless of Calculate's setting. How is that? Because Close[0]
is being used in calculations, and calculations need to be performant
for bar close values as well as current close values. Well, it turns
out just using Close[0] happens to be correct in (almost) all cases
for all values of Calculate when doing calculations. Pretty cool
design, eh?]
But when you do care, you'll need to write your own logic to
handle it. Let's look at that a bit more.
-=o=-
You might try doing something like this,
if (IsFirstTickOfBar)
{int B0 = (Calculate == Calculate.OnBarClose || State == State.Historical) ? 0 : 1;
Print(string.Format("{0} {1} {2} {3} {4}",Time[B0].ToString("yyyyMMdd HH:mm"),
Open[B0].ToString("0.##"),
High[B0].ToString("0.##"),
Low[B0].ToString("0.##"),
Close[B0].ToString("0.##")));return;}
Tip:
Throughout my code, whenever I access values from the recently
closed bars, I tend to specify the index through a global variable,
like this, Close[B0] or Open[B1] or Low[B0], etc.
private int B0 = 0;
private int B1 = 1;
(never found a need for B2, B3, etc, or beyond)
which I adjust later based upon the Calculate setting,
B0 = (Calculate == Calculate.OnBarClose || State == State.Historical) ? 0 : 1;
B1 = (Calculate == Calculate.OnBarClose || State == State.Historical) ? 1 : 2;
If I design the rest of the code right, I am usually well insulated
from whatever the Calculate setting happens to be.
But, be careful ...
B0 and B1 are only for accessing the most recently closed bars,
so I still use Close[0] in most calculations, so that the correct value
is being used in the formula regardless of Calculate.
In other words, when you absolutely know you want the values of the
most recently closed bars, the index variables B0 and B1 are always
set to the correct BarsAgo values.
Make sense?
Wow, I'm impressed. Thank you so much for your effort. Please ignore my previous post which i wrote before I saw your post. I think your post will solve my problem. I'll read many times and try to code as you recommend. Thanks again.
Leave a comment:
-
Hello,
Don't think question is only related for daily bars.
Same script must work all time frames, horly minute tick etc.
So your solution is not make sense to me or not enough to me.
First i think that Time[0] equel to session/current bar end time not start time.
If so i can write this kind of code and i think it'll work all time frames.
if (DateTime.Now.ConvertToTimeZone(NinjaTrader.Option s.SelectedTimeZone) >= Time[0]) { DoSomething(); }
Am i right. What you think? Also see some codes like that;
var barAgo = State == State.Historical ? 0 : 1;
if (Close[barsAgo] > Open[BarsAgo]) { ... }
Why some developers write this type of code? Is it related to my problem?
Thanks,
AA
Leave a comment:
-
When using OnBarClose,Originally posted by aytacasan View PostShortly i dont want to work if statement block for the current day even if i set calculate property to OnPriceChage. So how can i prevent that?
Close[0] is close price of the most recently closed bar <-- you want this
Close[1] is close price of the next recently closed bar
When using OnEachTick/OnPriceChange,
Close[0] is current close price of the active bar being built
Close[1] is close price of the most recently closed bar <-- you want this
Close[2] is close price of the next recently closed bar
Woah woah woah ... did you See that?
The meaning of Close[0] vs Close[1] has completely changed
based upon the value of the Calculate setting.
When using OnEachTick/OnPriceChange, all the BarsAgo
index values get shifted by 1, so that [0] is freed up to store
the current values of the active bar being built.
This is a big deal.
It bites people who are doing precisely what you're trying to do.
[That is, access values from the most recently closed bar.]
So, what can you do about that?
[Many times, you won't care. For ex, take a look at @EMA.cs,
or @CCI.cs, or any standard indicator -- most of them don't care
about Calculate and just use Close[0], etc -- but yet they still work
regardless of Calculate's setting. How is that? Because Close[0]
is being used in calculations, and calculations need to be performant
for bar close values as well as current close values. Well, it turns
out just using Close[0] happens to be correct in (almost) all cases
for all values of Calculate when doing calculations. Pretty cool
design, eh?]
But when you do care, you'll need to write your own logic to
handle it. Let's look at that a bit more.
-=o=-
You might try doing something like this,
if (IsFirstTickOfBar)
{int B0 = (Calculate == Calculate.OnBarClose || State == State.Historical) ? 0 : 1;
Print(string.Format("{0} {1} {2} {3} {4}",Time[B0].ToString("yyyyMMdd HH:mm"),
Open[B0].ToString("0.##"),
High[B0].ToString("0.##"),
Low[B0].ToString("0.##"),
Close[B0].ToString("0.##")));return;
}
Tip:
Throughout my code, whenever I access values from the recently
closed bars, I tend to specify the index through a global variable,
like this, Close[B0] or Open[B1] or Low[B0], etc.
private int B0 = 0;
private int B1 = 1;
// add more indexes, such as B2, B3, etc, as necessary
// idea is very extensible, but I've never needed them
which I adjust later based upon the Calculate setting,
B0 = (Calculate == Calculate.OnBarClose || State == State.Historical) ? 0 : 1;
B1 = (Calculate == Calculate.OnBarClose || State == State.Historical) ? 1 : 2;
If I design the rest of the code right, I am usually well insulated
from whatever the Calculate setting happens to be.
But, be careful ...
B0 and B1 are only for accessing the most recently closed bars,
so I still use Close[0] in most calculations, so that the correct value
is being used in the formula regardless of Calculate.
In other words, when you absolutely know you want the values of the
most recently closed bars, the index variables B0 and B1 are always
set to the correct BarsAgo values.
Make sense?Last edited by bltdavid; 12-09-2021, 04:29 PM.
- Likes 1
Leave a comment:
-
Hello aytacasan,
Thanks for writing in.
This is the expected behavior when using OnPriceChange. If you run a script using OnPriceChange, you will get data points for the current day printed to the output window.
You would need to add a condition to your If statement so that today's date is excluded. You may consider comparing Time[0] with the DateTime.Now properties (check for an equal day, month, year).
See this help guide for more information about Time[0]: https://ninjatrader.com/support/help...eries_time.htm
And this publicly available link about DateTime: http://msdn2.microsoft.com/en-us/lib....datetime.aspx
Let us know if we may assist further.
Leave a comment:
Latest Posts
Collapse
| Topics | Statistics | Last Post | ||
|---|---|---|---|---|
|
Started by Geovanny Suaza, 02-11-2026, 06:32 PM
|
0 responses
571 views
0 likes
|
Last Post
|
||
|
Started by Geovanny Suaza, 02-11-2026, 05:51 PM
|
0 responses
330 views
1 like
|
Last Post
|
||
|
Started by Mindset, 02-09-2026, 11:44 AM
|
0 responses
101 views
0 likes
|
Last Post
by Mindset
02-09-2026, 11:44 AM
|
||
|
Started by Geovanny Suaza, 02-02-2026, 12:30 PM
|
0 responses
548 views
1 like
|
Last Post
|
||
|
Started by RFrosty, 01-28-2026, 06:49 PM
|
0 responses
549 views
1 like
|
Last Post
by RFrosty
01-28-2026, 06:49 PM
|

Leave a comment: