Add Series<T> To specific BarsInProgress

Hi there, I am building a strategy that considers 15-minute bars and 240-minute bars. I am calculating a market bias on both time frames. The intention is to capture what is happening on a larger timeframe (240-minute) and consider that in the decision-making timeframe (15-minute). My 15-minute bias works just fine. Every 15 minutes, I get a new entry in my data series, so Bias15[0] will shuffle to Bias15[1], and at no point do I have any 0 values

My challenge is with my Bias240. The intention of my Bias240 series is to update every 240 minutes a new bias value. However, if I’m looking at my 15-minute chart, then a new Bias240 Data series entry populates every 15 minutes, not 240 minutes, and I ended up with a number of 0 values in my series. So I really only get a non-0 value every 16 bars.

I know there’s a thing I can do with CurrentBar (current bar of the chart you’re looking) and then CurrentBars[2] (returns current bar of a Data Series of a specified time frame). How do I get the same effect from a Series? If not, then I guess I’ll just make an array and manually store these values.

Any help would be greatly appreciated, thank you!!

Nathan.

what have you done with AddDataSeries to get the 240 minute bar data set?

how is your strat code referencing the bar set for 15 min vs 240 min?

1 Like

Hi there Strong-Thermal-Emiss,
Thank you for your reply. If you need any addional information please let know. Otherwise, I’ve pasted a trimmed down version of my code below with what I think is the information you’re requesting. I appreciate your help.

Nathan.
namespace NinjaTrader.NinjaScript.Strategies
{
public class Lab93M : Strategy
{
#region Constants & Variables
// Constants
…

    private Series<double> totalBias;
    private Series<double> Bias240min;
    private Series<double> Bias15min;

    ...
    #endregion

    protected override void OnStateChange()
    {
        if (State == State.SetDefaults)
        {
            ...

            AddPlots();
        }

        else if (State == State.Configure)
        {
            AddDataSeries(BarsPeriodType.Minute, Timeframe240min);      // BarsInProgress index = 1, 4-hour
            AddDataSeries(BarsPeriodType.Minute, Timeframe15min);       // BarsInProgress index = 2, 15-minute
        }

        else if (State == State.DataLoaded)
        {
            Bias240min  = new Series<double>(this, MaximumBarsLookBack.Infinite);
            Bias15min   = new Series<double>(this, MaximumBarsLookBack.Infinite);
            totalBias   = new Series<double>(this, MaximumBarsLookBack.Infinite);
        }
    }
}

protected override void OnBarUpdate()
    {
        // **********************************************************************************************
        //                                          4-Hour
        // **********************************************************************************************
        #region 4-hour Timeframe (HTF)
        if (BarsInProgress == 1 && CurrentBars[1] > 7)
        {
            Bias240min[0] = CalculateBias(tf240min);
        }
        #endregion

        // **********************************************************************************************
        //                                          15-Min
        // **********************************************************************************************
        #region 15-minute Timeframe (MTF)
        if (BarsInProgress == 2 && CurrentBars[2] > 2)
        {
            Bias15min[0] = CalculateBias(tf15min);
        }

        totalBias[0] = Bias15min[0] + Bias240min[0];
    }

}

In State.DataLoaded where you’re defining your Series, you need to define them in such a way that they line up with the appropriate data series. The way you have them, they are all lined up with the primary series (ie; price bars).

BarsArray[0] is price bars.
BarsArray[1] is your 240 min series
BarsArray[2] is your 15 min series

Therefore, if you want your Bias240min series to line up with your 240 min data series, you’ll need to define it as follows:

Bias240min = new Series(SMA(BarsArray[1],1),MaximumBarsLookBack.Infinite);
Bias15min = new Series(SMA(BarsArray[2],1),MaximumBarsLookBack.Infinite);

This will make the two series line up with their corresponding data series.

Hope this helps.

2 Likes

