How To use Heat Maps


How do you use Heat Maps ?

1 Like

#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using NinjaTrader.Gui.Chart;
using NinjaTrader.NinjaScript;
using NinjaTrader.NinjaScript.Indicators;
using SharpDX;
#endregion

namespace NinjaTrader.NinjaScript.Indicators
{
public class WTVolumeTPOHeatMap : Indicator
{
private Dictionary<double, double> volProfile;
private Dictionary<double, int> tpoProfile;

    private ATR atr;
    private EMA fastEma;
    private EMA slowEma;

    [NinjaScriptProperty]
    [Range(20, 2000)]
    [Display(Name = "Lookback Bars", Order = 1, GroupName = "Heat Map")]
    public int LookbackBars { get; set; }

    [NinjaScriptProperty]
    [Range(1, 100)]
    [Display(Name = "Row Size Ticks", Order = 2, GroupName = "Heat Map")]
    public int RowSizeTicks { get; set; }

    [NinjaScriptProperty]
    [Range(0, 100)]
    [Display(Name = "TPO Weight %", Order = 3, GroupName = "Heat Map")]
    public int TPOWeight { get; set; }

    [NinjaScriptProperty]
    [Range(20, 255)]
    [Display(Name = "Max Heat Opacity", Order = 4, GroupName = "Heat Map")]
    public int MaxOpacity { get; set; }

    [NinjaScriptProperty]
    [Display(Name = "Show POC Line", Order = 5, GroupName = "Heat Map")]
    public bool ShowPOC { get; set; }

    [NinjaScriptProperty]
    [Display(Name = "Show POC Label", Order = 6, GroupName = "Heat Map")]
    public bool ShowPOCLabel { get; set; }

    [NinjaScriptProperty]
    [Display(Name = "Show Value Area", Order = 7, GroupName = "Heat Map")]
    public bool ShowValueArea { get; set; }

    [NinjaScriptProperty]
    [Range(50, 90)]
    [Display(Name = "Value Area Percent", Order = 8, GroupName = "Heat Map")]
    public int ValueAreaPercent { get; set; }

    [NinjaScriptProperty]
    [Display(Name = "Show VAH VAL Labels", Order = 9, GroupName = "Heat Map")]
    public bool ShowValueAreaLabels { get; set; }

    [NinjaScriptProperty]
    [Display(Name = "Trend Matched Colors", Order = 10, GroupName = "Heat Map")]
    public bool TrendMatchedColors { get; set; }

    [NinjaScriptProperty]
    [Display(Name = "Show Volume Profile Bars", Order = 1, GroupName = "Volume Profile Bars")]
    public bool ShowVolumeProfileBars { get; set; }

    [NinjaScriptProperty]
    [Range(20, 500)]
    [Display(Name = "Profile Bar Max Width", Order = 2, GroupName = "Volume Profile Bars")]
    public int ProfileBarMaxWidth { get; set; }

    [NinjaScriptProperty]
    [Range(10, 200)]
    [Display(Name = "Profile Bar Right Offset", Order = 3, GroupName = "Volume Profile Bars")]
    public int ProfileBarRightOffset { get; set; }

    [NinjaScriptProperty]
    [Range(10, 255)]
    [Display(Name = "Profile Bar Opacity", Order = 4, GroupName = "Volume Profile Bars")]
    public int ProfileBarOpacity { get; set; }

    [NinjaScriptProperty]
    [Display(Name = "Show POC Bar", Order = 5, GroupName = "Volume Profile Bars")]
    public bool ShowPOCBar { get; set; }

    [NinjaScriptProperty]
    [Range(1, 5)]
    [Display(Name = "POC Bar Thickness Multiplier", Order = 6, GroupName = "Volume Profile Bars")]
    public int POCBarThickness { get; set; }

    [NinjaScriptProperty]
    [Display(Name = "Show Neon Trend Bars", Order = 1, GroupName = "Neon Bars")]
    public bool ShowNeonTrendBars { get; set; }

    [NinjaScriptProperty]
    [Range(1, 100)]
    [Display(Name = "ATR Period", Order = 2, GroupName = "Neon Bars")]
    public int AtrPeriod { get; set; }

    [NinjaScriptProperty]
    [Range(1, 200)]
    [Display(Name = "Fast Trend EMA", Order = 3, GroupName = "Neon Bars")]
    public int FastTrendEma { get; set; }

    [NinjaScriptProperty]
    [Range(1, 300)]
    [Display(Name = "Slow Trend EMA", Order = 4, GroupName = "Neon Bars")]
    public int SlowTrendEma { get; set; }

    [NinjaScriptProperty]
    [Range(2, 80)]
    [Display(Name = "Bar Width", Order = 5, GroupName = "Neon Bars")]
    public int BarWidth { get; set; }

    [NinjaScriptProperty]
    [Range(1, 500)]
    [Display(Name = "Min Range Ticks", Order = 6, GroupName = "Neon Bars")]
    public int MinRangeTicks { get; set; }

    [NinjaScriptProperty]
    [Range(1, 2000)]
    [Display(Name = "Max Range Ticks", Order = 7, GroupName = "Neon Bars")]
    public int MaxRangeTicks { get; set; }

