Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Miha Kralj
2024-09-23 08:38:20 -07:00
456 changed files with 60292 additions and 10790 deletions
-8
View File
@@ -1,8 +0,0 @@
# Top-most EditorConfig file
root = true
[*.{cs,vb}]
# Suppress S3776 (Cognitive Complexity)
dotnet_diagnostic.S3776.severity = none
# Suppress CA1416 (Platform Compatibility)
dotnet_diagnostic.CA1416.severity = none
Binary file not shown.
File diff suppressed because it is too large Load Diff
+22 -29
View File
@@ -3,10 +3,10 @@ on:
workflow_dispatch:
push:
branches:
- '*'
- main
pull_request:
branches:
- '*'
- main
jobs:
build_test:
@@ -45,17 +45,6 @@ jobs:
#configFilePath: GitVersion.yml
updateAssemblyInfo: true
############## Install Python
- name: Install pandas-ta
run: |
sudo apt install python3.10
sudo apt install python3.10-dev
pip3 install numpy
pip3 install pandas
pip3 install pandas-ta
python --version
############## Install more tools
- name: Install JDK11 for Sonar Scanner
@@ -84,21 +73,23 @@ jobs:
- name: Build Main branch of QuanTAlib DLL
if: ${{ github.ref != 'refs/heads/dev' }}
run: dotnet build ./Calculations/Calculations.csproj --configuration Release --nologo -p:PackageVersion=${{ steps.gitversion.outputs.MajorMinorPatch }}
run: dotnet build ./lib/quantalib.csproj --configuration Release --nologo -p:PackageVersion=${{ steps.gitversion.outputs.MajorMinorPatch }}
- name: Build dev branch of QuanTAlib DLL
if: ${{ github.ref == 'refs/heads/dev' }}
run: dotnet build ./Calculations/Calculations.csproj --configuration Release --nologo -p:PackageVersion=${{ steps.gitversion.outputs.FullSemVer }}
- name: Build Indicators DLL
run: dotnet build ./Indicators/Indicators.csproj --configuration Release --nologo
- name: Build Strategies DLL
run: dotnet build ./Strategies/Strategies.csproj --configuration Release --nologo
run: dotnet build ./lib/quantalib.csproj --configuration Release --nologo -p:PackageVersion=${{ steps.gitversion.outputs.FullSemVer }}
- name: Build Averages DLL
run: dotnet build ./quantower/Averages/Averages.csproj --configuration Release --nologo
- name: Build Statistics DLL
run: dotnet build ./quantower/Statistics/Statistics.csproj --configuration Release --nologo
- name: Build SyntheticVendor DLL
run: dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
- name: DotCover Test HTML
if: ${{ github.ref == 'refs/heads/dev' }}
run: dotnet dotcover test Tests/Tests.csproj --dcReportType=HTML --dcoutput=./dotcover.html
run: dotnet dotcover test tests/tests.csproj --dcReportType=HTML --dcoutput=./dotcover.html
- name: DotCover Test XML
if: ${{ github.ref == 'refs/heads/dev' }}
run: dotnet dotcover test Tests/Tests.csproj --dcReportType=DetailedXML --dcoutput=./dotcover.xml --verbosity=Detailed
run: dotnet dotcover test tests/tests.csproj --dcReportType=DetailedXML --dcoutput=./dotcover.xml --verbosity=Detailed
- name: Coverlet Test
if: ${{ github.ref == 'refs/heads/dev' }}
run: dotnet test -p:CollectCoverage=true --collect:"XPlat Code Coverage" --results-directory "./"
@@ -145,12 +136,13 @@ jobs:
release_name: ${{ steps.gitversion.outputs.SemVer }}
tag_name: prerelease
release_config: |
Calculations/bin/Release/net6.0/QuanTAlib.dll
Indicators/bin/Release/QuanTAlib_Indicators.dll
Strategies/bin/Release/QuanTAlib_Strategies.dll
lib/bin/Release/QuanTAlib.dll
quantower/Averages/bin/Release/Averages.dll
quantower/Statistics/bin/Release/Statistics.dll
SyntheticVendor/bin/Release/SyntheticVendor.dll
- name: Push package to myget.org
run: dotnet nuget push 'Calculations/bin/Release/QuanTAlib.*.nupkg'
run: dotnet nuget push 'lib/bin/Release/QuanTAlib.*.nupkg'
--api-key ${{ secrets.MYGET_DEPLOY_KEY_QUANTALIB }}
--source https://www.myget.org/F/quantalib/api/v2/package
--skip-duplicate
@@ -168,13 +160,14 @@ jobs:
release_name: ${{ steps.gitversion.outputs.MajorMinorPatch }}
tag_name: latest
release_config: |
Calculations/bin/Release/net6.0/QuanTAlib.dll
Indicators/bin/Release/QuanTAlib_Indicators.dll
Strategies/bin/Release/QuanTAlib_Strategies.dll
lib/bin/Release/QuanTAlib.dll
quantower/Averages/bin/Release/Averages.dll
quantower/Statistics/bin/Release/Statistics.dll
SyntheticVendor/bin/Release/SyntheticVendor.dll
- name: Push package to nuget.org
if: ${{ github.ref == 'refs/heads/main' }}
run: dotnet nuget push 'Calculations/bin/Release/QuanTAlib.*.nupkg'
run: dotnet nuget push 'lib/bin/Release/QuanTAlib.*.nupkg'
--api-key ${{ secrets.NUGET_DEPLOY_KEY_QUANTLIB }}
--source https://api.nuget.org/v3/index.json
--skip-duplicate
+30
View File
@@ -0,0 +1,30 @@
name: SonarCloud analysis
on:
push:
pull_request:
workflow_dispatch:
permissions:
pull-requests: read # allows SonarCloud to decorate PRs with analysis results
jobs:
Analysis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Analyze with SonarCloud
uses: SonarSource/sonarcloud-github-action@v2.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Generate a token on Sonarcloud.io, add it to the secrets of this repo with the name SONAR_TOKEN
with:
# Additional arguments for the SonarScanner CLI
args: >
-Dsonar.projectKey=mihakralj_QuanTAlib
-Dsonar.organization=mihakralj
-Dsonar.sources=.
-Dsonar.verbose=false
+49 -9
View File
@@ -1,7 +1,7 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
@@ -9,12 +9,6 @@
*.user
*.userosscache
*.sln.docstates
.vscode/
.fleet/
*.deps.json
.Sandbox/
#.sonarlint/
.DS_Store
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
@@ -29,6 +23,7 @@ mono_crash.*
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
@@ -67,6 +62,9 @@ project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
@@ -92,6 +90,7 @@ StyleCopReport.xml
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
@@ -143,6 +142,11 @@ _TeamCity*
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
@@ -290,6 +294,17 @@ node_modules/
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
@@ -346,6 +361,9 @@ ASALocalRun/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
@@ -354,5 +372,27 @@ MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
dotCover.Output.dcvr
/Tests/GlobalSuppressions.cs
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
-92
View File
@@ -1,92 +0,0 @@
using System;
public struct TValue
{
public DateTime Timestamp { get; set; }
public double Value { get; set; }
public TValue(DateTime timestamp, double value)
{
Timestamp = timestamp;
Value = value;
}
public override string ToString()
{
return $"[{this.Timestamp:yyyy-MM-dd HH:mm:ss}: {this.Value:F2}]";
}
public override bool Equals(object obj)
{
if (obj is TValue other)
{
return Timestamp == other.Timestamp && Value == other.Value;
}
return false;
}
public override int GetHashCode()
{
return HashCode.Combine(Timestamp, Value);
}
}
public struct TBar
{
public DateTime Timestamp { get; set; }
public double Open { get; set; }
public double High { get; set; }
public double Low { get; set; }
public double Close { get; set; }
public double Volume { get; set; }
public TBar(DateTime timestamp, double open, double high, double low, double close, double volume)
{
Timestamp = timestamp;
Open = open;
High = high;
Low = low;
Close = close;
Volume = volume;
}
public override string ToString()
{
return $"[{this.Timestamp:yyyy-MM-dd HH:mm:ss}: O={this.Open:F2}, H={this.High:F2}, L={this.Low:F2}, C={this.Close:F2}, V={this.Volume:F2}]";
}
public override bool Equals(object obj)
{
if (obj is TBar other)
{
return Timestamp == other.Timestamp &&
Open == other.Open &&
High == other.High &&
Low == other.Low &&
Close == other.Close &&
Volume == other.Volume;
}
return false;
}
public override int GetHashCode()
{
return HashCode.Combine(Timestamp, Open, High, Low, Close, Volume);
}
}
public class TValueEventArg<T> : EventArgs
{
public T Data { get; }
public bool IsClosed { get; }
public bool IsHot { get; }
public TValueEventArg(T data, bool isClosed, bool isHot)
{
Data = data;
IsClosed = isClosed;
IsHot = isHot;
}
}
-92
View File
@@ -1,92 +0,0 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#load "./base.cs"
#!csharp
TValue vv = new(DateTime.Now, 100);
display(vv.ToString());
#!csharp
TBar bb = new();
display(bb.ToString());
#!csharp
public class Emitter {
private Random random = new Random();
public event EventHandler<TValueEventArg<TValue>> Pub;
public void Emit() {
DateTime now = DateTime.Now;
double randomValue = random.NextDouble() * 100; // Generates a random number between 0 and 100
TValue value = new TValue(now, randomValue);
TValueEventArg<TValue> eventArg = new TValueEventArg<TValue>(value, true, true);
OnValuePub(eventArg);
}
protected virtual void OnValuePub(TValueEventArg<TValue> eventArg) {
Pub?.Invoke(this, eventArg);
}
}
public class BarEmitter
{
private Random random = new Random();
public event EventHandler<TValueEventArg<TBar>> Pub;
private double lastClose = 100.0; // Starting price
public void Emit()
{
double open = lastClose;
double close = open * (1 + (random.NextDouble() - 0.5) * 0.02); // +/- 1% change
double high = Math.Max(open, close) * (1 + random.NextDouble() * 0.005); // Up to 0.5% higher
double low = Math.Min(open, close) * (1 - random.NextDouble() * 0.005); // Up to 0.5% lower
double volume = random.NextDouble() * 1000000; // Random volume between 0 and 1,000,000
TBar bar = new TBar(DateTime.Now, open, high, low, close, volume);
lastClose = close;
TValueEventArg<TBar> eventArg = new TValueEventArg<TBar>(bar, true, true);
OnBarPub(eventArg);
}
protected virtual void OnBarPub(TValueEventArg<TBar> eventArg)
{
Pub?.Invoke(this, eventArg);
}
}
public class Listener
{
public void Sub(object sender, EventArgs e)
{
if (e is TValueEventArg<TValue> tValueArg) {
Console.WriteLine($"TValue: {tValueArg.Data.Value:F2}");
} else if (e is TValueEventArg<TBar> tBarArg) {
Console.WriteLine($"TBar: o={tBarArg.Data.Open:F2}, v={tBarArg.Data.Volume:F2}");
} else {
Console.WriteLine($"Unknown type: {e.GetType().Name}");
}
}
}
#!csharp
Emitter em1 = new();
BarEmitter em2 = new();
Listener list = new();
em1.Pub += list.Sub;
em2.Pub += list.Sub;
// Emit 5 random values
for (int i = 0; i < 3; i++) {
em1.Emit();
em2.Emit();
}
-29
View File
@@ -1,29 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
ADD - adding TSeries+TSeries together, or TSeries+double, or double+TSeries
Remarks:
Most of scaffolding is packaged in abstracty class Pair_TSeries_Indicator.
</summary> */
public class ADD_Series : Pair_TSeries_Indicator
{
public ADD_Series(TSeries d1, TSeries d2 ) : base(d1, d2) {
if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
}
public ADD_Series(TSeries d1, double dd2 ) : base(d1, dd2) {
if (base._d1.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
}
public ADD_Series(double dd1, TSeries d2 ) : base(dd1, d2) {
if (base._d2.Count > 0) { for (int i=0; i< base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
}
public override void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update)
{
(System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t, TValue1.v+TValue2.v);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
}
}
-52
View File
@@ -1,52 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
CORR: Pearson's Correlation Coefficient
PCC is a measure of linear correlation between two sets of data.
It is the ratio between the covariance of two variables and the product of
their standard deviations; it is essentially a normalized measurement of
the covariance, such that the result always has a value between 1 and 1.
Sources:
https://en.wikipedia.org/wiki/Pearson_correlation_coefficient
</summary> */
public class CORR_Series : Pair_TSeries_Indicator
{
public CORR_Series(TSeries d1, TSeries d2, int period, bool useNaN = false) : base(d1, d2, period, useNaN)
{
if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
}
private readonly System.Collections.Generic.List<double> _x = new();
private readonly System.Collections.Generic.List<double> _xx = new();
private readonly System.Collections.Generic.List<double> _y = new();
private readonly System.Collections.Generic.List<double> _yy = new();
private readonly System.Collections.Generic.List<double> _xy = new();
public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
{
Add_Replace_Trim(_x, TValue1.v, _p, update);
Add_Replace_Trim(_xx, TValue1.v * TValue1.v, _p, update);
Add_Replace_Trim(_y, TValue2.v, _p, update);
Add_Replace_Trim(_yy, TValue2.v * TValue2.v, _p, update);
Add_Replace_Trim(_xy, TValue1.v * TValue2.v, _p, update);
double _sumx = _x.Sum();
double _sumxx = _xx.Sum();
double _sumy = _y.Sum();
double _sumyy = _yy.Sum();
double _sumxy = _xy.Sum();
double _covar = (_sumxx - _sumx * _sumx / _p) * (_sumyy - _sumy * _sumy / _p);
double _cor = (_covar != 0) ? (_sumxy - _sumx * _sumy / _p) / Math.Sqrt(_covar) : 0.0;
var result = (TValue1.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _cor);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
}
}
-46
View File
@@ -1,46 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
COVAR: Covariance
Covariance is defined as the expected value (or mean) of the product
of their deviations from their individual expected values.
Sources:
https://en.wikipedia.org/wiki/Covariance
</summary> */
public class COVAR_Series : Pair_TSeries_Indicator
{
public COVAR_Series(TSeries d1, TSeries d2, int period, bool useNaN = false) : base(d1, d2, period, useNaN)
{
if (base._d1.Count > 0 && base._d2.Count > 0) {
for (int i = 0; i < base._d1.Count; i++) {
this.Add(base._d1[i], base._d2[i], false);
}
}
}
private readonly System.Collections.Generic.List<double> _x = new();
private readonly System.Collections.Generic.List<double> _y = new();
private readonly System.Collections.Generic.List<double> _xy = new();
public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
{
BufferTrim(_x, TValue1.v, _p, update);
BufferTrim(_y, TValue2.v, _p, update);
BufferTrim(_xy, TValue1.v * TValue2.v, _p, update);
double _avgx = _x.Average();
double _avgy = _y.Average();
double _avgxy = _xy.Average();
double _covar = _avgxy - (_avgx * _avgy);
var result = (TValue1.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _covar);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
}
}
-29
View File
@@ -1,29 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
DIV - divide TSeries/TSeries , or TSeries/double, or double/TSeries
Remarks:
Most of scaffolding is packaged in abstracty class Pair_TSeries_Indicator.
</summary> */
public class DIV_Series : Pair_TSeries_Indicator
{
public DIV_Series(TSeries d1, TSeries d2 ) : base(d1, d2) {
if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
}
public DIV_Series(TSeries d1, double dd2 ) : base(d1, dd2) {
if (base._d1.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
}
public DIV_Series(double dd1, TSeries d2 ) : base(dd1, d2) {
if (base._d2.Count > 0) { for (int i=0; i< base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
}
public override void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update)
{
(System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t,
(TValue2.v is not 0) ? TValue1.v/TValue2.v : Double.PositiveInfinity);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
}
}
-27
View File
@@ -1,27 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
MUL - multiply TSeries*TSeries together, or TSeries*double, or double*TSeries
</summary> */
public class MUL_Series : Pair_TSeries_Indicator
{
public MUL_Series(TSeries d1, TSeries d2 ) : base(d1, d2) {
if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
}
public MUL_Series(TSeries d1, double dd2 ) : base(d1, dd2) {
if (base._d1.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
}
public MUL_Series(double dd1, TSeries d2 ) : base(dd1, d2) {
if (base._d2.Count > 0) { for (int i=0; i< base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
}
public override void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update)
{
(System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t,
TValue1.v*TValue2.v);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
}
}
-28
View File
@@ -1,28 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
SUB - subtracting TSeries-TSeries, or TSeries-double, or double-TSeries
</summary> */
public class SUB_Series : Pair_TSeries_Indicator
{
public SUB_Series(TSeries d1, TSeries d2 ) : base(d1, d2) {
if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
}
public SUB_Series(TSeries d1, double dd2 ) : base(d1, dd2) {
if (base._d1.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
}
public SUB_Series(double dd1, TSeries d2 ) : base(dd1, d2) {
if (base._d2.Count > 0) { for (int i=0; i< base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
}
public override void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update)
{
(System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t,
TValue1.v-TValue2.v);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
}
}
@@ -1,132 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
Abstract classes with all scaffolding required to build indicators.
All abstracts support period, NaN, and all permutations of Add() methods.
Indicator classess need to implement:
- Chaining constructor (Abstract's constructor executes first)
- Default Add(value) class
- optional Add(series) bulk insert class (for optimization of historical analysis)
Single_TSeries_Indicator - one single-value TSeries in, one TSeries out.
Pair_TSeries_Indicator - Two TSeries in, one TSeries out. (includes simple semaphoring)
Single_TBars_Indicator - One OHLCV TBars in, one TSeries out.
</summary> */
public abstract class Pair_TSeries_Indicator : TSeries {
protected readonly int _p;
protected readonly bool _NaN;
protected readonly TSeries _d1;
protected readonly TSeries _d2;
protected readonly double _dd1, _dd2;
// Chainable Constructors - add them at the end of primary constructors if needed
protected Pair_TSeries_Indicator(TSeries source1, TSeries source2, int period, bool useNaN) {
_p = period;
_NaN = useNaN;
_d1 = source1;
_d2 = source2;
_dd1 = double.NaN;
_dd2 = double.NaN;
_d1.Pub += Sub;
_d2.Pub += Sub;
}
protected Pair_TSeries_Indicator(TSeries source1, TSeries source2) {
_d1 = source1;
_d2 = source2;
_dd1 = double.NaN;
_dd2 = double.NaN;
_d1.Pub += Sub;
_d2.Pub += Sub;
}
protected Pair_TSeries_Indicator(TSeries source1, double dd2) {
_d1 = source1;
_d2 = new TSeries();
_dd1 = double.NaN;
_dd2 = dd2;
_d1.Pub += Sub;
}
protected Pair_TSeries_Indicator(double dd1, TSeries source2) {
_d1 = new TSeries();
_d2 = source2;
_dd1 = dd1;
_dd2 = double.NaN;
_d2.Pub += Sub;
}
// overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list
public virtual void Add((DateTime t, double v) TValue1, (DateTime t, double v) TValue2, bool update) {
base.Add((TValue1.t, 0), update);
// default inserts zeros
}
// potentially overridable Add() bulk variations (could be replaced with faster bulk algos)
public virtual void Add(TSeries d1, TSeries d2) {
for (var i = 0; i < d1.Count; i++) {
Add(d1[i], d2[i], false);
}
}
public virtual void Add(TSeries d1, double dd2) {
for (var i = 0; i < d1.Count; i++) {
Add(d1[i], (d1[i].t, dd2), false);
}
}
public virtual void Add(double dd1, TSeries d2) {
for (var i = 0; i < d2.Count; i++) {
Add((d2[i].t, dd1), d2[i], false);
}
}
public void Add((DateTime t, double v) TValue1, (DateTime t, double v) TValue2) {
Add(TValue1, TValue2, false);
}
public void Add(bool update) {
if (_dd1 is double.NaN && _dd2 is double.NaN) {
// (Series, Series)
if (update || (_d1.Count > Count && _d2.Count > Count)) {
Add(_d1[_d1.Count - 1], _d2[_d2.Count - 1], update);
}
}
else if (_dd2 is not double.NaN && _dd1 is double.NaN) {
// (Series, Double)
Add(_d1[_d1.Count - 1], (_d1[_d1.Count - 1].t, _dd2), update);
}
else {
// (Double, Series)
Add((_d2[_d2.Count - 1].t, _dd1), _d2[_d2.Count - 1], update);
}
}
public void Add() {
Add(false);
}
public new void Sub(object source, TSeriesEventArgs e) {
Add(e.update);
}
protected static void Add_Replace(List<double> l, double v, bool update) {
if (update) {
l[l.Count - 1] = v;
}
else {
l.Add(v);
}
}
protected static void Add_Replace_Trim(List<double> l, double v, int p, bool update) {
Add_Replace(l, v, update);
if (l.Count > p && p != 0) {
l.RemoveAt(0);
}
}
}
-34
View File
@@ -1,34 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
COMPARE - Generates +1 if A is above B, -1 if A is below B and 0 if A=B
</summary> */
public class COMPARE_Series : Pair_TSeries_Indicator {
public COMPARE_Series(TSeries d1, TSeries d2) : base(d1, d2) {
if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
}
public COMPARE_Series(TSeries d1, double dd2) : base(d1, dd2) {
if (base._d1.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
}
public COMPARE_Series(double dd1, TSeries d2) : base(dd1, d2) {
if (base._d2.Count > 0) { for (int i = 0; i < base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
}
public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update) {
double val = TValue1.v > TValue2.v ? 1 : -1;
val = TValue1.v == TValue2.v ? 0 : val;
(System.DateTime t, double v) over = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t, TValue1.v > TValue2.v ? 1 : val);
if (update) { base[^1] = over; }
else { base.Add(over); }
}
}
-44
View File
@@ -1,44 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
OVER - Generates +1 if A is above B, -1 if A is below B and 0 if A=B
Remarks:
OVER.Cross generates 1 when A breaks B from below and -1 when A breaks B from above
</summary> */
public class CROSS_Series : Pair_TSeries_Indicator {
public TSeries Cross { get; set; } = new();
private double _previous = double.NaN;
public CROSS_Series(TSeries d1, TSeries d2) : base(d1, d2) {
if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
}
public CROSS_Series(TSeries d1, double dd2) : base(d1, dd2) {
if (base._d1.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
}
public CROSS_Series(double dd1, TSeries d2) : base(dd1, d2) {
if (base._d2.Count > 0) { for (int i = 0; i < base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
}
public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update) {
double val = TValue1.v > TValue2.v ? 1 : -1;
val = TValue1.v == TValue2.v ? 0 : val;
double over = TValue1.v > TValue2.v ? 1 : val;
val = (_previous < over) ? 1 : -1;
val = ((_previous == over) || Double.IsNaN(this._previous) || (this._previous == 0)) ? 0 : val;
(System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t,val);
this._previous = over;
if (update) { base[^1] = result; }
else { base.Add(result); }
}
}
-34
View File
@@ -1,34 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Linq;
public enum OType {
NIL = 0, // No position
BTO = 1, // Buy to Open
STC = 2, // Sell to Close
STO = 3, // Sell to Open
BTC = 4, // Buy to Close
END = 5, // Exit the trade
}
public class TOrders : List<(DateTime t, OType o)> {
public void Add((DateTime t, OType o) TOrder, bool update = false)
{
if (update) { this[^1] = TOrder; }
else { base.Add(TOrder); }
OnEvent(update);
}
protected virtual void OnEvent(bool update = false) {
Pub?.Invoke(this, new TSeriesEventArgs { update = update }); }
public delegate void NewDataEventHandler(object source, TSeriesEventArgs args);
public event NewDataEventHandler Pub;
}
-69
View File
@@ -1,69 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
ADL: Chaikin Accumulation/Distribution Line
ADL is a volume-based indicator that measures the cumulative Money Flow Volume:
1. Money Flow Multiplier = [(Close - Low) - (High - Close)] /(High - Low)
2. Money Flow Volume = Money Flow Multiplier x Volume for the Period
3. ADL = Previous ADL + Current Period's Money Flow Volume
Sources:
https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line
</summary> */
public class ADL_Series : TSeries {
protected readonly TBars _data;
private double _lastadl, _lastlastadl;
//core constructors
public ADL_Series() {
Name = $"ADL()";
_lastadl = _lastlastadl = 0;
}
public ADL_Series(TBars source) {
_data = source;
Name = $"ADL({(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_lastadl = _lastlastadl = 0;
_data.Pub += Sub;
Add(data: _data);
}
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) { this._lastadl = this._lastlastadl; }
else { this._lastlastadl = this._lastadl; }
double _adl = 0;
double tmp = TBar.h - TBar.l;
if (tmp > 0.0) {
_adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v);
}
_lastadl = _adl;
var ret = (TBar.t, _adl);
return base.Add(ret, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_lastadl = _lastlastadl = 0;
}
}
-90
View File
@@ -1,90 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
ADOSC: Chaikin Accumulation/Distribution Oscillator
ADO measures the momentum of ADL using the difference between slow (10-day) EMA(ADL)
and fast (3-day) EMA(ADL):
Chaikin A/D Oscillator is defined as 3-day EMA of ADL minus 10-day EMA of ADL
Sources:
https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_oscillator
</summary> */
public class ADOSC_Series : TSeries {
protected readonly TBars _data;
private readonly double _k1, _k2;
private double _lastema1, _lastlastema1, _lastema2, _lastlastema2;
private double _lastadl, _lastlastadl;
//core constructors
public ADOSC_Series(int shortPeriod, int longPeriod, bool useNaN = false) {
Name = $"ADOSC()";
_k1 = 2.0 / (shortPeriod + 1);
_k2 = 2.0 / (longPeriod + 1);
_lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
}
public ADOSC_Series(TBars source, int shortPeriod, int longPeriod, bool useNaN = false) :this(shortPeriod, longPeriod, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_lastadl = _lastlastadl = 0;
_data.Pub += Sub;
Add(data: _data);
}
public ADOSC_Series() : this(shortPeriod: 3, longPeriod: 10, useNaN: false) {}
public ADOSC_Series(TBars source) : this(source, shortPeriod: 3, longPeriod:10, useNaN:false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update= false) {
if (update) {
_lastadl = _lastlastadl;
_lastema1 = _lastlastema1;
_lastema2 = _lastlastema2;
}
double _adl = 0;
double tmp = TBar.h - TBar.l;
if (tmp > 0.0) { _adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v); }
if (this.Count == 0) { _lastema1 = _lastema2 = _adl; }
double _ema1 = (_adl - _lastema1) * _k1 + _lastema1;
double _ema2 = (_adl - _lastema2) * _k2 + _lastema2;
_lastlastadl = _lastadl;
_lastadl = _adl;
_lastlastema1 = _lastema1;
_lastema1 = _ema1;
_lastlastema2 = _lastema2;
_lastema2 = _ema2;
double _adosc = _ema1 - _ema2;
var ret = (TBar.t, _adosc);
return base.Add(ret, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
}
}
-114
View File
@@ -1,114 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
ALMA: Arnaud Legoux Moving Average
The ALMA moving average uses the curve of the Normal (Gauss) distribution, which
can be shifted from 0 to 1. This allows regulating the smoothness and high
sensitivity of the indicator. Sigma is another parameter that is responsible for
the shape of the curve coefficients. This moving average reduces lag of the data
in conjunction with smoothing to reduce noise.
Sources:
https://phemex.com/academy/what-is-arnaud-legoux-moving-averages
https://www.prorealcode.com/prorealtime-indicators/alma-arnaud-legoux-moving-average/
Discrepancy with Pandas-TA (but passes the validation with Skender.GetAlma)
</summary> */
public class ALMA_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly System.Collections.Generic.List<double> _weight;
private double _norm;
private readonly double _offset, _sigma;
//core constructors
public ALMA_Series(int period, double offset, double sigma, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"ALMA({period})";
_offset = offset;
_sigma = sigma;
_weight = new();
}
public ALMA_Series(TSeries source, int period, double offset, double sigma, bool useNaN) : this(period, offset, sigma, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public ALMA_Series() : this(period:0, offset:0.85, sigma:6.0, useNaN: false) { }
public ALMA_Series(int period) : this(period: period, offset:0.85, sigma:6.0, useNaN:false) { }
public ALMA_Series(TBars source) : this(source:source.Close, period:0, offset:0.85, sigma:6.0, useNaN:false) { }
public ALMA_Series(TBars source, int period) : this(source:source.Close, period:period, offset: 0.85, sigma: 6.0, useNaN: false) { }
public ALMA_Series(TBars source, int period, double offset, double sigma, bool useNaN) : this(source.Close, period:period, offset: offset, sigma: sigma, useNaN: false) { }
public ALMA_Series(TSeries source) : this(source, period:0, offset:0.85, sigma:6.0, useNaN:false) { }
public ALMA_Series(TSeries source, int period) : this(source:source, period:period, offset:0.85, sigma:6.0, useNaN:false) { }
public ALMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, offset: 0.85, sigma: 6.0, useNaN: useNaN) { }
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, double.NaN), update);
}
BufferTrim(_buffer, TValue.v, _period, update);
if (_weight.Count < _buffer.Count) {
for (var i = 0; i < _buffer.Count - _weight.Count; i++) {
_weight.Add(0.0);
}
}
if (_buffer.Count <= _period || _period == 0) {
var _len = _buffer.Count;
_norm = 0;
var _m = _offset * (_len - 1);
var _s = _len / _sigma;
for (var i = 0; i < _len; i++) {
var _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s));
_weight[i] = _wt;
_norm += _wt;
}
}
double _weightedSum = 0;
for (var i = 0; i < _buffer.Count; i++) {
_weightedSum += _weight[i] * _buffer[i];
}
var _alma = _weightedSum / _norm;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _alma);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
_weight.Clear();
}
}
-87
View File
@@ -1,87 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
ATRP: Average True Range Percent
Average True Range Percent is (ATR/Close Price)*100.
This normalizes so it can be compared to other stocks.
Sources:
https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/atrp
</summary> */
public class ATRP_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TBars _data;
private double _k;
private int _len;
private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
//core constructors
public ATRP_Series(int period, bool useNaN) {
_period = period;
_k = 1.0 / (double)(_period);
_NaN = useNaN;
_len = 0;
Name = $"ATRP({period})";
}
public ATRP_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(data: _data);
}
public ATRP_Series() : this(period: 1, useNaN: false) { }
public ATRP_Series(int period) : this(period: period, useNaN: false) { }
public ATRP_Series(TBars source) : this(source, period: 1, useNaN: false) { }
public ATRP_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
else {
_lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum;
_k = (_period == 0) ? 1 / (double)_len : _k;
_len++;
}
if (_len == 1) { _cm1 = TBar.c; }
double d1 = Math.Abs(TBar.h - TBar.l);
double d2 = Math.Abs(_cm1 - TBar.h);
double d3 = Math.Abs(_cm1 - TBar.l);
(DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
_cm1 = TBar.c;
double _atr = 0;
if (this.Count == 0) { _atr = d.v; }
else if (this.Count < _period + 1) { _sum += d.v; _atr = _sum / (this.Count); }
else { _atr = _k * (d.v - _lastatr) + _lastatr; }
_lastatr = _atr;
double _atrp = 100 * (_atr / TBar.c);
var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _atrp);
return base.Add(res, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_len = 0;
}
}
-88
View File
@@ -1,88 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
ATR: wildeR Moving Average
The average true range (ATR) is a price volatility indicator
showing the average price variation of assets within a given time period.
Sources:
https://en.wikipedia.org/wiki/Average_true_range
https://www.tradingview.com/wiki/Average_True_Range_(ATR)
https://www.investopedia.com/terms/a/atr.asp
</summary> */
public class ATR_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TBars _data;
private double _k;
private int _len;
private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
//core constructors
public ATR_Series(int period, bool useNaN) {
_period = period;
_k = 1.0 / (double)(_period);
_NaN = useNaN;
_len = 0;
Name = $"ATR({period})";
}
public ATR_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(data: _data);
}
public ATR_Series() : this(period: 1, useNaN: false) { }
public ATR_Series(int period) : this(period: period, useNaN: false) { }
public ATR_Series(TBars source) : this(source, period: 1, useNaN: false) { }
public ATR_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
else {
_lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum;
_k = (_period == 0) ? 1 / (double)_len : _k;
_len++;
}
if (_len == 1) { _cm1 = TBar.c; }
double d1 = Math.Abs(TBar.h - TBar.l);
double d2 = Math.Abs(_cm1 - TBar.h);
double d3 = Math.Abs(_cm1 - TBar.l);
(DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
_cm1 = TBar.c;
double _atr = 0;
if (this.Count == 0) { _atr = d.v; }
else if (this.Count < _period + 1) { _sum += d.v; _atr = _sum / (this.Count); }
else { _atr = _k * (d.v - _lastatr) + _lastatr; }
_lastatr = _atr;
var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _atr);
return base.Add(res, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_len = 0;
}
}
-112
View File
@@ -1,112 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
BBANDS: Bollinger Bands®
Price channels created by John Bollinger, depict volatility as standard deviation boundary
line range from a moving average of price. The bands automatically widen when volatility
increases and contract when volatility decreases. Their dynamic nature allows them to be
used on different securities with the standard settings.
Mid Band = simple moving average (SMA)
Upper Band = SMA + (standard deviation of price x multiplier)
Lower Band = SMA - (standard deviation of price x multiplier)
Bandwidth = Width of the channel: (Upper-Lower)/SMA
%B = The location of the data point within the channel: (Price-Lower)/(Upper/Lower)
Z-Score = number of standard deviations of the data point from SMA
Sources:
https://www.investopedia.com/terms/b/bollingerbands.asp
https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands
Note:
Bollinger Bands® is a registered trademark of John A. Bollinger.
</summary> */
public class BBANDS_Series : TSeries {
protected readonly int _period;
protected readonly double _multiplier;
protected readonly bool _NaN;
protected readonly TSeries _data;
public SMA_Series Mid { get; }
public TSeries Upper { get; }
public TSeries Lower { get; }
public TSeries PercentB { get; }
public TSeries Bandwidth { get; }
public TSeries Zscore { get; }
private readonly SDEV_Series _sdev;
//core constructors
public BBANDS_Series(int period, double multiplier, bool useNaN) {
_period = period;
_multiplier = multiplier;
_NaN = useNaN;
Name = $"BBANDS({period})";
}
public BBANDS_Series(TSeries source, int period, double multiplier, bool useNaN) : this(period, multiplier, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
Upper = new("BB_Up");
Lower = new("BB_Low");
Bandwidth = new("BBandwidth");
PercentB = new("%BBandwidth");
Zscore = new("Zscore");
Mid = new(period, false);
_sdev = new(period, false);
_data.Pub += Sub;
Add(_data);
}
public BBANDS_Series() : this(period:0, multiplier: 2.0, useNaN: false) { }
public BBANDS_Series(int period) : this(period: period, multiplier: 2.0, useNaN:false) { }
public BBANDS_Series(TBars source) : this(source:source.Close, period:0, multiplier: 2.0, useNaN:false) { }
public BBANDS_Series(TBars source, int period) : this(source:source.Close, period:period, multiplier: 2.0, useNaN: false) { }
public BBANDS_Series(TBars source, int period, double multiplier, bool useNaN) : this(source.Close, period:period, multiplier:multiplier, useNaN: false) { }
public BBANDS_Series(TSeries source) : this(source, period:0, useNaN:false) { }
public BBANDS_Series(TSeries source, int period) : this(source:source, period:period, useNaN:false) { }
public BBANDS_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, multiplier: 2.0, useNaN: useNaN) { }
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update=false) {
var _mid = Mid.Add(TValue,update);
var _sd = this._sdev.Add(TValue, update);
var _upper = Upper.Add((TValue.t, _mid.v + _sd.v * _multiplier), update);
var _lower = Lower.Add((TValue.t, _mid.v - _sd.v * _multiplier), update);
double _pbdnd = TValue.v - _lower.v;
double _pbdvr = _upper.v - _lower.v;
PercentB.Add((TValue.t, _pbdnd/_pbdvr), update);
Zscore.Add((TValue.t, (TValue.v-_mid.v)/_sd.v), update);
Bandwidth.Add((TValue.t, _pbdvr / _mid.v), update);
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _pbdvr / _mid.v);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
Mid.Clear();
_sdev.Clear();
Upper.Clear();
Lower.Clear();
}
}
-72
View File
@@ -1,72 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
BIAS: Rate of change between the source and a moving average.
Bias is a statistical term which means a systematic deviation from the actual value.
BIAS = (close - SMA) / SMA
= (close / SMA) - 1
Sources:
https://en.wikipedia.org/wiki/Bias_of_an_estimator
</summary> */
public class BIAS_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private readonly SMA_Series _sma;
//core constructors
public BIAS_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"BIAS({period})";
_sma = new(period, false);
}
public BIAS_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public BIAS_Series() : this(period: 0, useNaN: false) { }
public BIAS_Series(int period) : this(period: period, useNaN: false) { }
public BIAS_Series(TBars source) : this(source.Close, 0, false) { }
public BIAS_Series(TBars source, int period) : this(source.Close, period, false) { }
public BIAS_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public BIAS_Series(TSeries source) : this(source, 0, false) { }
public BIAS_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
var _s = _sma.Add(TValue,update);
double _bias = (TValue.v / ((_s.v!=0)?_s.v:1)) - 1;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _bias);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_sma.Reset();
}
}
-86
View File
@@ -1,86 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
CCI: Commodity Channel Index
Commodity Channel Index is a momentum oscillator used to primarily identify overbought
and oversold levels relative to a mean. CCI measures the current price level relative
to an average price level over a given period of time:
- CCI is relatively high when prices are far above their average.
- CCI is relatively low when prices are far below their average.
Using this method, CCI can be used to identify overbought and oversold levels.
Sources:
https://www.investopedia.com/terms/c/commoditychannelindex.asp
https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/cci
</summary> */
public class CCI_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TBars _data;
private readonly System.Collections.Generic.List<double> _tp = new();
//core constructors
public CCI_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"CCI({period})";
}
public CCI_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(data: _data);
}
public CCI_Series() : this(period: 2, useNaN: false) { }
public CCI_Series(int period) : this(period: period, useNaN: false) { }
public CCI_Series(TBars source) : this(source, period: 2, useNaN: false) { }
public CCI_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
double _tpItem = (TBar.h + TBar.l + TBar.c) / 3.0;
if (update) {
this._tp[this._tp.Count - 1] = _tpItem;
}
else {
this._tp.Add(_tpItem);
}
if (this._tp.Count > this._period) { this._tp.RemoveAt(0); }
// average TP over _tp buffer
double _avgTp = _tp.Average();
// average Deviation over _tp buffer
double _avgDv = 0;
for (int i = 0; i < this._tp.Count; i++) { _avgDv += Math.Abs(_avgTp - this._tp[i]); }
_avgDv /= this._tp.Count;
double _cci = (_avgDv == 0) ? 0 : (this._tp[this._tp.Count - 1] - _avgTp) / (0.015 * _avgDv);
var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _cci);
return base.Add(res, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_tp.Clear();
}
}
-90
View File
@@ -1,90 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
CMO: Chande Momentum Oscillator
Chande Momentum Oscillator (also known as CMO indicator) was developed by Tushar S. Chande
CMO is similar to other momentum oscillators (e.g. RSI or Stochastics). Alike RSI oscillator,
the CMO values move in the range from -100 to +100 points and its aim is to detect the
overbought and oversold market conditions. CMO calculates the price momentum on both the up
days as well as the down days. The CMO calculation is based on non-smoothed price values
meaning that it can reach its extremes more frequently and the short-time swings are more visible.
Sources:
https://www.technicalindicators.net/indicators-technical-analysis/144-cmo-chande-momentum-oscillator
</summary> */
public class CMO_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buff_up = new();
private readonly System.Collections.Generic.List<double> _buff_dn = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private double _plast_value, _last_value;
//core constructors
public CMO_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"CMO({period})";
}
public CMO_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public CMO_Series() : this(period: 0, useNaN: false) { }
public CMO_Series(int period) : this(period: period, useNaN: false) { }
public CMO_Series(TBars source) : this(source.Close, 0, false) { }
public CMO_Series(TBars source, int period) : this(source.Close, period, false) { }
public CMO_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public CMO_Series(TSeries source) : this(source, 0, false) { }
public CMO_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) { _last_value = _plast_value; } else { _plast_value = _last_value; }
BufferTrim(buffer:_buff_up, (TValue.v > _last_value) ? TValue.v - _last_value : 0, period:_period, update: update);
BufferTrim(buffer: _buff_dn, (TValue.v < _last_value) ? _last_value - TValue.v : 0, period: _period, update: update);
_last_value = TValue.v;
double _cmo_up = 0;
double _cmo_dn = 0;
for (int i = 0; i < Math.Min(_buff_up.Count, _buff_dn.Count); i++) {
_cmo_up += _buff_up[i];
_cmo_dn += _buff_dn[i];
}
double _cmo = 100 * (_cmo_up - _cmo_dn) / (_cmo_up + _cmo_dn);
if (_cmo_up + _cmo_dn == 0) { _cmo = 0; }
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _cmo);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buff_up.Clear();
_buff_dn.Clear();
}
}
-71
View File
@@ -1,71 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
CUSUM: Cumulative Sum (aka Running Total)
SUM across a period provides a rolling sum of all values across the period.
If SUM values would be divided with period, the output would be SMA()
Sources:
https://en.wikipedia.org/wiki/CUSUM
</summary> */
public class CUSUM_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public CUSUM_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"CUSUM({period})";
}
public CUSUM_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public CUSUM_Series() : this(period: 0, useNaN: false) { }
public CUSUM_Series(int period) : this(period: period, useNaN: false) { }
public CUSUM_Series(TBars source) : this(source.Close, 0, false) { }
public CUSUM_Series(TBars source, int period) : this(source.Close, period, false) { }
public CUSUM_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public CUSUM_Series(TSeries source) : this(source, period: 0, useNaN: false) { }
public CUSUM_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sum = 0;
for (int i = 0; i < _buffer.Count; i++) { _sum += _buffer[i]; }
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sum);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-83
View File
@@ -1,83 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
DECAY:
Linear decay can be modeled by a straight line with a negative slope of 1/period.
The value decreases in a straight line from the last maximum to 0.
Decay = Last Max - distance/period
Exponential decay is modeled as an exponential curve with diminishing factor of
1-1/p
</summary> */
public class DECAY_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private readonly bool _exp;
private double _pdecay, _ppdecay;
private readonly double _dfactor;
//core constructors
public DECAY_Series(int period, bool exponential, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"DECAY({period})";
_exp = exponential;
_dfactor = (_exp) ? 1.0 - 1.0 / (double)_period : 1 / (double)_period;
_pdecay = _ppdecay = 0;
}
public DECAY_Series(TSeries source, int period, bool exponential, bool useNaN) : this(period, exponential, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public DECAY_Series() : this(period: 0, exponential: false, useNaN: false) { }
public DECAY_Series(int period) : this(period: period, exponential: false, useNaN: false) { }
public DECAY_Series(TBars source) : this(source.Close, period: 0, exponential: false, useNaN: false) { }
public DECAY_Series(TBars source, int period) : this(source.Close, period: period, exponential:false, useNaN:false) { }
public DECAY_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, exponential: false, useNaN) { }
public DECAY_Series(TSeries source) : this(source, period: 0, exponential: false, useNaN:false) { }
public DECAY_Series(TSeries source, int period) : this(source: source, period: period, exponential: false, useNaN: false) { }
public DECAY_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, exponential: false, useNaN: useNaN) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
if (update) { _pdecay = _ppdecay; }
else { _ppdecay = _pdecay; }
if (this.Count == 0) { _pdecay = TValue.v; }
double _decay = Math.Max(TValue.v, Math.Max((_exp) ? _pdecay * _dfactor : _pdecay - _dfactor, 0));
_pdecay = _decay;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _decay);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_pdecay = _ppdecay = 0;
}
}
-127
View File
@@ -1,127 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
DEMA: Double Exponential Moving Average
DEMA uses EMA(EMA()) to calculate smoother Exponential moving average.
Sources:
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/double-exponential-moving-average-dema/
Remark:
ema1 = EMA(close, length)
ema2 = EMA(ema1, length)
DEMA = 2 * ema1 - ema2
</summary> */
public class DEMA_Series : TSeries {
private double _k;
private double _sum, _oldsum;
private double _lastema1, _oldema1, _lastema2, _oldema2;
private int _len;
private readonly bool _useSMA;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructor
public DEMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
Name = $"DEMA({period})";
_k = 2.0 / (_period + 1);
_len = 0;
_sum = _oldsum = _lastema1 = _lastema2 = 0;
}
//generic constructors (source)
public DEMA_Series() : this(0, false, true) {}
public DEMA_Series(int period) : this(period, false, true) {}
public DEMA_Series(TBars source) : this(source.Close, 0, false) {}
public DEMA_Series(TBars source, int period) : this(source.Close, period, false) {}
public DEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {}
public DEMA_Series(TSeries source, int period) : this(source, period, false, true) {}
public DEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {}
public DEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) {
_lastema1 = _oldema1;
_lastema2 = _oldema2;
_sum = _oldsum;
}
else {
_oldema1 = _lastema1;
_oldema2 = _lastema2;
_oldsum = _sum;
_len++;
}
if (_period == 0) {
_k = 2.0 / (_len + 1);
}
double _ema1, _ema2, _dema;
if (Count == 0) {
_ema1 = _ema2 = _sum = TValue.v;
}
else if (_len <= _period && _useSMA && _period != 0) {
_sum += TValue.v;
_ema1 = _sum / Math.Min(_len, _period);
_ema2 = _ema1;
}
else {
_ema1 = (TValue.v - _lastema1) * _k + _lastema1;
_ema2 = (_ema1 - _lastema2) * _k + _lastema2;
}
_dema = 2 * _ema1 - _ema2;
_lastema1 = double.IsNaN(_ema1) ? _lastema1 : _ema1;
_lastema2 = double.IsNaN(_ema2) ? _lastema2 : _ema2;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _dema);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) {
return (DateTime.Today, double.NaN);
}
foreach (var item in data) {
Add(item, false);
}
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return Add(_data.Last, update);
}
public (DateTime t, double v) Add() {
return Add(_data.Last, false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(_data.Last, e.update);
}
//reset calculation
public override void Reset() {
_sum = _oldsum = _lastema1 = _lastema2 = 0;
_len = 0;
}
}
-122
View File
@@ -1,122 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
/* <summary>
DWMA: Double Weighted Moving Average
The weights are decreasing over the period with p^2 decay
and the most recent data has the heaviest weight.
</summary> */
public class DWMA_Series : TSeries {
private readonly List<double> _buffer = new();
private List<double> _weights;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
protected int _len;
//core constructors
public DWMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"DWMA({period})";
_len = 0;
_weights = CalculateWeights(_period);
}
public DWMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public DWMA_Series() : this(0, false) {
}
public DWMA_Series(int period) : this(period, false) {
}
public DWMA_Series(TBars source) : this(source.Close, 0, false) {
}
public DWMA_Series(TBars source, int period) : this(source.Close, period, false) {
}
public DWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {
}
public DWMA_Series(TSeries source, int period) : this(source, period, false) {
}
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(_buffer, TValue.v, _period, update);
if (_period == 0) {
_len++;
_weights = CalculateWeights(_len);
}
double _dwma = 0, _wsum = 0;
var bufferCount = _buffer.Count;
var lockObj = new object();
Parallel.For(0, bufferCount, i =>
{
var temp = _buffer[i] * _weights[i];
lock (lockObj) {
_dwma += temp;
_wsum += _weights[i];
}
});
_dwma /= _wsum;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _dwma);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) {
return (DateTime.Today, double.NaN);
}
foreach (var item in data) {
Add(item, false);
}
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return Add(_data.Last, update);
}
public (DateTime t, double v) Add() {
return Add(_data.Last, false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(_data.Last, e.update);
}
//calculating weights
private static List<double> CalculateWeights(int period) {
var weights = new List<double>(period);
for (var i = 0; i < period; i++) {
weights.Add((i + 1) * (i + 1));
}
return weights;
}
//reset calculation
public override void Reset() {
_len = 0;
_buffer.Clear();
_weights = CalculateWeights(_period);
}
}
-120
View File
@@ -1,120 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
EMA: Exponential Moving Average
EMA needs very short history buffer and calculates the EMA value using just the
previous EMA value. The weight of the new datapoint (k) is k = 2 / (period-1)
Sources:
https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages
https://www.investopedia.com/ask/answers/122314/what-exponential-moving-average-ema-formula-and-how-ema-calculated.asp
https://blog.fugue88.ws/archives/2017-01/The-correct-way-to-start-an-Exponential-Moving-Average-EMA
Issues:
There is no consensus what the first EMA value should be - a zero, a first
datapoint, or an average of the initial Period bars. All three starting methods
converge within 20+ bars to the same moving average. Most implementations (including this one)
use SMA() for the first Period bars as a seeding value for EMA.
</summary> */
public class EMA_Series : TSeries {
private double _k;
private double _lastema, _oldema;
private double _sum, _oldsum;
private int _len;
private readonly bool _useSMA;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public EMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
Name = $"EMA({period})";
_k = 2.0 / (_period + 1);
_len = 0;
_sum = _oldsum = _lastema = _oldema = 0;
}
public EMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public EMA_Series() : this(0, false, true) {}
public EMA_Series(int period) : this(period, false, true) {}
public EMA_Series(TBars source) : this(source.Close, 0, false) {}
public EMA_Series(TBars source, int period) : this(source.Close, period, false) {}
public EMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {}
public EMA_Series(TSeries source, int period) : this(source, period, false, true) {}
public EMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {}
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) {
_lastema = _oldema;
_sum = _oldsum;
}
else {
_oldema = _lastema;
_oldsum = _sum;
_len++;
}
double _ema = 0;
if (_period == 0) {
_k = 2.0 / (_len + 1);
}
if (Count == 0) {
_ema = _sum = TValue.v;
}
else if (_len <= _period && _useSMA && _period != 0) {
_sum += TValue.v;
if (_period != 0 && _len > _period) {
_sum -= _data[Count - _period - (update ? 1 : 0)].v;
}
_ema = _sum / Math.Min(_len, _period);
}
else {
_ema = _k * (TValue.v - _lastema) + _lastema;
}
_lastema = double.IsNaN(_ema) ? _lastema : _ema;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _ema);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_sum = _oldsum = _lastema = _oldema = 0;
_len = 0;
}
}
-87
View File
@@ -1,87 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
ENTROPY:
Introduced by Claude Shannon in 1948, entropy measures the unpredictability
of the data, or equivalently, of its average information.
Calculation:
P = close / Σ(close)
ENTROPY = Σ(-P * Log(P) / Log(base))
Sources:
https://en.wikipedia.org/wiki/Entropy_(information_theory)
https://math.stackexchange.com/questions/3428693/how-to-calculate-entropy-from-a-set-of-correlated-samples
</summary> */
public class ENTROPY_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private readonly double _logbase;
private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly System.Collections.Generic.List<double> _buff2 = new();
//core constructors
public ENTROPY_Series(int period, double logbase, bool useNaN) {
_period = period;
_NaN = useNaN;
_logbase = logbase;
Name = $"ENTROPY({period})";
}
public ENTROPY_Series(TSeries source, int period, double logbase, bool useNaN) : this(period, logbase, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public ENTROPY_Series() : this(period: 0, logbase: 2.0, useNaN: false) { }
public ENTROPY_Series(int period) : this(period: period, logbase: 2.0, useNaN: false) { }
public ENTROPY_Series(TBars source) : this(source.Close, period: 0, logbase: 2.0, useNaN: false) { }
public ENTROPY_Series(TBars source, int period) : this(source.Close, period, logbase: 2.0, useNaN: false) { }
public ENTROPY_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, logbase: 2.0, useNaN: useNaN) { }
public ENTROPY_Series(TSeries source) : this(source, period: 0, logbase: 2.0, useNaN: false) { }
public ENTROPY_Series(TSeries source, int period) : this(source: source, period: period, logbase: 2.0, useNaN: false) { }
public ENTROPY_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, logbase: 2.0, useNaN: useNaN) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
double _sum = _buffer.Sum();
double _pp = this._buffer[^1] / _sum;
double _ppp = -_pp * Math.Log(_pp) / Math.Log(this._logbase);
BufferTrim(_buff2, _ppp, _period, update);
double _entp = _buff2.Sum();
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _entp);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
_buff2.Clear();
}
}
-94
View File
@@ -1,94 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Numerics;
using System.Linq;
/* <summary>
FWMA: Fibonacci's Weighted Moving Average is similar to a Weighted Moving Average
(WMA) where the weights are based on the Fibonacci Sequence.
</summary> */
public class FWMA_Series : TSeries {
private readonly List<double> _buffer = new();
private List<double> _weights;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
protected int _len;
public FWMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"FWMA({period})";
_len = 0;
_weights = CalculateWeights(_period);
}
public FWMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public FWMA_Series() : this(period: 0, useNaN: false) { }
public FWMA_Series(int period) : this(period: period, useNaN: false) { }
public FWMA_Series(TBars source) : this(source.Close, 0, false) { }
public FWMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public FWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public FWMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
if (_period == 0) {
_len++;
_weights = CalculateWeights(_len);
}
double _fwma = 0;
double totalWeights = _weights.Sum();
object lockObj = new object();
Parallel.For(0, _buffer.Count, i =>
{
double temp = _buffer[i] * _weights[i];
lock (lockObj) { _fwma += temp; }
});
_fwma /= totalWeights;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _fwma);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
private static List<double> CalculateWeights(int period) {
//to prevent overflow, max period can be no more than 1476
period = (period > 1476) ? 1476 : period;
List<double> weights = new List<double>(period);
BigInteger a = 0;
BigInteger b = 1;
for (int i = 0; i < period; i++) {
BigInteger temp = a;
a = b;
b = temp + b;
weights.Add((double)Decimal.Parse(a.ToString()));
}
return weights;
}
public override void Reset() {
_weights = CalculateWeights(_period);
_buffer.Clear();
}
}
-116
View File
@@ -1,116 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
HEMA: Hull-EMA Moving Average - a hybrid indicator
Modified HUll Moving Average; instead of using WMA (Weighted MA) for calculation,
HEMA uses EMA for Hull's formula:
EMA1 = EMA(n/2) of price - where k = 4/(n/2 +1)
EMA2 = EMA(n) of price - where k = 3/(n+1)
Raw HMA = (2 * EMA1) - EMA2
EMA3 = EMA(sqrt(n)) of Raw HMA - where k = 2/(sqrt(n)+1)
</summary> */
public class HEMA_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private double _k1, _k2, _k3;
private int _len;
private double _lastema1, _oldema1;
private double _lastema2, _oldema2;
private double _lasthema, _oldhema;
//core constructors
public HEMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"HEMA({period})";
(_k1, _k2, _k3) = CalculateK(_period);
_len = 0;
_lastema1 = _oldema1 = _lastema2 = _oldema2 = _lasthema = _oldhema = 0;
}
public HEMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public HEMA_Series() : this(period: 0, useNaN: false) { }
public HEMA_Series(int period) : this(period: period, useNaN: false) { }
public HEMA_Series(TBars source) : this(source.Close, 0, false) { }
public HEMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public HEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public HEMA_Series(TSeries source) : this(source, 0, false) { }
public HEMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) {
_lastema1 = _oldema1;
_lastema2 = _oldema2;
_lasthema = _oldhema;
}
else {
_oldema1 = _lastema1;
_oldema2 = _lastema2;
_oldhema = _lasthema;
}
double _ema1, _ema2, _hema;
if (_period == 0) {
_len++;
(_k1, _k2, _k3) = CalculateK(_len);
}
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, double.NaN), update);
} else if (this.Count == 0) {
_ema1 = _ema2 = _hema = TValue.v;
}
else {
_ema1 = _k1 * (TValue.v - _lastema1) + _lastema1;
_ema2 = _k2 * (TValue.v - _lastema2) + _lastema2;
_hema = _k3 * (((2 * _ema1) - _ema2) - _lasthema) + _lasthema;
}
_lastema1 = _ema1;
_lastema2 = _ema2;
_lasthema = _hema;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hema);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_lastema1 = _lastema2 = _lasthema = 0;
_oldema1 = _oldema2 = _oldhema = 0;
_len = 0;
}
public static (double k1, double k2, double k3) CalculateK(int len) {
double k1 = 8 / (double)(len + 7);
double k2 = 3 / (double)(len + 2);
double k3 = 2 / Math.Sqrt(len + 3);
return (k1, k2, k3);
}
}
-88
View File
@@ -1,88 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
HMA: Hull Moving Average
Developed by Alan Hull, an extremely fast and smooth moving average; almost
eliminates lag altogether and manages to improve smoothing at the same time.
Sources:
https://alanhull.com/hull-moving-average
https://school.stockcharts.com/doku.php?id=technical_indicators:hull_moving_average
WMA1 = WMA(n/2) of price
WMA2 = WMA(n) of price
Raw HMA = (2 * WMA1) - WMA2
HMA = WMA(sqrt(n)) of Raw HMA
</summary> */
public class HMA_Series : TSeries {
protected int _period, _period2, _psqrt;
protected readonly bool _NaN;
protected readonly TSeries _data;
protected WMA_Series _wma1, _wma2, _wma3;
//core constructors
public HMA_Series(int period, bool useNaN) {
_period = period;
_period2 = period /2;
_psqrt = (int)Math.Sqrt(period);
_NaN = useNaN;
_wma1 = new(Math.Max(_period2,1), false);
_wma2 = new(Math.Max(_period,1), false);
_wma3 = new(Math.Max(_psqrt,1), useNaN);
Name = $"HMA({period})";
}
public HMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public HMA_Series() : this(period: 0, useNaN: false) { }
public HMA_Series(int period) : this(period: period, useNaN: false) { }
public HMA_Series(TBars source) : this(source.Close, 0, false) { }
public HMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public HMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public HMA_Series(TSeries source) : this(source, 0, false) { }
public HMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (_period == 0) {
_wma1.Len = this.Count / 2;
_wma2.Len = this.Count;
_wma1.Len = (int)Math.Sqrt(this.Count);
}
double _w1 = _wma1.Add(TValue, update).v;
double _w2 = _wma2.Add(TValue, update).v;
double _hma = _wma3.Add((2 * _w1) - _w2, update).v;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hma);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_wma1.Reset();
_wma2.Reset();
_wma3.Reset();
}
}
-132
View File
@@ -1,132 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
HWMA: Holt-Winter Moving Average
Indicator HWMA (Holt-Winter Moving Average) is a three-parameter moving
average by the Holt-Winter method; Holt-Winters Exponential Smoothing is
used for forecasting time series data that exhibits both a trend and a
seasonal variation.
Sources:
https://timeseriesreasoning.com/contents/holt-winters-exponential-smoothing/
https://www.mql5.com/en/code/20856
nA - smoothed series (from 0 to 1)
nB - assess the trend (from 0 to 1)
nC - assess seasonality (from 0 to 1)
Heuristic for determining alpha, beta, and gamma from period:
alpha = 2 / (1 + period)
beta = 1 / period
gamma = 1 / period
F[i] = (1-nA) * (F[i-1] + V[i-1] + 0.5 * A[i-1]) + nA * Price[i]
V[i] = (1-nB) * (V[i-1] + A[i-1]) + nB * (F[i] - F[i-1])
A[i] = (1-nC) * A[i-1] + nC * (V[i] - V[i-1])
HWMA[i] = F[i] + V[i] + 0.5 * A[i]
</summary> */
public class HWMA_Series : TSeries {
private int _len;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
double _nA, _nB, _nC;
double _pF, _pV, _pA;
double _ppF, _ppV, _ppA;
//core constructors
public HWMA_Series(double nA, double nB, double nC, bool useNaN) {
_period = (int)((2 - nA) / nA);
_nA = nA;
_nB = nB;
_nC = nC;
_NaN = useNaN;
Name = $"HWMA({_period})";
_len = 0;
}
public HWMA_Series(TSeries source, double nA, double nB, double nC, bool useNaN = false) : this(nA, nB, nC, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public HWMA_Series() : this(period: 0, useNaN: false) { }
public HWMA_Series(int period) : this(period, useNaN: false) { }
public HWMA_Series(int period, bool useNaN) : this(nA: 2 / (1 + (double)period), nB: 1 / (double)period, nC: 1 / (double)period, useNaN) {
_period = period;
}
public HWMA_Series(TBars source) : this(source.Close, period: 0, useNaN: false) { }
public HWMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public HWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public HWMA_Series(TSeries source, int period) : this(source, period, false) { }
public HWMA_Series(TSeries source, int period, bool useNaN) : this(source, nA: 2 / (1 + (double)period), nB: 1 / (double)period, nC: 1 / (double)period, useNaN: useNaN) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
double _F, _V, _A;
if (_len == 0) { _pF = TValue.v; _pA = _pV = 0; }
if (update) { _pF = _ppF; _pV = _ppV; _pA = _ppA; }
else {
_ppF = _pF;
_ppV = _pV;
_ppA = _pA;
_len++;
}
if (_period == 0) {
_nA = 2 / (1 + (double)_len);
_nB = 1 / (double)_len;
_nC = 1 / (double)_len;
}
if (_period == 1) {
_nA = 1;
_nB = 0;
_nC = 0;
}
_F = (1 - _nA) * (_pF + _pV + 0.5 * _pA) + _nA * TValue.v;
_V = (1 - _nB) * (_pV + _pA) + _nB * (_F - _pF);
_A = (1 - _nC) * _pA + _nC * (_V - _pV);
double _hwma = _F + _V + 0.5 * _A;
_pF = _F;
_pV = _V;
_pA = _A;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hwma);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_len = 0;
}
}
-107
View File
@@ -1,107 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
KAMA: Kaufman's Adaptive Moving Average
Created in 1988 by American quantitative finance theorist Perry J. Kaufman and is known as
Kaufman's Adaptive Moving Average (KAMA). Even though the method was developed as early as 1972,
it was not until the popular book titled "Trading Systems and Methods" that it was made widely
available to the public. Unlike other conventional moving averages systems, the Kaufman's Adaptive
Moving Average, considers market volatility apart from price fluctuations.
KAMA[i] = KAMA[i-1] + SC * ( price - KAMA[i-1] )
Sources:
https://www.tutorialspoint.com/kaufman-s-adaptive-moving-average-kama-formula-and-how-does-it-work
https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/kaufmans-adaptive-moving-average-kama/
https://www.technicalindicators.net/indicators-technical-analysis/152-kama-kaufman-adaptive-moving-average
Remark:
If useNaN:true argument is provided, KAMA starts calculating values from [period] bar onwards.
Without useNaN argument (default setting), KAMA starts calculating values from bar 1 - and yields
slightly different results for the first 50 bars - and then converges with the other one.
</summary> */
public class KAMA_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
private double _lastkama, _lastlastkama;
private readonly double _scFast, _scSlow;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public KAMA_Series(int period, int fast, int slow, bool useNaN) {
_period = period;
_NaN = useNaN;
_scFast = 2.0 / (((period < fast) ? period : fast) + 1);
_scSlow = 2.0 / (slow + 1);
_lastkama = _lastlastkama = 0;
Name = $"KAMA({period})";
}
public KAMA_Series(TSeries source, int period, int fast, int slow, bool useNaN) : this(period, fast, slow, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public KAMA_Series() : this(period: 0, fast: 2, slow: 30, useNaN: false) { }
public KAMA_Series(int period) : this(period: period, fast: 2, slow: 30, useNaN: false) { }
public KAMA_Series(TBars source) : this(source.Close, period: 0, fast: 2, slow: 30, useNaN: false) { }
public KAMA_Series(TBars source, int period) : this(source.Close, period: period, fast: 2, slow: 30, useNaN: false) { }
public KAMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, fast: 2, slow: 30, useNaN: useNaN) { }
public KAMA_Series(TSeries source) : this(source, period: 0, fast: 2, slow: 30, useNaN: false) { }
public KAMA_Series(TSeries source, int period) : this(source: source, period: period, fast: 2, slow: 30, useNaN: false) { }
public KAMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, fast: 2, slow: 30, useNaN: useNaN) { }
public KAMA_Series(TSeries source, int period, int fast, int slow) : this(source: source, period: period, fast: fast, slow: slow, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
if (update) { _lastkama = _lastlastkama; }
else { _lastlastkama = _lastkama; }
BufferTrim(buffer: _buffer, value: TValue.v, period: _period + 1, update: update);
double _kama = 0;
if (this.Count < _period) { _kama = TValue.v; }
else {
double _change = Math.Abs(_buffer[^1] - _buffer[(_buffer.Count > _period + 1) ? 1 : 0]);
double _sumpv = 0;
for (int i = 1; i < _buffer.Count; i++) { _sumpv += Math.Abs(_buffer[(_buffer.Count > 0) ? i : 0] - _buffer[i - 1]); }
double _er = (_sumpv == 0) ? 0 : _change / _sumpv;
double _sc = (_er * (_scFast - _scSlow)) + _scSlow;
_kama = (_lastkama + (_sc * _sc * (TValue.v - _lastkama)));
}
_lastkama = _kama;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _kama);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
_lastkama = _lastlastkama = 0;
}
}
-96
View File
@@ -1,96 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
KURTOSIS: Kurtosis of population
Kurtosis characterizes the relative peakedness or flatness of a distribution
compared with the normal distribution. Positive kurtosis indicates a relatively
peaked distribution. Negative kurtosis indicates a relatively flat distribution.
The normal curve is called Mesokurtic curve. If the curve of a distribution is
more outlier prone (or heavier-tailed) than a normal or mesokurtic curve then
it is referred to as a Leptokurtic curve. If a curve is less outlier prone (or
lighter-tailed) than a normal curve, it is called as a platykurtic curve.
Calculation:
sum4 = Σ(close-SMA)^4
sum2 = (Σ(close-SMA)^2)^2
KURTOSIS = length * (sum4/sum2)
Sources:
https://en.wikipedia.org/wiki/Kurtosis
https://stats.oarc.ucla.edu/other/mult-pkg/faq/general/faq-whats-with-the-different-formulas-for-kurtosis/
</summary> */
public class KURTOSIS_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private readonly System.Collections.Generic.List<double> _buffer = new();
//core constructors
public KURTOSIS_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"KURTOSIS({period})";
}
public KURTOSIS_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public KURTOSIS_Series() : this(period: 0, useNaN: false) { }
public KURTOSIS_Series(int period) : this(period: period, useNaN: false) { }
public KURTOSIS_Series(TSeries source) : this(source, period: 0, useNaN: false) { }
public KURTOSIS_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
double _n = _buffer.Count;
double _avg = _buffer.Average();
double _s2 = 0;
double _s4 = 0;
for (int i = 0; i < this._buffer.Count; i++) {
_s2 += (_buffer[i] - _avg) * (_buffer[i] - _avg);
_s4 += (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg);
}
double _Vx = _s2 / (_n - 1);
double _kurt = (_n > 3) ?
(_n * (_n + 1) * _s4) / (_Vx * _Vx * (_n - 3) * (_n - 1) * (_n - 2)) - (3 * (_n - 1) * (_n - 1) / ((_n - 2) * (_n - 3))) //using Sheskin Algo
: (_s2 * _s2) / _n - 3; //using Snedecor and Cochran (1967) algo
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _kurt);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-78
View File
@@ -1,78 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
MACD: Moving Average Convergence/Divergence
Moving average convergence divergence (MACD) is a trend-following momentum
indicator that shows the relationship between two moving averages of a series.
The MACD is calculated by subtracting the 26-period exponential moving average (EMA)
from the 12-period EMA. MACD Signal is 9-day EMA of MACD.
</summary> */
public class MACD_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _slow, _fast, _signal;
protected readonly bool _NaN;
protected readonly TSeries _data;
private readonly EMA_Series _TSlow;
private readonly EMA_Series _TFast;
public EMA_Series Signal { get; }
//core constructors
public MACD_Series(int slow = 26, int fast = 12, int signal = 9, bool useNaN = false) {
_slow = slow;
_fast = fast;
_signal = signal;
_NaN = useNaN;
Name = $"MACD({slow},{fast},{signal})";
_TSlow = new(slow, useNaN:false, useSMA:true);
_TFast = new(fast, useNaN: false, useSMA: true);
Signal = new(signal, useNaN: false, useSMA: true);
}
public MACD_Series(TSeries source, int slow, int fast, int signal, bool useNaN) : this(slow, fast, signal, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MACD_Series(TSeries source) : this(source:source, slow:26, fast:12, signal:9 , useNaN:false) { }
public MACD_Series(TSeries source, int slow, int fast, int signal) : this(source: source, slow: slow, fast:fast, signal:signal, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
var _sslow = _TSlow.Add(TValue,update);
var _sfast = _TFast.Add(TValue, update);
Signal.Add((TValue.t, _sfast.v-_sslow.v));
var res = (TValue.t, Count < _fast - 1 && _NaN ? double.NaN : _sfast.v-_sslow.v);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-79
View File
@@ -1,79 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
MAD: Mean Absolute Deviation
Also known as AAD - Average Absolute Deviation, to differentiate it from Median Absolute Deviation
MAD defines the degree of variation across the series.
Calculation:
MAD = Σ(|close-SMA|) / period
Sources:
https://en.wikipedia.org/wiki/Average_absolute_deviation
</summary> */
public class MAD_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public MAD_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MAD({period})";
}
public MAD_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MAD_Series() : this(period: 0, useNaN: false) { }
public MAD_Series(int period) : this(period: period, useNaN: false) { }
public MAD_Series(TBars source) : this(source.Close, 0, false) { }
public MAD_Series(TBars source, int period) : this(source.Close, period, false) { }
public MAD_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public MAD_Series(TSeries source) : this(source, 0, false) { }
public MAD_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sma = _buffer.Average();
double _mad = 0;
for (int i = 0; i < _buffer.Count; i++) { _mad += Math.Abs(_buffer[i] - _sma); }
_mad /= this._buffer.Count;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mad);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-77
View File
@@ -1,77 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
MAE: Mean Absolute Error
Defined as a Mean (Average) of the absolute difference between actual and estimated values.
MAE = (1/n) * Σ|y_i - MA_i|
Sources:
https://en.wikipedia.org/wiki/Mean_absolute_error
</summary> */
public class MAE_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public MAE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MSE({period})";
}
public MAE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MAE_Series() : this(period: 0, useNaN: false) { }
public MAE_Series(int period) : this(period: period, useNaN: false) { }
public MAE_Series(TBars source) : this(source.Close, 0, false) { }
public MAE_Series(TBars source, int period) : this(source.Close, period, false) { }
public MAE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public MAE_Series(TSeries source) : this(source, 0, false) { }
public MAE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sma = _buffer.Average();
double _mae = 0;
for (int i = 0; i < _buffer.Count; i++) { _mae += Math.Abs(_buffer[i] - _sma); }
_mae /= this._buffer.Count;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mae);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-189
View File
@@ -1,189 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
MAMA: MESA Adaptive Moving Average
Created by John Ehlers, the MAMA indicator is a 5-period adaptive moving average of
high/low price that uses classic electrical radio-frequency signal processing algorithms
to reduce noise.
KAMAi = KAMAi - 1 + SC * ( price - KAMAi-1 )
Sources:
https://mesasoftware.com/papers/MAMA.pdf
https://www.tradingview.com/script/foQxLbU3-Ehlers-MESA-Adaptive-Moving-Average-LazyBear/
</summary> */
public class MAMA_Series : TSeries {
private int _len;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private double sumPr;
private double fastl, slowl;
private (double i, double i1, double i2, double i3, double i4, double i5, double i6, double io) pr, i1, q1, sm, dt;
private (double i, double i1, double io) i2, q2, re, im, pd, ph, mama, fama;
public TSeries Fama { get; }
private double mamaseed, famaseed;
//core constructors
public MAMA_Series(double fastlimit, double slowlimit, bool useNaN) {
_period = (int)(2 / fastlimit) - 1;
fastl = fastlimit;
slowl = slowlimit;
Fama = new TSeries();
_NaN = useNaN;
Name = $"MAMA({_period})";
_len = 0;
}
public MAMA_Series(TSeries source, double fastlimit, double slowlimit, bool useNaN = false) : this(fastlimit, slowlimit, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MAMA_Series() : this(period: 0, useNaN: false) { }
public MAMA_Series(int period) : this(period, useNaN: false) { }
public MAMA_Series(int period, bool useNaN) : this(fastlimit: 2 / (period + 1), slowlimit: 0.2 / (period + 1), useNaN) {
_period = period;
}
public MAMA_Series(TBars source) : this(source.Close, period: 0, useNaN: false) { }
public MAMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public MAMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public MAMA_Series(TSeries source, int period) : this(source, period, false) { }
public MAMA_Series(TSeries source, int period, bool useNaN) : this(source, fastlimit: 2 / ((double)period + 1), slowlimit: 0.2 / ((double)period + 1), useNaN: useNaN) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
if (!update) {
// roll forward (oldx = x)
pr.io = pr.i6; pr.i6 = pr.i5; pr.i5 = pr.i4; pr.i4 = pr.i3; pr.i3 = pr.i2; pr.i2 = pr.i1; pr.i1 = pr.i;
i1.io = i1.i6; i1.i6 = i1.i5; i1.i5 = i1.i4; i1.i4 = i1.i3; i1.i3 = i1.i2; i1.i2 = i1.i1; i1.i1 = i1.i;
q1.io = q1.i6; q1.i6 = q1.i5; q1.i5 = q1.i4; q1.i4 = q1.i3; q1.i3 = q1.i2; q1.i2 = q1.i1; q1.i1 = q1.i;
dt.io = dt.i6; dt.i6 = dt.i5; dt.i5 = dt.i4; dt.i4 = dt.i3; dt.i3 = dt.i2; dt.i2 = dt.i1; dt.i1 = dt.i;
sm.io = sm.i6; sm.i6 = sm.i5; sm.i5 = sm.i4; sm.i4 = sm.i3; sm.i3 = sm.i2; sm.i2 = sm.i1; sm.i1 = sm.i;
i2.io = i2.i1; i2.i1 = i2.i; q2.io = q2.i1; q2.i1 = q2.i;
re.io = re.i1; re.i1 = re.i; im.io = im.i1; im.i1 = im.i;
pd.io = pd.i1; pd.i1 = pd.i; ph.io = ph.i1; ph.i1 = ph.i;
mama.io = mama.i1; mama.i1 = mama.i;
fama.io = fama.i1;
fama.i1 = fama.i;
_len++;
}
if (_period == 0) {
fastl = 2 / (double)_len;
slowl = fastl * 0.1;
}
if (_period == 1) {
fastl = 1;
slowl = 1;
}
var i = _len - 1;
pr.i = TValue.v;
if (i > 5) {
var adj = 0.075 * pd.i1 + 0.54;
// smooth and detrender
sm.i = (4 * pr.i + 3 * pr.i1 + 2 * pr.i2 + pr.i3) / 10;
dt.i = (0.0962 * sm.i + 0.5769 * sm.i2 - 0.5769 * sm.i4 - 0.0962 * sm.i6) * adj;
// in-phase and quadrature
q1.i = (0.0962 * dt.i + 0.5769 * dt.i2 - 0.5769 * dt.i4 - 0.0962 * dt.i6) * adj;
i1.i = dt.i3;
// advance the phases by 90 degrees
double jI = (0.0962 * i1.i + 0.5769 * i1.i2 - 0.5769 * i1.i4 - 0.0962 * i1.i6) * adj;
double jQ = (0.0962 * q1.i + 0.5769 * q1.i2 - 0.5769 * q1.i4 - 0.0962 * q1.i6) * adj;
// phasor addition for 3-bar averaging
i2.i = i1.i - jQ;
q2.i = q1.i + jI;
i2.i = 0.2 * i2.i + 0.8 * i2.i1; // smoothing it
q2.i = 0.2 * q2.i + 0.8 * q2.i1;
// homodyne discriminator
re.i = i2.i * i2.i1 + q2.i * q2.i1;
im.i = i2.i * q2.i1 - q2.i * i2.i1;
re.i = 0.2 * re.i + 0.8 * re.i1; // smoothing it
im.i = 0.2 * im.i + 0.8 * im.i1;
// calculate period
pd.i = im.i != 0 && re.i != 0 ? 6.283185307179586 / Math.Atan(im.i / re.i) : 0d;
// adjust period to thresholds
pd.i = pd.i > 1.5 * pd.i1 ? 1.5 * pd.i1 : pd.i;
pd.i = pd.i < 0.67 * pd.i1 ? 0.67 * pd.i1 : pd.i;
pd.i = pd.i < 6d ? 6d : pd.i;
pd.i = pd.i > 50d ? 50d : pd.i;
// smooth the period
pd.i = 0.2 * pd.i + 0.8 * pd.i1;
// determine phase position
ph.i = i1.i != 0 ? Math.Atan(q1.i / i1.i) * 57.29577951308232 : 0;
// change in phase
var delta = Math.Max(ph.i1 - ph.i, 1d);
// adaptive alpha value
var alpha = Math.Max(fastl / delta, slowl);
// final indicators
mama.i = alpha * (pr.i - mama.i1) + mama.i1;
fama.i = 0.5d * alpha * (mama.i - fama.i1) + fama.i1;
}
else {
sumPr += pr.i;
pd.i = sm.i = dt.i = i1.i = q1.i = i2.i = q2.i = re.i = im.i = ph.i = 0;
mama.i = fama.i = sumPr / (i + 1);
if (_len == 1) {
mamaseed = famaseed = TValue.v;
}
else {
mamaseed = fastl * (TValue.v - mamaseed) + mamaseed;
famaseed = slowl * (TValue.v - famaseed) + famaseed;
}
}
double _fama = (i > 5) ? fama.i : famaseed;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _fama);
Fama.Add(res, update);
double _mama = (i > 5) ? mama.i : mamaseed;
res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mama);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_len = 0;
}
}
-85
View File
@@ -1,85 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
MAPE: Mean Absolute Percentage Error
Measures the size of the error in percentage terms
Calculation:
MAPE = Σ(|close SMA| / |close|) / n
Sources:
https://en.wikipedia.org/wiki/Mean_absolute_percentage_error
Remark:
returns infinity if any of observations is 0.
Use SMAPE or WMAPE instead to avoid division-by-zero in MAPE
</summary> */
public class MAPE_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public MAPE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MAPE({period})";
}
public MAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MAPE_Series() : this(period: 0, useNaN: false) { }
public MAPE_Series(int period) : this(period: period, useNaN: false) { }
public MAPE_Series(TBars source) : this(source.Close, 0, false) { }
public MAPE_Series(TBars source, int period) : this(source.Close, period, false) { }
public MAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public MAPE_Series(TSeries source) : this(source, 0, false) { }
public MAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sma = _buffer.Average();
double _mape = 0;
for (int i = 0; i < _buffer.Count; i++) {
_mape += (_buffer[i] != 0) ? Math.Abs(_buffer[i] - _sma) / Math.Abs(_buffer[i]) : double.PositiveInfinity;
}
_mape /= (_buffer.Count > 0) ? _buffer.Count : 1;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mape);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-68
View File
@@ -1,68 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
MAX - Maximum value in the given period in the series.
If period = 0 => period = full length of the series
</summary> */
public class MAX_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public MAX_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MAX({period})";
}
public MAX_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MAX_Series() : this(period: 0, useNaN: false) { }
public MAX_Series(int period) : this(period: period, useNaN: false) { }
public MAX_Series(TBars source) : this(source.Close, 0, false) { }
public MAX_Series(TBars source, int period) : this(source.Close, period, false) { }
public MAX_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public MAX_Series(TSeries source) : this(source, 0, false) { }
public MAX_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _max= _buffer.Max();
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _max);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-86
View File
@@ -1,86 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
MED - Median value
Median of numbers is the middlemost value of the given set of numbers.
It separates the higher half and the lower half of a given data sample.
At least half of the observations are smaller than or equal to median
and at least half of the observations are greater than or equal to the median.
If the number of values is odd, the middlemost observation of the sorted
list is the median of the given data. If the number of values is even,
median is the average of (n/2)th and [(n/2) + 1]th values of the sorted list.
If period = 0 => period is max
Sources:
https://corporatefinanceinstitute.com/resources/knowledge/other/median/
https://en.wikipedia.org/wiki/Median
</summary> */
public class MEDIAN_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public MEDIAN_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MEDIAN({period})";
}
public MEDIAN_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MEDIAN_Series() : this(period: 0, useNaN: false) { }
public MEDIAN_Series(int period) : this(period: period, useNaN: false) { }
public MEDIAN_Series(TBars source) : this(source.Close, 0, false) { }
public MEDIAN_Series(TBars source, int period) : this(source.Close, period, false) { }
public MEDIAN_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public MEDIAN_Series(TSeries source) : this(source, 0, false) { }
public MEDIAN_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
System.Collections.Generic.List<double> _s = new(this._buffer);
_s.Sort();
int _p1 = _s.Count / 2;
int _p2 = Math.Max(0, (_s.Count / 2) - 1);
double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _med);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-72
View File
@@ -1,72 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
MIDPOINT: Midpoint value (max+min)/2 in the given period in the series.
If period = 0 => period = full length of the series
Sources:
https://thefaqblog.com/what-is-the-midpoint-in-statistics/
</summary> */
public class MIDPOINT_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public MIDPOINT_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MIDPOINT({period})";
}
public MIDPOINT_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MIDPOINT_Series() : this(period: 0, useNaN: false) { }
public MIDPOINT_Series(int period) : this(period: period, useNaN: false) { }
public MIDPOINT_Series(TBars source) : this(source.Close, 0, false) { }
public MIDPOINT_Series(TBars source, int period) : this(source.Close, period, false) { }
public MIDPOINT_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public MIDPOINT_Series(TSeries source) : this(source, 0, false) { }
public MIDPOINT_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _max= _buffer.Max();
double _min = _buffer.Min();
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : (_max+_min)*0.5);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-65
View File
@@ -1,65 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
MIDPRICE: Midpoint price (highhest high + lowest low)/2 in the given period in the series.
If period = 0 => period = full length of the series
</summary> */
public class MIDPRICE_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TBars _data;
private readonly System.Collections.Generic.List<double> _bufferhi = new();
private readonly System.Collections.Generic.List<double> _bufferlo = new();
//core constructors
public MIDPRICE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MIDPRICE({period})";
}
public MIDPRICE_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(data: _data);
}
public MIDPRICE_Series() : this(period: 2, useNaN: false) { }
public MIDPRICE_Series(int period) : this(period: period, useNaN: false) { }
public MIDPRICE_Series(TBars source) : this(source, period: 2, useNaN: false) { }
public MIDPRICE_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
BufferTrim(_bufferhi, TBar.h, _period, update);
BufferTrim(_bufferlo, TBar.l, _period, update);
double _mid = (_bufferhi.Max() + _bufferlo.Min()) * 0.5;
var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _mid);
return base.Add(res, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_bufferhi.Clear();
_bufferlo.Clear();
}
}
-68
View File
@@ -1,68 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
MIN - Minimum value in the given period in the series.
If period = 0 => period = full length of the series
</summary> */
public class MIN_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public MIN_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MAX({period})";
}
public MIN_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MIN_Series() : this(period: 0, useNaN: false) { }
public MIN_Series(int period) : this(period: period, useNaN: false) { }
public MIN_Series(TBars source) : this(source.Close, 0, false) { }
public MIN_Series(TBars source, int period) : this(source.Close, period, false) { }
public MIN_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public MIN_Series(TSeries source) : this(source, 0, false) { }
public MIN_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _max= _buffer.Min();
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _max);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-76
View File
@@ -1,76 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
MSE: Mean Square Error
Defined as a Mean (Average) of the Square of the difference between actual and estimated values.
Sources:
https://en.wikipedia.org/wiki/Mean_squared_error
</summary> */
public class MSE_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public MSE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MSE({period})";
}
public MSE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MSE_Series() : this(period: 0, useNaN: false) { }
public MSE_Series(int period) : this(period: period, useNaN: false) { }
public MSE_Series(TBars source) : this(source.Close, 0, false) { }
public MSE_Series(TBars source, int period) : this(source.Close, period, false) { }
public MSE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public MSE_Series(TSeries source) : this(source, 0, false) { }
public MSE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sma = _buffer.Average();
double _mse = 0;
for (int i = 0; i < _buffer.Count; i++) { _mse += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
_mse /= this._buffer.Count;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mse);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-96
View File
@@ -1,96 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
OBV: On-Balance Volume
On-balance volume (OBV) is a technical trading momentum indicator that uses volume flow to predict
changes in stock price. Joseph Granville first developed the OBV metric in the 1963 book
Granville's New Key to Stock Market Profits.
| +volume; if close > close[previous]
OBV = OBV[previous] + | 0; if close = close[previous]
| -volume; if close < close[previous]
Sources:
https://www.investopedia.com/terms/o/onbalancevolume.asp
https://www.tradingview.com/wiki/On_Balance_Volume_(OBV)
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/on-balance-volume-obv/
https://www.motivewave.com/studies/on_balance_volume.htm
Note:
There is no consensus on what is the first OBV value in the series:
- TA-LIB uses the first volume: OBV[0] = volume[0]
- Skender stock library uses 0: OBV[0] = 0
</summary> */
public class OBV_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TBars _data;
private double _lastobv, _lastlastobv;
private double _lastclose, _lastlastclose;
//core constructors
public OBV_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"OBV({period})";
this._lastobv = this._lastlastobv = 0;
this._lastclose = this._lastlastclose = 0;
}
public OBV_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(data: _data);
}
public OBV_Series() : this(period: 2, useNaN: false) { }
public OBV_Series(int period) : this(period: period, useNaN: false) { }
public OBV_Series(TBars source) : this(source, period: 2, useNaN: false) { }
public OBV_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) {
this._lastobv = this._lastlastobv;
this._lastclose = this._lastlastclose;
}
double _obv = this._lastobv;
if (TBar.c > this._lastclose) { _obv += TBar.v; }
if (TBar.c < this._lastclose) { _obv -= TBar.v; }
this._lastlastobv = this._lastobv;
this._lastobv = _obv;
this._lastlastclose = this._lastclose;
this._lastclose = TBar.c;
var res = (TBar.t, (this.Count < this._period && this._NaN) ? double.NaN : _obv);
return base.Add(res, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
this._lastobv = this._lastlastobv = 0;
this._lastclose = this._lastlastclose = 0;
}
}
-116
View File
@@ -1,116 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
RMA: wildeR Moving Average
J. Welles Wilder introduced RMA as an alternative to EMA. RMA's weight (k) is
set as 1/period, giving less weight to the new data compared to EMA.
Sources:
https://archive.org/details/newconceptsintec00wild/page/23/mode/2up
https://tlc.thinkorswim.com/center/reference/Tech-Indicators/studies-library/V-Z/WildersSmoothing
https://www.incrediblecharts.com/indicators/wilder_moving_average.php
Issues:
Pandas-TA library calculates RMA using straight Exponential Weighted Mean:
pandas.ewm().mean() and returns incorrect first (period) of bars compared to
published formula. This implementation passess the validation test in Wilder's book.
</summary> */
public class RMA_Series : TSeries {
private double _k;
private double _lastrma, _oldrma;
private double _sum, _oldsum;
private readonly bool _useSMA;
private int _len;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructor
public RMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
Name = $"RMA({period})";
_k = 1.0 / (double)(this._period);
_len = 0;
_sum = _oldsum = _lastrma = _oldrma = 0;
}
//generic constructors (source)
public RMA_Series() : this(0, false, true) {}
public RMA_Series(int period) : this(period, false, true) {}
public RMA_Series(TBars source) : this(source.Close, 0, false) {}
public RMA_Series(TBars source, int period) : this(source.Close, period, false) {}
public RMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {}
public RMA_Series(TSeries source, int period) : this(source, period, false, true) {}
public RMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {}
public RMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) {
_lastrma = _oldrma;
_sum = _oldsum;
}
else {
_oldrma = _lastrma;
_oldsum = _sum;
_len++;
}
double _rma = 0;
if (_period == 0) {
_k = 1.0 / (double)(this._len);
}
if (Count == 0) {
_rma = _sum = TValue.v;
} else if (_len <= _period && _useSMA && _period != 0) {
_sum += TValue.v;
if (_period != 0 && _len > _period) {
_sum -= _data[Count - _period - (update ? 1 : 0)].v;
}
_rma = _sum / Math.Min(_len, _period);
}
else {
_rma = _k * (TValue.v - _lastrma) + _lastrma;
}
_lastrma = double.IsNaN(_rma) ? _lastrma : _rma;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _rma);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_sum = _oldsum = _lastrma = _oldrma = 0;
_len = 0;
}
}
-120
View File
@@ -1,120 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
RSI: Relative Strength Index
Created by J. Welles Wilder, the Relative Strength Index measures strength
of the winning/losing streak over N lookback periods on a scale of 0 to 100,
to depict overbought and oversold conditions.
Sources:
https://www.investopedia.com/terms/r/rsi.asp
</summary> */
public class RSI_Series : TSeries {
private readonly System.Collections.Generic.List<double> _gain = new();
private readonly System.Collections.Generic.List<double> _loss = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private double _avgGain, _avgLoss, _lastValue;
private double _avgGain_o, _avgLoss_o, _lastValue_o;
private int i;
//core constructors
public RSI_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"RSI({period})";
i = 0;
}
public RSI_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public RSI_Series() : this(period: 0, useNaN: false) { }
public RSI_Series(int period) : this(period: period, useNaN: false) { }
public RSI_Series(TBars source) : this(source.Close, 0, false) { }
public RSI_Series(TBars source, int period) : this(source.Close, period, false) { }
public RSI_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public RSI_Series(TSeries source) : this(source, 0, false) { }
public RSI_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
double _rsi = 0;
if (update) {
_lastValue = _lastValue_o;
_avgGain = _avgGain_o;
_avgLoss = _avgLoss_o;
}
else {
_lastValue_o = _lastValue;
_avgGain_o = _avgGain;
_avgLoss_o = _avgLoss;
}
if (i == 0) { _lastValue = TValue.v; }
double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0;
BufferTrim(_gain, _gainval, _period, update);
double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0;
BufferTrim(_loss, _lossval, _period, update);
_lastValue = TValue.v;
// calculate RSI
if (i > _period && _period != 0) {
_avgGain = ((_avgGain * (_period - 1)) + _gain[^1]) / _period;
_avgLoss = ((_avgLoss * (_period - 1)) + _loss[^1]) / _period;
if (_avgLoss > 0) {
double rs = _avgGain / _avgLoss;
_rsi = 100 - (100 / (1 + rs));
}
else { _rsi = 100; }
}
// initialize average gain
else {
double _sumGain = 0;
for (int p = 0; p < _gain.Count; p++) { _sumGain += _gain[p]; }
double _sumLoss = 0;
for (int p = 0; p < _loss.Count; p++) { _sumLoss += _loss[p]; }
_avgGain = _sumGain / _gain.Count;
_avgLoss = _sumLoss / _loss.Count;
_rsi = (_avgLoss > 0) ? 100 - (100 / (1 + (_avgGain / _avgLoss))) : 100;
}
if (!update) { i++; }
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _rsi);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
i = 0;
}
}
-82
View File
@@ -1,82 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
SDEV: Population Standard Deviation
Population Standard Deviation is the square root of the biased variance, also knons as
Uncorrected Sample Standard Deviation
Sources:
https://en.wikipedia.org/wiki/Standard_deviation#Uncorrected_sample_standard_deviation
Remark:
SDEV (Population Standard Deviation) is also known as a biased/uncorrected Standard Deviation.
For unbiased version that uses Bessel's correction, use SDEV instead.
</summary> */
public class SDEV_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public SDEV_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SDEV({period})";
}
public SDEV_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public SDEV_Series() : this(period: 0, useNaN: false) { }
public SDEV_Series(int period) : this(period: period, useNaN: false) { }
public SDEV_Series(TBars source) : this(source.Close, 0, false) { }
public SDEV_Series(TBars source, int period) : this(source.Close, period, false) { }
public SDEV_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public SDEV_Series(TSeries source) : this(source, 0, false) { }
public SDEV_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sma = _buffer.Average();
double _var = 0;
for (int i = 0; i < _buffer.Count; i++) { _var += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
_var /= this._buffer.Count;
double _sdev = Math.Sqrt(_var);
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sdev);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-122
View File
@@ -1,122 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
SLOPE: Slope of linear regression (using Least Square Method)
Linear Regression provides a slope of a straight line that is the best approximation of the given set of data.
The method of least squares is a standard approach in linear regression analysis to approximate the solution
by minimizing the sum of the squares of the residuals made in the results of each individual equation.
Additional outputs provided by LINREG:
.Intercept - y-intercept point of the best fit line
.RSquared - R-Squared (R²), Coefficient of Determination
.StdDev - Standard Deviation of data over given periods
y = Slope * x + Intercept
Sources:
https://en.wikipedia.org/wiki/Least_squares
</summary> */
public class SLOPE_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private readonly TSeries p_Intercept = new();
private readonly TSeries p_RSquared = new();
private readonly TSeries p_StdDev = new();
private readonly System.Collections.Generic.List<double> _buffer = new();
public TSeries Intercept => p_Intercept;
public TSeries RSquared => p_RSquared;
public TSeries StdDev => p_StdDev;
//core constructors
public SLOPE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SLOPE({period})";
}
public SLOPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public SLOPE_Series() : this(period: 0, useNaN: false) { }
public SLOPE_Series(int period) : this(period: period, useNaN: false) { }
public SLOPE_Series(TBars source) : this(source.Close, 0, false) { }
public SLOPE_Series(TBars source, int period) : this(source.Close, period, false) { }
public SLOPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public SLOPE_Series(TSeries source) : this(source, 0, false) { }
public SLOPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
int _len = this._buffer.Count;
// get averages for period
double sumX = 0;
double sumY = 0;
for (int p = 0; p < _len; p++) {
sumX += this.Count - _len + 2 + p;
sumY += _buffer[p];
}
double avgX = sumX / _len;
double avgY = sumY / _len;
// least squares method
double sumSqX = 0;
double sumSqY = 0;
double sumSqXY = 0;
for (int p = 0; p < _len; p++) {
double devX = this.Count - _len + 2 + p - avgX;
double devY = _buffer[p] - avgY;
sumSqX += devX * devX;
sumSqY += devY * devY;
sumSqXY += devX * devY;
}
double _slope = sumSqXY / sumSqX;
double _intercept = avgY - (_slope * avgX);
// calculate Standard Deviation and R-Squared
double stdDevX = Math.Sqrt(sumSqX / _len);
double stdDevY = Math.Sqrt(sumSqY / _len);
double _StdDev = stdDevY;
double arrr = (stdDevX * stdDevY != 0) ? sumSqXY / (stdDevX * stdDevY) / _len : 0;
double _RSquared = arrr * arrr;
var ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _intercept);
p_Intercept.Add(ret, update);
ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _StdDev);
p_StdDev.Add(ret, update);
ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _RSquared);
p_RSquared.Add(ret, update);
ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _slope);
return base.Add(ret, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-75
View File
@@ -1,75 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
SMAPE: Symmetric Mean Absolute Percentage Error
Measures the size of the error in percentage terms
Sources:
https://en.wikipedia.org/wiki/Symmetric_mean_absolute_percentage_error
</summary> */
public class SMAPE_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public SMAPE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SMAPE({period})";
}
public SMAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public SMAPE_Series() : this(period: 0, useNaN: false) { }
public SMAPE_Series(int period) : this(period: period, useNaN: false) { }
public SMAPE_Series(TBars source) : this(source.Close, 0, false) { }
public SMAPE_Series(TBars source, int period) : this(source.Close, period, false) { }
public SMAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public SMAPE_Series(TSeries source) : this(source, 0, false) { }
public SMAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sma = _buffer.Average();
double _smape = 0;
for (int i = 0; i < _buffer.Count; i++) { _smape += Math.Abs(_buffer[i] - _sma) / (Math.Abs(_buffer[i]) + Math.Abs(_sma)); }
_smape /= this._buffer.Count;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _smape);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-96
View File
@@ -1,96 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
SMA: Simple Moving Average
The weights are equally distributed across the period, resulting in a mean() of
the data within the period
Sources:
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/simple-moving-average-sma/
https://stats.stackexchange.com/a/24739
Remark:
This calc doesn't use LINQ or SUM() or any of (slow) iterative methods. It is not as fast as TA-LIB
implementation, but it does allow incremental additions of inputs and real-time calculations of SMA()
</summary> */
public class SMA_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
private double _sum, _oldsum;
private readonly int _period;
private readonly TSeries _data;
protected readonly bool _NaN;
//core constructor
public SMA_Series(int period, bool useNaN) {
_period = Math.Max(0, period);
_NaN = useNaN;
Name = $"SMA({period})";
_sum = _oldsum = 0;
}
public SMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public SMA_Series() : this(0, false) {}
public SMA_Series(int period) : this(period, false) {}
public SMA_Series(TBars source) : this(source.Close, 0, false) {}
public SMA_Series(TBars source, int period) : this(source.Close, period, false) {}
public SMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {}
public SMA_Series(TSeries source) : this(source, 0, false) {}
public SMA_Series(TSeries source, int period) : this(source, period, false) {}
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) { return (TValue.t, double.NaN);
} else {
if (update && _buffer.Count > 0) {
_sum -= _buffer[^1];
_buffer[^1] = TValue.v;
_oldsum = _sum;
}
else {
_buffer.Add(TValue.v);
_oldsum = _sum;
}
_sum += TValue.v;
if (_period != 0 && _buffer.Count > _period) {
_sum -= _buffer[0];
_buffer.RemoveAt(0);
}
}
double _div = _period == 0 ? _buffer.Count : Math.Min(_buffer.Count, _period);
var _sma = _sum / _div;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sma);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_sum = _oldsum = 0;
_buffer.Clear();
}
}
-93
View File
@@ -1,93 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
SMMA: Smoothed Moving Average
The Smoothed Moving Average (SMMA) is a combination of a SMA and an EMA. It gives the recent prices
an equal weighting as the historic prices as it takes all available price data into account.
The main advantage of a smoothed moving average is that it removes short-term fluctuations.
SMMA(i) = (SMMA-1*(N-1) + CLOSE (i)) / N
Sources:
https://blog.earn2trade.com/smoothed-moving-average
https://guide.traderevolution.com/traderevolution/mobile-applications/phone/android/technical-indicators/moving-averages/smma-smoothed-moving-average
https://www.chartmill.com/documentation/technical-analysis-indicators/217-MOVING-AVERAGES-%7C-The-Smoothed-Moving-Average-%28SMMA%29
</summary> */
public class SMMA_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private double _lastsmma, _lastlastsmma;
//core constructors
public SMMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SMMA({period})";
}
public SMMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public SMMA_Series() : this(period: 0, useNaN: false) { }
public SMMA_Series(int period) : this(period: period, useNaN: false) { }
public SMMA_Series(TBars source) : this(source.Close, 0, false) { }
public SMMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public SMMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public SMMA_Series(TSeries source) : this(source, 0, false) { }
public SMMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, double.NaN),update);
}
double _smma = 0;
if (update) { this._lastsmma = this._lastlastsmma; }
if (this.Count < this._period) {
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
_smma = _buffer.Average();
}
else {
_smma = ((_lastsmma * (_period - 1)) + TValue.v) / _period;
}
this._lastlastsmma = this._lastsmma;
this._lastsmma = _smma;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _smma);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
this._lastsmma = this._lastlastsmma = 0;
}
}
-82
View File
@@ -1,82 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
SSDEV: (Corrected) Sample Standard Deviation
Sample Standard Deviaton uses Bessel's correction to correct the bias in the variance.
Sources:
https://en.wikipedia.org/wiki/Standard_deviation#Corrected_sample_standard_deviation
Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction
Remark:
SSDEV (Sample Standard Deviation) is also known as a unbiased/corrected Standard Deviation.
For a population/biased/uncorrected Standard Deviation, use PSDEV instead
</summary> */
public class SSDEV_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public SSDEV_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SSDEV({period})";
}
public SSDEV_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public SSDEV_Series() : this(period: 0, useNaN: false) { }
public SSDEV_Series(int period) : this(period: period, useNaN: false) { }
public SSDEV_Series(TBars source) : this(source.Close, 0, false) { }
public SSDEV_Series(TBars source, int period) : this(source.Close, period, false) { }
public SSDEV_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public SSDEV_Series(TSeries source) : this(source, 0, false) { }
public SSDEV_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sma = _buffer.Average();
double _svar = 0;
for (int i = 0; i < this._buffer.Count; i++) { _svar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
_svar /= (_buffer.Count > 1) ? _buffer.Count - 1 : 1; // Bessel's correction
double _ssdev = Math.Sqrt(_svar);
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _ssdev);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-81
View File
@@ -1,81 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
VAR: Population Variance
Population variance without Bessel's correction
Sources:
https://en.wikipedia.org/wiki/Variance
Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction
Remark:
VAR (Population Variance) is also known as a biased Sample Variance. For unbiased
sample variance use SVAR instead.
</summary> */
public class SVAR_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public SVAR_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SVAR({period})";
}
public SVAR_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public SVAR_Series() : this(period: 0, useNaN: false) { }
public SVAR_Series(int period) : this(period: period, useNaN: false) { }
public SVAR_Series(TBars source) : this(source.Close, 0, false) { }
public SVAR_Series(TBars source, int period) : this(source.Close, period, false) { }
public SVAR_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public SVAR_Series(TSeries source) : this(source, 0, false) { }
public SVAR_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sma = _buffer.Average();
double _svar = 0;
for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); }
_svar /= (this._buffer.Count > 1) ? this._buffer.Count - 1 : 1; // Bessel's correction
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _svar);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-161
View File
@@ -1,161 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Numerics;
/* <summary>
T3: Tillson T3 Moving Average
Tim Tillson described it in "Technical Analysis of Stocks and Commodities", January 1998 in the
article "Better Moving Averages". Tillsons moving average becomes a popular indicator of
technical analysis as it gets less lag with the price chart and its curve is considerably smoother.
Sources:
https://technicalindicators.net/indicators-technical-analysis/150-t3-moving-average
http://www.binarytribune.com/forex-trading-indicators/t3-moving-average-indicator/
</summary> */
public class T3_Series : TSeries {
private readonly double _k, _k1m, _c1, _c2, _c3, _c4;
private readonly System.Collections.Generic.List<double> _buffer1 = new();
private readonly System.Collections.Generic.List<double> _buffer2 = new();
private readonly System.Collections.Generic.List<double> _buffer3 = new();
private readonly System.Collections.Generic.List<double> _buffer4 = new();
private readonly System.Collections.Generic.List<double> _buffer5 = new();
private readonly System.Collections.Generic.List<double> _buffer6 = new();
private readonly bool _useSMA;
private double _lastema1, _lastema2, _lastema3, _lastema4, _lastema5, _lastema6;
private double _llastema1, _llastema2, _llastema3, _llastema4, _llastema5, _llastema6;
protected int _len;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public T3_Series(int period, double vfactor, bool useSMA, bool useNaN) {
_period = period;
_len = 0;
_NaN = useNaN;
Name = $"T3({period})";
_useSMA = useSMA;
double _a = vfactor; //0.7; //0.618
_c1 = -_a * _a * _a;
_c2 = 3 * _a * _a + 3 * _a * _a * _a;
_c3 = -6 * _a * _a - 3 * _a - 3 * _a * _a * _a;
_c4 = 1 + 3 * _a + _a * _a * _a + 3 * _a * _a;
_k = 2.0 / (_period + 1);
_k1m = 1.0 - _k;
_lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0;
}
public T3_Series(TSeries source, int period, double vfactor, bool useSMA, bool useNaN) : this(period, vfactor, useSMA, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public T3_Series() : this(period: 0, vfactor: 0.7, useSMA: true, useNaN: false) { }
public T3_Series(int period) : this(period: period, vfactor: 0.7, useSMA: true, useNaN: false) { }
public T3_Series(TBars source) : this(source.Close, 0, vfactor: 0.7, useSMA: true, useNaN: false) { }
public T3_Series(TBars source, int period) : this(source.Close, period, vfactor: 0.7, useSMA: true, useNaN: false) { }
public T3_Series(TBars source, int period, bool useNaN) : this(source.Close, period, vfactor: 0.7, useSMA: true, useNaN: useNaN) { }
public T3_Series(TBars source, int period, double vfactor, bool useNaN) : this(source.Close, period, vfactor: vfactor, useSMA: true, useNaN: useNaN) { }
public T3_Series(TBars source, int period, bool useSMA, bool useNaN) : this(source.Close, period, vfactor: 0.7, useSMA: useSMA, useNaN: useNaN) { }
public T3_Series(TSeries source) : this(source, 0, vfactor: 0.7, useSMA: true, useNaN: false) { }
public T3_Series(TSeries source, int period) : this(source: source, period: period, vfactor: 0.7, useSMA: true, useNaN: false) { }
public T3_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, vfactor: 0.7, useSMA: true, useNaN: useNaN) { }
public T3_Series(TSeries source, int period, double vfactor) : this(source: source, period: period, vfactor: vfactor, useSMA: true, useNaN: false) { }
public T3_Series(TSeries source, int period, double vfactor, bool useNaN) : this(source: source, period: period, vfactor: vfactor, useSMA: true, useNaN: useNaN) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
double _ema1, _ema2, _ema3, _ema4, _ema5, _ema6;
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN),update);
}
if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; _lastema4 = _llastema4; _lastema5 = _llastema5; _lastema6 = _llastema6; }
else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _llastema4 = _lastema4; _llastema5 = _lastema5; _llastema6 = _lastema6; }
if (_len == 0) { _lastema1 = _lastema2 = _lastema3 = _lastema4 = _lastema5 = _lastema6 = TValue.v; }
if ((_len < _period) && _useSMA) {
BufferTrim(_buffer1, TValue.v, _period, update);
_ema1 = 0;
for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; }
_ema1 /= _buffer1.Count;
BufferTrim(_buffer2, _ema1, _period, update);
_ema2 = 0;
for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; }
_ema2 /= _buffer2.Count;
BufferTrim(_buffer3, _ema2, _period, update);
_ema3 = 0;
for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; }
_ema3 /= _buffer3.Count;
BufferTrim(_buffer4, _ema3, _period, update);
_ema4 = 0;
for (int i = 0; i < _buffer4.Count; i++) { _ema4 += _buffer4[i]; }
_ema4 /= _buffer4.Count;
BufferTrim(_buffer5, _ema4, _period, update);
_ema5 = 0;
for (int i = 0; i < _buffer5.Count; i++) { _ema5 += _buffer5[i]; }
_ema5 /= _buffer5.Count;
BufferTrim(_buffer6, _ema5, _period, update);
_ema6 = 0;
for (int i = 0; i < _buffer6.Count; i++) { _ema6 += _buffer6[i]; }
_ema6 /= _buffer6.Count;
}
else {
_ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m);
_ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m);
_ema3 = (_ema2 * this._k) + (this._lastema3 * this._k1m);
_ema4 = (_ema3 * this._k) + (this._lastema4 * this._k1m);
_ema5 = (_ema4 * this._k) + (this._lastema5 * this._k1m);
_ema6 = (_ema5 * this._k) + (this._lastema6 * this._k1m);
}
_len++;
_lastema1 = _ema1;
_lastema2 = _ema2;
_lastema3 = _ema3;
_lastema4 = _ema4;
_lastema5 = _ema5;
_lastema6 = _ema6;
double _T3 = _c1 * _ema6 + _c2 * _ema5 + _c3 * _ema4 + _c4 * _ema3;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _T3);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0;
_buffer1.Clear();
_buffer2.Clear();
_buffer3.Clear();
_buffer4.Clear();
_buffer5.Clear();
_buffer6.Clear();
_len = 0;
}
}
-138
View File
@@ -1,138 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
TBars class - includes all series for common data used in indicators and other calculations.
Has a bit limited overloading and casting (compared to TSeries)
Includes Select(int) method to simplify choosing the most optimal data source for indicators
Includes the most basic pricing calcs: HL2, OC2, OHL3, HLC3, OHLC4, HLCC4
(it is 'cheaper' to calculate them once during data capture than each time during data analysis)
</summary> */
public class TBars : System.Collections.Generic.List<(DateTime t, double o, double h, double l, double c, double v)>
{
public string Name { get; set; }
private readonly TSeries _open = new("open");
private readonly TSeries _high = new("high");
private readonly TSeries _low = new("low");
private readonly TSeries _close = new("close");
private readonly TSeries _volume = new("volume");
private readonly TSeries _hl2 = new("HL2");
private readonly TSeries _oc2 = new("OC2");
private readonly TSeries _ohl3 = new("OHL3");
private readonly TSeries _hlc3 = new("HLC3");
private readonly TSeries _ohlc4 = new("OHLC4");
private readonly TSeries _hlcc4 = new("HLCC4");
public TSeries Open => this._open;
public TSeries High => this._high;
public TSeries Low => this._low;
public TSeries Close => this._close;
public TSeries Volume => this._volume;
public TSeries HL2 => this._hl2;
public TSeries OC2 => this._oc2;
public TSeries OHL3 => this._ohl3;
public TSeries HLC3 => this._hlc3;
public TSeries OHLC4 => this._ohlc4;
public TSeries HLCC4 => this._hlcc4;
public TBars() { }
public TBars(string Name) {
this.Name = Name;
}
public (DateTime t, double o, double h, double l, double c, double v) Last => this[^1];
public TBars Tail(int count = 10)
{
TBars outBars = new();
if (count > this.Count) { count = this.Count; }
for (int i = this.Count - count; i < this.Count; i++) { outBars.Add(this[i]); }
return outBars;
}
public TSeries Select(int source)
{
return source switch
{
0 => _open,
1 => _high,
2 => _low,
3 => _close,
4 => _hl2,
5 => _oc2,
6 => _ohl3,
7 => _hlc3,
8 => _ohlc4,
_ => _hlcc4,
};
}
public static string SelectStr(int source)
{
return source switch
{
0 => "Open",
1 => "High",
2 => "Low",
3 => "Close",
4 => "HL2",
5 => "OC2",
6 => "OHL3",
7 => "HLC3",
8 => "OHLC4",
_ => "HLCC4",
};
}
public virtual (DateTime t, double v) Add((double o, double h, double l, double c, double v) p, bool update = false) =>
Add((t: (this.Count == 0) ? DateTime.Today : this[^1].t.AddDays(1),p.o,p.h,p.l,p.c,p.v),update);
public virtual (DateTime t, double v) Add(double o, double h, double l, double c, double v, bool update = false) =>
Add((o,h,l,c,v),update);
public virtual (DateTime t, double v) Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) =>
this.Add((t, o, h, l, c, v), update);
public virtual (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) { this[^1] = TBar; } else { base.Add(TBar); }
_open.Add((TBar.t, TBar.o), update);
_high.Add((TBar.t, TBar.h), update);
_low.Add((TBar.t, TBar.l), update);
_close.Add((TBar.t, TBar.c), update);
_volume.Add((TBar.t, TBar.v), update);
_hl2.Add((TBar.t, (TBar.h + TBar.l) * 0.5), update);
_oc2.Add((TBar.t, (TBar.o + TBar.c) * 0.5), update);
_ohl3.Add((TBar.t, (TBar.o + TBar.h + TBar.l) * 0.333333333333333), update);
_hlc3.Add((TBar.t, (TBar.h + TBar.l + TBar.c) * 0.333333333333333), update);
_ohlc4.Add((TBar.t, (TBar.o + TBar.h + TBar.l + TBar.c) * 0.25), update);
_hlcc4.Add((TBar.t, (TBar.h + TBar.l + TBar.c + TBar.c) * 0.25), update);
this.OnEvent(update);
return (TBar.t, (TBar.o + TBar.h + TBar.l + TBar.c) * 0.25);
}
public delegate void NewDataEventHandler(object source, TSeriesEventArgs args);
public event NewDataEventHandler Pub;
protected virtual void OnEvent(bool update = false) { if (Pub != null && Pub.Target != this) {
Pub(this, new TSeriesEventArgs { update = update }); } }
public void Sub(object source, TSeriesEventArgs e) { TBars ss = (TBars)source; if (ss.Count > 1) {
for (int i = 0; i < ss.Count; i++) { this.Add(ss[i]); }
} else {
this.Add(ss[^1], e.update);
}
}
/// common helpers
public static void BufferTrim(System.Collections.Generic.List<double> buffer, double value, int period, bool update) {
if (!update) {
buffer.Add(value);
if (buffer.Count > period && period > 0) { buffer.RemoveAt(0); }
return;
}
buffer[^1] = value;
}
public virtual void Reset() {
}
}
-120
View File
@@ -1,120 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
TEMA: Triple Exponential Moving Average
TEMA uses EMA(EMA(EMA())) to calculate less laggy Exponential moving average.
Sources:
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triple-exponential-moving-average-tema/
Remark:
ema1 = EMA(close, length)
ema2 = EMA(ema1, length)
ema3 = EMA(ema2, length)
TEMA = 3 * (ema1 - ema2) + ema3
</summary> */
public class TEMA_Series : TSeries {
private double _k;
private double _sum, _oldsum;
private double _lastema1, _oldema1, _lastema2, _oldema2, _lastema3, _oldema3;
private int _len;
private readonly bool _useSMA;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructor
public TEMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
Name = $"TEMA({period})";
_k = 2.0 / (_period + 1);
_len = 0;
_sum = _oldsum = _lastema1 = _lastema2 = _lastema3 = 0;
}
public TEMA_Series() : this(0, false, true) {}
public TEMA_Series(int period) : this(period, false, true) {}
public TEMA_Series(TBars source) : this(source.Close, 0, false) {}
public TEMA_Series(TBars source, int period) : this(source.Close, period, false) {}
public TEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {}
public TEMA_Series(TSeries source, int period) : this(source, period, false, true) {}
public TEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {}
public TEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) {
_lastema1 = _oldema1;
_lastema2 = _oldema2;
_lastema3 = _oldema3;
_sum = _oldsum;
}
else {
_oldema1 = _lastema1;
_oldema2 = _lastema2;
_oldema3 = _lastema3;
_oldsum = _sum;
_len++;
}
if (_period == 0) { _k = 2.0 / (_len + 1); }
double _ema1, _ema2, _ema3, _tema;
if (this.Count == 0) {
_ema1 = _ema2 = _ema3 =_sum = TValue.v;
}
else if (_len <= _period && _useSMA && _period != 0) {
_sum += TValue.v;
_ema1 = _sum / Math.Min(_len, _period);
_ema2 = _ema1;
_ema3 = _ema2;
}
else {
_ema1 = (TValue.v - _lastema1) * _k + _lastema1;
_ema2 = (_ema1 - _lastema2) * _k + _lastema2;
_ema3 = (_ema2 - _lastema3) * _k + _lastema3;
}
_tema = (3 * (_ema1 - _ema2)) + _ema3;
_lastema1 = Double.IsNaN(_ema1)?_lastema1:_ema1;
_lastema2 = Double.IsNaN(_ema2)?_lastema2:_ema2;
_lastema3 = Double.IsNaN(_ema3) ? _lastema3 : _ema3;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _tema);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_sum = _oldsum = _lastema1 = _lastema2 = 0;
_len = 0;
}
}
-84
View File
@@ -1,84 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
TRIMA: Triangular Moving Average
A weighted moving average where the shape of the weights are triangular and the greatest
weight is in the middle of the period,
Sources:
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triangular-moving-average-trima/
Remark:
trima = sma(sma(signal, n/2), n/2)
</summary> */
public class TRIMA_Series : TSeries {
private readonly int _p1a, _p1b;
private readonly SMA_Series sma, trima;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public TRIMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"xMA({period})";
_p1a = (int)Math.Floor((period * 0.5) + 1);
_p1b = (int)Math.Ceiling(0.5 * period);
sma = new(_p1a);
trima = new(_p1b);
}
public TRIMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public TRIMA_Series() : this(period: 0, useNaN: false) { }
public TRIMA_Series(int period) : this(period: period, useNaN: false) { }
public TRIMA_Series(TBars source) : this(source.Close, 0, false) { }
public TRIMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public TRIMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public TRIMA_Series(TSeries source) : this(source, 0, false) { }
public TRIMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
var _sma = sma.Add(TValue, update);
var _trima = trima.Add(_sma, update);
var res = (_trima.t, Count < _period - 1 && _NaN ? double.NaN : _trima.v);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
sma.Reset();
trima.Reset();
}
}
-118
View File
@@ -1,118 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
TRIX: Triple Exponential Average Oscillator
Developed by Jack Hutson in the early 1980s, the triple exponential average (TRIX)
has become a popular technical analysis tool to aid chartists in spotting diversions
and directional cues in stock trading patterns.
Sources:
https://www.investopedia.com/terms/t/trix.asp
</summary> */
public class TRIX_Series : TSeries {
private readonly double _k;
private readonly System.Collections.Generic.List<double> _buffer1 = new();
private readonly System.Collections.Generic.List<double> _buffer2 = new();
private readonly System.Collections.Generic.List<double> _buffer3 = new();
private double _lastema1, _lastema2, _lastema3;
private double _llastema1, _llastema2, _llastema3;
private int _len;
private readonly bool _useSMA;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public TRIX_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
Name = $"TRIX({period})";
_k = 2.0 / (_period + 1);
_len = 0;
_lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = 0;
}
public TRIX_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public TRIX_Series() : this(0, false, true) {}
public TRIX_Series(int period) : this(period, false, true) {}
public TRIX_Series(TBars source) : this(source.Close, 0, false) {}
public TRIX_Series(TBars source, int period) : this(source.Close, period, false) {}
public TRIX_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {}
public TRIX_Series(TSeries source, int period) : this(source, period, false, true) {}
public TRIX_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {}
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
if (_len == 0) { _lastema1 = _lastema2 = _lastema3 = TValue.v; }
if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; }
else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _len++;
}
double _ema1, _ema2, _ema3;
if ((this.Count < _period) && _useSMA) {
BufferTrim(_buffer1, TValue.v, _period, update);
_ema1 = 0;
for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; }
_ema1 /= _buffer1.Count;
BufferTrim(_buffer2, _ema1, _period, update);
_ema2 = 0;
for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; }
_ema2 /= _buffer2.Count;
BufferTrim(_buffer3, _ema2, _period, update);
_ema3 = 0;
for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; }
_ema3 /= _buffer3.Count;
}
else {
_ema1 = (TValue.v - _lastema1) * _k + _lastema1;
_ema2 = (_ema1 - _lastema2) * _k + _lastema2;
_ema3 = (_ema2 - _lastema3) * _k + _lastema3;
}
double _trix = 100 * (_ema3 - _lastema3) / _lastema3;
_lastema1 = _ema1;
_lastema2 = _ema2;
_lastema3 = _ema3;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _trix);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_len = 0;
}
}
-79
View File
@@ -1,79 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
TR: True Range
True Range was introduced by J. Welles Wilder in his book New Concepts in Technical Trading Systems.
It measures the daily range plus any gap from the closing price of the preceding day.
Calculation:
d1 = ABS(High - Low)
d2 = ABS(High - Previous close)
d3 = ABS(Previous close - Low)
TR = MAX(d1,d2,d3)
Sources:
https://www.macroption.com/true-range/
</summary> */
public class TR_Series : TSeries {
protected readonly TBars _data;
private double _cm1, _cm1_o;
//core constructors
public TR_Series() {
Name = $"TR()";
_cm1 = _cm1_o = double.NaN;
}
public TR_Series(TBars source) {
_data = source;
Name = $"TR({(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_cm1 = _cm1_o = double.NaN;
_data.Pub += Sub;
Add(data: _data);
}
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) {
_cm1 = _cm1_o;
}
else {
_cm1_o = _cm1;
}
if (_cm1 is double.NaN) {
_cm1 = TBar.c;
}
double d1 = Math.Abs(TBar.h - TBar.l);
double d2 = Math.Abs(_cm1 - TBar.h);
double d3 = Math.Abs(_cm1 - TBar.l);
_cm1 = TBar.c;
var ret = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
return base.Add(ret, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_cm1 = _cm1_o = double.NaN;
}
}
-117
View File
@@ -1,117 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Linq;
/* <summary>
TSeries is the cornerstone of all QuanTAlib classes.
TSeries is a single List of tuples (time, value) and contains several operators, casts, overloads
and other helpers that simplify usage of library.
Think of TSeries as an equivalent of Numpy array.
- includes Length property (to mimic array's method)
- includes publishing and subscribing methods that attach to events
</summary> */
public class TSeriesEventArgs : EventArgs {
public bool update { get; set; }
}
public class TSeries : List<(DateTime t, double v)> {
private readonly (DateTime t, double v) Default = (DateTime.MinValue, double.NaN);
public IEnumerable<DateTime> t => this.Select(item => item.t);
public IEnumerable<double> v => this.Select(item => item.v);
public (DateTime t, double v) Last => Count > 0 ? this[^1] : Default;
public int Length => Count;
public string Name { get; set; }
public int Keep = 0;
public TSeries() {
this.Name = "data";
}
public TSeries(string Name) {
this.Name = Name;
}
public virtual (DateTime t, double v) Add(double v, bool update = false) {
return Add((t: Count == 0 ? DateTime.Today : this[^1].t.AddDays(1), v), update);
}
public virtual (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) {
this[^1] = TValue;
}
else {
base.Add(TValue);
}
OnEvent(update);
return TValue;
}
public virtual (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) {
this[this.Count - 1] = (TBar.t, TBar.c);
}
else {
base.Add((TBar.t, TBar.c));
}
OnEvent(update);
return (TBar.t, TBar.c);
}
public virtual (DateTime t, double v) Add(TSeries data) {
foreach (var item in data) { Add(item); }
return data.Last;
}
public virtual (DateTime t, double v) Add(TBars data) {
foreach (var item in data) { Add(item.c, false); }
return (data.Last.t, data.Last.c);
}
public void Sub(object source, TSeriesEventArgs e) {
var data = (TSeries) source;
if (data == null) { return; }
foreach (var item in data) { Add(item); }
}
public delegate void NewEventHandler(object source, TSeriesEventArgs args);
public event NewEventHandler Pub;
protected virtual void OnEvent(bool update = false)
{
if (Keep > 0) {
TrimToSize(keep:Keep);
}
Pub?.Invoke(this, new TSeriesEventArgs {update = update});
}
/// common helpers
public static void BufferTrim(List<double> buffer, double value, int period, bool update) {
if (!update) {
buffer.Add(value);
if (buffer.Count > period && period > 0) { buffer.RemoveAt(0); }
return;
}
buffer[^1] = value;
}
public virtual void Reset() {
}
public void TrimToSize(int keep) {
if (keep >= this.Count) {
return; // No need to trim if the series is already smaller than or equal to n
}
// Remove elements from the beginning of the list
int elementsToRemove = this.Count - keep;
RemoveRange(0, elementsToRemove);
}
}
-81
View File
@@ -1,81 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
VAR: Population Variance
Population variance without Bessel's correction
Sources:
https://en.wikipedia.org/wiki/Variance
Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction
Remark:
VAR (Population Variance) is also known as a biased Sample Variance. For unbiased
sample variance use SVAR instead.
</summary> */
public class VAR_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public VAR_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"VAR({period})";
}
public VAR_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public VAR_Series() : this(period: 0, useNaN: false) { }
public VAR_Series(int period) : this(period: period, useNaN: false) { }
public VAR_Series(TBars source) : this(source.Close, 0, false) { }
public VAR_Series(TBars source, int period) : this(source.Close, period, false) { }
public VAR_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public VAR_Series(TSeries source) : this(source, 0, false) { }
public VAR_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sma = _buffer.Average();
double _pvar = 0;
for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
_pvar /= this._buffer.Count;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _pvar);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-82
View File
@@ -1,82 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
WMAPE: Weighted Mean Absolute Percentage Error
Measures the size of the error in percentage terms. Improves problems with MAPE
when there are zero or close-to-zero values because there would be a division by zero
or values of MAPE tending to infinity.
Sources:
https://en.wikipedia.org/wiki/WMAPE
</summary> */
public class WMAPE_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public WMAPE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"WMAPE({period})";
}
public WMAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public WMAPE_Series() : this(period: 0, useNaN: false) { }
public WMAPE_Series(int period) : this(period: period, useNaN: false) { }
public WMAPE_Series(TBars source) : this(source.Close, 0, false) { }
public WMAPE_Series(TBars source, int period) : this(source.Close, period, false) { }
public WMAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public WMAPE_Series(TSeries source) : this(source, 0, false) { }
public WMAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sma = _buffer.Average();
double _div = 0;
double _wmape = 0;
for (int i = 0; i < _buffer.Count; i++) {
_wmape += Math.Abs(_buffer[i] - _sma);
_div += Math.Abs(_buffer[i]);
}
_wmape = (_div != 0) ? _wmape / _div : double.PositiveInfinity;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _wmape);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
-104
View File
@@ -1,104 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
/* <summary>
WMA: (linearly) Weighted Moving Average
The weights are linearly decreasing over the period and the most recent data has
the heaviest weight.
Sources:
https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/weighted-moving-average-wma/
https://www.technicalindicators.net/indicators-technical-analysis/83-moving-averages-simple-exponential-weighted
</summary> */
public class WMA_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
private System.Collections.Generic.List<double> _weights;
protected int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
protected int _len;
public int Len {
get { return _len; }
set { _len = value; }
}
//core constructors
public WMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"WMA({period})";
_len = 1;
_weights = CalculateWeights(_period);
}
public WMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public WMA_Series() : this(period: 0, useNaN: false) { }
public WMA_Series(int period) : this(period: period, useNaN: false) { }
public WMA_Series(TBars source) : this(source.Close, 0, false) { }
public WMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public WMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public WMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update=false) {
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
if (_period == 0) {
_weights = CalculateWeights(_len);
_len++;
}
double _wma = 0;
double totalWeights = (_buffer.Count * (_buffer.Count + 1)) * 0.5;
object lockObj = new object();
Parallel.For(0, _buffer.Count, i =>
{
double temp = _buffer[i] * this._weights[i];
lock (lockObj) { _wma += temp; }
});
_wma /= totalWeights;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _wma);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//calculating weights
private static List<double> CalculateWeights(int period) {
List<double> weights = new List<double>(period);
for (int i = 0; i < period; i++) {
weights.Add(i + 1);
}
return weights;
}
//reset calculation
public override void Reset() {
_len = 0;
_weights = CalculateWeights(_period);
_buffer.Clear();
}
}
-95
View File
@@ -1,95 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
ZLEMA: Zero Lag Exponential Moving Average
The Zero lag exponential moving average (ZLEMA) indicator was created by John
Ehlers and Ric Way.
The formula for a given N-Day period and for a given Data series is:
Lag = (Period-1)/2
Ema Data = {Data+(Data-Data(Lag days ago))
ZLEMA = EMA (EmaData,Period)
Remark:
The idea is do a regular exponential moving average (EMA) calculation but on a
de-lagged data instead of doing it on the regular data. Data is de-lagged by
removing the data from "lag" days ago thus removing (or attempting to remove)
the cumulative lag effect of the moving average.
</summary> */
public class ZLEMA_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
private int _len;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private readonly EMA_Series _ema;
//core constructor
public ZLEMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
Name = $"ZLEMA({period})";
_len = 1;
_ema = new(period);
}
//generic constructors (source)
public ZLEMA_Series() : this(0, false, true) { }
public ZLEMA_Series(int period) : this(period, false, true) { }
public ZLEMA_Series(TBars source) : this(source.Close, 0, false) { }
public ZLEMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public ZLEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public ZLEMA_Series(TSeries source, int period) : this(source, period, false, true) { }
public ZLEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
public ZLEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
int _lag;
if (_period == 0) {
_lag = (int)((_len - 1) * 0.5);
_len++;
}
else { _lag = (int)((_period - 1) * 0.5); }
_lag = Math.Min(_lag, _buffer.Count - 1);
_lag = Math.Max(_lag, 0) + 1;
double _zlValue = 2 * TValue.v - _buffer[^_lag];
double _zlema = _ema.Add((TValue.t, _zlValue), update).v;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zlema);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
_ema.Reset();
}
}
-90
View File
@@ -1,90 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
ZL: Zero Lag
Data is de-lagged by removing the data from “lag” days ago, thus removing
(or attempting to) the cumulative effect of the moving average.
Calculation:
Lag = (Period-1)/2
ZL = Data + (Data - Data(Lag days ago) )
Sources:
https://mudrex.com/blog/zero-lag-ema-trading-strategy/
</summary> */
public class ZL_Series: TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
private int _len;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private readonly EMA_Series _ema;
//core constructor
public ZL_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
Name = $"ZL({period})";
_len = 1;
_ema = new(period);
}
//generic constructors (source)
public ZL_Series() : this(0, false, true) { }
public ZL_Series(int period) : this(period, false, true) { }
public ZL_Series(TBars source) : this(source.Close, 0, false) { }
public ZL_Series(TBars source, int period) : this(source.Close, period, false) { }
public ZL_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public ZL_Series(TSeries source, int period) : this(source, period, false, true) { }
public ZL_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
public ZL_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
int _lag;
if (_period == 0) {
_lag = (int)((_len - 1) * 0.5);
_len++;
}
else { _lag = (int)((_period - 1) * 0.5); }
_lag = Math.Min(_lag, _buffer.Count - 1);
_lag = Math.Max(_lag, 0) + 1;
double _zlValue = 2 * TValue.v - _buffer[^_lag];
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zlValue);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
_ema.Reset();
}
}
-88
View File
@@ -1,88 +0,0 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
ZSCORE: number of standard deviations from SMA
Z-score describes a value's relationship to the mean of a series, as measured in
terms of standard deviations from the mean. If a Z-score is 0, it indicates that
the data point's score is identical to the mean score. A Z-score of 1.0 would
indicate a value that is one standard deviation from the mean. Z-scores may be
positive or negative, with a positive value indicating the score is above the
mean and a negative score indicating it is below the mean.
Sources:
https://en.wikipedia.org/wiki/Z-score
https://www.investopedia.com/terms/z/zscore.asp
Calculation:
std = std * STDEV(close, length)
mean = SMA(close, length)
ZSCORE = (close - mean) / std
</summary> */
public class ZSCORE_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public ZSCORE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"ZSCORE({period})";
}
public ZSCORE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public ZSCORE_Series() : this(period: 0, useNaN: false) { }
public ZSCORE_Series(int period) : this(period: period, useNaN: false) { }
public ZSCORE_Series(TBars source) : this(source.Close, 0, false) { }
public ZSCORE_Series(TBars source, int period) : this(source.Close, period, false) { }
public ZSCORE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public ZSCORE_Series(TSeries source) : this(source, 0, false) { }
public ZSCORE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sma = _buffer.Average();
double _pvar = 0;
for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
_pvar /= this._buffer.Count;
double _psdev = Math.Sqrt(_pvar);
double _zscore = (_psdev == 0) ? 1 : (TValue.v - _sma) / _psdev;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zscore);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
+37
View File
@@ -0,0 +1,37 @@
<Project>
<PropertyGroup>
<NeutralLanguage>en-US</NeutralLanguage>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Deterministic>true</Deterministic>
<LangVersion>preview</LangVersion>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports>
<PlatformTarget>AnyCPU</PlatformTarget>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<OutputPath>bin\$(Configuration)\</OutputPath>
<ProduceReferenceAssembly>False</ProduceReferenceAssembly>
<DebugType>full</DebugType>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PlatformTarget>AnyCPU</PlatformTarget>
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All"/>
<PackageReference Include="GitVersion.MsBuild" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup Condition="'$(IsLocalBuild)' == 'true'">
<QuantowerRoot>D:\Quantower</QuantowerRoot>
<QuantowerPath>$([System.IO.Directory]::GetDirectories("$(QuantowerRoot)\TradingPlatform", "v1*")[0])</QuantowerPath>
</PropertyGroup>
</Project>
+10 -19
View File
@@ -1,30 +1,21 @@
mode: ContinuousDeployment
mode: ContinuousDelivery
branches:
main:
regex: ^main$
is-release-branch: true
is-mainline: true
prevent-increment-of-merged-branch-version: true
track-merge-target: false
increment: Patch
source-branches: [ 'develop' ]
is-release-branch: true
is-mainline: true
label: ''
develop:
regex: ^dev$
increment: Patch
is-release-branch: false
prevent-increment-of-merged-branch-version: false
source-branches: ['dev']
dev:
regex: ^dev(elop)?(ment)?$
increment: Inherit
track-merge-target: true
source-branches: []
is-release-branch: false
tracks-release-branches: true
is-mainline: false
label: dev
ignore:
sha: []
major-version-bump-message: '\+semver:\s?(feature|major)'
minor-version-bump-message: '\+semver:\s?(new|update|minor|add)'
no-bump-message: '\+semver:\s?(skip|none|fix)'
major-version-bump-message: '\+semver:\s?(breaking|major)'
minor-version-bump-message: '\+semver:\s?(feature|minor)'
patch-version-bump-message: '\+semver:\s?(fix|patch)'
no-bump-message: '\+semver:\s?(none|skip)'
commit-message-incrementing: Enabled
-284
View File
@@ -1,284 +0,0 @@
using System;
using System.Drawing;
using System.Linq;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class MovingAverage_chart : Indicator {
#region Parameters
[InputParameter("MA1: Type:", 0, variants: new object[]
{ "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
"ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
private int MA1type = 15;
[InputParameter("MA1: Smoothing period:", 1, 1, 999, 1, 1)]
private int MA1Period = 10;
[InputParameter("MA1: Data source:", 2, variants: new object[]
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
private int MA1DataSource = 3;
[InputParameter("MA2: Type:", 3, variants: new object[]
{ "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
"ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
private int MA2type = 16;
[InputParameter("MA2: Smoothing period:", 4, 1, 999, 1, 1)]
private int MA2Period = 50;
[InputParameter("MA2: Data source:", 5, variants: new object[]
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
private int MA2DataSource = 8;
[InputParameter("Long trades", 6)]
private bool LongTrades = true;
[InputParameter("Short trades", 6)]
private bool ShortTrades = true;
#endregion Parameters
protected HistoricalData History;
private TBars bars;
///////
private TSeries MA1, MA2;
private CROSS_Series trades;
private COMPARE_Series overunder;
///////
public MovingAverage_chart() {
this.SeparateWindow = false;
this.Name = "MAs Crossover";
this.AddLineSeries("MA1", Color.LimeGreen, 2, LineStyle.Solid);
this.AddLineSeries("MA2", Color.OrangeRed, 2, LineStyle.Solid);
}
protected override void OnInit() {
this.bars = new();
this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
for (int i = this.History.Count - 1; i >= 0; i--) {
var rec = this.History[i, SeekOriginHistory.Begin];
bars.Add(rec.TimeLeft, rec[PriceType.Open],
rec[PriceType.High], rec[PriceType.Low],
rec[PriceType.Close], rec[PriceType.Volume]);
}
this.Name = "MAs Cross: [ ";
switch (MA1type) {
case 0:
MA1 = new SMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"SMA";
break;
case 1:
MA1 = new EMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"EMA";
break;
case 2:
MA1 = new WMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"WMA";
break;
case 3:
MA1 = new T3_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"T3";
break;
case 4:
MA1 = new SMMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"SMMA";
break;
case 5:
MA1 = new TRIMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"TRIMA";
break;
case 6:
MA1 = new DWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"DWMA";
break;
case 7:
MA1 = new FWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period);
this.Name += $"FWMA";
break;
case 8:
MA1 = new DEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"DEMA";
break;
case 9:
MA1 = new TEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"TEMA";
break;
case 10:
MA1 = new ALMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"ALMA";
break;
case 11:
MA1 = new HMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"HMA";
break;
case 12:
MA1 = new HEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"HEMA";
break;
case 13:
double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA1Period);
MA1 = new MAMA_Series(source: bars.Select(this.MA1DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
this.Name += $"MAMA";
break;
case 14:
MA1 = new KAMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"KAMA";
break;
case 15:
MA1 = new ZLEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"ZLEMA";
break;
default:
MA1 = new JMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"JMA";
break;
}
this.Name = this.Name + $" ({MA1Period}:{TBars.SelectStr(this.MA1DataSource)}) : ";
switch (MA2type) {
case 0:
MA2 = new SMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"SMA";
break;
case 1:
MA2 = new EMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"EMA";
break;
case 2:
MA2 = new WMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"WMA";
break;
case 3:
MA2 = new T3_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"T3";
break;
case 4:
MA2 = new SMMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"SMMA";
break;
case 5:
MA2 = new TRIMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"TRIMA";
break;
case 6:
MA2 = new DWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"DWMA";
break;
case 7:
MA2 = new FWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period);
this.Name += $"FWMA";
break;
case 8:
MA2 = new DEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"DEMA";
break;
case 9:
MA2 = new TEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"TEMA";
break;
case 10:
MA2 = new ALMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"ALMA";
break;
case 11:
MA2 = new HMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"HMA";
break;
case 12:
MA2 = new HEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"HEMA";
break;
case 13:
double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA2Period);
MA2 = new MAMA_Series(source: bars.Select(this.MA2DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
this.Name += $"MAMA";
break;
case 14:
MA2 = new KAMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"KAMA";
break;
case 15:
MA2 = new ZLEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"ZLEMA";
break;
default:
MA2 = new JMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"JMA";
break;
}
this.Name += $"({MA2Period}:{TBars.SelectStr(this.MA2DataSource)}) ]";
int maxKeep = Math.Max(Math.Max(this.MA1Period, this.MA2Period), 100);
MA1.Keep = maxKeep;
MA2.Keep = maxKeep;
trades.Keep = maxKeep;
overunder.Keep = maxKeep;
overunder = new(MA1, MA2);
trades = new(MA1, MA2);
}
protected override void OnUpdate(UpdateArgs args) {
bool update = !(args.Reason == UpdateReason.NewBar ||
args.Reason == UpdateReason.HistoricalBar);
this.bars.Add(this.Time(), this.GetPrice(PriceType.Open),
this.GetPrice(PriceType.High),
this.GetPrice(PriceType.Low),
this.GetPrice(PriceType.Close),
this.GetPrice(PriceType.Volume), update);
this.SetValue(this.MA1[^1].v, lineIndex: 0);
this.SetValue(this.MA2[^1].v, lineIndex: 1);
if (trades[^1].v == 1) {
this.EndCloud(0, 1, Color.Empty);
if (LongTrades) {
this.LinesSeries[0].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.UpArrow));
this.BeginCloud(0, 1, Color.FromArgb(127, Color.Green));
}
if (ShortTrades) {
this.LinesSeries[1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.DownArrow));
}
}
if (trades[^1].v == -1) {
this.EndCloud(0, 1, Color.Empty);
if (ShortTrades) {
this.LinesSeries[1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.UpArrow));
this.BeginCloud(0, 1, Color.FromArgb(127, Color.Red));
}
if (LongTrades) {
this.LinesSeries[0].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.DownArrow));
}
}
}
public override void OnPaintChart(PaintChartEventArgs args) {
base.OnPaintChart(args);
if (this.CurrentChart == null) {return;}
Graphics graphics = args.Graphics;
var mainWindow = this.CurrentChart.MainWindow;
int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
int historycount = HistoricalData.Count;
int ymax = mainWindow.ClientRectangle.Height;
int xmax = mainWindow.ClientRectangle.Width;
/*
for (int i = leftIndex; i <= rightIndex; i++) {
int xi = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - 1 - i)));
int width = this.CurrentChart.BarsWidth;
int height = (int)((equity[i+historycount].v) *proportion);
Brush bb = Brushes.DarkSlateGray;
bb = (overunder[i+historycount].v>0 && LongTrades)? Brushes.Green : bb;
bb = (overunder[i + historycount].v < 0 && ShortTrades) ? Brushes.Red : bb;
graphics.FillRectangle(bb, xi, ymax - height, width, height);
}
*/
}
}
-307
View File
@@ -1,307 +0,0 @@
using System;
using System.Drawing;
using System.Linq;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class MovingAverageSlope_chart : Indicator {
#region Parameters
[InputParameter("MA1: Type:", 0, variants: new object[]
{ "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
"ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
private int MA1type = 16;
[InputParameter("MA1: Smoothing period:", 1, 1, 999, 1, 1)]
private int MA1Period = 10;
[InputParameter("MA1: Data source:", 2, variants: new object[]
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
private int MA1DataSource = 3;
[InputParameter("MA2: Type:", 3, variants: new object[]
{ "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
"ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
private int MA2type = 6;
[InputParameter("MA2: Smoothing period:", 4, 1, 999, 1, 1)]
private int MA2Period = 50;
[InputParameter("MA2: Data source:", 5, variants: new object[]
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
private int MA2DataSource = 8;
[InputParameter("Data required for slope calc:", 6, 2, 10, 1, 1)]
private int SlopePeriod = 3;
[InputParameter("Long trades", 7)]
private bool LongTrades = true;
[InputParameter("Short trades", 8)]
private bool ShortTrades;
#endregion Parameters
protected HistoricalData History;
private TBars bars;
///////
private TSeries MA1, MA2;
private SLOPE_Series sMA1, sMA2;
private CROSS_Series sig1, sig2;
private bool inLong, inShort;
///////
public MovingAverageSlope_chart() {
this.SeparateWindow = false;
this.Name = "Slopes convergence";
this.AddLineSeries("MA1", Color.DarkSlateGray, 2, LineStyle.Solid);
this.AddLineSeries("MA2", Color.DarkSlateGray, 2, LineStyle.Solid);
}
protected override void OnInit() {
this.bars = new();
this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
for (int i = this.History.Count - 1; i >= 0; i--) {
var rec = this.History[i, SeekOriginHistory.Begin];
bars.Add(rec.TimeLeft, rec[PriceType.Open],
rec[PriceType.High], rec[PriceType.Low],
rec[PriceType.Close], rec[PriceType.Volume]);
}
this.Name = "Slopes convergence: [ ";
switch (MA1type) {
case 0:
MA1 = new SMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"SMA";
break;
case 1:
MA1 = new EMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"EMA";
break;
case 2:
MA1 = new WMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"WMA";
break;
case 3:
MA1 = new T3_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"T3";
break;
case 4:
MA1 = new SMMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"SMMA";
break;
case 5:
MA1 = new TRIMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"TRIMA";
break;
case 6:
MA1 = new DWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"DWMA";
break;
case 7:
MA1 = new FWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period);
this.Name += $"FWMA";
break;
case 8:
MA1 = new DEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"DEMA";
break;
case 9:
MA1 = new TEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"TEMA";
break;
case 10:
MA1 = new ALMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"ALMA";
break;
case 11:
MA1 = new HMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"HMA";
break;
case 12:
MA1 = new HEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"HEMA";
break;
case 13:
double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA1Period);
MA1 = new MAMA_Series(source: bars.Select(this.MA1DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
this.Name += $"MAMA";
break;
case 14:
MA1 = new KAMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"KAMA";
break;
case 15:
MA1 = new ZLEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"ZLEMA";
break;
default:
MA1 = new JMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
this.Name += $"JMA";
break;
}
this.Name = this.Name + $" ({MA1Period}:{TBars.SelectStr(this.MA1DataSource)}) : ";
switch (MA2type) {
case 0:
MA2 = new SMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"SMA";
break;
case 1:
MA2 = new EMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"EMA";
break;
case 2:
MA2 = new WMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"WMA";
break;
case 3:
MA2 = new T3_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"T3";
break;
case 4:
MA2 = new SMMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"SMMA";
break;
case 5:
MA2 = new TRIMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"TRIMA";
break;
case 6:
MA2 = new DWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"DWMA";
break;
case 7:
MA2 = new FWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period);
this.Name += $"FWMA";
break;
case 8:
MA2 = new DEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"DEMA";
break;
case 9:
MA2 = new TEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"TEMA";
break;
case 10:
MA2 = new ALMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"ALMA";
break;
case 11:
MA2 = new HMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"HMA";
break;
case 12:
MA2 = new HEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"HEMA";
break;
case 13:
double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA2Period);
MA2 = new MAMA_Series(source: bars.Select(this.MA2DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
this.Name += $"MAMA";
break;
case 14:
MA2 = new KAMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"KAMA";
break;
case 15:
MA2 = new ZLEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"ZLEMA";
break;
default:
MA2 = new JMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
this.Name += $"JMA";
break;
}
this.Name += $"({MA2Period}:{TBars.SelectStr(this.MA2DataSource)}) ]";
sMA1 = new(MA1, SlopePeriod);
sMA2 = new(MA2, SlopePeriod);
sig1 = new(sMA1, 0);
sig2 = new(sMA2, 0);
int maxKeep = Math.Max(Math.Max(this.MA1Period, this.MA2Period), 100);
MA1.Keep = maxKeep;
MA2.Keep = maxKeep;
sMA1.Keep = maxKeep;
sMA2.Keep = maxKeep;
sig1.Keep = maxKeep;
sig2.Keep = maxKeep;
}
protected override void OnUpdate(UpdateArgs args) {
bool update = !(args.Reason == UpdateReason.NewBar ||
args.Reason == UpdateReason.HistoricalBar);
this.bars.Add(this.Time(),this.Open(), this.High(), this.Low(), this.Close(), this.Volume(), update);
this.SetValue(this.MA1[^1].v, lineIndex: 0);
this.SetValue(this.MA2[^1].v, lineIndex: 1);
Color s1Color= (this.sMA1[^1].v > 0)?Color.LimeGreen:Color.OrangeRed;
Color s2Color = (this.sMA2[^1].v > 0) ? Color.LimeGreen : Color.OrangeRed;
this.LinesSeries[0].SetMarker(0,s1Color);
this.LinesSeries[1].SetMarker(0,s2Color);
if (sig1[^1].v > 0 || sig2[^1].v > 0) {
if (sMA1[^1].v >= 0 && sMA2[^1].v >= 0 && LongTrades)
{
inLong = true;
this.BeginCloud(0, 1, Color.FromArgb(127, Color.DarkGreen));
this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v)? 0 : 1 ].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.UpArrow));
}
else {
this.EndCloud(0, 1, Color.Empty);
if (inShort && this.Count > 1)
{
this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v) ? 1 : 0].SetMarker(1, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.DownArrow));
inShort = false;
}
}
}
if (sig1[^1].v < 0 || sig2[^1].v < 0) {
if (sMA1[^1].v <= 0 && sMA2[^1].v <= 0 && ShortTrades)
{
inShort = true;
this.BeginCloud(0, 1, Color.FromArgb(100, Color.Red));
this.LinesSeries[(this.MA1[^1].v > this.MA2[^1].v) ? 0 : 1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.UpArrow));
}
else {
this.EndCloud(0, 1, Color.Empty);
if (inLong && this.Count > 1) {
LinesSeries[(this.MA1[^1].v > this.MA2[^1].v)?1:0].SetMarker(1, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.DownArrow));
inLong = false;
}
}
}
}
public override void OnPaintChart(PaintChartEventArgs args) {
base.OnPaintChart(args);
if (this.CurrentChart == null) {return;}
Graphics graphics = args.Graphics;
var mainWindow = this.CurrentChart.MainWindow;
int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
/*
int historycount = HistoricalData.Count;
int ymax = mainWindow.ClientRectangle.Height;
for (int i = leftIndex; i <= rightIndex; i++) {
int xi = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - 1 - i)));
int width = this.CurrentChart.BarsWidth;
int height = (int)((equity[i+historycount].v) *proportion);
Brush bb = Brushes.DarkSlateGray;
bb = (overunder[i+historycount].v>0 && LongTrades)? Brushes.Green : bb;
bb = (overunder[i + historycount].v < 0 && ShortTrades) ? Brushes.Red : bb;
graphics.FillRectangle(bb, xi, ymax - height, width, height);
}
*/
}
}
-97
View File
@@ -1,97 +0,0 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using TradingPlatform.BusinessLayer;
using TradingPlatform.BusinessLayer.Chart;
namespace QuanTAlib;
public class JMA_chart : Indicator {
#region Parameters
[InputParameter("Data source", 0, variants: new object[]
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
private int DataSource = 3;
[InputParameter("Smoothing period", 1, 1, 999, 1, 1)]
private int Period = 9;
[InputParameter("Volatility short", 2, 3, 50, 1, 1)]
private int Vshort = 10;
[InputParameter("Volatility long", 3, 20, 500, 1, 1)]
private int Vlong = 65;
[InputParameter("Phase", 4, -100, 100, 1, 2)]
private double Jphase;
#endregion Parameters
///////
private JMA_Series indicator;
///////
protected TBars bars;
protected IChartWindow mainWindow;
protected Graphics graphics;
protected int firstOnScreenBarIndex, lastOnScreenBarIndex;
protected HistoricalData History;
protected int HistPeriod;
public JMA_chart() {
Name = "JMA - Jurik Moving Avg";
Description = "Jurik Moving Average description";
AddLineSeries(lineName: "JMA", lineColor: Color.Yellow, lineWidth: 3,lineStyle: LineStyle.Solid);
SeparateWindow = false;
HistPeriod = Period;
}
protected override void OnInit() {
base.OnInit();
bars = new();
var dur1 = this.HistoricalData.FromTime;
var dur = this.HistoricalData.Period.Duration.TotalSeconds * (HistPeriod * 4); //seconds of two periods
this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
for (int i = this.History.Count - 1; i >= 0; i--) {
var rec = this.History[i, SeekOriginHistory.Begin];
bars.Add(rec.TimeLeft, rec[PriceType.Open],
rec[PriceType.High], rec[PriceType.Low],
rec[PriceType.Close], rec[PriceType.Volume]);
}
indicator = new(source: bars.Select(DataSource), period: Period, phase: Jphase, vshort: Vshort, vlong: Vlong, useNaN: true);
indicator.Keep = Math.Max(Period, 100);
}
protected override void OnUpdate(UpdateArgs args) {
base.OnUpdate(args);
bars.Add(Time(), GetPrice(PriceType.Open),
GetPrice(PriceType.High),
GetPrice(PriceType.Low),
GetPrice(PriceType.Close),
GetPrice(PriceType.Volume),
update: !(args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar));
this.SetValue(indicator[^1].v, lineIndex: 0);
}
public override void OnPaintChart(PaintChartEventArgs args) {
base.OnPaintChart(args);
if (this.CurrentChart == null) {
return;
}
graphics = args.Graphics;
mainWindow = this.CurrentChart.MainWindow;
DateTime leftTime = mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left);
DateTime rightTime = mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right);
firstOnScreenBarIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(leftTime);
lastOnScreenBarIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(rightTime));
}
}
-95
View File
@@ -1,95 +0,0 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class TrailingStop_chart : Indicator {
#region Parameters
[InputParameter("Period", 0, 1, 100, 1, 1)]
protected int _period = 30;
[InputParameter("Factor", 1, 1, 100, 0.1, 1)]
protected double _factor = 10;
[InputParameter("Long TS", 2)]
private bool _LongTS = true;
[InputParameter("Short TS", 3)]
private bool _ShortTS = true;
#endregion Parameters
///////
private HistoricalData History;
private TBars bars;
private ATR_Series _atr;
private double _tslineL, _ratchetL, _tslineS, _ratchetS;
///////
public TrailingStop_chart() {
Name = $"ATR Trailing Stop";
AddLineSeries(lineName: "TrailingATR Long", lineColor: Color.Yellow, lineWidth: 1,lineStyle: LineStyle.Dot);
AddLineSeries(lineName: "Ratchet Long", lineColor: Color.Yellow, lineWidth: 3, lineStyle: LineStyle.Solid);
AddLineSeries(lineName: "TrailingATR Short", lineColor: Color.Yellow, lineWidth: 1, lineStyle: LineStyle.Dot);
AddLineSeries(lineName: "Ratchet Short", lineColor: Color.Yellow, lineWidth: 3, lineStyle: LineStyle.Solid);
SeparateWindow = false;
}
protected override void OnInit() {
this.Name = $"Trailing Stop (ATR:{_period}, Mult:{_factor:f2})";
this.bars = new();
this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
for (int i = this.History.Count - 1; i >= 0; i--) {
var rec = this.History[i, SeekOriginHistory.Begin];
bars.Add(rec.TimeLeft, rec[PriceType.Open],
rec[PriceType.High], rec[PriceType.Low],
rec[PriceType.Close], rec[PriceType.Volume]);
}
_atr = new(source: bars, _period, useNaN: true);
_ratchetL = Double.NegativeInfinity;
_ratchetS = Double.PositiveInfinity;
this.LinesSeries[0].Visible = _LongTS;
this.LinesSeries[1].Visible = _LongTS;
this.LinesSeries[2].Visible = _ShortTS;
this.LinesSeries[3].Visible = _ShortTS;
}
protected override void OnUpdate(UpdateArgs args) {
bool update = !(args.Reason == UpdateReason.NewBar ||
args.Reason == UpdateReason.HistoricalBar);
this.bars.Add(this.Time(), this.GetPrice(PriceType.Open),
this.GetPrice(PriceType.High),
this.GetPrice(PriceType.Low),
this.GetPrice(PriceType.Close),
this.GetPrice(PriceType.Volume), update);
_tslineL = bars.High[^1].v - (_factor * _atr[^1].v);
_ratchetL = Math.Max(_tslineL,_ratchetL);
if (_ratchetL > bars.Low[^1].v) {
this.LinesSeries[1].SetMarker(0, new IndicatorLineMarker(Color.Yellow, bottomIcon: IndicatorLineMarkerIconType.DownArrow));
_ratchetL = _tslineL;
}
_tslineS = bars.High[^1].v + (_factor * _atr[^1].v);
_ratchetS = Math.Min(_tslineS, _ratchetS);
if (_ratchetS < bars.High[^1].v) {
this.LinesSeries[3].SetMarker(0, new IndicatorLineMarker(Color.Yellow, upperIcon: IndicatorLineMarkerIconType.UpArrow));
_ratchetS = _tslineS;
}
this.SetValue(_tslineL, lineIndex: 0);
this.SetValue(_ratchetL, lineIndex: 1);
this.SetValue(_tslineS, lineIndex: 2);
this.SetValue(_ratchetS, lineIndex: 3);
}
}
+32 -55
View File
@@ -1,74 +1,51 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32210.308
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Calculations", "Calculations\Calculations.csproj", "{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "quantalib", "lib\quantalib.csproj", "{584E06A9-CEB4-476A-85CC-6A8FF3974AE2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{D85FEBB4-B651-466F-85CC-FD902378D4D2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Indicators", "Indicators\Indicators.csproj", "{43AD2D78-024C-4D96-A70B-915CF519965A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MovingAverages", "quantower\averages\Averages.csproj", "{32CC09CC-26E3-4FCE-8932-C0513C4AD766}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Strategies", "Strategies\Strategies.csproj", "{FA526AF6-95BC-4AC0-8B46-A304FD06689D}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntheticVendor", "SyntheticVendor\SyntheticVendor.csproj", "{20B1B5F1-8C36-4668-B0AE-951C13AE197B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{47B6ACDB-F535-4FEB-9A0A-C427CAE8C28E}"
ProjectSection(SolutionItems) = preProject
docs\.nojekyll = docs\.nojekyll
docs\ALMA.md = docs\ALMA.md
docs\DEMA.md = docs\DEMA.md
docs\DWMA.md = docs\DWMA.md
docs\EMA.md = docs\EMA.md
docs\FMA.md = docs\FMA.md
docs\getting_started.ipynb = docs\getting_started.ipynb
docs\HEMA.md = docs\HEMA.md
docs\HMA.md = docs\HMA.md
docs\HWMA.md = docs\HWMA.md
docs\index.html = docs\index.html
docs\indicators.md = docs\indicators.md
docs\JMA.md = docs\JMA.md
docs\KAMA.md = docs\KAMA.md
docs\LICENSE = docs\LICENSE
docs\MAMA.md = docs\MAMA.md
docs\QA.md = docs\QA.md
docs\readme.md = docs\readme.md
docs\RMA.md = docs\RMA.md
docs\SMA.md = docs\SMA.md
docs\SMMA.md = docs\SMMA.md
docs\T3.md = docs\T3.md
docs\TEMA.md = docs\TEMA.md
docs\TRIMA.md = docs\TRIMA.md
docs\WMA.md = docs\WMA.md
docs\ZLEMA.md = docs\ZLEMA.md
docs\_sidebar.md = docs\_sidebar.md
EndProjectSection
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "quantower", "quantower", "{A8D9AE68-24E3-476C-BB98-244541BB4B43}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Statistics", "quantower\Statistics\Statistics.csproj", "{B6D3EB11-63B6-430F-B526-E1981B3D8214}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Release|Any CPU.Build.0 = Release|Any CPU
{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Release|Any CPU.Build.0 = Release|Any CPU
{43AD2D78-024C-4D96-A70B-915CF519965A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{43AD2D78-024C-4D96-A70B-915CF519965A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{43AD2D78-024C-4D96-A70B-915CF519965A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{43AD2D78-024C-4D96-A70B-915CF519965A}.Release|Any CPU.Build.0 = Release|Any CPU
{FA526AF6-95BC-4AC0-8B46-A304FD06689D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA526AF6-95BC-4AC0-8B46-A304FD06689D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA526AF6-95BC-4AC0-8B46-A304FD06689D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA526AF6-95BC-4AC0-8B46-A304FD06689D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E5592DC2-0542-45B2-A0CF-C6B1EDC72B87}
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{584E06A9-CEB4-476A-85CC-6A8FF3974AE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{584E06A9-CEB4-476A-85CC-6A8FF3974AE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{584E06A9-CEB4-476A-85CC-6A8FF3974AE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{584E06A9-CEB4-476A-85CC-6A8FF3974AE2}.Release|Any CPU.Build.0 = Release|Any CPU
{D85FEBB4-B651-466F-85CC-FD902378D4D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D85FEBB4-B651-466F-85CC-FD902378D4D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D85FEBB4-B651-466F-85CC-FD902378D4D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D85FEBB4-B651-466F-85CC-FD902378D4D2}.Release|Any CPU.Build.0 = Release|Any CPU
{32CC09CC-26E3-4FCE-8932-C0513C4AD766}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32CC09CC-26E3-4FCE-8932-C0513C4AD766}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32CC09CC-26E3-4FCE-8932-C0513C4AD766}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32CC09CC-26E3-4FCE-8932-C0513C4AD766}.Release|Any CPU.Build.0 = Release|Any CPU
{20B1B5F1-8C36-4668-B0AE-951C13AE197B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{20B1B5F1-8C36-4668-B0AE-951C13AE197B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{20B1B5F1-8C36-4668-B0AE-951C13AE197B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20B1B5F1-8C36-4668-B0AE-951C13AE197B}.Release|Any CPU.Build.0 = Release|Any CPU
{B6D3EB11-63B6-430F-B526-E1981B3D8214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B6D3EB11-63B6-430F-B526-E1981B3D8214}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6D3EB11-63B6-430F-B526-E1981B3D8214}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6D3EB11-63B6-430F-B526-E1981B3D8214}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{B6D3EB11-63B6-430F-B526-E1981B3D8214} = {A8D9AE68-24E3-476C-BB98-244541BB4B43}
EndGlobalSection
EndGlobal
+15
View File
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AlgoType>Vendor</AlgoType>
</PropertyGroup>
<ItemGroup>
<Reference Include="TradingPlatform.BusinessLayer">
<HintPath>..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
</Reference>
<None Include="..\.github\TradingPlatform.BusinessLayer.xml">
<Link>TradingPlatform.BusinessLayer.xml</Link>
</None>
</ItemGroup>
</Project>
-155
View File
@@ -1,155 +0,0 @@
using Xunit;
using System;
using QuanTAlib;
namespace Basics;
#nullable disable
public class Indicators
{
private static Type[] maSeriesTypes = new Type[]
{
typeof(SMA_Series),
typeof(EMA_Series),
typeof(DEMA_Series),
typeof(TEMA_Series),
typeof(WMA_Series),
typeof(ALMA_Series),
typeof(DWMA_Series),
typeof(FWMA_Series),
typeof(HMA_Series),
typeof(ZLEMA_Series),
typeof(RMA_Series),
typeof(HEMA_Series),
typeof(JMA_Series),
typeof(CUSUM_Series),
typeof(SMMA_Series),
typeof(T3_Series),
typeof(KAMA_Series),
typeof(TRIMA_Series),
typeof(MAMA_Series),
typeof(HWMA_Series),
};
[Theory]
[MemberData(nameof(MASeriesData))]
public void Name_exists(Type classType)
{
TSeries data = new("Data") {1,2,3};
var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries;
Assert.NotEmpty(MA_Series.Name);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Series_Length(Type classType)
{
GBM_Feed feed = new(1000);
TSeries data = feed.OHLC4;
var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries;
Assert.Equal(1000, MA_Series.Count);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Return_data(Type classType)
{
TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries;
var result = MA_Series.Add(20);
Assert.Equal(result.v, MA_Series.Last.v);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Update(Type classType)
{
TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries;
var pre_update = MA_Series.Last.v;
double pre_data = data.Last.v;
data.Add(20, true);
data.Add(pre_data, true);
Assert.Equal(pre_update, MA_Series.Last.v);
Assert.Equal(data.Count, MA_Series.Count);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Period_zero(Type classType)
{
GBM_Feed feed = new(100);
TSeries data = feed.OHLC4;
var MA_Series = Activator.CreateInstance(classType, data, 0, false) as TSeries;
Assert.Equal(data.Count, MA_Series.Count);
Assert.False(double.IsNaN(MA_Series.Last.v));
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Reset(Type classType)
{
GBM_Feed feed = new(10);
TSeries data = feed.OHLC4;
var MA_Series = Activator.CreateInstance(classType, data, 10, false) as TSeries;
MA_Series.Reset();
data.Add(0);
Assert.Equal(data.Last.v, MA_Series.Last.v);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Period_one(Type classType)
{
GBM_Feed feed = new(100);
TSeries data = feed.OHLC4;
var MA_Series = Activator.CreateInstance(classType, data, 1, false) as TSeries;
Assert.InRange(MA_Series.Last.v - data.Last.v, -10e-6, 10e-6);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void NaN_test(Type classType)
{
GBM_Feed feed = new(100);
TSeries data = feed.OHLC4;
var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries;
Assert.True(double.IsNaN(MA_Series[0].v));
Assert.True(double.IsNaN(MA_Series[8].v));
Assert.False(double.IsNaN(MA_Series[9].v));
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Edge_numbers(Type classType)
{
TSeries data = new() { double.Epsilon, double.PositiveInfinity, double.MaxValue, double.NegativeInfinity };
var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries;
Assert.Equal(4, MA_Series.Count);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void handling_NaN(Type classType) {
TSeries data = new("Name") { 1, 2, 3, 4, 5, 6, double.NaN, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries;
Assert.False(double.IsNaN(MA_Series.Last.v));
}
public static IEnumerable<object[]> MASeriesData()
{
foreach (var type in maSeriesTypes)
{
yield return new object[] { type };
}
}
}
#nullable restore
-160
View File
@@ -1,160 +0,0 @@
using Xunit;
using System;
using System.Runtime.InteropServices;
using QuanTAlib;
namespace Basics;
#nullable disable
public class Oscillators
{
private static Type[] maSeriesTypes = new[]
{
typeof(BIAS_Series),
typeof(MAX_Series),
typeof(MIN_Series),
typeof(MIDPOINT_Series),
typeof(ZL_Series),
typeof(DECAY_Series),
typeof(ENTROPY_Series),
typeof(KURTOSIS_Series),
typeof(MAD_Series),
typeof(MAPE_Series),
typeof(MAE_Series),
typeof(MSE_Series),
typeof(SDEV_Series),
typeof(SMAPE_Series),
typeof(WMAPE_Series),
typeof(SSDEV_Series),
typeof(VAR_Series),
typeof(SVAR_Series),
typeof(MEDIAN_Series),
typeof(ZSCORE_Series),
typeof(CMO_Series),
typeof(RSI_Series),
typeof(TRIX_Series),
typeof(BBANDS_Series),
};
[Theory]
[MemberData(nameof(MASeriesData))]
public void Name_exists(Type classType)
{
TSeries data = new("Data") {1,2,3};
var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries;
Assert.NotEmpty(MA_Series.Name);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Series_Length(Type classType)
{
GBM_Feed feed = new(1000);
TSeries data = feed.OHLC4;
var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries;
Assert.Equal(1000, MA_Series.Count);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Return_data(Type classType)
{
TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries;
var result = MA_Series.Add(20);
Assert.Equal(result.v, MA_Series.Last.v);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Update(Type classType)
{
TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries;
var pre_update = MA_Series.Last.v;
double pre_data = data.Last.v;
data.Add(20, true);
data.Add(pre_data, true);
Assert.Equal(pre_update, MA_Series.Last.v);
Assert.Equal(data.Count, MA_Series.Count);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Period_zero(Type classType)
{
GBM_Feed feed = new(100);
TSeries data = feed.OHLC4;
var MA_Series = Activator.CreateInstance(classType, data, 0, false) as TSeries;
Assert.Equal(data.Count, MA_Series.Count);
Assert.False(double.IsNaN(MA_Series.Last.v));
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Reset(Type classType)
{
GBM_Feed feed = new(10);
TSeries data = feed.OHLC4;
var MA_Series = Activator.CreateInstance(classType, data, 10, false) as TSeries;
MA_Series.Reset();
data.Add(1);
Assert.False(double.IsNaN(MA_Series.Last.v));
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Period_one(Type classType)
{
GBM_Feed feed = new(100);
TSeries data = feed.OHLC4;
var MA_Series = Activator.CreateInstance(classType, data, 1, false) as TSeries;
Assert.False(double.IsNaN(MA_Series[^1].v));
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void NaN_test(Type classType)
{
GBM_Feed feed = new(100);
TSeries data = feed.OHLC4;
var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries;
Assert.True(double.IsNaN(MA_Series[0].v));
Assert.True(double.IsNaN(MA_Series[8].v));
Assert.False(double.IsNaN(MA_Series[9].v));
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Edge_numbers(Type classType)
{
TSeries data = new() { double.Epsilon, double.PositiveInfinity, double.MaxValue, double.NegativeInfinity };
var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries;
Assert.Equal(4, MA_Series.Count);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void handling_NaN(Type classType) {
TSeries data = new("Name") { 1, 2, 3, 4, 5, 6, double.NaN, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries;
Assert.False(double.IsNaN(MA_Series.Last.v));
}
public static IEnumerable<object[]> MASeriesData()
{
foreach (var type in maSeriesTypes)
{
yield return new object[] { type };
}
}
}
#nullable restore
-96
View File
@@ -1,96 +0,0 @@
using Xunit;
using System;
using System.Runtime.InteropServices;
using QuanTAlib;
namespace Basics;
#nullable disable
public class TBars
{
private static Type[] maSeriesTypes = new Type[]
{
typeof(ATR_Series),
typeof(ATRP_Series),
typeof(TR_Series),
typeof(ADL_Series),
typeof(CCI_Series),
typeof(OBV_Series),
typeof(ADOSC_Series),
typeof(MIDPRICE_Series),
};
[Theory]
[MemberData(nameof(MASeriesData))]
public void Name_exists(Type classType)
{
GBM_Feed data = new(10);
var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
Assert.NotEmpty(MA_Series.Name);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Series_Length(Type classType)
{
GBM_Feed data = new(1000);
var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
Assert.Equal(1000, MA_Series.Count);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Return_data(Type classType)
{
GBM_Feed data = new(10);
var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
var result = MA_Series.Add((DateTime.Today, 1,2,3,4,5));
Assert.Equal(result.v, MA_Series.Last.v);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Update(Type classType)
{
GBM_Feed data = new(10);
var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
var pre_update = MA_Series.Last;
var pre_data = data.Last;
data.Add((DateTime.Today, 1, 2, 3, 4, 5), true);
data.Add(pre_data, true);
Assert.Equal(pre_update.v, MA_Series.Last.v);
Assert.Equal(data.Count, MA_Series.Count);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Reset(Type classType)
{
GBM_Feed data = new(10);
var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
MA_Series.Reset();
data.Add();
Assert.False(double.IsNaN(MA_Series.Last.v));
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Period_default(Type classType) {
GBM_Feed data = new(100);
var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
Assert.False(double.IsNaN(MA_Series.Last.v));
}
public static IEnumerable<object[]> MASeriesData()
{
foreach (var type in maSeriesTypes)
{
yield return new object[] { type };
}
}
}
#nullable restore
-64
View File
@@ -1,64 +0,0 @@
using Xunit;
using System;
using QuanTAlib;
namespace Pairs;
public class DIV_Test
{
[Fact]
public void DIVSeriesSeries_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 15 };
TSeries b = new() { 5, 4, 3, 2, 1, 3 };
DIV_Series c = new(a, b);
Assert.Equal(5, c.Last().v);
}
[Fact]
public void DIVSeriesDouble_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 15.0 };
DIV_Series c = new(a, 0);
Assert.Equal(double.PositiveInfinity, c.Last().v);
}
[Fact]
public void DIVDoubleSeries_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 3.0 };
DIV_Series c = new(12.0, a);
Assert.Equal(4.0, c.Last().v);
}
[Fact]
public void DIVEventing_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
TSeries b = new() { 5, 4, 3, 2, 1, 0 };
DIV_Series c = new(a, b);
a.Add(12.0);
b.Add(2);
Assert.Equal(6.0, c.Last().v);
}
[Fact]
public void DIVUpdatewDouble_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 15 };
double b = 2;
DIV_Series c = new(a, b);
a.Add(10, true);
Assert.Equal(5, c.Last().v);
}
[Fact]
public void DIVUpdating_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
TSeries b = new() { 5, 4, 3, 2, 1, 1 };
DIV_Series c = new(a, b);
a.Add(10, true);
b.Add(2, true);
Assert.Equal(5, c.Last().v);
}
}
-64
View File
@@ -1,64 +0,0 @@
using Xunit;
using System;
using QuanTAlib;
namespace Pairs;
public class MUL_Test
{
[Fact]
public void MULSeriesSeries_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
TSeries b = new() { 5, 4, 3, 2, 1, 1 };
MUL_Series c = new(a, b);
Assert.Equal(5, c.Last().v);
}
[Fact]
public void MULSeriesDouble_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
MUL_Series c = new(a, 10.0);
Assert.Equal(50, c.Last().v);
}
[Fact]
public void MULDoubleSeries_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
MUL_Series c = new(5.0, a);
Assert.Equal(25, c.Last().v);
}
[Fact]
public void MULEventing_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
TSeries b = new() { 5, 4, 3, 2, 1, 0 };
MUL_Series c = new(a, b);
a.Add(2);
b.Add(5);
Assert.Equal(10, c.Last().v);
}
[Fact]
public void MULUpdateDouble_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
double b = 10;
MUL_Series c = new(a, b);
a.Add(2, true);
Assert.Equal(20, c.Last().v);
}
[Fact]
public void MULUpdating_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
TSeries b = new() { 5, 4, 3, 2, 1, 0 };
MUL_Series c = new(a, b);
a.Add(10, true);
b.Add(10, true);
Assert.Equal(100, c.Last().v);
}
}
-64
View File
@@ -1,64 +0,0 @@
using Xunit;
using System;
using QuanTAlib;
namespace Pairs;
public class SUB_Test
{
[Fact]
public void SUBSeriesSeries_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
TSeries b = new() { 5, 4, 3, 2, 1, 1 };
SUB_Series c = new(a, b);
Assert.Equal(4, c.Last().v);
}
[Fact]
public void SUBSeriesDouble_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 15.0 };
SUB_Series c = new(a, 10.0);
Assert.Equal(5.0, c.Last().v);
}
[Fact]
public void SUBDoubleSeries_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 15.0 };
SUB_Series c = new(10.0, a);
Assert.Equal(-5.0, c.Last().v);
}
[Fact]
public void SUBEventing_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
TSeries b = new() { 5, 4, 3, 2, 1, 0 };
SUB_Series c = new(a, b);
a.Add(7.0);
b.Add(2);
Assert.Equal(5.0, c.Last().v);
}
[Fact]
public void SUBUpdatewDouble_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 15 };
double b = 10;
SUB_Series c = new(a, b);
a.Add(1, true);
Assert.Equal(-9, c.Last().v);
}
[Fact]
public void SUBUpdating_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
TSeries b = new() { 5, 4, 3, 2, 1, 1 };
SUB_Series c = new(a, b);
a.Add(10, true);
b.Add(0, true);
Assert.Equal(10, c.Last().v);
}
}
-112
View File
@@ -1,112 +0,0 @@
using Xunit;
using System;
using QuanTAlib;
namespace Bars;
public class TBars_Test
{
[Fact]
public void InsertingTuple()
{
TBars s = new() { (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, c: Double.NegativeInfinity, v: Double.PositiveInfinity) };
var tup = (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue,
c: Double.NegativeInfinity, v: Double.PositiveInfinity);
Assert.Equal(tup, s[^1]);
}
[Fact]
public void Casting_Parameters()
{
TBars s = new()
{
{ DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false }
};
Assert.Equal(0.1, s[^1].o);
Assert.Equal(1.1, s[^1].h);
Assert.Equal(2.1, s[^1].l);
Assert.Equal(3.1, s[^1].c);
Assert.Equal(4.1, s[^1].v);
Assert.Equal(DateTime.Today, s[^1].t);
Assert.Single(s);
}
[Fact]
public void Updating_Value()
{
TBars s = new()
{
{ DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 }
};
s.Add(DateTime.Today, 1.0, 1.0, 1.0, 1.0, 1.0, update: false);
s.Add(DateTime.Today, 0.0, 0.0, 0.0, 0.0, 0.0, update: true);
Assert.Equal(0.0, s[^1].o);
Assert.Equal(0.0, s[^1].h);
Assert.Equal(0.0, s[^1].l);
Assert.Equal(0.0, s[^1].c);
Assert.Equal(0.0, s[^1].v);
Assert.Equal(2, s.Count);
}
[Fact]
public void Extracting_TSeries()
{
TBars s = new()
{
{ DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 },
{ DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1 }
};
TSeries t = s.Open;
Assert.Equal(t.t, s.Open.t);
Assert.Equal(t.v, s.Open.v);
t = s.High;
Assert.Equal(t.t, s.High.t);
Assert.Equal(t.v, s.High.v);
t = s.Low;
Assert.Equal(t.t, s.Low.t);
Assert.Equal(t.v, s.Low.v);
t = s.Close;
Assert.Equal(t.t, s.Close.t);
Assert.Equal(t.v, s.Close.v);
t = s.Volume;
Assert.Equal(t.t, s.Volume.t);
Assert.Equal(t.v, s.Volume.v);
t = s.HL2;
Assert.Equal(t.t, s.HL2.t);
Assert.Equal(t.v, s.HL2.v);
t = s.OC2;
Assert.Equal(t.t, s.OC2.t);
Assert.Equal(t.v, s.OC2.v);
t = s.OHL3;
Assert.Equal(t.t, s.OHL3.t);
Assert.Equal(t.v, s.OHL3.v);
t = s.HLC3;
Assert.Equal(t.t, s.HLC3.t);
Assert.Equal(t.v, s.HLC3.v);
t = s.OHLC4;
Assert.Equal(t.t, s.OHLC4.t);
Assert.Equal(t.v, s.OHLC4.v);
t = s.HLCC4;
Assert.Equal(t.t, s.HLCC4.t);
Assert.Equal(t.v, s.HLCC4.v);
}
[Fact]
public void Broadcasting_Events()
{
TBars s = new() { (DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1) };
TSeries t = new();
s.Close.Pub += t.Sub;
s.Add(DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false);
Assert.Equal(s.Close.v, t.v);
Assert.Equal(s.Close.Count, t.Count);
}
}
+23 -33
View File
@@ -1,45 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net7.0</TargetFrameworks>
<LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyVersion>0.2.1.0</AssemblyVersion>
<FileVersion>0.2.1.0</FileVersion>
<InformationalVersion>0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d</InformationalVersion>
<Version>0.2.1-dev.2</Version>
<NoWarn>$(NoWarn);NETSDK1057</NoWarn>
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>QuanTAlib.Tests</RootNamespace>
<AssemblyName>QuanTAlib.Tests</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="pythonnet" Version="3.0.1" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0-preview-20230223-05" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="Skender.Stock.Indicators" Version="2.5.0" />
<PackageReference Include="TALib.NETCore" Version="0.4.4" />
<PackageReference Include="Skender.Stock.Indicators" Version="3.0.0-preview1014-0015" />
<PackageReference Include="Tulip.NETCore" Version="0.8.0.1" />
<PackageReference Include="System.Text.Json" Version="8.0.0-preview.3.23174.8" />
<PackageReference Include="Trady.Analysis" Version="3.2.8" />
<!--
<PackageReference Include="quantconnect.indicators" Version="2.5.16573" />
<PackageReference Include="stocksharp.algo" Version="5.0.193" />
<PackageReference Include="OoplesFinance.StockIndicators" Version="1.0.53" />
-->
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Calculations\Calculations.csproj" />
</ItemGroup>
<ItemGroup>
<None Remove="Python.Included" />
<None Remove="pythonnet" />
<None Remove="Tulip.NETCore" />
<None Remove="System.Text.Json" />
</ItemGroup>
<ItemGroup>
<Folder Include="Statistics\" />
<ProjectReference Include="..\lib\quantalib.csproj" />
</ItemGroup>
</Project>
-416
View File
@@ -1,416 +0,0 @@
using Xunit;
using System;
using QuanTAlib;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using Python.Runtime;
namespace Validations;
public class PandasTA : IDisposable {
private bool disposed = false;
private readonly GBM_Feed bars;
private readonly Random rnd = new();
private readonly int period, skip;
private readonly int digits;
private readonly dynamic np;
private readonly dynamic ta;
private readonly dynamic pd;
private readonly dynamic df;
public PandasTA() {
bars = new GBM_Feed(5000, 0.8, 0.0);
period = rnd.Next(28) + 3;
skip = period + 50;
digits = 8;
var pythonDLL = PythonLibrary.Locate();
Runtime.PythonDLL = pythonDLL;
PythonEngine.Initialize();
np = Py.Import("numpy");
pd = Py.Import("pandas");
ta = Py.Import("pandas_ta");
string[] cols = {"open", "high", "low", "close", "volume"};
var ary = new double[bars.Count, 5];
for (var i = 0; i < bars.Count; i++) {
ary[i, 0] = bars.Open[i].v;
ary[i, 1] = bars.High[i].v;
ary[i, 2] = bars.Low[i].v;
ary[i, 3] = bars.Close[i].v;
ary[i, 4] = bars.Volume[i].v;
}
df = ta.DataFrame(data: np.array(ary), index: np.array(bars.Close.t), columns: np.array(cols));
}
public void Dispose() {
Dispose(true);
PythonEngine.Shutdown();
GC.SuppressFinalize(this);
}
~PandasTA() {
Dispose(false);
}
protected virtual void Dispose(bool disposing) {
if (!disposed) {
disposed = true;
}
}
[Fact]
private void ADL() {
ADL_Series QL = new(bars);
var pta = df.ta.ad(high: df.high, low: df.low, close: df.close, volume: df.volume);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void BBANDS() {
BBANDS_Series QL = new(bars.Close, period);
var pta = df.ta.bbands(close: df.close, length: period).to_numpy();
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL.Lower[i].v;
var PanTA_item = (double) pta[i][0]; //lower
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
QL_item = QL.Mid[i].v;
PanTA_item = (double) pta[i][1]; //mid
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
QL_item = QL.Upper[i].v;
PanTA_item = (double) pta[i][2]; //upper
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void BIAS() {
BIAS_Series QL = new(bars.Close, period, false);
var pta = df.ta.bias(close: df.close, length: period);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void CCI() {
CCI_Series QL = new(bars, period, false);
var pta = df.ta.cci(close: df.close, length: period);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void DEMA() {
DEMA_Series QL = new(bars.Close, period, false);
var pta = df.ta.dema(close: df.close, length: period);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void EMA() {
EMA_Series QL = new(bars.Close, period, false);
var pta = df.ta.ema(close: df.close, length: period);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void ENTROPY() {
ENTROPY_Series QL = new(bars.Close, period, false);
var pta = df.ta.entropy(close: df.close, length: period);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void HL2() {
var pta = df.ta.hl2(high: df.high, low: df.low);
for (var i = bars.HL2.Length - 1; i > skip; i--) {
var QL_item = bars.HL2[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void HLC3() {
var pta = df.ta.hlc3(high: df.high, low: df.low, close: df.close);
for (var i = bars.HLC3.Length; i > skip; i--) {
var QL_item = bars.HLC3[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void HMA() {
HMA_Series QL = new(bars.Close, period, false);
var pta = df.ta.hma(close: df.close, length: period);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void KURTOSIS() {
KURTOSIS_Series QL = new(bars.Close, period, false);
var pta = df.ta.kurtosis(close: df.close, length: period);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void MACD() {
MACD_Series QL = new(bars.Close, 26, 12, 9, false);
var pta = df.ta.macd(close: df.close).to_numpy();
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1][0];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
QL_item = QL.Signal[i - 1].v;
PanTA_item = (double) pta[i - 1][2];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void MAD() {
MAD_Series QL = new(bars.Close, period, false);
var pta = df.ta.mad(close: df.close, length: period);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void MEDIAN() {
MEDIAN_Series QL = new(bars.Close, period);
var pta = df.ta.median(close: df.close, length: period);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void OBV() {
OBV_Series QL = new(bars);
var pta = df.ta.obv(close: df.close, volume: df.volume);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void OHLC4() {
var pta = df.ta.ohlc4(open: df.open, high: df.high, low: df.low, close: df.close);
for (var i = bars.OHLC4.Length; i > skip; i--) {
var QL_item = bars.OHLC4[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void SDEV() {
SDEV_Series QL = new(bars.Close, period, false);
var pta = df.ta.stdev(close: df.close, length: period, ddof: 0);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void SMA() {
SMA_Series QL = new(bars.Close, period, false);
var pta = df.ta.sma(close: df.close, length: period);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void SSDEV() {
SSDEV_Series QL = new(bars.Close, period, false);
var pta = df.ta.stdev(close: df.close, length: period, ddof: 1);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void SVARIANCE() {
SVAR_Series QL = new(bars.Close, period);
var pta = df.ta.variance(close: df.close, length: period, ddof: 1);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void TEMA() {
TEMA_Series QL = new(bars.Close, period, false);
var pta = df.ta.tema(close: df.close, length: period);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void TR() {
TR_Series QL = new(bars);
var pta = df.ta.true_range(high: df.high, low: df.low, close: df.close);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void TRIMA() {
// TODO: return length to variable length (period) when Pandas-TA fixes trima to calculate even periods right
TRIMA_Series QL = new(bars.Close, 11);
var pta = df.ta.trima(close: df.close, length: 11);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void VARIANCE() {
VAR_Series QL = new(bars.Close, period);
var pta = df.ta.variance(close: df.close, length: period, ddof: 0);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void WMA() {
WMA_Series QL = new(bars.Close, period, false);
var pta = df.ta.wma(close: df.close, length: period);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
private void ZSCORE() {
ZSCORE_Series QL = new(bars.Close, period, false);
var pta = df.ta.zscore(close: df.close, length: period, ddof: 0);
for (var i = QL.Length - 1; i > skip; i--) {
var QL_item = QL[i - 1].v;
var PanTA_item = (double) pta[i - 1];
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
}
public static class PythonLibrary {
public static string Locate() {
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
string[] paths = Environment.GetEnvironmentVariable("PATH")?.Split(';') ?? Array.Empty<string>();
foreach (string path in paths) {
string[] pythonDLLs = Directory.GetFiles(path, "python3*.dll");
if (pythonDLLs.Length > 0) {
foreach (string item in pythonDLLs) {
if (!item.EndsWith("python3.dll", StringComparison.OrdinalIgnoreCase)) {
return item;
}
}
}
}
throw new FileNotFoundException("Python library not found in PATH");
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
return "/usr/lib/x86_64-linux-gnu/libpython3.10.so";
/*
List<string> pythonLibraries = new List<string>();
List<string> directoriesToSearch = new List<string> { "/home/runner/.local/lib" }; // Add more directories as needed
string filePattern = "libpython3.*.so";
SearchFiles(directoriesToSearch, filePattern, pythonLibraries);
if (pythonLibraries.Count > 0) {
return pythonLibraries[0];
}
else {
throw new FileNotFoundException("Python library not found");
}
*/
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
throw new NotSupportedException("Not supported yet");
}
else { throw new NotSupportedException("Unsupported operating system"); }
}
static void SearchFiles(List<string> directoriesToSearch, string filePattern, List<string> foundFiles)
{
foreach (string directory in directoriesToSearch)
{
if (Directory.Exists(directory))
{
try
{
string[] files = Directory.GetFiles(directory, filePattern, SearchOption.AllDirectories);
foundFiles.AddRange(files);
}
catch (Exception e)
{
Console.WriteLine("Error searching in directory: " + directory + " - " + e.Message);
}
}
}
}
}
-486
View File
@@ -1,486 +0,0 @@
using System;
using QuanTAlib;
using Skender.Stock.Indicators;
using Xunit;
namespace Validations;
public class Skender
{
private readonly GBM_Feed bars;
private readonly Random rnd = new();
private readonly int period, digits, skip;
private readonly IEnumerable<Quote> quotes;
public Skender()
{
bars = new(Bars: 10000, Volatility: 0.5, Drift: 0.0, Precision: 2);
period = rnd.Next(30) + 5;
digits = 6; //minimizing rounding errors in type conversions
skip = period+2;
quotes = bars.Select(q => new Quote
{
Date = q.t,
Open = (decimal)q.o,
High = (decimal)q.h,
Low = (decimal)q.l,
Close = (decimal)q.c,
Volume = (decimal)q.v
});
}
/*
[Fact]
public void ADL()
{
ADL_Series QL = new(bars);
var SK = quotes.GetAdl().Select(i => i.Adl);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1)!;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
*/
[Fact]
public void ALMA()
{
ALMA_Series QL = new(bars.Close, period, useNaN: false);
var SK = quotes.GetAlma(period).Select(i => i.Alma.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void ATR()
{
ATR_Series QL = new(bars, period:period,useNaN: false);
var SK = quotes.GetAtr(period).Select(i => i.Atr.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void ATRP()
{
ATRP_Series QL = new(bars, period, false);
var SK = quotes.GetAtr(period).Select(i => i.Atrp.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void BBANDS()
{
BBANDS_Series QL = new(bars.Close, period, 2.0, useNaN: false);
var SK = quotes.GetBollingerBands(period, 2.0);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL.Mid[i - 1].v;
double SK_item = SK.ElementAt(i - 1).Sma!.Value;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
QL_item = QL.Upper[i - 1].v;
SK_item = SK.ElementAt(i - 1).UpperBand!.Value;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
QL_item = QL.Lower[i - 1].v;
SK_item = SK.ElementAt(i - 1).LowerBand!.Value;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
QL_item = QL.Bandwidth[i - 1].v;
SK_item = SK.ElementAt(i - 1).Width!.Value;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
QL_item = QL.PercentB[i - 1].v;
SK_item = SK.ElementAt(i - 1).PercentB!.Value;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
QL_item = QL.Zscore[i - 1].v;
SK_item = SK.ElementAt(i - 1).ZScore!.Value;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void CCI()
{
CCI_Series QL = new(bars, period, false);
var SK = quotes.GetCci(period).Select(i => i.Cci.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void CMO()
{
CMO_Series QL = new(bars.Close, period, false);
var SK = quotes.GetCmo(period).Select(i => i.Cmo.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void CORR()
{
CORR_Series QL = new(bars.High, bars.Low, period, false);
var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period).Select(i => i.Correlation.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void COVAR()
{
COVAR_Series QL = new(bars.High, bars.Low, period, false);
var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period).Select(i => i.Covariance.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void DEMA()
{
DEMA_Series QL = new(bars.Close, period, false, useSMA: true);
var SK = quotes.GetDema(period).Select(i => i.Dema.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void EMA()
{
EMA_Series QL = new(bars.Close, period, false);
var SK = quotes.GetEma(lookbackPeriods: period).Select(i => i.Ema.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void HL2()
{
TSeries QL = bars.HL2;
var SK = quotes.GetBaseQuote(CandlePart.HL2).ToList();
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1).Value;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void HLC3()
{
TSeries QL = bars.HLC3;
var SK = quotes.GetBaseQuote(CandlePart.HLC3).ToList();
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1).Value;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void HMA()
{
HMA_Series QL = new(bars.Close, period, useNaN: false);
var SK = quotes.GetHma(period).Select(i => i.Hma.Null2NaN()!);
for (int i = QL.Length; i > skip*2; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void KAMA()
{
// TODO: check precision of KAMA()
KAMA_Series QL = new(bars.Close, period, useNaN: false);
var SK = quotes.GetKama(period).Select(i => i.Kama.Null2NaN()!);
for (int i = QL.Length; i > skip+2; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void SLOPE()
{
SLOPE_Series QL = new(bars.Close, period, useNaN: false);
var SK = quotes.GetSlope(period);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = (double)SK.ElementAt(i - 1).Slope!;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
QL_item = QL.Intercept[i - 1].v;
SK_item = (double)SK.ElementAt(i - 1).Intercept!;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
QL_item = QL.RSquared[i - 1].v;
SK_item = (double)SK.ElementAt(i - 1).RSquared!;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
QL_item = QL.StdDev[i - 1].v;
SK_item = (double)SK.ElementAt(i - 1).StdDev!;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void MACD()
{
MACD_Series QL = new(bars.Close, 26, 12, 9, useNaN: false);
var SK = quotes.GetMacd(12, 26, 9);
for (int i = QL.Length; i > 27; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1).Macd.Null2NaN()!;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
//QL_item = QL.Signal[i - 1].v;
//SK_item = SK.ElementAt(i - 1).Signal.Null2NaN()!;
//Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void MAD()
{
MAD_Series QL = new(bars.Close, period, false);
var SK = quotes.GetSmaAnalysis(period).Select(i => i.Mad.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void MAMA()
{
MAMA_Series QL = new(bars.HL2, fastlimit: 0.5, slowlimit: 0.05);
var SK = quotes.GetMama(fastLimit: 0.5, slowLimit: 0.05);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1).Mama.Null2NaN()!;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
QL_item = QL.Fama[i - 1].v;
SK_item = SK.ElementAt(i - 1).Fama.Null2NaN()!;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void MAPE()
{
MAPE_Series QL = new(bars.Close, period, false);
var SK = quotes.GetSmaAnalysis(period).Select(i => i.Mape.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void MSE()
{
MSE_Series QL = new(bars.Close, period, false);
var SK = quotes.GetSmaAnalysis(period).Select(i => i.Mse.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void OBV()
{
OBV_Series QL = new(bars, period, false);
var SK = quotes.GetObv(period).Select(i => i.Obv!);
for (int i = QL.Length; i > skip; i--) {
double QL_item = QL.Last().v;
// adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB
double SK_item = SK.Last()! + (double)quotes.First().Volume!;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void OC2()
{
TSeries QL = bars.OC2;
var SK = quotes.GetBaseQuote(CandlePart.OC2).ToList();
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1).Value;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void OHL3()
{
TSeries QL = bars.OHL3;
var SK = quotes.GetBaseQuote(CandlePart.OHL3).ToList();
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1).Value;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void OHLC4()
{
TSeries QL = bars.OHLC4;
var SK = quotes.GetBaseQuote(CandlePart.OHLC4).ToList();
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1).Value;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void RSI()
{
RSI_Series QL = new(bars.Close, period, useNaN: false);
var SK = quotes.GetRsi(period).Select(i => i.Rsi.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void SDEV()
{
SDEV_Series QL = new(bars.Close, period, useNaN: false);
var SK = quotes.GetStdDev(period).Select(i => i.StdDev.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void SMA()
{
SMA_Series QL = new(bars.Close, period, false);
var SK = quotes.GetSma(period).Select(i => i.Sma.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void SMMA()
{
SMMA_Series QL = new(bars.Close, period, useNaN: false);
var SK = quotes.GetSmma(period).Select(i => i.Smma.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void T3()
{
T3_Series QL = new(source: bars.Close, period: period, vfactor: 0.7, false);
var SK = quotes.GetT3(lookbackPeriods: period, volumeFactor: 0.7).Select(i => i.T3.Null2NaN()!);
for (int i = QL.Length; i > period*15; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void TRIX() {
TRIX_Series QL = new(bars.Close, period, false);
var SK = quotes.GetTrix(period).Select(i => i.Trix.Null2NaN()!);
for (int i = QL.Length; i > period*12; i--) {
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
}
}
[Fact]
public void TEMA()
{
TEMA_Series QL = new(bars.Close, period, false);
var SK = quotes.GetTema(period).Select(i => i.Tema.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void TR()
{
TR_Series QL = new(bars);
var SK = quotes.GetTr().Select(i => i.Tr.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void WMA()
{
WMA_Series QL = new(bars.Close, period, false);
var SK = quotes.GetWma(period).Select(i => i.Wma.Null2NaN()!);
for (int i = QL.Length; i > skip*2; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
[Fact]
public void ZSCORE()
{
ZSCORE_Series QL = new(bars.Close, period, useNaN: false);
var SK = quotes.GetStdDev(period).Select(i => i.ZScore.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
}
}
}
-483
View File
@@ -1,483 +0,0 @@
using Xunit;
using System;
using TALib;
using QuanTAlib;
namespace Validations;
public class Ta_Lib
{
private readonly GBM_Feed bars;
private readonly Random rnd = new();
private readonly int period, digits, skip;
private readonly double[] TALIB;
private readonly double[] TALIB2;
private readonly double[] inopen;
private readonly double[] inhigh;
private readonly double[] inlow;
private readonly double[] inclose;
private readonly double[] involume;
public Ta_Lib()
{
bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0, Precision: 3);
period = rnd.Next(28) + 3;
skip = period+2;
digits = 9;
TALIB = new double[bars.Count];
TALIB2 = new double[bars.Count];
inopen = bars.Open.v.ToArray();
inhigh = bars.High.v.ToArray();
inlow = bars.Low.v.ToArray();
inclose = bars.Close.v.ToArray();
involume = bars.Volume.v.ToArray();
}
[Fact]
public void ADD()
{
ADD_Series QL = new(bars.Open, bars.Close);
Core.Add(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void ADL()
{
ADL_Series QL = new(bars);
Core.Ad(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > 0; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void ADOSC()
{
ADOSC_Series QL = new(bars, 3, 10, false);
Core.AdOsc(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > skip*2; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void ATR()
{
ATR_Series QL = new(bars, period:period, useNaN: false);
Core.Atr(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void BBANDS()
{
double[] outMiddle = new double[bars.Count];
double[] outUpper = new double[bars.Count];
double[] outLower = new double[bars.Count];
BBANDS_Series QL = new(bars.Close, period: period, multiplier: 2.0, false);
Core.Bbands(inclose, 0, bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod: period, optInNbDevUp: 2.0, optInNbDevDn: 2.0);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL.Upper[i].v;
double TA_item = outUpper[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), high: Math.Exp(-digits));
QL_item = QL.Mid[i].v;
TA_item = outMiddle[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), high: Math.Exp(-digits));
QL_item = QL.Lower[i].v;
TA_item = outLower[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), high: Math.Exp(-digits));
}
}
[Fact]
public void CCI()
{
CCI_Series QL = new(bars, period, false);
Core.Cci(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
/* CMO in TA-LIB is not valid
[Fact]
public void CMO() {
CMO_Series QL = new(bars.Close, period, false);
Core.Cmo(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
*/
[Fact]
public void CORR()
{
CORR_Series QL = new(bars.Open, bars.Close, period);
Core.Correl(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, optInTimePeriod: period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void DEMA()
{
DEMA_Series QL = new(bars.Close, period, false, useSMA: false);
Core.Dema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > period*10; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void DIV()
{
DIV_Series QL = new(bars.Open, bars.Close);
Core.Div(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void EMA()
{
EMA_Series QL = new(bars.Close, period, false);
Core.Ema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void HL2()
{
TSeries QL = bars.HL2;
Core.MedPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void HLC3()
{
TSeries QL = bars.HLC3;
Core.TypPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void HLCC4()
{
TSeries QL = bars.HLCC4;
Core.WclPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void KAMA() {
KAMA_Series QL = new(bars.Close, period, fast: 2, slow: 30);
Core.Kama(inReal: inclose, startIdx: 0, endIdx: bars.Count - 1, outReal: TALIB, outBegIdx: out int outBegIdx, outNbElement: out _, optInTimePeriod: period);
for (int i = QL.Length - 1; i > skip * 15; i--) {
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void MACD()
{
double[] macdSignal = new double[bars.Count];
double[] macdHist = new double[bars.Count];
MACD_Series QL = new(bars.Close, slow: 26, fast: 12, signal: 9, false);
// TA-LIB runs EMA without SMA, leaving first 100 values for convergence
Core.Macd(inclose, 0, bars.Count - 1, outMacd: TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _, optInFastPeriod: 12, optInSlowPeriod: 26, optInSignalPeriod: 9);
for (int i = QL.Length - 1; i > 100; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
QL_item = QL.Signal[i].v;
TA_item = macdSignal[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
/*
[Fact]
public void MAMA()
{
MAMA_Series QL = new(bars.Close, fastlimit: 0.5, slowlimit: 0.05);
Core.Mama(inReal: inclose, startIdx: 0, endIdx: bars.Count - 1, outMama: TALIB, outFama: TALIB2, outBegIdx: out int outBegIdx, outNbElement: out _, optInFastLimit: 0.5, optInSlowLimit: 0.05);
for (int i = QL.Length - 1; i > skip * 10; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits-1), Math.Exp(-digits-1));
}
}
*/
[Fact]
public void MAX()
{
MAX_Series QL = new(bars.Close, period, false);
Core.Max(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void MIDPOINT()
{
MIDPOINT_Series QL = new(bars.Close, period, false);
Core.MidPoint(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void MIDPRICE()
{
MIDPRICE_Series QL = new(bars, period, false);
Core.MidPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void MIN()
{
MIN_Series QL = new(bars.Close, period, false);
Core.Min(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void MUL()
{
MUL_Series QL = new(bars.Open, bars.Close);
Core.Mult(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void OBV()
{
OBV_Series QL = new(bars, period, false);
Core.Obv(inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void OHLC4()
{
TSeries QL = bars.OHLC4;
Core.AvgPrice(inopen, inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void RSI()
{
RSI_Series QL = new(bars.Close, period, false);
Core.Rsi(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void SDEV()
{
SDEV_Series QL = new(bars.Close, period, false);
Core.StdDev(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void SMA()
{
SMA_Series QL = new(bars.Close, period, false);
Core.Sma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void SUB()
{
SUB_Series QL = new(bars.Open, bars.Close);
Core.Sub(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void SUM()
{
CUSUM_Series QL = new(bars.Close, period, false);
Core.Sum(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void T3()
{
T3_Series QL = new(source: bars.Close, period: period, vfactor: 0.7, useNaN: false);
Core.T3(inReal: inclose, startIdx: 0, endIdx: bars.Count - 1, outReal: TALIB, outBegIdx: out int outBegIdx, outNbElement: out _, optInTimePeriod: period, optInVFactor: 0.7);
for (int i = QL.Length - 1; i > period*10; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void TEMA()
{
TEMA_Series QL = new(bars.Close, period, false);
Core.Tema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip * 15; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void TR()
{
TR_Series QL = new(bars);
Core.TRange(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void TRIMA()
{
TRIMA_Series QL = new(bars.Close, period, false);
Core.Trima(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void TRIX() {
TRIX_Series QL = new(bars.Close, period, useNaN: false, useSMA: true);
Core.Trix(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > period*10; i--) {
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void VAR()
{
VAR_Series QL = new(bars.Close, period, false);
Core.Var(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip * 15; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void WMA()
{
WMA_Series QL = new(bars.Close, period, false);
Core.Wma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TA_item = TALIB[i - outBegIdx];
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
}
-524
View File
@@ -1,524 +0,0 @@
using Xunit;
using System;
using Tulip;
using QuanTAlib;
namespace Validations;
public class Tulip_Test
{
private readonly GBM_Feed bars;
private readonly Random rnd = new();
private readonly int period, digits, skip;
private readonly double[] outdata;
private readonly double[] inopen;
private readonly double[] inhigh;
private readonly double[] inlow;
private readonly double[] inclose;
private readonly double[] involume;
public Tulip_Test()
{
bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0, Precision: 3);
period = rnd.Next(28) + 3;
skip = period+5;
digits = 8;
outdata = new double[bars.Count];
inopen = bars.Open.v.ToArray();
inhigh = bars.High.v.ToArray();
inlow = bars.Low.v.ToArray();
inclose = bars.Close.v.ToArray()!;
involume = bars.Volume.v.ToArray()!;
}
[Fact]
public void ADL()
{
double[][] arrin = {inhigh, inlow, inclose, involume };
double[][] arrout = { outdata };
ADL_Series QL = new(bars);
Tulip.Indicators.ad.Run(inputs: arrin, options: new double[] { }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void ADD()
{
double[][] arrin = { inhigh, inlow };
double[][] arrout = { outdata };
ADD_Series QL = new(bars.High, bars.Low);
Tulip.Indicators.add.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void ADOSC()
{
double[][] arrin = { inhigh, inlow, inclose, involume };
double[][] arrout = { outdata };
int s = 3;
ADOSC_Series QL = new(bars, s, period, false);
Tulip.Indicators.adosc.Run(inputs: arrin, options: new double[] { s, period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TU_item = arrout[0][i-period+1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void ATR()
{
double[][] arrin = { inhigh, inlow, inclose };
double[][] arrout = { outdata };
ATR_Series QL = new(bars, period:period, useNaN:false);
Tulip.Indicators.atr.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
//Tulip ATR doesn't use warm-up SMA, compensating with 200 warming bars
for (int i = QL.Length - 1; i > 200+skip; i--)
{
double QL_item = QL[i].v;
double TU_item = arrout[0][i - period + 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void BBANDS()
{
double[][] arrin = { inclose };
double[] outmid = new double[bars.Count];
double[] outlower = new double[bars.Count];
double[] outupper = new double[bars.Count];
double[][] arrout = { outlower, outmid, outupper};
BBANDS_Series QL = new(bars.Close, period, 2, false);
Tulip.Indicators.bbands.Run(inputs: arrin, options: new double[] { period, 2 }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL.Lower[i].v;
double TU_item = outlower[i - period + 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
QL_item = QL.Mid[i].v;
TU_item = outmid[i - period + 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
QL_item = QL.Upper[i].v;
TU_item = outupper[i - period + 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
/*
[Fact]
public void CCI() {
double[][] arrin = { inhigh, inlow, inclose };
double[][] arrout = { outdata };
CCI_Series QL = new(bars, period, useNaN: false);
Tulip.Indicators.cci.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = outdata[i - period + 1];
Assert.Equal(QL_item,TU_item);
//Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
*/
[Fact]
public void CMO() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
CMO_Series QL = new(bars.Close, period, useNaN: false);
Tulip.Indicators.cmo.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - period];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void DECAY() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
DECAY_Series QL = new(bars.Close, period, useNaN: false);
Tulip.Indicators.decay.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip + 200; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void DEMA() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
DEMA_Series QL = new(bars.Close, period, useNaN: false, useSMA: false);
Tulip.Indicators.dema.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip+200; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i-(period+period-2)];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void DIV() {
double[][] arrin = { inhigh, inlow };
double[][] arrout = { outdata };
DIV_Series QL = new(bars.High, bars.Low);
Tulip.Indicators.div.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void EDECAY() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
DECAY_Series QL = new(bars.Close, period, exponential: true, useNaN: false);
Tulip.Indicators.edecay.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip + 200; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void EMA()
{
double[][] arrin = { inclose };
double[][] arrout = { outdata };
// Tulip EMA doesn't use SMA to warm-up
EMA_Series QL = new(bars.Close, period, false, useSMA: false);
Tulip.Indicators.ema.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void HL2() {
double[][] arrin = { inhigh, inlow };
double[][] arrout = { outdata };
TSeries QL = bars.HL2;
Tulip.Indicators.medprice.Run(inputs: arrin, options: new double[] { }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void HLC3() {
double[][] arrin = { inhigh, inlow, inclose };
double[][] arrout = { outdata };
TSeries QL = bars.HLC3;
Tulip.Indicators.typprice.Run(inputs: arrin, options: new double[] { }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void HLCC4() {
double[][] arrin = { inhigh, inlow, inclose };
double[][] arrout = { outdata };
TSeries QL = bars.HLCC4;
Tulip.Indicators.wcprice.Run(inputs: arrin, options: new double[] { }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void HMA() {
int p = 10;
double[][] arrin = { inclose };
double[][] arrout = { outdata };
HMA_Series QL = new(bars.Close, p, false);
Tulip.Indicators.hma.Run(inputs: arrin, options: new double[] { p }, outputs: arrout);
for (int i = QL.Length - 1; i > skip+2; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - p - 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits-2), Math.Exp(-digits-2));
}
}
[Fact]
public void KAMA() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
KAMA_Series QL = new(bars.Close, period);
Tulip.Indicators.kama.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > 250; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - period + 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void LINREG() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
SLOPE_Series QL = new(bars.Close, period);
Tulip.Indicators.linregslope.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - period+1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void MACD() {
double[] outsignal = new double[bars.Count];
double[] outhist = new double[bars.Count];
double[][] arrin = { inclose };
double[][] arrout = { outdata, outsignal, outhist };
MACD_Series QL = new(bars.Close, slow: 26,fast: 10, signal: 9);
Tulip.Indicators.macd.Run(inputs: arrin, options: new double[] { 10,26,9 }, outputs: arrout);
for (int i = QL.Length - 1; i > 150; i--) {
double QL_item = QL[i].v;
double TU_item =outdata[i - 26+1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void MAX() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
MAX_Series QL = new(bars.Close, period, false);
Tulip.Indicators.max.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i-period+1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void MIN() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
MIN_Series QL = new(bars.Close, period, false);
Tulip.Indicators.min.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - period + 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void MUL() {
double[][] arrin = { inhigh, inlow };
double[][] arrout = { outdata };
MUL_Series QL = new(bars.High, bars.Low);
Tulip.Indicators.mul.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void OBV() {
double[][] arrin = { inclose, involume };
double[][] arrout = { outdata };
OBV_Series QL = new(bars, period, false);
Tulip.Indicators.obv.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i] + arrin[1][0];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void OHLC4()
{
double[][] arrin = { inopen, inhigh, inlow, inclose };
double[][] arrout = { outdata };
TSeries QL = bars.OHLC4;
Tulip.Indicators.avgprice.Run(inputs: arrin, options: new double[] { }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void RMA() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
RMA_Series QL = new(bars.Close, period, false);
Tulip.Indicators.wilders.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - period + 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void RSI() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
RSI_Series QL = new(bars.Close, period, false);
Tulip.Indicators.rsi.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - period];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void SMA()
{
double[][] arrin = { inclose };
double[][] arrout = { outdata };
SMA_Series QL = new(bars.Close, period, false);
Tulip.Indicators.sma.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].v;
double TU_item = arrout[0][i-period+1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void SDEV() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
SDEV_Series QL = new(bars.Close, period, false);
Tulip.Indicators.stddev.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - period + 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void SUB() {
double[][] arrin = { inhigh, inlow };
double[][] arrout = { outdata };
SUB_Series QL = new(bars.High, bars.Low);
Tulip.Indicators.sub.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void SUM() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
CUSUM_Series QL = new(bars.Close, period, false);
Tulip.Indicators.sum.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - period + 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void TR() {
double[][] arrin = { inhigh,inlow,inclose };
double[][] arrout = { outdata };
TR_Series QL = new(bars);
Tulip.Indicators.tr.Run(inputs: arrin, options: new double[] {}, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void TEMA() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
TEMA_Series QL = new(bars.Close, period, false);
Tulip.Indicators.tema.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip+200; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - (period-1)*3];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void TRIMA() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
TRIMA_Series QL = new(bars.Close, period, false);
Tulip.Indicators.trima.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - period + 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
/*
[Fact]
public void TRIX() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
TRIX_Series QL = new(bars.Close, period);
Tulip.Indicators.trix.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > period+200; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - (period*3) + 2];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits+2), Math.Exp(-digits+2));
}
}
*/
[Fact]
public void VAR() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
VAR_Series QL = new(bars.Close, period, false);
Tulip.Indicators.var.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - period + 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void WMA() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
WMA_Series QL = new(bars.Close, period, false);
Tulip.Indicators.wma.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
double TU_item = arrout[0][i - period + 1];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
[Fact]
public void ZLEMA() {
int p = 4;
double[][] arrin = { inclose };
double[][] arrout = { outdata };
ZLEMA_Series QL = new(bars.Close, p, false);
Tulip.Indicators.zlema.Run(inputs: arrin, options: new double[] { p }, outputs: arrout);
for (int i = QL.Length - 1; i > skip+20; i--) {
double QL_item = QL[i].v;
double TU_item = outdata[i];
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits-2), Math.Exp(-digits-2));
}
}
}
+97
View File
@@ -0,0 +1,97 @@
using Xunit;
using Trady.Analysis.Indicator;
using Trady.Core;
using Trady.Core.Infrastructure;
using QuanTAlib;
public class TradyTests
{
private readonly TBarSeries bars;
private readonly GbmFeed feed;
private Random rnd;
private readonly double range;
private int period, iterations;
private int skip;
private IEnumerable<IOhlcv> Candles;
public TradyTests()
{
rnd = new((int)DateTime.Now.Ticks);
feed = new(sigma: 0.5, mu: 0.0);
bars = new(feed);
range = 1e-9;
feed.Add(10000);
iterations = 3;
skip = 500;
Candles = bars.Select(bar => new Candle(
bar.Time,
(decimal)bar.Open,
(decimal)bar.High,
(decimal)bar.Low,
(decimal)bar.Close,
(decimal)bar.Volume
)).ToList();
}
[Fact]
public void SMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Sma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var Trady = new SimpleMovingAverage(Candles, period)
.Compute()
.Select(result => new
{
Date = result.DateTime,
Value = result.Tick.HasValue ? (double)result.Tick.Value : double.NaN
})
.ToList();
Assert.Equal(QL.Length, Trady.Count);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].Value;
double Tr_item = Trady[i].Value;
Assert.InRange(Tr_item - QL_item, -range, range);
}
}
}
[Fact]
public void EMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Ema ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var Trady = new ExponentialMovingAverage(Candles, period)
.Compute()
.Select(result => new
{
Date = result.DateTime,
Value = result.Tick.HasValue ? (double)result.Tick.Value : double.NaN
})
.ToList();
Assert.Equal(QL.Length, Trady.Count);
for (int i = QL.Length - 1; i > skip*2; i--)
{
double QL_item = QL[i].Value;
double Tr_item = Trady[i].Value;
Assert.InRange(Tr_item - QL_item, -range, range);
}
}
}
}
+82
View File
@@ -0,0 +1,82 @@
using Xunit;
using Tulip;
using QuanTAlib;
public class TulipTests
{
private readonly TBarSeries bars;
private readonly GbmFeed feed;
private Random rnd;
private readonly double range;
private int period, iterations;
private readonly double[] data;
private readonly double[] outdata;
private int skip;
public TulipTests()
{
rnd = new((int)DateTime.Now.Ticks);
feed = new(sigma: 0.5, mu: 0.0);
bars = new(feed);
range = 1e-9;
feed.Add(10000);
iterations = 3;
skip = 500;
data = feed.Close.v.ToArray();
outdata = new double[data.Count()];
}
[Fact]
public void SMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Sma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
double[][] arrin = [data];
double[][] arrout = [outdata];
Tulip.Indicators.sma.Run(inputs: arrin, options: [period], outputs: arrout);
Assert.Equal(QL.Length, arrout[0].Length);
for (int i = QL.Length - 1; i > skip; i--)
{
double QL_item = QL[i].Value;
double TU = i<period-1?double.NaN:arrout[0][i-period+1];
Assert.InRange(TU - QL_item, -range, range);
}
}
}
[Fact]
public void EMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = 20;
Ema ma = new(period, useSma: false);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
double[][] arrin = [data];
double[][] arrout = [outdata];
Tulip.Indicators.ema.Run(inputs: arrin, options: [period], outputs: arrout);
Assert.Equal(QL.Length, arrout[0].Count());
for (int i = QL.Length - 1; i > skip*2; i--) //Initial Tulip Ema value is (wrongly) set to the first input value - therefore large skip
{
double QL_item = QL[i].Value;
double TU = arrout[0][i];
//Assert.InRange(TU - QL_item, -range, range);
Assert.True(Math.Abs(TU - QL_item) <= range, $"Assertion failed at index {i} for period {period}: TU = {TU}, QL_item = {QL_item}, delta = {TU-QL_item}");
}
}
}
}
+883
View File
@@ -0,0 +1,883 @@
using Xunit;
using QuanTAlib;
public class Consistency
{
Random rnd;
int series_len = 1000;
int corrections = 100;
public Consistency()
{ //constructor
rnd = new((int)DateTime.Now.Ticks);
}
[Fact]
public void CanUpdate()
{
GbmFeed gbm = new();
TSeries input = new(gbm.Close);
TSeries output = new(input);
gbm.Add(10000);
Assert.Equal(input.Count, output.Count);
for (int i = 0; i < input.Count; i++)
{
Assert.Equal(input[i].v, output[i].v);
}
}
[Fact]
public void Alma_isNew()
{
int p = (int)rnd.Next(2, 100);
double offset = rnd.Next();
double sigma = rnd.Next(1, 100);
Alma ma1 = new(period: p, offset: offset, sigma: sigma);
Alma ma2 = new(period: p, offset: offset, sigma: sigma);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Convolution_isNew()
{
Convolution ma1 = new(new double[] { 1.0, 2, 3, 2, 1 });
Convolution ma2 = new(new double[] { 1.0, 2, 3, 2, 1 });
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Dema_isNew()
{
int p = (int)rnd.Next(2, 100);
Dema ma1 = new(p);
Dema ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Dsma_isNew()
{
int p = (int)rnd.Next(2, 100);
Dsma ma1 = new(p);
Dsma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Dwma_isNew()
{
int p = (int)rnd.Next(2, 100);
Dwma ma1 = new(p);
Dwma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void EmaSma_isNew()
{
int p = (int)rnd.Next(2, 100);
Ema ma1 = new(p, useSma: true);
Ema ma2 = new(p, useSma: true);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Ema_isNew()
{
int p = (int)rnd.Next(2, 100);
Ema ma1 = new(p, useSma: false);
Ema ma2 = new(p, useSma: false);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Sma_isNew()
{
int p = (int)rnd.Next(2, 100);
Sma ma1 = new(p);
Sma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Epma_isNew()
{
int p = (int)rnd.Next(2, 100);
Epma ma1 = new(p);
Epma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Frama_isNew()
{
int p = (int)rnd.Next(2, 100);
Frama ma1 = new(p);
Frama ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Fwma_isNew()
{
int p = (int)rnd.Next(2, 100);
Fwma ma1 = new(p);
Fwma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Gma_isNew()
{
int p = (int)rnd.Next(2, 100);
Gma ma1 = new(p);
Gma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Hma_isNew()
{
int p = (int)rnd.Next(2, 100);
Hma ma1 = new(p);
Hma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Hwma_isNew()
{
int p = (int)rnd.Next(2, 100);
Hwma ma1 = new(p);
Hwma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
/*
[Fact]
public void Jma_isNew()
{
int p = (int)rnd.Next(2, 100);
Jma ma1 = new(p);
Jma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
//Assert.Equal(ma1.Value, ma2.Value);
Assert.True(ma1.Value == ma2.Value, $"Assertion failed at p={p}, Value={item1.Value}. ma1.Value={ma1.Value}, ma2.Value={ma2.Value}");
}
}
*/
[Fact]
public void Kama_isNew()
{
int p = (int)rnd.Next(2, 100);
Kama ma1 = new(p);
Kama ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Ltma_isNew()
{
int p = rnd.Next(0, 1);
Ltma ma1 = new(p);
Ltma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Mama_isNew()
{
int p = rnd.Next(0, 1);
Mama ma1 = new(p, p * 0.1);
Mama ma2 = new(p, p * 0.1);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
Assert.True(ma1.Value == ma2.Value, $"Assertion failed for p={p}, i={i}. Expected {ma1.Value} but got {ma2.Value}.");
}
}
[Fact]
public void Mgdi_isNew()
{
int p = (int)rnd.Next(2, 100);
Mgdi ma1 = new(p);
Mgdi ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Mma_isNew()
{
int p = (int)rnd.Next(2, 100);
Mma ma1 = new(p);
Mma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Qema_isNew()
{
int p = (int)rnd.Next(2, 100);
Qema ma1 = new();
Qema ma2 = new();
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Rema_isNew()
{
int p = (int)rnd.Next(2, 100);
Rema ma1 = new(p);
Rema ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Rma_isNew()
{
int p = (int)rnd.Next(2, 100);
Rma ma1 = new(p);
Rma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Sinema_isNew()
{
int p = (int)rnd.Next(2, 100);
Sinema ma1 = new(p);
Sinema ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Smma_isNew()
{
int p = (int)rnd.Next(2, 100);
Smma ma1 = new(p);
Smma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void T3_isNew()
{
int p = (int)rnd.Next(2, 100);
T3 ma1 = new(p);
T3 ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Tema_isNew()
{
int p = (int)rnd.Next(2, 100);
Tema ma1 = new(p);
Tema ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Trima_isNew()
{
int p = (int)rnd.Next(2, 100);
Trima ma1 = new(p);
Trima ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Vidya_isNew()
{
int p = (int)rnd.Next(2, 100);
Vidya ma1 = new(p);
Vidya ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Wma_isNew()
{
int p = (int)rnd.Next(2, 100);
Wma ma1 = new(p);
Wma ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Zlema_isNew()
{
int p = (int)rnd.Next(2, 100);
Zlema ma1 = new(p);
Zlema ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Entropy_isNew()
{
int p = (int)rnd.Next(2, 100);
Entropy ma1 = new(p);
Entropy ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Kurtosis_isNew()
{
int p = (int)rnd.Next(2, 100);
Kurtosis ma1 = new(p);
Kurtosis ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Max_isNew()
{
int p = (int)rnd.Next(2, 100);
Max ma1 = new(p, 0.01);
Max ma2 = new(p, 0.01);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Min_isNew()
{
int p = (int)rnd.Next(2, 100);
Min ma1 = new(p, 0.01);
Min ma2 = new(p, 0.01);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Med_isNew()
{
int p = (int)rnd.Next(2, 100);
Median ma1 = new(p);
Median ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Mode_isNew()
{
int p = (int)rnd.Next(2, 100);
Mode ma1 = new(p);
Mode ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Percentile_isNew()
{
int p = (int)rnd.Next(2, 100);
Percentile ma1 = new(p, 50);
Percentile ma2 = new(p, 50);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Skew_isNew()
{
int p = (int)rnd.Next(2, 100);
Skew ma1 = new(p);
Skew ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Stddev_isNew()
{
int p = (int)rnd.Next(2, 100);
Stddev ma1 = new(p);
Stddev ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Variance_isNew()
{
int p = (int)rnd.Next(2, 100);
Variance ma1 = new(p);
Variance ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
[Fact]
public void Zscore_isNew()
{
int p = (int)rnd.Next(2, 100);
Zscore ma1 = new(p);
Zscore ma2 = new(p);
for (int i = 0; i < series_len; i++)
{
TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
ma1.Calc(item1);
for (int j = 0; j < corrections; j++)
{
item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
ma1.Calc(item1);
}
ma2.Calc(new TValue(item1.Time, item1.Value, IsNew: true));
Assert.Equal(ma1.Value, ma2.Value);
}
}
}
+324
View File
@@ -0,0 +1,324 @@
using Xunit;
using Skender.Stock.Indicators;
using QuanTAlib;
public class SkenderTests
{
private readonly TBarSeries bars;
private readonly GbmFeed feed;
private Random rnd;
private readonly double range;
private int period, iterations;
private readonly IEnumerable<Quote> quotes;
public SkenderTests()
{
rnd = new((int)DateTime.Now.Ticks);
feed = new(sigma: 0.5, mu: 0.0);
bars = new(feed);
range = 1e-9;
feed.Add(10000);
iterations = 3;
quotes = bars.Select(q => new Quote
{
Date = q.Time,
Open = (decimal)q.Open,
High = (decimal)q.High,
Low = (decimal)q.Low,
Close = (decimal)q.Close,
Volume = (decimal)q.Volume
});
}
[Fact]
public void SMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Sma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetSma(lookbackPeriods: period).Select(i => i.Sma.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > period; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void SMAEMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Ema ma = new(period, useSma: true);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetEma(lookbackPeriods: period).Select(i => i.Ema.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > period; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void EMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Ema ma = new(period, useSma: false);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetEma(lookbackPeriods: period).Select(i => i.Ema.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > QL.Length - 500; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void DEMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Dema ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetDema(lookbackPeriods: period).Select(i => i.Dema.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > QL.Length - 500; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void TEMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Tema ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetTema(lookbackPeriods: period).Select(i => i.Tema.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > QL.Length - 500; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void SMAConvolution()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
double[] kernel = Enumerable.Repeat(1.0, period).ToArray();
Convolution ma = new(kernel);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetSma(lookbackPeriods: period).Select(i => i.Sma.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > period; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void WMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Wma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetWma(lookbackPeriods: period).Select(i => i.Wma.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > period + 2; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void HMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Hma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetHma(lookbackPeriods: period).Select(i => i.Hma.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > period + 5; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void EPMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Epma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetEpma(lookbackPeriods: period).Select(i => i.Epma.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > period + 5; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void ALMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Alma ma = new(period, offset: 0.85, sigma: 6);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetAlma(lookbackPeriods: period).Select(i => i.Alma.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > period; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void T3()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
T3 ma = new(period, vfactor: 0.7, useSma: false);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetT3(lookbackPeriods: period, volumeFactor: 0.7).Select(i => i.T3.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > period; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void SMMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Smma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetSmma(lookbackPeriods: period).Select(i => i.Smma.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > period; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void KAMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Kama ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.GetKama(erPeriods: period).Select(i => i.Kama.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > period; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void MAMA()
{
for (int run = 0; run < iterations; run++)
{
//period = rnd.Next(50) + 5;
Mama ma = new(fastLimit: 0.5, slowLimit: 0.05);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.Select(q => (q.Date, (double)q.Close))
.GetMama(fastLimit: 0.5, slowLimit: 0.05)
.Select(i => i.Mama.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > 100; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
[Fact]
public void MGDI()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Mgdi ma = new(period: period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
var SK = quotes.Select(q => (q.Date, (double)q.Close))
.GetDynamic(lookbackPeriods: period)
.Select(i => i.Dynamic.Null2NaN()!);
Assert.Equal(QL.Length, SK.Count());
for (int i = QL.Length - 1; i > period + 5; i--)
{
Assert.InRange(SK.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
}
+152
View File
@@ -0,0 +1,152 @@
using Xunit;
using TALib;
using QuanTAlib;
public class TAlibTests
{
private readonly TBarSeries bars;
private readonly GbmFeed feed;
private Random rnd;
private readonly double range;
private int period, iterations;
private readonly double[] data;
private readonly double[] TALIB;
public TAlibTests()
{
rnd = new((int)DateTime.Now.Ticks);
feed = new(sigma: 0.5, mu: 0.0);
bars = new(feed);
range = 1e-9;
feed.Add(10000);
iterations = 3;
data = feed.Close.v.ToArray();
TALIB = new double[data.Count()];
}
[Fact]
public void SMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Sma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
Core.Sma(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period);
Assert.Equal(QL.Length, TALIB.Count());
for (int i = QL.Length - 1; i > period; i--)
{
double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
}
[Fact]
public void EMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Ema ma = new(period, useSma: true);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
Core.Ema(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period);
Assert.Equal(QL.Length, TALIB.Count());
for (int i = QL.Length - 1; i > period; i--)
{
double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
}
[Fact]
public void DEMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Dema ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
Core.Dema(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period);
Assert.Equal(QL.Length, TALIB.Count());
for (int i = QL.Length - 1; i > period*20; i--)
{
double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
}
[Fact]
public void TEMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Tema ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
Core.Tema(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period);
Assert.Equal(QL.Length, TALIB.Count());
for (int i = QL.Length - 1; i > period*20; i--)
{
double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
}
//TODO fix WMA
/*
[Fact]
public void WMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
Wma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
Core.Wma(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period);
Assert.Equal(QL.Length, TALIB.Count());
for (int i = QL.Length - 1; i > period*3; i--)
{
double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
}
*/
[Fact]
public void T3()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
T3 ma = new(period, vfactor: 0.7, useSma: false);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
Core.T3(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, optInTimePeriod: period, optInVFactor: 0.7);
Assert.Equal(QL.Length, TALIB.Count());
for (int i = QL.Length - 1; i > period*20; i--)
{
double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
}
}
+16
View File
@@ -0,0 +1,16 @@
# Top-most EditorConfig file
root = true
[*.{cs,vb}]
# Suppress S3776 (Cognitive Complexity)
dotnet_diagnostic.S3776.severity = none
# Suppress CA1416 (Platform Compatibility)
dotnet_diagnostic.CA1416.severity = none
dotnet_style_parentheses_in_control_flow_statements = always_for_clarity:suggestion
csharp_new_line_before_open_brace = none
csharp_new_line_before_else = false
csharp_new_line_before_catch = false
csharp_new_line_before_finally = false
csharp_new_line_before_members_in_object_initializers = false
csharp_new_line_before_members_in_anonymous_types = false
csharp_new_line_between_query_expression_clauses = false

Some files were not shown because too many files have changed in this diff Show More