fc77,
This is awesome. So instead of “this” (which I don’t fully understand what “this” means), you’re creating a simple moving average of the last 1 bars for the respective data series. Makes sense and it’s a super elegant solution (which I like).

Can you point me to any resources that would help me to understand what “this” is and why I can just replace it with a SMA? I hover over “Series” and it says it’s a “NinjascriptBase.” I click on that, and it takes me further into the weeds to some stuff that I just don’t understand. Screenshot below (hopefully). I’m not asking for a full tutorial on this, but if I’m to search for things to better understand this, could you tell me what to search for? It seems like these are the nuts and bolts of the functions I’m calling when writing a Ninjascript, and it would benefit me if I understood them maybe a level or two deeper. Thanks again for your help with this.

edit: so I know that I can just search for C# what is “this.” I’ve done that before, but it only returns stuff like… well… this:
" The this keyword is a reference to the current instance of the class.

In your example, this is used to reference the current instance of the class Complex and it removes the ambiguity between int real in the signature of the constructor vs. the public int real; in the class definition."

I just don’t understand that. My ask is more “hey, have you ever come across a YouTube video or some resource where someone really puts it into terms that are easy to grasp.” Again: thank you.

Nathan.

When you write “this” in this context, you are referring it to the instance of the class, which is the strategy or indicator itself. Passing this to a series like new Series<double>(this) links the data series so it gets updated in sync with its bar updates. https://ninjatrader.com/support/helpguides/nt8/NT%20HelpGuide%20English.html?seriest.htm

In this example, I use a series based on the point of control that I passed to an SMA. point-of-control-sma/PointOfControlMovingAverage.cs at main ¡ WaleeTheRobot/point-of-control-sma ¡ GitHub

1 Like

“this” is a reference to the specific instance of the class - here the indicator or strategy is the class as you can see from the declaration line. ex:

public class MyBeautifulIndicator : Indicator

Let’s say you have two charts. One with 3 days of data and one with 10 days of data loaded. You add the same indicator on both charts. Now you have two instances of the same indicator (class) running on your platform. Let’s say the indicator makes a call to Draw.TextFixed() to place a text label on the chart window based on some calculations. Since you have different number of days on the two charts, results may be different. Draw.TextFixed() will need to know which chart to place the appropriate text on. By passing “this” from the indicator instance to Draw.TextFixed(), you’re giving it a reference (think of it as an address) where to place its text. The two indicator instances will pass “this” to Draw.TextFixed() to tell it where to draw the corresponding text.

In the context of declaring the new Series, again “this” refers to the current indicator instance. The Series declaration by default will use the primary bar series from “this” (ie; Bars or BarsArray[0]). If you have additional data series defined in your indicator and want a new Series aligned with those other data series, then you’ll have to instantiate the Series using the appropriate BarsArray[N].

Where to learn: NinjaScript is built on C#. There are NT specific syntax that you can read about in NT’s documentation as I’m sure you already know. The rest is standard C# stuff. I would say the best way to learn would be to probably read a primer on C# or object oriented programming (OOP) and learn about how classes are built, instantiated and used.

Going back to the Series example, in my previous reply I jumped straight to the final answer. You don’t have to use the SMA when you declare the new Series. You could also do something like this.

Bias240min = new Series(BarsArray[1], MaximumBarsLookBack.Infinite);

I believe this works too. But if you enable compile time warnings (right click in NS Editor > Show Warnings), I believe the above syntax will generate a warning. I like all my scripts to compile clean and without warnings. I asked NT scripting support about this warning and they suggested the syntax with the SMA that I posted previously. With either syntax, you’re declaring a new Series that aligns with the specific data series. The one with SMA compiles clean (without warnings), but I believe both will work. This is why I suggested the syntax with SMA. I heavily use the syntax with SMA in all my script so I know it works.

Hope this helps and it wasn’t more than what you wanted to see LOL.

Good luck.

