Merge remote-tracking branch 'origin/main'

This commit is contained in:
Miha
2024-10-26 07:06:17 -07:00
391 changed files with 21168 additions and 19731 deletions
+17
View File
@@ -0,0 +1,17 @@
version = 1
[[analyzers]]
name = "csharp"
enabled = true
[[analyzers]]
name = "test-coverage"
enabled = true
[[analyzers]]
name = "secrets"
enabled = true
[[transformers]]
name = "dotnet-format"
enabled = true
Binary file not shown.
+1 -26
View File
@@ -377,21 +377,6 @@
Mediates a history meta data with available data types and intervals on vendor side
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.Integration.HistoryMetadata.AllowedHistoryTypes">
<summary>
History data types
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.Integration.HistoryMetadata.AllowedBasePeriods">
<summary>
History intervals
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.Integration.HistoryMetadata.AllowedPeriods">
<summary>
History intervals
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.Integration.MessageAsset.Id">
<summary>
Asset id bearer
@@ -1948,7 +1933,7 @@
<param name="toTime"></param>
<returns></returns>
</member>
<member name="M:TradingPlatform.BusinessLayer.Symbol.GetHistory(TradingPlatform.BusinessLayer.HistoryAggregation,TradingPlatform.BusinessLayer.HistoryType,System.DateTime,System.DateTime)">
<member name="M:TradingPlatform.BusinessLayer.Symbol.GetHistory(TradingPlatform.BusinessLayer.HistoryAggregation,System.DateTime,System.DateTime)">
<summary>
Gets historical data according to aggregation and other parameters
</summary>
@@ -2965,21 +2950,11 @@
Gets HistoricalData symbol
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.HistoricalData.Period">
<summary>
Gets HistoricalData Period
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.HistoricalData.Aggregation">
<summary>
Gets HistoricalData aggregation
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.HistoricalData.HistoryType">
<summary>
Gets HistoricalData history type
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.HistoricalData.FromTime">
<summary>
Gets HistoricalData left time boundary
+254
View File
@@ -0,0 +1,254 @@
# This workflow integrates SonarCloud analysis, coverage reporting,
# CodeQL analysis, SecurityCodeScan, and Codacy Security Scan
# for code scanning and vulnerability detection - and if they all pass, publish
name: Publish Workflow
on:
push: # Triggers on push events to any branch
pull_request: # Triggers on pull request events targeting any branch
workflow_dispatch: # Allows manual triggering of the workflow
permissions:
contents: write
pull-requests: read # Allows SonarCloud to decorate PRs with analysis results
security-events: write # Required for CodeQL analysis and uploading SARIF results
jobs:
Code_Coverage:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'
- name: Install dotnet tools
run: |
dotnet tool install JetBrains.dotCover.GlobalTool --global
dotnet tool install dotnet-sonarscanner --global
dotnet tool install dotnet-coverage --global
dotnet tool install --global coverlet.console
dotnet tool install --global dotnet-reportgenerator-globaltool
dotnet restore
- name: Build Projects
run: |
dotnet build --no-restore --configuration Debug
dotnet build ./lib/quantalib.csproj --configuration Release --nologo
dotnet build ./quantower/Averages/_Averages.csproj --configuration Release --nologo
dotnet build ./quantower/Statistics/_Statistics.csproj --configuration Release --nologo
dotnet build ./quantower/Volatility/_Volatility.csproj --configuration Release --nologo
dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
- name: Run Tests with Coverage
run: |
dotnet test --no-build --configuration Debug /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml"
dotnet dotcover test Tests/Tests.csproj --dcReportType=HTML --dcoutput=./dotcover.html
dotnet dotcover test Tests/Tests.csproj --dcReportType=DetailedXML --dcoutput=./dotcover.xml --verbosity=Detailed
dotnet test -p:CollectCoverage=true --collect:"XPlat Code Coverage" --results-directory "./"
- name: Generate Coverage Report
run: |
reportgenerator -reports:*cover*.xml -targetdir:.
- name: Upload Coverage to Codacy
uses: codacy/codacy-coverage-reporter-action@v1
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: '*cover*.xml'
- name: Upload Coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: 'cover*'
verbose: true
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
args: >
-Dsonar.projectKey=mihakralj_QuanTAlib
-Dsonar.organization=mihakralj-quantalib
-Dsonar.sources=.
-Dsonar.cs.opencover.reportsPaths=**/*cover*.xml
-Dsonar.cs.dotcover.reportsPaths=**/dotcover.xml
-Dsonar.coverage.exclusions=**Tests.cs
CodeQL:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: 'csharp'
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore --configuration Debug
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@v4
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
verbose: true
output: results.sarif
format: sarif
gh-code-scanning-compat: true
max-allowed-issues: 2147483647
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
SecurityCodeScan:
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup NuGet
uses: nuget/setup-nuget@v1
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v1
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.x
3.1.x
dotnet-quality: 'preview'
- name: Set up projects for analysis
uses: security-code-scan/security-code-scan-add-action@v1
- name: Build
run: |
dotnet restore
dotnet build --no-restore --configuration Debug
- name: Convert SARIF for uploading to GitHub
uses: security-code-scan/security-code-scan-results-action@v1
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
build_publish:
needs: [Code_Coverage, CodeQL, SecurityCodeScan]
if: |
success() &&
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) ||
github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v0
with:
versionSpec: '6.x'
includePrerelease: true
- name: Determine Version
id: gitversion
uses: gittools/actions/gitversion/execute@v0
with:
useConfigFile: true
updateAssemblyInfo: true
- name: Build projects
run: |
dotnet build ./lib/quantalib.csproj --configuration Release --nologo \
-p:PackageVersion=${{ steps.gitversion.outputs.MajorMinorPatch }}
dotnet build ./quantower/Averages/_Averages.csproj --configuration Release --nologo
dotnet build ./quantower/Statistics/_Statistics.csproj --configuration Release --nologo
dotnet build ./quantower/Volatility/_Volatility.csproj --configuration Release --nologo
dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
############# Publish dev release
- name: Create or Update Development Release
if: github.ref == 'refs/heads/dev'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release delete development --yes || true
gh release create development \
--title "Development Build" \
--notes "Latest development build from commit ${{ github.sha }}" \
--prerelease \
--target ${{ github.sha }} \
lib/bin/Release/QuanTAlib.dll \
quantower/Averages/bin/Release/Averages.dll \
quantower/Statistics/bin/Release/Statistics.dll \
quantower/Volatility/bin/Release/Volatility.dll \
SyntheticVendor/bin/Release/SyntheticVendor.dll
- name: Push prerelease package to myget.org
if: github.ref == 'refs/heads/dev'
run: |
dotnet nuget push 'lib/bin/Release/QuanTAlib.*.nupkg' \
--source https://www.myget.org/F/quantalib/api/v3/index.json \
--force-english-output \
--api-key ${{ secrets.MYGET_DEPLOY_KEY_QUANTALIB }}
############## Publish main release
- name: Create GitHub Release
if: ${{ github.ref == 'refs/heads/main' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create v${{ steps.gitversion.outputs.MajorMinorPatch }} \
--title "Release ${{ steps.gitversion.outputs.MajorMinorPatch }}" \
--notes "Release notes for version ${{ steps.gitversion.outputs.MajorMinorPatch }}" \
quantower/Averages/bin/Release/Averages.dll \
quantower/Statistics/bin/Release/Statistics.dll \
quantower/Volatility/bin/Release/Volatility.dll \
SyntheticVendor/bin/Release/SyntheticVendor.dll
- name: Push release package to nuget.org
if: ${{ github.ref == 'refs/heads/main' }}
run: |
dotnet nuget push 'lib/bin/Release/QuanTAlib.*.nupkg' \
--source https://api.nuget.org/v3/index.json \
--skip-duplicate \
--api-key ${{ secrets.NUGET_DEPLOY_KEY_QUANTLIB }}
-61
View File
@@ -1,61 +0,0 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow checks out code, performs a Codacy security scan
# and integrates the results with the
# GitHub Advanced Security code scanning feature. For more information on
# the Codacy security scan action usage and parameters, see
# https://github.com/codacy/codacy-analysis-cli-action.
# For more information on Codacy Analysis CLI in general, see
# https://github.com/codacy/codacy-analysis-cli.
name: Codacy Security Scan
on:
push:
branches: [ "main" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "main" ]
schedule:
- cron: '17 22 * * 0'
permissions:
contents: read
jobs:
codacy-security-scan:
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
name: Codacy Security Scan
runs-on: ubuntu-latest
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout code
uses: actions/checkout@v4
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b
with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
verbose: true
output: results.sarif
format: sarif
# Adjust severity of non-security issues
gh-code-scanning-compat: true
# Force 0 exit code to allow SARIF file generation
# This will handover control about PR rejection to the GitHub side
max-allowed-issues: 2147483647
# Upload the SARIF file generated in the previous step
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
-92
View File
@@ -1,92 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL Advanced"
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: '40 12 * * 1'
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: csharp
build-mode: autobuild
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
-174
View File
@@ -1,174 +0,0 @@
name: Stage/build/test/release/publish
on:
workflow_dispatch:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build_test:
#runs-on: windows-latest
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
############## Install tools
- name: Create Quantower folder at root
run: |
sudo mkdir -p /Quantower/
sudo chmod -R 777 /Quantower
- name: Install .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.x'
dotnet-quality: 'preview'
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v0
with:
versionSpec: '6.x'
includePrerelease: true
- name: Determine Version
id: gitversion
uses: gittools/actions/gitversion/execute@v0
with:
useConfigFile: true
#configFilePath: GitVersion.yml
updateAssemblyInfo: true
############## Install more tools
- name: Install JDK11 for Sonar Scanner
uses: actions/setup-java@v3
with:
java-version: 11
distribution: 'zulu'
- name: Install JetBrains
run: dotnet tool install JetBrains.dotCover.GlobalTool --global
- name: Install Sonar Scanner
run: dotnet tool install dotnet-sonarscanner --global
- name: Install dotnet-coverage
run: dotnet tool install dotnet-coverage --global
- name: Sonar start
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: dotnet sonarscanner begin /o:"mihakralj" /k:"mihakralj_QuanTAlib"
/d:sonar.login="${{ secrets.SONAR_TOKEN }}"
/d:sonar.host.url="https://sonarcloud.io"
/d:sonar.cs.dotcover.reportsPaths=dotcover*
############# Build and test
- name: Build Main branch of QuanTAlib DLL
if: ${{ github.ref != 'refs/heads/dev' }}
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 ./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
- name: DotCover Test XML
if: ${{ github.ref == 'refs/heads/dev' }}
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 "./"
############## Report to Sonar/CodeCov/Codacy
- name: Move coverage report to project root
if: ${{ github.ref == 'refs/heads/dev' }}
run: |
report=$(find . -name '*coverage.cobertura.xml' | head -1)
mv "$report" ./coverage.cobertura.xml
- name: Upload to Codacy
if: ${{ github.ref == 'refs/heads/dev' }}
uses: codacy/codacy-coverage-reporter-action@v1
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: "*cover*.xml"
- name: Upload to Codecov
if: ${{ github.ref == 'refs/heads/dev' }}
uses: codecov/codecov-action@v3
with:
files: cover*
verbose: true
- name: Upload to Sonar
if: ${{ github.ref == 'refs/heads/dev' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: dotnet sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
############## Publish dev release
- name: Publish dev release assets
if: ${{ github.ref == 'refs/heads/dev' }}
uses: SourceSprint/upload-multiple-releases@1.0.7
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
prerelease: true
overwrite: true
release_name: ${{ steps.gitversion.outputs.SemVer }}
tag_name: prerelease
release_config: |
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 'lib/bin/Release/QuanTAlib.*.nupkg'
--api-key ${{ secrets.MYGET_DEPLOY_KEY_QUANTALIB }}
--source https://www.myget.org/F/quantalib/api/v2/package
--skip-duplicate
############## Publish main release
- name: Publish main release assets
if: ${{ github.ref == 'refs/heads/main' }}
uses: SourceSprint/upload-multiple-releases@1.0.7
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
prerelease: false
overwrite: true
release_name: ${{ steps.gitversion.outputs.MajorMinorPatch }}
tag_name: latest
release_config: |
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 'lib/bin/Release/QuanTAlib.*.nupkg'
--api-key ${{ secrets.NUGET_DEPLOY_KEY_QUANTLIB }}
--source https://api.nuget.org/v3/index.json
--skip-duplicate
-41
View File
@@ -1,41 +0,0 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow integrates SecurityCodeScan with GitHub's Code Scanning feature
# SecurityCodeScan is a vulnerability patterns detector for C# and VB.NET
name: SecurityCodeScan
on:
push:
branches: [ "main" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "main" ]
schedule:
- cron: '23 14 * * 2'
jobs:
SCS:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: nuget/setup-nuget@04b0c2b8d1b97922f67eca497d7cf0bf17b8ffe1
- uses: microsoft/setup-msbuild@v1.0.2
- name: Set up projects for analysis
uses: security-code-scan/security-code-scan-add-action@f8ff4f2763ed6f229eded80b1f9af82ae7f32a0d
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Convert sarif for uploading to GitHub
uses: security-code-scan/security-code-scan-results-action@cdb3d5e639054395e45bf401cba8688fcaf7a687
- name: Upload sarif
uses: github/codeql-action/upload-sarif@v3
-67
View File
@@ -1,67 +0,0 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow helps you trigger a SonarCloud analysis of your code and populates
# GitHub Code Scanning alerts with the vulnerabilities found.
# Free for open source project.
# 1. Login to SonarCloud.io using your GitHub account
# 2. Import your project on SonarCloud
# * Add your GitHub organization first, then add your repository as a new project.
# * Please note that many languages are eligible for automatic analysis,
# which means that the analysis will start automatically without the need to set up GitHub Actions.
# * This behavior can be changed in Administration > Analysis Method.
#
# 3. Follow the SonarCloud in-product tutorial
# * a. Copy/paste the Project Key and the Organization Key into the args parameter below
# (You'll find this information in SonarCloud. Click on "Information" at the bottom left)
#
# * b. Generate a new token and add it to your Github repository's secrets using the name SONAR_TOKEN
# (On SonarCloud, click on your avatar on top-right > My account > Security
# or go directly to https://sonarcloud.io/account/security/)
# Feel free to take a look at our documentation (https://docs.sonarcloud.io/getting-started/github/)
# or reach out to our community forum if you need some help (https://community.sonarsource.com/c/help/sc/9)
name: SonarCloud analysis
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:
permissions:
pull-requests: read # allows SonarCloud to decorate PRs with analysis results
jobs:
Analysis:
runs-on: ubuntu-latest
steps:
- name: Analyze with SonarCloud
# You can pin the exact commit or the version.
# uses: SonarSource/sonarcloud-github-action@v2.2.0
uses: SonarSource/sonarcloud-github-action@4006f663ecaf1f8093e8e4abb9227f6041f52216
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Generate a token on Sonarcloud.io, add it to the secrets of this repo with the name SONAR_TOKEN (Settings > Secrets > Actions > add new repository secret)
with:
# Additional arguments for the SonarScanner CLI
args:
# Unique keys of your project and organization. You can find them in SonarCloud > Information (bottom-left menu)
# mandatory
-Dsonar.projectKey= mihakralj_QuanTAlib
-Dsonar.organization= mihakralj
# Comma-separated paths to directories containing main source files.
#-Dsonar.sources= # optional, default is project base directory
# Comma-separated paths to directories containing test source files.
#-Dsonar.tests= # optional. For more info about Code Coverage, please refer to https://docs.sonarcloud.io/enriching/test-coverage/overview/
# Adds more detail to both client and server-side analysis logs, activating DEBUG mode for the scanner, and adding client-side environment variables and system properties to the server-side log of analysis report processing.
#-Dsonar.verbose= # optional, default is false
# When you need the analysis to take place in a directory other than the one from which it was launched, default is .
projectBaseDir: .
+4
View File
@@ -0,0 +1,4 @@
{
"sonarCloudOrganization": "mihakralj-quantalib",
"projectKey": "mihakralj_QuanTAlib"
}
+17
View File
@@ -0,0 +1,17 @@
{
"sonarlint.connectedMode.connections.sonarcloud": [
{
"organizationKey": "mihakralj",
"token": "6df7cd62a17dc4e1c5532df1da2f49d5a977dd50",
"connectionId": "mihakralj"
}
],
"sarif-viewer.connectToGithubCodeScanning": "on",
"dotnet.dotnetPath": "C:/Program Files/dotnet",
"omnisharp.useModernNet": true,
"omnisharp.sdkPath": "C:/Program Files/dotnet/sdk",
"sonarlint.connectedMode.project": {
"connectionId": "mihakralj",
"projectKey": "mihakralj_QuanTAlib"
}
}
+32 -8
View File
@@ -1,11 +1,12 @@
<Project>
<PropertyGroup>
<NeutralLanguage>en-US</NeutralLanguage>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>preview</LangVersion>
<NoWarn>$(NoWarn);NU1903;NU5104</NoWarn>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Deterministic>true</Deterministic>
<LangVersion>preview</LangVersion>
<NeutralLanguage>en-US</NeutralLanguage>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports>
@@ -21,17 +22,40 @@
<PlatformTarget>AnyCPU</PlatformTarget>
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>link</TrimMode>
<PublishAot>true</PublishAot>
<PublishReadyToRun>true</PublishReadyToRun>
<TieredCompilation>true</TieredCompilation>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
<PublishSingleFile>true</PublishSingleFile>
<DebugSymbols>false</DebugSymbols>
<Deterministic>true</Deterministic>
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
<EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>
<EventSourceSupport>false</EventSourceSupport>
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
<InvariantGlobalization>true</InvariantGlobalization>
<MetadataUpdaterSupport>false</MetadataUpdaterSupport>
<UseSystemResourceKeys>true</UseSystemResourceKeys>
</PropertyGroup>
<PropertyGroup>
<NoWarn>S1944,S2053,S2222,S2259,S2583,S2589,S3329,S3655,S3900,S3949,S3966,S4158,S4347,S5773,S6781</NoWarn>
</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>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All"/>
<PackageReference Include="Microsoft.DotNet.Interactive.Formatting" Version="1.0.0-beta.21459.1" />
</ItemGroup>
<PropertyGroup Condition="'$(IsLocalBuild)' == 'true'">
<!-- Set the correct path to Quantower here -->
<QuantowerRoot>D:\Quantower</QuantowerRoot>
<QuantowerPath>$([System.IO.Directory]::GetDirectories("$(QuantowerRoot)\TradingPlatform", "v1*")[0])</QuantowerPath>
</PropertyGroup>
</Project>
</Project>
+7 -26
View File
@@ -1,37 +1,18 @@
assembly-versioning-scheme: MajorMinorPatch
assembly-file-versioning-scheme: MajorMinorPatch
mode: ContinuousDeployment
tag-prefix: '[vV]?'
next-version: 0.6.1
mode: ContinuousDelivery
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
branches:
main:
regex: ^main$
mode: ContinuousDeployment
label: ''
mode: ContinuousDelivery
increment: Patch
track-merge-target: false
source-branches: []
tracks-release-branches: false
is-release-branch: true
is-main-branch: true
pre-release-weight: 55000
dev:
regex: ^dev(elop)?(ment)?$
mode: ContinuousDelivery
label: dev
increment: Patch
track-merge-target: true
source-branches: ['main']
tracks-release-branches: true
is-release-branch: false
is-main-branch: false
pre-release-weight: 0
mode: ContinuousDeployment
increment: Inherit
ignore:
sha: []
sha: []
merge-message-formats: {}
+37 -29
View File
@@ -1,19 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "quantalib", "lib\quantalib.csproj", "{584E06A9-CEB4-476A-85CC-6A8FF3974AE2}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "quantalib", "lib\quantalib.csproj", "{1E050FA4-630E-4801-9DE9-D2536DACA9B0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{D85FEBB4-B651-466F-85CC-FD902378D4D2}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "quantower", "quantower", "{1B9AC248-76F8-44DD-958D-F1DC08EE1E87}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MovingAverages", "quantower\averages\Averages.csproj", "{32CC09CC-26E3-4FCE-8932-C0513C4AD766}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Statistics", "quantower\Statistics\_Statistics.csproj", "{2E9427C7-144F-488E-A29D-789ACC1C32AE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntheticVendor", "SyntheticVendor\SyntheticVendor.csproj", "{20B1B5F1-8C36-4668-B0AE-951C13AE197B}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Averages", "quantower\Averages\_Averages.csproj", "{6BE10C39-4127-446C-818B-7976FCDD51D5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "quantower", "quantower", "{A8D9AE68-24E3-476C-BB98-244541BB4B43}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volatility", "quantower\Volatility\_Volatility.csproj", "{B7DC44F7-D3A3-4C70-9025-513E0182B646}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Statistics", "quantower\Statistics\Statistics.csproj", "{B6D3EB11-63B6-430F-B526-E1981B3D8214}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntheticVendor", "SyntheticVendor\SyntheticVendor.csproj", "{1CF111D9-33E6-4A11-8FEC-F23300A78D15}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{2D97C971-20BF-40DB-94AA-3279F787D3CB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -24,28 +25,35 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
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
{1E050FA4-630E-4801-9DE9-D2536DACA9B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E050FA4-630E-4801-9DE9-D2536DACA9B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E050FA4-630E-4801-9DE9-D2536DACA9B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E050FA4-630E-4801-9DE9-D2536DACA9B0}.Release|Any CPU.Build.0 = Release|Any CPU
{2E9427C7-144F-488E-A29D-789ACC1C32AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E9427C7-144F-488E-A29D-789ACC1C32AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E9427C7-144F-488E-A29D-789ACC1C32AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E9427C7-144F-488E-A29D-789ACC1C32AE}.Release|Any CPU.Build.0 = Release|Any CPU
{6BE10C39-4127-446C-818B-7976FCDD51D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6BE10C39-4127-446C-818B-7976FCDD51D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6BE10C39-4127-446C-818B-7976FCDD51D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6BE10C39-4127-446C-818B-7976FCDD51D5}.Release|Any CPU.Build.0 = Release|Any CPU
{B7DC44F7-D3A3-4C70-9025-513E0182B646}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B7DC44F7-D3A3-4C70-9025-513E0182B646}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7DC44F7-D3A3-4C70-9025-513E0182B646}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B7DC44F7-D3A3-4C70-9025-513E0182B646}.Release | Any CPU.ActiveCfg = Release | Any CPU
{B7DC44F7-D3A3-4C70-9025-513E0182B646}.Release | Any CPU.Build.0 = Release | Any CPU
{1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Debug | Any CPU.ActiveCfg = Debug | Any CPU
{1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Debug | Any CPU.Build.0 = Debug | Any CPU
{1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Release | Any CPU.ActiveCfg = Release | Any CPU
{1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Release | Any CPU.Build.0 = Release | Any CPU
{2D97C971-20BF-40DB-94AA-3279F787D3CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D97C971-20BF-40DB-94AA-3279F787D3CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D97C971-20BF-40DB-94AA-3279F787D3CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D97C971-20BF-40DB-94AA-3279F787D3CB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{B6D3EB11-63B6-430F-B526-E1981B3D8214} = {A8D9AE68-24E3-476C-BB98-244541BB4B43}
{2E9427C7-144F-488E-A29D-789ACC1C32AE} = {1B9AC248-76F8-44DD-958D-F1DC08EE1E87}
{6BE10C39-4127-446C-818B-7976FCDD51D5} = {1B9AC248-76F8-44DD-958D-F1DC08EE1E87}
{B7DC44F7-D3A3-4C70-9025-513E0182B646} = {1B9AC248-76F8-44DD-958D-F1DC08EE1E87}
EndGlobalSection
EndGlobal
File diff suppressed because it is too large Load Diff
+1
View File
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AlgoType>Vendor</AlgoType>
<AssemblyVersion>0.0.0.0</AssemblyVersion>
</PropertyGroup>
<ItemGroup>
+23 -12
View File
@@ -1,35 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>QuanTAlib.Tests</RootNamespace>
<AssemblyName>QuanTAlib.Tests</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="coverlet.collector" Version="6.0.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.0-pre.35">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="xunit.runner.console" Version="2.9.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<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="Tulip.NETCore" Version="0.8.0.1" />
<PackageReference Include="Trady.Analysis" Version="3.2.8" />
<!--
<PackageReference Include="quantconnect.indicators" Version="2.5.16573" />
<PackageReference Include="stocksharp.algo" Version="5.0.193" />
<PackageReference Include="OoplesFinance.StockIndicators" Version="1.0.53" />
-->
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\lib\quantalib.csproj" />
<Reference Include="TradingPlatform.BusinessLayer">
<HintPath>..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
</Reference>
<None Include="..\.github\TradingPlatform.BusinessLayer.xml">
<Link>TradingPlatform.BusinessLayer.xml</Link>
</None>
</ItemGroup>
</Project>
<ItemGroup>
<ProjectReference Include="..\lib\*.csproj" />
<ProjectReference Include="..\quantower\Volatility\_Volatility.csproj" Aliases="volatility" />
<ProjectReference Include="..\quantower\Averages\_Averages.csproj" Aliases="averages" />
<ProjectReference Include="..\quantower\Statistics\_Statistics.csproj" Aliases="statistics" />
</ItemGroup>
</Project>
+40 -29
View File
@@ -2,21 +2,26 @@ using Xunit;
using Trady.Analysis.Indicator;
using Trady.Core;
using Trady.Core.Infrastructure;
using QuanTAlib;
using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
#pragma warning disable S1944, S2053, S2222, S2259, S2583, S2589, S3329, S3655, S3900, S3949, S3966, S4158, S4347, S5773, S6781
namespace QuanTAlib;
public class TradyTests
{
private readonly TBarSeries bars;
private readonly GbmFeed feed;
private Random rnd;
private readonly RandomNumberGenerator rng;
private readonly double range;
private int period, iterations;
private int skip;
private IEnumerable<IOhlcv> Candles;
private readonly int iterations;
private readonly int skip;
private readonly IEnumerable<IOhlcv> Candles;
public TradyTests()
{
rnd = new((int)DateTime.Now.Ticks);
rng = RandomNumberGenerator.Create();
feed = new(sigma: 0.5, mu: 0.0);
bars = new(feed);
range = 1e-9;
@@ -33,31 +38,39 @@ public class TradyTests
)).ToList();
}
private int GetRandomNumber(int minValue, int maxValue)
{
byte[] randomBytes = new byte[4];
rng.GetBytes(randomBytes);
int randomInt = BitConverter.ToInt32(randomBytes, 0);
return Math.Abs(randomInt % (maxValue - minValue)) + minValue;
}
[Fact]
public void SMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
int period = GetRandomNumber(5, 55);
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();
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;
double Tr_item = Trady[i].Value;
Assert.InRange(Tr_item - QL_item, -range, range);
}
}
@@ -68,30 +81,28 @@ public class TradyTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
int period = GetRandomNumber(5, 55);
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();
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--)
for (int i = QL.Length - 1; i > skip * 2; i--)
{
double QL_item = QL[i].Value;
double Tr_item = Trady[i].Value;
double Tr_item = Trady[i].Value;
Assert.InRange(Tr_item - QL_item, -range, range);
}
}
}
}
+25 -19
View File
@@ -1,23 +1,26 @@
using Xunit;
using Tulip;
using QuanTAlib;
using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
#pragma warning disable S1944, S2053, S2222, S2259, S2583, S2589, S3329, S3655, S3900, S3949, S3966, S4158, S4347, S5773, S6781
namespace QuanTAlib;
public class TulipTests
{
private readonly TBarSeries bars;
private readonly GbmFeed feed;
private Random rnd;
private readonly RandomNumberGenerator rng;
private readonly double range;
private int period, iterations;
private readonly int iterations;
private readonly double[] data;
private readonly double[] outdata;
private int skip;
private readonly int skip;
public TulipTests()
{
rnd = new((int)DateTime.Now.Ticks);
rng = RandomNumberGenerator.Create();
feed = new(sigma: 0.5, mu: 0.0);
bars = new(feed);
range = 1e-9;
feed.Add(10000);
iterations = 3;
@@ -26,12 +29,20 @@ public class TulipTests
outdata = new double[data.Count()];
}
private int GetRandomNumber(int minValue, int maxValue)
{
byte[] randomBytes = new byte[4];
rng.GetBytes(randomBytes);
int randomInt = BitConverter.ToInt32(randomBytes, 0);
return Math.Abs(randomInt % (maxValue - minValue)) + minValue;
}
[Fact]
public void SMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
int period = GetRandomNumber(5, 55);
Sma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -44,7 +55,7 @@ public class TulipTests
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];
double TU = i < period - 1 ? double.NaN : arrout[0][i - period + 1];
Assert.InRange(TU - QL_item, -range, range);
}
}
@@ -55,28 +66,23 @@ public class TulipTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = 20;
int period = GetRandomNumber(5, 35);
Ema ma = new(period, useSma: false);
TSeries QL = new();
foreach (TBar item in feed)
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
{ 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
Assert.Equal(QL.Length, arrout[0].Length);
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}");
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
@@ -1,883 +0,0 @@
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);
}
}
}
+102
View File
@@ -0,0 +1,102 @@
using Xunit;
using System.Security.Cryptography;
#pragma warning disable S1944, S2053, S2222, S2259, S2583, S2589, S3329, S3655, S3900, S3949, S3966, S4158, S4347, S5773, S6781
namespace QuanTAlib;
public class EventingTests
{
[Fact]
public void EventBasedCalculations()
{
// Create a cryptographically secure random number generator
using var rng = RandomNumberGenerator.Create();
// Create an input series to hold our random values
var input = new TSeries();
int p = 10;
// Create a list of indicator pairs (direct calculation and event-based) with names
var indicators = new List<(string Name, AbstractBase Direct, AbstractBase EventBased)>
{
("Afirma", new Afirma(p,p,Afirma.WindowType.BlackmanHarris), new Afirma(input, p,p,Afirma.WindowType.BlackmanHarris)),
("Alma", new Alma(p), new Alma(input, p)),
("Convolution", new Convolution(new double[] {1,2,3,2,1}), new Convolution(input, new double[] {1,2,3,2,1})),
("Dema", new Dema(p), new Dema(input, p)),
("Dsma", new Dsma(p), new Dsma(input, p)),
("Dwma", new Dwma(p), new Dwma(input, p)),
("Ema", new Ema(p), new Ema(input, p)),
("Epma", new Epma(p), new Epma(input, p)),
("Pwma", new Pwma(p), new Pwma(input, p)),
("Frama", new Frama(p), new Frama(input, p)),
("Fwma", new Fwma(p), new Fwma(input, p)),
("Gma", new Gma(p), new Gma(input, p)),
("Hma", new Hma(p), new Hma(input, p)),
("Htit", new Htit(), new Htit(input)),
("Hwma", new Hwma(p), new Hwma(input, p)),
("Jma", new Jma(p), new Jma(input, p)),
("Kama", new Kama(p), new Kama(input, p)),
("Ltma", new Ltma(gamma: 0.2), new Ltma(input, gamma: 0.2)),
("Maaf", new Maaf(p), new Maaf(input, p)),
("Mama", new Mama(p), new Mama(input, p)),
("Mgdi", new Mgdi(p, kFactor: 0.6), new Mgdi(input, p, kFactor: 0.6)),
("Mma", new Mma(p), new Mma(input, p)),
("Qema", new Qema(k1: 0.2, k2: 0.2, k3: 0.2, k4: 0.2), new Qema(input, k1: 0.2, k2: 0.2, k3: 0.2, k4: 0.2)),
("Rema", new Rema(p), new Rema(input, p)),
("Rma", new Rma(p), new Rma(input, p)),
("Sma", new Sma(p), new Sma(input, p)),
("Wma", new Wma(p), new Wma(input, p)),
("Rma", new Rma(p), new Rma(input, p)),
("Tema", new Tema(p), new Tema(input, p)),
("Kama", new Kama(2, 30, 6), new Kama(input, 2, 30, 6)),
("Zlema", new Zlema(p), new Zlema(input, p)),
// error classes
("Mae", new Mae(p), new Mae(input, p)),
("Mapd", new Mapd(p), new Mapd(input, p)),
("Mape", new Mape(p), new Mape(input, p)),
("Mase", new Mase(p), new Mase(input, p)),
("Mda", new Mda(p), new Mda(input, p)),
("Me", new Me(p), new Me(input, p)),
("Mpe", new Mpe(p), new Mpe(input, p)),
("Mse", new Mse(p), new Mse(input, p)),
("Msle", new Msle(p), new Msle(input, p)),
("Rae", new Rae(p), new Rae(input, p)),
("Rmse", new Rmse(p), new Rmse(input, p)),
("Rmsle", new Rmsle(p), new Rmsle(input, p)),
("Rse", new Rse(p), new Rse(input, p)),
("Smape", new Smape(p), new Smape(input, p)),
("Rsquared", new Rsquared(p), new Rsquared(input, p)),
("Huberloss", new Huberloss(p), new Huberloss(input, p))
};
// Generate 200 random values and feed them to both direct and event-based indicators
for (int i = 0; i < 200; i++)
{
double randomValue = GetRandomDouble(rng) * 100;
input.Add(randomValue);
// Calculate direct indicators
foreach (var (_, direct, _) in indicators)
{
direct.Calc(randomValue);
}
}
// Compare the results of direct and event-based calculations
for (int i = 0; i < indicators.Count; i++)
{
var (name, direct, eventBased) = indicators[i];
bool areEqual = (double.IsNaN(direct.Value) && double.IsNaN(eventBased.Value)) ||
Math.Abs(direct.Value - eventBased.Value) < 1e-9;
Assert.True(areEqual, $"Indicator {name} failed: Expected {direct.Value}, Actual {eventBased.Value}");
}
}
private static double GetRandomDouble(RandomNumberGenerator rng)
{
byte[] bytes = new byte[8];
rng.GetBytes(bytes);
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue;
}
}
+170
View File
@@ -0,0 +1,170 @@
using Xunit;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
namespace QuanTAlib;
/// <summary>
/// Contains unit tests for bar-based indicators in QuanTAlib.
/// </summary>
public class BarIndicatorTests
{
private readonly RandomNumberGenerator rng;
private const int SeriesLen = 1000;
private const int Corrections = 100;
/// <summary>
/// Initializes a new instance of the BarIndicatorTests class.
/// </summary>
public BarIndicatorTests()
{
rng = RandomNumberGenerator.Create();
}
private static readonly ITValue[] indicators = new ITValue[]
{
new Atr(period: 14),
// Add other TBar-based indicators here
};
/// <summary>
/// Tests if the indicator produces consistent results when processing new and updated bars.
/// </summary>
/// <param name="indicator">The indicator to test.</param>
[Theory]
[MemberData(nameof(GetIndicators))]
public void IndicatorIsNew(ITValue indicator)
{
var indicator1 = indicator;
var indicator2 = indicator;
MethodInfo calcMethod = FindCalcMethod(indicator.GetType());
if (calcMethod == null)
{
throw new InvalidOperationException($"Calc method not found for indicator type: {indicator.GetType().Name}");
}
for (int i = 0; i < SeriesLen; i++)
{
TBar item1 = GenerateRandomBar(isNew: true);
InvokeCalc(indicator1, calcMethod, item1);
for (int j = 0; j < Corrections; j++)
{
item1 = GenerateRandomBar(isNew: false);
InvokeCalc(indicator1, calcMethod, item1);
}
var item2 = new TBar(item1.Time, item1.Open, item1.High, item1.Low, item1.Close, item1.Volume, IsNew: true);
InvokeCalc(indicator2, calcMethod, item2);
Assert.Equal(indicator1.Value, indicator2.Value);
}
}
/// <summary>
/// Finds the appropriate Calc method for the given indicator type.
/// </summary>
/// <param name="type">The type of the indicator.</param>
/// <returns>The MethodInfo for the Calc method.</returns>
private static MethodInfo FindCalcMethod(Type type)
{
while (type != null && type != typeof(object))
{
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Where(m => m.Name == "Calc")
.ToList();
if (methods.Count > 0)
{
// Prefer the method with TBar parameter
var method = methods.Find(m =>
{
var parameters = m.GetParameters();
return parameters.Length == 1 && parameters[0].ParameterType == typeof(TBar);
});
// If not found, return the first method
return method ?? methods[0];
}
type = type.BaseType!;
}
return null!;
}
/// <summary>
/// Invokes the Calc method on the given indicator with the provided input.
/// </summary>
/// <param name="indicator">The indicator instance.</param>
/// <param name="calcMethod">The Calc method to invoke.</param>
/// <param name="input">The input TBar.</param>
private static void InvokeCalc(ITValue indicator, MethodInfo calcMethod, TBar input)
{
var parameters = calcMethod.GetParameters();
if (parameters.Length == 1)
{
calcMethod.Invoke(indicator, new object[] { input });
}
else if (parameters.Length == 2)
{
calcMethod.Invoke(indicator, new object[] { input, double.NaN });
}
else
{
throw new InvalidOperationException($"Invalid number of parameters for Calc method in indicator type: {indicator.GetType().Name}");
}
}
/// <summary>
/// Generates a random TBar for testing purposes.
/// </summary>
/// <param name="isNew">Indicates whether the generated bar should be marked as new.</param>
/// <returns>A randomly generated TBar.</returns>
private TBar GenerateRandomBar(bool isNew)
{
double open = GetRandomDouble() * 200 - 100;
double close = GetRandomDouble() * 200 - 100;
double high = Math.Max(open, close) + GetRandomDouble() * 10;
double low = Math.Min(open, close) - GetRandomDouble() * 10;
long volume = GetRandomNumber(0, 10000);
return new TBar(Time: DateTime.Now, Open: open, High: high, Low: low, Close: close, Volume: volume, IsNew: isNew);
}
/// <summary>
/// Generates a random double between 0 and 1.
/// </summary>
/// <returns>A random double between 0 and 1.</returns>
private double GetRandomDouble()
{
byte[] bytes = new byte[8];
rng.GetBytes(bytes);
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue;
}
/// <summary>
/// Generates a random integer between minValue (inclusive) and maxValue (exclusive).
/// </summary>
/// <param name="minValue">The minimum value (inclusive).</param>
/// <param name="maxValue">The maximum value (exclusive).</param>
/// <returns>A random integer between minValue and maxValue.</returns>
private int GetRandomNumber(int minValue, int maxValue)
{
byte[] randomBytes = new byte[4];
rng.GetBytes(randomBytes);
int randomInt = BitConverter.ToInt32(randomBytes, 0);
return Math.Abs(randomInt % (maxValue - minValue)) + minValue;
}
/// <summary>
/// Provides the list of indicators for parameterized tests.
/// </summary>
/// <returns>An enumerable of object arrays, each containing an indicator instance.</returns>
public static IEnumerable<object[]> GetIndicators()
{
return indicators.Select(indicator => new object[] { indicator });
}
}
+103
View File
@@ -0,0 +1,103 @@
extern alias volatility;
extern alias averages;
extern alias statistics;
using Xunit;
using System.Reflection;
using TradingPlatform.BusinessLayer;
using statistics::QuanTAlib;
using averages::QuanTAlib;
using volatility::QuanTAlib;
namespace QuanTAlib
{
public class QuantowerTests
{
private static void TestIndicator<T>(string fieldName = "ma") where T : Indicator, new()
{
var indicator = new T();
try
{
var onInitMethod = typeof(T).GetMethod("OnInit", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(onInitMethod);
onInitMethod.Invoke(indicator, null);
var onUpdateMethod = typeof(T).GetMethod("OnUpdate", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(onUpdateMethod);
var field = typeof(T).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(field);
var fieldValue = field.GetValue(indicator);
Assert.NotNull(fieldValue);
Assert.NotNull(indicator.ShortName);
Assert.NotEmpty(indicator.ShortName);
Assert.NotNull(indicator.Name);
Assert.NotEmpty(indicator.Name);
Assert.NotNull(indicator.Description);
Assert.NotEmpty(indicator.Description);
Assert.IsAssignableFrom<Indicator>(indicator);
}
catch (Exception ex)
{
throw new Xunit.Sdk.XunitException($"Test failed for {typeof(T).Name}: {ex.Message}");
}
}
// Averages Indicators
[Fact] public void Afirma() => TestIndicator<AfirmaIndicator>();
[Fact] public void Alma() => TestIndicator<AlmaIndicator>();
[Fact] public void Dema() => TestIndicator<DemaIndicator>();
[Fact] public void Dsma() => TestIndicator<DsmaIndicator>();
[Fact] public void Dwma() => TestIndicator<DwmaIndicator>();
[Fact] public void Ema() => TestIndicator<EmaIndicator>();
[Fact] public void Epma() => TestIndicator<EpmaIndicator>();
[Fact] public void Frama() => TestIndicator<FramaIndicator>();
[Fact] public void Fwma() => TestIndicator<FwmaIndicator>();
[Fact] public void Gma() => TestIndicator<GmaIndicator>();
[Fact] public void Hma() => TestIndicator<HmaIndicator>();
[Fact] public void Htit() => TestIndicator<HtitIndicator>();
[Fact] public void Hwma() => TestIndicator<HwmaIndicator>();
[Fact] public void Jma() => TestIndicator<JmaIndicator>();
[Fact] public void Kama() => TestIndicator<KamaIndicator>();
[Fact] public void Ltma() => TestIndicator<LtmaIndicator>();
[Fact] public void Maaf() => TestIndicator<MaafIndicator>();
[Fact] public void Mama() => TestIndicator<MamaIndicator>();
[Fact] public void Mgdi() => TestIndicator<MgdiIndicator>();
[Fact] public void Mma() => TestIndicator<MmaIndicator>();
[Fact] public void Pwma() => TestIndicator<PwmaIndicator>();
[Fact] public void Qema() => TestIndicator<QemaIndicator>();
[Fact] public void Rema() => TestIndicator<RemaIndicator>();
[Fact] public void Rma() => TestIndicator<RmaIndicator>();
[Fact] public void Sinema() => TestIndicator<SinemaIndicator>();
[Fact] public void Sma() => TestIndicator<SmaIndicator>();
[Fact] public void Smma() => TestIndicator<SmmaIndicator>();
[Fact] public void T3() => TestIndicator<T3Indicator>();
[Fact] public void Tema() => TestIndicator<TemaIndicator>();
[Fact] public void Trima() => TestIndicator<TrimaIndicator>();
[Fact] public void Vidya() => TestIndicator<VidyaIndicator>();
[Fact] public void Wma() => TestIndicator<WmaIndicator>();
[Fact] public void Zlema() => TestIndicator<ZlemaIndicator>();
// Statistics Indicators
[Fact] public void Curvature() => TestIndicator<CurvatureIndicator>("curvature");
[Fact] public void Entropy() => TestIndicator<EntropyIndicator>("entropy");
[Fact] public void Kurtosis() => TestIndicator<KurtosisIndicator>("kurtosis");
[Fact] public void Max() => TestIndicator<MaxIndicator>("ma");
[Fact] public void Median() => TestIndicator<MedianIndicator>("med");
[Fact] public void Min() => TestIndicator<MinIndicator>("mi");
[Fact] public void Mode() => TestIndicator<ModeIndicator>("mode");
[Fact] public void Percentile() => TestIndicator<PercentileIndicator>("percentile");
[Fact] public void Skew() => TestIndicator<SkewIndicator>("skew");
[Fact] public void Slope() => TestIndicator<SlopeIndicator>("slope");
[Fact] public void Stddev() => TestIndicator<StddevIndicator>("stddev");
[Fact] public void Variance() => TestIndicator<VarianceIndicator>("variance");
[Fact] public void Zscore() => TestIndicator<ZscoreIndicator>("zScore");
// Volatility Indicators
[Fact] public void Atr() => TestIndicator<AtrIndicator>("atr");
[Fact] public void Historical() => TestIndicator<HistoricalIndicator>("historical");
[Fact] public void Realized() => TestIndicator<RealizedIndicator>("realized");
[Fact] public void Rvi() => TestIndicator<RviIndicator>("rvi");
}
}
+52 -22
View File
@@ -1,25 +1,29 @@
using Xunit;
using Skender.Stock.Indicators;
using QuanTAlib;
using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
#pragma warning disable S1944, S2053, S2222, S2259, S2583, S2589, S3329, S3655, S3900, S3949, S3966, S4158, S4347, S5773, S6781
namespace QuanTAlib.Tests;
public class SkenderTests
{
private readonly TBarSeries bars;
private readonly GbmFeed feed;
private Random rnd;
private readonly RandomNumberGenerator rng;
private readonly double range;
private int period, iterations;
private int period;
private readonly int iterations = 3; // Initialized directly at declaration
private readonly IEnumerable<Quote> quotes;
public SkenderTests()
{
rnd = new((int)DateTime.Now.Ticks);
rng = RandomNumberGenerator.Create();
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,
@@ -31,12 +35,20 @@ public class SkenderTests
});
}
private int GetRandomNumber(int minValue, int maxValue)
{
byte[] randomBytes = new byte[4];
rng.GetBytes(randomBytes);
int randomInt = BitConverter.ToInt32(randomBytes, 0);
return Math.Abs(randomInt % (maxValue - minValue)) + minValue;
}
[Fact]
public void SMA()
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
Sma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -55,7 +67,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
Ema ma = new(period, useSma: true);
TSeries QL = new();
foreach (TBar item in feed)
@@ -74,7 +86,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
Ema ma = new(period, useSma: false);
TSeries QL = new();
foreach (TBar item in feed)
@@ -93,7 +105,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
Dema ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -112,7 +124,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
Tema ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -131,7 +143,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
double[] kernel = Enumerable.Repeat(1.0, period).ToArray();
Convolution ma = new(kernel);
TSeries QL = new();
@@ -151,7 +163,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
Wma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -170,7 +182,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
Hma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -189,7 +201,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
Epma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -208,7 +220,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
Alma ma = new(period, offset: 0.85, sigma: 6);
TSeries QL = new();
foreach (TBar item in feed)
@@ -227,7 +239,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
T3 ma = new(period, vfactor: 0.7, useSma: false);
TSeries QL = new();
foreach (TBar item in feed)
@@ -246,7 +258,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
Smma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -265,7 +277,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
Kama ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -284,7 +296,6 @@ public class SkenderTests
{
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)
@@ -305,7 +316,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
period = GetRandomNumber(5, 55);
Mgdi ma = new(period: period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -321,4 +332,23 @@ public class SkenderTests
}
}
}
[Fact]
public void ATR()
{
for (int run = 0; run < iterations; run++)
{
period = GetRandomNumber(5, 55);
Atr ma = new(period: period);
TSeries QL = new();
foreach (TBar item in bars) { QL.Add(ma.Calc(item)); }
var atrValues = quotes.GetAtr(lookbackPeriods: period).Select(i => i.Atr.Null2NaN()!);
const int AdditionalPeriods = 500;
for (int i = QL.Length - 1; i > 1000 + AdditionalPeriods; i--)
{
Assert.InRange(atrValues.ElementAt(i) - QL[i].Value, -range, range);
}
}
}
}
+26 -48
View File
@@ -1,29 +1,36 @@
using Xunit;
using TALib;
using QuanTAlib;
using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
namespace QuanTAlib;
public class TAlibTests
{
private readonly TBarSeries bars;
private readonly GbmFeed feed;
private Random rnd;
private readonly RandomNumberGenerator rng;
private readonly double range;
private int period, iterations;
private readonly int iterations;
private readonly double[] data;
private readonly double[] TALIB;
public TAlibTests()
{
rnd = new((int)DateTime.Now.Ticks);
rng = RandomNumberGenerator.Create();
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()];
}
private int GetRandomNumber(int minValue, int maxValue)
{
byte[] randomBytes = new byte[4];
rng.GetBytes(randomBytes);
int randomInt = BitConverter.ToInt32(randomBytes, 0);
return Math.Abs(randomInt % (maxValue - minValue)) + minValue;
}
[Fact]
@@ -31,7 +38,7 @@ public class TAlibTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
int period = GetRandomNumber(5, 55);
Sma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -40,7 +47,6 @@ public class TAlibTests
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);
}
}
@@ -51,7 +57,7 @@ public class TAlibTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
int period = GetRandomNumber(5, 55);
Ema ma = new(period, useSma: true);
TSeries QL = new();
foreach (TBar item in feed)
@@ -60,7 +66,6 @@ public class TAlibTests
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);
}
}
@@ -71,16 +76,15 @@ public class TAlibTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
int period = GetRandomNumber(5, 55);
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--)
Assert.Equal(QL.Length, TALIB.Length);
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);
}
}
@@ -91,62 +95,36 @@ public class TAlibTests
{
for (int run = 0; run < iterations; run++)
{
period = rnd.Next(50) + 5;
int period = GetRandomNumber(5, 55);
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--)
Assert.Equal(QL.Length, TALIB.Length);
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;
int period = GetRandomNumber(5, 55);
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--)
Core.T3(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, optInTimePeriod: period, optInVFactor: 0.7);
Assert.Equal(QL.Length, TALIB.Length);
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);
}
}
}
}
+529
View File
@@ -0,0 +1,529 @@
using Xunit;
using System.Security.Cryptography;
namespace QuanTAlib.Tests;
public class AveragesUpdateTests
{
private readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
private const int RandomUpdates = 100;
private const double ReferenceValue = 100.0;
private const int precision = 8;
private double GetRandomDouble()
{
byte[] bytes = new byte[8];
rng.GetBytes(bytes);
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue * 200 - 100; // Range: -100 to 100
}
[Fact]
public void Afirma_Update()
{
var indicator = new Afirma(periods: 14, taps: 4, window: Afirma.WindowType.Blackman);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Alma_Update()
{
var indicator = new Alma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Convolution_Update()
{
var indicator = new Convolution(new double[] { 1, 2, 3, 2, 1 });
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Dema_Update()
{
var indicator = new Dema(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Dsma_Update()
{
var indicator = new Dsma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Dwma_Update()
{
var indicator = new Dwma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Ema_Update()
{
var indicator = new Ema(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Epma_Update()
{
var indicator = new Epma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Frama_Update()
{
var indicator = new Frama(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Fwma_Update()
{
var indicator = new Fwma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Gma_Update()
{
var indicator = new Gma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Hma_Update()
{
var indicator = new Hma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Htit_Update()
{
var indicator = new Htit();
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Hwma_Update()
{
var indicator = new Hwma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Jma_Update()
{
var indicator = new Jma(period: 14, phase: 0);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Kama_Update()
{
var indicator = new Kama(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Ltma_Update()
{
var indicator = new Ltma(gamma: 0.2);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Maaf_Update()
{
var indicator = new Maaf(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mama_Update()
{
var indicator = new Mama(fastLimit: 0.5, slowLimit: 0.05);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mgdi_Update()
{
var indicator = new Mgdi(period: 14, kFactor: 0.6);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mma_Update()
{
var indicator = new Mma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Pwma_Update()
{
var indicator = new Pwma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Qema_Update()
{
var indicator = new Qema(k1: 0.2, k2: 0.2, k3: 0.2, k4: 0.2);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rema_Update()
{
var indicator = new Rema(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rma_Update()
{
var indicator = new Rma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Sinema_Update()
{
var indicator = new Sinema(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Sma_Update()
{
var indicator = new Sma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Smma_Update()
{
var indicator = new Smma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void T3_Update()
{
var indicator = new T3(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Tema_Update()
{
var indicator = new Tema(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Trima_Update()
{
var indicator = new Trima(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Vidya_Update()
{
var indicator = new Vidya(shortPeriod: 14, longPeriod: 30, alpha: 0.2);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Wma_Update()
{
var indicator = new Wma(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Zlema_Update()
{
var indicator = new Zlema(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
}
+259
View File
@@ -0,0 +1,259 @@
using Xunit;
using System.Security.Cryptography;
namespace QuanTAlib.Tests;
public class UpdateTests
{
private readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
private const int RandomUpdates = 100;
private const double ReferenceValue = 100.0;
private const int precision = 8;
private double GetRandomDouble()
{
byte[] bytes = new byte[8];
rng.GetBytes(bytes);
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue * 200 - 100; // Range: -100 to 100
}
[Fact]
public void Huberloss_Update()
{
var indicator = new Huberloss(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mae_Update()
{
var indicator = new Mae(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mapd_Update()
{
var indicator = new Mapd(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mape_Update()
{
var indicator = new Mape(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mase_Update()
{
var indicator = new Mase(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mda_Update()
{
var indicator = new Mda(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Me_Update()
{
var indicator = new Me(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mpe_Update()
{
var indicator = new Mpe(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mse_Update()
{
var indicator = new Mse(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Msle_Update()
{
var indicator = new Msle(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rae_Update()
{
var indicator = new Rae(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rmse_Update()
{
var indicator = new Rmse(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rmsle_Update()
{
var indicator = new Rmsle(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rse_Update()
{
var indicator = new Rse(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Smape_Update()
{
var indicator = new Smape(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rsquared_Update()
{
var indicator = new Rsquared(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
}
+214
View File
@@ -0,0 +1,214 @@
using Xunit;
using System.Security.Cryptography;
namespace QuanTAlib.Tests;
public class StatisticsUpdateTests
{
private readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
private const int RandomUpdates = 100;
private const double ReferenceValue = 100.0;
private const int precision = 8;
private double GetRandomDouble()
{
byte[] bytes = new byte[8];
rng.GetBytes(bytes);
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue * 200 - 100; // Range: -100 to 100
}
[Fact]
public void Curvature_Update()
{
var indicator = new Curvature(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Entropy_Update()
{
var indicator = new Entropy(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Kurtosis_Update()
{
var indicator = new Kurtosis(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Max_Update()
{
var indicator = new Max(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Median_Update()
{
var indicator = new Median(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Min_Update()
{
var indicator = new Min(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Mode_Update()
{
var indicator = new Mode(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Percentile_Update()
{
var indicator = new Percentile(period: 14, percent: 50);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Skew_Update()
{
var indicator = new Skew(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Slope_Update()
{
var indicator = new Slope(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Stddev_Update()
{
var indicator = new Stddev(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Variance_Update()
{
var indicator = new Variance(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Zscore_Update()
{
var indicator = new Zscore(period: 14);
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
}
+89
View File
@@ -0,0 +1,89 @@
using Xunit;
using System.Security.Cryptography;
namespace QuanTAlib.Tests;
public class VolatilityUpdateTests
{
private readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
private const int RandomUpdates = 100;
private const double ReferenceValue = 100.0;
private const int precision = 8;
private double GetRandomDouble()
{
byte[] bytes = new byte[8];
rng.GetBytes(bytes);
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue * 200 - 100; // Range: -100 to 100
}
private TBar GetRandomBar(bool IsNew)
{
double open = GetRandomDouble();
double high = open + Math.Abs(GetRandomDouble());
double low = open - Math.Abs(GetRandomDouble());
double close = low + (high - low) * GetRandomDouble();
return new TBar(DateTime.Now, open, high, low, close, 1000, IsNew);
}
[Fact]
public void Atr_Update()
{
var indicator = new Atr(period: 14);
TBar r = GetRandomBar(true);
double initialValue = indicator.Calc(r);
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(GetRandomBar(IsNew: false));
}
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Historical_Update()
{
var indicator = new Historical(period: 14);
double initialValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(GetRandomBar(false));
}
double finalValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Realized_Update()
{
var indicator = new Realized(period: 14);
double initialValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(GetRandomBar(false));
}
double finalValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Rvi_Update()
{
var indicator = new Rvi(period: 14);
double initialValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(GetRandomBar(false));
}
double finalValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
}
-16
View File
@@ -1,16 +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
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
-358
View File
@@ -1,358 +0,0 @@
## 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
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
.vscode/
.fleet/
*.deps.json
.Sandbox/
#.sonarlint/
.DS_Store
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
dotCover.Output.dcvr
/Tests/GlobalSuppressions.cs
-237
View File
@@ -1,237 +0,0 @@
using System;
public readonly record struct TValue(DateTime Time, double Value, bool IsNew = true, bool IsHot = true)
{
public DateTime Time { get; init; } = Time;
public double Value { get; init; } = Value;
public bool IsNew { get; init; } = IsNew;
public bool IsHot { get; init; } = IsHot;
public TValue() : this(DateTime.UtcNow, 0) { }
public TValue(double value) : this(DateTime.UtcNow, value) { }
public TValue((DateTime time, double value) tuple) : this(tuple.time, tuple.value) { }
public static implicit operator double(TValue tv) => tv.Value;
public static implicit operator DateTime(TValue tv) => tv.Time;
public static implicit operator TValue(double value) => new TValue(DateTime.UtcNow, value);
public override string ToString() => $"[{Time:yyyy-MM-dd HH:mm:ss}: {Value:F2}]";
}
public readonly record struct TBar(DateTime Time, double Open, double High, double Low, double Close, double Volume, bool IsNew = true)
{
public DateTime Time { get; init; } = Time;
public double Open { get; init; } = Open;
public double High { get; init; } = High;
public double Low { get; init; } = Low;
public double Close { get; init; } = Close;
public double Volume { get; init; } = Volume;
public bool IsNew { get; init; } = IsNew;
public TBar() : this(DateTime.UtcNow, 0, 0, 0, 0, 0) { }
public TBar(double open, double high, double low, double close, double volume) : this(DateTime.UtcNow, open, high, low, close, volume) { }
public TBar((DateTime time, double open, double high, double low, double close, double volume) tuple) : this(tuple.time, tuple.open, tuple.high, tuple.low, tuple.close, tuple.volume) { }
public override string ToString() => $"[{Time:yyyy-MM-dd HH:mm:ss}: O={Open:F2}, H={High:F2}, L={Low:F2}, C={Close:F2}, V={Volume:F2}]";
}
/////////////////////
///
/////////////////////
public class GBM_Feed
{
private readonly double _mu;
private readonly double _sigma;
private readonly Random _random;
private double _lastClose;
private double _lastHigh;
private double _lastLow;
public GBM_Feed(double initialPrice, double mu, double sigma)
{
_lastClose = initialPrice;
_lastHigh = initialPrice;
_lastLow = initialPrice;
_mu = mu;
_sigma = sigma;
_random = Random.Shared;
}
public TBar Generate(bool IsNew = true)
{
DateTime time = DateTime.UtcNow;
double dt = 1.0 / 252; // Assuming daily steps in a trading year of 252 days
double drift = (_mu - 0.5 * _sigma * _sigma) * dt;
double diffusion = _sigma * Math.Sqrt(dt) * NormalRandom();
double newClose = _lastClose * Math.Exp(drift + diffusion);
double open = _lastClose;
double high = Math.Max(open, newClose) * (1 + _random.NextDouble() * 0.01);
double low = Math.Min(open, newClose) * (1 - _random.NextDouble() * 0.01);
double volume = 1000 + _random.NextDouble() * 1000; // Random volume between 1000 and 2000
if (!IsNew)
{
high = Math.Max(_lastHigh, high);
low = Math.Min(_lastLow, low);
}
else
{
_lastClose = newClose;
}
_lastHigh = high;
_lastLow = low;
return new TBar(time, open, high, low, newClose, volume, IsNew);
}
private double NormalRandom()
{
// Box-Muller transform to generate standard normal random variable
double u1 = 1.0 - _random.NextDouble(); // Uniform(0,1] random doubles
double u2 = 1.0 - _random.NextDouble();
return Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
}
}
/// <summary>
/// ////////////////
/// </summary>
public class EMA
{
private double lastEma, lastEmaCandidate, k;
private int period, i;
public TValue Value { get; private set; }
public bool IsHot { get; private set; }
public EMA(int period) {
Init(period);
}
public void Init(int period)
{
this.period = period;
this.k = 2.0 / (period + 1);
this.lastEma = this.lastEmaCandidate = double.NaN;
this.i = 0;
}
public TValue Update(TValue input, bool IsNew = true) {
double ema;
if (double.IsNaN(lastEma)) { lastEma = input.Value; }
if (IsNew) {
lastEma = lastEmaCandidate;
i++;
}
double kk = (i<period)?(2.0/(i+1)):k;
ema = lastEma + kk * (input.Value - lastEma);
lastEmaCandidate = ema;
IsHot = i >= period;
Value = new TValue(input.Time, ema, IsNew, IsHot);
return Value;
}
}
/////////////////
///
public class SMA
{
private CircularBuffer<double> buffer;
private int period;
private double sum;
public TValue Value { get; private set; }
public bool IsHot { get; private set; }
public SMA(int period)
{
Init(period);
}
public void Init(int period)
{
this.period = period;
this.buffer = new CircularBuffer<double>(period);
this.sum = 0;
this.IsHot = false;
this.Value = default;
}
public TValue Update(TValue input, bool IsNew = true)
{
if (IsNew)
{
if (buffer.Count == period) {
sum -= buffer[0];
}
buffer.Add(input);
sum += input.Value;
} else {
if (buffer.Count > 0) {
sum -= buffer[buffer.Count - 1];
sum += input.Value;
buffer[buffer.Count - 1] = input;
} else {
buffer.Add(input);
sum += input.Value;
}
}
double sma = buffer.Count > 0 ? sum / buffer.Count : double.NaN;
IsHot = buffer.Count >= period;
Value = new TValue(input.Time, sma, IsNew, IsHot);
return Value;
}
}
/////////////////////
///
/////////////////////
public class CircularBuffer<double>
{
private double[] _buffer;
private int _start;
private int _size;
public CircularBuffer(int capacity) {
_buffer = new double[capacity];
_start = 0;
_size = 0;
}
public int Capacity => _buffer.Length;
public int Count => _size;
public void Add(double item) {
if (_size < Capacity) {
_buffer[(_start + _size) % Capacity] = item;
_size++;
} else {
_buffer[_start] = item;
_start = (_start + 1) % Capacity;
}
}
public double this[int index] {
get {
if (index < 0 || index >= _size)
throw new IndexOutOfRangeException();
return _buffer[(_start + index) % Capacity];
}
set {
if (index < 0 || index >= _size)
throw new IndexOutOfRangeException();
_buffer[(_start + index) % Capacity] = value;
}
}
}
-163
View File
@@ -1,163 +0,0 @@
#!meta
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
#!csharp
#r "\bin\Debug\calculations.dll"
using QuanTAlib;
#!csharp
TValue vv = new(10);
display(vv.ToString());
display(vv.IsHot);
TBar bb = new(1,1,1,1,10);
display(bb.ToString());
display(bb.IsNew);
#!csharp
int i=10;
SMA sma = new(i);
Console.WriteLine($"{"Close",10} {"SMA(" + i + ")",10}");
for (int i = 0; i < 20; i++)
{
TValue c =(double)i+1;
sma.Update(10000,true);
sma.Update(1,false);
sma.Update(-1000,false);
sma.Update(c,false);
Console.WriteLine($"{i+1} {(double)c,10:F2} {(double)sma.Value,10:F2} {sma.Value.IsHot}");
}
#!csharp
public class Emitter {
private Random random = new Random();
public event EventHandler<EventArg<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);
EventArg<TValue> eventArg = new EventArg<TValue>(value, true, true);
OnValuePub(eventArg);
}
protected virtual void OnValuePub(EventArg<TValue> eventArg) {
Pub?.Invoke(this, eventArg);
}
}
public class BarEmitter
{
private Random random = new Random();
public event EventHandler<EventArg<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;
EventArg<TBar> eventArg = new EventArg<TBar>(bar, true, true);
OnBarPub(eventArg);
}
protected virtual void OnBarPub(EventArg<TBar> eventArg)
{
Pub?.Invoke(this, eventArg);
}
}
public class Listener
{
public void Sub(object sender, EventArgs e)
{
if (e is EventArg<TValue> tValueArg) {
Console.WriteLine($"TValue: {tValueArg.Data.Value:F2}");
} else if (e is EventArg<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();
}
#!csharp
public abstract class Indicator {
protected Indicator() {
Init(); }
public virtual void Init() {}
public virtual TValue Calc(TValue input, bool isNew=true, bool isHot=true) {
return new TValue();
}
}
public class EMA : Indicator
{
private double lastEma, lastEmaCandidate, k;
private int period, i;
public EMA(int period) {
Init(period);
}
public void Init(int period)
{
this.period = period;
this.k = 2.0 / (period + 1);
this.lastEma = this.lastEmaCandidate = double.NaN;
this.i = 0;
}
public override TValue Calc(TValue input, bool isNew = true, bool isHot = true) {
double ema;
if (double.IsNaN(lastEma)) { lastEma = lastEmaCandidate = input.Value; }
if (isNew) {
lastEma = lastEmaCandidate;
i++;
}
double kk = (i>=period)?k:(2.0/(i+1));
ema = lastEma + kk * (input.Value - lastEma);
lastEmaCandidate = ema;
return new TValue(input.Timestamp, ema);
}
}
#!csharp
EMA ema = new(3);
display(ema.Calc(100));
display(ema.Calc(0,false));
display(ema.Calc(100,false));
display(ema.Calc(0));
-5
View File
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="SonarQube - QuanTAlib QuanTAlib" ToolsVersion="17.0">
<Include Path="..\.sonarlint\mihakralj_quantalibcsharp.ruleset" Action="Default" />
<Include Path="..\.sonarlint\mihakralj_quantalibcsharp.ruleset" Action="Default" />
</RuleSet>
-19
View File
@@ -1,19 +0,0 @@
{
"ServerUri": "https://sonarcloud.io/",
"Organization": {
"Key": "mihakralj",
"Name": "Miha Kralj"
},
"ProjectKey": "mihakralj_QuanTAlib",
"ProjectName": "QuanTAlib",
"Profiles": {
"CSharp": {
"ProfileKey": "AYBIHuVX3Y_jZnooaQv1",
"ProfileTimestamp": "2022-04-20T17:57:57Z"
},
"Secrets": {
"ProfileKey": "AYXoTKve9Ao2yLWbNVCT",
"ProfileTimestamp": "2023-01-25T09:40:14Z"
}
}
}
@@ -1,89 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<AnalysisInput xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Settings>
<Setting>
<Key>sonar.cs.analyzeGeneratedCode</Key>
<Value>false</Value>
</Setting>
<Setting>
<Key>sonar.cs.file.suffixes</Key>
<Value>.cs</Value>
</Setting>
<Setting>
<Key>sonar.cs.ignoreHeaderComments</Key>
<Value>true</Value>
</Setting>
<Setting>
<Key>sonar.cs.roslyn.ignoreIssues</Key>
<Value>false</Value>
</Setting>
</Settings>
<Rules>
<Rule>
<Key>S107</Key>
<Parameters>
<Parameter>
<Key>max</Key>
<Value>7</Value>
</Parameter>
</Parameters>
</Rule>
<Rule>
<Key>S110</Key>
<Parameters>
<Parameter>
<Key>max</Key>
<Value>5</Value>
</Parameter>
</Parameters>
</Rule>
<Rule>
<Key>S1479</Key>
<Parameters>
<Parameter>
<Key>maximum</Key>
<Value>30</Value>
</Parameter>
</Parameters>
</Rule>
<Rule>
<Key>S2342</Key>
<Parameters>
<Parameter>
<Key>flagsAttributeFormat</Key>
<Value>^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?s$</Value>
</Parameter>
<Parameter>
<Key>format</Key>
<Value>^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$</Value>
</Parameter>
</Parameters>
</Rule>
<Rule>
<Key>S2436</Key>
<Parameters>
<Parameter>
<Key>max</Key>
<Value>2</Value>
</Parameter>
<Parameter>
<Key>maxMethod</Key>
<Value>3</Value>
</Parameter>
</Parameters>
</Rule>
<Rule>
<Key>S3776</Key>
<Parameters>
<Parameter>
<Key>propertyThreshold</Key>
<Value>3</Value>
</Parameter>
<Parameter>
<Key>threshold</Key>
<Value>15</Value>
</Parameter>
</Parameters>
</Rule>
</Rules>
</AnalysisInput>
@@ -1,32 +0,0 @@
{
"sonarlint.rules": {
"secrets:S6338": {
"level": "On",
"severity": "Blocker"
},
"secrets:S6337": {
"level": "On",
"severity": "Blocker"
},
"secrets:S6290": {
"level": "On",
"severity": "Blocker"
},
"secrets:S6334": {
"level": "On",
"severity": "Blocker"
},
"secrets:S6336": {
"level": "On",
"severity": "Blocker"
},
"secrets:S6335": {
"level": "On",
"severity": "Blocker"
},
"secrets:S6292": {
"level": "On",
"severity": "Blocker"
}
}
}
@@ -1,390 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Name="SonarQube - QuanTAlib QuanTAlib" Description="This rule set was automatically generated from SonarQube https://sonarcloud.io/profiles/show?key=AYBIHuVX3Y_jZnooaQv1" ToolsVersion="14.0">
<Rules AnalyzerId="SonarAnalyzer.CSharp" RuleNamespace="SonarAnalyzer.CSharp">
<Rule Id="S100" Action="None" />
<Rule Id="S1006" Action="Warning" />
<Rule Id="S101" Action="None" />
<Rule Id="S103" Action="None" />
<Rule Id="S104" Action="None" />
<Rule Id="S1048" Action="Warning" />
<Rule Id="S105" Action="None" />
<Rule Id="S106" Action="None" />
<Rule Id="S1066" Action="Warning" />
<Rule Id="S1067" Action="None" />
<Rule Id="S107" Action="Warning" />
<Rule Id="S1075" Action="Info" />
<Rule Id="S108" Action="Warning" />
<Rule Id="S109" Action="None" />
<Rule Id="S110" Action="Warning" />
<Rule Id="S1104" Action="Info" />
<Rule Id="S1109" Action="None" />
<Rule Id="S1110" Action="Warning" />
<Rule Id="S1116" Action="Info" />
<Rule Id="S1117" Action="Warning" />
<Rule Id="S1118" Action="Warning" />
<Rule Id="S112" Action="Warning" />
<Rule Id="S1121" Action="Warning" />
<Rule Id="S1123" Action="Warning" />
<Rule Id="S1125" Action="Info" />
<Rule Id="S1128" Action="None" />
<Rule Id="S113" Action="None" />
<Rule Id="S1133" Action="None" />
<Rule Id="S1134" Action="Warning" />
<Rule Id="S1135" Action="Info" />
<Rule Id="S1144" Action="Warning" />
<Rule Id="S1147" Action="None" />
<Rule Id="S1151" Action="None" />
<Rule Id="S1155" Action="Info" />
<Rule Id="S1163" Action="Warning" />
<Rule Id="S1168" Action="Warning" />
<Rule Id="S1172" Action="Warning" />
<Rule Id="S1185" Action="Info" />
<Rule Id="S1186" Action="Warning" />
<Rule Id="S1192" Action="None" />
<Rule Id="S1199" Action="Info" />
<Rule Id="S1200" Action="None" />
<Rule Id="S1206" Action="Info" />
<Rule Id="S121" Action="None" />
<Rule Id="S1210" Action="Info" />
<Rule Id="S1215" Action="Warning" />
<Rule Id="S122" Action="None" />
<Rule Id="S1226" Action="None" />
<Rule Id="S1227" Action="None" />
<Rule Id="S1244" Action="None" />
<Rule Id="S125" Action="Warning" />
<Rule Id="S126" Action="None" />
<Rule Id="S1264" Action="Info" />
<Rule Id="S127" Action="None" />
<Rule Id="S1301" Action="None" />
<Rule Id="S1309" Action="None" />
<Rule Id="S131" Action="None" />
<Rule Id="S134" Action="None" />
<Rule Id="S138" Action="None" />
<Rule Id="S1449" Action="None" />
<Rule Id="S1450" Action="Info" />
<Rule Id="S1451" Action="None" />
<Rule Id="S1479" Action="Warning" />
<Rule Id="S1481" Action="Info" />
<Rule Id="S1541" Action="None" />
<Rule Id="S1607" Action="Warning" />
<Rule Id="S1643" Action="Info" />
<Rule Id="S1656" Action="Warning" />
<Rule Id="S1659" Action="None" />
<Rule Id="S1694" Action="None" />
<Rule Id="S1696" Action="None" />
<Rule Id="S1698" Action="None" />
<Rule Id="S1699" Action="Warning" />
<Rule Id="S1751" Action="Warning" />
<Rule Id="S1764" Action="Warning" />
<Rule Id="S1821" Action="None" />
<Rule Id="S1848" Action="Warning" />
<Rule Id="S1854" Action="Warning" />
<Rule Id="S1858" Action="None" />
<Rule Id="S1862" Action="Warning" />
<Rule Id="S1871" Action="Warning" />
<Rule Id="S1905" Action="Info" />
<Rule Id="S1939" Action="Info" />
<Rule Id="S1940" Action="Info" />
<Rule Id="S1944" Action="Warning" />
<Rule Id="S1994" Action="None" />
<Rule Id="S2053" Action="Warning" />
<Rule Id="S2094" Action="None" />
<Rule Id="S2114" Action="Warning" />
<Rule Id="S2115" Action="Warning" />
<Rule Id="S2123" Action="Warning" />
<Rule Id="S2148" Action="None" />
<Rule Id="S2156" Action="None" />
<Rule Id="S2166" Action="None" />
<Rule Id="S2178" Action="Warning" />
<Rule Id="S2183" Action="Info" />
<Rule Id="S2184" Action="Info" />
<Rule Id="S2187" Action="Warning" />
<Rule Id="S2190" Action="Warning" />
<Rule Id="S2197" Action="None" />
<Rule Id="S2198" Action="None" />
<Rule Id="S2201" Action="Warning" />
<Rule Id="S2219" Action="Info" />
<Rule Id="S2221" Action="None" />
<Rule Id="S2222" Action="Warning" />
<Rule Id="S2223" Action="Warning" />
<Rule Id="S2225" Action="Warning" />
<Rule Id="S2228" Action="None" />
<Rule Id="S2234" Action="Warning" />
<Rule Id="S2251" Action="Warning" />
<Rule Id="S2252" Action="Warning" />
<Rule Id="S2259" Action="Warning" />
<Rule Id="S2275" Action="Warning" />
<Rule Id="S2290" Action="Warning" />
<Rule Id="S2291" Action="Warning" />
<Rule Id="S2292" Action="Info" />
<Rule Id="S2302" Action="None" />
<Rule Id="S2306" Action="Warning" />
<Rule Id="S2325" Action="None" />
<Rule Id="S2326" Action="Warning" />
<Rule Id="S2327" Action="None" />
<Rule Id="S2328" Action="Info" />
<Rule Id="S2330" Action="None" />
<Rule Id="S2333" Action="None" />
<Rule Id="S2339" Action="None" />
<Rule Id="S2342" Action="Info" />
<Rule Id="S2344" Action="Info" />
<Rule Id="S2345" Action="Info" />
<Rule Id="S2346" Action="Warning" />
<Rule Id="S2357" Action="None" />
<Rule Id="S2360" Action="None" />
<Rule Id="S2365" Action="Warning" />
<Rule Id="S2368" Action="Warning" />
<Rule Id="S2372" Action="Warning" />
<Rule Id="S2376" Action="Warning" />
<Rule Id="S2386" Action="Info" />
<Rule Id="S2387" Action="None" />
<Rule Id="S2436" Action="Warning" />
<Rule Id="S2437" Action="Warning" />
<Rule Id="S2445" Action="None" />
<Rule Id="S2479" Action="Warning" />
<Rule Id="S2486" Action="Info" />
<Rule Id="S2551" Action="Warning" />
<Rule Id="S2583" Action="Warning" />
<Rule Id="S2589" Action="Warning" />
<Rule Id="S2674" Action="None" />
<Rule Id="S2681" Action="Warning" />
<Rule Id="S2688" Action="Warning" />
<Rule Id="S2692" Action="Warning" />
<Rule Id="S2696" Action="Warning" />
<Rule Id="S2699" Action="Warning" />
<Rule Id="S2701" Action="None" />
<Rule Id="S2737" Action="Info" />
<Rule Id="S2743" Action="Warning" />
<Rule Id="S2755" Action="Warning" />
<Rule Id="S2757" Action="Warning" />
<Rule Id="S2760" Action="None" />
<Rule Id="S2761" Action="Warning" />
<Rule Id="S2857" Action="Warning" />
<Rule Id="S2930" Action="Warning" />
<Rule Id="S2931" Action="None" />
<Rule Id="S2933" Action="Warning" />
<Rule Id="S2934" Action="Info" />
<Rule Id="S2952" Action="None" />
<Rule Id="S2953" Action="Warning" />
<Rule Id="S2955" Action="None" />
<Rule Id="S2970" Action="None" />
<Rule Id="S2971" Action="Warning" />
<Rule Id="S2995" Action="Warning" />
<Rule Id="S2996" Action="Warning" />
<Rule Id="S2997" Action="Warning" />
<Rule Id="S3005" Action="Warning" />
<Rule Id="S3010" Action="Warning" />
<Rule Id="S3011" Action="Warning" />
<Rule Id="S3052" Action="None" />
<Rule Id="S3059" Action="None" />
<Rule Id="S3060" Action="Warning" />
<Rule Id="S3063" Action="None" />
<Rule Id="S3168" Action="Warning" />
<Rule Id="S3169" Action="Warning" />
<Rule Id="S3172" Action="Warning" />
<Rule Id="S3215" Action="None" />
<Rule Id="S3216" Action="None" />
<Rule Id="S3217" Action="Warning" />
<Rule Id="S3218" Action="Warning" />
<Rule Id="S3220" Action="Info" />
<Rule Id="S3234" Action="None" />
<Rule Id="S3235" Action="None" />
<Rule Id="S3236" Action="Info" />
<Rule Id="S3237" Action="Warning" />
<Rule Id="S3240" Action="None" />
<Rule Id="S3241" Action="Info" />
<Rule Id="S3242" Action="None" />
<Rule Id="S3244" Action="Warning" />
<Rule Id="S3246" Action="Warning" />
<Rule Id="S3247" Action="Info" />
<Rule Id="S3249" Action="Warning" />
<Rule Id="S3251" Action="Info" />
<Rule Id="S3253" Action="None" />
<Rule Id="S3254" Action="None" />
<Rule Id="S3256" Action="Info" />
<Rule Id="S3257" Action="None" />
<Rule Id="S3260" Action="Info" />
<Rule Id="S3261" Action="Info" />
<Rule Id="S3262" Action="Warning" />
<Rule Id="S3263" Action="Warning" />
<Rule Id="S3264" Action="Warning" />
<Rule Id="S3265" Action="Warning" />
<Rule Id="S3267" Action="Info" />
<Rule Id="S3329" Action="Warning" />
<Rule Id="S3343" Action="Warning" />
<Rule Id="S3346" Action="Warning" />
<Rule Id="S3353" Action="None" />
<Rule Id="S3358" Action="Warning" />
<Rule Id="S3366" Action="None" />
<Rule Id="S3376" Action="Info" />
<Rule Id="S3397" Action="Info" />
<Rule Id="S3398" Action="None" />
<Rule Id="S3400" Action="Info" />
<Rule Id="S3415" Action="Warning" />
<Rule Id="S3427" Action="Warning" />
<Rule Id="S3431" Action="None" />
<Rule Id="S3433" Action="Warning" />
<Rule Id="S3440" Action="Info" />
<Rule Id="S3441" Action="None" />
<Rule Id="S3442" Action="Warning" />
<Rule Id="S3443" Action="Warning" />
<Rule Id="S3444" Action="Info" />
<Rule Id="S3445" Action="Warning" />
<Rule Id="S3447" Action="Warning" />
<Rule Id="S3449" Action="Warning" />
<Rule Id="S3450" Action="Info" />
<Rule Id="S3451" Action="Warning" />
<Rule Id="S3453" Action="Warning" />
<Rule Id="S3456" Action="Info" />
<Rule Id="S3457" Action="Warning" />
<Rule Id="S3458" Action="Info" />
<Rule Id="S3459" Action="Info" />
<Rule Id="S3464" Action="Warning" />
<Rule Id="S3466" Action="Warning" />
<Rule Id="S3532" Action="None" />
<Rule Id="S3597" Action="Warning" />
<Rule Id="S3598" Action="Warning" />
<Rule Id="S3600" Action="Warning" />
<Rule Id="S3603" Action="Warning" />
<Rule Id="S3604" Action="Info" />
<Rule Id="S3610" Action="Warning" />
<Rule Id="S3626" Action="Info" />
<Rule Id="S3655" Action="Warning" />
<Rule Id="S3717" Action="None" />
<Rule Id="S3776" Action="Warning" />
<Rule Id="S3869" Action="Warning" />
<Rule Id="S3871" Action="Warning" />
<Rule Id="S3872" Action="None" />
<Rule Id="S3874" Action="None" />
<Rule Id="S3875" Action="Warning" />
<Rule Id="S3876" Action="None" />
<Rule Id="S3877" Action="Warning" />
<Rule Id="S3878" Action="None" />
<Rule Id="S3880" Action="None" />
<Rule Id="S3881" Action="Warning" />
<Rule Id="S3884" Action="Warning" />
<Rule Id="S3885" Action="Warning" />
<Rule Id="S3887" Action="Info" />
<Rule Id="S3889" Action="Warning" />
<Rule Id="S3897" Action="Info" />
<Rule Id="S3898" Action="None" />
<Rule Id="S3900" Action="None" />
<Rule Id="S3902" Action="None" />
<Rule Id="S3903" Action="Warning" />
<Rule Id="S3904" Action="Warning" />
<Rule Id="S3906" Action="None" />
<Rule Id="S3908" Action="None" />
<Rule Id="S3909" Action="None" />
<Rule Id="S3923" Action="Warning" />
<Rule Id="S3925" Action="Warning" />
<Rule Id="S3926" Action="Warning" />
<Rule Id="S3927" Action="Warning" />
<Rule Id="S3928" Action="Warning" />
<Rule Id="S3937" Action="None" />
<Rule Id="S3949" Action="None" />
<Rule Id="S3956" Action="None" />
<Rule Id="S3962" Action="None" />
<Rule Id="S3963" Action="Info" />
<Rule Id="S3966" Action="Warning" />
<Rule Id="S3967" Action="None" />
<Rule Id="S3971" Action="Warning" />
<Rule Id="S3972" Action="Warning" />
<Rule Id="S3973" Action="Warning" />
<Rule Id="S3981" Action="Warning" />
<Rule Id="S3984" Action="Warning" />
<Rule Id="S3990" Action="None" />
<Rule Id="S3992" Action="None" />
<Rule Id="S3993" Action="None" />
<Rule Id="S3994" Action="None" />
<Rule Id="S3995" Action="None" />
<Rule Id="S3996" Action="None" />
<Rule Id="S3997" Action="None" />
<Rule Id="S3998" Action="Warning" />
<Rule Id="S4000" Action="None" />
<Rule Id="S4002" Action="None" />
<Rule Id="S4004" Action="None" />
<Rule Id="S4005" Action="None" />
<Rule Id="S4015" Action="Warning" />
<Rule Id="S4016" Action="None" />
<Rule Id="S4017" Action="None" />
<Rule Id="S4018" Action="None" />
<Rule Id="S4019" Action="Warning" />
<Rule Id="S4022" Action="None" />
<Rule Id="S4023" Action="None" />
<Rule Id="S4025" Action="None" />
<Rule Id="S4026" Action="None" />
<Rule Id="S4027" Action="None" />
<Rule Id="S4035" Action="Warning" />
<Rule Id="S4039" Action="None" />
<Rule Id="S4040" Action="None" />
<Rule Id="S4041" Action="None" />
<Rule Id="S4047" Action="None" />
<Rule Id="S4049" Action="None" />
<Rule Id="S4050" Action="None" />
<Rule Id="S4052" Action="None" />
<Rule Id="S4055" Action="None" />
<Rule Id="S4056" Action="None" />
<Rule Id="S4057" Action="None" />
<Rule Id="S4058" Action="None" />
<Rule Id="S4059" Action="None" />
<Rule Id="S4060" Action="None" />
<Rule Id="S4061" Action="Info" />
<Rule Id="S4069" Action="None" />
<Rule Id="S4070" Action="Warning" />
<Rule Id="S4136" Action="Info" />
<Rule Id="S4143" Action="Warning" />
<Rule Id="S4144" Action="Warning" />
<Rule Id="S4158" Action="Info" />
<Rule Id="S4159" Action="Warning" />
<Rule Id="S4200" Action="Warning" />
<Rule Id="S4201" Action="Info" />
<Rule Id="S4210" Action="Warning" />
<Rule Id="S4211" Action="Warning" />
<Rule Id="S4212" Action="None" />
<Rule Id="S4214" Action="Warning" />
<Rule Id="S4220" Action="Warning" />
<Rule Id="S4225" Action="None" />
<Rule Id="S4226" Action="None" />
<Rule Id="S4260" Action="Warning" />
<Rule Id="S4261" Action="None" />
<Rule Id="S4275" Action="Warning" />
<Rule Id="S4277" Action="Warning" />
<Rule Id="S4423" Action="Warning" />
<Rule Id="S4426" Action="Warning" />
<Rule Id="S4428" Action="Warning" />
<Rule Id="S4433" Action="Warning" />
<Rule Id="S4456" Action="Warning" />
<Rule Id="S4457" Action="Warning" />
<Rule Id="S4462" Action="None" />
<Rule Id="S4487" Action="Warning" />
<Rule Id="S4524" Action="Warning" />
<Rule Id="S4545" Action="None" />
<Rule Id="S4564" Action="None" />
<Rule Id="S4581" Action="Warning" />
<Rule Id="S4583" Action="Warning" />
<Rule Id="S4586" Action="Warning" />
<Rule Id="S4635" Action="Warning" />
<Rule Id="S4663" Action="None" />
<Rule Id="S4830" Action="Warning" />
<Rule Id="S5034" Action="Warning" />
<Rule Id="S5445" Action="Warning" />
<Rule Id="S5542" Action="Warning" />
<Rule Id="S5547" Action="Warning" />
<Rule Id="S5659" Action="Warning" />
<Rule Id="S5773" Action="Warning" />
<Rule Id="S5856" Action="None" />
<Rule Id="S6354" Action="None" />
<Rule Id="S6419" Action="None" />
<Rule Id="S6420" Action="None" />
<Rule Id="S6421" Action="None" />
<Rule Id="S6422" Action="None" />
<Rule Id="S6423" Action="None" />
<Rule Id="S6424" Action="None" />
<Rule Id="S6507" Action="None" />
<Rule Id="S6513" Action="None" />
<Rule Id="S818" Action="Info" />
<Rule Id="S881" Action="None" />
<Rule Id="S907" Action="Warning" />
<Rule Id="S927" Action="Warning" />
</Rules>
</RuleSet>
-1
View File
@@ -1 +0,0 @@
{"sonar.exclusions":[],"sonar.global.exclusions":["**/build-wrapper-dump.json"],"sonar.inclusions":[]}
-32
View File
@@ -1,32 +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); }
}
}
@@ -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); }
}
}
@@ -1,48 +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); }
}
}
-32
View File
@@ -1,32 +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); }
}
}
-30
View File
@@ -1,30 +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); }
}
}
-31
View File
@@ -1,31 +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); }
}
}
-80
View File
@@ -1,80 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Title>QuanTAlib</Title>
<Version>0.2.30</Version>
<AssemblyVersion>0.2.30</AssemblyVersion>
<FileVersion>0.2.30</FileVersion>
<Product>Library of TA Calculations, Charts and Strategies for Quantower</Product>
<Description>Quantitative Technical Analysis Library in C# for Quantower</Description>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/mihakralj/QuanTAlib</RepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<Authors>Miha Kralj</Authors>
<Copyright>Miha Kralj</Copyright>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageReadmeFile>readme.md</PackageReadmeFile>
<TargetFrameworks>net8.0;net7.0</TargetFrameworks>
<ImplicitUsings>disable</ImplicitUsings>
<LangVersion>preview</LangVersion>
<Nullable>disable</Nullable>
<DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports>
<NeutralLanguage>en-US</NeutralLanguage>
<RootNamespace>QuanTAlib</RootNamespace>
<AssemblyName>QuanTAlib</AssemblyName>
<IsPublishable>True</IsPublishable>
<PlatformTarget>AnyCPU</PlatformTarget>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageTags>
Indicators;Stock;Market;Technical;Analysis;Algorithmic;Trading;Trade;Trend;Momentum;Finance;Algorithm;Algo;
AlgoTrading;Financial;Strategy;Chart;Charting;Oscillator;Overlay;Equity;Bitcoin;Crypto;Cryptocurrency;Forex;
Quantitative;Historical;Quotes;
</PackageTags>
<PackageLicenseFile>
</PackageLicenseFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>full</DebugType>
<Optimize>True</Optimize>
<WarningLevel>7</WarningLevel>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<PlatformTarget>anycpu</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>full</DebugType>
<Optimize>True</Optimize>
<WarningLevel>7</WarningLevel>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<PlatformTarget>anycpu</PlatformTarget>
</PropertyGroup>
<PropertyGroup>
<PackageIcon>QuanTAlib2.png</PackageIcon>
<PackageIconUrl>https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png</PackageIconUrl>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<CodeAnalysisRuleSet>..\.sonarlint\mihakralj_quantalibcsharp.ruleset</CodeAnalysisRuleSet>
<Version>0.2.1-dev.2</Version>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\.sonarlint\mihakralj_quantalib\CSharp\SonarLint.xml" Link="SonarLint.xml" />
</ItemGroup>
<ItemGroup>
<None Include="..\docs\readme.md">
<Pack>True</Pack>
<PackagePath>
</PackagePath>
</None>
<None Include="..\.github\QuanTAlib2.png">
<Pack>True</Pack>
<Visible>False</Visible>
<PackagePath>
</PackagePath>
</None>
</ItemGroup>
</Project>
@@ -1,157 +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);
}
}
}
@@ -1,55 +0,0 @@
namespace QuanTAlib;
using System;
using System.Text.Json;
/* <summary>
Alphavantage - Free API to collect 100 recent daily quotes. It requires a (free) API key
Get API key at https://www.alphavantage.co/support/#api-key
Parameters:
Symbol: stock ("AAPL"),
APIkey: unique Alphavantage API key
</summary>
*/
public class Alphavantage_Feed : TBars
{
public enum Interval { Month, Week, Day, Hour, Min30, Min15, Min5, Min1 }
public Alphavantage_Feed(string Symbol = "IBM", string APIkey = "demo")
{
System.Net.Http.HttpClient client = new();
string req = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED" + "&symbol=" + Symbol + "&apikey=" + APIkey;
var msg = client.GetStringAsync(req).Result;
var jres = JsonSerializer.Deserialize<JsonDocument>(msg).RootElement;
jres.TryGetProperty("Time Series (Daily)", out JsonElement json);
if (json.ValueKind == JsonValueKind.Undefined) { throw new InvalidOperationException("Stock symbol " + Symbol + " not found"); }
foreach (var val in json.EnumerateObject()) { base.Add(GetOHLC(val)); }
base.Reverse();
}
private static (DateTime t, double o, double h, double l, double c, double v) GetOHLC(JsonProperty json)
{
double o, h, l, c, v;
o = h = l = c = v = 0;
DateTime date = Convert.ToDateTime(json.Name);
foreach (var val in json.Value.EnumerateObject())
{
switch (val.Name)
{
case "1. open": o = Convert.ToDouble(val.Value.ToString()); break;
case "1b. open (USD)": o = Convert.ToDouble(val.Value.ToString()); break;
case "2. high": h = Convert.ToDouble(val.Value.ToString()); break;
case "2b. high (USD)": h = Convert.ToDouble(val.Value.ToString()); break;
case "3. low": l = Convert.ToDouble(val.Value.ToString()); break;
case "3b. low (USD)": l = Convert.ToDouble(val.Value.ToString()); break;
case "4. close": c = Convert.ToDouble(val.Value.ToString()); break;
case "4b. close (USD)": c = Convert.ToDouble(val.Value.ToString()); break;
case "5. adjusted close": c = Convert.ToDouble(val.Value.ToString()); break;
case "5. volume": v = Convert.ToDouble(val.Value.ToString()); break;
case "6. volume": v = Convert.ToDouble(val.Value.ToString()); break;
default: o = 0; h = 0; l = 0; c = 0; v = 0; break;
}
}
return (date, o, h, l, c, v);
}
}
-67
View File
@@ -1,67 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
GBM - Geometric Brownian Motion is a random simulator of market movement, returning List<Quote>
GBM can be used for testing indicators, validation and Monte Carlo simulations of strategies.
Sample usage:
GBM-Random data = new(); // generates 1 year (252) list of bars
GBM-Random data = new(Bars: 1000); // generates 1,000 bars
GBM-Random data = new(Bars: 252, Volatility: 0.05, Drift: 0.0005, Seed: 100.0)
Parameters
Bars: number of bars (quotes) requested
Volatility: how dymamic/volatile the series should be; default is 1
Drift: incremental drift due to annual interest rate; default is 5%
Seed: starting value of the random series; should not be 0
</summary> */
public class GBM_Feed : TBars
{
private double seed;
readonly double drift, volatility;
readonly int precision;
public GBM_Feed(int Bars = 252, double Volatility = 1.0, double Drift = 0.05, double Seed = 100.0, int Precision = 2)
{
this.seed = Seed;
volatility = Volatility * 0.01;
drift = Drift * 0.01;
precision = Precision;
for (int i = 0; i < Bars; i++)
{
DateTime Timestamp = DateTime.Today.AddDays(i - Bars);
this.Add(Timestamp);
}
}
public void Add(bool update = false) { this.Add(DateTime.Now, update); }
public void Add(DateTime timestamp, bool update = false)
{
double Open = GBM_value(seed, volatility * volatility, drift, precision);
double Close = GBM_value(Open, volatility, drift, precision);
double OCMax = Math.Max(Open, Close);
double High = (GBM_value(seed, volatility * 0.5, 0, precision));
High = (High < OCMax) ? (2 * OCMax) - High : High;
double OCMin = Math.Min(Open, Close);
double Low = (GBM_value(seed, volatility * 0.5, 0, precision));
Low = (Low > OCMin) ? (2 * OCMin) - Low : Low;
double Volume = GBM_value(seed * 10, volatility * 2, Drift: 0, precision: 1);
base.Add((timestamp, Open, High, Low, Close, Volume), update);
seed = Close;
}
private static double GBM_value(double Seed, double Volatility, double Drift, int precision)
{
Random rnd = new();
double U1 = 1.0 - rnd.NextDouble();
double U2 = 1.0 - rnd.NextDouble();
double Z = Math.Sqrt(-2.0 * Math.Log(U1)) * Math.Sin(2.0 * Math.PI * U2);
return Math.Round(Seed * Math.Exp(Drift - (Volatility * Volatility * 0.5) + (Volatility * Z)), digits: precision);
}
}
-28
View File
@@ -1,28 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
Random Bars generator - used for testing, validation and fun
Returns 'bars' number of candles that follow common market movement.
volatility defines how 'jumpy' is the series of
startvalue defines beginning closing price that then guides the rest of series
</summary> */
public class RND_Feed : TBars
{
public RND_Feed(int Bars, double Volatility = 0.05, double Startvalue = 100.0)
{
Random rnd = new();
double c = Startvalue;
for (int i = 0; i < Bars; i++)
{
double o = Math.Round(c + (c * (((Volatility * 0.1) * rnd.NextDouble()) - 0.005)), 2);
double h = Math.Round(o + (c * Volatility * rnd.NextDouble()), 2);
double l = Math.Round(o - (c * Volatility * rnd.NextDouble()), 2);
c = Math.Round(l + ((h - l) * rnd.NextDouble()), 2);
double v = Math.Round(1000 * rnd.NextDouble(), 2);
this.Add(DateTime.Today.AddDays(i - Bars), o, h, l, c, v);
}
}
}
-50
View File
@@ -1,50 +0,0 @@
namespace QuanTAlib;
using System;
using System.Text.Json;
/* <summary>
Yahoo Finance - Free API feed to collect daily market quotes
Parameters:
Symbol: stock symbol (default: "IBM")
Period: number of days of collected history (default: 252)
Usage:
Yahoo_Feed ticker = new("MSFT", 20)
</summary>
*/
public class Yahoo_Feed : TBars
{
public Yahoo_Feed(string Symbol = "IBM", int Period = 252)
{
Period = (int)(Period * 1.45);
string requestUrl = "https://query1.finance.yahoo.com/v8/finance/chart/" +
Symbol + "?interval=1d&period1=" +
(int)new DateTimeOffset(DateTime.UtcNow.AddDays(-Period + 1)).ToUnixTimeSeconds() + "&period2=" +
(int)new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
System.Net.Http.HttpClient client = new();
var msg = client.GetStringAsync(requestUrl).Result;
var jresult = JsonSerializer.Deserialize<JsonDocument>(msg).RootElement;
jresult.TryGetProperty("chart", out JsonElement json);
json.TryGetProperty("result", out json);
json[0].TryGetProperty("timestamp", out JsonElement datetime);
json[0].TryGetProperty("indicators", out json);
json.TryGetProperty("quote", out json);
json[0].TryGetProperty("open", out JsonElement open);
json[0].TryGetProperty("high", out JsonElement high);
json[0].TryGetProperty("low", out JsonElement low);
json[0].TryGetProperty("close", out JsonElement close);
json[0].TryGetProperty("volume", out JsonElement volume);
for (int i = 0; i < datetime.GetArrayLength(); i++)
{
DateTime d = DateTimeOffset.FromUnixTimeSeconds(long.Parse(datetime[i].GetRawText())).DateTime;
double o = Math.Round(double.Parse(open[i].GetRawText()), 3);
double h = Math.Round(double.Parse(high[i].GetRawText()), 3);
double l = Math.Round(double.Parse(low[i].GetRawText()), 3);
double c = Math.Round(double.Parse(close[i].GetRawText()), 3);
double v = Math.Round(double.Parse(volume[i].GetRawText()), 3);
base.Add(d, o, h, l, c, v);
}
}
}
@@ -1,39 +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); }
}
}
@@ -1,49 +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); }
}
}
@@ -1,91 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
EQUITY - Generates P&L portfolio based on trades signals and equity prices
</summary> */
//base prices: bars.close
//trade signals: trades
//optional: long, short, long&short
//optional: warmup period: warmup
/*
public class EQUITY_Series : Single_TSeries_Indicator {
readonly TSeries inmarket; //for every bar
private readonly TSeries _price;
private double _equity;
private readonly double _capital;
readonly int _warmup;
double _cash;
int _units;
private bool _longbuy, _longsell;
double _long_order, _open_order;
double _investment_value;
short _inmarket;
public EQUITY_Series(TSeries signal, TSeries price, int warmup = 0, double capital = 1000) : base(signal, period: 0, useNaN: false) {
_capital = capital;
_cash = _capital;
_investment_value = 0;
_warmup = (warmup > 0) ? warmup : 1;
inmarket = new();
_longbuy = _longsell = false;
_open_order = 0;
_inmarket = 0;
_units = 0;
_long_order = 0;
_price = price; //we buy on the Open price of the NEXT bar
_long_order = 0;
if (base._data.Count > 0) { base.Add(base._data); }
}
public override void Add((System.DateTime t, double v) TValue, bool update) {
if (this.Count > _warmup) {
// harvest the gain-loss from previous day
_investment_value = _units * _price[this.Count - 1].v;
_equity = _cash + _investment_value;
//execute orders from previous bar
if (_longbuy && _inmarket == 0) { //time to execute the long buy
_units = (int)(_cash / _price[this.Count - 1].v);
_long_order = _units * _price[this.Count - 1].v;
_cash -= _long_order;
_open_order = _long_order;
_equity = _cash + _open_order;
_inmarket = 1;
_longbuy = false;
}
if (_longsell && _inmarket == 1) { //time to execute the long sell
_long_order = (_units * _price[this.Count - 1].v);
_cash += _long_order;
_units = 0;
_open_order = 0;
_equity = _cash + _open_order;
_inmarket = 0;
_longsell = false;
}
if (_inmarket == 0 && TValue.v == 1) { _longbuy = true; } //out of market, enter long
if (_inmarket == 1 && TValue.v == -1) { _longsell = true; } //long market, exit long
//Console.WriteLine($"{TValue.v,3}\t {(_inmarket)} : {_cash,10:f2} + {_units*_price[^1].v,7:f2} = {_equity-_capital:f2}");
}
inmarket.Add((TValue.t, (double)_inmarket));
base.Add((TValue.t, _equity), update, _NaN);
}
}
*/
-38
View File
@@ -1,38 +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;
}
@@ -1,79 +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;
}
}
@@ -1,100 +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;
}
}
@@ -1,129 +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();
}
}
@@ -1,97 +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;
}
}
@@ -1,98 +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;
}
}
@@ -1,121 +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();
}
}
@@ -1,81 +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();
}
}
@@ -1,97 +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();
}
}
-100
View File
@@ -1,100 +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();
}
}
@@ -1,80 +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();
}
}
@@ -1,93 +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;
}
}
@@ -1,144 +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;
}
}
@@ -1,143 +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);
}
}
-136
View File
@@ -1,136 +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;
}
}
@@ -1,97 +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();
}
}
@@ -1,105 +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();
}
}
@@ -1,133 +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);
}
}
@@ -1,98 +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();
}
}
@@ -1,146 +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;
}
}
-176
View File
@@ -1,176 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
JMA: Jurik Moving Average
Mark Jurik's Moving Average (JMA) attempts to eliminate noise to see the
underlying activity. It has extremely low lag, is very smooth and is responsive
to market gaps.
Sources:
https://c.mql5.com/forextsd/forum/164/jurik_1.pdf
https://www.prorealcode.com/prorealtime-indicators/jurik-volatility-bands/
Issues:
Real JMA algorithm is not published and this formula is derived through
deduction and reverse analysis of JMA behavior. It is really close, but not
exact - published JMA tests against JMA.CSV fail with small deviation. The
original algo is slightly different, yet this approximation is close enough.
</summary> */
public class JMA_Series : TSeries
{
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private readonly System.Collections.Generic.List<double> volty_short = new();
private readonly System.Collections.Generic.List<double> vsum_buff = new();
private readonly double pr;
private double upperBand, lowerBand, vsum, Kv;
private double prev_ma1, prev_det0, prev_det1, prev_vsum, prev_jma;
private double p_upperBand, p_lowerBand, p_Kv, p_prev_ma1, p_prev_det0, p_prev_det1, p_prev_vsum, p_prev_jma;
private readonly int _voltyS, _voltyL;
//core constructors
public JMA_Series(int period, double phase, int vshort, int vlong, bool useNaN)
{
_period = period;
_NaN = useNaN;
Name = $"JMA({period})";
upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0;
pr = (phase * 0.01) + 1.5;
if (phase < -100) { pr = 0.5; }
if (phase > 100) { pr = 2.5; }
_voltyS = vshort;
_voltyL = vlong;
}
public JMA_Series(TSeries source, int period, double phase, int vshort, int vlong, bool useNaN) : this(period, phase, vshort, vlong, useNaN)
{
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public JMA_Series() : this(period: 0, phase: 0, vshort: 10, vlong: 65, useNaN: false) { }
public JMA_Series(int period) : this(period: period, phase: 0, vshort: 10, vlong: 65, useNaN: false) { }
public JMA_Series(TBars source) : this(source.Close, period: 0, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
public JMA_Series(TBars source, int period) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
public JMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { }
public JMA_Series(TSeries source) : this(source, period: 0, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
public JMA_Series(TSeries source, int period) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
public JMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
{
if (this.Count == 0) { prev_ma1 = prev_jma = TValue.v; }
if (update)
{
upperBand = p_upperBand;
lowerBand = p_lowerBand;
Kv = p_Kv;
prev_vsum = p_prev_vsum;
prev_ma1 = p_prev_ma1;
prev_det0 = p_prev_det0;
prev_det1 = p_prev_det1;
prev_jma = p_prev_jma;
}
else
{
p_upperBand = upperBand;
p_lowerBand = lowerBand;
p_Kv = Kv;
p_prev_vsum = prev_vsum;
p_prev_ma1 = prev_ma1;
p_prev_det0 = prev_det0;
p_prev_det1 = prev_det1;
p_prev_jma = prev_jma;
}
if (double.IsNaN(TValue.v))
{
return base.Add((TValue.t, double.NaN), update);
}
// from Tvalue to volty
double del1 = TValue.v - upperBand;
double del2 = TValue.v - lowerBand;
upperBand = (del1 > 0) ? TValue.v : TValue.v - (Kv * del1);
lowerBand = (del2 < 0) ? TValue.v : TValue.v - (Kv * del2);
double volty = Math.Abs(del1) > Math.Abs(del2) ? Math.Abs(del1) :
(Math.Abs(del1) < Math.Abs(del2) ? Math.Abs(del2) :
Math.Abs(0.5 * (del1 + del2)));
//// from volty to avolty
if (update) { volty_short[volty_short.Count - 1] = volty; }
else { volty_short.Add(volty); }
if (volty_short.Count > _voltyS) { volty_short.RemoveAt(0); }
vsum = prev_vsum + 0.1 * (volty - volty_short.First());
prev_vsum = vsum;
if (update) { vsum_buff[vsum_buff.Count - 1] = vsum; }
else { vsum_buff.Add(vsum); }
if (vsum_buff.Count > _voltyL) { vsum_buff.RemoveAt(0); }
double avolty = 0;
for (int i = 0; i < vsum_buff.Count; i++) { avolty += vsum_buff[i]; }
avolty /= vsum_buff.Count;
/// from avolty to rolty
double rvolty = (avolty != 0) ? volty / avolty : 0;
double len1 = (Math.Log(Math.Sqrt(_period)) / Math.Log(2.0)) + 2;
if (len1 < 0) { len1 = 0; }
double pow1 = Math.Max(len1 - 2.0, 0.5);
if (rvolty > Math.Pow(len1, 1.0 / pow1)) { rvolty = Math.Pow(len1, 1.0 / pow1); }
if (rvolty < 1) { rvolty = 1; }
//// from rvolty to second smoothing
double pow2 = Math.Pow(rvolty, pow1);
double beta = 0.45 * (_period - 1) / (0.45 * (_period - 1) + 2);
Kv = Math.Pow(beta, Math.Sqrt(pow2));
double alpha = Math.Pow(beta, pow2);
double ma1 = (1 - alpha) * TValue.v + alpha * prev_ma1;
prev_ma1 = ma1;
double det0 = (1 - beta) * (TValue.v - ma1) + beta * prev_det0;
prev_det0 = det0;
double ma2 = ma1 + pr * det0;
double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - prev_jma)) + (alpha * alpha * prev_det1);
prev_det1 = det1;
double jma = prev_jma + det1;
prev_jma = jma;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : jma);
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()
{
upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0;
}
}
@@ -1,118 +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;
}
}
@@ -1,107 +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();
}
}
@@ -1,88 +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();
}
}
@@ -1,88 +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();
}
}
@@ -1,86 +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();
}
}
@@ -1,207 +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;
}
}
@@ -1,95 +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();
}
}
@@ -1,77 +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();
}
}
@@ -1,95 +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();
}
}
@@ -1,81 +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();
}
}
@@ -1,74 +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();
}
}
@@ -1,77 +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();
}
}
@@ -1,85 +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();
}
}
-106
View File
@@ -1,106 +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;
}
}
-133
View File
@@ -1,133 +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;
}
}
-134
View File
@@ -1,134 +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;
}
}
@@ -1,91 +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();
}
}
@@ -1,130 +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();
}
}
@@ -1,84 +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();
}
}
-112
View File
@@ -1,112 +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();
}
}
@@ -1,105 +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;
}
}
@@ -1,91 +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();
}
}
@@ -1,90 +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();
}
}
-173
View File
@@ -1,173 +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;
}
}
-153
View File
@@ -1,153 +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()
{
}
}

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