This commit is contained in:
Miha Kralj
2024-11-03 15:52:25 -08:00
parent 7b41d84c66
commit 7f6c29151c
7 changed files with 162 additions and 104 deletions
+22
View File
@@ -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
+125 -62
View File
@@ -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
@@ -69,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
@@ -76,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"
@@ -87,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 }}
@@ -109,7 +163,13 @@ jobs:
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
@@ -119,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
@@ -132,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@v2 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')) ||
@@ -203,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
@@ -227,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:
@@ -248,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: |
-19
View File
@@ -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)
{ {
+2 -2
View File
@@ -22,7 +22,7 @@ namespace QuanTAlib;
public class Dsma : AbstractBase public class Dsma : AbstractBase
{ {
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
@@ -59,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;
+1 -3
View File
@@ -53,7 +53,6 @@ public sealed class Cv : AbstractBase
private readonly double _omega; private readonly double _omega;
private double _prevClose; private double _prevClose;
private double _prevVariance; private double _prevVariance;
private double _longTermVariance;
private bool _isInitialized; private bool _isInitialized;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -82,7 +81,6 @@ public sealed class Cv : AbstractBase
base.Init(); base.Init();
_prevClose = 0; _prevClose = 0;
_prevVariance = 0; _prevVariance = 0;
_longTermVariance = 0;
_isInitialized = false; _isInitialized = false;
} }
@@ -116,7 +114,7 @@ public sealed class Cv : AbstractBase
// Initialize with first available data if not done // Initialize with first available data if not done
if (!_isInitialized && _index > _period) if (!_isInitialized && _index > _period)
{ {
_longTermVariance = squaredReturn; // Use current squared return as initial estimate double _longTermVariance = squaredReturn; // Use current squared return as initial estimate
_prevVariance = _longTermVariance; _prevVariance = _longTermVariance;
_isInitialized = true; _isInitialized = true;
} }
+3 -5
View File
@@ -41,7 +41,6 @@ namespace QuanTAlib;
public sealed class Cvi : AbstractBase public sealed class Cvi : AbstractBase
{ {
private readonly int _period; private readonly int _period;
private readonly int _smoothPeriod;
private readonly CircularBuffer _smoothed; private readonly CircularBuffer _smoothed;
private readonly double _alpha; private readonly double _alpha;
private double _ema; private double _ema;
@@ -50,10 +49,9 @@ public sealed class Cvi : AbstractBase
public Cvi(int period = 10, int smoothPeriod = 10) public Cvi(int period = 10, int smoothPeriod = 10)
{ {
_period = period; _period = period;
_smoothPeriod = smoothPeriod; _alpha = 2.0 / (smoothPeriod + 1);
_alpha = 2.0 / (_smoothPeriod + 1); WarmupPeriod = _period + smoothPeriod;
WarmupPeriod = _period + _smoothPeriod; Name = $"CVI({_period},{smoothPeriod})";
Name = $"CVI({_period},{_smoothPeriod})";
_smoothed = new CircularBuffer(_period); _smoothed = new CircularBuffer(_period);
Init(); Init();
} }
+9 -13
View File
@@ -42,7 +42,6 @@ namespace QuanTAlib;
[SkipLocalsInit] [SkipLocalsInit]
public sealed class Fcb : AbstractBase public sealed class Fcb : AbstractBase
{ {
private readonly int _period;
private readonly double _smoothing; private readonly double _smoothing;
private readonly CircularBuffer _highs; private readonly CircularBuffer _highs;
private readonly CircularBuffer _lows; private readonly CircularBuffer _lows;
@@ -56,11 +55,10 @@ public sealed class Fcb : AbstractBase
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Fcb(int period = 20, double smoothing = 0.5) public Fcb(int period = 20, double smoothing = 0.5)
{ {
_period = period;
_smoothing = smoothing; _smoothing = smoothing;
_alpha = 2.0 / (_period + 1); _alpha = 2.0 / (period + 1);
WarmupPeriod = period + 4; // Need extra periods for fractal identification WarmupPeriod = period + 4; // Need extra periods for fractal identification
Name = $"FCB({_period},{_smoothing})"; Name = $"FCB({period},{_smoothing})";
_highs = new CircularBuffer(period); _highs = new CircularBuffer(period);
_lows = new CircularBuffer(period); _lows = new CircularBuffer(period);
Init(); Init();
@@ -116,16 +114,14 @@ public sealed class Fcb : AbstractBase
bool isFractalHigh = false; bool isFractalHigh = false;
bool isFractalLow = false; bool isFractalLow = false;
if (_index >= 5) // Fractal high: current high is higher than 2 bars before and after
{ isFractalHigh = _highs[2] > _highs[0] && _highs[2] > _highs[1] &&
// Fractal high: current high is higher than 2 bars before and after _highs[2] > _highs[3] && _highs[2] > _highs[4];
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];
// 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 // Update EMAs with fractal points
if (isFractalHigh) if (isFractalHigh)