First, the concept ofthisis a C# thing, not a NinjaScript thing.
[That is, just know thatthisis a programming concept in C# and NinjaScript is just a programming framework that happens to use it.]

Second, when you’re programming in an object-oriented language, which C# most definitely is, it helps to think in terms of classes – because almost every variable you deal with is said to be an object of a certain class.

[In the old days, we’d say a ‘variable of a certain type’, so the new object-oriented way is to say an ‘object of a certain class’. The classic idea of a ‘variable of a certain type’ does not go away, but saying an ‘object of certain class’ is the new high level way of basically saying the same thing. After all, a class is just another kind of type. That is, the older concept of ‘type’ is still superior to that of ‘class’.]

Ok, in C# it really helps to think of everything as an object, which just means an object has a class type. Remember, the class is like a blueprint, it can have data and functions (which we call methods) that can be called to act on that data. An ‘object’ is what is created (in memory) when you say (in code) I want a thing to be created and I want it to represent a certain class.

The thing that is created is created with code, and the result is stored in memory.
But the thing that is created is not called a thing.

It’s called an object.

-=o=-

Let’s look at an example.
Inside your strategy (or indicator), let’s say you have,

EMA myEMA;

and later you do,

myEMA = EMA(200);

That line meansmyEMAis a variable, and an instance of theEMAclass is being created, meaningmyEMAbecomes a reference to an object of classEMA. (Saying ‘reference to an object’ gets old, so we usually just say ‘instance’, and we usually don’t say ‘created’, we say ‘instantiated’.)

[EDIT: In pedantic nerdy circles, you’re more likely to see ‘instance of a class’, not ‘object of a class’ – but I don’t think the difference matters that much. To me, the ‘instance’ is accessed via the reference stored in the variablemyEMA, but the thing immediately behind that reference is, duh, an object – it doesn’t really matter how you say it – at a high enough level the terms are fairly interchangeable.]

Remember, an object is just pieces of data all grouped together via code (either yours or somebody else’s) but that code can also have methods that can be called on that data. In C#, we say the reference to that object is stored in your variablemyEMA, aka, the ‘instance’.

Ok, still with me? Now, let’s talk aboutthisand what it means.

Recall I saidmyEMAis a reference? Well, when dealing with objects, you have to have a reference to it, meaning a variable has to contain it – meaning you, the programmer, chose some variable name and assigned it a value.

But let’s say inside the class that you are writing (such as your indicator), you need a reference to yourself. Yep, for some reason, you need a reference to the current object (because somebody above you is calling your indicator, so your indicator code is currently running), and you need to pass a reference to yourself to somebody else who needs it.

That’s whatthismeans. It’s a reference to the current object that is running, and when you passthisto somebody else, that somebody else now has a reference to the object that called them, just in case they want to call back into the calling object to get some data or call some method of the calling object. Yep, this need is rather common in object oriented programming. In fact, the need to get a reference to yourself is so common, Microsoft madethisa predefined keyword.

And there you have it! In summary,thisis a predefined variable name which always contains a reference to the object that is currently running. Under the hood, the C# execution environment is constantly adjusting the value ofthisautomatically.

Let’s dissect these 3 lines of code,

x = new Series<double>(this);
y = new Series<double>(SMA(BarsArray[0],1));
z = new Series<double>(SMA(BarsArray[1],1));

I’ll try to reveal the magic behind the curtain.

Unlike theAddOnplugin, theIndicatorandStrategyare always associated with bars – usually these bars come from the chart itself, but they don’t have to. (Stop and think about that a second: that the bars input can come from anywhere, not just a chart, should blow your programmer’s mind – that’s quite a software architectural achievement. That decoupling ultimately helps to provide some extreme design flexibility as well as the basis for some amazing capabilities, but I digress.)

When you specifythisin line 1, you’re asking for a new object of classSeriesto be created, and for that object to be associated with the bars the indicator is already associated with, aka, the bars on the chart. That’s what thethisargument is doing – it allows theSeriesclass to call back into your currently running indicator instance to get the bars associated with that instance, and make a newSeriesobject that is synced to those same bars, which is all stored as a reference in the variablex.

In line 2, it’s the same thing. Why? BecauseSMA(BarsArray[0],1)is a way to reference the bars associated with thatSMAindicator instance , which is created using bars fromBarsArray[0]. ButBarsArray[0]is (as you know) just another way to say the bars on the chart. Thus, bothxandyare data series synced to the same bars(*).

[EDIT: (*) Usually this is true, but specifyingBarsArray[0]forces the series to be associated with the primary bars of the chart, whereas specifyingthismeans the primary bars normally associated with the indicator instance could have been hijacked if you changed the input data series of the indicator when you added that indicator to the chart. Changing the input data series of an indicator is a rather advanced need, and probably not that common, so like I said, they’re usually the same thing.]

Ah, finally, line 3. So, what’s going on?

It’s simple. The Series class is reaching into (er, I mean, calling back into) theSMAindicator to get the bars associated with that indicator instance, but in the case of line 3, the bars are coming fromBarsArray[1]– so a new instance of theSeriesclass is created and it is synced to those bars fromBarsArray[1]– and a reference to this new object is stored in the variable z.

Make sense?

:smiling_face_with_sunglasses:

2 Likes

Btw, I’ll pass along some interesting NinjaScript historical tidbits.

These 3 lines of NT8 code,

x = new Series<double>(this);
y = new Series<double>(SMA(BarsArray[0],1));
z = new Series<double>(SMA(BarsArray[1],1));

actually reveal coding baggage of a historical nature. (Coding baggage is also called bitrot, but I digress.)

How so? Well, in NT8, the help guide clearly shows that these lines can now be coded like this,

x = new Series<double>(this);
y = new Series<double>(BarsArray[0]);
z = new Series<double>(BarsArray[1]);

Using a ‘dummy’ indicator instance, such asSMA,is the old NT7 way of doing the same thing. The dummy instance was needed as a middleman so that the data series constructor could instantiate the new data series instance with the bars associated with the dummy indicator instance.

That is, in both NT7 and NT8, the data series class constructor provides the hidden magic glue that syncs the newly instantiated data series object to a specific Bars object. But the NT7 NinjaScript framework didn’t allow a Bars object as an argument, thus the need to always specify some kind of indicator instance (which was usuallythis),but it could be any indicator instance. Said another way, it’s not the indicator instance that is important. The data series constructor just needs the indicator instance to get to the bars – so that it can do it’s magic and sync the new data series to the bars already associated with that instance.

[NOTE: It’s important to realize the use of theSMAindicator is completely arbitrary, it could be any indicator class. The choice ofSMAis just to use something simple. Remember, the data series constructor just needs the indicator instance to get the bars associated with that instance, so which indicator you specify doesn’t matter – it’s really just a placeholder, a ‘dummy’ indicator instance, used like a temporary variable, just to get access to the bars inside that indicator instance. That’s it.]

In NT8, this need for a dummy instance of an indicator (needed in NT7 as a middleman just to get to the bars associated with that instance) was finally seen as kinda dumb (er, I mean, as an oversight) and a reference to a Bars object can now be specified directly as an argument. This is an excellent example of overloading (and also how programmer insights into the everyday use of a framework can make the next version of the framework better and more convenient.)

Anyways, seeing the old style means the code (or coder) may have come from the NT7 era – the new NT8 way is much cleaner because it doesn’t have to cloud the mind with the ‘dummy middleman instance’ explanation.

Nevertheless, the old NT7 way should still work just fine in NT8.

Just my 2¢.

:slightly_smiling_face:

3 Likes

It’s been a while since I fiddled with this but I believe using this syntax gives a compile warning if you turn on warnings.

y = new Series<double>(BarsArray[0]);

The following syntax was suggested by NT support at the time to eliminate this warning.

y = new Series<double>(SMA(BarsArray[0],1));

I prefer to have warnings enabled when I compile so I can see warnings and address them to make sure the code is “clean”.

2 Likes