    [NinjaScriptProperty]
    [Range(1, 100)]
    [Display(Name = "Neon Opacity", Order = 8, GroupName = "Neon Bars")]
    public int NeonOpacity { get; set; }

    [NinjaScriptProperty]
    [Range(0, 30)]
    [Display(Name = "Glow Size", Order = 9, GroupName = "Neon Bars")]
    public int GlowSize { get; set; }

    [NinjaScriptProperty]
    [Display(Name = "Use Body Only", Order = 10, GroupName = "Neon Bars")]
    public bool UseBodyOnly { get; set; }

    protected override void OnStateChange()
    {
        if (State == State.SetDefaults)
        {
            Name = "WTVolumeTPOHeatMap";
            Description = "Volume Profile + TPO heat map with matched trend gradient profile bars, POC bar, VAH/VAL, and neon trend bars.";

            Calculate = Calculate.OnEachTick;
            IsOverlay = true;
            DrawOnPricePanel = true;
            DisplayInDataBox = false;
            PaintPriceMarkers = false;
            IsAutoScale = false;
            IsSuspendedWhileInactive = true;

            LookbackBars = 220;
            RowSizeTicks = 20;
            TPOWeight = 40;
            MaxOpacity = 90;
            ShowPOC = true;
            ShowPOCLabel = true;
            ShowValueArea = true;
            ValueAreaPercent = 70;
            ShowValueAreaLabels = true;
            TrendMatchedColors = true;

            ShowVolumeProfileBars = true;
            ProfileBarMaxWidth = 180;
            ProfileBarRightOffset = 35;
            ProfileBarOpacity = 190;
            ShowPOCBar = true;
            POCBarThickness = 2;

            ShowNeonTrendBars = true;
            AtrPeriod = 14;
            FastTrendEma = 20;
            SlowTrendEma = 50;
            BarWidth = 14;
            MinRangeTicks = 2;
            MaxRangeTicks = 80;
            NeonOpacity = 90;
            GlowSize = 5;
            UseBodyOnly = false;
        }
        else if (State == State.DataLoaded)
        {
            volProfile = new Dictionary<double, double>();
            tpoProfile = new Dictionary<double, int>();

            atr = ATR(AtrPeriod);
            fastEma = EMA(FastTrendEma);
            slowEma = EMA(SlowTrendEma);
        }
    }

    protected override void OnBarUpdate() { }

    private double RowSize()
    {
        return TickSize * Math.Max(1, RowSizeTicks);
    }

    private double RoundToRow(double price)
    {
        double row = RowSize();
        return Instrument.MasterInstrument.RoundToTickSize(Math.Round(price / row) * row);
    }

    private void AddRow(double price, double volume)
    {
        double p = RoundToRow(price);

        if (!volProfile.ContainsKey(p))
            volProfile[p] = 0;

        if (!tpoProfile.ContainsKey(p))
            tpoProfile[p] = 0;

        volProfile[p] += volume;
        tpoProfile[p]++;
    }

    private void BuildProfile()
    {
        volProfile.Clear();
        tpoProfile.Clear();

        if (ChartBars == null || Bars == null)
            return;

        int toIndex = Math.Min(ChartBars.ToIndex, CurrentBar);
        int fromIndex = Math.Max(0, toIndex - LookbackBars);

        for (int index = fromIndex; index <= toIndex; index++)
        {
            double high = High.GetValueAt(index);
            double low = Low.GetValueAt(index);
            double volume = Volume.GetValueAt(index);

            if (high <= low || volume <= 0)
                continue;

            double row = RowSize();
            int rows = Math.Max(1, (int)Math.Ceiling((high - low) / row));
            double volumePerRow = volume / rows;

            for (int i = 0; i <= rows; i++)
                AddRow(low + i * row, volumePerRow);
        }
    }

    private double GetScore(double price, double maxVol, int maxTPO)
    {
        double volNorm = maxVol > 0 ? volProfile[price] / maxVol : 0;
        double tpoNorm = maxTPO > 0 ? (double)tpoProfile[price] / maxTPO : 0;

        return volNorm * (1.0 - TPOWeight / 100.0) + tpoNorm * (TPOWeight / 100.0);
    }

    private int CurrentTrendState()
    {
        if (fastEma == null || slowEma == null || CurrentBar < Math.Max(FastTrendEma, SlowTrendEma))
            return 0;

        double fast = fastEma.GetValueAt(CurrentBar);
        double slow = slowEma.GetValueAt(CurrentBar);

        if (fast > slow)
            return 1;

        if (fast < slow)
            return -1;

        return 0;
    }

    protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
    {
        base.OnRender(chartControl, chartScale);

        if (ChartPanel == null || ChartBars == null || Bars == null || RenderTarget == null)
            return;

        DrawVolumeTPOHeatMap(chartScale);

        if (ShowNeonTrendBars)
            DrawNeonTrendBars(chartControl, chartScale);
    }

