Rsi and Rsx

This commit is contained in:
Miha Kralj
2024-10-24 18:30:59 -07:00
parent 707d81ff72
commit efc8e553db
7 changed files with 267 additions and 7 deletions
+1 -1
View File
@@ -23,7 +23,7 @@
|KEL - Keltner Channels||GetKeltner|||
|NATR - Normalized Average True Range||GetAtr|||
|CHN - Price Channel Indicator|||||
|RSI - Relative Strength Index||GetRsi|||
|RSI - Relative Strength Index|`Rsi`|GetRsi|||
|SAR - Parabolic Stop and Reverse||GetParabolicSar|||
|SRSI - Stochastic RSI||GetStochRsi|||
|STARC - Starc Bands||GetStarcBands|||
+4 -4
View File
@@ -32,7 +32,7 @@ public class Jma : AbstractBase
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Jma(int period, int phase = 0, double factor = 0.45)
public Jma(int period, int phase = 0, double factor = 0.45, int buffer = 10)
{
if (period < 1)
{
@@ -42,7 +42,7 @@ public class Jma : AbstractBase
_period = period;
_phase = Math.Clamp((phase * 0.01) + 1.5, 0.5, 2.5);
_vsumBuff = new CircularBuffer(10);
_vsumBuff = new CircularBuffer(buffer);
_avoltyBuff = new CircularBuffer(65);
_beta = factor * (_period - 1) / (factor * (_period - 1) + 2);
@@ -56,7 +56,7 @@ public class Jma : AbstractBase
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Jvolty.</param>
/// <param name="phase">The phase parameter for the JMA-style calculation.</param>
public Jma(object source, int period, int phase = 0) : this(period, phase)
public Jma(object source, int period, int phase = 0, double factor = 0.45, int buffer = 10) : this(period, phase, factor, buffer)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
@@ -148,7 +148,7 @@ public class Jma : AbstractBase
_prevDet0 = det0;
double ma2 = ma1 + _phase * det0;
double det1 = ((ma2 - _prevJma) * (1 - _alpha) * (1 - _alpha) ) + (_alpha * _alpha * _prevDet1);
double det1 = ((ma2 - _prevJma) * (1 - _alpha) * (1 - _alpha)) + (_alpha * _alpha * _prevDet1);
_prevDet1 = det1;
double jma = _prevJma + det1;
_prevJma = jma;
+62
View File
@@ -0,0 +1,62 @@
using System;
namespace QuanTAlib;
/// <summary>
/// Represents a Relative Strength Index (RSI) calculator following Wilder's algorithm.
/// </summary>
public class Rsi : AbstractBase
{
private readonly Rma _avgGain;
private readonly Rma _avgLoss;
private double _prevValue, _p_prevValue;
public Rsi(int period = 14)
{
if (period < 1)
throw new ArgumentOutOfRangeException(nameof(period));
_avgGain = new(period, useSma: true);
_avgLoss = new(period, useSma: true);
_index = 0;
WarmupPeriod = period + 1;
Name = $"RSI({period})";
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_index++;
_p_prevValue = _prevValue;
}
else
{
_prevValue = _p_prevValue;
}
}
protected override double Calculation()
{
ManageState(Input.IsNew);
if (_index == 1)
{
_prevValue = Input.Value;
}
double change = Input.Value - _prevValue;
double gain = Math.Max(change, 0);
double loss = Math.Max(-change, 0);
_prevValue = Input.Value;
_avgGain.Calc(gain, IsNew: Input.IsNew);
_avgLoss.Calc(loss, IsNew: Input.IsNew);
double rsi = (_avgLoss.Value > 0) ? 100 - (100 / (1 + (_avgGain.Value / _avgLoss.Value))) : 100;
return rsi;
}
}
+64
View File
@@ -0,0 +1,64 @@
using System;
namespace QuanTAlib;
/// <summary>
/// Jurik's superior replacement for RSI
/// </summary>
public class Rsx : AbstractBase
{
private readonly Rma _avgGain;
private readonly Rma _avgLoss;
private readonly Jma _rsx;
private double _prevValue, _p_prevValue;
public Rsx(int period = 14, int phase = 0, double factor = 0.55)
{
if (period < 1)
throw new ArgumentOutOfRangeException(nameof(period));
_avgGain = new(period);
_avgLoss = new(period);
_rsx = new(8, 100, 0.25, 3);
_index = 0;
WarmupPeriod = period + 1;
Name = $"RSX({period})";
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_index++;
_p_prevValue = _prevValue;
}
else
{
_prevValue = _p_prevValue;
}
}
protected override double Calculation()
{
ManageState(Input.IsNew);
if (_index == 1)
{
_prevValue = Input.Value;
}
double change = Input.Value - _prevValue;
double gain = Math.Max(change, 0);
double loss = Math.Max(-change, 0);
_prevValue = Input.Value;
_avgGain.Calc(gain, IsNew: Input.IsNew);
_avgLoss.Calc(loss, IsNew: Input.IsNew);
double rsi = (_avgLoss.Value > 0) ? 100 - (100 / (1 + (_avgGain.Value / _avgLoss.Value))) : 100;
double rsx = _rsx.Calc(rsi, Input.IsNew);
return rsx;
}
}
+2 -2
View File
@@ -62,7 +62,7 @@ public class MacdIndicator : Indicator, IWatchlistIndicator
SignalSeries = new(name: $"SIGNAL", color: Color.Yellow, width: 2, style: LineStyle.Solid);
HistogramSeries = new(name: $"HISTOGRAM", color: Color.White, width: 2, style: LineStyle.Solid);
HistSlopeSeries = new(name: $"SLOPE", color: Color.Transparent, width: 2, style: LineStyle.Solid);
HistSlopeSeries.Visible = false;
AddLineSeries(MainSeries);
AddLineSeries(SignalSeries);
@@ -119,7 +119,7 @@ public class MacdIndicator : Indicator, IWatchlistIndicator
for (int i = rightIndex; i < leftIndex; i++)
{
int barX = (int)converter.GetChartX(this.HistoricalData.Time(i));
int barY = (int)converter.GetChartY(HistogramSeries![i]);
int barY = (int)converter.GetChartY(HistogramSeries![i]*2.0);
int barY0 = (int)converter.GetChartY(0);
int HistBarWidth = this.CurrentChart.BarsWidth - 2;
+67
View File
@@ -0,0 +1,67 @@
using System.Drawing;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class RsiIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)]
public int Periods { get; set; } = 14;
[InputParameter("Data source", sortIndex: 5, variants: [
"Open", SourceType.Open,
"High", SourceType.High,
"Low", SourceType.Low,
"Close", SourceType.Close,
"HL/2 (Median)", SourceType.HL2,
"OC/2 (Midpoint)", SourceType.OC2,
"OHL/3 (Mean)", SourceType.OHL3,
"HLC/3 (Typical)", SourceType.HLC3,
"OHLC/4 (Average)", SourceType.OHLC4,
"HLCC/4 (Weighted)", SourceType.HLCC4
])]
public SourceType Source { get; set; } = SourceType.Close;
[InputParameter("Show cold values", sortIndex: 21)]
public bool ShowColdValues { get; set; } = true;
private Rsi? rsi;
protected string? SourceName;
protected LineSeries? RsiSeries;
public int MinHistoryDepths => Periods + 1;
int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public RsiIndicator()
{
Name = "RSI - Relative Strength Index";
Description = "Measures the speed and magnitude of recent price changes to evaluate overbought or oversold conditions.";
SeparateWindow = true;
SourceName = Source.ToString();
RsiSeries = new($"RSI {Periods}", Color.Blue, 2, LineStyle.Solid);
AddLineSeries(RsiSeries);
}
protected override void OnInit()
{
rsi = new Rsi(Periods);
base.OnInit();
}
protected override void OnUpdate(UpdateArgs args)
{
TValue input = this.GetInputValue(args, Source);
rsi!.Calc(input);
RsiSeries!.SetValue(rsi.Value);
RsiSeries!.SetMarker(0, Color.Transparent);
}
public override string ShortName => $"RSI ({Periods}:{SourceName})";
#pragma warning disable CA1416 // Validate platform compatibility
public override void OnPaintChart(PaintChartEventArgs args)
{
base.OnPaintChart(args);
this.PaintSmoothCurve(args, RsiSeries!, rsi!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2);
}
}
+67
View File
@@ -0,0 +1,67 @@
using System.Drawing;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class RsxIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Rsi Period", sortIndex: 1, 1, 2000, 1, 0)]
public int Period { get; set; } = 14;
[InputParameter("Data source", sortIndex: 5, variants: [
"Open", SourceType.Open,
"High", SourceType.High,
"Low", SourceType.Low,
"Close", SourceType.Close,
"HL/2 (Median)", SourceType.HL2,
"OC/2 (Midpoint)", SourceType.OC2,
"OHL/3 (Mean)", SourceType.OHL3,
"HLC/3 (Typical)", SourceType.HLC3,
"OHLC/4 (Average)", SourceType.OHLC4,
"HLCC/4 (Weighted)", SourceType.HLCC4
])]
public SourceType Source { get; set; } = SourceType.Close;
[InputParameter("Show cold values", sortIndex: 21)]
public bool ShowColdValues { get; set; } = true;
private Rsx? rsx;
protected string? SourceName;
protected LineSeries? RsxSeries;
public int MinHistoryDepths => Period + 1;
int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public RsxIndicator()
{
Name = "RSX - Jurik Trend Strengt Index";
Description = "Measures the speed and magnitude of recent price changes to evaluate overbought or oversold conditions.";
SeparateWindow = true;
SourceName = Source.ToString();
RsxSeries = new($"RSX {Period}", Color.Blue, 2, LineStyle.Solid);
AddLineSeries(RsxSeries);
}
protected override void OnInit()
{
rsx = new(Period);
base.OnInit();
}
protected override void OnUpdate(UpdateArgs args)
{
TValue input = this.GetInputValue(args, Source);
rsx!.Calc(input);
RsxSeries!.SetValue(rsx.Value);
RsxSeries!.SetMarker(0, Color.Transparent);
}
public override string ShortName => $"RSX ({Period}:{SourceName})";
#pragma warning disable CA1416 // Validate platform compatibility
public override void OnPaintChart(PaintChartEventArgs args)
{
base.OnPaintChart(args);
this.PaintSmoothCurve(args, RsxSeries!, rsx!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2);
}
}