Access the Volume Profile Drawing Tool From and Indicator

Can a NinjaScript indicator, strategy programmatically create and control the Order Flow Volume Profile drawing tool itself?

I am not asking about the OrderFlowVolumeProfile indicator class.

What I want to know is whether the actual drawing tool version can be created and driven from NinjaScript so that I can:

  • select two points from within my own custom indicator then have the built-in Order Flow Volume Profile drawing tool draw for that exact range

If yes, what is the supported public API or class/method to do that?

I see we can access the POC, VAH & VAL but I want to use an indicator to draw a Volume profile from points calculated from within the indicator.

That tool is not exposed via the usual Draw factory class. You have to create and remove it manually. Removal is actually trickier than creation. Here’s a code snippet that creates and removes a volume profile drawing tool. Call the removal in State==State.Terminated for every tool you create. Use draw to create a tool when needed.

		public void RemoveVolumeProfile(DrawingTools.OrderFlowVolumeProfile dt)
		{
			if (dt == null) return;
			dt.SetState(State.Terminated);

			if (ChartControl != null)
			{
				MethodInfo removeMethod = typeof(ChartControl).GetMethod(
					"RemoveDrawingTool",
					BindingFlags.NonPublic | BindingFlags.Instance);

				if (removeMethod != null)
				{
					removeMethod.Invoke(ChartControl, new object[] { dt, true, true });
				}
			}

			RemoveDrawObject(dt.Tag);
		}

        public DrawingTools.OrderFlowVolumeProfile DrawVolumeProfile(string tag,int startBarsAgo,double startY,int endBarsAgo, double endY)
		{
			DateTime startTime = Time[startBarsAgo];
			DateTime endTime = Time[endBarsAgo];

            DrawingTools.OrderFlowVolumeProfile dt = new DrawingTools.OrderFlowVolumeProfile();
            DrawingTool.SetDrawingToolCommonValues(dt, tag, false, this, false);
            IDrawingTool idt = dt as IDrawingTool;

            ChartAnchor anchor = DrawingTool.CreateChartAnchor(this, startBarsAgo, startTime, startY);
            anchor.CopyDataValues(dt.StartAnchor);
            dt.StartAnchor.IsEditing = false;

			anchor = DrawingTool.CreateChartAnchor(this, endBarsAgo, endTime, endY);
            anchor.CopyDataValues(dt.EndAnchor);
            dt.EndAnchor.IsEditing = false;

			dt.DrawnBy = null;

            DrawingToolAttachedTo attachedTo = new DrawingToolAttachedTo();
            attachedTo.ChartObject = ChartBars;
            attachedTo.Instrument = Instrument;
            dt.AttachedTo = attachedTo;

            dt.SetState(State.Active);

			return dt;
        }
3 Likes

Thanks Mark. That was very helpfull.

I’ve successfully created the built-in DrawingTools.OrderFlowVolumeProfile from a custom NinjaScript indicator thanks to Mark’s tip above .

It is drawing correctly, but I want to know whether there is a supported way to force that Volume Profile drawing tool to render on top of candles / other chart objects . Some way of duplicating the funtion of the right mouse menu “bring to front”

I’m glad the other code is working for you. I managed to fix the removal issue i was having with that code. Here’s a much cleaner version that creates the drawing tool properly owned by it’s parent indicator so it doesn’t need special remove handling.

        public DrawingTools.OrderFlowVolumeProfile DrawVolumeProfile(Indicator owner, string tag,int startBarsAgo,double startY,int endBarsAgo, double endY, bool isGlobal=false, string templateName="")
		{
			DateTime startTime = owner.Time[startBarsAgo];
			DateTime endTime = owner.Time[endBarsAgo];

            if (isGlobal && tag[0] != GlobalDrawingToolManager.GlobalDrawingToolTagPrefix)
                tag = $"{GlobalDrawingToolManager.GlobalDrawingToolTagPrefix}{tag}";

            if (DrawingTool.GetByTagOrNew(owner, typeof(DrawingTools.OrderFlowVolumeProfile), tag, templateName) is not DrawingTools.OrderFlowVolumeProfile dt)
                return default;

            DrawingTool.SetDrawingToolCommonValues(dt, tag, false, owner, false);

            ChartAnchor anchor = DrawingTool.CreateChartAnchor(owner, startBarsAgo, startTime, startY);
            anchor.CopyDataValues(dt.StartAnchor);
            dt.StartAnchor.IsEditing = false;

			anchor = DrawingTool.CreateChartAnchor(owner, endBarsAgo, endTime, endY);
            anchor.CopyDataValues(dt.EndAnchor);
            dt.EndAnchor.IsEditing = false;

            DrawingToolAttachedTo attachedTo = new DrawingToolAttachedTo();
            attachedTo.ChartObject = owner.ChartBars;
            attachedTo.Instrument = owner.Instrument;
            dt.AttachedTo = attachedTo;

            dt.SetState(State.Active);

			return dt;
        }

To set Z-Order so the drawing tool is always on top, I would try setting the ZOrderType on the drawing tool object to DrawingToolZOrder.AlwaysDrawnLast

dt.ZOrderType = DrawingToolZOrder.AlwaysDrawnLast;
2 Likes

Thanks Mark.

I had already tried dt.ZOrderType = DrawingToolZOrder.AlwaysDrawnLast;, but I had it placed before dt.SetState(State.Active); along with the other volume profile properties.

Once I moved it to after dt.SetState(State.Active);, it worked.

Thanks as well for the cleaner version of the code. I have it working now, but your new approach looks much better, so I’m going to recode it using that method.

1 Like