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)
But a lot of time when price on heavy volume is up (or vice verse), it's just place where big/smart money reversed, i.e. already sold their longs to those who are buying and sometimes in addition to that sold also their newly established shorts again to those who continue to buy believing market is going to go higher. Is that correct ?
I was getting irksome runtime errors when trying to convert some NT6.5 Level II volume indicators to work with NT7. Here is the solution.
First of all, I cannot recommend highly enough the use of "try catch final' error trapping during development. Diagnostic Print statements can eventually be commented out, but the error traps WITH ERROR RECOVERY should be left in the production version unless someone can show me that they cause a performance penalty. Error trapping was a big help to me in solving this problem.
Typically we will put the Level 2 data from OnMarketDepth events into a list. But this will not work the same in NT7 as in NT6.5.
In NT6.5, the rows.insert method seems to implicitly add a row to the list if needed to accommodate the item that is being inserted.
In NT7, this is not the case. It seems that you must explicitly create enough row objects to hold anything that you would want to insert. Inserts will fail if e.position is less than rows. count. An index out of range error will be generated. If it is not trapped and handled, the indicator will crash.
The necessary number of rows can be created by a routine that calls the rows.Add method within OnMarketDepth, This should either run only once upon program startup, or should test to make sure there are no more than the required number of rows before it adds any more. You don't want the row.Count to inflate with a bunch of empty rows. It's a lot easier to add them than to remove them.
Meanwhile in OnMarketDepth and graphics plot routines that use Level II data, it is a very wise idea to trap and handle errors using try{ catch{} and to put a return statement in the catch, better to miss a few ticks of data than to crash the indicator.
This seems to work pretty good. Try it and let me know how it works for you!
I recommend that you also add error traps to the other major modules of your program, including OnBarUpdate() and any custom Plot() methods you have added. If any methods other than OnMarketDepth ask for anything from the lists before the rows have been inserted in OnMarketDepth() there will be a runtime error. To avoid this you can insert the following code into any method that is having that problem. Then the needed rows will be inserted right there, instead of waiting for OnMarketDepth() to do it. By the time OnMarketDepth() triggers, enough rows will already exist so that no more will be created.
#if NT7
if(rows.Count<5) // Keep that number, 5, low so we won't do this routine more than once.
//The only way there can be more than 5 of these rows if the insertion routine below has already run.
//Create as many rows as you will need for your Level II data.
//I don't know if you can get more than 20 rows of Level 2 data so 22 rows should be enough.
{ int idx =0;
for (idx = 0; idx < 22/2; idx++)
{ //insert placeholder objects of type LadderRowrows into the list at positions [idx]
askRows.Insert(idx, new LadderRow((int)0,(int) 0, ""));
bidRows.Insert(idx, new LadderRow((int)0,(int) 0, ""));
}
}
}
#endif
Change "DOM Bands" in the Print statements to the name of YOUR program. Here goes!
//=============================================================================================
//These Lists need to have been declared as variables in the variables region:
//private List<LadderRow> askRows = new List<LadderRow>();
//private List<LadderRow> bidRows = new List<LadderRow>();
protected override void OnMarketDepth(MarketDepthEventArgs e)
{
// try, catch will handle any runtime errors, preventing the program from crashing
try{ // this { is the start of the area that is being monitored for errors
// there may be runtime errors when this starts up in NT7
{
List<LadderRow> rows = null;
// Checks to see if the Market Data is of the Ask type
if (e.MarketDataType == MarketDataType.Ask)
rows = askRows;
// Checks to see if the Market Data is of the Bid type
else if (e.MarketDataType == MarketDataType.Bid)
rows = bidRows;
if (rows == null)
return;
#if NT7 // This switch will prevent the bracketed code from being compiled in NT6.5.
// In NT7, MUST explcitly create list rows before inserting into them, to prevent runtime error
{ // Could also have used the Add method but this is more fun.
if(rows.Count<5) //Create as many rows as you will need for your Level II data. I don't think you can get more than 20 rows of Level 2 data, so 22 rows should be enough.
{ int idx =0;
for (idx = 0; idx < 22/2; idx++)
{ //insert placeholder objects of type LadderRowrows into the list
askRows.Insert(idx, new LadderRow((int)0,(int) 0, ""));
bidRows.Insert(idx, new LadderRow((int)0,(int) 0, ""));
}
}
}
#endif
// In NT7, insertion will fail if there is not already an empty row to insert into
// Checks to see if the action taken by the Ask data was an insertion into the ladder
if (e.Operation == Operation.Insert)
{
rows.Insert(e.Position, new LadderRow((int)e.Price,(int) e.Volume, e.MarketMaker));
Print("Rowcount, DOM_Bands7 = "+rows.Count);
}
/* Checks to see if the action taken by the Ask data was a removal of itself from the ladder
Note: Due to the multi threaded architecture of the NT core, race conditions could occur
-> check if e.Position is within valid range */
else if (e.Operation == Operation.Remove && e.Position < rows.Count)
rows.RemoveAt(e.Position);
/* Checks to see if the action taken by the Ask data was to update of data already on the ladder
Note: Due to the multi threaded architecture of the NT core, race conditions could occur
-> check if e.Position is within valid range */
else if (e.Operation == Operation.Update && e.Position < rows.Count)
{
rows[e.Position].MarketMaker = e.MarketMaker;
rows[e.Position].Price = e.Price;
rows[e.Position].Volume =(int) e.Volume;
}
// Calling ChartControl.Refresh() will cause the Level II data to update real-time. Adding
// this delay routine will prevent CPU utilization from going through the roof. Setting a
// really high value will effectly delay the update until the next tick arrives which could
// be a really long time is the market is really slow. This may or may not matter to some.
}
} //This is the end of the region that is being monitored for runtime errors
catch (Exception ex){
// Following is what we do if there is an error, sure beats crashing the indicator
Print("Trapped exception in DOM_Bands.OnMarketDepth(): " + ex.Message);
return; //prevents the indicator from crashing
}
}
private class LadderRow //for futures there is no Market Maker, but we can still use this to populate the lists
{
public string MarketMaker; // relevant for stocks only
public double Price;
public int Volume;
public LadderRow(double myPrice, int myVolume, string myMarketMaker)
{
MarketMaker = myMarketMaker;
Price = myPrice;
Volume = myVolume;
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++==
What about Supply and Demand, not just traded volume? Several time in the last weeks I saw reversals based on the DOM_Bands Indicator. When the DOM got very heavy [30,000 total] the market traded in a range (I'm showing a tick chart, which I now shun). But it does illustrate the point: when large Supply = large Demand, or Supply>>Demand, or Supply<<Demand it can mean something to later price action.
There were times when there was what I call a Throw-Over or Throw-Under: The book is really biased in one direction and Dom_Bands show the delta line crossing the bid or ask cumulative total line. This week they were reversals. (Once Zondor make his modification to DOM_bands this data will be saved with the GomRecorder and I'll show examples after they happen again.)
When the delta rides one of the other lines then moves toward the other with a defined slope it means the available Supply or demand is being consumed resulting in traded volume and a price trend. Twice on the chart you can see this happen as the price moves from 1136 to 1138 around 11:27 am PST & after a sell off, the next up trend from 1136 to 1138 at 12:05 to 12:22 pm. Chart have fractal relationships so this happens on all time frames.
FulcrumTrader is claiming that the data from DTNIQ matches that from the CME, but that Zenfire doesn't. Esignal, IB, Tradestation, and TT are also mentioned in other posts as not being accurate.
I read that too. But I already have Ninja & Tradestation and I hesitate to add Investor RT & IQFeed.
I wonder how bad is the difference?
in any case, I think that's not the biggest issue with Ninja.. the biggest issue is that you have to record it real time. My NT crashed on Friday and I had to restart it. I missed data during that time. That sucks cause with Zenfire you have no way to get it back. with IQFeed & Investor RT you can get 30 days history on the bid/ask.
Ninja really needs to improve on this. I heard for NT 7.0 the bid ask isn't usable, I don't remember the details but it's disappointing. This is actually one of the only reasons I keep tradestation..