    private void DrawVolumeTPOHeatMap(ChartScale chartScale)
    {
        BuildProfile();

        if (volProfile.Count == 0)
            return;

        double maxVol = 0;
        int maxTPO = 0;

        foreach (double price in volProfile.Keys)
        {
            maxVol = Math.Max(maxVol, volProfile[price]);
            maxTPO = Math.Max(maxTPO, tpoProfile[price]);
        }

        float panelLeft = ChartPanel.X;
        float panelRight = ChartPanel.X + ChartPanel.W;
        float panelTop = ChartPanel.Y;
        float panelBottom = ChartPanel.Y + ChartPanel.H;

        double pocPrice = 0;
        double bestScore = 0;
        double totalScore = 0;

        foreach (double price in volProfile.Keys)
        {
            double score = GetScore(price, maxVol, maxTPO);
            totalScore += score;

            if (score > bestScore)
            {
                bestScore = score;
                pocPrice = price;
            }
        }

        double vah = pocPrice;
        double val = pocPrice;

        if (ShowValueArea && totalScore > 0 && pocPrice > 0)
        {
            List<double> prices = new List<double>(volProfile.Keys);
            prices.Sort();

            int pocIndex = prices.IndexOf(pocPrice);
            int lowIndex = pocIndex;
            int highIndex = pocIndex;

            double collected = bestScore;
            double target = totalScore * (ValueAreaPercent / 100.0);

            while (collected < target && (lowIndex > 0 || highIndex < prices.Count - 1))
            {
                double lowScore = lowIndex > 0 ? GetScore(prices[lowIndex - 1], maxVol, maxTPO) : -1;
                double highScore = highIndex < prices.Count - 1 ? GetScore(prices[highIndex + 1], maxVol, maxTPO) : -1;

                if (highScore >= lowScore)
                {
                    highIndex++;
                    collected += Math.Max(0, highScore);
                }
                else
                {
                    lowIndex--;
                    collected += Math.Max(0, lowScore);
                }
            }

            val = prices[lowIndex];
            vah = prices[highIndex];
        }

        int trend = CurrentTrendState();

        foreach (double price in volProfile.Keys)
        {
            double score = GetScore(price, maxVol, maxTPO);

            float y1 = chartScale.GetYByValue(price + RowSize() * 0.5);
            float y2 = chartScale.GetYByValue(price - RowSize() * 0.5);

            float top = Math.Min(y1, y2);
            float bottom = Math.Max(y1, y2);

            if (bottom < panelTop || top > panelBottom)
                continue;

            top = Math.Max(top, panelTop);
            bottom = Math.Min(bottom, panelBottom);

            int alpha = Math.Max(15, (int)(MaxOpacity * score));

            SharpDX.Color heatColor;

            if (TrendMatchedColors)
            {
                if (trend > 0)
                    heatColor = new SharpDX.Color((byte)0, (byte)180, (byte)255, (byte)alpha);
                else if (trend < 0)
                    heatColor = new SharpDX.Color((byte)255, (byte)70, (byte)0, (byte)alpha);
                else
                    heatColor = new SharpDX.Color((byte)160, (byte)80, (byte)255, (byte)alpha);
            }
            else
            {
                if (score < 0.25)
                    heatColor = new SharpDX.Color((byte)0, (byte)80, (byte)160, (byte)alpha);
                else if (score < 0.50)
                    heatColor = new SharpDX.Color((byte)0, (byte)180, (byte)255, (byte)alpha);
                else if (score < 0.75)
                    heatColor = new SharpDX.Color((byte)255, (byte)180, (byte)0, (byte)alpha);
                else
                    heatColor = new SharpDX.Color((byte)255, (byte)0, (byte)0, (byte)alpha);
            }

            using (var brush = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, heatColor))
            {
                RenderTarget.FillRectangle(
                    new RectangleF(panelLeft, top, panelRight - panelLeft, Math.Max(4f, bottom - top)),
                    brush
                );
            }

            if (ShowVolumeProfileBars && maxVol > 0)
            {
                float profileRight = panelRight - ProfileBarRightOffset;
                float width = (float)(ProfileBarMaxWidth * (volProfile[price] / maxVol));
                float profileLeft = profileRight - width;

                float h = Math.Max(4f, bottom - top);

                bool isPocRow = Math.Abs(price - pocPrice) < RowSize() * 0.5;

                if (isPocRow && ShowPOCBar)
                    h *= POCBarThickness;

                RectangleF barRect = new RectangleF(profileLeft, top, width, h);

                if (TrendMatchedColors)
                    DrawTrendMatchedProfileBar(barRect, trend, ProfileBarOpacity, isPocRow);
                else
                    DrawDefaultProfileBar(barRect, score, isPocRow);
            }
        }
        SharpDX.Color lineColor;

        if (TrendMatchedColors)
        {
            if (trend > 0)
                lineColor = new SharpDX.Color((byte)0, (byte)255, (byte)255, (byte)230);
            else if (trend < 0)
                lineColor = new SharpDX.Color((byte)255, (byte)150, (byte)0, (byte)230);
            else
                lineColor = new SharpDX.Color((byte)190, (byte)100, (byte)255, (byte)230);
        }
        else
        {
            lineColor = new SharpDX.Color((byte)0, (byte)255, (byte)255, (byte)210);
        }

