NexusFi: Find Your Edge


Home Menu

 





Global variables in NT


Discussion in NinjaTrader

Updated
      Top Posters
    1. looks_one Geir with 6 posts (30 thanks)
    2. looks_two Cheech with 5 posts (1 thanks)
    3. looks_3 shodson with 4 posts (10 thanks)
    4. looks_4 Zondor with 3 posts (4 thanks)
      Best Posters
    1. looks_one Geir with 5 thanks per post
    2. looks_two shodson with 2.5 thanks per post
    3. looks_3 drmartell with 1.5 thanks per post
    4. looks_4 Zondor with 1.3 thanks per post
    1. trending_up 17,968 views
    2. thumb_up 51 thanks given
    3. group 20 followers
    1. forum 24 posts
    2. attach_file 5 attachments




 
Search this Thread

Global variables in NT

  #11 (permalink)
 
Zondor's Avatar
 Zondor 
Portland Oregon, United States
 
Experience: Beginner
Platform: Ninjatrader®
Broker: CQG, Kinetick
Trading: Gameplay Klownbine® Trading of Globex
Posts: 1,333 since Jul 2009
Thanks Given: 1,246
Thanks Received: 2,731

Let's postulate a workspace with ~10, ~20 charts, or N charts of one instrument that I want to pretend I am trading, in the simulator, of course! Let's call the charts that I use for my "trading" decisions the "client" charts.

Suppose that for some reason I want to be able to put the daily pivots and previous N days VWAPS, Highs, Lows, PoC's etc on all of those charts.

It would NOT be necessary to add pivot, VWAP and profile level indicators to all of these "client" charts. There would be one chart with an indicator that calculates these values and pushes them to another indicator that stores the values in a static DataTable. So the calculations to determine the values only need to be done on ONE chart.

Now that these values are stored in a static DataTable, my understanding is that they would then be accessible to very simple read only indicators on the "client" charts. These indicators would not need to do any calculations and, since the DataTable is static, would not be reliant upon instances of external indicators - they would just grab the values from the static DataTable.

In this particular case all of the static data remain unchanged during the course of the session, so the size of the DataTable would be very small. But even if we extend the concept to include in the table something like the CURRENT DAY VWAP, and the width of its various types of deviation bands, at [for example] one minute intervals, the size of the DataTable would remain manageable.

And, for non-historical operation, the pushing indicators could update the values of static variables, so that the very latest real time values could always be available. So the DataTable would be used only to backfill the "client" charts.

"If we don't loosen up some money, this sucker is going down." -GW Bush, 2008
“Lack of proof that something is true does not prove that it is not true - when you want to believe.” -Humpty Dumpty, 2014
“The greatest shortcoming of the human race is our inability to understand the exponential function.”
Prof. Albert Bartlett
Follow me on Twitter Visit my NexusFi Trade Journal Reply With Quote
The following 3 users say Thank You to Zondor for this post:

Can you help answer these questions
from other members on NexusFi?
Request for MACD with option to use different MAs for fa …
NinjaTrader
NexusFi Journal Challenge - April 2024
Feedback and Announcements
ZombieSqueeze
Platforms and Indicators
My NT8 Volume Profile Split by Asian/Euro/Open
NinjaTrader
 
Best Threads (Most Thanked)
in the last 7 days on NexusFi
Retail Trading As An Industry
58 thanks
Battlestations: Show us your trading desks!
55 thanks
NexusFi site changelog and issues/problem reporting
48 thanks
What percentage per day is possible? [Poll]
31 thanks
GFIs1 1 DAX trade per day journal
29 thanks

  #12 (permalink)
 Geir 
Oslo, Norway
 
Experience: Intermediate
Platform: Ninja Trader
Trading: ES
Posts: 10 since Jan 2011
Thanks Given: 46
Thanks Received: 40


Zondor View Post
Let's postulate a workspace with ~10, ~20 charts, or N charts of one instrument that I want to pretend I am trading, in the simulator, of course! Let's call the charts that I use for my "trading" decisions the "client" charts.

Suppose that for some reason I want to be able to put the daily pivots and previous N days VWAPS, Highs, Lows, PoC's etc on all of those charts.

