NexusFi: Find Your Edge


Home Menu

 





Design a DayTrader Scalping Trend Pivot Indicator


Discussion in Traders Hideout

Updated
      Top Posters
    1. looks_one hyperscalper with 18 posts (29 thanks)
    2. looks_two Pablherasgarcia with 2 posts (0 thanks)
    3. looks_3 Successlife with 1 posts (0 thanks)
    4. looks_4 JBWTrader with 1 posts (0 thanks)
    1. trending_up 6,153 views
    2. thumb_up 29 thanks given
    3. group 16 followers
    1. forum 24 posts
    2. attach_file 6 attachments




 
Search this Thread

Design a DayTrader Scalping Trend Pivot Indicator

  #11 (permalink)
 hyperscalper 
boise idaho
 
Experience: Advanced
Platform: NinjaTrader C# Custom
Broker: NinjaTrader LeeLoo Rithmic
Trading: Nasdaq Futures NQ/MNQ
Posts: 314 since Apr 2020
Thanks Given: 15
Thanks Received: 522

OKAY, enough time has passed, and I did spend some time on this
project of finding Significant Pivots through measurement of "inside
Book", or "Market Depth" analysis.

This is a "standalone" NinjaTrader (using NinjaScript Editor) Indicator,
although that's not my preferred way to develop things; but I know
that most people will want the code in that way, source code, and
all in a single file, that they can just Paste into the NinjaScript
Editor.

SO.... I'm gonna just throw down the code. But before I do, I want
you to see what will, at first, appear perhaps to "spaghetti-like" and
just Random and Useless. However, on closer examination, I hope you'll
see what I'm talking about.

FIRSTLY, I HAVE TO EXPLAIN A BIT WHAT YOU'RE SEEING IN THE
SNAPSHOT HERE, AND SOME ASSUMPTIONS AND PRINCIPLES
SURROUNDING THE VISUALIZATION AND PREDICTIONS:

I HAVE USED THIS ONLY ON THE NASDAQ NQ CONTRACT, so if you
are going to stray into other instruments, it's uncharted territory.....

1) UNFORTUNATELY, but it must be said, "Your Mileage will Vary" from
what is being shown here. Why? I have a high performance 6 Core
server, co-located <1 millisecond from the CME exchange in Chicago,
AND, more importantly, I'm using LeeLoo's Rithmic Full Market Depth
which is incoming, as you'll see to the OnMarketDepth Indicator
callback.... Many Market Depths are 10 Tiers only on both sides of
the market, which would be OK, except that they may be somewhat
"aggregated". The code is expecting 12 Tiers, but that slight lack
of "tier width" might still yield a decent, usable result; however,
I want y'all to understand there's no way to guarantee that.

2) THIS IS FOR TRADERS WHO CODE, and who are interested in
perhaps picking up some coding tips, or digging into source code.
The code I'll eventually provide will have some redundant areas,
calculations that are never used; and will also use an "Object Oriented"
approach with inline class definitions. As things get more complex,
they can quickly outstrip what you can do in the NinjaScript Editor/
Compiler context; and it would be best to be using Visual Studio
(free Community Edition) as coding becomes even more complex,
so you could split up classes into separate files, and deliver this
Indicator as a DLL file instead..... just saying' that's the direction
in which y'all should be moving, when you're doing anything other
than a "simple or trivial" Indicator.....

3) The Basic Idea here, is that at significant Inflection points in the
short term Price movements; that MORE SIZE appears and is to be
interpreted as PUSHING the Market Price (in the near future) in
a different Trend direction. So, THE CHARTING INVERTS THE
DISPLAY so that More size on the BID side, is represented as UP,
which is our prediction; just as more size on the ASK side is shown
as DOWN. So the Difference between ASK and BID size ( A - B )
is INVERTED, better showing the Prediction for the near future.

4) When the Indicator is dragged onto the Price Chart, as shown,
ensure that the Indicator scale is on the LEFT side, and do not use
Auto Scaling. INSTEAD, use fixed scaling where the ZERO level
BLACK dashed line, is in the middle of the display, and MANUAL
scaling is used to increase or decrease the Lines' deflections.

WHAT DO THE LINES MEAN?

BLUE represents an analysis of 1 POINT (4 Tick or Tier levels)
against the inside market, but I believe it DISCARDS the Inside
BID and Inside ASK level, considered as "junk" or "noise"...
Call these Tiers 0..3 like array indices, where 0 is the extreme
Inside market.

PURPLE represents 4 Tiers which are Tiers 4..7 roughly 1 Point
away from the Inside.

GRAY represents 4 Tiers which are Tiers 8..11 or roughly 1 Points
away from the Inside market. If you have only 10 DOM Tiers,
then a couple will be missing, but I imagine the calculations will
still be done, although I haven't tested that.

The PINK line is a SUMMARY LINE. It is the AVERAGE of the 3 lines
above, where the Average is then MULTIPLIED by 2. So the PINK
line is your best visual indication of the Consensus of the 3
individual Bias Predictions above.

