mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-19 11:08:05 +00:00
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:
@@ -9,10 +9,6 @@ indicator("Average Daily Range (ADR)", "ADR", overlay=false)
|
||||
//@returns float ADR value
|
||||
//@optimized for performance and dirty data
|
||||
adr(simple int length, simple int method = 1) =>
|
||||
if length <= 0
|
||||
runtime.error("Length must be greater than 0")
|
||||
if method < 1 or method > 3
|
||||
runtime.error("Method must be 1 (SMA), 2 (EMA), or 3 (WMA)")
|
||||
var int p = math.max(1, length)
|
||||
var int head = 0
|
||||
var int count = 0
|
||||
|
||||
@@ -8,8 +8,6 @@ indicator("Average True Range (ATR)", "ATR", overlay=false)
|
||||
//@returns The ATR value.
|
||||
//@optimized Beta precomputation for RMA warmup compensation
|
||||
atr(simple int length) =>
|
||||
if length <= 0
|
||||
runtime.error("Period must be greater than 0")
|
||||
var float prevClose = close
|
||||
float tr1 = high - low
|
||||
float tr2 = math.abs(high - prevClose)
|
||||
|
||||
@@ -8,8 +8,6 @@ indicator("Average True Range Normalized (ATRN)", "ATRN", overlay=false, format=
|
||||
//@returns The ATRN value, normalized relative to its maximum over the longer period.
|
||||
//@optimized Beta precomputation for RMA warmup compensation
|
||||
atrn(simple int length) =>
|
||||
if length <= 0
|
||||
runtime.error("Period must be greater than 0")
|
||||
var float prevClose = close
|
||||
float tr1 = high - low
|
||||
float tr2 = math.abs(high - prevClose)
|
||||
|
||||
@@ -10,8 +10,6 @@ indicator("Bollinger Band Width (BBW)", "BBW", overlay=false)
|
||||
//@returns BBW value representing the width between Bollinger Bands
|
||||
//@optimized for performance and dirty data
|
||||
bbw(series float source, simple int period, simple float multiplier) =>
|
||||
if period <= 0 or multiplier <= 0.0
|
||||
runtime.error("Period and multiplier must be greater than 0")
|
||||
var int p = math.max(1, period), var int head = 0, var int count = 0
|
||||
var array<float> buffer = array.new_float(p, na)
|
||||
var float sum = 0.0, var float sumSq = 0.0
|
||||
@@ -28,7 +26,7 @@ bbw(series float source, simple int period, simple float multiplier) =>
|
||||
head := (head + 1) % p
|
||||
float basis = nz(sum / count, source)
|
||||
float dev = count > 1 ? multiplier * math.sqrt(math.max(0.0, sumSq / count - basis * basis)) : 0.0
|
||||
2 * dev
|
||||
basis != 0.0 ? 2 * dev / basis : 0.0
|
||||
|
||||
// ---------- Main loop ----------
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ indicator("Bollinger Band Width Normalized (BBWN)", "BBWN", overlay=false)
|
||||
//@returns BBWN value representing current BBW normalized to [0,1] range
|
||||
//@optimized for performance and dirty data
|
||||
bbwn(series float source, simple int period, simple float multiplier, simple int lookback) =>
|
||||
if period <= 0 or multiplier <= 0.0 or lookback <= 0
|
||||
runtime.error("Period, multiplier, and lookback must be greater than 0")
|
||||
var int p = math.max(1, period), var int head = 0, var int count = 0
|
||||
var array<float> buffer = array.new_float(p, na)
|
||||
var float sum = 0.0, var float sumSq = 0.0
|
||||
@@ -29,7 +27,7 @@ bbwn(series float source, simple int period, simple float multiplier, simple int
|
||||
head := (head + 1) % p
|
||||
float basis = nz(sum / count, source)
|
||||
float dev = count > 1 ? multiplier * math.sqrt(math.max(0.0, sumSq / count - basis * basis)) : 0.0
|
||||
float bbw = 2 * dev
|
||||
float bbw = basis != 0.0 ? 2 * dev / basis : 0.0
|
||||
var int l = math.max(1, lookback), var int hist_head = 0, var int hist_count = 0
|
||||
var array<float> hist_buffer = array.new_float(l, na)
|
||||
var float min_val = bbw, var float max_val = bbw
|
||||
|
||||
@@ -11,8 +11,6 @@ indicator("Bollinger Band Width Percentile (BBWP)", "BBWP", overlay=false, forma
|
||||
//@returns BBWP value representing current BBW percentile in historical range
|
||||
//@optimized for performance and dirty data
|
||||
bbwp(series float source, simple int period, simple float multiplier, simple int lookback) =>
|
||||
if period <= 0 or multiplier <= 0.0 or lookback <= 0
|
||||
runtime.error("Period, multiplier, and lookback must be greater than 0")
|
||||
var int p = math.max(1, period), var int head = 0, var int count = 0
|
||||
var array<float> buffer = array.new_float(p, na)
|
||||
var float sum = 0.0, var float sumSq = 0.0
|
||||
@@ -29,7 +27,7 @@ bbwp(series float source, simple int period, simple float multiplier, simple int
|
||||
head := (head + 1) % p
|
||||
float basis = nz(sum / count, source)
|
||||
float dev = count > 1 ? multiplier * math.sqrt(math.max(0.0, sumSq / count - basis * basis)) : 0.0
|
||||
float bbw = 2 * dev
|
||||
float bbw = basis != 0.0 ? 2 * dev / basis : 0.0
|
||||
var int l = math.max(1, lookback), var int hist_head = 0, var int hist_count = 0
|
||||
var array<float> hist_buffer = array.new_float(l, na)
|
||||
float hist_oldest = array.get(hist_buffer, hist_head)
|
||||
|
||||
@@ -9,10 +9,6 @@ indicator("Close-to-Close Volatility (CCV)", "CCV", overlay=false)
|
||||
//@returns float Volatility value
|
||||
//@optimized Beta precomputation for RMA warmup compensation
|
||||
ccv(simple int length, simple int method) =>
|
||||
if length <= 0
|
||||
runtime.error("Length must be greater than 0")
|
||||
if method < 1 or method > 3
|
||||
runtime.error("Method must be 1 (SMA), 2 (EMA), or 3 (WMA)")
|
||||
var int p = math.max(1, length)
|
||||
var int head = 0
|
||||
var int count = 0
|
||||
|
||||
@@ -10,14 +10,6 @@ indicator("Conditional Volatility (CV)", "CV", overlay=false)
|
||||
//@returns float Conditional volatility value
|
||||
//@optimized for performance and efficient variance updating
|
||||
cv(simple int length, simple float alpha, simple float beta) =>
|
||||
if length <= 0
|
||||
runtime.error("Length must be greater than 0")
|
||||
if alpha <= 0.0 or alpha >= 1.0
|
||||
runtime.error("Alpha must be between 0 and 1")
|
||||
if beta <= 0.0 or beta >= 1.0
|
||||
runtime.error("Beta must be between 0 and 1")
|
||||
if alpha + beta >= 1.0
|
||||
runtime.error("Alpha + Beta must be less than 1 for stationarity")
|
||||
var float omega = 0.0
|
||||
var float longRunVar = 0.0
|
||||
var float prevVariance = 0.0
|
||||
|
||||
@@ -9,8 +9,6 @@ indicator("Chaikin's Volatility (CVI)", "CVI", overlay=false)
|
||||
//@returns float Volatility value measuring change in trading ranges
|
||||
//@optimized for performance using efficient range ROC calculation
|
||||
cvi(simple int roc_length, simple int smooth_length) =>
|
||||
if roc_length <= 0 or smooth_length <= 0
|
||||
runtime.error("Lengths must be greater than 0")
|
||||
var float prevEma = 0.0
|
||||
hlRange = high - low
|
||||
alpha = 2.0 / (smooth_length + 1)
|
||||
|
||||
@@ -8,9 +8,6 @@ indicator("Elder's Thermometer", "ETHERM", overlay=false)
|
||||
//@returns [thermometer, signal] The raw thermometer value and EMA signal line
|
||||
//@optimized Beta precomputation for EMA warmup compensation
|
||||
etherm(simple int period) =>
|
||||
if period <= 0
|
||||
runtime.error("Period must be greater than 0")
|
||||
|
||||
// Step 1: Calculate raw thermometer value
|
||||
// Temperature = max of upward high protrusion and downward low protrusion
|
||||
// Only outward extensions count; contractions clamp to zero
|
||||
|
||||
@@ -11,10 +11,6 @@ indicator("Exponential Weighted MA Volatility", "EWMA Volty", overlay=false)
|
||||
//@returns float The EWMA Volatility value.
|
||||
//@optimized for performance and dirty data
|
||||
ewmaVolty(series float src, simple int length, simple bool annualize = true, simple int annualPeriods = 252) =>
|
||||
if length <= 0
|
||||
runtime.error("Length must be greater than 0")
|
||||
if annualize and annualPeriods <= 0
|
||||
runtime.error("Annual periods must be greater than 0 if annualizing")
|
||||
float logReturn = nz(math.log(src / src[1]),0.0)
|
||||
float squaredReturn = logReturn * logReturn
|
||||
var float raw_rma_sq_ret = 0.0, var float e_rma = 1.0
|
||||
|
||||
@@ -10,10 +10,6 @@ indicator("Garman-Klass Volatility (GKV)", "GKV", overlay=false)
|
||||
//@returns float The Garman-Klass Volatility value.
|
||||
//@optimized for performance and dirty data
|
||||
gkv(simple int length, simple bool annualize = true, simple int annualPeriods = 252) =>
|
||||
if length <= 0
|
||||
runtime.error("Length must be greater than 0")
|
||||
if annualize and annualPeriods <= 0
|
||||
runtime.error("Annual periods must be greater than 0 if annualizing")
|
||||
float lnH = math.log(high), float lnL = math.log(low), float lnO = math.log(open), float lnC = math.log(close)
|
||||
float C_2LN2_1 = 0.3862941611 // 2 * math.log(2) - 1
|
||||
float term1 = 0.5 * math.pow(lnH - lnL, 2)
|
||||
|
||||
@@ -10,10 +10,6 @@ indicator("High-Low Volatility (HLV)", "HLV", overlay=false)
|
||||
//@returns float The High-Low Volatility value.
|
||||
//@optimized for performance and dirty data
|
||||
hlv(simple int length, simple bool annualize = true, simple int annualPeriods = 252) =>
|
||||
if length <= 0
|
||||
runtime.error("Length must be greater than 0")
|
||||
if annualize and annualPeriods <= 0
|
||||
runtime.error("Annual periods must be greater than 0 if annualizing")
|
||||
float lnH = math.log(high), float lnL = math.log(low)
|
||||
float C_4LN2_INV = 0.3606737602 // 1.0 / (4.0 * math.log(2.0))
|
||||
float parkinsonEstimator = C_4LN2_INV * math.pow(lnH - lnL, 2)
|
||||
|
||||
@@ -11,10 +11,6 @@ indicator("Historical Volatility (HV)", "HV", overlay=false)
|
||||
//@returns float The Historical Volatility value.
|
||||
//@optimized for performance and dirty data
|
||||
hv(series float src_price, simple int length_hv, simple bool annualize = true, simple int annualPeriods = 252) =>
|
||||
if length_hv <= 1
|
||||
runtime.error("Length for HV must be greater than 1")
|
||||
if annualize and annualPeriods <= 0
|
||||
runtime.error("Annual periods must be greater than 0 if annualizing")
|
||||
var array<float> _buffer_hv = array.new_float(length_hv, na)
|
||||
var int _head_idx_hv = 0
|
||||
var int _current_fill_count_hv = 0
|
||||
|
||||
@@ -9,8 +9,6 @@ indicator("Mass Index (MASSI)", "MASSI", overlay=false)
|
||||
//@returns float Mass Index value
|
||||
//@optimized for performance and dirty data
|
||||
massi(simple int ema_length, simple int sum_length) =>
|
||||
if ema_length <= 0 or sum_length <= 0
|
||||
runtime.error("Periods must be greater than 0")
|
||||
float a = 2.0 / (ema_length + 1)
|
||||
float beta = 1.0 - a
|
||||
var bool warmup = true, var float e = 1.0
|
||||
|
||||
@@ -8,8 +8,6 @@ indicator("Normalized Average True Range", "NATR", overlay=false, format=format.
|
||||
//@returns The NATR value as a percentage of close price.
|
||||
//@optimized Beta precomputation for RMA warmup compensation
|
||||
natr(simple int length) =>
|
||||
if length <= 0
|
||||
runtime.error("Period must be greater than 0")
|
||||
float prevClose = nz(close[1], close)
|
||||
float tr1 = high - low
|
||||
float tr2 = math.abs(high - prevClose)
|
||||
|
||||
@@ -9,10 +9,6 @@ indicator("Rogers-Satchell Volatility (RSV)", "RSV", overlay=false)
|
||||
//@param annualPeriods Number of periods in a year for annualization. Default is 252 for daily data.
|
||||
//@returns float The Rogers-Satchell Volatility value.
|
||||
rsv(simple int length, simple bool annualize = true, simple int annualPeriods = 252) =>
|
||||
if length <= 0
|
||||
runtime.error("Length must be greater than 0")
|
||||
if annualize and annualPeriods <= 0
|
||||
runtime.error("Annual periods must be greater than 0 if annualizing")
|
||||
float h = math.max(high, 0.0000001)
|
||||
float l = math.max(low, 0.0000001)
|
||||
float o = math.max(open, 0.0000001)
|
||||
|
||||
@@ -10,10 +10,6 @@ indicator("Realized Volatility (RV)", "RV", overlay=false)
|
||||
//@param annualPeriods Number of periods (of the main chart's timeframe) in a year for annualization. Default is 252 (assuming daily chart).
|
||||
//@returns float The Realized Volatility value.
|
||||
rv(simple int length = 20, simple string intradayTimeframe = "5", simple bool annualize = true, simple int annualPeriods = 252) =>
|
||||
if length <= 0
|
||||
runtime.error("Length must be greater than 0")
|
||||
if annualize and annualPeriods <= 0
|
||||
runtime.error("Annual periods must be greater than 0 if annualizing")
|
||||
intraday_closes_arr = request.security_lower_tf(syminfo.tickerid, intradayTimeframe, close)
|
||||
float sum_sq_log_returns = 0.0
|
||||
if array.size(intraday_closes_arr) > 1
|
||||
|
||||
@@ -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 ===
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,8 +8,6 @@ indicator("Ulcer Index (UI)", shorttitle="UI", format=format.price, precision=2,
|
||||
//@param period The lookback period. Default is 14.
|
||||
//@returns float The Ulcer Index value.
|
||||
ui(series float src, int period) =>
|
||||
if period <= 0
|
||||
runtime.error("Period must be greater than 0")
|
||||
var deque = array.new_int(0)
|
||||
var src_buffer = array.new_float(period, na)
|
||||
var int current_index = 0
|
||||
|
||||
@@ -9,8 +9,6 @@ indicator("Volatility of Volatility (VOV)", shorttitle="VOV", format=format.pric
|
||||
//@param vovPeriod The lookback period for calculating the standard deviation of the volatility series. Default is 10.
|
||||
//@returns float The VOV value.
|
||||
vov(series float src, int volatilityPeriod, int vovPeriod) =>
|
||||
if volatilityPeriod <= 0 or vovPeriod <= 0
|
||||
runtime.error("Periods must be greater than 0")
|
||||
var int p1 = 0
|
||||
var array<float> buffer1 = array.new_float(0)
|
||||
var int head1 = 0, var int count1 = 0
|
||||
|
||||
@@ -9,8 +9,6 @@ indicator("Volatility Ratio (VR)", shorttitle="VR", format=format.price, precisi
|
||||
//@param atrPeriod The lookback period for ATR. Must be > 0.
|
||||
//@returns float The Volatility Ratio value for the current bar.
|
||||
vr(int atrPeriod) =>
|
||||
if atrPeriod <= 0
|
||||
runtime.error("ATR Period must be greater than 0")
|
||||
var float EPSILON_ATR = 1e-10
|
||||
var float raw_atr = 0.0
|
||||
var float e_compensator = 1.0
|
||||
|
||||
@@ -8,9 +8,6 @@ indicator("Yang-Zhang Volatility (YZV)", shorttitle="YZV", overlay=false)
|
||||
//@returns Yang-Zhang Volatility value for the current bar
|
||||
//@optimized Uses bias-corrected RMA with OHLC prices for O(1) complexity per bar
|
||||
yzv(int length) =>
|
||||
if length <= 0
|
||||
runtime.error("Length must be greater than 0 for YZV calculation.")
|
||||
float(na)
|
||||
o=open,h=high,l=low,c=close,pc=na(close[1])?open:close[1]
|
||||
ro=math.log(o/pc),rc=math.log(c/o),rh=math.log(h/o),rl=math.log(l/o)
|
||||
s_o_sq=ro*ro,s_c_sq=rc*rc
|
||||
|
||||
Reference in New Issue
Block a user