mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-17 18:18:04 +00:00
Merge branch 'dev'
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
name: "CodeQL Config"
|
||||||
|
|
||||||
|
queries:
|
||||||
|
- uses: security-and-quality
|
||||||
|
- uses: security-extended
|
||||||
|
|
||||||
|
paths-ignore:
|
||||||
|
- '**/test/**'
|
||||||
|
- '**/tests/**'
|
||||||
|
- '**/*.test.cs'
|
||||||
|
- '**/obj/**'
|
||||||
|
- '**/bin/**'
|
||||||
|
- '**/docs/**'
|
||||||
|
|
||||||
|
query-filters:
|
||||||
|
- exclude:
|
||||||
|
problem.severity:
|
||||||
|
- warning
|
||||||
|
- recommendation
|
||||||
|
|
||||||
|
paths:
|
||||||
|
- src
|
||||||
+127
-63
@@ -1,17 +1,37 @@
|
|||||||
name: Publish Workflow
|
name: Publish Workflow
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push: # Triggers on push events to any branch
|
push:
|
||||||
pull_request: # Triggers on pull request events targeting any branch
|
paths-ignore:
|
||||||
workflow_dispatch: # Allows manual triggering of the workflow
|
- '**.md'
|
||||||
|
- 'docs/**'
|
||||||
|
- '.gitignore'
|
||||||
|
- 'LICENSE'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
- 'docs/**'
|
||||||
|
- '.gitignore'
|
||||||
|
- 'LICENSE'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
pull-requests: read # Allows SonarCloud to decorate PRs with analysis results
|
pull-requests: read # Allows SonarCloud to decorate PRs with analysis results
|
||||||
security-events: write # Required for CodeQL analysis and uploading SARIF results
|
security-events: write # Required for CodeQL analysis and uploading SARIF results
|
||||||
|
|
||||||
|
env:
|
||||||
|
DOTNET_VERSION: '8.x'
|
||||||
|
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
|
||||||
|
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Code_Coverage:
|
Code_Coverage:
|
||||||
|
timeout-minutes: 30
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
@@ -22,7 +42,20 @@ jobs:
|
|||||||
- name: Setup .NET SDK
|
- name: Setup .NET SDK
|
||||||
uses: actions/setup-dotnet@v4
|
uses: actions/setup-dotnet@v4
|
||||||
with:
|
with:
|
||||||
dotnet-version: '8.x'
|
dotnet-version: ${{ env.DOTNET_VERSION }}
|
||||||
|
|
||||||
|
- name: Cache NuGet packages
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.nuget/packages
|
||||||
|
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
|
||||||
|
restore-keys: ${{ runner.os }}-nuget-
|
||||||
|
|
||||||
|
- name: Cache dotnet tools
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.dotnet/tools
|
||||||
|
key: ${{ runner.os }}-dotnet-tools-${{ hashFiles('**/*.csproj') }}
|
||||||
|
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
@@ -61,6 +94,7 @@ jobs:
|
|||||||
/d:sonar.exclusions="**/TestResults/**/*,**/bin/**/*,**/obj/**/*,**/*.html,**/coverage/**/*,**/CoverageReport/**/*,**/*.md,**/*.css,**/docs/**/*,**/archive/**/*,**/notebooks/**/*" `
|
/d:sonar.exclusions="**/TestResults/**/*,**/bin/**/*,**/obj/**/*,**/*.html,**/coverage/**/*,**/CoverageReport/**/*,**/*.md,**/*.css,**/docs/**/*,**/archive/**/*,**/notebooks/**/*" `
|
||||||
/d:sonar.test.exclusions="**Tests.cs,**/obj/**/*,**/bin/**/*" `
|
/d:sonar.test.exclusions="**Tests.cs,**/obj/**/*,**/bin/**/*" `
|
||||||
/d:sonar.cpd.exclusions="**Tests.cs" `
|
/d:sonar.cpd.exclusions="**Tests.cs" `
|
||||||
|
/d:sonar.scanner.scanAll="false" `
|
||||||
/d:sonar.cs.roslyn.ignoreIssues="false" `
|
/d:sonar.cs.roslyn.ignoreIssues="false" `
|
||||||
/d:sonar.issue.ignore.multicriteria="e1" `
|
/d:sonar.issue.ignore.multicriteria="e1" `
|
||||||
/d:sonar.issue.ignore.multicriteria.e1.ruleKey="csharpsquid:S1944,csharpsquid:S2053,csharpsquid:S2222,csharpsquid:S2259,csharpsquid:S2583,csharpsquid:S2589,csharpsquid:S3329,csharpsquid:S3655,csharpsquid:S3900,csharpsquid:S3949,csharpsquid:S3966,csharpsquid:S4158,csharpsquid:S4347,csharpsquid:S5773,csharpsquid:S6781" `
|
/d:sonar.issue.ignore.multicriteria.e1.ruleKey="csharpsquid:S1944,csharpsquid:S2053,csharpsquid:S2222,csharpsquid:S2259,csharpsquid:S2583,csharpsquid:S2589,csharpsquid:S3329,csharpsquid:S3655,csharpsquid:S3900,csharpsquid:S3949,csharpsquid:S3966,csharpsquid:S4158,csharpsquid:S4347,csharpsquid:S5773,csharpsquid:S6781" `
|
||||||
@@ -68,6 +102,8 @@ jobs:
|
|||||||
/d:sonar.verbose="true"
|
/d:sonar.verbose="true"
|
||||||
|
|
||||||
- name: Build Projects
|
- name: Build Projects
|
||||||
|
id: build
|
||||||
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
dotnet build --no-restore --configuration Debug
|
dotnet build --no-restore --configuration Debug
|
||||||
dotnet build ./lib/quantalib.csproj --configuration Release --nologo
|
dotnet build ./lib/quantalib.csproj --configuration Release --nologo
|
||||||
@@ -75,8 +111,15 @@ jobs:
|
|||||||
dotnet build ./quantower/Statistics/_Statistics.csproj --configuration Release --nologo
|
dotnet build ./quantower/Statistics/_Statistics.csproj --configuration Release --nologo
|
||||||
dotnet build ./quantower/Volatility/_Volatility.csproj --configuration Release --nologo
|
dotnet build ./quantower/Volatility/_Volatility.csproj --configuration Release --nologo
|
||||||
dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
|
dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
|
||||||
|
if ($LASTEXITCODE -ne 0) { Write-Error "Build failed" }
|
||||||
|
|
||||||
|
- name: Check Build Status
|
||||||
|
if: steps.build.outcome == 'failure'
|
||||||
|
run: exit 1
|
||||||
|
|
||||||
- name: Run Tests with Coverage
|
- name: Run Tests with Coverage
|
||||||
|
id: tests
|
||||||
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
dotnet test --no-build --configuration Debug /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
|
dotnet test --no-build --configuration Debug /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
|
||||||
dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml"
|
dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml"
|
||||||
@@ -86,9 +129,21 @@ jobs:
|
|||||||
|
|
||||||
- name: Generate Coverage Report
|
- name: Generate Coverage Report
|
||||||
run: |
|
run: |
|
||||||
reportgenerator -reports:*cover*.xml -targetdir:.
|
reportgenerator -reports:*cover*.xml -targetdir:./coverage-report
|
||||||
|
|
||||||
|
- name: Upload Coverage Reports
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: coverage-reports
|
||||||
|
path: |
|
||||||
|
**/TestResults
|
||||||
|
**/coverage-report
|
||||||
|
**/*cover*.xml
|
||||||
|
**/dotcover.*
|
||||||
|
|
||||||
- name: End SonarCloud Analysis
|
- name: End SonarCloud Analysis
|
||||||
|
if: always()
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
@@ -102,13 +157,19 @@ jobs:
|
|||||||
coverage-reports: '*cover*.xml'
|
coverage-reports: '*cover*.xml'
|
||||||
|
|
||||||
- name: Upload Coverage to Codecov
|
- name: Upload Coverage to Codecov
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v4
|
||||||
with:
|
with:
|
||||||
files: 'cover*'
|
files: 'cover*'
|
||||||
verbose: true
|
verbose: true
|
||||||
|
|
||||||
CodeQL:
|
CodeQL:
|
||||||
|
timeout-minutes: 30
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
security-events: write
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -118,12 +179,22 @@ jobs:
|
|||||||
- name: Setup .NET SDK
|
- name: Setup .NET SDK
|
||||||
uses: actions/setup-dotnet@v4
|
uses: actions/setup-dotnet@v4
|
||||||
with:
|
with:
|
||||||
dotnet-version: '8.x'
|
dotnet-version: ${{ env.DOTNET_VERSION }}
|
||||||
|
|
||||||
|
- name: Cache NuGet packages
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.nuget/packages
|
||||||
|
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
|
||||||
|
restore-keys: ${{ runner.os }}-nuget-
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v3
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: 'csharp'
|
languages: 'csharp'
|
||||||
|
queries: security-and-quality
|
||||||
|
config-file: ./.github/codeql/codeql-config.yml
|
||||||
|
tools: latest
|
||||||
|
|
||||||
- name: Restore dependencies
|
- name: Restore dependencies
|
||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
@@ -131,63 +202,51 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: dotnet build --no-restore --configuration Debug
|
run: dotnet build --no-restore --configuration Debug
|
||||||
|
|
||||||
- name: Run Codacy Analysis CLI
|
|
||||||
uses: codacy/codacy-analysis-cli-action@v4
|
|
||||||
with:
|
|
||||||
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
|
|
||||||
verbose: true
|
|
||||||
output: results.sarif
|
|
||||||
format: sarif
|
|
||||||
gh-code-scanning-compat: true
|
|
||||||
max-allowed-issues: 2147483647
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v3
|
uses: github/codeql-action/analyze@v3
|
||||||
|
|
||||||
- name: Upload SARIF results file
|
|
||||||
uses: github/codeql-action/upload-sarif@v3
|
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
output: results
|
||||||
|
upload: true
|
||||||
|
|
||||||
SecurityCodeScan:
|
- name: Run Snyk to check for vulnerabilities
|
||||||
runs-on: windows-latest
|
uses: snyk/actions/dotnet@master
|
||||||
steps:
|
continue-on-error: true
|
||||||
- name: Checkout repository
|
env:
|
||||||
uses: actions/checkout@v4
|
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||||
|
LD_PRELOAD: '' # Clear the LD_PRELOAD to avoid CodeQL conflicts
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
args: |
|
||||||
|
--file=./lib/quantalib.csproj
|
||||||
|
--severity-threshold=low
|
||||||
|
--detection-depth=4
|
||||||
|
--package-manager=nuget
|
||||||
|
|
||||||
- name: Setup NuGet
|
- name: Run Snyk on Solution
|
||||||
uses: nuget/setup-nuget@v1
|
uses: snyk/actions/dotnet@master
|
||||||
|
if: always()
|
||||||
- name: Setup MSBuild
|
continue-on-error: true
|
||||||
uses: microsoft/setup-msbuild@v1
|
env:
|
||||||
|
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||||
- name: Setup .NET SDK
|
LD_PRELOAD: ''
|
||||||
uses: actions/setup-dotnet@v4
|
|
||||||
with:
|
with:
|
||||||
dotnet-version: |
|
args: |
|
||||||
8.x
|
--file=QuanTAlib.sln
|
||||||
3.1.x
|
--all-projects
|
||||||
dotnet-quality: 'preview'
|
--detection-depth=4
|
||||||
|
|
||||||
- name: Set up projects for analysis
|
|
||||||
uses: security-code-scan/security-code-scan-add-action@v1
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
dotnet restore
|
|
||||||
dotnet build --no-restore --configuration Debug
|
|
||||||
|
|
||||||
- name: Convert SARIF for uploading to GitHub
|
|
||||||
uses: security-code-scan/security-code-scan-results-action@v1
|
|
||||||
|
|
||||||
- name: Upload SARIF
|
|
||||||
uses: github/codeql-action/upload-sarif@v3
|
|
||||||
|
|
||||||
|
- name: Run Snyk IaC
|
||||||
|
uses: snyk/actions/iac@master
|
||||||
|
continue-on-error: true
|
||||||
|
env:
|
||||||
|
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||||
|
LD_PRELOAD: ''
|
||||||
|
with:
|
||||||
|
args: |
|
||||||
|
--severity-threshold=low
|
||||||
|
|
||||||
build_publish:
|
build_publish:
|
||||||
needs: [Code_Coverage, CodeQL, SecurityCodeScan]
|
timeout-minutes: 20
|
||||||
|
needs: [Code_Coverage, CodeQL]
|
||||||
if: |
|
if: |
|
||||||
success() &&
|
success() &&
|
||||||
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) ||
|
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) ||
|
||||||
@@ -202,7 +261,14 @@ jobs:
|
|||||||
- name: Setup .NET SDK
|
- name: Setup .NET SDK
|
||||||
uses: actions/setup-dotnet@v4
|
uses: actions/setup-dotnet@v4
|
||||||
with:
|
with:
|
||||||
dotnet-version: '8.x'
|
dotnet-version: ${{ env.DOTNET_VERSION }}
|
||||||
|
|
||||||
|
- name: Cache NuGet packages
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.nuget/packages
|
||||||
|
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
|
||||||
|
restore-keys: ${{ runner.os }}-nuget-
|
||||||
|
|
||||||
- name: Install GitVersion
|
- name: Install GitVersion
|
||||||
uses: gittools/actions/gitversion/setup@v0
|
uses: gittools/actions/gitversion/setup@v0
|
||||||
@@ -226,8 +292,6 @@ jobs:
|
|||||||
dotnet build ./quantower/Volatility/_Volatility.csproj --configuration Release --nologo
|
dotnet build ./quantower/Volatility/_Volatility.csproj --configuration Release --nologo
|
||||||
dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
|
dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
|
||||||
|
|
||||||
############# Publish dev release
|
|
||||||
|
|
||||||
- name: Create or Update Development Release
|
- name: Create or Update Development Release
|
||||||
if: github.ref == 'refs/heads/dev'
|
if: github.ref == 'refs/heads/dev'
|
||||||
env:
|
env:
|
||||||
@@ -247,16 +311,16 @@ jobs:
|
|||||||
|
|
||||||
- name: Push prerelease package to myget.org
|
- name: Push prerelease package to myget.org
|
||||||
if: github.ref == 'refs/heads/dev'
|
if: github.ref == 'refs/heads/dev'
|
||||||
|
continue-on-error: true
|
||||||
|
id: myget-push
|
||||||
run: |
|
run: |
|
||||||
dotnet nuget push 'lib/bin/Release/QuanTAlib.*.nupkg' \
|
dotnet nuget push 'lib/bin/Release/QuanTAlib.*.nupkg' \
|
||||||
--source https://www.myget.org/F/quantalib/api/v3/index.json \
|
--source https://www.myget.org/F/quantalib/api/v3/index.json \
|
||||||
--force-english-output \
|
--force-english-output \
|
||||||
--api-key ${{ secrets.MYGET_DEPLOY_KEY_QUANTALIB }}
|
--api-key ${{ secrets.MYGET_DEPLOY_KEY_QUANTALIB }}
|
||||||
|
|
||||||
############## Publish main release
|
|
||||||
|
|
||||||
- name: Create GitHub Release
|
- name: Create GitHub Release
|
||||||
if: ${{ github.ref == 'refs/heads/main' }}
|
if: github.ref == 'refs/heads/main'
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
<Deterministic>true</Deterministic>
|
<Deterministic>true</Deterministic>
|
||||||
<NeutralLanguage>en-US</NeutralLanguage>
|
<NeutralLanguage>en-US</NeutralLanguage>
|
||||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
|
||||||
<DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports>
|
<DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports>
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
@@ -21,6 +20,9 @@
|
|||||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
|
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
|
||||||
|
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||||
|
<UpdateAssemblyInfo>true</UpdateAssemblyInfo>
|
||||||
|
<GenerateGitVersionInformation>true</GenerateGitVersionInformation>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||||
@@ -49,6 +51,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All"/>
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All"/>
|
||||||
<PackageReference Include="Microsoft.DotNet.Interactive.Formatting" Version="1.0.0-beta.21459.1" />
|
<PackageReference Include="Microsoft.DotNet.Interactive.Formatting" Version="1.0.0-beta.21459.1" />
|
||||||
|
<PackageReference Include="GitVersion.MsBuild" Version="6.0.0-beta.7" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(IsLocalBuild)' == 'true' AND $([MSBuild]::IsOSPlatform('Windows'))">
|
<PropertyGroup Condition="'$(IsLocalBuild)' == 'true' AND $([MSBuild]::IsOSPlatform('Windows'))">
|
||||||
|
|||||||
@@ -597,25 +597,6 @@ public class SyntheticVendor : Vendor
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
private HistoryItemBar GenerateTriangleWave(DateTime time, TimeSpan slice)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,6 +17,24 @@ public class StatisticsUpdateTests
|
|||||||
return ((double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue * 200) - 100; // Range: -100 to 100
|
return ((double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue * 200) - 100; // Range: -100 to 100
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TBar GetRandomBar(bool IsNew)
|
||||||
|
{
|
||||||
|
double open = GetRandomDouble();
|
||||||
|
double high = open + Math.Abs(GetRandomDouble());
|
||||||
|
double low = open - Math.Abs(GetRandomDouble());
|
||||||
|
double close = low + (high - low) * GetRandomDouble();
|
||||||
|
return new TBar(DateTime.Now, open, high, low, close, 1000, IsNew);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TBar GetRandomBar(bool IsNew)
|
||||||
|
{
|
||||||
|
double open = GetRandomDouble();
|
||||||
|
double high = open + Math.Abs(GetRandomDouble());
|
||||||
|
double low = open - Math.Abs(GetRandomDouble());
|
||||||
|
double close = low + (high - low) * GetRandomDouble();
|
||||||
|
return new TBar(DateTime.Now, open, high, low, close, 1000, IsNew);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Curvature_Update()
|
public void Curvature_Update()
|
||||||
{
|
{
|
||||||
@@ -47,6 +65,22 @@ public class StatisticsUpdateTests
|
|||||||
Assert.Equal(initialValue, finalValue, precision);
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Hurst_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Hurst(period: 100, minLength: 10);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Kurtosis_Update()
|
public void Kurtosis_Update()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,6 +26,22 @@ public class VolatilityUpdateTests
|
|||||||
return new TBar(DateTime.Now, open, high, low, close, 1000, IsNew);
|
return new TBar(DateTime.Now, open, high, low, close, 1000, IsNew);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Adr_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Adr(period: 14);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Atr_Update()
|
public void Atr_Update()
|
||||||
{
|
{
|
||||||
@@ -42,6 +58,166 @@ public class VolatilityUpdateTests
|
|||||||
Assert.Equal(initialValue, finalValue, precision);
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Ap_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Ap(period: 20);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Atrp_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Atrp(period: 14);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Bband_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Bband(period: 20, multiplier: 2.0);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Ccv_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Ccv(period: 20);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Ce_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Ce(period: 22, multiplier: 3.0);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Cv_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Cv(period: 20);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Cvi_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Cvi(period: 10, smoothPeriod: 10);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Ewma_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Ewma(period: 20, lambda: 0.94);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Fcb_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Fcb(period: 20, smoothing: 0.5);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Gkv_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Gkv(period: 20);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Historical_Update()
|
public void Historical_Update()
|
||||||
{
|
{
|
||||||
@@ -57,6 +233,22 @@ public class VolatilityUpdateTests
|
|||||||
Assert.Equal(initialValue, finalValue, precision);
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Hlv_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Hlv(period: 20);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Jvolty_Update()
|
public void Jvolty_Update()
|
||||||
{
|
{
|
||||||
@@ -102,22 +294,6 @@ public class VolatilityUpdateTests
|
|||||||
Assert.Equal(initialValue, finalValue, precision);
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Cvi_Update()
|
|
||||||
{
|
|
||||||
var indicator = new Cvi(period: 14);
|
|
||||||
TBar r = GetRandomBar(true);
|
|
||||||
double initialValue = indicator.Calc(r);
|
|
||||||
|
|
||||||
for (int i = 0; i < RandomUpdates; i++)
|
|
||||||
{
|
|
||||||
indicator.Calc(GetRandomBar(IsNew: false));
|
|
||||||
}
|
|
||||||
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
|
||||||
|
|
||||||
Assert.Equal(initialValue, finalValue, precision);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Tr_Update()
|
public void Tr_Update()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -319,4 +319,68 @@ public class VolumeUpdateTests
|
|||||||
|
|
||||||
Assert.Equal(initialValue, finalValue, precision);
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Vf_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Vf(period: 13);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Vp_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Vp(period: 14);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Vwap_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Vwap();
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Vwma_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Vwma(period: 20);
|
||||||
|
TBar r = GetRandomBar(true);
|
||||||
|
double initialValue = indicator.Calc(r);
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(GetRandomBar(IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
# Indicators in QuanTAlib
|
# Indicators in QuanTAlib
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
| **Category** | **Status** | **Completion** |
|
| **Category** | **Status** | **Completion** |
|
||||||
|--------------|:----------:|:--------------:|
|
|--------------|:----------:|:--------------:|
|
||||||
| Basic Transforms | 6 of 6 | 100% |
|
| Basic Transforms | 6 of 6 | 100% |
|
||||||
| Averages & Trends | 33 of 33 | 100% |
|
| Averages & Trends | 33 of 33 | 100% |
|
||||||
| Momentum | 17 of 17 | 100% |
|
| Momentum | 17 of 17 | 100% |
|
||||||
| Oscillators | 12 of 29 | 41% |
|
| Oscillators | 11 of 29 | 38% |
|
||||||
| Volatility | 15 of 35 | 43% |
|
| Volatility | 24 of 35 | 69% |
|
||||||
| Volume | 19 of 19 | 100% |
|
| Volume | 15 of 19 | 79% |
|
||||||
| Numerical Analysis | 13 of 20 | 65% |
|
| Numerical Analysis | 13 of 19 | 68% |
|
||||||
| Errors | 16 of 16 | 100% |
|
| Errors | 16 of 16 | 100% |
|
||||||
| **Total** | **131 of 175** | **75%** |
|
| **Total** | **135 of 174** | **78%** |
|
||||||
|
|
||||||
|Technical Indicator Name| Class Name|
|
|Technical Indicator Name| Class Name|
|
||||||
|-----------|:----------:|
|
|-----------|:----------:|
|
||||||
@@ -109,16 +111,16 @@
|
|||||||
|ATR - Average True Range|`Atr`|
|
|ATR - Average True Range|`Atr`|
|
||||||
|ATRP - Average True Range Percent|`Atrp`|
|
|ATRP - Average True Range Percent|`Atrp`|
|
||||||
|ATRS - ATR Trailing Stop|`Atrs`|
|
|ATRS - ATR Trailing Stop|`Atrs`|
|
||||||
|🚧 BB* - Bollinger Bands® (Upper, Middle, Lower)|`Bb`|
|
|BB* - Bollinger Bands® (Upper, Middle, Lower)|`Bb`|
|
||||||
|🚧 CCV - Close-to-Close Volatility|`Ccv`|
|
|CCV - Close-to-Close Volatility|`Ccv`|
|
||||||
|🚧 CE - Chandelier Exit|`Ce`|
|
|CE - Chandelier Exit|`Ce`|
|
||||||
|🚧 CV - Conditional Volatility (ARCH/GARCH)|`Cv`|
|
|CV - Conditional Volatility (ARCH/GARCH)|`Cv`|
|
||||||
|🚧 CVI - Chaikin's Volatility|`Cvi`|
|
|CVI - Chaikin's Volatility|`Cvi`|
|
||||||
|🚧 DC* - Donchian Channels (Upper, Middle, Lower)|`Dc`|
|
|🚧 DC* - Donchian Channels (Upper, Middle, Lower)|`Dc`|
|
||||||
|🚧 EWMA - Exponential Weighted Moving Average Volatility|`Ewma`|
|
|EWMA - Exponential Weighted Moving Average Volatility|`Ewma`|
|
||||||
|🚧 FCB - Fractal Chaos Bands|`Fcb`|
|
|FCB - Fractal Chaos Bands|`Fcb`|
|
||||||
|🚧 GKV - Garman-Klass Volatility|`Gkv`|
|
|GKV - Garman-Klass Volatility|`Gkv`|
|
||||||
|🚧 HLV - High-Low Volatility|`Hlv`|
|
|HLV - High-Low Volatility|`Hlv`|
|
||||||
|HV - Historical Volatility|`Hv`|
|
|HV - Historical Volatility|`Hv`|
|
||||||
|🚧 ICH* - Ichimoku Cloud (Conversion, Base, Leading Span A, Leading Span B, Lagging Span)|`Ich`|
|
|🚧 ICH* - Ichimoku Cloud (Conversion, Base, Leading Span A, Leading Span B, Lagging Span)|`Ich`|
|
||||||
|JVOLTY - Jurik Volatility|`Jvolty`|
|
|JVOLTY - Jurik Volatility|`Jvolty`|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ namespace QuanTAlib;
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class Dema : AbstractBase
|
public class Dema : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly int _period;
|
|
||||||
private readonly double _k;
|
private readonly double _k;
|
||||||
private readonly double _epsilon = 1e-10;
|
private readonly double _epsilon = 1e-10;
|
||||||
private double _lastEma1, _p_lastEma1;
|
private double _lastEma1, _p_lastEma1;
|
||||||
@@ -31,8 +30,7 @@ public class Dema : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
||||||
}
|
}
|
||||||
_period = period;
|
_k = 2.0 / (period + 1);
|
||||||
_k = 2.0 / (_period + 1);
|
|
||||||
Name = "Dema";
|
Name = "Dema";
|
||||||
double percentile = 0.85; //targeting 85th percentile of correctness of converging EMA
|
double percentile = 0.85; //targeting 85th percentile of correctness of converging EMA
|
||||||
WarmupPeriod = (int)System.Math.Ceiling(-period * System.Math.Log(1 - percentile));
|
WarmupPeriod = (int)System.Math.Ceiling(-period * System.Math.Log(1 - percentile));
|
||||||
|
|||||||
@@ -21,9 +21,8 @@ namespace QuanTAlib;
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class Dsma : AbstractBase
|
public class Dsma : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly int _period;
|
|
||||||
private readonly CircularBuffer _buffer;
|
private readonly CircularBuffer _buffer;
|
||||||
private readonly double _c1, _c2, _c3;
|
private readonly double _c2, _c3;
|
||||||
private readonly double _scaleFactor;
|
private readonly double _scaleFactor;
|
||||||
private readonly double _periodRecip; // 1/_period
|
private readonly double _periodRecip; // 1/_period
|
||||||
private readonly double _scaleByPeriod; // 5/_period
|
private readonly double _scaleByPeriod; // 5/_period
|
||||||
@@ -49,7 +48,6 @@ public class Dsma : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(scaleFactor), "Scale factor must be between 0 and 1 (exclusive).");
|
throw new ArgumentOutOfRangeException(nameof(scaleFactor), "Scale factor must be between 0 and 1 (exclusive).");
|
||||||
}
|
}
|
||||||
_period = period;
|
|
||||||
_periodRecip = 1.0 / period;
|
_periodRecip = 1.0 / period;
|
||||||
_scaleFactor = scaleFactor;
|
_scaleFactor = scaleFactor;
|
||||||
_buffer = new CircularBuffer(period);
|
_buffer = new CircularBuffer(period);
|
||||||
@@ -61,7 +59,7 @@ public class Dsma : AbstractBase
|
|||||||
|
|
||||||
_c2 = b1;
|
_c2 = b1;
|
||||||
_c3 = -a1 * a1;
|
_c3 = -a1 * a1;
|
||||||
_c1 = 1.0 - _c2 - _c3;
|
double _c1 = 1.0 - _c2 - _c3;
|
||||||
_c1Half = _c1 * 0.5;
|
_c1Half = _c1 * 0.5;
|
||||||
_scaleByPeriod = 5.0 / period;
|
_scaleByPeriod = 5.0 / period;
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ public class Epma : AbstractBase
|
|||||||
{
|
{
|
||||||
private readonly int _period;
|
private readonly int _period;
|
||||||
private readonly Convolution _convolution;
|
private readonly Convolution _convolution;
|
||||||
private readonly double[] _baseKernel;
|
|
||||||
|
|
||||||
/// <param name="period">The number of data points used in the EPMA calculation.</param>
|
/// <param name="period">The number of data points used in the EPMA calculation.</param>
|
||||||
/// <exception cref="ArgumentException">Thrown when period is less than 1.</exception>
|
/// <exception cref="ArgumentException">Thrown when period is less than 1.</exception>
|
||||||
@@ -37,7 +36,7 @@ public class Epma : AbstractBase
|
|||||||
throw new System.ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
throw new System.ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
||||||
}
|
}
|
||||||
_period = period;
|
_period = period;
|
||||||
_baseKernel = GenerateKernel(_period);
|
double[] _baseKernel = GenerateKernel(_period);
|
||||||
_convolution = new Convolution(_baseKernel);
|
_convolution = new Convolution(_baseKernel);
|
||||||
Name = "Epma";
|
Name = "Epma";
|
||||||
WarmupPeriod = period;
|
WarmupPeriod = period;
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ namespace QuanTAlib;
|
|||||||
public class Fwma : AbstractBase
|
public class Fwma : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly Convolution _convolution;
|
private readonly Convolution _convolution;
|
||||||
private readonly double[] _kernel;
|
|
||||||
|
|
||||||
/// <param name="period">The number of data points used in the FWMA calculation.</param>
|
/// <param name="period">The number of data points used in the FWMA calculation.</param>
|
||||||
/// <exception cref="ArgumentException">Thrown when period is less than 1.</exception>
|
/// <exception cref="ArgumentException">Thrown when period is less than 1.</exception>
|
||||||
@@ -36,7 +35,7 @@ public class Fwma : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new System.ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
throw new System.ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
||||||
}
|
}
|
||||||
_kernel = GenerateKernel(period);
|
double[] _kernel = GenerateKernel(period);
|
||||||
_convolution = new Convolution(_kernel);
|
_convolution = new Convolution(_kernel);
|
||||||
Name = "Fwma";
|
Name = "Fwma";
|
||||||
WarmupPeriod = period;
|
WarmupPeriod = period;
|
||||||
|
|||||||
+1
-2
@@ -26,7 +26,6 @@ namespace QuanTAlib;
|
|||||||
public class Gma : AbstractBase
|
public class Gma : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly Convolution _convolution;
|
private readonly Convolution _convolution;
|
||||||
private readonly double[] _kernel;
|
|
||||||
|
|
||||||
/// <param name="period">The number of data points used in the GMA calculation.</param>
|
/// <param name="period">The number of data points used in the GMA calculation.</param>
|
||||||
/// <exception cref="ArgumentException">Thrown when period is less than 1.</exception>
|
/// <exception cref="ArgumentException">Thrown when period is less than 1.</exception>
|
||||||
@@ -36,7 +35,7 @@ public class Gma : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new System.ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
throw new System.ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
||||||
}
|
}
|
||||||
_kernel = GenerateKernel(period);
|
double[] _kernel = GenerateKernel(period);
|
||||||
_convolution = new Convolution(_kernel);
|
_convolution = new Convolution(_kernel);
|
||||||
Name = "Gma";
|
Name = "Gma";
|
||||||
WarmupPeriod = period;
|
WarmupPeriod = period;
|
||||||
|
|||||||
+4
-10
@@ -28,11 +28,6 @@ namespace QuanTAlib;
|
|||||||
public class Hma : AbstractBase
|
public class Hma : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly Convolution _wmaHalf, _wmaFull, _wmaFinal;
|
private readonly Convolution _wmaHalf, _wmaFull, _wmaFinal;
|
||||||
private readonly int _period;
|
|
||||||
private readonly int _sqrtPeriod;
|
|
||||||
private readonly double[] _kernelHalf;
|
|
||||||
private readonly double[] _kernelFull;
|
|
||||||
private readonly double[] _kernelFinal;
|
|
||||||
|
|
||||||
/// <param name="period">The number of data points used in the HMA calculation. Must be at least 2.</param>
|
/// <param name="period">The number of data points used in the HMA calculation. Must be at least 2.</param>
|
||||||
/// <exception cref="ArgumentException">Thrown when period is less than 2.</exception>
|
/// <exception cref="ArgumentException">Thrown when period is less than 2.</exception>
|
||||||
@@ -42,13 +37,12 @@ public class Hma : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new System.ArgumentException("Period must be greater than or equal to 2.", nameof(period));
|
throw new System.ArgumentException("Period must be greater than or equal to 2.", nameof(period));
|
||||||
}
|
}
|
||||||
_period = period;
|
int _sqrtPeriod = (int)System.Math.Sqrt(period);
|
||||||
_sqrtPeriod = (int)System.Math.Sqrt(period);
|
|
||||||
|
|
||||||
// Generate all kernels once
|
// Generate all kernels once
|
||||||
_kernelHalf = GenerateWmaKernel(period / 2);
|
double[] _kernelHalf = GenerateWmaKernel(period / 2);
|
||||||
_kernelFull = GenerateWmaKernel(period);
|
double[] _kernelFull = GenerateWmaKernel(period);
|
||||||
_kernelFinal = GenerateWmaKernel(_sqrtPeriod);
|
double[] _kernelFinal = GenerateWmaKernel(_sqrtPeriod);
|
||||||
|
|
||||||
// Initialize convolutions with pre-generated kernels
|
// Initialize convolutions with pre-generated kernels
|
||||||
_wmaHalf = new Convolution(_kernelHalf);
|
_wmaHalf = new Convolution(_kernelHalf);
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ namespace QuanTAlib;
|
|||||||
public class Sinema : AbstractBase
|
public class Sinema : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly Convolution _convolution;
|
private readonly Convolution _convolution;
|
||||||
private readonly double[] _kernel;
|
|
||||||
|
|
||||||
/// <param name="period">The number of data points used in the SINEMA calculation.</param>
|
/// <param name="period">The number of data points used in the SINEMA calculation.</param>
|
||||||
/// <exception cref="ArgumentException">Thrown when period is less than 1.</exception>
|
/// <exception cref="ArgumentException">Thrown when period is less than 1.</exception>
|
||||||
@@ -38,7 +37,7 @@ public class Sinema : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new System.ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
throw new System.ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
||||||
}
|
}
|
||||||
_kernel = GenerateKernel(period);
|
double[] _kernel = GenerateKernel(period);
|
||||||
_convolution = new Convolution(_kernel);
|
_convolution = new Convolution(_kernel);
|
||||||
Name = "Sinema";
|
Name = "Sinema";
|
||||||
WarmupPeriod = period;
|
WarmupPeriod = period;
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ namespace QuanTAlib;
|
|||||||
public class Sma : AbstractBase
|
public class Sma : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly CircularBuffer _buffer;
|
private readonly CircularBuffer _buffer;
|
||||||
private readonly int _period;
|
|
||||||
|
|
||||||
/// <param name="period">The number of data points used in the SMA calculation.</param>
|
/// <param name="period">The number of data points used in the SMA calculation.</param>
|
||||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||||
@@ -37,7 +36,6 @@ public class Sma : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new System.ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
throw new System.ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
||||||
}
|
}
|
||||||
_period = period;
|
|
||||||
_buffer = new CircularBuffer(period);
|
_buffer = new CircularBuffer(period);
|
||||||
Name = "Sma";
|
Name = "Sma";
|
||||||
WarmupPeriod = period;
|
WarmupPeriod = period;
|
||||||
|
|||||||
+1
-3
@@ -28,7 +28,6 @@ namespace QuanTAlib;
|
|||||||
public class T3 : AbstractBase
|
public class T3 : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly int _period;
|
private readonly int _period;
|
||||||
private readonly double _vfactor;
|
|
||||||
private readonly bool _useSma;
|
private readonly bool _useSma;
|
||||||
private readonly double _k;
|
private readonly double _k;
|
||||||
private readonly double _c1, _c2, _c3, _c4;
|
private readonly double _c1, _c2, _c3, _c4;
|
||||||
@@ -48,7 +47,6 @@ public class T3 : AbstractBase
|
|||||||
throw new System.ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
throw new System.ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
||||||
}
|
}
|
||||||
_period = period;
|
_period = period;
|
||||||
_vfactor = vfactor;
|
|
||||||
_useSma = useSma;
|
_useSma = useSma;
|
||||||
WarmupPeriod = period;
|
WarmupPeriod = period;
|
||||||
|
|
||||||
@@ -69,7 +67,7 @@ public class T3 : AbstractBase
|
|||||||
_buffer5 = new(period);
|
_buffer5 = new(period);
|
||||||
_buffer6 = new(period);
|
_buffer6 = new(period);
|
||||||
|
|
||||||
Name = $"T3({_period}, {_vfactor})";
|
Name = $"T3({_period}, {vfactor})";
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-10
@@ -1,36 +1,27 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Title>QuanTAlib</Title>
|
<Title>QuanTAlib</Title>
|
||||||
<Product>Library of TA Calculations, Charts and Strategies for Quantower</Product>
|
<Product>Library of TA Calculations, Charts and Strategies for Quantower</Product>
|
||||||
<Description>Quantitative Technical Analysis Library in C# for Quantower</Description>
|
<Description>Quantitative Technical Analysis Library in C# for Quantower</Description>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<RepositoryUrl>https://github.com/mihakralj/QuanTAlib</RepositoryUrl>
|
<RepositoryUrl>https://github.com/mihakralj/QuanTAlib</RepositoryUrl>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
|
||||||
<Authors>Miha Kralj</Authors>
|
<Authors>Miha Kralj</Authors>
|
||||||
<Copyright>Miha Kralj</Copyright>
|
<Copyright>Miha Kralj</Copyright>
|
||||||
<PackageReadmeFile>readme.md</PackageReadmeFile>
|
<PackageReadmeFile>readme.md</PackageReadmeFile>
|
||||||
<RootNamespace>QuanTAlib</RootNamespace>
|
<RootNamespace>QuanTAlib</RootNamespace>
|
||||||
<AssemblyName>QuanTAlib</AssemblyName>
|
<AssemblyName>QuanTAlib</AssemblyName>
|
||||||
<AssemblyVersion>0.0.0.0</AssemblyVersion>
|
|
||||||
<IsPublishable>True</IsPublishable>
|
<IsPublishable>True</IsPublishable>
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
|
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
<PackageIcon>QuanTAlib2.png</PackageIcon>
|
<PackageIcon>QuanTAlib2.png</PackageIcon>
|
||||||
<PackageReadmeFile>readme.md</PackageReadmeFile>
|
|
||||||
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
||||||
<PackageTags>
|
<PackageTags>
|
||||||
Indicators;Stock;Market;Technical;Analysis;Algorithmic;Trading;Trade;Trend;Momentum;Finance;Algorithm;Algo;
|
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;
|
AlgoTrading;Financial;Strategy;Chart;Charting;Oscillator;Overlay;Equity;Bitcoin;Crypto;Cryptocurrency;Forex;
|
||||||
Quantitative;Historical;Quotes;
|
Quantitative;Historical;Quotes;
|
||||||
</PackageTags>
|
</PackageTags>
|
||||||
<PackageIcon>QuanTAlib2.png</PackageIcon>
|
|
||||||
<PackageIconUrl>https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png</PackageIconUrl>
|
<PackageIconUrl>https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png</PackageIconUrl>
|
||||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||||
<NoWarn>$(NoWarn);NU1903;NU5104</NoWarn>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -51,4 +42,4 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
namespace QuanTAlib;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HURST: Hurst Exponent
|
||||||
|
/// A measure of long-term memory of time series that relates to the
|
||||||
|
/// autocorrelations of the time series, and the rate at which these
|
||||||
|
/// decrease as the lag between pairs of values increases.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The Hurst Exponent calculation process:
|
||||||
|
/// 1. Calculate log returns of the series
|
||||||
|
/// 2. Create subsequences of different lengths
|
||||||
|
/// 3. For each length:
|
||||||
|
/// - Calculate range (max-min) of cumulative deviations
|
||||||
|
/// - Calculate standard deviation
|
||||||
|
/// - Calculate R/S ratio
|
||||||
|
/// 4. Fit log(R/S) vs log(length) to find H
|
||||||
|
///
|
||||||
|
/// Key characteristics:
|
||||||
|
/// - H = 0.5: Random walk (Brownian motion)
|
||||||
|
/// - 0.5 < H ≤ 1.0: Trending (persistent) series
|
||||||
|
/// - 0 ≤ H < 0.5: Mean-reverting (anti-persistent) series
|
||||||
|
/// - Default minimum length is 10
|
||||||
|
/// - Default maximum length is period/2
|
||||||
|
///
|
||||||
|
/// Formula:
|
||||||
|
/// R(n)/S(n) = c * n^H
|
||||||
|
/// where:
|
||||||
|
/// R(n) = range of cumulative deviations
|
||||||
|
/// S(n) = standard deviation
|
||||||
|
/// n = subsequence length
|
||||||
|
/// H = Hurst exponent
|
||||||
|
///
|
||||||
|
/// Market Applications:
|
||||||
|
/// - Market efficiency analysis
|
||||||
|
/// - Trend strength measurement
|
||||||
|
/// - Trading strategy development
|
||||||
|
/// - Risk assessment
|
||||||
|
/// - Market regime identification
|
||||||
|
///
|
||||||
|
/// Sources:
|
||||||
|
/// H.E. Hurst (1951)
|
||||||
|
/// "Long-term Storage Capacity of Reservoirs"
|
||||||
|
/// Transactions of the American Society of Civil Engineers, 116, 770-799
|
||||||
|
///
|
||||||
|
/// Note: Returns a value between 0 and 1
|
||||||
|
/// </remarks>
|
||||||
|
|
||||||
|
[SkipLocalsInit]
|
||||||
|
public sealed class Hurst : AbstractBase
|
||||||
|
{
|
||||||
|
private readonly int _period;
|
||||||
|
private readonly int _minLength;
|
||||||
|
private readonly CircularBuffer _prices;
|
||||||
|
private readonly CircularBuffer _logReturns;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Hurst(int period = 100, int minLength = 10)
|
||||||
|
{
|
||||||
|
if (minLength < 10)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(minLength), "Minimum length must be at least 10.");
|
||||||
|
}
|
||||||
|
if (period <= minLength * 2)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(period), "Period must be at least twice the minimum length.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_period = period;
|
||||||
|
_minLength = minLength;
|
||||||
|
WarmupPeriod = period + 1; // Need one extra period for returns
|
||||||
|
Name = $"HURST({_period})";
|
||||||
|
_prices = new CircularBuffer(period);
|
||||||
|
_logReturns = new CircularBuffer(period);
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="source">The data source object that publishes updates.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Hurst(object source, int period = 100, int minLength = 10) : this(period, minLength)
|
||||||
|
{
|
||||||
|
var pubEvent = source.GetType().GetEvent("Pub");
|
||||||
|
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
base.Init();
|
||||||
|
_prices.Clear();
|
||||||
|
_logReturns.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected override void ManageState(bool isNew)
|
||||||
|
{
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_lastValidValue = Value;
|
||||||
|
_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
private static (double range, double stdDev) CalculateRangeAndStdDev(ReadOnlySpan<double> data)
|
||||||
|
{
|
||||||
|
int n = data.Length;
|
||||||
|
if (n == 0) return (0, 0);
|
||||||
|
|
||||||
|
// Calculate mean
|
||||||
|
double mean = 0;
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
mean += data[i];
|
||||||
|
}
|
||||||
|
mean /= n;
|
||||||
|
|
||||||
|
// Calculate cumulative deviations and std dev
|
||||||
|
double max = double.MinValue;
|
||||||
|
double min = double.MaxValue;
|
||||||
|
double sumSquaredDev = 0;
|
||||||
|
double cumDev = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
double dev = data[i] - mean;
|
||||||
|
cumDev += dev;
|
||||||
|
max = Math.Max(max, cumDev);
|
||||||
|
min = Math.Min(min, cumDev);
|
||||||
|
sumSquaredDev += dev * dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
double range = max - min;
|
||||||
|
double stdDev = Math.Sqrt(sumSquaredDev / n);
|
||||||
|
|
||||||
|
return (range, stdDev);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
protected override double Calculation()
|
||||||
|
{
|
||||||
|
ManageState(BarInput.IsNew);
|
||||||
|
|
||||||
|
// Add price and calculate log return
|
||||||
|
_prices.Add(BarInput.Close);
|
||||||
|
if (_index > 1)
|
||||||
|
{
|
||||||
|
double logReturn = Math.Log(BarInput.Close / _prices[1]);
|
||||||
|
_logReturns.Add(logReturn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need enough values for calculation
|
||||||
|
if (_index <= _period)
|
||||||
|
{
|
||||||
|
return 0.5; // Return random walk value until we have enough data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate R/S values for different lengths
|
||||||
|
int maxLength = _period / 2;
|
||||||
|
int numPoints = 0;
|
||||||
|
double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
|
||||||
|
|
||||||
|
for (int length = _minLength; length <= maxLength; length *= 2)
|
||||||
|
{
|
||||||
|
var (range, stdDev) = CalculateRangeAndStdDev(_logReturns.GetSpan()[..length]);
|
||||||
|
if (stdDev > 0)
|
||||||
|
{
|
||||||
|
double rs = range / stdDev;
|
||||||
|
if (rs > 0)
|
||||||
|
{
|
||||||
|
double x = Math.Log(length);
|
||||||
|
double y = Math.Log(rs);
|
||||||
|
sumX += x;
|
||||||
|
sumY += y;
|
||||||
|
sumXY += x * y;
|
||||||
|
sumX2 += x * x;
|
||||||
|
numPoints++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate Hurst exponent using linear regression
|
||||||
|
double hurst = 0.5; // Default to random walk
|
||||||
|
if (numPoints > 1)
|
||||||
|
{
|
||||||
|
double slope = (numPoints * sumXY - sumX * sumY) / (numPoints * sumX2 - sumX * sumX);
|
||||||
|
hurst = Math.Max(0, Math.Min(1, slope)); // Clamp between 0 and 1
|
||||||
|
}
|
||||||
|
|
||||||
|
IsHot = _index >= WarmupPeriod;
|
||||||
|
return hurst;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
namespace QuanTAlib;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// BBAND: Bollinger Bands®
|
||||||
|
/// A technical analysis tool that creates a band of three lines:
|
||||||
|
/// - Middle Band: n-period simple moving average (SMA)
|
||||||
|
/// - Upper Band: Middle Band + (standard deviation * multiplier)
|
||||||
|
/// - Lower Band: Middle Band - (standard deviation * multiplier)
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The Bollinger Bands calculation process:
|
||||||
|
/// 1. Calculate the middle band (SMA of closing prices)
|
||||||
|
/// 2. Calculate the standard deviation of prices
|
||||||
|
/// 3. Upper and lower bands are the middle band +/- standard deviation * multiplier
|
||||||
|
///
|
||||||
|
/// Key characteristics:
|
||||||
|
/// - Adapts to volatility
|
||||||
|
/// - Default period is 20 days
|
||||||
|
/// - Default multiplier is 2.0
|
||||||
|
/// - Returns three bands (upper, middle, lower)
|
||||||
|
/// - Wider bands indicate higher volatility
|
||||||
|
/// - Narrower bands indicate lower volatility
|
||||||
|
///
|
||||||
|
/// Formula:
|
||||||
|
/// Middle Band = SMA(Close, period)
|
||||||
|
/// Standard Deviation = SQRT(SUM((Close - Middle Band)^2) / period)
|
||||||
|
/// Upper Band = Middle Band + (multiplier * Standard Deviation)
|
||||||
|
/// Lower Band = Middle Band - (multiplier * Standard Deviation)
|
||||||
|
///
|
||||||
|
/// Market Applications:
|
||||||
|
/// - Volatility measurement
|
||||||
|
/// - Overbought/oversold identification
|
||||||
|
/// - Price breakout detection
|
||||||
|
/// - Trend strength analysis
|
||||||
|
/// - Dynamic support/resistance levels
|
||||||
|
///
|
||||||
|
/// Sources:
|
||||||
|
/// John Bollinger (1980s)
|
||||||
|
/// https://www.bollingerbands.com
|
||||||
|
///
|
||||||
|
/// Note: Returns three values: upper, middle, and lower bands
|
||||||
|
/// </remarks>
|
||||||
|
|
||||||
|
[SkipLocalsInit]
|
||||||
|
public sealed class Bband : AbstractBase
|
||||||
|
{
|
||||||
|
private readonly int _period;
|
||||||
|
private readonly double _multiplier;
|
||||||
|
private readonly CircularBuffer _prices;
|
||||||
|
private double _middleBand;
|
||||||
|
private double _upperBand;
|
||||||
|
private double _lowerBand;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Bband(int period = 20, double multiplier = 2.0)
|
||||||
|
{
|
||||||
|
_period = period;
|
||||||
|
_multiplier = multiplier;
|
||||||
|
WarmupPeriod = period;
|
||||||
|
Name = $"BBAND({_period},{_multiplier})";
|
||||||
|
_prices = new CircularBuffer(period);
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="source">The data source object that publishes updates.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Bband(object source, int period = 20, double multiplier = 2.0) : this(period, multiplier)
|
||||||
|
{
|
||||||
|
var pubEvent = source.GetType().GetEvent("Pub");
|
||||||
|
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
base.Init();
|
||||||
|
_middleBand = 0;
|
||||||
|
_upperBand = 0;
|
||||||
|
_lowerBand = 0;
|
||||||
|
_prices.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected override void ManageState(bool isNew)
|
||||||
|
{
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_lastValidValue = Value;
|
||||||
|
_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
protected override double Calculation()
|
||||||
|
{
|
||||||
|
ManageState(BarInput.IsNew);
|
||||||
|
|
||||||
|
// Add current price to buffer
|
||||||
|
_prices.Add(BarInput.Close);
|
||||||
|
|
||||||
|
// Need enough values for calculation
|
||||||
|
if (_index <= _period)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate middle band (SMA)
|
||||||
|
_middleBand = _prices.Average();
|
||||||
|
|
||||||
|
// Calculate standard deviation
|
||||||
|
double sumSquaredDeviations = 0;
|
||||||
|
for (int i = 0; i < _period; i++)
|
||||||
|
{
|
||||||
|
double deviation = _prices[i] - _middleBand;
|
||||||
|
sumSquaredDeviations += deviation * deviation;
|
||||||
|
}
|
||||||
|
double standardDeviation = Math.Sqrt(sumSquaredDeviations / _period);
|
||||||
|
|
||||||
|
// Calculate bands
|
||||||
|
double bandWidth = _multiplier * standardDeviation;
|
||||||
|
_upperBand = _middleBand + bandWidth;
|
||||||
|
_lowerBand = _middleBand - bandWidth;
|
||||||
|
|
||||||
|
IsHot = _index >= WarmupPeriod;
|
||||||
|
return _middleBand; // Return middle band as primary value
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the upper band value
|
||||||
|
/// </summary>
|
||||||
|
public double UpperBand => _upperBand;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the middle band value (SMA)
|
||||||
|
/// </summary>
|
||||||
|
public double MiddleBand => _middleBand;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the lower band value
|
||||||
|
/// </summary>
|
||||||
|
public double LowerBand => _lowerBand;
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
namespace QuanTAlib;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CCV: Close-to-Close Volatility
|
||||||
|
/// A measure of price volatility that uses only closing prices,
|
||||||
|
/// calculated as the standard deviation of logarithmic returns.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The CCV calculation process:
|
||||||
|
/// 1. Calculate logarithmic returns: ln(Close[t]/Close[t-1])
|
||||||
|
/// 2. Calculate standard deviation of returns over the period
|
||||||
|
/// 3. Annualize by multiplying by sqrt(trading days per year)
|
||||||
|
///
|
||||||
|
/// Key characteristics:
|
||||||
|
/// - Uses only closing prices
|
||||||
|
/// - Based on logarithmic returns
|
||||||
|
/// - Default period is 20 days
|
||||||
|
/// - Annualized by default (multiply by sqrt(252))
|
||||||
|
/// - Expressed as a percentage
|
||||||
|
///
|
||||||
|
/// Formula:
|
||||||
|
/// Returns = ln(Close[t]/Close[t-1])
|
||||||
|
/// CCV = StdDev(Returns, period) * sqrt(252) * 100
|
||||||
|
///
|
||||||
|
/// Market Applications:
|
||||||
|
/// - Volatility measurement
|
||||||
|
/// - Risk assessment
|
||||||
|
/// - Option pricing
|
||||||
|
/// - Trading strategy development
|
||||||
|
/// - Portfolio management
|
||||||
|
///
|
||||||
|
/// Sources:
|
||||||
|
/// Close-to-Close Volatility concept
|
||||||
|
/// https://www.investopedia.com/terms/v/volatility.asp
|
||||||
|
///
|
||||||
|
/// Note: Returns annualized volatility as a percentage
|
||||||
|
/// </remarks>
|
||||||
|
|
||||||
|
[SkipLocalsInit]
|
||||||
|
public sealed class Ccv : AbstractBase
|
||||||
|
{
|
||||||
|
private readonly int _period;
|
||||||
|
private readonly bool _annualize;
|
||||||
|
private readonly CircularBuffer _returns;
|
||||||
|
private double _prevClose;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Ccv(int period = 20, bool annualize = true)
|
||||||
|
{
|
||||||
|
_period = period;
|
||||||
|
_annualize = annualize;
|
||||||
|
WarmupPeriod = period + 1; // Need one extra period for returns calculation
|
||||||
|
Name = $"CCV({_period})";
|
||||||
|
_returns = new CircularBuffer(period);
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="source">The data source object that publishes updates.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Ccv(object source, int period = 20, bool annualize = true) : this(period, annualize)
|
||||||
|
{
|
||||||
|
var pubEvent = source.GetType().GetEvent("Pub");
|
||||||
|
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
base.Init();
|
||||||
|
_prevClose = 0;
|
||||||
|
_returns.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected override void ManageState(bool isNew)
|
||||||
|
{
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_lastValidValue = Value;
|
||||||
|
_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
protected override double Calculation()
|
||||||
|
{
|
||||||
|
ManageState(BarInput.IsNew);
|
||||||
|
|
||||||
|
// Skip first period to establish previous close
|
||||||
|
if (_index == 1)
|
||||||
|
{
|
||||||
|
_prevClose = BarInput.Close;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate logarithmic return
|
||||||
|
double logReturn = Math.Log(BarInput.Close / _prevClose);
|
||||||
|
_returns.Add(logReturn);
|
||||||
|
_prevClose = BarInput.Close;
|
||||||
|
|
||||||
|
// Need enough values for calculation
|
||||||
|
if (_index <= _period)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate standard deviation
|
||||||
|
double mean = _returns.Average();
|
||||||
|
double sumSquaredDeviations = 0;
|
||||||
|
for (int i = 0; i < _period; i++)
|
||||||
|
{
|
||||||
|
double deviation = _returns[i] - mean;
|
||||||
|
sumSquaredDeviations += deviation * deviation;
|
||||||
|
}
|
||||||
|
double stdDev = Math.Sqrt(sumSquaredDeviations / _period);
|
||||||
|
|
||||||
|
// Annualize if requested (sqrt(252) for trading days in a year)
|
||||||
|
if (_annualize)
|
||||||
|
{
|
||||||
|
stdDev *= Math.Sqrt(252);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to percentage
|
||||||
|
double volatility = stdDev * 100;
|
||||||
|
|
||||||
|
IsHot = _index >= WarmupPeriod;
|
||||||
|
return volatility;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
namespace QuanTAlib;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CE: Chandelier Exit
|
||||||
|
/// A volatility-based stop-loss indicator that adapts to market conditions,
|
||||||
|
/// using ATR to set stop levels above/below recent price extremes.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The CE calculation process:
|
||||||
|
/// 1. Calculate highest high and lowest low over the period
|
||||||
|
/// 2. Calculate ATR over the period
|
||||||
|
/// 3. Long Exit = Highest High - (ATR * multiplier)
|
||||||
|
/// 4. Short Exit = Lowest Low + (ATR * multiplier)
|
||||||
|
///
|
||||||
|
/// Key characteristics:
|
||||||
|
/// - Adapts to market volatility
|
||||||
|
/// - Default period is 22 days
|
||||||
|
/// - Default multiplier is 3.0
|
||||||
|
/// - Returns both long and short exit levels
|
||||||
|
/// - Based on ATR and price extremes
|
||||||
|
///
|
||||||
|
/// Formula:
|
||||||
|
/// ATR = Average(TR, period)
|
||||||
|
/// Long Exit = Highest High[period] - (multiplier * ATR)
|
||||||
|
/// Short Exit = Lowest Low[period] + (multiplier * ATR)
|
||||||
|
///
|
||||||
|
/// Market Applications:
|
||||||
|
/// - Stop loss placement
|
||||||
|
/// - Position management
|
||||||
|
/// - Trend following
|
||||||
|
/// - Risk control
|
||||||
|
/// - Exit strategy
|
||||||
|
///
|
||||||
|
/// Sources:
|
||||||
|
/// Chuck LeBeau
|
||||||
|
/// https://www.investopedia.com/terms/c/chandelier-exit.asp
|
||||||
|
///
|
||||||
|
/// Note: Returns two values: long exit and short exit levels
|
||||||
|
/// </remarks>
|
||||||
|
|
||||||
|
[SkipLocalsInit]
|
||||||
|
public sealed class Ce : AbstractBase
|
||||||
|
{
|
||||||
|
private readonly int _period;
|
||||||
|
private readonly double _multiplier;
|
||||||
|
private readonly CircularBuffer _tr;
|
||||||
|
private readonly CircularBuffer _highs;
|
||||||
|
private readonly CircularBuffer _lows;
|
||||||
|
private double _prevClose;
|
||||||
|
private double _longExit;
|
||||||
|
private double _shortExit;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Ce(int period = 22, double multiplier = 3.0)
|
||||||
|
{
|
||||||
|
_period = period;
|
||||||
|
_multiplier = multiplier;
|
||||||
|
WarmupPeriod = period + 1; // Need one extra period for TR
|
||||||
|
Name = $"CE({_period},{_multiplier})";
|
||||||
|
_tr = new CircularBuffer(period);
|
||||||
|
_highs = new CircularBuffer(period);
|
||||||
|
_lows = new CircularBuffer(period);
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="source">The data source object that publishes updates.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Ce(object source, int period = 22, double multiplier = 3.0) : this(period, multiplier)
|
||||||
|
{
|
||||||
|
var pubEvent = source.GetType().GetEvent("Pub");
|
||||||
|
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
base.Init();
|
||||||
|
_prevClose = 0;
|
||||||
|
_longExit = 0;
|
||||||
|
_shortExit = 0;
|
||||||
|
_tr.Clear();
|
||||||
|
_highs.Clear();
|
||||||
|
_lows.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected override void ManageState(bool isNew)
|
||||||
|
{
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_lastValidValue = Value;
|
||||||
|
_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
protected override double Calculation()
|
||||||
|
{
|
||||||
|
ManageState(BarInput.IsNew);
|
||||||
|
|
||||||
|
// Skip first period to establish previous close
|
||||||
|
if (_index == 1)
|
||||||
|
{
|
||||||
|
_prevClose = BarInput.Close;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate True Range
|
||||||
|
double tr = Math.Max(BarInput.High - BarInput.Low,
|
||||||
|
Math.Max(Math.Abs(BarInput.High - _prevClose),
|
||||||
|
Math.Abs(BarInput.Low - _prevClose)));
|
||||||
|
|
||||||
|
// Add values to buffers
|
||||||
|
_tr.Add(tr);
|
||||||
|
_highs.Add(BarInput.High);
|
||||||
|
_lows.Add(BarInput.Low);
|
||||||
|
|
||||||
|
// Store current close for next calculation
|
||||||
|
_prevClose = BarInput.Close;
|
||||||
|
|
||||||
|
// Need enough values for calculation
|
||||||
|
if (_index <= _period)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate ATR
|
||||||
|
double atr = _tr.Average();
|
||||||
|
|
||||||
|
// Find highest high and lowest low
|
||||||
|
double highestHigh = double.MinValue;
|
||||||
|
double lowestLow = double.MaxValue;
|
||||||
|
for (int i = 0; i < _period; i++)
|
||||||
|
{
|
||||||
|
highestHigh = Math.Max(highestHigh, _highs[i]);
|
||||||
|
lowestLow = Math.Min(lowestLow, _lows[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate exit levels
|
||||||
|
_longExit = highestHigh - (_multiplier * atr);
|
||||||
|
_shortExit = lowestLow + (_multiplier * atr);
|
||||||
|
|
||||||
|
IsHot = _index >= WarmupPeriod;
|
||||||
|
return _longExit; // Return long exit as primary value
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the long exit level
|
||||||
|
/// </summary>
|
||||||
|
public double LongExit => _longExit;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the short exit level
|
||||||
|
/// </summary>
|
||||||
|
public double ShortExit => _shortExit;
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
namespace QuanTAlib;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CV: Conditional Volatility (GARCH)
|
||||||
|
/// Implements the GARCH(1,1) model for estimating conditional volatility,
|
||||||
|
/// which captures volatility clustering and mean reversion in financial markets.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The CV (GARCH) calculation process:
|
||||||
|
/// 1. Calculate returns: (Close[t] - Close[t-1])/Close[t-1]
|
||||||
|
/// 2. Update variance estimate using GARCH(1,1) formula:
|
||||||
|
/// σ²[t] = ω + α*r²[t-1] + β*σ²[t-1]
|
||||||
|
/// 3. Take square root to get volatility
|
||||||
|
///
|
||||||
|
/// Key characteristics:
|
||||||
|
/// - Captures volatility clustering
|
||||||
|
/// - Mean-reverting behavior
|
||||||
|
/// - Responds to market shocks
|
||||||
|
/// - Default period is 20 days
|
||||||
|
/// - Returns annualized volatility
|
||||||
|
///
|
||||||
|
/// Formula:
|
||||||
|
/// Returns[t] = (Close[t] - Close[t-1])/Close[t-1]
|
||||||
|
/// σ²[t] = ω + α*Returns²[t-1] + β*σ²[t-1]
|
||||||
|
/// CV[t] = sqrt(σ²[t]) * sqrt(252) * 100
|
||||||
|
///
|
||||||
|
/// Where:
|
||||||
|
/// ω (omega) = long-term variance * (1 - α - β)
|
||||||
|
/// α (alpha) = weight of recent squared return
|
||||||
|
/// β (beta) = weight of previous variance
|
||||||
|
///
|
||||||
|
/// Market Applications:
|
||||||
|
/// - Risk measurement
|
||||||
|
/// - Option pricing
|
||||||
|
/// - Value at Risk (VaR)
|
||||||
|
/// - Portfolio optimization
|
||||||
|
/// - Volatility forecasting
|
||||||
|
///
|
||||||
|
/// Sources:
|
||||||
|
/// Bollerslev (1986)
|
||||||
|
/// https://en.wikipedia.org/wiki/GARCH
|
||||||
|
///
|
||||||
|
/// Note: Returns annualized volatility as a percentage
|
||||||
|
/// </remarks>
|
||||||
|
|
||||||
|
[SkipLocalsInit]
|
||||||
|
public sealed class Cv : AbstractBase
|
||||||
|
{
|
||||||
|
private readonly int _period;
|
||||||
|
private readonly double _alpha;
|
||||||
|
private readonly double _beta;
|
||||||
|
private readonly double _omega;
|
||||||
|
private double _prevClose;
|
||||||
|
private double _prevVariance;
|
||||||
|
private bool _isInitialized;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Cv(int period = 20, double alpha = 0.1, double beta = 0.8)
|
||||||
|
{
|
||||||
|
_period = period;
|
||||||
|
_alpha = alpha;
|
||||||
|
_beta = beta;
|
||||||
|
_omega = 0.001 * (1 - alpha - beta); // Initial estimate, will be updated with actual data
|
||||||
|
WarmupPeriod = period + 1; // Need one extra period for returns
|
||||||
|
Name = $"CV({_period})";
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="source">The data source object that publishes updates.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Cv(object source, int period = 20, double alpha = 0.1, double beta = 0.8) : this(period, alpha, beta)
|
||||||
|
{
|
||||||
|
var pubEvent = source.GetType().GetEvent("Pub");
|
||||||
|
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
base.Init();
|
||||||
|
_prevClose = 0;
|
||||||
|
_prevVariance = 0;
|
||||||
|
_isInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected override void ManageState(bool isNew)
|
||||||
|
{
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_lastValidValue = Value;
|
||||||
|
_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
protected override double Calculation()
|
||||||
|
{
|
||||||
|
ManageState(BarInput.IsNew);
|
||||||
|
|
||||||
|
// Skip first period to establish previous close
|
||||||
|
if (_index == 1)
|
||||||
|
{
|
||||||
|
_prevClose = BarInput.Close;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate return
|
||||||
|
double return_ = (BarInput.Close - _prevClose) / _prevClose;
|
||||||
|
double squaredReturn = return_ * return_;
|
||||||
|
_prevClose = BarInput.Close;
|
||||||
|
|
||||||
|
// Initialize with first available data if not done
|
||||||
|
if (!_isInitialized && _index > _period)
|
||||||
|
{
|
||||||
|
double _longTermVariance = squaredReturn; // Use current squared return as initial estimate
|
||||||
|
_prevVariance = _longTermVariance;
|
||||||
|
_isInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need enough values for calculation
|
||||||
|
if (_index <= _period)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update variance estimate using GARCH(1,1)
|
||||||
|
double variance = _omega + _alpha * squaredReturn + _beta * _prevVariance;
|
||||||
|
_prevVariance = variance;
|
||||||
|
|
||||||
|
// Calculate annualized volatility as percentage
|
||||||
|
double volatility = Math.Sqrt(variance) * Math.Sqrt(252) * 100;
|
||||||
|
|
||||||
|
IsHot = _index >= WarmupPeriod;
|
||||||
|
return volatility;
|
||||||
|
}
|
||||||
|
}
|
||||||
+57
-47
@@ -2,65 +2,63 @@ using System.Runtime.CompilerServices;
|
|||||||
namespace QuanTAlib;
|
namespace QuanTAlib;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// CVI: Chaikin's Volatility
|
/// CVI: Chaikin's Volatility Index
|
||||||
/// A technical indicator developed by Marc Chaikin that measures the volatility of a financial instrument by comparing the spread between the high and low prices.
|
/// Measures the rate of change of a moving average of the difference
|
||||||
|
/// between high and low prices, indicating volatility expansion/contraction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// The CVI calculation process:
|
/// The CVI calculation process:
|
||||||
/// 1. Calculates the difference between the high and low prices.
|
/// 1. Calculate High-Low difference
|
||||||
/// 2. Applies an exponential moving average (EMA) to the differences.
|
/// 2. Take EMA of High-Low difference
|
||||||
/// 3. Computes the percentage change in the EMA over a specified period.
|
/// 3. Calculate ROC of the EMA over specified period
|
||||||
///
|
///
|
||||||
/// Key characteristics:
|
/// Key characteristics:
|
||||||
/// - Measures volatility
|
/// - Measures volatility expansion/contraction
|
||||||
/// - Uses high and low prices
|
/// - Default period is 10 days
|
||||||
/// - Percentage-based
|
/// - Default smoothing period is 10 days
|
||||||
/// - EMA smoothing
|
/// - Positive values indicate expanding volatility
|
||||||
|
/// - Negative values indicate contracting volatility
|
||||||
///
|
///
|
||||||
/// Formula:
|
/// Formula:
|
||||||
/// CVI = (EMA(high - low, period) - EMA(high - low, period, offset)) / EMA(high - low, period, offset) * 100
|
/// HL = High - Low
|
||||||
|
/// Smoothed = EMA(HL, smoothPeriod)
|
||||||
|
/// CVI = ((Smoothed - Smoothed[period]) / Smoothed[period]) * 100
|
||||||
///
|
///
|
||||||
/// Market Applications:
|
/// Market Applications:
|
||||||
/// - Volatility assessment
|
/// - Volatility measurement
|
||||||
/// - Trend confirmation
|
/// - Trend strength analysis
|
||||||
/// - Risk management
|
/// - Market regime identification
|
||||||
/// - Entry/exit timing
|
/// - Trading range analysis
|
||||||
|
/// - Breakout confirmation
|
||||||
///
|
///
|
||||||
/// Sources:
|
/// Sources:
|
||||||
/// Marc Chaikin - Original development
|
/// Marc Chaikin
|
||||||
/// https://www.investopedia.com/terms/c/chaikins-volatility.asp
|
/// https://www.investopedia.com/terms/c/chaikinvolatility.asp
|
||||||
///
|
///
|
||||||
/// Note: Higher CVI values indicate higher volatility
|
/// Note: Returns percentage change in volatility
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[SkipLocalsInit]
|
[SkipLocalsInit]
|
||||||
public sealed class Cvi : AbstractBase
|
public sealed class Cvi : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly int _period;
|
private readonly int _period;
|
||||||
private readonly Ema _ema;
|
private readonly CircularBuffer _smoothed;
|
||||||
private readonly CircularBuffer _buffer;
|
private readonly double _alpha;
|
||||||
private double _prevEma;
|
private double _ema;
|
||||||
|
|
||||||
/// <param name="period">The number of periods for CVI calculation.</param>
|
|
||||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Cvi(int period)
|
public Cvi(int period = 10, int smoothPeriod = 10)
|
||||||
{
|
{
|
||||||
if (period < 1)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(period),
|
|
||||||
"Period must be greater than or equal to 1.");
|
|
||||||
}
|
|
||||||
_period = period;
|
_period = period;
|
||||||
_ema = new Ema(period);
|
_alpha = 2.0 / (smoothPeriod + 1);
|
||||||
_buffer = new CircularBuffer(period);
|
WarmupPeriod = _period + smoothPeriod;
|
||||||
WarmupPeriod = period;
|
Name = $"CVI({_period},{smoothPeriod})";
|
||||||
Name = $"CVI({period})";
|
_smoothed = new CircularBuffer(_period);
|
||||||
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <param name="source">The data source object that publishes updates.</param>
|
/// <param name="source">The data source object that publishes updates.</param>
|
||||||
/// <param name="period">The number of periods for CVI calculation.</param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Cvi(object source, int period) : this(period)
|
public Cvi(object source, int period = 10, int smoothPeriod = 10) : this(period, smoothPeriod)
|
||||||
{
|
{
|
||||||
var pubEvent = source.GetType().GetEvent("Pub");
|
var pubEvent = source.GetType().GetEvent("Pub");
|
||||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||||
@@ -70,9 +68,8 @@ public sealed class Cvi : AbstractBase
|
|||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
base.Init();
|
base.Init();
|
||||||
_ema.Init();
|
_ema = 0;
|
||||||
_buffer.Clear();
|
_smoothed.Clear();
|
||||||
_prevEma = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -80,6 +77,7 @@ public sealed class Cvi : AbstractBase
|
|||||||
{
|
{
|
||||||
if (isNew)
|
if (isNew)
|
||||||
{
|
{
|
||||||
|
_lastValidValue = Value;
|
||||||
_index++;
|
_index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,20 +87,32 @@ public sealed class Cvi : AbstractBase
|
|||||||
{
|
{
|
||||||
ManageState(BarInput.IsNew);
|
ManageState(BarInput.IsNew);
|
||||||
|
|
||||||
double highLowDiff = BarInput.High - BarInput.Low;
|
// Calculate High-Low difference
|
||||||
_buffer.Add(highLowDiff, BarInput.IsNew);
|
double hl = BarInput.High - BarInput.Low;
|
||||||
|
|
||||||
double ema = _ema.Calc(new TValue(Input.Time, highLowDiff, BarInput.IsNew)).Value;
|
// Calculate EMA of High-Low difference
|
||||||
|
if (_index == 1)
|
||||||
double cvi = 0;
|
|
||||||
if (_index >= _period)
|
|
||||||
{
|
{
|
||||||
double prevEma = _buffer[_buffer.Count - _period];
|
_ema = hl;
|
||||||
cvi = (ema - prevEma) / prevEma * 100;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_ema = (_alpha * hl) + ((1 - _alpha) * _ema);
|
||||||
}
|
}
|
||||||
|
|
||||||
_prevEma = ema;
|
// Add smoothed value to buffer
|
||||||
|
_smoothed.Add(_ema);
|
||||||
|
|
||||||
|
// Need enough values for calculation
|
||||||
|
if (_index <= _period)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate rate of change
|
||||||
|
double roc = ((_ema - _smoothed[_period - 1]) / _smoothed[_period - 1]) * 100;
|
||||||
|
|
||||||
IsHot = _index >= WarmupPeriod;
|
IsHot = _index >= WarmupPeriod;
|
||||||
return cvi;
|
return roc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
namespace QuanTAlib;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// EWMA: Exponential Weighted Moving Average Volatility
|
||||||
|
/// A volatility measure that gives more weight to recent observations,
|
||||||
|
/// calculated using squared returns and exponential weighting.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The EWMA calculation process:
|
||||||
|
/// 1. Calculate returns: (Close[t] - Close[t-1])/Close[t-1]
|
||||||
|
/// 2. Square returns
|
||||||
|
/// 3. Apply exponential weighting to squared returns
|
||||||
|
/// 4. Take square root and annualize
|
||||||
|
///
|
||||||
|
/// Key characteristics:
|
||||||
|
/// - More responsive to recent volatility changes
|
||||||
|
/// - Default decay factor (lambda) is 0.94
|
||||||
|
/// - Default period is 20 days
|
||||||
|
/// - Annualized by default (multiply by sqrt(252))
|
||||||
|
/// - Expressed as a percentage
|
||||||
|
///
|
||||||
|
/// Formula:
|
||||||
|
/// Returns[t] = (Close[t] - Close[t-1])/Close[t-1]
|
||||||
|
/// EWMA[t] = λ * EWMA[t-1] + (1-λ) * Returns[t]²
|
||||||
|
/// Volatility = sqrt(EWMA) * sqrt(252) * 100
|
||||||
|
///
|
||||||
|
/// Where:
|
||||||
|
/// λ (lambda) = decay factor (typically 0.94)
|
||||||
|
///
|
||||||
|
/// Market Applications:
|
||||||
|
/// - Risk measurement
|
||||||
|
/// - Option pricing
|
||||||
|
/// - Value at Risk (VaR)
|
||||||
|
/// - Portfolio optimization
|
||||||
|
/// - Volatility forecasting
|
||||||
|
///
|
||||||
|
/// Sources:
|
||||||
|
/// RiskMetrics™ Technical Document (1996)
|
||||||
|
/// https://www.msci.com/documents/10199/5915b101-4206-4ba0-aee2-3449d5c7e95a
|
||||||
|
///
|
||||||
|
/// Note: Returns annualized volatility as a percentage
|
||||||
|
/// </remarks>
|
||||||
|
|
||||||
|
[SkipLocalsInit]
|
||||||
|
public sealed class Ewma : AbstractBase
|
||||||
|
{
|
||||||
|
private readonly int _period;
|
||||||
|
private readonly double _lambda;
|
||||||
|
private readonly bool _annualize;
|
||||||
|
private double _prevClose;
|
||||||
|
private double _ewma;
|
||||||
|
private bool _isInitialized;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Ewma(int period = 20, double lambda = 0.94, bool annualize = true)
|
||||||
|
{
|
||||||
|
_period = period;
|
||||||
|
_lambda = lambda;
|
||||||
|
_annualize = annualize;
|
||||||
|
WarmupPeriod = period + 1; // Need one extra period for returns
|
||||||
|
Name = $"EWMA({_period},{_lambda})";
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="source">The data source object that publishes updates.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Ewma(object source, int period = 20, double lambda = 0.94, bool annualize = true) : this(period, lambda, annualize)
|
||||||
|
{
|
||||||
|
var pubEvent = source.GetType().GetEvent("Pub");
|
||||||
|
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
base.Init();
|
||||||
|
_prevClose = 0;
|
||||||
|
_ewma = 0;
|
||||||
|
_isInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected override void ManageState(bool isNew)
|
||||||
|
{
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_lastValidValue = Value;
|
||||||
|
_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
protected override double Calculation()
|
||||||
|
{
|
||||||
|
ManageState(BarInput.IsNew);
|
||||||
|
|
||||||
|
// Skip first period to establish previous close
|
||||||
|
if (_index == 1)
|
||||||
|
{
|
||||||
|
_prevClose = BarInput.Close;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate return
|
||||||
|
double return_ = (BarInput.Close - _prevClose) / _prevClose;
|
||||||
|
double squaredReturn = return_ * return_;
|
||||||
|
_prevClose = BarInput.Close;
|
||||||
|
|
||||||
|
// Initialize EWMA if not done
|
||||||
|
if (!_isInitialized && _index > _period)
|
||||||
|
{
|
||||||
|
_ewma = squaredReturn;
|
||||||
|
_isInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need enough values for calculation
|
||||||
|
if (_index <= _period)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update EWMA
|
||||||
|
_ewma = _lambda * _ewma + (1 - _lambda) * squaredReturn;
|
||||||
|
|
||||||
|
// Calculate volatility
|
||||||
|
double volatility = Math.Sqrt(_ewma);
|
||||||
|
|
||||||
|
// Annualize if requested
|
||||||
|
if (_annualize)
|
||||||
|
{
|
||||||
|
volatility *= Math.Sqrt(252);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to percentage
|
||||||
|
volatility *= 100;
|
||||||
|
|
||||||
|
IsHot = _index >= WarmupPeriod;
|
||||||
|
return volatility;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
namespace QuanTAlib;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// FCB: Fractal Chaos Bands
|
||||||
|
/// Adaptive price bands based on fractal geometry concepts,
|
||||||
|
/// identifying potential support and resistance levels.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The FCB calculation process:
|
||||||
|
/// 1. Identify fractal highs and lows over the period
|
||||||
|
/// 2. Calculate high and low bands using fractal points
|
||||||
|
/// 3. Smooth bands using exponential moving average
|
||||||
|
///
|
||||||
|
/// Key characteristics:
|
||||||
|
/// - Adapts to market structure
|
||||||
|
/// - Default period is 20 days
|
||||||
|
/// - Default smoothing factor is 0.5
|
||||||
|
/// - Returns upper and lower bands
|
||||||
|
/// - Based on fractal geometry concepts
|
||||||
|
///
|
||||||
|
/// Formula:
|
||||||
|
/// Fractal High = High[t] where High[t] > High[t±1,2]
|
||||||
|
/// Fractal Low = Low[t] where Low[t] < Low[t±1,2]
|
||||||
|
/// Upper Band = EMA(Fractal Highs, smoothing)
|
||||||
|
/// Lower Band = EMA(Fractal Lows, smoothing)
|
||||||
|
///
|
||||||
|
/// Market Applications:
|
||||||
|
/// - Support/resistance identification
|
||||||
|
/// - Trend analysis
|
||||||
|
/// - Volatility measurement
|
||||||
|
/// - Breakout detection
|
||||||
|
/// - Trading range analysis
|
||||||
|
///
|
||||||
|
/// Sources:
|
||||||
|
/// Bill Williams' Chaos Theory
|
||||||
|
/// Trading Chaos (2nd Edition) by Bill Williams
|
||||||
|
///
|
||||||
|
/// Note: Returns three values: upper, middle, and lower bands
|
||||||
|
/// </remarks>
|
||||||
|
|
||||||
|
[SkipLocalsInit]
|
||||||
|
public sealed class Fcb : AbstractBase
|
||||||
|
{
|
||||||
|
private readonly double _smoothing;
|
||||||
|
private readonly CircularBuffer _highs;
|
||||||
|
private readonly CircularBuffer _lows;
|
||||||
|
private double _upperBand;
|
||||||
|
private double _middleBand;
|
||||||
|
private double _lowerBand;
|
||||||
|
private double _upperEma;
|
||||||
|
private double _lowerEma;
|
||||||
|
private readonly double _alpha;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Fcb(int period = 20, double smoothing = 0.5)
|
||||||
|
{
|
||||||
|
_smoothing = smoothing;
|
||||||
|
_alpha = 2.0 / (period + 1);
|
||||||
|
WarmupPeriod = period + 4; // Need extra periods for fractal identification
|
||||||
|
Name = $"FCB({period},{_smoothing})";
|
||||||
|
_highs = new CircularBuffer(period);
|
||||||
|
_lows = new CircularBuffer(period);
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="source">The data source object that publishes updates.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Fcb(object source, int period = 20, double smoothing = 0.5) : this(period, smoothing)
|
||||||
|
{
|
||||||
|
var pubEvent = source.GetType().GetEvent("Pub");
|
||||||
|
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
base.Init();
|
||||||
|
_upperBand = 0;
|
||||||
|
_middleBand = 0;
|
||||||
|
_lowerBand = 0;
|
||||||
|
_upperEma = 0;
|
||||||
|
_lowerEma = 0;
|
||||||
|
_highs.Clear();
|
||||||
|
_lows.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected override void ManageState(bool isNew)
|
||||||
|
{
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_lastValidValue = Value;
|
||||||
|
_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
protected override double Calculation()
|
||||||
|
{
|
||||||
|
ManageState(BarInput.IsNew);
|
||||||
|
|
||||||
|
// Add current high/low to buffers
|
||||||
|
_highs.Add(BarInput.High);
|
||||||
|
_lows.Add(BarInput.Low);
|
||||||
|
|
||||||
|
// Need enough values for calculation
|
||||||
|
if (_index <= 4)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for fractal patterns
|
||||||
|
bool isFractalHigh = false;
|
||||||
|
bool isFractalLow = false;
|
||||||
|
|
||||||
|
// Fractal high: current high is higher than 2 bars before and after
|
||||||
|
isFractalHigh = _highs[2] > _highs[0] && _highs[2] > _highs[1] &&
|
||||||
|
_highs[2] > _highs[3] && _highs[2] > _highs[4];
|
||||||
|
|
||||||
|
// Fractal low: current low is lower than 2 bars before and after
|
||||||
|
isFractalLow = _lows[2] < _lows[0] && _lows[2] < _lows[1] &&
|
||||||
|
_lows[2] < _lows[3] && _lows[2] < _lows[4];
|
||||||
|
|
||||||
|
|
||||||
|
// Update EMAs with fractal points
|
||||||
|
if (isFractalHigh)
|
||||||
|
{
|
||||||
|
_upperEma = (_alpha * _highs[2]) + ((1 - _alpha) * _upperEma);
|
||||||
|
}
|
||||||
|
if (isFractalLow)
|
||||||
|
{
|
||||||
|
_lowerEma = (_alpha * _lows[2]) + ((1 - _alpha) * _lowerEma);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply smoothing to bands
|
||||||
|
_upperBand = _smoothing * _upperEma + (1 - _smoothing) * BarInput.High;
|
||||||
|
_lowerBand = _smoothing * _lowerEma + (1 - _smoothing) * BarInput.Low;
|
||||||
|
_middleBand = (_upperBand + _lowerBand) / 2;
|
||||||
|
|
||||||
|
IsHot = _index >= WarmupPeriod;
|
||||||
|
return _middleBand; // Return middle band as primary value
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the upper band value
|
||||||
|
/// </summary>
|
||||||
|
public double UpperBand => _upperBand;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the middle band value
|
||||||
|
/// </summary>
|
||||||
|
public double MiddleBand => _middleBand;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the lower band value
|
||||||
|
/// </summary>
|
||||||
|
public double LowerBand => _lowerBand;
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
namespace QuanTAlib;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GKV: Garman-Klass Volatility
|
||||||
|
/// An efficient estimator of volatility that uses open, high, low,
|
||||||
|
/// and close prices to capture intraday price movements.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The GKV calculation process:
|
||||||
|
/// 1. Calculate components using OHLC prices
|
||||||
|
/// 2. Combine components using optimal weights
|
||||||
|
/// 3. Take rolling average over period
|
||||||
|
/// 4. Annualize and convert to percentage
|
||||||
|
///
|
||||||
|
/// Key characteristics:
|
||||||
|
/// - More efficient than close-to-close volatility
|
||||||
|
/// - Uses full OHLC price information
|
||||||
|
/// - Default period is 20 days
|
||||||
|
/// - Annualized by default
|
||||||
|
/// - Expressed as a percentage
|
||||||
|
///
|
||||||
|
/// Formula:
|
||||||
|
/// u = ln(High/Low)²/2
|
||||||
|
/// c = ln(Close/Open)²
|
||||||
|
/// GKV = sqrt(sum((0.5*u - (2*ln(2)-1)*c) / period) * 252) * 100
|
||||||
|
///
|
||||||
|
/// Market Applications:
|
||||||
|
/// - Volatility estimation
|
||||||
|
/// - Risk measurement
|
||||||
|
/// - Option pricing
|
||||||
|
/// - Trading strategy development
|
||||||
|
/// - Market analysis
|
||||||
|
///
|
||||||
|
/// Sources:
|
||||||
|
/// Garman and Klass (1980)
|
||||||
|
/// Journal of Business 53(1): 67-78
|
||||||
|
///
|
||||||
|
/// Note: Returns annualized volatility as a percentage
|
||||||
|
/// </remarks>
|
||||||
|
|
||||||
|
[SkipLocalsInit]
|
||||||
|
public sealed class Gkv : AbstractBase
|
||||||
|
{
|
||||||
|
private readonly int _period;
|
||||||
|
private readonly bool _annualize;
|
||||||
|
private readonly CircularBuffer _components;
|
||||||
|
private readonly double _ln2;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Gkv(int period = 20, bool annualize = true)
|
||||||
|
{
|
||||||
|
_period = period;
|
||||||
|
_annualize = annualize;
|
||||||
|
WarmupPeriod = period;
|
||||||
|
Name = $"GKV({_period})";
|
||||||
|
_components = new CircularBuffer(period);
|
||||||
|
_ln2 = Math.Log(2);
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="source">The data source object that publishes updates.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Gkv(object source, int period = 20, bool annualize = true) : this(period, annualize)
|
||||||
|
{
|
||||||
|
var pubEvent = source.GetType().GetEvent("Pub");
|
||||||
|
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
base.Init();
|
||||||
|
_components.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected override void ManageState(bool isNew)
|
||||||
|
{
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_lastValidValue = Value;
|
||||||
|
_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
protected override double Calculation()
|
||||||
|
{
|
||||||
|
ManageState(BarInput.IsNew);
|
||||||
|
|
||||||
|
// Calculate components
|
||||||
|
double u = Math.Log(BarInput.High / BarInput.Low);
|
||||||
|
u = u * u / 2;
|
||||||
|
|
||||||
|
double c = Math.Log(BarInput.Close / BarInput.Open);
|
||||||
|
c = c * c;
|
||||||
|
|
||||||
|
// Combine components with optimal weights
|
||||||
|
double component = 0.5 * u - (2 * _ln2 - 1) * c;
|
||||||
|
_components.Add(component);
|
||||||
|
|
||||||
|
// Need enough values for calculation
|
||||||
|
if (_index <= _period)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate average component
|
||||||
|
double avgComponent = _components.Average();
|
||||||
|
|
||||||
|
// Calculate volatility
|
||||||
|
double volatility = Math.Sqrt(avgComponent);
|
||||||
|
|
||||||
|
// Annualize if requested
|
||||||
|
if (_annualize)
|
||||||
|
{
|
||||||
|
volatility *= Math.Sqrt(252);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to percentage
|
||||||
|
volatility *= 100;
|
||||||
|
|
||||||
|
IsHot = _index >= WarmupPeriod;
|
||||||
|
return volatility;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
namespace QuanTAlib;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HLV: High-Low Volatility
|
||||||
|
/// A volatility measure based on the high-low range relative
|
||||||
|
/// to the previous close, capturing intraday price movements.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The HLV calculation process:
|
||||||
|
/// 1. Calculate normalized high-low range
|
||||||
|
/// 2. Take rolling average over period
|
||||||
|
/// 3. Convert to annualized volatility
|
||||||
|
///
|
||||||
|
/// Key characteristics:
|
||||||
|
/// - Captures intraday price movements
|
||||||
|
/// - Uses high, low, and previous close
|
||||||
|
/// - Default period is 20 days
|
||||||
|
/// - Annualized by default
|
||||||
|
/// - Expressed as a percentage
|
||||||
|
///
|
||||||
|
/// Formula:
|
||||||
|
/// Range = (High - Low) / PrevClose
|
||||||
|
/// HLV = sqrt(sum(Range² / period) * 252) * 100
|
||||||
|
///
|
||||||
|
/// Market Applications:
|
||||||
|
/// - Volatility measurement
|
||||||
|
/// - Risk assessment
|
||||||
|
/// - Trading range analysis
|
||||||
|
/// - Market regime identification
|
||||||
|
/// - Position sizing
|
||||||
|
///
|
||||||
|
/// Sources:
|
||||||
|
/// Parkinson (1980) modified
|
||||||
|
/// The Extreme Value Method for Estimating the Variance of the Rate of Return
|
||||||
|
/// Journal of Business 53(1): 61-65
|
||||||
|
///
|
||||||
|
/// Note: Returns annualized volatility as a percentage
|
||||||
|
/// </remarks>
|
||||||
|
|
||||||
|
[SkipLocalsInit]
|
||||||
|
public sealed class Hlv : AbstractBase
|
||||||
|
{
|
||||||
|
private readonly int _period;
|
||||||
|
private readonly bool _annualize;
|
||||||
|
private readonly CircularBuffer _ranges;
|
||||||
|
private double _prevClose;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Hlv(int period = 20, bool annualize = true)
|
||||||
|
{
|
||||||
|
_period = period;
|
||||||
|
_annualize = annualize;
|
||||||
|
WarmupPeriod = period + 1; // Need one extra period for previous close
|
||||||
|
Name = $"HLV({_period})";
|
||||||
|
_ranges = new CircularBuffer(period);
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="source">The data source object that publishes updates.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Hlv(object source, int period = 20, bool annualize = true) : this(period, annualize)
|
||||||
|
{
|
||||||
|
var pubEvent = source.GetType().GetEvent("Pub");
|
||||||
|
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
base.Init();
|
||||||
|
_prevClose = 0;
|
||||||
|
_ranges.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected override void ManageState(bool isNew)
|
||||||
|
{
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_lastValidValue = Value;
|
||||||
|
_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
protected override double Calculation()
|
||||||
|
{
|
||||||
|
ManageState(BarInput.IsNew);
|
||||||
|
|
||||||
|
// Skip first period to establish previous close
|
||||||
|
if (_index == 1)
|
||||||
|
{
|
||||||
|
_prevClose = BarInput.Close;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate normalized range
|
||||||
|
double range = (BarInput.High - BarInput.Low) / _prevClose;
|
||||||
|
double squaredRange = range * range;
|
||||||
|
_ranges.Add(squaredRange);
|
||||||
|
|
||||||
|
// Store current close for next calculation
|
||||||
|
_prevClose = BarInput.Close;
|
||||||
|
|
||||||
|
// Need enough values for calculation
|
||||||
|
if (_index <= _period)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate average squared range
|
||||||
|
double avgSquaredRange = _ranges.Average();
|
||||||
|
|
||||||
|
// Calculate volatility
|
||||||
|
double volatility = Math.Sqrt(avgSquaredRange);
|
||||||
|
|
||||||
|
// Annualize if requested
|
||||||
|
if (_annualize)
|
||||||
|
{
|
||||||
|
volatility *= Math.Sqrt(252);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to percentage
|
||||||
|
volatility *= 100;
|
||||||
|
|
||||||
|
IsHot = _index >= WarmupPeriod;
|
||||||
|
return volatility;
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-10
@@ -1,21 +1,21 @@
|
|||||||
# Volatility indicators
|
# Volatility indicators
|
||||||
Done: 15, Todo: 20
|
Done: 24, Todo: 11
|
||||||
|
|
||||||
✔️ ADR - Average Daily Range
|
✔️ ADR - Average Daily Range
|
||||||
✔️ AP - Andrew's Pitchfork
|
✔️ AP - Andrew's Pitchfork
|
||||||
✔️ ATR - Average True Range
|
✔️ ATR - Average True Range
|
||||||
✔️ ATRP - Average True Range Percent
|
✔️ ATRP - Average True Range Percent
|
||||||
✔️ ATRS - ATR Trailing Stop
|
✔️ ATRS - ATR Trailing Stop
|
||||||
*BB - Bollinger Bands® (Upper, Middle, Lower)
|
✔️ BBAND - Bollinger Bands® (Upper, Middle, Lower)
|
||||||
CCV - Close-to-Close Volatility
|
✔️ CCV - Close-to-Close Volatility
|
||||||
CE - Chandelier Exit
|
✔️ CE - Chandelier Exit
|
||||||
CV - Conditional Volatility (ARCH/GARCH)
|
✔️ CV - Conditional Volatility (ARCH/GARCH)
|
||||||
CVI - Chaikin's Volatility
|
✔️ CVI - Chaikin's Volatility
|
||||||
*DC - Donchian Channels (Upper, Middle, Lower)
|
*DC - Donchian Channels (Upper, Middle, Lower)
|
||||||
EWMA - Exponential Weighted Moving Average Volatility
|
✔️ EWMA - Exponential Weighted Moving Average Volatility
|
||||||
FCB - Fractal Chaos Bands
|
✔️ FCB - Fractal Chaos Bands
|
||||||
GKV - Garman-Klass Volatility
|
✔️ GKV - Garman-Klass Volatility
|
||||||
HLV - High-Low Volatility
|
✔️ HLV - High-Low Volatility
|
||||||
✔️ HV - Historical Volatility
|
✔️ HV - Historical Volatility
|
||||||
*ICH - Ichimoku Cloud (Conversion, Base, Leading Span A, Leading Span B, Lagging Span)
|
*ICH - Ichimoku Cloud (Conversion, Base, Leading Span A, Leading Span B, Lagging Span)
|
||||||
✔️ JVOLTY - Jurik Volatility
|
✔️ JVOLTY - Jurik Volatility
|
||||||
|
|||||||
@@ -2,13 +2,10 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>Averages</AssemblyName>
|
<AssemblyName>Averages</AssemblyName>
|
||||||
<AlgoType>Indicator</AlgoType>
|
<AlgoType>Indicator</AlgoType>
|
||||||
<AssemblyVersion>0.0.0.0</AssemblyVersion>
|
|
||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
|
|
||||||
<UpdateAssemblyInfo>true</UpdateAssemblyInfo>
|
|
||||||
<GenerateGitVersionInformation>true</GenerateGitVersionInformation>
|
|
||||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -16,7 +13,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\*.cs" />
|
<Compile Include="..\*.cs" />
|
||||||
<Compile Include="*.cs" />
|
<Compile Include="*.cs" />
|
||||||
|
|
||||||
<Compile Include="..\..\lib\**\*.cs" Exclude="..\..\lib\bin\**;..\..\lib\obj\**" />
|
<Compile Include="..\..\lib\**\*.cs" Exclude="..\..\lib\bin\**;..\..\lib\obj\**" />
|
||||||
<Reference Include="TradingPlatform.BusinessLayer">
|
<Reference Include="TradingPlatform.BusinessLayer">
|
||||||
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
|
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
|
||||||
@@ -32,4 +28,4 @@
|
|||||||
DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Averages" />
|
DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Averages" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -2,13 +2,10 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>Momentum</AssemblyName>
|
<AssemblyName>Momentum</AssemblyName>
|
||||||
<AlgoType>Indicator</AlgoType>
|
<AlgoType>Indicator</AlgoType>
|
||||||
<AssemblyVersion>0.0.0.0</AssemblyVersion>
|
|
||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
|
|
||||||
<UpdateAssemblyInfo>true</UpdateAssemblyInfo>
|
|
||||||
<GenerateGitVersionInformation>true</GenerateGitVersionInformation>
|
|
||||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -30,4 +27,4 @@
|
|||||||
<Copy SourceFiles="$(OutputPath)\Momentum.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Momentum" />
|
<Copy SourceFiles="$(OutputPath)\Momentum.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Momentum" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -2,13 +2,10 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>Oscillators</AssemblyName>
|
<AssemblyName>Oscillators</AssemblyName>
|
||||||
<AlgoType>Indicator</AlgoType>
|
<AlgoType>Indicator</AlgoType>
|
||||||
<AssemblyVersion>0.0.0.0</AssemblyVersion>
|
|
||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
|
|
||||||
<UpdateAssemblyInfo>true</UpdateAssemblyInfo>
|
|
||||||
<GenerateGitVersionInformation>true</GenerateGitVersionInformation>
|
|
||||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -30,4 +27,4 @@
|
|||||||
<Copy SourceFiles="$(OutputPath)\Oscillators.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Oscillators" />
|
<Copy SourceFiles="$(OutputPath)\Oscillators.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Oscillators" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -2,13 +2,10 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>Statistics</AssemblyName>
|
<AssemblyName>Statistics</AssemblyName>
|
||||||
<AlgoType>Indicator</AlgoType>
|
<AlgoType>Indicator</AlgoType>
|
||||||
<AssemblyVersion>0.0.0.0</AssemblyVersion>
|
|
||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
|
|
||||||
<UpdateAssemblyInfo>true</UpdateAssemblyInfo>
|
|
||||||
<GenerateGitVersionInformation>true</GenerateGitVersionInformation>
|
|
||||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -2,13 +2,10 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>Volatility</AssemblyName>
|
<AssemblyName>Volatility</AssemblyName>
|
||||||
<AlgoType>Indicator</AlgoType>
|
<AlgoType>Indicator</AlgoType>
|
||||||
<AssemblyVersion>0.0.0.0</AssemblyVersion>
|
|
||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
|
|
||||||
<UpdateAssemblyInfo>true</UpdateAssemblyInfo>
|
|
||||||
<GenerateGitVersionInformation>true</GenerateGitVersionInformation>
|
|
||||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -16,7 +13,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\*.cs" />
|
<Compile Include="..\*.cs" />
|
||||||
<Compile Include="*.cs" />
|
<Compile Include="*.cs" />
|
||||||
|
|
||||||
<Compile Include="..\..\lib\**\*.cs" Exclude="..\..\lib\bin\**;..\..\lib\obj\**" />
|
<Compile Include="..\..\lib\**\*.cs" Exclude="..\..\lib\bin\**;..\..\lib\obj\**" />
|
||||||
<Reference Include="TradingPlatform.BusinessLayer">
|
<Reference Include="TradingPlatform.BusinessLayer">
|
||||||
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
|
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
|
||||||
@@ -31,4 +27,4 @@
|
|||||||
<Copy SourceFiles="$(OutputPath)\Volatility.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Volatility" />
|
<Copy SourceFiles="$(OutputPath)\Volatility.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Volatility" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -2,13 +2,10 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>Volume</AssemblyName>
|
<AssemblyName>Volume</AssemblyName>
|
||||||
<AlgoType>Indicator</AlgoType>
|
<AlgoType>Indicator</AlgoType>
|
||||||
<AssemblyVersion>0.0.0.0</AssemblyVersion>
|
|
||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
<IsLocalBuild Condition="'$(GITHUB_ACTIONS)' == ''">true</IsLocalBuild>
|
|
||||||
<UpdateAssemblyInfo>true</UpdateAssemblyInfo>
|
|
||||||
<GenerateGitVersionInformation>true</GenerateGitVersionInformation>
|
|
||||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -30,4 +27,4 @@
|
|||||||
<Copy SourceFiles="$(OutputPath)\Volume.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Volume" />
|
<Copy SourceFiles="$(OutputPath)\Volume.dll" DestinationFolder="$(QuantowerRoot)\Settings\Scripts\Indicators\QuanTAlib\Volume" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
Reference in New Issue
Block a user