NexusFi: Find Your Edge


Home Menu

 





NinjaScript Little Helpers Code Share - Snippets/UserDefinedMethods


Discussion in NinjaTrader

Updated
      Top Posters
    1. looks_one gregid with 13 posts (28 thanks)
    2. looks_two bltdavid with 12 posts (17 thanks)
    3. looks_3 Fat Tails with 3 posts (8 thanks)
    4. looks_4 timefreedom with 2 posts (4 thanks)
      Best Posters
    1. looks_one Fat Tails with 2.7 thanks per post
    2. looks_two gregid with 2.2 thanks per post
    3. looks_3 timefreedom with 2 thanks per post
    4. looks_4 bltdavid with 1.4 thanks per post
    1. trending_up 10,408 views
    2. thumb_up 61 thanks given
    3. group 11 followers
    1. forum 34 posts
    2. attach_file 3 attachments




 
Search this Thread

NinjaScript Little Helpers Code Share - Snippets/UserDefinedMethods

  #21 (permalink)
 bltdavid 
San Jose, CA, USA
 
Experience: Intermediate
Platform: NinjaTrader
Posts: 112 since Dec 2013
Thanks Given: 35
Thanks Received: 103


gregid View Post
As I was writing g3ChartSpan indicator I needed a way of formatting the TimeSpan to optionally exclude some information if it == 0 and additionally give me some further info like years, months and weeks.

On a similar note, I also needed a way to display time spans in easy to read English, but I was only concerned with Days, Hours, Minutes, and Seconds. Why? In OnTermination() of my strategy, I wanted to print the total runtime since the strategy had started. For example,
 
Code
4/15/15 15:03:55 Strategy 'MyStrat' Terminated at '15:03:55 Wed Apr 15, 2015'
4/15/15 15:03:55 Strategy 'MyStrat' Total runtime '13 hours, 2 minutes, 3 seconds'

I wrote a routine called Duration(), which included several overloads. The main routine just takes 2 DateTime variables,
 
Code
        public static string Duration(DateTime BeginDate, DateTime EndDate)
        {
            if (DateTime.Compare(BeginDate, EndDate) > 0)
                return Duration(EndDate, BeginDate, true);
            else
                return Duration(BeginDate, EndDate, true);
        }

In certain cases I wanted to disable printing of the seconds (regardless if seconds > 0), thus the middle-man overload which takes a 3rd argument as a boolean. WantSeconds=false will set seconds to zero in the timespan structure, which means it won't be included in the returned string. Normally I call the 2-arg version above, except in those cases where I know I don't want to see Seconds, that's when I call this 3-arg version, setting the 3rd argument to false,
 
Code
        public static string Duration(DateTime BeginDate, DateTime EndDate, bool WantSeconds)
        {
            TimeSpan ts = EndDate - BeginDate;

            if (!WantSeconds && (ts.Days + ts.Hours + ts.Minutes) > 0)
                ts = new TimeSpan(ts.Days, ts.Hours, ts.Minutes, 0);

            return Duration(ts);
        }

Finally, here is the routine that formats the returned string. Note how if any one of Days, Hours, Minutes or Seconds is zero, that value won't be included. The exception is if all values are zero, then you'd get the default string "0 seconds".

 
Code
        public static string Duration(TimeSpan ts)
        {
            string Days = String.Format("{0} day{1}", ts.Days, (ts.Days == 1 ? "" : "s"));
            string Hours = String.Format("{0} hour{1}", ts.Hours, (ts.Hours == 1 ? "" : "s"));
            string Minutes = String.Format("{0} minute{1}", ts.Minutes, (ts.Minutes == 1 ? "" : "s"));
            string Seconds = String.Format("{0} second{1}", ts.Seconds, (ts.Seconds == 1 ? "" : "s"));

            string result = null;

            if (ts.Days > 0)
                result += (result == null ? Days : ", " + Days);

            if (ts.Hours > 0)
                result += (result == null ? Hours : ", " + Hours);

            if (ts.Minutes > 0)
                result += (result == null ? Minutes : ", " + Minutes);

            if (ts.Seconds > 0 || result == null)
                result += (result == null ? Seconds : ", " + Seconds);

            return result;
        }

