mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-27 17:27:43 +00:00
[CodeFactor] Apply fixes to commit 4a01f03
This commit is contained in:
@@ -105,9 +105,9 @@ public sealed class Regchannel : ITValuePublisher
|
||||
// sumX = 0 + 1 + ... + (n-1) = n(n-1)/2
|
||||
_sumX = 0.5 * period * (period - 1);
|
||||
// sumX2 = 0² + 1² + ... + (n-1)² = (n-1)n(2n-1)/6
|
||||
double sumX2 = (period - 1.0) * period * (2.0 * period - 1.0) / 6.0;
|
||||
double sumX2 = (period - 1.0) * period * ((2.0 * period) - 1.0) / 6.0;
|
||||
// denominator = n * sumX2 - sumX²
|
||||
_denominator = period * sumX2 - _sumX * _sumX;
|
||||
_denominator = (period * sumX2) - (_sumX * _sumX);
|
||||
|
||||
Reset();
|
||||
}
|
||||
@@ -218,8 +218,8 @@ public sealed class Regchannel : ITValuePublisher
|
||||
if (count < _period)
|
||||
{
|
||||
sx = 0.5 * n * (n - 1);
|
||||
double sx2 = (n - 1.0) * n * (2.0 * n - 1.0) / 6.0;
|
||||
denom = n * sx2 - sx * sx;
|
||||
double sx2 = (n - 1.0) * n * ((2.0 * n) - 1.0) / 6.0;
|
||||
denom = (n * sx2) - (sx * sx);
|
||||
}
|
||||
|
||||
double slope, intercept, regression;
|
||||
@@ -232,8 +232,8 @@ public sealed class Regchannel : ITValuePublisher
|
||||
}
|
||||
else
|
||||
{
|
||||
slope = (n * sumXY - sx * sumY) / denom;
|
||||
intercept = (sumY - slope * sx) / n;
|
||||
slope = ((n * sumXY) - (sx * sumY)) / denom;
|
||||
intercept = (sumY - (slope * sx)) / n;
|
||||
// Regression value at current point (x = count - 1)
|
||||
regression = Math.FusedMultiplyAdd(slope, count - 1, intercept);
|
||||
}
|
||||
@@ -362,8 +362,8 @@ public sealed class Regchannel : ITValuePublisher
|
||||
|
||||
// Precompute constants for full period
|
||||
double sumXFull = 0.5 * period * (period - 1);
|
||||
double sumX2Full = (period - 1.0) * period * (2.0 * period - 1.0) / 6.0;
|
||||
double denomFull = period * sumX2Full - sumXFull * sumXFull;
|
||||
double sumX2Full = (period - 1.0) * period * ((2.0 * period) - 1.0) / 6.0;
|
||||
double denomFull = (period * sumX2Full) - (sumXFull * sumXFull);
|
||||
|
||||
// Circular buffer of NaN-sanitised values for O(1) sliding-window recurrences.
|
||||
const int StackAllocThreshold = 256;
|
||||
@@ -442,8 +442,8 @@ public sealed class Regchannel : ITValuePublisher
|
||||
if (count < period)
|
||||
{
|
||||
sx = 0.5 * n * (n - 1);
|
||||
double sx2 = (n - 1.0) * n * (2.0 * n - 1.0) / 6.0;
|
||||
denom = n * sx2 - sx * sx;
|
||||
double sx2 = (n - 1.0) * n * ((2.0 * n) - 1.0) / 6.0;
|
||||
denom = (n * sx2) - (sx * sx);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -461,14 +461,14 @@ public sealed class Regchannel : ITValuePublisher
|
||||
}
|
||||
else
|
||||
{
|
||||
slope = (n * sumXY - sx * sumY) / denom;
|
||||
intercept = (sumY - slope * sx) / n;
|
||||
slope = ((n * sumXY) - (sx * sumY)) / denom;
|
||||
intercept = (sumY - (slope * sx)) / n;
|
||||
regression = Math.FusedMultiplyAdd(slope, count - 1, intercept);
|
||||
}
|
||||
|
||||
// Closed-form residual variance (normal-equation identity):
|
||||
// sumResiduals² = sumY² − intercept·sumY − slope·sumXY
|
||||
double sumResiduals2 = Math.Max(0.0, sumY2 - intercept * sumY - slope * sumXY);
|
||||
double sumResiduals2 = Math.Max(0.0, sumY2 - (intercept * sumY) - (slope * sumXY));
|
||||
double stdDev = Math.Sqrt(sumResiduals2 / n);
|
||||
double band = multiplier * stdDev;
|
||||
|
||||
|
||||
@@ -105,9 +105,9 @@ public sealed class Sdchannel : ITValuePublisher
|
||||
// sumX = 0 + 1 + ... + (n-1) = n(n-1)/2
|
||||
_sumX = 0.5 * period * (period - 1);
|
||||
// sumX2 = 0² + 1² + ... + (n-1)² = (n-1)n(2n-1)/6
|
||||
double sumX2 = (period - 1.0) * period * (2.0 * period - 1.0) / 6.0;
|
||||
double sumX2 = (period - 1.0) * period * ((2.0 * period) - 1.0) / 6.0;
|
||||
// denominator = n * sumX2 - sumX²
|
||||
_denominator = period * sumX2 - _sumX * _sumX;
|
||||
_denominator = (period * sumX2) - (_sumX * _sumX);
|
||||
|
||||
Reset();
|
||||
}
|
||||
@@ -218,8 +218,8 @@ public sealed class Sdchannel : ITValuePublisher
|
||||
if (count < _period)
|
||||
{
|
||||
sx = 0.5 * n * (n - 1);
|
||||
double sx2 = (n - 1.0) * n * (2.0 * n - 1.0) / 6.0;
|
||||
denom = n * sx2 - sx * sx;
|
||||
double sx2 = (n - 1.0) * n * ((2.0 * n) - 1.0) / 6.0;
|
||||
denom = (n * sx2) - (sx * sx);
|
||||
}
|
||||
|
||||
double slope, intercept, regression;
|
||||
@@ -232,8 +232,8 @@ public sealed class Sdchannel : ITValuePublisher
|
||||
}
|
||||
else
|
||||
{
|
||||
slope = (n * sumXY - sx * sumY) / denom;
|
||||
intercept = (sumY - slope * sx) / n;
|
||||
slope = ((n * sumXY) - (sx * sumY)) / denom;
|
||||
intercept = (sumY - (slope * sx)) / n;
|
||||
// Regression value at current point (x = count - 1)
|
||||
regression = Math.FusedMultiplyAdd(slope, count - 1, intercept);
|
||||
}
|
||||
@@ -362,8 +362,8 @@ public sealed class Sdchannel : ITValuePublisher
|
||||
|
||||
// Precompute constants for full period
|
||||
double sumXFull = 0.5 * period * (period - 1);
|
||||
double sumX2Full = (period - 1.0) * period * (2.0 * period - 1.0) / 6.0;
|
||||
double denomFull = period * sumX2Full - sumXFull * sumXFull;
|
||||
double sumX2Full = (period - 1.0) * period * ((2.0 * period) - 1.0) / 6.0;
|
||||
double denomFull = (period * sumX2Full) - (sumXFull * sumXFull);
|
||||
|
||||
// Circular buffer of NaN-sanitised values for O(1) sliding-window recurrences.
|
||||
const int StackAllocThreshold = 256;
|
||||
@@ -441,8 +441,8 @@ public sealed class Sdchannel : ITValuePublisher
|
||||
if (count < period)
|
||||
{
|
||||
sx = 0.5 * n * (n - 1);
|
||||
double sx2 = (n - 1.0) * n * (2.0 * n - 1.0) / 6.0;
|
||||
denom = n * sx2 - sx * sx;
|
||||
double sx2 = (n - 1.0) * n * ((2.0 * n) - 1.0) / 6.0;
|
||||
denom = (n * sx2) - (sx * sx);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -460,8 +460,8 @@ public sealed class Sdchannel : ITValuePublisher
|
||||
}
|
||||
else
|
||||
{
|
||||
slope = (n * sumXY - sx * sumY) / denom;
|
||||
intercept = (sumY - slope * sx) / n;
|
||||
slope = ((n * sumXY) - (sx * sumY)) / denom;
|
||||
intercept = (sumY - (slope * sx)) / n;
|
||||
regression = Math.FusedMultiplyAdd(slope, count - 1, intercept);
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ public class CcorValidationTests
|
||||
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
double val = 100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / period);
|
||||
double val = 100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / period));
|
||||
ccor.Update(new TValue(DateTime.UtcNow.AddMinutes(i), val), true);
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ public class CcorValidationTests
|
||||
$"Sine wave should produce non-trivial phasor: Real={ccor.Real:F4}, Imag={ccor.Imag:F4}");
|
||||
|
||||
// R² + I² should be near 1 for a pure tone at the matched frequency
|
||||
double magnitude = Math.Sqrt(ccor.Real * ccor.Real + ccor.Imag * ccor.Imag);
|
||||
double magnitude = Math.Sqrt((ccor.Real * ccor.Real) + (ccor.Imag * ccor.Imag));
|
||||
Assert.True(magnitude > 0.5,
|
||||
$"Phasor magnitude should be significant for matched sine: {magnitude:F4}");
|
||||
}
|
||||
@@ -138,7 +138,7 @@ public class CcorValidationTests
|
||||
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
double val = 100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / period);
|
||||
double val = 100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / period));
|
||||
ccor.Update(new TValue(DateTime.UtcNow.AddMinutes(i), val), true);
|
||||
}
|
||||
|
||||
@@ -374,7 +374,7 @@ public class CcorValidationTests
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddMinutes(i),
|
||||
100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / 20.0)), isNew: true);
|
||||
100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / 20.0))), isNew: true);
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -158,7 +158,7 @@ public sealed class Ccor : AbstractBase
|
||||
// Phasor angle (degrees) with quadrant resolution
|
||||
if (imagVal != 0.0)
|
||||
{
|
||||
angleVal = 90.0 + Math.Atan(realVal / imagVal) * (180.0 / Math.PI);
|
||||
angleVal = 90.0 + (Math.Atan(realVal / imagVal) * (180.0 / Math.PI));
|
||||
}
|
||||
if (imagVal > 0.0)
|
||||
{
|
||||
@@ -342,7 +342,7 @@ public sealed class Ccor : AbstractBase
|
||||
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
int idx = ((bufIdx - 1 - k) % period + period) % period;
|
||||
int idx = (((bufIdx - 1 - k) % period) + period) % period;
|
||||
double x = priceBuf[idx];
|
||||
double y = cosTab[k];
|
||||
sx += x;
|
||||
@@ -353,8 +353,8 @@ public sealed class Ccor : AbstractBase
|
||||
}
|
||||
|
||||
double nd = n;
|
||||
double dp = (nd * sxx - sx * sx) * (nd * syy - sy * sy);
|
||||
realVal = dp > 0.0 ? Math.Clamp((nd * sxy - sx * sy) / Math.Sqrt(dp), -1.0, 1.0) : 0.0;
|
||||
double dp = ((nd * sxx) - (sx * sx)) * ((nd * syy) - (sy * sy));
|
||||
realVal = dp > 0.0 ? Math.Clamp(((nd * sxy) - (sx * sy)) / Math.Sqrt(dp), -1.0, 1.0) : 0.0;
|
||||
}
|
||||
|
||||
output[i] = realVal;
|
||||
@@ -423,13 +423,13 @@ public sealed class Ccor : AbstractBase
|
||||
}
|
||||
|
||||
double nd = n;
|
||||
double denomProd = (nd * sxx - sx * sx) * (nd * syy - sy * sy);
|
||||
double denomProd = ((nd * sxx) - (sx * sx)) * ((nd * syy) - (sy * sy));
|
||||
if (denomProd <= 0.0)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double r = (nd * sxy - sx * sy) / Math.Sqrt(denomProd);
|
||||
double r = ((nd * sxy) - (sx * sy)) / Math.Sqrt(denomProd);
|
||||
return Math.Clamp(r, -1.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class EacpValidationTests
|
||||
// Generate sine wave with known period
|
||||
for (int i = 0; i < 500; i++)
|
||||
{
|
||||
double price = 100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / knownPeriod);
|
||||
double price = 100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / knownPeriod));
|
||||
eacp.Update(new TValue(DateTime.UtcNow.AddSeconds(i), price));
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ public class EacpValidationTests
|
||||
// Generate sine wave
|
||||
for (int i = 0; i < 300; i++)
|
||||
{
|
||||
double price = 100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / 20.0);
|
||||
double price = 100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / 20.0));
|
||||
eacpEnhanced.Update(new TValue(DateTime.UtcNow.AddSeconds(i), price));
|
||||
eacpNormal.Update(new TValue(DateTime.UtcNow.AddSeconds(i), price));
|
||||
}
|
||||
@@ -293,7 +293,7 @@ public class EacpValidationTests
|
||||
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
double price = 0.0001 + 0.00001 * Math.Sin(2.0 * Math.PI * i / 20.0);
|
||||
double price = 0.0001 + (0.00001 * Math.Sin(2.0 * Math.PI * i / 20.0));
|
||||
eacp.Update(new TValue(DateTime.UtcNow.AddSeconds(i), price));
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ public class EacpValidationTests
|
||||
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
double price = 1e10 + 1e9 * Math.Sin(2.0 * Math.PI * i / 20.0);
|
||||
double price = 1e10 + (1e9 * Math.Sin(2.0 * Math.PI * i / 20.0));
|
||||
eacp.Update(new TValue(DateTime.UtcNow.AddSeconds(i), price));
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ public class EacpValidationTests
|
||||
// Generate pure sine wave
|
||||
for (int i = 0; i < 300; i++)
|
||||
{
|
||||
double price = 100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / 20.0);
|
||||
double price = 100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / 20.0));
|
||||
eacp.Update(new TValue(DateTime.UtcNow.AddSeconds(i), price));
|
||||
}
|
||||
|
||||
@@ -406,8 +406,8 @@ public class EacpValidationTests
|
||||
// Generate two different sine waves
|
||||
for (int i = 0; i < 500; i++)
|
||||
{
|
||||
double price1 = 100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / period1);
|
||||
double price2 = 100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / period2);
|
||||
double price1 = 100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / period1));
|
||||
double price2 = 100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / period2));
|
||||
|
||||
eacp1.Update(new TValue(DateTime.UtcNow.AddSeconds(i), price1));
|
||||
eacp2.Update(new TValue(DateTime.UtcNow.AddSeconds(i), price2));
|
||||
@@ -428,7 +428,7 @@ public class EacpValidationTests
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddMinutes(i),
|
||||
100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / 20.0)), isNew: true);
|
||||
100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / 20.0))), isNew: true);
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -191,10 +191,10 @@ public sealed class Eacp : AbstractBase
|
||||
// High-pass filter: removes DC and low-frequency trend
|
||||
double hp2 = s.Hp1;
|
||||
double hp1 = s.Hp0;
|
||||
double coef = (1.0 - _alphaHP / 2.0);
|
||||
double hp0 = coef * coef * (price0 - 2.0 * price1 + price2)
|
||||
+ 2.0 * (1.0 - _alphaHP) * hp1
|
||||
- (1.0 - _alphaHP) * (1.0 - _alphaHP) * hp2;
|
||||
double coef = (1.0 - (_alphaHP / 2.0));
|
||||
double hp0 = (coef * coef * (price0 - (2.0 * price1) + price2))
|
||||
+ (2.0 * (1.0 - _alphaHP) * hp1)
|
||||
- ((1.0 - _alphaHP) * (1.0 - _alphaHP) * hp2);
|
||||
|
||||
// Super-smoother filter: removes high-frequency noise
|
||||
double filt2 = s.Filt1;
|
||||
@@ -290,12 +290,12 @@ public sealed class Eacp : AbstractBase
|
||||
double corrVal = 0;
|
||||
if (valid > 1)
|
||||
{
|
||||
double denomX = valid * sxx - sx * sx;
|
||||
double denomY = valid * syy - sy * sy;
|
||||
double denomX = (valid * sxx) - (sx * sx);
|
||||
double denomY = (valid * syy) - (sy * sy);
|
||||
double denom = denomX * denomY;
|
||||
if (denom > 0)
|
||||
{
|
||||
corrVal = (valid * sxy - sx * sy) / Math.Sqrt(denom);
|
||||
corrVal = ((valid * sxy) - (sx * sy)) / Math.Sqrt(denom);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ public sealed class Eacp : AbstractBase
|
||||
}
|
||||
|
||||
// Power = amplitude squared
|
||||
double sq = cosAcc * cosAcc + sinAcc * sinAcc;
|
||||
double sq = (cosAcc * cosAcc) + (sinAcc * sinAcc);
|
||||
|
||||
// Smooth the power spectrum (EMA-like smoothing)
|
||||
// Power squared per Ehlers: emphasizes spectral peaks, suppresses noise
|
||||
|
||||
@@ -103,7 +103,7 @@ public sealed class HtDcperiodValidationTests : IDisposable
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddMinutes(i),
|
||||
100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / 20.0)), isNew: true);
|
||||
100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / 20.0))), isNew: true);
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -27,7 +27,7 @@ public class HtDcphaseTests
|
||||
// Feed data through publisher
|
||||
for (int i = 0; i < 80; i++)
|
||||
{
|
||||
source.Add(new TValue(DateTime.UtcNow.AddMinutes(i), 100 + Math.Sin(i * 0.3) * 10));
|
||||
source.Add(new TValue(DateTime.UtcNow.AddMinutes(i), 100 + (Math.Sin(i * 0.3) * 10)));
|
||||
}
|
||||
|
||||
Assert.True(ht.IsHot);
|
||||
@@ -131,7 +131,7 @@ public class HtDcphaseTests
|
||||
// Prime with data
|
||||
for (int i = 0; i < 70; i++)
|
||||
{
|
||||
ht.Update(new TValue(now.AddMinutes(i), 100 + Math.Sin(i * 0.1) * 10));
|
||||
ht.Update(new TValue(now.AddMinutes(i), 100 + (Math.Sin(i * 0.1) * 10)));
|
||||
}
|
||||
|
||||
Assert.True(ht.IsHot);
|
||||
@@ -153,7 +153,7 @@ public class HtDcphaseTests
|
||||
|
||||
for (int i = 0; i < 70; i++)
|
||||
{
|
||||
ht.Update(new TValue(now.AddMinutes(i), 100 + i * 0.5));
|
||||
ht.Update(new TValue(now.AddMinutes(i), 100 + (i * 0.5)));
|
||||
}
|
||||
|
||||
// New bar
|
||||
@@ -187,7 +187,7 @@ public class HtDcphaseTests
|
||||
|
||||
for (int i = 0; i < 80; i++)
|
||||
{
|
||||
ht.Update(new TValue(now.AddMinutes(i), 100 + Math.Sin(i * 0.2) * 5));
|
||||
ht.Update(new TValue(now.AddMinutes(i), 100 + (Math.Sin(i * 0.2) * 5)));
|
||||
}
|
||||
|
||||
Assert.True(ht.IsHot);
|
||||
@@ -203,7 +203,7 @@ public class HtDcphaseTests
|
||||
|
||||
for (int i = 0; i < 80; i++)
|
||||
{
|
||||
ht.Update(new TValue(now.AddMinutes(i), 100 + i * 0.5));
|
||||
ht.Update(new TValue(now.AddMinutes(i), 100 + (i * 0.5)));
|
||||
}
|
||||
|
||||
var result = ht.Update(new TValue(now.AddMinutes(80), double.PositiveInfinity));
|
||||
@@ -236,14 +236,14 @@ public class HtDcphaseTests
|
||||
|
||||
for (int i = 0; i < 80; i++)
|
||||
{
|
||||
ht.Update(new TValue(now.AddMinutes(i), 100 + Math.Sin(i * 0.2) * 5));
|
||||
ht.Update(new TValue(now.AddMinutes(i), 100 + (Math.Sin(i * 0.2) * 5)));
|
||||
}
|
||||
var firstResult = ht.Last.Value;
|
||||
|
||||
ht.Reset();
|
||||
for (int i = 0; i < 80; i++)
|
||||
{
|
||||
ht.Update(new TValue(now.AddMinutes(i), 100 + Math.Sin(i * 0.2) * 5));
|
||||
ht.Update(new TValue(now.AddMinutes(i), 100 + (Math.Sin(i * 0.2) * 5)));
|
||||
}
|
||||
Assert.Equal(firstResult, ht.Last.Value);
|
||||
}
|
||||
@@ -352,7 +352,7 @@ public class HtDcphaseTests
|
||||
var values = new double[80];
|
||||
for (int i = 0; i < 80; i++)
|
||||
{
|
||||
values[i] = 100 + Math.Sin(i * 0.2) * 5;
|
||||
values[i] = 100 + (Math.Sin(i * 0.2) * 5);
|
||||
}
|
||||
|
||||
ht.Prime(values, TimeSpan.FromMinutes(5));
|
||||
|
||||
@@ -103,7 +103,7 @@ public sealed class HtDcphaseValidationTests : IDisposable
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddMinutes(i),
|
||||
100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / 20.0)), isNew: true);
|
||||
100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / 20.0))), isNew: true);
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -141,8 +141,8 @@ public sealed class HtDcphase : AbstractBase
|
||||
double input1 = buffer[KEY_Q1];
|
||||
DoHilbertTransform(buffer, KEY_JQ, input1, true, hilbertIdx, adjustedPrevPeriod);
|
||||
|
||||
q2 = 0.2 * (buffer[KEY_Q1] + buffer[KEY_JI]) + 0.8 * prevQ2;
|
||||
i2 = 0.2 * (i1ForOddPrev3 - buffer[KEY_JQ]) + 0.8 * prevI2;
|
||||
q2 = (0.2 * (buffer[KEY_Q1] + buffer[KEY_JI])) + (0.8 * prevQ2);
|
||||
i2 = (0.2 * (i1ForOddPrev3 - buffer[KEY_JQ])) + (0.8 * prevI2);
|
||||
|
||||
i1ForEvenPrev3 = i1ForEvenPrev2;
|
||||
i1ForEvenPrev2 = buffer[KEY_DETRENDER];
|
||||
@@ -166,8 +166,8 @@ public sealed class HtDcphase : AbstractBase
|
||||
hilbertIdx = 0;
|
||||
}
|
||||
|
||||
q2 = 0.2 * (buffer[KEY_Q1] + buffer[KEY_JI]) + 0.8 * prevQ2;
|
||||
i2 = 0.2 * (i1ForEvenPrev3 - buffer[KEY_JQ]) + 0.8 * prevI2;
|
||||
q2 = (0.2 * (buffer[KEY_Q1] + buffer[KEY_JI])) + (0.8 * prevQ2);
|
||||
i2 = (0.2 * (i1ForEvenPrev3 - buffer[KEY_JQ])) + (0.8 * prevI2);
|
||||
|
||||
i1ForOddPrev3 = i1ForOddPrev2;
|
||||
i1ForOddPrev2 = buffer[KEY_DETRENDER];
|
||||
@@ -296,7 +296,7 @@ public sealed class HtDcphase : AbstractBase
|
||||
}
|
||||
|
||||
// Calculate smoothed price using WMA
|
||||
double adjustedPrevPeriod = 0.075 * s.Period + 0.54;
|
||||
double adjustedPrevPeriod = (0.075 * s.Period) + 0.54;
|
||||
|
||||
s.PeriodWMASub += price;
|
||||
s.PeriodWMASub -= s.TrailingWMAValue;
|
||||
|
||||
@@ -133,7 +133,7 @@ public sealed class HtSineValidationTests : IDisposable
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddMinutes(i),
|
||||
100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / 20.0)), isNew: true);
|
||||
100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / 20.0))), isNew: true);
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -161,8 +161,8 @@ public sealed class HtSine : AbstractBase
|
||||
double input1 = buffer[KEY_Q1];
|
||||
DoHilbertTransform(buffer, KEY_JQ, input1, true, hilbertIdx, adjustedPrevPeriod);
|
||||
|
||||
q2 = 0.2 * (buffer[KEY_Q1] + buffer[KEY_JI]) + 0.8 * prevQ2;
|
||||
i2 = 0.2 * (i1ForOddPrev3 - buffer[KEY_JQ]) + 0.8 * prevI2;
|
||||
q2 = (0.2 * (buffer[KEY_Q1] + buffer[KEY_JI])) + (0.8 * prevQ2);
|
||||
i2 = (0.2 * (i1ForOddPrev3 - buffer[KEY_JQ])) + (0.8 * prevI2);
|
||||
|
||||
// The variable I1 is the detrender delayed for 3 price bars.
|
||||
i1ForEvenPrev3 = i1ForEvenPrev2;
|
||||
@@ -187,8 +187,8 @@ public sealed class HtSine : AbstractBase
|
||||
hilbertIdx = 0;
|
||||
}
|
||||
|
||||
q2 = 0.2 * (buffer[KEY_Q1] + buffer[KEY_JI]) + 0.8 * prevQ2;
|
||||
i2 = 0.2 * (i1ForEvenPrev3 - buffer[KEY_JQ]) + 0.8 * prevI2;
|
||||
q2 = (0.2 * (buffer[KEY_Q1] + buffer[KEY_JI])) + (0.8 * prevQ2);
|
||||
i2 = (0.2 * (i1ForEvenPrev3 - buffer[KEY_JQ])) + (0.8 * prevI2);
|
||||
|
||||
// The variable i1 is the detrender delayed for 3 price bars.
|
||||
i1ForOddPrev3 = i1ForOddPrev2;
|
||||
@@ -199,8 +199,8 @@ public sealed class HtSine : AbstractBase
|
||||
private static void CalcSmoothedPeriod(
|
||||
ref double re, double i2, double q2, ref double prevI2, ref double prevQ2, ref double im, ref double period)
|
||||
{
|
||||
re = Math.FusedMultiplyAdd(0.2, i2 * prevI2 + q2 * prevQ2, 0.8 * re);
|
||||
im = Math.FusedMultiplyAdd(0.2, i2 * prevQ2 - q2 * prevI2, 0.8 * im);
|
||||
re = Math.FusedMultiplyAdd(0.2, (i2 * prevI2) + (q2 * prevQ2), 0.8 * re);
|
||||
im = Math.FusedMultiplyAdd(0.2, (i2 * prevQ2) - (q2 * prevI2), 0.8 * im);
|
||||
|
||||
prevQ2 = q2;
|
||||
prevI2 = i2;
|
||||
@@ -373,7 +373,7 @@ public sealed class HtSine : AbstractBase
|
||||
}
|
||||
|
||||
// Calculate smoothed price using WMA
|
||||
double adjustedPrevPeriod = 0.075 * s.Period + 0.54;
|
||||
double adjustedPrevPeriod = (0.075 * s.Period) + 0.54;
|
||||
|
||||
s.PeriodWMASub += price;
|
||||
s.PeriodWMASub -= s.TrailingWMAValue;
|
||||
|
||||
@@ -476,7 +476,7 @@ public sealed class Adx : ITValuePublisher
|
||||
double dx = CalcDx(trSmooth, dmPlusSmooth, dmMinusSmooth);
|
||||
dxSum += dx;
|
||||
|
||||
int adxStart = period * 2 - 1;
|
||||
int adxStart = (period * 2) - 1;
|
||||
|
||||
for (int i = period + 1; i <= adxStart; i++)
|
||||
{
|
||||
|
||||
@@ -55,7 +55,7 @@ public sealed class HtTrendmodeValidationTests : IDisposable
|
||||
// Act - Process with sinusoidal data
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
double value = 100.0 + Math.Sin(i * 0.2) * 10.0 + Math.Sin(i * 0.05) * 5.0;
|
||||
double value = 100.0 + (Math.Sin(i * 0.2) * 10.0) + (Math.Sin(i * 0.05) * 5.0);
|
||||
indicator.Update(new TValue(DateTime.UtcNow.AddMinutes(i), value));
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public sealed class HtTrendmodeValidationTests : IDisposable
|
||||
// Act
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
double value = 100.0 + Math.Sin(i * 0.15) * 8.0;
|
||||
double value = 100.0 + (Math.Sin(i * 0.15) * 8.0);
|
||||
indicator.Update(new TValue(DateTime.UtcNow.AddMinutes(i), value));
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ public sealed class HtTrendmodeValidationTests : IDisposable
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddMinutes(i),
|
||||
100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / 20.0)), isNew: true);
|
||||
100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / 20.0))), isNew: true);
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -124,8 +124,8 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
// Add 4 bars with increasing trend
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
double basePrice = 100 + i * 5;
|
||||
ichimoku.Update(new TBar(baseTime + i * 60000, basePrice, basePrice + 5, basePrice - 5, basePrice, 1000));
|
||||
double basePrice = 100 + (i * 5);
|
||||
ichimoku.Update(new TBar(baseTime + (i * 60000), basePrice, basePrice + 5, basePrice - 5, basePrice, 1000));
|
||||
}
|
||||
|
||||
// Tenkan (2-period) uses last 2 bars: bars 3,4
|
||||
@@ -223,7 +223,7 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
ichimoku.Update(new TBar(baseTime + i * 60000, (highs[i] + lows[i]) / 2, highs[i], lows[i], (highs[i] + lows[i]) / 2, 1000));
|
||||
ichimoku.Update(new TBar(baseTime + (i * 60000), (highs[i] + lows[i]) / 2, highs[i], lows[i], (highs[i] + lows[i]) / 2, 1000));
|
||||
}
|
||||
|
||||
// 5-period: max(100,110,120,115,105) = 120, min(90,85,80,88,92) = 80
|
||||
@@ -244,7 +244,7 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
ichimoku.Update(new TBar(baseTime + i * 60000, 100, 110, 90, 100, 1000));
|
||||
ichimoku.Update(new TBar(baseTime + (i * 60000), 100, 110, 90, 100, 1000));
|
||||
}
|
||||
|
||||
// 10-period includes the extreme bar
|
||||
@@ -254,7 +254,7 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
Assert.Equal(125.0, ichimoku.SenkouB.Value, Precision);
|
||||
|
||||
// Add another bar to drop the extreme
|
||||
ichimoku.Update(new TBar(baseTime + 10 * 60000, 100, 110, 90, 100, 1000));
|
||||
ichimoku.Update(new TBar(baseTime + (10 * 60000), 100, 110, 90, 100, 1000));
|
||||
|
||||
// Now 10-period window doesn't include extreme bar
|
||||
// max(110,110,...) = 110, min(90,90,...) = 90
|
||||
@@ -291,8 +291,8 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
double expectedClose = 100 + i * 1.5;
|
||||
ichimoku.Update(new TBar(baseTime + i * 60000, expectedClose, expectedClose + 5, expectedClose - 5, expectedClose, 1000));
|
||||
double expectedClose = 100 + (i * 1.5);
|
||||
ichimoku.Update(new TBar(baseTime + (i * 60000), expectedClose, expectedClose + 5, expectedClose - 5, expectedClose, 1000));
|
||||
Assert.Equal(expectedClose, ichimoku.Chikou.Value, Precision);
|
||||
}
|
||||
}
|
||||
@@ -315,14 +315,14 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
double price = 50 + i; // 50 to 59
|
||||
ichimoku.Update(new TBar(baseTime + i * 60000, price, price + 5, price - 5, price, 1000));
|
||||
ichimoku.Update(new TBar(baseTime + (i * 60000), price, price + 5, price - 5, price, 1000));
|
||||
}
|
||||
|
||||
// Then jump to much higher prices - affects Tenkan and Kijun more than SenkouB
|
||||
for (int i = 10; i < 15; i++)
|
||||
{
|
||||
double price = 100 + (i - 10) * 2;
|
||||
ichimoku.Update(new TBar(baseTime + i * 60000, price, price + 5, price - 5, price, 1000));
|
||||
double price = 100 + ((i - 10) * 2);
|
||||
ichimoku.Update(new TBar(baseTime + (i * 60000), price, price + 5, price - 5, price, 1000));
|
||||
}
|
||||
|
||||
// In this scenario, SenkouA should be above SenkouB (bullish cloud)
|
||||
@@ -344,14 +344,14 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
double price = 150 - i; // 150 down to 141
|
||||
ichimoku.Update(new TBar(baseTime + i * 60000, price, price + 5, price - 5, price, 1000));
|
||||
ichimoku.Update(new TBar(baseTime + (i * 60000), price, price + 5, price - 5, price, 1000));
|
||||
}
|
||||
|
||||
// Then drop to much lower prices
|
||||
for (int i = 10; i < 15; i++)
|
||||
{
|
||||
double price = 100 - (i - 10) * 3;
|
||||
ichimoku.Update(new TBar(baseTime + i * 60000, price, price + 5, price - 5, price, 1000));
|
||||
double price = 100 - ((i - 10) * 3);
|
||||
ichimoku.Update(new TBar(baseTime + (i * 60000), price, price + 5, price - 5, price, 1000));
|
||||
}
|
||||
|
||||
// In downtrend, SenkouB (longer term) should be above SenkouA (bearish cloud)
|
||||
@@ -374,9 +374,9 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Random walk-ish price movement
|
||||
double change = Math.Sin(i * 0.1) * 2 + Math.Cos(i * 0.05);
|
||||
double change = (Math.Sin(i * 0.1) * 2) + Math.Cos(i * 0.05);
|
||||
price += change;
|
||||
barSeries.Add(new TBar(baseTime + i * 60000, price, price + 2, price - 2, price, 1000));
|
||||
barSeries.Add(new TBar(baseTime + (i * 60000), price, price + 2, price - 2, price, 1000));
|
||||
}
|
||||
|
||||
// Process all bars
|
||||
@@ -406,8 +406,8 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
// Process enough bars to warmup
|
||||
for (int i = 0; i < 70; i++)
|
||||
{
|
||||
double price = 40000 + Math.Sin(i * 0.05) * 1000;
|
||||
ichimoku.Update(new TBar(baseTime + i * 60000, price, price + 50, price - 50, price, 10));
|
||||
double price = 40000 + (Math.Sin(i * 0.05) * 1000);
|
||||
ichimoku.Update(new TBar(baseTime + (i * 60000), price, price + 50, price - 50, price, 10));
|
||||
}
|
||||
|
||||
Assert.True(ichimoku.IsHot);
|
||||
@@ -427,7 +427,7 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
for (int i = 0; i < 60; i++)
|
||||
{
|
||||
double price = 100 + i;
|
||||
barSeries.Add(new TBar(baseTime + i * 60000, price, price + 5, price - 5, price, 1000));
|
||||
barSeries.Add(new TBar(baseTime + (i * 60000), price, price + 5, price - 5, price, 1000));
|
||||
}
|
||||
|
||||
// Batch processing
|
||||
@@ -472,7 +472,7 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
for (int i = 0; i < 60; i++)
|
||||
{
|
||||
double price = 100 + i;
|
||||
barSeries.Add(new TBar(baseTime + i * 60000, price, price + 5, price - 5, price, 1000));
|
||||
barSeries.Add(new TBar(baseTime + (i * 60000), price, price + 5, price - 5, price, 1000));
|
||||
}
|
||||
|
||||
var (results, indicator) = Ichimoku.Calculate(barSeries);
|
||||
@@ -500,7 +500,7 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
// Phase 1: Ranging market - Tenkan ≈ Kijun
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
ichimoku.Update(new TBar(baseTime + i * 60000, 100, 105, 95, 100, 1000));
|
||||
ichimoku.Update(new TBar(baseTime + (i * 60000), 100, 105, 95, 100, 1000));
|
||||
}
|
||||
|
||||
// Capture initial state (using discards since we're testing the response to change)
|
||||
@@ -510,8 +510,8 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
// Phase 2: Sharp upward move - Tenkan should rise faster
|
||||
for (int i = 5; i < 10; i++)
|
||||
{
|
||||
double price = 100 + (i - 5) * 5;
|
||||
ichimoku.Update(new TBar(baseTime + i * 60000, price, price + 3, price - 3, price, 1000));
|
||||
double price = 100 + ((i - 5) * 5);
|
||||
ichimoku.Update(new TBar(baseTime + (i * 60000), price, price + 3, price - 3, price, 1000));
|
||||
}
|
||||
|
||||
// Tenkan (short-term) should react faster to the uptrend
|
||||
@@ -689,7 +689,7 @@ public sealed class IchimokuValidationTests : IDisposable
|
||||
// Build state well past warmup
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
double p = 100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / 20.0);
|
||||
double p = 100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / 20.0));
|
||||
ind.Update(new TBar(t0.AddMinutes(i), p, p + 2, p - 2, p, 1000), isNew: true);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public class TtmSqueezeValidationTests
|
||||
// Very tight range bars - stddev will be near 0
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 100.0, 100.01, 99.99, 100.0, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 100.0, 100.01, 99.99, 100.0, 1000));
|
||||
}
|
||||
|
||||
// With effectively zero stddev, BB bands collapse to the mean
|
||||
@@ -45,7 +45,7 @@ public class TtmSqueezeValidationTests
|
||||
double high = 105;
|
||||
double low = 95;
|
||||
double close = (high + low) / 2; // exactly at midline
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 100, high, low, close, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 100, high, low, close, 1000));
|
||||
}
|
||||
|
||||
// Momentum should be near zero since price = midline
|
||||
@@ -113,7 +113,7 @@ public class TtmSqueezeValidationTests
|
||||
double midline = 100; // (110 + 90) / 2
|
||||
double close = midline + (i * 2); // 100, 102, 104, ...
|
||||
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 100, high, low, close, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 100, high, low, close, 1000));
|
||||
}
|
||||
|
||||
// Momentum should be strongly positive with rising trend
|
||||
@@ -135,28 +135,28 @@ public class TtmSqueezeValidationTests
|
||||
// Uptrend (rising above zero - cyan = 0)
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 100 + i * 2, 105 + i * 2, 95 + i * 2, 103 + i * 2, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 100 + (i * 2), 105 + (i * 2), 95 + (i * 2), 103 + (i * 2), 1000));
|
||||
colorsSeen.Add(squeeze.ColorCode);
|
||||
}
|
||||
|
||||
// Now weakening but still positive (falling above zero - blue = 1)
|
||||
for (int i = 5; i < 10; i++)
|
||||
{
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 115, 118, 112, 114, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 115, 118, 112, 114, 1000));
|
||||
colorsSeen.Add(squeeze.ColorCode);
|
||||
}
|
||||
|
||||
// Downtrend (falling below zero - red = 2)
|
||||
for (int i = 10; i < 15; i++)
|
||||
{
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 100 - (i - 10) * 3, 102 - (i - 10) * 3, 95 - (i - 10) * 3, 97 - (i - 10) * 3, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 100 - ((i - 10) * 3), 102 - ((i - 10) * 3), 95 - ((i - 10) * 3), 97 - ((i - 10) * 3), 1000));
|
||||
colorsSeen.Add(squeeze.ColorCode);
|
||||
}
|
||||
|
||||
// Recovering but still negative (rising below zero - yellow = 3)
|
||||
for (int i = 15; i < 20; i++)
|
||||
{
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 80, 85, 78, 82, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 80, 85, 78, 82, 1000));
|
||||
colorsSeen.Add(squeeze.ColorCode);
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ public class TtmSqueezeValidationTests
|
||||
// Strong uptrend to ensure positive and rising momentum
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 100 + i * 5, 105 + i * 5, 95 + i * 5, 103 + i * 5, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 100 + (i * 5), 105 + (i * 5), 95 + (i * 5), 103 + (i * 5), 1000));
|
||||
}
|
||||
|
||||
if (squeeze.MomentumPositive && squeeze.MomentumRising)
|
||||
@@ -191,7 +191,7 @@ public class TtmSqueezeValidationTests
|
||||
// Strong downtrend to ensure negative and falling momentum
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 100 - i * 5, 105 - i * 5, 95 - i * 5, 97 - i * 5, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 100 - (i * 5), 105 - (i * 5), 95 - (i * 5), 97 - (i * 5), 1000));
|
||||
}
|
||||
|
||||
if (!squeeze.MomentumPositive && !squeeze.MomentumRising)
|
||||
@@ -215,7 +215,7 @@ public class TtmSqueezeValidationTests
|
||||
// Start with tight range to build squeeze
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 100, 100.1, 99.9, 100, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 100, 100.1, 99.9, 100, 1000));
|
||||
if (squeeze.SqueezeFired)
|
||||
{
|
||||
squeezeFiredCount++;
|
||||
@@ -226,7 +226,7 @@ public class TtmSqueezeValidationTests
|
||||
for (int i = 5; i < 10; i++)
|
||||
{
|
||||
double volatility = (i - 4) * 5;
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 100, 100 + volatility, 100 - volatility, 100 + volatility - 2, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 100, 100 + volatility, 100 - volatility, 100 + volatility - 2, 1000));
|
||||
if (squeeze.SqueezeFired)
|
||||
{
|
||||
squeezeFiredCount++;
|
||||
@@ -250,10 +250,10 @@ public class TtmSqueezeValidationTests
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
double price = 100 + Math.Sin(i * 0.2) * 10;
|
||||
double price = 100 + (Math.Sin(i * 0.2) * 10);
|
||||
double high = price + 2;
|
||||
double low = price - 2;
|
||||
source.Add(new TBar(baseTime + i * 60000, price, high, low, price + 0.5, 1000));
|
||||
source.Add(new TBar(baseTime + (i * 60000), price, high, low, price + 0.5, 1000));
|
||||
}
|
||||
|
||||
// Batch calculation
|
||||
@@ -301,7 +301,7 @@ public class TtmSqueezeValidationTests
|
||||
// All bars identical
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 100, 100, 100, 100, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 100, 100, 100, 100, 1000));
|
||||
}
|
||||
|
||||
Assert.True(double.IsFinite(squeeze.Momentum.Value));
|
||||
@@ -318,7 +318,7 @@ public class TtmSqueezeValidationTests
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
double range = (i + 1) * 100; // Increasing volatility
|
||||
squeeze.Update(new TBar(baseTime + i * 60000, 100, 100 + range, 100 - range, 100 + range / 2, 1000));
|
||||
squeeze.Update(new TBar(baseTime + (i * 60000), 100, 100 + range, 100 - range, 100 + (range / 2), 1000));
|
||||
}
|
||||
|
||||
Assert.True(double.IsFinite(squeeze.Momentum.Value));
|
||||
@@ -334,7 +334,7 @@ public class TtmSqueezeValidationTests
|
||||
// Build state well past warmup
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
double p = 100.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / 20.0);
|
||||
double p = 100.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / 20.0));
|
||||
ind.Update(new TBar(t0.AddMinutes(i), p, p + 2, p - 2, p, 1000), isNew: true);
|
||||
}
|
||||
|
||||
|
||||
@@ -210,8 +210,8 @@ public sealed class TtmSqueeze : ITValuePublisher
|
||||
|
||||
// Precompute linear regression constants
|
||||
_sumX = 0.5 * momPeriod * (momPeriod - 1);
|
||||
double sumX2 = (momPeriod - 1.0) * momPeriod * (2.0 * momPeriod - 1.0) / 6.0;
|
||||
_denominator = momPeriod * sumX2 - _sumX * _sumX;
|
||||
double sumX2 = (momPeriod - 1.0) * momPeriod * ((2.0 * momPeriod) - 1.0) / 6.0;
|
||||
_denominator = (momPeriod * sumX2) - (_sumX * _sumX);
|
||||
|
||||
Reset();
|
||||
}
|
||||
@@ -328,11 +328,11 @@ public sealed class TtmSqueeze : ITValuePublisher
|
||||
|
||||
double bbCount = Math.Min(_barCount, _bbPeriod);
|
||||
double bbMean = bbCount > 0 ? _priceSum / bbCount : close;
|
||||
double bbVariance = bbCount > 1 ? (_priceSumSquares - _priceSum * _priceSum / bbCount) / bbCount : 0;
|
||||
double bbVariance = bbCount > 1 ? (_priceSumSquares - (_priceSum * _priceSum / bbCount)) / bbCount : 0;
|
||||
double bbStdDev = Math.Sqrt(Math.Max(0, bbVariance));
|
||||
|
||||
double bbUpper = bbMean + _bbMult * bbStdDev;
|
||||
double bbLower = bbMean - _bbMult * bbStdDev;
|
||||
double bbUpper = bbMean + (_bbMult * bbStdDev);
|
||||
double bbLower = bbMean - (_bbMult * bbStdDev);
|
||||
|
||||
// === Keltner Channel Calculation ===
|
||||
// EMA with warmup compensation
|
||||
@@ -354,8 +354,8 @@ public sealed class TtmSqueeze : ITValuePublisher
|
||||
_atrE = Math.FusedMultiplyAdd(_atrE, 1 - atrAlpha, 0);
|
||||
double atr = _atrE < 1.0 ? _atrRma / (1.0 - _atrE) : _atrRma;
|
||||
|
||||
double kcUpper = kcMid + _kcMult * atr;
|
||||
double kcLower = kcMid - _kcMult * atr;
|
||||
double kcUpper = kcMid + (_kcMult * atr);
|
||||
double kcLower = kcMid - (_kcMult * atr);
|
||||
|
||||
// === Squeeze Detection ===
|
||||
bool wasSqueezeOn = _prevSqueezeOn;
|
||||
@@ -380,7 +380,7 @@ public sealed class TtmSqueeze : ITValuePublisher
|
||||
{
|
||||
double oldest = _momentumBuffer[0];
|
||||
double prevSumY = _momentumSumY;
|
||||
_momentumSumXY = _momentumSumXY + prevSumY - _momPeriod * oldest;
|
||||
_momentumSumXY = _momentumSumXY + prevSumY - (_momPeriod * oldest);
|
||||
_momentumSumY -= oldest;
|
||||
}
|
||||
_momentumBuffer.Add(deviation);
|
||||
@@ -411,8 +411,8 @@ public sealed class TtmSqueeze : ITValuePublisher
|
||||
if (momCount < _momPeriod)
|
||||
{
|
||||
sx = 0.5 * n * (n - 1);
|
||||
double sx2 = (n - 1.0) * n * (2.0 * n - 1.0) / 6.0;
|
||||
denom = n * sx2 - sx * sx;
|
||||
double sx2 = (n - 1.0) * n * ((2.0 * n) - 1.0) / 6.0;
|
||||
denom = (n * sx2) - (sx * sx);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -426,8 +426,8 @@ public sealed class TtmSqueeze : ITValuePublisher
|
||||
}
|
||||
else
|
||||
{
|
||||
double slope = (n * _momentumSumXY - sx * _momentumSumY) / denom;
|
||||
double intercept = (_momentumSumY - slope * sx) / n;
|
||||
double slope = ((n * _momentumSumXY) - (sx * _momentumSumY)) / denom;
|
||||
double intercept = (_momentumSumY - (slope * sx)) / n;
|
||||
// Regression value at current point (x = count - 1)
|
||||
momentum = Math.FusedMultiplyAdd(slope, n - 1, intercept);
|
||||
}
|
||||
@@ -561,5 +561,4 @@ public sealed class TtmSqueeze : ITValuePublisher
|
||||
_lowBuffer.Restore();
|
||||
_momentumBuffer.Restore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public sealed class MaeValidationTests : IDisposable
|
||||
// Build state well past warmup
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
ind.Update(100.0 + i * 0.5, 98.0 + i * 0.5);
|
||||
ind.Update(100.0 + (i * 0.5), 98.0 + (i * 0.5));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -93,7 +93,7 @@ public sealed class MapeValidationTests : IDisposable
|
||||
// Build state well past warmup (actual always > 0 so MAPE denominator is valid)
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
ind.Update(100.0 + i * 0.5, 98.0 + i * 0.5);
|
||||
ind.Update(100.0 + (i * 0.5), 98.0 + (i * 0.5));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -336,7 +336,7 @@ public sealed class Mdae : AbstractBase
|
||||
}
|
||||
|
||||
// Median-of-three pivot selection for better pivot choice
|
||||
int mid = left + (right - left) / 2;
|
||||
int mid = left + ((right - left) / 2);
|
||||
if (span[mid] < span[left])
|
||||
{
|
||||
(span[left], span[mid]) = (span[mid], span[left]);
|
||||
|
||||
@@ -80,7 +80,7 @@ public sealed class MseValidationTests : IDisposable
|
||||
// Build state well past warmup
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
ind.Update(100.0 + i * 0.5, 98.0 + i * 0.5);
|
||||
ind.Update(100.0 + (i * 0.5), 98.0 + (i * 0.5));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -82,7 +82,7 @@ public sealed class RmseValidationTests : IDisposable
|
||||
// Build state well past warmup
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
ind.Update(100.0 + i * 0.5, 98.0 + i * 0.5);
|
||||
ind.Update(100.0 + (i * 0.5), 98.0 + (i * 0.5));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -203,7 +203,7 @@ public sealed class RsquaredValidationTests : IDisposable
|
||||
// Build state well past warmup
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
ind.Update(100.0 + i * 0.5, 98.0 + i * 0.5);
|
||||
ind.Update(100.0 + (i * 0.5), 98.0 + (i * 0.5));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -817,8 +817,8 @@ public sealed class CsvFeedTests : IDisposable
|
||||
Assert.Equal(startTime, series[0].Time); // Jan 1
|
||||
Assert.Equal(startTime + interval.Ticks, series[1].Time); // Jan 2
|
||||
// Gap here (Jan 3 missing)
|
||||
Assert.Equal(startTime + 3 * interval.Ticks, series[2].Time); // Jan 4
|
||||
Assert.Equal(startTime + 4 * interval.Ticks, series[3].Time); // Jan 5
|
||||
Assert.Equal(startTime + (3 * interval.Ticks), series[2].Time); // Jan 4
|
||||
Assert.Equal(startTime + (4 * interval.Ticks), series[3].Time); // Jan 5
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -941,7 +941,7 @@ public sealed class CsvFeedTests : IDisposable
|
||||
// Jan 1 and Jan 3 present; Jan 2 absent → Fetch includes both with gap
|
||||
Assert.Equal(2, series.Count);
|
||||
Assert.Equal(startTime, series[0].Time);
|
||||
Assert.Equal(startTime + 2 * TimeSpan.FromDays(1).Ticks, series[1].Time);
|
||||
Assert.Equal(startTime + (2 * TimeSpan.FromDays(1).Ticks), series[1].Time);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -276,7 +276,7 @@ public class GBMTests
|
||||
|
||||
Assert.Equal(startTime, series[0].Time);
|
||||
Assert.Equal(startTime + interval.Ticks, series[1].Time);
|
||||
Assert.Equal(startTime + 2 * interval.Ticks, series[2].Time);
|
||||
Assert.Equal(startTime + (2 * interval.Ticks), series[2].Time);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
||||
@@ -113,7 +113,7 @@ public sealed class GBM : IFeed
|
||||
const double minutesPerYear = 252.0 * 6.5 * 60.0;
|
||||
double dt = timeframe.TotalMinutes / minutesPerYear;
|
||||
|
||||
_drift = (mu - 0.5 * sigma * sigma) * dt;
|
||||
_drift = (mu - (0.5 * sigma * sigma)) * dt;
|
||||
_vol = sigma * Math.Sqrt(dt);
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ public sealed class GBM : IFeed
|
||||
price = _lastPrice;
|
||||
}
|
||||
|
||||
double volume = 1000 + NextDouble() * 1000;
|
||||
double volume = 1000 + (NextDouble() * 1000);
|
||||
|
||||
double open = _lastPrice;
|
||||
double close = price;
|
||||
@@ -226,8 +226,8 @@ public sealed class GBM : IFeed
|
||||
double rnd1 = NextDouble();
|
||||
double rnd2 = NextDouble();
|
||||
|
||||
double high = Math.Max(open, close) * (1.0 + rnd1 * 0.01);
|
||||
double low = Math.Min(open, close) * (1.0 - rnd2 * 0.01);
|
||||
double high = Math.Max(open, close) * (1.0 + (rnd1 * 0.01));
|
||||
double low = Math.Min(open, close) * (1.0 - (rnd2 * 0.01));
|
||||
|
||||
// Ensure valid OHLC constraints
|
||||
high = Math.Max(high, Math.Max(open, close));
|
||||
@@ -252,7 +252,7 @@ public sealed class GBM : IFeed
|
||||
price = _lastPrice;
|
||||
}
|
||||
|
||||
double additionalVolume = 1000 + NextDouble() * 1000;
|
||||
double additionalVolume = 1000 + (NextDouble() * 1000);
|
||||
|
||||
var bar = _currentBar;
|
||||
double newClose = price;
|
||||
@@ -412,7 +412,7 @@ public sealed class GBM : IFeed
|
||||
{
|
||||
const double minutesPerYear = 252.0 * 6.5 * 60.0;
|
||||
double dt = interval.TotalMinutes / minutesPerYear;
|
||||
double drift = (Mu - 0.5 * Sigma * Sigma) * dt;
|
||||
double drift = (Mu - (0.5 * Sigma * Sigma)) * dt;
|
||||
double vol = Sigma * Math.Sqrt(dt);
|
||||
|
||||
long timeStep = interval.Ticks;
|
||||
@@ -441,8 +441,8 @@ public sealed class GBM : IFeed
|
||||
o[i] = open;
|
||||
c[i] = close;
|
||||
|
||||
double high = Math.Max(open, close) * (1.0 + rnd1 * 0.01);
|
||||
double low = Math.Min(open, close) * (1.0 - rnd2 * 0.01);
|
||||
double high = Math.Max(open, close) * (1.0 + (rnd1 * 0.01));
|
||||
double low = Math.Min(open, close) * (1.0 - (rnd2 * 0.01));
|
||||
|
||||
// Ensure valid OHLC constraints
|
||||
high = Math.Max(high, Math.Max(open, close));
|
||||
@@ -451,7 +451,7 @@ public sealed class GBM : IFeed
|
||||
|
||||
h[i] = high;
|
||||
l[i] = low;
|
||||
v[i] = 1000 + rnd3 * 1000;
|
||||
v[i] = 1000 + (rnd3 * 1000);
|
||||
|
||||
currentPrice = price;
|
||||
currentTime += timeStep;
|
||||
|
||||
@@ -79,7 +79,7 @@ public sealed class BaxterKing : AbstractBase
|
||||
_pLow = pLow;
|
||||
_pHigh = pHigh;
|
||||
_k = k;
|
||||
_filterLen = 2 * k + 1;
|
||||
_filterLen = (2 * k) + 1;
|
||||
|
||||
Name = $"BaxterKing({pLow},{pHigh},{k})";
|
||||
WarmupPeriod = _filterLen;
|
||||
@@ -218,7 +218,7 @@ public sealed class BaxterKing : AbstractBase
|
||||
{
|
||||
double a = 2.0 * Math.PI / pHigh; // low cutoff angular frequency
|
||||
double b = 2.0 * Math.PI / pLow; // high cutoff angular frequency
|
||||
int filterLen = 2 * k + 1;
|
||||
int filterLen = (2 * k) + 1;
|
||||
|
||||
// Compute ideal band-pass weights B[j] for j = 0..K
|
||||
// B_0 = (b - a) / pi
|
||||
@@ -266,7 +266,7 @@ public sealed class BaxterKing : AbstractBase
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output,
|
||||
int pLow = 6, int pHigh = 32, int k = 12)
|
||||
{
|
||||
int filterLen = 2 * k + 1;
|
||||
int filterLen = (2 * k) + 1;
|
||||
double[] weights = new double[filterLen];
|
||||
ComputeWeights(weights, pLow, pHigh, k);
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ public sealed class Bilateral : AbstractBase
|
||||
// Use Math.Max(0, ...) to handle potential floating point negative zero
|
||||
// Pre-compute inverse for efficiency
|
||||
double invCount = 1.0 / count;
|
||||
double variance = Math.Max(0, (_state.SumSq - sum * sum * invCount) * invCount);
|
||||
double variance = Math.Max(0, (_state.SumSq - (sum * sum * invCount)) * invCount);
|
||||
double stdev = Math.Sqrt(variance);
|
||||
|
||||
double sigmaR = Math.Max(stdev * _sigmaRMult, 1e-10);
|
||||
@@ -437,7 +437,7 @@ public sealed class Bilateral : AbstractBase
|
||||
|
||||
// Calculate StDev
|
||||
double invCount = 1.0 / count;
|
||||
double variance = Math.Max(0, (sumSq - sum * sum * invCount) * invCount);
|
||||
double variance = Math.Max(0, (sumSq - (sum * sum * invCount)) * invCount);
|
||||
double stdev = Math.Sqrt(variance);
|
||||
|
||||
double sigmaR = Math.Max(stdev * sigmaRMult, 1e-10);
|
||||
|
||||
@@ -267,7 +267,7 @@ public sealed class Loess : AbstractBase
|
||||
dist = 0.9999;
|
||||
}
|
||||
|
||||
double t = 1.0 - dist * dist * dist;
|
||||
double t = 1.0 - (dist * dist * dist);
|
||||
double w = t * t * t;
|
||||
|
||||
double xi = i - halfWindow;
|
||||
@@ -277,7 +277,7 @@ public sealed class Loess : AbstractBase
|
||||
x2Sum += xi * xi * w;
|
||||
}
|
||||
|
||||
double delta = weightSum * x2Sum - xSum * xSum;
|
||||
double delta = (weightSum * x2Sum) - (xSum * xSum);
|
||||
if (Math.Abs(delta) < double.Epsilon)
|
||||
{
|
||||
delta = 1.0;
|
||||
@@ -293,12 +293,12 @@ public sealed class Loess : AbstractBase
|
||||
dist = 0.9999;
|
||||
}
|
||||
|
||||
double t = 1.0 - dist * dist * dist;
|
||||
double t = 1.0 - (dist * dist * dist);
|
||||
double w = t * t * t;
|
||||
double xi = i - halfWindow;
|
||||
|
||||
double term1 = x2Sum - xi * xSum;
|
||||
double term2 = targetX * (xi * weightSum - xSum);
|
||||
double term1 = x2Sum - (xi * xSum);
|
||||
double term2 = targetX * ((xi * weightSum) - xSum);
|
||||
|
||||
double kValue = (w / delta) * (term1 + term2);
|
||||
|
||||
|
||||
@@ -349,7 +349,7 @@ public sealed class AfirmaValidationTests : IDisposable
|
||||
// Build state well past warmup
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + i * 0.5));
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + (i * 0.5)));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -316,7 +316,7 @@ public sealed class Afirma : AbstractBase
|
||||
// Calculation in loop for clarity or formula:
|
||||
double dn = (double)n;
|
||||
sx = (dn - 1.0) * dn * 0.5;
|
||||
sx2 = (dn - 1.0) * dn * (2.0 * dn - 1.0) / 6.0;
|
||||
sx2 = (dn - 1.0) * dn * ((2.0 * dn) - 1.0) / 6.0;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
@@ -328,11 +328,11 @@ public sealed class Afirma : AbstractBase
|
||||
sxy += i * val;
|
||||
}
|
||||
|
||||
double denom = dn * sx2 - sx * sx;
|
||||
double denom = (dn * sx2) - (sx * sx);
|
||||
if (Math.Abs(denom) > 1e-10)
|
||||
{
|
||||
double slope = (dn * sxy - sx * sy) / denom;
|
||||
double intercept = (sy - slope * sx) / dn;
|
||||
double slope = ((dn * sxy) - (sx * sy)) / denom;
|
||||
double intercept = (sy - (slope * sx)) / dn;
|
||||
|
||||
double lsSum = 0.0;
|
||||
double lsCount = 0.0;
|
||||
@@ -345,7 +345,7 @@ public sealed class Afirma : AbstractBase
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// Use fitted value (intercept + slope * i) for i < n, otherwise use original from buffer
|
||||
double val = i < n ? intercept + slope * i : _buffer[count - 1 - i];
|
||||
double val = i < n ? intercept + (slope * i) : _buffer[count - 1 - i];
|
||||
lsSum += val;
|
||||
lsCount++;
|
||||
}
|
||||
@@ -390,7 +390,7 @@ public sealed class Afirma : AbstractBase
|
||||
for (int k = 0; k < _period; k++)
|
||||
{
|
||||
double kTwoPiDivP = k * twoPiDivP;
|
||||
double coef = a0 + a1 * Math.Cos(kTwoPiDivP);
|
||||
double coef = a0 + (a1 * Math.Cos(kTwoPiDivP));
|
||||
if (Math.Abs(a2) > 1e-9)
|
||||
{
|
||||
coef += a2 * Math.Cos(2.0 * kTwoPiDivP);
|
||||
@@ -475,7 +475,7 @@ public sealed class Afirma : AbstractBase
|
||||
for (int k = 0; k < period; k++)
|
||||
{
|
||||
double kTwoPiDivP = k * twoPiDivP;
|
||||
double coef = a0 + a1 * Math.Cos(kTwoPiDivP);
|
||||
double coef = a0 + (a1 * Math.Cos(kTwoPiDivP));
|
||||
if (Math.Abs(a2) > 1e-9)
|
||||
{
|
||||
coef += a2 * Math.Cos(2.0 * kTwoPiDivP);
|
||||
@@ -544,7 +544,7 @@ public sealed class Afirma : AbstractBase
|
||||
double sx = 0.0, sx2 = 0.0, sy = 0.0, sxy = 0.0;
|
||||
double dn = (double)n;
|
||||
sx = (dn - 1.0) * dn * 0.5;
|
||||
sx2 = (dn - 1.0) * dn * (2.0 * dn - 1.0) / 6.0;
|
||||
sx2 = (dn - 1.0) * dn * ((2.0 * dn) - 1.0) / 6.0;
|
||||
|
||||
for (int j = 0; j < n; j++)
|
||||
{
|
||||
@@ -555,11 +555,11 @@ public sealed class Afirma : AbstractBase
|
||||
sxy = Math.FusedMultiplyAdd(j, v, sxy);
|
||||
}
|
||||
|
||||
double denom = dn * sx2 - sx * sx;
|
||||
double denom = (dn * sx2) - (sx * sx);
|
||||
if (Math.Abs(denom) > 1e-10)
|
||||
{
|
||||
double slope = (dn * sxy - sx * sy) / denom;
|
||||
double intercept = (sy - slope * sx) / dn;
|
||||
double slope = ((dn * sxy) - (sx * sy)) / denom;
|
||||
double intercept = (sy - (slope * sx)) / dn;
|
||||
|
||||
double lsSum = 0.0;
|
||||
double lsCount = 0.0;
|
||||
|
||||
@@ -402,12 +402,12 @@ public sealed class CciValidationTests(ITestOutputHelper output) : IDisposable
|
||||
// Build state well past warmup
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
double p = 100.0 + i * 0.5;
|
||||
ind.Update(new TBar(t0 + i * TimeSpan.TicksPerSecond, p, p + 1, p - 1, p, 1000));
|
||||
double p = 100.0 + (i * 0.5);
|
||||
ind.Update(new TBar(t0 + (i * TimeSpan.TicksPerSecond), p, p + 1, p - 1, p, 1000));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
long anchorTime = t0 + 50 * TimeSpan.TicksPerSecond;
|
||||
long anchorTime = t0 + (50 * TimeSpan.TicksPerSecond);
|
||||
var anchorBar = new TBar(anchorTime, 125.0, 126.0, 124.0, 125.0, 1000);
|
||||
ind.Update(anchorBar, isNew: true);
|
||||
double anchorResult = ind.Last.Value;
|
||||
|
||||
@@ -248,7 +248,7 @@ public sealed class MacdValidationTests : IDisposable
|
||||
// Build state well past warmup
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + i * 0.5));
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + (i * 0.5)));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -129,7 +129,6 @@ public sealed class Macd : ITValuePublisher, IDisposable
|
||||
return new TSeries(t, v);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the indicator state using the provided series history.
|
||||
/// </summary>
|
||||
|
||||
@@ -248,8 +248,8 @@ public class PrsValidationTests
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
double basePrice = 100 * (1 + i * 0.05); // 5% growth
|
||||
double compPrice = 50 * (1 + i * 0.05); // 5% growth
|
||||
double basePrice = 100 * (1 + (i * 0.05)); // 5% growth
|
||||
double compPrice = 50 * (1 + (i * 0.05)); // 5% growth
|
||||
var result = prs.Update(basePrice, compPrice, true);
|
||||
results.Add(result.Value);
|
||||
}
|
||||
@@ -556,7 +556,7 @@ public class PrsValidationTests
|
||||
// Build state well past warmup
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
ind.Update(100.0 + i * 0.5, 98.0 + i * 0.5);
|
||||
ind.Update(100.0 + (i * 0.5), 98.0 + (i * 0.5));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -352,5 +352,4 @@ public sealed class Prs : AbstractBase
|
||||
TSeries results = Batch(baseSeries, compSeries, smoothPeriod);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -78,7 +78,6 @@ public class RsxValidationTests
|
||||
// Core RSX calculations (assuming price input as closing price):
|
||||
double f8 = 100 * price;
|
||||
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
lastF8 = f8;
|
||||
@@ -89,32 +88,32 @@ public class RsxValidationTests
|
||||
lastF8 = f8;
|
||||
|
||||
// First smoothing stage:
|
||||
f28 = ialpha * f28 + alpha * v8;
|
||||
f30 = alpha * f28 + ialpha * f30;
|
||||
double vC = 1.5 * f28 - 0.5 * f30;
|
||||
f28 = (ialpha * f28) + (alpha * v8);
|
||||
f30 = (alpha * f28) + (ialpha * f30);
|
||||
double vC = (1.5 * f28) - (0.5 * f30);
|
||||
// Second smoothing stage:
|
||||
f38 = ialpha * f38 + alpha * vC;
|
||||
f40 = alpha * f38 + ialpha * f40;
|
||||
double v10 = 1.5 * f38 - 0.5 * f40;
|
||||
f38 = (ialpha * f38) + (alpha * vC);
|
||||
f40 = (alpha * f38) + (ialpha * f40);
|
||||
double v10 = (1.5 * f38) - (0.5 * f40);
|
||||
// Third smoothing stage:
|
||||
f48 = ialpha * f48 + alpha * v10;
|
||||
f50 = alpha * f48 + ialpha * f50;
|
||||
double v14 = 1.5 * f48 - 0.5 * f50;
|
||||
f48 = (ialpha * f48) + (alpha * v10);
|
||||
f50 = (alpha * f48) + (ialpha * f50);
|
||||
double v14 = (1.5 * f48) - (0.5 * f50);
|
||||
// Repeat stages for absolute value (momentum magnitude):
|
||||
f58 = ialpha * f58 + alpha * Math.Abs(v8);
|
||||
f60 = alpha * f58 + ialpha * f60;
|
||||
double v18 = 1.5 * f58 - 0.5 * f60;
|
||||
f68 = ialpha * f68 + alpha * v18;
|
||||
f70 = alpha * f68 + ialpha * f70;
|
||||
double v1C = 1.5 * f68 - 0.5 * f70;
|
||||
f78 = ialpha * f78 + alpha * v1C;
|
||||
f80 = alpha * f78 + ialpha * f80;
|
||||
double v20 = 1.5 * f78 - 0.5 * f80;
|
||||
f58 = (ialpha * f58) + (alpha * Math.Abs(v8));
|
||||
f60 = (alpha * f58) + (ialpha * f60);
|
||||
double v18 = (1.5 * f58) - (0.5 * f60);
|
||||
f68 = (ialpha * f68) + (alpha * v18);
|
||||
f70 = (alpha * f68) + (ialpha * f70);
|
||||
double v1C = (1.5 * f68) - (0.5 * f70);
|
||||
f78 = (ialpha * f78) + (alpha * v1C);
|
||||
f80 = (alpha * f78) + (ialpha * f80);
|
||||
double v20 = (1.5 * f78) - (0.5 * f80);
|
||||
// Final RSX value:
|
||||
double rsx;
|
||||
if (v20 > 1e-10) // Avoid division by zero
|
||||
{
|
||||
double v4 = (v14 / v20 + 1.0) * 50.0;
|
||||
double v4 = ((v14 / v20) + 1.0) * 50.0;
|
||||
rsx = Math.Clamp(v4, 0.0, 100.0);
|
||||
}
|
||||
else
|
||||
@@ -152,7 +151,7 @@ public class RsxValidationTests
|
||||
// Build state well past warmup
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + i * 0.5));
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + (i * 0.5)));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -103,10 +103,10 @@ public class DecayIndicatorTests
|
||||
{
|
||||
indicator.HistoricalData.AddBar(
|
||||
now.AddMinutes(i),
|
||||
100 + i * 2,
|
||||
105 + i * 2,
|
||||
95 + i * 2,
|
||||
102 + i * 2);
|
||||
100 + (i * 2),
|
||||
105 + (i * 2),
|
||||
95 + (i * 2),
|
||||
102 + (i * 2));
|
||||
indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar));
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ public class DecayIndicatorTests
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
double price = 100 + i * 5;
|
||||
double price = 100 + (i * 5);
|
||||
indicator.HistoricalData.AddBar(now.AddMinutes(i), price, price + 2, price - 2, price);
|
||||
indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar));
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ public class DecayTests
|
||||
|
||||
for (int i = 0; i < largeSize; i++)
|
||||
{
|
||||
source[i] = 100.0 + i * 0.1;
|
||||
source[i] = 100.0 + (i * 0.1);
|
||||
}
|
||||
|
||||
Decay.Batch(source, output, TestPeriod);
|
||||
|
||||
@@ -331,7 +331,7 @@ public class DwtValidationTests
|
||||
// Build state well past warmup (WarmupPeriod = 2^4 = 16)
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + i * 0.5));
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + (i * 0.5)));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -440,9 +440,9 @@ public sealed class Dwt : AbstractBase
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static double Get(Span<double> b, int h, int c, int lag)
|
||||
{
|
||||
int idx = ((h - 1 - lag) % c + c) % c;
|
||||
int idx = (((h - 1 - lag) % c) + c) % c;
|
||||
int maxLag = c - 1;
|
||||
if (lag > maxLag) { idx = ((h - 1 - maxLag) % c + c) % c; }
|
||||
if (lag > maxLag) { idx = (((h - 1 - maxLag) % c) + c) % c; }
|
||||
return b[idx];
|
||||
}
|
||||
|
||||
|
||||
@@ -103,10 +103,10 @@ public class EdecayIndicatorTests
|
||||
{
|
||||
indicator.HistoricalData.AddBar(
|
||||
now.AddMinutes(i),
|
||||
100 + i * 2,
|
||||
105 + i * 2,
|
||||
95 + i * 2,
|
||||
102 + i * 2);
|
||||
100 + (i * 2),
|
||||
105 + (i * 2),
|
||||
95 + (i * 2),
|
||||
102 + (i * 2));
|
||||
indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar));
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ public class EdecayIndicatorTests
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
double price = 100 + i * 5;
|
||||
double price = 100 + (i * 5);
|
||||
indicator.HistoricalData.AddBar(now.AddMinutes(i), price, price + 2, price - 2, price);
|
||||
indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar));
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ public class EdecayTests
|
||||
|
||||
for (int i = 0; i < largeSize; i++)
|
||||
{
|
||||
source[i] = 100.0 + i * 0.1;
|
||||
source[i] = 100.0 + (i * 0.1);
|
||||
}
|
||||
|
||||
Edecay.Batch(source, output, TestPeriod);
|
||||
|
||||
@@ -53,7 +53,7 @@ public class FftValidationTests
|
||||
|
||||
for (int i = 0; i < windowSize * 3; i++)
|
||||
{
|
||||
double signal = 50.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / targetPeriod);
|
||||
double signal = 50.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / targetPeriod));
|
||||
indicator.Update(new TValue(time.AddMinutes(i), signal), true);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class FftValidationTests
|
||||
|
||||
for (int i = 0; i < windowSize * 4; i++)
|
||||
{
|
||||
double signal = 50.0 + 10.0 * Math.Sin(2.0 * Math.PI * i / targetPeriod);
|
||||
double signal = 50.0 + (10.0 * Math.Sin(2.0 * Math.PI * i / targetPeriod));
|
||||
indicator.Update(new TValue(time.AddMinutes(i), signal), true);
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ public class FftValidationTests
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + 10.0 * Math.Sin(2 * Math.PI * i / 8.0)));
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + (10.0 * Math.Sin(2 * Math.PI * i / 8.0))));
|
||||
}
|
||||
|
||||
var anchorTime = t0.AddSeconds(50);
|
||||
|
||||
@@ -84,7 +84,7 @@ public sealed class Fft : AbstractBase
|
||||
_hanning = new double[windowSize];
|
||||
for (int n = 0; n < windowSize; n++)
|
||||
{
|
||||
_hanning[n] = 0.5 - 0.5 * Math.Cos(twoPiOverN * n);
|
||||
_hanning[n] = 0.5 - (0.5 * Math.Cos(twoPiOverN * n));
|
||||
}
|
||||
|
||||
// Precompute bit-reversal permutation table
|
||||
@@ -262,7 +262,7 @@ public sealed class Fft : AbstractBase
|
||||
}
|
||||
|
||||
// Parabolic interpolation: shift = 0.5*(a-c)/(a - 2b + c)
|
||||
double denom = a - 2.0 * b + c;
|
||||
double denom = a - (2.0 * b) + c;
|
||||
double shift = Math.Abs(denom) > 0.0 ? 0.5 * (a - c) / denom : 0.0;
|
||||
double dominantPeriod = (double)_windowSize / (bestK + shift);
|
||||
|
||||
@@ -417,7 +417,7 @@ public sealed class Fft : AbstractBase
|
||||
{
|
||||
for (int n = 0; n < windowSize; n++)
|
||||
{
|
||||
hanning[n] = 0.5 - 0.5 * Math.Cos(twoPiOverN * n);
|
||||
hanning[n] = 0.5 - (0.5 * Math.Cos(twoPiOverN * n));
|
||||
bitRev[n] = BitReverse(n, log2N);
|
||||
}
|
||||
|
||||
@@ -476,7 +476,7 @@ public sealed class Fft : AbstractBase
|
||||
workIm[bestK + 1] * workIm[bestK + 1])
|
||||
: bestMag;
|
||||
|
||||
double denom = a - 2.0 * bestMag + c;
|
||||
double denom = a - (2.0 * bestMag) + c;
|
||||
double shift = Math.Abs(denom) > 0.0 ? 0.5 * (a - c) / denom : 0.0;
|
||||
double dominant = (double)windowSize / (bestK + shift);
|
||||
double clamped = Math.Clamp(dominant, minPeriod, maxPeriod);
|
||||
|
||||
@@ -73,7 +73,7 @@ public sealed class Ifft : AbstractBase
|
||||
_hanning = new double[windowSize];
|
||||
for (int n = 0; n < windowSize; n++)
|
||||
{
|
||||
_hanning[n] = 0.5 - 0.5 * Math.Cos(twoPiOverN * n);
|
||||
_hanning[n] = 0.5 - (0.5 * Math.Cos(twoPiOverN * n));
|
||||
}
|
||||
|
||||
// Precompute bit-reversal permutation table
|
||||
@@ -330,7 +330,7 @@ public sealed class Ifft : AbstractBase
|
||||
{
|
||||
for (int n = 0; n < windowSize; n++)
|
||||
{
|
||||
hanning[n] = 0.5 - 0.5 * Math.Cos(twoPiOverN * n);
|
||||
hanning[n] = 0.5 - (0.5 * Math.Cos(twoPiOverN * n));
|
||||
bitRev[n] = BitReverse(n, log2N);
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public sealed class QqeValidationTests
|
||||
// Strongly trending up
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
ind.Update(new TValue(DateTime.UtcNow.AddMinutes(i), 50.0 + i * 0.5));
|
||||
ind.Update(new TValue(DateTime.UtcNow.AddMinutes(i), 50.0 + (i * 0.5)));
|
||||
}
|
||||
|
||||
Assert.True(ind.IsHot);
|
||||
@@ -130,7 +130,7 @@ public sealed class QqeValidationTests
|
||||
// Strongly trending down
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
ind.Update(new TValue(DateTime.UtcNow.AddMinutes(i), 200.0 - i * 0.5));
|
||||
ind.Update(new TValue(DateTime.UtcNow.AddMinutes(i), 200.0 - (i * 0.5)));
|
||||
}
|
||||
|
||||
Assert.True(ind.IsHot);
|
||||
@@ -251,7 +251,7 @@ public sealed class QqeValidationTests
|
||||
// Build state well past warmup (WarmupPeriod ≈ 37)
|
||||
for (int i = 0; i < 60; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + i * 0.5));
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + (i * 0.5)));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -101,11 +101,11 @@ public sealed class Qqe : AbstractBase
|
||||
_sfAlpha = 2.0 / (smoothFactor + 1.0);
|
||||
_sfBeta = 1.0 - _sfAlpha;
|
||||
|
||||
int darPeriod = 2 * smoothFactor - 1;
|
||||
int darPeriod = (2 * smoothFactor) - 1;
|
||||
_darAlpha = 2.0 / (darPeriod + 1.0);
|
||||
_darBeta = 1.0 - _darAlpha;
|
||||
|
||||
WarmupPeriod = rsiPeriod + smoothFactor + darPeriod * 2;
|
||||
WarmupPeriod = rsiPeriod + smoothFactor + (darPeriod * 2);
|
||||
|
||||
_s = new State(
|
||||
Count: 0,
|
||||
@@ -168,7 +168,7 @@ public sealed class Qqe : AbstractBase
|
||||
double avgGain = s.RmaGain * cRma;
|
||||
double avgLoss = s.RmaLoss * cRma;
|
||||
double rs = avgLoss < Epsilon ? 100.0 : avgGain / avgLoss;
|
||||
double rsiVal = 100.0 - 100.0 / (1.0 + rs);
|
||||
double rsiVal = 100.0 - (100.0 / (1.0 + rs));
|
||||
|
||||
// ── Stage 2: EMA smooth of RSI (α = 2/(SF+1)) with §2 warmup → rsiMA ──
|
||||
s.RawRsiMa = Math.FusedMultiplyAdd(s.RawRsiMa, _sfBeta, rsiVal * _sfAlpha);
|
||||
|
||||
@@ -225,12 +225,12 @@ public sealed class SqueezeValidationTests
|
||||
// Build state well past warmup (WarmupPeriod = 20)
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
double p = 100.0 + i * 0.5;
|
||||
ind.Update(new TBar(t0 + i * TimeSpan.TicksPerSecond, p, p + 1, p - 1, p, 1000), isNew: true);
|
||||
double p = 100.0 + (i * 0.5);
|
||||
ind.Update(new TBar(t0 + (i * TimeSpan.TicksPerSecond), p, p + 1, p - 1, p, 1000), isNew: true);
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
long anchorTime = t0 + 50 * TimeSpan.TicksPerSecond;
|
||||
long anchorTime = t0 + (50 * TimeSpan.TicksPerSecond);
|
||||
var anchorBar = new TBar(anchorTime, 125.0, 126.0, 124.0, 125.0, 1000);
|
||||
ind.Update(anchorBar, isNew: true);
|
||||
double anchorMomentum = ind.Momentum;
|
||||
|
||||
@@ -213,7 +213,7 @@ public sealed class Squeeze : ITValuePublisher
|
||||
|
||||
int n = Math.Max(1, s.SmaCount);
|
||||
double smaVal = s.SmaSum / n;
|
||||
double variance = Math.Max(0.0, s.SmaSumSq / n - smaVal * smaVal);
|
||||
double variance = Math.Max(0.0, (s.SmaSumSq / n) - (smaVal * smaVal));
|
||||
double stddev = Math.Sqrt(variance);
|
||||
double bbUpper = Math.FusedMultiplyAdd(_bbMult, stddev, smaVal);
|
||||
double bbLower = Math.FusedMultiplyAdd(-_bbMult, stddev, smaVal);
|
||||
@@ -269,7 +269,7 @@ public sealed class Squeeze : ITValuePublisher
|
||||
if (!double.IsNaN(dl) && dl < lowest) { lowest = dl; }
|
||||
}
|
||||
double donMid = (highest + lowest) * 0.5;
|
||||
double delta = close - (donMid + smaVal) * 0.5;
|
||||
double delta = close - ((donMid + smaVal) * 0.5);
|
||||
|
||||
// ===== STAGE 5: Linear regression of delta over period (O(1) incremental) =====
|
||||
UpdateLrBuf(ref s, delta);
|
||||
@@ -277,16 +277,16 @@ public sealed class Squeeze : ITValuePublisher
|
||||
int pn = Math.Min(s.LrCount, _period);
|
||||
int startIdx = s.LrCount - pn;
|
||||
// Closed-form sums: ΣX and ΣX²
|
||||
double sumX = (double)pn * (2.0 * startIdx + pn - 1) * 0.5;
|
||||
double sumX = (double)pn * ((2.0 * startIdx) + pn - 1) * 0.5;
|
||||
double sumX2 = Math.FusedMultiplyAdd(
|
||||
pn, (double)startIdx * startIdx,
|
||||
Math.FusedMultiplyAdd(
|
||||
(double)startIdx * (pn - 1), pn,
|
||||
(double)(pn - 1) * pn * (2 * pn - 1) / 6.0));
|
||||
(double)(pn - 1) * pn * ((2 * pn) - 1) / 6.0));
|
||||
double denomX = Math.FusedMultiplyAdd(pn, sumX2, -(sumX * sumX));
|
||||
double slope = denomX == 0.0 ? 0.0
|
||||
: Math.FusedMultiplyAdd(pn, s.SumXY, -(sumX * s.SumY)) / denomX;
|
||||
double intercept = (s.SumY - slope * sumX) / pn;
|
||||
double intercept = (s.SumY - (slope * sumX)) / pn;
|
||||
double momentum = Math.FusedMultiplyAdd(slope, s.LrCount - 1, intercept);
|
||||
|
||||
_s = s;
|
||||
@@ -554,7 +554,7 @@ public sealed class Squeeze : ITValuePublisher
|
||||
|
||||
int n = Math.Max(1, smaCount);
|
||||
double smaVal = smaSum / n;
|
||||
double vari = Math.Max(0.0, smaSumSq / n - smaVal * smaVal);
|
||||
double vari = Math.Max(0.0, (smaSumSq / n) - (smaVal * smaVal));
|
||||
double sd = Math.Sqrt(vari);
|
||||
double bbUpper = Math.FusedMultiplyAdd(bbMult, sd, smaVal);
|
||||
double bbLower = Math.FusedMultiplyAdd(-bbMult, sd, smaVal);
|
||||
@@ -602,7 +602,7 @@ public sealed class Squeeze : ITValuePublisher
|
||||
if (!double.IsNaN(dl) && dl < lowest) { lowest = dl; }
|
||||
}
|
||||
double donMid = (highest + lowest) * 0.5;
|
||||
double delta = c - (donMid + smaVal) * 0.5;
|
||||
double delta = c - ((donMid + smaVal) * 0.5);
|
||||
|
||||
// Stage 5: LinReg incremental
|
||||
double oldLr = lrBuf[lrHead];
|
||||
@@ -620,16 +620,16 @@ public sealed class Squeeze : ITValuePublisher
|
||||
|
||||
int pn = Math.Min(lrCount, period);
|
||||
int startI = lrCount - pn;
|
||||
double sx = (double)pn * (2.0 * startI + pn - 1) * 0.5;
|
||||
double sx = (double)pn * ((2.0 * startI) + pn - 1) * 0.5;
|
||||
double sx2 = Math.FusedMultiplyAdd(
|
||||
pn, (double)startI * startI,
|
||||
Math.FusedMultiplyAdd(
|
||||
(double)startI * (pn - 1), pn,
|
||||
(double)(pn - 1) * pn * (2 * pn - 1) / 6.0));
|
||||
(double)(pn - 1) * pn * ((2 * pn) - 1) / 6.0));
|
||||
double denomX = Math.FusedMultiplyAdd(pn, sx2, -(sx * sx));
|
||||
double slope = denomX == 0.0 ? 0.0
|
||||
: Math.FusedMultiplyAdd(pn, sumXY, -(sx * sumY)) / denomX;
|
||||
double intc = (sumY - slope * sx) / pn;
|
||||
double intc = (sumY - (slope * sx)) / pn;
|
||||
double momentum = Math.FusedMultiplyAdd(slope, lrCount - 1, intc);
|
||||
|
||||
momOut[i] = momentum;
|
||||
|
||||
@@ -415,7 +415,7 @@ public sealed class StochrsiValidationTests : IDisposable
|
||||
// Build state well past warmup (WarmupPeriod ≈ 31)
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + i * 0.5));
|
||||
ind.Update(new TValue(t0.AddSeconds(i), 100.0 + (i * 0.5)));
|
||||
}
|
||||
|
||||
// Anchor bar
|
||||
|
||||
@@ -124,7 +124,6 @@ public sealed class Acf : AbstractBase
|
||||
double oldVal = _buffer.Oldest;
|
||||
_sum -= oldVal;
|
||||
_sumSq = Math.FusedMultiplyAdd(-oldVal, oldVal, _sumSq);
|
||||
|
||||
}
|
||||
|
||||
// Add new value
|
||||
|
||||
@@ -507,5 +507,4 @@ public sealed class Cointegration : AbstractBase
|
||||
|
||||
return (result, indicator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -357,5 +357,4 @@ public sealed class Correlation : AbstractBase
|
||||
|
||||
return (result, indicator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public sealed class Covariance : AbstractBase
|
||||
if (n >= 2)
|
||||
{
|
||||
// Standard covariance formula: (sumXY - sumX*sumY/n) / denom
|
||||
double numerator = _sumXY - (_sumX * _sumY) / n;
|
||||
double numerator = _sumXY - ((_sumX * _sumY) / n);
|
||||
double denominator = _isPopulation ? n : (n - 1);
|
||||
cov = numerator / denominator;
|
||||
}
|
||||
@@ -278,7 +278,7 @@ public sealed class Covariance : AbstractBase
|
||||
double n = i + 1;
|
||||
if (n >= 2)
|
||||
{
|
||||
double numerator = sumXY - (sumX * sumY) / n;
|
||||
double numerator = sumXY - ((sumX * sumY) / n);
|
||||
double denominator = isPopulation ? n : (n - 1);
|
||||
output[i] = numerator / denominator;
|
||||
}
|
||||
@@ -309,7 +309,7 @@ public sealed class Covariance : AbstractBase
|
||||
|
||||
sumX = sumX - oldX + x;
|
||||
sumY = sumY - oldY + y;
|
||||
sumXY = sumXY - oldX * oldY + x * y;
|
||||
sumXY = sumXY - (oldX * oldY) + (x * y);
|
||||
|
||||
bufferX[bufferIndex] = x;
|
||||
bufferY[bufferIndex] = y;
|
||||
@@ -320,7 +320,7 @@ public sealed class Covariance : AbstractBase
|
||||
}
|
||||
|
||||
double n = period;
|
||||
double numerator = sumXY - (sumX * sumY) / n;
|
||||
double numerator = sumXY - ((sumX * sumY) / n);
|
||||
double denominator = isPopulation ? n : (n - 1);
|
||||
output[i] = numerator / denominator;
|
||||
|
||||
@@ -364,7 +364,7 @@ public sealed class Covariance : AbstractBase
|
||||
double n = i + 1;
|
||||
if (n >= 2)
|
||||
{
|
||||
double num = sumXY - (sumX * sumY) / n;
|
||||
double num = sumXY - ((sumX * sumY) / n);
|
||||
double den = isPopulation ? n : (n - 1);
|
||||
Unsafe.Add(ref outRef, i) = num / den;
|
||||
}
|
||||
@@ -400,7 +400,7 @@ public sealed class Covariance : AbstractBase
|
||||
var vInvDenom = Vector256.Create(invDenom);
|
||||
var vZero = Vector256<double>.Zero;
|
||||
|
||||
int simdEnd = period + ((len - period) / VectorWidth) * VectorWidth;
|
||||
int simdEnd = period + (((len - period) / VectorWidth) * VectorWidth);
|
||||
int tickCount = period;
|
||||
|
||||
for (int i = period; i < simdEnd; i += VectorWidth)
|
||||
@@ -513,9 +513,9 @@ public sealed class Covariance : AbstractBase
|
||||
|
||||
sumX = sumX - oldX + x;
|
||||
sumY = sumY - oldY + y;
|
||||
sumXY = sumXY - oldX * oldY + x * y;
|
||||
sumXY = sumXY - (oldX * oldY) + (x * y);
|
||||
|
||||
double numerator = sumXY - sumX * sumY * invN;
|
||||
double numerator = sumXY - (sumX * sumY * invN);
|
||||
Unsafe.Add(ref outRef, i) = numerator * invDenom;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ public sealed class Kurtosis : AbstractBase
|
||||
|
||||
// Second central moment (variance): m₂ = Σ(x-μ)²/n
|
||||
// = (SumSq - Sum²/n) / n
|
||||
double m2Numerator = _sumSq - (_sum * _sum) / n;
|
||||
double m2Numerator = _sumSq - ((_sum * _sum) / n);
|
||||
if (m2Numerator < Epsilon)
|
||||
{
|
||||
m2Numerator = 0;
|
||||
@@ -165,10 +165,10 @@ public sealed class Kurtosis : AbstractBase
|
||||
// m₄ = SumQu/n - 4·mean·SumCu/n + 6·mean²·SumSq/n - 3·mean⁴
|
||||
// Note: last term -4·mean³·Sum/n + mean⁴ = -4·mean⁴ + mean⁴ = -3·mean⁴
|
||||
double meanSq = mean * mean;
|
||||
double m4 = _sumQu / n
|
||||
- 4.0 * mean * _sumCu / n
|
||||
+ 6.0 * meanSq * _sumSq / n
|
||||
- 3.0 * meanSq * meanSq;
|
||||
double m4 = (_sumQu / n)
|
||||
- (4.0 * mean * _sumCu / n)
|
||||
+ (6.0 * meanSq * _sumSq / n)
|
||||
- (3.0 * meanSq * meanSq);
|
||||
|
||||
// Population excess kurtosis: g₂ = m₄/m₂² - 3
|
||||
double g2 = (m4 / (m2 * m2)) - 3.0;
|
||||
@@ -184,7 +184,7 @@ public sealed class Kurtosis : AbstractBase
|
||||
double denom = (n - 2.0) * (n - 3.0);
|
||||
if (Math.Abs(denom) > Epsilon)
|
||||
{
|
||||
kurtosis = ((n - 1.0) / denom) * ((n + 1.0) * g2 + 6.0);
|
||||
kurtosis = ((n - 1.0) / denom) * (((n + 1.0) * g2) + 6.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,7 +327,7 @@ public sealed class Kurtosis : AbstractBase
|
||||
{
|
||||
double mean = sum / n;
|
||||
|
||||
double m2Numerator = sumSq - (sum * sum) / n;
|
||||
double m2Numerator = sumSq - ((sum * sum) / n);
|
||||
if (m2Numerator < Epsilon)
|
||||
{
|
||||
return 0;
|
||||
@@ -342,10 +342,10 @@ public sealed class Kurtosis : AbstractBase
|
||||
|
||||
// Fourth central moment via raw moments
|
||||
double meanSq = mean * mean;
|
||||
double m4 = sumQu / n
|
||||
- 4.0 * mean * sumCu / n
|
||||
+ 6.0 * meanSq * sumSq / n
|
||||
- 3.0 * meanSq * meanSq;
|
||||
double m4 = (sumQu / n)
|
||||
- (4.0 * mean * sumCu / n)
|
||||
+ (6.0 * meanSq * sumSq / n)
|
||||
- (3.0 * meanSq * meanSq);
|
||||
|
||||
double g2 = (m4 / (m2 * m2)) - 3.0;
|
||||
|
||||
@@ -361,7 +361,7 @@ public sealed class Kurtosis : AbstractBase
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ((n - 1.0) / denom) * ((n + 1.0) * g2 + 6.0);
|
||||
return ((n - 1.0) / denom) * (((n + 1.0) * g2) + 6.0);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -415,8 +415,8 @@ public sealed class Kurtosis : AbstractBase
|
||||
double oldSq = oldVal * oldVal;
|
||||
sum = sum - oldVal + val;
|
||||
sumSq = sumSq - oldSq + valSq;
|
||||
sumCu = sumCu - oldSq * oldVal + valSq * val;
|
||||
sumQu = sumQu - oldSq * oldSq + valSq * valSq;
|
||||
sumCu = sumCu - (oldSq * oldVal) + (valSq * val);
|
||||
sumQu = sumQu - (oldSq * oldSq) + (valSq * valSq);
|
||||
|
||||
output[i] = CalculateKurtosisFromSums(sum, sumSq, sumCu, sumQu, period, isPopulation);
|
||||
|
||||
@@ -507,7 +507,7 @@ public sealed class Kurtosis : AbstractBase
|
||||
var vFisherNp1 = Vector256.Create(isPopulation ? 1.0 : fisherNp1);
|
||||
var vFisherAdd = Vector256.Create(fisherAdd);
|
||||
|
||||
int simdEnd = period + ((len - period) / VectorWidth) * VectorWidth;
|
||||
int simdEnd = period + (((len - period) / VectorWidth) * VectorWidth);
|
||||
int tickCount = period;
|
||||
|
||||
for (int i = period; i < simdEnd; i += VectorWidth)
|
||||
|
||||
@@ -103,7 +103,7 @@ public sealed class Skew : AbstractBase
|
||||
|
||||
// Calculate 2nd moment (Variance)
|
||||
// m2 = Sum((x-mean)^2) / n = (SumSq - Sum^2/n) / n
|
||||
double m2Numerator = _sumSq - (_sum * _sum) / n;
|
||||
double m2Numerator = _sumSq - ((_sum * _sum) / n);
|
||||
if (m2Numerator < Epsilon)
|
||||
{
|
||||
m2Numerator = 0;
|
||||
@@ -312,8 +312,8 @@ public sealed class Skew : AbstractBase
|
||||
}
|
||||
|
||||
sum = sum - oldVal + val;
|
||||
sumSq = sumSq - oldVal * oldVal + val * val;
|
||||
sumCu = sumCu - oldVal * oldVal * oldVal + val * val * val;
|
||||
sumSq = sumSq - (oldVal * oldVal) + (val * val);
|
||||
sumCu = sumCu - (oldVal * oldVal * oldVal) + (val * val * val);
|
||||
|
||||
output[i] = CalculateSkewFromSums(sum, sumSq, sumCu, period, isPopulation);
|
||||
|
||||
@@ -349,7 +349,7 @@ public sealed class Skew : AbstractBase
|
||||
{
|
||||
double mean = sum / n;
|
||||
|
||||
double m2Numerator = sumSq - (sum * sum) / n;
|
||||
double m2Numerator = sumSq - ((sum * sum) / n);
|
||||
if (m2Numerator < Epsilon)
|
||||
{
|
||||
return 0;
|
||||
@@ -422,7 +422,7 @@ public sealed class Skew : AbstractBase
|
||||
var vEpsilon = Vector256.Create(Epsilon);
|
||||
var vZero = Vector256<double>.Zero;
|
||||
|
||||
int simdEnd = period + ((len - period) / VectorWidth) * VectorWidth;
|
||||
int simdEnd = period + (((len - period) / VectorWidth) * VectorWidth);
|
||||
int tickCount = period;
|
||||
|
||||
for (int i = period; i < simdEnd; i += VectorWidth)
|
||||
|
||||
@@ -237,7 +237,7 @@ public sealed class Spearman : AbstractBase
|
||||
}
|
||||
|
||||
// Average rank: 1-based position = countSmaller + (countEqual - 1) / 2.0 + 1
|
||||
ranks[i] = countSmaller + (countEqual - 1) * 0.5 + 1.0;
|
||||
ranks[i] = countSmaller + ((countEqual - 1) * 0.5) + 1.0;
|
||||
}
|
||||
}
|
||||
/// <summary>Not supported. This indicator requires two input spans.</summary>
|
||||
|
||||
@@ -97,7 +97,7 @@ public sealed class Variance : AbstractBase
|
||||
// Using Sum:
|
||||
// Var = (SumSq - (Sum*Sum)/N) / ...
|
||||
|
||||
double numerator = _sumSq - (_buffer.Sum * _buffer.Sum) / n;
|
||||
double numerator = _sumSq - ((_buffer.Sum * _buffer.Sum) / n);
|
||||
|
||||
// Handle floating point noise
|
||||
if (numerator < 0)
|
||||
@@ -271,7 +271,7 @@ public sealed class Variance : AbstractBase
|
||||
double n = i + 1;
|
||||
if (n > 1)
|
||||
{
|
||||
double numerator = sumSq - (sum * sum) / n;
|
||||
double numerator = sumSq - ((sum * sum) / n);
|
||||
if (numerator < 0)
|
||||
{
|
||||
numerator = 0;
|
||||
@@ -310,7 +310,7 @@ public sealed class Variance : AbstractBase
|
||||
}
|
||||
|
||||
double n = period;
|
||||
double numerator = sumSq - (sum * sum) / n;
|
||||
double numerator = sumSq - ((sum * sum) / n);
|
||||
if (numerator < 0)
|
||||
{
|
||||
numerator = 0;
|
||||
@@ -343,7 +343,7 @@ public sealed class Variance : AbstractBase
|
||||
double n = i + 1;
|
||||
if (n > 1)
|
||||
{
|
||||
double num = sumSq - (sum * sum) / n;
|
||||
double num = sumSq - ((sum * sum) / n);
|
||||
if (num < 0)
|
||||
{
|
||||
num = 0;
|
||||
@@ -382,7 +382,7 @@ public sealed class Variance : AbstractBase
|
||||
var vInvDenom = Vector512.Create(invDenom);
|
||||
var vZero = Vector512<double>.Zero;
|
||||
|
||||
int simdEnd = period + ((len - period) / VectorWidth) * VectorWidth;
|
||||
int simdEnd = period + (((len - period) / VectorWidth) * VectorWidth);
|
||||
int tickCount = period;
|
||||
|
||||
for (int i = period; i < simdEnd; i += VectorWidth)
|
||||
@@ -465,7 +465,7 @@ public sealed class Variance : AbstractBase
|
||||
sumSq = Math.FusedMultiplyAdd(-oldVal, oldVal, sumSq);
|
||||
sumSq = Math.FusedMultiplyAdd(val, val, sumSq);
|
||||
|
||||
double numerator = sumSq - sum * sum * invN;
|
||||
double numerator = sumSq - (sum * sum * invN);
|
||||
if (numerator < 0)
|
||||
{
|
||||
numerator = 0;
|
||||
@@ -498,7 +498,7 @@ public sealed class Variance : AbstractBase
|
||||
var vInvDenom = Vector128.Create(invDenom);
|
||||
var vZero = Vector128<double>.Zero;
|
||||
|
||||
int simdEnd = period + ((len - period) / VectorWidth) * VectorWidth;
|
||||
int simdEnd = period + (((len - period) / VectorWidth) * VectorWidth);
|
||||
int tickCount = period;
|
||||
|
||||
for (int i = period; i < simdEnd; i += VectorWidth)
|
||||
@@ -569,7 +569,7 @@ public sealed class Variance : AbstractBase
|
||||
sumSq = Math.FusedMultiplyAdd(-oldVal, oldVal, sumSq);
|
||||
sumSq = Math.FusedMultiplyAdd(val, val, sumSq);
|
||||
|
||||
double numerator = sumSq - sum * sum * invN;
|
||||
double numerator = sumSq - (sum * sum * invN);
|
||||
if (numerator < 0)
|
||||
{
|
||||
numerator = 0;
|
||||
@@ -602,7 +602,7 @@ public sealed class Variance : AbstractBase
|
||||
var vInvDenom = Vector256.Create(invDenom);
|
||||
var vZero = Vector256<double>.Zero;
|
||||
|
||||
int simdEnd = period + ((len - period) / VectorWidth) * VectorWidth;
|
||||
int simdEnd = period + (((len - period) / VectorWidth) * VectorWidth);
|
||||
int tickCount = period;
|
||||
|
||||
for (int i = period; i < simdEnd; i += VectorWidth)
|
||||
@@ -693,7 +693,7 @@ public sealed class Variance : AbstractBase
|
||||
sumSq = Math.FusedMultiplyAdd(-oldVal, oldVal, sumSq);
|
||||
sumSq = Math.FusedMultiplyAdd(val, val, sumSq);
|
||||
|
||||
double numerator = sumSq - sum * sum * invN;
|
||||
double numerator = sumSq - (sum * sum * invN);
|
||||
if (numerator < 0)
|
||||
{
|
||||
numerator = 0;
|
||||
|
||||
@@ -255,8 +255,8 @@ public sealed class Nlma : AbstractBase
|
||||
else
|
||||
{
|
||||
// Cycle zone: t continues from 1 upward
|
||||
double numer = (double)(i - phase + 1) * (2 * Cycle - 1);
|
||||
double denom = (double)(Cycle * period - 1);
|
||||
double numer = (double)(i - phase + 1) * ((2 * Cycle) - 1);
|
||||
double denom = (double)((Cycle * period) - 1);
|
||||
t = 1.0 + (denom > 0 ? numer / denom : 0.0);
|
||||
}
|
||||
|
||||
|
||||
@@ -127,9 +127,9 @@ public class RviTests
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
var time = DateTime.UtcNow.AddSeconds(i);
|
||||
double close = 100.0 + Math.Sin(i * 0.5) * 3.0; // oscillating
|
||||
double high = close + 2.0 + Math.Sin(i * 0.3) * 1.5; // asymmetric highs
|
||||
double low = close - 1.0 - Math.Cos(i * 0.7) * 0.8; // asymmetric lows
|
||||
double close = 100.0 + (Math.Sin(i * 0.5) * 3.0); // oscillating
|
||||
double high = close + 2.0 + (Math.Sin(i * 0.3) * 1.5); // asymmetric highs
|
||||
double low = close - 1.0 - (Math.Cos(i * 0.7) * 0.8); // asymmetric lows
|
||||
|
||||
rviBar.Update(new TBar(time, close - 0.5, high, low, close, 1000));
|
||||
rviClose.Update(new TValue(time, close));
|
||||
@@ -267,7 +267,7 @@ public class RviTests
|
||||
// Build up some history
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
rvi.Update(new TValue(time.AddSeconds(i), 100.0 + i * 0.1), isNew: true);
|
||||
rvi.Update(new TValue(time.AddSeconds(i), 100.0 + (i * 0.1)), isNew: true);
|
||||
}
|
||||
|
||||
_ = rvi.Last; // Capture state before update
|
||||
@@ -291,7 +291,7 @@ public class RviTests
|
||||
// Build history
|
||||
for (int i = 0; i < 30; i++)
|
||||
{
|
||||
rvi.Update(new TValue(time.AddSeconds(i), 100.0 + i * 0.5), isNew: true);
|
||||
rvi.Update(new TValue(time.AddSeconds(i), 100.0 + (i * 0.5)), isNew: true);
|
||||
}
|
||||
|
||||
// Start a new bar
|
||||
@@ -648,7 +648,7 @@ public class RviTests
|
||||
var source = new TSeries();
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
source.Add(new TValue(DateTime.UtcNow.AddSeconds(i), 100.0 + i * 0.5));
|
||||
source.Add(new TValue(DateTime.UtcNow.AddSeconds(i), 100.0 + (i * 0.5)));
|
||||
}
|
||||
|
||||
var result = Rvi.Batch(source, stdevLength: 10, rmaLength: 14);
|
||||
@@ -665,7 +665,7 @@ public class RviTests
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
var time = DateTime.UtcNow.AddSeconds(i);
|
||||
double price = 100.0 + i * 0.5;
|
||||
double price = 100.0 + (i * 0.5);
|
||||
source.Add(new TBar(time, price - 1, price + 1, price - 2, price, 1000));
|
||||
}
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ public class RviValidationTests
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
rvi.Update(new TValue(DateTime.UtcNow.AddMinutes(i), 100.0 + i * 0.5));
|
||||
rvi.Update(new TValue(DateTime.UtcNow.AddMinutes(i), 100.0 + (i * 0.5)));
|
||||
}
|
||||
|
||||
Assert.True(rvi.Last.Value > 80.0, $"Strictly rising prices should produce high RVI, got {rvi.Last.Value}");
|
||||
@@ -183,7 +183,7 @@ public class RviValidationTests
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
rvi.Update(new TValue(DateTime.UtcNow.AddMinutes(i), 100.0 - i * 0.5));
|
||||
rvi.Update(new TValue(DateTime.UtcNow.AddMinutes(i), 100.0 - (i * 0.5)));
|
||||
}
|
||||
|
||||
Assert.True(rvi.Last.Value < 20.0, $"Strictly falling prices should produce low RVI, got {rvi.Last.Value}");
|
||||
@@ -486,7 +486,7 @@ public class RviValidationTests
|
||||
// Multiple corrections on same price
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var tempPrice = new TValue(prices[29].Time, prices[29].Value * (1.0 + j * 0.01));
|
||||
var tempPrice = new TValue(prices[29].Time, prices[29].Value * (1.0 + (j * 0.01)));
|
||||
rvi.Update(tempPrice, isNew: false);
|
||||
}
|
||||
|
||||
@@ -575,7 +575,7 @@ public class RviValidationTests
|
||||
// Symmetric oscillation
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
double price = 100.0 + Math.Sin(i * 0.1) * 5; // Oscillating ±5
|
||||
double price = 100.0 + (Math.Sin(i * 0.1) * 5); // Oscillating ±5
|
||||
rvi.Update(new TValue(DateTime.UtcNow.AddMinutes(i), price));
|
||||
}
|
||||
|
||||
@@ -621,5 +621,4 @@ public class RviValidationTests
|
||||
double mean = values.Average();
|
||||
return values.Average(v => Math.Pow(v - mean, 2));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -269,7 +269,6 @@ public sealed class Vwma : ITValuePublisher
|
||||
return Last;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the indicator state using the provided bar series history.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user