Slicing ISeries objects - futures io
futures io



Slicing ISeries objects


Discussion in NinjaTrader

Updated
      Top Posters
    1. looks_one benJephunneh with 4 posts (1 thanks)
    2. looks_two chipwitch with 2 posts (0 thanks)
    3. looks_3 westsider with 1 posts (0 thanks)
    4. looks_4 forrestang with 1 posts (1 thanks)
    1. trending_up 793 views
    2. thumb_up 2 thanks given
    3. group 3 followers
    1. forum 8 posts
    2. attach_file 0 attachments




Welcome to futures io: the largest futures trading community on the planet, with well over 150,000 members
  • Genuine reviews from real traders, not fake reviews from stealth vendors
  • Quality education from leading professional traders
  • We are a friendly, helpful, and positive community
  • We do not tolerate rude behavior, trolling, or vendors advertising in posts
  • We are here to help, just let us know what you need
You'll need to register in order to view the content of the threads and start contributing to our community.  It's free and simple.

-- Big Mike, Site Administrator

(If you already have an account, login at the top of the page)

 
Search this Thread
 

Slicing ISeries objects

(login for full post details)
  #1 (permalink)
benJephunneh
Huntsville, AL
 
 
Posts: 10 since Feb 2022
Thanks: 7 given, 4 received

This post is about my creating an alternative to array slicing for NinjaScript, since NT8 is still under the thumb of C#5. Please let loose your suggestions and criticism, or maybe you've already done this in a better way. I'd be glad to hear what y'all have to say. Ultimately, my hope is that it can help other NinjaScript coders.

Onward.

As a recovering MATLAB user...well...who am I kidding. I actually do like MATLAB. One of the things I especially like, in fact, is its array-slicing operator, the ":":
 
Code
apple = 1:1e6; % Creates the array [1 2 3 4 ... 999999 1000000].
sliceOfApple = apple(1:3:end); % Selecting every third value.
I'd like to do this for creating slices out of ISeries objects. C# 8(?) gives us a reasonable alternative, the ".." operator, but again, NinjaTrader does not yet give us such treasures. As far as I understand it, the coder has a couple options for creating this functionality, namely operator overloading and method extensions.

And if ISeries objects were LINQable, that would also present an easy alternative. I did experiment with this in a roundabout way but the code is...how do we say...ugly?
 
Code
// _x is a double[] of ordinal numbers; the independent variable (0, 1, 2, 3...).
// _dataArray will be the slice out of the ISeries object.

_x.ToList().ForEach(index => _dataArray[(int)(_x.Count() - index)] = Input[(int)index]); // And of course you can change this depending on how you want things ordered.
What I dislike about this approach, though, is its requirement to pass in the independent variable object, and I'd much rather have a dynamic way of doing it such that I wouldn't have to be constantly recreating that vector.

As a somewhat new C# coder, operator overloading seems hairy, to me. A method extension seemed simple enough, so I chose ISeries<double>.Range. After all that preamble, here is what I wanted to share in this post and get suggestions about:
 
Code
using NinjaTrader.Cbi;