YOU WILL GENERALLY OBSERVE "DIVERGENCE" BETWEEN PRICE
MOVEMENT and these "Opposing Forces" which are preparing to
turn the Market Trending. Visually, this can be useful, and you should
be looking for the Larger such Signals, for the most significant of
Micro Trending changes.

I WILL ANSWER QUESTIONS, OF COURSE, but I really can't "hold your
hands" so please dig into the code before you just throw out a question.
Not trying to be flippant here, but I just don't have time....

YOU ARE ENCOURAGED, once you understand it, and have the skills,
to take the code and modify it for your own purposes. ONLY A FEW
of you will actually do that, and I'm happy to give suggestions...

Nobody (especially myself) is claiming that Measuring these subtle
biases, is going to be a nice "clean" signal. The Market's purpose is
to Completely Confuse Traders, and thus make it impossible to make
short term decisions which are correct !! You can throw a lot of
technology at the problem, and you can Fail. I know, since I've done
this for a long time. HOWEVER, sometimes if you stick to a reasonable
Hypothesis, like "I wonder whether Market Maker is PUSHING size onto
the Book" before pushing the Market price the other way....... Just
sometimes, if you are persistent enough; you may be able to find
those OFTEN VERY SUBTLE CLUES which can enable you to Sharpen
Up your trade decisions..... Good Luck, cuz we'll all need it !!! LOL

hyperscalper

Attached Thumbnails
Click image for larger version

Name:	Major-inflection-points.PNG
Views:	168
Size:	514.8 KB
ID:	322362  
Started this thread Reply With Quote
Thanked by:

Can you help answer these questions
from other members on NexusFi?
Better Renko Gaps
The Elite Circle
ZombieSqueeze
Platforms and Indicators
About a successful futures trader who didn´t know anyth …
Psychology and Money Management
Pivot Indicator like the old SwingTemp by Big Mike
NinjaTrader
Cheap historycal L1 data for stocks
Stocks and ETFs
 
  #12 (permalink)
 hyperscalper 
boise idaho
 
Experience: Advanced
Platform: NinjaTrader C# Custom
Broker: NinjaTrader LeeLoo Rithmic
Trading: Nasdaq Futures NQ/MNQ
Posts: 314 since Apr 2020
Thanks Given: 15
Thanks Received: 522

OK, here's the code, "As Is" no Warranty, use it any way you wish

Clearly, you can paste this, in its entirety, into the NinjaScript Editor
after creating a "dummy" Indicator of the same name, then just
paste this to replace everything and compile.

Any Bugs, and "Mea Culpa" but you can fix them. I've run this thing
for a while, with no problems, but see my Caveats in the prior post...
It ain't polished, may be considered a "hack" but when is anything
really finished ??? lol (I digress) It was an exploration of possibilities,
and I find it quite useful and enlightening for my own work, which
is always nice; it gave me a better understanding.