Reply With Quote
Thanked by:

Can you help answer these questions
from other members on NexusFi?
ZombieSqueeze
Platforms and Indicators
New Micros: Ultra 10-Year & Ultra T-Bond -- Live Now
Treasury Notes and Bonds
Build trailing stop for micro index(s)
Psychology and Money Management
Better Renko Gaps
The Elite Circle
The space time continuum and the dynamics of a financial …
Emini and Emicro Index
 
  #22 (permalink)
 bltdavid 
San Jose, CA, USA
 
Experience: Intermediate
Platform: NinjaTrader
Posts: 112 since Dec 2013
Thanks Given: 35
Thanks Received: 103

Similar to my Duration() routine, I wrote another routine called BriefDuration(), which uses single character suffixes for the days, hours, minutes, and seconds. See attached screenshot showing an example use case.

 
Code
        public static string BriefDuration(DateTime BeginDate, DateTime EndDate)
        {
            if (DateTime.Compare(BeginDate, EndDate) > 0)
                return BriefDuration(EndDate, BeginDate, true);
            else
                return BriefDuration(BeginDate, EndDate, true);
        }

        public static string BriefDuration(DateTime BeginDate, DateTime EndDate, bool WantSeconds)
        {
            TimeSpan ts = EndDate - BeginDate;

            if (!WantSeconds && (ts.Days + ts.Hours + ts.Minutes) > 0)
                ts = new TimeSpan(ts.Days, ts.Hours, ts.Minutes, 0);

            return BriefDuration(ts);
        }

        public static string BriefDuration(TimeSpan ts)
        {
            string result = null;

            if (ts.Days > 0)
                result += String.Format("{0}d", ts.Days);

            if (ts.Hours > 0)
                result += (result == null ? null : " ") + String.Format("{0}h", ts.Hours);

            if (ts.Minutes > 0)
                result += (result == null ? null : " ") + String.Format("{0}m", ts.Minutes);

            if (ts.Seconds > 0 || result == null)
                result += (result == null ? null : " ") + String.Format("{0}s", ts.Seconds);

            return result;
        }

Attached Thumbnails
Click image for larger version

Name:	IMGDT_20150425_145317.jpg
Views:	237
Size:	846.0 KB
ID:	181342  
Reply With Quote
Thanked by:
  #23 (permalink)
 
gregid's Avatar
 gregid 
Wrocław, Poland
 
Experience: Intermediate
Platform: NinjaTrader, Racket
Trading: Ockham's razor
Posts: 650 since Aug 2009
Thanks Given: 320
Thanks Received: 623


Thanks @bltdavid for your contributions to the thread - seeing how many times we all end up reinventing the same stuff makes me wonder what we would all do with the free time on our hands if sharing was just a bit more common

Started this thread Reply With Quote
  #24 (permalink)
 bltdavid 
San Jose, CA, USA
 
Experience: Intermediate
Platform: NinjaTrader
Posts: 112 since Dec 2013
Thanks Given: 35
Thanks Received: 103


gregid View Post
Thanks @bltdavid for your contributions to the thread - seeing how many times we all end up reinventing the same stuff makes me wonder what we would all do with the free time on our hands if sharing was just a bit more common

The problem is sharing code at this low, building-block level (aka, small & useful misc utility routines) is not as common as the high level sharing of entire code units (aka, indicators and strategies). My point is: sharing is happening around here, it's just naturally slanted towards sharing fuller units of code in the forms of indicators & strategies, and perhaps a full class library or two.

But I love the world of well thought-out, well-named small routines.

FWIW, I have found great general purpose code snippets on StackOverflow.com.

But finding general purpose NinjaTrader specific routines has been a (rather laborious) continual exercise of being alert to attachments and uploads, then specifically downloading those files and hunting for any useful looking stand-alone routines.