        if (ShowValueArea && val > 0 && vah > 0)
        {
            DrawLine(chartScale, vah, panelLeft, panelRight, lineColor, 2f);
            DrawLine(chartScale, val, panelLeft, panelRight, lineColor, 2f);

            if (ShowValueAreaLabels)
            {
                DrawText(chartScale, "VAH " + vah.ToString("0.00"), vah, panelRight - 155, lineColor);
                DrawText(chartScale, "VAL " + val.ToString("0.00"), val, panelRight - 155, lineColor);
            }
        }

        if (ShowPOC && pocPrice > 0)
        {
            SharpDX.Color pocColor;

            if (TrendMatchedColors)
            {
                if (trend > 0)
                    pocColor = new SharpDX.Color((byte)255, (byte)255, (byte)255, (byte)245);
                else if (trend < 0)
                    pocColor = new SharpDX.Color((byte)255, (byte)230, (byte)120, (byte)245);
                else
                    pocColor = new SharpDX.Color((byte)230, (byte)180, (byte)255, (byte)245);
            }
            else
            {
                pocColor = new SharpDX.Color((byte)255, (byte)255, (byte)255, (byte)230);
            }

            DrawLine(chartScale, pocPrice, panelLeft, panelRight, pocColor, 2.5f);

            if (ShowPOCLabel)
                DrawText(chartScale, "POC " + pocPrice.ToString("0.00"), pocPrice, panelRight - 155, pocColor);
        }
    }