For example, this thing takes like the Average of the Top N observed
sizes (throwing out the largest) during a Bar Period (like 5 seconds on that
screenshot in prior posting, and then clear that on Each Bar update.
Best for something like a 5 second Interval chart; but you can
experiment..... etc...

Enjoy, and hope it helps or even inspires someone to go further !!

hyperscalper


 
Code
#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Indicators in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Indicators
{
	public class InnerTierSize : Indicator
	{
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Graphically represent Inner Tier size activity.";
				Name										= "InnerTierSize";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= false;
				DrawVerticalGridLines						= false;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
			}
			else if (State == State.Configure)
			{
				AddPlot(new Stroke(Brushes.Black), PlotStyle.Hash, "zeroIndex"); // index 0
				Plots[0].Width = 8;
				AddPlot(new Stroke(Brushes.Blue), PlotStyle.Line, "deltaBias"); // index 1, inner range
				Plots[1].Width = 6;
				AddPlot(new Stroke(Brushes.Purple), PlotStyle.Line, "deltaBias2"); // index 2, mid range
				Plots[2].Width = 8;
				AddPlot(new Stroke(Brushes.DarkGray), PlotStyle.Line, "deltaBias3"); // index 3, wider range
				Plots[3].Width = 10;
				AddPlot(new Stroke(Brushes.HotPink), PlotStyle.Line, "concensus"); // index 4, avg concensus
				Plots[4].Width = 10;
			}
		}
		
		private double bidTiers = 0;
		private int nBidTiers = 0;
		private double askTiers = 0;
		private int nAskTiers = 0;

		private double bidTiers2 = 0;
		private int nBidTiers2 = 0;
		private double askTiers2 = 0;
		private int nAskTiers2 = 0;

		private double bidTiers3 = 0;
		private int nBidTiers3 = 0;
		private double askTiers3 = 0;
		private int nAskTiers3 = 0;

		private void clearData() {
		bidTiers = 0;
		nBidTiers = 0;
		askTiers = 0;
		nAskTiers = 0;
			
		bidTiers2 = 0;
		nBidTiers2 = 0;
		askTiers2 = 0;
		nAskTiers2 = 0;
			
		bidTiers3 = 0;
		nBidTiers3 = 0;
		askTiers3 = 0;
		nAskTiers3 = 0;
			
		}

        public static int roundToNearestInt(double value) {
            // rounds to "nearest" integer positive or negative values
            // codeproject.com/articles/58289/c-round-function
            // do not try to use Math.Round (too tricky)
            if (value >= 0) {
                return (int)(value + 0.5);
            } else {
                return (int)(value - 0.5);
            }
        }

		protected sealed override void OnMarketDepth(MarketDepthEventArgs marketDepthUpdate)
		{
            if ( marketDepthUpdate.Operation != Operation.Update && marketDepthUpdate.Operation != Operation.Add) {
                return;
            }
			double lastBidPrice = 0;
			double lastAskPrice = 0;
			try { 
				lastBidPrice = this.GetCurrentBid();
				lastAskPrice = this.GetCurrentAsk();
			}
			catch(Exception ex) {
				return;
			}
			if (lastBidPrice==0 || lastAskPrice==0) return;
			{
				double price = marketDepthUpdate.Price;
				if (price <= lastBidPrice) { // BID side tiers
					double deltaPrice = lastBidPrice - price;
					double deltaTicks = deltaPrice / TickSize;
					int tierIdx = roundToNearestInt(deltaTicks);
					if (tierIdx < 0 || tierIdx > 11) return; // reject
					// we are taking every tier as a case, rather than
					// just to use a range of tier indexes
					if (tierIdx==0) {
						double vol = marketDepthUpdate.Volume;
						if (vol>1) { // reject inner singles
						bidTiers += vol;
						++nBidTiers;
						bidCapture.addData(vol);
						}
					}
					else if (tierIdx==1) {
						double vol = marketDepthUpdate.Volume;
						bidTiers += vol; // TODO temp mix with Tiers
						++nBidTiers;
						bidCapture.addData(vol);
					}
					else if (tierIdx==2) {
						double vol = marketDepthUpdate.Volume;
						bidTiers += vol; // TODO temp mix with Tiers
						++nBidTiers;
						bidCapture.addData(vol);
					}
					else if (tierIdx==3) {
						double vol = marketDepthUpdate.Volume;
						bidTiers += vol; // TODO temp mix with Tiers
						++nBidTiers;
						bidCapture.addData(vol);
					}
					
					else if (tierIdx==4) {
						double vol = marketDepthUpdate.Volume;
						bidTiers2 += vol;
						++nBidTiers2;
						bidCapture2.addData(vol);
					}
					else if (tierIdx==5) {
						double vol = marketDepthUpdate.Volume;
						bidTiers2 += vol; // TODO temp mix with Tiers
						++nBidTiers2;
						bidCapture2.addData(vol);
					}
					else if (tierIdx==6) {
						double vol = marketDepthUpdate.Volume;
						bidTiers2 += vol; // TODO temp mix with Tiers
						++nBidTiers2;
						bidCapture2.addData(vol);
					}
					else if (tierIdx==7) {
						double vol = marketDepthUpdate.Volume;
						bidTiers2 += vol; // TODO temp mix with Tiers
						++nBidTiers2;
						bidCapture2.addData(vol);
					}
					else if (tierIdx==8) {
						double vol = marketDepthUpdate.Volume;
						bidTiers3 += vol;
						++nBidTiers3;
						bidCapture3.addData(vol);
					}
					else if (tierIdx==9) {
						double vol = marketDepthUpdate.Volume;
						bidTiers3 += vol; // TODO temp mix with Tiers
						++nBidTiers3;
						bidCapture3.addData(vol);
					}
					else if (tierIdx==10) {
						double vol = marketDepthUpdate.Volume;
						bidTiers3 += vol; // TODO temp mix with Tiers
						++nBidTiers3;
						bidCapture3.addData(vol);
					}
					else if (tierIdx==11) {
						double vol = marketDepthUpdate.Volume;
						bidTiers3 += vol; // TODO temp mix with Tiers
						++nBidTiers3;
						bidCapture3.addData(vol);
					}
				}
				else if (price >= lastAskPrice) { // ASK side tiers
					double deltaPrice = price - lastAskPrice;
					double deltaTicks = deltaPrice / TickSize;
					int tierIdx = roundToNearestInt(deltaTicks);
					if (tierIdx < 0 || tierIdx > 11) return; // reject
					if (tierIdx==0) {
						double vol = marketDepthUpdate.Volume;
						if (vol>1) {
						askTiers += vol;
						++nAskTiers;
						askCapture.addData(vol);
						}
					}
					else if (tierIdx==1) {
						double vol = marketDepthUpdate.Volume;
						askTiers += vol; // TODO temp mix with Tiers
						++nAskTiers;
						askCapture.addData(vol);
					}
					else if (tierIdx==2) {
						double vol = marketDepthUpdate.Volume;
						askTiers += vol; // TODO temp mix with Tiers
						++nAskTiers;
						askCapture.addData(vol);
					}
					else if (tierIdx==3) {
						double vol = marketDepthUpdate.Volume;
						askTiers += vol; // TODO temp mix with Tiers
						++nAskTiers;
						askCapture.addData(vol);
					}
					else if (tierIdx==4) {
						double vol = marketDepthUpdate.Volume;
						askTiers2 += vol;
						++nAskTiers2;
						askCapture2.addData(vol);
					}
					else if (tierIdx==5) {
						double vol = marketDepthUpdate.Volume;
						askTiers2 += vol; // TODO temp mix with Tiers
						++nAskTiers2;
						askCapture2.addData(vol);
					}
					else if (tierIdx==6) {
						double vol = marketDepthUpdate.Volume;
						askTiers2 += vol; // TODO temp mix with Tiers
						++nAskTiers2;
						askCapture2.addData(vol);
					}
					else if (tierIdx==7) {
						double vol = marketDepthUpdate.Volume;
						askTiers2 += vol; // TODO temp mix with Tiers
						++nAskTiers2;
						askCapture2.addData(vol);
					}
					else if (tierIdx==8) {
						double vol = marketDepthUpdate.Volume;
						askTiers3 += vol;
						++nAskTiers3;
						askCapture3.addData(vol);
					}
					else if (tierIdx==9) {
						double vol = marketDepthUpdate.Volume;
						askTiers3 += vol; // TODO temp mix with Tiers
						++nAskTiers3;
						askCapture3.addData(vol);
					}
					else if (tierIdx==10) {
						double vol = marketDepthUpdate.Volume;
						askTiers3 += vol; // TODO temp mix with Tiers
						++nAskTiers3;
						askCapture3.addData(vol);
					}
					else if (tierIdx==11) {
						double vol = marketDepthUpdate.Volume;
						askTiers3 += vol; // TODO temp mix with Tiers
						++nAskTiers3;
						askCapture3.addData(vol);
					}
				}
				// 
			}
		}
		
		private static bool USE_NINJA_PRINT = true;
		
        public void ninjaPrint2(string msg) { // secondary tab
            if (!USE_NINJA_PRINT) return;
            PrintTo = PrintTo.OutputTab2;
            Print(msg);
        }

		private class SimpleSmoother {
			private double data = 0;
			private double data2 = 0;
			private double data3 = 0;
			private double data4 = 0;
			private double data5 = 0; // not using arrays LOL
			private static int MAX_ITEMS = 4;
			
			public void addData(double dataArg) {
				data5 = data4;
				data4 = data3;
				data3 = data2;
				data2 = data;
				data = dataArg; // new data
				++countForPeriod;
				if (dataArg > absoluteMax) { // capture max data
					absoluteMax6 = absoluteMax5;
					absoluteMax5 = absoluteMax4;
					absoluteMax4 = absoluteMax3;
					absoluteMax3 = absoluteMax2;
					absoluteMax2 = absoluteMax;
					absoluteMax = dataArg;
				}
			}
			
			public double getAvg() {
				return getAvg(4);
			}
			
			public double getAvg(int numItemsArg) {
				int numItems = numItemsArg;
				if (numItems<1) numItems=1;
				if (numItems>MAX_ITEMS) numItems = MAX_ITEMS;
				double sumX = 0;
				int n = 0;
				int itemCounter = 0;
				++itemCounter;
				if (itemCounter<=numItems) {
					sumX += data;
					++n;
				}
				++itemCounter;
				if (itemCounter<=numItems) {
					sumX += data2;
					++n;
				}
				++itemCounter;
				if (itemCounter<=numItems) {
					sumX += data3;
					++n;
				}
				++itemCounter;
				if (itemCounter<=numItems) {
					sumX += data4;
					++n;
				}
				++itemCounter;
				if (itemCounter<=numItems) {
					sumX += data5;
					++n;
				}
				return ( n==0 ? 0 : sumX / n );
			}
			
			private double absoluteMax = 0;
			private double absoluteMax2 = 0;
			private double absoluteMax3 = 0;
			private double absoluteMax4 = 0;
			private double absoluteMax5 = 0;
			private double absoluteMax6 = 0;
			private int countForPeriod = 0;
			
			public void resetMax() {
				absoluteMax = 0;
				absoluteMax2 = 0;
				absoluteMax3 = 0;
				absoluteMax4 = 0;
				absoluteMax5 = 0;
				absoluteMax6 = 0;
				countForPeriod = 0;
			}
			
			public int getCountForPeriod() {
				return countForPeriod;
			}
			
			// return average of highest 3
			public double getMaxForPeriod() {
				double sumX = 0;
				int n = 0;
				if (absoluteMax!=0) {
					sumX += absoluteMax; ++n;
				}
				if (absoluteMax2!=0) {
					sumX += absoluteMax2; ++n;
				}
				if (absoluteMax3!=0) {
					sumX += absoluteMax3; ++n;
				}
				if (absoluteMax4!=0) {
					sumX += absoluteMax4; ++n;
				}
				if (absoluteMax5!=0) {
					sumX += absoluteMax5; ++n;
				}
				if (absoluteMax6!=0) {
					sumX += absoluteMax6; ++n;
				}
				return (n==0 ? 0 : sumX / n);
			}
			
			public double getMax() {
				double max = 0; // there is no zero size
				if (data>max) max = data;
				if (data2>max) max = data2;
				if (data3>max) max = data3;
				if (data4>max) max = data4;
				if (data5>max) max = data5;
				return max;
			}
			
		}
		
		private static double compress(double valueArg, double exponent) {
			double value = valueArg;
			bool isNegative = false;
			double valCompressed = 0;
			try {
				// we will compress only positive values
				isNegative = ( value < 0 );
				if (isNegative) value = -1 * value; // use positive values
				valCompressed = Math.Pow(value, exponent);
			}
			catch(Exception ex) {
				return 0;
			}
			// restore negative sign if negative
			return ( isNegative? valCompressed * -1 : valCompressed);
		}
		
		private SimpleSmoother concensusSmoother = new SimpleSmoother();
		private SimpleSmoother smootherDelta = new SimpleSmoother();
		private SimpleSmoother smootherDelta2 = new SimpleSmoother();
		private SimpleSmoother smootherDelta3 = new SimpleSmoother();
		private SimpleSmoother bidCapture = new SimpleSmoother();
		private SimpleSmoother askCapture = new SimpleSmoother();
		private SimpleSmoother bidCapture2 = new SimpleSmoother();
		private SimpleSmoother askCapture2 = new SimpleSmoother();
		private SimpleSmoother bidCapture3 = new SimpleSmoother();
		private SimpleSmoother askCapture3 = new SimpleSmoother();
		
		double lastDeltaTiers = 0;
		double lastAvgAskTiers = 0;
		double lastAvgBidTiers = 0;
		
		double lastDeltaTiers2 = 0;
		double lastAvgAskTiers2 = 0;
		double lastAvgBidTiers2 = 0;
		
		double lastDeltaTiers3 = 0;
		double lastAvgAskTiers3 = 0;
		double lastAvgBidTiers3 = 0;
		double lastAvgConcensus = 0;
		
		private static bool USE_CAPTURE = true; // ALWAYS TRUE
		private static double EXPONENT = 0.6;

		protected override void OnBarUpdate()
		{
			Values[0][0] = 0; // zero line
			try {
			double avgBidTiers = 0;
			double avgAskTiers = 0;
			double avgBidTiers2 = 0;
			double avgAskTiers2 = 0;
			double avgBidTiers3 = 0;
			double avgAskTiers3 = 0;
			
			double lastPlottedInner = 0;
			double lastPlottedMiddle = 0;
			double lastPlottedOuter = 0;
			
			
			{
				avgBidTiers = USE_CAPTURE? bidCapture.getMaxForPeriod() : ( bidTiers / nBidTiers );
				if (avgBidTiers!=0) lastAvgBidTiers = avgBidTiers;
			}
			
			{
				avgAskTiers = USE_CAPTURE? askCapture.getMaxForPeriod() : ( askTiers / nAskTiers );
				if (avgAskTiers!=0) lastAvgAskTiers = avgAskTiers;
			}
			
			if ( lastAvgBidTiers!=0 && lastAvgAskTiers != 0 ) {
				double delta = lastAvgAskTiers - lastAvgBidTiers;
				lastDeltaTiers = delta;
				smootherDelta.addData(delta);
				double avgDelta = smootherDelta.getAvg(); // retrieve average
				double avgCompressed = compress(avgDelta, EXPONENT);
				Values[1][0] = lastPlottedInner = -1 * (avgCompressed * 40); // invert for PUSH prediction
			}
			else {
				double avgDelta = smootherDelta.getAvg(); // retrieve average
				if (avgDelta!=0) {
				double avgCompressed = compress(avgDelta, EXPONENT);
				Values[1][0] = lastPlottedInner = -1 * (avgCompressed * 40); // TODO should smooth these
				}
			}
			
			// WIDER DOM balance
			{
				avgBidTiers2 = USE_CAPTURE? bidCapture2.getMaxForPeriod() : ( bidTiers2 / nBidTiers2 );
				if (avgBidTiers2!=0) lastAvgBidTiers2 = avgBidTiers2;
			}
			
			{
				avgAskTiers2 = USE_CAPTURE? askCapture2.getMaxForPeriod() : ( askTiers2 / nAskTiers2 );
				if (avgAskTiers2!=0) lastAvgAskTiers2 = avgAskTiers2;
			}
			
			
			if ( lastAvgBidTiers2!=0 && lastAvgAskTiers2 != 0 ) {
				double delta2 = lastAvgAskTiers2 - lastAvgBidTiers2;
				lastDeltaTiers2 = delta2;
				smootherDelta2.addData(delta2);
				double avgDelta2 = smootherDelta2.getAvg(); // retrieve average
				double avgCompressed2 = compress(avgDelta2, EXPONENT);
				Values[2][0] = lastPlottedMiddle = -1 * (avgCompressed2 * 40); // invert for PUSH prediction
			}
			else {
				double avgDelta2 = smootherDelta2.getAvg(); // retrieve average
				if (avgDelta2!=0) {
				double avgCompressed2 = compress(avgDelta2, EXPONENT);
				Values[2][0] = lastPlottedMiddle = -1 * (avgCompressed2 * 40); // TODO should smooth these
				}
			}
			
			// WIDEST DOM balance
			{
				avgBidTiers3 = USE_CAPTURE? bidCapture3.getMaxForPeriod() : ( bidTiers3 / nBidTiers3 );
				if (avgBidTiers3!=0) lastAvgBidTiers3 = avgBidTiers3;
			}
			
			{
				avgAskTiers3 = USE_CAPTURE? askCapture3.getMaxForPeriod() : ( askTiers3 / nAskTiers3 );
				if (avgAskTiers3!=0) lastAvgAskTiers3 = avgAskTiers3;
			}
			
			
			if ( lastAvgBidTiers3!=0 && lastAvgAskTiers3 != 0 ) {
				double delta3 = lastAvgAskTiers3 - lastAvgBidTiers3;
				lastDeltaTiers3 = delta3;
				smootherDelta3.addData(delta3);
				double avgDelta3 = smootherDelta3.getAvg(); // retrieve average
				double avgCompressed3 = compress(avgDelta3, EXPONENT);
				Values[3][0] = lastPlottedOuter = -1 * (avgCompressed3 * 40); // invert for PUSH prediction
			}
			else {
				double avgDelta3 = smootherDelta3.getAvg(); // retrieve average
				if (avgDelta3!=0) {
				double avgCompressed3 = compress(avgDelta3, EXPONENT);
				Values[3][0] = lastPlottedOuter = -1 * (avgCompressed3 * 40); // TODO should smooth these
				}
			}
			
			double concensus = ( lastPlottedInner + lastPlottedMiddle + lastPlottedOuter ) * 0.33;
			concensusSmoother.addData(concensus);
			double avgConcensus = concensusSmoother.getAvg();
			if (avgConcensus!=0) lastAvgConcensus = avgConcensus;
			Values[4][0] = (2 * lastAvgConcensus);
			
			//ninjaPrint2("Counts bid: "+bidCapture.getCountForPeriod()+" ask: "+askCapture.getCountForPeriod());
			bidCapture.resetMax();
			askCapture.resetMax();
			bidCapture2.resetMax();
			askCapture2.resetMax();
			bidCapture3.resetMax();
			askCapture3.resetMax();
			clearData();
			}
			catch(Exception ex) {
				ninjaPrint2("OnBarUpdate Exception: "+ex.Message);
			}
		}
	}
}