Another problem is: creating these useful well-named utility classes and/or routines (general purpose or otherwise) is a bit of a fine art, usually practiced only by dedicated and skilled programming professionals. I mean, you probably won't find many cool snippets in some quickie indicator or strategy ... mostly because they're not needed but also because not every code author has the skill or insight or desire to build great low-level standalone routines.

[In summary, I heartily agree with you. These new-fangled terms the kids use such as "refactoring" and "agile" are simply thought exercises that typically center on the reusable-ness and readable-ness of well-named and well-designed routines.]

Reply With Quote
Thanked by:
  #25 (permalink)
 
aquarius's Avatar
 aquarius 
Monterrey, Mexico
 
Experience: Beginner
Platform: NinjaTrader
Trading: Treasuries
Posts: 22 since Nov 2012
Thanks Given: 5
Thanks Received: 69


bltdavid View Post
 
Code
  
        public static string BriefDuration(TimeSpan ts)
        {
            string result = null;

            if (ts.Days > 0)
                result += String.Format("{0}d", ts.Days);

            if (ts.Hours > 0)
                result += (result == null ? null : " ") + String.Format("{0}h", ts.Hours);

            if (ts.Minutes > 0)
                result += (result == null ? null : " ") + String.Format("{0}m", ts.Minutes);

            if (ts.Seconds > 0 || result == null)
                result += (result == null ? null : " ") + String.Format("{0}s", ts.Seconds);

            return result;
        }

Please allow me to chime in a little bit ... normally when you modify strings so often, they some how affect performance, mostly because there's garbage collection activity involved from the .Net framework.

A good practice, is to use the StringBuilder class that .net provides instead, i.e.:

 
Code
        public static string BriefDuration(TimeSpan ts)
        {
            StringBuilder result = new StringBuilder();

            if (ts.Days > 0)
                result.AppendFormat("{0}d", ts.Days);

            if (ts.Hours > 0)
                result.Append(" ").AppendFormat("{0}h", ts.Hours);

            if (ts.Minutes > 0)
                result.Append(" ").AppendFormat("{0}m", ts.Minutes);

            if (ts.Seconds > 0)
                result.Append(" ").AppendFormat("{0}s", ts.Seconds);

            return result.ToString().Trim();
        }
Not sure if the code above will give the same results as the one you posted, but hope so ...

here's a link regarding .net strings (also Java's) inmutable property:
c# - Why .NET String is immutable? - Stack Overflow


Reply With Quote
Thanked by:
  #26 (permalink)
 
gregid's Avatar
 gregid 
Wrocław, Poland
 
Experience: Intermediate
Platform: NinjaTrader, Racket
Trading: Ockham's razor
Posts: 650 since Aug 2009
Thanks Given: 320
Thanks Received: 623

One of my biggest complaints about NinjaTrader is the fact that some basic NT collections/arrays don't implement IEnumerable interface. This unnecesarilly complicates things - it is simply not making use of the existing .NET features.

I am a great fan of flexibility given to the user by LINQ - for an example of LINQ use for arithmetic operations on arrays see the g3VWStdDev indicator. To make use of LINQ you require to operate on enumerable, so until my requests for future @NinjaTrader releases to make that change materialize, I wrote some extension methods to collections/arrays I use most often. Obviously any conversion will always make some impact on the performance but in most cases for most uses it is still worth the flexibility of the newer .NET features (like LINQ)

