Use it as secondary chart style. 100tick with 5 minute BodyBox (transparent body):
#region Using declarations
using NinjaTrader.Data;
using NinjaTrader.Gui.Chart;
using SharpDX;
using SharpDX.Direct2D1;
using System;
#endregion
namespace NinjaTrader.NinjaScript.ChartStyles
{
public class BodyBoxStyle : ChartStyle
{
private object icon;
public override int GetBarPaintWidth(int barWidth) =>
10 - 2 * (int)Math.Round(Stroke.Width);
public override object Icon =>
icon ??= Gui.Tools.Icons.ChartBox2;
public override void OnRender(
ChartControl chartControl,
ChartScale chartScale,
ChartBars chartBars)
{
Bars bars = chartBars.Bars;
float chartMinX = ConvertToHorizontalPixels(
chartControl,
chartControl.CanvasLeft + chartControl.Properties.BarMarginRight);
RectangleF rect = new();
int toIndex = chartBars.ToIndex;
if (toIndex >= 0 && toIndex < bars.Count - 1)
toIndex++;
for (int idx = chartBars.FromIndex; idx <= toIndex; idx++)
{
double openValue = bars.GetOpen(idx);
double closeValue = bars.GetClose(idx);
float openY = chartScale.GetYByValue(openValue);
float closeY = chartScale.GetYByValue(closeValue);
Brush overriddenBarBrush =
chartControl.GetBarOverrideBrush(chartBars, idx);
Brush overriddenOutlineBrush =
chartControl.GetCandleOutlineOverrideBrush(chartBars, idx);
float x = chartControl.GetXByBarIndex(chartBars, idx);
float boxStartPosition;
if (idx == chartBars.FromIndex && (toIndex == 0 || idx == 0))
{
if (toIndex == 0)
boxStartPosition = chartMinX;
else
boxStartPosition =
2 * x - chartControl.GetXByBarIndex(chartBars, idx + 1);
}
else
{
boxStartPosition =
chartControl.GetXByBarIndex(chartBars, idx - 1);
}
if (Math.Abs(x - boxStartPosition) < 0.2)
continue;
float width = Math.Max(2f, Math.Abs(x - boxStartPosition));
bool upBar = closeValue >= openValue;
if (upBar)
{
width -= Stroke.Width;
rect.X = boxStartPosition;
rect.Y = Math.Min(openY, closeY);
rect.Width = width;
rect.Height = Math.Max(1f, Math.Abs(closeY - openY));
TransformBrush(overriddenBarBrush ?? UpBrushDX, rect);
TransformBrush(overriddenOutlineBrush ?? Stroke.BrushDX, rect);
RenderTarget.FillRectangle(
rect,
overriddenBarBrush ?? UpBrushDX);
RenderTarget.DrawRectangle(
rect,
overriddenOutlineBrush ?? Stroke.BrushDX,
Stroke.Width,
Stroke.StrokeStyle);
}
else
{
width -= Stroke2.Width;
rect.X = boxStartPosition;
rect.Y = Math.Min(openY, closeY);
rect.Width = width;
rect.Height = Math.Max(1f, Math.Abs(closeY - openY));
TransformBrush(overriddenBarBrush ?? DownBrushDX, rect);
TransformBrush(overriddenOutlineBrush ?? Stroke2.BrushDX, rect);
RenderTarget.FillRectangle(
rect,
overriddenBarBrush ?? DownBrushDX);
RenderTarget.DrawRectangle(
rect,
overriddenOutlineBrush ?? Stroke2.BrushDX,
Stroke2.Width,
Stroke2.StrokeStyle);
}
}
}
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Name = "Body Box";
ChartStyleType = (ChartStyleType)5700; // custom enum value
BarWidth = 1;
}
else if (State == State.Configure)
{
Properties.Remove(Properties.Find("BarWidthUI", true));
SetPropertyName("DownBrush", "Down Body Color");
SetPropertyName("UpBrush", "Up Body Color");
SetPropertyName("Stroke", "Up Outline");
SetPropertyName("Stroke2", "Down Outline");
}
}
}
}
