This commit is contained in:
Miha Kralj
2024-10-11 20:21:57 -07:00
committed by GitHub
97 changed files with 3762 additions and 339 deletions
+12 -8
View File
@@ -13,7 +13,7 @@
<PackageReference Include="xunit.runner.console" Version="2.9.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
@@ -25,15 +25,19 @@
<PackageReference Include="TALib.NETCore" Version="0.4.4" />
<PackageReference Include="Tulip.NETCore" Version="0.8.0.1" />
<PackageReference Include="Trady.Analysis" Version="3.2.8" />
<!--
<PackageReference Include="quantconnect.indicators" Version="2.5.16573" />
<PackageReference Include="stocksharp.algo" Version="5.0.193" />
<PackageReference Include="OoplesFinance.StockIndicators" Version="1.0.53" />
-->
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\lib\quantalib.csproj" />
<Reference Include="TradingPlatform.BusinessLayer">
<HintPath>..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
</Reference>
<None Include="..\.github\TradingPlatform.BusinessLayer.xml">
<Link>TradingPlatform.BusinessLayer.xml</Link>
</None>
</ItemGroup>
</Project>
<ItemGroup>
<ProjectReference Include="..\quantower\**\*.csproj" />
</ItemGroup>
</Project>
+21 -3
View File
@@ -8,7 +8,7 @@ namespace QuanTAlib;
public class EventingTests
{
[Fact]
public void VerifyEventBasedCalculations()
public void EventBasedCalculations()
{
// Create a cryptographically secure random number generator
using var rng = RandomNumberGenerator.Create();
@@ -28,6 +28,7 @@ public class EventingTests
("Dwma", new Dwma(p), new Dwma(input, p)),
("Ema", new Ema(p), new Ema(input, p)),
("Epma", new Epma(p), new Epma(input, p)),
("Pwma", new Pwma(p), new Pwma(input, p)),
("Frama", new Frama(p), new Frama(input, p)),
("Fwma", new Fwma(p), new Fwma(input, p)),
("Gma", new Gma(p), new Gma(input, p)),
@@ -49,7 +50,24 @@ public class EventingTests
("Rma", new Rma(p), new Rma(input, p)),
("Tema", new Tema(p), new Tema(input, p)),
("Kama", new Kama(2, 30, 6), new Kama(input, 2, 30, 6)),
("Zlema", new Zlema(p), new Zlema(input, p))
("Zlema", new Zlema(p), new Zlema(input, p)),
// error classes
("Mae", new Mae(p), new Mae(input, p)),
("Mapd", new Mapd(p), new Mapd(input, p)),
("Mape", new Mape(p), new Mape(input, p)),
("Mase", new Mase(p), new Mase(input, p)),
("Mda", new Mda(p), new Mda(input, p)),
("Me", new Me(p), new Me(input, p)),
("Mpe", new Mpe(p), new Mpe(input, p)),
("Mse", new Mse(p), new Mse(input, p)),
("Msle", new Msle(p), new Msle(input, p)),
("Rae", new Rae(p), new Rae(input, p)),
("Rmse", new Rmse(p), new Rmse(input, p)),
("Rmsle", new Rmsle(p), new Rmsle(input, p)),
("Rse", new Rse(p), new Rse(input, p)),
("Smape", new Smape(p), new Smape(input, p)),
("Rsquared", new Rsquared(p), new Rsquared(input, p)),
("Huberloss", new Huberloss(p), new Huberloss(input, p))
};
// Generate 200 random values and feed them to both direct and event-based indicators
@@ -81,4 +99,4 @@ public class EventingTests
rng.GetBytes(bytes);
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue;
}
}
}
-157
View File
@@ -1,157 +0,0 @@
using Xunit;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
namespace QuanTAlib;
public class IndicatorTests
{
private readonly RandomNumberGenerator rng;
private const int SeriesLen = 1000;
private const int Corrections = 100;
public IndicatorTests()
{
rng = RandomNumberGenerator.Create();
}
private int GetRandomNumber(int minValue, int maxValue)
{
byte[] randomBytes = new byte[4];
rng.GetBytes(randomBytes);
int randomInt = BitConverter.ToInt32(randomBytes, 0);
return Math.Abs(randomInt % (maxValue - minValue)) + minValue;
}
// skipcq: CS-R1055
private static readonly ITValue[] indicators =
{
new Ema(period: 10, useSma: true),
new Alma(period: 14, offset: 0.85, sigma: 6),
new Afirma(periods: 4, taps: 4, window: Afirma.WindowType.Blackman),
new Convolution(new[] { 1.0, 2, 3, 2, 1 }),
new Dema(period: 14),
new Dsma(period: 14),
new Dwma(period: 14),
new Epma(period: 14),
new Frama(period: 14),
new Fwma(period: 14),
new Gma(period: 14),
new Hma(period: 14),
new Hwma(period: 14),
new Kama(period: 14),
new Mama(fastLimit: 0.5, slowLimit: 0.05),
new Mgdi(period: 14),
new Mma(period: 14),
new Qema(),
new Rema(period: 14),
new Rma(period: 14),
new Sinema(period: 14),
new Sma(period: 14),
new Smma(period: 14),
new T3(period: 14),
new Tema(period: 14),
new Trima(period: 14),
new Vidya(shortPeriod: 14, longPeriod: 30, alpha: 0.2),
new Wma(period: 14),
new Zlema(period: 14),
new Curvature(period: 14),
new Entropy(period: 14),
new Kurtosis(period: 14),
new Max(period: 14, decay: 0.01),
new Median(period: 14),
new Min(period: 14, decay: 0.01),
new Median(period: 14),
new Mode(period: 14),
new Percentile(period: 14, percent: 50),
new Skew(period: 14),
new Slope(period: 14),
new Stddev(period: 14),
new Variance(period: 14),
new Zscore(period: 14),
new Historical(period: 14),
new Realized(period: 14)
};
[Theory]
[MemberData(nameof(GetIndicators))]
public void IndicatorIsNew(ITValue indicator)
{
var indicator1 = indicator;
var indicator2 = indicator;
MethodInfo calcMethod = FindCalcMethod(indicator.GetType());
if (calcMethod == null)
{
throw new InvalidOperationException($"Calc method not found for indicator type: {indicator.GetType().Name}");
}
for (int i = 0; i < SeriesLen; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: GetRandomNumber(-100, 100), IsNew: true);
InvokeCalc(indicator1, calcMethod, item1);
for (int j = 0; j < Corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: GetRandomNumber(-100, 100), IsNew: false);
InvokeCalc(indicator1, calcMethod, item1);
}
var item2 = new TValue(item1.Time, item1.Value, IsNew: true);
InvokeCalc(indicator2, calcMethod, item2);
Assert.Equal(indicator1.Value, indicator2.Value);
}
}
private static MethodInfo FindCalcMethod(Type type)
{
while (type != null && type != typeof(object))
{
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Where(m => m.Name == "Calc")
.ToList();
if (methods.Count > 0)
{
// Prefer the method with TValue parameter
var method = methods.FirstOrDefault(m =>
{
var parameters = m.GetParameters();
return parameters.Length == 1 && parameters[0].ParameterType == typeof(TValue);
});
// If not found, return the first method
return method ?? methods.First();
}
type = type.BaseType!;
}
return null!;
}
private static void InvokeCalc(ITValue indicator, MethodInfo calcMethod, TValue input)
{
var parameters = calcMethod.GetParameters();
if (parameters.Length == 1)
{
calcMethod.Invoke(indicator, new object[] { input });
}
else if (parameters.Length == 2)
{
calcMethod.Invoke(indicator, new object[] { input, double.NaN });
}
else
{
throw new InvalidOperationException($"Invalid number of parameters for Calc method in indicator type: {indicator.GetType().Name}");
}
}
public static IEnumerable<object[]> GetIndicators()
{
return indicators.Select(indicator => new object[] { indicator });
}
}
+94
View File
@@ -0,0 +1,94 @@
using Xunit;
using System;
using System.Reflection;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib
{
public class QuantowerTests
{
private void TestIndicator<T>(string fieldName = "ma") where T : Indicator, new()
{
var indicator = new T();
try
{
var onInitMethod = typeof(T).GetMethod("OnInit", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(onInitMethod);
onInitMethod.Invoke(indicator, null);
var field = typeof(T).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(field);
var fieldValue = field.GetValue(indicator);
Assert.NotNull(fieldValue);
Assert.NotNull(indicator.ShortName);
Assert.NotEmpty(indicator.ShortName);
Assert.NotNull(indicator.Name);
Assert.NotEmpty(indicator.Name);
Assert.NotNull(indicator.Description);
Assert.NotEmpty(indicator.Description);
Assert.IsAssignableFrom<Indicator>(indicator);
}
catch (Exception ex)
{
throw new Xunit.Sdk.XunitException($"Test failed for {typeof(T).Name}: {ex.Message}");
}
}
// Averages Indicators
[Fact] public void Afirma() => TestIndicator<AfirmaIndicator>();
[Fact] public void Alma() => TestIndicator<AlmaIndicator>();
[Fact] public void Dema() => TestIndicator<DemaIndicator>();
[Fact] public void Dsma() => TestIndicator<DsmaIndicator>();
[Fact] public void Dwma() => TestIndicator<DwmaIndicator>();
[Fact] public void Ema() => TestIndicator<EmaIndicator>();
[Fact] public void Epma() => TestIndicator<EpmaIndicator>();
[Fact] public void Frama() => TestIndicator<FramaIndicator>();
[Fact] public void Fwma() => TestIndicator<FwmaIndicator>();
[Fact] public void Gma() => TestIndicator<GmaIndicator>();
[Fact] public void Hma() => TestIndicator<HmaIndicator>();
[Fact] public void Htit() => TestIndicator<HtitIndicator>();
[Fact] public void Hwma() => TestIndicator<HwmaIndicator>();
[Fact] public void Jma() => TestIndicator<JmaIndicator>();
[Fact] public void Kama() => TestIndicator<KamaIndicator>();
[Fact] public void Ltma() => TestIndicator<LtmaIndicator>();
[Fact] public void Maaf() => TestIndicator<MaafIndicator>();
[Fact] public void Mama() => TestIndicator<MamaIndicator>();
[Fact] public void Mgdi() => TestIndicator<MgdiIndicator>();
[Fact] public void Mma() => TestIndicator<MmaIndicator>();
[Fact] public void Pwma() => TestIndicator<PwmaIndicator>();
[Fact] public void Qema() => TestIndicator<QemaIndicator>();
[Fact] public void Rema() => TestIndicator<RemaIndicator>();
[Fact] public void Rma() => TestIndicator<RmaIndicator>();
[Fact] public void Sinema() => TestIndicator<SinemaIndicator>();
[Fact] public void Sma() => TestIndicator<SmaIndicator>();
[Fact] public void Smma() => TestIndicator<SmmaIndicator>();
[Fact] public void T3() => TestIndicator<T3Indicator>();
[Fact] public void Tema() => TestIndicator<TemaIndicator>();
[Fact] public void Trima() => TestIndicator<TrimaIndicator>();
[Fact] public void Vidya() => TestIndicator<VidyaIndicator>();
[Fact] public void Wma() => TestIndicator<WmaIndicator>();
[Fact] public void Zlema() => TestIndicator<ZlemaIndicator>();
// Statistics Indicators
[Fact] public void Curvature() => TestIndicator<CurvatureIndicator>("curvature");
[Fact] public void Entropy() => TestIndicator<EntropyIndicator>("entropy");
[Fact] public void Kurtosis() => TestIndicator<KurtosisIndicator>("kurtosis");
[Fact] public void Max() => TestIndicator<MaxIndicator>("ma");
[Fact] public void Median() => TestIndicator<MedianIndicator>("med");
[Fact] public void Min() => TestIndicator<MinIndicator>("mi");
[Fact] public void Mode() => TestIndicator<ModeIndicator>("mode");
[Fact] public void Percentile() => TestIndicator<PercentileIndicator>("percentile");
[Fact] public void Skew() => TestIndicator<SkewIndicator>("skew");
[Fact] public void Slope() => TestIndicator<SlopeIndicator>("slope");
[Fact] public void Stddev() => TestIndicator<StddevIndicator>("stddev");
[Fact] public void Variance() => TestIndicator<VarianceIndicator>("variance");
[Fact] public void Zscore() => TestIndicator<ZScoreIndicator>("zScore");
// Volatility Indicators
[Fact] public void Atr() => TestIndicator<AtrIndicator>("atr");
[Fact] public void Historical() => TestIndicator<HistoricalIndicator>("historical");
[Fact] public void Realized() => TestIndicator<RealizedIndicator>("realized");
[Fact] public void Rvi() => TestIndicator<RviIndicator>("rvi");
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ using System.Security.Cryptography;
#pragma warning disable S1944, S2053, S2222, S2259, S2583, S2589, S3329, S3655, S3900, S3949, S3966, S4158, S4347, S5773, S6781
namespace QuanTAlib;
namespace QuanTAlib.Tests;
public class SkenderTests
{
-20
View File
@@ -109,26 +109,6 @@ public class TAlibTests
}
}
[Fact]
public void WMA()
{
for (int run = 0; run < iterations; run++)
{
int period = GetRandomNumber(5, 55);
Wma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
Core.Wma(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period);
Assert.Equal(QL.Length, TALIB.Count());
for (int i = QL.Length - 1; i > 2000; i--)
{
Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
}
[Fact]
public void T3()
{
+529
View File
@@ -0,0 +1,529 @@
using Xunit;
using System.Security.Cryptography;
namespace QuanTAlib.Tests;
public class AveragesUpdateTests
{
private readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
private const int RandomUpdates = 100;
private const double ReferenceValue = 100.0;
private const int precision = 8;
private double GetRandomDouble()
{
byte[] bytes = new byte[8];
rng.GetBytes(bytes);
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue * 200 - 100; // Range: -100 to 100
}
[Fact]
public void Afirma_Update()
{
var indicator = new Afirma(periods: 14, taps: 4, window: Afirma.WindowType.Blackman);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Alma_Update()
{
var indicator = new Alma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Convolution_Update()
{
var indicator = new Convolution(new double[] { 1, 2, 3, 2, 1 });
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Dema_Update()
{
var indicator = new Dema(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Dsma_Update()
{
var indicator = new Dsma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Dwma_Update()
{
var indicator = new Dwma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Ema_Update()
{
var indicator = new Ema(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Epma_Update()
{
var indicator = new Epma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Frama_Update()
{
var indicator = new Frama(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Fwma_Update()
{
var indicator = new Fwma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Gma_Update()
{
var indicator = new Gma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Hma_Update()
{
var indicator = new Hma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Htit_Update()
{
var indicator = new Htit();
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Hwma_Update()
{
var indicator = new Hwma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Jma_Update()
{
var indicator = new Jma(period: 14, phase: 0);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Kama_Update()
{
var indicator = new Kama(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Ltma_Update()
{
var indicator = new Ltma(gamma: 0.2);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Maaf_Update()
{
var indicator = new Maaf(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mama_Update()
{
var indicator = new Mama(fastLimit: 0.5, slowLimit: 0.05);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mgdi_Update()
{
var indicator = new Mgdi(period: 14, kFactor: 0.6);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mma_Update()
{
var indicator = new Mma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Pwma_Update()
{
var indicator = new Pwma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Qema_Update()
{
var indicator = new Qema(k1: 0.2, k2: 0.2, k3: 0.2, k4: 0.2);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rema_Update()
{
var indicator = new Rema(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rma_Update()
{
var indicator = new Rma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Sinema_Update()
{
var indicator = new Sinema(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Sma_Update()
{
var indicator = new Sma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Smma_Update()
{
var indicator = new Smma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void T3_Update()
{
var indicator = new T3(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Tema_Update()
{
var indicator = new Tema(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Trima_Update()
{
var indicator = new Trima(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Vidya_Update()
{
var indicator = new Vidya(shortPeriod: 14, longPeriod: 30, alpha: 0.2);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Wma_Update()
{
var indicator = new Wma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Zlema_Update()
{
var indicator = new Zlema(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
}
+259
View File
@@ -0,0 +1,259 @@
using Xunit;
using System.Security.Cryptography;
namespace QuanTAlib.Tests;
public class UpdateTests
{
private readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
private const int RandomUpdates = 100;
private const double ReferenceValue = 100.0;
private const int precision = 8;
private double GetRandomDouble()
{
byte[] bytes = new byte[8];
rng.GetBytes(bytes);
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue * 200 - 100; // Range: -100 to 100
}
[Fact]
public void Huberloss_Update()
{
var indicator = new Huberloss(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mae_Update()
{
var indicator = new Mae(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mapd_Update()
{
var indicator = new Mapd(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mape_Update()
{
var indicator = new Mape(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mase_Update()
{
var indicator = new Mase(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mda_Update()
{
var indicator = new Mda(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Me_Update()
{
var indicator = new Me(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mpe_Update()
{
var indicator = new Mpe(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mse_Update()
{
var indicator = new Mse(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Msle_Update()
{
var indicator = new Msle(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rae_Update()
{
var indicator = new Rae(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rmse_Update()
{
var indicator = new Rmse(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rmsle_Update()
{
var indicator = new Rmsle(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rse_Update()
{
var indicator = new Rse(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Smape_Update()
{
var indicator = new Smape(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rsquared_Update()
{
var indicator = new Rsquared(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
}
+214
View File
@@ -0,0 +1,214 @@
using Xunit;
using System.Security.Cryptography;
namespace QuanTAlib.Tests;
public class StatisticsUpdateTests
{
private readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
private const int RandomUpdates = 100;
private const double ReferenceValue = 100.0;
private const int precision = 8;
private double GetRandomDouble()
{
byte[] bytes = new byte[8];
rng.GetBytes(bytes);
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue * 200 - 100; // Range: -100 to 100
}
[Fact]
public void Curvature_Update()
{
var indicator = new Curvature(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Entropy_Update()
{
var indicator = new Entropy(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Kurtosis_Update()
{
var indicator = new Kurtosis(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Max_Update()
{
var indicator = new Max(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Median_Update()
{
var indicator = new Median(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Min_Update()
{
var indicator = new Min(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mode_Update()
{
var indicator = new Mode(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Percentile_Update()
{
var indicator = new Percentile(period: 14, percent: 50);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Skew_Update()
{
var indicator = new Skew(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Slope_Update()
{
var indicator = new Slope(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Stddev_Update()
{
var indicator = new Stddev(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Variance_Update()
{
var indicator = new Variance(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Zscore_Update()
{
var indicator = new Zscore(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
}
+17 -17
View File
@@ -13,7 +13,7 @@
|OHLC4 - Average Price|`.OHLC4`|CandlePart.OHLC4|AvgPrice||
|HLCC4 - Weighted Price|`.HLCC4`||WclPrice||
|<br>||||
|**STATISTICS AND NUMERICAL ANALYSIS**|**QuanTALib**|Skender.Stock|TALib.NETCore|Tulip.NETCore|Trady|
|**STATISTICS, ERRORS AND NUMERICAL ANALYSIS**|**QuanTALib**|Skender.Stock|TALib.NETCore|Tulip.NETCore|Trady|
|BETA - Beta coefficient|||||
|CORR - Correlation Coefficient|||||
|CURVATURE - Rate of Change in Direction or Slope|`Curvature`||||
@@ -21,28 +21,28 @@
|KURTOSIS - Measure of Tails/Peakedness|`Kurtosis`||||
|HUBER - Huber Loss|||||
|MAX - Maximum with exponential decay|`Max`||||
|MAE - Mean Absolute Error|||||
|MAPD - Mean Absolute Percentage Deviation|||||
|MAPE - Mean Absolute Percentage Error|||||
|MASE - Mean Absolute Scaled Error|||||
|MAE - Mean Absolute Error|`Mae`||||
|MAPD - Mean Absolute Percentage Deviation|`Mapd`||||
|MAPE - Mean Absolute Percentage Error|`Mape`||||
|MASE - Mean Absolute Scaled Error|`Mase`||||
|MDA - Mean Directional Accuracy|||||
|ME - Mean Error|||||
|ME - Mean Error|`Me`||||
|MEDIAN - Middle value|`Median`||||
|MIN - Minimum with exponential decay|`Min`||||
|MODE - Most Frequent Value|`Mode`||||
|MPE - Pean Percentage Error|||||
|MSE - Mean Squared Error|||||
|MSLE - Mean Squared Logarithmic Error|||||
|MPE - Pean Percentage Error|`Mpe`||||
|MSE - Mean Squared Error|`Mse`||||
|MSLE - Mean Squared Logarithmic Error|`Msle`||||
|PERCENTILE - Rank Order|`Percentile`||||
|RSQUARED - Coefficient of Determination R-Squared|||||
|RAE - Relative Absolute Error|||||
|RMSE - Root Mean Squared Error|||||
|RSE - Relateive Squared Error|||||
|RMSLE - Root Mean Squared Logarithmic Error|||||
|RAE - Relative Absolute Error|`Rae`||||
|RMSE - Root Mean Squared Error|`Rmse`||||
|RSE - Relateive Squared Error|`Rse`||||
|RMSLE - Root Mean Squared Logarithmic Error|`Rmsle`||||
|SKEW - Skewness, asymmetry of distribution|`Skew`||||
|SLOPE - Rate of Change, Linear Regression|`Slope`||||
|SMAPE - Symmetric Mean Absolute Percentage Error|||||
|STDDEV - Standard Deviation, Measure of Spread|||||
|SMAPE - Symmetric Mean Absolute Percentage Error|`Smape`||||
|STDDEV - Standard Deviation, Measure of Spread|`Stddev`||||
|THEIL - Theil's U Statistics|||||
|VARIANCE - Average of Squared Deviations|`Variance`||||
|ZSCORE - Standardized Score|`Zscore`||||
@@ -72,7 +72,7 @@
|MGDI - McGinley Dynamic Indicator|`Mgdi`|`✔️`|||
|MMA - Modified Moving Average|`Mma`||||
|PPMA - Pivot Point Moving Average|||||
|PWMA - Pascal's Weighted Moving Average|||||
|PWMA - Pascal's Weighted Moving Average|`Pwma`||||
|QEMA - Quad Exponential Moving Average|`Qema`||||
|RMA - WildeR's Moving Average|`Rma`||||
|SINEMA - Sine Weighted Moving Average|`Sinema`||||
@@ -87,7 +87,7 @@
|TSF - Time Series Forecast|||`✔️`|`✔️`|
|VIDYA - Variable Index Dynamic Average|`Vidya`|||`✔️`|
|VORTEX - Vortex Indicator||`✔️`|||
|WMA - Weighted Moving Average|`Wma`|`✔️`|`✔️`|`✔️`|
|WMA - Weighted Moving Average|`Wma`|`✔️`||`✔️`|
|ZLEMA - Zero Lag EMA Average|`Zlema`|||`✔️`|
|<br>||||
|**VOLATILITY INDICATORS**|**QuanTALib**|Skender.Stock|TALib.NETCore|Tulip.NETCore|Trady|
+6 -6
View File
@@ -14,18 +14,18 @@ public class Maaf : AbstractBase
private readonly int _period;
public Maaf(int Period = 39, double Threshold = 0.002)
public Maaf(int period = 39, double threshold = 0.002)
{
_period = Period;
_threshold = Threshold;
_period = period;
_threshold = threshold;
_priceBuffer = new CircularBuffer(4);
_smoothBuffer = new CircularBuffer(Period);
_smoothBuffer = new CircularBuffer(period);
Name = "MAAF";
WarmupPeriod = Period;
WarmupPeriod = period;
Init();
}
public Maaf(object source, int Period = 39, double Threshold = 0.002) : this(Period, Threshold)
public Maaf(object source, int period = 39, double threshold = 0.002) : this(period, threshold)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
+85
View File
@@ -0,0 +1,85 @@
namespace QuanTAlib;
public class Pwma : AbstractBase
{
private readonly int _period;
private readonly Convolution _convolution;
public Pwma(int period)
{
if (period < 1)
{
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
}
_period = period;
_convolution = new Convolution(GenerateKernel(_period));
Name = "Pwma";
WarmupPeriod = period;
Init();
}
public Pwma(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
private new void Init()
{
base.Init();
_convolution.Init();
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
protected override double Calculation()
{
ManageState(Input.IsNew);
// Use Convolution for calculation
TValue convolutionResult = _convolution.Calc(Input);
double result = convolutionResult.Value;
// Adjust for partial periods during warmup
if (_index < _period)
{
double[] partialKernel = GenerateKernel(_index);
result /= partialKernel.Sum();
}
IsHot = _index >= WarmupPeriod;
return result;
}
public static double[] GenerateKernel(int period)
{
double[] kernel = new double[period];
kernel[0] = 1;
for (int i = 1; i < period; i++)
{
for (int j = i; j > 0; j--)
{
kernel[j] += kernel[j - 1];
}
}
// Normalize the kernel
double weightSum = kernel.Sum();
for (int i = 0; i < period; i++)
{
kernel[i] /= weightSum;
}
return kernel;
}
}
+138
View File
@@ -0,0 +1,138 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Huber Loss calculator that combines the best properties of L2 squared loss for normal data
/// and L1 absolute loss for outliers.
/// </summary>
/// <remarks>
/// The Huberloss class calculates the Huber Loss using circular buffers
/// to efficiently manage the actual and predicted data points within the specified period.
/// </remarks>
public class Huberloss : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
private readonly double _delta;
/// <summary>
/// Initializes a new instance of the Huberloss class with the specified period and delta.
/// </summary>
/// <param name="period">The period over which to calculate the Huber Loss.</param>
/// <param name="delta">The threshold at which to switch from squared to linear loss.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1 or delta is less than or equal to 0.
/// </exception>
public Huberloss(int period, double delta = 1.0)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
if (delta <= 0)
{
throw new ArgumentOutOfRangeException(nameof(delta), "Delta must be greater than 0.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
_delta = delta;
Name = $"Huberloss(period={period}, delta={delta})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mape class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
public Huberloss(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Huberloss instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Huberloss instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Huber Loss calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Huber Loss value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Huber Loss using the formula:
/// L(a, p) = 0.5 * (a - p)^2 for |a - p| <= delta
/// L(a, p) = delta * |a - p| - 0.5 * delta^2 for |a - p| > delta
/// where a is the actual value, p is the predicted value, and delta is the threshold.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double huberLoss = 0;
if (_actualBuffer.Count > 0)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double sumLoss = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
double error = Math.Abs(actualValues[i] - predictedValues[i]);
if (error <= _delta)
{
sumLoss += 0.5 * error * error;
}
else
{
sumLoss += _delta * error - 0.5 * _delta * _delta;
}
}
huberLoss = sumLoss / _actualBuffer.Count;
}
IsHot = _index >= WarmupPeriod;
return huberLoss;
}
/// <summary>
/// Calculates the Huber Loss for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Huber Loss.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+123
View File
@@ -0,0 +1,123 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Mean Absolute Error calculator that measures the average absolute difference
/// between actual values and predicted values.
/// </summary>
/// <remarks>
/// The Mae class calculates the Mean Absolute Error using circular buffers
/// to efficiently manage the actual and predicted data points within the specified period.
/// </remarks>
public class Mae : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Mae class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Mean Absolute Error.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Mae(int period)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Mae(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mae class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Error.</param>
public Mae(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Mae instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Mae instance based on whether a new value is being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current input is a new value.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Mean Absolute Error calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Mean Absolute Error value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Mean Absolute Error using the formula:
/// MAE = sum(|actual - predicted|) / n
/// where actual is each actual value, predicted is each predicted value, and n is the number of values.
/// If Input2.Value is NaN, it uses the average of actual values as the predicted value.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double mae = 0;
if (_actualBuffer.Count > 0)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double sumOfAbsoluteDifferences = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
sumOfAbsoluteDifferences += Math.Abs(actualValues[i] - predictedValues[i]);
}
mae = sumOfAbsoluteDifferences / _actualBuffer.Count;
}
IsHot = _index >= WarmupPeriod;
return mae;
}
/// <summary>
/// Calculates the Mean Absolute Error for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Mean Absolute Error.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+132
View File
@@ -0,0 +1,132 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Mean Absolute Percentage Deviation calculator that measures the average absolute percentage difference
/// between actual values and predicted values.
/// </summary>
/// <remarks>
/// The Mapd class calculates the Mean Absolute Percentage Deviation using circular buffers
/// to efficiently manage the actual and predicted data points within the specified period.
/// </remarks>
public class Mapd : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Mapd class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Deviation.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Mapd(int period)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Mapd(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mapd class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Deviation.</param>
public Mapd(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Mapd instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Mapd instance based on whether a new value is being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current input is a new value.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Mean Absolute Percentage Deviation calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Mean Absolute Percentage Deviation value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Mean Absolute Percentage Deviation using the formula:
/// MAPD = (sum(|actual - predicted| / |actual|) / n) * 100
/// where actual is each actual value, predicted is each predicted value, and n is the number of values.
/// If there's only one value in the buffer or if any actual value is zero, those values are excluded from the calculation.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double mapd = 0;
if (_actualBuffer.Count > 0)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double sumOfAbsolutePercentageDeviations = 0;
int validCount = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
if (actualValues[i] != 0)
{
sumOfAbsolutePercentageDeviations += Math.Abs((actualValues[i] - predictedValues[i]) / actualValues[i]);
validCount++;
}
}
if (validCount > 0)
{
mapd = (sumOfAbsolutePercentageDeviations / validCount) * 100;
}
}
IsHot = _index >= WarmupPeriod;
return mapd;
}
/// <summary>
/// Calculates the Mean Absolute Percentage Deviation for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Mean Absolute Percentage Deviation.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+132
View File
@@ -0,0 +1,132 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Mean Absolute Percentage Error calculator that measures the average absolute percentage difference
/// between actual values and predicted values.
/// </summary>
/// <remarks>
/// The Mape class calculates the Mean Absolute Percentage Error using a circular buffer
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Mape : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Mape class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Mape(int period)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Mape(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mape class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
public Mape(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Mape instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Mape instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Mean Absolute Percentage Error calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Mean Absolute Percentage Error value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Mean Absolute Percentage Error using the formula:
/// MAPE = (sum(|actual - predicted| / |actual|) / n) * 100
/// where actual is each actual value, predicted is each predicted value, and n is the number of values.
/// If any actual value is zero, it is excluded from the calculation to avoid division by zero.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double mape = 0;
if (_actualBuffer.Count > 0)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double sumAbsolutePercentageError = 0;
int validCount = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
if (actualValues[i] != 0)
{
sumAbsolutePercentageError += Math.Abs((actualValues[i] - predictedValues[i]) / actualValues[i]);
validCount++;
}
}
if (validCount > 0)
{
mape = (sumAbsolutePercentageError / validCount) * 100;
}
}
IsHot = _index >= WarmupPeriod;
return mape;
}
/// <summary>
/// Calculates the Mean Absolute Percentage Error for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Mean Absolute Percentage Error.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+136
View File
@@ -0,0 +1,136 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Mean Absolute Scaled Error calculator that measures the ratio of the mean absolute error
/// of the forecast values to the mean absolute error of the naive forecast.
/// </summary>
/// <remarks>
/// The Mase class calculates the Mean Absolute Scaled Error using circular buffers
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Mase : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _forecastBuffer;
private readonly int _period;
/// <summary>
/// Initializes a new instance of the Mase class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Mean Absolute Scaled Error.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 3.
/// </exception>
public Mase(int period)
{
if (period < 3)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 3.");
}
_period = period;
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_forecastBuffer = new CircularBuffer(period);
Name = $"Mase(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mase class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Scaled Error.</param>
public Mase(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Mase instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_forecastBuffer.Clear();
}
/// <summary>
/// Manages the state of the Mase instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Mean Absolute Scaled Error calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Mean Absolute Scaled Error value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Mean Absolute Scaled Error using the formula:
/// MASE = mean(|actual - forecast|) / mean(|actual[t] - actual[t-1]|)
/// where actual is each actual value and forecast is each forecast value.
/// If there are fewer than 3 values in the buffers, the method returns 0.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double forecast = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_forecastBuffer.Add(forecast, Input.IsNew);
double mase = 0;
if (_actualBuffer.Count >= 3)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var forecastValues = _forecastBuffer.GetSpan().ToArray();
double sumAbsoluteError = 0;
double sumAbsoluteNaiveError = 0;
int count = Math.Min(_actualBuffer.Count, _period);
for (int i = 1; i < count; i++)
{
sumAbsoluteError += Math.Abs(actualValues[i] - forecastValues[i]);
sumAbsoluteNaiveError += Math.Abs(actualValues[i] - actualValues[i - 1]);
}
double meanAbsoluteError = sumAbsoluteError / (count - 1);
double meanAbsoluteNaiveError = sumAbsoluteNaiveError / (count - 1);
if (meanAbsoluteNaiveError != 0)
{
mase = meanAbsoluteError / meanAbsoluteNaiveError;
}
}
IsHot = _index >= WarmupPeriod;
return mase;
}
/// <summary>
/// Calculates the Mean Absolute Scaled Error for the given actual and forecast values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="forecast">The forecast value.</param>
/// <returns>The calculated Mean Absolute Scaled Error.</returns>
public double Calc(double actual, double forecast)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, forecast);
return Calculation();
}
}
+135
View File
@@ -0,0 +1,135 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Mean Directional Accuracy calculator that measures the average accuracy
/// of predicted directional changes compared to actual directional changes.
/// </summary>
/// <remarks>
/// The Mda class calculates the Mean Directional Accuracy using a circular buffer
/// to efficiently manage the data points within the specified period.
/// Mean Directional Accuracy is useful in financial analysis for evaluating the performance
/// of forecasting models in predicting the direction of price movements.
/// </remarks>
public class Mda : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _forecastBuffer;
/// <summary>
/// Initializes a new instance of the Mda class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Mean Directional Accuracy.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 2.
/// </exception>
public Mda(int period)
{
if (period < 2)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2.");
}
WarmupPeriod = 1;
_actualBuffer = new CircularBuffer(period);
_forecastBuffer = new CircularBuffer(period);
Name = $"Mda(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mda class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Directional Accuracy.</param>
public Mda(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Mda instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_forecastBuffer.Clear();
}
/// <summary>
/// Manages the state of the Mda instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Mean Directional Accuracy calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Mean Directional Accuracy value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Mean Directional Accuracy using the formula:
/// MDA = (number of correct directional predictions / total number of predictions) * 100
/// A correct directional prediction is when the sign of the actual change matches
/// the sign of the predicted change.
/// The result is expressed as a percentage, where 100% indicates perfect directional accuracy
/// and 50% indicates performance no better than random guessing.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double forecast = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_forecastBuffer.Add(forecast, Input.IsNew);
double mda = 0;
if (_actualBuffer.Count > 1)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var forecastValues = _forecastBuffer.GetSpan().ToArray();
int correctPredictions = 0;
int totalPredictions = actualValues.Length - 1;
for (int i = 1; i < actualValues.Length; i++)
{
double actualChange = actualValues[i] - actualValues[i - 1];
double forecastChange = forecastValues[i] - actualValues[i - 1];
if ((actualChange >= 0 && forecastChange >= 0) || (actualChange < 0 && forecastChange < 0))
{
correctPredictions++;
}
}
mda = (double)correctPredictions / totalPredictions * 100;
}
IsHot = _actualBuffer.Count > 1; // MDA calc is valid from bar 2
return mda;
}
/// <summary>
/// Calculates the Mean Directional Accuracy for the given actual and forecast values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="forecast">The forecast value.</param>
/// <returns>The calculated Mean Directional Accuracy.</returns>
public double Calc(double actual, double forecast)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, forecast);
return Calculation();
}
}
+122
View File
@@ -0,0 +1,122 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Mean Error calculator that measures the average difference
/// between actual values and predicted values.
/// </summary>
/// <remarks>
/// The Me class calculates the Mean Error using a circular buffer
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Me : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Me class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Mean Error.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Me(int period)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Me(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mape class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
public Me(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Me instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Me instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Mean Error calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Mean Error value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Mean Error using the formula:
/// ME = sum(actual - predicted) / n
/// where actual is each actual value, predicted is each predicted value, and n is the number of values.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double me = 0;
if (_actualBuffer.Count > 0)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double sumError = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
sumError += actualValues[i] - predictedValues[i];
}
me = sumError / _actualBuffer.Count;
}
IsHot = _index >= WarmupPeriod;
return me;
}
/// <summary>
/// Calculates the Mean Error for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Mean Error.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+132
View File
@@ -0,0 +1,132 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Mean Percentage Error calculator that measures the average percentage difference
/// between actual values and predicted values.
/// </summary>
/// <remarks>
/// The Mpe class calculates the Mean Percentage Error using a circular buffer
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Mpe : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Mpe class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Mean Percentage Error.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Mpe(int period)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Mpe(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mape class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
public Mpe(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Mpe instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Mpe instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Mean Percentage Error calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Mean Percentage Error value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Mean Percentage Error using the formula:
/// MPE = (sum((actual - predicted) / actual) / n) * 100
/// where actual is each actual value, predicted is each predicted value, and n is the number of values.
/// If any actual value is zero, it is excluded from the calculation to avoid division by zero.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double mpe = 0;
if (_actualBuffer.Count > 0)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double sumPercentageError = 0;
int validCount = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
if (actualValues[i] != 0)
{
sumPercentageError += (actualValues[i] - predictedValues[i]) / actualValues[i];
validCount++;
}
}
if (validCount > 0)
{
mpe = (sumPercentageError / validCount) * 100;
}
}
IsHot = _index >= WarmupPeriod;
return mpe;
}
/// <summary>
/// Calculates the Mean Percentage Error for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Mean Percentage Error.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+124
View File
@@ -0,0 +1,124 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Mean Squared Error calculator that measures the average of the squares
/// of the differences between actual values and predicted values.
/// </summary>
/// <remarks>
/// The Mse class calculates the Mean Squared Error using a circular buffer
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Mse : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Mse class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Mean Squared Error.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Mse(int period)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Mse(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mape class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
public Mse(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Mse instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Mse instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Mean Squared Error calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Mean Squared Error value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Mean Squared Error using the formula:
/// MSE = sum((actual - predicted)^2) / n
/// where actual is each actual value, predicted is each predicted value, and n is the number of values.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double mse = 0;
if (_actualBuffer.Count > 0)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double sumSquaredError = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
double error = actualValues[i] - predictedValues[i];
sumSquaredError += error * error;
}
mse = sumSquaredError / _actualBuffer.Count;
}
IsHot = _index >= WarmupPeriod;
return mse;
}
/// <summary>
/// Calculates the Mean Squared Error for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Mean Squared Error.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
_lastValidValue = predicted;
return Calculation();
}
}
+126
View File
@@ -0,0 +1,126 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Mean Squared Logarithmic Error calculator that measures the average of the squares
/// of the differences between the logarithms of actual values and predicted values.
/// </summary>
/// <remarks>
/// The Msle class calculates the Mean Squared Logarithmic Error using a circular buffer
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Msle : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Msle class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Mean Squared Logarithmic Error.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Msle(int period)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Msle(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mape class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
public Msle(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Msle instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Msle instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Mean Squared Logarithmic Error calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Mean Squared Logarithmic Error value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Mean Squared Logarithmic Error using the formula:
/// MSLE = sum((log(actual + 1) - log(predicted + 1))^2) / n
/// where actual is each actual value, predicted is each predicted value, and n is the number of values.
/// We add 1 to both actual and predicted values to avoid taking the log of zero.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double msle = 0;
if (_actualBuffer.Count > 0)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double sumSquaredLogError = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
double logActual = Math.Log(actualValues[i] + 1);
double logPredicted = Math.Log(predictedValues[i] + 1);
double logError = logActual - logPredicted;
sumSquaredLogError += logError * logError;
}
msle = sumSquaredLogError / _actualBuffer.Count;
}
IsHot = _index >= WarmupPeriod;
return msle;
}
/// <summary>
/// Calculates the Mean Squared Logarithmic Error for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Mean Squared Logarithmic Error.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+129
View File
@@ -0,0 +1,129 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Relative Absolute Error calculator that measures the ratio of the sum of absolute errors
/// to the sum of absolute differences between actual values and the mean of actual values.
/// </summary>
/// <remarks>
/// The Rae class calculates the Relative Absolute Error using circular buffers
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Rae : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Rae class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Relative Absolute Error.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 2.
/// </exception>
public Rae(int period)
{
if (period < 2)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Rae(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mape class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
public Rae(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Rae instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Rae instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Relative Absolute Error calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Relative Absolute Error value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Relative Absolute Error using the formula:
/// RAE = sum(|actual - predicted|) / sum(|actual - mean(actual)|)
/// where actual is each actual value, predicted is each predicted value, and mean(actual) is the average of actual values.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double rae = 0;
if (_actualBuffer.Count >= 2)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double actualMean = actualValues.Average();
double sumAbsoluteError = 0;
double sumAbsoluteDifferenceFromMean = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
sumAbsoluteError += Math.Abs(actualValues[i] - predictedValues[i]);
sumAbsoluteDifferenceFromMean += Math.Abs(actualValues[i] - actualMean);
}
if (sumAbsoluteDifferenceFromMean != 0)
{
rae = sumAbsoluteError / sumAbsoluteDifferenceFromMean;
}
}
IsHot = _index >= WarmupPeriod;
return rae;
}
/// <summary>
/// Calculates the Relative Absolute Error for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Relative Absolute Error.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+122
View File
@@ -0,0 +1,122 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Root Mean Squared Error calculator that measures the square root of the average
/// of the squares of the differences between actual values and predicted values.
/// </summary>
/// <remarks>
/// The Rmse class calculates the Root Mean Squared Error using a circular buffer
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Rmse : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Rmse class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Root Mean Squared Error.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Rmse(int period)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Rmse(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mape class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
public Rmse(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Rmse instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Rmse instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Root Mean Squared Error calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Root Mean Squared Error value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Root Mean Squared Error using the formula:
/// RMSE = sqrt(sum((actual - predicted)^2) / n)
/// where actual is each actual value, predicted is each predicted value, and n is the number of values.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double rmse = 0;
if (_actualBuffer.Count > 0)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double sumSquaredError = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
double error = actualValues[i] - predictedValues[i];
sumSquaredError += error * error;
}
rmse = Math.Sqrt(sumSquaredError / _actualBuffer.Count);
}
IsHot = _index >= WarmupPeriod;
return rmse;
}
/// <summary>
/// Calculates the Root Mean Squared Error for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Root Mean Squared Error.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+126
View File
@@ -0,0 +1,126 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Root Mean Squared Logarithmic Error calculator that measures the square root of the average
/// of the squares of the differences between the logarithms of actual values and predicted values.
/// </summary>
/// <remarks>
/// The Rmsle class calculates the Root Mean Squared Logarithmic Error using a circular buffer
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Rmsle : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Rmsle class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Root Mean Squared Logarithmic Error.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Rmsle(int period)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Rmsle(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mape class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
public Rmsle(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Rmsle instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Rmsle instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Root Mean Squared Logarithmic Error calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Root Mean Squared Logarithmic Error value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Root Mean Squared Logarithmic Error using the formula:
/// RMSLE = sqrt(sum((log(actual + 1) - log(predicted + 1))^2) / n)
/// where actual is each actual value, predicted is each predicted value, and n is the number of values.
/// We add 1 to both actual and predicted values to avoid taking the log of zero.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double rmsle = 0;
if (_actualBuffer.Count > 0)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double sumSquaredLogError = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
double logActual = Math.Log(actualValues[i] + 1);
double logPredicted = Math.Log(predictedValues[i] + 1);
double logError = logActual - logPredicted;
sumSquaredLogError += logError * logError;
}
rmsle = Math.Sqrt(sumSquaredLogError / _actualBuffer.Count);
}
IsHot = _index >= WarmupPeriod;
return rmsle;
}
/// <summary>
/// Calculates the Root Mean Squared Logarithmic Error for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Root Mean Squared Logarithmic Error.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+132
View File
@@ -0,0 +1,132 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Relative Squared Error calculator that measures the ratio of the sum of squared errors
/// to the sum of squared differences between actual values and the mean of actual values.
/// </summary>
/// <remarks>
/// The Rse class calculates the Relative Squared Error using circular buffers
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Rse : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Rse class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Relative Squared Error.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 2.
/// </exception>
public Rse(int period)
{
if (period < 2)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Rse(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mape class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
public Rse(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Rse instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Rse instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Relative Squared Error calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Relative Squared Error value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Relative Squared Error using the formula:
/// RSE = sum((actual - predicted)^2) / sum((actual - mean(actual))^2)
/// where actual is each actual value, predicted is each predicted value, and mean(actual) is the average of actual values.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double rse = 0;
if (_actualBuffer.Count >= 2)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double actualMean = actualValues.Average();
double sumSquaredError = 0;
double sumSquaredDifferenceFromMean = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
double error = actualValues[i] - predictedValues[i];
sumSquaredError += error * error;
double differenceFromMean = actualValues[i] - actualMean;
sumSquaredDifferenceFromMean += differenceFromMean * differenceFromMean;
}
if (sumSquaredDifferenceFromMean != 0)
{
rse = sumSquaredError / sumSquaredDifferenceFromMean;
}
}
IsHot = _index >= WarmupPeriod;
return rse;
}
/// <summary>
/// Calculates the Relative Squared Error for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Relative Squared Error.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+132
View File
@@ -0,0 +1,132 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Coefficient of Determination (R-squared) calculator that measures the proportion of
/// the variance in the dependent variable that is predictable from the independent variable(s).
/// </summary>
/// <remarks>
/// The Rsquared class calculates the Coefficient of Determination using circular buffers
/// to efficiently manage the actual and predicted data points within the specified period.
/// </remarks>
public class Rsquared : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Rsquared class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Coefficient of Determination.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 2.
/// </exception>
public Rsquared(int period)
{
if (period < 2)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Rsquared(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mape class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
public Rsquared(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Rsquared instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Rsquared instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Coefficient of Determination calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Coefficient of Determination value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Coefficient of Determination using the formula:
/// R^2 = 1 - (SSres / SStot)
/// where SSres is the sum of squared residuals and SStot is the total sum of squares.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double rsquared = 0;
if (_actualBuffer.Count >= 2)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double actualMean = actualValues.Average();
double ssRes = 0;
double ssTot = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
double residual = actualValues[i] - predictedValues[i];
ssRes += residual * residual;
double deviation = actualValues[i] - actualMean;
ssTot += deviation * deviation;
}
if (ssTot != 0)
{
rsquared = 1 - (ssRes / ssTot);
}
}
IsHot = _index >= WarmupPeriod;
return rsquared;
}
/// <summary>
/// Calculates the Coefficient of Determination for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Coefficient of Determination.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+132
View File
@@ -0,0 +1,132 @@
namespace QuanTAlib;
/// <summary>
/// Represents a Symmetric Mean Absolute Percentage Error calculator that measures the percentage difference
/// between actual and predicted values, using a symmetric formula to handle both positive and negative errors equally.
/// </summary>
/// <remarks>
/// The Smape class calculates the Symmetric Mean Absolute Percentage Error using circular buffers
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Smape : AbstractBase
{
private readonly CircularBuffer _actualBuffer;
private readonly CircularBuffer _predictedBuffer;
/// <summary>
/// Initializes a new instance of the Smape class with the specified period.
/// </summary>
/// <param name="period">The period over which to calculate the Symmetric Mean Absolute Percentage Error.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Smape(int period)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
WarmupPeriod = period;
_actualBuffer = new CircularBuffer(period);
_predictedBuffer = new CircularBuffer(period);
Name = $"Smape(period={period})";
Init();
}
/// <summary>
/// Initializes a new instance of the Mape class with the specified source and period.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Mean Absolute Percentage Error.</param>
public Smape(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Smape instance by clearing the buffers.
/// </summary>
public override void Init()
{
base.Init();
_actualBuffer.Clear();
_predictedBuffer.Clear();
}
/// <summary>
/// Manages the state of the Smape instance based on whether new values are being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current inputs are new values.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
/// <summary>
/// Performs the Symmetric Mean Absolute Percentage Error calculation for the current period.
/// </summary>
/// <returns>
/// The calculated Symmetric Mean Absolute Percentage Error value for the current period.
/// </returns>
/// <remarks>
/// This method calculates the Symmetric Mean Absolute Percentage Error using the formula:
/// SMAPE = (100% / n) * sum(2 * |actual - predicted| / (|actual| + |predicted|))
/// where actual is each actual value, predicted is each predicted value, and n is the number of values.
/// </remarks>
protected override double Calculation()
{
ManageState(Input.IsNew);
double actual = Input.Value;
_actualBuffer.Add(actual, Input.IsNew);
double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value;
_predictedBuffer.Add(predicted, Input.IsNew);
double smape = 0;
if (_actualBuffer.Count > 0)
{
var actualValues = _actualBuffer.GetSpan().ToArray();
var predictedValues = _predictedBuffer.GetSpan().ToArray();
double sumSymmetricPercentageError = 0;
int validCount = 0;
for (int i = 0; i < _actualBuffer.Count; i++)
{
double denominator = Math.Abs(actualValues[i]) + Math.Abs(predictedValues[i]);
if (denominator != 0)
{
sumSymmetricPercentageError += 2 * Math.Abs(actualValues[i] - predictedValues[i]) / denominator;
validCount++;
}
}
if (validCount > 0)
{
smape = (100.0 / validCount) * sumSymmetricPercentageError;
}
}
IsHot = _index >= WarmupPeriod;
return smape;
}
/// <summary>
/// Calculates the Symmetric Mean Absolute Percentage Error for the given actual and predicted values.
/// </summary>
/// <param name="actual">The actual value.</param>
/// <param name="predicted">The predicted value.</param>
/// <returns>The calculated Symmetric Mean Absolute Percentage Error.</returns>
public double Calc(double actual, double predicted)
{
Input = new TValue(DateTime.Now, actual);
Input2 = new TValue(DateTime.Now, predicted);
return Calculation();
}
}
+13 -8
View File
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Title>QuanTAlib</Title>
<Product>Library of TA Calculations, Charts and Strategies for Quantower</Product>
<Description>Quantitative Technical Analysis Library in C# for Quantower</Description>
<Title>QuanTAlib</Title>
<Product>Library of TA Calculations, Charts and Strategies for Quantower</Product>
<Description>Quantitative Technical Analysis Library in C# for Quantower</Description>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/mihakralj/QuanTAlib</RepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
@@ -14,7 +14,7 @@
<AssemblyName>QuanTAlib</AssemblyName>
<IsPublishable>True</IsPublishable>
<PlatformTarget>AnyCPU</PlatformTarget>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
@@ -27,10 +27,15 @@
Quantitative;Historical;Quotes;
</PackageTags>
<PackageIcon>QuanTAlib2.png</PackageIcon>
<PackageIconUrl>https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png</PackageIconUrl>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<PackageIconUrl>https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png</PackageIconUrl>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" Exclude="obj\**\*.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\docs\readme.md" Pack="true" PackagePath=""/>
<None Include="..\.github\QuanTAlib2.png" Pack="true" Visible="false" PackagePath=""/>
@@ -38,11 +43,11 @@
<ItemGroup>
<Reference Include="TradingPlatform.BusinessLayer">
<HintPath>..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
<HintPath>..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
</Reference>
<None Include="..\.github\TradingPlatform.BusinessLayer.xml">
<Link>TradingPlatform.BusinessLayer.xml</Link>
</None>
</ItemGroup>
</Project>
</Project>
+22 -1
View File
@@ -4,15 +4,36 @@ namespace QuanTAlib;
/// Calculates the rate of change of the slope over a specified period.
/// Provides insights into trend acceleration or deceleration.
/// </summary>
/// <remarks>
/// Curvature is a second-order derivative that measures how quickly the slope (first-order derivative) is changing.
/// Positive curvature indicates accelerating uptrends or decelerating downtrends.
/// Negative curvature indicates decelerating uptrends or accelerating downtrends.
/// This indicator can be useful for identifying potential trend reversals or confirming trend strength.
/// </remarks>
public class Curvature : AbstractBase
{
private readonly int _period;
private readonly Slope _slopeCalculator;
private readonly CircularBuffer _slopeBuffer;
/// <summary>
/// Gets the y-intercept of the curvature line.
/// </summary>
public double? Intercept { get; private set; }
/// <summary>
/// Gets the standard deviation of the slope values used in the curvature calculation.
/// </summary>
public double? StdDev { get; private set; }
/// <summary>
/// Gets the R-squared value, indicating the goodness of fit of the curvature line.
/// </summary>
public double? RSquared { get; private set; }
/// <summary>
/// Gets the last calculated point on the curvature line.
/// </summary>
public double? Line { get; private set; }
/// <summary>
@@ -153,4 +174,4 @@ public class Curvature : AbstractBase
IsHot = _slopeBuffer.Count == _period;
return curvature;
}
}
}
+14 -2
View File
@@ -4,8 +4,20 @@ namespace QuanTAlib;
/// Measures the unpredictability of data using Shannon's Entropy.
/// Provides insights into the randomness or information content of the time series.
/// </summary>
/// <remarks>
/// Shannon's Entropy quantifies the average amount of information contained in a message.
/// In the context of time series analysis, it can be used to:
/// - Detect regime changes or structural breaks in the data.
/// - Assess the complexity or predictability of price movements.
/// - Identify periods of high uncertainty or information flow in the market.
/// The entropy value is normalized between 0 and 1, where 1 indicates maximum randomness
/// and 0 indicates perfect predictability.
/// </remarks>
public class Entropy : AbstractBase
{
/// <summary>
/// The number of data points to consider for the entropy calculation.
/// </summary>
private readonly int Period;
private readonly CircularBuffer _buffer;
@@ -24,7 +36,7 @@ public class Entropy : AbstractBase
"Period must be greater than or equal to 2 for entropy calculation.");
}
Period = period;
WarmupPeriod = 2;
WarmupPeriod = 2; // Minimum number of points needed for entropy calculation
_buffer = new CircularBuffer(period);
Name = $"Entropy(period={period})";
Init();
@@ -110,4 +122,4 @@ public class Entropy : AbstractBase
IsHot = _buffer.Count >= Period;
return entropy;
}
}
}
+22
View File
@@ -4,8 +4,25 @@ namespace QuanTAlib;
/// Calculates excess kurtosis using the Sheskin Algorithm.
/// Measures the "tailedness" of the probability distribution of a real-valued random variable.
/// </summary>
/// <remarks>
/// Kurtosis is a measure of the combined weight of a distribution's tails relative to the center of the distribution.
/// In financial time series analysis, kurtosis can provide insights into:
/// - The frequency and magnitude of extreme returns.
/// - The potential for outliers or "black swan" events.
/// - The shape of the return distribution compared to a normal distribution.
///
/// Interpretation:
/// - Excess kurtosis > 0: Heavy-tailed distribution (more extreme values than a normal distribution)
/// - Excess kurtosis = 0: Normal distribution
/// - Excess kurtosis < 0: Light-tailed distribution (fewer extreme values than a normal distribution)
///
/// High kurtosis in financial returns may indicate a higher risk of extreme events.
/// </remarks>
public class Kurtosis : AbstractBase
{
/// <summary>
/// The number of data points to consider for the kurtosis calculation.
/// </summary>
private readonly int Period;
private readonly CircularBuffer _buffer;
@@ -73,6 +90,11 @@ public class Kurtosis : AbstractBase
/// <remarks>
/// Uses the Sheskin Algorithm for kurtosis calculation.
/// Requires at least 4 data points for a valid calculation.
///
/// Interpretation of results:
/// - Positive values indicate a distribution with heavier tails and a higher peak compared to a normal distribution.
/// - Negative values indicate a distribution with lighter tails and a lower peak compared to a normal distribution.
/// - A value close to 0 suggests a distribution similar to a normal distribution in terms of tailedness.
/// </remarks>
protected override double Calculation()
{
+41 -3
View File
@@ -4,19 +4,57 @@ namespace QuanTAlib;
/// Calculates the maximum value over a specified period, with an optional decay factor.
/// Useful for tracking the highest point in a time series with the ability to gradually forget old peaks.
/// </summary>
/// <remarks>
/// The Max indicator is particularly useful in financial analysis for:
/// - Identifying resistance levels in price charts.
/// - Tracking the highest price over a given period.
/// - Implementing trailing stop-loss strategies.
///
/// The decay factor allows the indicator to adapt to changing market conditions by
/// gradually reducing the influence of older maximum values.
/// </remarks>
public class Max : AbstractBase
{
/// <summary>
/// The number of data points to consider for the maximum calculation.
/// </summary>
private readonly int Period;
/// <summary>
/// Circular buffer to store the most recent data points.
/// </summary>
private readonly CircularBuffer _buffer;
/// <summary>
/// The half-life decay factor used to gradually forget old peaks.
/// </summary>
private readonly double _halfLife;
private double _currentMax, _p_currentMax;
private int _timeSinceNewMax, _p_timeSinceNewMax;
/// <summary>
/// The current maximum value.
/// </summary>
private double _currentMax;
/// <summary>
/// The previous maximum value.
/// </summary>
private double _p_currentMax;
/// <summary>
/// The number of periods since a new maximum was set.
/// </summary>
private int _timeSinceNewMax;
/// <summary>
/// The previous value of _timeSinceNewMax.
/// </summary>
private int _p_timeSinceNewMax;
/// <summary>
/// Initializes a new instance of the Max class.
/// </summary>
/// <param name="period">The number of data points to consider. Must be at least 1.</param>
/// <param name="decay">Half-life decay factor. Set to 0 for no decay, higher for faster forgetting. Default is 0.</param>
/// <param name="decay">Half-life decay factor. Set to 0 for no decay, higher for faster forgetting of old peaks. Default is 0.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when the period is less than 1 or decay is negative.
/// </exception>
+21
View File
@@ -4,8 +4,20 @@ namespace QuanTAlib;
/// Calculates the median value over a specified period.
/// Provides a measure of central tendency that is robust to outliers.
/// </summary>
/// <remarks>
/// The Median indicator is particularly useful in financial analysis for:
/// - Providing a robust measure of central tendency that is less affected by extreme values than the mean.
/// - Identifying the middle value in a dataset, which can be helpful in understanding price distributions.
/// - Serving as a basis for other indicators or trading strategies that require a stable reference point.
///
/// Unlike the mean, the median is not influenced by extreme outliers, making it valuable
/// in markets with occasional large price swings or in the presence of data anomalies.
/// </remarks>
public class Median : AbstractBase
{
/// <summary>
/// The number of data points to consider for the median calculation.
/// </summary>
private readonly int Period;
private readonly CircularBuffer _buffer;
@@ -41,6 +53,15 @@ public class Median : AbstractBase
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Resets the Median indicator to its initial state.
/// </summary>
public override void Init()
{
base.Init();
_buffer.Clear();
}
/// <summary>
/// Manages the state of the indicator.
/// </summary>
+36 -4
View File
@@ -9,20 +9,52 @@ namespace QuanTAlib;
/// The Min class uses a circular buffer to store values and calculates the minimum
/// efficiently. It also implements a decay mechanism to adjust the minimum value over
/// time, allowing for a more responsive indicator in changing market conditions.
///
/// The decay factor allows the indicator to "forget" old minimum values gradually,
/// which can be useful in adapting to new price trends or market regimes.
/// </remarks>
public class Min : AbstractBase
{
/// <summary>
/// The number of data points to consider for the minimum calculation.
/// </summary>
private readonly int Period;
/// <summary>
/// Circular buffer to store the most recent data points.
/// </summary>
private readonly CircularBuffer _buffer;
/// <summary>
/// The half-life decay factor used to gradually forget old minimums.
/// </summary>
private readonly double _halfLife;
private double _currentMin, _p_currentMin;
private int _timeSinceNewMin, _p_timeSinceNewMin;
/// <summary>
/// The current minimum value.
/// </summary>
private double _currentMin;
/// <summary>
/// The previous minimum value.
/// </summary>
private double _p_currentMin;
/// <summary>
/// The number of periods since a new minimum was set.
/// </summary>
private int _timeSinceNewMin;
/// <summary>
/// The previous value of _timeSinceNewMin.
/// </summary>
private int _p_timeSinceNewMin;
/// <summary>
/// Initializes a new instance of the Min class with the specified period and decay.
/// </summary>
/// <param name="period">The period over which to calculate the minimum value.</param>
/// <param name="decay">The decay factor to apply to older values (default is 0).</param>
/// <param name="decay">The decay factor to apply to older values. Higher values cause faster forgetting of old minimums. Default is 0 (no decay).</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1 or decay is negative.
/// </exception>
@@ -49,7 +81,7 @@ public class Min : AbstractBase
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the minimum value.</param>
/// <param name="decay">The decay factor to apply to older values (default is 0).</param>
/// <param name="decay">The decay factor to apply to older values. Higher values cause faster forgetting of old minimums. Default is 0 (no decay).</param>
public Min(object source, int period, double decay = 0) : this(period, decay)
{
var pubEvent = source.GetType().GetEvent("Pub");
+17
View File
@@ -8,9 +8,17 @@ namespace QuanTAlib;
/// The Mode class uses a circular buffer to store values and calculates the mode
/// efficiently. Before the specified period is reached, it returns the average of
/// the available values as an approximation.
///
/// In financial analysis, the mode can be useful for:
/// - Identifying the most common price levels, which could indicate support or resistance.
/// - Analyzing the distribution of returns or other financial metrics.
/// - Detecting patterns in trading volume or other discrete financial data.
/// </remarks>
public class Mode : AbstractBase
{
/// <summary>
/// The number of data points to consider for the mode calculation.
/// </summary>
private readonly int Period;
private readonly CircularBuffer _buffer;
@@ -45,6 +53,15 @@ public class Mode : AbstractBase
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Resets the Mode indicator to its initial state.
/// </summary>
public override void Init()
{
base.Init();
_buffer.Clear();
}
/// <summary>
/// Manages the state of the Mode instance based on whether a new value is being processed.
/// </summary>
+16 -2
View File
@@ -9,11 +9,25 @@ namespace QuanTAlib;
/// percentile efficiently. It uses linear interpolation when the percentile falls
/// between two data points. Before the specified period is reached, it returns the
/// average of the available values as an approximation.
///
/// In financial analysis, percentiles are useful for:
/// - Assessing the relative standing of a value within a distribution.
/// - Identifying outliers or extreme values in financial data.
/// - Creating risk measures, such as Value at Risk (VaR) calculations.
/// - Analyzing the distribution of returns, trading volumes, or other financial metrics.
/// </remarks>
public class Percentile : AbstractBase
{
/// <summary>
/// The number of data points to consider for the percentile calculation.
/// </summary>
private readonly int Period;
/// <summary>
/// The percentile to calculate (between 0 and 100).
/// </summary>
private readonly double Percent;
private readonly CircularBuffer _buffer;
/// <summary>
@@ -36,7 +50,7 @@ public class Percentile : AbstractBase
}
Period = period;
Percent = percent;
WarmupPeriod = 2;
WarmupPeriod = 2; // Minimum number of points needed for percentile calculation
_buffer = new CircularBuffer(period);
Name = $"Percentile(period={period}, percent={percent})";
Init();
@@ -125,4 +139,4 @@ public class Percentile : AbstractBase
IsHot = _buffer.Count >= Period;
return result;
}
}
}
+18 -1
View File
@@ -9,9 +9,21 @@ namespace QuanTAlib;
/// efficiently. It uses the adjusted Fisher-Pearson standardized moment coefficient
/// for sample skewness calculation. A minimum of 3 data points is required for the
/// calculation.
///
/// In financial analysis, skewness is important for:
/// - Assessing the asymmetry of returns distribution.
/// - Evaluating the risk of extreme events in either direction.
/// - Complementing other risk measures like standard deviation.
/// - Informing investment decisions and risk management strategies.
///
/// Positive skewness indicates a longer tail on the right side of the distribution,
/// while negative skewness indicates a longer tail on the left side.
/// </remarks>
public class Skew : AbstractBase
{
/// <summary>
/// The number of data points to consider for the skewness calculation.
/// </summary>
private readonly int Period;
private readonly CircularBuffer _buffer;
@@ -79,6 +91,11 @@ public class Skew : AbstractBase
/// to calculate the sample skewness. It requires at least 3 data points for the
/// calculation. If there are fewer than 3 data points, or if the standard
/// deviation is zero, the method returns 0.
///
/// Interpretation of results:
/// - Positive values indicate right-skewed distribution (longer tail on the right side).
/// - Negative values indicate left-skewed distribution (longer tail on the left side).
/// - Values close to 0 suggest a relatively symmetric distribution.
/// </remarks>
protected override double Calculation()
{
@@ -117,4 +134,4 @@ public class Skew : AbstractBase
IsHot = _buffer.Count >= Period;
return skew;
}
}
}
+29
View File
@@ -7,15 +7,37 @@ namespace QuanTAlib;
/// The Slope class calculates the slope of a linear regression line, along with other
/// statistical measures such as intercept, standard deviation, R-squared, and the last
/// point on the regression line. It uses the least squares method for calculation.
///
/// In financial analysis, slope is important for:
/// - Identifying trends in price movements or other financial metrics.
/// - Measuring the rate of change in a financial time series.
/// - Assessing the strength and direction of relationships between variables.
/// - Supporting technical analysis indicators and trading strategies.
/// </remarks>
public class Slope : AbstractBase
{
private readonly int _period;
private readonly CircularBuffer _buffer;
private readonly CircularBuffer _timeBuffer;
/// <summary>
/// Gets the y-intercept of the regression line.
/// </summary>
public double? Intercept { get; private set; }
/// <summary>
/// Gets the standard deviation of the y-values.
/// </summary>
public double? StdDev { get; private set; }
/// <summary>
/// Gets the R-squared value, indicating the goodness of fit of the regression line.
/// </summary>
public double? RSquared { get; private set; }
/// <summary>
/// Gets the y-value of the last point on the regression line.
/// </summary>
public double? Line { get; private set; }
/// <summary>
@@ -90,6 +112,13 @@ public class Slope : AbstractBase
/// It also calculates and updates the Intercept, StdDev, RSquared, and Line properties.
/// If there are fewer than 2 data points, or if the sum of squared x deviations is 0,
/// the method returns 0 and sets the additional properties to null.
///
/// Interpretation of results:
/// - Positive slope: Indicates an upward trend in the data.
/// - Negative slope: Indicates a downward trend in the data.
/// - Slope close to 0: Indicates a relatively flat or no clear trend in the data.
/// The magnitude of the slope represents the rate of change in the dependent variable
/// (y) for each unit change in the independent variable (x).
/// </remarks>
protected override double Calculation()
{
+18
View File
@@ -8,10 +8,23 @@ namespace QuanTAlib;
/// The Stddev class calculates either the population standard deviation or the sample
/// standard deviation based on the isPopulation parameter. It uses a circular buffer
/// to efficiently manage the data points within the specified period.
///
/// In financial analysis, standard deviation is important for:
/// - Measuring volatility of financial instruments or portfolios.
/// - Assessing risk in investments.
/// - Calculating Sharpe ratios and other risk-adjusted performance measures.
/// - Identifying potential outliers or unusual market behavior.
/// </remarks>
public class Stddev : AbstractBase
{
/// <summary>
/// Indicates whether to calculate population (true) or sample (false) standard deviation.
/// </summary>
private readonly bool IsPopulation;
/// <summary>
/// Circular buffer to store the most recent data points.
/// </summary>
private readonly CircularBuffer _buffer;
/// <summary>
@@ -87,6 +100,11 @@ public class Stddev : AbstractBase
/// sqrt(sum((x - mean)^2) / (n - 1)) for sample,
/// where x is each value, mean is the average of all values, and n is the number of values.
/// If there's only one value in the buffer, the method returns 0.
///
/// Interpretation of results:
/// - A low standard deviation indicates that the values tend to be close to the mean.
/// - A high standard deviation indicates that the values are spread out over a wider range.
/// - In financial contexts, higher standard deviation often implies higher volatility or risk.
/// </remarks>
protected override double Calculation()
{
+19
View File
@@ -8,10 +8,23 @@ namespace QuanTAlib;
/// The Variance class calculates either the population variance or the sample
/// variance based on the isPopulation parameter. It uses a circular buffer
/// to efficiently manage the data points within the specified period.
///
/// In financial analysis, variance is important for:
/// - Measuring the dispersion of returns around the mean.
/// - Assessing risk and volatility in financial instruments or portfolios.
/// - Serving as a basis for other risk measures like standard deviation and beta.
/// - Contributing to portfolio optimization techniques, such as Modern Portfolio Theory.
/// </remarks>
public class Variance : AbstractBase
{
/// <summary>
/// Indicates whether to calculate population (true) or sample (false) variance.
/// </summary>
private readonly bool IsPopulation;
/// <summary>
/// Circular buffer to store the most recent data points.
/// </summary>
private readonly CircularBuffer _buffer;
/// <summary>
@@ -87,6 +100,12 @@ public class Variance : AbstractBase
/// sum((x - mean)^2) / (n - 1) for sample,
/// where x is each value, mean is the average of all values, and n is the number of values.
/// If there's only one value in the buffer, the method returns 0.
///
/// Interpretation of results:
/// - A low variance indicates that the values tend to be close to the mean and to each other.
/// - A high variance indicates that the values are spread out over a wider range.
/// - In financial contexts, higher variance often implies higher volatility or risk.
/// - Variance is always non-negative, and its units are squared units of the original data.
/// </remarks>
protected override double Calculation()
{
+22 -1
View File
@@ -8,10 +8,23 @@ namespace QuanTAlib;
/// The Zscore class calculates the Z-score (also known as standard score) for
/// the most recent value in a given period. It uses a circular buffer to
/// efficiently manage the data points within the specified period.
///
/// In financial analysis, Z-score is important for:
/// - Identifying outliers or unusual price movements.
/// - Normalizing data across different scales or time periods.
/// - Assessing the relative position of a value within its historical distribution.
/// - Supporting trading strategies based on mean reversion or momentum.
/// </remarks>
public class Zscore : AbstractBase
{
/// <summary>
/// The number of data points to consider for the Z-score calculation.
/// </summary>
private readonly int Period;
/// <summary>
/// Circular buffer to store the most recent data points.
/// </summary>
private readonly CircularBuffer _buffer;
/// <summary>
@@ -78,6 +91,14 @@ public class Zscore : AbstractBase
/// Z = (x - μ) / σ
/// where x is the input value, μ is the mean of the period, and σ is the sample standard deviation.
/// If there are fewer than 2 data points or if the standard deviation is 0, the method returns 0.
///
/// Interpretation of results:
/// - A Z-score of 0 indicates that the data point is exactly on the mean.
/// - A positive Z-score indicates the data point is above the mean.
/// - A negative Z-score indicates the data point is below the mean.
/// - The magnitude of the Z-score represents how many standard deviations away from the mean the data point is.
/// - In a normal distribution, about 68% of the values have a Z-score between -1 and 1,
/// 95% between -2 and 2, and 99.7% between -3 and 3.
/// </remarks>
protected override double Calculation()
{
@@ -104,4 +125,4 @@ public class Zscore : AbstractBase
IsHot = _buffer.Count >= Period;
return zScore;
}
}
}
+2 -2
View File
@@ -11,8 +11,8 @@ QuanTAlib.Formatters.Initialize();
#!csharp
TSeries input = new();
Sma ma1 = new (6);
Sma ma2 = new (input, 6);
Beta ma1 = new (6);
Beta ma2 = new (input, 6);
Random random = new Random();
+3 -3
View File
@@ -9,8 +9,6 @@ public class AfirmaIndicator : IndicatorBase
[InputParameter("Periods for lowpass cutoff", sortIndex: 2, 1, 2000, 1, 0)]
public int Periods { get; set; } = 6;
[InputParameter("Window Type", sortIndex: 3, variants: [
"Rectangular", Afirma.WindowType.Rectangular,
"Hanning", Afirma.WindowType.Hanning1,
@@ -32,6 +30,8 @@ public class AfirmaIndicator : IndicatorBase
protected override void InitIndicator()
{
base.InitIndicator();
ma = new Afirma(periods: Periods, taps: Taps, window: Window);
}
}
}
+5 -3
View File
@@ -1,5 +1,5 @@
using TradingPlatform.BusinessLayer;
using QuanTAlib;
namespace QuanTAlib;
public class AlmaIndicator : IndicatorBase
{
@@ -7,10 +7,10 @@ public class AlmaIndicator : IndicatorBase
public int Period { get; set; } = 10;
[InputParameter("Offset", sortIndex: 5)]
public double Offset = 0.85;
public double Offset { get; set; } = 0.85;
[InputParameter("Sigma", sortIndex: 6)]
public double Sigma = 6.0;
public double Sigma { get; set; } = 6.0;
private Alma? ma;
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"ALMA {Period} : {Offset:F2} : {Sigma:F0} : {SourceName}";
@@ -18,6 +18,8 @@ public class AlmaIndicator : IndicatorBase
public AlmaIndicator() : base()
{
Name = "ALMA - Arnaud Legoux Moving Average";
Description = "Arnaud Legoux Moving Average";
}
protected override void InitIndicator()
+10 -12
View File
@@ -5,28 +5,26 @@
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
<UpdateAssemblyInfo>true</UpdateAssemblyInfo>
<GenerateGitVersionInformation>true</GenerateGitVersionInformation>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
<Compile Include="..\..\lib\**\*.cs" Exclude="..\..\lib\obj\**">
<Link>lib\%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
<Target Name="CopyCustomContent" AfterTargets="AfterBuild" Condition="'$(IsLocalBuild)' == 'true'">
<Copy SourceFiles="$(OutputPath)\Averages.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Averages" />
</Target>
<ItemGroup>
<Compile Include="..\*.cs">
<Link>%(Filename)%(Extension)</Link>
</Compile>
<Compile Include="..\*.cs" />
<Compile Include="*.cs" />
<ProjectReference Include="..\..\lib\quantalib.csproj" Private="true" IncludeAssets="all" />
<Reference Include="TradingPlatform.BusinessLayer">
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
</Reference>
<None Include="..\..\.github\TradingPlatform.BusinessLayer.xml">
<Link>TradingPlatform.BusinessLayer.xml</Link>
</None>
</ItemGroup>
</Project>
<Target Name="CopyCustomContent" AfterTargets="AfterBuild" Condition="'$(IsLocalBuild)' == 'true'">
<Copy SourceFiles="$(OutputPath)\Averages.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Averages" />
</Target>
</Project>
+2 -1
View File
@@ -1,5 +1,5 @@
using TradingPlatform.BusinessLayer;
using QuanTAlib;
namespace QuanTAlib;
public class DemaIndicator : IndicatorBase
{
@@ -12,6 +12,7 @@ public class DemaIndicator : IndicatorBase
public DemaIndicator() : base()
{
Name = "DEMA - Double Exponential Moving Average";
Description = "A faster-responding moving average that reduces lag by applying the EMA twice.";
}
protected override void InitIndicator()
+2 -1
View File
@@ -1,5 +1,5 @@
using TradingPlatform.BusinessLayer;
using QuanTAlib;
namespace QuanTAlib;
public class DsmaIndicator : IndicatorBase
{
@@ -15,6 +15,7 @@ public class DsmaIndicator : IndicatorBase
public DsmaIndicator() : base()
{
Name = "DSMA - Deviation Scaled Moving Average";
Description = "A moving average that adjusts its responsiveness based on price deviations from the mean.";
}
protected override void InitIndicator()
+2 -2
View File
@@ -1,5 +1,5 @@
using TradingPlatform.BusinessLayer;
using QuanTAlib;
namespace QuanTAlib;
public class DwmaIndicator : IndicatorBase
{
@@ -10,10 +10,10 @@ public class DwmaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"DWMA {Period} : {SourceName}";
public DwmaIndicator() : base()
{
Name = "DWMA - Double Weighted Moving Average";
Description = "A moving average that applies double weighting to recent prices for increased responsiveness.";
}
protected override void InitIndicator()
+2 -2
View File
@@ -1,5 +1,5 @@
using TradingPlatform.BusinessLayer;
using QuanTAlib;
namespace QuanTAlib;
public class EmaIndicator : IndicatorBase
{
@@ -16,7 +16,7 @@ public class EmaIndicator : IndicatorBase
public EmaIndicator() : base()
{
Name = "EMA - Exponential Moving Average";
Description = "Exponential Moving Average";
Description = "Moving average that gives more weight to recent prices, reducing lag in trend following.";
}
protected override void InitIndicator()
+2 -1
View File
@@ -1,5 +1,5 @@
using TradingPlatform.BusinessLayer;
using QuanTAlib;
namespace QuanTAlib;
public class EpmaIndicator : IndicatorBase
{
@@ -13,6 +13,7 @@ public class EpmaIndicator : IndicatorBase
public EpmaIndicator() : base()
{
Name = "EPMA - Endpoint Moving Average";
Description = "Moving average that emphasizes the most recent data point, useful for identifying trend changes.";
}
protected override void InitIndicator()
+2 -2
View File
@@ -1,5 +1,5 @@
using TradingPlatform.BusinessLayer;
using QuanTAlib;
namespace QuanTAlib;
public class FramaIndicator : IndicatorBase
{
@@ -10,10 +10,10 @@ public class FramaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"FRAMA {Period} : {SourceName}";
public FramaIndicator() : base()
{
Name = "FRAMA - Fractal Adaptive Moving Average";
Description = "Adaptive moving average that adjusts its smoothing based on market fractal dimension.";
}
protected override void InitIndicator()
+2 -2
View File
@@ -1,5 +1,5 @@
using TradingPlatform.BusinessLayer;
using QuanTAlib;
namespace QuanTAlib;
public class FwmaIndicator : IndicatorBase
{
@@ -10,10 +10,10 @@ public class FwmaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"FWMA {Period} : {SourceName}";
public FwmaIndicator() : base()
{
Name = "FWMA - Fibonacci-Weighted Moving Average";
Description = "Moving average that uses Fibonacci sequence for weighting, emphasizing recent and key historical prices.";
}
protected override void InitIndicator()
+2 -2
View File
@@ -1,5 +1,5 @@
using TradingPlatform.BusinessLayer;
using QuanTAlib;
namespace QuanTAlib;
public class GmaIndicator : IndicatorBase
{
@@ -10,10 +10,10 @@ public class GmaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"GMA {Period} : {SourceName}";
public GmaIndicator() : base()
{
Name = "GMA - Gaussian-Weighted Moving Average";
Description = "Moving average using Gaussian distribution for weighting, balancing recent and historical data.";
}
protected override void InitIndicator()
+1 -1
View File
@@ -10,10 +10,10 @@ public class HmaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"HMA {Period} : {SourceName}";
public HmaIndicator() : base()
{
Name = "HMA - Hull Moving Average";
Description = "Responsive moving average that reduces lag while maintaining smoothness in price action.";
}
protected override void InitIndicator()
+1
View File
@@ -10,6 +10,7 @@ public class HtitIndicator : IndicatorBase
public HtitIndicator() : base()
{
Name = "HTIT - Hilbert Transform Instantaneous Trendline";
Description = "Uses Hilbert Transform to identify the dominant cycle and generate a smooth, lag-free trendline.";
}
protected override void InitIndicator()
+1 -4
View File
@@ -16,17 +16,14 @@ public class HwmaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"HWMA {nA:F2} : {nB:F2} : {nC:F2} : {SourceName}";
public HwmaIndicator() : base()
{
Name = "HWMA - Holt-Winter Moving Average";
Description = "Triple exponential moving average that accounts for level, trend, and seasonal components.";
}
protected override void InitIndicator()
{
//nA = 2 / (1 + (double)Period);
//nB = 1 / (double)Period;
//nC = 1 / (double)Period;
ma = new Hwma(nA: nA, nB: nB, nC: nC);
base.InitIndicator();
}
+1 -1
View File
@@ -12,10 +12,10 @@ public class JmaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"JMA {Period} : {Phase} : {SourceName}";
public JmaIndicator() : base()
{
Name = "JMA - Jurik Moving Average";
Description = "Adaptive moving average with reduced lag and noise, adjustable smoothness and phase shift.";
}
protected override void InitIndicator()
+1 -1
View File
@@ -14,10 +14,10 @@ public class KamaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"KAMA {Period} : {Fast} : {Slow} : {SourceName}";
public KamaIndicator() : base()
{
Name = "KAMA - Kaufman's Adaptive Moving Average";
Description = "Adaptive moving average that adjusts to market volatility, reducing lag in trending markets.";
}
protected override void InitIndicator()
+1
View File
@@ -13,6 +13,7 @@ public class LtmaIndicator : IndicatorBase
public LtmaIndicator() : base()
{
Name = "LTMA - Laguerre Transform Moving Average";
Description = "Moving average using Laguerre polynomials, offering adjustable smoothing and lag reduction.";
}
protected override void InitIndicator()
+3 -2
View File
@@ -7,7 +7,7 @@ public class MaafIndicator : IndicatorBase
public int Period { get; set; } = 39;
[InputParameter("Threshold", sortIndex: 5, minimum: 0, maximum: 1, increment: 0.001, decimalPlaces: 3)]
public double Threshold = 0.002;
private double Threshold { get; set; } = 0.002;
private Maaf? ma;
protected override AbstractBase QuanTAlib => ma!;
@@ -16,11 +16,12 @@ public class MaafIndicator : IndicatorBase
public MaafIndicator() : base()
{
Name = "MAAF - Median-Average Adaptive Filter";
Description = "Adaptive filter combining median and average, reducing noise while preserving trend responsiveness.";
}
protected override void InitIndicator()
{
base.InitIndicator();
ma = new Maaf(Period: Period, Threshold: Threshold);
ma = new Maaf(period: Period, threshold: Threshold);
}
}
+1 -1
View File
@@ -11,10 +11,10 @@ public class MamaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"MAMA : {Fast} : {Slow} : {SourceName}";
public MamaIndicator() : base()
{
Name = "MAMA - MESA Adaptive Moving Average";
Description = "Adaptive moving average using MESA algorithm to adjust to market cycles and reduce lag.";
}
protected override void InitIndicator()
+1 -2
View File
@@ -9,15 +9,14 @@ public class MgdiIndicator : IndicatorBase
[InputParameter("k Factor", sortIndex: 2, minimum: 0.0, maximum: 1.0, increment: 0.1, decimalPlaces: 2)]
public double kfactor { get; set; } = 0.6;
private Mgdi? ma;
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"MGDI {Period} : {kfactor:F2} : {SourceName}";
public MgdiIndicator() : base()
{
Name = "MGDI - McGinley Dynamic Index";
Description = "Adaptive moving average that adjusts to market speed, reducing whipsaws in trending markets.";
}
protected override void InitIndicator()
+1
View File
@@ -13,6 +13,7 @@ public class MmaIndicator : IndicatorBase
public MmaIndicator() : base()
{
Name = "MMA - Modified Moving Average";
Description = "Variation of EMA that reduces lag and smooths price action, balancing responsiveness and stability.";
}
protected override void InitIndicator()
+24
View File
@@ -0,0 +1,24 @@
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class PwmaIndicator : IndicatorBase
{
[InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
public int Period { get; set; } = 10;
private Pwma? ma;
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"PWMA {Period} : {SourceName}";
public PwmaIndicator() : base()
{
Name = "PWMA - Pascal's Weighted Moving Average";
Description = "Moving average using Pascal's triangle coefficients, emphasizing recent data with smooth transitions.";
}
protected override void InitIndicator()
{
base.InitIndicator();
ma = new Pwma(period: Period);
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ public class QemaIndicator : IndicatorBase
public QemaIndicator() : base()
{
Name = "QEMA - Quad Exponential Moving Average";
Description = "Quad Exponential Moving Average";
Description = "Combines four EMAs with different smoothing factors to reduce lag and improve trend following.";
}
protected override void InitIndicator()
+1
View File
@@ -16,6 +16,7 @@ public class RemaIndicator : IndicatorBase
public RemaIndicator() : base()
{
Name = "REMA - Regularized Exponential Moving Average";
Description = "EMA variant with regularization to reduce noise and improve stability in volatile markets.";
}
protected override void InitIndicator()
+2 -2
View File
@@ -10,10 +10,10 @@ public class RmaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"RMA {Period} : {SourceName}";
public RmaIndicator() : base()
{
Name = "RMA - wildeR Moving Average";
Name = "RMA - Wilder's Moving Average";
Description = "Smoothed moving average that reduces whipsaws, commonly used in RSI calculations.";
}
protected override void InitIndicator()
+1
View File
@@ -13,6 +13,7 @@ public class SinemaIndicator : IndicatorBase
public SinemaIndicator() : base()
{
Name = "SINEMA - Sine-Weighted Moving Average";
Description = "Moving average using sine function for weighting, balancing recent and historical price data.";
}
protected override void InitIndicator()
+1 -1
View File
@@ -10,10 +10,10 @@ public class SmaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"SMA {Period} : {SourceName}";
public SmaIndicator() : base()
{
Name = "SMA - Simple Moving Average";
Description = "Basic moving average that calculates the arithmetic mean of prices over a specified period.";
}
protected override void InitIndicator()
+1 -1
View File
@@ -10,10 +10,10 @@ public class SmmaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"SMMA {Period} : {SourceName}";
public SmmaIndicator() : base()
{
Name = "SMMA - Smoothed Moving Average";
Description = "Moving average that gives more weight to recent data while retaining all historical data.";
}
protected override void InitIndicator()
+1
View File
@@ -19,6 +19,7 @@ public class T3Indicator : IndicatorBase
public T3Indicator() : base()
{
Name = "T3 - Tillson T3 Moving Average";
Description = "Triple exponential moving average with reduced lag and smoothing, adjustable via volume factor.";
}
protected override void InitIndicator()
+1
View File
@@ -13,6 +13,7 @@ public class TemaIndicator : IndicatorBase
public TemaIndicator() : base()
{
Name = "TEMA - Triple Exponential Moving Average";
Description = "Moving average that applies EMA three times to reduce lag and improve responsiveness to trends.";
}
protected override void InitIndicator()
+1 -1
View File
@@ -10,10 +10,10 @@ public class TrimaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"TRIMA {Period} : {SourceName}";
public TrimaIndicator() : base()
{
Name = "TRIMA - Triangular Moving Average";
Description = "Weighted moving average giving more importance to the middle of the period for smoother output.";
}
protected override void InitIndicator()
+1 -1
View File
@@ -14,10 +14,10 @@ public class VidyaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"VIDYA {Period} : {SourceName}";
public VidyaIndicator() : base()
{
Name = "VIDYA - Variable Index Dynamic Average";
Description = "Adaptive moving average that adjusts based on market volatility for improved trend following.";
}
protected override void InitIndicator()
+1 -1
View File
@@ -10,10 +10,10 @@ public class WmaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"WMA {Period} : {SourceName}";
public WmaIndicator() : base()
{
Name = "WMA - Weighted Moving Average";
Description = "Moving average that assigns higher weights to recent data points for improved responsiveness.";
}
protected override void InitIndicator()
+2 -2
View File
@@ -10,10 +10,10 @@ public class ZlemaIndicator : IndicatorBase
protected override AbstractBase QuanTAlib => ma!;
public override string ShortName => $"ZLEMA {Period} : {SourceName}";
public ZlemaIndicator() : base()
{
Name = "ZLEMA - Weighted Moving Average";
Name = "ZLEMA - Zero-Lag Exponential Moving Average";
Description = "EMA variant that reduces lag by using linear extrapolation, providing faster response to price changes.";
}
protected override void InitIndicator()
+2 -1
View File
@@ -13,6 +13,7 @@ public class CurvatureIndicator : IndicatorBase
public CurvatureIndicator()
{
Name = "CURVATURE - Rate of Change of Slope";
Description = "Measures the rate of change of the slope, indicating acceleration or deceleration in price movement.";
SeparateWindow = true;
}
@@ -21,4 +22,4 @@ public class CurvatureIndicator : IndicatorBase
curvature = new(Period);
MinHistoryDepths = curvature.WarmupPeriod;
}
}
}
+2 -1
View File
@@ -13,6 +13,7 @@ public class EntropyIndicator : IndicatorBase
public EntropyIndicator() : base()
{
Name = "ENTROPY - Entropy";
Description = "Measures the randomness or uncertainty in price movements, useful for identifying market phases.";
SeparateWindow = true;
}
@@ -22,4 +23,4 @@ public class EntropyIndicator : IndicatorBase
MinHistoryDepths = entropy.WarmupPeriod;
base.InitIndicator();
}
}
}
+2 -1
View File
@@ -13,6 +13,7 @@ public class KurtosisIndicator : IndicatorBase
public KurtosisIndicator() : base()
{
Name = "KURTOSIS - Relative Flatness";
Description = "Measures the 'tailedness' of price distribution, indicating potential for extreme market movements.";
SeparateWindow = true;
}
@@ -22,4 +23,4 @@ public class KurtosisIndicator : IndicatorBase
MinHistoryDepths = kurtosis.WarmupPeriod;
base.InitIndicator();
}
}
}
+2 -1
View File
@@ -15,7 +15,8 @@ public class MaxIndicator : IndicatorBase
public MaxIndicator() : base()
{
Name = "MAX - Maximum value (with decay) ";
Name = "MAX - Maximum value (with decay)";
Description = "Tracks the maximum value over a period, with a decay factor to gradually adjust to new highs.";
}
protected override void InitIndicator()
+2 -1
View File
@@ -12,6 +12,7 @@ public class MedianIndicator : IndicatorBase
public MedianIndicator() : base()
{
Name = "MEDIAN - Median historical value";
Description = "Calculates the middle value of price data over a specified period, less affected by outliers than mean.";
}
protected override void InitIndicator()
@@ -20,4 +21,4 @@ public class MedianIndicator : IndicatorBase
MinHistoryDepths = med.WarmupPeriod;
base.InitIndicator();
}
}
}
+2 -1
View File
@@ -15,6 +15,7 @@ public class MinIndicator : IndicatorBase
public MinIndicator() : base()
{
Name = "MIN - Minimum value (with decay)";
Description = "Tracks the minimum value over a period, with a decay factor to gradually adjust to new lows.";
}
protected override void InitIndicator()
@@ -24,4 +25,4 @@ public class MinIndicator : IndicatorBase
Source = 3;
base.InitIndicator();
}
}
}
+2 -1
View File
@@ -12,6 +12,7 @@ public class ModeIndicator : IndicatorBase
public ModeIndicator() : base()
{
Name = "MODE - Most frequent historical value";
Description = "Identifies the most frequently occurring price value over a specified period, indicating price clusters.";
}
protected override void InitIndicator()
@@ -20,4 +21,4 @@ public class ModeIndicator : IndicatorBase
MinHistoryDepths = mode.WarmupPeriod;
base.InitIndicator();
}
}
}
+3 -3
View File
@@ -14,7 +14,8 @@ public class PercentileIndicator : IndicatorBase
public PercentileIndicator() : base()
{
Name = "PERCENTILE - n-th Percentile ";
Name = "PERCENTILE - n-th Percentile";
Description = "Calculates the value below which a given percentage of observations falls within a specified period.";
SeparateWindow = false;
}
@@ -24,5 +25,4 @@ public class PercentileIndicator : IndicatorBase
MinHistoryDepths = percentile.WarmupPeriod;
base.InitIndicator();
}
}
}
+2 -2
View File
@@ -1,4 +1,3 @@
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
@@ -14,6 +13,7 @@ public class SkewIndicator : IndicatorBase
public SkewIndicator() : base()
{
Name = "SKEW - Skewness";
Description = "Measures the asymmetry of price distribution, indicating potential trend direction or reversal.";
SeparateWindow = true;
}
@@ -23,4 +23,4 @@ public class SkewIndicator : IndicatorBase
MinHistoryDepths = skew.WarmupPeriod;
base.InitIndicator();
}
}
}
+2 -1
View File
@@ -13,6 +13,7 @@ public class SlopeIndicator : IndicatorBase
public SlopeIndicator()
{
Name = "SLOPE - Trend Slope";
Description = "Measures the rate of change in price over a specified period, indicating trend strength and direction.";
SeparateWindow = true;
}
@@ -21,4 +22,4 @@ public class SlopeIndicator : IndicatorBase
slope = new(Period);
MinHistoryDepths = slope.WarmupPeriod;
}
}
}
+10 -12
View File
@@ -5,28 +5,26 @@
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
<UpdateAssemblyInfo>true</UpdateAssemblyInfo>
<GenerateGitVersionInformation>true</GenerateGitVersionInformation>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
<Compile Include="..\..\lib\**\*.cs" Exclude="..\..\lib\obj\**">
<Link>lib\%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
<Target Name="CopyCustomContent" AfterTargets="AfterBuild" Condition="'$(IsLocalBuild)' == 'true'">
<Copy SourceFiles="$(OutputPath)\Statistics.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Statistics" />
</Target>
<ItemGroup>
<Compile Include="..\*.cs">
<Link>%(Filename)%(Extension)</Link>
</Compile>
<Compile Include="..\*.cs" />
<Compile Include="*.cs" />
<ProjectReference Include="..\..\lib\quantalib.csproj" Private="true" IncludeAssets="all" />
<Reference Include="TradingPlatform.BusinessLayer">
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
</Reference>
<None Include="..\..\.github\TradingPlatform.BusinessLayer.xml">
<Link>TradingPlatform.BusinessLayer.xml</Link>
</None>
</ItemGroup>
</Project>
<Target Name="CopyCustomContent" AfterTargets="AfterBuild" Condition="'$(IsLocalBuild)' == 'true'">
<Copy SourceFiles="$(OutputPath)\Statistics.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Statistics" />
</Target>
</Project>
+2 -1
View File
@@ -15,6 +15,7 @@ public class StddevIndicator : IndicatorBase
public StddevIndicator() : base()
{
Name = "STDDEV - Standard Deviation";
Description = "Measures price volatility by calculating the dispersion of prices from their average over a period.";
SeparateWindow = true;
}
@@ -24,4 +25,4 @@ public class StddevIndicator : IndicatorBase
MinHistoryDepths = stddev.WarmupPeriod;
base.InitIndicator();
}
}
}
@@ -15,6 +15,7 @@ public class VarianceIndicator : IndicatorBase
public VarianceIndicator() : base()
{
Name = "VAR - Variance";
Description = "Measures the spread of price data around its mean, indicating volatility and potential trend changes.";
SeparateWindow = true;
}
@@ -25,4 +26,4 @@ public class VarianceIndicator : IndicatorBase
MinHistoryDepths = variance.WarmupPeriod;
base.InitIndicator();
}
}
}
+2 -2
View File
@@ -13,6 +13,7 @@ public class ZScoreIndicator : IndicatorBase
public ZScoreIndicator() : base()
{
Name = "ZSCORE - Standard Score";
Description = "Measures how many standard deviations a price is from the mean, indicating overbought/oversold levels.";
SeparateWindow = true;
}
@@ -22,5 +23,4 @@ public class ZScoreIndicator : IndicatorBase
MinHistoryDepths = zScore.WarmupPeriod;
base.InitIndicator();
}
}
}
+2 -1
View File
@@ -12,6 +12,7 @@ public class AtrIndicator : IndicatorBarBase
public AtrIndicator()
{
Name = "ATR - Average True Range";
Description = "Measures market volatility by calculating the average range between high and low prices.";
SeparateWindow = true;
}
@@ -20,4 +21,4 @@ public class AtrIndicator : IndicatorBarBase
atr = new(Period);
MinHistoryDepths = atr!.WarmupPeriod;
}
}
}
+2 -1
View File
@@ -16,6 +16,7 @@ public class HistoricalIndicator : IndicatorBase
public HistoricalIndicator() : base()
{
Name = "HV - Historical Volatility";
Description = "Measures price fluctuations over time, indicating market volatility based on past price movements.";
SeparateWindow = true;
}
@@ -25,4 +26,4 @@ public class HistoricalIndicator : IndicatorBase
MinHistoryDepths = historical.WarmupPeriod;
base.InitIndicator();
}
}
}
+2 -1
View File
@@ -16,6 +16,7 @@ public class RealizedIndicator : IndicatorBase
public RealizedIndicator() : base()
{
Name = "RV - Realized Volatility";
Description = "Measures actual price volatility over a specific period, useful for risk assessment and forecasting.";
SeparateWindow = true;
}
@@ -25,4 +26,4 @@ public class RealizedIndicator : IndicatorBase
MinHistoryDepths = realized.WarmupPeriod;
base.InitIndicator();
}
}
}
+2 -5
View File
@@ -13,12 +13,9 @@ public class RviIndicator : IndicatorBase
public RviIndicator() : base()
{
Name = "RVI - Relative Volatility Index";
Description = "Measures the direction of volatility, helping to identify overbought or oversold conditions in price.";
SeparateWindow = true;
// Adding upper and lower reference lines
//AddLineSeries("UpperLevel", 80, System.Drawing.Color.Gray, 1, LineStyle.Dot);
//AddLineSeries("LowerLevel", 20, System.Drawing.Color.Gray, 1, LineStyle.Dot);
}
}
protected override void InitIndicator()
{
+10 -12
View File
@@ -5,28 +5,26 @@
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
<UpdateAssemblyInfo>true</UpdateAssemblyInfo>
<GenerateGitVersionInformation>true</GenerateGitVersionInformation>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
<Compile Include="..\..\lib\**\*.cs" Exclude="..\..\lib\obj\**">
<Link>lib\%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
<Target Name="CopyCustomContent" AfterTargets="AfterBuild" Condition="'$(IsLocalBuild)' == 'true'">
<Copy SourceFiles="$(OutputPath)\Volatility.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Volatility" />
</Target>
<ItemGroup>
<Compile Include="..\*.cs">
<Link>%(Filename)%(Extension)</Link>
</Compile>
<Compile Include="..\*.cs" />
<Compile Include="*.cs" />
<ProjectReference Include="..\..\lib\quantalib.csproj" Private="true" IncludeAssets="all" />
<Reference Include="TradingPlatform.BusinessLayer">
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
</Reference>
<None Include="..\..\.github\TradingPlatform.BusinessLayer.xml">
<Link>TradingPlatform.BusinessLayer.xml</Link>
</None>
</ItemGroup>
</Project>
<Target Name="CopyCustomContent" AfterTargets="AfterBuild" Condition="'$(IsLocalBuild)' == 'true'">
<Copy SourceFiles="$(OutputPath)\Volatility.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Volatility" />
</Target>
</Project>
+2 -1
View File
@@ -3,10 +3,11 @@ using TradingPlatform.BusinessLayer;
using TradingPlatform.BusinessLayer.Chart;
using System.Runtime.CompilerServices;
using System.Drawing.Drawing2D;
using QuanTAlib;
using System.Collections;
using TradingPlatform.BusinessLayer.TimeSync;
namespace QuanTAlib;
#pragma warning disable CA1416 // Validate platform compatibility
public abstract class IndicatorBase : Indicator, IWatchlistIndicator
{