It would NOT be necessary to add pivot, VWAP and profile level indicators to all of these "client" charts. There would be one chart with an indicator that calculates these values and pushes them to another indicator that stores the values in a static DataTable. So the calculations to determine the values only need to be done on ONE chart.

Now that these values are stored in a static DataTable, my understanding is that they would then be accessible to very simple read only indicators on the "client" charts. These indicators would not need to do any calculations and, since the DataTable is static, would not be reliant upon instances of external indicators - they would just grab the values from the static DataTable.

In this particular case all of the static data remain unchanged during the course of the session, so the size of the DataTable would be very small. But even if we extend the concept to include in the table something like the CURRENT DAY VWAP, and the width of its various types of deviation bands, at [for example] one minute intervals, the size of the DataTable would remain manageable.

And, for non-historical operation, the pushing indicators could update the values of static variables, so that the very latest real time values could always be available. So the DataTable would be used only to backfill the "client" charts.

Hi Zondor

sorry about the late reply, I only just saw your post.

I use my global variables exactly the way you outline it. As you probably saw I have written the receiving indicator in such a way that it caches the latest value. So in my humble opinion there is little overhead for pushing out real time values to the lower time frame charts. You just need to let the sending indicator update real time.

I have written a new indicator that picks up the global variable values. If I recall correctly it can handle up to 8 different global variables. That makes it a bit easier to handle. It also has a parameter for showing the name of the GV on the chart. It then really helps to have a good naming standard for the global variable names, like for instance <instrument><bar size><indicator><key indicator setting (for instance length)>. And of course it makes sense to let the GV plot identically to the original indicator so that you visually recognize the plot.

Regards
Geir

Started this thread Reply With Quote
The following 4 users say Thank You to Geir for this post:
  #13 (permalink)
Rory
 
Posts: 2,743 since May 2014
Thanks Given: 5,444
Thanks Received: 8,140


Hi @drmartell,


drmartell View Post
When I add this user defined method, it compiles fine, but it causes all my custom indicators to stop appearing on the Indicator chart dialog. Can anyone see what might be causing that?

Update: It appears to be this line:

 
Code
public static DataTable	gvTable = new DataTable(); // stores all historical data

but I still don't know why. . .

I tried to compile your code on NT7 and find that the DataTable type is unrecognised. Should this be a part of the available library functions or should I add a reference to some database dll?

Thanks in advance.

Reply With Quote
  #14 (permalink)
 Geir 
Oslo, Norway
 
Experience: Intermediate
Platform: Ninja Trader
Trading: ES
Posts: 10 since Jan 2011
Thanks Given: 46
Thanks Received: 40

Hi Rory

in case your question relates to my initial post there is actually a small omission in my explanation. You need to reference System.Data.dll by right clicking in the NT window for coding and choose References. Then you need to figure out where to find System.Data.dll. Mine is under C:\Windows\Microsoft.NET\Framework64\v2.0.50727\System.Data.dll

Good luck
Geir

Started this thread Reply With Quote
The following user says Thank You to Geir for this post:
  #15 (permalink)
Rory
 
Posts: 2,743 since May 2014
Thanks Given: 5,444
Thanks Received: 8,140


Geir View Post
Hi Rory

in case your question relates to my initial post there is actually a small omission in my explanation. You need to reference System.Data.dll by right clicking in the NT window for coding and choose References. Then you need to figure out where to find System.Data.dll. Mine is under C:\Windows\Microsoft.NET\Framework64\v2.0.50727\System.Data.dll

Good luck
Geir

Much appreciated Geir, thanks for the response! Tried a few DLLs but not that one of course. Looking forward to testing, cheers for your efforts on this idea. Rory.

Reply With Quote
  #16 (permalink)
 Cheech 
Mesa, AZ/USA
 
Experience: Intermediate
Platform: NinjaTrader, ThinkorSwim
Broker: AMP Futures/CQG, TDA
Trading: Currency Futures, my Harley Davidson
Posts: 107 since Jun 2012
Thanks Given: 43
Thanks Received: 133


shodson View Post
I would avoid accessing public static data sets directly in order to be more thread-safe. First, I would make the data private, etc.

@shodson @Geir

