Refactor tests and project files for improved consistency and clarity

This commit is contained in:
Miha Kralj
2025-12-27 18:09:04 -08:00
parent bf99f3caa9
commit f2487ced04
58 changed files with 863 additions and 276 deletions
+2 -1
View File
@@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net10.0;net8.0</TargetFrameworks>
<TargetFrameworks Condition="'$(Configuration)' == 'Release'">net10.0;net8.0</TargetFrameworks>
<TargetFramework Condition="'$(Configuration)' == 'Debug'">net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
+10 -11
View File
@@ -1,7 +1,7 @@
namespace QuanTAlib.Tests
{
public class TBarTests
namespace QuanTAlib.Tests;
public class TBarTests
{
[Fact]
public void Constructor_SetsPropertiesCorrectly()
@@ -195,13 +195,13 @@ namespace QuanTAlib.Tests
string result = bar.ToString();
Assert.Contains("2024-06-15", result);
Assert.Contains("10:30:00", result);
Assert.Contains("O=100.50", result);
Assert.Contains("H=110.25", result);
Assert.Contains("L=90.75", result);
Assert.Contains("C=105.00", result);
Assert.Contains("V=1000.00", result);
Assert.Contains("2024-06-15", result, StringComparison.Ordinal);
Assert.Contains("10:30:00", result, StringComparison.Ordinal);
Assert.Contains("O=100.50", result, StringComparison.Ordinal);
Assert.Contains("H=110.25", result, StringComparison.Ordinal);
Assert.Contains("L=90.75", result, StringComparison.Ordinal);
Assert.Contains("C=105.00", result, StringComparison.Ordinal);
Assert.Contains("V=1000.00", result, StringComparison.Ordinal);
}
[Fact]
@@ -345,6 +345,5 @@ namespace QuanTAlib.Tests
var bar2 = new TBar(12346, 100, 110, 90, 105, 1000);
Assert.True(bar1 != bar2);
}
}
}
+3 -3
View File
@@ -45,9 +45,9 @@ namespace QuanTAlib.Tests
string result = tValue.ToString();
Assert.Contains("2023-01-01", result);
Assert.Contains("12:00:00", result);
Assert.Contains("123.46", result);
Assert.Contains("2023-01-01", result, StringComparison.Ordinal);
Assert.Contains("12:00:00", result, StringComparison.Ordinal);
Assert.Contains("123.46", result, StringComparison.Ordinal);
}
[Fact]
+1 -1
View File
@@ -49,7 +49,7 @@ public static class ValidationHelper
}
}
public static void VerifyData<TResult>(double[] qOutput, List<TResult> sSeries, Func<TResult, double?> selector, int skip = 100, double tolerance = DefaultTolerance)
public static void VerifyData<TResult>(double[] qOutput, IReadOnlyList<TResult> sSeries, Func<TResult, double?> selector, int skip = 100, double tolerance = DefaultTolerance)
{
Assert.Equal(qOutput.Length, sSeries.Count);
+5 -5
View File
@@ -35,9 +35,9 @@ public class AoIndicatorTests
var indicator = new AoIndicator { FastPeriod = 10, SlowPeriod = 40 };
indicator.Initialize();
Assert.Contains("AO", indicator.ShortName);
Assert.Contains("10", indicator.ShortName);
Assert.Contains("40", indicator.ShortName);
Assert.Contains("AO", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("10", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("40", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -45,8 +45,8 @@ public class AoIndicatorTests
{
var indicator = new AoIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Ao.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Ao.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+2 -2
View File
@@ -69,10 +69,10 @@ public sealed class AoValidationTests : IDisposable
var tulipIndicator = Tulip.Indicators.ao;
double[][] inputs = { high, low };
double[] options = { };
double[] options = Array.Empty<double>();
int lookback = 33;
double[][] outputs = { new double[_data.Bars.Count - lookback] };
double[][] outputs = [new double[_data.Bars.Count - lookback]];
tulipIndicator.Run(inputs, options, outputs);
var tulipResults = outputs[0];
+5 -5
View File
@@ -35,9 +35,9 @@ public class ApoIndicatorTests
var indicator = new ApoIndicator { FastPeriod = 10, SlowPeriod = 40 };
indicator.Initialize();
Assert.Contains("APO", indicator.ShortName);
Assert.Contains("10", indicator.ShortName);
Assert.Contains("40", indicator.ShortName);
Assert.Contains("APO", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("10", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("40", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -45,8 +45,8 @@ public class ApoIndicatorTests
{
var indicator = new ApoIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Apo.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Apo.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+4 -4
View File
@@ -34,8 +34,8 @@ public class AroonIndicatorTests
var indicator = new AroonIndicator { Period = 20 };
indicator.Initialize();
Assert.Contains("Aroon", indicator.ShortName);
Assert.Contains("20", indicator.ShortName);
Assert.Contains("Aroon", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("20", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -43,8 +43,8 @@ public class AroonIndicatorTests
{
var indicator = new AroonIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Aroon.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Aroon.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
@@ -34,8 +34,8 @@ public class AroonOscIndicatorTests
var indicator = new AroonOscIndicator { Period = 20 };
indicator.Initialize();
Assert.Contains("AroonOsc", indicator.ShortName);
Assert.Contains("20", indicator.ShortName);
Assert.Contains("AroonOsc", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("20", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -43,8 +43,8 @@ public class AroonOscIndicatorTests
{
var indicator = new AroonOscIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("AroonOsc.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("AroonOsc.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
@@ -97,41 +97,4 @@ public sealed class AroonOscValidationTests : IDisposable
ValidationHelper.VerifyData(results, tulipOsc, lookback: 14);
}
[Fact(Skip = "Ooples implementation deviates significantly from standard (TA-Lib, Tulip, Skender, QuanTAlib)")]
public void MatchesOoples()
{
// Note: OoplesFinance implementation of Aroon Oscillator is an outlier.
// It deviates from the consensus of TA-Lib, Tulip, Skender, and QuanTAlib.
// The deviation is not a simple offset; it involves inconsistent steps and reversals,
// likely due to differences in how the high/low window indices are tracked.
var aroon = new AroonOsc(14);
var results = new List<double>();
for (int i = 0; i < _data.Bars.Count; i++)
{
var res = aroon.Update(_data.Bars[i]);
results.Add(res.Value);
}
var ooplesData = _data.SkenderQuotes.Select(q => new TickerData
{
Date = q.Date,
Open = (double)q.Open,
High = (double)q.High,
Low = (double)q.Low,
Close = (double)q.Close,
Volume = (double)q.Volume
}).ToList();
var stockData = new StockData(ooplesData);
// Ooples only provides CalculateAroonOscillator
var aroonOscResults = stockData.CalculateAroonOscillator(14);
var ooplesOsc = aroonOscResults.OutputValues["Aroon"]
.ToArray();
// Verify Oscillator
ValidationHelper.VerifyData(results, ooplesOsc, lookback: 14, tolerance: ValidationHelper.OoplesTolerance);
}
}
+2 -2
View File
@@ -40,8 +40,8 @@ public class BopIndicatorTests
{
var indicator = new BopIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Bop.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Bop.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+1 -1
View File
@@ -62,7 +62,7 @@ public sealed class BopValidationTests : IDisposable
var close = _data.Bars.Close.Values.ToArray();
double[][] inputs = { open, high, low, close };
double[] options = { }; // No options for BOP
double[] options = Array.Empty<double>(); // No options for BOP
var bopInd = Tulip.Indicators.bop;
double[][] outputs = { new double[open.Length - bopInd.Start(options)] };
+5 -5
View File
@@ -38,9 +38,9 @@ public class CfbIndicatorTests
// Initialize to update SourceName
indicator.Initialize();
Assert.Contains("CFB", indicator.ShortName);
Assert.Contains("5-20", indicator.ShortName);
Assert.Contains("Close", indicator.ShortName);
Assert.Contains("CFB", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("5-20", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("Close", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -48,8 +48,8 @@ public class CfbIndicatorTests
{
var indicator = new CfbIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Cfb.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Cfb.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+4 -4
View File
@@ -35,8 +35,8 @@ public class DmxIndicatorTests
// Initialize to update SourceName (though DMX doesn't use SourceName)
indicator.Initialize();
Assert.Contains("DMX", indicator.ShortName);
Assert.Contains("20", indicator.ShortName);
Assert.Contains("DMX", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("20", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -44,8 +44,8 @@ public class DmxIndicatorTests
{
var indicator = new DmxIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Dmx.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Dmx.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+2 -2
View File
@@ -49,8 +49,8 @@ public class MacdIndicatorTests
{
var indicator = new MacdIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Macd.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Macd.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+3 -3
View File
@@ -39,7 +39,7 @@ public class RsiIndicatorTests
};
indicator.Initialize();
Assert.Contains("RSI(20)", indicator.ShortName);
Assert.Contains("RSI(20)", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -47,8 +47,8 @@ public class RsiIndicatorTests
{
var indicator = new RsiIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Rsi.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Rsi.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+394 -50
View File
@@ -1,63 +1,261 @@
using Xunit;
using System;
using System.Collections.Generic;
using Xunit;
namespace QuanTAlib.Tests;
namespace QuanTAlib;
public class RsiTests
{
[Fact]
public void BasicCalculation()
public void Constructor_InvalidParameters_ThrowsArgumentException()
{
Assert.Throws<ArgumentException>(() => new Rsi(0));
Assert.Throws<ArgumentException>(() => new Rsi(-1));
}
[Fact]
public void BasicCalculation_DoesNotCrash()
{
var rsi = new Rsi(14);
// RSI requires a period of data to be valid
var gbm = new GBM();
var series = gbm.Fetch(1000, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
for (int i = 0; i < series.Count; i++)
{
rsi.Update(series.Close[i]);
}
Assert.True(double.IsFinite(rsi.Last.Value));
}
[Fact]
public void Properties_Accessible()
{
var rsi = new Rsi(14);
Assert.Equal("Rsi(14)", rsi.Name);
Assert.False(rsi.IsHot);
Assert.Equal(0, rsi.Last.Value);
}
[Fact]
public void BatchMatchesStreaming()
public void IsHot_BecomesTrueAfterWarmup()
{
var rsi = new Rsi(5);
var series = new TSeries();
// Generate some data
for (int i = 0; i < 20; i++)
var rsi = new Rsi(14);
var gbm = new GBM();
var series = gbm.Fetch(50, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
Assert.False(rsi.IsHot);
// RSI wraps two RMA indicators (gain and loss)
// RMA wraps EMA with alpha = 1/period
// EMA becomes hot when E <= 0.05, which occurs after ~-ln(0.05)/ln(1-alpha) values
// For period=14: alpha=1/14, needs ~40 values to become hot
// Both RMAs must be hot for RSI to be hot
for (int i = 0; i < 45; i++)
{
series.Add(new TValue(DateTime.UtcNow.AddMinutes(i), 100 + Math.Sin(i) * 10));
rsi.Update(series.Close[i]);
if (i < 40)
{
Assert.False(rsi.IsHot, $"Should not be hot at index {i}");
}
}
var batchResult = rsi.Update(series);
// After sufficient warmup, IsHot should be true
Assert.True(rsi.IsHot);
}
[Fact]
public void IsNew_True_AdvancesState()
{
var rsi = new Rsi(5);
var gbm = new GBM();
var series = gbm.Fetch(10, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
for (int i = 0; i < 9; i++)
{
rsi.Update(series.Close[i], isNew: true);
}
var val1 = rsi.Update(series.Close[9], isNew: true);
var nextTime = series.Close[9].Time + TimeSpan.FromMinutes(1).Ticks;
var val2 = rsi.Update(new TValue(nextTime, series.Close[9].Value + 1), isNew: true);
Assert.NotEqual(val1.Value, val2.Value);
}
[Fact]
public void IsNew_False_UpdatesCurrentBar()
{
var rsi = new Rsi(5);
var gbm = new GBM();
var series = gbm.Fetch(10, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
for (int i = 0; i < 9; i++)
{
rsi.Update(series.Close[i]);
}
var val1 = rsi.Update(series.Close[9], isNew: true);
var modifiedValue = new TValue(series.Close[9].Time, series.Close[9].Value + 5);
var val2 = rsi.Update(modifiedValue, isNew: false);
// Should update the same bar
Assert.Equal(val1.Time, val2.Time);
Assert.NotEqual(val1.Value, val2.Value);
}
[Fact]
public void IsNew_Consistency()
{
var rsi = new Rsi(14);
var gbm = new GBM();
var series = gbm.Fetch(100, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
// Feed first 99
for (int i = 0; i < 99; i++)
{
rsi.Update(series.Close[i]);
}
// Update with 100th point (isNew=true)
rsi.Update(series.Close[99], true);
// Update with modified 100th point (isNew=false)
var modifiedValue = new TValue(series.Close[99].Time, series.Close[99].Value + 2.0);
var val2 = rsi.Update(modifiedValue, false);
// Create new instance and feed up to modified
var rsi2 = new Rsi(14);
for (int i = 0; i < 99; i++)
{
rsi2.Update(series.Close[i]);
}
var val3 = rsi2.Update(modifiedValue, true);
Assert.Equal(val3.Value, val2.Value, 1e-9);
}
[Fact]
public void IterativeCorrections_RestoreToOriginalState()
{
var rsi = new Rsi(10);
var gbm = new GBM();
var series = gbm.Fetch(50, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
// Feed N values
for (int i = 0; i < 30; i++)
{
rsi.Update(series.Close[i]);
}
var originalValue = rsi.Last;
// Make M updates with isNew=false
for (int m = 0; m < 5; m++)
{
var modifiedValue = new TValue(series.Close[29].Time, series.Close[29].Value + m);
rsi.Update(modifiedValue, isNew: false);
}
// Restore with original 30th value
var restoredValue = rsi.Update(series.Close[29], isNew: false);
Assert.Equal(originalValue.Value, restoredValue.Value, 1e-9);
}
[Fact]
public void Reset_ClearsState()
{
var rsi = new Rsi(14);
var gbm = new GBM();
var series = gbm.Fetch(100, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
for (int i = 0; i < series.Count; i++)
{
rsi.Update(series.Close[i]);
}
Assert.True(rsi.IsHot);
var valueBefore = rsi.Last.Value;
rsi.Reset();
var streamResults = new System.Collections.Generic.List<double>();
foreach (var item in series)
Assert.False(rsi.IsHot);
Assert.Equal(0, rsi.Last.Value);
// Feed again
for (int i = 0; i < series.Count; i++)
{
streamResults.Add(rsi.Update(item).Value);
rsi.Update(series.Close[i]);
}
for (int i = 0; i < series.Count; i++)
{
Assert.Equal(batchResult[i].Value, streamResults[i], 8);
}
Assert.True(rsi.IsHot);
Assert.Equal(valueBefore, rsi.Last.Value, 1e-9);
}
[Fact]
public void SpanMatchesBatch()
public void NaN_Input_DoesNotCrash()
{
var rsi = new Rsi(5);
var series = new TSeries();
// Generate some data
var rsi = new Rsi(10);
var gbm = new GBM();
var series = gbm.Fetch(20, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
for (int i = 0; i < 15; i++)
{
rsi.Update(series.Close[i]);
}
// Feed NaN
var nanValue = new TValue(DateTime.UtcNow, double.NaN);
var result = rsi.Update(nanValue);
// Should not crash and should return finite value
Assert.True(double.IsFinite(result.Value));
}
[Fact]
public void Infinity_Input_DoesNotCrash()
{
var rsi = new Rsi(10);
var gbm = new GBM();
var series = gbm.Fetch(20, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
for (int i = 0; i < 15; i++)
{
rsi.Update(series.Close[i]);
}
var infValue = new TValue(DateTime.UtcNow, double.PositiveInfinity);
var result = rsi.Update(infValue);
Assert.True(double.IsFinite(result.Value));
}
[Fact]
public void MultipleNaN_ContinuesCorrectly()
{
var rsi = new Rsi(10);
var gbm = new GBM();
var series = gbm.Fetch(30, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
for (int i = 0; i < 20; i++)
{
series.Add(new TValue(DateTime.UtcNow.AddMinutes(i), 100 + Math.Sin(i) * 10));
rsi.Update(series.Close[i]);
}
var batchResult = rsi.Update(series);
var output = new double[series.Count];
Rsi.Calculate(series.Values, output, 5);
for (int i = 0; i < series.Count; i++)
// Feed multiple NaN
for (int i = 0; i < 5; i++)
{
Assert.Equal(batchResult[i].Value, output[i], 8);
var nanValue = new TValue(DateTime.UtcNow.AddMinutes(i), double.NaN);
var result = rsi.Update(nanValue);
Assert.True(double.IsFinite(result.Value));
}
// Continue with valid data
for (int i = 20; i < 30; i++)
{
var result = rsi.Update(series.Close[i]);
Assert.True(double.IsFinite(result.Value));
}
}
@@ -72,24 +270,170 @@ public class RsiTests
}
var result = rsi.Update(series);
// Flat line means no gains or losses, RSI should be 50 (or 0/100 depending on implementation details, but typically 50 or 0 if no moves)
// Actually, if AvgGain=0 and AvgLoss=0, RSI is typically defined as 50 or 0.
// Our implementation: RS = 0/0 -> NaN?
// Let's check implementation.
// If AvgLoss is 0, RSI is 100.
// If AvgGain is 0, RSI is 0.
// If both are 0?
// In Rma: if all inputs are 0, Rma is 0.
// So AvgGain=0, AvgLoss=0.
// RS = 0/0 = NaN.
// RSI = 100 - 100/(1+NaN) = NaN.
// Let's see what happens.
// Actually, standard behavior for flat line is often 50 or 0.
// Let's verify what our implementation does.
// If we look at Rsi.cs:
// if (avgLoss == 0) return avgGain == 0 ? 50 : 100;
// Flat line: no gains or losses, RSI = 50
Assert.Equal(50, result.Last.Value);
}
[Fact]
public void TSeries_Update_Matches_Streaming()
{
var rsi = new Rsi(14);
var gbm = new GBM();
var series = gbm.Fetch(200, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
var streamingResults = new List<double>();
for (int i = 0; i < series.Count; i++)
{
streamingResults.Add(rsi.Update(series.Close[i]).Value);
}
var rsi2 = new Rsi(14);
var seriesResults = rsi2.Update(series.Close);
Assert.Equal(streamingResults.Count, seriesResults.Count);
for (int i = 0; i < seriesResults.Count; i++)
{
Assert.Equal(streamingResults[i], seriesResults.Values[i], 1e-9);
}
}
[Fact]
public void StaticBatch_Matches_Streaming()
{
var gbm = new GBM();
var series = gbm.Fetch(200, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
var rsi = new Rsi(14);
var streamingResults = new List<double>();
for (int i = 0; i < series.Count; i++)
{
streamingResults.Add(rsi.Update(series.Close[i]).Value);
}
var batchResults = Rsi.Batch(series.Close, 14);
Assert.Equal(streamingResults.Count, batchResults.Count);
for (int i = 0; i < batchResults.Count; i++)
{
Assert.Equal(streamingResults[i], batchResults.Values[i], 1e-9);
}
}
[Fact]
public void SpanCalc_ValidatesInput()
{
var source = new double[10];
var output = new double[5];
Assert.Throws<ArgumentException>(() => Rsi.Calculate(source, output, 14));
}
[Fact]
public void SpanCalc_InvalidPeriod_Throws()
{
var source = new double[10];
var output = new double[10];
Assert.Throws<ArgumentException>(() => Rsi.Calculate(source, output, 0));
Assert.Throws<ArgumentException>(() => Rsi.Calculate(source, output, -1));
}
[Fact]
public void SpanCalc_MatchesTSeriesCalc()
{
var gbm = new GBM();
var series = gbm.Fetch(200, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
var batchResults = Rsi.Batch(series.Close, 14);
var output = new double[series.Count];
Rsi.Calculate(series.Close.Values, output, 14);
for (int i = 0; i < output.Length; i++)
{
Assert.Equal(batchResults.Values[i], output[i], 1e-9);
}
}
[Fact]
public void SpanCalc_HandlesNaN()
{
var source = new double[20];
var gbm = new GBM();
var series = gbm.Fetch(20, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
for (int i = 0; i < 20; i++)
{
source[i] = series.Close[i].Value;
}
source[10] = double.NaN;
source[15] = double.NaN;
var output = new double[20];
Rsi.Calculate(source, output, 10);
// Should not crash and produce finite results
for (int i = 0; i < output.Length; i++)
{
Assert.True(double.IsFinite(output[i]) || output[i] == 0);
}
}
[Fact]
public void AllModes_ProduceSameResult()
{
int period = 14;
var gbm = new GBM();
var series = gbm.Fetch(200, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
// 1. Batch Mode
var batchSeries = Rsi.Batch(series.Close, period);
double expected = batchSeries.Last.Value;
// 2. Span Mode
var spanOutput = new double[series.Count];
Rsi.Calculate(series.Close.Values, spanOutput, period);
double spanResult = spanOutput[^1];
// 3. Streaming Mode
var streamingRsi = new Rsi(period);
for (int i = 0; i < series.Count; i++)
{
streamingRsi.Update(series.Close[i]);
}
double streamingResult = streamingRsi.Last.Value;
// 4. Eventing Mode
var pubSource = new TSeries();
var eventingRsi = new Rsi(pubSource, period);
for (int i = 0; i < series.Count; i++)
{
pubSource.Add(series.Close[i]);
}
double eventingResult = eventingRsi.Last.Value;
// Assert
Assert.Equal(expected, spanResult, 9);
Assert.Equal(expected, streamingResult, 9);
Assert.Equal(expected, eventingResult, 9);
}
[Fact]
public void Chainability_Works()
{
var rsi = new Rsi(14);
var gbm = new GBM();
var series = gbm.Fetch(10, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
// Test TSeries chain
var result = rsi.Update(series.Close);
Assert.NotNull(result);
Assert.IsType<TSeries>(result);
// Test TValue chain (returns TValue)
var result2 = rsi.Update(series.Close[0]);
Assert.IsType<TValue>(result2);
}
}
+4 -4
View File
@@ -34,8 +34,8 @@ public class RsxIndicatorTests
{
var indicator = new RsxIndicator { Period = 15 };
Assert.Contains("RSX", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("RSX", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -43,8 +43,8 @@ public class RsxIndicatorTests
{
var indicator = new RsxIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Rsx.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Rsx.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+4 -4
View File
@@ -34,8 +34,8 @@ public class VelIndicatorTests
{
var indicator = new VelIndicator { Period = 15 };
Assert.Contains("VEL", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("VEL", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -43,8 +43,8 @@ public class VelIndicatorTests
{
var indicator = new VelIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Vel.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Vel.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+2 -26
View File
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net10.0;net8.0</TargetFrameworks>
<TargetFrameworks Condition="'$(Configuration)' == 'Release'">net10.0;net8.0</TargetFrameworks>
<TargetFramework Condition="'$(Configuration)' == 'Debug'">net10.0</TargetFramework>
<Title>QuanTAlib</Title>
<Product>Library of TA Calculations, Charts and Strategies for Quantower</Product>
<Description>Quantitative Technical Analysis Library in C# for Quantower</Description>
@@ -42,31 +43,6 @@
<Compile Include="**/*.cs" Exclude="**/*.Tests.cs;**/*.Quantower.cs;**/obj/**/*.cs;**/bin/**/*.cs;feeds/gbm/ValidationHelper.cs;feeds/gbm/ValidationTestData.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="GitVersion.MsBuild" Version="6.5.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="JetBrains.Annotations" Version="2025.2.4" />
<PackageReference Include="Roslynator.Analyzers" Version="4.12.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.183">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.*">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="..\.github\QuanTAlib2.png" Pack="true" Visible="false" PackagePath="" />
+2 -2
View File
@@ -34,8 +34,8 @@ public class AlmaIndicatorTests
{
var indicator = new AlmaIndicator { Period = 15 };
Assert.Contains("ALMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("ALMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
+2 -2
View File
@@ -32,8 +32,8 @@ public class BesselIndicatorTests
{
var indicator = new BesselIndicator { Length = 15 };
Assert.Contains("BESSEL", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("BESSEL", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -34,8 +34,8 @@ public class BilateralIndicatorTests
{
var indicator = new BilateralIndicator { Period = 15 };
Assert.Contains("Bilateral", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("Bilateral", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -43,8 +43,8 @@ public class BilateralIndicatorTests
{
var indicator = new BilateralIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Bilateral.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Bilateral.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+4 -4
View File
@@ -34,8 +34,8 @@ public class BlmaIndicatorTests
var indicator = new BlmaIndicator { Period = 20 };
indicator.Initialize();
Assert.Contains("BLMA", indicator.ShortName);
Assert.Contains("20", indicator.ShortName);
Assert.Contains("BLMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("20", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -43,8 +43,8 @@ public class BlmaIndicatorTests
{
var indicator = new BlmaIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Blma.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Blma.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+4 -4
View File
@@ -35,8 +35,8 @@ public class ButterIndicatorTests
var indicator = new ButterIndicator { Period = 20 };
indicator.Initialize();
Assert.Contains("BUTTER", indicator.ShortName);
Assert.Contains("20", indicator.ShortName);
Assert.Contains("BUTTER", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("20", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -44,8 +44,8 @@ public class ButterIndicatorTests
{
var indicator = new ButterIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Butter.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Butter.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+5 -5
View File
@@ -33,8 +33,8 @@ public class ConvIndicatorTests
{
var indicator = new ConvIndicator();
Assert.Contains("CONV", indicator.ShortName);
Assert.Contains("Close", indicator.ShortName);
Assert.Contains("CONV", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("Close", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -42,8 +42,8 @@ public class ConvIndicatorTests
{
var indicator = new ConvIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Conv.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Conv.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
@@ -172,6 +172,6 @@ public class ConvIndicatorTests
{
var indicator = new ConvIndicator();
Assert.Contains("Convolution", indicator.Description);
Assert.Contains("Convolution", indicator.Description, StringComparison.Ordinal);
}
}
+2 -5
View File
@@ -43,13 +43,10 @@ public class ConvIndicator : Indicator, IWatchlistIndicator
try
{
var weights = WeightsInput.Split(',')
.Select(s => double.Parse(s.Trim()))
.Select(s => double.Parse(s.Trim(), System.Globalization.CultureInfo.InvariantCulture))
.ToArray();
if (weights.Length == 0)
throw new ArgumentException("Weights cannot be empty");
_conv = new Conv(weights);
_conv = new Conv(weights.Length == 0 ? [1.0] : weights);
}
catch (FormatException)
{
+4 -4
View File
@@ -32,8 +32,8 @@ public class DemaIndicatorTests
{
var indicator = new DemaIndicator { Period = 15 };
Assert.Contains("DEMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("DEMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -41,8 +41,8 @@ public class DemaIndicatorTests
{
var indicator = new DemaIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Dema.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Dema.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+4 -4
View File
@@ -32,8 +32,8 @@ public class DwmaIndicatorTests
{
var indicator = new DwmaIndicator { Period = 15 };
Assert.Contains("DWMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("DWMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -41,8 +41,8 @@ public class DwmaIndicatorTests
{
var indicator = new DwmaIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Dwma.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Dwma.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+2 -2
View File
@@ -32,8 +32,8 @@ public class EmaIndicatorTests
{
var indicator = new EmaIndicator { Period = 15 };
Assert.Contains("EMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("EMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
+4 -4
View File
@@ -33,8 +33,8 @@ public class HmaIndicatorTests
{
var indicator = new HmaIndicator { Period = 21 };
Assert.Contains("HMA", indicator.ShortName);
Assert.Contains("21", indicator.ShortName);
Assert.Contains("HMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("21", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -42,8 +42,8 @@ public class HmaIndicatorTests
{
var indicator = new HmaIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Hma.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Hma.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+2 -2
View File
@@ -13,8 +13,8 @@ public class HtitIndicatorTests
var indicator = new HtitIndicator();
indicator.Initialize();
Assert.Equal("HTIT - Ehlers Hilbert Transform Instantaneous Trend", indicator.Name);
Assert.StartsWith("HTIT", indicator.ShortName);
Assert.Contains("Close", indicator.ShortName);
Assert.StartsWith("HTIT", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("Close", indicator.ShortName, StringComparison.Ordinal);
Assert.Equal(0, HtitIndicator.MinHistoryDepths);
Assert.Single(indicator.LinesSeries);
}
+5 -5
View File
@@ -33,9 +33,9 @@ public class JmaIndicatorTests
{
var indicator = new JmaIndicator { Period = 15, Phase = 50 };
Assert.Contains("JMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("50", indicator.ShortName);
Assert.Contains("JMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("50", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -43,8 +43,8 @@ public class JmaIndicatorTests
{
var indicator = new JmaIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Jma.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Jma.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+2 -2
View File
@@ -34,8 +34,8 @@ public class KamaIndicatorTests
{
var indicator = new KamaIndicator { Period = 15 };
Assert.Contains("KAMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("KAMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
+4 -4
View File
@@ -33,8 +33,8 @@ public class LsmaIndicatorTests
{
var indicator = new LsmaIndicator { Period = 15, Offset = 2 };
Assert.Contains("LSMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("LSMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -42,8 +42,8 @@ public class LsmaIndicatorTests
{
var indicator = new LsmaIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Lsma.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Lsma.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+2 -2
View File
@@ -34,8 +34,8 @@ public class MamaIndicatorTests
var indicator = new MamaIndicator { FastLimit = 0.5, SlowLimit = 0.05 };
indicator.Initialize();
Assert.Contains("MAMA", indicator.ShortName);
Assert.Contains("Close", indicator.ShortName);
Assert.Contains("MAMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("Close", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
+4 -4
View File
@@ -34,8 +34,8 @@ public class PwmaIndicatorTests
{
var indicator = new PwmaIndicator { Period = 15 };
Assert.Contains("PWMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("PWMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -43,8 +43,8 @@ public class PwmaIndicatorTests
{
var indicator = new PwmaIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Pwma.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Pwma.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+2 -2
View File
@@ -32,8 +32,8 @@ public class RmaIndicatorTests
{
var indicator = new RmaIndicator { Period = 15 };
Assert.Contains("RMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("RMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
+2 -2
View File
@@ -32,8 +32,8 @@ public class SmaIndicatorTests
{
var indicator = new SmaIndicator { Period = 15 };
Assert.Contains("SMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("SMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
+2 -2
View File
@@ -32,8 +32,8 @@ public class SsfIndicatorTests
{
var indicator = new SsfIndicator { Period = 15 };
Assert.Contains("SSF", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("SSF", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
+5 -5
View File
@@ -35,9 +35,9 @@ public class SuperIndicatorTests
var indicator = new SuperIndicator { Period = 20, Multiplier = 2.5 };
indicator.Initialize();
Assert.Contains("Super", indicator.ShortName);
Assert.Contains("20", indicator.ShortName);
Assert.Contains("2.5", indicator.ShortName);
Assert.Contains("Super", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("20", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("2.5", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -45,8 +45,8 @@ public class SuperIndicatorTests
{
var indicator = new SuperIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Super.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Super.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+3 -3
View File
@@ -34,9 +34,9 @@ public class T3IndicatorTests
{
var indicator = new T3Indicator { Period = 15, VolumeFactor = 0.618 };
Assert.Contains("T3", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("0.62", indicator.ShortName); // F2 formatting
Assert.Contains("T3", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("0.62", indicator.ShortName, StringComparison.Ordinal); // F2 formatting
}
[Fact]
+4 -4
View File
@@ -32,8 +32,8 @@ public class TemaIndicatorTests
{
var indicator = new TemaIndicator { Period = 15 };
Assert.Contains("TEMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("TEMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -41,8 +41,8 @@ public class TemaIndicatorTests
{
var indicator = new TemaIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Tema.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Tema.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
+5 -5
View File
@@ -32,8 +32,8 @@ public class TrimaIndicatorTests
{
var indicator = new TrimaIndicator { Period = 15 };
Assert.Contains("TRIMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("TRIMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -41,8 +41,8 @@ public class TrimaIndicatorTests
{
var indicator = new TrimaIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Trima.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Trima.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
@@ -179,6 +179,6 @@ public class TrimaIndicatorTests
{
var indicator = new TrimaIndicator();
Assert.Contains("Triangular", indicator.Description);
Assert.Contains("Triangular", indicator.Description, StringComparison.Ordinal);
}
}
+2 -2
View File
@@ -32,8 +32,8 @@ public class VidyaIndicatorTests
{
var indicator = new VidyaIndicator { Period = 15 };
Assert.Contains("VIDYA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("VIDYA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
+5 -5
View File
@@ -32,8 +32,8 @@ public class WmaIndicatorTests
{
var indicator = new WmaIndicator { Period = 15 };
Assert.Contains("WMA", indicator.ShortName);
Assert.Contains("15", indicator.ShortName);
Assert.Contains("WMA", indicator.ShortName, StringComparison.Ordinal);
Assert.Contains("15", indicator.ShortName, StringComparison.Ordinal);
}
[Fact]
@@ -41,8 +41,8 @@ public class WmaIndicatorTests
{
var indicator = new WmaIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Wma.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Wma.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]
@@ -180,6 +180,6 @@ public class WmaIndicatorTests
{
var indicator = new WmaIndicator();
Assert.Contains("Weighted", indicator.Description);
Assert.Contains("Weighted", indicator.Description, StringComparison.Ordinal);
}
}
+2 -2
View File
@@ -49,8 +49,8 @@ public class AdoscIndicatorTests
{
var indicator = new AdoscIndicator();
Assert.Contains("github.com", indicator.SourceCodeLink);
Assert.Contains("Adosc.Quantower.cs", indicator.SourceCodeLink);
Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal);
Assert.Contains("Adosc.Quantower.cs", indicator.SourceCodeLink, StringComparison.Ordinal);
}
[Fact]