#region NinjaScript generated code. Neither change nor remove.

namespace NinjaTrader.NinjaScript.Indicators
{
	public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
	{
		private InnerTierSize[] cacheInnerTierSize;
		public InnerTierSize InnerTierSize()
		{
			return InnerTierSize(Input);
		}

		public InnerTierSize InnerTierSize(ISeries<double> input)
		{
			if (cacheInnerTierSize != null)
				for (int idx = 0; idx < cacheInnerTierSize.Length; idx++)
					if (cacheInnerTierSize[idx] != null &&  cacheInnerTierSize[idx].EqualsInput(input))
						return cacheInnerTierSize[idx];
			return CacheIndicator<InnerTierSize>(new InnerTierSize(), input, ref cacheInnerTierSize);
		}
	}
}

namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
	public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
	{
		public Indicators.InnerTierSize InnerTierSize()
		{
			return indicator.InnerTierSize(Input);
		}

		public Indicators.InnerTierSize InnerTierSize(ISeries<double> input )
		{
			return indicator.InnerTierSize(input);
		}
	}
}

namespace NinjaTrader.NinjaScript.Strategies
{
	public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
	{
		public Indicators.InnerTierSize InnerTierSize()
		{
			return indicator.InnerTierSize(Input);
		}

		public Indicators.InnerTierSize InnerTierSize(ISeries<double> input )
		{
			return indicator.InnerTierSize(input);
		}
	}
}

