#region Using declarations using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using System.Windows.Media; using System.Xml.Serialization; using NinjaTrader.Cbi; using NinjaTrader.Gui; using NinjaTrader.Gui.Chart; using NinjaTrader.Gui.SuperDom; using NinjaTrader.Gui.Tools; using NinjaTrader.Data; using NinjaTrader.NinjaScript; using NinjaTrader.Core.FloatingPoint; using NinjaTrader.NinjaScript.DrawingTools; using System.Net; using System.Net.Cache; using System.IO; #endregion //This namespace holds Indicators in this folder and is required. Do not change it. namespace NinjaTrader.NinjaScript.Indicators { public class WTTAutoLevelsDisplay : Indicator { // INTERNAL VARIABLES static object locker = new object(); public class LevelInfo { public int id = 0; public double price1 = 0; public double price2 = 0; } List levels; DateTime lastRefresh = DateTime.MinValue; SharpDX.Direct2D1.Brush levelBrushDX, levelBrushDXFaded; Size stringMeasure; protected override void OnStateChange() { if (State == State.SetDefaults) { Description = @"WWT - Displays zones on a chart read from an online file"; Name = "WTT Target Levels"; Calculate = Calculate.OnPriceChange; IsOverlay = true; DisplayInDataBox = true; DrawOnPricePanel = true; DrawHorizontalGridLines = true; DrawVerticalGridLines = true; PaintPriceMarkers = true; ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right; //Disable this property if your indicator requires custom values that cumulate with each new market data event. //See Help Guide for additional information. IsSuspendedWhileInactive = true; // EXTERNAL INPUT DEFAULTS LevelsColor = Brushes.SkyBlue; LevelsOpacity = 30; FileURL = developer ? @"https://www.dropbox.com/s/b4yj8c8jzrbd7z6/ES_Targets.azr?dl=1" : string.Empty; DataRefreshInterval = 5; } else if (State == State.Configure) { } else if (State == State.DataLoaded) { } else if (State == State.Historical) { SetZOrder(-1); // behind price bars RefreshLevelsData(); } } protected override void OnBarUpdate() { if (DateTime.Now > lastRefresh.AddMinutes(DataRefreshInterval)) RefreshLevelsData(); } // ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ #region data reading private bool RefreshLevelsData() { if (levels == null) levels = new List(); else levels.Clear(); bool ok = ReadFileURL(FileURL); lastRefresh = DateTime.Now; return ok; } private bool ReadFileURL(string URL) { lock (locker) { // check internet for authorisation HttpWebRequest netReq = (HttpWebRequest)HttpWebRequest.Create(URL); netReq.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.Reload); // fetch the csv doc from the web server using (HttpWebResponse netResp = (HttpWebResponse)netReq.GetResponse()) { // check that we got a valid reponse if (netResp != null && netResp.StatusCode == HttpStatusCode.OK) { // read the response stream into a document Stream receiveStream = netResp.GetResponseStream(); Encoding encode = System.Text.Encoding.GetEncoding("utf-8"); StreamReader readStream = new StreamReader( receiveStream, encode ); string totalContents = readStream.ReadToEnd(); Print("Read this file: "+Environment.NewLine+totalContents); string[] file = totalContents.Split(Environment.NewLine.ToCharArray(),StringSplitOptions.RemoveEmptyEntries); Print("lines in total file[] is "+file.Length); for (int line = 0; line < file.Length; line++) { string[] cells = file[line].Split(new[]{'\t'},StringSplitOptions.None); if (cells.Length < 4) continue; // match instrument if (cells[0].ToUpper().Trim() != Instrument.MasterInstrument.Name.ToUpper()) continue; int id = 0; double price1 = 0, price2 = 0; bool ok = int.TryParse(cells[1],out id); if (!ok) { Print("Could not parse '"+cells[1]+"' to int"); continue; } ok = double.TryParse(cells[2],out price1); if (!ok) { Print("Could not parse '"+cells[2]+"' to double"); continue; } ok = double.TryParse(cells[3],out price2); if (!ok) { Print("Could not parse '"+cells[3]+"' to double"); continue; } // all good LevelInfo newLevel = new LevelInfo(); newLevel.id = id; newLevel.price1 = price1; newLevel.price2 = price2; // add to collection levels.Add(newLevel); // if (developer) Print("\tAdded level "+id+" from "+price1+" to "+price2); Print("\tAdded level "+id+" from "+price1+" to "+price2); } } } } return levels.Count > 0; } #endregion #region custom graphics public override void OnRenderTargetChanged() { levelBrushDX = null; levelBrushDXFaded = null; } protected override void OnRender(ChartControl chartControl, ChartScale chartScale) { if (Bars == null || ChartBars == null || CurrentBars[0] < 2 || !this.IsVisible) return; base.OnRender(chartControl,chartScale); if (levelBrushDX == null) { levelBrushDX = LevelsColor.ToDxBrush(RenderTarget); levelBrushDXFaded = LevelsColor.ToDxBrush(RenderTarget); levelBrushDXFaded.Opacity = LevelsOpacity*0.01f; stringMeasure = MeasureString("Target X",chartControl.Properties.LabelFont); } // Set text to chart label color and font SharpDX.DirectWrite.TextFormat textFormat = chartControl.Properties.LabelFont.ToDirectWriteTextFormat(); for (int l = 0; l < levels.Count; l++) { Print("Rendering......"+levels[l].price1); int id = levels[l].id; double p1 = levels[l].price1; double p2 = levels[l].price2; int y1 = chartScale.GetYByValue(p1); int y2 = chartScale.GetYByValue(p2); int yBot = chartScale.GetYByValue(Math.Min(p1,p2)); RenderTarget.FillRectangle(new SharpDX.RectangleF(ChartPanel.X,y1,ChartPanel.W,Math.Abs(y2-y1)+1),levelBrushDXFaded); // Draw pivot text SharpDX.DirectWrite.TextLayout textLayout = new SharpDX.DirectWrite.TextLayout(NinjaTrader.Core.Globals.DirectWriteFactory, " Target "+id.ToString(), textFormat, ChartPanel.W, textFormat.FontSize); float height = (float)stringMeasure.Height; RenderTarget.DrawTextLayout(new SharpDX.Vector2((float)ChartPanel.X,(float)yBot-height*1f), textLayout, levelBrushDX); textLayout.Dispose(); } textFormat.Dispose(); } private Size MeasureString(string candidate, SimpleFont font) { var formattedText = new FormattedText( candidate, System.Globalization.CultureInfo.CurrentUICulture, System.Windows.FlowDirection.LeftToRight, font.Typeface, font.Size, Brushes.Black); return new Size(formattedText.Width, formattedText.Height); } #endregion #region misc protected bool developer { get { // return NinjaTrader.Cbi.License.MachineId == "974A3723B4E169F107FE944660A9D982"; // JD development machine (win10 Parallels) return true; } } #endregion #region Properties [NinjaScriptProperty] [XmlIgnore] [Display(Name="LevelsColor", Order=10, GroupName="Parameters")] public Brush LevelsColor { get; set; } [Browsable(false)] public string LevelsColorSerializable { get { return Serialize.BrushToString(LevelsColor); } set { LevelsColor = Serialize.StringToBrush(value); } } [NinjaScriptProperty] [Range(0, int.MaxValue)] [Display(Name="LevelsOpacity", Description="Opacity 0 to 100", Order=20, GroupName="Parameters")] public int LevelsOpacity { get; set; } [NinjaScriptProperty] [Display(Name="FileURL", Description="The URL of the online file", Order=30, GroupName="Parameters")] public string FileURL { get; set; } [NinjaScriptProperty] [Range(1, 240)] [Display(Name="Data RefreshInterval (Minutes)", Description="Minutes between reads of the URL", Order=40, GroupName="Parameters")] public int DataRefreshInterval { get; set; } #endregion } } #region NinjaScript generated code. Neither change nor remove. namespace NinjaTrader.NinjaScript.Indicators { public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase { private WTTAutoLevelsDisplay[] cacheWTTAutoLevelsDisplay; public WTTAutoLevelsDisplay WTTAutoLevelsDisplay(Brush levelsColor, int levelsOpacity, string fileURL, int dataRefreshInterval) { return WTTAutoLevelsDisplay(Input, levelsColor, levelsOpacity, fileURL, dataRefreshInterval); } public WTTAutoLevelsDisplay WTTAutoLevelsDisplay(ISeries input, Brush levelsColor, int levelsOpacity, string fileURL, int dataRefreshInterval) { if (cacheWTTAutoLevelsDisplay != null) for (int idx = 0; idx < cacheWTTAutoLevelsDisplay.Length; idx++) if (cacheWTTAutoLevelsDisplay[idx] != null && cacheWTTAutoLevelsDisplay[idx].LevelsColor == levelsColor && cacheWTTAutoLevelsDisplay[idx].LevelsOpacity == levelsOpacity && cacheWTTAutoLevelsDisplay[idx].FileURL == fileURL && cacheWTTAutoLevelsDisplay[idx].DataRefreshInterval == dataRefreshInterval && cacheWTTAutoLevelsDisplay[idx].EqualsInput(input)) return cacheWTTAutoLevelsDisplay[idx]; return CacheIndicator(new WTTAutoLevelsDisplay(){ LevelsColor = levelsColor, LevelsOpacity = levelsOpacity, FileURL = fileURL, DataRefreshInterval = dataRefreshInterval }, input, ref cacheWTTAutoLevelsDisplay); } } } namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns { public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase { public Indicators.WTTAutoLevelsDisplay WTTAutoLevelsDisplay(Brush levelsColor, int levelsOpacity, string fileURL, int dataRefreshInterval) { return indicator.WTTAutoLevelsDisplay(Input, levelsColor, levelsOpacity, fileURL, dataRefreshInterval); } public Indicators.WTTAutoLevelsDisplay WTTAutoLevelsDisplay(ISeries input , Brush levelsColor, int levelsOpacity, string fileURL, int dataRefreshInterval) { return indicator.WTTAutoLevelsDisplay(input, levelsColor, levelsOpacity, fileURL, dataRefreshInterval); } } } namespace NinjaTrader.NinjaScript.Strategies { public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase { public Indicators.WTTAutoLevelsDisplay WTTAutoLevelsDisplay(Brush levelsColor, int levelsOpacity, string fileURL, int dataRefreshInterval) { return indicator.WTTAutoLevelsDisplay(Input, levelsColor, levelsOpacity, fileURL, dataRefreshInterval); } public Indicators.WTTAutoLevelsDisplay WTTAutoLevelsDisplay(ISeries input , Brush levelsColor, int levelsOpacity, string fileURL, int dataRefreshInterval) { return indicator.WTTAutoLevelsDisplay(input, levelsColor, levelsOpacity, fileURL, dataRefreshInterval); } } } #endregion