Here you have:
- ToDoubleArray extensions to DataSeries with 2 overloads - complete DataSeries and a windowed one
- ToEnumerable extensions to IDataSeries with 2 overloads - complete IDataSeries and a windowed one

 
Code
    public static class DataSeriesExtensions
    {
        // Example Use: var test = MyPlot.ToDoubleArray();
        public static double[] ToDoubleArray(this DataSeries series)
        {
            if (series == null) return null;
            int seriesCount = series.Count;
            double[] tempArray = new double[seriesCount];
            for (int i = 0; i < seriesCount; i++)
                tempArray[i] = series[i];
            return tempArray;
        }

        // Example Use: var test = MyPlot.ToDoubleArray(14);
        public static double[] ToDoubleArray(this DataSeries series, int window)
        {
            if (series == null) return null;
            double[] tempArray = new double[window];
            for (int i = 0; i < window; i++)
                tempArray[i] = series[i];
            return tempArray;
        }

        // Example Use: var test = MyPlot.ToEnumerable<double>();
        // The non windowed version doesn't work properly on bar series, eg. Close, Open, etc.)
        // As a workaround use: var test = Close.ToEnumerable<double>(CurrentBar);
        public static IEnumerable<T> ToEnumerable<T>(this IDataSeries series) //where T: IConvertible
        {
            if (series == null) return null;
            int window = series.Count;
            T[] tempArray = new T[window];
            for (int i = 0; i < window; i++)
            {
                tempArray[i] = (T)Convert.ChangeType(series[i], typeof(T));
            }
            return tempArray;
        }

        // Example Use: var test = MyPlot.ToEnumerable<double>(14);
        public static IEnumerable<T> ToEnumerable<T>(this IDataSeries series, int window) //where T: IConvertible
        {
            if (series == null) return null;
            T[] tempArray = new T[window];
            for (int i = 0; i < window; i++)
            {
                tempArray[i] = (T)Convert.ChangeType(series[i], typeof(T));
            }
            return tempArray;
        }
    }
With these extensions getting average of last 10 values of MyPlot dataseries is as simple as:
 
Code
	var myArray = MyPlot.ToDoubleArray(10);
        myArray.Average();

Started this thread Reply With Quote
Thanked by:
  #27 (permalink)
 
gregid's Avatar
 gregid 
Wrocław, Poland
 
Experience: Intermediate
Platform: NinjaTrader, Racket
Trading: Ockham's razor
Posts: 650 since Aug 2009
Thanks Given: 320
Thanks Received: 623

There are situations where my calculations/actions in the indicator or strategy depend on the combination of the parameters. My personal preference of dealing with combinations is to utilise bitwise operators. Let me demonstrate an example for enums. The example is quite naive and could be solved with 4 bools - this is just to show how it works so you can use it for more complex problems.

Let's say I want to give the user a flexible option of what detail of the trade to draw on the chart - including all the combination of the details. I will start with providing an enum:
 
Code
    
    [Flags] //<- crucial for this to work
    public enum DrawOrderDetails
    {
        Entries   = 1 << 0, //decimal:1 binary:0001
        Exits     = 1 << 1, //decimal:2 binary:0010
        Targets   = 1 << 2, //decimal:4 binary:0100
        Stops     = 1 << 3, //decimal:8 binary:1000
        EntriesExits = Entries | Exits,                            //decimal:3 binary:0011
        EntriesExitsTargets = EntriesExits | Targets,              //decimal:7 binary:0111
        EntriesExitsStops = EntriesExits | Stops,                  //decimal:11 binary:1011
        EntriesExitsTargetsStops = EntriesExits | Targets | Stops, //decimal:15 binary:1111
        EntriesTargets = Entries | Targets,                        //decimal:5 binary:0101
        EntriesStops = Entries | Stops,                            //decimal:9 binary:1001
        ExitsTargets = Exits | Targets,                            //decimal:6 binary:0110
        ExitsStops = Exits | Stops,                                //decimal:10 binary:1010
        TargetsStops = Targets | Stops                             //decimal:12 binary:1100
    }
As you can see this provides all the possible combination of objects to be drawn. I provided in the comments the values that will be assigned to individual enum values - you could use any of them if you want eg. decimal or binary but this forces you to be more cautious which values do you assign. Instead in the example for first 4 individual values I used bitwise left shift operator (<<) to provide the right individual values for us. For the combinations bitwise OR (|) to provide the right values.

Now assuming we have eg.
 
Code
private DrawOrderDetails drawDetails;
and would like to check for the condition we can use bitwise operators like this:
 