#endregion

END OF CODE.

hyperscalper

Started this thread Reply With Quote
Thanked by:
  #13 (permalink)
 hyperscalper 
boise idaho
 
Experience: Advanced
Platform: NinjaTrader C# Custom
Broker: NinjaTrader LeeLoo Rithmic
Trading: Nasdaq Futures NQ/MNQ
Posts: 314 since Apr 2020
Thanks Given: 15
Thanks Received: 522


Minor error, possibly:

private static int MAX_ITEMS = 4;

should probably be 5 instead..... anyway you decide.

hyperscalper


[EDIT] funny enough, I integrated the basic "highest for interval"
approach into my other Custom Strategy logic; and I believe it does give better
results. Just goes to show that unless you try things; you may never
find ways to improve !!! LOL

[EDIT2] I'd also suggest setting this to FALSE so the Indicator runs even
if window is minimized... I think that's what it means...

IsSuspendedWhileInactive = true; // change to false

Started this thread Reply With Quote
Thanked by:
  #14 (permalink)
 hyperscalper 
boise idaho
 
Experience: Advanced
Platform: NinjaTrader C# Custom
Broker: NinjaTrader LeeLoo Rithmic
Trading: Nasdaq Futures NQ/MNQ
Posts: 314 since Apr 2020
Thanks Given: 15
Thanks Received: 522

