#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 VP : Indicator { private const int TickBars = 1; private Dictionary volumeProfile = new Dictionary(); private int maxPixelWidth = 500; protected override void OnStateChange() { if (State == State.SetDefaults) { Description = @"Volume Profile"; Name = "Volume Profile"; Calculate = Calculate.OnEachTick; IsOverlay = true; DisplayInDataBox = true; DrawOnPricePanel = true; DrawHorizontalGridLines = true; DrawVerticalGridLines = true; PaintPriceMarkers = true; ScaleJustification = ScaleJustification.Right; IsSuspendedWhileInactive = false; ProfileColor = Brushes.DimGray; Opacity = 25; } else if (State == State.Configure) { AddDataSeries(Instrument.FullName, new BarsPeriod { BarsPeriodType = BarsPeriodType.Tick, Value = 1 }, Bars.TradingHours.Name); } else if (State == State.Historical) { SetZOrder(-1); // Display behind bars on chart. } } protected override void OnBarUpdate() { if (TickBars == BarsInProgress) { if (Bars.IsFirstBarOfSession) volumeProfile.Clear(); // Reset the volume profile for the new session. double lastPrice = Closes[TickBars][0]; if (!volumeProfile.ContainsKey(lastPrice)) volumeProfile[lastPrice] = 0; volumeProfile[lastPrice] += (long)Volumes[TickBars][0]; } } protected override void OnRender(ChartControl chartControl, ChartScale chartScale) { base.OnRender(chartControl, chartScale); Brush profileColorWithTransparency = new SolidColorBrush( Color.FromArgb((byte)(255 * (Opacity / 100.0)), ((SolidColorBrush)ProfileColor).Color.R, ((SolidColorBrush)ProfileColor).Color.G, ((SolidColorBrush)ProfileColor).Color.B) ); SharpDX.Direct2D1.Brush profileBrush = profileColorWithTransparency.ToDxBrush(RenderTarget); long maxVolume = volumeProfile.Values.Max(); double tickSize = Bars.Instrument.MasterInstrument.TickSize; foreach (var entry in volumeProfile) { double priceLevel = entry.Key; long volumeAtPrice = entry.Value; int yLower = chartScale.GetYByValue(priceLevel - tickSize / 2); int yUpper = chartScale.GetYByValue(priceLevel + tickSize / 2); int height = Math.Abs(yUpper - yLower); int barWidth = (int)((volumeAtPrice / (double)maxVolume) * maxPixelWidth); int startX = ChartPanel.X + ChartPanel.W - barWidth; RenderTarget.FillRectangle(new SharpDX.RectangleF(startX, yUpper, barWidth, height), profileBrush); } profileBrush.Dispose(); } public override string DisplayName { get { return Name; } } [Display(Name = "Profile Color", Description = "Color of the volume profile", Order = 1, GroupName = "Volume Profile")] public Brush ProfileColor { get; set; } [Display(Name = "Max Width (Pixels)", Description = "Maximum pixel width for volume bars", Order = 2, GroupName = "Volume Profile")] public int MaxPixelWidth { get { return maxPixelWidth; } set { maxPixelWidth = value; } } [Display(Name = "Opacity (%)", Description = "Opacity of volume profile", Order = 3, GroupName = "Volume Profile")] public int Opacity { get; set; } } } #region NinjaScript generated code. Neither change nor remove. namespace NinjaTrader.NinjaScript.Indicators { public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase { private VP[] cacheVP; public VP VP() { return VP(Input); } public VP VP(ISeries input) { if (cacheVP != null) for (int idx = 0; idx < cacheVP.Length; idx++) if (cacheVP[idx] != null && cacheVP[idx].EqualsInput(input)) return cacheVP[idx]; return CacheIndicator(new VP(), input, ref cacheVP); } } } namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns { public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase { public Indicators.VP VP() { return indicator.VP(Input); } public Indicators.VP VP(ISeries input ) { return indicator.VP(input); } } } namespace NinjaTrader.NinjaScript.Strategies { public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase { public Indicators.VP VP() { return indicator.VP(Input); } public Indicators.VP VP(ISeries input ) { return indicator.VP(input); } } } #endregion