First I would like to thank all that contributed to the code and ideas in this section, this is exactly what I was looking for in order to solve a problem that I was having with a few indicators I am in the process of developing. I agree that the sharing of global variables in a multiprocessor environment requires a locking mechanism.

So, if I understood your instructions all of your code (with the necessary modifications) needed to be placed into the partial indicator containing the methods as provided by @Geir. Note I tested the unmodified version first and everything worked fine. There are a number of errors that are displayed by the receiver when the chart first comes up (see SS). However, they do not appear when refreshing the chart (F5). They also do not appear if both indicators are deleted, applied and then re-added.

Also, the second problem is that the output of the indicators do not match, sometimes. Although I did not do extensive testing of the unmodified version, after an F5 refresh they plots always matched. The only difference between the unmodified and the modified version is the addition of the locking code. What I also noticed is that they go back into sync after refreshing the historical data even through they did from an F5 refresh, however they begin to go out of sync after the refresh.

I may need to retest the original code again but before I remove the locking to do so I wanted to make sure I understood your instructions correctly and maybe clear up the error messages when it first starts up.

Thank you for your assistance.


 
Code
// GlobalVariableMethods
// by Geir Nilsen
// 
// use SetGlobalVariable to push the global variable value. Note that this method has to be called at CurrentBar 0
// in order to do some house keeping.
#region Using declarations
using System;
using System.ComponentModel;
using System.Drawing;
using NinjaTrader.Cbi;
using NinjaTrader.Data;
using NinjaTrader.Gui.Chart;
using System;
using System.Data;
using System.Collections.Generic;
	
#endregion

namespace NinjaTrader.Indicator
{
    partial class Indicator
    {		
		#region Variables
		// the following dictionaries hold real time values. When new time stamp comes in then data is sent to 
		// table for historic data
		/*
		public static Dictionary<string, DateTime> gvTime 	= new Dictionary<string, DateTime>();
		public static Dictionary<string, double> gvPrice 	= new Dictionary<string, double>();
		
		public static DataTable	gvTable = new DataTable(); // stores all historical data
		*/
		private static Dictionary<string, DateTime>	 	gvTime 	= new Dictionary<string, DateTime>();
		private static Dictionary<string, double> 		gvPrice = new Dictionary<string, double>();
		
		private static DataTable						gvTable = new DataTable(); 		// stores all historical data
		
		private static object 							lockObject = new object();		// Locking Object
		
		#endregion Variables
		
		public void SetGlobalVariable(string identifier, DateTime timeStamp, double value)
		{
		lock(lockObject);
		{	
			
			// prepare table first time the method is used
			if(gvTable.Columns.Count == 0)
			{
				gvTable.Columns.Add("ID", typeof(string));
				gvTable.Columns.Add("Time", typeof(DateTime));
				gvTable.Columns.Add("Price", typeof(double));
			}
			
			// clean up table in case data is already available (when refreshing chart)
			if(CurrentBar == 0)
			{
				string criteria = "ID = '" + identifier + "'";		// sql string
				DataRow[] toBeDeleted = gvTable.Select(criteria);	// perform sql
				if(toBeDeleted.Length > 0)
					foreach (DataRow row in toBeDeleted)
						gvTable.Rows.Remove(row);
			}	
			
			// add new values. For historical data table a row can just be added
			if(Historical)
				gvTable.Rows.Add(identifier, timeStamp, value);
			else
			{
				// check if new timestamp is <> from what is held in dictionary -> new bar
				// ==> add row to gvTable. store current value in dictionary.
				DateTime oldTimeStamp;
				gvTime.TryGetValue(identifier, out oldTimeStamp);
				
				// if we get a new timeStamp, then real time time stamp has changed. Send to table
				if(timeStamp != oldTimeStamp)
				{
					gvTable.Rows.Add(identifier, timeStamp, value);
				}
				
				// cache updated global variable
				gvTime[identifier] = timeStamp;
				gvPrice[identifier] = value;
			}	
		}
		//return true;
		
		}
		public double GetGlobalVariable(string identifier, DateTime timeStamp)
		{
		lock(lockObject);
		{
			
			double toBeReturned = -1;
			
			if(!Historical)
				// check if timeStamp is cached in dictionary. If yes, then return value
				gvPrice.TryGetValue(identifier, out toBeReturned);
			else
			{
				// select specified global variable data from table
				string criteria = "ID = '" + identifier + "'"; 		// sql string
				DataRow[] valuesForID = gvTable.Select(criteria);	// perform sql
				
				// walk through from oldest until time stamp in table is younger than what we are looking for
				foreach(DataRow row in valuesForID)
				{
					if((DateTime)row[1] <= timeStamp)
						toBeReturned = (double)row[2];
					else
						break;
				}
			}
			return toBeReturned;
		}
		}
	}	
}