AS UKRAINE IS INVADED...

Here is a screenshot from 9am Chicago time showing InnerTierSize
yielding some information on the micro trend.

As I said, it takes some getting used to; but it does extract
the info fairly well.

If you don't have these colored lines, then you most likely do
not have a Market Depth or "Level 2" feed from your broker.

As I said, I use LeeLoo Rithmic which includes Market Depth
by default, and cannot test it on any other feeds.

hyperscalper

Attached Thumbnails
Click image for larger version

Name:	InnerTiersSize-now.PNG
Views:	155
Size:	390.8 KB
ID:	322389  
Started this thread Reply With Quote
Thanked by:
  #15 (permalink)
 hyperscalper 
boise idaho
 
Experience: Advanced
Platform: NinjaTrader C# Custom
Broker: NinjaTrader LeeLoo Rithmic
Trading: Nasdaq Futures NQ/MNQ
Posts: 314 since Apr 2020
Thanks Given: 15
Thanks Received: 522

LET'S DISCUSS WHY THIS IS A LEADING INDICATOR

Most traders have little choice, so they simply Chase Price.

But close analysis of Price Discontinuities and Spread behavior
show why this is a very bad event.

Most traders who are Chasing Price, are also using Market Orders,
where there is little price control.

As Price is moving in an UPTREND, the ASK/OFFER price is being
elevated, and lesser size is planted close to the market, so
that any Big Lot buying will suffer having to "eat through"
or "consume" higher and higher ASK tiers in order for the
size to be satisfied.

