mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-27 17:27:43 +00:00
Squash
dotcover s1 .sln s1 s1 s2 s3 s4 s5 s1 s2 x x2 x3 x4 x5 x6 x1 sonarcube cleanup1 sonarcube cleanup2 sonarcube cleanup 3 fixes q q q q q q q q q1 q2 q q1 codacy 1
This commit is contained in:
@@ -1,174 +1,137 @@
|
||||
name: Stage/build/test/release/publish
|
||||
name: CI/CD Pipeline
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
branches: [main, dev]
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
branches: [main, dev]
|
||||
|
||||
env:
|
||||
DOTNET_VERSION: '8.0.x'
|
||||
JAVA_VERSION: '11'
|
||||
JAVA_DISTRIBUTION: 'zulu'
|
||||
|
||||
jobs:
|
||||
build_test:
|
||||
#runs-on: windows-latest
|
||||
build_test_publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
############## Install tools
|
||||
|
||||
- name: Create Quantower folder at root
|
||||
- name: Setup environment
|
||||
run: |
|
||||
sudo mkdir -p /Quantower/
|
||||
sudo chmod -R 777 /Quantower
|
||||
|
||||
- name: Install .NET
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '8.x'
|
||||
dotnet-quality: 'preview'
|
||||
dotnet-version: ${{ env.DOTNET_VERSION }}
|
||||
|
||||
- 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
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: 'zulu'
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
distribution: ${{ env.JAVA_DISTRIBUTION }}
|
||||
|
||||
- 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: Install tools
|
||||
run: |
|
||||
dotnet tool install --global GitVersion.Tool
|
||||
dotnet tool install --global dotnet-sonarscanner --version 8.0.3
|
||||
dotnet tool install --global dotnet-coverage
|
||||
|
||||
- name: Sonar start
|
||||
- name: Determine Version
|
||||
id: gitversion
|
||||
run: |
|
||||
dotnet-gitversion
|
||||
echo "::set-output name=MajorMinorPatch::$(dotnet-gitversion /output json /showvariable MajorMinorPatch)"
|
||||
echo "::set-output name=FullSemVer::$(dotnet-gitversion /output json /showvariable FullSemVer)"
|
||||
echo "::set-output name=SemVer::$(dotnet-gitversion /output json /showvariable SemVer)"
|
||||
|
||||
- name: Start Sonar analysis
|
||||
if: github.ref == 'refs/heads/dev'
|
||||
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
|
||||
dotnet sonarscanner begin /o:"mihakralj" /k:"mihakralj_QuanTAlib" \
|
||||
/d:sonar.token="${{ secrets.SONAR_TOKEN }}" \
|
||||
/d:sonar.scanner.scanAll=false \
|
||||
/d:sonar.host.url="https://sonarcloud.io" \
|
||||
/d:sonar.cs.opencover.reportsPaths="**/TestResults/coverage.opencover.xml" \
|
||||
/d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml
|
||||
|
||||
- name: Upload to Codacy
|
||||
if: ${{ github.ref == 'refs/heads/dev' }}
|
||||
|
||||
- name: Build projects
|
||||
run: |
|
||||
dotnet build ./lib/quantalib.csproj --configuration Release --nologo \
|
||||
-p:PackageVersion=${{ github.ref == 'refs/heads/dev' && steps.gitversion.outputs.FullSemVer || steps.gitversion.outputs.MajorMinorPatch }}
|
||||
dotnet build ./quantower/Averages/Averages.csproj --configuration Release --nologo
|
||||
dotnet build ./quantower/Statistics/Statistics.csproj --configuration Release --nologo
|
||||
dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
|
||||
|
||||
- name: Run tests with coverage
|
||||
if: github.ref == 'refs/heads/dev'
|
||||
run: |
|
||||
dotnet test --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput="./TestResults/"
|
||||
dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml"
|
||||
|
||||
- name: Generate and process coverage report
|
||||
if: github.ref == 'refs/heads/dev'
|
||||
uses: danielpalme/ReportGenerator-GitHub-Action@5.1.26
|
||||
with:
|
||||
reports: '**/TestResults/coverage.opencover.xml'
|
||||
targetdir: 'coveragereport'
|
||||
reporttypes: 'HtmlInline;Cobertura'
|
||||
|
||||
- name: Upload coverage 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"
|
||||
coverage-reports: "coveragereport/Cobertura.xml"
|
||||
|
||||
- name: Upload to Codecov
|
||||
if: ${{ github.ref == 'refs/heads/dev' }}
|
||||
- name: Upload coverage to Codecov
|
||||
if: github.ref == 'refs/heads/dev'
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: cover*
|
||||
files: coveragereport/Cobertura.xml
|
||||
verbose: true
|
||||
|
||||
- name: Upload to Sonar
|
||||
if: ${{ github.ref == 'refs/heads/dev' }}
|
||||
- name: Finish Sonar analysis
|
||||
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' }}
|
||||
- name: Publish release assets
|
||||
uses: SourceSprint/upload-multiple-releases@1.0.7
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
prerelease: true
|
||||
prerelease: ${{ github.ref == 'refs/heads/dev' }}
|
||||
overwrite: true
|
||||
release_name: ${{ steps.gitversion.outputs.SemVer }}
|
||||
release_name: ${{ github.ref == 'refs/heads/dev' && steps.gitversion.outputs.SemVer || steps.gitversion.outputs.MajorMinorPatch }}
|
||||
tag_name: ${{ steps.gitversion.outputs.SemVer }}
|
||||
release_config: |
|
||||
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: ${{ steps.gitversion.outputs.SemVer }}
|
||||
release_config: |
|
||||
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
|
||||
- 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
|
||||
|
||||
- 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
|
||||
+4
-1
@@ -395,4 +395,7 @@ FodyWeavers.xsd
|
||||
*.msp
|
||||
|
||||
# JetBrains Rider
|
||||
*.sln.iml
|
||||
*.sln.iml
|
||||
*.dcvr
|
||||
|
||||
dotcover.html
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"SonarCloudOrganization": "mihakralj",
|
||||
"ProjectKey": "mihakralj_QuanTAlib"
|
||||
}
|
||||
+16
-9
@@ -7,31 +7,38 @@
|
||||
<Deterministic>true</Deterministic>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
|
||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||
<ProduceReferenceAssembly>False</ProduceReferenceAssembly>
|
||||
<DebugType>full</DebugType>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
|
||||
|
||||
<!-- GitVersion settings -->
|
||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||
<UpdateAssemblyInfo>true</UpdateAssemblyInfo>
|
||||
<GenerateAssemblyVersionAttribute>true</GenerateAssemblyVersionAttribute>
|
||||
<GenerateAssemblyFileVersionAttribute>true</GenerateAssemblyFileVersionAttribute>
|
||||
<GenerateAssemblyInformationalVersionAttribute>true</GenerateAssemblyInformationalVersionAttribute>
|
||||
<GetVersion>false</GetVersion>
|
||||
<GenerateGitVersionInformation>true</GenerateGitVersionInformation>
|
||||
<WriteVersionInfoToBuildLog>true</WriteVersionInfoToBuildLog>
|
||||
</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="GitVersion.MsBuild" Version="6.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(IsLocalBuild)' == 'true'">
|
||||
<QuantowerRoot>D:\Quantower</QuantowerRoot>
|
||||
<QuantowerPath>$([System.IO.Directory]::GetDirectories("$(QuantowerRoot)\TradingPlatform", "v1*")[0])</QuantowerPath>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,3 +1,4 @@
|
||||
semantic-version-format: Loose
|
||||
mode: ContinuousDelivery
|
||||
branches:
|
||||
main:
|
||||
|
||||
+4
-3
@@ -1,13 +1,13 @@
|
||||
|
||||
|
||||
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}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{D85FEBB4-B651-466F-85CC-FD902378D4D2}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{D85FEBB4-B651-466F-85CC-FD902378D4D2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MovingAverages", "quantower\averages\Averages.csproj", "{32CC09CC-26E3-4FCE-8932-C0513C4AD766}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MovingAverages", "quantower\Averages\Averages.csproj", "{32CC09CC-26E3-4FCE-8932-C0513C4AD766}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntheticVendor", "SyntheticVendor\SyntheticVendor.csproj", "{20B1B5F1-8C36-4668-B0AE-951C13AE197B}"
|
||||
EndProject
|
||||
@@ -49,3 +49,4 @@ Global
|
||||
{B6D3EB11-63B6-430F-B526-E1981B3D8214} = {A8D9AE68-24E3-476C-BB98-244541BB4B43}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
+251
-285
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Security.Cryptography;
|
||||
using TradingPlatform.BusinessLayer;
|
||||
using TradingPlatform.BusinessLayer.Integration;
|
||||
|
||||
@@ -73,31 +74,50 @@ namespace SyntheticVendorNamespace
|
||||
CreateMessageSymbol("W17", "2 Geometric Brownian motion", "QT", "USD", SymbolType.Synthetic)
|
||||
};
|
||||
|
||||
/*
|
||||
Bond,
|
||||
CFD,
|
||||
Crypto,
|
||||
Debentures,
|
||||
Equities,
|
||||
ETF,
|
||||
FixedIncome,
|
||||
Forex,
|
||||
Forward,
|
||||
Futures,
|
||||
Indexes,
|
||||
Options,
|
||||
Spot,
|
||||
Synthetic,
|
||||
Swap,
|
||||
Warrants,
|
||||
/*
|
||||
Bond,
|
||||
CFD,
|
||||
Crypto,
|
||||
Debentures,
|
||||
Equities,
|
||||
ETF,
|
||||
FixedIncome,
|
||||
Forex,
|
||||
Forward,
|
||||
Futures,
|
||||
Indexes,
|
||||
Options,
|
||||
Spot,
|
||||
Synthetic,
|
||||
Swap,
|
||||
Warrants,
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private MessageSymbol CreateMessageSymbol(
|
||||
public static VendorMetaData GetVendorMetaData()
|
||||
{
|
||||
return new VendorMetaData
|
||||
{
|
||||
VendorName = "Synthetic Vendor",
|
||||
VendorDescription = "A synthetic vendor for testing and demonstration purposes",
|
||||
GetDefaultConnections = () =>
|
||||
{
|
||||
var defaultConnection = Vendor.CreateDefaultConnectionInfo(
|
||||
"Synthetic Connection",
|
||||
"Synthetic Vendor",
|
||||
"", // Replace with actual path if you have a logo
|
||||
allowCreateCustomConnections: true
|
||||
);
|
||||
return new List<ConnectionInfo> { defaultConnection };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static MessageSymbol CreateMessageSymbol(
|
||||
string id,
|
||||
string name,
|
||||
string exchangeId,
|
||||
@@ -127,27 +147,7 @@ namespace SyntheticVendorNamespace
|
||||
return messageSymbol;
|
||||
}
|
||||
|
||||
public static VendorMetaData GetVendorMetaData()
|
||||
{
|
||||
return new VendorMetaData()
|
||||
{
|
||||
VendorName = "Synthetic Vendor",
|
||||
VendorDescription = "A synthetic vendor for testing and demonstration purposes",
|
||||
GetDefaultConnections = () =>
|
||||
{
|
||||
var defaultConnection = Vendor.CreateDefaultConnectionInfo(
|
||||
"Synthetic Connection",
|
||||
"Synthetic Vendor",
|
||||
"", // Replace with actual path if you have a logo
|
||||
allowCreateCustomConnections: true
|
||||
);
|
||||
return new List<ConnectionInfo> { defaultConnection };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private MessageSymbol CreateMessageSymbol(string id, string name, string exchangeId, string assetId, SymbolType type)
|
||||
private static MessageSymbol CreateMessageSymbol(string id, string name, string exchangeId, string assetId, SymbolType type)
|
||||
{
|
||||
return new MessageSymbol(id)
|
||||
{
|
||||
@@ -173,26 +173,26 @@ namespace SyntheticVendorNamespace
|
||||
LotStep = 0.01,
|
||||
MaxLot = 1000000,
|
||||
SymbolType = type
|
||||
/*
|
||||
SymbolType.Unknown,
|
||||
[EnumMember] Forex,
|
||||
[EnumMember] Equities,
|
||||
[EnumMember] CFD,
|
||||
[EnumMember] Indexes,
|
||||
[EnumMember] Futures,
|
||||
[EnumMember] Options,
|
||||
[EnumMember] ETF,
|
||||
[EnumMember] Crypto,
|
||||
[EnumMember] Synthetic,
|
||||
[EnumMember] Spot,
|
||||
[EnumMember] Forward,
|
||||
[EnumMember] FixedIncome,
|
||||
[EnumMember] Warrants,
|
||||
/*
|
||||
SymbolType.Unknown,
|
||||
[EnumMember] Forex,
|
||||
[EnumMember] Equities,
|
||||
[EnumMember] CFD,
|
||||
[EnumMember] Indexes,
|
||||
[EnumMember] Futures,
|
||||
[EnumMember] Options,
|
||||
[EnumMember] ETF,
|
||||
[EnumMember] Crypto,
|
||||
[EnumMember] Synthetic,
|
||||
[EnumMember] Spot,
|
||||
[EnumMember] Forward,
|
||||
[EnumMember] FixedIncome,
|
||||
[EnumMember] Warrants,
|
||||
|
||||
[EnumMember] Debentures,
|
||||
[EnumMember] Bond,
|
||||
[EnumMember] Swap,
|
||||
*/
|
||||
[EnumMember] Debentures,
|
||||
[EnumMember] Bond,
|
||||
[EnumMember] Swap,
|
||||
*/
|
||||
};
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ namespace SyntheticVendorNamespace
|
||||
|
||||
public override PingResult Ping()
|
||||
{
|
||||
return new PingResult()
|
||||
return new PingResult
|
||||
{
|
||||
State = PingEnum.Connected,
|
||||
PingTime = TimeSpan.FromMilliseconds(2),
|
||||
@@ -226,12 +226,7 @@ namespace SyntheticVendorNamespace
|
||||
|
||||
public override void OnConnected(CancellationToken token)
|
||||
{
|
||||
// This method is called after a successful connection
|
||||
// You can initialize resources or start any necessary processes here
|
||||
base.OnConnected(token);
|
||||
|
||||
// For example, you might want to push some initial messages or data
|
||||
// PushMessage(new MessageVendorEvent("SyntheticVendor connected successfully"));
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +262,10 @@ namespace SyntheticVendorNamespace
|
||||
var historyItems = new List<IHistoryItem>();
|
||||
var symbolId = requestParameters.SymbolId;
|
||||
|
||||
if (string.IsNullOrEmpty(symbolId)) return historyItems;
|
||||
if (string.IsNullOrEmpty(symbolId))
|
||||
{
|
||||
return historyItems;
|
||||
}
|
||||
|
||||
DateTime from = requestParameters.FromTime;
|
||||
DateTime to = requestParameters.ToTime;
|
||||
@@ -284,7 +282,9 @@ namespace SyntheticVendorNamespace
|
||||
{
|
||||
DateTime intervalEnd = currentTime.AddTicks(periodTimeSpan.Ticks * MAX_ITEMS_PER_REQUEST);
|
||||
if (intervalEnd > to)
|
||||
{
|
||||
intervalEnd = to;
|
||||
}
|
||||
|
||||
while (currentTime <= intervalEnd)
|
||||
{
|
||||
@@ -293,7 +293,10 @@ namespace SyntheticVendorNamespace
|
||||
|
||||
currentTime = currentTime.Add(periodTimeSpan);
|
||||
|
||||
if (requestParameters.CancellationToken.IsCancellationRequested) return historyItems;
|
||||
if (requestParameters.CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return historyItems;
|
||||
}
|
||||
}
|
||||
|
||||
currentTime = intervalEnd;
|
||||
@@ -306,7 +309,6 @@ namespace SyntheticVendorNamespace
|
||||
{
|
||||
switch (symbolId)
|
||||
{
|
||||
//case "W0": return GenerateConstant;
|
||||
case "W1": return GenerateSpike;
|
||||
case "W2": return GenerateDiracDelta;
|
||||
case "W3": return GenerateSquareWave;
|
||||
@@ -331,7 +333,7 @@ namespace SyntheticVendorNamespace
|
||||
|
||||
public override HistoryMetadata GetHistoryMetadata(CancellationToken cancellationToken)
|
||||
{
|
||||
return new HistoryMetadata()
|
||||
return new HistoryMetadata
|
||||
{
|
||||
AllowedHistoryTypes = new HistoryType[]
|
||||
{
|
||||
@@ -360,71 +362,58 @@ namespace SyntheticVendorNamespace
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
/*******************************************************************************************************************************************/
|
||||
|
||||
private HistoryItemBar GenerateSpike(DateTime time, TimeSpan slice)
|
||||
{
|
||||
// Ensure we're working with UTC time
|
||||
DateTime utcTime = time.ToUniversalTime();
|
||||
|
||||
// Calculate the number of hours since the epoch
|
||||
double hoursSinceEpoch = (utcTime - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalHours;
|
||||
|
||||
// Calculate the position within the 25-hour cycle
|
||||
int cyclePosition = (int)Math.Floor(hoursSinceEpoch % 25);
|
||||
|
||||
// Determine if this is a spike hour (hour 24 in the cycle) or the hour after
|
||||
bool isSpike = cyclePosition == 24;
|
||||
bool isAfterSpike = cyclePosition == 0;
|
||||
|
||||
double openValue, closeValue;
|
||||
if (isSpike)
|
||||
private HistoryItemBar GenerateSpike(DateTime time, TimeSpan slice)
|
||||
{
|
||||
openValue = 0;
|
||||
closeValue = 100;
|
||||
}
|
||||
else if (isAfterSpike)
|
||||
{
|
||||
openValue = 100;
|
||||
closeValue = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
openValue = closeValue = 0.000001;
|
||||
// Ensure we're working with UTC time
|
||||
DateTime utcTime = time.ToUniversalTime();
|
||||
|
||||
// Calculate the number of hours since the epoch
|
||||
double hoursSinceEpoch = (utcTime - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalHours;
|
||||
|
||||
// Calculate the position within the 25-hour cycle
|
||||
int cyclePosition = (int)Math.Floor(hoursSinceEpoch % 25);
|
||||
|
||||
// Determine if this is a spike hour (hour 24 in the cycle) or the hour after
|
||||
bool isSpike = cyclePosition == 24;
|
||||
bool isAfterSpike = cyclePosition == 0;
|
||||
|
||||
double openValue, closeValue;
|
||||
if (isSpike)
|
||||
{
|
||||
openValue = 0;
|
||||
closeValue = 100;
|
||||
}
|
||||
else if (isAfterSpike)
|
||||
{
|
||||
openValue = 100;
|
||||
closeValue = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
openValue = closeValue = 0.000001;
|
||||
}
|
||||
|
||||
return new HistoryItemBar
|
||||
{
|
||||
TicksLeft = time.Ticks,
|
||||
TicksRight = time.Add(slice).Ticks - 1,
|
||||
Open = openValue,
|
||||
High = Math.Max(openValue, closeValue),
|
||||
Low = Math.Min(openValue, closeValue),
|
||||
Close = closeValue,
|
||||
Volume = Math.Abs(closeValue - openValue),
|
||||
Ticks = time.Add(slice).Ticks - time.Ticks
|
||||
};
|
||||
}
|
||||
|
||||
return new HistoryItemBar
|
||||
{
|
||||
TicksLeft = time.Ticks,
|
||||
TicksRight = time.Add(slice).Ticks - 1,
|
||||
Open = openValue,
|
||||
High = Math.Max(openValue, closeValue),
|
||||
Low = Math.Min(openValue, closeValue),
|
||||
Close = closeValue,
|
||||
Volume = Math.Abs(closeValue - openValue),
|
||||
Ticks = time.Add(slice).Ticks - time.Ticks
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static readonly double[] distributionValues = new double[]
|
||||
{
|
||||
0.010, // Extreme left tail
|
||||
0.050, // Left tail
|
||||
0.200, // Left of center
|
||||
0.480, // Center (peak)
|
||||
0.200, // Right of center
|
||||
0.050, // Right tail
|
||||
0.010 // Extreme right tail
|
||||
};
|
||||
|
||||
private HistoryItemBar GenerateDiracDelta(DateTime time, TimeSpan slice)
|
||||
{
|
||||
@@ -497,7 +486,7 @@ namespace SyntheticVendorNamespace
|
||||
double value = 50 + 50 * Math.Sin(cyclePosition * frequency); // Oscillate between 0 and 100
|
||||
double nextValue = 50 + 50 * Math.Sin((cyclePosition + slice.TotalMinutes) * frequency);
|
||||
|
||||
double factor = 0.6 * Math.Abs (nextValue - value);
|
||||
double factor = 0.6 * Math.Abs(nextValue - value);
|
||||
|
||||
return new HistoryItemBar
|
||||
{
|
||||
@@ -505,8 +494,8 @@ namespace SyntheticVendorNamespace
|
||||
TicksRight = time.Add(slice).Ticks - 1,
|
||||
Open = value,
|
||||
|
||||
High = Math.Max(value, nextValue)+factor,
|
||||
Low = Math.Min(value, nextValue)-factor,
|
||||
High = Math.Max(value, nextValue) + factor,
|
||||
Low = Math.Min(value, nextValue) - factor,
|
||||
|
||||
Close = nextValue,
|
||||
Volume = Math.Abs(nextValue - value) * 100, // Volume proportional to price change
|
||||
@@ -607,26 +596,6 @@ namespace SyntheticVendorNamespace
|
||||
};
|
||||
}
|
||||
|
||||
private HistoryItemBar GeneratePulseWave(DateTime time, TimeSpan slice)
|
||||
{
|
||||
double hours = (time - DateTime.UnixEpoch).TotalHours;
|
||||
double period = 24; // 24-hour period
|
||||
double position = hours % period;
|
||||
double value = position < period / 5 ? 100 : -100; // 20% duty cycle
|
||||
|
||||
return new HistoryItemBar
|
||||
{
|
||||
TicksLeft = time.Ticks,
|
||||
TicksRight = time.Add(slice).Ticks - 1,
|
||||
Open = value,
|
||||
High = 100,
|
||||
Low = -100,
|
||||
Close = value,
|
||||
Volume = 100,
|
||||
Ticks = 100
|
||||
};
|
||||
}
|
||||
|
||||
private HistoryItemBar GenerateTriangleWave(DateTime time, TimeSpan slice)
|
||||
{
|
||||
double hours = (time - DateTime.UnixEpoch).TotalHours;
|
||||
@@ -787,9 +756,6 @@ namespace SyntheticVendorNamespace
|
||||
double period = 12.0;
|
||||
double frequency = 2 * Math.PI / period; // Frequency for a 5-hour period
|
||||
|
||||
// Determine the start of the current 5-hour cycle
|
||||
double cycleStartTime = Math.Floor(hours / period) * period;
|
||||
|
||||
// Calculate the phase of the signal within the current 5-hour cycle
|
||||
double phase = frequency * (hours % period);
|
||||
|
||||
@@ -824,8 +790,8 @@ namespace SyntheticVendorNamespace
|
||||
|
||||
|
||||
private double currentFrequency = Math.PI / 220.0; // Initial frequency
|
||||
private double accumulatedPhase = 0;
|
||||
private double lastCloseValue = 0; // To store the last close value
|
||||
private double accumulatedPhase;
|
||||
private double lastCloseValue; // To store the last close value
|
||||
|
||||
private HistoryItemBar GenerateFMSignal(DateTime time, TimeSpan slice)
|
||||
{
|
||||
@@ -915,81 +881,81 @@ namespace SyntheticVendorNamespace
|
||||
|
||||
|
||||
|
||||
private double previousClose = 50;
|
||||
private const double meanPrice = 50;
|
||||
private double previousClose = 50;
|
||||
private const double meanPrice = 50;
|
||||
|
||||
private HistoryItemBar GeneratePinkNoise(DateTime time, TimeSpan slice)
|
||||
{
|
||||
double volatility = 2;
|
||||
double meanReversionStrength = 0.1;
|
||||
|
||||
// Generate open price
|
||||
double openNoise = GeneratePinkNoiseValue();
|
||||
double open = previousClose + volatility * openNoise + meanReversionStrength * (meanPrice - previousClose);
|
||||
|
||||
// Generate close price
|
||||
double closeNoise = GeneratePinkNoiseValue();
|
||||
double close = open + volatility * closeNoise + meanReversionStrength * (meanPrice - open);
|
||||
|
||||
// Determine High and Low
|
||||
double high = Math.Max(open, close);
|
||||
double low = Math.Min(open, close);
|
||||
|
||||
// Add variation to High and Low
|
||||
double highNoise = Math.Abs(GeneratePinkNoiseValue());
|
||||
high += volatility * highNoise;
|
||||
|
||||
double lowNoise = Math.Abs(GeneratePinkNoiseValue());
|
||||
low -= volatility * lowNoise;
|
||||
|
||||
double volume = Math.Abs(GeneratePinkNoiseValue()) * 1000 + 100;
|
||||
|
||||
// Update previous close for the next iteration
|
||||
previousClose = close;
|
||||
|
||||
return new HistoryItemBar
|
||||
{
|
||||
TicksLeft = time.Ticks,
|
||||
TicksRight = time.Add(slice).Ticks - 1,
|
||||
Open = open,
|
||||
High = high,
|
||||
Low = low,
|
||||
Close = close,
|
||||
Volume = volume,
|
||||
Ticks = slice.Ticks
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private const int NumOctaves = 6;
|
||||
private double[] pinkNoiseState = new double[NumOctaves];
|
||||
private double GeneratePinkNoiseValue()
|
||||
{
|
||||
double total = 0;
|
||||
|
||||
for (int i = 0; i < NumOctaves; i++)
|
||||
private HistoryItemBar GeneratePinkNoise(DateTime time, TimeSpan slice)
|
||||
{
|
||||
double white = random.NextDouble() * 2 - 1;
|
||||
pinkNoiseState[i] = (pinkNoiseState[i] + white) * 0.5;
|
||||
total += pinkNoiseState[i] * Math.Pow(2, -i);
|
||||
double volatility = 2;
|
||||
double meanReversionStrength = 0.1;
|
||||
|
||||
// Generate open price
|
||||
double openNoise = GeneratePinkNoiseValue();
|
||||
double open = previousClose + volatility * openNoise + meanReversionStrength * (meanPrice - previousClose);
|
||||
|
||||
// Generate close price
|
||||
double closeNoise = GeneratePinkNoiseValue();
|
||||
double close = open + volatility * closeNoise + meanReversionStrength * (meanPrice - open);
|
||||
|
||||
// Determine High and Low
|
||||
double high = Math.Max(open, close);
|
||||
double low = Math.Min(open, close);
|
||||
|
||||
// Add variation to High and Low
|
||||
double highNoise = Math.Abs(GeneratePinkNoiseValue());
|
||||
high += volatility * highNoise;
|
||||
|
||||
double lowNoise = Math.Abs(GeneratePinkNoiseValue());
|
||||
low -= volatility * lowNoise;
|
||||
|
||||
double volume = Math.Abs(GeneratePinkNoiseValue()) * 1000 + 100;
|
||||
|
||||
// Update previous close for the next iteration
|
||||
previousClose = close;
|
||||
|
||||
return new HistoryItemBar
|
||||
{
|
||||
TicksLeft = time.Ticks,
|
||||
TicksRight = time.Add(slice).Ticks - 1,
|
||||
Open = open,
|
||||
High = high,
|
||||
Low = low,
|
||||
Close = close,
|
||||
Volume = volume,
|
||||
Ticks = slice.Ticks
|
||||
};
|
||||
}
|
||||
|
||||
// Normalize
|
||||
return total / NumOctaves;
|
||||
}
|
||||
|
||||
private const int NumOctaves = 6;
|
||||
private readonly double[] pinkNoiseState = new double[NumOctaves];
|
||||
private double GeneratePinkNoiseValue()
|
||||
{
|
||||
double total = 0;
|
||||
|
||||
for (int i = 0; i < NumOctaves; i++)
|
||||
{
|
||||
double white = random.NextDouble() * 2 - 1;
|
||||
pinkNoiseState[i] = (pinkNoiseState[i] + white) * 0.5;
|
||||
total += pinkNoiseState[i] * Math.Pow(2, -i);
|
||||
}
|
||||
|
||||
// Normalize
|
||||
return total / NumOctaves;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private double lastValue = 0;
|
||||
private double lastValue;
|
||||
|
||||
private HistoryItemBar GenerateBrownNoise(DateTime time, TimeSpan slice)
|
||||
{
|
||||
double dt = slice.TotalDays / 365.0; // Time step in years
|
||||
double sigma = 25.0; // Annual volatility
|
||||
private HistoryItemBar GenerateBrownNoise(DateTime time, TimeSpan slice)
|
||||
{
|
||||
double dt = slice.TotalDays / 365.0; // Time step in years
|
||||
double sigma = 25.0; // Annual volatility
|
||||
|
||||
double increment = GenerateGaussian(0, sigma * Math.Sqrt(dt));
|
||||
double open = lastValue * (1 + GenerateGaussian(0, 0.05));
|
||||
double close = open + increment;
|
||||
double increment = GenerateGaussian(0, sigma * Math.Sqrt(dt));
|
||||
double open = lastValue * (1 + GenerateGaussian(0, 0.05));
|
||||
double close = open + increment;
|
||||
|
||||
// Simulate intra-period high and low
|
||||
double high = Math.Max(open, close);
|
||||
@@ -997,81 +963,81 @@ private HistoryItemBar GenerateBrownNoise(DateTime time, TimeSpan slice)
|
||||
double low = Math.Min(open, close);
|
||||
low -= low * Math.Abs(GenerateGaussian(0, 0.06));
|
||||
|
||||
lastValue = close;
|
||||
lastValue = close;
|
||||
|
||||
return new HistoryItemBar
|
||||
{
|
||||
TicksLeft = time.Ticks,
|
||||
TicksRight = time.Add(slice).Ticks - 1,
|
||||
Open = open,
|
||||
High = high,
|
||||
Low = low,
|
||||
Close = close,
|
||||
Volume = Math.Abs(close - open) * 1000, // Simplified volume calculation
|
||||
Ticks = slice.Ticks
|
||||
};
|
||||
}
|
||||
// Helper method to generate Gaussian distributed random numbers
|
||||
private double GenerateGaussian(double mean, double stdDev)
|
||||
{
|
||||
double u1 = 1.0 - random.NextDouble(); // Uniform(0,1] random doubles
|
||||
double u2 = 1.0 - random.NextDouble();
|
||||
double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
|
||||
return mean + stdDev * randStdNormal;
|
||||
}
|
||||
return new HistoryItemBar
|
||||
{
|
||||
TicksLeft = time.Ticks,
|
||||
TicksRight = time.Add(slice).Ticks - 1,
|
||||
Open = open,
|
||||
High = high,
|
||||
Low = low,
|
||||
Close = close,
|
||||
Volume = Math.Abs(close - open) * 1000, // Simplified volume calculation
|
||||
Ticks = slice.Ticks
|
||||
};
|
||||
}
|
||||
// Helper method to generate Gaussian distributed random numbers
|
||||
private double GenerateGaussian(double mean, double stdDev)
|
||||
{
|
||||
double u1 = 1.0 - random.NextDouble(); // Uniform(0,1] random doubles
|
||||
double u2 = 1.0 - random.NextDouble();
|
||||
double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
|
||||
return mean + stdDev * randStdNormal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private double GBMLastClose = 100; // Starting price
|
||||
private readonly double GBMMu = 0.05; // Annual drift
|
||||
private readonly double GBMSigma = 0.2; // Annual volatility
|
||||
private double GBMLastClose = 100; // Starting price
|
||||
private readonly double GBMMu = 0.05; // Annual drift
|
||||
private readonly double GBMSigma = 0.2; // Annual volatility
|
||||
|
||||
private HistoryItemBar GenerateGBM(DateTime time, TimeSpan slice)
|
||||
{
|
||||
// Convert time slice to years
|
||||
double dt = slice.TotalDays / 365.0;
|
||||
private HistoryItemBar GenerateGBM(DateTime time, TimeSpan slice)
|
||||
{
|
||||
// Convert time slice to years
|
||||
double dt = slice.TotalDays / 365.0;
|
||||
|
||||
// Generate a random normal variable for the main price movement
|
||||
double epsilon = GenerateGaussian(0, 1);
|
||||
// Generate a random normal variable for the main price movement
|
||||
double epsilon = GenerateGaussian(0, 1);
|
||||
|
||||
// Calculate the price movement using GBM equation
|
||||
double drift = (GBMMu - 0.5 * GBMSigma * GBMSigma) * dt;
|
||||
double diffusion = GBMSigma * Math.Sqrt(dt) * epsilon;
|
||||
double returnValue = Math.Exp(drift + diffusion);
|
||||
// Calculate the price movement using GBM equation
|
||||
double drift = (GBMMu - 0.5 * GBMSigma * GBMSigma) * dt;
|
||||
double diffusion = GBMSigma * Math.Sqrt(dt) * epsilon;
|
||||
double returnValue = Math.Exp(drift + diffusion);
|
||||
|
||||
// Add variability between previous close and current open
|
||||
double openVariability = GBMLastClose * GBMSigma * Math.Sqrt(dt) * GenerateGaussian(0, 1) * 0.1;
|
||||
double open = GBMLastClose + openVariability;
|
||||
// Add variability between previous close and current open
|
||||
double openVariability = GBMLastClose * GBMSigma * Math.Sqrt(dt) * GenerateGaussian(0, 1) * 0.1;
|
||||
double open = GBMLastClose + openVariability;
|
||||
|
||||
// Calculate new close price
|
||||
double close = open * returnValue;
|
||||
// Calculate new close price
|
||||
double close = open * returnValue;
|
||||
|
||||
// Generate High and Low values
|
||||
double highLowRange = Math.Max(Math.Abs(close - open), GBMLastClose * GBMSigma * Math.Sqrt(dt) * Math.Abs(GenerateGaussian(0, 1)));
|
||||
double high = Math.Max(open, close) + highLowRange * 0.5;
|
||||
double low = Math.Min(open, close) - highLowRange * 0.5;
|
||||
// Generate High and Low values
|
||||
double highLowRange = Math.Max(Math.Abs(close - open), GBMLastClose * GBMSigma * Math.Sqrt(dt) * Math.Abs(GenerateGaussian(0, 1)));
|
||||
double high = Math.Max(open, close) + highLowRange * 0.5;
|
||||
double low = Math.Min(open, close) - highLowRange * 0.5;
|
||||
|
||||
// Generate volume (you may want to adjust this based on your needs)
|
||||
double volume = Math.Max(100, 1000 * Math.Abs(close - open) + 500 * GenerateGaussian(0, 1));
|
||||
// Generate volume (you may want to adjust this based on your needs)
|
||||
double volume = Math.Max(100, 1000 * Math.Abs(close - open) + 500 * GenerateGaussian(0, 1));
|
||||
|
||||
// Update last close for next iteration
|
||||
GBMLastClose = close;
|
||||
// Update last close for next iteration
|
||||
GBMLastClose = close;
|
||||
|
||||
return new HistoryItemBar
|
||||
{
|
||||
TicksLeft = time.Ticks,
|
||||
TicksRight = time.Add(slice).Ticks - 1,
|
||||
Open = open,
|
||||
High = high,
|
||||
Low = low,
|
||||
Close = close,
|
||||
Volume = volume,
|
||||
Ticks = slice.Ticks
|
||||
};
|
||||
}
|
||||
return new HistoryItemBar
|
||||
{
|
||||
TicksLeft = time.Ticks,
|
||||
TicksRight = time.Add(slice).Ticks - 1,
|
||||
Open = open,
|
||||
High = high,
|
||||
Low = low,
|
||||
Close = close,
|
||||
Volume = volume,
|
||||
Ticks = slice.Ticks
|
||||
};
|
||||
}
|
||||
|
||||
private double FBMLastClose = 100; // Starting price
|
||||
private double FBMHurst = 0.85; // Hurst parameter (0.5 < H < 1 for persistent fBm)
|
||||
private readonly double FBMHurst = 0.85; // Hurst parameter (0.5 < H < 1 for persistent fBm)
|
||||
private readonly double FBMSigma = 0.25; // Volatility parameter
|
||||
private readonly double FBMDrift = 0.001; // drift
|
||||
|
||||
|
||||
+10
-2
@@ -4,7 +4,15 @@
|
||||
<RootNamespace>QuanTAlib.Tests</RootNamespace>
|
||||
<AssemblyName>QuanTAlib.Tests</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.msbuild" Version="3.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
@@ -12,11 +20,11 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0-rc.1.24431.7" />
|
||||
<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" />
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ using Xunit;
|
||||
using Trady.Analysis.Indicator;
|
||||
using Trady.Core;
|
||||
using Trady.Core.Infrastructure;
|
||||
using QuanTAlib;
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class TradyTests
|
||||
{
|
||||
|
||||
+3
-4
@@ -1,6 +1,6 @@
|
||||
using Xunit;
|
||||
using Tulip;
|
||||
using QuanTAlib;
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class TulipTests
|
||||
{
|
||||
@@ -23,7 +23,7 @@ public class TulipTests
|
||||
iterations = 3;
|
||||
skip = 500;
|
||||
data = feed.Close.v.ToArray();
|
||||
outdata = new double[data.Count()];
|
||||
outdata = new double[data.Length];
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -66,12 +66,11 @@ public class TulipTests
|
||||
double[][] arrout = [outdata];
|
||||
Tulip.Indicators.ema.Run(inputs: arrin, options: [period], outputs: arrout);
|
||||
|
||||
Assert.Equal(QL.Length, arrout[0].Count());
|
||||
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}");
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Xunit;
|
||||
using QuanTAlib;
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class Consistency
|
||||
{
|
||||
@@ -312,31 +312,6 @@ public class Consistency
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
[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()
|
||||
{
|
||||
@@ -442,7 +417,6 @@ public class Consistency
|
||||
[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++)
|
||||
@@ -683,7 +657,7 @@ public class Consistency
|
||||
[Fact]
|
||||
public void Kurtosis_isNew()
|
||||
{
|
||||
int p = (int)rnd.Next(2, 100);
|
||||
int p = (int)rnd.Next(5, 100);
|
||||
Kurtosis ma1 = new(p);
|
||||
Kurtosis ma2 = new(p);
|
||||
for (int i = 0; i < series_len; i++)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Xunit;
|
||||
using Skender.Stock.Indicators;
|
||||
using QuanTAlib;
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class SkenderTests
|
||||
{
|
||||
@@ -284,7 +284,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)
|
||||
|
||||
+8
-31
@@ -1,6 +1,6 @@
|
||||
using Xunit;
|
||||
using TALib;
|
||||
using QuanTAlib;
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class TAlibTests
|
||||
{
|
||||
@@ -22,7 +22,7 @@ public class TAlibTests
|
||||
feed.Add(10000);
|
||||
iterations = 3;
|
||||
data = feed.Close.v.ToArray();
|
||||
TALIB = new double[data.Count()];
|
||||
TALIB = new double[data.Length];
|
||||
|
||||
}
|
||||
|
||||
@@ -37,11 +37,11 @@ public class TAlibTests
|
||||
foreach (TBar item in feed)
|
||||
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
|
||||
Core.Sma(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period);
|
||||
Assert.Equal(QL.Length, TALIB.Count());
|
||||
Assert.Equal(QL.Length, TALIB.Length);
|
||||
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);
|
||||
Assert.InRange(TL - QL[i].Value, -range, range);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ public class TAlibTests
|
||||
foreach (TBar item in feed)
|
||||
{ QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
|
||||
Core.Ema(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period);
|
||||
Assert.Equal(QL.Length, TALIB.Count());
|
||||
Assert.Equal(QL.Length, TALIB.Length);
|
||||
for (int i = QL.Length - 1; i > period; i--)
|
||||
{
|
||||
double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
|
||||
@@ -77,7 +77,7 @@ public class TAlibTests
|
||||
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());
|
||||
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];
|
||||
@@ -97,7 +97,7 @@ public class TAlibTests
|
||||
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());
|
||||
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];
|
||||
@@ -106,29 +106,6 @@ public class TAlibTests
|
||||
}
|
||||
}
|
||||
|
||||
//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()
|
||||
{
|
||||
@@ -140,7 +117,7 @@ public class TAlibTests
|
||||
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());
|
||||
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];
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
@@ -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>
|
||||
@@ -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 +0,0 @@
|
||||
{"sonar.exclusions":[],"sonar.global.exclusions":["**/build-wrapper-dump.json"],"sonar.inclusions":[]}
|
||||
@@ -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); }
|
||||
}
|
||||
}
|
||||
@@ -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); }
|
||||
}
|
||||
}
|
||||
@@ -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); }
|
||||
}
|
||||
}
|
||||
@@ -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); }
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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". Tillson’s 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;
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
namespace QuanTAlib;
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
/* <summary>
|
||||
TEMA: Triple Exponential Moving Average
|
||||
TEMA uses EMA(EMA(EMA())) to calculate less laggy Exponential moving average.
|
||||
|
||||
Sources:
|
||||
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triple-exponential-moving-average-tema/
|
||||
|
||||
Remark:
|
||||
ema1 = EMA(close, length)
|
||||
ema2 = EMA(ema1, length)
|
||||
ema3 = EMA(ema2, length)
|
||||
TEMA = 3 * (ema1 - ema2) + ema3
|
||||
|
||||
</summary> */
|
||||
|
||||
public class TEMA_Series : TSeries
|
||||
{
|
||||
private double _k;
|
||||
private double _sum, _oldsum;
|
||||
private double _lastema1, _oldema1, _lastema2, _oldema2, _lastema3, _oldema3;
|
||||
private int _len;
|
||||
private readonly bool _useSMA;
|
||||
protected readonly int _period;
|
||||
protected readonly bool _NaN;
|
||||
protected readonly TSeries _data;
|
||||
|
||||
//core constructor
|
||||
public TEMA_Series(int period, bool useNaN, bool useSMA)
|
||||
{
|
||||
_period = period;
|
||||
_NaN = useNaN;
|
||||
_useSMA = useSMA;
|
||||
Name = $"TEMA({period})";
|
||||
_k = 2.0 / (_period + 1);
|
||||
_len = 0;
|
||||
_sum = _oldsum = _lastema1 = _lastema2 = _lastema3 = 0;
|
||||
}
|
||||
public TEMA_Series() : this(0, false, true) { }
|
||||
public TEMA_Series(int period) : this(period, false, true) { }
|
||||
public TEMA_Series(TBars source) : this(source.Close, 0, false) { }
|
||||
public TEMA_Series(TBars source, int period) : this(source.Close, period, false) { }
|
||||
public TEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
|
||||
public TEMA_Series(TSeries source, int period) : this(source, period, false, true) { }
|
||||
public TEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
|
||||
public TEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA)
|
||||
{
|
||||
_data = source;
|
||||
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
|
||||
_data.Pub += Sub;
|
||||
Add(_data);
|
||||
}
|
||||
|
||||
// core Add() algo
|
||||
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
|
||||
{
|
||||
if (update)
|
||||
{
|
||||
_lastema1 = _oldema1;
|
||||
_lastema2 = _oldema2;
|
||||
_lastema3 = _oldema3;
|
||||
_sum = _oldsum;
|
||||
}
|
||||
else
|
||||
{
|
||||
_oldema1 = _lastema1;
|
||||
_oldema2 = _lastema2;
|
||||
_oldema3 = _lastema3;
|
||||
_oldsum = _sum;
|
||||
_len++;
|
||||
}
|
||||
|
||||
if (_period == 0) { _k = 2.0 / (_len + 1); }
|
||||
|
||||
double _ema1, _ema2, _ema3, _tema;
|
||||
if (this.Count == 0)
|
||||
{
|
||||
_ema1 = _ema2 = _ema3 = _sum = TValue.v;
|
||||
}
|
||||
else if (_len <= _period && _useSMA && _period != 0)
|
||||
{
|
||||
_sum += TValue.v;
|
||||
_ema1 = _sum / Math.Min(_len, _period);
|
||||
_ema2 = _ema1;
|
||||
_ema3 = _ema2;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ema1 = (TValue.v - _lastema1) * _k + _lastema1;
|
||||
_ema2 = (_ema1 - _lastema2) * _k + _lastema2;
|
||||
_ema3 = (_ema2 - _lastema3) * _k + _lastema3;
|
||||
}
|
||||
|
||||
_tema = (3 * (_ema1 - _ema2)) + _ema3;
|
||||
|
||||
_lastema1 = Double.IsNaN(_ema1) ? _lastema1 : _ema1;
|
||||
_lastema2 = Double.IsNaN(_ema2) ? _lastema2 : _ema2;
|
||||
_lastema3 = Double.IsNaN(_ema3) ? _lastema3 : _ema3;
|
||||
|
||||
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _tema);
|
||||
return base.Add(res, update);
|
||||
}
|
||||
|
||||
//variation of Add()
|
||||
public override (DateTime t, double v) Add(TSeries data)
|
||||
{
|
||||
if (data == null) { return (DateTime.Today, Double.NaN); }
|
||||
foreach (var item in data) { Add(item, false); }
|
||||
return _data.Last;
|
||||
}
|
||||
public (DateTime t, double v) Add(bool update)
|
||||
{
|
||||
return this.Add(TValue: _data.Last, update: update);
|
||||
}
|
||||
public (DateTime t, double v) Add()
|
||||
{
|
||||
return Add(TValue: _data.Last, update: false);
|
||||
}
|
||||
private new void Sub(object source, TSeriesEventArgs e)
|
||||
{
|
||||
Add(TValue: _data.Last, update: e.update);
|
||||
}
|
||||
|
||||
//reset calculation
|
||||
public override void Reset()
|
||||
{
|
||||
_sum = _oldsum = _lastema1 = _lastema2 = 0;
|
||||
_len = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
namespace QuanTAlib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/* <summary>
|
||||
TRIMA: Triangular Moving Average
|
||||
A weighted moving average where the shape of the weights are triangular and the greatest
|
||||
weight is in the middle of the period,
|
||||
|
||||
Sources:
|
||||
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triangular-moving-average-trima/
|
||||
|
||||
Remark:
|
||||
trima = sma(sma(signal, n/2), n/2)
|
||||
|
||||
</summary> */
|
||||
|
||||
public class TRIMA_Series : TSeries
|
||||
{
|
||||
private readonly int _p1a, _p1b;
|
||||
private readonly SMA_Series sma, trima;
|
||||
protected readonly int _period;
|
||||
protected readonly bool _NaN;
|
||||
protected readonly TSeries _data;
|
||||
|
||||
//core constructors
|
||||
public TRIMA_Series(int period, bool useNaN)
|
||||
{
|
||||
_period = period;
|
||||
_NaN = useNaN;
|
||||
Name = $"xMA({period})";
|
||||
_p1a = (int)Math.Floor((period * 0.5) + 1);
|
||||
_p1b = (int)Math.Ceiling(0.5 * period);
|
||||
sma = new(_p1a);
|
||||
trima = new(_p1b);
|
||||
|
||||
}
|
||||
public TRIMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
|
||||
{
|
||||
_data = source;
|
||||
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
|
||||
_data.Pub += Sub;
|
||||
Add(_data);
|
||||
}
|
||||
public TRIMA_Series() : this(period: 0, useNaN: false) { }
|
||||
public TRIMA_Series(int period) : this(period: period, useNaN: false) { }
|
||||
public TRIMA_Series(TBars source) : this(source.Close, 0, false) { }
|
||||
public TRIMA_Series(TBars source, int period) : this(source.Close, period, false) { }
|
||||
public TRIMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
|
||||
public TRIMA_Series(TSeries source) : this(source, 0, false) { }
|
||||
public TRIMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
|
||||
|
||||
//////////////////
|
||||
// core Add() algo
|
||||
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
|
||||
{
|
||||
if (double.IsNaN(TValue.v))
|
||||
{
|
||||
return base.Add((TValue.t, Double.NaN), update);
|
||||
}
|
||||
|
||||
var _sma = sma.Add(TValue, update);
|
||||
var _trima = trima.Add(_sma, update);
|
||||
|
||||
var res = (_trima.t, Count < _period - 1 && _NaN ? double.NaN : _trima.v);
|
||||
return base.Add(res, update);
|
||||
}
|
||||
|
||||
public override (DateTime t, double v) Add(TSeries data)
|
||||
{
|
||||
if (data == null) { return (DateTime.Today, Double.NaN); }
|
||||
foreach (var item in data) { Add(item, false); }
|
||||
return _data.Last;
|
||||
}
|
||||
public (DateTime t, double v) Add(bool update)
|
||||
{
|
||||
return this.Add(TValue: _data.Last, update: update);
|
||||
}
|
||||
public (DateTime t, double v) Add()
|
||||
{
|
||||
return Add(TValue: _data.Last, update: false);
|
||||
}
|
||||
private new void Sub(object source, TSeriesEventArgs e)
|
||||
{
|
||||
Add(TValue: _data.Last, update: e.update);
|
||||
}
|
||||
|
||||
//reset calculation
|
||||
public override void Reset()
|
||||
{
|
||||
sma.Reset();
|
||||
trima.Reset();
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
namespace QuanTAlib;
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
/* <summary>
|
||||
TRIX: Triple Exponential Average Oscillator
|
||||
Developed by Jack Hutson in the early 1980s, the triple exponential average (TRIX)
|
||||
has become a popular technical analysis tool to aid chartists in spotting diversions
|
||||
and directional cues in stock trading patterns.
|
||||
|
||||
Sources:
|
||||
https://www.investopedia.com/terms/t/trix.asp
|
||||
|
||||
</summary> */
|
||||
|
||||
public class TRIX_Series : TSeries
|
||||
{
|
||||
private readonly double _k;
|
||||
private readonly System.Collections.Generic.List<double> _buffer1 = new();
|
||||
private readonly System.Collections.Generic.List<double> _buffer2 = new();
|
||||
private readonly System.Collections.Generic.List<double> _buffer3 = new();
|
||||
private double _lastema1, _lastema2, _lastema3;
|
||||
private double _llastema1, _llastema2, _llastema3;
|
||||
private int _len;
|
||||
private readonly bool _useSMA;
|
||||
protected readonly int _period;
|
||||
protected readonly bool _NaN;
|
||||
protected readonly TSeries _data;
|
||||
|
||||
//core constructors
|
||||
|
||||
public TRIX_Series(int period, bool useNaN, bool useSMA)
|
||||
{
|
||||
_period = period;
|
||||
_NaN = useNaN;
|
||||
_useSMA = useSMA;
|
||||
Name = $"TRIX({period})";
|
||||
_k = 2.0 / (_period + 1);
|
||||
_len = 0;
|
||||
_lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = 0;
|
||||
}
|
||||
public TRIX_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA)
|
||||
{
|
||||
_data = source;
|
||||
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
|
||||
_data.Pub += Sub;
|
||||
Add(_data);
|
||||
}
|
||||
public TRIX_Series() : this(0, false, true) { }
|
||||
public TRIX_Series(int period) : this(period, false, true) { }
|
||||
public TRIX_Series(TBars source) : this(source.Close, 0, false) { }
|
||||
public TRIX_Series(TBars source, int period) : this(source.Close, period, false) { }
|
||||
public TRIX_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
|
||||
public TRIX_Series(TSeries source, int period) : this(source, period, false, true) { }
|
||||
public TRIX_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
|
||||
|
||||
|
||||
//////////////////
|
||||
// core Add() algo
|
||||
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
|
||||
{
|
||||
if (double.IsNaN(TValue.v))
|
||||
{
|
||||
return base.Add((TValue.t, Double.NaN), update);
|
||||
}
|
||||
if (_len == 0) { _lastema1 = _lastema2 = _lastema3 = TValue.v; }
|
||||
if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; }
|
||||
else
|
||||
{
|
||||
_llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _len++;
|
||||
}
|
||||
|
||||
double _ema1, _ema2, _ema3;
|
||||
if ((this.Count < _period) && _useSMA)
|
||||
{
|
||||
BufferTrim(_buffer1, TValue.v, _period, update);
|
||||
_ema1 = 0;
|
||||
for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; }
|
||||
_ema1 /= _buffer1.Count;
|
||||
|
||||
BufferTrim(_buffer2, _ema1, _period, update);
|
||||
_ema2 = 0;
|
||||
for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; }
|
||||
_ema2 /= _buffer2.Count;
|
||||
|
||||
BufferTrim(_buffer3, _ema2, _period, update);
|
||||
_ema3 = 0;
|
||||
for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; }
|
||||
_ema3 /= _buffer3.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ema1 = (TValue.v - _lastema1) * _k + _lastema1;
|
||||
_ema2 = (_ema1 - _lastema2) * _k + _lastema2;
|
||||
_ema3 = (_ema2 - _lastema3) * _k + _lastema3;
|
||||
}
|
||||
double _trix = 100 * (_ema3 - _lastema3) / _lastema3;
|
||||
_lastema1 = _ema1;
|
||||
_lastema2 = _ema2;
|
||||
_lastema3 = _ema3;
|
||||
|
||||
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _trix);
|
||||
return base.Add(res, update);
|
||||
}
|
||||
|
||||
//variation of Add()
|
||||
public override (DateTime t, double v) Add(TSeries data)
|
||||
{
|
||||
if (data == null) { return (DateTime.Today, Double.NaN); }
|
||||
foreach (var item in data) { Add(item, false); }
|
||||
return _data.Last;
|
||||
}
|
||||
public (DateTime t, double v) Add(bool update)
|
||||
{
|
||||
return this.Add(TValue: _data.Last, update: update);
|
||||
}
|
||||
public (DateTime t, double v) Add()
|
||||
{
|
||||
return Add(TValue: _data.Last, update: false);
|
||||
}
|
||||
private new void Sub(object source, TSeriesEventArgs e)
|
||||
{
|
||||
Add(TValue: _data.Last, update: e.update);
|
||||
}
|
||||
|
||||
//reset calculation
|
||||
public override void Reset()
|
||||
{
|
||||
_len = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
namespace QuanTAlib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/* <summary>
|
||||
TR: True Range
|
||||
True Range was introduced by J. Welles Wilder in his book New Concepts in Technical Trading Systems.
|
||||
It measures the daily range plus any gap from the closing price of the preceding day.
|
||||
|
||||
Calculation:
|
||||
d1 = ABS(High - Low)
|
||||
d2 = ABS(High - Previous close)
|
||||
d3 = ABS(Previous close - Low)
|
||||
TR = MAX(d1,d2,d3)
|
||||
|
||||
Sources:
|
||||
https://www.macroption.com/true-range/
|
||||
|
||||
</summary> */
|
||||
|
||||
public class TR_Series : TSeries
|
||||
{
|
||||
protected readonly TBars _data;
|
||||
private double _cm1, _cm1_o;
|
||||
|
||||
//core constructors
|
||||
public TR_Series()
|
||||
{
|
||||
Name = $"TR()";
|
||||
_cm1 = _cm1_o = double.NaN;
|
||||
}
|
||||
public TR_Series(TBars source)
|
||||
{
|
||||
_data = source;
|
||||
Name = $"TR({(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
|
||||
_cm1 = _cm1_o = double.NaN;
|
||||
_data.Pub += Sub;
|
||||
Add(data: _data);
|
||||
}
|
||||
|
||||
//////////////////
|
||||
// core Add() algo
|
||||
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false)
|
||||
{
|
||||
|
||||
if (update)
|
||||
{
|
||||
_cm1 = _cm1_o;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cm1_o = _cm1;
|
||||
}
|
||||
|
||||
if (_cm1 is double.NaN)
|
||||
{
|
||||
_cm1 = TBar.c;
|
||||
}
|
||||
|
||||
double d1 = Math.Abs(TBar.h - TBar.l);
|
||||
double d2 = Math.Abs(_cm1 - TBar.h);
|
||||
double d3 = Math.Abs(_cm1 - TBar.l);
|
||||
_cm1 = TBar.c;
|
||||
var ret = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
|
||||
return base.Add(ret, update);
|
||||
|
||||
}
|
||||
|
||||
public new void Add(TBars data)
|
||||
{
|
||||
foreach (var item in data) { Add(item, false); }
|
||||
}
|
||||
public (DateTime t, double v) Add(bool update)
|
||||
{
|
||||
return this.Add(TBar: _data.Last, update: update);
|
||||
}
|
||||
public (DateTime t, double v) Add()
|
||||
{
|
||||
return Add(TBar: _data.Last, update: false);
|
||||
}
|
||||
private new void Sub(object source, TSeriesEventArgs e)
|
||||
{
|
||||
Add(TBar: _data.Last, update: e.update);
|
||||
}
|
||||
|
||||
//reset calculation
|
||||
public override void Reset()
|
||||
{
|
||||
_cm1 = _cm1_o = double.NaN;
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
namespace QuanTAlib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
|
||||
/* <summary>
|
||||
TSeries is the cornerstone of all QuanTAlib classes.
|
||||
TSeries is a single List of tuples (time, value) and contains several operators, casts, overloads
|
||||
and other helpers that simplify usage of library.
|
||||
Think of TSeries as an equivalent of Numpy array.
|
||||
|
||||
- includes Length property (to mimic array's method)
|
||||
- includes publishing and subscribing methods that attach to events
|
||||
|
||||
</summary> */
|
||||
public class TSeriesEventArgs : EventArgs
|
||||
{
|
||||
public bool update { get; set; }
|
||||
}
|
||||
|
||||
public class TSeries : List<(DateTime t, double v)>
|
||||
{
|
||||
private readonly (DateTime t, double v) Default = (DateTime.MinValue, double.NaN);
|
||||
public IEnumerable<DateTime> t => this.Select(item => item.t);
|
||||
public IEnumerable<double> v => this.Select(item => item.v);
|
||||
public (DateTime t, double v) Last => Count > 0 ? this[^1] : Default;
|
||||
|
||||
public int Length => Count;
|
||||
public string Name { get; set; }
|
||||
public int Keep = 0;
|
||||
|
||||
public TSeries()
|
||||
{
|
||||
this.Name = "data";
|
||||
}
|
||||
|
||||
public TSeries(string Name)
|
||||
{
|
||||
this.Name = Name;
|
||||
}
|
||||
|
||||
public virtual (DateTime t, double v) Add(double v, bool update = false)
|
||||
{
|
||||
return Add((t: Count == 0 ? DateTime.Today : this[^1].t.AddDays(1), v), update);
|
||||
}
|
||||
|
||||
public virtual (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
|
||||
{
|
||||
if (update)
|
||||
{
|
||||
this[^1] = TValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.Add(TValue);
|
||||
}
|
||||
|
||||
OnEvent(update);
|
||||
return TValue;
|
||||
}
|
||||
|
||||
public virtual (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false)
|
||||
{
|
||||
if (update)
|
||||
{
|
||||
this[this.Count - 1] = (TBar.t, TBar.c);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.Add((TBar.t, TBar.c));
|
||||
}
|
||||
|
||||
OnEvent(update);
|
||||
return (TBar.t, TBar.c);
|
||||
}
|
||||
|
||||
public virtual (DateTime t, double v) Add(TSeries data)
|
||||
{
|
||||
foreach (var item in data) { Add(item); }
|
||||
return data.Last;
|
||||
}
|
||||
|
||||
public virtual (DateTime t, double v) Add(TBars data)
|
||||
{
|
||||
foreach (var item in data) { Add(item.c, false); }
|
||||
return (data.Last.t, data.Last.c);
|
||||
}
|
||||
|
||||
public void Sub(object source, TSeriesEventArgs e)
|
||||
{
|
||||
var data = (TSeries)source;
|
||||
if (data == null) { return; }
|
||||
foreach (var item in data) { Add(item); }
|
||||
}
|
||||
|
||||
public delegate void NewEventHandler(object source, TSeriesEventArgs args);
|
||||
|
||||
public event NewEventHandler Pub;
|
||||
|
||||
protected virtual void OnEvent(bool update = false)
|
||||
{
|
||||
if (Keep > 0)
|
||||
{
|
||||
TrimToSize(keep: Keep);
|
||||
}
|
||||
Pub?.Invoke(this, new TSeriesEventArgs { update = update });
|
||||
}
|
||||
|
||||
/// common helpers
|
||||
public static void BufferTrim(List<double> buffer, double value, int period, bool update)
|
||||
{
|
||||
if (!update)
|
||||
{
|
||||
buffer.Add(value);
|
||||
if (buffer.Count > period && period > 0) { buffer.RemoveAt(0); }
|
||||
return;
|
||||
}
|
||||
buffer[^1] = value;
|
||||
}
|
||||
public virtual void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
public void TrimToSize(int keep)
|
||||
{
|
||||
if (keep >= this.Count)
|
||||
{
|
||||
return; // No need to trim if the series is already smaller than or equal to n
|
||||
}
|
||||
|
||||
// Remove elements from the beginning of the list
|
||||
int elementsToRemove = this.Count - keep;
|
||||
RemoveRange(0, elementsToRemove);
|
||||
}
|
||||
}
|
||||
@@ -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 VAR_Series : TSeries
|
||||
{
|
||||
private readonly System.Collections.Generic.List<double> _buffer = new();
|
||||
protected readonly int _period;
|
||||
protected readonly bool _NaN;
|
||||
protected readonly TSeries _data;
|
||||
|
||||
//core constructors
|
||||
public VAR_Series(int period, bool useNaN)
|
||||
{
|
||||
_period = period;
|
||||
_NaN = useNaN;
|
||||
Name = $"VAR({period})";
|
||||
}
|
||||
public VAR_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
|
||||
{
|
||||
_data = source;
|
||||
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
|
||||
_data.Pub += Sub;
|
||||
Add(_data);
|
||||
}
|
||||
public VAR_Series() : this(period: 0, useNaN: false) { }
|
||||
public VAR_Series(int period) : this(period: period, useNaN: false) { }
|
||||
public VAR_Series(TBars source) : this(source.Close, 0, false) { }
|
||||
public VAR_Series(TBars source, int period) : this(source.Close, period, false) { }
|
||||
public VAR_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
|
||||
public VAR_Series(TSeries source) : this(source, 0, false) { }
|
||||
public VAR_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
|
||||
|
||||
//////////////////
|
||||
// core Add() algo
|
||||
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
|
||||
{
|
||||
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
|
||||
|
||||
double _sma = _buffer.Average();
|
||||
|
||||
double _pvar = 0;
|
||||
for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
|
||||
_pvar /= this._buffer.Count;
|
||||
|
||||
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _pvar);
|
||||
return base.Add(res, update);
|
||||
}
|
||||
|
||||
public override (DateTime t, double v) Add(TSeries data)
|
||||
{
|
||||
if (data == null) { return (DateTime.Today, Double.NaN); }
|
||||
foreach (var item in data) { Add(item, false); }
|
||||
return _data.Last;
|
||||
}
|
||||
public (DateTime t, double v) Add(bool update)
|
||||
{
|
||||
return this.Add(TValue: _data.Last, update: update);
|
||||
}
|
||||
public (DateTime t, double v) Add()
|
||||
{
|
||||
return Add(TValue: _data.Last, update: false);
|
||||
}
|
||||
private new void Sub(object source, TSeriesEventArgs e)
|
||||
{
|
||||
Add(TValue: _data.Last, update: e.update);
|
||||
}
|
||||
|
||||
//reset calculation
|
||||
public override void Reset()
|
||||
{
|
||||
_buffer.Clear();
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace QuanTAlib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/* <summary>
|
||||
WMAPE: Weighted Mean Absolute Percentage Error
|
||||
Measures the size of the error in percentage terms. Improves problems with MAPE
|
||||
when there are zero or close-to-zero values because there would be a division by zero
|
||||
or values of MAPE tending to infinity.
|
||||
|
||||
Sources:
|
||||
https://en.wikipedia.org/wiki/WMAPE
|
||||
|
||||
</summary> */
|
||||
|
||||
public class WMAPE_Series : TSeries
|
||||
{
|
||||
private readonly System.Collections.Generic.List<double> _buffer = new();
|
||||
protected readonly int _period;
|
||||
protected readonly bool _NaN;
|
||||
protected readonly TSeries _data;
|
||||
|
||||
//core constructors
|
||||
public WMAPE_Series(int period, bool useNaN)
|
||||
{
|
||||
_period = period;
|
||||
_NaN = useNaN;
|
||||
Name = $"WMAPE({period})";
|
||||
}
|
||||
public WMAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
|
||||
{
|
||||
_data = source;
|
||||
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
|
||||
_data.Pub += Sub;
|
||||
Add(_data);
|
||||
}
|
||||
public WMAPE_Series() : this(period: 0, useNaN: false) { }
|
||||
public WMAPE_Series(int period) : this(period: period, useNaN: false) { }
|
||||
public WMAPE_Series(TBars source) : this(source.Close, 0, false) { }
|
||||
public WMAPE_Series(TBars source, int period) : this(source.Close, period, false) { }
|
||||
public WMAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
|
||||
public WMAPE_Series(TSeries source) : this(source, 0, false) { }
|
||||
public WMAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
|
||||
|
||||
//////////////////
|
||||
// core Add() algo
|
||||
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
|
||||
{
|
||||
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
|
||||
|
||||
double _sma = _buffer.Average();
|
||||
|
||||
double _div = 0;
|
||||
double _wmape = 0;
|
||||
for (int i = 0; i < _buffer.Count; i++)
|
||||
{
|
||||
_wmape += Math.Abs(_buffer[i] - _sma);
|
||||
_div += Math.Abs(_buffer[i]);
|
||||
}
|
||||
_wmape = (_div != 0) ? _wmape / _div : double.PositiveInfinity;
|
||||
|
||||
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _wmape);
|
||||
return base.Add(res, update);
|
||||
}
|
||||
|
||||
public override (DateTime t, double v) Add(TSeries data)
|
||||
{
|
||||
if (data == null) { return (DateTime.Today, Double.NaN); }
|
||||
foreach (var item in data) { Add(item, false); }
|
||||
return _data.Last;
|
||||
}
|
||||
public (DateTime t, double v) Add(bool update)
|
||||
{
|
||||
return this.Add(TValue: _data.Last, update: update);
|
||||
}
|
||||
public (DateTime t, double v) Add()
|
||||
{
|
||||
return Add(TValue: _data.Last, update: false);
|
||||
}
|
||||
private new void Sub(object source, TSeriesEventArgs e)
|
||||
{
|
||||
Add(TValue: _data.Last, update: e.update);
|
||||
}
|
||||
|
||||
//reset calculation
|
||||
public override void Reset()
|
||||
{
|
||||
_buffer.Clear();
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
namespace QuanTAlib;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
/* <summary>
|
||||
WMA: (linearly) Weighted Moving Average
|
||||
The weights are linearly decreasing over the period and the most recent data has
|
||||
the heaviest weight.
|
||||
|
||||
Sources:
|
||||
https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/weighted-moving-average-wma/
|
||||
https://www.technicalindicators.net/indicators-technical-analysis/83-moving-averages-simple-exponential-weighted
|
||||
|
||||
</summary> */
|
||||
|
||||
public class WMA_Series : TSeries
|
||||
{
|
||||
private readonly System.Collections.Generic.List<double> _buffer = new();
|
||||
private System.Collections.Generic.List<double> _weights;
|
||||
protected int _period;
|
||||
protected readonly bool _NaN;
|
||||
protected readonly TSeries _data;
|
||||
protected int _len;
|
||||
public int Len
|
||||
{
|
||||
get { return _len; }
|
||||
set { _len = value; }
|
||||
}
|
||||
|
||||
//core constructors
|
||||
public WMA_Series(int period, bool useNaN)
|
||||
{
|
||||
_period = period;
|
||||
_NaN = useNaN;
|
||||
Name = $"WMA({period})";
|
||||
_len = 1;
|
||||
_weights = CalculateWeights(_period);
|
||||
}
|
||||
public WMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
|
||||
{
|
||||
_data = source;
|
||||
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
|
||||
_data.Pub += Sub;
|
||||
Add(_data);
|
||||
}
|
||||
public WMA_Series() : this(period: 0, useNaN: false) { }
|
||||
public WMA_Series(int period) : this(period: period, useNaN: false) { }
|
||||
public WMA_Series(TBars source) : this(source.Close, 0, false) { }
|
||||
public WMA_Series(TBars source, int period) : this(source.Close, period, false) { }
|
||||
public WMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
|
||||
public WMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
|
||||
|
||||
//////////////////
|
||||
// core Add() algo
|
||||
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
|
||||
{
|
||||
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
|
||||
if (_period == 0)
|
||||
{
|
||||
_weights = CalculateWeights(_len);
|
||||
_len++;
|
||||
}
|
||||
double _wma = 0;
|
||||
double totalWeights = (_buffer.Count * (_buffer.Count + 1)) * 0.5;
|
||||
object lockObj = new object();
|
||||
Parallel.For(0, _buffer.Count, i =>
|
||||
{
|
||||
double temp = _buffer[i] * this._weights[i];
|
||||
lock (lockObj) { _wma += temp; }
|
||||
});
|
||||
_wma /= totalWeights;
|
||||
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _wma);
|
||||
return base.Add(res, update);
|
||||
}
|
||||
|
||||
public override (DateTime t, double v) Add(TSeries data)
|
||||
{
|
||||
if (data == null) { return (DateTime.Today, Double.NaN); }
|
||||
foreach (var item in data) { Add(item, false); }
|
||||
return _data.Last;
|
||||
}
|
||||
public (DateTime t, double v) Add(bool update)
|
||||
{
|
||||
return this.Add(TValue: _data.Last, update: update);
|
||||
}
|
||||
public (DateTime t, double v) Add()
|
||||
{
|
||||
return Add(TValue: _data.Last, update: false);
|
||||
}
|
||||
private new void Sub(object source, TSeriesEventArgs e)
|
||||
{
|
||||
Add(TValue: _data.Last, update: e.update);
|
||||
}
|
||||
|
||||
//calculating weights
|
||||
private static List<double> CalculateWeights(int period)
|
||||
{
|
||||
List<double> weights = new List<double>(period);
|
||||
for (int i = 0; i < period; i++)
|
||||
{
|
||||
weights.Add(i + 1);
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
|
||||
//reset calculation
|
||||
public override void Reset()
|
||||
{
|
||||
_len = 0;
|
||||
_weights = CalculateWeights(_period);
|
||||
_buffer.Clear();
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
namespace QuanTAlib;
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
/* <summary>
|
||||
ZLEMA: Zero Lag Exponential Moving Average
|
||||
The Zero lag exponential moving average (ZLEMA) indicator was created by John
|
||||
Ehlers and Ric Way.
|
||||
|
||||
The formula for a given N-Day period and for a given Data series is:
|
||||
Lag = (Period-1)/2
|
||||
Ema Data = {Data+(Data-Data(Lag days ago))
|
||||
ZLEMA = EMA (EmaData,Period)
|
||||
|
||||
Remark:
|
||||
The idea is do a regular exponential moving average (EMA) calculation but on a
|
||||
de-lagged data instead of doing it on the regular data. Data is de-lagged by
|
||||
removing the data from "lag" days ago thus removing (or attempting to remove)
|
||||
the cumulative lag effect of the moving average.
|
||||
|
||||
</summary> */
|
||||
|
||||
public class ZLEMA_Series : TSeries
|
||||
{
|
||||
private readonly System.Collections.Generic.List<double> _buffer = new();
|
||||
private int _len;
|
||||
protected readonly int _period;
|
||||
protected readonly bool _NaN;
|
||||
protected readonly TSeries _data;
|
||||
private readonly EMA_Series _ema;
|
||||
|
||||
//core constructor
|
||||
public ZLEMA_Series(int period, bool useNaN, bool useSMA)
|
||||
{
|
||||
_period = period;
|
||||
_NaN = useNaN;
|
||||
Name = $"ZLEMA({period})";
|
||||
_len = 1;
|
||||
_ema = new(period);
|
||||
}
|
||||
//generic constructors (source)
|
||||
|
||||
public ZLEMA_Series() : this(0, false, true) { }
|
||||
public ZLEMA_Series(int period) : this(period, false, true) { }
|
||||
public ZLEMA_Series(TBars source) : this(source.Close, 0, false) { }
|
||||
public ZLEMA_Series(TBars source, int period) : this(source.Close, period, false) { }
|
||||
public ZLEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
|
||||
public ZLEMA_Series(TSeries source, int period) : this(source, period, false, true) { }
|
||||
public ZLEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
|
||||
public ZLEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA)
|
||||
{
|
||||
_data = source;
|
||||
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
|
||||
_data.Pub += Sub;
|
||||
Add(_data);
|
||||
}
|
||||
|
||||
// core Add() algo
|
||||
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
|
||||
{
|
||||
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
|
||||
int _lag;
|
||||
if (_period == 0)
|
||||
{
|
||||
_lag = (int)((_len - 1) * 0.5);
|
||||
_len++;
|
||||
}
|
||||
else { _lag = (int)((_period - 1) * 0.5); }
|
||||
_lag = Math.Min(_lag, _buffer.Count - 1);
|
||||
_lag = Math.Max(_lag, 0) + 1;
|
||||
double _zlValue = 2 * TValue.v - _buffer[^_lag];
|
||||
double _zlema = _ema.Add((TValue.t, _zlValue), update).v;
|
||||
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zlema);
|
||||
return base.Add(res, update);
|
||||
}
|
||||
|
||||
//variation of Add()
|
||||
public override (DateTime t, double v) Add(TSeries data)
|
||||
{
|
||||
if (data == null) { return (DateTime.Today, Double.NaN); }
|
||||
foreach (var item in data) { Add(item, false); }
|
||||
return _data.Last;
|
||||
}
|
||||
|
||||
public (DateTime t, double v) Add(bool update)
|
||||
{
|
||||
return this.Add(TValue: _data.Last, update: update);
|
||||
}
|
||||
public (DateTime t, double v) Add()
|
||||
{
|
||||
return Add(TValue: _data.Last, update: false);
|
||||
}
|
||||
private new void Sub(object source, TSeriesEventArgs e)
|
||||
{
|
||||
Add(TValue: _data.Last, update: e.update);
|
||||
}
|
||||
|
||||
//reset calculation
|
||||
public override void Reset()
|
||||
{
|
||||
_buffer.Clear();
|
||||
_ema.Reset();
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
namespace QuanTAlib;
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
/* <summary>
|
||||
ZL: Zero Lag
|
||||
Data is de-lagged by removing the data from “lag” days ago, thus removing
|
||||
(or attempting to) the cumulative effect of the moving average.
|
||||
|
||||
Calculation:
|
||||
Lag = (Period-1)/2
|
||||
ZL = Data + (Data - Data(Lag days ago) )
|
||||
|
||||
Sources:
|
||||
https://mudrex.com/blog/zero-lag-ema-trading-strategy/
|
||||
|
||||
</summary> */
|
||||
|
||||
public class ZL_Series : TSeries
|
||||
{
|
||||
private readonly System.Collections.Generic.List<double> _buffer = new();
|
||||
private int _len;
|
||||
protected readonly int _period;
|
||||
protected readonly bool _NaN;
|
||||
protected readonly TSeries _data;
|
||||
private readonly EMA_Series _ema;
|
||||
|
||||
//core constructor
|
||||
public ZL_Series(int period, bool useNaN, bool useSMA)
|
||||
{
|
||||
_period = period;
|
||||
_NaN = useNaN;
|
||||
Name = $"ZL({period})";
|
||||
_len = 1;
|
||||
_ema = new(period);
|
||||
}
|
||||
//generic constructors (source)
|
||||
|
||||
public ZL_Series() : this(0, false, true) { }
|
||||
public ZL_Series(int period) : this(period, false, true) { }
|
||||
public ZL_Series(TBars source) : this(source.Close, 0, false) { }
|
||||
public ZL_Series(TBars source, int period) : this(source.Close, period, false) { }
|
||||
public ZL_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
|
||||
public ZL_Series(TSeries source, int period) : this(source, period, false, true) { }
|
||||
public ZL_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
|
||||
public ZL_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA)
|
||||
{
|
||||
_data = source;
|
||||
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
|
||||
_data.Pub += Sub;
|
||||
Add(_data);
|
||||
}
|
||||
|
||||
// core Add() algo
|
||||
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
|
||||
{
|
||||
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
|
||||
int _lag;
|
||||
if (_period == 0)
|
||||
{
|
||||
_lag = (int)((_len - 1) * 0.5);
|
||||
_len++;
|
||||
}
|
||||
else { _lag = (int)((_period - 1) * 0.5); }
|
||||
_lag = Math.Min(_lag, _buffer.Count - 1);
|
||||
_lag = Math.Max(_lag, 0) + 1;
|
||||
double _zlValue = 2 * TValue.v - _buffer[^_lag];
|
||||
|
||||
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zlValue);
|
||||
return base.Add(res, update);
|
||||
}
|
||||
|
||||
//variation of Add()
|
||||
public override (DateTime t, double v) Add(TSeries data)
|
||||
{
|
||||
if (data == null) { return (DateTime.Today, Double.NaN); }
|
||||
foreach (var item in data) { Add(item, false); }
|
||||
return _data.Last;
|
||||
}
|
||||
public (DateTime t, double v) Add(bool update)
|
||||
{
|
||||
return this.Add(TValue: _data.Last, update: update);
|
||||
}
|
||||
public (DateTime t, double v) Add()
|
||||
{
|
||||
return Add(TValue: _data.Last, update: false);
|
||||
}
|
||||
private new void Sub(object source, TSeriesEventArgs e)
|
||||
{
|
||||
Add(TValue: _data.Last, update: e.update);
|
||||
}
|
||||
|
||||
//reset calculation
|
||||
public override void Reset()
|
||||
{
|
||||
_buffer.Clear();
|
||||
_ema.Reset();
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace QuanTAlib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/* <summary>
|
||||
ZSCORE: number of standard deviations from SMA
|
||||
Z-score describes a value's relationship to the mean of a series, as measured in
|
||||
terms of standard deviations from the mean. If a Z-score is 0, it indicates that
|
||||
the data point's score is identical to the mean score. A Z-score of 1.0 would
|
||||
indicate a value that is one standard deviation from the mean. Z-scores may be
|
||||
positive or negative, with a positive value indicating the score is above the
|
||||
mean and a negative score indicating it is below the mean.
|
||||
|
||||
Sources:
|
||||
https://en.wikipedia.org/wiki/Z-score
|
||||
https://www.investopedia.com/terms/z/zscore.asp
|
||||
|
||||
Calculation:
|
||||
std = std * STDEV(close, length)
|
||||
mean = SMA(close, length)
|
||||
ZSCORE = (close - mean) / std
|
||||
|
||||
</summary> */
|
||||
|
||||
public class ZSCORE_Series : TSeries
|
||||
{
|
||||
private readonly System.Collections.Generic.List<double> _buffer = new();
|
||||
protected readonly int _period;
|
||||
protected readonly bool _NaN;
|
||||
protected readonly TSeries _data;
|
||||
|
||||
//core constructors
|
||||
public ZSCORE_Series(int period, bool useNaN)
|
||||
{
|
||||
_period = period;
|
||||
_NaN = useNaN;
|
||||
Name = $"ZSCORE({period})";
|
||||
}
|
||||
public ZSCORE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
|
||||
{
|
||||
_data = source;
|
||||
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
|
||||
_data.Pub += Sub;
|
||||
Add(_data);
|
||||
}
|
||||
public ZSCORE_Series() : this(period: 0, useNaN: false) { }
|
||||
public ZSCORE_Series(int period) : this(period: period, useNaN: false) { }
|
||||
public ZSCORE_Series(TBars source) : this(source.Close, 0, false) { }
|
||||
public ZSCORE_Series(TBars source, int period) : this(source.Close, period, false) { }
|
||||
public ZSCORE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
|
||||
public ZSCORE_Series(TSeries source) : this(source, 0, false) { }
|
||||
public ZSCORE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
|
||||
|
||||
//////////////////
|
||||
// core Add() algo
|
||||
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
|
||||
{
|
||||
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
|
||||
double _sma = _buffer.Average();
|
||||
|
||||
double _pvar = 0;
|
||||
for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
|
||||
_pvar /= this._buffer.Count;
|
||||
double _psdev = Math.Sqrt(_pvar);
|
||||
double _zscore = (_psdev == 0) ? 1 : (TValue.v - _sma) / _psdev;
|
||||
|
||||
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zscore);
|
||||
return base.Add(res, update);
|
||||
}
|
||||
|
||||
public override (DateTime t, double v) Add(TSeries data)
|
||||
{
|
||||
if (data == null) { return (DateTime.Today, Double.NaN); }
|
||||
foreach (var item in data) { Add(item, false); }
|
||||
return _data.Last;
|
||||
}
|
||||
public (DateTime t, double v) Add(bool update)
|
||||
{
|
||||
return this.Add(TValue: _data.Last, update: update);
|
||||
}
|
||||
public (DateTime t, double v) Add()
|
||||
{
|
||||
return Add(TValue: _data.Last, update: false);
|
||||
}
|
||||
private new void Sub(object source, TSeriesEventArgs e)
|
||||
{
|
||||
Add(TValue: _data.Last, update: e.update);
|
||||
}
|
||||
|
||||
//reset calculation
|
||||
public override void Reset()
|
||||
{
|
||||
_buffer.Clear();
|
||||
}
|
||||
}
|
||||
@@ -1,298 +0,0 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using TradingPlatform.BusinessLayer;
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class MovingAverage_chart : Indicator
|
||||
{
|
||||
#region Parameters
|
||||
[InputParameter("MA1: Type:", 0, variants: new object[]
|
||||
{ "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
|
||||
"ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
|
||||
private int MA1type = 15;
|
||||
|
||||
[InputParameter("MA1: Smoothing period:", 1, 1, 999, 1, 1)]
|
||||
private int MA1Period = 10;
|
||||
|
||||
[InputParameter("MA1: Data source:", 2, variants: new object[]
|
||||
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
|
||||
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
|
||||
private int MA1DataSource = 3;
|
||||
|
||||
[InputParameter("MA2: Type:", 3, variants: new object[]
|
||||
{ "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
|
||||
"ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
|
||||
private int MA2type = 16;
|
||||
|
||||
[InputParameter("MA2: Smoothing period:", 4, 1, 999, 1, 1)]
|
||||
private int MA2Period = 50;
|
||||
|
||||
[InputParameter("MA2: Data source:", 5, variants: new object[]
|
||||
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
|
||||
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
|
||||
private int MA2DataSource = 8;
|
||||
|
||||
[InputParameter("Long trades", 6)]
|
||||
private bool LongTrades = true;
|
||||
|
||||
[InputParameter("Short trades", 6)]
|
||||
private bool ShortTrades = true;
|
||||
|
||||
#endregion Parameters
|
||||
|
||||
protected HistoricalData History;
|
||||
private TBars bars;
|
||||
|
||||
///////
|
||||
private TSeries MA1, MA2;
|
||||
private CROSS_Series trades;
|
||||
private COMPARE_Series overunder;
|
||||
|
||||
///////
|
||||
|
||||
public MovingAverage_chart()
|
||||
{
|
||||
this.SeparateWindow = false;
|
||||
this.Name = "MAs Crossover";
|
||||
this.AddLineSeries("MA1", Color.LimeGreen, 2, LineStyle.Solid);
|
||||
this.AddLineSeries("MA2", Color.OrangeRed, 2, LineStyle.Solid);
|
||||
}
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
this.bars = new();
|
||||
this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
|
||||
for (int i = this.History.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var rec = this.History[i, SeekOriginHistory.Begin];
|
||||
bars.Add(rec.TimeLeft, rec[PriceType.Open],
|
||||
rec[PriceType.High], rec[PriceType.Low],
|
||||
rec[PriceType.Close], rec[PriceType.Volume]);
|
||||
}
|
||||
this.Name = "MAs Cross: [ ";
|
||||
switch (MA1type)
|
||||
{
|
||||
case 0:
|
||||
MA1 = new SMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"SMA";
|
||||
break;
|
||||
case 1:
|
||||
MA1 = new EMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"EMA";
|
||||
break;
|
||||
case 2:
|
||||
MA1 = new WMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"WMA";
|
||||
break;
|
||||
case 3:
|
||||
MA1 = new T3_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"T3";
|
||||
break;
|
||||
case 4:
|
||||
MA1 = new SMMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"SMMA";
|
||||
break;
|
||||
case 5:
|
||||
MA1 = new TRIMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"TRIMA";
|
||||
break;
|
||||
case 6:
|
||||
MA1 = new DWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"DWMA";
|
||||
break;
|
||||
case 7:
|
||||
MA1 = new FWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period);
|
||||
this.Name += $"FWMA";
|
||||
break;
|
||||
case 8:
|
||||
MA1 = new DEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"DEMA";
|
||||
break;
|
||||
case 9:
|
||||
MA1 = new TEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"TEMA";
|
||||
break;
|
||||
case 10:
|
||||
MA1 = new ALMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"ALMA";
|
||||
break;
|
||||
case 11:
|
||||
MA1 = new HMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"HMA";
|
||||
break;
|
||||
case 12:
|
||||
MA1 = new HEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"HEMA";
|
||||
break;
|
||||
case 13:
|
||||
double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA1Period);
|
||||
MA1 = new MAMA_Series(source: bars.Select(this.MA1DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
|
||||
this.Name += $"MAMA";
|
||||
break;
|
||||
case 14:
|
||||
MA1 = new KAMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"KAMA";
|
||||
break;
|
||||
case 15:
|
||||
MA1 = new ZLEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"ZLEMA";
|
||||
break;
|
||||
default:
|
||||
MA1 = new JMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"JMA";
|
||||
break;
|
||||
}
|
||||
|
||||
this.Name = this.Name + $" ({MA1Period}:{TBars.SelectStr(this.MA1DataSource)}) : ";
|
||||
|
||||
switch (MA2type)
|
||||
{
|
||||
case 0:
|
||||
MA2 = new SMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"SMA";
|
||||
break;
|
||||
case 1:
|
||||
MA2 = new EMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"EMA";
|
||||
break;
|
||||
case 2:
|
||||
MA2 = new WMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"WMA";
|
||||
break;
|
||||
case 3:
|
||||
MA2 = new T3_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"T3";
|
||||
break;
|
||||
case 4:
|
||||
MA2 = new SMMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"SMMA";
|
||||
break;
|
||||
case 5:
|
||||
MA2 = new TRIMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"TRIMA";
|
||||
break;
|
||||
case 6:
|
||||
MA2 = new DWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"DWMA";
|
||||
break;
|
||||
case 7:
|
||||
MA2 = new FWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period);
|
||||
this.Name += $"FWMA";
|
||||
break;
|
||||
case 8:
|
||||
MA2 = new DEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"DEMA";
|
||||
break;
|
||||
case 9:
|
||||
MA2 = new TEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"TEMA";
|
||||
break;
|
||||
case 10:
|
||||
MA2 = new ALMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"ALMA";
|
||||
break;
|
||||
case 11:
|
||||
MA2 = new HMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"HMA";
|
||||
break;
|
||||
case 12:
|
||||
MA2 = new HEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"HEMA";
|
||||
break;
|
||||
case 13:
|
||||
double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA2Period);
|
||||
MA2 = new MAMA_Series(source: bars.Select(this.MA2DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
|
||||
this.Name += $"MAMA";
|
||||
break;
|
||||
case 14:
|
||||
MA2 = new KAMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"KAMA";
|
||||
break;
|
||||
case 15:
|
||||
MA2 = new ZLEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"ZLEMA";
|
||||
break;
|
||||
default:
|
||||
MA2 = new JMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"JMA";
|
||||
break;
|
||||
}
|
||||
this.Name += $"({MA2Period}:{TBars.SelectStr(this.MA2DataSource)}) ]";
|
||||
|
||||
int maxKeep = Math.Max(Math.Max(this.MA1Period, this.MA2Period), 100);
|
||||
MA1.Keep = maxKeep;
|
||||
MA2.Keep = maxKeep;
|
||||
trades.Keep = maxKeep;
|
||||
overunder.Keep = maxKeep;
|
||||
|
||||
overunder = new(MA1, MA2);
|
||||
trades = new(MA1, MA2);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(UpdateArgs args)
|
||||
{
|
||||
bool update = !(args.Reason == UpdateReason.NewBar ||
|
||||
args.Reason == UpdateReason.HistoricalBar);
|
||||
this.bars.Add(this.Time(), this.GetPrice(PriceType.Open),
|
||||
this.GetPrice(PriceType.High),
|
||||
this.GetPrice(PriceType.Low),
|
||||
this.GetPrice(PriceType.Close),
|
||||
this.GetPrice(PriceType.Volume), update);
|
||||
this.SetValue(this.MA1[^1].v, lineIndex: 0);
|
||||
this.SetValue(this.MA2[^1].v, lineIndex: 1);
|
||||
|
||||
if (trades[^1].v == 1)
|
||||
{
|
||||
this.EndCloud(0, 1, Color.Empty);
|
||||
if (LongTrades)
|
||||
{
|
||||
this.LinesSeries[0].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.UpArrow));
|
||||
this.BeginCloud(0, 1, Color.FromArgb(127, Color.Green));
|
||||
}
|
||||
if (ShortTrades)
|
||||
{
|
||||
this.LinesSeries[1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.DownArrow));
|
||||
}
|
||||
}
|
||||
if (trades[^1].v == -1)
|
||||
{
|
||||
this.EndCloud(0, 1, Color.Empty);
|
||||
if (ShortTrades)
|
||||
{
|
||||
this.LinesSeries[1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.UpArrow));
|
||||
this.BeginCloud(0, 1, Color.FromArgb(127, Color.Red));
|
||||
}
|
||||
if (LongTrades)
|
||||
{
|
||||
this.LinesSeries[0].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.DownArrow));
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void OnPaintChart(PaintChartEventArgs args)
|
||||
{
|
||||
base.OnPaintChart(args);
|
||||
if (this.CurrentChart == null) { return; }
|
||||
Graphics graphics = args.Graphics;
|
||||
var mainWindow = this.CurrentChart.MainWindow;
|
||||
int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
|
||||
int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
|
||||
int historycount = HistoricalData.Count;
|
||||
int ymax = mainWindow.ClientRectangle.Height;
|
||||
int xmax = mainWindow.ClientRectangle.Width;
|
||||
|
||||
/*
|
||||
for (int i = leftIndex; i <= rightIndex; i++) {
|
||||
int xi = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - 1 - i)));
|
||||
int width = this.CurrentChart.BarsWidth;
|
||||
int height = (int)((equity[i+historycount].v) *proportion);
|
||||
|
||||
Brush bb = Brushes.DarkSlateGray;
|
||||
bb = (overunder[i+historycount].v>0 && LongTrades)? Brushes.Green : bb;
|
||||
bb = (overunder[i + historycount].v < 0 && ShortTrades) ? Brushes.Red : bb;
|
||||
|
||||
graphics.FillRectangle(bb, xi, ymax - height, width, height);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -1,320 +0,0 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using TradingPlatform.BusinessLayer;
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class MovingAverageSlope_chart : Indicator
|
||||
{
|
||||
#region Parameters
|
||||
[InputParameter("MA1: Type:", 0, variants: new object[]
|
||||
{ "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
|
||||
"ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
|
||||
private int MA1type = 16;
|
||||
|
||||
[InputParameter("MA1: Smoothing period:", 1, 1, 999, 1, 1)]
|
||||
private int MA1Period = 10;
|
||||
|
||||
[InputParameter("MA1: Data source:", 2, variants: new object[]
|
||||
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
|
||||
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
|
||||
private int MA1DataSource = 3;
|
||||
|
||||
[InputParameter("MA2: Type:", 3, variants: new object[]
|
||||
{ "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
|
||||
"ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
|
||||
private int MA2type = 6;
|
||||
|
||||
[InputParameter("MA2: Smoothing period:", 4, 1, 999, 1, 1)]
|
||||
private int MA2Period = 50;
|
||||
|
||||
[InputParameter("MA2: Data source:", 5, variants: new object[]
|
||||
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
|
||||
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
|
||||
private int MA2DataSource = 8;
|
||||
|
||||
[InputParameter("Data required for slope calc:", 6, 2, 10, 1, 1)]
|
||||
private int SlopePeriod = 3;
|
||||
|
||||
[InputParameter("Long trades", 7)]
|
||||
private bool LongTrades = true;
|
||||
|
||||
[InputParameter("Short trades", 8)]
|
||||
private bool ShortTrades;
|
||||
|
||||
#endregion Parameters
|
||||
|
||||
protected HistoricalData History;
|
||||
private TBars bars;
|
||||
|
||||
///////
|
||||
private TSeries MA1, MA2;
|
||||
private SLOPE_Series sMA1, sMA2;
|
||||
private CROSS_Series sig1, sig2;
|
||||
|
||||
private bool inLong, inShort;
|
||||
///////
|
||||
|
||||
public MovingAverageSlope_chart()
|
||||
{
|
||||
this.SeparateWindow = false;
|
||||
this.Name = "Slopes convergence";
|
||||
this.AddLineSeries("MA1", Color.DarkSlateGray, 2, LineStyle.Solid);
|
||||
this.AddLineSeries("MA2", Color.DarkSlateGray, 2, LineStyle.Solid);
|
||||
}
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
this.bars = new();
|
||||
this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
|
||||
for (int i = this.History.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var rec = this.History[i, SeekOriginHistory.Begin];
|
||||
bars.Add(rec.TimeLeft, rec[PriceType.Open],
|
||||
rec[PriceType.High], rec[PriceType.Low],
|
||||
rec[PriceType.Close], rec[PriceType.Volume]);
|
||||
}
|
||||
this.Name = "Slopes convergence: [ ";
|
||||
switch (MA1type)
|
||||
{
|
||||
case 0:
|
||||
MA1 = new SMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"SMA";
|
||||
break;
|
||||
case 1:
|
||||
MA1 = new EMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"EMA";
|
||||
break;
|
||||
case 2:
|
||||
MA1 = new WMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"WMA";
|
||||
break;
|
||||
case 3:
|
||||
MA1 = new T3_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"T3";
|
||||
break;
|
||||
case 4:
|
||||
MA1 = new SMMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"SMMA";
|
||||
break;
|
||||
case 5:
|
||||
MA1 = new TRIMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"TRIMA";
|
||||
break;
|
||||
case 6:
|
||||
MA1 = new DWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"DWMA";
|
||||
break;
|
||||
case 7:
|
||||
MA1 = new FWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period);
|
||||
this.Name += $"FWMA";
|
||||
break;
|
||||
case 8:
|
||||
MA1 = new DEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"DEMA";
|
||||
break;
|
||||
case 9:
|
||||
MA1 = new TEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"TEMA";
|
||||
break;
|
||||
case 10:
|
||||
MA1 = new ALMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"ALMA";
|
||||
break;
|
||||
case 11:
|
||||
MA1 = new HMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"HMA";
|
||||
break;
|
||||
case 12:
|
||||
MA1 = new HEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"HEMA";
|
||||
break;
|
||||
case 13:
|
||||
double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA1Period);
|
||||
MA1 = new MAMA_Series(source: bars.Select(this.MA1DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
|
||||
this.Name += $"MAMA";
|
||||
break;
|
||||
case 14:
|
||||
MA1 = new KAMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"KAMA";
|
||||
break;
|
||||
case 15:
|
||||
MA1 = new ZLEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"ZLEMA";
|
||||
break;
|
||||
default:
|
||||
MA1 = new JMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
|
||||
this.Name += $"JMA";
|
||||
break;
|
||||
}
|
||||
|
||||
this.Name = this.Name + $" ({MA1Period}:{TBars.SelectStr(this.MA1DataSource)}) : ";
|
||||
|
||||
switch (MA2type)
|
||||
{
|
||||
case 0:
|
||||
MA2 = new SMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"SMA";
|
||||
break;
|
||||
case 1:
|
||||
MA2 = new EMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"EMA";
|
||||
break;
|
||||
case 2:
|
||||
MA2 = new WMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"WMA";
|
||||
break;
|
||||
case 3:
|
||||
MA2 = new T3_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"T3";
|
||||
break;
|
||||
case 4:
|
||||
MA2 = new SMMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"SMMA";
|
||||
break;
|
||||
case 5:
|
||||
MA2 = new TRIMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"TRIMA";
|
||||
break;
|
||||
case 6:
|
||||
MA2 = new DWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"DWMA";
|
||||
break;
|
||||
case 7:
|
||||
MA2 = new FWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period);
|
||||
this.Name += $"FWMA";
|
||||
break;
|
||||
case 8:
|
||||
MA2 = new DEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"DEMA";
|
||||
break;
|
||||
case 9:
|
||||
MA2 = new TEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"TEMA";
|
||||
break;
|
||||
case 10:
|
||||
MA2 = new ALMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"ALMA";
|
||||
break;
|
||||
case 11:
|
||||
MA2 = new HMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"HMA";
|
||||
break;
|
||||
case 12:
|
||||
MA2 = new HEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"HEMA";
|
||||
break;
|
||||
case 13:
|
||||
double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA2Period);
|
||||
MA2 = new MAMA_Series(source: bars.Select(this.MA2DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
|
||||
this.Name += $"MAMA";
|
||||
break;
|
||||
case 14:
|
||||
MA2 = new KAMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"KAMA";
|
||||
break;
|
||||
case 15:
|
||||
MA2 = new ZLEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"ZLEMA";
|
||||
break;
|
||||
default:
|
||||
MA2 = new JMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
|
||||
this.Name += $"JMA";
|
||||
break;
|
||||
}
|
||||
this.Name += $"({MA2Period}:{TBars.SelectStr(this.MA2DataSource)}) ]";
|
||||
|
||||
sMA1 = new(MA1, SlopePeriod);
|
||||
sMA2 = new(MA2, SlopePeriod);
|
||||
sig1 = new(sMA1, 0);
|
||||
sig2 = new(sMA2, 0);
|
||||
|
||||
int maxKeep = Math.Max(Math.Max(this.MA1Period, this.MA2Period), 100);
|
||||
|
||||
MA1.Keep = maxKeep;
|
||||
MA2.Keep = maxKeep;
|
||||
sMA1.Keep = maxKeep;
|
||||
sMA2.Keep = maxKeep;
|
||||
sig1.Keep = maxKeep;
|
||||
sig2.Keep = maxKeep;
|
||||
}
|
||||
|
||||
protected override void OnUpdate(UpdateArgs args)
|
||||
{
|
||||
bool update = !(args.Reason == UpdateReason.NewBar ||
|
||||
args.Reason == UpdateReason.HistoricalBar);
|
||||
this.bars.Add(this.Time(), this.Open(), this.High(), this.Low(), this.Close(), this.Volume(), update);
|
||||
this.SetValue(this.MA1[^1].v, lineIndex: 0);
|
||||
this.SetValue(this.MA2[^1].v, lineIndex: 1);
|
||||
|
||||
Color s1Color = (this.sMA1[^1].v > 0) ? Color.LimeGreen : Color.OrangeRed;
|
||||
Color s2Color = (this.sMA2[^1].v > 0) ? Color.LimeGreen : Color.OrangeRed;
|
||||
|
||||
this.LinesSeries[0].SetMarker(0, s1Color);
|
||||
this.LinesSeries[1].SetMarker(0, s2Color);
|
||||
|
||||
if (sig1[^1].v > 0 || sig2[^1].v > 0)
|
||||
{
|
||||
if (sMA1[^1].v >= 0 && sMA2[^1].v >= 0 && LongTrades)
|
||||
{
|
||||
inLong = true;
|
||||
this.BeginCloud(0, 1, Color.FromArgb(127, Color.DarkGreen));
|
||||
this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v) ? 0 : 1].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.UpArrow));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.EndCloud(0, 1, Color.Empty);
|
||||
if (inShort && this.Count > 1)
|
||||
{
|
||||
this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v) ? 1 : 0].SetMarker(1, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.DownArrow));
|
||||
inShort = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sig1[^1].v < 0 || sig2[^1].v < 0)
|
||||
{
|
||||
if (sMA1[^1].v <= 0 && sMA2[^1].v <= 0 && ShortTrades)
|
||||
{
|
||||
inShort = true;
|
||||
this.BeginCloud(0, 1, Color.FromArgb(100, Color.Red));
|
||||
this.LinesSeries[(this.MA1[^1].v > this.MA2[^1].v) ? 0 : 1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.UpArrow));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.EndCloud(0, 1, Color.Empty);
|
||||
if (inLong && this.Count > 1)
|
||||
{
|
||||
LinesSeries[(this.MA1[^1].v > this.MA2[^1].v) ? 1 : 0].SetMarker(1, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.DownArrow));
|
||||
inLong = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void OnPaintChart(PaintChartEventArgs args)
|
||||
{
|
||||
base.OnPaintChart(args);
|
||||
if (this.CurrentChart == null) { return; }
|
||||
Graphics graphics = args.Graphics;
|
||||
var mainWindow = this.CurrentChart.MainWindow;
|
||||
int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
|
||||
int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
|
||||
/*
|
||||
int historycount = HistoricalData.Count;
|
||||
int ymax = mainWindow.ClientRectangle.Height;
|
||||
|
||||
|
||||
for (int i = leftIndex; i <= rightIndex; i++) {
|
||||
int xi = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - 1 - i)));
|
||||
int width = this.CurrentChart.BarsWidth;
|
||||
int height = (int)((equity[i+historycount].v) *proportion);
|
||||
|
||||
Brush bb = Brushes.DarkSlateGray;
|
||||
bb = (overunder[i+historycount].v>0 && LongTrades)? Brushes.Green : bb;
|
||||
bb = (overunder[i + historycount].v < 0 && ShortTrades) ? Brushes.Red : bb;
|
||||
|
||||
graphics.FillRectangle(bb, xi, ymax - height, width, height);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using TradingPlatform.BusinessLayer;
|
||||
using TradingPlatform.BusinessLayer.Chart;
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class JMA_chart : Indicator
|
||||
{
|
||||
#region Parameters
|
||||
|
||||
[InputParameter("Data source", 0, variants: new object[]
|
||||
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
|
||||
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
|
||||
private int DataSource = 3;
|
||||
|
||||
[InputParameter("Smoothing period", 1, 1, 999, 1, 1)]
|
||||
private int Period = 9;
|
||||
|
||||
[InputParameter("Volatility short", 2, 3, 50, 1, 1)]
|
||||
private int Vshort = 10;
|
||||
|
||||
[InputParameter("Volatility long", 3, 20, 500, 1, 1)]
|
||||
private int Vlong = 65;
|
||||
|
||||
[InputParameter("Phase", 4, -100, 100, 1, 2)]
|
||||
private double Jphase;
|
||||
|
||||
#endregion Parameters
|
||||
|
||||
///////
|
||||
private JMA_Series indicator;
|
||||
///////
|
||||
|
||||
protected TBars bars;
|
||||
protected IChartWindow mainWindow;
|
||||
protected Graphics graphics;
|
||||
protected int firstOnScreenBarIndex, lastOnScreenBarIndex;
|
||||
protected HistoricalData History;
|
||||
protected int HistPeriod;
|
||||
public JMA_chart()
|
||||
{
|
||||
Name = "JMA - Jurik Moving Avg";
|
||||
Description = "Jurik Moving Average description";
|
||||
AddLineSeries(lineName: "JMA", lineColor: Color.Yellow, lineWidth: 3, lineStyle: LineStyle.Solid);
|
||||
SeparateWindow = false;
|
||||
HistPeriod = Period;
|
||||
}
|
||||
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
base.OnInit();
|
||||
bars = new();
|
||||
var dur1 = this.HistoricalData.FromTime;
|
||||
var dur = this.HistoricalData.Period.Duration.TotalSeconds * (HistPeriod * 4); //seconds of two periods
|
||||
|
||||
this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
|
||||
|
||||
for (int i = this.History.Count - 1; i >= 0; i--)
|
||||
{
|
||||
|
||||
var rec = this.History[i, SeekOriginHistory.Begin];
|
||||
|
||||
bars.Add(rec.TimeLeft, rec[PriceType.Open],
|
||||
rec[PriceType.High], rec[PriceType.Low],
|
||||
rec[PriceType.Close], rec[PriceType.Volume]);
|
||||
}
|
||||
|
||||
indicator = new(source: bars.Select(DataSource), period: Period, phase: Jphase, vshort: Vshort, vlong: Vlong, useNaN: true);
|
||||
indicator.Keep = Math.Max(Period, 100);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(UpdateArgs args)
|
||||
{
|
||||
base.OnUpdate(args);
|
||||
bars.Add(Time(), GetPrice(PriceType.Open),
|
||||
GetPrice(PriceType.High),
|
||||
GetPrice(PriceType.Low),
|
||||
GetPrice(PriceType.Close),
|
||||
GetPrice(PriceType.Volume),
|
||||
update: !(args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar));
|
||||
|
||||
this.SetValue(indicator[^1].v, lineIndex: 0);
|
||||
}
|
||||
public override void OnPaintChart(PaintChartEventArgs args)
|
||||
{
|
||||
base.OnPaintChart(args);
|
||||
if (this.CurrentChart == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
graphics = args.Graphics;
|
||||
mainWindow = this.CurrentChart.MainWindow;
|
||||
|
||||
DateTime leftTime = mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left);
|
||||
DateTime rightTime = mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right);
|
||||
firstOnScreenBarIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(leftTime);
|
||||
lastOnScreenBarIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(rightTime));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using TradingPlatform.BusinessLayer;
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class TrailingStop_chart : Indicator
|
||||
{
|
||||
#region Parameters
|
||||
|
||||
[InputParameter("Period", 0, 1, 100, 1, 1)]
|
||||
protected int _period = 30;
|
||||
|
||||
[InputParameter("Factor", 1, 1, 100, 0.1, 1)]
|
||||
protected double _factor = 10;
|
||||
|
||||
[InputParameter("Long TS", 2)]
|
||||
private bool _LongTS = true;
|
||||
|
||||
[InputParameter("Short TS", 3)]
|
||||
private bool _ShortTS = true;
|
||||
|
||||
#endregion Parameters
|
||||
|
||||
///////
|
||||
private HistoricalData History;
|
||||
private TBars bars;
|
||||
private ATR_Series _atr;
|
||||
private double _tslineL, _ratchetL, _tslineS, _ratchetS;
|
||||
|
||||
///////
|
||||
|
||||
public TrailingStop_chart()
|
||||
{
|
||||
Name = $"ATR Trailing Stop";
|
||||
AddLineSeries(lineName: "TrailingATR Long", lineColor: Color.Yellow, lineWidth: 1, lineStyle: LineStyle.Dot);
|
||||
AddLineSeries(lineName: "Ratchet Long", lineColor: Color.Yellow, lineWidth: 3, lineStyle: LineStyle.Solid);
|
||||
|
||||
AddLineSeries(lineName: "TrailingATR Short", lineColor: Color.Yellow, lineWidth: 1, lineStyle: LineStyle.Dot);
|
||||
AddLineSeries(lineName: "Ratchet Short", lineColor: Color.Yellow, lineWidth: 3, lineStyle: LineStyle.Solid);
|
||||
|
||||
SeparateWindow = false;
|
||||
}
|
||||
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
this.Name = $"Trailing Stop (ATR:{_period}, Mult:{_factor:f2})";
|
||||
this.bars = new();
|
||||
|
||||
this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
|
||||
for (int i = this.History.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var rec = this.History[i, SeekOriginHistory.Begin];
|
||||
bars.Add(rec.TimeLeft, rec[PriceType.Open],
|
||||
rec[PriceType.High], rec[PriceType.Low],
|
||||
rec[PriceType.Close], rec[PriceType.Volume]);
|
||||
}
|
||||
_atr = new(source: bars, _period, useNaN: true);
|
||||
_ratchetL = Double.NegativeInfinity;
|
||||
_ratchetS = Double.PositiveInfinity;
|
||||
|
||||
this.LinesSeries[0].Visible = _LongTS;
|
||||
this.LinesSeries[1].Visible = _LongTS;
|
||||
this.LinesSeries[2].Visible = _ShortTS;
|
||||
this.LinesSeries[3].Visible = _ShortTS;
|
||||
}
|
||||
|
||||
protected override void OnUpdate(UpdateArgs args)
|
||||
{
|
||||
bool update = !(args.Reason == UpdateReason.NewBar ||
|
||||
args.Reason == UpdateReason.HistoricalBar);
|
||||
this.bars.Add(this.Time(), this.GetPrice(PriceType.Open),
|
||||
this.GetPrice(PriceType.High),
|
||||
this.GetPrice(PriceType.Low),
|
||||
this.GetPrice(PriceType.Close),
|
||||
this.GetPrice(PriceType.Volume), update);
|
||||
|
||||
_tslineL = bars.High[^1].v - (_factor * _atr[^1].v);
|
||||
_ratchetL = Math.Max(_tslineL, _ratchetL);
|
||||
if (_ratchetL > bars.Low[^1].v)
|
||||
{
|
||||
this.LinesSeries[1].SetMarker(0, new IndicatorLineMarker(Color.Yellow, bottomIcon: IndicatorLineMarkerIconType.DownArrow));
|
||||
_ratchetL = _tslineL;
|
||||
}
|
||||
|
||||
_tslineS = bars.High[^1].v + (_factor * _atr[^1].v);
|
||||
_ratchetS = Math.Min(_tslineS, _ratchetS);
|
||||
if (_ratchetS < bars.High[^1].v)
|
||||
{
|
||||
this.LinesSeries[3].SetMarker(0, new IndicatorLineMarker(Color.Yellow, upperIcon: IndicatorLineMarkerIconType.UpArrow));
|
||||
_ratchetS = _tslineS;
|
||||
}
|
||||
|
||||
this.SetValue(_tslineL, lineIndex: 0);
|
||||
this.SetValue(_ratchetL, lineIndex: 1);
|
||||
this.SetValue(_tslineS, lineIndex: 2);
|
||||
this.SetValue(_ratchetS, lineIndex: 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
<AlgoType>Indicator</AlgoType>
|
||||
<AssemblyName>QuanTAlib_Indicators</AssemblyName>
|
||||
<RootNamespace>QuanTAlib</RootNamespace>
|
||||
<DebugType>embedded</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<Nullable>disable</Nullable>
|
||||
<SignAssembly>False</SignAssembly>
|
||||
<CodeAnalysisRuleSet>..\.sonarlint\mihakralj_quantalibcsharp.ruleset</CodeAnalysisRuleSet>
|
||||
<AssemblyVersion>0.2.1.0</AssemblyVersion>
|
||||
<FileVersion>0.2.1.0</FileVersion>
|
||||
<InformationalVersion>0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d</InformationalVersion>
|
||||
<Version>0.2.1-dev.2</Version>
|
||||
<SuppressNETSdkWarningProperty>NETSDK1057</SuppressNETSdkWarningProperty>
|
||||
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
|
||||
<NoWarn>NETSDK1057</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<Optimize>True</Optimize>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
|
||||
<PlatformTarget>anycpu</PlatformTarget>
|
||||
<DebugType>full</DebugType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DebugType>embedded</DebugType>
|
||||
<Optimize>True</Optimize>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
|
||||
<PlatformTarget>anycpu</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="..\.sonarlint\mihakralj_quantalib\CSharp\SonarLint.xml" Link="SonarLint.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
|
||||
<Copy SourceFiles=".\bin\$(Configuration)\QuanTAlib_Indicators.dll" DestinationFolder="\Quantower\Settings\Scripts\Indicators\QuanTAlib" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Calculations\**\*.cs" Exclude="..\Calculations\obj\**">
|
||||
<Link>QuanTAlib\%(RecursiveDir)%(Filename)%(Extension)</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="TradingPlatform.BusinessLayer">
|
||||
<HintPath>..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user