    private void DrawDefaultProfileBar(RectangleF rect, double score, bool isPoc)
    {
        SharpDX.Color color;

        if (isPoc)
            color = new SharpDX.Color((byte)255, (byte)255, (byte)255, (byte)240);
        else if (score >= 0.75)
            color = new SharpDX.Color((byte)255, (byte)0, (byte)0, (byte)ProfileBarOpacity);
        else if (score >= 0.50)
            color = new SharpDX.Color((byte)255, (byte)180, (byte)0, (byte)ProfileBarOpacity);
        else
            color = new SharpDX.Color((byte)0, (byte)180, (byte)255, (byte)ProfileBarOpacity);

        using (var brush = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, color))
            RenderTarget.FillRectangle(rect, brush);
    }

    private void DrawTrendMatchedProfileBar(RectangleF rect, int trend, int opacity, bool isPoc)
    {
        float a = Math.Max(0.05f, Math.Min(1f, opacity / 255f));

        SharpDX.Direct2D1.GradientStop[] stopsArray;

        if (trend > 0)
        {
            stopsArray = new SharpDX.Direct2D1.GradientStop[]
            {
                new SharpDX.Direct2D1.GradientStop { Position = 0.00f, Color = new Color4(0.00f, 0.10f, 0.40f, a) },
                new SharpDX.Direct2D1.GradientStop { Position = 0.30f, Color = new Color4(0.00f, 0.35f, 1.00f, a) },
                new SharpDX.Direct2D1.GradientStop { Position = 0.65f, Color = new Color4(0.00f, 0.85f, 1.00f, a) },
                new SharpDX.Direct2D1.GradientStop { Position = 1.00f, Color = isPoc ? new Color4(1.00f, 1.00f, 1.00f, a) : new Color4(0.00f, 1.00f, 0.65f, a) }
            };
        }
        else if (trend < 0)
        {
            stopsArray = new SharpDX.Direct2D1.GradientStop[]
            {
                new SharpDX.Direct2D1.GradientStop { Position = 0.00f, Color = new Color4(0.30f, 0.00f, 0.00f, a) },
                new SharpDX.Direct2D1.GradientStop { Position = 0.30f, Color = new Color4(0.75f, 0.00f, 0.00f, a) },
                new SharpDX.Direct2D1.GradientStop { Position = 0.65f, Color = new Color4(1.00f, 0.20f, 0.00f, a) },
                new SharpDX.Direct2D1.GradientStop { Position = 1.00f, Color = isPoc ? new Color4(1.00f, 1.00f, 0.00f, a) : new Color4(1.00f, 0.55f, 0.00f, a) }
            };
        }
        else
        {
            stopsArray = new SharpDX.Direct2D1.GradientStop[]
            {
                new SharpDX.Direct2D1.GradientStop { Position = 0.00f, Color = new Color4(0.12f, 0.12f, 0.12f, a) },
                new SharpDX.Direct2D1.GradientStop { Position = 0.50f, Color = new Color4(0.50f, 0.00f, 0.75f, a) },
                new SharpDX.Direct2D1.GradientStop { Position = 1.00f, Color = isPoc ? new Color4(1.00f, 1.00f, 1.00f, a) : new Color4(0.85f, 0.85f, 0.85f, a) }
            };
        }

        SharpDX.Direct2D1.GradientStopCollection stops = null;
        SharpDX.Direct2D1.LinearGradientBrush gradient = null;

        try
        {
            stops = new SharpDX.Direct2D1.GradientStopCollection(RenderTarget, stopsArray);

            gradient = new SharpDX.Direct2D1.LinearGradientBrush(
                RenderTarget,
                new SharpDX.Direct2D1.LinearGradientBrushProperties
                {
                    StartPoint = new Vector2(rect.Left, rect.Top),
                    EndPoint = new Vector2(rect.Right, rect.Top)
                },
                stops
            );

            RenderTarget.FillRectangle(rect, gradient);
        }
        finally
        {
            if (gradient != null) gradient.Dispose();
            if (stops != null) stops.Dispose();
        }
    }

    private void DrawLine(ChartScale chartScale, double price, float x1, float x2, SharpDX.Color color, float width)
    {
        float y = chartScale.GetYByValue(price);

        using (var brush = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, color))
            RenderTarget.DrawLine(new Vector2(x1, y), new Vector2(x2, y), brush, width);
    }

    private void DrawText(ChartScale chartScale, string text, double price, float x, SharpDX.Color color)
    {
        float y = chartScale.GetYByValue(price) - 10;

        using (var brush = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, color))
        using (var format = new SharpDX.DirectWrite.TextFormat(Core.Globals.DirectWriteFactory, "Arial", 13))
            RenderTarget.DrawText(text, format, new RectangleF(x, y, 150, 24), brush);
    }

    private void DrawNeonTrendBars(ChartControl chartControl, ChartScale chartScale)
    {
        int minBars = Math.Max(SlowTrendEma, AtrPeriod) + 2;

        for (int i = ChartBars.FromIndex; i <= ChartBars.ToIndex; i++)
        {
            if (i < minBars || i > CurrentBar)
                continue;

            double open = Opens[0].GetValueAt(i);
            double high = Highs[0].GetValueAt(i);
            double low = Lows[0].GetValueAt(i);
            double close = Closes[0].GetValueAt(i);

            double fast = fastEma.GetValueAt(i);
            double slow = slowEma.GetValueAt(i);

            bool upTrend = fast > slow;
            bool downTrend = fast < slow;

            double rangeTicks = (high - low) / TickSize;

            if (rangeTicks < MinRangeTicks)
                continue;

            double topPrice = UseBodyOnly ? Math.Max(open, close) : high;
            double bottomPrice = UseBodyOnly ? Math.Min(open, close) : low;

            float x = chartControl.GetXByBarIndex(ChartBars, i);
            float yTop = chartScale.GetYByValue(topPrice);
            float yBottom = chartScale.GetYByValue(bottomPrice);

            float top = Math.Min(yTop, yBottom);
            float height = Math.Abs(yBottom - yTop);

            if (height < 10)
                height = 10;

            double strength = rangeTicks / MaxRangeTicks;
            strength = Math.Max(0.15, Math.Min(1.0, strength));

            float alpha = (float)(strength * (NeonOpacity / 100.0));

            DrawTrendHeatBar(x, top, height, alpha, upTrend, downTrend);
        }
    }

    private void DrawTrendHeatBar(float x, float top, float height, float alpha, bool upTrend, bool downTrend)
    {
        float width = BarWidth;
        float left = x - width;
        float rectWidth = width * 2f;

        RectangleF glowRect = new RectangleF(left - GlowSize, top - GlowSize, rectWidth + GlowSize * 2, height + GlowSize * 2);
        RectangleF mainRect = new RectangleF(left, top, rectWidth, height);

        SharpDX.Direct2D1.RoundedRectangle glowRound = new SharpDX.Direct2D1.RoundedRectangle
        {
            Rect = glowRect,
            RadiusX = width + GlowSize,
            RadiusY = width + GlowSize
        };

        SharpDX.Direct2D1.RoundedRectangle mainRound = new SharpDX.Direct2D1.RoundedRectangle
        {
            Rect = mainRect,
            RadiusX = width,
            RadiusY = width
        };

        SharpDX.Direct2D1.GradientStopCollection stops = null;
        SharpDX.Direct2D1.LinearGradientBrush gradient = null;
        SharpDX.Direct2D1.SolidColorBrush glow = null;
        SharpDX.Direct2D1.SolidColorBrush outline = null;

        try
        {
            SharpDX.Direct2D1.GradientStop[] stopArray;

            if (upTrend)
            {
                stopArray = new SharpDX.Direct2D1.GradientStop[]
                {
                    new SharpDX.Direct2D1.GradientStop { Position = 0.00f, Color = new Color4(0.00f, 0.10f, 0.40f, alpha) },
                    new SharpDX.Direct2D1.GradientStop { Position = 0.25f, Color = new Color4(0.00f, 0.35f, 1.00f, alpha) },
                    new SharpDX.Direct2D1.GradientStop { Position = 0.50f, Color = new Color4(0.00f, 0.85f, 1.00f, alpha) },
                    new SharpDX.Direct2D1.GradientStop { Position = 0.75f, Color = new Color4(0.00f, 1.00f, 0.65f, alpha) },
                    new SharpDX.Direct2D1.GradientStop { Position = 1.00f, Color = new Color4(1.00f, 1.00f, 1.00f, alpha) }
                };

                glow = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, new Color4(0.00f, 0.85f, 1.00f, alpha * 0.25f));
                outline = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, new Color4(0.00f, 1.00f, 1.00f, alpha * 0.80f));
            }
            else if (downTrend)
            {
                stopArray = new SharpDX.Direct2D1.GradientStop[]
                {
                    new SharpDX.Direct2D1.GradientStop { Position = 0.00f, Color = new Color4(0.30f, 0.00f, 0.00f, alpha) },
                    new SharpDX.Direct2D1.GradientStop { Position = 0.25f, Color = new Color4(0.75f, 0.00f, 0.00f, alpha) },
                    new SharpDX.Direct2D1.GradientStop { Position = 0.50f, Color = new Color4(1.00f, 0.20f, 0.00f, alpha) },
                    new SharpDX.Direct2D1.GradientStop { Position = 0.75f, Color = new Color4(1.00f, 0.55f, 0.00f, alpha) },
                    new SharpDX.Direct2D1.GradientStop { Position = 1.00f, Color = new Color4(1.00f, 1.00f, 0.00f, alpha) }
                };

                glow = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, new Color4(1.00f, 0.25f, 0.00f, alpha * 0.25f));
                outline = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, new Color4(1.00f, 0.65f, 0.00f, alpha * 0.80f));
            }
            else
            {
                stopArray = new SharpDX.Direct2D1.GradientStop[]
                {
                    new SharpDX.Direct2D1.GradientStop { Position = 0.00f, Color = new Color4(0.12f, 0.12f, 0.12f, alpha) },
                    new SharpDX.Direct2D1.GradientStop { Position = 0.50f, Color = new Color4(0.50f, 0.00f, 0.75f, alpha) },
                    new SharpDX.Direct2D1.GradientStop { Position = 1.00f, Color = new Color4(0.85f, 0.85f, 0.85f, alpha) }
                };

                glow = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, new Color4(0.65f, 0.00f, 1.00f, alpha * 0.20f));
                outline = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, new Color4(0.80f, 0.45f, 1.00f, alpha * 0.70f));
            }

            stops = new SharpDX.Direct2D1.GradientStopCollection(RenderTarget, stopArray);

            gradient = new SharpDX.Direct2D1.LinearGradientBrush(
                RenderTarget,
                new SharpDX.Direct2D1.LinearGradientBrushProperties
                {
                    StartPoint = new Vector2(x, top),
                    EndPoint = new Vector2(x, top + height)
                },
                stops
            );

            RenderTarget.FillRoundedRectangle(glowRound, glow);
            RenderTarget.FillRoundedRectangle(mainRound, gradient);
            RenderTarget.DrawRoundedRectangle(mainRound, outline, 1.3f);
        }
        finally
        {
            if (outline != null) outline.Dispose();
            if (glow != null) glow.Dispose();
            if (gradient != null) gradient.Dispose();
            if (stops != null) stops.Dispose();
        }
    }
}

}

