diff --git a/.github/workflows/Publish.yml b/.github/workflows/Publish.yml
index 44d7bdaf..bab332b0 100644
--- a/.github/workflows/Publish.yml
+++ b/.github/workflows/Publish.yml
@@ -1,7 +1,3 @@
-# This workflow integrates SonarCloud analysis, coverage reporting,
-# CodeQL analysis, SecurityCodeScan, and Codacy Security Scan
-# for code scanning and vulnerability detection - and if they all pass, publish
-
name: Publish Workflow
on:
@@ -16,7 +12,7 @@ permissions:
jobs:
Code_Coverage:
- runs-on: ubuntu-latest
+ runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
@@ -28,6 +24,20 @@ jobs:
with:
dotnet-version: '8.x'
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ java-version: 17
+ distribution: 'zulu'
+
+ - name: Cache SonarCloud scanner
+ id: cache-sonar-scanner
+ uses: actions/cache@v4
+ with:
+ path: .\.sonar\scanner
+ key: ${{ runner.os }}-sonar-scanner
+ restore-keys: ${{ runner.os }}-sonar-scanner
+
- name: Install dotnet tools
run: |
dotnet tool install JetBrains.dotCover.GlobalTool --global
@@ -37,6 +47,26 @@ jobs:
dotnet tool install --global dotnet-reportgenerator-globaltool
dotnet restore
+ - name: Begin SonarCloud Analysis
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ shell: powershell
+ run: |
+ dotnet sonarscanner begin /k:"mihakralj_QuanTAlib" /o:"mihakralj-quantalib" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" `
+ /d:sonar.solution.file="QuanTAlib.sln" `
+ /d:sonar.cs.opencover.reportsPaths="**/*cover*.xml" `
+ /d:sonar.cs.dotcover.reportsPaths="**/dotcover.xml" `
+ /d:sonar.coverage.exclusions="**Tests.cs,**/*.md,**/*.html,**/*.css,**/docs/**/*,**/archive/**/*,**/notebooks/**/*,**/obj/**/*,**/bin/**/*" `
+ /d:sonar.exclusions="**/TestResults/**/*,**/bin/**/*,**/obj/**/*,**/*.html,**/coverage/**/*,**/CoverageReport/**/*,**/*.md,**/*.css,**/docs/**/*,**/archive/**/*,**/notebooks/**/*" `
+ /d:sonar.test.exclusions="**Tests.cs,**/obj/**/*,**/bin/**/*" `
+ /d:sonar.cpd.exclusions="**Tests.cs" `
+ /d:sonar.cs.roslyn.ignoreIssues="false" `
+ /d:sonar.issue.ignore.multicriteria="e1" `
+ /d:sonar.issue.ignore.multicriteria.e1.ruleKey="csharpsquid:S1944,csharpsquid:S2053,csharpsquid:S2222,csharpsquid:S2259,csharpsquid:S2583,csharpsquid:S2589,csharpsquid:S3329,csharpsquid:S3655,csharpsquid:S3900,csharpsquid:S3949,csharpsquid:S3966,csharpsquid:S4158,csharpsquid:S4347,csharpsquid:S5773,csharpsquid:S6781" `
+ /d:sonar.issue.ignore.multicriteria.e1.resourceKey="**/*.cs" `
+ /d:sonar.verbose="true"
+
- name: Build Projects
run: |
dotnet build --no-restore --configuration Debug
@@ -58,6 +88,13 @@ jobs:
run: |
reportgenerator -reports:*cover*.xml -targetdir:.
+ - name: End SonarCloud Analysis
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ shell: powershell
+ run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
+
- name: Upload Coverage to Codacy
uses: codacy/codacy-coverage-reporter-action@v1
with:
@@ -70,20 +107,6 @@ jobs:
files: 'cover*'
verbose: true
- - name: SonarCloud Scan
- uses: SonarSource/sonarcloud-github-action@master
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- with:
- args: >
- -Dsonar.projectKey=mihakralj_QuanTAlib
- -Dsonar.organization=mihakralj-quantalib
- -Dsonar.sources=.
- -Dsonar.cs.opencover.reportsPaths=**/*cover*.xml
- -Dsonar.cs.dotcover.reportsPaths=**/dotcover.xml
- -Dsonar.coverage.exclusions=**Tests.cs
-
CodeQL:
runs-on: ubuntu-latest
steps:
diff --git a/.sonarlint/QuanTAlib.json b/.sonarlint/QuanTAlib.json
index f75a1bc1..c44cece3 100644
--- a/.sonarlint/QuanTAlib.json
+++ b/.sonarlint/QuanTAlib.json
@@ -1,4 +1,4 @@
{
- "sonarCloudOrganization": "mihakralj-quantalib",
+ "sonarCloudOrganization": "mihakralj",
"projectKey": "mihakralj_QuanTAlib"
}
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 00000000..dcc54733
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,33 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Debug Tests",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "dotnet",
+ "args": [
+ "test",
+ "${workspaceFolder}/QuanTAlib.sln",
+ "--no-build"
+ ],
+ "cwd": "${workspaceFolder}",
+ "stopAtEntry": false,
+ "console": "internalConsole",
+ "logging": {
+ "moduleLoad": false
+ }
+ },
+ {
+ "name": "Debug Library",
+ "type": "coreclr",
+ "request": "attach",
+ "processId": "${command:pickProcess}",
+ "justMyCode": true,
+ "logging": {
+ "moduleLoad": false
+ }
+ }
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index dbbc4e17..e27b36ee 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -7,11 +7,17 @@
}
],
"sarif-viewer.connectToGithubCodeScanning": "on",
- "dotnet.dotnetPath": "C:/Program Files/dotnet",
"omnisharp.useModernNet": true,
- "omnisharp.sdkPath": "C:/Program Files/dotnet/sdk",
"sonarlint.connectedMode.project": {
"connectionId": "mihakralj",
"projectKey": "mihakralj_QuanTAlib"
- }
-}
\ No newline at end of file
+ },
+ "dotnet.backgroundAnalysis.analyzerDiagnosticsScope": "fullSolution",
+ "dotnet.completion.showCompletionItemsFromUnimportedNamespaces": true,
+ "dotnetAcquisitionExtension.enableTelemetry": false,
+ "dotnet-test-explorer.testProjectPath": "Tests",
+ "dotnet-test-explorer.autoWatch": true,
+ "dotnet-test-explorer.showCodeLens": true,
+ "dotnet-test-explorer.testArguments": "/p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=./TestResults/coverage.cobertura.xml"
+
+}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 00000000..33d40edd
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,62 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/QuanTAlib.sln",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ }
+ },
+ {
+ "label": "test",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "test",
+ "${workspaceFolder}/QuanTAlib.sln",
+ "--no-build",
+ "--verbosity:normal"
+ ],
+ "problemMatcher": "$msCompile",
+ "group": {
+ "kind": "test",
+ "isDefault": true
+ },
+ "dependsOn": ["build"]
+ },
+ {
+ "label": "test with coverage",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "test",
+ "${workspaceFolder}/QuanTAlib.sln",
+ "/p:CollectCoverage=true",
+ "/p:CoverletOutputFormat=lcov",
+ "/p:CoverletOutput=./lcov.info",
+ "--no-build"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "clean",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "clean",
+ "${workspaceFolder}/QuanTAlib.sln"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
index df85d4db..a5cfd53c 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -11,7 +11,7 @@
false
true
AnyCPU
- False
+ True
bin\$(Configuration)\
False
full
@@ -51,9 +51,7 @@
-
-
-
+
D:\Quantower
$([System.IO.Directory]::GetDirectories("$(QuantowerRoot)\TradingPlatform", "v1*")[0])
diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj
index 18f54f05..31f09837 100644
--- a/Tests/Tests.csproj
+++ b/Tests/Tests.csproj
@@ -2,11 +2,16 @@
QuanTAlib.Tests
QuanTAlib.Tests
+ false
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Tests/test_core.cs b/Tests/test_core.cs
new file mode 100644
index 00000000..49d67d4b
--- /dev/null
+++ b/Tests/test_core.cs
@@ -0,0 +1,251 @@
+using Xunit;
+
+namespace QuanTAlib.Tests;
+
+public class CoreTests
+{
+ #region CircularBuffer Tests
+
+ [Fact]
+ public void CircularBuffer_BasicOperations()
+ {
+ var buffer = new CircularBuffer(5);
+
+ // Test initial state
+ Assert.Equal(5, buffer.Capacity);
+ Assert.Equal(0, buffer.Count);
+
+ // Test adding items
+ buffer.Add(1.0);
+ buffer.Add(2.0);
+ Assert.Equal(2, buffer.Count);
+ Assert.Equal(1.0, buffer[0]);
+ Assert.Equal(2.0, buffer[^1]);
+
+ // Test overflow behavior
+ buffer.Add(3.0);
+ buffer.Add(4.0);
+ buffer.Add(5.0);
+ buffer.Add(6.0); // Should remove oldest item (1.0)
+ Assert.Equal(5, buffer.Count);
+ Assert.Equal(2.0, buffer[0]);
+ Assert.Equal(6.0, buffer[^1]);
+ }
+
+ [Fact]
+ public void CircularBuffer_UpdateBehavior()
+ {
+ var buffer = new CircularBuffer(3);
+
+ // Add new values
+ buffer.Add(1.0, isNew: true);
+ buffer.Add(2.0, isNew: true);
+ Assert.Equal(2, buffer.Count);
+
+ // Update last value
+ buffer.Add(2.5, isNew: false);
+ Assert.Equal(2, buffer.Count);
+ Assert.Equal(2.5, buffer[^1]);
+ }
+
+ [Fact]
+ public void CircularBuffer_MinMaxSumAverage()
+ {
+ var buffer = new CircularBuffer(5);
+
+ buffer.Add(1.0);
+ buffer.Add(2.0);
+ buffer.Add(3.0);
+ buffer.Add(4.0);
+ buffer.Add(5.0);
+
+ Assert.Equal(1.0, buffer.Min());
+ Assert.Equal(5.0, buffer.Max());
+ Assert.Equal(15.0, buffer.Sum());
+ Assert.Equal(3.0, buffer.Average());
+ }
+
+ [Fact]
+ public void CircularBuffer_Enumeration()
+ {
+ var buffer = new CircularBuffer(3);
+
+ buffer.Add(1.0);
+ buffer.Add(2.0);
+ buffer.Add(3.0);
+
+ var list = buffer.ToList();
+ Assert.Equal(3, list.Count);
+ Assert.Equal(1.0, list[0]);
+ Assert.Equal(3.0, list[2]);
+ }
+
+ #endregion
+
+ #region TBar Tests
+
+ [Fact]
+ public void TBar_Construction()
+ {
+ // Default constructor
+ var bar1 = new TBar();
+ Assert.Equal(0, bar1.Open);
+ Assert.True(bar1.IsNew);
+
+ // Value constructor
+ var bar2 = new TBar(10.0);
+ Assert.Equal(10.0, bar2.Open);
+ Assert.Equal(10.0, bar2.High);
+ Assert.Equal(10.0, bar2.Low);
+ Assert.Equal(10.0, bar2.Close);
+
+ // Full constructor
+ var time = DateTime.Now;
+ var bar3 = new TBar(time, 10.0, 12.0, 9.0, 11.0, 1000.0, false);
+ Assert.Equal(time, bar3.Time);
+ Assert.Equal(10.0, bar3.Open);
+ Assert.Equal(12.0, bar3.High);
+ Assert.Equal(9.0, bar3.Low);
+ Assert.Equal(11.0, bar3.Close);
+ Assert.Equal(1000.0, bar3.Volume);
+ Assert.False(bar3.IsNew);
+ }
+
+ [Fact]
+ public void TBar_DerivedValues()
+ {
+ var bar = new TBar(DateTime.Now, 10.0, 20.0, 5.0, 15.0, 1000.0);
+
+ Assert.Equal(12.5, bar.HL2); // (20 + 5) / 2
+ Assert.Equal(12.5, bar.OC2); // (10 + 15) / 2
+ Assert.Equal(11.67, bar.OHL3, 2); // (10 + 20 + 5) / 3
+ Assert.Equal(13.33, bar.HLC3, 2); // (20 + 5 + 15) / 3
+ Assert.Equal(12.5, bar.OHLC4); // (10 + 20 + 5 + 15) / 4
+ Assert.Equal(13.75, bar.HLCC4); // (20 + 5 + 15 + 15) / 4
+ }
+
+ [Fact]
+ public void TBarSeries_Operations()
+ {
+ var series = new TBarSeries();
+ var time = DateTime.Now;
+ var bar1 = new TBar(time, 10.0, 12.0, 9.0, 11.0, 1000.0);
+ var bar2 = new TBar(time.AddMinutes(1), 11.0, 13.0, 10.0, 12.0, 1100.0);
+
+ // Test adding bars
+ series.Add(bar1);
+ series.Add(bar2);
+ Assert.Equal(2, series.Count);
+
+ // Test updating last bar
+ var bar2Update = new TBar(bar2.Time, 11.0, 13.5, 9.5, 12.5, 1200.0, false);
+ series.Add(bar2Update);
+ Assert.Equal(2, series.Count);
+ Assert.Equal(12.5, series.Last.Close);
+
+ // Test derived series
+ Assert.Equal(11.0, series.Open.Last.Value);
+ Assert.Equal(13.5, series.High.Last.Value);
+ Assert.Equal(9.5, series.Low.Last.Value);
+ Assert.Equal(12.5, series.Close.Last.Value);
+ Assert.Equal(1200.0, series.Volume.Last.Value);
+ }
+
+ #endregion
+
+ #region TValue Tests
+
+ [Fact]
+ public void TValue_Construction()
+ {
+ // Default constructor
+ var value1 = new TValue();
+ Assert.Equal(0, value1.Value);
+ Assert.True(value1.IsNew);
+ Assert.True(value1.IsHot);
+
+ // Value constructor
+ var value2 = new TValue(10.0);
+ Assert.Equal(10.0, value2.Value);
+
+ // Full constructor
+ var time = DateTime.Now;
+ var value3 = new TValue(time, 10.0, false, false);
+ Assert.Equal(time, value3.Time);
+ Assert.Equal(10.0, value3.Value);
+ Assert.False(value3.IsNew);
+ Assert.False(value3.IsHot);
+ }
+
+ [Fact]
+ public void TValue_Conversions()
+ {
+ var value = new TValue(10.0);
+
+ // Test implicit conversions
+ double d = value;
+ Assert.Equal(10.0, d);
+
+ DateTime time = value;
+ Assert.Equal(value.Time, time);
+
+ // Test implicit conversion from double
+ TValue newValue = 20.0;
+ Assert.Equal(20.0, newValue.Value);
+ }
+
+ [Fact]
+ public void TSeries_Operations()
+ {
+ var series = new TSeries();
+ var time = DateTime.Now;
+
+ // Test adding values
+ series.Add(time, 10.0);
+ series.Add(time.AddMinutes(1), 20.0);
+ Assert.Equal(2, series.Count);
+
+ // Test updating last value
+ series.Add(new TValue(time.AddMinutes(1), 25.0, false));
+ Assert.Equal(2, series.Count);
+ Assert.Equal(25.0, series.Last.Value);
+
+ // Test adding range of values
+ var values = new[] { 30.0, 40.0, 50.0 };
+ foreach (var value in values)
+ {
+ series.Add(time.AddMinutes(series.Count + 1), value);
+ }
+ Assert.Equal(5, series.Count);
+
+ // Test conversions
+ var doubleList = (List)series;
+ Assert.Equal(5, doubleList.Count);
+ Assert.Equal(50.0, doubleList[^1]);
+
+ var doubleArray = (double[])series;
+ Assert.Equal(5, doubleArray.Length);
+ Assert.Equal(50.0, doubleArray[^1]);
+ }
+
+ [Fact]
+ public void TSeries_EventHandling()
+ {
+ var series = new TSeries();
+ var receivedValues = new List();
+ var time = DateTime.Now;
+
+ series.Pub += (object sender, in ValueEventArgs args) => receivedValues.Add(args.Tick.Value);
+
+ series.Add(time, 10.0);
+ series.Add(time.AddMinutes(1), 20.0);
+ series.Add(time.AddMinutes(2), 30.0);
+
+ Assert.Equal(3, receivedValues.Count);
+ Assert.Equal(10.0, receivedValues[0]);
+ Assert.Equal(20.0, receivedValues[1]);
+ Assert.Equal(30.0, receivedValues[2]);
+ }
+
+ #endregion
+}
diff --git a/Tests/test_eventing.cs b/Tests/test_eventing.cs
index 9a61defd..78ad4f8e 100644
--- a/Tests/test_eventing.cs
+++ b/Tests/test_eventing.cs
@@ -13,12 +13,13 @@ public class EventingTests
// Create a cryptographically secure random number generator
using var rng = RandomNumberGenerator.Create();
- // Create an input series to hold our random values
+ // Create input series to hold our random values
var input = new TSeries();
+ var barInput = new TBarSeries();
int p = 10;
- // Create a list of indicator pairs (direct calculation and event-based) with names
- var indicators = new List<(string Name, AbstractBase Direct, AbstractBase EventBased)>
+ // Create a list of value-based indicator pairs
+ var valueIndicators = new List<(string Name, AbstractBase Direct, AbstractBase EventBased)>
{
("Afirma", new Afirma(p,p,Afirma.WindowType.BlackmanHarris), new Afirma(input, p,p,Afirma.WindowType.BlackmanHarris)),
("Alma", new Alma(p), new Alma(input, p)),
@@ -51,7 +52,36 @@ public class EventingTests
("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)),
- // error classes
+ ("Sinema", new Sinema(p), new Sinema(input, p)),
+ ("Smma", new Smma(p), new Smma(input, p)),
+ ("T3", new T3(p), new T3(input, p)),
+ ("Trima", new Trima(p), new Trima(input, p)),
+ ("Vidya", new Vidya(p), new Vidya(input, p)),
+ ("Apo", new Apo(12, 26), new Apo(input, 12, 26)),
+ ("Macd", new Macd(12, 26, 9), new Macd(input, 12, 26, 9)),
+ ("Rsi", new Rsi(p), new Rsi(input, p)),
+ ("Rsx", new Rsx(p), new Rsx(input, p)),
+ ("Cmo", new Cmo(p), new Cmo(input, p)),
+ ("Cog", new Cog(p), new Cog(input, p)),
+ ("Curvature", new Curvature(p), new Curvature(input, p)),
+ ("Entropy", new Entropy(p), new Entropy(input, p)),
+ ("Kurtosis", new Kurtosis(p), new Kurtosis(input, p)),
+ ("Max", new Max(p), new Max(input, p)),
+ ("Median", new Median(p), new Median(input, p)),
+ ("Min", new Min(p), new Min(input, p)),
+ ("Mode", new Mode(p), new Mode(input, p)),
+ ("Percentile", new Percentile(p, 0.5), new Percentile(input, p, 0.5)),
+ ("Skew", new Skew(p), new Skew(input, p)),
+ ("Slope", new Slope(p), new Slope(input, p)),
+ ("Stddev", new Stddev(p), new Stddev(input, p)),
+ ("Variance", new Variance(p), new Variance(input, p)),
+ ("Zscore", new Zscore(p), new Zscore(input, p)),
+ // Volatility indicators (value-based)
+ ("Hv", new Hv(p), new Hv(input, p)),
+ ("Jvolty", new Jvolty(p), new Jvolty(input, p)),
+ ("Rv", new Rv(p), new Rv(input, p)),
+ ("Rvi", new Rvi(p), new Rvi(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)),
@@ -67,29 +97,71 @@ public class EventingTests
("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))
+ ("Huber", new Huber(p), new Huber(input, p))
};
- // Generate 200 random values and feed them to both direct and event-based indicators
+ // Create a list of bar-based indicator pairs
+ var barIndicators = new List<(string Name, AbstractBase Direct, AbstractBase EventBased)>
+ {
+ // Volume indicators
+ ("Adl", new Adl(), new Adl(barInput)),
+ ("Adosc", new Adosc(3, 10), new Adosc(barInput, 3, 10)),
+ ("Aobv", new Aobv(), new Aobv(barInput)),
+ ("Cmf", new Cmf(20), new Cmf(barInput, 20)),
+ ("Eom", new Eom(14), new Eom(barInput, 14)),
+ ("Kvo", new Kvo(34, 55), new Kvo(barInput, 34, 55)),
+ // Volatility indicators (bar-based)
+ ("Atr", new Atr(14), new Atr(barInput, 14)),
+ // Oscillators (bar-based)
+ ("Chop", new Chop(14), new Chop(barInput, 14))
+ };
+
+ // Generate 200 random values and feed them to indicators
for (int i = 0; i < 200; i++)
{
+ // Generate random value for value-based indicators
double randomValue = GetRandomDouble(rng) * 100;
input.Add(randomValue);
- // Calculate direct indicators
- foreach (var (_, direct, _) in indicators)
+ // Calculate value-based indicators
+ foreach (var (_, direct, _) in valueIndicators)
{
direct.Calc(randomValue);
}
+
+ // Generate random bar for bar-based indicators
+ var bar = new TBar(
+ DateTime.Now,
+ randomValue,
+ randomValue + Math.Abs(GetRandomDouble(rng) * 10),
+ randomValue - Math.Abs(GetRandomDouble(rng) * 10),
+ randomValue + GetRandomDouble(rng) * 5,
+ Math.Abs(GetRandomDouble(rng) * 1000),
+ true
+ );
+ barInput.Add(bar);
+
+ // Calculate bar-based indicators
+ foreach (var (_, direct, _) in barIndicators)
+ {
+ direct.Calc(bar);
+ }
}
- // Compare the results of direct and event-based calculations
- for (int i = 0; i < indicators.Count; i++)
+ // Compare the results for value-based indicators
+ foreach (var (name, direct, eventBased) in valueIndicators)
{
- var (name, direct, eventBased) = indicators[i];
bool areEqual = (double.IsNaN(direct.Value) && double.IsNaN(eventBased.Value)) ||
Math.Abs(direct.Value - eventBased.Value) < 1e-9;
- Assert.True(areEqual, $"Indicator {name} failed: Expected {direct.Value}, Actual {eventBased.Value}");
+ Assert.True(areEqual, $"Value indicator {name} failed: Expected {direct.Value}, Actual {eventBased.Value}");
+ }
+
+ // Compare the results for bar-based indicators
+ foreach (var (name, direct, eventBased) in barIndicators)
+ {
+ bool areEqual = (double.IsNaN(direct.Value) && double.IsNaN(eventBased.Value)) ||
+ Math.Abs(direct.Value - eventBased.Value) < 1e-9;
+ Assert.True(areEqual, $"Bar indicator {name} failed: Expected {direct.Value}, Actual {eventBased.Value}");
}
}
diff --git a/Tests/test_updates_errors.cs b/Tests/test_updates_errors.cs
index 67db6037..13641eb8 100644
--- a/Tests/test_updates_errors.cs
+++ b/Tests/test_updates_errors.cs
@@ -20,7 +20,7 @@ public class UpdateTests
[Fact]
public void Huberloss_Update()
{
- var indicator = new Huberloss(period: 14);
+ var indicator = new Huber(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
diff --git a/Tests/test_updates_momentum.cs b/Tests/test_updates_momentum.cs
new file mode 100644
index 00000000..4f8c3028
--- /dev/null
+++ b/Tests/test_updates_momentum.cs
@@ -0,0 +1,292 @@
+using Xunit;
+using System.Security.Cryptography;
+
+namespace QuanTAlib.Tests;
+
+public class MomentumUpdateTests
+{
+ 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
+ }
+
+ private TBar GetRandomBar(bool IsNew)
+ {
+ double open = GetRandomDouble();
+ double high = open + Math.Abs(GetRandomDouble());
+ double low = open - Math.Abs(GetRandomDouble());
+ double close = low + (high - low) * GetRandomDouble();
+ return new TBar(DateTime.Now, open, high, low, close, 1000, IsNew);
+ }
+
+ [Fact]
+ public void Adx_Update()
+ {
+ var indicator = new Adx(period: 14);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Adxr_Update()
+ {
+ var indicator = new Adxr(period: 14);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Apo_Update()
+ {
+ var indicator = new Apo(fastPeriod: 12, slowPeriod: 26);
+ 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 Dmi_Update()
+ {
+ var indicator = new Dmi(period: 14);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Dmx_Update()
+ {
+ var indicator = new Dmx(period: 14);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Dpo_Update()
+ {
+ var indicator = new Dpo(period: 20);
+ 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 Macd_Update()
+ {
+ var indicator = new Macd(fastPeriod: 12, slowPeriod: 26, signalPeriod: 9);
+ 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() + 100, IsNew: false)); // Ensure positive prices
+ }
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Pmo_Update()
+ {
+ var indicator = new Pmo(period1: 35, period2: 20);
+ 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 Po_Update()
+ {
+ var indicator = new Po(fastPeriod: 10, slowPeriod: 21);
+ 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 Ppo_Update()
+ {
+ var indicator = new Ppo(fastPeriod: 12, slowPeriod: 26);
+ 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 Prs_Update()
+ {
+ var indicator = new Prs();
+ indicator.SetBenchmark(ReferenceValue);
+ double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.SetBenchmark(GetRandomDouble() + 100); // Ensure positive benchmark
+ indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
+ }
+
+ indicator.SetBenchmark(ReferenceValue);
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Roc_Update()
+ {
+ var indicator = new Roc(period: 12);
+ 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() + 100, IsNew: false)); // Ensure positive prices
+ }
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Mom_Update()
+ {
+ var indicator = new Mom(period: 10);
+ 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 Trix_Update()
+ {
+ var indicator = new Trix(period: 18);
+ 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() + 100, IsNew: false)); // Ensure positive prices
+ }
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Tsi_Update()
+ {
+ var indicator = new Tsi(firstPeriod: 25, secondPeriod: 13);
+ 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() + 100, IsNew: false)); // Ensure positive prices
+ }
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Vel_Update()
+ {
+ var indicator = new Vel(period: 10);
+ 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 Vortex_Update()
+ {
+ var indicator = new Vortex(period: 14);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+}
diff --git a/Tests/test_updates_oscillators.cs b/Tests/test_updates_oscillators.cs
new file mode 100644
index 00000000..a9d74a8e
--- /dev/null
+++ b/Tests/test_updates_oscillators.cs
@@ -0,0 +1,190 @@
+using Xunit;
+using System.Security.Cryptography;
+
+namespace QuanTAlib.Tests;
+
+public class OscillatorsUpdateTests
+{
+ 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 Rsi_Update()
+ {
+ var indicator = new Rsi(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 Rsx_Update()
+ {
+ var indicator = new Rsx(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 Cmo_Update()
+ {
+ var indicator = new Cmo(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 Ao_Update()
+ {
+ var indicator = new Ao();
+ TBar r = new(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TBar(DateTime.Now, GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), 1000, IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Ac_Update()
+ {
+ var indicator = new Ac();
+ TBar r = new(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TBar(DateTime.Now, GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), 1000, IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Aroon_Update()
+ {
+ var indicator = new Aroon(period: 25);
+ TBar r = new(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TBar(DateTime.Now, GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), 1000, IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Bop_Update()
+ {
+ var indicator = new Bop();
+ TBar r = new(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TBar(DateTime.Now, GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), 1000, IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Cci_Update()
+ {
+ var indicator = new Cci(period: 20);
+ TBar r = new(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TBar(DateTime.Now, GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), 1000, IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Cfo_Update()
+ {
+ var indicator = new Cfo(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 Chop_Update()
+ {
+ var indicator = new Chop(period: 14);
+ TBar r = new(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TBar(DateTime.Now, GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), 1000, IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Cog_Update()
+ {
+ var indicator = new Cog(period: 10);
+ 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);
+ }
+}
diff --git a/Tests/test_updates_volatility.cs b/Tests/test_updates_volatility.cs
index ba7976ee..bf9fabec 100644
--- a/Tests/test_updates_volatility.cs
+++ b/Tests/test_updates_volatility.cs
@@ -45,14 +45,29 @@ public class VolatilityUpdateTests
[Fact]
public void Historical_Update()
{
- var indicator = new Historical(period: 14);
- double initialValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true));
+ var indicator = new Hv(period: 14);
+ double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
- indicator.Calc(GetRandomBar(false));
+ indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
- double finalValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: false));
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Jvolty_Update()
+ {
+ var indicator = new Jvolty(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);
}
@@ -60,14 +75,14 @@ public class VolatilityUpdateTests
[Fact]
public void Realized_Update()
{
- var indicator = new Realized(period: 14);
- double initialValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true));
+ var indicator = new Rv(period: 14);
+ double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
- indicator.Calc(GetRandomBar(false));
+ indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
- double finalValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: false));
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
@@ -76,13 +91,125 @@ public class VolatilityUpdateTests
public void Rvi_Update()
{
var indicator = new Rvi(period: 14);
- double initialValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true));
+ double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
- indicator.Calc(GetRandomBar(false));
+ indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
- double finalValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: false));
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Cvi_Update()
+ {
+ var indicator = new Cvi(period: 14);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Tr_Update()
+ {
+ var indicator = new Tr();
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Ui_Update()
+ {
+ var indicator = new Ui(period: 14);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Vc_Update()
+ {
+ var indicator = new Vc(period: 20, deviations: 2.0);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Vov_Update()
+ {
+ var indicator = new Vov(period: 20);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Vr_Update()
+ {
+ var indicator = new Vr(shortPeriod: 10, longPeriod: 20);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Vs_Update()
+ {
+ var indicator = new Vs(period: 14, multiplier: 2.0);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
diff --git a/Tests/test_updates_volume.cs b/Tests/test_updates_volume.cs
new file mode 100644
index 00000000..66058a26
--- /dev/null
+++ b/Tests/test_updates_volume.cs
@@ -0,0 +1,322 @@
+using Xunit;
+using System.Security.Cryptography;
+
+namespace QuanTAlib.Tests;
+
+public class VolumeUpdateTests
+{
+ private readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
+ private const int RandomUpdates = 100;
+ 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
+ }
+
+ private TBar GetRandomBar(bool IsNew)
+ {
+ double open = GetRandomDouble();
+ double high = open + Math.Abs(GetRandomDouble());
+ double low = open - Math.Abs(GetRandomDouble());
+ double close = low + (high - low) * GetRandomDouble();
+ double volume = Math.Abs(GetRandomDouble()) * 1000; // Random positive volume
+ return new TBar(DateTime.Now, open, high, low, close, volume, IsNew);
+ }
+
+ [Fact]
+ public void Adl_Update()
+ {
+ var indicator = new Adl();
+ TBar r = GetRandomBar(true);
+
+ // First calculation with IsNew: true
+ double value1 = indicator.Calc(r);
+
+ // Multiple recalculations with IsNew: false should not change the value
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+ }
+
+ // Final calculation with IsNew: false should match initial value
+ double value2 = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+ Assert.Equal(value1, value2, precision);
+
+ // New calculation with IsNew: true should update the value
+ double value3 = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: true));
+ Assert.NotEqual(value1, value3, precision);
+ }
+
+ [Fact]
+ public void Adosc_Update()
+ {
+ var indicator = new Adosc(shortPeriod: 3, longPeriod: 10);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Aobv_Update()
+ {
+ var indicator = new Aobv();
+ TBar r = GetRandomBar(true);
+
+ // First calculation with IsNew: true
+ double value1 = indicator.Calc(r);
+
+ // Multiple recalculations with IsNew: false should not change the value
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+ }
+
+ // Final calculation with IsNew: false should match initial value
+ double value2 = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+ Assert.Equal(value1, value2, precision);
+
+ // New calculation with IsNew: true should update the value
+ double value3 = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: true));
+ Assert.NotEqual(value1, value3, precision);
+ }
+
+ [Fact]
+ public void Cmf_Update()
+ {
+ var indicator = new Cmf(period: 20);
+ TBar r = GetRandomBar(true);
+
+ // Generate a sequence of bars for warmup
+ var warmupBars = new List();
+ for (int i = 0; i < indicator.WarmupPeriod; i++)
+ {
+ var bar = GetRandomBar(IsNew: true);
+ warmupBars.Add(bar);
+ indicator.Calc(bar);
+ }
+
+ // Calculate initial value after warmup
+ double initialValue = indicator.Calc(r);
+
+ // Apply random updates
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+
+ // Reset and replay the same sequence
+ indicator.Init();
+ foreach (var bar in warmupBars)
+ {
+ indicator.Calc(bar);
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Eom_Update()
+ {
+ var indicator = new Eom(period: 14);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Kvo_Update()
+ {
+ var indicator = new Kvo(shortPeriod: 34, longPeriod: 55);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Mfi_Update()
+ {
+ var indicator = new Mfi(period: 14);
+ TBar r = GetRandomBar(true);
+
+ // Generate a sequence of bars for warmup
+ var warmupBars = new List();
+ for (int i = 0; i < indicator.WarmupPeriod; i++)
+ {
+ var bar = GetRandomBar(IsNew: true);
+ warmupBars.Add(bar);
+ indicator.Calc(bar);
+ }
+
+ // Calculate initial value after warmup
+ double initialValue = indicator.Calc(r);
+
+ // Apply random updates
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+
+ // Reset and replay the same sequence
+ indicator.Init();
+ foreach (var bar in warmupBars)
+ {
+ indicator.Calc(bar);
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Nvi_Update()
+ {
+ var indicator = new Nvi();
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Obv_Update()
+ {
+ var indicator = new Obv();
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Pvi_Update()
+ {
+ var indicator = new Pvi();
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Pvol_Update()
+ {
+ var indicator = new Pvol();
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Pvo_Update()
+ {
+ var indicator = new Pvo(shortPeriod: 12, longPeriod: 26);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Pvr_Update()
+ {
+ var indicator = new Pvr();
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Pvt_Update()
+ {
+ var indicator = new Pvt();
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Tvi_Update()
+ {
+ var indicator = new Tvi(minTick: 0.5);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+}
diff --git a/benchmark/benchmark.csproj b/benchmark/benchmark.csproj
deleted file mode 100644
index 0940953e..00000000
--- a/benchmark/benchmark.csproj
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
- Exe
- net8.0
- false
- enable
- latest
- false
-
-
-
-
-
-
-
-
-
-
-
- true
- AnyCPU
- pdbonly
- true
- true
-
-
-
\ No newline at end of file
diff --git a/benchmark/growthBench.cs b/benchmark/growthBench.cs
deleted file mode 100644
index 6dd123e4..00000000
--- a/benchmark/growthBench.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using BenchmarkDotNet.Attributes;
-using BenchmarkDotNet.Configs;
-using BenchmarkDotNet.Jobs;
-using BenchmarkDotNet.Running;
-
-namespace QuanTAlib;
-
-public class Program
-{
- public static void Main(string[] args)
- {
- var config = DefaultConfig.Instance
- .WithOption(ConfigOptions.DisableOptimizationsValidator, true);
- BenchmarkRunner.Run(config);
- }
-}
-
-[MemoryDiagnoser]
-[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 3, iterationCount: 5)]
-public class EmaBenchmark
-{
- private const int Period = 10;
- private const int Length = 100_000;
- private GbmFeed gbm = null!;
- private TSeries inputs = null!;
-
- [GlobalSetup]
- public void Setup()
- {
- gbm = new GbmFeed();
- inputs = new();
-
- for (int i = 0; i < Length; i++)
- {
- TBar item = gbm.Generate(DateTime.Now);
- inputs.Add(new TValue(item.Time, item.Close, true, true));
- }
- }
-
- [Benchmark]
- public void Ema_bench()
- {
- Ema ma1 = new(Period);
- for (int i = 0; i < Length; i++)
- {
- TValue item = gbm.Generate(DateTime.Now).Close;
- ma1.Calc(item);
- }
-
- }
-
- [Benchmark]
- public void Alma_bench()
- {
- Alma ma1 = new(Period);
- for (int i = 0; i < Length; i++)
- {
- TValue item = gbm.Generate(DateTime.Now).Close;
- ma1.Calc(item);
- }
- }
-
- [Benchmark]
- public void Dema_bench()
- {
- Dema ma1 = new(Period);
- for (int i = 0; i < Length; i++)
- {
- TValue item = gbm.Generate(DateTime.Now).Close;
- ma1.Calc(item);
- }
- }
-}
\ No newline at end of file
diff --git a/docs/Progress.csv b/docs/Progress.csv
deleted file mode 100644
index 7ea5a50e..00000000
--- a/docs/Progress.csv
+++ /dev/null
@@ -1,134 +0,0 @@
-AC,Acceleration Oscillator
-AD,Chaikin A/D Line
-ADOSC,Chaikin A/D Oscillator
-ADL,Accumulation / Distribution Line
-ADX,Average Directional Movement Index
-ADXR,Average Directional Movement Index Rating
-Alligator,Alligator Indicator
-ALMA,Arnaud Legoux Moving Average
-AO,Awesome Oscillator
-APO,Absolute Price Oscillator
-AROON,Aroon Indicator
-AROONOSC,Aroon Oscillator
-ATS,ATR Trailing Stop
-ATR,Average True Range
-AVGPRICE,Average Price
-BB,Bollinger Bands
-BBF,Bollinger Bands Flat
-BBP,Bull and Bear Power
-BC,Beta Coefficient
-BETA,Beta
-BOP,Balance of Power
-CCI,Commodity Channel Index
-CE,Chandelier Exit
-Channel,Price Channel
-CI,Choppiness Index
-CMF,Chaikin Money Flow
-CMO,Chande Momentum Oscillator
-CORREL,Pearson's Correlation Coefficient
-CRSI,ConnorsRSI
-DC,Donchian Channels
-DCP,Dominant Cycle Periods
-DEMA,Double Exponential Moving Average
-DMI,Directional Movement Index
-DPO,Detrended Price Oscillator
-DX,Directional Movement Index
-EMA,Exponential Moving Average
-EPMA,Endpoint Moving Average
-ERI,Elder-ray Index
-FCB,Fractal Chaos Bands
-FI,Force Index
-GO,Gator Oscillator
-HE,Hurst Exponent
-HMA,Hull Moving Average
-HT_TRENDLINE,Hilbert Transform - Instantaneous Trendline
-HT_TRENDMODE,Hilbert Transform - Trend vs Cycle Mode
-HV,Historical Volatility
-IC,Ichimoku Cloud
-KAMA,Kaufman Adaptive Moving Average
-KDJ,KDJ Index
-Keltner,Keltner Channel
-KVO,Klinger Volume Oscillator
-LINEARREG,Linear Regression
-LINEARREG_ANGLE,Linear Regression Angle
-LINEARREG_INTERCEPT,Linear Regression Intercept
-LINEARREG_SLOPE,Linear Regression Slope
-LSMA,Least Squares Moving Average
-LWMA,Linearly Weighted Moving Average
-MACDEXT,MACD with controllable MA type
-MACDFIX,Moving Average Convergence Divergence Fix 12/26
-MAD,Mean absolute deviation
-MAE,Moving Average Envelope
-MAMA,MESA Adaptive Moving Average
-MAPE,Mean absolute percentage error
-MAX,Highest value over a specified period
-MAXINDEX,Index of highest value over a specified period
-MD,McGinley Dynamic
-MEDPRICE,Median Price
-MFI,Money Flow Index
-MIN,Lowest value over a specified period
-MININDEX,Index of lowest value over a specified period
-MINMAX,Lowest and highest values over a specified period
-MINMAXINDEX,Indexes of lowest and highest values over a period
-MMA,Modified Moving Average
-MOM,Momentum
-MSE,Mean square error
-NATR,Normalized Average True Range
-OBV,On Balance Volume
-OsMA,Moving Average of Oscillator
-PAZ,Price Action Zones
-Pivots,Pivots
-PMO,Price Momentum Oscillator
-PP,Pivot Points
-PPO,Percentage Price Oscillator
-PPMA,Pivot Point Moving Average
-PRS,Price Relative Strength
-PVI,Positive Volume Index
-PVO,Percentage Volume Oscillator
-Qstick,Qstick Indicator
-R2,R-Squared (Coefficient of Determination)
-Regression,Regression Line Indicator
-RLW,%R Larry Williams
-RMA,Running Moving Average
-ROC,Rate of Change
-ROCB,ROC with Bands
-RPP,Rolling Pivot Points
-RRA,Rescaled Range Analysis
-RSI,Relative Strength Index
-SAR,Parabolic SAR
-SAREXT,Parabolic SAR - Extended
-SDC,Standard Deviation Channels
-SI,Swing Index
-SLR,Slope and Linear Regression
-SMA,Simple Moving Average
-SMI,Stochastic Momentum Index
-SMMA,Smoothed Moving Average
-ST,SuperTrend
-STARC,STARC Bands
-STC,Schaff Trend Cycle
-STDDEV,Standard Deviation
-STOCH,Stochastic
-STOCHF,Stochastic Fast
-STOCHRSI,Stochastic Relative Strength Index
-SUM,Summation
-T3,Triple Exponential Moving Average (T3)
-TEMA,Triple Exponential Moving Average
-TRANGE,True Range
-TRIMA,Triangular Moving Average
-TRIX,1-day Rate-Of-Change (ROC) of a Triple Smooth EMA
-TSI,True Strength Index
-TYPPRICE,Typical Price
-UI,Ulcer Index
-ULTOSC,Ultimate Oscillator
-VAR,Variance
-VI,Vortex Indicator
-Volume,Volume Indicator
-VS,Volatility Stop
-VWAP,Volume Weighted Average Price
-VWMA,Volume Weighted Moving Average
-WA,Williams Alligator
-WCLPRICE,Weighted Close Price
-WF,Williams Fractal
-WMA,Weighted Moving Average
-ZS,Z-Score
-ZZ,ZigZag Indicator
diff --git a/docs/_sidebar.md b/docs/_sidebar.md
index 5df2cf71..40084778 100644
--- a/docs/_sidebar.md
+++ b/docs/_sidebar.md
@@ -1,22 +1,24 @@
-
* [Home](/)
-* Introduction
+
+* [List of Indicators](indicators/indicators.md)
+
+* 🚧 Introduction
* [Overview]()
* [Features]()
* [Historical vs Real-time analysis](essays/realtime.md)
-* Core Concepts
+* 🚧 Core Concepts
* [Time Series Data Handling]()
* [Calculation classes]()
* [Presentation Classes]()
-* QuanTAlib C# Library
+* 🚧 QuanTAlib C# Library
* [Installation]()
* [Quick Start Guide]()
* [Usage Examples]()
* [Tests and Validation]()
-* Quantower Charts
+* 🚧 Quantower Charts
* [Installation]()
* [Quick Start Guide]()
* [Using VS Code for QuanTower coding](setup/vscode.md)
@@ -24,7 +26,24 @@
* [Creating Custom Indicators]()
* [Inspecting Quantower Internals]()
-* [Available Indicators](indicators/indicators.md)
+* [🚧 Available Indicators](indicators/indicators.md)
+ * Momentum
+ * [ADX - Average Directional Index](indicators/momentum/adx/description.md)
+ * [ADXR - Average Directional Index Rating](indicators/momentum/adxr/description.md)
+ * [APO - Absolute Price Oscillator](indicators/momentum/apo/description.md)
+ * [DMI - Directional Movement Index](indicators/momentum/dmi/description.md)
+ * [DMX - Directional Movement Extended](indicators/momentum/dmx/description.md)
+ * [DPO - Detrended Price Oscillator](indicators/momentum/dpo/description.md)
+ * [MOM - Momentum](indicators/momentum/mom/description.md)
+ * [PMO - Price Momentum Oscillator](indicators/momentum/pmo/description.md)
+ * [PO - Price Oscillator](indicators/momentum/po/description.md)
+ * [PPO - Percentage Price Oscillator](indicators/momentum/ppo/description.md)
+ * [PRS - Price Relative Strength](indicators/momentum/prs/description.md)
+ * [ROC - Rate of Change](indicators/momentum/roc/description.md)
+ * [TRIX - Triple Exponential](indicators/momentum/trix/description.md)
+ * [TSI - True Strength Index](indicators/momentum/tsi/description.md)
+ * [VEL - Velocity](indicators/momentum/vel/description.md)
+ * [VORTEX - Vortex Indicator](indicators/momentum/vortex/description.md)
* Basic Transforms
* Numerical Analysis
* Errors
@@ -92,4 +111,3 @@
* Oscillators
* Volatility
* Volume
-
diff --git a/docs/index.html b/docs/index.html
index c98425ed..23a7f5e8 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -3,71 +3,140 @@
QuanTAlib Documentation
+
+
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-