mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-24 21:48:03 +00:00
Refactor error handling and calculations in TheilU, Wmape, and TukeyBiweight classes; update buffer handling for consistency
- Updated buffer handling in TheilU and Wmape classes to ensure consistency after adding new values. - Changed the resync interval constant in TukeyBiweight for better clarity. - Refactored state structures to record structs in Gauss, Hann, Hp, Hpf, Kalman, Loess, Notch, and other filter classes for improved performance and readability. - Enhanced numerical stability in Mama class calculations using Fused Multiply-Add (FMA) for precision. - Added comprehensive tests for Atan2 validation to compare .NET's Math.Atan2 with PineScript's implementation, ensuring accuracy across various edge cases. - Updated NDepend badges to reflect changes in classes, methods, and lines of code.
This commit is contained in:
@@ -52,8 +52,7 @@ public class VwapsdIndicator : Indicator, IWatchlistIndicator
|
||||
|
||||
protected override void OnUpdate(UpdateArgs args)
|
||||
{
|
||||
var item = HistoricalData[Count - 1, SeekOriginHistory.Begin];
|
||||
var time = HistoricalData.Time();
|
||||
var item = HistoricalData[0, SeekOriginHistory.End];
|
||||
|
||||
// VWAP requires OHLCV data - using HLC3 for price
|
||||
double high = item[PriceType.High];
|
||||
@@ -61,7 +60,7 @@ public class VwapsdIndicator : Indicator, IWatchlistIndicator
|
||||
double close = item[PriceType.Close];
|
||||
double volume = item[PriceType.Volume];
|
||||
|
||||
TBar bar = new(time, item[PriceType.Open], high, low, close, volume);
|
||||
TBar bar = new(item.TimeLeft, item[PriceType.Open], high, low, close, volume);
|
||||
TValue result = vwapsd!.Update(bar, args.IsNewBar());
|
||||
|
||||
VwapSeries!.SetValue(result.Value, vwapsd.IsHot, ShowColdValues);
|
||||
|
||||
@@ -325,6 +325,37 @@ public class VwapsdTests
|
||||
Assert.NotEqual(vwapBeforeReset, vwapsd.Vwap.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Vwapsd_SessionReset_ResetsIsHotGating()
|
||||
{
|
||||
var vwapsd = new Vwapsd(1.0);
|
||||
var gbm = new GBM(startPrice: 100.0, mu: 0.02, sigma: 0.1, seed: 42);
|
||||
var bars = gbm.Fetch(20, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
|
||||
// Process bars until IsHot is true (WarmupPeriod = 2)
|
||||
vwapsd.Update(bars[0]);
|
||||
Assert.False(vwapsd.IsHot);
|
||||
vwapsd.Update(bars[1]);
|
||||
Assert.True(vwapsd.IsHot);
|
||||
|
||||
// Process more bars to ensure we're well past warmup
|
||||
for (int i = 2; i < 10; i++)
|
||||
{
|
||||
vwapsd.Update(bars[i]);
|
||||
}
|
||||
Assert.True(vwapsd.IsHot);
|
||||
|
||||
// Reset session - IsHot should become false
|
||||
var resetBar1 = new TBar(DateTime.UtcNow, 200, 210, 190, 200, 1000);
|
||||
vwapsd.Update(resetBar1, isNew: true, reset: true);
|
||||
Assert.False(vwapsd.IsHot, "IsHot should be false after reset (1 bar accumulated)");
|
||||
|
||||
// Process second bar after reset - IsHot should become true
|
||||
var resetBar2 = new TBar(DateTime.UtcNow.AddMinutes(1), 205, 215, 195, 205, 1100);
|
||||
vwapsd.Update(resetBar2, isNew: true);
|
||||
Assert.True(vwapsd.IsHot, "IsHot should be true after 2 bars accumulated post-reset");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Vwapsd_VwapFormula_MatchesExpected()
|
||||
{
|
||||
|
||||
@@ -106,12 +106,12 @@ public sealed class VwapsdValidationTests : IDisposable
|
||||
streamingLower.Add(streamingVwapsd.Lower.Value);
|
||||
}
|
||||
|
||||
// Span mode - using HLC3 for price
|
||||
// Span mode - using bar.HLC3 for price to match streaming mode
|
||||
double[] price = new double[bars.Count];
|
||||
double[] volume = new double[bars.Count];
|
||||
for (int i = 0; i < bars.Count; i++)
|
||||
{
|
||||
price[i] = (bars[i].High + bars[i].Low + bars[i].Close) / 3.0;
|
||||
price[i] = bars[i].HLC3;
|
||||
volume[i] = bars[i].Volume;
|
||||
}
|
||||
|
||||
|
||||
@@ -132,8 +132,7 @@ public sealed class Vwapsd : AbstractBase
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public TValue Update(TBar bar, bool isNew = true, bool reset = false)
|
||||
{
|
||||
double hlc3 = (bar.High + bar.Low + bar.Close) / 3.0;
|
||||
return Update(new TValue(bar.Time, hlc3), bar.Volume, isNew, reset);
|
||||
return Update(new TValue(bar.Time, bar.HLC3), bar.Volume, isNew, reset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -168,6 +167,9 @@ public sealed class Vwapsd : AbstractBase
|
||||
// Handle reset
|
||||
if (reset || !_state.IsInitialized)
|
||||
{
|
||||
// Reset warmup tracking for proper IsHot gating after session reset
|
||||
_index = 1;
|
||||
|
||||
if (vol > 0)
|
||||
{
|
||||
_state = _state with
|
||||
|
||||
Reference in New Issue
Block a user