#region NinjaScript generated code. Neither change nor remove.

namespace NinjaTrader.NinjaScript.Indicators
{
public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
{
private WTVolumeTPOHeatMap cacheWTVolumeTPOHeatMap;
public WTVolumeTPOHeatMap WTVolumeTPOHeatMap(int lookbackBars, int rowSizeTicks, int tPOWeight, int maxOpacity, bool showPOC, bool showPOCLabel, bool showValueArea, int valueAreaPercent, bool showValueAreaLabels, bool trendMatchedColors, bool showVolumeProfileBars, int profileBarMaxWidth, int profileBarRightOffset, int profileBarOpacity, bool showPOCBar, int pOCBarThickness, bool showNeonTrendBars, int atrPeriod, int fastTrendEma, int slowTrendEma, int barWidth, int minRangeTicks, int maxRangeTicks, int neonOpacity, int glowSize, bool useBodyOnly)
{
return WTVolumeTPOHeatMap(Input, lookbackBars, rowSizeTicks, tPOWeight, maxOpacity, showPOC, showPOCLabel, showValueArea, valueAreaPercent, showValueAreaLabels, trendMatchedColors, showVolumeProfileBars, profileBarMaxWidth, profileBarRightOffset, profileBarOpacity, showPOCBar, pOCBarThickness, showNeonTrendBars, atrPeriod, fastTrendEma, slowTrendEma, barWidth, minRangeTicks, maxRangeTicks, neonOpacity, glowSize, useBodyOnly);
}

	public WTVolumeTPOHeatMap WTVolumeTPOHeatMap(ISeries<double> input, int lookbackBars, int rowSizeTicks, int tPOWeight, int maxOpacity, bool showPOC, bool showPOCLabel, bool showValueArea, int valueAreaPercent, bool showValueAreaLabels, bool trendMatchedColors, bool showVolumeProfileBars, int profileBarMaxWidth, int profileBarRightOffset, int profileBarOpacity, bool showPOCBar, int pOCBarThickness, bool showNeonTrendBars, int atrPeriod, int fastTrendEma, int slowTrendEma, int barWidth, int minRangeTicks, int maxRangeTicks, int neonOpacity, int glowSize, bool useBodyOnly)
	{
		if (cacheWTVolumeTPOHeatMap != null)
			for (int idx = 0; idx < cacheWTVolumeTPOHeatMap.Length; idx++)
				if (cacheWTVolumeTPOHeatMap[idx] != null && cacheWTVolumeTPOHeatMap[idx].LookbackBars == lookbackBars && cacheWTVolumeTPOHeatMap[idx].RowSizeTicks == rowSizeTicks && cacheWTVolumeTPOHeatMap[idx].TPOWeight == tPOWeight && cacheWTVolumeTPOHeatMap[idx].MaxOpacity == maxOpacity && cacheWTVolumeTPOHeatMap[idx].ShowPOC == showPOC && cacheWTVolumeTPOHeatMap[idx].ShowPOCLabel == showPOCLabel && cacheWTVolumeTPOHeatMap[idx].ShowValueArea == showValueArea && cacheWTVolumeTPOHeatMap[idx].ValueAreaPercent == valueAreaPercent && cacheWTVolumeTPOHeatMap[idx].ShowValueAreaLabels == showValueAreaLabels && cacheWTVolumeTPOHeatMap[idx].TrendMatchedColors == trendMatchedColors && cacheWTVolumeTPOHeatMap[idx].ShowVolumeProfileBars == showVolumeProfileBars && cacheWTVolumeTPOHeatMap[idx].ProfileBarMaxWidth == profileBarMaxWidth && cacheWTVolumeTPOHeatMap[idx].ProfileBarRightOffset == profileBarRightOffset && cacheWTVolumeTPOHeatMap[idx].ProfileBarOpacity == profileBarOpacity && cacheWTVolumeTPOHeatMap[idx].ShowPOCBar == showPOCBar && cacheWTVolumeTPOHeatMap[idx].POCBarThickness == pOCBarThickness && cacheWTVolumeTPOHeatMap[idx].ShowNeonTrendBars == showNeonTrendBars && cacheWTVolumeTPOHeatMap[idx].AtrPeriod == atrPeriod && cacheWTVolumeTPOHeatMap[idx].FastTrendEma == fastTrendEma && cacheWTVolumeTPOHeatMap[idx].SlowTrendEma == slowTrendEma && cacheWTVolumeTPOHeatMap[idx].BarWidth == barWidth && cacheWTVolumeTPOHeatMap[idx].MinRangeTicks == minRangeTicks && cacheWTVolumeTPOHeatMap[idx].MaxRangeTicks == maxRangeTicks && cacheWTVolumeTPOHeatMap[idx].NeonOpacity == neonOpacity && cacheWTVolumeTPOHeatMap[idx].GlowSize == glowSize && cacheWTVolumeTPOHeatMap[idx].UseBodyOnly == useBodyOnly && cacheWTVolumeTPOHeatMap[idx].EqualsInput(input))
					return cacheWTVolumeTPOHeatMap[idx];
		return CacheIndicator<WTVolumeTPOHeatMap>(new WTVolumeTPOHeatMap(){ LookbackBars = lookbackBars, RowSizeTicks = rowSizeTicks, TPOWeight = tPOWeight, MaxOpacity = maxOpacity, ShowPOC = showPOC, ShowPOCLabel = showPOCLabel, ShowValueArea = showValueArea, ValueAreaPercent = valueAreaPercent, ShowValueAreaLabels = showValueAreaLabels, TrendMatchedColors = trendMatchedColors, ShowVolumeProfileBars = showVolumeProfileBars, ProfileBarMaxWidth = profileBarMaxWidth, ProfileBarRightOffset = profileBarRightOffset, ProfileBarOpacity = profileBarOpacity, ShowPOCBar = showPOCBar, POCBarThickness = pOCBarThickness, ShowNeonTrendBars = showNeonTrendBars, AtrPeriod = atrPeriod, FastTrendEma = fastTrendEma, SlowTrendEma = slowTrendEma, BarWidth = barWidth, MinRangeTicks = minRangeTicks, MaxRangeTicks = maxRangeTicks, NeonOpacity = neonOpacity, GlowSize = glowSize, UseBodyOnly = useBodyOnly }, input, ref cacheWTVolumeTPOHeatMap);
	}
}

}

namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
{
public Indicators.WTVolumeTPOHeatMap WTVolumeTPOHeatMap(int lookbackBars, int rowSizeTicks, int tPOWeight, int maxOpacity, bool showPOC, bool showPOCLabel, bool showValueArea, int valueAreaPercent, bool showValueAreaLabels, bool trendMatchedColors, bool showVolumeProfileBars, int profileBarMaxWidth, int profileBarRightOffset, int profileBarOpacity, bool showPOCBar, int pOCBarThickness, bool showNeonTrendBars, int atrPeriod, int fastTrendEma, int slowTrendEma, int barWidth, int minRangeTicks, int maxRangeTicks, int neonOpacity, int glowSize, bool useBodyOnly)
{
return indicator.WTVolumeTPOHeatMap(Input, lookbackBars, rowSizeTicks, tPOWeight, maxOpacity, showPOC, showPOCLabel, showValueArea, valueAreaPercent, showValueAreaLabels, trendMatchedColors, showVolumeProfileBars, profileBarMaxWidth, profileBarRightOffset, profileBarOpacity, showPOCBar, pOCBarThickness, showNeonTrendBars, atrPeriod, fastTrendEma, slowTrendEma, barWidth, minRangeTicks, maxRangeTicks, neonOpacity, glowSize, useBodyOnly);
}

	public Indicators.WTVolumeTPOHeatMap WTVolumeTPOHeatMap(ISeries<double> input , int lookbackBars, int rowSizeTicks, int tPOWeight, int maxOpacity, bool showPOC, bool showPOCLabel, bool showValueArea, int valueAreaPercent, bool showValueAreaLabels, bool trendMatchedColors, bool showVolumeProfileBars, int profileBarMaxWidth, int profileBarRightOffset, int profileBarOpacity, bool showPOCBar, int pOCBarThickness, bool showNeonTrendBars, int atrPeriod, int fastTrendEma, int slowTrendEma, int barWidth, int minRangeTicks, int maxRangeTicks, int neonOpacity, int glowSize, bool useBodyOnly)
	{
		return indicator.WTVolumeTPOHeatMap(input, lookbackBars, rowSizeTicks, tPOWeight, maxOpacity, showPOC, showPOCLabel, showValueArea, valueAreaPercent, showValueAreaLabels, trendMatchedColors, showVolumeProfileBars, profileBarMaxWidth, profileBarRightOffset, profileBarOpacity, showPOCBar, pOCBarThickness, showNeonTrendBars, atrPeriod, fastTrendEma, slowTrendEma, barWidth, minRangeTicks, maxRangeTicks, neonOpacity, glowSize, useBodyOnly);
	}
}

}

