├── .gitignore ├── DrawingTools └── irArrowLine.cs ├── ExportNinjaScript └── BigCandle.zip ├── Indicators ├── BigCandle.cs ├── ColumnPanel.cs ├── CumulativeDelta.cs ├── CumulativeDeltaDifference.cs ├── Delta.cs ├── FootprintChart.cs ├── Level2Column.cs ├── ProfileColumns.cs ├── Spread.cs ├── VolumeProfileColumn.cs └── ZipperLength.cs ├── SuperDomColumns ├── CurrentTrades.cs └── NumTouches.cs └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | @*.cs 2 | *.dll 3 | *.resx 4 | AssemblyInfo.cs 5 | NinjaTrader.Custom.csproj 6 | NinjaTrader.Custom.xml 7 | NinjaTrader.Vendor.cs 8 | Resource.Designer.cs 9 | ResourceEnumConverter.cs 10 | AddOns/PriceActionSwingBaseMethods.cs 11 | Indicators/JTRelativeVolumeNT8.cs 12 | Indicators/Poncho/PriceActionSwing.cs 13 | Indicators/Poncho/PriceActionSwingOscillator.cs 14 | Indicators/Sim22/Sim22_PriorAllOHLC.cs 15 | Indicators/unGomDelta. Bar Delta for tick replay.cs 16 | Indicators/unGomDelta.Cum Delta for tick replay.cs 17 | Indicators/unGomDelta.UnGomCumDeltaFiltered.cs 18 | -------------------------------------------------------------------------------- /DrawingTools/irArrowLine.cs: -------------------------------------------------------------------------------- 1 | //Originally created by Seth Ellis twdsje@gmail.com 2 | 3 | #region Using declarations 4 | using System; 5 | 6 | using System.Windows; 7 | using System.Windows.Input; 8 | 9 | using System.Collections.Generic; 10 | using System.ComponentModel; 11 | using System.ComponentModel.DataAnnotations; 12 | using System.Linq; 13 | using System.Text; 14 | using System.Threading.Tasks; 15 | using System.Windows.Media; 16 | using System.Xml.Serialization; 17 | using NinjaTrader.Cbi; 18 | using NinjaTrader.Core; 19 | using NinjaTrader.Gui; 20 | using NinjaTrader.Gui.Chart; 21 | using NinjaTrader.Gui.SuperDom; 22 | using NinjaTrader.Gui.Tools; 23 | using NinjaTrader.Data; 24 | using NinjaTrader.NinjaScript; 25 | using NinjaTrader.Core.FloatingPoint; 26 | using SharpDX.DirectWrite; 27 | 28 | #endregion 29 | 30 | //This namespace holds Drawing tools in this folder and is required. Do not change it. 31 | namespace NinjaTrader.NinjaScript.DrawingTools 32 | { 33 | public class irArrowLine : ArrowLine 34 | { 35 | private TextFormat cachedTextFormat; 36 | private Gui.Tools.SimpleFont font; 37 | private bool Initalized; 38 | 39 | protected override void OnStateChange() 40 | { 41 | base.OnStateChange(); 42 | 43 | if (State == State.SetDefaults) 44 | { 45 | Description = @"An arrow line with a price marker attached."; 46 | Name = "irArrowLine"; 47 | 48 | Font = new Gui.Tools.SimpleFont() { Size = 14 }; 49 | TextColor = Stroke.Brush; 50 | Text = ""; 51 | } 52 | else if (State == State.Configure) 53 | { 54 | } 55 | } 56 | 57 | public void InitializeDrawingTools() 58 | { 59 | if(Initalized) return; 60 | 61 | cachedTextFormat = Font.ToDirectWriteTextFormat(); 62 | } 63 | 64 | public override void OnRender(ChartControl chartControl, ChartScale chartScale) 65 | { 66 | base.OnRender(chartControl, chartScale); 67 | 68 | InitializeDrawingTools(); 69 | 70 | //Calculate where to draw the text. 71 | //Refer to parent class Lines.cs OnRender method for more information. 72 | ChartPanel panel = chartControl.ChartPanels[chartScale.PanelIndex]; 73 | double strokePixAdj = ((double)(Stroke.Width % 2)).ApproxCompare(0) == 0 ? 0.5d : 0d; 74 | Vector pixelAdjustVec = new Vector(strokePixAdj, strokePixAdj); 75 | 76 | Point endPoint = EndAnchor.GetPoint(chartControl, panel, chartScale); 77 | Point endPointAdjusted = endPoint + pixelAdjustVec; 78 | SharpDX.Vector2 endVec = endPointAdjusted.ToVector2(); 79 | 80 | //Calculate the current price. 81 | string text = (Text != "" ? Text : chartControl.Instrument.MasterInstrument.FormatPrice(chartScale.GetValueByY(endVec.Y), true)); 82 | 83 | //Set properties for rectangle to draw the object. 84 | TextLayout tl = new TextLayout(Core.Globals.DirectWriteFactory, text, cachedTextFormat, ChartPanel.W, ChartPanel.H); 85 | SharpDX.RectangleF rect = new SharpDX.RectangleF(); 86 | rect.X = (float)endVec.X; 87 | rect.Y = (float)endVec.Y - 6f; 88 | rect.Width = (float)-(tl.Metrics.Width); 89 | rect.Height = (float)-(tl.Metrics.Height); 90 | 91 | //Draw the text. 92 | using(SharpDX.Direct2D1.Brush myDxBrush = TextColor.ToDxBrush(RenderTarget)) 93 | { 94 | chartScale.GetValueByY(endVec.Y);RenderTarget.DrawText(string.Format("{0}", text), cachedTextFormat, rect, myDxBrush); 95 | } 96 | } 97 | 98 | [Display(ResourceType = typeof(Custom.Resource), Name = "Text", GroupName = "Label")] 99 | public string Text 100 | { get; set; } 101 | 102 | [Display(ResourceType = typeof(Custom.Resource), Name = "NinjaScriptDrawingToolTextFont", GroupName = "Label")] 103 | public Gui.Tools.SimpleFont Font 104 | { 105 | get { return font; } 106 | set 107 | { 108 | font = value; 109 | Initalized = false; 110 | } 111 | } 112 | 113 | [NinjaScriptProperty] 114 | [XmlIgnore] 115 | [Display(Name = "Text Color", GroupName = "Label")] 116 | public Brush TextColor 117 | { get; set; } 118 | 119 | [Browsable(false)] 120 | public string TextColorSerializable 121 | { 122 | get { return Serialize.BrushToString(TextColor); } 123 | set { TextColor = Serialize.StringToBrush(value); } 124 | } 125 | 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /ExportNinjaScript/BigCandle.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twdsje/Ninjatrader-scripts/1e77d93515fbb5ea3e9cc4d02a6daf7acae366b0/ExportNinjaScript/BigCandle.zip -------------------------------------------------------------------------------- /Indicators/BigCandle.cs: -------------------------------------------------------------------------------- 1 | #region Using declarations 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Xml.Serialization; 13 | using NinjaTrader.Cbi; 14 | using NinjaTrader.Gui; 15 | using NinjaTrader.Gui.Chart; 16 | using NinjaTrader.Gui.SuperDom; 17 | using NinjaTrader.Gui.Tools; 18 | using NinjaTrader.Data; 19 | using NinjaTrader.NinjaScript; 20 | using NinjaTrader.Core.FloatingPoint; 21 | using NinjaTrader.NinjaScript.DrawingTools; 22 | #endregion 23 | 24 | //This namespace holds Indicators in this folder and is required. Do not change it. 25 | namespace NinjaTrader.NinjaScript.Indicators 26 | { 27 | public class BigCandle : Indicator 28 | { 29 | private double priorSum; 30 | private double sum; 31 | 32 | protected override void OnStateChange() 33 | { 34 | if (State == State.SetDefaults) 35 | { 36 | Description = @"Indicator to help highlight candles that have an unusualy high range."; 37 | Name = "BigCandle"; 38 | Calculate = Calculate.OnPriceChange; 39 | IsOverlay = false; 40 | DisplayInDataBox = true; 41 | DrawOnPricePanel = false; 42 | DrawHorizontalGridLines = true; 43 | DrawVerticalGridLines = true; 44 | PaintPriceMarkers = false; 45 | ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right; 46 | //Disable this property if your indicator requires custom values that cumulate with each new market data event. 47 | //See Help Guide for additional information. 48 | IsSuspendedWhileInactive = true; 49 | DeviationFactor = 2; 50 | Period = 15; 51 | DeviationPeriod = 1500; 52 | AlertEnabled = false; 53 | AlertPriority = Priority.Medium; 54 | AlertRearm = 300; 55 | DrawArrows = true; 56 | Highlight = Brushes.Aquamarine; 57 | AddPlot(new Stroke(Brushes.DimGray, 2), PlotStyle.Bar, "Range"); 58 | AddPlot(Brushes.MidnightBlue, "AverageRange"); 59 | AddPlot(Brushes.SlateBlue, "RangeDeviation"); 60 | } 61 | else if (State == State.Configure) 62 | { 63 | } 64 | } 65 | 66 | protected override void OnBarUpdate() 67 | { 68 | //Add your custom indicator logic here. 69 | Range[0] = High[0] - Low[0]; 70 | 71 | double currentDeviation; 72 | 73 | if(Bars.IsFirstBarOfSession) 74 | { 75 | AverageRange[0] = WMA(Range, Period)[0]; 76 | currentDeviation = StdDev(Range, DeviationPeriod)[0]; 77 | } 78 | else 79 | { 80 | AverageRange[0] = WMA(Range, Period)[0]; 81 | currentDeviation = StdDev(Range, DeviationPeriod)[1]; 82 | } 83 | 84 | RangeDeviation[0] = AverageRange[0] + currentDeviation * DeviationFactor; 85 | 86 | if(Range[0] > RangeDeviation[0]) 87 | { 88 | PlotBrushes[0][0] = Highlight; 89 | 90 | if(DrawArrows) 91 | { 92 | DrawOnPricePanel = true; 93 | Draw.ArrowUp(this, "BigCandle " + Time[0].ToString(), true, 0, Low[0], Highlight); 94 | DrawOnPricePanel = false; 95 | } 96 | 97 | if(AlertEnabled) 98 | Alert("BigCandle", AlertPriority, "Unusual price movement", NinjaTrader.Core.Globals.InstallDir+@"\sounds\Alert1.wav", AlertRearm, Brushes.Black, Highlight); 99 | } 100 | 101 | } 102 | 103 | #region Properties 104 | [Range(1, int.MaxValue)] 105 | [NinjaScriptProperty] 106 | [Display(Name="Deviation Factor", Description="Number of standard deviations required to highlight a bar as unusual.", Order=1, GroupName="Parameters")] 107 | public double DeviationFactor 108 | { get; set; } 109 | 110 | [Range(1, int.MaxValue)] 111 | [NinjaScriptProperty] 112 | [Display(Name = "Period", GroupName = "Parameters", Order = 1)] 113 | public int Period 114 | { get; set; } 115 | 116 | [Range(1, int.MaxValue)] 117 | [NinjaScriptProperty] 118 | [Display(Name = "Deviation Period", GroupName = "Parameters", Order = 1)] 119 | public int DeviationPeriod 120 | { get; set; } 121 | 122 | [XmlIgnore()] 123 | [Display(Name = "Highlight Color", GroupName = "Parameters", Order = 3)] 124 | public SolidColorBrush Highlight 125 | { get; set; } 126 | 127 | [Browsable(false)] 128 | public string HighlightSerialize 129 | { 130 | get { return Serialize.BrushToString(Highlight); } 131 | set { Highlight = (SolidColorBrush)Serialize.StringToBrush(value); } 132 | } 133 | 134 | [Display(Name = "Show Markers", GroupName = "Parameters", Order = 4)] 135 | public bool DrawArrows 136 | { get; set;} 137 | 138 | [Display(Name = "Enable Alerts", GroupName = "Alert", Order = 0)] 139 | public bool AlertEnabled 140 | { get; set;} 141 | 142 | [Display(Name = "Priority", GroupName = "Alert", Order = 0)] 143 | public Priority AlertPriority 144 | { get; set;} 145 | 146 | [Range(1, int.MaxValue)] 147 | [Display(Name="Alert Rearm Time", Description="How long before this alert can be triggered again.", Order=1, GroupName="Alert")] 148 | public int AlertRearm 149 | { get; set; } 150 | 151 | [Browsable(false)] 152 | [XmlIgnore] 153 | public Series Range 154 | { 155 | get { return Values[0]; } 156 | } 157 | 158 | [Browsable(false)] 159 | [XmlIgnore] 160 | public Series AverageRange 161 | { 162 | get { return Values[1]; } 163 | } 164 | 165 | [Browsable(false)] 166 | [XmlIgnore] 167 | public Series RangeDeviation 168 | { 169 | get { return Values[2]; } 170 | } 171 | #endregion 172 | 173 | } 174 | } 175 | 176 | #region NinjaScript generated code. Neither change nor remove. 177 | 178 | namespace NinjaTrader.NinjaScript.Indicators 179 | { 180 | public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase 181 | { 182 | private BigCandle[] cacheBigCandle; 183 | public BigCandle BigCandle(double deviationFactor, int period, int deviationPeriod) 184 | { 185 | return BigCandle(Input, deviationFactor, period, deviationPeriod); 186 | } 187 | 188 | public BigCandle BigCandle(ISeries input, double deviationFactor, int period, int deviationPeriod) 189 | { 190 | if (cacheBigCandle != null) 191 | for (int idx = 0; idx < cacheBigCandle.Length; idx++) 192 | if (cacheBigCandle[idx] != null && cacheBigCandle[idx].DeviationFactor == deviationFactor && cacheBigCandle[idx].Period == period && cacheBigCandle[idx].DeviationPeriod == deviationPeriod && cacheBigCandle[idx].EqualsInput(input)) 193 | return cacheBigCandle[idx]; 194 | return CacheIndicator(new BigCandle(){ DeviationFactor = deviationFactor, Period = period, DeviationPeriod = deviationPeriod }, input, ref cacheBigCandle); 195 | } 196 | } 197 | } 198 | 199 | namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns 200 | { 201 | public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase 202 | { 203 | public Indicators.BigCandle BigCandle(double deviationFactor, int period, int deviationPeriod) 204 | { 205 | return indicator.BigCandle(Input, deviationFactor, period, deviationPeriod); 206 | } 207 | 208 | public Indicators.BigCandle BigCandle(ISeries input , double deviationFactor, int period, int deviationPeriod) 209 | { 210 | return indicator.BigCandle(input, deviationFactor, period, deviationPeriod); 211 | } 212 | } 213 | } 214 | 215 | namespace NinjaTrader.NinjaScript.Strategies 216 | { 217 | public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase 218 | { 219 | public Indicators.BigCandle BigCandle(double deviationFactor, int period, int deviationPeriod) 220 | { 221 | return indicator.BigCandle(Input, deviationFactor, period, deviationPeriod); 222 | } 223 | 224 | public Indicators.BigCandle BigCandle(ISeries input , double deviationFactor, int period, int deviationPeriod) 225 | { 226 | return indicator.BigCandle(input, deviationFactor, period, deviationPeriod); 227 | } 228 | } 229 | } 230 | 231 | #endregion 232 | -------------------------------------------------------------------------------- /Indicators/ColumnPanel.cs: -------------------------------------------------------------------------------- 1 | #region Using declarations 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Media; 10 | using System.Xml.Serialization; 11 | using NinjaTrader.Cbi; 12 | using NinjaTrader.Core; 13 | using NinjaTrader.Gui; 14 | using NinjaTrader.Gui.Chart; 15 | using NinjaTrader.Gui.SuperDom; 16 | using NinjaTrader.Gui.Tools; 17 | using NinjaTrader.Data; 18 | using NinjaTrader.NinjaScript; 19 | using NinjaTrader.Core.FloatingPoint; 20 | using NinjaTrader.NinjaScript.DrawingTools; 21 | using SharpDX.DirectWrite; 22 | #endregion 23 | 24 | public enum Timeframe { Session, Week, Month, Never }; 25 | 26 | //This namespace holds Indicators in this folder and is required. Do not change it. 27 | namespace NinjaTrader.NinjaScript.Indicators 28 | { 29 | public class ColumnPanel : Indicator 30 | { 31 | protected override void OnStateChange() 32 | { 33 | if (State == State.SetDefaults) 34 | { 35 | Description = @"Enter the description for your new custom Indicator here."; 36 | Name = "ColumnPanel"; 37 | Calculate = Calculate.OnBarClose; 38 | IsOverlay = false; 39 | DisplayInDataBox = true; 40 | DrawOnPricePanel = true; 41 | DrawHorizontalGridLines = true; 42 | DrawVerticalGridLines = true; 43 | PaintPriceMarkers = true; 44 | ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right; 45 | //Disable this property if your indicator requires custom values that cumulate with each new market data event. 46 | //See Help Guide for additional information. 47 | IsSuspendedWhileInactive = true; 48 | 49 | textSize = 11; 50 | TextColor = Brushes.Black; 51 | LeftJustified = false; 52 | Resizable = false; 53 | IsInitalized = false; 54 | } 55 | else if (State == State.Historical) 56 | { 57 | if (ChartControl == null) return; 58 | 59 | InitalizeColumnPanel(ChartControl); 60 | InitializeLifetimeDrawingTools(); 61 | } 62 | else if (State == State.Terminated) 63 | { 64 | if (ChartControl == null) return; 65 | 66 | TerminateColumnPanel(ChartControl); 67 | } 68 | } 69 | 70 | protected override void OnBarUpdate() 71 | { 72 | //Add your custom indicator logic here. 73 | } 74 | 75 | public void InitalizeColumnPanel(ChartControl chartControl) 76 | { 77 | MinimumWidth = CalculateMinimumWidth(); 78 | MinimumTextHeight = CalculateMinimumTextHeight(); 79 | CurrentWidth = MinimumWidth + ResizableWidth; 80 | 81 | CalculatePosition(chartControl); 82 | 83 | if(LeftJustified) 84 | { 85 | //chartControl.Properties.BarMarginLeft += CurrentWidth; 86 | } 87 | else 88 | { 89 | chartControl.Properties.BarMarginRight = Position + CurrentWidth; 90 | } 91 | } 92 | 93 | public void TerminateColumnPanel(ChartControl chartControl) 94 | { 95 | if (ChartControl == null || IsInitalized != true) return; 96 | 97 | if(LeftJustified) 98 | { 99 | //chartControl.Properties.BarMarginLeft -= CurrentWidth; 100 | } 101 | else 102 | { 103 | chartControl.Properties.BarMarginRight -= CurrentWidth; 104 | } 105 | } 106 | 107 | public void InitializeLifetimeDrawingTools() 108 | { 109 | textFormat = new TextFormat(Globals.DirectWriteFactory, "Arial", FontWeight.Bold, FontStyle.Normal, FontStretch.Normal, textSize) 110 | { 111 | TextAlignment = TextAlignment.Trailing, //TextAlignment.Leading, 112 | WordWrapping = WordWrapping.NoWrap 113 | }; 114 | } 115 | 116 | public void OnWidthChanged() 117 | { 118 | 119 | } 120 | 121 | public void CalculatePosition(ChartControl chartControl) 122 | { 123 | Position = 0; 124 | 125 | //Adjust our position based on the width of all indicators on the same side of the chart that come before us. 126 | foreach (NinjaTrader.Gui.NinjaScript.IndicatorRenderBase indicator in chartControl.Indicators) 127 | { 128 | if(indicator is ColumnPanel && indicator.State != State.SetDefaults && indicator!= this) 129 | { 130 | ColumnPanel currentpanel = indicator as ColumnPanel; 131 | 132 | if(currentpanel.LeftJustified == LeftJustified) 133 | { 134 | Position += currentpanel.CurrentWidth; 135 | } 136 | } 137 | } 138 | } 139 | 140 | public int CalculateMinimumWidth() 141 | { 142 | return getTextWidth("99000") + 6; 143 | } 144 | 145 | public int CalculateMinimumTextHeight() 146 | { 147 | return getTextHeight("0") - 5; 148 | } 149 | 150 | private int getTextWidth(string text) 151 | { 152 | SimpleFont sf = new NinjaTrader.Gui.Tools.SimpleFont("Consolas", textSize); 153 | 154 | float textWidth = 0f; 155 | 156 | if(text.Length > 0) 157 | { 158 | TextFormat tf = new TextFormat(new SharpDX.DirectWrite.Factory(), sf.Family.ToString(), SharpDX.DirectWrite.FontWeight.Normal, SharpDX.DirectWrite.FontStyle.Normal, (float)sf.Size); 159 | TextLayout tl = new TextLayout(Core.Globals.DirectWriteFactory, text, tf, ChartPanel.W, ChartPanel.H); 160 | 161 | textWidth = tl.Metrics.Width; 162 | 163 | tf.Dispose(); 164 | tl.Dispose(); 165 | } 166 | 167 | return (int)textWidth; 168 | } 169 | 170 | private int getTextHeight(string text) 171 | { 172 | SimpleFont sf = new NinjaTrader.Gui.Tools.SimpleFont("Consolas", textSize); 173 | 174 | float textHeight = 0f; 175 | 176 | if(text.Length > 0) 177 | { 178 | TextFormat tf = new TextFormat(new SharpDX.DirectWrite.Factory(), sf.Family.ToString(), SharpDX.DirectWrite.FontWeight.Normal, SharpDX.DirectWrite.FontStyle.Normal, (float)sf.Size); 179 | TextLayout tl = new TextLayout(Core.Globals.DirectWriteFactory, text, tf, ChartPanel.W, ChartPanel.H); 180 | 181 | textHeight = tl.Metrics.Height; 182 | 183 | tf.Dispose(); 184 | tl.Dispose(); 185 | } 186 | 187 | return (int)textHeight; 188 | } 189 | 190 | // protected override void OnRender(ChartControl chartControl, ChartScale chartScale) 191 | // { 192 | // if(Bars == null || Bars.Instrument == null || IsInHitTest || CurrentBar < 1) { return; } 193 | 194 | //// if(!IsInitalized) 195 | //// { 196 | //// InitalizeColumnPanel(ChartControl); 197 | //// InitializeLifetimeDrawingTools(); 198 | //// IsInitalized = true; 199 | //// } 200 | 201 | // base.OnRender(chartControl, chartScale); 202 | // } 203 | 204 | #region Properties 205 | 206 | protected int MinimumWidth 207 | { get; set; } 208 | 209 | protected int CurrentWidth 210 | { get; set; } 211 | 212 | protected int ResizableWidth 213 | { get; set; } 214 | 215 | protected int Position 216 | { get; set; } 217 | 218 | protected bool Resizable 219 | { get; set; } 220 | 221 | protected TextFormat textFormat 222 | { get; set; } 223 | 224 | protected bool IsInitalized 225 | { get; set; } 226 | 227 | protected int MinimumTextHeight 228 | { get; set; } 229 | 230 | protected DateTime LastRender 231 | { get; set; } 232 | 233 | [NinjaScriptProperty] 234 | [XmlIgnore] 235 | [Display(Name = "Left Justified", GroupName = "Column Style")] 236 | public bool LeftJustified 237 | { get; set; } 238 | 239 | private int JustificationFactor 240 | { 241 | get 242 | { 243 | return (LeftJustified == false ? 1 : -1); 244 | } 245 | } 246 | 247 | [Range(1, int.MaxValue), NinjaScriptProperty] 248 | [Display(Name = "Text Size", GroupName = "Parameters", Order = 7)] 249 | public int textSize 250 | { get; set; } 251 | 252 | [NinjaScriptProperty] 253 | [XmlIgnore] 254 | [Display(Name = "Text Color", GroupName = "Parameters", Order = 9)] 255 | public Brush TextColor 256 | { get; set; } 257 | 258 | [Browsable(false)] 259 | public string TextColorSerializable 260 | { 261 | get { return Serialize.BrushToString(TextColor); } 262 | set { TextColor = Serialize.StringToBrush(value); } 263 | } 264 | 265 | #endregion 266 | } 267 | 268 | 269 | } 270 | 271 | #region NinjaScript generated code. Neither change nor remove. 272 | 273 | namespace NinjaTrader.NinjaScript.Indicators 274 | { 275 | public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase 276 | { 277 | private ColumnPanel[] cacheColumnPanel; 278 | public ColumnPanel ColumnPanel(bool leftJustified, int textSize, Brush textColor) 279 | { 280 | return ColumnPanel(Input, leftJustified, textSize, textColor); 281 | } 282 | 283 | public ColumnPanel ColumnPanel(ISeries input, bool leftJustified, int textSize, Brush textColor) 284 | { 285 | if (cacheColumnPanel != null) 286 | for (int idx = 0; idx < cacheColumnPanel.Length; idx++) 287 | if (cacheColumnPanel[idx] != null && cacheColumnPanel[idx].LeftJustified == leftJustified && cacheColumnPanel[idx].textSize == textSize && cacheColumnPanel[idx].TextColor == textColor && cacheColumnPanel[idx].EqualsInput(input)) 288 | return cacheColumnPanel[idx]; 289 | return CacheIndicator(new ColumnPanel(){ LeftJustified = leftJustified, textSize = textSize, TextColor = textColor }, input, ref cacheColumnPanel); 290 | } 291 | } 292 | } 293 | 294 | namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns 295 | { 296 | public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase 297 | { 298 | public Indicators.ColumnPanel ColumnPanel(bool leftJustified, int textSize, Brush textColor) 299 | { 300 | return indicator.ColumnPanel(Input, leftJustified, textSize, textColor); 301 | } 302 | 303 | public Indicators.ColumnPanel ColumnPanel(ISeries input , bool leftJustified, int textSize, Brush textColor) 304 | { 305 | return indicator.ColumnPanel(input, leftJustified, textSize, textColor); 306 | } 307 | } 308 | } 309 | 310 | namespace NinjaTrader.NinjaScript.Strategies 311 | { 312 | public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase 313 | { 314 | public Indicators.ColumnPanel ColumnPanel(bool leftJustified, int textSize, Brush textColor) 315 | { 316 | return indicator.ColumnPanel(Input, leftJustified, textSize, textColor); 317 | } 318 | 319 | public Indicators.ColumnPanel ColumnPanel(ISeries input , bool leftJustified, int textSize, Brush textColor) 320 | { 321 | return indicator.ColumnPanel(input, leftJustified, textSize, textColor); 322 | } 323 | } 324 | } 325 | 326 | #endregion 327 | -------------------------------------------------------------------------------- /Indicators/CumulativeDelta.cs: -------------------------------------------------------------------------------- 1 | #region Using declarations 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Xml.Serialization; 13 | using NinjaTrader.Cbi; 14 | using NinjaTrader.Gui; 15 | using NinjaTrader.Gui.Chart; 16 | using NinjaTrader.Gui.SuperDom; 17 | using NinjaTrader.Gui.Tools; 18 | using NinjaTrader.Data; 19 | using NinjaTrader.NinjaScript; 20 | using NinjaTrader.Core.FloatingPoint; 21 | using NinjaTrader.NinjaScript.DrawingTools; 22 | #endregion 23 | 24 | public enum CumulativeDeltaTimeframe { Session, Week, Month, Never }; 25 | 26 | //This namespace holds Indicators in this folder and is required. Do not change it. 27 | namespace NinjaTrader.NinjaScript.Indicators 28 | { 29 | 30 | 31 | public class CumulativeDelta : Indicator 32 | { 33 | public class Profile 34 | { 35 | public long CurrentCumulativeDelta; 36 | 37 | public Profile() 38 | { 39 | CurrentCumulativeDelta = 0; 40 | } 41 | 42 | public void AddAskVolume(double price, long volume) 43 | { 44 | CurrentCumulativeDelta += volume; 45 | } 46 | 47 | public void AddBidVolume(double price, long volume) 48 | { 49 | CurrentCumulativeDelta -= volume; 50 | } 51 | } 52 | 53 | private Profile myProfile = new Profile(); 54 | private SessionIterator sessionIterator; 55 | 56 | protected override void OnStateChange() 57 | { 58 | if (State == State.SetDefaults) 59 | { 60 | Description = @"Enter the description for your new custom Indicator here."; 61 | Name = "CumulativeDelta"; 62 | Calculate = Calculate.OnBarClose; 63 | IsOverlay = false; 64 | DisplayInDataBox = true; 65 | DrawOnPricePanel = true; 66 | DrawHorizontalGridLines = true; 67 | DrawVerticalGridLines = true; 68 | PaintPriceMarkers = true; 69 | ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right; 70 | //Disable this property if your indicator requires custom values that cumulate with each new market data event. 71 | //See Help Guide for additional information. 72 | IsSuspendedWhileInactive = true; 73 | AddPlot(Brushes.CornflowerBlue, "CumDelta"); 74 | 75 | ResetDeltaOn = CumulativeDeltaTimeframe.Never; 76 | } 77 | else if (State == State.Configure) 78 | { 79 | sessionIterator = new SessionIterator(Bars); 80 | } 81 | } 82 | 83 | protected override void OnBarUpdate() 84 | { 85 | 86 | if(CurrentBars[0] <= BarsRequiredToPlot) return; 87 | 88 | //Reset profile on session week or day. 89 | if(IsFirstTickOfBar && ResetDeltaOn != CumulativeDeltaTimeframe.Never) 90 | { 91 | DateTime previous = sessionIterator.GetTradingDay(Time[1]); 92 | DateTime current = sessionIterator.GetTradingDay(Time[0]); 93 | 94 | //Reset profile on daily basis. 95 | if(ResetDeltaOn == CumulativeDeltaTimeframe.Session && !current.DayOfWeek.Equals(previous.DayOfWeek)) 96 | { 97 | myProfile = new Profile(); 98 | } 99 | 100 | //Reset profile on weekly basis. 101 | else if(ResetDeltaOn == CumulativeDeltaTimeframe.Week && current.DayOfWeek.CompareTo(previous.DayOfWeek) < 0) 102 | { 103 | myProfile = new Profile(); 104 | } 105 | 106 | //Reset profile on monthly basis. 107 | else if(ResetDeltaOn != CumulativeDeltaTimeframe.Month && !current.Month.Equals(previous.Month)) 108 | { 109 | myProfile = new Profile(); 110 | } 111 | } 112 | 113 | Value[0] = myProfile.CurrentCumulativeDelta; 114 | } 115 | 116 | protected override void OnMarketData(MarketDataEventArgs e) 117 | { 118 | if (e.MarketDataType == MarketDataType.Last) 119 | { 120 | if (e.Price >= e.Ask) 121 | { 122 | myProfile.AddAskVolume(e.Price, e.Volume); 123 | } 124 | else if(e.Price <= e.Bid) 125 | { 126 | myProfile.AddBidVolume(e.Price, e.Volume); 127 | } 128 | } 129 | } 130 | 131 | #region Properties 132 | 133 | [XmlIgnore] 134 | [NinjaScriptProperty] 135 | [Display(Name="ResetDeltaOn", Description="Reset Profile On", Order=0, GroupName="General")] 136 | public CumulativeDeltaTimeframe ResetDeltaOn 137 | { get; set; } 138 | 139 | [XmlIgnore] 140 | [Browsable(false)] 141 | public string ResetDeltaOnSerializable 142 | { 143 | get { return ResetDeltaOn.ToString(); } 144 | set { ResetDeltaOn = (CumulativeDeltaTimeframe) Enum.Parse(typeof(CumulativeDeltaTimeframe), value); } 145 | } 146 | 147 | [Browsable(false)] 148 | [XmlIgnore] 149 | public Series CumDelta 150 | { 151 | get { return Values[0]; } 152 | } 153 | #endregion 154 | 155 | } 156 | } 157 | 158 | #region NinjaScript generated code. Neither change nor remove. 159 | 160 | namespace NinjaTrader.NinjaScript.Indicators 161 | { 162 | public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase 163 | { 164 | private CumulativeDelta[] cacheCumulativeDelta; 165 | public CumulativeDelta CumulativeDelta(CumulativeDeltaTimeframe resetDeltaOn) 166 | { 167 | return CumulativeDelta(Input, resetDeltaOn); 168 | } 169 | 170 | public CumulativeDelta CumulativeDelta(ISeries input, CumulativeDeltaTimeframe resetDeltaOn) 171 | { 172 | if (cacheCumulativeDelta != null) 173 | for (int idx = 0; idx < cacheCumulativeDelta.Length; idx++) 174 | if (cacheCumulativeDelta[idx] != null && cacheCumulativeDelta[idx].ResetDeltaOn == resetDeltaOn && cacheCumulativeDelta[idx].EqualsInput(input)) 175 | return cacheCumulativeDelta[idx]; 176 | return CacheIndicator(new CumulativeDelta(){ ResetDeltaOn = resetDeltaOn }, input, ref cacheCumulativeDelta); 177 | } 178 | } 179 | } 180 | 181 | namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns 182 | { 183 | public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase 184 | { 185 | public Indicators.CumulativeDelta CumulativeDelta(CumulativeDeltaTimeframe resetDeltaOn) 186 | { 187 | return indicator.CumulativeDelta(Input, resetDeltaOn); 188 | } 189 | 190 | public Indicators.CumulativeDelta CumulativeDelta(ISeries input , CumulativeDeltaTimeframe resetDeltaOn) 191 | { 192 | return indicator.CumulativeDelta(input, resetDeltaOn); 193 | } 194 | } 195 | } 196 | 197 | namespace NinjaTrader.NinjaScript.Strategies 198 | { 199 | public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase 200 | { 201 | public Indicators.CumulativeDelta CumulativeDelta(CumulativeDeltaTimeframe resetDeltaOn) 202 | { 203 | return indicator.CumulativeDelta(Input, resetDeltaOn); 204 | } 205 | 206 | public Indicators.CumulativeDelta CumulativeDelta(ISeries input , CumulativeDeltaTimeframe resetDeltaOn) 207 | { 208 | return indicator.CumulativeDelta(input, resetDeltaOn); 209 | } 210 | } 211 | } 212 | 213 | #endregion 214 | -------------------------------------------------------------------------------- /Indicators/CumulativeDeltaDifference.cs: -------------------------------------------------------------------------------- 1 | #region Using declarations 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Media; 10 | using System.Xml.Serialization; 11 | using NinjaTrader.Cbi; 12 | using NinjaTrader.Core; 13 | using NinjaTrader.Gui; 14 | using NinjaTrader.Gui.Chart; 15 | using NinjaTrader.Gui.SuperDom; 16 | using NinjaTrader.Gui.Tools; 17 | using NinjaTrader.Data; 18 | using NinjaTrader.NinjaScript; 19 | using NinjaTrader.Core.FloatingPoint; 20 | using NinjaTrader.NinjaScript.DrawingTools; 21 | using SharpDX; 22 | using SharpDX.DirectWrite; 23 | #endregion 24 | 25 | //This namespace holds Indicators in this folder and is required. Do not change it. 26 | namespace NinjaTrader.NinjaScript.Indicators 27 | { 28 | 29 | public class CumulativeDeltaDifference : ColumnPanel 30 | { 31 | public class RowData 32 | { 33 | public long CumulativeDelta; 34 | public long DeltaDifference; 35 | public double Price; 36 | 37 | public RowData(long cumulativeDelta, double price) 38 | { 39 | CumulativeDelta = cumulativeDelta; 40 | DeltaDifference = 0; 41 | Price = price; 42 | } 43 | } 44 | 45 | public class Profile 46 | { 47 | public Dictionary Data; 48 | public long CurrentCumulativeDelta; 49 | 50 | public double HiPrice; 51 | public long HiValue; 52 | 53 | public Profile() 54 | { 55 | Data = new Dictionary(); 56 | } 57 | 58 | public void AddAskVolume(double price, long volume) 59 | { 60 | CurrentCumulativeDelta += volume; 61 | 62 | RowData val; 63 | 64 | if (Data.TryGetValue(price, out val)) 65 | { 66 | val.CumulativeDelta = CurrentCumulativeDelta; 67 | } 68 | else 69 | { 70 | Data.Add(price, new RowData(CurrentCumulativeDelta, price)); 71 | } 72 | 73 | CalculateValues(); 74 | } 75 | 76 | public void AddBidVolume(double price, long volume) 77 | { 78 | CurrentCumulativeDelta -= volume; 79 | 80 | RowData val; 81 | 82 | if (Data.TryGetValue(price, out val)) 83 | { 84 | val.CumulativeDelta = CurrentCumulativeDelta; 85 | } 86 | else 87 | { 88 | Data.Add(price, new RowData(CurrentCumulativeDelta, price)); 89 | } 90 | 91 | CalculateValues(); 92 | } 93 | 94 | public void CalculateValues() 95 | { 96 | HiValue = 0; 97 | 98 | foreach(KeyValuePair kvp in Data) 99 | { 100 | RowData r = kvp.Value; 101 | 102 | r.DeltaDifference = CurrentCumulativeDelta - r.CumulativeDelta; 103 | 104 | if(Math.Abs(r.DeltaDifference) > HiValue) 105 | { 106 | HiValue = Math.Abs(r.DeltaDifference); 107 | HiPrice = r.Price; 108 | } 109 | } 110 | } 111 | } 112 | 113 | 114 | 115 | #region Private Variables 116 | 117 | 118 | private Profile myProfile = new Profile(); 119 | private SessionIterator sessionIterator; 120 | 121 | #endregion 122 | 123 | protected override void OnStateChange() 124 | { 125 | base.OnStateChange(); 126 | 127 | if (State == State.SetDefaults) 128 | { 129 | Description = "Difference in cumulative delta for each price level between current cumulative delta and cumulative delta the last time that price was touched."; 130 | Name = "CumulativeDeltaDifference"; 131 | Calculate = Calculate.OnEachTick; 132 | IsOverlay = true; 133 | IsAutoScale = false; 134 | DrawOnPricePanel = true; 135 | PaintPriceMarkers = false; 136 | IsSuspendedWhileInactive = false; 137 | BarsRequiredToPlot = 2; 138 | ScaleJustification = ScaleJustification.Right; 139 | 140 | positiveColor = Brushes.CornflowerBlue; 141 | negativeColor = Brushes.Orange; 142 | neutralColor = Brushes.White; 143 | textSize = 11; 144 | ResizableWidth = 30; 145 | } 146 | else if (State == State.Configure) 147 | { 148 | ZOrder = ChartBars.ZOrder - 1; 149 | 150 | if(!Bars.IsTickReplay) 151 | { 152 | Draw.TextFixed(this, "tickReplay", "Please enable Tick Replay!", TextPosition.TopRight); 153 | } 154 | 155 | //AddDataSeries(BarsPeriodType.Day, 1); 156 | sessionIterator = new SessionIterator(Bars); 157 | } 158 | } 159 | 160 | protected override void OnBarUpdate() 161 | { 162 | 163 | if(CurrentBars[0] <= BarsRequiredToPlot) return; 164 | 165 | //Reset profile on session week or day. 166 | if(IsFirstTickOfBar && ResetProfileOn != Timeframe.Never) 167 | { 168 | DateTime previous = sessionIterator.GetTradingDay(Time[1]); 169 | DateTime current = sessionIterator.GetTradingDay(Time[0]); 170 | 171 | //Reset profile on daily basis. 172 | if(ResetProfileOn == Timeframe.Session && !current.DayOfWeek.Equals(previous.DayOfWeek)) 173 | { 174 | myProfile = new Profile(); 175 | } 176 | 177 | //Reset profile on weekly basis. 178 | else if(ResetProfileOn == Timeframe.Week && current.DayOfWeek.CompareTo(previous.DayOfWeek) < 0) 179 | { 180 | myProfile = new Profile(); 181 | } 182 | 183 | //Reset profile on monthly basis. 184 | else if(ResetProfileOn != Timeframe.Month && !current.Month.Equals(previous.Month)) 185 | { 186 | myProfile = new Profile(); 187 | } 188 | } 189 | } 190 | 191 | protected override void OnMarketData(MarketDataEventArgs e) 192 | { 193 | if (e.MarketDataType == MarketDataType.Last) 194 | { 195 | if (e.Price >= e.Ask) 196 | { 197 | myProfile.AddAskVolume(e.Price, e.Volume); 198 | } 199 | else if(e.Price <= e.Bid) 200 | { 201 | myProfile.AddBidVolume(e.Price, e.Volume); 202 | } 203 | } 204 | } 205 | 206 | protected override void OnRender(ChartControl chartControl, ChartScale chartScale) 207 | { 208 | base.OnRender(chartControl, chartScale); 209 | if(Bars == null || Bars.Instrument == null || CurrentBar < 1) { return; } 210 | 211 | LastRender = DateTime.Now; 212 | 213 | try 214 | { 215 | 216 | foreach(KeyValuePair row in myProfile.Data) 217 | { 218 | drawRow(chartControl, chartScale, row.Value); 219 | } 220 | 221 | } 222 | catch(Exception e) 223 | { 224 | 225 | Print("Cumulative Delta Difference: " + e.Message); 226 | } 227 | } 228 | 229 | private void drawRow(ChartControl chartControl, ChartScale chartScale, RowData row) 230 | { 231 | 232 | //Calculate color of this row. 233 | //Brush brushColor = new SolidColorBrush(System.Windows.Media.Color.FromRgb(255, 0, 0)); //bidColor.Freeze(); 234 | float alpha = alpha = (float)((double)Math.Abs(row.DeltaDifference) / (double)myProfile.HiValue); 235 | Brush brushColor = neutralColor; 236 | if(row.DeltaDifference > 0) 237 | { 238 | brushColor= positiveColor; 239 | } 240 | else if (row.DeltaDifference < 0) 241 | { 242 | brushColor = negativeColor; 243 | } 244 | 245 | 246 | //Calculate width of this row. 247 | 248 | 249 | 250 | //Calculate cell properties 251 | double y1 = ((chartScale.GetYByValue(row.Price) + chartScale.GetYByValue(row.Price + TickSize)) / 2) + 1; 252 | double y2 = ((chartScale.GetYByValue(row.Price) + chartScale.GetYByValue(row.Price - TickSize)) / 2) - 1; 253 | 254 | SharpDX.RectangleF rect = new SharpDX.RectangleF(); 255 | rect.X = (float)chartControl.CanvasRight - Position; 256 | rect.Y = (float)y1; 257 | rect.Width = (float)-((ResizableWidth * alpha) + MinimumWidth - 2); 258 | rect.Height = (float)Math.Abs(y1 - y2); 259 | 260 | //Draw the row. 261 | using(SharpDX.Direct2D1.Brush rowBrush = brushColor.ToDxBrush(RenderTarget)) 262 | { 263 | //rowBrush.Opacity = alpha; 264 | rowBrush.Opacity = alpha; 265 | RenderTarget.FillRectangle(rect, neutralColor.ToDxBrush(RenderTarget)); 266 | RenderTarget.FillRectangle(rect, rowBrush); 267 | } 268 | 269 | if(rect.Height > this.MinimumTextHeight) 270 | { 271 | RenderTarget.DrawText(string.Format("{0}", row.DeltaDifference), textFormat, rect, TextColor.ToDxBrush(RenderTarget)); 272 | } 273 | } 274 | 275 | #region Properties 276 | 277 | [XmlIgnore] 278 | [NinjaScriptProperty] 279 | [Display(Name="ResetProfileOn", Description="Reset Profile On", Order=0, GroupName="General")] 280 | public Timeframe ResetProfileOn 281 | { get; set; } 282 | 283 | [XmlIgnore] 284 | [Browsable(false)] 285 | public string ResetProfileOnSerializable 286 | { 287 | get { return ResetProfileOn.ToString(); } 288 | set { ResetProfileOn = (Timeframe) Enum.Parse(typeof(Timeframe), value); } 289 | } 290 | 291 | [NinjaScriptProperty] 292 | [XmlIgnore] 293 | [Display(Name = "Negative Delta Color", GroupName = "Parameters", Order = 9)] 294 | public Brush negativeColor 295 | { get; set; } 296 | 297 | [Browsable(false)] 298 | public string negativeColorSerializable 299 | { 300 | get { return Serialize.BrushToString(negativeColor); } 301 | set { negativeColor = Serialize.StringToBrush(value); } 302 | } 303 | 304 | [NinjaScriptProperty] 305 | [XmlIgnore] 306 | [Display(Name = "Positive Delta Color", GroupName = "Parameters", Order = 9)] 307 | public Brush positiveColor 308 | { get; set; } 309 | 310 | [Browsable(false)] 311 | public string positiveColorSerializable 312 | { 313 | get { return Serialize.BrushToString(positiveColor); } 314 | set { positiveColor = Serialize.StringToBrush(value); } 315 | } 316 | 317 | [NinjaScriptProperty] 318 | [XmlIgnore] 319 | [Display(Name = "Neutral Delta Color", GroupName = "Parameters", Order = 9)] 320 | public Brush neutralColor 321 | { get; set; } 322 | 323 | [Browsable(false)] 324 | public string neutralColorSerializable 325 | { 326 | get { return Serialize.BrushToString(neutralColor); } 327 | set { neutralColor = Serialize.StringToBrush(value); } 328 | } 329 | 330 | #endregion 331 | } 332 | } 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | -------------------------------------------------------------------------------- /Indicators/Delta.cs: -------------------------------------------------------------------------------- 1 | #region Using declarations 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Xml.Serialization; 13 | using NinjaTrader.Cbi; 14 | using NinjaTrader.Gui; 15 | using NinjaTrader.Gui.Chart; 16 | using NinjaTrader.Gui.SuperDom; 17 | using NinjaTrader.Gui.Tools; 18 | using NinjaTrader.Data; 19 | using NinjaTrader.NinjaScript; 20 | using NinjaTrader.Core.FloatingPoint; 21 | using NinjaTrader.NinjaScript.DrawingTools; 22 | #endregion 23 | 24 | //This namespace holds Indicators in this folder and is required. Do not change it. 25 | namespace NinjaTrader.NinjaScript.Indicators 26 | { 27 | public class Delta : Indicator 28 | { 29 | protected override void OnStateChange() 30 | { 31 | if (State == State.SetDefaults) 32 | { 33 | Description = @"Shows change in price."; 34 | Name = "Delta"; 35 | Calculate = Calculate.OnBarClose; 36 | IsOverlay = false; 37 | DisplayInDataBox = true; 38 | DrawOnPricePanel = true; 39 | DrawHorizontalGridLines = true; 40 | DrawVerticalGridLines = true; 41 | PaintPriceMarkers = true; 42 | ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right; 43 | //Disable this property if your indicator requires custom values that cumulate with each new market data event. 44 | //See Help Guide for additional information. 45 | IsSuspendedWhileInactive = true; 46 | AddPlot(new Stroke(Brushes.Orange, 2), PlotStyle.Bar, "DeltaPlot"); 47 | } 48 | else if (State == State.Configure) 49 | { 50 | } 51 | } 52 | 53 | protected override void OnBarUpdate() 54 | { 55 | if (CurrentBar == 0) 56 | Value[0] = Input[0]; 57 | else 58 | { 59 | Value[0] = Input[0] - Input [1]; 60 | } 61 | } 62 | 63 | #region Properties 64 | 65 | [Browsable(false)] 66 | [XmlIgnore] 67 | public Series DeltaPlot 68 | { 69 | get { return Values[0]; } 70 | } 71 | #endregion 72 | 73 | } 74 | } 75 | 76 | #region NinjaScript generated code. Neither change nor remove. 77 | 78 | namespace NinjaTrader.NinjaScript.Indicators 79 | { 80 | public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase 81 | { 82 | private Delta[] cacheDelta; 83 | public Delta Delta() 84 | { 85 | return Delta(Input); 86 | } 87 | 88 | public Delta Delta(ISeries input) 89 | { 90 | if (cacheDelta != null) 91 | for (int idx = 0; idx < cacheDelta.Length; idx++) 92 | if (cacheDelta[idx] != null && cacheDelta[idx].EqualsInput(input)) 93 | return cacheDelta[idx]; 94 | return CacheIndicator(new Delta(), input, ref cacheDelta); 95 | } 96 | } 97 | } 98 | 99 | namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns 100 | { 101 | public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase 102 | { 103 | public Indicators.Delta Delta() 104 | { 105 | return indicator.Delta(Input); 106 | } 107 | 108 | public Indicators.Delta Delta(ISeries input ) 109 | { 110 | return indicator.Delta(input); 111 | } 112 | } 113 | } 114 | 115 | namespace NinjaTrader.NinjaScript.Strategies 116 | { 117 | public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase 118 | { 119 | public Indicators.Delta Delta() 120 | { 121 | return indicator.Delta(Input); 122 | } 123 | 124 | public Indicators.Delta Delta(ISeries input ) 125 | { 126 | return indicator.Delta(input); 127 | } 128 | } 129 | } 130 | 131 | #endregion 132 | -------------------------------------------------------------------------------- /Indicators/FootprintChart.cs: -------------------------------------------------------------------------------- 1 | #region Using declarations 2 | using System; 3 | using System.Drawing; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using System.ComponentModel; 7 | using System.ComponentModel.DataAnnotations; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Windows; 12 | using System.Windows.Input; 13 | using System.Windows.Media; 14 | using System.Xml.Serialization; 15 | using NinjaTrader.Cbi; 16 | using NinjaTrader.Core; 17 | using NinjaTrader.Gui; 18 | using NinjaTrader.Gui.Chart; 19 | using NinjaTrader.Gui.SuperDom; 20 | using NinjaTrader.Data; 21 | using NinjaTrader.NinjaScript; 22 | using NinjaTrader.Core.FloatingPoint; 23 | using NinjaTrader.NinjaScript.DrawingTools; 24 | using SharpDX.Direct2D1; 25 | using SharpDX; 26 | using SharpDX.DirectWrite; 27 | //using System.Windows.Forms; 28 | 29 | using System.Windows.Controls; 30 | using System.Windows.Automation; 31 | using System.Windows.Automation.Provider; 32 | #endregion 33 | 34 | #region Enums 35 | public enum FootPrintBarEnum 36 | { 37 | BidAsk, 38 | VolumeDelta 39 | } 40 | public enum FootPrintBarColorEnum 41 | { 42 | Saturation, 43 | VolumeBar, 44 | Solid, 45 | None 46 | } 47 | public enum ClosePriceEnum 48 | { 49 | TextColor, 50 | Rectangle, 51 | None 52 | } 53 | public enum HighestVolumeEnum 54 | { 55 | Rectangle, 56 | None 57 | } 58 | //public enum ZOrderType 59 | //{ 60 | // Normal, 61 | // AlwaysDrawnFirst 62 | //} 63 | 64 | 65 | #endregion 66 | 67 | //This namespace holds Indicators in this folder and is required. Do not change it. 68 | namespace NinjaTrader.NinjaScript.Indicators 69 | { 70 | public class FootprintChart : Indicator 71 | { 72 | #region Variable and Structure Declarations 73 | 74 | private int barSpacing = 90; 75 | private int barWidth = 43; 76 | private bool setChartProperties = true; 77 | private string displayName = null; 78 | FootPrintBarEnum footPrintBarType = FootPrintBarEnum.BidAsk; 79 | FootPrintBarColorEnum footPrintBarColor = FootPrintBarColorEnum.Saturation; 80 | ClosePriceEnum closePriceIndicator = ClosePriceEnum.TextColor; 81 | HighestVolumeEnum highestVolumeIndicator = HighestVolumeEnum.Rectangle; 82 | NinjaTrader.Gui.Tools.SimpleFont textFont = new NinjaTrader.Gui.Tools.SimpleFont("Consolas", 12); 83 | 84 | public class FootprintBar 85 | { 86 | public double Volume {get; set;} 87 | public double SessionVolume {get; set;} 88 | public double Delta {get; set;} 89 | public double SessionDelta {get;set;} 90 | 91 | 92 | public string BarDelta1;// {get;set;} 93 | 94 | public double LastHit {get;set;} 95 | public bool BidLastHit {get;set;} 96 | 97 | public double MaxVolume {get;set;} 98 | public double MaxVolumePrice {get;set;} 99 | public double MaxDelta {get;set;} 100 | public double MaxDeltaPrice {get;set;} 101 | 102 | public Dictionary Footprints {get;set;} 103 | 104 | public FootprintBar(FootprintBar previous) 105 | { 106 | Footprints = new Dictionary(); 107 | SessionVolume = previous.SessionVolume; 108 | SessionDelta = previous.SessionDelta; 109 | Volume = 0; 110 | Delta = 0; 111 | LastHit = 0; 112 | } 113 | 114 | public FootprintBar() 115 | { 116 | Footprints = new Dictionary(); 117 | SessionVolume = 0; 118 | Volume = 0; 119 | Delta = 0; 120 | BarDelta1 = "Bar Delta"; 121 | LastHit = 0; 122 | } 123 | 124 | 125 | public void AddAskVolume(double price, double volume) 126 | { 127 | double currentVolume = 0; 128 | double deltaVolume = 0; 129 | BidAskVolume val; 130 | 131 | if (Footprints.TryGetValue(price, out val)) 132 | { 133 | val.askVolume += volume; 134 | val.currentVolume += volume; 135 | 136 | currentVolume = val.currentVolume; 137 | } 138 | else 139 | { 140 | Footprints.Add(price, new BidAskVolume(volume, volume, 0, price)); 141 | currentVolume = volume; 142 | } 143 | 144 | if(currentVolume > MaxVolume) 145 | { 146 | MaxVolume = currentVolume; 147 | MaxVolumePrice = price; 148 | } 149 | 150 | Volume = Volume + volume; 151 | SessionVolume = SessionVolume + volume; 152 | Delta = Delta + volume; 153 | SessionDelta = SessionDelta + volume; 154 | 155 | LastHit = price; 156 | BidLastHit = false; 157 | } 158 | 159 | public void AddBidVolume(double price, double volume) 160 | { 161 | double currentVolume = 0; 162 | double deltaVolume = 0; 163 | BidAskVolume val; 164 | 165 | if (Footprints.TryGetValue(price, out val)) 166 | { 167 | val.bidVolume += volume; 168 | val.currentVolume += volume; 169 | 170 | currentVolume = val.currentVolume; 171 | } 172 | else 173 | { 174 | Footprints.Add(price, new BidAskVolume(volume, 0, volume, price)); 175 | 176 | currentVolume = volume; 177 | } 178 | 179 | if(currentVolume > MaxVolume) 180 | { 181 | MaxVolume = currentVolume; 182 | MaxVolumePrice = price; 183 | } 184 | 185 | Volume = Volume + volume; 186 | SessionVolume = SessionVolume + volume; 187 | Delta = Delta - volume; 188 | SessionDelta = SessionDelta - volume; 189 | 190 | LastHit = price; 191 | BidLastHit = true; 192 | } 193 | 194 | public double FindMaxDeltaVolume() 195 | { 196 | foreach(KeyValuePair pair in Footprints) 197 | { 198 | if(pair.Value.deltaVolume > MaxDelta) 199 | { 200 | MaxDelta = pair.Value.deltaVolume; 201 | MaxDeltaPrice = pair.Value.Price; 202 | } 203 | } 204 | 205 | return MaxDeltaPrice; 206 | } 207 | } 208 | 209 | public class BidAskVolume 210 | { 211 | public double currentVolume; 212 | public double askVolume; 213 | public double bidVolume; 214 | public double Price; 215 | 216 | 217 | public BidAskVolume(double cv, double av, double bv, double price) 218 | { 219 | currentVolume = cv; 220 | askVolume = av; 221 | bidVolume = bv; 222 | Price = price; 223 | 224 | } 225 | 226 | public double deltaVolume 227 | { 228 | get{ return Math.Abs(bidVolume - askVolume); } 229 | } 230 | } 231 | 232 | 233 | private FootprintBar CurrentFootprint = new FootprintBar(); 234 | private List FootprintBars = new List(); 235 | 236 | private Dictionary bidAskVolume = new Dictionary(); 237 | 238 | double tmpAskVolume; 239 | double tmpBidVolume; 240 | double tmpCurrentVolume; 241 | int chartBarIndex; 242 | 243 | double barVolume; // bar volume 244 | double barDelta; // bar delta 245 | double lastHit = 0; // meant to show(text colour) if it was a buy or sell on the close of each bar ... current bar[0] ok but not previous closes .... under construction 246 | 247 | #endregion 248 | 249 | protected override void OnStateChange() 250 | { 251 | if (State == State.SetDefaults) 252 | { 253 | 254 | if (State == State.Historical) 255 | { 256 | } 257 | 258 | 259 | Description = @"Displays candlestick bars with coloured histogram of buy & sell volumes and more..."; 260 | Name = "FootprintChart"; // by Seth 20.12.2016 261 | Calculate = Calculate.OnEachTick; 262 | IsOverlay = true; 263 | DisplayInDataBox = true; 264 | DrawOnPricePanel = true; 265 | DrawHorizontalGridLines = true; 266 | DrawVerticalGridLines = true; 267 | PaintPriceMarkers = true; 268 | ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right; 269 | IsAutoScale = true; 270 | IsSuspendedWhileInactive = true; 271 | 272 | // default color values 273 | BarDeltaDownColor = Brushes.Pink; 274 | BarDeltaUpColor = Brushes.LightGreen; 275 | SessionDeltaDownColor = Brushes.Tomato; 276 | SessionDeltaUpColor = Brushes.LimeGreen; 277 | FooterFontColor = Brushes.Black; 278 | BarVolumeBackgroundColor = Brushes.LightBlue; 279 | SessionVolumeBackgroundColor = Brushes.DodgerBlue; 280 | FootBrintParClosePriceColor = Brushes.Gold; 281 | FootBrintParHighestVolumeColor = Brushes.LawnGreen; 282 | FootBrintParHighestDeltaColor = Brushes.Magenta; 283 | FootBrintParTextColor = Brushes.Black; 284 | FootPrintBarUpColor = Brushes.LimeGreen; 285 | FootPrintBarDownColor = Brushes.Red; 286 | 287 | // current price line 288 | LineSpreadColor = Brushes.Black; 289 | LineShortColor = Brushes.Red; 290 | LineLongColor = Brushes.Green; 291 | LineStyle = DashStyleHelper.Dot; 292 | LineWidth = 2; 293 | 294 | // default boolean values 295 | ShowCurrentPrice = false; 296 | ShowFooter = true; 297 | ShowCandleStickBars = true; 298 | ShowBodyBar = false; 299 | ShowWicks = true; 300 | } 301 | else if (State == State.Configure) 302 | { 303 | setChartProperties = true; 304 | 305 | 306 | // create a better display name 307 | displayName = Name + " (" + Instrument.FullName + ", " + BarsPeriod.Value + " " + BarsPeriod.BarsPeriodType.ToString() + ", Bar Type: " + footPrintBarType.ToString() + ", Color Type: " + footPrintBarColor.ToString() + ")"; 308 | } 309 | } 310 | 311 | public override string DisplayName 312 | { 313 | get { return (displayName != null ? displayName : Name); } 314 | } 315 | 316 | protected override void OnMarketData(MarketDataEventArgs e) 317 | { 318 | if (e.MarketDataType == MarketDataType.Last){ 319 | 320 | lastHit=0; 321 | 322 | if (e.Price >= e.Ask) 323 | { 324 | CurrentFootprint.AddAskVolume(e.Price, e.Volume); 325 | 326 | if(ShowCurrentPrice) 327 | Draw.HorizontalLine(this, "CurrPrice", false, e.Price, LineShortColor, LineStyle, LineWidth); 328 | } 329 | else if(e.Price <= e.Bid) 330 | { 331 | CurrentFootprint.AddBidVolume(e.Price, e.Volume); 332 | 333 | if(ShowCurrentPrice) 334 | Draw.HorizontalLine(this, "CurrPrice", false, e.Price, LineLongColor, LineStyle, LineWidth); 335 | } 336 | } 337 | } 338 | 339 | protected override void OnBarUpdate() 340 | { 341 | BarBrushes[0] = Brushes.Transparent; 342 | CandleOutlineBrushes[0] = Brushes.Transparent; 343 | 344 | if (!Bars.IsTickReplay) 345 | Draw.TextFixed(this, "warning msg", "WARNING: Tick Replay must be enabled for FootPrintChart to display historical values.", TextPosition.TopRight); 346 | 347 | if (IsFirstTickOfBar) 348 | { 349 | if (Bars.IsFirstBarOfSession) 350 | { 351 | CurrentFootprint = new FootprintBar(); 352 | FootprintBars.Add(CurrentFootprint); 353 | } 354 | else 355 | { 356 | CurrentFootprint = new FootprintBar(CurrentFootprint); 357 | FootprintBars.Add(CurrentFootprint); 358 | } 359 | } 360 | } 361 | 362 | public override void OnCalculateMinMax() 363 | { 364 | // exit if ChartBars has not yet been initialized 365 | if (ChartBars == null) 366 | return; 367 | 368 | // int barLowPrice and barHighPrice to min and max double vals 369 | double barLowPrice = double.MaxValue; 370 | double barHighPrice = double.MinValue; 371 | 372 | // loop through the bars visible on the chart 373 | for (int index = ChartBars.FromIndex; index <= ChartBars.ToIndex; index++) 374 | { 375 | // get min/max of bar high/low values 376 | barLowPrice = Math.Min(barLowPrice, Low.GetValueAt(index)); 377 | barHighPrice = Math.Max(barHighPrice, High.GetValueAt(index)); 378 | } 379 | 380 | // number of ticks between high/low price 381 | double priceTicks = (barHighPrice - barLowPrice) * (1 / TickSize); 382 | 383 | // number of ticks on the chart panel based on the chart panel height and text font size 384 | double panelTicks = ChartPanel.H / (textFont.Size + 4); 385 | 386 | // number of ticks we'll need to add to high and low price to auto adjust the chart 387 | double ticksNeeded = (panelTicks - priceTicks) / 2; 388 | 389 | // calc min and max chart prices 390 | MinValue = barLowPrice - (ticksNeeded * TickSize); 391 | MaxValue = barHighPrice + (ticksNeeded * TickSize); 392 | } 393 | 394 | protected override void OnRender(ChartControl chartControl, ChartScale chartScale) 395 | { 396 | // set the bar spacing and width of the chart, we only want to do this once and not on every render 397 | if (setChartProperties) { 398 | chartControl.Properties.BarDistance = barSpacing; 399 | chartControl.BarWidth = barWidth; 400 | setChartProperties = false; 401 | } 402 | 403 | // create the TextFormat structure for the footprint bars 404 | TextFormat footPrintBarFont = new TextFormat(new SharpDX.DirectWrite.Factory(), 405 | textFont.Family.ToString(), 406 | textFont.Bold ? SharpDX.DirectWrite.FontWeight.Bold : SharpDX.DirectWrite.FontWeight.Normal, 407 | textFont.Italic ? SharpDX.DirectWrite.FontStyle.Italic : SharpDX.DirectWrite.FontStyle.Normal, 408 | (float)textFont.Size); 409 | 410 | for (chartBarIndex = ChartBars.FromIndex; chartBarIndex <= ChartBars.ToIndex; chartBarIndex++) 411 | { 412 | // current bar prices 413 | double barClosePrice = ChartBars.Bars.GetClose(chartBarIndex); 414 | double barOpenPrice = ChartBars.Bars.GetOpen(chartBarIndex); 415 | double barHighPrice = ChartBars.Bars.GetHigh(chartBarIndex); 416 | double barLowPrice = ChartBars.Bars.GetLow(chartBarIndex); 417 | 418 | barVolume = ChartBars.Bars.GetVolume(chartBarIndex); 419 | 420 | 421 | // current bar X and Y points 422 | int x = chartControl.GetXByBarIndex(ChartBars, chartBarIndex) - (int)chartControl.BarWidth; 423 | float barX = chartControl.GetXByBarIndex(ChartBars, chartBarIndex); 424 | float barOpenY = chartScale.GetYByValue(barOpenPrice); 425 | float barCloseY = chartScale.GetYByValue(barClosePrice); 426 | float barHighY = chartScale.GetYByValue(barHighPrice); 427 | float barLowY = chartScale.GetYByValue(barLowPrice); 428 | 429 | // vectors and rectangle for the candlestick bars 430 | Vector2 point0 = new Vector2(); 431 | Vector2 point1 = new Vector2(); 432 | RectangleF rect = new RectangleF(); 433 | 434 | // calculate the physical font size for the selected font 435 | GlyphTypeface gtf = new GlyphTypeface(); 436 | System.Windows.Media.Typeface t_face = new System.Windows.Media.Typeface(new System.Windows.Media.FontFamily(textFont.Family.ToString()), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal); 437 | t_face.TryGetGlyphTypeface(out gtf); 438 | 439 | // chart drawing starts from the current price line down, so for our footprint rectangles we need to offset our footprint bar drawings up a bit so they align with the price marker 440 | double fontOffset = (gtf.CapsHeight * textFont.Size) * 0.6 * 1.8; 441 | double rectangleOffset = (gtf.CapsHeight * textFont.Size) * 1.8; 442 | 443 | // init totalDelta and maxVolumePrice 444 | double totalDelta = 0; 445 | double maxVolumePrice = 0; 446 | 447 | double sessionDelta = 0; 448 | double sessionVolume = 0; 449 | 450 | // BARS 451 | #region FootPrint Bars 452 | if (chartBarIndex == ChartBars.Count) 453 | { 454 | double maxVolume = double.MinValue;; 455 | double maxAskVolume = double.MinValue; 456 | double maxBidVolume = double.MinValue; 457 | double footPrintBarTopVolume = double.MinValue; 458 | 459 | foreach (KeyValuePair kvp in CurrentFootprint.Footprints) 460 | { 461 | if ((kvp.Value.askVolume + kvp.Value.bidVolume) > maxVolume) { 462 | maxVolume = kvp.Value.askVolume + kvp.Value.bidVolume; 463 | maxVolumePrice = kvp.Key; 464 | } 465 | 466 | if (footPrintBarType == FootPrintBarEnum.BidAsk) { 467 | maxBidVolume = Math.Max(maxBidVolume, kvp.Value.bidVolume); 468 | maxAskVolume = Math.Max(maxAskVolume, kvp.Value.askVolume); 469 | } else { 470 | maxBidVolume = Math.Max(maxBidVolume, (kvp.Value.askVolume + kvp.Value.bidVolume)); 471 | maxAskVolume = Math.Max(maxAskVolume, (kvp.Value.askVolume - kvp.Value.bidVolume)); 472 | } 473 | 474 | int y = chartScale.GetYByValue(kvp.Key) - (int)(fontOffset); 475 | 476 | // determine the bar opacity 477 | double curr_percent = 100 * (barVolume / maxVolume); 478 | double curr_opacity = Math.Round((curr_percent / 100) * 0.8, 1); 479 | curr_opacity = curr_opacity == 0 ? 0.1 : curr_opacity; 480 | 481 | // set the color based on the volume direction 482 | SharpDX.Direct2D1.Brush footPrintBarColor = FootPrintBarUpColor.ToDxBrush(RenderTarget); 483 | if (kvp.Value.askVolume < kvp.Value.bidVolume) 484 | footPrintBarColor = FootPrintBarDownColor.ToDxBrush(RenderTarget); 485 | 486 | // draw the background color 487 | if (FootPrintBarColor == FootPrintBarColorEnum.VolumeBar) 488 | { 489 | 490 | double ratioAsk = 0; 491 | double ratioBid = 0; 492 | 493 | if (maxAskVolume != 0) 494 | ratioAsk = 1f - (kvp.Value.askVolume / maxAskVolume); 495 | 496 | if (maxBidVolume != 0) 497 | ratioBid = 1f - (kvp.Value.bidVolume / maxBidVolume); 498 | 499 | // determine the width of the rectangle based on the bid/ask volume 500 | double width = (chartControl.BarWidth - (chartControl.BarWidth * ratioBid)) + (chartControl.BarWidth - (chartControl.BarWidth * ratioAsk)); 501 | 502 | RenderTarget.FillRectangle(new RectangleF(x + (float)(chartControl.BarWidth * ratioBid), y, (float)(width), (float)(rectangleOffset)), footPrintBarColor); 503 | } 504 | else if (FootPrintBarColor == FootPrintBarColorEnum.Saturation) 505 | { 506 | footPrintBarColor.Opacity = (float)curr_opacity; 507 | RenderTarget.FillRectangle(new RectangleF(x, y, (float)(chartControl.BarWidth * 2), (float)(rectangleOffset)), footPrintBarColor); 508 | } 509 | else if (FootPrintBarColor == FootPrintBarColorEnum.Solid) 510 | { 511 | RenderTarget.FillRectangle(new RectangleF(x, y, (float)(chartControl.BarWidth * 2), (float)(rectangleOffset)), footPrintBarColor); 512 | } 513 | 514 | // create the bid/ask or volume/delta strings to show on the chart 515 | string bidStr = null; 516 | string askStr = null; 517 | if (footPrintBarType == FootPrintBarEnum.BidAsk) { 518 | bidStr = kvp.Value.bidVolume.ToString(); 519 | askStr = kvp.Value.askVolume.ToString(); 520 | } else { 521 | bidStr = barVolume.ToString(); 522 | askStr = barDelta.ToString(); 523 | } 524 | 525 | 526 | // draw the bid footprint bar string 527 | footPrintBarFont.TextAlignment = SharpDX.DirectWrite.TextAlignment.Trailing; 528 | if (kvp.Key == barClosePrice && closePriceIndicator == ClosePriceEnum.TextColor && lastHit==1) 529 | RenderTarget.DrawText(bidStr, footPrintBarFont, new RectangleF(barX - 5 - (float)chartControl.BarWidth, y, (float)chartControl.BarWidth, (float)(rectangleOffset)), 530 | FootBrintParClosePriceColor.ToDxBrush(RenderTarget)); 531 | else 532 | RenderTarget.DrawText(bidStr, footPrintBarFont, new RectangleF(barX - 5 - (float)chartControl.BarWidth, y, (float)chartControl.BarWidth, (float)(rectangleOffset)), 533 | FootBrintParTextColor.ToDxBrush(RenderTarget)); 534 | 535 | // draw the ask footprint bar string 536 | footPrintBarFont.TextAlignment = SharpDX.DirectWrite.TextAlignment.Leading; 537 | if (kvp.Key == barClosePrice && closePriceIndicator == ClosePriceEnum.TextColor && lastHit==2) 538 | RenderTarget.DrawText(askStr, footPrintBarFont, new RectangleF(barX + 5, y, (float)chartControl.BarWidth, (float)(rectangleOffset)), 539 | FootBrintParClosePriceColor.ToDxBrush(RenderTarget)); 540 | else 541 | RenderTarget.DrawText(askStr, footPrintBarFont, new RectangleF(barX + 5, y, (float)chartControl.BarWidth, (float)(rectangleOffset)), 542 | FootBrintParTextColor.ToDxBrush(RenderTarget)); 543 | } 544 | } 545 | else 546 | { 547 | double maxVolume = double.MinValue; 548 | double maxAskVolume = double.MinValue; 549 | double maxBidVolume = double.MinValue; 550 | 551 | foreach (KeyValuePair kvp in FootprintBars[chartBarIndex].Footprints) 552 | { 553 | BidAskVolume t = kvp.Value; 554 | 555 | if ((t.askVolume + t.bidVolume) > maxVolume) { 556 | maxVolume = t.askVolume + t.bidVolume; 557 | maxVolumePrice = t.Price; 558 | } 559 | 560 | if (footPrintBarType == FootPrintBarEnum.BidAsk) { 561 | maxBidVolume = Math.Max(maxBidVolume, t.bidVolume); 562 | maxAskVolume = Math.Max(maxAskVolume, t.askVolume); 563 | } else { 564 | maxBidVolume = Math.Max(maxBidVolume, (t.bidVolume + t.askVolume)); 565 | maxAskVolume = Math.Max(maxAskVolume, (t.askVolume - t.askVolume)); 566 | } 567 | 568 | // y value of where our drawing will start minus our fontOffset 569 | int y = chartScale.GetYByValue(t.Price) - (int)(fontOffset); 570 | 571 | // sum up the totalDelta, currentVolume, and delta values 572 | totalDelta += t.askVolume; 573 | totalDelta -= t.bidVolume; 574 | barVolume = t.askVolume + t.bidVolume; 575 | 576 | double curr_percent = 100 * (barVolume / maxVolume); 577 | double curr_opacity = Math.Round((curr_percent / 100) * 0.8, 1); 578 | curr_opacity = curr_opacity == 0 ? 0.1 : curr_opacity; 579 | 580 | // set the color based on the volume direction 581 | SharpDX.Direct2D1.Brush footPrintBarColor = FootPrintBarUpColor.ToDxBrush(RenderTarget); 582 | if (t.askVolume < t.bidVolume) 583 | footPrintBarColor = FootPrintBarDownColor.ToDxBrush(RenderTarget); 584 | 585 | // draw the background color 586 | if (FootPrintBarColor == FootPrintBarColorEnum.VolumeBar) 587 | { 588 | double ratioAsk = 0; 589 | double ratioBid = 0; 590 | 591 | if (maxAskVolume != 0) 592 | ratioAsk = 1f - (t.askVolume / maxAskVolume); 593 | 594 | if (maxBidVolume != 0) 595 | ratioBid = 1f - (t.bidVolume / maxBidVolume); 596 | 597 | // determine the width of the rectangle based on the bid/ask volume 598 | double width = (chartControl.BarWidth - (chartControl.BarWidth * ratioBid)) + (chartControl.BarWidth - (chartControl.BarWidth * ratioAsk)); 599 | 600 | RenderTarget.FillRectangle(new RectangleF(x + (float)(chartControl.BarWidth * ratioBid), y, (float)(width), (float)(rectangleOffset)), footPrintBarColor); 601 | } 602 | else if (FootPrintBarColor == FootPrintBarColorEnum.Saturation) 603 | { 604 | footPrintBarColor.Opacity = (float)curr_opacity; 605 | RenderTarget.FillRectangle(new RectangleF(x, y, (float)(chartControl.BarWidth * 2), (float)(rectangleOffset)), footPrintBarColor); 606 | } 607 | else if (FootPrintBarColor == FootPrintBarColorEnum.Solid) 608 | { 609 | RenderTarget.FillRectangle(new RectangleF(x, y, (float)(chartControl.BarWidth * 2), (float)(rectangleOffset)), footPrintBarColor); 610 | } 611 | 612 | // create the bid/ask or volume/delta strings to show on the chart 613 | string bidStr = null; 614 | string askStr = null; 615 | if (footPrintBarType == FootPrintBarEnum.BidAsk) 616 | { 617 | bidStr = t.bidVolume.ToString(); 618 | askStr = t.askVolume.ToString(); 619 | } 620 | else 621 | { 622 | bidStr = barVolume.ToString(); 623 | askStr = barDelta.ToString(); 624 | } 625 | 626 | // draw the bid footprint bar string 627 | footPrintBarFont.TextAlignment = SharpDX.DirectWrite.TextAlignment.Trailing; 628 | if (t.Price == barClosePrice && closePriceIndicator == ClosePriceEnum.TextColor) 629 | RenderTarget.DrawText(bidStr, footPrintBarFont, new RectangleF(barX - 5 - (float)chartControl.BarWidth, y, (float)chartControl.BarWidth, (float)(rectangleOffset)), 630 | FootBrintParClosePriceColor.ToDxBrush(RenderTarget)); 631 | else 632 | RenderTarget.DrawText(bidStr, footPrintBarFont, new RectangleF(barX - 5 - (float)chartControl.BarWidth, y, (float)chartControl.BarWidth, (float)(rectangleOffset)), 633 | FootBrintParTextColor.ToDxBrush(RenderTarget)); 634 | 635 | // draw the ask footprint bar string 636 | footPrintBarFont.TextAlignment = SharpDX.DirectWrite.TextAlignment.Leading; 637 | if (t.Price == barClosePrice && closePriceIndicator == ClosePriceEnum.TextColor) 638 | RenderTarget.DrawText(askStr, footPrintBarFont, new RectangleF(barX + 5, y, (float)chartControl.BarWidth, (float)(rectangleOffset)), 639 | FootBrintParClosePriceColor.ToDxBrush(RenderTarget)); 640 | else 641 | RenderTarget.DrawText(askStr, footPrintBarFont, new RectangleF(barX + 5, y, (float)chartControl.BarWidth, (float)(rectangleOffset)), 642 | FootBrintParTextColor.ToDxBrush(RenderTarget)); 643 | } 644 | 645 | //Draw rectangle around point of max delta 646 | SharpDX.Direct2D1.Brush footBrintParHighestDeltaColor = FootBrintParHighestDeltaColor.ToDxBrush(RenderTarget); 647 | RenderTarget.DrawRectangle(new RectangleF(x, chartScale.GetYByValue(FootprintBars[chartBarIndex].FindMaxDeltaVolume()) - (int)(fontOffset), (float)(chartControl.BarWidth * 2), (float)(rectangleOffset)), footBrintParHighestDeltaColor, 3); 648 | 649 | //Draw rectangle around point of max volume. 650 | SharpDX.Direct2D1.Brush footBrintParHighestVolumeColor = FootBrintParHighestVolumeColor.ToDxBrush(RenderTarget); 651 | RenderTarget.DrawRectangle(new RectangleF(x, chartScale.GetYByValue(FootprintBars[chartBarIndex].MaxVolumePrice) - (int)(fontOffset), (float)(chartControl.BarWidth * 2), (float)(rectangleOffset)), footBrintParHighestVolumeColor, 2); 652 | 653 | 654 | } 655 | #endregion 656 | 657 | #region CandleStick Bars 658 | if (ShowCandleStickBars || ShowBodyBar) 659 | { 660 | if (Math.Abs(barOpenY - barCloseY) < 0.0000001) { 661 | // draw doji bar if no movement between open and close 662 | if (ShowCandleStickBars) { 663 | point0.X = x ; 664 | point0.Y = barCloseY; 665 | point1.X = x - 1; 666 | point1.Y = barCloseY; 667 | 668 | RenderTarget.DrawLine(point0, point1, ChartBars.Properties.ChartStyle.Stroke.BrushDX, 1); 669 | } 670 | 671 | if (ShowBodyBar) { 672 | point0.X = barX - 3; 673 | point0.Y = barCloseY; 674 | point1.X = barX + 3; 675 | point1.Y = barCloseY; 676 | 677 | RenderTarget.DrawLine(point0, point1, ChartBars.Properties.ChartStyle.Stroke.BrushDX, 1); 678 | } 679 | } else { 680 | if (ShowCandleStickBars) { 681 | rect.X = barX - 2;//(int)chartControl.BarWidth-7; 682 | rect.Y = Math.Min(barCloseY, barOpenY); 683 | rect.Width = 4; 684 | rect.Height = Math.Max(barOpenY, barCloseY) - Math.Min(barCloseY, barOpenY); 685 | 686 | // set the candlestick color based on open and close price 687 | System.Windows.Media.Brush candleStickColor = barClosePrice >= barOpenPrice ? ChartBars.Properties.ChartStyle.UpBrush : ChartBars.Properties.ChartStyle.DownBrush; 688 | 689 | // draw the candlestick 690 | RenderTarget.FillRectangle(rect, candleStickColor.ToDxBrush(RenderTarget)); 691 | 692 | // draw the candlestick outline color, the color and width come from the main chart properties 693 | RenderTarget.DrawRectangle(rect, ChartBars.Properties.ChartStyle.Stroke.BrushDX, ChartBars.Properties.ChartStyle.Stroke.Width); 694 | } 695 | 696 | if (ShowBodyBar) { 697 | rect.X = barX - (int)chartControl.BarWidth; 698 | rect.Y = Math.Min(barCloseY, barOpenY) ; 699 | rect.Width = barWidth * 2; 700 | rect.Height = (Math.Max(barOpenY, barCloseY) - Math.Min(barCloseY, barOpenY)) + (float)rectangleOffset; 701 | 702 | // set the candlestick color based on open and close price 703 | System.Windows.Media.Brush candleStickColor = barClosePrice >= barOpenPrice ? ChartBars.Properties.ChartStyle.UpBrush : ChartBars.Properties.ChartStyle.DownBrush; 704 | 705 | // draw the candlestick outline color, the color and width come from the main chart properties 706 | RenderTarget.DrawRectangle(rect, candleStickColor.ToDxBrush(RenderTarget), 2); 707 | } 708 | } 709 | 710 | if (ShowWicks) { 711 | // high wick 712 | if (barHighY < Math.Min(barOpenY, barCloseY)) { 713 | if (ShowCandleStickBars) { 714 | point0.X = barX ; 715 | point0.Y = barHighY; 716 | point1.X = barX ; 717 | point1.Y = Math.Min(barOpenY, barCloseY); 718 | 719 | // draw the high wick, the color and width come from the main chart properties 720 | RenderTarget.DrawLine(point0, point1, ChartBars.Properties.ChartStyle.Stroke2.BrushDX, ChartBars.Properties.ChartStyle.Stroke2.Width); 721 | } 722 | 723 | if (ShowBodyBar) { 724 | point0.X = barX; 725 | point0.Y = barHighY; 726 | point1.X = barX; 727 | 728 | if (Math.Abs(barOpenY - barCloseY) < 0.0000001) 729 | point1.Y = Math.Max(barOpenY, barCloseY); 730 | else 731 | point1.Y = Math.Max(barOpenY, barCloseY) + ((float)rectangleOffset / 2); 732 | } 733 | } 734 | 735 | // low wick 736 | if (barLowY > Math.Max(barOpenY, barCloseY)) { 737 | if (ShowCandleStickBars) { 738 | point0.X = barX ; 739 | point0.Y = barLowY; 740 | point1.X = barX ; 741 | point1.Y = Math.Max(barOpenY, barCloseY); 742 | 743 | // draw the low wick, the color and width come from the main chart properties 744 | RenderTarget.DrawLine(point0, point1, ChartBars.Properties.ChartStyle.Stroke2.BrushDX, ChartBars.Properties.ChartStyle.Stroke2.Width); 745 | } 746 | 747 | if (ShowBodyBar) { 748 | point0.X = barX; 749 | point0.Y = barLowY; 750 | point1.X = barX; 751 | 752 | if (Math.Abs(barOpenY - barCloseY) < 0.0000001) 753 | point1.Y = Math.Max(barOpenY, barCloseY); 754 | else 755 | point1.Y = Math.Max(barOpenY, barCloseY) + ((float)rectangleOffset / 2); 756 | 757 | } 758 | } 759 | } 760 | } 761 | #endregion 762 | 763 | 764 | // FOOTER 765 | #region Title Box Footer 766 | if (ShowFooter) { 767 | SharpDX.Direct2D1.Brush volumeColor; 768 | 769 | // set the volume background color 770 | volumeColor = BarVolumeBackgroundColor.ToDxBrush(RenderTarget); 771 | 772 | 773 | 774 | float xBar = chartControl.GetXByBarIndex(ChartBars, chartBarIndex) + (float)(chartControl.BarWidth); 775 | // 776 | // RenderTarget.FillRectangle(new RectangleF(xBar, (float)(ChartPanel.H - 57), (float)(chartControl.BarWidth * 2), (float)rectangleOffset), volumeColor); 777 | // RenderTarget.FillRectangle(new RectangleF(xBar, (float)(ChartPanel.H - 42), (float)(chartControl.BarWidth * 4), (float)rectangleOffset), volumeColor); 778 | // RenderTarget.FillRectangle(new RectangleF(xBar, (float)(ChartPanel.H - 27), (float)(chartControl.BarWidth * 4), (float)rectangleOffset), volumeColor); 779 | // RenderTarget.FillRectangle(new RectangleF(xBar, (float)(ChartPanel.H - 12), (float)(chartControl.BarWidth * 4), (float)rectangleOffset), volumeColor); 780 | 781 | // draw the Bar Delta text string 782 | // footPrintBarFont.TextAlignment = SharpDX.DirectWrite.TextAlignment.Center; 783 | // RenderTarget.DrawText(FootprintBars[chartBarIndex].ToString(), footPrintBarFont, new RectangleF(xBar, (float)(ChartPanel.H - 57), (float)(chartControl.BarWidth), (float)rectangleOffset), 784 | // FooterFontColor.ToDxBrush(RenderTarget), DrawTextOptions.None, MeasuringMode.GdiClassic); 785 | 786 | // // draw the Session Delta text string 787 | // // if(xBar != chartBarIndex) 788 | 789 | 790 | // testing ideas 791 | // RenderTarget.FillRectangle(new RectangleF(FootprintBars[chartBarIndex].BarDelta1, (float)(ChartPanel.H - 57), (float)(chartControl.BarWidth * 2), (float)rectangleOffset), volumeColor); 792 | 793 | 794 | 795 | // footPrintBarFont.TextAlignment = SharpDX.DirectWrite.TextAlignment.Center; 796 | // RenderTarget.DrawText("Session Delta".ToString(), footPrintBarFont, new RectangleF(xBar, (float)(ChartPanel.H - 42), (float)(chartControl.BarWidth * 4), (float)rectangleOffset), 797 | // FooterFontColor.ToDxBrush(RenderTarget), DrawTextOptions.None, MeasuringMode.GdiClassic); 798 | 799 | // // draw the Bar Volume text string 800 | // footPrintBarFont.TextAlignment = SharpDX.DirectWrite.TextAlignment.Center; 801 | // RenderTarget.DrawText("Bar Volume".ToString(), footPrintBarFont, new RectangleF(xBar, (float)(ChartPanel.H - 27), (float)(chartControl.BarWidth * 4), (float)rectangleOffset), 802 | // FooterFontColor.ToDxBrush(RenderTarget), DrawTextOptions.None, MeasuringMode.GdiClassic); 803 | 804 | // // draw the Session Volume text string 805 | // footPrintBarFont.TextAlignment = SharpDX.DirectWrite.TextAlignment.Center; 806 | // RenderTarget.DrawText("Session Volume".ToString(), footPrintBarFont, new RectangleF(xBar, (float)(ChartPanel.H - 12), (float)(chartControl.BarWidth * 4), (float)rectangleOffset), 807 | // FooterFontColor.ToDxBrush(RenderTarget), DrawTextOptions.None, MeasuringMode.GdiClassic); 808 | } 809 | #endregion 810 | 811 | #region Bar Delta Footer 812 | if (ShowFooter) { 813 | SharpDX.Direct2D1.Brush deltaColor; 814 | 815 | // set the background color based on the delta number 816 | if (totalDelta > 0) 817 | deltaColor = BarDeltaUpColor.ToDxBrush(RenderTarget); 818 | else 819 | deltaColor = BarDeltaDownColor.ToDxBrush(RenderTarget); 820 | 821 | float xBar = chartControl.GetXByBarIndex(ChartBars, chartBarIndex - 1) + (float)(chartControl.BarWidth+4 ); 822 | 823 | RenderTarget.FillRectangle(new RectangleF(xBar, (float)(ChartPanel.H - 57), (float)(chartControl.BarWidth * 2), (float)rectangleOffset), deltaColor); 824 | 825 | // draw the bar delta string 826 | footPrintBarFont.TextAlignment = SharpDX.DirectWrite.TextAlignment.Center; 827 | RenderTarget.DrawText(FootprintBars[chartBarIndex].Delta.ToString(), footPrintBarFont, new RectangleF(xBar, (float)(ChartPanel.H - 57), (float)(chartControl.BarWidth * 2), (float)rectangleOffset), 828 | FooterFontColor.ToDxBrush(RenderTarget), DrawTextOptions.None, MeasuringMode.GdiClassic); 829 | } 830 | #endregion 831 | 832 | #region Session delta Footer 833 | if (ShowFooter) { 834 | SharpDX.Direct2D1.Brush deltaColor; 835 | 836 | // set the session delta background color 837 | if (sessionDelta > 0) 838 | deltaColor = SessionDeltaUpColor.ToDxBrush(RenderTarget); 839 | else 840 | deltaColor = SessionDeltaDownColor.ToDxBrush(RenderTarget); 841 | 842 | float xBar = chartControl.GetXByBarIndex(ChartBars, chartBarIndex-1) + (float)(chartControl.BarWidth+4); 843 | 844 | RenderTarget.FillRectangle(new RectangleF(xBar, (float)(ChartPanel.H - 42), (float)(chartControl.BarWidth * 2), (float)rectangleOffset), deltaColor); 845 | 846 | // draw the session delta string 847 | footPrintBarFont.TextAlignment = SharpDX.DirectWrite.TextAlignment.Center; 848 | 849 | RenderTarget.DrawText(FootprintBars[chartBarIndex].SessionDelta.ToString(), footPrintBarFont, new RectangleF(xBar, (float)(ChartPanel.H - 42), (float)(chartControl.BarWidth * 2), (float)rectangleOffset), 850 | FooterFontColor.ToDxBrush(RenderTarget), DrawTextOptions.None, MeasuringMode.GdiClassic); 851 | } 852 | #endregion 853 | 854 | #region Bar Volume Footer 855 | if (ShowFooter) { 856 | SharpDX.Direct2D1.Brush volumeColor; 857 | 858 | // set the volume background color 859 | volumeColor = BarVolumeBackgroundColor.ToDxBrush(RenderTarget); 860 | 861 | float xBar = chartControl.GetXByBarIndex(ChartBars, chartBarIndex - 1) + (float)(chartControl.BarWidth+4); 862 | 863 | RenderTarget.FillRectangle(new RectangleF(xBar, (float)(ChartPanel.H - 27), (float)(chartControl.BarWidth * 2), (float)rectangleOffset), volumeColor); 864 | 865 | // draw the bar volume string 866 | footPrintBarFont.TextAlignment = SharpDX.DirectWrite.TextAlignment.Center; 867 | RenderTarget.DrawText(FootprintBars[chartBarIndex].Volume.ToString(), footPrintBarFont, new RectangleF(xBar, (float)(ChartPanel.H - 27), (float)(chartControl.BarWidth * 2), (float)rectangleOffset), 868 | FooterFontColor.ToDxBrush(RenderTarget), DrawTextOptions.None, MeasuringMode.GdiClassic); 869 | } 870 | #endregion 871 | 872 | #region Session Volume Footer 873 | if (ShowFooter) { 874 | SharpDX.Direct2D1.Brush volumeColor; 875 | 876 | // set the volume background color 877 | volumeColor = SessionVolumeBackgroundColor.ToDxBrush(RenderTarget); 878 | 879 | float xBar = chartControl.GetXByBarIndex(ChartBars, chartBarIndex - 1) + (float)(chartControl.BarWidth+4); 880 | 881 | RenderTarget.FillRectangle(new RectangleF(xBar, (float)(ChartPanel.H - 12), (float)(chartControl.BarWidth * 2), (float)rectangleOffset), volumeColor); 882 | 883 | // draw the session volume string 884 | footPrintBarFont.TextAlignment = SharpDX.DirectWrite.TextAlignment.Center; 885 | RenderTarget.DrawText(FootprintBars[chartBarIndex].SessionVolume.ToString(), footPrintBarFont, new RectangleF(xBar, (float)(ChartPanel.H - 12), (float)(chartControl.BarWidth * 2), (float)rectangleOffset), 886 | FooterFontColor.ToDxBrush(RenderTarget), DrawTextOptions.None, MeasuringMode.GdiClassic); 887 | } 888 | 889 | #endregion 890 | } 891 | } 892 | 893 | #region Properties 894 | 895 | #region Chart Properties 896 | [Range(1, int.MaxValue)] 897 | [NinjaScriptProperty] 898 | [Display(Name="Bar Spacing", Description="Sets the space between the footprint bars.", Order=1, GroupName="1. Chart Properties")] 899 | public int BarSpacing 900 | { 901 | get { return barSpacing; } 902 | set {barSpacing = Math.Max(1, value);} 903 | } 904 | 905 | [Range(1, int.MaxValue)] 906 | [NinjaScriptProperty] 907 | [Display(Name="Bar Width", Description="Sets the width of the footprint bars.", Order=2, GroupName="1. Chart Properties")] 908 | public int BarWidth 909 | { 910 | get { return barWidth; } 911 | set {barWidth = Math.Max(1, value);} 912 | } 913 | 914 | [NinjaScriptProperty] 915 | [Display(Name = "Bar Font", Description = "Text font for the chart bars.", Order = 4, GroupName = "1. Chart Properties")] 916 | public NinjaTrader.Gui.Tools.SimpleFont TextFont 917 | { 918 | get { return textFont; } 919 | set { textFont = value; } 920 | } 921 | #endregion 922 | 923 | #region CandleStick Properties 924 | [NinjaScriptProperty] 925 | [Display(Name="Show CandleStick", Order=1, Description = "Show the CandleStick.", GroupName="2. CandleStick Bar Properties")] 926 | public bool ShowCandleStickBars 927 | { get; set; } 928 | 929 | [NinjaScriptProperty] 930 | [Display(Name="Show Outline in FootPrint Bar", Order=2, Description = "Shows a candlestick outline in the FootPrint bar body.", GroupName="2. CandleStick Bar Properties")] 931 | public bool ShowBodyBar 932 | { get; set; } 933 | 934 | [NinjaScriptProperty] 935 | [Display(Name="Show Bar Wicks", Order=3, Description = "Show High/Low Wicks", GroupName="2. CandleStick Bar Properties")] 936 | public bool ShowWicks 937 | { get; set; } 938 | 939 | #endregion 940 | 941 | #region FootPrint Bar Properties 942 | [NinjaScriptProperty] 943 | [Display(Name="Bar Type", Description="Shows either Bid/Ask volume or Volume/Delta", Order=1, GroupName = "3. Candle Properties")] 944 | public FootPrintBarEnum FootPrintBarType 945 | { 946 | get { return footPrintBarType; } 947 | set { footPrintBarType = value; } 948 | } 949 | 950 | [NinjaScriptProperty] 951 | [Display(Name="Bar Color", Description="Shows either a volume bar or a saturation color backgroud.", Order=2, GroupName = "3. Candle Properties")] 952 | public FootPrintBarColorEnum FootPrintBarColor 953 | { 954 | get { return footPrintBarColor; } 955 | set { footPrintBarColor = value; } 956 | } 957 | 958 | [XmlIgnore] 959 | [Display(ResourceType = typeof(Custom.Resource), Name = "Text Color", Description = "Color for the text string.", Order = 3, GroupName = "3. Candle Properties")] 960 | public System.Windows.Media.Brush FootBrintParTextColor 961 | { get; set; } 962 | 963 | [Browsable(false)] 964 | public string FootBrintParTextColorSerialize 965 | { 966 | get { return Serialize.BrushToString(FootBrintParTextColor); } 967 | set { FootBrintParTextColor = Serialize.StringToBrush(value); } 968 | } 969 | 970 | [XmlIgnore] 971 | [Display(ResourceType = typeof(Custom.Resource), Name = "Volume Up Bar Color", Description = "Color for the up volume bars.", Order = 4, GroupName = "3. Candle Properties")] 972 | public System.Windows.Media.Brush FootPrintBarUpColor 973 | { get; set; } 974 | 975 | [Browsable(false)] 976 | public string FootPrintBarUpColorSerialize 977 | { 978 | get { return Serialize.BrushToString(FootPrintBarUpColor); } 979 | set { FootPrintBarUpColor = Serialize.StringToBrush(value); } 980 | } 981 | 982 | [XmlIgnore] 983 | [Display(ResourceType = typeof(Custom.Resource), Name = "Volume Down Bar Color", Description = "Color for the down volume bars.", Order = 5, GroupName = "3. Candle Properties")] 984 | public System.Windows.Media.Brush FootPrintBarDownColor 985 | { get; set; } 986 | 987 | [Browsable(false)] 988 | public string FootPrintBarDownColorSerialize 989 | { 990 | get { return Serialize.BrushToString(FootPrintBarDownColor); } 991 | set { FootPrintBarDownColor = Serialize.StringToBrush(value); } 992 | } 993 | 994 | [NinjaScriptProperty] 995 | [Display(Name="Close Indicator", Description="Indicates the close price in text or rectangle.", Order=6, GroupName = "3. Candle Properties")] 996 | public ClosePriceEnum ClosePriceIndicator 997 | { 998 | get { return closePriceIndicator; } 999 | set { closePriceIndicator = value; } 1000 | } 1001 | 1002 | [XmlIgnore] 1003 | [Display(ResourceType = typeof(Custom.Resource), Name = "Bar Close Color", Description = "Color for the close price.", Order = 7, GroupName = "3. Candle Properties")] 1004 | public System.Windows.Media.Brush FootBrintParClosePriceColor 1005 | { get; set; } 1006 | 1007 | [Browsable(false)] 1008 | public string FootBrintParClosePriceColorSerialize 1009 | { 1010 | get { return Serialize.BrushToString(FootBrintParClosePriceColor); } 1011 | set { FootBrintParClosePriceColor = Serialize.StringToBrush(value); } 1012 | } 1013 | 1014 | [NinjaScriptProperty] 1015 | [Display(Name="High Volume Indicator", Description="Indicates the high volume in text or rectangle.", Order=8, GroupName = "3. Candle Properties")] 1016 | public HighestVolumeEnum HighVolumeIndicator 1017 | { 1018 | get { return highestVolumeIndicator; } 1019 | set { highestVolumeIndicator = value; } 1020 | } 1021 | 1022 | 1023 | [XmlIgnore] 1024 | [Display(ResourceType = typeof(Custom.Resource), Name = "Highest Volume Indicator Color", Description = "Color for the high volume rectangle.", Order = 9, GroupName = "3. Candle Properties")] 1025 | public System.Windows.Media.Brush FootBrintParHighestVolumeColor 1026 | { get; set; } 1027 | 1028 | [Browsable(false)] 1029 | public string FootBrintParHighestVolumeBarColorSerialize 1030 | { 1031 | get { return Serialize.BrushToString(FootBrintParHighestVolumeColor); } 1032 | set { FootBrintParHighestVolumeColor = Serialize.StringToBrush(value); } 1033 | } 1034 | 1035 | [XmlIgnore] 1036 | [Display(ResourceType = typeof(Custom.Resource), Name = "Highest Volume Indicator Color", Description = "Color for the high volume rectangle.", Order = 9, GroupName = "3. Candle Properties")] 1037 | public System.Windows.Media.Brush FootBrintParHighestDeltaColor 1038 | { get; set; } 1039 | 1040 | [Browsable(false)] 1041 | public string FootBrintParHighestDeltaBarColorSerialize 1042 | { 1043 | get { return Serialize.BrushToString(FootBrintParHighestDeltaColor); } 1044 | set { FootBrintParHighestDeltaColor = Serialize.StringToBrush(value); } 1045 | } 1046 | #endregion 1047 | 1048 | #region Footer Properties 1049 | [NinjaScriptProperty] 1050 | [Display(Name="Show Footer Delta", Order=1, GroupName="4. Footer Properties")] 1051 | public bool ShowFooter 1052 | { get; set; } 1053 | 1054 | [XmlIgnore] 1055 | [Display(ResourceType = typeof(Custom.Resource), Name = "Text Color", Order = 2, GroupName = "4. Footer Properties")] 1056 | public System.Windows.Media.Brush FooterFontColor 1057 | { get; set; } 1058 | 1059 | [Browsable(false)] 1060 | public string FooterFontColorSerialize 1061 | { 1062 | get { return Serialize.BrushToString(FooterFontColor); } 1063 | set { FooterFontColor = Serialize.StringToBrush(value); } 1064 | } 1065 | 1066 | [XmlIgnore] 1067 | [Display(ResourceType = typeof(Custom.Resource), Name = "Bar Delta Up Background Color", Order = 3, GroupName = "4. Footer Properties")] 1068 | public System.Windows.Media.Brush BarDeltaUpColor 1069 | { get; set; } 1070 | 1071 | [Browsable(false)] 1072 | public string BarDeltaUpColorSerialize 1073 | { 1074 | get { return Serialize.BrushToString(BarDeltaUpColor); } 1075 | set { BarDeltaUpColor = Serialize.StringToBrush(value); } 1076 | } 1077 | 1078 | [XmlIgnore] 1079 | [Display(ResourceType = typeof(Custom.Resource), Name = "Bar Delta Down Background Color", Order = 4, GroupName = "4. Footer Properties")] 1080 | public System.Windows.Media.Brush BarDeltaDownColor 1081 | { get; set; } 1082 | 1083 | [Browsable(false)] 1084 | public string BarDeltaDownColorSerialize 1085 | { 1086 | get { return Serialize.BrushToString(BarDeltaDownColor); } 1087 | set { BarDeltaDownColor = Serialize.StringToBrush(value); } 1088 | } 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | [XmlIgnore] 1095 | [Display(ResourceType = typeof(Custom.Resource), Name = "Session Delta Up Background Color", Order = 5, GroupName = "4. Footer Properties")] 1096 | public System.Windows.Media.Brush SessionDeltaUpColor 1097 | { get; set; } 1098 | 1099 | [Browsable(false)] 1100 | public string SessionDeltaUpColorSerialize 1101 | { 1102 | get { return Serialize.BrushToString(SessionDeltaUpColor); } 1103 | set { SessionDeltaUpColor = Serialize.StringToBrush(value); } 1104 | } 1105 | 1106 | [XmlIgnore] 1107 | [Display(ResourceType = typeof(Custom.Resource), Name = "Session Delta Down Background Color", Order = 6, GroupName = "4. Footer Properties")] 1108 | public System.Windows.Media.Brush SessionDeltaDownColor 1109 | { get; set; } 1110 | 1111 | [Browsable(false)] 1112 | public string SessionDeltaDownColorSerialize 1113 | { 1114 | get { return Serialize.BrushToString(SessionDeltaDownColor); } 1115 | set { SessionDeltaDownColor = Serialize.StringToBrush(value); } 1116 | } 1117 | #endregion 1118 | 1119 | [XmlIgnore] 1120 | [Display(ResourceType = typeof(Custom.Resource), Name = "Bar Volume Background Color", Order = 7, GroupName = "4. Footer Properties")] 1121 | public System.Windows.Media.Brush BarVolumeBackgroundColor 1122 | { get; set; } 1123 | 1124 | [Browsable(false)] 1125 | public string BarVolumeBackgroundColorSerialize 1126 | { 1127 | get { return Serialize.BrushToString(BarVolumeBackgroundColor); } 1128 | set { BarVolumeBackgroundColor = Serialize.StringToBrush(value); } 1129 | } 1130 | [XmlIgnore] 1131 | [Display(ResourceType = typeof(Custom.Resource), Name = "Session Volume Background Color", Order = 8, GroupName = "4. Footer Properties")] 1132 | public System.Windows.Media.Brush SessionVolumeBackgroundColor 1133 | { get; set; } 1134 | 1135 | [Browsable(false)] 1136 | public string SessionVolumeBackgroundColorSerialize 1137 | { 1138 | get { return Serialize.BrushToString(SessionVolumeBackgroundColor); } 1139 | set { SessionVolumeBackgroundColor = Serialize.StringToBrush(value); } 1140 | } 1141 | #endregion 1142 | 1143 | #region PriceLine 1144 | [NinjaScriptProperty] 1145 | [Display(Name="Show current price", Order=1, GroupName="7. CurrentPrice")] 1146 | public bool ShowCurrentPrice 1147 | { get; set; } 1148 | 1149 | [XmlIgnore] 1150 | [Display(Name="Spread Color", Description="Price SPREAD color", Order=2, GroupName="7. CurrentPrice")] 1151 | public System.Windows.Media.Brush LineSpreadColor 1152 | { get; set; } 1153 | 1154 | [Browsable(false)] 1155 | public string LineSpreadColorSerializable 1156 | { 1157 | get { return Serialize.BrushToString(LineSpreadColor); } 1158 | set { LineSpreadColor = Serialize.StringToBrush(value); } 1159 | } 1160 | [XmlIgnore] 1161 | [Display(Name="Short Color", Description="Price SHORT color", Order=3, GroupName="7. CurrentPrice")] 1162 | public System.Windows.Media.Brush LineShortColor 1163 | { get; set; } 1164 | 1165 | [Browsable(false)] 1166 | public string LineShortColorSerializable 1167 | { 1168 | get { return Serialize.BrushToString(LineShortColor); } 1169 | set { LineShortColor = Serialize.StringToBrush(value); } 1170 | } 1171 | 1172 | [XmlIgnore] 1173 | [Display(Name="Long Color", Description="Price LONG color", Order=4, GroupName="7. CurrentPrice")] 1174 | public System.Windows.Media.Brush LineLongColor 1175 | { get; set; } 1176 | 1177 | [Browsable(false)] 1178 | public string LineLongColorSerializable 1179 | { 1180 | get { return Serialize.BrushToString(LineLongColor); } 1181 | set { LineLongColor = Serialize.StringToBrush(value); } 1182 | } 1183 | 1184 | 1185 | [NinjaScriptProperty] 1186 | [Display(Name="LineStyle", Description="Price Line Style", Order=5, GroupName="7. CurrentPrice")] 1187 | public DashStyleHelper LineStyle 1188 | { get; set; } 1189 | 1190 | [Range(1, int.MaxValue)] 1191 | [NinjaScriptProperty] 1192 | [Display(Name="LineWidth", Description="Price Line Width", Order=6, GroupName="7. CurrentPrice")] 1193 | public int LineWidth 1194 | { get; set; } 1195 | 1196 | #endregion 1197 | } 1198 | } 1199 | 1200 | #region NinjaScript generated code. Neither change nor remove. 1201 | 1202 | namespace NinjaTrader.NinjaScript.Indicators 1203 | { 1204 | public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase 1205 | { 1206 | private FootprintChart[] cacheFootprintChart; 1207 | public FootprintChart FootprintChart(int barSpacing, int barWidth, NinjaTrader.Gui.Tools.SimpleFont textFont, bool showCandleStickBars, bool showBodyBar, bool showWicks, FootPrintBarEnum footPrintBarType, FootPrintBarColorEnum footPrintBarColor, ClosePriceEnum closePriceIndicator, HighestVolumeEnum highVolumeIndicator, bool showFooter, bool showCurrentPrice, DashStyleHelper lineStyle, int lineWidth) 1208 | { 1209 | return FootprintChart(Input, barSpacing, barWidth, textFont, showCandleStickBars, showBodyBar, showWicks, footPrintBarType, footPrintBarColor, closePriceIndicator, highVolumeIndicator, showFooter, showCurrentPrice, lineStyle, lineWidth); 1210 | } 1211 | 1212 | public FootprintChart FootprintChart(ISeries input, int barSpacing, int barWidth, NinjaTrader.Gui.Tools.SimpleFont textFont, bool showCandleStickBars, bool showBodyBar, bool showWicks, FootPrintBarEnum footPrintBarType, FootPrintBarColorEnum footPrintBarColor, ClosePriceEnum closePriceIndicator, HighestVolumeEnum highVolumeIndicator, bool showFooter, bool showCurrentPrice, DashStyleHelper lineStyle, int lineWidth) 1213 | { 1214 | if (cacheFootprintChart != null) 1215 | for (int idx = 0; idx < cacheFootprintChart.Length; idx++) 1216 | if (cacheFootprintChart[idx] != null && cacheFootprintChart[idx].BarSpacing == barSpacing && cacheFootprintChart[idx].BarWidth == barWidth && cacheFootprintChart[idx].TextFont == textFont && cacheFootprintChart[idx].ShowCandleStickBars == showCandleStickBars && cacheFootprintChart[idx].ShowBodyBar == showBodyBar && cacheFootprintChart[idx].ShowWicks == showWicks && cacheFootprintChart[idx].FootPrintBarType == footPrintBarType && cacheFootprintChart[idx].FootPrintBarColor == footPrintBarColor && cacheFootprintChart[idx].ClosePriceIndicator == closePriceIndicator && cacheFootprintChart[idx].HighVolumeIndicator == highVolumeIndicator && cacheFootprintChart[idx].ShowFooter == showFooter && cacheFootprintChart[idx].ShowCurrentPrice == showCurrentPrice && cacheFootprintChart[idx].LineStyle == lineStyle && cacheFootprintChart[idx].LineWidth == lineWidth && cacheFootprintChart[idx].EqualsInput(input)) 1217 | return cacheFootprintChart[idx]; 1218 | return CacheIndicator(new FootprintChart(){ BarSpacing = barSpacing, BarWidth = barWidth, TextFont = textFont, ShowCandleStickBars = showCandleStickBars, ShowBodyBar = showBodyBar, ShowWicks = showWicks, FootPrintBarType = footPrintBarType, FootPrintBarColor = footPrintBarColor, ClosePriceIndicator = closePriceIndicator, HighVolumeIndicator = highVolumeIndicator, ShowFooter = showFooter, ShowCurrentPrice = showCurrentPrice, LineStyle = lineStyle, LineWidth = lineWidth }, input, ref cacheFootprintChart); 1219 | } 1220 | } 1221 | } 1222 | 1223 | namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns 1224 | { 1225 | public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase 1226 | { 1227 | public Indicators.FootprintChart FootprintChart(int barSpacing, int barWidth, NinjaTrader.Gui.Tools.SimpleFont textFont, bool showCandleStickBars, bool showBodyBar, bool showWicks, FootPrintBarEnum footPrintBarType, FootPrintBarColorEnum footPrintBarColor, ClosePriceEnum closePriceIndicator, HighestVolumeEnum highVolumeIndicator, bool showFooter, bool showCurrentPrice, DashStyleHelper lineStyle, int lineWidth) 1228 | { 1229 | return indicator.FootprintChart(Input, barSpacing, barWidth, textFont, showCandleStickBars, showBodyBar, showWicks, footPrintBarType, footPrintBarColor, closePriceIndicator, highVolumeIndicator, showFooter, showCurrentPrice, lineStyle, lineWidth); 1230 | } 1231 | 1232 | public Indicators.FootprintChart FootprintChart(ISeries input , int barSpacing, int barWidth, NinjaTrader.Gui.Tools.SimpleFont textFont, bool showCandleStickBars, bool showBodyBar, bool showWicks, FootPrintBarEnum footPrintBarType, FootPrintBarColorEnum footPrintBarColor, ClosePriceEnum closePriceIndicator, HighestVolumeEnum highVolumeIndicator, bool showFooter, bool showCurrentPrice, DashStyleHelper lineStyle, int lineWidth) 1233 | { 1234 | return indicator.FootprintChart(input, barSpacing, barWidth, textFont, showCandleStickBars, showBodyBar, showWicks, footPrintBarType, footPrintBarColor, closePriceIndicator, highVolumeIndicator, showFooter, showCurrentPrice, lineStyle, lineWidth); 1235 | } 1236 | } 1237 | } 1238 | 1239 | namespace NinjaTrader.NinjaScript.Strategies 1240 | { 1241 | public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase 1242 | { 1243 | public Indicators.FootprintChart FootprintChart(int barSpacing, int barWidth, NinjaTrader.Gui.Tools.SimpleFont textFont, bool showCandleStickBars, bool showBodyBar, bool showWicks, FootPrintBarEnum footPrintBarType, FootPrintBarColorEnum footPrintBarColor, ClosePriceEnum closePriceIndicator, HighestVolumeEnum highVolumeIndicator, bool showFooter, bool showCurrentPrice, DashStyleHelper lineStyle, int lineWidth) 1244 | { 1245 | return indicator.FootprintChart(Input, barSpacing, barWidth, textFont, showCandleStickBars, showBodyBar, showWicks, footPrintBarType, footPrintBarColor, closePriceIndicator, highVolumeIndicator, showFooter, showCurrentPrice, lineStyle, lineWidth); 1246 | } 1247 | 1248 | public Indicators.FootprintChart FootprintChart(ISeries input , int barSpacing, int barWidth, NinjaTrader.Gui.Tools.SimpleFont textFont, bool showCandleStickBars, bool showBodyBar, bool showWicks, FootPrintBarEnum footPrintBarType, FootPrintBarColorEnum footPrintBarColor, ClosePriceEnum closePriceIndicator, HighestVolumeEnum highVolumeIndicator, bool showFooter, bool showCurrentPrice, DashStyleHelper lineStyle, int lineWidth) 1249 | { 1250 | return indicator.FootprintChart(input, barSpacing, barWidth, textFont, showCandleStickBars, showBodyBar, showWicks, footPrintBarType, footPrintBarColor, closePriceIndicator, highVolumeIndicator, showFooter, showCurrentPrice, lineStyle, lineWidth); 1251 | } 1252 | } 1253 | } 1254 | 1255 | #endregion 1256 | -------------------------------------------------------------------------------- /Indicators/Level2Column.cs: -------------------------------------------------------------------------------- 1 | #region Using declarations 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | using System.Windows.Media; 9 | using System.Xml.Serialization; 10 | using NinjaTrader.Cbi; 11 | using NinjaTrader.Core; 12 | using NinjaTrader.Gui; 13 | using NinjaTrader.Gui.Chart; 14 | using NinjaTrader.Gui.SuperDom; 15 | using NinjaTrader.Gui.Tools; 16 | using NinjaTrader.Data; 17 | using NinjaTrader.NinjaScript; 18 | using NinjaTrader.Core.FloatingPoint; 19 | using NinjaTrader.NinjaScript.DrawingTools; 20 | using SharpDX; 21 | using SharpDX.DirectWrite; 22 | #endregion 23 | 24 | //This namespace holds Indicators in this folder and is required. Do not change it. 25 | namespace NinjaTrader.NinjaScript.Indicators 26 | { 27 | 28 | public class Level2Column : ColumnPanel 29 | { 30 | public class RowData 31 | { 32 | public long Liquidity; 33 | public double Price; 34 | public MarketDataType DataType; 35 | public bool Active; 36 | public RowData(double price, long liquidity, MarketDataType dataType, bool active) 37 | { 38 | Liquidity = liquidity; 39 | Price = price; 40 | DataType = dataType; 41 | Active = active; 42 | } 43 | } 44 | 45 | public class OrderBook 46 | { 47 | public Dictionary Data; 48 | public Double HighestLiquidityPrice; 49 | public long HighestLiquidity; 50 | 51 | public OrderBook() 52 | { 53 | Data = new Dictionary(); 54 | } 55 | 56 | public void Update(MarketDepthEventArgs args) 57 | { 58 | RowData val; 59 | 60 | if(args.Operation == Operation.Update || args.Operation == Operation.Add) 61 | { 62 | if (Data.TryGetValue(args.Price, out val)) 63 | { 64 | val.Price = args.Price; 65 | val.Liquidity = args.Volume; 66 | val.DataType = args.MarketDataType; 67 | val.Active = true; 68 | } 69 | else 70 | { 71 | Data.Add(args.Price, new RowData(args.Price, args.Volume, args.MarketDataType, true)); 72 | } 73 | } 74 | 75 | else if(args.Operation == Operation.Remove) 76 | { 77 | if (Data.TryGetValue(args.Price, out val)) 78 | { 79 | val.Active = false; 80 | } 81 | } 82 | 83 | FindHighestLiqudity(); 84 | } 85 | 86 | public void FindHighestLiqudity() 87 | { 88 | long highestLiquidity = 0; 89 | Double highestLiquidityPrice = 0; 90 | 91 | foreach(KeyValuePair pair in Data) 92 | { 93 | if(pair.Value.Liquidity > highestLiquidity) 94 | { 95 | highestLiquidity = pair.Value.Liquidity; 96 | highestLiquidityPrice = pair.Value.Price; 97 | } 98 | } 99 | 100 | HighestLiquidity = highestLiquidity; 101 | HighestLiquidityPrice = HighestLiquidityPrice; 102 | } 103 | 104 | } 105 | 106 | 107 | 108 | #region Variables 109 | 110 | 111 | private OrderBook MyOrderBook = new OrderBook(); 112 | 113 | public int ColumnIndex = 0; 114 | 115 | #endregion 116 | 117 | protected override void OnStateChange() 118 | { 119 | base.OnStateChange(); 120 | 121 | if (State == State.SetDefaults) 122 | { 123 | Description = "Draws level2 info as a colum next to your chart."; 124 | Name = "Level2 Column"; 125 | Calculate = Calculate.OnEachTick; 126 | IsOverlay = true; 127 | IsAutoScale = false; 128 | DrawOnPricePanel = true; 129 | PaintPriceMarkers = false; 130 | IsSuspendedWhileInactive = false; 131 | BarsRequiredToPlot = 2; 132 | ScaleJustification = ScaleJustification.Right; 133 | 134 | AskColor = Brushes.CornflowerBlue; 135 | BidColor = Brushes.Orange; 136 | InactiveAskColor = Brushes.Blue; 137 | InactiveBidColor = Brushes.DarkOrange; 138 | textSize = 11; 139 | ResizableWidth = 30; 140 | } 141 | else if (State == State.Configure) 142 | { 143 | ZOrder = ChartBars.ZOrder + 1; 144 | } 145 | } 146 | 147 | protected override void OnMarketDepth(MarketDepthEventArgs e) 148 | { 149 | MyOrderBook.Update(e); 150 | ForceRefresh(); 151 | } 152 | 153 | // OnRender 154 | protected override void OnRender(ChartControl chartControl, ChartScale chartScale) 155 | { 156 | base.OnRender(chartControl, chartScale); 157 | if(Bars == null || Bars.Instrument == null || CurrentBar < 1) { return; } 158 | 159 | LastRender = DateTime.Now; 160 | 161 | try 162 | { 163 | 164 | foreach(KeyValuePair row in MyOrderBook.Data) 165 | { 166 | drawRow(chartControl, chartScale, row.Value); 167 | } 168 | 169 | } 170 | catch(Exception e) 171 | { 172 | 173 | Print("Level2Column: " + e.Message); 174 | } 175 | } 176 | 177 | private void drawRow(ChartControl chartControl, ChartScale chartScale, RowData row) 178 | { 179 | Brush brushColor = AskColor; 180 | 181 | //Determine color of this row. 182 | if(row.DataType == MarketDataType.Ask && row.Active == true) 183 | brushColor = AskColor; 184 | if(row.DataType == MarketDataType.Ask && row.Active == false) 185 | brushColor = InactiveAskColor; 186 | if(row.DataType == MarketDataType.Bid && row.Active == true) 187 | brushColor = BidColor; 188 | if(row.DataType == MarketDataType.Bid && row.Active == false) 189 | brushColor = InactiveBidColor; 190 | 191 | //Calculate Histogram width. 192 | double percentage = ((double)row.Liquidity / MyOrderBook.HighestLiquidity); 193 | double histogram = ResizableWidth * percentage; 194 | 195 | //Calculate Cell Properties 196 | double y1 = ((chartScale.GetYByValue(row.Price) + chartScale.GetYByValue(row.Price + TickSize)) / 2) + 1; 197 | double y2 = ((chartScale.GetYByValue(row.Price) + chartScale.GetYByValue(row.Price - TickSize)) / 2) - 1; 198 | 199 | SharpDX.RectangleF rect = new SharpDX.RectangleF(); 200 | rect.X = (float)chartControl.CanvasRight - Position; 201 | rect.Y = (float)y1; 202 | rect.Width = (float)-(MinimumWidth + histogram); 203 | rect.Height = (float)Math.Abs(y1 - y2); 204 | 205 | //Draw the row. 206 | using(SharpDX.Direct2D1.Brush rowBrush = brushColor.ToDxBrush(RenderTarget)) 207 | { 208 | RenderTarget.FillRectangle(rect, rowBrush); 209 | } 210 | 211 | if(rect.Height > this.MinimumTextHeight) 212 | { 213 | RenderTarget.DrawText(string.Format("{0}", row.Liquidity), textFormat, rect, TextColor.ToDxBrush(RenderTarget)); 214 | } 215 | } 216 | 217 | #region Properties 218 | 219 | [NinjaScriptProperty] 220 | [XmlIgnore] 221 | [Display(Name = "Bid Color", GroupName = "Parameters", Order = 9)] 222 | public Brush BidColor 223 | { get; set; } 224 | 225 | [Browsable(false)] 226 | public string BidColorSerializable 227 | { 228 | get { return Serialize.BrushToString(BidColor); } 229 | set { BidColor = Serialize.StringToBrush(value); } 230 | } 231 | 232 | [NinjaScriptProperty] 233 | [XmlIgnore] 234 | [Display(Name = "Ask Color", GroupName = "Parameters", Order = 9)] 235 | public Brush AskColor 236 | { get; set; } 237 | 238 | [Browsable(false)] 239 | public string AskColorSerializable 240 | { 241 | get { return Serialize.BrushToString(AskColor); } 242 | set { AskColor = Serialize.StringToBrush(value); } 243 | } 244 | 245 | [NinjaScriptProperty] 246 | [XmlIgnore] 247 | [Display(Name = "Inactive Bid Color", GroupName = "Parameters", Order = 9)] 248 | public Brush InactiveBidColor 249 | { get; set; } 250 | 251 | [Browsable(false)] 252 | public string InactiveBidColorSerializable 253 | { 254 | get { return Serialize.BrushToString(InactiveBidColor); } 255 | set { InactiveBidColor = Serialize.StringToBrush(value); } 256 | } 257 | 258 | [NinjaScriptProperty] 259 | [XmlIgnore] 260 | [Display(Name = "Inactive Ask Color", GroupName = "Parameters", Order = 9)] 261 | public Brush InactiveAskColor 262 | { get; set; } 263 | 264 | [Browsable(false)] 265 | public string InactiveAskColorSerializable 266 | { 267 | get { return Serialize.BrushToString(InactiveAskColor); } 268 | set { InactiveAskColor = Serialize.StringToBrush(value); } 269 | } 270 | 271 | #endregion; 272 | 273 | } 274 | } 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | -------------------------------------------------------------------------------- /Indicators/Spread.cs: -------------------------------------------------------------------------------- 1 | #region Using declarations 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Xml.Serialization; 13 | using NinjaTrader.Cbi; 14 | using NinjaTrader.Gui; 15 | using NinjaTrader.Gui.Chart; 16 | using NinjaTrader.Gui.SuperDom; 17 | using NinjaTrader.Gui.Tools; 18 | using NinjaTrader.Data; 19 | using NinjaTrader.NinjaScript; 20 | using NinjaTrader.Core.FloatingPoint; 21 | using NinjaTrader.NinjaScript.DrawingTools; 22 | #endregion 23 | 24 | //This namespace holds Indicators in this folder and is required. Do not change it. 25 | namespace NinjaTrader.NinjaScript.Indicators 26 | { 27 | public class Spread : Indicator 28 | { 29 | protected override void OnStateChange() 30 | { 31 | if (State == State.SetDefaults) 32 | { 33 | Description = @"Shows the difference between two instruments."; 34 | Name = "Spread"; 35 | Calculate = Calculate.OnPriceChange; 36 | IsOverlay = false; 37 | DisplayInDataBox = true; 38 | DrawOnPricePanel = true; 39 | DrawHorizontalGridLines = true; 40 | DrawVerticalGridLines = true; 41 | PaintPriceMarkers = true; 42 | ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right; 43 | BarsRequiredToPlot = 1; 44 | //Disable this property if your indicator requires custom values that cumulate with each new market data event. 45 | //See Help Guide for additional information. 46 | IsSuspendedWhileInactive = true; 47 | FrontLeg = string.Empty; 48 | BackLeg = string.Empty; 49 | FrontRatio = 3; 50 | BackRatio = 1; 51 | AddPlot(Brushes.Orange, "MySpread"); 52 | } 53 | else if (State == State.Configure) 54 | { 55 | AddDataSeries(FrontLeg, BarsArray[0].BarsPeriod); 56 | AddDataSeries(BackLeg, BarsArray[0].BarsPeriod); 57 | } 58 | } 59 | 60 | protected override void OnBarUpdate() 61 | { 62 | if (CurrentBars[0] <= BarsRequiredToPlot || CurrentBars[1] <= BarsRequiredToPlot || CurrentBars[2] <= BarsRequiredToPlot) 63 | return; 64 | 65 | Value[0] = BarsArray[1][0] * FrontRatio - BarsArray[2][0] * BackRatio; 66 | } 67 | 68 | #region Properties 69 | [NinjaScriptProperty] 70 | [Display(Name="FrontLeg", Description="Front leg of the contract EG ZN 06-17", Order=1, GroupName="Parameters")] 71 | public string FrontLeg 72 | { get; set; } 73 | 74 | [NinjaScriptProperty] 75 | [Display(Name="FrontRatio", Description="Ratio for front leg. See http://www.cmegroup.com/trading/interest-rates/intercommodity-spread.html", Order=1, GroupName="Parameters")] 76 | public int FrontRatio 77 | { get; set; } 78 | 79 | [NinjaScriptProperty] 80 | [Display(Name="BackLeg", Description="Back leg of the contract eg ZB 06-17", Order=2, GroupName="Parameters")] 81 | public string BackLeg 82 | { get; set; } 83 | 84 | [NinjaScriptProperty] 85 | [Display(Name="BackRatio", Description="Ratio for back leg. See http://www.cmegroup.com/trading/interest-rates/intercommodity-spread.html", Order=1, GroupName="Parameters")] 86 | public int BackRatio 87 | { get; set; } 88 | 89 | [Browsable(false)] 90 | [XmlIgnore] 91 | public Series MySpread 92 | { 93 | get { return Values[0]; } 94 | } 95 | #endregion 96 | 97 | } 98 | } 99 | 100 | #region NinjaScript generated code. Neither change nor remove. 101 | 102 | namespace NinjaTrader.NinjaScript.Indicators 103 | { 104 | public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase 105 | { 106 | private Spread[] cacheSpread; 107 | public Spread Spread(string frontLeg, int frontRatio, string backLeg, int backRatio) 108 | { 109 | return Spread(Input, frontLeg, frontRatio, backLeg, backRatio); 110 | } 111 | 112 | public Spread Spread(ISeries input, string frontLeg, int frontRatio, string backLeg, int backRatio) 113 | { 114 | if (cacheSpread != null) 115 | for (int idx = 0; idx < cacheSpread.Length; idx++) 116 | if (cacheSpread[idx] != null && cacheSpread[idx].FrontLeg == frontLeg && cacheSpread[idx].FrontRatio == frontRatio && cacheSpread[idx].BackLeg == backLeg && cacheSpread[idx].BackRatio == backRatio && cacheSpread[idx].EqualsInput(input)) 117 | return cacheSpread[idx]; 118 | return CacheIndicator(new Spread(){ FrontLeg = frontLeg, FrontRatio = frontRatio, BackLeg = backLeg, BackRatio = backRatio }, input, ref cacheSpread); 119 | } 120 | } 121 | } 122 | 123 | namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns 124 | { 125 | public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase 126 | { 127 | public Indicators.Spread Spread(string frontLeg, int frontRatio, string backLeg, int backRatio) 128 | { 129 | return indicator.Spread(Input, frontLeg, frontRatio, backLeg, backRatio); 130 | } 131 | 132 | public Indicators.Spread Spread(ISeries input , string frontLeg, int frontRatio, string backLeg, int backRatio) 133 | { 134 | return indicator.Spread(input, frontLeg, frontRatio, backLeg, backRatio); 135 | } 136 | } 137 | } 138 | 139 | namespace NinjaTrader.NinjaScript.Strategies 140 | { 141 | public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase 142 | { 143 | public Indicators.Spread Spread(string frontLeg, int frontRatio, string backLeg, int backRatio) 144 | { 145 | return indicator.Spread(Input, frontLeg, frontRatio, backLeg, backRatio); 146 | } 147 | 148 | public Indicators.Spread Spread(ISeries input , string frontLeg, int frontRatio, string backLeg, int backRatio) 149 | { 150 | return indicator.Spread(input, frontLeg, frontRatio, backLeg, backRatio); 151 | } 152 | } 153 | } 154 | 155 | #endregion 156 | -------------------------------------------------------------------------------- /Indicators/VolumeProfileColumn.cs: -------------------------------------------------------------------------------- 1 | #region Using declarations 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Media; 10 | using System.Xml.Serialization; 11 | using NinjaTrader.Cbi; 12 | using NinjaTrader.Core; 13 | using NinjaTrader.Gui; 14 | using NinjaTrader.Gui.Chart; 15 | using NinjaTrader.Gui.SuperDom; 16 | using NinjaTrader.Gui.Tools; 17 | using NinjaTrader.Data; 18 | using NinjaTrader.NinjaScript; 19 | using NinjaTrader.Core.FloatingPoint; 20 | using NinjaTrader.NinjaScript.DrawingTools; 21 | using SharpDX; 22 | using SharpDX.DirectWrite; 23 | #endregion 24 | 25 | //This namespace holds Indicators in this folder and is required. Do not change it. 26 | namespace NinjaTrader.NinjaScript.Indicators 27 | { 28 | 29 | public class VolumeProfileColumn : ColumnPanel 30 | { 31 | public class RowData 32 | { 33 | public long TotalVolume; 34 | public long AskVolume; 35 | public long BidVolume; 36 | public long DeltaVolume; 37 | public double Price; 38 | 39 | public RowData(long totalVolume, long askVolume, long bidVolume, double price) 40 | { 41 | TotalVolume = totalVolume; 42 | AskVolume = askVolume; 43 | BidVolume = bidVolume; 44 | DeltaVolume = bidVolume - askVolume; 45 | Price = price; 46 | } 47 | } 48 | 49 | public class Profile 50 | { 51 | public Dictionary Data; 52 | public long HiValue; 53 | public double HiPrice; 54 | 55 | public Profile() 56 | { 57 | Data = new Dictionary(); 58 | } 59 | 60 | public void AddAskVolume(double price, long volume) 61 | { 62 | RowData val; 63 | 64 | if (Data.TryGetValue(price, out val)) 65 | { 66 | val.AskVolume += volume; 67 | val.TotalVolume += volume; 68 | } 69 | else 70 | { 71 | Data.Add(price, new RowData(volume, volume, 0, price)); 72 | } 73 | 74 | CalculateValues(); 75 | } 76 | 77 | public void AddBidVolume(double price, long volume) 78 | { 79 | RowData val; 80 | 81 | if (Data.TryGetValue(price, out val)) 82 | { 83 | val.BidVolume += volume; 84 | val.TotalVolume += volume; 85 | } 86 | else 87 | { 88 | Data.Add(price, new RowData(volume, 0, volume, price)); 89 | } 90 | 91 | CalculateValues(); 92 | } 93 | 94 | public void CalculateValues() 95 | { 96 | HiValue = 0; 97 | 98 | foreach(KeyValuePair kvp in Data) 99 | { 100 | RowData r = kvp.Value; 101 | 102 | if(Math.Abs(r.TotalVolume) > HiValue) 103 | { 104 | HiValue = Math.Abs(r.TotalVolume); 105 | HiPrice = r.Price; 106 | } 107 | } 108 | } 109 | } 110 | 111 | #region Private Variables 112 | 113 | 114 | private Profile myProfile = new Profile(); 115 | private SessionIterator sessionIterator; 116 | 117 | #endregion 118 | 119 | protected override void OnStateChange() 120 | { 121 | base.OnStateChange(); 122 | 123 | if (State == State.SetDefaults) 124 | { 125 | Description = "Shows volume traded at each price for specified time period."; 126 | Name = "Volume Profile Column"; 127 | Calculate = Calculate.OnEachTick; 128 | IsOverlay = true; 129 | IsAutoScale = false; 130 | DrawOnPricePanel = true; 131 | PaintPriceMarkers = false; 132 | IsSuspendedWhileInactive = false; 133 | BarsRequiredToPlot = 2; 134 | ScaleJustification = ScaleJustification.Right; 135 | 136 | positiveColor = Brushes.CornflowerBlue; 137 | negativeColor = Brushes.Orange; 138 | neutralColor = Brushes.White; 139 | textSize = 11; 140 | ResizableWidth = 30; 141 | } 142 | else if (State == State.Configure) 143 | { 144 | ZOrder = ChartBars.ZOrder - 1; 145 | 146 | if(!Bars.IsTickReplay) 147 | { 148 | Draw.TextFixed(this, "tickReplay", "Please enable Tick Replay!", TextPosition.TopRight); 149 | } 150 | 151 | //AddDataSeries(BarsPeriodType.Day, 1); 152 | sessionIterator = new SessionIterator(Bars); 153 | } 154 | } 155 | 156 | protected override void OnBarUpdate() 157 | { 158 | 159 | if(CurrentBars[0] <= BarsRequiredToPlot) return; 160 | 161 | //Reset profile on session week or day. 162 | if(IsFirstTickOfBar && ResetProfileOn != Timeframe.Never) 163 | { 164 | DateTime previous = sessionIterator.GetTradingDay(Time[1]); 165 | DateTime current = sessionIterator.GetTradingDay(Time[0]); 166 | 167 | //Reset profile on daily basis. 168 | if(ResetProfileOn == Timeframe.Session && !current.DayOfWeek.Equals(previous.DayOfWeek)) 169 | { 170 | myProfile = new Profile(); 171 | } 172 | 173 | //Reset profile on weekly basis. 174 | else if(ResetProfileOn == Timeframe.Week && current.DayOfWeek.CompareTo(previous.DayOfWeek) < 0) 175 | { 176 | myProfile = new Profile(); 177 | } 178 | 179 | //Reset profile on monthly basis. 180 | else if(ResetProfileOn != Timeframe.Month && !current.Month.Equals(previous.Month)) 181 | { 182 | myProfile = new Profile(); 183 | } 184 | } 185 | } 186 | 187 | protected override void OnMarketData(MarketDataEventArgs e) 188 | { 189 | if (e.MarketDataType == MarketDataType.Last) 190 | { 191 | if (e.Price >= e.Ask) 192 | { 193 | myProfile.AddAskVolume(e.Price, e.Volume); 194 | } 195 | else if(e.Price <= e.Bid) 196 | { 197 | myProfile.AddBidVolume(e.Price, e.Volume); 198 | } 199 | } 200 | } 201 | 202 | protected override void OnRender(ChartControl chartControl, ChartScale chartScale) 203 | { 204 | base.OnRender(chartControl, chartScale); 205 | if(Bars == null || Bars.Instrument == null || CurrentBar < 1) { return; } 206 | 207 | LastRender = DateTime.Now; 208 | 209 | try 210 | { 211 | 212 | foreach(KeyValuePair row in myProfile.Data) 213 | { 214 | drawRow(chartControl, chartScale, row.Value); 215 | } 216 | 217 | } 218 | catch(Exception e) 219 | { 220 | 221 | Print("Volume Profile Column: " + e.Message); 222 | } 223 | } 224 | 225 | private void drawRow(ChartControl chartControl, ChartScale chartScale, RowData row) 226 | { 227 | 228 | //Calculate color of this row. 229 | //Brush brushColor = new SolidColorBrush(System.Windows.Media.Color.FromRgb(255, 0, 0)); //bidColor.Freeze(); 230 | float alpha = alpha = (float)((double)Math.Abs(row.TotalVolume) / (double)myProfile.HiValue); 231 | Brush brushColor = neutralColor; 232 | 233 | //Calculate width of this row. 234 | 235 | 236 | 237 | //Calculate cell properties 238 | double y1 = ((chartScale.GetYByValue(row.Price) + chartScale.GetYByValue(row.Price + TickSize)) / 2) + 1; 239 | double y2 = ((chartScale.GetYByValue(row.Price) + chartScale.GetYByValue(row.Price - TickSize)) / 2) - 1; 240 | 241 | SharpDX.RectangleF rect = new SharpDX.RectangleF(); 242 | rect.X = (float)chartControl.CanvasRight - Position; 243 | rect.Y = (float)y1; 244 | rect.Width = (float)-((ResizableWidth * alpha) + MinimumWidth - 2); 245 | rect.Height = (float)Math.Abs(y1 - y2); 246 | 247 | //Draw the row. 248 | using(SharpDX.Direct2D1.Brush rowBrush = brushColor.ToDxBrush(RenderTarget)) 249 | { 250 | //rowBrush.Opacity = alpha; 251 | rowBrush.Opacity = alpha; 252 | RenderTarget.FillRectangle(rect, neutralColor.ToDxBrush(RenderTarget)); 253 | RenderTarget.FillRectangle(rect, rowBrush); 254 | } 255 | 256 | if(rect.Height > this.MinimumTextHeight) 257 | { 258 | RenderTarget.DrawText(string.Format("{0}", row.TotalVolume), textFormat, rect, TextColor.ToDxBrush(RenderTarget)); 259 | } 260 | } 261 | 262 | #region Properties 263 | 264 | [XmlIgnore] 265 | [NinjaScriptProperty] 266 | [Display(Name="ResetProfileOn", Description="Reset Profile On", Order=0, GroupName="General")] 267 | public Timeframe ResetProfileOn 268 | { get; set; } 269 | 270 | [XmlIgnore] 271 | [Browsable(false)] 272 | public string ResetProfileOnSerializable 273 | { 274 | get { return ResetProfileOn.ToString(); } 275 | set { ResetProfileOn = (Timeframe) Enum.Parse(typeof(Timeframe), value); } 276 | } 277 | 278 | [NinjaScriptProperty] 279 | [XmlIgnore] 280 | [Display(Name = "Negative Delta Color", GroupName = "Parameters", Order = 9)] 281 | public Brush negativeColor 282 | { get; set; } 283 | 284 | [Browsable(false)] 285 | public string negativeColorSerializable 286 | { 287 | get { return Serialize.BrushToString(negativeColor); } 288 | set { negativeColor = Serialize.StringToBrush(value); } 289 | } 290 | 291 | [NinjaScriptProperty] 292 | [XmlIgnore] 293 | [Display(Name = "Positive Delta Color", GroupName = "Parameters", Order = 9)] 294 | public Brush positiveColor 295 | { get; set; } 296 | 297 | [Browsable(false)] 298 | public string positiveColorSerializable 299 | { 300 | get { return Serialize.BrushToString(positiveColor); } 301 | set { positiveColor = Serialize.StringToBrush(value); } 302 | } 303 | 304 | [NinjaScriptProperty] 305 | [XmlIgnore] 306 | [Display(Name = "Neutral Delta Color", GroupName = "Parameters", Order = 9)] 307 | public Brush neutralColor 308 | { get; set; } 309 | 310 | [Browsable(false)] 311 | public string neutralColorSerializable 312 | { 313 | get { return Serialize.BrushToString(neutralColor); } 314 | set { neutralColor = Serialize.StringToBrush(value); } 315 | } 316 | 317 | #endregion 318 | } 319 | } 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | -------------------------------------------------------------------------------- /Indicators/ZipperLength.cs: -------------------------------------------------------------------------------- 1 | #region Using declarations 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Xml.Serialization; 13 | using NinjaTrader.Cbi; 14 | using NinjaTrader.Gui; 15 | using NinjaTrader.Gui.Chart; 16 | using NinjaTrader.Gui.SuperDom; 17 | using NinjaTrader.Gui.Tools; 18 | using NinjaTrader.Data; 19 | using NinjaTrader.NinjaScript; 20 | using NinjaTrader.Core.FloatingPoint; 21 | using NinjaTrader.NinjaScript.DrawingTools; 22 | #endregion 23 | 24 | //This namespace holds Indicators in this folder and is required. Do not change it. 25 | namespace NinjaTrader.NinjaScript.Indicators 26 | { 27 | public class ZipperLength : Indicator 28 | { 29 | protected override void OnStateChange() 30 | { 31 | if (State == State.SetDefaults) 32 | { 33 | Description = @"How long has it been in a range for?"; 34 | Name = "ZipperLength"; 35 | Calculate = Calculate.OnBarClose; 36 | IsOverlay = false; 37 | DisplayInDataBox = true; 38 | DrawOnPricePanel = true; 39 | DrawHorizontalGridLines = true; 40 | DrawVerticalGridLines = true; 41 | PaintPriceMarkers = true; 42 | ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right; 43 | //Disable this property if your indicator requires custom values that cumulate with each new market data event. 44 | //See Help Guide for additional information. 45 | IsSuspendedWhileInactive = true; 46 | 47 | Width = 2; 48 | 49 | AddPlot(new Stroke(Brushes.Goldenrod, 2), PlotStyle.Bar, "ZipperLength"); 50 | } 51 | else if (State == State.Configure) 52 | { 53 | 54 | } 55 | } 56 | 57 | protected override void OnBarUpdate() 58 | { 59 | if (CurrentBar < Width) 60 | { 61 | Value[0] = 0; 62 | return; 63 | } 64 | 65 | int current = 0; 66 | double high = High[current]; 67 | double low = Low[current]; 68 | 69 | do 70 | { 71 | high = Math.Max(high, High[current]); 72 | low = Math.Min(low, Low[current]); 73 | current++; 74 | } 75 | while(high - low <= Width * TickSize && current < CurrentBar); 76 | 77 | Value[0] = current; 78 | 79 | //Colors 80 | if(current > Width * 3.5) 81 | { 82 | PlotBrushes[0][0] = Brushes.Orange; 83 | } 84 | else if(current > Width * 1.5) 85 | { 86 | PlotBrushes[0][0] = Brushes.CornflowerBlue; 87 | } 88 | else if(current > Width) 89 | { 90 | PlotBrushes[0][0] = Brushes.DarkGray; 91 | } 92 | else 93 | { 94 | PlotBrushes[0][0] = Brushes.Black; 95 | } 96 | } 97 | 98 | #region Properties 99 | [NinjaScriptProperty] 100 | [Range(2, int.MaxValue)] 101 | [Display(Name="Width", Order=1, GroupName="Parameters")] 102 | public int Width 103 | { get; set; } 104 | #endregion 105 | 106 | } 107 | } 108 | 109 | #region NinjaScript generated code. Neither change nor remove. 110 | 111 | namespace NinjaTrader.NinjaScript.Indicators 112 | { 113 | public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase 114 | { 115 | private ZipperLength[] cacheZipperLength; 116 | public ZipperLength ZipperLength(int width) 117 | { 118 | return ZipperLength(Input, width); 119 | } 120 | 121 | public ZipperLength ZipperLength(ISeries input, int width) 122 | { 123 | if (cacheZipperLength != null) 124 | for (int idx = 0; idx < cacheZipperLength.Length; idx++) 125 | if (cacheZipperLength[idx] != null && cacheZipperLength[idx].Width == width && cacheZipperLength[idx].EqualsInput(input)) 126 | return cacheZipperLength[idx]; 127 | return CacheIndicator(new ZipperLength(){ Width = width }, input, ref cacheZipperLength); 128 | } 129 | } 130 | } 131 | 132 | namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns 133 | { 134 | public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase 135 | { 136 | public Indicators.ZipperLength ZipperLength(int width) 137 | { 138 | return indicator.ZipperLength(Input, width); 139 | } 140 | 141 | public Indicators.ZipperLength ZipperLength(ISeries input , int width) 142 | { 143 | return indicator.ZipperLength(input, width); 144 | } 145 | } 146 | } 147 | 148 | namespace NinjaTrader.NinjaScript.Strategies 149 | { 150 | public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase 151 | { 152 | public Indicators.ZipperLength ZipperLength(int width) 153 | { 154 | return indicator.ZipperLength(Input, width); 155 | } 156 | 157 | public Indicators.ZipperLength ZipperLength(ISeries input , int width) 158 | { 159 | return indicator.ZipperLength(input, width); 160 | } 161 | } 162 | } 163 | 164 | #endregion 165 | -------------------------------------------------------------------------------- /SuperDomColumns/CurrentTrades.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2015, NinjaTrader LLC . 3 | // NinjaTrader reserves the right to modify or overwrite this NinjaScript component with each release. 4 | // 5 | #region Using declarations 6 | using NinjaTrader.Data; 7 | using NinjaTrader.Gui.SuperDom; 8 | using NinjaTrader.NinjaScript.SuperDomColumns; 9 | using System; 10 | using System.Collections.Concurrent; 11 | using System.ComponentModel; 12 | using System.ComponentModel.DataAnnotations; 13 | using System.Linq; 14 | using System.Windows; 15 | using System.Windows.Input; 16 | using System.Windows.Media; 17 | using System.Xml.Serialization; 18 | #endregion 19 | 20 | namespace NinjaTrader.NinjaScript.SuperDomColumns 21 | { 22 | 23 | public enum VolumeSide {bid, ask}; 24 | 25 | public class CurrentTrades : SuperDomColumn 26 | { 27 | private readonly object barsSync = new object(); 28 | private bool clearLoadingSent; 29 | private FontFamily fontFamily; 30 | private FontStyle fontStyle; 31 | private FontWeight fontWeight; 32 | private Pen gridPen; 33 | private double halfPenWidth; 34 | private bool heightUpdateNeeded; 35 | private int lastMaxIndex = -1; 36 | private long maxVolume; 37 | private bool mouseEventsSubscribed; 38 | private double textHeight; 39 | private Point textPosition = new Point(4, 0); 40 | private string tradingHoursData = TradingHours.UseInstrumentSettings; 41 | private long totalBuyVolume; 42 | private long totalLastVolume; 43 | private long totalSellVolume; 44 | private Typeface typeFace; 45 | private double lastBid = 0; 46 | private double lastAsk = 0; 47 | private double lastClose = 0; 48 | 49 | 50 | private void OnBarsUpdate(object sender, BarsUpdateEventArgs e) 51 | { 52 | if (State == State.Active && SuperDom != null && SuperDom.IsConnected) 53 | { 54 | if (SuperDom.IsReloading) 55 | { 56 | OnPropertyChanged(); 57 | return; 58 | } 59 | 60 | BarsUpdateEventArgs barsUpdate = e; 61 | lock (barsSync) 62 | { 63 | int currentMaxIndex = barsUpdate.MaxIndex; 64 | 65 | for (int i = lastMaxIndex + 1; i <= currentMaxIndex; i++) 66 | { 67 | 68 | if (barsUpdate.BarsSeries.GetIsFirstBarOfSession(i)) 69 | { 70 | // If a new session starts, clear out the old values and start fresh 71 | maxVolume = 0; 72 | totalBuyVolume = 0; 73 | totalLastVolume = 0; 74 | totalSellVolume = 0; 75 | Sells.Clear(); 76 | Buys.Clear(); 77 | LastVolumes.Clear(); 78 | } 79 | 80 | double ask = barsUpdate.BarsSeries.GetAsk(i); 81 | double bid = barsUpdate.BarsSeries.GetBid(i); 82 | double close = barsUpdate.BarsSeries.GetClose(i); 83 | long volume = barsUpdate.BarsSeries.GetVolume(i); 84 | 85 | if (ask != double.MinValue && close >= ask) 86 | { 87 | Buys.AddOrUpdate(close, volume, (price, oldVolume) => oldVolume + volume); 88 | totalBuyVolume += volume; 89 | } 90 | else if (bid != double.MinValue && close <= bid) 91 | { 92 | Sells.AddOrUpdate(close, volume, (price, oldVolume) => oldVolume + volume); 93 | totalSellVolume += volume; 94 | } 95 | 96 | 97 | if((Bidask == VolumeSide.ask && lastBid != bid && close <= bid) || (Bidask == VolumeSide.bid && lastAsk != ask && close >= ask)) 98 | { 99 | lastBid = bid; 100 | lastAsk = ask; 101 | lastClose = close; 102 | 103 | long newVolume; 104 | LastVolumes.AddOrUpdate(close, newVolume = volume, (price, oldVolume) => newVolume = 0); 105 | totalLastVolume += volume; 106 | 107 | if (newVolume > maxVolume) 108 | maxVolume = newVolume; 109 | } 110 | 111 | if ((Bidask == VolumeSide.ask && close <= bid) || (Bidask == VolumeSide.bid && close >= ask)) 112 | { 113 | long newVolume; 114 | LastVolumes.AddOrUpdate(close, newVolume = volume, (price, oldVolume) => newVolume = oldVolume + volume); 115 | totalLastVolume += volume; 116 | 117 | if (newVolume > maxVolume) 118 | maxVolume = newVolume; 119 | } 120 | } 121 | 122 | lastMaxIndex = barsUpdate.MaxIndex; 123 | if (!clearLoadingSent) 124 | { 125 | SuperDom.Dispatcher.InvokeAsync(() => SuperDom.ClearLoadingString()); 126 | clearLoadingSent = true; 127 | } 128 | } 129 | } 130 | } 131 | 132 | private void OnMouseLeave(object sender, MouseEventArgs e) 133 | { 134 | OnPropertyChanged(); 135 | } 136 | 137 | private void OnMouseEnter(object sender, MouseEventArgs e) 138 | { 139 | OnPropertyChanged(); 140 | } 141 | 142 | private void OnMouseMove(object sender, MouseEventArgs e) 143 | { 144 | OnPropertyChanged(); 145 | } 146 | 147 | protected override void OnRender(DrawingContext dc, double renderWidth) 148 | { 149 | // This may be true if the UI for a column hasn't been loaded yet (e.g., restoring multiple tabs from workspace won't load each tab until it's clicked by the user) 150 | if (gridPen == null) 151 | { 152 | if (UiWrapper != null && PresentationSource.FromVisual(UiWrapper) != null) 153 | { 154 | Matrix m = PresentationSource.FromVisual(UiWrapper).CompositionTarget.TransformToDevice; 155 | double dpiFactor = 1 / m.M11; 156 | gridPen = new Pen(Application.Current.TryFindResource("BorderThinBrush") as Brush, 1 * dpiFactor); 157 | halfPenWidth = gridPen.Thickness * 0.5; 158 | } 159 | } 160 | 161 | if (fontFamily != SuperDom.Font.Family 162 | || (SuperDom.Font.Italic && fontStyle != FontStyles.Italic) 163 | || (!SuperDom.Font.Italic && fontStyle == FontStyles.Italic) 164 | || (SuperDom.Font.Bold && fontWeight != FontWeights.Bold) 165 | || (!SuperDom.Font.Bold && fontWeight == FontWeights.Bold)) 166 | { 167 | // Only update this if something has changed 168 | fontFamily = SuperDom.Font.Family; 169 | fontStyle = SuperDom.Font.Italic ? FontStyles.Italic : FontStyles.Normal; 170 | fontWeight = SuperDom.Font.Bold ? FontWeights.Bold : FontWeights.Normal; 171 | typeFace = new Typeface(fontFamily, fontStyle, fontWeight, FontStretches.Normal); 172 | heightUpdateNeeded = true; 173 | } 174 | 175 | double verticalOffset = -gridPen.Thickness; 176 | 177 | lock (SuperDom.Rows) 178 | foreach (PriceRow row in SuperDom.Rows) 179 | { 180 | if (renderWidth - halfPenWidth >= 0) 181 | { 182 | // Draw cell 183 | Rect rect = new Rect(-halfPenWidth, verticalOffset, renderWidth - halfPenWidth, SuperDom.ActualRowHeight); 184 | 185 | // Create a guidelines set 186 | GuidelineSet guidelines = new GuidelineSet(); 187 | guidelines.GuidelinesX.Add(rect.Left + halfPenWidth); 188 | guidelines.GuidelinesX.Add(rect.Right + halfPenWidth); 189 | guidelines.GuidelinesY.Add(rect.Top + halfPenWidth); 190 | guidelines.GuidelinesY.Add(rect.Bottom + halfPenWidth); 191 | 192 | dc.PushGuidelineSet(guidelines); 193 | dc.DrawRectangle(BackColor, null, rect); 194 | dc.DrawLine(gridPen, new Point(-gridPen.Thickness, rect.Bottom), new Point(renderWidth - halfPenWidth, rect.Bottom)); 195 | dc.DrawLine(gridPen, new Point(rect.Right, verticalOffset), new Point(rect.Right, rect.Bottom)); 196 | //dc.Pop(); 197 | 198 | if (SuperDom.IsConnected 199 | && !SuperDom.IsReloading 200 | && State == NinjaTrader.NinjaScript.State.Active) 201 | { 202 | // Draw proportional volume bar 203 | long buyVolume = 0; 204 | long sellVolume = 0; 205 | long totalRowVolume = 0; 206 | long totalVolume = 0; 207 | 208 | 209 | if (LastVolumes.TryGetValue(row.Price, out totalRowVolume)) 210 | totalVolume = totalLastVolume; 211 | else 212 | { 213 | verticalOffset += SuperDom.ActualRowHeight; 214 | continue; 215 | } 216 | 217 | 218 | double totalWidth = renderWidth * ((double)totalRowVolume / maxVolume); 219 | if (totalWidth - gridPen.Thickness >= 0) 220 | { 221 | dc.DrawRectangle(BarColor, null, new Rect(0, verticalOffset + halfPenWidth, totalWidth == renderWidth ? totalWidth - gridPen.Thickness * 1.5 : totalWidth - halfPenWidth, rect.Height - gridPen.Thickness)); 222 | } 223 | // Print volume value - remember to set MaxTextWidth so text doesn't spill into another column 224 | if (totalRowVolume > 0) 225 | { 226 | string volumeString = string.Empty; 227 | 228 | volumeString = totalRowVolume.ToString(Core.Globals.GeneralOptions.CurrentCulture); 229 | 230 | if (renderWidth - 6 > 0) 231 | { 232 | if (DisplayText || rect.Contains(Mouse.GetPosition(UiWrapper))) 233 | { 234 | FormattedText volumeText = new FormattedText(volumeString, Core.Globals.GeneralOptions.CurrentCulture, FlowDirection.LeftToRight, typeFace, SuperDom.Font.Size, ForeColor) { MaxLineCount = 1, MaxTextWidth = renderWidth - 6, Trimming = TextTrimming.CharacterEllipsis }; 235 | 236 | // Getting the text height is expensive, so only update it if something's changed 237 | if (heightUpdateNeeded) 238 | { 239 | textHeight = volumeText.Height; 240 | heightUpdateNeeded = false; 241 | } 242 | 243 | textPosition.Y = verticalOffset + (SuperDom.ActualRowHeight - textHeight) / 2; 244 | dc.DrawText(volumeText, textPosition); 245 | } 246 | } 247 | } 248 | verticalOffset += SuperDom.ActualRowHeight; 249 | } 250 | else 251 | verticalOffset += SuperDom.ActualRowHeight; 252 | 253 | dc.Pop(); 254 | } 255 | } 256 | } 257 | 258 | public override void OnRestoreValues() 259 | { 260 | // Forecolor and standard bar color 261 | bool restored = false; 262 | 263 | SolidColorBrush defaultForeColor = Application.Current.FindResource("immutableBrushVolumeColumnForeground") as SolidColorBrush; 264 | if ( (ForeColor as SolidColorBrush).Color == (ImmutableForeColor as SolidColorBrush).Color 265 | && (ImmutableForeColor as SolidColorBrush).Color != defaultForeColor.Color) 266 | { 267 | ForeColor = defaultForeColor; 268 | ImmutableForeColor = defaultForeColor; 269 | restored = true; 270 | } 271 | 272 | SolidColorBrush defaultBarColor = Application.Current.FindResource("immutableBrushVolumeColumnBackground") as SolidColorBrush; 273 | if ((BarColor as SolidColorBrush).Color == (ImmutableBarColor as SolidColorBrush).Color 274 | && (ImmutableBarColor as SolidColorBrush).Color != defaultBarColor.Color) 275 | { 276 | BarColor = defaultBarColor; 277 | ImmutableBarColor = defaultBarColor; 278 | restored = true; 279 | } 280 | 281 | if (restored) OnPropertyChanged(); 282 | } 283 | 284 | protected override void OnStateChange() 285 | { 286 | if (State == State.SetDefaults) 287 | { 288 | Name = "CurrentTrades"; 289 | Buys = new ConcurrentDictionary(); 290 | BackColor = Brushes.Transparent; 291 | BarColor = Application.Current.TryFindResource("brushVolumeColumnBackground") as Brush; 292 | BuyColor = Brushes.Green; 293 | DefaultWidth = 160; 294 | PreviousWidth = -1; 295 | DisplayText = true; 296 | ForeColor = Application.Current.TryFindResource("brushVolumeColumnForeground") as Brush; 297 | ImmutableBarColor = Application.Current.TryFindResource("immutableBrushVolumeColumnBackground") as Brush; 298 | ImmutableForeColor = Application.Current.TryFindResource("immutableBrushVolumeColumnForeground") as Brush; 299 | IsDataSeriesRequired = true; 300 | LastVolumes = new ConcurrentDictionary(); 301 | SellColor = Brushes.Red; 302 | Sells = new ConcurrentDictionary(); 303 | Bidask = VolumeSide.bid; 304 | } 305 | else if (State == State.Configure) 306 | { 307 | if (UiWrapper != null && PresentationSource.FromVisual(UiWrapper) != null) 308 | { 309 | Matrix m = PresentationSource.FromVisual(UiWrapper).CompositionTarget.TransformToDevice; 310 | double dpiFactor = 1 / m.M11; 311 | gridPen = new Pen(Application.Current.TryFindResource("BorderThinBrush") as Brush, 1 * dpiFactor); 312 | halfPenWidth = gridPen.Thickness * 0.5; 313 | } 314 | 315 | if (SuperDom.Instrument != null && SuperDom.IsConnected) 316 | { 317 | BarsPeriod bp = new BarsPeriod 318 | { 319 | MarketDataType = MarketDataType.Last, 320 | BarsPeriodType = BarsPeriodType.Tick, 321 | Value = 1 322 | }; 323 | 324 | SuperDom.Dispatcher.InvokeAsync(() => SuperDom.SetLoadingString()); 325 | clearLoadingSent = false; 326 | 327 | if (BarsRequest != null) 328 | { 329 | BarsRequest.Update -= OnBarsUpdate; 330 | BarsRequest = null; 331 | } 332 | 333 | BarsRequest = new BarsRequest(SuperDom.Instrument, 334 | Cbi.Connection.PlaybackConnection != null ? Cbi.Connection.PlaybackConnection.Now : Core.Globals.Now, 335 | Cbi.Connection.PlaybackConnection != null ? Cbi.Connection.PlaybackConnection.Now : Core.Globals.Now); 336 | 337 | BarsRequest.BarsPeriod = bp; 338 | BarsRequest.TradingHours = (TradingHoursData == TradingHours.UseInstrumentSettings || TradingHours.Get(TradingHoursData) == null) ? SuperDom.Instrument.MasterInstrument.TradingHours : TradingHours.Get(TradingHoursData); 339 | BarsRequest.Update += OnBarsUpdate; 340 | 341 | BarsRequest.Request((request, errorCode, errorMessage) => 342 | { 343 | // Make sure this isn't a bars callback from another column instance 344 | if (request != BarsRequest) 345 | return; 346 | 347 | lastMaxIndex = 0; 348 | maxVolume = 0; 349 | totalBuyVolume = 0; 350 | totalLastVolume = 0; 351 | totalSellVolume = 0; 352 | Sells.Clear(); 353 | Buys.Clear(); 354 | LastVolumes.Clear(); 355 | 356 | if (State >= NinjaTrader.NinjaScript.State.Terminated) 357 | return; 358 | 359 | if (errorCode == Cbi.ErrorCode.UserAbort) 360 | { 361 | if (State <= NinjaTrader.NinjaScript.State.Terminated) 362 | if (SuperDom != null && !clearLoadingSent) 363 | { 364 | SuperDom.Dispatcher.InvokeAsync(() => SuperDom.ClearLoadingString()); 365 | clearLoadingSent = true; 366 | } 367 | 368 | request.Update -= OnBarsUpdate; 369 | request.Dispose(); 370 | request = null; 371 | return; 372 | } 373 | 374 | if (errorCode != Cbi.ErrorCode.NoError) 375 | { 376 | request.Update -= OnBarsUpdate; 377 | request.Dispose(); 378 | request = null; 379 | if (SuperDom != null && !clearLoadingSent) 380 | { 381 | SuperDom.Dispatcher.InvokeAsync(() => SuperDom.ClearLoadingString()); 382 | clearLoadingSent = true; 383 | } 384 | } 385 | else if (errorCode == Cbi.ErrorCode.NoError) 386 | { 387 | SessionIterator superDomSessionIt = new SessionIterator(request.Bars); 388 | bool isInclude60 = request.Bars.BarsType.IncludesEndTimeStamp(false); 389 | if (superDomSessionIt.IsInSession(Core.Globals.Now, isInclude60, request.Bars.BarsType.IsIntraday)) 390 | { 391 | for (int i = 0; i < request.Bars.Count; i++) 392 | { 393 | DateTime time = request.Bars.BarsSeries.GetTime(i); 394 | if ((isInclude60 && time <= superDomSessionIt.ActualSessionBegin) || (!isInclude60 && time < superDomSessionIt.ActualSessionBegin)) 395 | continue; 396 | 397 | double ask = request.Bars.BarsSeries.GetAsk(i); 398 | double bid = request.Bars.BarsSeries.GetBid(i); 399 | double close = request.Bars.BarsSeries.GetClose(i); 400 | long volume = request.Bars.BarsSeries.GetVolume(i); 401 | 402 | if (ask != double.MinValue && close >= ask) 403 | { 404 | Buys.AddOrUpdate(close, volume, (price, oldVolume) => oldVolume + volume); 405 | totalBuyVolume += volume; 406 | } 407 | else if (bid != double.MinValue && close <= bid) 408 | { 409 | Sells.AddOrUpdate(close, volume, (price, oldVolume) => oldVolume + volume); 410 | totalSellVolume += volume; 411 | } 412 | 413 | long newVolume; 414 | LastVolumes.AddOrUpdate(close, newVolume = volume, (price, oldVolume) => newVolume = 0); 415 | totalLastVolume += volume; 416 | 417 | if (newVolume > maxVolume) 418 | maxVolume = newVolume; 419 | } 420 | 421 | lastMaxIndex = request.Bars.Count - 1; 422 | 423 | // Repaint the column on the SuperDOM 424 | OnPropertyChanged(); 425 | } 426 | 427 | if (SuperDom != null && !clearLoadingSent) 428 | { 429 | SuperDom.Dispatcher.InvokeAsync(() => SuperDom.ClearLoadingString()); 430 | clearLoadingSent = true; 431 | } 432 | } 433 | }); 434 | } 435 | } 436 | else if (State == State.Active) 437 | { 438 | if (!DisplayText) 439 | { 440 | WeakEventManager.AddHandler(UiWrapper, "MouseMove", OnMouseMove); 441 | WeakEventManager.AddHandler(UiWrapper, "MouseEnter", OnMouseEnter); 442 | WeakEventManager.AddHandler(UiWrapper, "MouseLeave", OnMouseLeave); 443 | mouseEventsSubscribed = true; 444 | } 445 | } 446 | else if (State == State.Terminated) 447 | { 448 | if (BarsRequest != null) 449 | { 450 | BarsRequest.Update -= OnBarsUpdate; 451 | BarsRequest.Dispose(); 452 | } 453 | 454 | BarsRequest = null; 455 | 456 | if (SuperDom != null && !clearLoadingSent) 457 | { 458 | SuperDom.Dispatcher.InvokeAsync(() => SuperDom.ClearLoadingString()); 459 | clearLoadingSent = true; 460 | } 461 | 462 | if (!DisplayText && mouseEventsSubscribed) 463 | { 464 | WeakEventManager.RemoveHandler(UiWrapper, "MouseMove", OnMouseMove); 465 | WeakEventManager.RemoveHandler(UiWrapper, "MouseEnter", OnMouseEnter); 466 | WeakEventManager.RemoveHandler(UiWrapper, "MouseLeave", OnMouseLeave); 467 | mouseEventsSubscribed = false; 468 | } 469 | 470 | lastMaxIndex = 0; 471 | maxVolume = 0; 472 | totalBuyVolume = 0; 473 | totalLastVolume = 0; 474 | totalSellVolume = 0; 475 | Sells.Clear(); 476 | Buys.Clear(); 477 | LastVolumes.Clear(); 478 | } 479 | } 480 | 481 | #region Bar Collections 482 | [XmlIgnore] 483 | [Browsable(false)] 484 | public ConcurrentDictionary Buys { get; set; } 485 | 486 | [XmlIgnore] 487 | [Browsable(false)] 488 | public ConcurrentDictionary LastVolumes { get; set; } 489 | 490 | [XmlIgnore] 491 | [Browsable(false)] 492 | public ConcurrentDictionary Sells { get; set; } 493 | #endregion 494 | 495 | #region Properties 496 | 497 | [NinjaScriptProperty] 498 | [Display(Name="Bidask", Order=1, GroupName="Parameters")] 499 | public VolumeSide Bidask 500 | { get; set; } 501 | 502 | [XmlIgnore] 503 | [Display(ResourceType = typeof(Resource), Name = "NinjaScriptColumnBaseBackground", GroupName = "PropertyCategoryVisual", Order = 130)] 504 | public Brush BackColor { get; set; } 505 | 506 | [Browsable(false)] 507 | public string BackColorSerialize 508 | { 509 | get { return NinjaTrader.Gui.Serialize.BrushToString(BackColor); } 510 | set { BackColor = NinjaTrader.Gui.Serialize.StringToBrush(value); } 511 | } 512 | 513 | [XmlIgnore] 514 | [Display(ResourceType = typeof(Resource), Name = "NinjaScriptBarColor", GroupName = "PropertyCategoryVisual", Order = 110)] 515 | public Brush BarColor { get; set; } 516 | 517 | [Browsable(false)] 518 | public string BarColorSerialize 519 | { 520 | get { return NinjaTrader.Gui.Serialize.BrushToString(BarColor); } 521 | set { BarColor = NinjaTrader.Gui.Serialize.StringToBrush(value); } 522 | } 523 | 524 | [XmlIgnore] 525 | [Display(ResourceType = typeof(Resource), Name = "NinjaScriptBuyColor", GroupName = "PropertyCategoryVisual", Order = 120)] 526 | public Brush BuyColor { get; set; } 527 | 528 | [Browsable(false)] 529 | public string BuyColorSerialize 530 | { 531 | get { return NinjaTrader.Gui.Serialize.BrushToString(BuyColor); } 532 | set { BuyColor = NinjaTrader.Gui.Serialize.StringToBrush(value); } 533 | } 534 | 535 | [Display(ResourceType = typeof(Resource), Name = "NinjaScriptDisplayText", GroupName = "PropertyCategoryVisual", Order = 175)] 536 | public bool DisplayText { get; set; } 537 | 538 | 539 | [XmlIgnore] 540 | [Display(ResourceType = typeof(Resource), Name = "NinjaScriptColumnBaseForeground", GroupName = "PropertyCategoryVisual", Order = 140)] 541 | public Brush ForeColor { get; set; } 542 | 543 | [Browsable(false)] 544 | public string ForeColorSerialize 545 | { 546 | get { return NinjaTrader.Gui.Serialize.BrushToString(ForeColor); } 547 | set { ForeColor = NinjaTrader.Gui.Serialize.StringToBrush(value); } 548 | } 549 | 550 | [XmlIgnore] 551 | [Browsable(false)] 552 | public Brush ImmutableBarColor { get; set; } 553 | 554 | [Browsable(false)] 555 | public string ImmutableBarColorSerialize 556 | { 557 | get { return NinjaTrader.Gui.Serialize.BrushToString(ImmutableBarColor, "CustomVolume.ImmutableBarColor"); } 558 | set { ImmutableBarColor = NinjaTrader.Gui.Serialize.StringToBrush(value, "CustomVolume.ImmutableBarColor"); } 559 | } 560 | 561 | [XmlIgnore] 562 | [Browsable(false)] 563 | public Brush ImmutableForeColor { get; set; } 564 | 565 | [Browsable(false)] 566 | public string ImmutableForeColorSerialize 567 | { 568 | get { return NinjaTrader.Gui.Serialize.BrushToString(ImmutableForeColor, "CustomVolume.ImmutableForeColor"); } 569 | set { ImmutableForeColor = NinjaTrader.Gui.Serialize.StringToBrush(value, "CustomVolume.ImmutableForeColor"); } 570 | } 571 | 572 | [XmlIgnore] 573 | [Display(ResourceType = typeof(Resource), Name = "NinjaScriptSellColor", GroupName = "PropertyCategoryVisual", Order = 170)] 574 | public Brush SellColor { get; set; } 575 | 576 | [Browsable(false)] 577 | public string SellColorSerialize 578 | { 579 | get { return NinjaTrader.Gui.Serialize.BrushToString(SellColor); } 580 | set { SellColor = NinjaTrader.Gui.Serialize.StringToBrush(value); } 581 | } 582 | 583 | [Display(ResourceType = typeof(Resource), Name = "IndicatorSuperDomBaseTradingHoursTemplate", GroupName = "NinjaScriptTimeFrame", Order = 60)] 584 | [RefreshProperties(RefreshProperties.All)] 585 | [TypeConverter(typeof(NinjaTrader.NinjaScript.TradingHoursDataConverter))] 586 | public string TradingHoursData 587 | { 588 | get { return tradingHoursData; } 589 | set { tradingHoursData = value; } 590 | } 591 | 592 | #endregion 593 | } 594 | } 595 | -------------------------------------------------------------------------------- /SuperDomColumns/NumTouches.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2015, NinjaTrader LLC . 3 | // NinjaTrader reserves the right to modify or overwrite this NinjaScript component with each release. 4 | // 5 | #region Using declarations 6 | using NinjaTrader.Data; 7 | using NinjaTrader.Gui.SuperDom; 8 | using NinjaTrader.NinjaScript.SuperDomColumns; 9 | using System; 10 | using System.Collections.Concurrent; 11 | using System.ComponentModel; 12 | using System.ComponentModel.DataAnnotations; 13 | using System.Linq; 14 | using System.Windows; 15 | using System.Windows.Input; 16 | using System.Windows.Media; 17 | using System.Xml.Serialization; 18 | #endregion 19 | 20 | namespace NinjaTrader.NinjaScript.SuperDomColumns 21 | { 22 | 23 | public class NumTouches : SuperDomColumn 24 | { 25 | private readonly object barsSync = new object(); 26 | private bool clearLoadingSent; 27 | private FontFamily fontFamily; 28 | private FontStyle fontStyle; 29 | private FontWeight fontWeight; 30 | private Pen gridPen; 31 | private double halfPenWidth; 32 | private bool heightUpdateNeeded; 33 | private int lastMaxIndex = -1; 34 | private long maxVolume; 35 | private bool mouseEventsSubscribed; 36 | private double textHeight; 37 | private Point textPosition = new Point(4, 0); 38 | private string tradingHoursData = TradingHours.UseInstrumentSettings; 39 | private long totalBuyVolume; 40 | private long totalLastVolume; 41 | private long totalSellVolume; 42 | private Typeface typeFace; 43 | private double lastBid = 0; 44 | private double lastAsk = 0; 45 | private double lastClose = 0; 46 | 47 | 48 | private void OnBarsUpdate(object sender, BarsUpdateEventArgs e) 49 | { 50 | if (State == State.Active && SuperDom != null && SuperDom.IsConnected) 51 | { 52 | if (SuperDom.IsReloading) 53 | { 54 | OnPropertyChanged(); 55 | return; 56 | } 57 | 58 | BarsUpdateEventArgs barsUpdate = e; 59 | lock (barsSync) 60 | { 61 | int currentMaxIndex = barsUpdate.MaxIndex; 62 | 63 | for (int i = lastMaxIndex + 1; i <= currentMaxIndex; i++) 64 | { 65 | 66 | if (barsUpdate.BarsSeries.GetIsFirstBarOfSession(i)) 67 | { 68 | // If a new session starts, clear out the old values and start fresh 69 | LastVolumes.Clear(); 70 | } 71 | 72 | double ask = barsUpdate.BarsSeries.GetAsk(i); 73 | double bid = barsUpdate.BarsSeries.GetBid(i); 74 | double close = barsUpdate.BarsSeries.GetClose(i); 75 | long volume = barsUpdate.BarsSeries.GetVolume(i); 76 | 77 | if(Bidask == VolumeSide.ask && lastBid != bid && close <= bid) 78 | { 79 | lastBid = bid; 80 | 81 | long newVolume; 82 | LastVolumes.AddOrUpdate(bid, newVolume = 1, (price, oldVolume) => newVolume = oldVolume + 1); 83 | } 84 | 85 | if(Bidask == VolumeSide.bid && lastAsk != ask && close >= ask) 86 | { 87 | lastAsk = ask; 88 | 89 | long newVolume; 90 | LastVolumes.AddOrUpdate(ask, newVolume = 1, (price, oldVolume) => newVolume = oldVolume + 1); 91 | } 92 | } 93 | 94 | lastMaxIndex = barsUpdate.MaxIndex; 95 | if (!clearLoadingSent) 96 | { 97 | SuperDom.Dispatcher.InvokeAsync(() => SuperDom.ClearLoadingString()); 98 | clearLoadingSent = true; 99 | } 100 | } 101 | } 102 | } 103 | 104 | private void OnMouseLeave(object sender, MouseEventArgs e) 105 | { 106 | OnPropertyChanged(); 107 | } 108 | 109 | private void OnMouseEnter(object sender, MouseEventArgs e) 110 | { 111 | OnPropertyChanged(); 112 | } 113 | 114 | private void OnMouseMove(object sender, MouseEventArgs e) 115 | { 116 | OnPropertyChanged(); 117 | } 118 | 119 | protected override void OnRender(DrawingContext dc, double renderWidth) 120 | { 121 | // This may be true if the UI for a column hasn't been loaded yet (e.g., restoring multiple tabs from workspace won't load each tab until it's clicked by the user) 122 | if (gridPen == null) 123 | { 124 | if (UiWrapper != null && PresentationSource.FromVisual(UiWrapper) != null) 125 | { 126 | Matrix m = PresentationSource.FromVisual(UiWrapper).CompositionTarget.TransformToDevice; 127 | double dpiFactor = 1 / m.M11; 128 | gridPen = new Pen(Application.Current.TryFindResource("BorderThinBrush") as Brush, 1 * dpiFactor); 129 | halfPenWidth = gridPen.Thickness * 0.5; 130 | } 131 | } 132 | 133 | if (fontFamily != SuperDom.Font.Family 134 | || (SuperDom.Font.Italic && fontStyle != FontStyles.Italic) 135 | || (!SuperDom.Font.Italic && fontStyle == FontStyles.Italic) 136 | || (SuperDom.Font.Bold && fontWeight != FontWeights.Bold) 137 | || (!SuperDom.Font.Bold && fontWeight == FontWeights.Bold)) 138 | { 139 | // Only update this if something has changed 140 | fontFamily = SuperDom.Font.Family; 141 | fontStyle = SuperDom.Font.Italic ? FontStyles.Italic : FontStyles.Normal; 142 | fontWeight = SuperDom.Font.Bold ? FontWeights.Bold : FontWeights.Normal; 143 | typeFace = new Typeface(fontFamily, fontStyle, fontWeight, FontStretches.Normal); 144 | heightUpdateNeeded = true; 145 | } 146 | 147 | double verticalOffset = -gridPen.Thickness; 148 | 149 | lock (SuperDom.Rows) 150 | foreach (PriceRow row in SuperDom.Rows) 151 | { 152 | if (renderWidth - halfPenWidth >= 0) 153 | { 154 | // Draw cell 155 | Rect rect = new Rect(-halfPenWidth, verticalOffset, renderWidth - halfPenWidth, SuperDom.ActualRowHeight); 156 | 157 | // Create a guidelines set 158 | GuidelineSet guidelines = new GuidelineSet(); 159 | guidelines.GuidelinesX.Add(rect.Left + halfPenWidth); 160 | guidelines.GuidelinesX.Add(rect.Right + halfPenWidth); 161 | guidelines.GuidelinesY.Add(rect.Top + halfPenWidth); 162 | guidelines.GuidelinesY.Add(rect.Bottom + halfPenWidth); 163 | 164 | dc.PushGuidelineSet(guidelines); 165 | dc.DrawRectangle(BackColor, null, rect); 166 | dc.DrawLine(gridPen, new Point(-gridPen.Thickness, rect.Bottom), new Point(renderWidth - halfPenWidth, rect.Bottom)); 167 | dc.DrawLine(gridPen, new Point(rect.Right, verticalOffset), new Point(rect.Right, rect.Bottom)); 168 | //dc.Pop(); 169 | 170 | if (SuperDom.IsConnected 171 | && !SuperDom.IsReloading 172 | && State == NinjaTrader.NinjaScript.State.Active) 173 | { 174 | // Draw proportional volume bar 175 | long buyVolume = 0; 176 | long sellVolume = 0; 177 | long totalRowVolume = 0; 178 | long totalVolume = 0; 179 | 180 | 181 | if (LastVolumes.TryGetValue(row.Price, out totalRowVolume)) 182 | totalVolume = totalLastVolume; 183 | else 184 | { 185 | verticalOffset += SuperDom.ActualRowHeight; 186 | continue; 187 | } 188 | 189 | 190 | // Print volume value - remember to set MaxTextWidth so text doesn't spill into another column 191 | if (totalRowVolume > 0) 192 | { 193 | string volumeString = string.Empty; 194 | 195 | volumeString = totalRowVolume.ToString(Core.Globals.GeneralOptions.CurrentCulture); 196 | 197 | if (renderWidth - 6 > 0) 198 | { 199 | if (DisplayText || rect.Contains(Mouse.GetPosition(UiWrapper))) 200 | { 201 | FormattedText volumeText = new FormattedText(volumeString, Core.Globals.GeneralOptions.CurrentCulture, FlowDirection.LeftToRight, typeFace, SuperDom.Font.Size, ForeColor) { MaxLineCount = 1, MaxTextWidth = renderWidth - 6, Trimming = TextTrimming.CharacterEllipsis }; 202 | 203 | // Getting the text height is expensive, so only update it if something's changed 204 | if (heightUpdateNeeded) 205 | { 206 | textHeight = volumeText.Height; 207 | heightUpdateNeeded = false; 208 | } 209 | 210 | textPosition.Y = verticalOffset + (SuperDom.ActualRowHeight - textHeight) / 2; 211 | dc.DrawText(volumeText, textPosition); 212 | } 213 | } 214 | } 215 | verticalOffset += SuperDom.ActualRowHeight; 216 | } 217 | else 218 | verticalOffset += SuperDom.ActualRowHeight; 219 | 220 | dc.Pop(); 221 | } 222 | } 223 | } 224 | 225 | public override void OnRestoreValues() 226 | { 227 | // Forecolor and standard bar color 228 | bool restored = false; 229 | 230 | SolidColorBrush defaultForeColor = Application.Current.FindResource("immutableBrushVolumeColumnForeground") as SolidColorBrush; 231 | if ( (ForeColor as SolidColorBrush).Color == (ImmutableForeColor as SolidColorBrush).Color 232 | && (ImmutableForeColor as SolidColorBrush).Color != defaultForeColor.Color) 233 | { 234 | ForeColor = defaultForeColor; 235 | ImmutableForeColor = defaultForeColor; 236 | restored = true; 237 | } 238 | 239 | SolidColorBrush defaultBarColor = Application.Current.FindResource("immutableBrushVolumeColumnBackground") as SolidColorBrush; 240 | if ((BarColor as SolidColorBrush).Color == (ImmutableBarColor as SolidColorBrush).Color 241 | && (ImmutableBarColor as SolidColorBrush).Color != defaultBarColor.Color) 242 | { 243 | BarColor = defaultBarColor; 244 | ImmutableBarColor = defaultBarColor; 245 | restored = true; 246 | } 247 | 248 | if (restored) OnPropertyChanged(); 249 | } 250 | 251 | protected override void OnStateChange() 252 | { 253 | if (State == State.SetDefaults) 254 | { 255 | Name = "Num Touches"; 256 | Buys = new ConcurrentDictionary(); 257 | BackColor = Brushes.Transparent; 258 | BarColor = Application.Current.TryFindResource("brushVolumeColumnBackground") as Brush; 259 | BuyColor = Brushes.Green; 260 | DefaultWidth = 160; 261 | PreviousWidth = -1; 262 | DisplayText = true; 263 | ForeColor = Application.Current.TryFindResource("brushVolumeColumnForeground") as Brush; 264 | ImmutableBarColor = Application.Current.TryFindResource("immutableBrushVolumeColumnBackground") as Brush; 265 | ImmutableForeColor = Application.Current.TryFindResource("immutableBrushVolumeColumnForeground") as Brush; 266 | IsDataSeriesRequired = true; 267 | LastVolumes = new ConcurrentDictionary(); 268 | SellColor = Brushes.Red; 269 | Sells = new ConcurrentDictionary(); 270 | Bidask = VolumeSide.bid; 271 | } 272 | else if (State == State.Configure) 273 | { 274 | if (UiWrapper != null && PresentationSource.FromVisual(UiWrapper) != null) 275 | { 276 | Matrix m = PresentationSource.FromVisual(UiWrapper).CompositionTarget.TransformToDevice; 277 | double dpiFactor = 1 / m.M11; 278 | gridPen = new Pen(Application.Current.TryFindResource("BorderThinBrush") as Brush, 1 * dpiFactor); 279 | halfPenWidth = gridPen.Thickness * 0.5; 280 | } 281 | 282 | if (SuperDom.Instrument != null && SuperDom.IsConnected) 283 | { 284 | BarsPeriod bp = new BarsPeriod 285 | { 286 | MarketDataType = MarketDataType.Last, 287 | BarsPeriodType = BarsPeriodType.Tick, 288 | Value = 1 289 | }; 290 | 291 | SuperDom.Dispatcher.InvokeAsync(() => SuperDom.SetLoadingString()); 292 | clearLoadingSent = false; 293 | 294 | if (BarsRequest != null) 295 | { 296 | BarsRequest.Update -= OnBarsUpdate; 297 | BarsRequest = null; 298 | } 299 | 300 | BarsRequest = new BarsRequest(SuperDom.Instrument, 301 | Cbi.Connection.PlaybackConnection != null ? Cbi.Connection.PlaybackConnection.Now : Core.Globals.Now, 302 | Cbi.Connection.PlaybackConnection != null ? Cbi.Connection.PlaybackConnection.Now : Core.Globals.Now); 303 | 304 | BarsRequest.BarsPeriod = bp; 305 | BarsRequest.TradingHours = (TradingHoursData == TradingHours.UseInstrumentSettings || TradingHours.Get(TradingHoursData) == null) ? SuperDom.Instrument.MasterInstrument.TradingHours : TradingHours.Get(TradingHoursData); 306 | BarsRequest.Update += OnBarsUpdate; 307 | 308 | BarsRequest.Request((request, errorCode, errorMessage) => 309 | { 310 | // Make sure this isn't a bars callback from another column instance 311 | if (request != BarsRequest) 312 | return; 313 | 314 | lastMaxIndex = 0; 315 | maxVolume = 0; 316 | totalBuyVolume = 0; 317 | totalLastVolume = 0; 318 | totalSellVolume = 0; 319 | Sells.Clear(); 320 | Buys.Clear(); 321 | LastVolumes.Clear(); 322 | 323 | if (State >= NinjaTrader.NinjaScript.State.Terminated) 324 | return; 325 | 326 | if (errorCode == Cbi.ErrorCode.UserAbort) 327 | { 328 | if (State <= NinjaTrader.NinjaScript.State.Terminated) 329 | if (SuperDom != null && !clearLoadingSent) 330 | { 331 | SuperDom.Dispatcher.InvokeAsync(() => SuperDom.ClearLoadingString()); 332 | clearLoadingSent = true; 333 | } 334 | 335 | request.Update -= OnBarsUpdate; 336 | request.Dispose(); 337 | request = null; 338 | return; 339 | } 340 | 341 | if (errorCode != Cbi.ErrorCode.NoError) 342 | { 343 | request.Update -= OnBarsUpdate; 344 | request.Dispose(); 345 | request = null; 346 | if (SuperDom != null && !clearLoadingSent) 347 | { 348 | SuperDom.Dispatcher.InvokeAsync(() => SuperDom.ClearLoadingString()); 349 | clearLoadingSent = true; 350 | } 351 | } 352 | else if (errorCode == Cbi.ErrorCode.NoError) 353 | { 354 | SessionIterator superDomSessionIt = new SessionIterator(request.Bars); 355 | bool isInclude60 = request.Bars.BarsType.IncludesEndTimeStamp(false); 356 | if (superDomSessionIt.IsInSession(Core.Globals.Now, isInclude60, request.Bars.BarsType.IsIntraday)) 357 | { 358 | for (int i = 0; i < request.Bars.Count; i++) 359 | { 360 | DateTime time = request.Bars.BarsSeries.GetTime(i); 361 | if ((isInclude60 && time <= superDomSessionIt.ActualSessionBegin) || (!isInclude60 && time < superDomSessionIt.ActualSessionBegin)) 362 | continue; 363 | 364 | double ask = request.Bars.BarsSeries.GetAsk(i); 365 | double bid = request.Bars.BarsSeries.GetBid(i); 366 | double close = request.Bars.BarsSeries.GetClose(i); 367 | long volume = request.Bars.BarsSeries.GetVolume(i); 368 | 369 | if (ask != double.MinValue && close >= ask) 370 | { 371 | Buys.AddOrUpdate(close, volume, (price, oldVolume) => oldVolume + volume); 372 | totalBuyVolume += volume; 373 | } 374 | else if (bid != double.MinValue && close <= bid) 375 | { 376 | Sells.AddOrUpdate(close, volume, (price, oldVolume) => oldVolume + volume); 377 | totalSellVolume += volume; 378 | } 379 | 380 | long newVolume; 381 | LastVolumes.AddOrUpdate(close, newVolume = volume, (price, oldVolume) => newVolume = 0); 382 | totalLastVolume += volume; 383 | 384 | if (newVolume > maxVolume) 385 | maxVolume = newVolume; 386 | } 387 | 388 | lastMaxIndex = request.Bars.Count - 1; 389 | 390 | // Repaint the column on the SuperDOM 391 | OnPropertyChanged(); 392 | } 393 | 394 | if (SuperDom != null && !clearLoadingSent) 395 | { 396 | SuperDom.Dispatcher.InvokeAsync(() => SuperDom.ClearLoadingString()); 397 | clearLoadingSent = true; 398 | } 399 | } 400 | }); 401 | } 402 | } 403 | else if (State == State.Active) 404 | { 405 | if (!DisplayText) 406 | { 407 | WeakEventManager.AddHandler(UiWrapper, "MouseMove", OnMouseMove); 408 | WeakEventManager.AddHandler(UiWrapper, "MouseEnter", OnMouseEnter); 409 | WeakEventManager.AddHandler(UiWrapper, "MouseLeave", OnMouseLeave); 410 | mouseEventsSubscribed = true; 411 | } 412 | } 413 | else if (State == State.Terminated) 414 | { 415 | if (BarsRequest != null) 416 | { 417 | BarsRequest.Update -= OnBarsUpdate; 418 | BarsRequest.Dispose(); 419 | } 420 | 421 | BarsRequest = null; 422 | 423 | if (SuperDom != null && !clearLoadingSent) 424 | { 425 | SuperDom.Dispatcher.InvokeAsync(() => SuperDom.ClearLoadingString()); 426 | clearLoadingSent = true; 427 | } 428 | 429 | if (!DisplayText && mouseEventsSubscribed) 430 | { 431 | WeakEventManager.RemoveHandler(UiWrapper, "MouseMove", OnMouseMove); 432 | WeakEventManager.RemoveHandler(UiWrapper, "MouseEnter", OnMouseEnter); 433 | WeakEventManager.RemoveHandler(UiWrapper, "MouseLeave", OnMouseLeave); 434 | mouseEventsSubscribed = false; 435 | } 436 | 437 | lastMaxIndex = 0; 438 | maxVolume = 0; 439 | totalBuyVolume = 0; 440 | totalLastVolume = 0; 441 | totalSellVolume = 0; 442 | Sells.Clear(); 443 | Buys.Clear(); 444 | LastVolumes.Clear(); 445 | } 446 | } 447 | 448 | #region Bar Collections 449 | [XmlIgnore] 450 | [Browsable(false)] 451 | public ConcurrentDictionary Buys { get; set; } 452 | 453 | [XmlIgnore] 454 | [Browsable(false)] 455 | public ConcurrentDictionary LastVolumes { get; set; } 456 | 457 | [XmlIgnore] 458 | [Browsable(false)] 459 | public ConcurrentDictionary Sells { get; set; } 460 | #endregion 461 | 462 | #region Properties 463 | 464 | [NinjaScriptProperty] 465 | [Display(Name="Bidask", Order=1, GroupName="Parameters")] 466 | public VolumeSide Bidask 467 | { get; set; } 468 | 469 | [XmlIgnore] 470 | [Display(ResourceType = typeof(Resource), Name = "NinjaScriptColumnBaseBackground", GroupName = "PropertyCategoryVisual", Order = 130)] 471 | public Brush BackColor { get; set; } 472 | 473 | [Browsable(false)] 474 | public string BackColorSerialize 475 | { 476 | get { return NinjaTrader.Gui.Serialize.BrushToString(BackColor); } 477 | set { BackColor = NinjaTrader.Gui.Serialize.StringToBrush(value); } 478 | } 479 | 480 | [XmlIgnore] 481 | [Display(ResourceType = typeof(Resource), Name = "NinjaScriptBarColor", GroupName = "PropertyCategoryVisual", Order = 110)] 482 | public Brush BarColor { get; set; } 483 | 484 | [Browsable(false)] 485 | public string BarColorSerialize 486 | { 487 | get { return NinjaTrader.Gui.Serialize.BrushToString(BarColor); } 488 | set { BarColor = NinjaTrader.Gui.Serialize.StringToBrush(value); } 489 | } 490 | 491 | [XmlIgnore] 492 | [Display(ResourceType = typeof(Resource), Name = "NinjaScriptBuyColor", GroupName = "PropertyCategoryVisual", Order = 120)] 493 | public Brush BuyColor { get; set; } 494 | 495 | [Browsable(false)] 496 | public string BuyColorSerialize 497 | { 498 | get { return NinjaTrader.Gui.Serialize.BrushToString(BuyColor); } 499 | set { BuyColor = NinjaTrader.Gui.Serialize.StringToBrush(value); } 500 | } 501 | 502 | [Display(ResourceType = typeof(Resource), Name = "NinjaScriptDisplayText", GroupName = "PropertyCategoryVisual", Order = 175)] 503 | public bool DisplayText { get; set; } 504 | 505 | 506 | [XmlIgnore] 507 | [Display(ResourceType = typeof(Resource), Name = "NinjaScriptColumnBaseForeground", GroupName = "PropertyCategoryVisual", Order = 140)] 508 | public Brush ForeColor { get; set; } 509 | 510 | [Browsable(false)] 511 | public string ForeColorSerialize 512 | { 513 | get { return NinjaTrader.Gui.Serialize.BrushToString(ForeColor); } 514 | set { ForeColor = NinjaTrader.Gui.Serialize.StringToBrush(value); } 515 | } 516 | 517 | [XmlIgnore] 518 | [Browsable(false)] 519 | public Brush ImmutableBarColor { get; set; } 520 | 521 | [Browsable(false)] 522 | public string ImmutableBarColorSerialize 523 | { 524 | get { return NinjaTrader.Gui.Serialize.BrushToString(ImmutableBarColor, "CustomVolume.ImmutableBarColor"); } 525 | set { ImmutableBarColor = NinjaTrader.Gui.Serialize.StringToBrush(value, "CustomVolume.ImmutableBarColor"); } 526 | } 527 | 528 | [XmlIgnore] 529 | [Browsable(false)] 530 | public Brush ImmutableForeColor { get; set; } 531 | 532 | [Browsable(false)] 533 | public string ImmutableForeColorSerialize 534 | { 535 | get { return NinjaTrader.Gui.Serialize.BrushToString(ImmutableForeColor, "CustomVolume.ImmutableForeColor"); } 536 | set { ImmutableForeColor = NinjaTrader.Gui.Serialize.StringToBrush(value, "CustomVolume.ImmutableForeColor"); } 537 | } 538 | 539 | [XmlIgnore] 540 | [Display(ResourceType = typeof(Resource), Name = "NinjaScriptSellColor", GroupName = "PropertyCategoryVisual", Order = 170)] 541 | public Brush SellColor { get; set; } 542 | 543 | [Browsable(false)] 544 | public string SellColorSerialize 545 | { 546 | get { return NinjaTrader.Gui.Serialize.BrushToString(SellColor); } 547 | set { SellColor = NinjaTrader.Gui.Serialize.StringToBrush(value); } 548 | } 549 | 550 | [Display(ResourceType = typeof(Resource), Name = "IndicatorSuperDomBaseTradingHoursTemplate", GroupName = "NinjaScriptTimeFrame", Order = 60)] 551 | [RefreshProperties(RefreshProperties.All)] 552 | [TypeConverter(typeof(NinjaTrader.NinjaScript.TradingHoursDataConverter))] 553 | public string TradingHoursData 554 | { 555 | get { return tradingHoursData; } 556 | set { tradingHoursData = value; } 557 | } 558 | 559 | #endregion 560 | } 561 | } 562 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | How to check out: 2 | 3 | 1. Download git tools for windows. 4 | 2. Create a new folder. 5 | 3. Clone this repository into the new folder. 6 | 4. Copy the contents of the Ninjatrader-scripts folder into your NinjaTrader 8 scripts directory (Documents/NinjaTrader8/bin/Custom 7 | 8 | The .git folder is what you need for git to recognize your NinjaTrader8 custom directory as under git. --------------------------------------------------------------------------------