Attached Thumbnails
Click image for larger version

Name:	GV_Errors.png
Views:	209
Size:	49.6 KB
ID:	173346   Click image for larger version

Name:	GV_error_2.png
Views:	230
Size:	81.4 KB
ID:	173348  
Attached Files
Elite Membership required to download: Global Variables Methods.cs
Reply With Quote
  #17 (permalink)
 
shodson's Avatar
 shodson 
OC, California, USA
Quantoholic
 
Experience: Advanced
Platform: IB/TWS, NinjaTrader, ToS
Broker: IB, ToS, Kinetick
Trading: stocks, options, futures, VIX
Posts: 1,976 since Jun 2009
Thanks Given: 533
Thanks Received: 3,709

It looks like your GetGlobalVariable() is getting called before the gvTable and it's columns are initialized. In GetGlobalVariable() you need to make sure your gvTable.Columns.Count > 0 before doing the gvTable.Select().

The clues were in the error message


Follow me on Twitter Visit my NexusFi Trade Journal Reply With Quote
  #18 (permalink)
 Cheech 
Mesa, AZ/USA
 
Experience: Intermediate
Platform: NinjaTrader, ThinkorSwim
Broker: AMP Futures/CQG, TDA
Trading: Currency Futures, my Harley Davidson
Posts: 107 since Jun 2012
Thanks Given: 43
Thanks Received: 133


shodson View Post
It looks like your GetGlobalVariable() is getting called before the gvTable and it's columns are initialized. In GetGlobalVariable() you need to make sure your gvTable.Columns.Count > 0 before doing the gvTable.Select().

The clues were in the error message


OK, I think I understand what you are saying (I am not a C# programmer so please bear with me on this).

In the GetGlobalVariables method would the test below satisfy the requirement?

If(!Historical && gvTable.Columns.Count > 0)

Is the reason that it worked after the first time because the table was populated?

Reply With Quote
  #19 (permalink)
 
shodson's Avatar
 shodson 
OC, California, USA
Quantoholic
 
Experience: Advanced
Platform: IB/TWS, NinjaTrader, ToS
Broker: IB, ToS, Kinetick
Trading: stocks, options, futures, VIX
Posts: 1,976 since Jun 2009
Thanks Given: 533
Thanks Received: 3,709

No, you want to put the check at a higher level, the error is happening inside the "else" part of your if.

I'd do this

below the line

 
Code
double toBeReturned = -1;
put this line

 
Code
if (gvTable.Columns.Count == 0)
    return toBeReturned;
if the table columns aren't there, just get out and bail

Follow me on Twitter Visit my NexusFi Trade Journal Reply With Quote
The following user says Thank You to shodson for this post:
  #20 (permalink)
 Cheech 
Mesa, AZ/USA
 
Experience: Intermediate
Platform: NinjaTrader, ThinkorSwim
Broker: AMP Futures/CQG, TDA
Trading: Currency Futures, my Harley Davidson
Posts: 107 since Jun 2012
Thanks Given: 43
Thanks Received: 133



shodson View Post
No, you want to put the check at a higher level, the error is happening inside the "else" part of your if.

I'd do this

below the line

 
Code
double toBeReturned = -1;
put this line

 
Code
if (gvTable.Columns.Count == 0)
    return toBeReturned;
if the table columns aren't there, just get out and bail

OK thank you, I will do that, give it a shot, and report the results.

That said, the second problem is that after the historical data is plotted (correctly) they go out of sync. I didn't modify any of the original code when I added in the locks and at this point not sure if the original code worked. Should the locaks have prevented this from happening or is there something missing in the original code?

Reply With Quote





Last Updated on March 31, 2016


© 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