namespace NinjaTrader.NinjaScript.Strategies
{
public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
{
public Indicators.WTVolumeTPOHeatMap WTVolumeTPOHeatMap(int lookbackBars, int rowSizeTicks, int tPOWeight, int maxOpacity, bool showPOC, bool showPOCLabel, bool showValueArea, int valueAreaPercent, bool showValueAreaLabels, bool trendMatchedColors, bool showVolumeProfileBars, int profileBarMaxWidth, int profileBarRightOffset, int profileBarOpacity, bool showPOCBar, int pOCBarThickness, bool showNeonTrendBars, int atrPeriod, int fastTrendEma, int slowTrendEma, int barWidth, int minRangeTicks, int maxRangeTicks, int neonOpacity, int glowSize, bool useBodyOnly)
{
return indicator.WTVolumeTPOHeatMap(Input, lookbackBars, rowSizeTicks, tPOWeight, maxOpacity, showPOC, showPOCLabel, showValueArea, valueAreaPercent, showValueAreaLabels, trendMatchedColors, showVolumeProfileBars, profileBarMaxWidth, profileBarRightOffset, profileBarOpacity, showPOCBar, pOCBarThickness, showNeonTrendBars, atrPeriod, fastTrendEma, slowTrendEma, barWidth, minRangeTicks, maxRangeTicks, neonOpacity, glowSize, useBodyOnly);
}

	public Indicators.WTVolumeTPOHeatMap WTVolumeTPOHeatMap(ISeries<double> input , int lookbackBars, int rowSizeTicks, int tPOWeight, int maxOpacity, bool showPOC, bool showPOCLabel, bool showValueArea, int valueAreaPercent, bool showValueAreaLabels, bool trendMatchedColors, bool showVolumeProfileBars, int profileBarMaxWidth, int profileBarRightOffset, int profileBarOpacity, bool showPOCBar, int pOCBarThickness, bool showNeonTrendBars, int atrPeriod, int fastTrendEma, int slowTrendEma, int barWidth, int minRangeTicks, int maxRangeTicks, int neonOpacity, int glowSize, bool useBodyOnly)
	{
		return indicator.WTVolumeTPOHeatMap(input, lookbackBars, rowSizeTicks, tPOWeight, maxOpacity, showPOC, showPOCLabel, showValueArea, valueAreaPercent, showValueAreaLabels, trendMatchedColors, showVolumeProfileBars, profileBarMaxWidth, profileBarRightOffset, profileBarOpacity, showPOCBar, pOCBarThickness, showNeonTrendBars, atrPeriod, fastTrendEma, slowTrendEma, barWidth, minRangeTicks, maxRangeTicks, neonOpacity, glowSize, useBodyOnly);
	}
}

}

#endregion

Groovy!

When I tried it, Fast/Slow EMA had the same values (value corresponded to current price, btw) so trend did not work.

[NeonBar] Bar 32819 | Fast: 30125.5000 | Slow: 30125.5000 | UpTrend: False | DownTrend: False
[NeonBar] Bar 32819 | Fast: 30125.5000 | Slow: 30125.5000 | UpTrend: False | DownTrend: False
[NeonBar] Bar 32819 | Fast: 30125.7500 | Slow: 30125.7500 | UpTrend: False | DownTrend: False

that’s weird, I’ll probably use a different method to add codes

2 Likes