namespace NinjaTrader.NinjaScript
{
public static class MyUtilities {
public static double[] Range(this ISeries<double> series, int startBarsAgo, int endBarsAgo) {
if (startBarsAgo < 0 || startBarsAgo <= endBarsAgo)
NinjaTrader.NinjaScript.NinjaScript.Log("Some error message", LogLevel.Error);
int numValues = startBarsAgo - endBarsAgo + 1; double[] values = new double[numValues]; for (var ii = startBarsAgo; ii >= endbarsAgo; ii--) {
if (series.IsValidDataPoint(ii))
values[startBarsAgo - ii] = series[ii]; // values vector will be built in the same order as they're indexed in the ISeries object.
} return values;
}
To use it in an indicator, now, I do the following:
 
Code
_dataArray = Input.Range(Period, EndBarsAgo);
// or...
_dataArray = Input.Range(12, 1)
Well, that's it. I hope it helps. And again, please let me know your thoughts. I did approach this from the perspective of needing to create the independent-variable object for an indicator I was writing, so there's the possibility I pidgeon-holed myself to a specific approach.

--Caleb

Reply With Quote
The following user says Thank You to benJephunneh for this post:

Can you help answer these questions
from other members on futures io?
use of Ultimate Oscillator in NT8
NinjaTrader
NT8 - Footprint Chart adding on code
NinjaTrader
Moving Average Price Scan
ThinkOrSwim
Pinescript to EL conversion - ema cloud indicator
TradeStation
TOS Fold Loop to NT8 For Loop
NinjaTrader
 
 
(login for full post details)
  #2 (permalink)
 chipwitch 
Nashville, TN
 
Experience: Beginner
Platform: NinjaTrader
Broker: NinjaTrader, Continuum Data
Trading: MES for now... baby steps
 
chipwitch's Avatar
 
Posts: 320 since Feb 2022
Thanks: 229 given, 595 received

I'm unfamiliar with matlab and "slicing" but if you mean taking an array and breaking it up into 2 or 3 smaller arrays, doesn't Array.Copy work with iSeries? I haven't tried that, but I would think that would be much faster than iterating through your array.

Reply With Quote
 
(login for full post details)
  #3 (permalink)
benJephunneh
Huntsville, AL
 
 
Posts: 10 since Feb 2022
Thanks: 7 given, 4 received


Update:
Return the independent and dependent variable vectors. I used a jagged array so I could do vector assignment in one line, outside of the loop.
Method summary added.

 
Code
/// <summary>
/// Slice ISeries object.
/// </summary>
/// <param name="series">ISeries object</param>
/// <param name="startBarsAgo>Start index</param>
/// <param name="endBarsAgo>End index</param>
/// <returns>Jagged array: [0] is independent variable vector; [1] is dependent variable vector.</returns>
public static double[][] Range(this ISeries<double> series, int startBarsAgo, int endBarsAgo)
{
if (startBarsAgo < 0 || startBarsAgo <= endBarsAgo)
NinjaTrader.NinjaScript.NinjaScript.Log("Indexing error", LogLevel.Error);
int numValues = startBarsAgo - endBarsAgo + 1; double[][] values = new double[2][]; values[0] = Enumerable.Range(endBarsAgo, numValues).Select(Convert.ToDouble).ToArray(); values[1] = new double[numValues]; for (var ii = startBarsAgo; ii >= endBarsAgo; ii--) {
if (series.IsValidDataPoint(ii))
values[1][startBarsAgo - ii] = series[ii];
} return values;
}

Reply With Quote
 
(login for full post details)
  #4 (permalink)
benJephunneh
Huntsville, AL
 
 
Posts: 10 since Feb 2022
Thanks: 7 given, 4 received


chipwitch View Post
I'm unfamiliar with matlab and "slicing" but if you mean taking an array and breaking it up into 2 or 3 smaller arrays, doesn't Array.Copy work with iSeries? I haven't tried that, but I would think that would be much faster than iterating through your array.

By "slicing" I mean cutting out elements of an array and assigning the subset to a new object. For example, let's say you want the last ten elements of Input. Input.Range(10, 1), as I have it, would be equivalent to the following:
 
Code
double[] vector = new double[10];

for (var ii = 10; ii >= 1; ii--)
vector[10 - ii] = Input[ii];
Slicing simply hides the for loop.

That would be interesting, if I could use Array, somehow. So far, I've not been able to successfully compile anything in which I pass an ISeries<double> as an argument to an Array method. E.g. _dataArray = Array.Copy(Input, 60, _dataArray, 0, 60); I may not have the remaining arguments correct, but I can't compile to troubleshoot. Error regards conversion of NinjaScript.ISeries<double> to System.Array.

Reply With Quote
 
(login for full post details)
  #5 (permalink)
 forrestang 
Urban Samurai
Chicago IL
 
Experience: None
Platform: Ninja, MT4, Matlab
Broker: CQG, AMP, MB, DTN
Trading: E/U, G/U
 
forrestang's Avatar
 
Posts: 1,321 since Jun 2010
Thanks: 346 given, 1,033 received

I'm not sure I totally understand exactly what the issue is, but I think I may have a use-case, albeit different?

Here I have a big list... but I only do operations on a small segment of that list. In this case, it is simply calculating an average.

So, at the class level... I define the List that will hold my vals:
 
Code
List<double> ADRs3 = new List<double>();

In onBarUpdate(), I push values into this list either by:
 
Code
ADRs3.Add(someValue); //Which pushes it to the end of the list
or I can change the LATEST value IN PLACE by:
 
Code
ADRs3[ADRs3.Count-1] = someValue;
If I ever need to iterate over that list to see what's in it, I can do something like, on the last bar on the chart, iterate over the list once an show me the values:
 
Code
if (CurrentBar==Bars.Count-2) //Call for last bar on chart( ==1532
{
  for (int i=0; i < ADRs3.Count; i++)
    {
      Print( i+ "  " +   ADRs3[i]  );					
    }
 }

To the part about taking a slice of the list.... So, the INDICATOR simply calculates an average of a daily [email protected] So the list contans ALL values on the chart, but I only want to use a SLICE of that data...

So I have a function that takes the list... makes a COPY(at least thats what I think its doing?), and I only calculate and average based on the last n-values, using that GetRange extension:
 
Code
public double GetAverage( List<double> myList, int LookBackPeriod )	//Gets pipsize given a string value
{
  myList = myList.ToList().GetRange(myList.Count() - LookBackPeriod, LookBackPeriod); 	//Reduce list to on last n-samples
  return Math.Round( myList.Average(),2);
}

When I need to calculate that average, I pass my main list to the function, along with how many items to calculate the average for... in a function call via:
 
Code
s3Avg = GetAverage( ADRs3.ToList(), Period); //Get ADR

I'm not sure if this is helpful, but when I need to store data, instead of using arrays, I use Lists... and this is an example of only using a slice of that list to perform calculations on.

The key point, is that I am not modifying the original list, I'm am essentially copying it, and modifying the copy.

Reply With Quote
The following user says Thank You to forrestang for this post:
 
(login for full post details)
  #6 (permalink)
 chipwitch 
Nashville, TN
 
Experience: Beginner
Platform: NinjaTrader
Broker: NinjaTrader, Continuum Data
Trading: MES for now... baby steps
 
chipwitch's Avatar
 
Posts: 320 since Feb 2022
Thanks: 229 given, 595 received

if you can use forrestang's suggestion, there is a copy method for List. I have never used it though. I couldn't find a way to copy an ISeries.

Reply With Quote
 
(login for full post details)
  #7 (permalink)
benJephunneh
Huntsville, AL
 
 
Posts: 10 since Feb 2022
Thanks: 7 given, 4 received

It's not really an issue, just a desire. I just wanted an easier way to take chunks out of the ISeries objects. @forrestang, your one block of code where you run a for-loop to inspect the values in your List is similar to what is required to extract values from ISeries objects, but only because NT is still limited by C# 5. With the latest version of C#, whenever NT gets updated to it, this method extension's usefulness will likely expire.

Let me describe one use case for why using a List or something similar is inconsequential. I have a numeric-derivative indicator that uses the Math.NET library. Let's say I want to do a three-point numeric derivative of, say, NT's built-in linear regression indicator with a period of 14. (There's no need for this since LinRegSlope already exists, but it makes for a good example since people actually use it.)

Prereqs:
 
Code
private double[] _threePointVector = double[3];
private NumericalDerivative _D = new NumericalDerivative(3, 1);
Ideally, if array slicing was possible, we would do the following to get the values from the last three bars of LinReg(14):
 
Code
 _threePointVector = LinReg(14)[3:1];
Since this is not possible, the following is required (as far as I know, anyway):
 
Code
for (var ii = 3; ii > 0; ii++)
{
    _threePointVector[3 - ii] = LinReg(14)[ii];
    // The [3 -ii] indexing insures the values are put in the same order into _threePointVector as they are in LinReg(14).  You could just as easily call Reverse() for the array after you build it.  It's all the same.
}

// And then the difference calculation:
double diff = _D.EvaluateDerivative(_threePointVector, 1, 1);
So _threePointVector had to be made no matter what, and whether it's a double[] or List or Queue or whatever is irrelevant (although better as double[], in this case), but it had to be made from values stored in the ISeries object, LinReg(14). It's the ISeries object I want to slice, so this method extension would work for PriceSeries objects and the rest, also. Granted, the for loop is short, but I'd still like to hide it and simplify the expressions. Notably, this feature must have been a popular C# request such that slicing is now a part of the latest version.

So with, say, the Range method extension, I can cut out the for loop to the following:
 
Code
_threePointVector = LinReg(14).Range(3, 1);
double diff = _D.EvaluateDerivative(_threePointVector, 1, 1);
Does that clarify things, at all? I'd still like to learn about operator overloading, which could have an even simpler appearance, but I'm not there, yet.

Reply With Quote
 
(login for full post details)
  #8 (permalink)
 westsider 
St Louis, MO
 
Experience: Intermediate
Platform: Ninjatrader TOS Jigsaw
Broker: Ninjatrader
Trading: MES
 
westsider's Avatar
 
Posts: 114 since Jun 2011
Thanks: 55 given, 127 received

Caleb,
Your static class was exactly what I was looking for. Thanks very much. I am so pleased to forgo the for loops since we know there is a better way.
Thanks,
Warren

Follow me on Twitter Visit my futures io Trade Journal Reply With Quote
 
(login for full post details)
  #9 (permalink)
TigerStripes
Surrey
 
 
Posts: 33 since Mar 2021
Thanks: 9 given, 16 received


benJephunneh View Post
By "slicing" I mean cutting out elements of an array and assigning the subset to a new object. For example, let's say you want the last ten elements of Input. Input.Range(10, 1), as I have it, would be equivalent to the following:
 
Code
double[] vector = new double[10];

for (var ii = 10; ii >= 1; ii--)
vector[10 - ii] = Input[ii];
Slicing simply hides the for loop.

That would be interesting, if I could use Array, somehow. So far, I've not been able to successfully compile anything in which I pass an ISeries<double> as an argument to an Array method. E.g. _dataArray = Array.Copy(Input, 60, _dataArray, 0, 60); I may not have the remaining arguments correct, but I can't compile to troubleshoot. Error regards conversion of NinjaScript.ISeries<double> to System.Array.

So part of your code I may be new but not sure why "StartBarsAgo < 0" when to start you want bars to begin, or if it is to instantiate a variable you could do that pre if conditional and then assign a more literal instatiation when the time is right.

Also it is possible you could use the items itterate inside a list, give conditions for when outside the list a conditions is met and inside the list itterate based on a set of conditions to allow usage to conditions only for ceratin int funtions or values.

EDIT: what mentioned here is exactly as forrstang had mentioned above, again newbie and not versed in classes as well but sure that there are important features, and think .Range is a useful function as well hope to see more improvments possible in updates of NT, as well thnking ab when NT becomes obselete or there is a "9" rather useful imporvments in the .NET and C# current code base.

Reply With Quote


futures io Trading Community Platforms and Indicators NinjaTrader > Slicing ISeries objects


Last Updated on June 14, 2022


Upcoming Webinars and Events
 

NinjaTrader Indicator Challenge!

Ongoing
     



Copyright © 2022 by futures io, s.a., Av Ricardo J. Alfaro, Century Tower, Panama, Ph: +507 833-9432 (Panama and Intl), +1 888-312-3001 (USA and Canada), info@futures.io
All information is for educational use only and is not investment advice.
There is a substantial risk of loss in trading commodity futures, stocks, options and foreign exchange products. Past performance is not indicative of future results.
no new posts