note: I do have an indicator folder named RadIndicators for my custom indicators.
// // Copyright (C) 2019, NinjaTrader LLC <www.ninjatrader.com>. // NinjaTrader reserves the right to modify or overwrite this NinjaScript component with each release. // #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.Data; using NinjaTrader.NinjaScript; using NinjaTrader.Core.FloatingPoint; using NinjaTrader.NinjaScript.DrawingTools; #endregion // This namespace holds indicators in this folder and is required. Do not change it. namespace NinjaTrader.NinjaScript.Indicators.RadIndicators { /// <summary> /// Plots the relative volume at the current time of day /// To be used with bars that arent time based. /// </summary> public class RadRelativeVolume : Indicator { private DateTime sessionStartTime; private double cumulativeVolume = 0; private TimeSpan startTime = new TimeSpan(4, 0, 0); // Default start time at 4 AM private double initialVolume = 100; // Default initial volume to avoid divide by zero private int historicalDays = 5; // Default: look back 5 days protected override void OnStateChange() { if (State == State.SetDefaults) { Description = @"Indicator for VPS with daily and historical average."; Name = "CustomVPSIndicator"; Calculate = Calculate.OnEachTick; // Necessary for VPS calculation IsOverlay = false; // This indicator does not overlay on the price chart MaximumBarsLookBack = MaximumBarsLookBack.Infinite; AddPlot(Brushes.DodgerBlue, "DailyVPS"); // Plot 1 AddPlot(Brushes.Coral, "AverageVPS"); // Plot 2 AddPlot(Brushes.Green, "RelativeVolume"); // Plot 2 } else if (State == State.DataLoaded) { } } protected override void OnBarUpdate() { // Ensure the session start time and cumulative volume are correctly initialized if (Bars.IsFirstBarOfSession || CurrentBar == 0) { sessionStartTime = Time[0].Date.Add(startTime); cumulativeVolume = initialVolume; } cumulativeVolume += Volume[0]; // Update Daily VPS plot TimeSpan elapsedSinceStart = Time[0] - sessionStartTime; Values[0][0] = cumulativeVolume / Math.Max(elapsedSinceStart.TotalSeconds, 1); // Avoid division by zero // Calculate and update Average VPS plot continuously Values[1][0] = CalculateMonteCarloAverageVPS(Time[0]); // Update the ratio plot only if averageVPS is not zero to avoid division by zero if (Values[1][0] != 0) Values[2][0] = Values[0][0] / Values[1][0]; } // Placeholder for calculating average VPS from previous 5 days using Monte Carlo method private double CalculateMonteCarloAverageVPS(DateTime currentTime) { // List to hold VPS values from the previous days for the same time List<double> previousVPSValues = new List<double>(); // Assuming we're calculating for the current time each day DateTime targetTime = Time[0]; // Calculate and store VPS for each of the historical days for (int daysBack = 1; daysBack <= historicalDays; daysBack++) { DateTime historicalTime = targetTime.AddDays(-daysBack); int barIndex = Bars.GetBar(historicalTime); if (barIndex > 0 && barIndex < CurrentBar) { // Approximate the VPS for this historical day at the target time double historicalVolume = Volume[barIndex]; // Simplified, consider using a better approximation double vps = historicalVolume; // This is a simplification, adjust according to your actual VPS calculation logic previousVPSValues.Add(vps); } } // Now, apply the Monte Carlo method to the collected VPS values // Sort the list to prepare for removing the highest and lowest values previousVPSValues.Sort(); if (previousVPSValues.Count >= 5) { // Remove the highest and lowest VPS values to apply Monte Carlo smoothing previousVPSValues.RemoveAt(0); // Remove the lowest previousVPSValues.RemoveAt(previousVPSValues.Count - 1); // Remove the highest } // Calculate and return the average of the remaining VPS values return previousVPSValues.Any() ? previousVPSValues.Average() : 0; // Ensure there's data to average } #region Properties [Browsable(false)] [XmlIgnore] public Series<double> Daily_Total_Volume { get { return Values[0]; } } [Browsable(false)] [XmlIgnore] public Series<double> AverageVPS { get { return Values[1]; } } [Browsable(false)] [XmlIgnore] public Series<double> RelativeVolume { get { return Values[2]; } } [Range(1, int.MaxValue), NinjaScriptProperty] public int HistoricalDays { get { return historicalDays; } set { historicalDays = Math.Max(1, value); } // Ensure at least 1 day } #endregion } } #region NinjaScript generated code. Neither change nor remove. namespace NinjaTrader.NinjaScript.Indicators { public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase { private RadIndicators.RadRelativeVolume[] cacheRadRelativeVolume; public RadIndicators.RadRelativeVolume RadRelativeVolume(int historicalDays) { return RadRelativeVolume(Input, historicalDays); } public RadIndicators.RadRelativeVolume RadRelativeVolume(ISeries<double> input, int historicalDays) { if (cacheRadRelativeVolume != null) for (int idx = 0; idx < cacheRadRelativeVolume.Length; idx++) if (cacheRadRelativeVolume[idx] != null && cacheRadRelativeVolume[idx].HistoricalDays == historicalDays && cacheRadRelativeVolume[idx].EqualsInput(input)) return cacheRadRelativeVolume[idx]; return CacheIndicator<RadIndicators.RadRelativeVolume>(new RadIndicators.RadRelativeVolume(){ HistoricalDays = historicalDays }, input, ref cacheRadRelativeVolume); } } } namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns { public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase { public Indicators.RadIndicators.RadRelativeVolume RadRelativeVolume(int historicalDays) { return indicator.RadRelativeVolume(Input, historicalDays); } public Indicators.RadIndicators.RadRelativeVolume RadRelativeVolume(ISeries<double> input , int historicalDays) { return indicator.RadRelativeVolume(input, historicalDays); } } } namespace NinjaTrader.NinjaScript.Strategies { public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase { public Indicators.RadIndicators.RadRelativeVolume RadRelativeVolume(int historicalDays) { return indicator.RadRelativeVolume(Input, historicalDays); } public Indicators.RadIndicators.RadRelativeVolume RadRelativeVolume(ISeries<double> input , int historicalDays) { return indicator.RadRelativeVolume(input, historicalDays); } } } #endregion
Comment