Code
            if ((DrawOrderDetails.Entries & drawDetails) == DrawOrderDetails.Entries)
            {
                //DrawLine for Entry
            }
But it's not the most readable code you could find.

Instead we could write an extension method to the enum:
 
Code
    public static class EnumExtensions
    {
        public static bool Includes(this DrawOrderDetails testValue, DrawOrderDetails testFor)
        {
            return (testFor & testValue) == testFor;
        }
    }
Now the test for all the conditions are much easier on the eyes:
 
Code
            if (drawDetails.Includes(DrawOrderDetails.Entries))
            {
                //DrawLine for Entry
            }
            if (drawDetails.Includes(DrawOrderDetails.Exits))
            {
                //DrawLine for Exit
            }
            if (drawDetails.Includes(DrawOrderDetails.Targets))
            {
                //DrawLine for Target
            }
            if (drawDetails.Includes(DrawOrderDetails.Stops))
            {
                //DrawLine for Stop
            }
Now for example the Entry line will be drawn for the enum with that includes Entries (in decimals: 1,3,5,7,9,11,15), the same for other conditions

Started this thread Reply With Quote
Thanked by:
  #28 (permalink)
 bltdavid 
San Jose, CA, USA
 
Experience: Intermediate
Platform: NinjaTrader
Posts: 112 since Dec 2013
Thanks Given: 35
Thanks Received: 103


gregid View Post
Now the test for all the conditions are much easier on the eyes:
 
Code
            if (drawDetails.Includes(DrawOrderDetails.Entries))
            {
                //DrawLine for Entry
            }
            if (drawDetails.Includes(DrawOrderDetails.Exits))
            {
                //DrawLine for Exit
            }
            if (drawDetails.Includes(DrawOrderDetails.Targets))
            {
                //DrawLine for Target
            }
            if (drawDetails.Includes(DrawOrderDetails.Stops))
            {
                //DrawLine for Stop
            }

Love it, but I think "IsDefined" or "IsEnabled" is a better name than "Includes" ... reads a bit better.

Reply With Quote
  #29 (permalink)
 
gregid's Avatar
 gregid 
Wrocław, Poland
 
Experience: Intermediate
Platform: NinjaTrader, Racket
Trading: Ockham's razor
Posts: 650 since Aug 2009
Thanks Given: 320
Thanks Received: 623


bltdavid View Post
Love it, but I think "IsDefined" or "IsEnabled" is a better name than "Includes" ... reads a bit better.

To each his own

Started this thread Reply With Quote
Thanked by:
  #30 (permalink)
 
ratfink's Avatar
 ratfink 
Birmingham UK
Market Wizard
 
Experience: Intermediate
Platform: NinjaTrader
Broker: TST/Rithmic
Trading: YM/Gold
Posts: 3,633 since Dec 2012
Thanks Given: 17,423
Thanks Received: 8,425



bltdavid View Post
Love it, but I think "IsDefined" or "IsEnabled" is a better name than "Includes" ... reads a bit better.

Couldn't disagree more.

With simple 'bool's it should just be:

 
Code
if (entryDetails)
{
    // draw
}
if (exitDetails)
{
    // draw
}
if (targetDetails)
{
    //draw
}
if (stopDetails)
{
    //draw
}

Often in the desire to be with the OO street kids we miss the elephant in the room.


gregid View Post
To each his own

Couldn't disagree more.

That's like saying "It's all about the taking part", when we know it's only ever about the winning.


Cheers both, it's a good sport.

Travel Well
Visit my NexusFi Trade Journal Reply With Quote




Last Updated on May 15, 2015


© 2024 NexusFi™, s.a., All Rights Reserved.
Av Ricardo J. Alfaro, Century Tower, Panama City, Panama, Ph: +507 833-9432 (Panama and Intl), +1 888-312-3001 (USA and Canada)
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.
About Us - Contact Us - Site Rules, Acceptable Use, and Terms and Conditions - Privacy Policy - Downloads - Top
no new posts