fix(docs): correct .md documentation across errors, dynamics, filters, forecasts, momentum, numerics, oscillators, reversals, statistics, trends, volatility, volume

Deep review of all indicator categories verified .md headers against .cs WarmupPeriod, parameters, inputs, and outputs. Fixes include warmup corrections, parameter documentation, output type accuracy, and Pine Script alignment.
This commit is contained in:
Miha Kralj
2026-03-10 18:38:23 -07:00
parent 8906c62dcf
commit 35a6702b06
178 changed files with 2579 additions and 998 deletions
+11 -5
View File
@@ -258,28 +258,34 @@ public class RviValidationTests
}
/// <summary>
/// Validates TBar update uses only Close price.
/// Validates TBar update uses High and Low channels (revised 1995 algorithm),
/// producing a different result than single-price Close-only input.
/// </summary>
[Fact]
public void Rvi_TBar_UsesOnlyClose()
public void Rvi_TBar_UsesDualChannel_HighLow()
{
var bars = GenerateTestData(50);
// Using TBar
// Using TBar (revised: high + low dual-channel)
var rviBar = new Rvi(10, 14);
for (int i = 0; i < bars.Count; i++)
{
rviBar.Update(bars[i]);
}
// Using just Close prices
// Using just Close prices (single-channel)
var rviClose = new Rvi(10, 14);
for (int i = 0; i < bars.Count; i++)
{
rviClose.Update(new TValue(bars[i].Time, bars[i].Close));
}
Assert.Equal(rviClose.Last.Value, rviBar.Last.Value, 10);
// TBar uses High/Low channels → different from Close-only
Assert.NotEqual(rviClose.Last.Value, rviBar.Last.Value);
// Both should still be in valid range
Assert.True(rviBar.Last.Value >= 0 && rviBar.Last.Value <= 100);
Assert.True(rviClose.Last.Value >= 0 && rviClose.Last.Value <= 100);
}
// === Parameter Sensitivity ===
+57 -1
View File
@@ -55,9 +55,13 @@ public sealed class Rvi : AbstractBase
public Rvi(int stdevLength = 10, int rmaLength = 14)
{
if (stdevLength < 2)
{
throw new ArgumentException("Standard deviation length must be at least 2", nameof(stdevLength));
}
if (rmaLength < 1)
{
throw new ArgumentException("RMA length must be at least 1", nameof(rmaLength));
}
_stdevLength = stdevLength;
_rmaLength = rmaLength;
@@ -101,7 +105,9 @@ public sealed class Rvi : AbstractBase
public TSeries Update(TBarSeries source)
{
if (source.Count == 0)
{
return [];
}
int len = source.Count;
var t = new List<long>(len);
@@ -126,7 +132,9 @@ public sealed class Rvi : AbstractBase
// Sync internal state
for (int i = 0; i < len; i++)
{
Update(source[i], isNew: true);
}
return new TSeries(t, v);
}
@@ -134,7 +142,9 @@ public sealed class Rvi : AbstractBase
public override TSeries Update(TSeries source)
{
if (source.Count == 0)
{
return [];
}
int len = source.Count;
var t = new List<long>(len);
@@ -150,7 +160,9 @@ public sealed class Rvi : AbstractBase
source.Times.CopyTo(tSpan);
for (int i = 0; i < len; i++)
{
Update(new TValue(source.Times[i], source.Values[i]), isNew: true);
}
return new TSeries(t, v);
}
@@ -188,9 +200,13 @@ public sealed class Rvi : AbstractBase
double rviValue = (rviHi + rviLo) * 0.5;
if (!double.IsFinite(rviValue))
{
rviValue = _lastValue;
}
else
{
_lastValue = rviValue;
}
Last = new TValue(timeTicks, rviValue);
PubEvent(Last, isNew);
@@ -244,9 +260,13 @@ public sealed class Rvi : AbstractBase
double upStdVal = 0.0;
double downStdVal = 0.0;
if (priceChange > 0)
{
upStdVal = currentStdDev;
}
else if (priceChange < 0)
{
downStdVal = currentStdDev;
}
double rawRmaUp = Math.FusedMultiplyAdd(s.RawRmaUp, _rmaLength - 1, upStdVal) / _rmaLength;
double eUp = (1 - _alpha) * s.EUp;
@@ -266,7 +286,9 @@ public sealed class Rvi : AbstractBase
public override void Prime(ReadOnlySpan<double> source, TimeSpan? step = null)
{
for (int i = 0; i < source.Length; i++)
{
Update(new TValue(DateTime.UtcNow, source[i]), isNew: true);
}
}
public override void Reset()
@@ -288,9 +310,13 @@ public sealed class Rvi : AbstractBase
public static TSeries Batch(TSeries source, int stdevLength = 10, int rmaLength = 14)
{
if (stdevLength < 2)
{
throw new ArgumentException("Standard deviation length must be at least 2", nameof(stdevLength));
}
if (rmaLength < 1)
{
throw new ArgumentException("RMA length must be at least 1", nameof(rmaLength));
}
int len = source.Count;
var t = new List<long>(len);
@@ -323,11 +349,17 @@ public sealed class Rvi : AbstractBase
int rmaLength = 14)
{
if (stdevLength < 2)
{
throw new ArgumentException("Standard deviation length must be at least 2", nameof(stdevLength));
}
if (rmaLength < 1)
{
throw new ArgumentException("RMA length must be at least 1", nameof(rmaLength));
}
if (output.Length < prices.Length)
{
throw new ArgumentException("Output span must be at least as long as prices span", nameof(output));
}
// Single-price: feed same data to both channels, average = original
BatchDual(prices, prices, output, stdevLength, rmaLength);
@@ -344,15 +376,23 @@ public sealed class Rvi : AbstractBase
int rmaLength = 14)
{
if (stdevLength < 2)
{
throw new ArgumentException("Standard deviation length must be at least 2", nameof(stdevLength));
}
if (rmaLength < 1)
{
throw new ArgumentException("RMA length must be at least 1", nameof(rmaLength));
}
int len = highs.Length;
if (len == 0)
{
return;
}
if (output.Length < len)
{
throw new ArgumentException("Output span must be at least as long as input span", nameof(output));
}
// Allocate temp buffers for each channel's RVI output
Span<double> rviHi = len <= 256 ? stackalloc double[len] : new double[len];
@@ -363,7 +403,9 @@ public sealed class Rvi : AbstractBase
// Average
for (int i = 0; i < len; i++)
{
output[i] = (rviHi[i] + rviLo[i]) * 0.5;
}
}
/// <summary>
@@ -377,7 +419,9 @@ public sealed class Rvi : AbstractBase
{
int len = prices.Length;
if (len == 0)
{
return;
}
double alpha = 1.0 / rmaLength;
@@ -407,7 +451,9 @@ public sealed class Rvi : AbstractBase
}
if (count < stdevLength)
{
count++;
}
else
{
double oldest = priceBuffer[head];
@@ -434,7 +480,9 @@ public sealed class Rvi : AbstractBase
prevPrice = price;
if (count < stdevLength)
{
count++;
}
else
{
double oldest = priceBuffer[head];
@@ -458,9 +506,13 @@ public sealed class Rvi : AbstractBase
double upStdVal = 0.0;
double downStdVal = 0.0;
if (priceChange > 0)
{
upStdVal = currentStdDev;
}
else if (priceChange < 0)
{
downStdVal = currentStdDev;
}
rawRmaUp = Math.FusedMultiplyAdd(rawRmaUp, rmaLength - 1, upStdVal) / rmaLength;
eUp = (1 - alpha) * eUp;
@@ -474,9 +526,13 @@ public sealed class Rvi : AbstractBase
double rviValue = sumAvgStd > Epsilon ? (100.0 * avgUpStd / sumAvgStd) : 50.0;
if (!double.IsFinite(rviValue))
{
rviValue = lastValue;
}
else
{
lastValue = rviValue;
}
output[i] = rviValue;
}
@@ -488,4 +544,4 @@ public sealed class Rvi : AbstractBase
TSeries results = indicator.Update(source);
return (results, indicator);
}
}
}
-4
View File
@@ -9,10 +9,6 @@ indicator("Relative Volatility Index (RVI)", shorttitle="RVI", overlay=false)
//@param rmaLength The lookback period for Wilder's smoothing (RMA) of the upward and downward standard deviations. Default is 14.
//@returns float The Relative Volatility Index value.
rvi(series float src = close, simple int stdevLength = 10, simple int rmaLength = 14) =>
if stdevLength <= 1
runtime.error("Standard Deviation Length must be greater than 1")
if rmaLength <= 0
runtime.error("RMA Length must be greater than 0")
float currentStdDev = 0.0
var array<float> buffer_stddev = array.new_float(stdevLength, na) // p_stddev simplified
var int head_stddev = 0, var int count_stddev = 0