This commit is contained in:
Miha Kralj
2026-03-17 09:26:27 -07:00
7 changed files with 31 additions and 31 deletions
+6 -6
View File
@@ -111,7 +111,7 @@ public sealed class Hwc : AbstractBase
_decayGamma = 1.0 - gamma; _decayGamma = 1.0 - gamma;
_multiplier = multiplier; _multiplier = multiplier;
int effectivePeriod = Math.Max((int)(2.0 / alpha - 1.0), 1); int effectivePeriod = Math.Max((int)((2.0 / alpha) - 1.0), 1);
WarmupPeriod = effectivePeriod; WarmupPeriod = effectivePeriod;
Name = $"Hwc({alpha:F3},{beta:F3},{gamma:F3},{multiplier:F1})"; Name = $"Hwc({alpha:F3},{beta:F3},{gamma:F3},{multiplier:F1})";
_state = new State(double.NaN, 0, 0, 0, double.NaN, false); _state = new State(double.NaN, 0, 0, 0, double.NaN, false);
@@ -179,7 +179,7 @@ public sealed class Hwc : AbstractBase
double prevA = _state.A; double prevA = _state.A;
// HWMA: F = α×src + (1−α)×(prevF + prevV + 0.5×prevA) // HWMA: F = α×src + (1−α)×(prevF + prevV + 0.5×prevA)
double forecast = prevF + prevV + 0.5 * prevA; double forecast = prevF + prevV + (0.5 * prevA);
double newF = Math.FusedMultiplyAdd(forecast, _decayAlpha, _alpha * val); double newF = Math.FusedMultiplyAdd(forecast, _decayAlpha, _alpha * val);
// V = β×(F prevF) + (1−β)×(prevV + prevA) // V = β×(F prevF) + (1−β)×(prevV + prevA)
@@ -188,7 +188,7 @@ public sealed class Hwc : AbstractBase
// A = γ×(V prevV) + (1−γ)×prevA // A = γ×(V prevV) + (1−γ)×prevA
double newA = Math.FusedMultiplyAdd(prevA, _decayGamma, _gamma * (newV - prevV)); double newA = Math.FusedMultiplyAdd(prevA, _decayGamma, _gamma * (newV - prevV));
result = newF + newV + 0.5 * newA; result = newF + newV + (0.5 * newA);
// Adaptive volatility filter: filt = α×(src forecast)² + (1−α)×prevFilt // Adaptive volatility filter: filt = α×(src forecast)² + (1−α)×prevFilt
double err = val - forecast; double err = val - forecast;
@@ -240,7 +240,7 @@ public sealed class Hwc : AbstractBase
for (int i = 0; i < source.Length; i++) for (int i = 0; i < source.Length; i++)
{ {
Update(new TValue(startTime + i * step.Value, source[i]), isNew: true); Update(new TValue(startTime + (i * step.Value), source[i]), isNew: true);
} }
} }
@@ -299,11 +299,11 @@ public sealed class Hwc : AbstractBase
} }
else else
{ {
double forecast = f + v + 0.5 * a; double forecast = f + v + (0.5 * a);
double newF = Math.FusedMultiplyAdd(forecast, dA, alpha * val); double newF = Math.FusedMultiplyAdd(forecast, dA, alpha * val);
double newV = Math.FusedMultiplyAdd(v + a, dB, beta * (newF - f)); double newV = Math.FusedMultiplyAdd(v + a, dB, beta * (newF - f));
double newA = Math.FusedMultiplyAdd(a, dG, gamma * (newV - v)); double newA = Math.FusedMultiplyAdd(a, dG, gamma * (newV - v));
result = newF + newV + 0.5 * newA; result = newF + newV + (0.5 * newA);
double err = val - forecast; double err = val - forecast;
filt = Math.FusedMultiplyAdd(err * err, alpha, filt * dA); filt = Math.FusedMultiplyAdd(err * err, alpha, filt * dA);
+1 -1
View File
@@ -174,7 +174,7 @@ public sealed class HwcTests
// Low volatility: small oscillation // Low volatility: small oscillation
indCalm.Update(new TValue(DateTime.UtcNow.AddMinutes(i), 100.0 + Math.Sin(i * 0.1))); indCalm.Update(new TValue(DateTime.UtcNow.AddMinutes(i), 100.0 + Math.Sin(i * 0.1)));
// High volatility: large oscillation // High volatility: large oscillation
indVolatile.Update(new TValue(DateTime.UtcNow.AddMinutes(i), 100.0 + Math.Sin(i * 0.1) * 20)); indVolatile.Update(new TValue(DateTime.UtcNow.AddMinutes(i), 100.0 + (Math.Sin(i * 0.1) * 20)));
} }
double widthCalm = indCalm.Upper.Value - indCalm.Lower.Value; double widthCalm = indCalm.Upper.Value - indCalm.Lower.Value;
+4 -4
View File
@@ -74,7 +74,7 @@ public sealed class VwmacdTests
var ind = new Vwmacd(fastPeriod: 3, slowPeriod: 5, signalPeriod: 3); var ind = new Vwmacd(fastPeriod: 3, slowPeriod: 5, signalPeriod: 3);
for (int i = 0; i < 20; i++) for (int i = 0; i < 20; i++)
{ {
var bar = new TBar(DateTime.UtcNow.AddMinutes(i), 100 + i, 105 + i, 95 + i, 101 + i, 1000 + i * 10); var bar = new TBar(DateTime.UtcNow.AddMinutes(i), 100 + i, 105 + i, 95 + i, 101 + i, 1000 + (i * 10));
ind.Update(bar); ind.Update(bar);
} }
Assert.True(double.IsFinite(ind.Last.Value)); Assert.True(double.IsFinite(ind.Last.Value));
@@ -116,7 +116,7 @@ public sealed class VwmacdTests
var ind = new Vwmacd(fastPeriod: 5, slowPeriod: 10, signalPeriod: 3); var ind = new Vwmacd(fastPeriod: 5, slowPeriod: 10, signalPeriod: 3);
for (int i = 0; i < 30; i++) for (int i = 0; i < 30; i++)
{ {
double price = 100.0 + i * 2; double price = 100.0 + (i * 2);
var bar = new TBar(DateTime.UtcNow.AddMinutes(i), price, price + 1, price - 1, price, 10000); var bar = new TBar(DateTime.UtcNow.AddMinutes(i), price, price + 1, price - 1, price, 10000);
ind.Update(bar); ind.Update(bar);
} }
@@ -130,7 +130,7 @@ public sealed class VwmacdTests
var ind = new Vwmacd(fastPeriod: 5, slowPeriod: 10, signalPeriod: 3); var ind = new Vwmacd(fastPeriod: 5, slowPeriod: 10, signalPeriod: 3);
for (int i = 0; i < 30; i++) for (int i = 0; i < 30; i++)
{ {
double price = 200.0 - i * 2; double price = 200.0 - (i * 2);
var bar = new TBar(DateTime.UtcNow.AddMinutes(i), price, price + 1, price - 1, price, 10000); var bar = new TBar(DateTime.UtcNow.AddMinutes(i), price, price + 1, price - 1, price, 10000);
ind.Update(bar); ind.Update(bar);
} }
@@ -326,7 +326,7 @@ public sealed class VwmacdTests
// ind1: uniform volume // ind1: uniform volume
ind1.Update(new TBar(DateTime.UtcNow.AddMinutes(i), price, price + 1, price - 1, price, 1000)); ind1.Update(new TBar(DateTime.UtcNow.AddMinutes(i), price, price + 1, price - 1, price, 1000));
// ind2: high volume on latter bars (accelerating weight) // ind2: high volume on latter bars (accelerating weight)
ind2.Update(new TBar(DateTime.UtcNow.AddMinutes(i), price, price + 1, price - 1, price, 1000 + i * 500)); ind2.Update(new TBar(DateTime.UtcNow.AddMinutes(i), price, price + 1, price - 1, price, 1000 + (i * 500)));
} }
// Both should be finite; values may differ due to volume weighting // Both should be finite; values may differ due to volume weighting
@@ -46,8 +46,8 @@ public sealed class BwMfiValidationTests
double range1 = mfi1 * vol1; double range1 = mfi1 * vol1;
double range2 = mfi2 * vol2; double range2 = mfi2 * vol2;
m.Update(new TBar(t, 100, 100 + range1 / 2, 100 - range1 / 2, 100, vol1)); m.Update(new TBar(t, 100, 100 + (range1 / 2), 100 - (range1 / 2), 100, vol1));
m.Update(new TBar(t.AddMinutes(1), 100, 100 + range2 / 2, 100 - range2 / 2, 100, vol2)); m.Update(new TBar(t.AddMinutes(1), 100, 100 + (range2 / 2), 100 - (range2 / 2), 100, vol2));
Assert.Equal(expectedZone, m.Zone); Assert.Equal(expectedZone, m.Zone);
} }
+4 -4
View File
@@ -173,13 +173,13 @@ public sealed class Atrstop : ITValuePublisher
double upperEval, lowerEval; double upperEval, lowerEval;
if (_useHighLow) if (_useHighLow)
{ {
upperEval = high + _multiplier * atrValue; upperEval = high + (_multiplier * atrValue);
lowerEval = low - _multiplier * atrValue; lowerEval = low - (_multiplier * atrValue);
} }
else else
{ {
upperEval = close + _multiplier * atrValue; upperEval = close + (_multiplier * atrValue);
lowerEval = close - _multiplier * atrValue; lowerEval = close - (_multiplier * atrValue);
} }
// Initialize bands on first hot bar // Initialize bands on first hot bar
@@ -57,7 +57,7 @@ public sealed class ConvexityIndicatorTests
{ {
ind.HistoricalData.AddBar( ind.HistoricalData.AddBar(
DateTime.UtcNow.AddMinutes(i), DateTime.UtcNow.AddMinutes(i),
100 + i * 0.5, 101 + i * 0.5, 99 + i * 0.5, 100.5 + i * 0.5, 1000); 100 + (i * 0.5), 101 + (i * 0.5), 99 + (i * 0.5), 100.5 + (i * 0.5), 1000);
} }
ind.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); ind.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar));
@@ -93,10 +93,10 @@ public sealed class ConvexityTests
for (int i = 1; i <= period; i++) for (int i = 1; i <= period; i++)
{ {
double sign = (i % 2 == 0) ? 1 : -1; double sign = (i % 2 == 0) ? 1 : -1;
double magnitude = 0.01 + rng.NextDouble() * 0.03; double magnitude = 0.01 + (rng.NextDouble() * 0.03);
double mktReturn = sign * magnitude; double mktReturn = sign * magnitude;
mkt *= (1 + mktReturn); mkt *= (1 + mktReturn);
ast *= (1 + 2 * mktReturn); // exactly 2x market return ast *= (1 + (2 * mktReturn)); // exactly 2x market return
c.Update(ast, mkt); c.Update(ast, mkt);
} }
@@ -123,7 +123,7 @@ public sealed class ConvexityTests
for (int i = 1; i <= period; i++) for (int i = 1; i <= period; i++)
{ {
double sign = (i % 2 == 0) ? 1 : -1; double sign = (i % 2 == 0) ? 1 : -1;
double magnitude = 0.01 + rng.NextDouble() * 0.03; // 1%-4% varying double magnitude = 0.01 + (rng.NextDouble() * 0.03); // 1%-4% varying
double mktReturn = sign * magnitude; double mktReturn = sign * magnitude;
double astReturn; double astReturn;
if (mktReturn > 0) if (mktReturn > 0)
@@ -157,8 +157,8 @@ public sealed class ConvexityTests
c.Update(100.0, 100.0); c.Update(100.0, 100.0);
for (int i = 0; i < 50; i++) for (int i = 0; i < 50; i++)
{ {
double ast = 100.0 + rng.NextDouble() * 20 - 10; double ast = 100.0 + (rng.NextDouble() * 20) - 10;
double mkt = 100.0 + rng.NextDouble() * 20 - 10; double mkt = 100.0 + (rng.NextDouble() * 20) - 10;
c.Update(ast, mkt); c.Update(ast, mkt);
Assert.True(c.ConvexityValue >= 0, $"Convexity must be ≥ 0, got {c.ConvexityValue} at i={i}"); Assert.True(c.ConvexityValue >= 0, $"Convexity must be ≥ 0, got {c.ConvexityValue} at i={i}");
} }
@@ -179,8 +179,8 @@ public sealed class ConvexityTests
for (int i = 1; i <= period + 5; i++) for (int i = 1; i <= period + 5; i++)
{ {
double sign = (i % 2 == 0) ? 1 : -1; double sign = (i % 2 == 0) ? 1 : -1;
double magnitude = 0.005 + rng.NextDouble() * 0.02; double magnitude = 0.005 + (rng.NextDouble() * 0.02);
price *= (1 + sign * magnitude); price *= (1 + (sign * magnitude));
c.Update(price, price); c.Update(price, price);
} }
@@ -296,9 +296,9 @@ public sealed class ConvexityTests
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
double sign = (i % 2 == 0) ? 1 : -1; double sign = (i % 2 == 0) ? 1 : -1;
double magnitude = 0.005 + rng.NextDouble() * 0.02; double magnitude = 0.005 + (rng.NextDouble() * 0.02);
ast *= (1 + sign * magnitude * 1.5); ast *= (1 + (sign * magnitude * 1.5));
mkt *= (1 + sign * magnitude); mkt *= (1 + (sign * magnitude));
assetSeries.Add(new TValue(i, ast)); assetSeries.Add(new TValue(i, ast));
marketSeries.Add(new TValue(i, mkt)); marketSeries.Add(new TValue(i, mkt));
} }
@@ -394,7 +394,7 @@ public sealed class ConvexityTests
for (int i = 1; i <= period; i++) for (int i = 1; i <= period; i++)
{ {
double sign = (i % 2 == 0) ? 1 : -1; double sign = (i % 2 == 0) ? 1 : -1;
double magnitude = 0.01 + rng.NextDouble() * 0.03; double magnitude = 0.01 + (rng.NextDouble() * 0.03);
double mktRet = sign * magnitude; double mktRet = sign * magnitude;
mkt *= (1 + mktRet); mkt *= (1 + mktRet);
ast *= (1 - mktRet); // inverse ast *= (1 - mktRet); // inverse
@@ -440,8 +440,8 @@ public sealed class ConvexityTests
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)
{ {
ast *= (1 + (rng.NextDouble() - 0.5) * 0.04); ast *= (1 + ((rng.NextDouble() - 0.5) * 0.04));
mkt *= (1 + (rng.NextDouble() - 0.5) * 0.02); mkt *= (1 + ((rng.NextDouble() - 0.5) * 0.02));
c.Update(ast, mkt); c.Update(ast, mkt);
Assert.True(double.IsFinite(c.ConvexityValue), $"ConvexityValue not finite at i={i}"); Assert.True(double.IsFinite(c.ConvexityValue), $"ConvexityValue not finite at i={i}");