diff --git a/.deepsource.toml b/.deepsource.toml
new file mode 100644
index 00000000..f3badbc4
--- /dev/null
+++ b/.deepsource.toml
@@ -0,0 +1,20 @@
+version = 1
+
+[[analyzers]]
+name = "csharp"
+enabled = true
+
+[analyzers.meta]
+language_version = "11.0"
+
+[[analyzers]]
+name = "test-coverage"
+enabled = true
+
+[[analyzers]]
+name = "secrets"
+enabled = true
+
+[[transformers]]
+name = "dotnet-format"
+enabled = true
\ No newline at end of file
diff --git a/.github/workflows/Publish.yml b/.github/workflows/Publish.yml
new file mode 100644
index 00000000..68ad111e
--- /dev/null
+++ b/.github/workflows/Publish.yml
@@ -0,0 +1,306 @@
+# This workflow integrates SonarCloud analysis, coverage reporting,
+# CodeQL analysis, SecurityCodeScan, and Codacy Security Scan
+# for code scanning and vulnerability detection.
+
+name: Publish Workflow
+
+on:
+ push: # Triggers on push events to any branch
+ pull_request: # Triggers on pull request events targeting any branch
+ workflow_dispatch: # Allows manual triggering of the workflow
+
+permissions:
+ contents: write
+ pull-requests: read # Allows SonarCloud to decorate PRs with analysis results
+ security-events: write # Required for CodeQL analysis and uploading SARIF results
+
+jobs:
+ SonarCloud:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET SDK
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '8.0.x'
+
+ - name: Install JDK11 for Sonar Scanner
+ uses: actions/setup-java@v3
+ with:
+ java-version: '11'
+ distribution: 'zulu'
+
+ - name: Install dotnet-sonarscanner
+ run: |
+ dotnet tool install --global dotnet-sonarscanner
+ dotnet tool install JetBrains.dotCover.GlobalTool --global
+ dotnet tool install dotnet-coverage --global
+ dotnet restore
+
+ - name: SonarCloud Scanner Start
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ run: |
+ dotnet sonarscanner begin \
+ /k:"mihakralj_QuanTAlib" \
+ /o:"mihakralj" \
+ /d:sonar.login="${{ secrets.SONAR_TOKEN }}" \
+ /d:sonar.host.url="https://sonarcloud.io" \
+ /d:sonar.cs.dotcover.reportsPaths=dotcover*
+
+ - name: Build
+ run: |
+ dotnet build --no-restore --configuration Debug
+ dotnet build ./lib/quantalib.csproj --configuration Release --nologo
+ dotnet build ./quantower/Averages/Averages.csproj --configuration Release --nologo
+ dotnet build ./quantower/Statistics/Statistics.csproj --configuration Release --nologo
+ dotnet build ./quantower/Volatility/Volatility.csproj --configuration Release --nologo
+ dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
+ dotnet dotcover test Tests/Tests.csproj --dcReportType=HTML --dcoutput=./dotcover.html
+
+ - name: SonarCloud Scanner End
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ run: dotnet sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
+
+ Code_Coverage:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET SDK
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '8.0.x'
+
+ - name: Install dotnet tools
+ run: |
+ dotnet tool install JetBrains.dotCover.GlobalTool --global
+ dotnet tool install dotnet-sonarscanner --global
+ dotnet tool install dotnet-coverage --global
+ dotnet tool install --global coverlet.console
+ dotnet tool install --global dotnet-reportgenerator-globaltool
+ dotnet restore
+
+ - name: Build Projects
+ run: |
+ dotnet build --no-restore --configuration Debug
+ dotnet build ./lib/quantalib.csproj --configuration Release --nologo
+ dotnet build ./quantower/Averages/Averages.csproj --configuration Release --nologo
+ dotnet build ./quantower/Statistics/Statistics.csproj --configuration Release --nologo
+ dotnet build ./quantower/Volatility/Volatility.csproj --configuration Release --nologo
+ dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
+
+ - name: Run Tests with Coverage
+ run: |
+ dotnet test --no-build --configuration Debug /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
+ dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml"
+ dotnet dotcover test Tests/Tests.csproj --dcReportType=HTML --dcoutput=./dotcover.html
+ dotnet dotcover test Tests/Tests.csproj --dcReportType=DetailedXML --dcoutput=./dotcover.xml --verbosity=Detailed
+ dotnet test -p:CollectCoverage=true --collect:"XPlat Code Coverage" --results-directory "./"
+
+ - name: Generate Coverage Report
+ run: |
+ reportgenerator -reports:*cover*.xml -targetdir:.
+
+ - name: Upload Coverage to Codacy
+ uses: codacy/codacy-coverage-reporter-action@v1
+ with:
+ project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
+ coverage-reports: '*cover*.xml'
+
+ - name: Upload Coverage to Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ files: 'cover*'
+ verbose: true
+
+ CodeQL:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET SDK
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '8.0.x'
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v3
+ with:
+ languages: 'csharp'
+
+ - name: Restore dependencies
+ run: dotnet restore
+
+ - name: Build
+ run: dotnet build --no-restore --configuration Debug
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v3
+
+ SecurityCodeScan:
+ runs-on: windows-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup NuGet
+ uses: nuget/setup-nuget@v1
+
+ - name: Setup MSBuild
+ uses: microsoft/setup-msbuild@v1
+
+ - name: Setup .NET SDK
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '3.1.x'
+
+ - name: Set up projects for analysis
+ uses: security-code-scan/security-code-scan-add-action@v1
+
+ - name: Restore dependencies
+ run: dotnet restore
+
+ - name: Build
+ run: 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
+
+ Codacy_Scan:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ security-events: write
+ actions: read
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - 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: Upload SARIF results file
+ uses: github/codeql-action/upload-sarif@v3
+ with:
+ sarif_file: results.sarif
+
+ build_publish:
+ needs: [SonarCloud, Code_Coverage, CodeQL, SecurityCodeScan, Codacy_Scan]
+ if: success()
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET SDK
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '8.0.x'
+
+ - name: Install GitVersion
+ uses: gittools/actions/gitversion/setup@v0
+ with:
+ versionSpec: '6.x'
+ includePrerelease: true
+
+ - name: Determine Version
+ id: gitversion
+ uses: gittools/actions/gitversion/execute@v0
+ with:
+ useConfigFile: true
+ updateAssemblyInfo: true
+
+ - name: Build projects
+ run: |
+ dotnet build ./lib/quantalib.csproj --configuration Release --nologo \
+ -p:PackageVersion=${{ steps.gitversion.outputs.MajorMinorPatch }}
+ dotnet build ./quantower/Averages/Averages.csproj --configuration Release --nologo
+ dotnet build ./quantower/Statistics/Statistics.csproj --configuration Release --nologo
+ dotnet build ./quantower/Volatility/Volatility.csproj --configuration Release --nologo
+ dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
+
+############# Publish dev release
+
+ - name: Update Development Release
+ if: github.ref == 'refs/heads/dev'
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ MYGET_URL: https://www.myget.org/feed/quantalib/package/nuget/QuanTAlib
+ PACKAGE_VERSION: ${{ steps.gitversion.outputs.NuGetVersion }}
+ run: |
+ tag_name="development"
+ release_name="Development Build"
+ gh release delete $tag_name --yes || true
+ git push origin :refs/tags/$tag_name || true
+ gh release create $tag_name \
+ --title "$release_name" \
+ --notes "Latest development build from commit ${{ github.sha }}
+
+ MyGet Package: [$MYGET_URL/$PACKAGE_VERSION]($MYGET_URL/$PACKAGE_VERSION) \n" \
+ --prerelease \
+ --target ${{ github.sha }} \
+ quantower/Averages/bin/Release/Averages.dll \
+ quantower/Statistics/bin/Release/Statistics.dll \
+ quantower/Volatility/bin/Release/Volatility.dll \
+ SyntheticVendor/bin/Release/SyntheticVendor.dll
+
+ - name: Push prerelease package to myget.org
+ if: github.ref == 'refs/heads/dev'
+ run: |
+ dotnet nuget push 'lib/bin/Release/QuanTAlib.*.nupkg' \
+ --source https://www.myget.org/F/quantalib/api/v3/index.json \
+ --force-english-output \
+ --api-key ${{ secrets.MYGET_DEPLOY_KEY_QUANTALIB }}
+
+############## Publish main release
+
+ - name: Publish release assets
+ if: ${{ github.ref == 'refs/heads/main' }}
+ uses: SourceSprint/upload-multiple-releases@1.0.7
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ prerelease: false
+ overwrite: true
+ release_name: ${{ steps.gitversion.outputs.MajorMinorPatch }}
+ tag_name: latest
+ release_config: |
+ quantower/Averages/bin/Release/Averages.dll
+ quantower/Statistics/bin/Release/Statistics.dll
+ quantower/Volatility/bin/Release/Volatility.dll
+ SyntheticVendor/bin/Release/SyntheticVendor.dll
+
+ - name: Push release package to nuget.org
+ if: ${{ github.ref == 'refs/heads/main' }}
+ run: dotnet nuget push 'lib/bin/Release/QuanTAlib.*.nupkg' \
+ --source https://api.nuget.org/v3/index.json \
+ --skip-duplicate \
+ --api-key ${{ secrets.NUGET_DEPLOY_KEY_QUANTLIB }}
\ No newline at end of file
diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml
deleted file mode 100644
index 513090d9..00000000
--- a/.github/workflows/codacy.yml
+++ /dev/null
@@ -1,61 +0,0 @@
-# This workflow uses actions that are not certified by GitHub.
-# They are provided by a third-party and are governed by
-# separate terms of service, privacy policy, and support
-# documentation.
-
-# This workflow checks out code, performs a Codacy security scan
-# and integrates the results with the
-# GitHub Advanced Security code scanning feature. For more information on
-# the Codacy security scan action usage and parameters, see
-# https://github.com/codacy/codacy-analysis-cli-action.
-# For more information on Codacy Analysis CLI in general, see
-# https://github.com/codacy/codacy-analysis-cli.
-
-name: Codacy Security Scan
-
-on:
- push:
- branches: [ "main" ]
- pull_request:
- # The branches below must be a subset of the branches above
- branches: [ "main" ]
- schedule:
- - cron: '17 22 * * 0'
-
-permissions:
- contents: read
-
-jobs:
- codacy-security-scan:
- permissions:
- contents: read # for actions/checkout to fetch code
- security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
- actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
- name: Codacy Security Scan
- runs-on: ubuntu-latest
- steps:
- # Checkout the repository to the GitHub Actions runner
- - name: Checkout code
- uses: actions/checkout@v4
-
- # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- - name: Run Codacy Analysis CLI
- uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b
- with:
- # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
- # You can also omit the token and run the tools that support default configurations
- project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
- verbose: true
- output: results.sarif
- format: sarif
- # Adjust severity of non-security issues
- gh-code-scanning-compat: true
- # Force 0 exit code to allow SARIF file generation
- # This will handover control about PR rejection to the GitHub side
- max-allowed-issues: 2147483647
-
- # Upload the SARIF file generated in the previous step
- - name: Upload SARIF results file
- uses: github/codeql-action/upload-sarif@v3
- with:
- sarif_file: results.sarif
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
deleted file mode 100644
index ddf8b5b8..00000000
--- a/.github/workflows/codeql.yml
+++ /dev/null
@@ -1,92 +0,0 @@
-# For most projects, this workflow file will not need changing; you simply need
-# to commit it to your repository.
-#
-# You may wish to alter this file to override the set of languages analyzed,
-# or to provide custom queries or build logic.
-#
-# ******** NOTE ********
-# We have attempted to detect the languages in your repository. Please check
-# the `language` matrix defined below to confirm you have the correct set of
-# supported CodeQL languages.
-#
-name: "CodeQL Advanced"
-
-on:
- push:
- branches: [ "main" ]
- pull_request:
- branches: [ "main" ]
- schedule:
- - cron: '40 12 * * 1'
-
-jobs:
- analyze:
- name: Analyze (${{ matrix.language }})
- # Runner size impacts CodeQL analysis time. To learn more, please see:
- # - https://gh.io/recommended-hardware-resources-for-running-codeql
- # - https://gh.io/supported-runners-and-hardware-resources
- # - https://gh.io/using-larger-runners (GitHub.com only)
- # Consider using larger runners or machines with greater resources for possible analysis time improvements.
- runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
- permissions:
- # required for all workflows
- security-events: write
-
- # required to fetch internal or private CodeQL packs
- packages: read
-
- # only required for workflows in private repositories
- actions: read
- contents: read
-
- strategy:
- fail-fast: false
- matrix:
- include:
- - language: csharp
- build-mode: autobuild
- # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
- # Use `c-cpp` to analyze code written in C, C++ or both
- # Use 'java-kotlin' to analyze code written in Java, Kotlin or both
- # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
- # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
- # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
- # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
- # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
-
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v3
- with:
- languages: ${{ matrix.language }}
- build-mode: ${{ matrix.build-mode }}
- # If you wish to specify custom queries, you can do so here or in a config file.
- # By default, queries listed here will override any specified in a config file.
- # Prefix the list here with "+" to use these queries and those in the config file.
-
- # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
- # queries: security-extended,security-and-quality
-
- # If the analyze step fails for one of the languages you are analyzing with
- # "We were unable to automatically build your code", modify the matrix above
- # to set the build mode to "manual" for that language. Then modify this step
- # to build your code.
- # âšī¸ Command-line programs to run using the OS shell.
- # đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- - if: matrix.build-mode == 'manual'
- shell: bash
- run: |
- echo 'If you are using a "manual" build mode for one or more of the' \
- 'languages you are analyzing, replace this with the commands to build' \
- 'your code, for example:'
- echo ' make bootstrap'
- echo ' make release'
- exit 1
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v3
- with:
- category: "/language:${{matrix.language}}"
diff --git a/Directory.Build.props b/Directory.Build.props
index cb841319..65b4088f 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -20,6 +20,33 @@
snupkg
AnyCPU
true
+
+
+ $(GitVersion_NuGetVersion)
+ $(GitVersion_AssemblySemVer)
+ $(GitVersion_AssemblySemFileVer)
+ $(GitVersion_InformationalVersion)
+
+
+
+ true
+ link
+ true
+ true
+ true
+ none
+ true
+ true
+ true
+ false
+ true
+ false
+ false
+ false
+ false
+ true
+ false
+ true
@@ -35,4 +62,6 @@
$([System.IO.Directory]::GetDirectories("$(QuantowerRoot)\TradingPlatform", "v1*")[0])
-
\ No newline at end of file
+
+
+
diff --git a/GitVersion.yml b/GitVersion.yml
index ce39df9f..6fbaef20 100644
--- a/GitVersion.yml
+++ b/GitVersion.yml
@@ -18,19 +18,28 @@ branches:
source-branches: []
tracks-release-branches: false
is-release-branch: true
- is-main-branch: true
pre-release-weight: 55000
dev:
- regex: ^dev(elop)?(ment)?$
+ regex: ^dev$
mode: ContinuousDelivery
- label: dev
+ label: ''
+ increment: Patch
+ track-merge-target: true
+ source-branches: ['main']
+ tracks-release-branches: true
+ is-release-branch: false
+ pre-release-weight: 0
+
+ develop:
+ regex: ^develop$
+ mode: ContinuousDelivery
+ label: ''
increment: Patch
track-merge-target: true
source-branches: ['main']
tracks-release-branches: true
is-release-branch: false
- is-main-branch: false
pre-release-weight: 0
ignore:
diff --git a/SyntheticVendor/SyntheticVendor.cs b/SyntheticVendor/SyntheticVendor.cs
index e1a7f559..60c2118a 100644
--- a/SyntheticVendor/SyntheticVendor.cs
+++ b/SyntheticVendor/SyntheticVendor.cs
@@ -3,18 +3,22 @@
using System.Threading;
using TradingPlatform.BusinessLayer;
using TradingPlatform.BusinessLayer.Integration;
+using System.Diagnostics.CodeAnalysis;
-namespace SyntheticVendorNamespace
+
+namespace SyntheticVendorNamespace;
+[SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")]
+
+
+public class SyntheticVendor : Vendor
{
- public class SyntheticVendor : Vendor
- {
- private readonly List exchanges;
- private readonly List assets;
- private readonly List symbols;
+ private readonly List exchanges;
+ private readonly List assets;
+ private readonly List symbols;
- public SyntheticVendor()
- {
- exchanges = new List
+ public SyntheticVendor()
+ {
+ exchanges = new List
{
//Spike,
@@ -42,13 +46,13 @@ public SyntheticVendor()
new MessageExchange { Id = "QT", ExchangeName = "6 QuanTAlib" }
};
- assets = new List
+ assets = new List
{
new MessageAsset { Id = "USD", Name = "USD" },
};
- symbols = new List
+ symbols = new List
{
CreateMessageSymbol(id: "W1", name: "1 Digital spike", exchangeId: "QT", assetId: "USD", type: SymbolType.Crypto,
description: "Sudden sharp spike in the signal"),
@@ -73,277 +77,277 @@ public SyntheticVendor()
CreateMessageSymbol("W17", "2 Geometric Brownian motion", "QT", "USD", SymbolType.Synthetic)
};
-/*
- Bond,
- CFD,
- Crypto,
- Debentures,
- Equities,
- ETF,
- FixedIncome,
- Forex,
- Forward,
- Futures,
- Indexes,
- Options,
- Spot,
- Synthetic,
- Swap,
- Warrants,
+ /*
+ Bond,
+ CFD,
+ Crypto,
+ Debentures,
+ Equities,
+ ETF,
+ FixedIncome,
+ Forex,
+ Forward,
+ Futures,
+ Indexes,
+ Options,
+ Spot,
+ Synthetic,
+ Swap,
+ Warrants,
-*/
+ */
- }
+ }
- private MessageSymbol CreateMessageSymbol(
- string id,
- string name,
- string exchangeId,
- string assetId,
- SymbolType type,
- string description)
+ private MessageSymbol CreateMessageSymbol(
+ string id,
+ string name,
+ string exchangeId,
+ string assetId,
+ SymbolType type,
+ string description)
+ {
+ var messageSymbol = new MessageSymbol(id)
{
- var messageSymbol = new MessageSymbol(id)
- {
- Name = name,
- Description = description,
- SymbolType = type,
- ExchangeId = exchangeId,
- ProductAssetId = assetId,
-
- // Setting some default values
- QuotingCurrencyAssetID = "USD",
- HistoryType = HistoryType.Last,
- DeltaCalculationType = DeltaCalculationType.TickDirection,
- LotSize = 1,
- VariableTickList = new List
+ Name = name,
+ Description = description,
+ SymbolType = type,
+ ExchangeId = exchangeId,
+ ProductAssetId = assetId,
+
+ // Setting some default values
+ QuotingCurrencyAssetID = "USD",
+ HistoryType = HistoryType.Last,
+ DeltaCalculationType = DeltaCalculationType.TickDirection,
+ LotSize = 1,
+ VariableTickList = new List
{
new VariableTick(0.01) // Default tick size
}
- };
+ };
- return messageSymbol;
- }
+ return messageSymbol;
+ }
- public static VendorMetaData GetVendorMetaData()
+ public static VendorMetaData GetVendorMetaData()
+ {
+ return new VendorMetaData()
{
- return new VendorMetaData()
+ VendorName = "Synthetic Vendor",
+ VendorDescription = "A synthetic vendor for testing and demonstration purposes",
+ GetDefaultConnections = () =>
{
- VendorName = "Synthetic Vendor",
- VendorDescription = "A synthetic vendor for testing and demonstration purposes",
- GetDefaultConnections = () =>
- {
- var defaultConnection = Vendor.CreateDefaultConnectionInfo(
- "Synthetic Connection",
- "Synthetic Vendor",
- "", // Replace with actual path if you have a logo
- allowCreateCustomConnections: true
- );
- return new List { defaultConnection };
- }
- };
- }
+ var defaultConnection = Vendor.CreateDefaultConnectionInfo(
+ "Synthetic Connection",
+ "Synthetic Vendor",
+ "", // Replace with actual path if you have a logo
+ allowCreateCustomConnections: true
+ );
+ return new List { defaultConnection };
+ }
+ };
+ }
- private MessageSymbol CreateMessageSymbol(string id, string name, string exchangeId, string assetId, SymbolType type)
+ private MessageSymbol CreateMessageSymbol(string id, string name, string exchangeId, string assetId, SymbolType type)
+ {
+ return new MessageSymbol(id)
{
- return new MessageSymbol(id)
- {
- Name = name,
- ExchangeId = exchangeId,
- ProductAssetId = assetId,
- QuotingCurrencyAssetID = "USD",
- QuotingType = SymbolQuotingType.LotSize,
- LotSize = 1,
- NettingType = NettingType.OnePosition,
- VolumeType = SymbolVolumeType.Volume,
- AllowCalculateRealtimeTicks = true,
- AllowCalculateRealtimeTrades = false,
- AllowCalculateRealtimeVolume = true,
- AllowCalculateRealtimeChange = true,
- AllowAbbreviatePriceByTickSize = false,
- NotionalValueStep = 0.01,
- DeltaCalculationType = DeltaCalculationType.AggressorFlag, // Changed from None to AggressorFlag
- MinVolumeAnalysisTickSize = 0.01,
- MaturityDate = DateTime.MaxValue, // Set to max value for non-expiring symbols
- HistoryType = HistoryType.Last,
- MinLot = 0.01,
- LotStep = 0.01,
- MaxLot = 1000000,
- SymbolType = type
-/*
- SymbolType.Unknown,
- [EnumMember] Forex,
- [EnumMember] Equities,
- [EnumMember] CFD,
- [EnumMember] Indexes,
- [EnumMember] Futures,
- [EnumMember] Options,
- [EnumMember] ETF,
- [EnumMember] Crypto,
- [EnumMember] Synthetic,
- [EnumMember] Spot,
- [EnumMember] Forward,
- [EnumMember] FixedIncome,
- [EnumMember] Warrants,
-
- [EnumMember] Debentures,
- [EnumMember] Bond,
- [EnumMember] Swap,
-*/
- };
- }
+ Name = name,
+ ExchangeId = exchangeId,
+ ProductAssetId = assetId,
+ QuotingCurrencyAssetID = "USD",
+ QuotingType = SymbolQuotingType.LotSize,
+ LotSize = 1,
+ NettingType = NettingType.OnePosition,
+ VolumeType = SymbolVolumeType.Volume,
+ AllowCalculateRealtimeTicks = true,
+ AllowCalculateRealtimeTrades = false,
+ AllowCalculateRealtimeVolume = true,
+ AllowCalculateRealtimeChange = true,
+ AllowAbbreviatePriceByTickSize = false,
+ NotionalValueStep = 0.01,
+ DeltaCalculationType = DeltaCalculationType.AggressorFlag, // Changed from None to AggressorFlag
+ MinVolumeAnalysisTickSize = 0.01,
+ MaturityDate = DateTime.MaxValue, // Set to max value for non-expiring symbols
+ HistoryType = HistoryType.Last,
+ MinLot = 0.01,
+ LotStep = 0.01,
+ MaxLot = 1000000,
+ SymbolType = type
+ /*
+ SymbolType.Unknown,
+ [EnumMember] Forex,
+ [EnumMember] Equities,
+ [EnumMember] CFD,
+ [EnumMember] Indexes,
+ [EnumMember] Futures,
+ [EnumMember] Options,
+ [EnumMember] ETF,
+ [EnumMember] Crypto,
+ [EnumMember] Synthetic,
+ [EnumMember] Spot,
+ [EnumMember] Forward,
+ [EnumMember] FixedIncome,
+ [EnumMember] Warrants,
+
+ [EnumMember] Debentures,
+ [EnumMember] Bond,
+ [EnumMember] Swap,
+ */
+ };
+ }
- public override ConnectionResult Connect(ConnectRequestParameters connectRequestParameters)
- {
- // Simulating connection process
- Thread.Sleep(100); // Simulate some connection delay
+ public override ConnectionResult Connect(ConnectRequestParameters connectRequestParameters)
+ {
+ // Simulating connection process
+ Thread.Sleep(100); // Simulate some connection delay
- return ConnectionResult.CreateSuccess("Successfully connected to Synthetic Vendor");
- }
+ return ConnectionResult.CreateSuccess("Successfully connected to Synthetic Vendor");
+ }
- public override void Disconnect()
- {
- // Simulating disconnection process
- Thread.Sleep(500); // Simulate some disconnection delay
+ public override void Disconnect()
+ {
+ // Simulating disconnection process
+ Thread.Sleep(500); // Simulate some disconnection delay
- }
+ }
- public override PingResult Ping()
- {
+ public override PingResult Ping()
+ {
return new PingResult()
- {
- State = PingEnum.Connected,
- PingTime = TimeSpan.FromMilliseconds(2),
- RoundTripTime = TimeSpan.FromMilliseconds(2)
- };
- }
-
+ {
+ State = PingEnum.Connected,
+ PingTime = TimeSpan.FromMilliseconds(2),
+ RoundTripTime = TimeSpan.FromMilliseconds(2)
+ };
+ }
- public override void OnConnected(CancellationToken token)
- {
- // This method is called after a successful connection
- // You can initialize resources or start any necessary processes here
- base.OnConnected(token);
- // For example, you might want to push some initial messages or data
- // PushMessage(new MessageVendorEvent("SyntheticVendor connected successfully"));
- }
+ public override void OnConnected(CancellationToken token)
+ {
+ // This method is called after a successful connection
+ // You can initialize resources or start any necessary processes here
+ base.OnConnected(token);
+ // For example, you might want to push some initial messages or data
+ // PushMessage(new MessageVendorEvent("SyntheticVendor connected successfully"));
+ }
- public override IList GetExchanges(CancellationToken token)
- {
- return exchanges;
- }
- public override IList GetAssets(CancellationToken token)
- {
- return assets;
- }
+ public override IList GetExchanges(CancellationToken token)
+ {
+ return exchanges;
+ }
- public override IList GetSymbols(CancellationToken token)
- {
- return symbols;
- }
+ public override IList GetAssets(CancellationToken token)
+ {
+ return assets;
+ }
- public override void SubscribeSymbol(SubscribeQuotesParameters parameters)
- {
- // Empty method for data subscription to be filled later
- }
+ public override IList GetSymbols(CancellationToken token)
+ {
+ return symbols;
+ }
- public override void UnSubscribeSymbol(SubscribeQuotesParameters parameters)
- {
- // Empty method for data unsubscription to be filled later
- }
+ public override void SubscribeSymbol(SubscribeQuotesParameters parameters)
+ {
+ // Empty method for data subscription to be filled later
+ }
+ public override void UnSubscribeSymbol(SubscribeQuotesParameters parameters)
+ {
+ // Empty method for data unsubscription to be filled later
+ }
- public override IList LoadHistory(HistoryRequestParameters requestParameters)
- {
- var historyItems = new List();
- var symbolId = requestParameters.SymbolId;
- if (string.IsNullOrEmpty(symbolId)) return historyItems;
+ public override IList LoadHistory(HistoryRequestParameters requestParameters)
+ {
+ var historyItems = new List();
+ var symbolId = requestParameters.SymbolId;
- DateTime from = requestParameters.FromTime;
- DateTime to = requestParameters.ToTime;
+ if (string.IsNullOrEmpty(symbolId)) return historyItems;
- TimeSpan periodTimeSpan = requestParameters.Aggregation.GetPeriod.Duration;
+ DateTime from = requestParameters.FromTime;
+ DateTime to = requestParameters.ToTime;
- // Define the maximum number of items to generate per request
- const int MAX_ITEMS_PER_REQUEST = 10000;
+ TimeSpan periodTimeSpan = requestParameters.Aggregation.GetPeriod.Duration;
- Func waveGenerator = GetWaveGenerator(symbolId);
+ // Define the maximum number of items to generate per request
+ const int MAX_ITEMS_PER_REQUEST = 10000;
- DateTime currentTime = from;
- while (currentTime < to)
- {
- DateTime intervalEnd = currentTime.AddTicks(periodTimeSpan.Ticks * MAX_ITEMS_PER_REQUEST);
- if (intervalEnd > to)
- intervalEnd = to;
+ Func waveGenerator = GetWaveGenerator(symbolId);
- while (currentTime <= intervalEnd)
- {
- var historyItem = waveGenerator(currentTime, periodTimeSpan); //calling generator fuction
- historyItems.Add(historyItem);
+ DateTime currentTime = from;
+ while (currentTime < to)
+ {
+ DateTime intervalEnd = currentTime.AddTicks(periodTimeSpan.Ticks * MAX_ITEMS_PER_REQUEST);
+ if (intervalEnd > to)
+ intervalEnd = to;
- currentTime = currentTime.Add(periodTimeSpan);
+ while (currentTime <= intervalEnd)
+ {
+ var historyItem = waveGenerator(currentTime, periodTimeSpan); //calling generator fuction
+ historyItems.Add(historyItem);
- if (requestParameters.CancellationToken.IsCancellationRequested) return historyItems;
- }
+ currentTime = currentTime.Add(periodTimeSpan);
- currentTime = intervalEnd;
+ if (requestParameters.CancellationToken.IsCancellationRequested) return historyItems;
}
- return historyItems;
+ currentTime = intervalEnd;
}
- private Func GetWaveGenerator(string symbolId)
+ return historyItems;
+ }
+
+ private Func GetWaveGenerator(string symbolId)
+ {
+ switch (symbolId)
{
- switch (symbolId)
- {
- //case "W0": return GenerateConstant;
- case "W1": return GenerateSpike;
- case "W2": return GenerateDiracDelta;
- case "W3": return GenerateSquareWave;
- case "W4": return GenerateSawtoothWave;
- case "W5": return GenerateInverseSawtoothWave;
- case "W6": return GenerateTriangleWave;
- case "W7": return GenerateSineWave;
- case "W8": return GenerateSincWave;
- case "W9": return GenerateGaussianPulse;
- case "W10": return GenerateFrequencySweep;
- case "W11": return GenerateAMSignal;
- case "W12": return GenerateFMSignal;
- case "W13": return GenerateWhiteNoise;
- case "W14": return GeneratePinkNoise;
- case "W15": return GenerateBrownNoise;
- case "W16": return GenerateFBM;
- case "W17": return GenerateGBM;
-
- default: return GenerateSineWave;
- }
+ //case "W0": return GenerateConstant;
+ case "W1": return GenerateSpike;
+ case "W2": return GenerateDiracDelta;
+ case "W3": return GenerateSquareWave;
+ case "W4": return GenerateSawtoothWave;
+ case "W5": return GenerateInverseSawtoothWave;
+ case "W6": return GenerateTriangleWave;
+ case "W7": return GenerateSineWave;
+ case "W8": return GenerateSincWave;
+ case "W9": return GenerateGaussianPulse;
+ case "W10": return GenerateFrequencySweep;
+ case "W11": return GenerateAMSignal;
+ case "W12": return GenerateFMSignal;
+ case "W13": return GenerateWhiteNoise;
+ case "W14": return GeneratePinkNoise;
+ case "W15": return GenerateBrownNoise;
+ case "W16": return GenerateFBM;
+ case "W17": return GenerateGBM;
+
+ default: return GenerateSineWave;
}
+ }
- public override HistoryMetadata GetHistoryMetadata(CancellationToken cancellationToken)
+ public override HistoryMetadata GetHistoryMetadata(CancellationToken cancellationToken)
+ {
+ return new HistoryMetadata()
{
- return new HistoryMetadata()
+ AllowedHistoryTypes = new HistoryType[]
{
- AllowedHistoryTypes = new HistoryType[]
- {
HistoryType.Bid,
HistoryType.Ask,
HistoryType.Midpoint,
HistoryType.Last,
HistoryType.BidAsk,
HistoryType.Mark,
- },
- AllowedPeriods = new Period[]
- {
+ },
+ AllowedPeriods = new Period[]
+ {
Period.TICK1,
Period.SECOND1, Period.SECOND5, Period.SECOND10, Period.SECOND15, Period.SECOND30,
Period.MIN1, Period.MIN2, Period.MIN3, Period.MIN4, Period.MIN5,
@@ -354,19 +358,19 @@ public override HistoryMetadata GetHistoryMetadata(CancellationToken cancellatio
Period.WEEK1,
Period.MONTH1,
Period.YEAR1
- },
- UseHistoryLocalCache = false
- };
- }
+ },
+ UseHistoryLocalCache = false
+ };
+ }
-/*******************************************************************************************************************************************/
-/*******************************************************************************************************************************************/
-/*******************************************************************************************************************************************/
-/*******************************************************************************************************************************************/
-/*******************************************************************************************************************************************/
-/*******************************************************************************************************************************************/
-/*******************************************************************************************************************************************/
+ /*******************************************************************************************************************************************/
+ /*******************************************************************************************************************************************/
+ /*******************************************************************************************************************************************/
+ /*******************************************************************************************************************************************/
+ /*******************************************************************************************************************************************/
+ /*******************************************************************************************************************************************/
+ /*******************************************************************************************************************************************/
private HistoryItemBar GenerateSpike(DateTime time, TimeSpan slice)
{
@@ -415,8 +419,8 @@ private HistoryItemBar GenerateSpike(DateTime time, TimeSpan slice)
- private static readonly double[] distributionValues = new double[]
- {
+ private static readonly double[] distributionValues = new double[]
+ {
0.010, // Extreme left tail
0.050, // Left tail
0.200, // Left of center
@@ -424,547 +428,547 @@ private HistoryItemBar GenerateSpike(DateTime time, TimeSpan slice)
0.200, // Right of center
0.050, // Right tail
0.010 // Extreme right tail
- };
-
- private HistoryItemBar GenerateDiracDelta(DateTime time, TimeSpan slice)
- {
- // Ensure we're working with UTC time
- DateTime utcTime = time.ToUniversalTime();
+ };
- // Calculate the start of the current day
- DateTime dayStart = utcTime.Date;
+ private HistoryItemBar GenerateDiracDelta(DateTime time, TimeSpan slice)
+ {
+ // Ensure we're working with UTC time
+ DateTime utcTime = time.ToUniversalTime();
- // Determine which bar of the day we're on
- int barOfDay = (int)((utcTime - dayStart).Ticks / slice.Ticks);
+ // Calculate the start of the current day
+ DateTime dayStart = utcTime.Date;
- double openValue, closeValue;
- double scaleFactor = 100; // Scale factor to convert to percentage
+ // Determine which bar of the day we're on
+ int barOfDay = (int)((utcTime - dayStart).Ticks / slice.Ticks);
- // Generate the spike pattern for the first 4 bars of each day
- switch (barOfDay)
- {
- case 0:
- openValue = 0.000001 * scaleFactor;
- closeValue = 0.05 * scaleFactor;
- break;
- case 1:
- openValue = 0.05 * scaleFactor;
- closeValue = 0.50 * scaleFactor;
- break;
- case 2:
- openValue = 0.50 * scaleFactor;
- closeValue = 0.05 * scaleFactor;
- break;
- case 3:
- openValue = 0.05 * scaleFactor;
- closeValue = 0.0000001 * scaleFactor;
- break;
- default:
- // Outside of the spike period, use baseline value
- openValue = closeValue = 0.000001;
- break;
- }
+ double openValue, closeValue;
+ double scaleFactor = 100; // Scale factor to convert to percentage
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = openValue,
- High = Math.Max(openValue, closeValue),
- Low = Math.Min(openValue, closeValue),
- Close = closeValue,
- Volume = Math.Abs(closeValue - openValue),
- Ticks = time.Add(slice).Ticks - time.Ticks
- };
+ // Generate the spike pattern for the first 4 bars of each day
+ switch (barOfDay)
+ {
+ case 0:
+ openValue = 0.000001 * scaleFactor;
+ closeValue = 0.05 * scaleFactor;
+ break;
+ case 1:
+ openValue = 0.05 * scaleFactor;
+ closeValue = 0.50 * scaleFactor;
+ break;
+ case 2:
+ openValue = 0.50 * scaleFactor;
+ closeValue = 0.05 * scaleFactor;
+ break;
+ case 3:
+ openValue = 0.05 * scaleFactor;
+ closeValue = 0.0000001 * scaleFactor;
+ break;
+ default:
+ // Outside of the spike period, use baseline value
+ openValue = closeValue = 0.000001;
+ break;
}
+ return new HistoryItemBar
+ {
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = openValue,
+ High = Math.Max(openValue, closeValue),
+ Low = Math.Min(openValue, closeValue),
+ Close = closeValue,
+ Volume = Math.Abs(closeValue - openValue),
+ Ticks = time.Add(slice).Ticks - time.Ticks
+ };
+ }
- private HistoryItemBar GenerateSineWave(DateTime time, TimeSpan slice)
- {
- // Ensure we're working with UTC time
- DateTime utcTime = time.ToUniversalTime();
- // Calculate the number of hours since the epoch
- double minutesSinceEpoch = (utcTime - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMinutes;
+ private HistoryItemBar GenerateSineWave(DateTime time, TimeSpan slice)
+ {
+ // Ensure we're working with UTC time
+ DateTime utcTime = time.ToUniversalTime();
- // Calculate the position within the 25-hour cycle
- double cyclePosition = minutesSinceEpoch % 1500;
+ // Calculate the number of hours since the epoch
+ double minutesSinceEpoch = (utcTime - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMinutes;
+ // Calculate the position within the 25-hour cycle
+ double cyclePosition = minutesSinceEpoch % 1500;
- // Calculate the sine wave values
- double frequency = 2 * Math.PI / 1500; // Complete cycle over 25 hours
- double value = 50 + 50 * Math.Sin(cyclePosition * frequency); // Oscillate between 0 and 100
- double nextValue = 50 + 50 * Math.Sin((cyclePosition + slice.TotalMinutes) * frequency);
- double factor = 0.6 * Math.Abs (nextValue - value);
+ // Calculate the sine wave values
+ double frequency = 2 * Math.PI / 1500; // Complete cycle over 25 hours
+ double value = 50 + 50 * Math.Sin(cyclePosition * frequency); // Oscillate between 0 and 100
+ double nextValue = 50 + 50 * Math.Sin((cyclePosition + slice.TotalMinutes) * frequency);
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = value,
+ double factor = 0.6 * Math.Abs(nextValue - value);
- High = Math.Max(value, nextValue)+factor,
- Low = Math.Min(value, nextValue)-factor,
+ return new HistoryItemBar
+ {
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = value,
- Close = nextValue,
- Volume = Math.Abs(nextValue - value) * 100, // Volume proportional to price change
- Ticks = time.Add(slice).Ticks - time.Ticks
- };
- }
+ High = Math.Max(value, nextValue) + factor,
+ Low = Math.Min(value, nextValue) - factor,
+ Close = nextValue,
+ Volume = Math.Abs(nextValue - value) * 100, // Volume proportional to price change
+ Ticks = time.Add(slice).Ticks - time.Ticks
+ };
+ }
- private HistoryItemBar GenerateSquareWave(DateTime time, TimeSpan slice)
- {
- // Ensure we're working with UTC time
- DateTime utcTime = time.ToUniversalTime();
- // Calculate the time within the day (in hours)
- double hoursInDay = utcTime.TimeOfDay.TotalHours;
+ private HistoryItemBar GenerateSquareWave(DateTime time, TimeSpan slice)
+ {
+ // Ensure we're working with UTC time
+ DateTime utcTime = time.ToUniversalTime();
- double openValue, closeValue;
+ // Calculate the time within the day (in hours)
+ double hoursInDay = utcTime.TimeOfDay.TotalHours;
- if (hoursInDay < 12)
- {
- // First half of the day
- openValue = 99;
- closeValue = 100;
- }
- else
- {
- // Second half of the day
- openValue = 1;
- closeValue = 0.0001;
- }
+ double openValue, closeValue;
- // Handle transition bars
- if (Math.Abs(hoursInDay - 12) < slice.TotalHours / 2)
- {
- // Transition from 100 to 0 at noon
- openValue = 100;
- closeValue = 0.0001;
- }
- else if (hoursInDay < slice.TotalHours / 2 || hoursInDay > 24 - slice.TotalHours / 2)
- {
- // Transition from 0 to 100 at midnight
- openValue = 0.0001;
- closeValue = 100;
- }
- else
- {
- // No action
- }
+ if (hoursInDay < 12)
+ {
+ // First half of the day
+ openValue = 99;
+ closeValue = 100;
+ }
+ else
+ {
+ // Second half of the day
+ openValue = 1;
+ closeValue = 0.0001;
+ }
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = openValue,
- High = Math.Max(openValue, closeValue),
- Low = Math.Min(openValue, closeValue),
- Close = closeValue,
- Volume = Math.Abs(closeValue - openValue),
- Ticks = time.Add(slice).Ticks - time.Ticks
- };
+ // Handle transition bars
+ if (Math.Abs(hoursInDay - 12) < slice.TotalHours / 2)
+ {
+ // Transition from 100 to 0 at noon
+ openValue = 100;
+ closeValue = 0.0001;
+ }
+ else if (hoursInDay < slice.TotalHours / 2 || hoursInDay > 24 - slice.TotalHours / 2)
+ {
+ // Transition from 0 to 100 at midnight
+ openValue = 0.0001;
+ closeValue = 100;
+ }
+ else
+ {
+ // No action
}
- private HistoryItemBar GenerateSawtoothWave(DateTime time, TimeSpan slice)
+ return new HistoryItemBar
{
- double hours = (time - DateTime.UnixEpoch).TotalHours;
- double period = 24; // 24-hour period
- double position = hours % period;
- double value = 200 * (position / period) - 100;
- double nextValue = 200 * ((position + slice.TotalHours) % period / period) - 100;
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = openValue,
+ High = Math.Max(openValue, closeValue),
+ Low = Math.Min(openValue, closeValue),
+ Close = closeValue,
+ Volume = Math.Abs(closeValue - openValue),
+ Ticks = time.Add(slice).Ticks - time.Ticks
+ };
+ }
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = value,
- High = Math.Max(value, nextValue),
- Low = Math.Min(value, nextValue),
- Close = nextValue,
- Volume = 100,
- Ticks = 100
- };
- }
+ private HistoryItemBar GenerateSawtoothWave(DateTime time, TimeSpan slice)
+ {
+ double hours = (time - DateTime.UnixEpoch).TotalHours;
+ double period = 24; // 24-hour period
+ double position = hours % period;
+ double value = 200 * (position / period) - 100;
+ double nextValue = 200 * ((position + slice.TotalHours) % period / period) - 100;
- private HistoryItemBar GenerateInverseSawtoothWave(DateTime time, TimeSpan slice)
+ return new HistoryItemBar
{
- double hours = (time - DateTime.UnixEpoch).TotalHours;
- double period = 24; // 24-hour period
- double position = hours % period;
- double value = 100 - (200 * (position / period));
- double nextValue = 100 - (200 * ((position + slice.TotalHours) % period / period));
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = value,
+ High = Math.Max(value, nextValue),
+ Low = Math.Min(value, nextValue),
+ Close = nextValue,
+ Volume = 100,
+ Ticks = 100
+ };
+ }
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = value,
- High = Math.Max(value, nextValue),
- Low = Math.Min(value, nextValue),
- Close = nextValue,
- Volume = 100,
- Ticks = 100
- };
- }
+ private HistoryItemBar GenerateInverseSawtoothWave(DateTime time, TimeSpan slice)
+ {
+ double hours = (time - DateTime.UnixEpoch).TotalHours;
+ double period = 24; // 24-hour period
+ double position = hours % period;
+ double value = 100 - (200 * (position / period));
+ double nextValue = 100 - (200 * ((position + slice.TotalHours) % period / period));
- private HistoryItemBar GeneratePulseWave(DateTime time, TimeSpan slice)
+ return new HistoryItemBar
{
- 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
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = value,
+ High = Math.Max(value, nextValue),
+ Low = Math.Min(value, nextValue),
+ Close = nextValue,
+ Volume = 100,
+ Ticks = 100
+ };
+ }
- 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 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
- private HistoryItemBar GenerateTriangleWave(DateTime time, TimeSpan slice)
+ return new HistoryItemBar
{
- double hours = (time - DateTime.UnixEpoch).TotalHours;
- double period = 24;
- double position = hours % period;
- double value = 200 * (Math.Abs(position / period - 0.5) - 0.25) * 100;
- double nextValue = 200 * (Math.Abs(((position + slice.TotalHours) % period) / period - 0.5) - 0.25) * 100;
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = value,
+ High = 100,
+ Low = -100,
+ Close = value,
+ Volume = 100,
+ Ticks = 100
+ };
+ }
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = value,
- High = Math.Max(value, nextValue),
- Low = Math.Min(value, nextValue),
- Close = nextValue,
- Volume = 100,
- Ticks = 100
- };
- }
+ private HistoryItemBar GenerateTriangleWave(DateTime time, TimeSpan slice)
+ {
+ double hours = (time - DateTime.UnixEpoch).TotalHours;
+ double period = 24;
+ double position = hours % period;
+ double value = 200 * (Math.Abs(position / period - 0.5) - 0.25) * 100;
+ double nextValue = 200 * (Math.Abs(((position + slice.TotalHours) % period) / period - 0.5) - 0.25) * 100;
- private HistoryItemBar GenerateSincWave(DateTime time, TimeSpan slice)
+ return new HistoryItemBar
{
- double minutes = (time - DateTime.UnixEpoch).TotalMinutes;
- double period = 1500.0; // 24-hour period
- double frequency = 2 * Math.PI / period; // Full cycle over 24 hours
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = value,
+ High = Math.Max(value, nextValue),
+ Low = Math.Min(value, nextValue),
+ Close = nextValue,
+ Volume = 100,
+ Ticks = 100
+ };
+ }
- // Adjust time to center the main peak at 12 hours
- double t = minutes % period - period / 2;
+ private HistoryItemBar GenerateSincWave(DateTime time, TimeSpan slice)
+ {
+ double minutes = (time - DateTime.UnixEpoch).TotalMinutes;
+ double period = 1500.0; // 24-hour period
+ double frequency = 2 * Math.PI / period; // Full cycle over 24 hours
- // Scale factor
- double scaleFactor = 7.0;
+ // Adjust time to center the main peak at 12 hours
+ double t = minutes % period - period / 2;
- // Calculate Sinc value
- double x = scaleFactor * frequency * t;
- double sincValue = x != 0 ? 100 * Math.Sin(x) / x : 100;
+ // Scale factor
+ double scaleFactor = 7.0;
- // Calculate next value
- double nextT = ((minutes + slice.TotalMinutes) % period) - period / 2;
- double nextX = scaleFactor * frequency * nextT;
- double nextSincValue = nextX != 0 ? 100 * Math.Sin(nextX) / nextX : 100;
+ // Calculate Sinc value
+ double x = scaleFactor * frequency * t;
+ double sincValue = x != 0 ? 100 * Math.Sin(x) / x : 100;
- // Ensure minimum value
- double minValue = 0.00001;
- sincValue = Math.Sign(sincValue) * Math.Max(Math.Abs(sincValue), minValue);
- nextSincValue = Math.Sign(nextSincValue) * Math.Max(Math.Abs(nextSincValue), minValue);
+ // Calculate next value
+ double nextT = ((minutes + slice.TotalMinutes) % period) - period / 2;
+ double nextX = scaleFactor * frequency * nextT;
+ double nextSincValue = nextX != 0 ? 100 * Math.Sin(nextX) / nextX : 100;
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = sincValue,
- High = Math.Max(sincValue, nextSincValue),
- Low = Math.Min(sincValue, nextSincValue),
- Close = nextSincValue,
- Volume = Math.Abs(nextSincValue - sincValue), // Volume as the change in value
- Ticks = slice.Ticks
- };
- }
+ // Ensure minimum value
+ double minValue = 0.00001;
+ sincValue = Math.Sign(sincValue) * Math.Max(Math.Abs(sincValue), minValue);
+ nextSincValue = Math.Sign(nextSincValue) * Math.Max(Math.Abs(nextSincValue), minValue);
- private HistoryItemBar GenerateGaussianPulse(DateTime time, TimeSpan slice)
+ return new HistoryItemBar
{
- double hours = (time - DateTime.UnixEpoch).TotalHours;
- double totalPeriod = 24.0; // 24-hour total cycle
- double pulsePeriod = 12.0; // 12-hour pulse duration
- double position = hours % totalPeriod;
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = sincValue,
+ High = Math.Max(sincValue, nextSincValue),
+ Low = Math.Min(sincValue, nextSincValue),
+ Close = nextSincValue,
+ Volume = Math.Abs(nextSincValue - sincValue), // Volume as the change in value
+ Ticks = slice.Ticks
+ };
+ }
- // Parameters for the Gaussian pulse
- double amplitude = 100.0; // Maximum amplitude
- double center = pulsePeriod / 2.0; // Center of the pulse (at 6 hours within the pulse period)
- double width = pulsePeriod / 6.0; // Width of the pulse (adjusts the spread)
+ private HistoryItemBar GenerateGaussianPulse(DateTime time, TimeSpan slice)
+ {
+ double hours = (time - DateTime.UnixEpoch).TotalHours;
+ double totalPeriod = 24.0; // 24-hour total cycle
+ double pulsePeriod = 12.0; // 12-hour pulse duration
+ double position = hours % totalPeriod;
- double baselineValue = 0.00001; // Value outside the pulse period
+ // Parameters for the Gaussian pulse
+ double amplitude = 100.0; // Maximum amplitude
+ double center = pulsePeriod / 2.0; // Center of the pulse (at 6 hours within the pulse period)
+ double width = pulsePeriod / 6.0; // Width of the pulse (adjusts the spread)
- // Calculate the Gaussian pulse value
- double value;
- if (position < pulsePeriod)
- {
- value = amplitude * Math.Exp(-Math.Pow(position - center, 2) / (2 * Math.Pow(width, 2))) + baselineValue;
- }
- else
- {
- value = baselineValue;
- }
+ double baselineValue = 0.00001; // Value outside the pulse period
- // Calculate the next value for the slice
- double nextPosition = (hours + slice.TotalHours) % totalPeriod;
- double nextValue;
- if (nextPosition < pulsePeriod)
- {
- nextValue = amplitude * Math.Exp(-Math.Pow(nextPosition - center, 2) / (2 * Math.Pow(width, 2))) + baselineValue;
- }
- else
- {
- nextValue = baselineValue;
- }
+ // Calculate the Gaussian pulse value
+ double value;
+ if (position < pulsePeriod)
+ {
+ value = amplitude * Math.Exp(-Math.Pow(position - center, 2) / (2 * Math.Pow(width, 2))) + baselineValue;
+ }
+ else
+ {
+ value = baselineValue;
+ }
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = value,
- High = Math.Max(value, nextValue),
- Low = Math.Min(value, nextValue),
- Close = nextValue,
- Volume = Math.Abs(nextValue - value), // Volume as the change in value
- Ticks = slice.Ticks
- };
+ // Calculate the next value for the slice
+ double nextPosition = (hours + slice.TotalHours) % totalPeriod;
+ double nextValue;
+ if (nextPosition < pulsePeriod)
+ {
+ nextValue = amplitude * Math.Exp(-Math.Pow(nextPosition - center, 2) / (2 * Math.Pow(width, 2))) + baselineValue;
+ }
+ else
+ {
+ nextValue = baselineValue;
}
- private HistoryItemBar GenerateFrequencySweep(DateTime time, TimeSpan slice)
+ return new HistoryItemBar
{
- double hours = (time - DateTime.UnixEpoch).TotalHours;
- double sweepPeriod = 48.0; // 48-hour period
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = value,
+ High = Math.Max(value, nextValue),
+ Low = Math.Min(value, nextValue),
+ Close = nextValue,
+ Volume = Math.Abs(nextValue - value), // Volume as the change in value
+ Ticks = slice.Ticks
+ };
+ }
- // Starting frequency (very low)
- double minFreq = Math.PI / 48.0;
+ private HistoryItemBar GenerateFrequencySweep(DateTime time, TimeSpan slice)
+ {
+ double hours = (time - DateTime.UnixEpoch).TotalHours;
+ double sweepPeriod = 48.0; // 48-hour period
- // Calculate the ending frequency to ensure continuity
- double maxFreq = Math.PI * 1.0 * Math.Exp(2 * Math.PI / sweepPeriod);
+ // Starting frequency (very low)
+ double minFreq = Math.PI / 48.0;
- // Calculate the exponential factor for frequency sweep
- double expFactor = Math.Log(maxFreq / minFreq) / sweepPeriod;
+ // Calculate the ending frequency to ensure continuity
+ double maxFreq = Math.PI * 1.0 * Math.Exp(2 * Math.PI / sweepPeriod);
- // Calculate the overall phase up to the current time
- double totalPhase = (minFreq / expFactor) * (Math.Exp(expFactor * (hours % sweepPeriod)) - 1);
+ // Calculate the exponential factor for frequency sweep
+ double expFactor = Math.Log(maxFreq / minFreq) / sweepPeriod;
- // Shift the phase to start the cycle at 100 (cosine-like behavior)
- totalPhase += Math.PI / 2;
+ // Calculate the overall phase up to the current time
+ double totalPhase = (minFreq / expFactor) * (Math.Exp(expFactor * (hours % sweepPeriod)) - 1);
- // Calculate the value of the signal at the current time
- double value = 100.0 * Math.Sin(totalPhase);
+ // Shift the phase to start the cycle at 100 (cosine-like behavior)
+ totalPhase += Math.PI / 2;
- // Calculate the value of the signal at the end of the slice
- double nextPhase = (minFreq / expFactor) * (Math.Exp(expFactor * ((hours + slice.TotalHours) % sweepPeriod)) - 1);
- nextPhase += Math.PI / 2; // Apply the same phase shift
- double nextValue = 100.0 * Math.Sin(nextPhase);
+ // Calculate the value of the signal at the current time
+ double value = 100.0 * Math.Sin(totalPhase);
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = value,
- High = Math.Max(value, nextValue),
- Low = Math.Min(value, nextValue),
- Close = nextValue,
- Volume = Math.Abs(nextValue - value), // Volume as the change in value
- Ticks = slice.Ticks
- };
- }
+ // Calculate the value of the signal at the end of the slice
+ double nextPhase = (minFreq / expFactor) * (Math.Exp(expFactor * ((hours + slice.TotalHours) % sweepPeriod)) - 1);
+ nextPhase += Math.PI / 2; // Apply the same phase shift
+ double nextValue = 100.0 * Math.Sin(nextPhase);
+
+ return new HistoryItemBar
+ {
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = value,
+ High = Math.Max(value, nextValue),
+ Low = Math.Min(value, nextValue),
+ Close = nextValue,
+ Volume = Math.Abs(nextValue - value), // Volume as the change in value
+ Ticks = slice.Ticks
+ };
+ }
#pragma warning disable S2245
- // NOSONAR
- readonly Random random = new Random();
+ // NOSONAR
+ readonly Random random = new Random();
#pragma warning restore S2245
- private double currentAmplitude = 100;
- private HistoryItemBar GenerateAMSignal(DateTime time, TimeSpan slice)
- {
- double hours = (time - DateTime.UnixEpoch).TotalHours;
- double period = 12.0;
- double frequency = 2 * Math.PI / period; // Frequency for a 5-hour period
+ private double currentAmplitude = 100;
+ private HistoryItemBar GenerateAMSignal(DateTime time, TimeSpan slice)
+ {
+ double hours = (time - DateTime.UnixEpoch).TotalHours;
+ double period = 12.0;
+ double frequency = 2 * Math.PI / period; // Frequency for a 5-hour period
- // Determine the start of the current 5-hour cycle
- double cycleStartTime = Math.Floor(hours / period) * period;
+ // Determine the start of the current 5-hour cycle
+ double cycleStartTime = Math.Floor(hours / period) * period;
- // Calculate the phase of the signal within the current 5-hour cycle
- double phase = frequency * (hours % period);
+ // Calculate the phase of the signal within the current 5-hour cycle
+ double phase = frequency * (hours % period);
- // If we're at the start of a new 5-hour cycle, generate a new amplitude
- if (hours % period == 0)
- {
- currentAmplitude = random.NextDouble() * 100;
- }
+ // If we're at the start of a new 5-hour cycle, generate a new amplitude
+ if (hours % period == 0)
+ {
+ currentAmplitude = random.NextDouble() * 100;
+ }
- // Calculate the value of the signal at the current time
- double value = currentAmplitude * Math.Sin(phase);
+ // Calculate the value of the signal at the current time
+ double value = currentAmplitude * Math.Sin(phase);
- // Calculate the value of the signal at the end of the slice
- double nextPhase = frequency * ((hours + slice.TotalHours) % period);
- double nextValue = currentAmplitude * Math.Sin(nextPhase);
+ // Calculate the value of the signal at the end of the slice
+ double nextPhase = frequency * ((hours + slice.TotalHours) % period);
+ double nextValue = currentAmplitude * Math.Sin(nextPhase);
- // Create the HistoryItemBar
- var historyItem = new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = value,
- High = Math.Max(value, nextValue),
- Low = Math.Min(value, nextValue),
- Close = nextValue, // Set Close to the newly calculated value
- Volume = Math.Abs(nextValue), // Volume as the change in value
- Ticks = slice.Ticks
- };
+ // Create the HistoryItemBar
+ var historyItem = new HistoryItemBar
+ {
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = value,
+ High = Math.Max(value, nextValue),
+ Low = Math.Min(value, nextValue),
+ Close = nextValue, // Set Close to the newly calculated value
+ Volume = Math.Abs(nextValue), // Volume as the change in value
+ Ticks = slice.Ticks
+ };
- return historyItem;
- }
+ return historyItem;
+ }
- private double currentFrequency = Math.PI / 220.0; // Initial frequency
- private double accumulatedPhase = 0;
- private double lastCloseValue = 0; // To store the last close value
+ private double currentFrequency = Math.PI / 220.0; // Initial frequency
+ private double accumulatedPhase = 0;
+ private double lastCloseValue = 0; // To store the last close value
- private HistoryItemBar GenerateFMSignal(DateTime time, TimeSpan slice)
- {
- double amplitude = 100.0; // Maximum amplitude
- double minFreq = Math.PI / 256.0;
- double maxFreq = Math.PI / 32.0;
+ private HistoryItemBar GenerateFMSignal(DateTime time, TimeSpan slice)
+ {
+ double amplitude = 100.0; // Maximum amplitude
+ double minFreq = Math.PI / 256.0;
+ double maxFreq = Math.PI / 32.0;
- // Randomly adjust the frequency
- double frequencyStep = (maxFreq - minFreq) * 0.2; // 20% of the frequency range
- currentFrequency += (random.NextDouble() - 0.5) * 2 * frequencyStep;
- currentFrequency = Math.Max(minFreq, Math.Min(maxFreq, currentFrequency)); // Clamp frequency
+ // Randomly adjust the frequency
+ double frequencyStep = (maxFreq - minFreq) * 0.2; // 20% of the frequency range
+ currentFrequency += (random.NextDouble() - 0.5) * 2 * frequencyStep;
+ currentFrequency = Math.Max(minFreq, Math.Min(maxFreq, currentFrequency)); // Clamp frequency
- // Calculate phase increment for this slice
- double phaseIncrement = currentFrequency * slice.TotalHours;
+ // Calculate phase increment for this slice
+ double phaseIncrement = currentFrequency * slice.TotalHours;
- // Calculate the open value (which is the last close value)
- double openValue = lastCloseValue;
+ // Calculate the open value (which is the last close value)
+ double openValue = lastCloseValue;
- // Calculate the close value
- accumulatedPhase += phaseIncrement;
- double closeValue = amplitude * Math.Sin(2 * Math.PI * accumulatedPhase);
+ // Calculate the close value
+ accumulatedPhase += phaseIncrement;
+ double closeValue = amplitude * Math.Sin(2 * Math.PI * accumulatedPhase);
- // Determine high and low values
- double midPhase = accumulatedPhase - (phaseIncrement / 2);
- double midValue = amplitude * Math.Sin(2 * Math.PI * midPhase);
- double highValue = Math.Max(Math.Max(openValue, closeValue), midValue);
- double lowValue = Math.Min(Math.Min(openValue, closeValue), midValue);
+ // Determine high and low values
+ double midPhase = accumulatedPhase - (phaseIncrement / 2);
+ double midValue = amplitude * Math.Sin(2 * Math.PI * midPhase);
+ double highValue = Math.Max(Math.Max(openValue, closeValue), midValue);
+ double lowValue = Math.Min(Math.Min(openValue, closeValue), midValue);
- // Store the close value for the next iteration
- lastCloseValue = closeValue;
+ // Store the close value for the next iteration
+ lastCloseValue = closeValue;
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = openValue,
- High = highValue,
- Low = lowValue,
- Close = closeValue,
- Volume = Math.Abs(closeValue - openValue), // Volume as the change in value
- Ticks = slice.Ticks
- };
- }
+ return new HistoryItemBar
+ {
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = openValue,
+ High = highValue,
+ Low = lowValue,
+ Close = closeValue,
+ Volume = Math.Abs(closeValue - openValue), // Volume as the change in value
+ Ticks = slice.Ticks
+ };
+ }
- private HistoryItemBar GenerateWhiteNoise(DateTime time, TimeSpan slice)
- {
- double volatility = 2;
- double meanReversionStrength = 0.1;
+ private HistoryItemBar GenerateWhiteNoise(DateTime time, TimeSpan slice)
+ {
+ double volatility = 2;
+ double meanReversionStrength = 0.1;
- double openNoise = random.NextDouble();
- double open = previousClose + volatility * openNoise + meanReversionStrength * (meanPrice - previousClose);
- double closeNoise = random.NextDouble();
- double close = open + volatility * closeNoise + meanReversionStrength * (meanPrice - open);
+ double openNoise = random.NextDouble();
+ double open = previousClose + volatility * openNoise + meanReversionStrength * (meanPrice - previousClose);
+ double closeNoise = random.NextDouble();
+ double close = open + volatility * closeNoise + meanReversionStrength * (meanPrice - open);
- // Determine High and Low
- double high = Math.Max(open, close);
- double low = Math.Min(open, close);
+ // Determine High and Low
+ double high = Math.Max(open, close);
+ double low = Math.Min(open, close);
- // Add variation to High and Low
- double highNoise = Math.Abs(random.NextDouble());
- high += volatility * highNoise;
+ // Add variation to High and Low
+ double highNoise = Math.Abs(random.NextDouble());
+ high += volatility * highNoise;
- double lowNoise = Math.Abs(random.NextDouble());
- low -= volatility * lowNoise;
+ double lowNoise = Math.Abs(random.NextDouble());
+ low -= volatility * lowNoise;
- double volume = Math.Abs(random.NextDouble()) * 1000 + 100;
+ double volume = Math.Abs(random.NextDouble()) * 1000 + 100;
- previousClose = close;
+ previousClose = close;
- // Create the HistoryItemBar
- var historyItem = new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = open,
- High = high,
- Low = low,
- Close = close,
- Volume = volume,
- Ticks = slice.Ticks
- };
+ // Create the HistoryItemBar
+ var historyItem = new HistoryItemBar
+ {
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = open,
+ High = high,
+ Low = low,
+ Close = close,
+ Volume = volume,
+ Ticks = slice.Ticks
+ };
- return historyItem;
- }
+ return historyItem;
+ }
-private double previousClose = 50;
-private const double meanPrice = 50;
+ private double previousClose = 50;
+ private const double meanPrice = 50;
-private HistoryItemBar GeneratePinkNoise(DateTime time, TimeSpan slice)
-{
- double volatility = 2;
- double meanReversionStrength = 0.1;
+ private HistoryItemBar GeneratePinkNoise(DateTime time, TimeSpan slice)
+ {
+ double volatility = 2;
+ double meanReversionStrength = 0.1;
- // Generate open price
- double openNoise = GeneratePinkNoiseValue();
- double open = previousClose + volatility * openNoise + meanReversionStrength * (meanPrice - previousClose);
+ // Generate open price
+ double openNoise = GeneratePinkNoiseValue();
+ double open = previousClose + volatility * openNoise + meanReversionStrength * (meanPrice - previousClose);
- // Generate close price
- double closeNoise = GeneratePinkNoiseValue();
- double close = open + volatility * closeNoise + meanReversionStrength * (meanPrice - open);
+ // Generate close price
+ double closeNoise = GeneratePinkNoiseValue();
+ double close = open + volatility * closeNoise + meanReversionStrength * (meanPrice - open);
- // Determine High and Low
- double high = Math.Max(open, close);
- double low = Math.Min(open, close);
+ // Determine High and Low
+ double high = Math.Max(open, close);
+ double low = Math.Min(open, close);
- // Add variation to High and Low
- double highNoise = Math.Abs(GeneratePinkNoiseValue());
- high += volatility * highNoise;
+ // Add variation to High and Low
+ double highNoise = Math.Abs(GeneratePinkNoiseValue());
+ high += volatility * highNoise;
- double lowNoise = Math.Abs(GeneratePinkNoiseValue());
- low -= volatility * lowNoise;
+ double lowNoise = Math.Abs(GeneratePinkNoiseValue());
+ low -= volatility * lowNoise;
- double volume = Math.Abs(GeneratePinkNoiseValue()) * 1000 + 100;
+ double volume = Math.Abs(GeneratePinkNoiseValue()) * 1000 + 100;
- // Update previous close for the next iteration
- previousClose = close;
+ // Update previous close for the next iteration
+ previousClose = close;
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = open,
- High = high,
- Low = low,
- Close = close,
- Volume = volume,
- Ticks = slice.Ticks
- };
-}
+ return new HistoryItemBar
+ {
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = open,
+ High = high,
+ Low = low,
+ Close = close,
+ Volume = volume,
+ Ticks = slice.Ticks
+ };
+ }
private const int NumOctaves = 6;
@@ -986,154 +990,153 @@ private double GeneratePinkNoiseValue()
-private double lastValue = 0;
+ private double lastValue = 0;
-private HistoryItemBar GenerateBrownNoise(DateTime time, TimeSpan slice)
-{
- double dt = slice.TotalDays / 365.0; // Time step in years
- double sigma = 25.0; // Annual volatility
+ private HistoryItemBar GenerateBrownNoise(DateTime time, TimeSpan slice)
+ {
+ double dt = slice.TotalDays / 365.0; // Time step in years
+ double sigma = 25.0; // Annual volatility
- double increment = GenerateGaussian(0, sigma * Math.Sqrt(dt));
- double open = lastValue * (1 + GenerateGaussian(0, 0.05));
- double close = open + increment;
+ double increment = GenerateGaussian(0, sigma * Math.Sqrt(dt));
+ double open = lastValue * (1 + GenerateGaussian(0, 0.05));
+ double close = open + increment;
- // Simulate intra-period high and low
- double high = Math.Max(open, close);
- high += high * Math.Abs(GenerateGaussian(0, 0.06));
- double low = Math.Min(open, close);
- low -= low * Math.Abs(GenerateGaussian(0, 0.06));
+ // Simulate intra-period high and low
+ double high = Math.Max(open, close);
+ high += high * Math.Abs(GenerateGaussian(0, 0.06));
+ double low = Math.Min(open, close);
+ low -= low * Math.Abs(GenerateGaussian(0, 0.06));
- lastValue = close;
+ lastValue = close;
- return new HistoryItemBar
+ return new HistoryItemBar
+ {
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = open,
+ High = high,
+ Low = low,
+ Close = close,
+ Volume = Math.Abs(close - open) * 1000, // Simplified volume calculation
+ Ticks = slice.Ticks
+ };
+ }
+ // Helper method to generate Gaussian distributed random numbers
+ private double GenerateGaussian(double mean, double stdDev)
{
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = open,
- High = high,
- Low = low,
- Close = close,
- Volume = Math.Abs(close - open) * 1000, // Simplified volume calculation
- Ticks = slice.Ticks
- };
-}
-// Helper method to generate Gaussian distributed random numbers
-private double GenerateGaussian(double mean, double stdDev)
-{
- double u1 = 1.0 - random.NextDouble(); // Uniform(0,1] random doubles
- double u2 = 1.0 - random.NextDouble();
- double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
- return mean + stdDev * randStdNormal;
-}
+ double u1 = 1.0 - random.NextDouble(); // Uniform(0,1] random doubles
+ double u2 = 1.0 - random.NextDouble();
+ double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
+ return mean + stdDev * randStdNormal;
+ }
-private double GBMLastClose = 100; // Starting price
-private double GBMMu = 0.05; // Annual drift
-private double GBMSigma = 0.2; // Annual volatility
+ private double GBMLastClose = 100; // Starting price
+ private double GBMMu = 0.05; // Annual drift
+ private double GBMSigma = 0.2; // Annual volatility
-private HistoryItemBar GenerateGBM(DateTime time, TimeSpan slice)
-{
- // Convert time slice to years
- double dt = slice.TotalDays / 365.0;
+ private HistoryItemBar GenerateGBM(DateTime time, TimeSpan slice)
+ {
+ // Convert time slice to years
+ double dt = slice.TotalDays / 365.0;
- // Generate a random normal variable for the main price movement
- double epsilon = GenerateGaussian(0, 1);
+ // Generate a random normal variable for the main price movement
+ double epsilon = GenerateGaussian(0, 1);
- // Calculate the price movement using GBM equation
- double drift = (GBMMu - 0.5 * GBMSigma * GBMSigma) * dt;
- double diffusion = GBMSigma * Math.Sqrt(dt) * epsilon;
- double returnValue = Math.Exp(drift + diffusion);
+ // Calculate the price movement using GBM equation
+ double drift = (GBMMu - 0.5 * GBMSigma * GBMSigma) * dt;
+ double diffusion = GBMSigma * Math.Sqrt(dt) * epsilon;
+ double returnValue = Math.Exp(drift + diffusion);
- // Add variability between previous close and current open
- double openVariability = GBMLastClose * GBMSigma * Math.Sqrt(dt) * GenerateGaussian(0, 1) * 0.1;
- double open = GBMLastClose + openVariability;
+ // Add variability between previous close and current open
+ double openVariability = GBMLastClose * GBMSigma * Math.Sqrt(dt) * GenerateGaussian(0, 1) * 0.1;
+ double open = GBMLastClose + openVariability;
- // Calculate new close price
- double close = open * returnValue;
+ // Calculate new close price
+ double close = open * returnValue;
- // Generate High and Low values
- double highLowRange = Math.Max(Math.Abs(close - open), GBMLastClose * GBMSigma * Math.Sqrt(dt) * Math.Abs(GenerateGaussian(0, 1)));
- double high = Math.Max(open, close) + highLowRange * 0.5;
- double low = Math.Min(open, close) - highLowRange * 0.5;
+ // Generate High and Low values
+ double highLowRange = Math.Max(Math.Abs(close - open), GBMLastClose * GBMSigma * Math.Sqrt(dt) * Math.Abs(GenerateGaussian(0, 1)));
+ double high = Math.Max(open, close) + highLowRange * 0.5;
+ double low = Math.Min(open, close) - highLowRange * 0.5;
- // Generate volume (you may want to adjust this based on your needs)
- double volume = Math.Max(100, 1000 * Math.Abs(close - open) + 500 * GenerateGaussian(0, 1));
+ // Generate volume (you may want to adjust this based on your needs)
+ double volume = Math.Max(100, 1000 * Math.Abs(close - open) + 500 * GenerateGaussian(0, 1));
- // Update last close for next iteration
- GBMLastClose = close;
+ // Update last close for next iteration
+ GBMLastClose = close;
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = open,
- High = high,
- Low = low,
- Close = close,
- Volume = volume,
- Ticks = slice.Ticks
- };
-}
-
- private double FBMLastClose = 100; // Starting price
- private double FBMHurst = 0.85; // Hurst parameter (0.5 < H < 1 for persistent fBm)
- private double FBMSigma = 0.25; // Volatility parameter
- private double FBMDrift = 0.001; // drift
-
- private HistoryItemBar GenerateFBM(DateTime time, TimeSpan slice)
+ return new HistoryItemBar
{
- double dt = Math.Pow(slice.TotalDays / 365.0, 0.5);
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = open,
+ High = high,
+ Low = low,
+ Close = close,
+ Volume = volume,
+ Ticks = slice.Ticks
+ };
+ }
- double epsilon = GenerateFractionalGaussianNoise(FBMHurst);
+ private double FBMLastClose = 100; // Starting price
+ private double FBMHurst = 0.85; // Hurst parameter (0.5 < H < 1 for persistent fBm)
+ private double FBMSigma = 0.25; // Volatility parameter
+ private double FBMDrift = 0.001; // drift
- double drift = FBMDrift * dt;
- double diffusion = FBMSigma * Math.Pow(dt, FBMHurst) * epsilon;
+ private HistoryItemBar GenerateFBM(DateTime time, TimeSpan slice)
+ {
+ double dt = Math.Pow(slice.TotalDays / 365.0, 0.5);
- double openVariability = FBMLastClose * FBMSigma * Math.Pow(dt, FBMHurst) * GenerateFractionalGaussianNoise(FBMHurst) * 0.1;
- double open = FBMLastClose + openVariability;
+ double epsilon = GenerateFractionalGaussianNoise(FBMHurst);
- double close = open * Math.Exp(drift + diffusion);
+ double drift = FBMDrift * dt;
+ double diffusion = FBMSigma * Math.Pow(dt, FBMHurst) * epsilon;
- double highLowRange = Math.Max(Math.Abs(close - open),
- FBMLastClose * FBMSigma * Math.Pow(dt, FBMHurst) * Math.Abs(GenerateFractionalGaussianNoise(FBMHurst)) * 2);
- double high = Math.Max(open, close) + highLowRange * 0.5;
- double low = Math.Min(open, close) - highLowRange * 0.5;
+ double openVariability = FBMLastClose * FBMSigma * Math.Pow(dt, FBMHurst) * GenerateFractionalGaussianNoise(FBMHurst) * 0.1;
+ double open = FBMLastClose + openVariability;
- double volume = Math.Max(100, 2000 * Math.Abs(close - open) +
- 1000 * Math.Abs(GenerateFractionalGaussianNoise(FBMHurst)));
+ double close = open * Math.Exp(drift + diffusion);
- FBMLastClose = close;
+ double highLowRange = Math.Max(Math.Abs(close - open),
+ FBMLastClose * FBMSigma * Math.Pow(dt, FBMHurst) * Math.Abs(GenerateFractionalGaussianNoise(FBMHurst)) * 2);
+ double high = Math.Max(open, close) + highLowRange * 0.5;
+ double low = Math.Min(open, close) - highLowRange * 0.5;
- return new HistoryItemBar
- {
- TicksLeft = time.Ticks,
- TicksRight = time.Add(slice).Ticks - 1,
- Open = open,
- High = high,
- Low = low,
- Close = close,
- Volume = volume,
- Ticks = slice.Ticks
- };
- }
+ double volume = Math.Max(100, 2000 * Math.Abs(close - open) +
+ 1000 * Math.Abs(GenerateFractionalGaussianNoise(FBMHurst)));
+
+ FBMLastClose = close;
- private double GenerateFractionalGaussianNoise(double hurst)
+ return new HistoryItemBar
{
- double sum = 0;
- int n = 1000; // Number of terms in the approximation
+ TicksLeft = time.Ticks,
+ TicksRight = time.Add(slice).Ticks - 1,
+ Open = open,
+ High = high,
+ Low = low,
+ Close = close,
+ Volume = volume,
+ Ticks = slice.Ticks
+ };
+ }
- for (int i = 1; i <= n; i++)
- {
- double ri = GenerateGaussian(0, 1);
- sum += (Math.Pow(i, hurst - 0.5) - Math.Pow(i - 1, hurst - 0.5)) * ri;
- }
+ private double GenerateFractionalGaussianNoise(double hurst)
+ {
+ double sum = 0;
+ int n = 1000; // Number of terms in the approximation
- return sum / Math.Sqrt(n);
+ for (int i = 1; i <= n; i++)
+ {
+ double ri = GenerateGaussian(0, 1);
+ sum += (Math.Pow(i, hurst - 0.5) - Math.Pow(i - 1, hurst - 0.5)) * ri;
}
+ return sum / Math.Sqrt(n);
+ }
- // Add other necessary overrides and implementations as needed
- }
-}
\ No newline at end of file
+
+ // Add other necessary overrides and implementations as needed
+}
diff --git a/Tests/test_Trady.cs b/Tests/test_Trady.cs
index ebf70c4e..44451a2a 100644
--- a/Tests/test_Trady.cs
+++ b/Tests/test_Trady.cs
@@ -2,7 +2,11 @@
using Trady.Analysis.Indicator;
using Trady.Core;
using Trady.Core.Infrastructure;
-using QuanTAlib;
+using System.Diagnostics.CodeAnalysis;
+
+namespace QuanTAlib;
+
+[SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")]
public class TradyTests
{
diff --git a/Tests/test_Tulip.cs b/Tests/test_Tulip.cs
index 174b4046..623f0595 100644
--- a/Tests/test_Tulip.cs
+++ b/Tests/test_Tulip.cs
@@ -1,7 +1,10 @@
using Xunit;
using Tulip;
-using QuanTAlib;
+using System.Diagnostics.CodeAnalysis;
+namespace QuanTAlib;
+
+[SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")]
public class TulipTests
{
private readonly TBarSeries bars;
@@ -71,10 +74,7 @@ public void EMA()
double QL_item = QL[i].Value;
double TU = arrout[0][i];
Assert.True(Math.Abs(TU - QL_item) <= range, $"Assertion failed at index {i} for period {period}: TU = {TU}, QL_item = {QL_item}, delta = {TU - QL_item}");
-
}
}
}
-
-
}
\ No newline at end of file
diff --git a/Tests/test_iTBar.cs b/Tests/test_iTBar.cs
index db5d70ae..3c8afe4a 100644
--- a/Tests/test_iTBar.cs
+++ b/Tests/test_iTBar.cs
@@ -1,58 +1,60 @@
using Xunit;
using System.Reflection;
+using System.Diagnostics.CodeAnalysis;
-namespace QuanTAlib
+namespace QuanTAlib;
+
+[SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")]
+
+public class BarIndicatorTests
{
- public class BarIndicatorTests
- {
- private readonly Random rnd;
- private const int SeriesLen = 1000;
- private const int Corrections = 100;
+ private readonly Random rnd;
+ private const int SeriesLen = 1000;
+ private const int Corrections = 100;
- public BarIndicatorTests()
- {
- rnd = new Random((int)DateTime.Now.Ticks);
- }
+ public BarIndicatorTests()
+ {
+ rnd = new Random((int)DateTime.Now.Ticks);
+ }
- private static readonly iTValue[] indicators = new iTValue[]
- {
+ private static readonly iTValue[] indicators = new iTValue[]
+ {
new Atr(period: 14),
- };
+ };
+
+ [Theory]
+ [MemberData(nameof(GetIndicators))]
+ public void IndicatorIsNew(iTValue indicator)
+ {
+ var indicator1 = indicator;
+ var indicator2 = indicator;
- [Theory]
- [MemberData(nameof(GetIndicators))]
- public void IndicatorIsNew(iTValue indicator)
+ MethodInfo calcMethod = indicator.GetType().GetMethod("Calc")!;
+ if (calcMethod == null)
{
- var indicator1 = indicator;
- var indicator2 = indicator;
+ throw new Exception($"Calc method not found for indicator type: {indicator.GetType().Name}");
+ }
- MethodInfo calcMethod = indicator.GetType().GetMethod("Calc")!;
- if (calcMethod == null)
- {
- throw new Exception($"Calc method not found for indicator type: {indicator.GetType().Name}");
- }
+ for (int i = 0; i < SeriesLen; i++)
+ {
+ TBar item1 = new(Time: DateTime.Now, Open: rnd.Next(-100, 100), High: rnd.Next(-100, 100), Low: rnd.Next(-100, 100), Close: rnd.Next(-100, 100), Volume: rnd.Next(-1000, 1000), IsNew: true);
+ calcMethod.Invoke(indicator1, new object[] { item1 });
- for (int i = 0; i < SeriesLen; i++)
+ for (int j = 0; j < Corrections; j++)
{
- TBar item1 = new(Time: DateTime.Now, Open: rnd.Next(-100, 100), High: rnd.Next(-100, 100), Low: rnd.Next(-100, 100), Close: rnd.Next(-100, 100), Volume: rnd.Next(-1000, 1000), IsNew: true);
+ item1 = new(Time: DateTime.Now, Open: rnd.Next(-100, 100), High: rnd.Next(-100, 100), Low: rnd.Next(-100, 100), Close: rnd.Next(-100, 100), Volume: rnd.Next(-1000, 1000), IsNew: false);
calcMethod.Invoke(indicator1, new object[] { item1 });
+ }
- for (int j = 0; j < Corrections; j++)
- {
- item1 = new(Time: DateTime.Now, Open: rnd.Next(-100, 100), High: rnd.Next(-100, 100), Low: rnd.Next(-100, 100), Close: rnd.Next(-100, 100), Volume: rnd.Next(-1000, 1000), IsNew: false);
- calcMethod.Invoke(indicator1, new object[] { item1 });
- }
-
- var item2 = new TBar (item1.Time, item1.Open, item1.High, item1.Low, item1.Close, item1.Volume , IsNew: true);
- calcMethod.Invoke(indicator2, new object[] { item2 });
+ var item2 = new TBar(item1.Time, item1.Open, item1.High, item1.Low, item1.Close, item1.Volume, IsNew: true);
+ calcMethod.Invoke(indicator2, new object[] { item2 });
- Assert.Equal(indicator1.Value, indicator2.Value);
- }
+ Assert.Equal(indicator1.Value, indicator2.Value);
}
+ }
- public static IEnumerable