I'm Trying to create a Multi Oscillator Indicator that contains all three, Stochastics, MFI & RSI,
MFI and Stochastics are plotting fine, but RSI is not, I do not have any errors, but I can't seem to figure out why it is not working,
I'm pasting the code below, pLEASE HELP.
//
// Copyright (C) 2023, 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.MWQ
{
public class MWQMultiOscillatorOverlap : Indicator
{
private Series<double> den;
private Series<double> fastK;
private Series<double> negative;
private Series<double> positive;
private Series<double> avgDown;
private Series<double> avgUp;
private Series<double> up;
private Series<double> down;
private Series<double> nom;
private MIN min;
private MAX max;
private SMA smaFastK;
private SMA smaK;
private SMA smaDown;
private SMA smaUp;
private SUM sumNegative;
private SUM sumPositive;
private double constant1;
private double constant2;
private double constant3;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Description = NinjaTrader.Custom.Resource.NinjaScriptIndicatorDe scriptionStochastics;
Name = "MWQMultiOscillatorOverlap";
IsSuspendedWhileInactive = true;
PeriodD = 7;
PeriodK = 14;
SmoothStoch = 3;
MFIPeriod = 14;
RSIPeriod = 14;
RSISmooth = 3;
AddPlot(Brushes.DodgerBlue, NinjaTrader.Custom.Resource.StochasticsD);
AddPlot(Brushes.Goldenrod, NinjaTrader.Custom.Resource.StochasticsK);
AddPlot(Brushes.DarkCyan, NinjaTrader.Custom.Resource.NinjaScriptIndicatorNa meMFI);
AddPlot(Brushes.AntiqueWhite, NinjaTrader.Custom.Resource.NinjaScriptIndicatorNa meRSI);
AddPlot(Brushes.DarkSalmon, NinjaTrader.Custom.Resource.NinjaScriptIndicatorAv g);
AddLine(Brushes.DarkCyan, 20, NinjaTrader.Custom.Resource.NinjaScriptIndicatorLo wer);
AddLine(Brushes.DarkCyan, 80, NinjaTrader.Custom.Resource.NinjaScriptIndicatorUp per);
}
else if (State == State.DataLoaded)
{
den = new Series<double>(this);
nom = new Series<double>(this);
fastK = new Series<double>(this);
min = MIN(Low, PeriodK);
max = MAX(High, PeriodK);
smaFastK = SMA(fastK, SmoothStoch);
smaK = SMA(K, PeriodD);
negative = new Series<double>(this);
positive = new Series<double>(this);
sumNegative = SUM(negative, MFIPeriod);
sumPositive = SUM(positive, MFIPeriod);
avgUp = new Series<double>(this);
avgDown = new Series<double>(this);
down = new Series<double>(this);
up = new Series<double>(this);
smaDown = SMA(down, RSIPeriod);
smaUp = SMA(up, RSIPeriod);
}
}
protected override void OnBarUpdate()
{
{
double min0 = min[0];
nom[0] = Close[0] - min0;
den[0] = max[0] - min0;
if (den[0].ApproxCompare(0) == 0)
fastK[0] = CurrentBar == 0 ? 50 : fastK[1];
else
fastK[0] = Math.Min(100, Math.Max(0, 100 * nom[0] / den[0]));
}
// Slow %K == Fast %D
K[0] = smaFastK[0];
D[0] = smaK[0];
//MFI
{
if (CurrentBar == 0)
MFI[0] = 50;
else
{
double typical0 = Typical[0];
double typical1 = Typical[1];
double volume0 = Instrument.MasterInstrument.InstrumentType == InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume((long)Volume[0]) : Volume[0];
negative[0] = typical0 < typical1 ? typical0 * volume0 : 0;
positive[0] = typical0 > typical1 ? typical0 * volume0 : 0;
double sumNegative0 = sumNegative[0];
MFI[0] = sumNegative0 == 0 ? 50 : 100.0 - (100.0 / (1 + sumPositive[0] / sumNegative0));
}
}
//RSI
{
if (CurrentBar == 0)
constant1 = 2.0 / (1 + RSISmooth);
constant2 = (1 - (2.0 / (1 + RSISmooth)));
constant3 = (RSIPeriod - 1);
down[0] = 0;
up[0] = 0;
if (RSIPeriod < 3)
Avg[0] = 50;
return;
}
double input0 = Input[0];
double input1 = Input[1];
down[0] = Math.Max(input1 - input0, 0);
up[0] = Math.Max(input0 - input1, 0);
if (CurrentBar + 1 < RSIPeriod)
{
if (CurrentBar + 1 == RSIPeriod - 1)
Avg[0] = 50;
return;
}
if ((CurrentBar + 1) == RSIPeriod)
{
// First averages
avgDown[0] = smaDown[0];
avgUp[0] = smaUp[0];
}
else
{
// Rest of averages are smoothed
avgDown[0] = (avgDown[1] * constant3 + down[0]) / RSIPeriod;
avgUp[0] = (avgUp[1] * constant3 + up[0]) / RSIPeriod;
}
double avgDown0 = avgDown[0];
double value0 = avgDown0 == 0 ? 100 : 100 - 100 / (1 + avgUp[0] / avgDown0);
// RSI & Avg
RSI[0] = value0;
Avg[0] = constant1 * value0 + constant2 * Avg[1];
return;
}
region Properties
[Browsable(false)]
[XmlIgnore()]
public Series<double> D
{
get { return Values[0]; }
}
[Browsable(false)]
[XmlIgnore()]
public Series<double> K
{
get { return Values[1]; }
}
[Browsable(false)]
[XmlIgnore()]
public Series<double> MFI
{
get { return Values[2]; }
}
[Browsable(false)]
[XmlIgnore()]
public Series<double> RSI
{
get { return Values[3]; }
}
[Browsable(false)]
[XmlIgnore()]
public Series<double> Avg
{
get { return Values[4]; }
}
[Range(1, int.MaxValue), NinjaScriptProperty]
[Display(ResourceType = typeof(Custom.Resource), Name = "PeriodD", GroupName = "NinjaScriptParameters", Order = 0)]
public int PeriodD
{ get; set; }
[Range(1, int.MaxValue), NinjaScriptProperty]
[Display(ResourceType = typeof(Custom.Resource), Name = "PeriodK", GroupName = "NinjaScriptParameters", Order = 1)]
public int PeriodK
{ get; set; }
[Range(1, int.MaxValue), NinjaScriptProperty]
[Display(ResourceType = typeof(Custom.Resource), Name = "SmoothStoch", GroupName = "NinjaScriptParameters", Order = 2)]
public int SmoothStoch
{ get; set; }
[Range(1, int.MaxValue), NinjaScriptProperty]
[Display(ResourceType = typeof(Custom.Resource), Name = "MFIPeriod", GroupName = "NinjaScriptParameters", Order = 3)]
public int MFIPeriod
{ get; set; }
[Range(1, int.MaxValue), NinjaScriptProperty]
[Display(ResourceType = typeof(Custom.Resource), Name = "RSIPeriod", GroupName = "NinjaScriptParameters", Order = 4)]
public int RSIPeriod
{ get; set; }
[Range(1, int.MaxValue), NinjaScriptProperty]
[Display(ResourceType = typeof(Custom.Resource), Name = "RSISmooth", GroupName = "NinjaScriptParameters", Order = 5)]
public int RSISmooth
{ get; set; }
#endregion
}
}
region NinjaScript generated code. Neither change nor remove.
namespace NinjaTrader.NinjaScript.Indicators
{
public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
{
private MWQ.MWQMultiOscillatorOverlap[] cacheMWQMultiOscillatorOverlap;
public MWQ.MWQMultiOscillatorOverlap MWQMultiOscillatorOverlap(int periodD, int periodK, int smoothStoch, int mFIPeriod, int rSIPeriod, int rSISmooth)
{
return MWQMultiOscillatorOverlap(Input, periodD, periodK, smoothStoch, mFIPeriod, rSIPeriod, rSISmooth);
}
public MWQ.MWQMultiOscillatorOverlap MWQMultiOscillatorOverlap(ISeries<double> input, int periodD, int periodK, int smoothStoch, int mFIPeriod, int rSIPeriod, int rSISmooth)
{
if (cacheMWQMultiOscillatorOverlap != null)
for (int idx = 0; idx < cacheMWQMultiOscillatorOverlap.Length; idx++)
if (cacheMWQMultiOscillatorOverlap[idx] != null && cacheMWQMultiOscillatorOverlap[idx].PeriodD == periodD && cacheMWQMultiOscillatorOverlap[idx].PeriodK == periodK && cacheMWQMultiOscillatorOverlap[idx].SmoothStoch == smoothStoch && cacheMWQMultiOscillatorOverlap[idx].MFIPeriod == mFIPeriod && cacheMWQMultiOscillatorOverlap[idx].RSIPeriod == rSIPeriod && cacheMWQMultiOscillatorOverlap[idx].RSISmooth == rSISmooth && cacheMWQMultiOscillatorOverlap[idx].EqualsInput(input))
return cacheMWQMultiOscillatorOverlap[idx];
return CacheIndicator<MWQ.MWQMultiOscillatorOverlap>(new MWQ.MWQMultiOscillatorOverlap(){ PeriodD = periodD, PeriodK = periodK, SmoothStoch = smoothStoch, MFIPeriod = mFIPeriod, RSIPeriod = rSIPeriod, RSISmooth = rSISmooth }, input, ref cacheMWQMultiOscillatorOverlap);
}
}
}
namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
{
public Indicators.MWQ.MWQMultiOscillatorOverlap MWQMultiOscillatorOverlap(int periodD, int periodK, int smoothStoch, int mFIPeriod, int rSIPeriod, int rSISmooth)
{
return indicator.MWQMultiOscillatorOverlap(Input, periodD, periodK, smoothStoch, mFIPeriod, rSIPeriod, rSISmooth);
}
public Indicators.MWQ.MWQMultiOscillatorOverlap MWQMultiOscillatorOverlap(ISeries<double> input , int periodD, int periodK, int smoothStoch, int mFIPeriod, int rSIPeriod, int rSISmooth)
{
return indicator.MWQMultiOscillatorOverlap(input, periodD, periodK, smoothStoch, mFIPeriod, rSIPeriod, rSISmooth);
}
}
}
namespace NinjaTrader.NinjaScript.Strategies
{
public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
{
public Indicators.MWQ.MWQMultiOscillatorOverlap MWQMultiOscillatorOverlap(int periodD, int periodK, int smoothStoch, int mFIPeriod, int rSIPeriod, int rSISmooth)
{
return indicator.MWQMultiOscillatorOverlap(Input, periodD, periodK, smoothStoch, mFIPeriod, rSIPeriod, rSISmooth);
}
public Indicators.MWQ.MWQMultiOscillatorOverlap MWQMultiOscillatorOverlap(ISeries<double> input , int periodD, int periodK, int smoothStoch, int mFIPeriod, int rSIPeriod, int rSISmooth)
{
return indicator.MWQMultiOscillatorOverlap(input, periodD, periodK, smoothStoch, mFIPeriod, rSIPeriod, rSISmooth);
}
}
}
#endregion
Comment