Welcome to NexusFi: the best trading community on the planet, with over 150,000 members Sign Up Now for Free
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 for basic access, or support us by becoming an Elite Member -- see if you qualify for a discount below.
-- Big Mike, Site Administrator
(If you already have an account, login at the top of the page)
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
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.
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?
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
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.
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.
// 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;
}
}
}
}
Elite Membership required to download: Global Variables Methods.cs
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().
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?
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
double toBeReturned = -1;
put this line
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?