This is by design, and is fundamental to how Market Maker both
controls Her Risk, as well as achieving significant Price advantage.

SO, YOU DEFINITELY WANT TO ENTER BEFORE THE TREND CHANGE
SHOWS ITSELF IN ACTUAL PRICE MOVEMENT.

For many traders, they say they require "Confirmation" of the
new Trend before they will Enter in Trend direction; effectively
"chasing" Price, and hoping that Price exhibits a "Trend Momentum"
which is a dubious assumption at best.

For very short term Scalpers, this InnerTierSize indicator gives a
glimpse into the "sneaky world" of Market Maker; and how Size
placement Bias can be exploited to PREDICT the Trend change,
before the Price gives up the "secret" that the Trend has Changed.

This is a Leading Indicator, because Market Maker exhibits this
"inside market tier size bias" BEFORE the Trend turns... It may be
too FAST for most of you as traders, but it's important to understand
that PRICE does not predict PRICE. Once Price changes, it's
TOO LATE to get the BEST price...

Something OTHER THAN Price must be used to Predict a Price
change BEFORE it actually reveals itself..... Just sayin' LOL

Just something to think about as a Day Trading Fast Scalper...


hyperscalper

Started this thread Reply With Quote
Thanked by:
  #16 (permalink)
 hyperscalper 
boise idaho
 
Experience: Advanced
Platform: NinjaTrader C# Custom
Broker: NinjaTrader LeeLoo Rithmic
Trading: Nasdaq Futures NQ/MNQ
Posts: 314 since Apr 2020
Thanks Given: 15
Thanks Received: 522

IS PRICING CONTINUOUS, OR DOES IT HAVE GAPS ??

Most of us think that, when there is High Liquidity, that
Prices jump up or down in 1 Tick amounts, so that there is
never a "GAP" between one Bid price and the next, or between
one Ask/Offer price and the next one.

This is not true. And the Existence of "Gaps" in successive
Prices on the Inside Market might be used to gain an
advantage.

Attached is an image of a simple "Gap" analysis. What do the
numbers mean ?? Here's a chunk, so let's see what each line
means. Just the format of the first marked line:

This means a GAP of 5 ticks was found between the PREVIOUS
BID price, and the CURRENT BID price of 5 Price Ticks. Also
that the ASK gap between the Previous ASK price and the Current
ASK price showed a Gap of 2 Price Ticks. The time between the
Previous and the Current GAP detection was 32 milliseconds.
Additionally, if the size of the BID Gap is significantly greater than
the ASK, then *** is shown; but if ASK Gap is larger, a ###
would have been shown.

WHAT MIGHT WE EXPECT ?? Well, just using Common Sense, near
a Price Trend Bottom, we would expect that the BID would "snap"
lower significantly more than the ASK, as the Price Trend is still
moving down, and any Retail Sellers would then be exposed to
WORSE Pricing, since Market Maker would drop the BID against any
Retail Sellers (who sell to the Bid). On an uptrend, near the Top,
we'd expect the opposite, that the ASK Price would be allowed to
lift and/or have lesser sizes against the market, so that any Retail
Buyers would have a WORSE price.

Using this logic and hypothesis; we could use the existence of Gaps,
and of Gap Imbalances (directional Spread widening) to detect the
imminent Top or Bottom trending conditions, as well, MAYBE.

GAP bid: 5 *** ask: 2 msecs: 32 <====
GAP bid: 3 ask: 4 msecs: 30
GAP bid: 4 ask: 4 msecs: 31
GAP bid: 4 ask: 5 msecs: 336
GAP bid: 3 ask: 4 msecs: 34
GAP bid: 4 ask: 4 msecs: 325
GAP bid: 2 ask: 4 msecs: 23

But the fact that there are Gaps at all, or that they are so large,
might be "food for thought".

This is NQ on the first day of Russia's invasion of Ukraine, but I
suspect it could possibly be useful just about any time.

[EDIT]
IN SUMMARY: If/When we see an ASK Gap, e.g. 8, alongside
a BID Gap of Zero... that means the BID did not move, but the
ASK "snapped" away; likely at a Top... If ASK Gap is zero, but
BID Gap is high, then we have a likely Bottom where the BID
is being dropped, against Retail Sellers probably, while the ASK
is holding firm...

hyperscaper

Attached Thumbnails
Click image for larger version

Name:	Bid-ask-Gap-Analysis.PNG
Views:	106
Size:	43.7 KB
ID:	322400  
Started this thread Reply With Quote
Thanked by:
  #17 (permalink)
 hyperscalper 
boise idaho
 
Experience: Advanced
Platform: NinjaTrader C# Custom
Broker: NinjaTrader LeeLoo Rithmic
Trading: Nasdaq Futures NQ/MNQ
Posts: 314 since Apr 2020
Thanks Given: 15
Thanks Received: 522

JUST ANOTHER SCREENSHOT

I'll just put in a screenshot showing what we are looking
for with this indicator.

We can see the advanced notice that this Rally is near its
top, as the consensus bias (PINK line) and the lines groupings
are consistently below the zero line (BLACK dashed line).

I call this a "leading indicator" because it uses the fundamental
behaviors of Market Maker shifting size bias before the Price
movement happens....

hyperscalper

Attached Thumbnails
Click image for larger version

Name:	Inner-bias-Sell-signal.PNG
Views:	141
Size:	113.0 KB
ID:	322416  
Started this thread Reply With Quote
Thanked by:
  #18 (permalink)
 
Successlife's Avatar
 Successlife 
Any part of the world.
 
Experience: Master
Platform: Iq feed- Ensign
Trading: ES
Posts: 68 since Jul 2009
Thanks Given: 2
Thanks Received: 14

Sorry if this is can be some stupid idea.
I see a good performance is Renko chart for NQ (I use NinzaRenko like 16-4)
If you like use more longer time frame , for example 2 minute chart, is s good idea to move to every tick ?
thanks you for your time.

Reply With Quote
  #19 (permalink)
 hyperscalper 
boise idaho
 
Experience: Advanced
Platform: NinjaTrader C# Custom
Broker: NinjaTrader LeeLoo Rithmic
Trading: Nasdaq Futures NQ/MNQ
Posts: 314 since Apr 2020
Thanks Given: 15
Thanks Received: 522


Successlife View Post
Sorry if this is can be some stupid idea.
I see a good performance is Renko chart for NQ (I use NinzaRenko like 16-4)
If you like use more longer time frame , for example 2 minute chart, is s good idea to move to every tick ?
thanks you for your time.

Well, I use the indicator on interval charts less than about 10 seconds, so pretty fast.
But there's no reason you can't use it on other chart types, I guess; although until there
is an OnBarUpdate, you won't be seeing the updated measurement.

So, I'd guess that you are correct that OnBarUpdate should be done on every tick
if you used a much longer 2 minute interval. OnBarUpdate coding could be done
differently so that it didn't update every tick, since that would be unnecessary;
so I'll leave that coding to You !

Tweak the code as you like; since you may learn something, and can adapt it to
your requirements. My work uses NQ only; but on Instruments with other "personalities"
some adaptation could make sense...

hyperscalper

Started this thread Reply With Quote
Thanked by:
  #20 (permalink)
 Pablherasgarcia 
Madrid
 
Experience: Intermediate
Platform: Ninjatrader
Broker: Ninjatrader
Trading: CL, ES
Posts: 63 since Jan 2015
Thanks Given: 10
Thanks Received: 57


Maybe I say something without much sense but, what would it be like to apply this indicator to a market with fewer participants but also very volatile as the NQ? I'm thinking of the Ultrabond (UB). I haven't tried it because I don't code, nor am I asking you, it's just an idea. Thank you.

Reply With Quote




Last Updated on March 14, 2022


© 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