SIMD Refactor: Merge simd-dev into dev (#55)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: aider (openrouter/anthropic/claude-sonnet-4) <aider@aider.chat>
Co-authored-by: Warp <agent@warp.dev>
This commit is contained in:
Miha Kralj
2026-01-18 19:02:03 -08:00
committed by GitHub
parent 5bcdf8d614
commit 86fe32a682
1750 changed files with 198235 additions and 80539 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

+122 -122
View File
@@ -186,7 +186,7 @@
</member>
<member name="P:TradingPlatform.BusinessLayer.Chart.IChartWindow.YScaleFactor">
<summary>
</summary>
</member>
<member name="T:TradingPlatform.BusinessLayer.Chart.IChartWindowCoordinatesConverter">
@@ -764,12 +764,12 @@
</member>
<member name="P:TradingPlatform.BusinessLayer.Abstractions.IVwapHistoryItem.RangeIndex">
<summary>
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.Abstractions.IVwapHistoryItem.TimeLeft">
<summary>
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.Abstractions.IVwapHistoryItem.Value">
@@ -779,22 +779,22 @@
</member>
<member name="P:TradingPlatform.BusinessLayer.Abstractions.IVwapHistoryItem.STDCoefficient">
<summary>
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.Abstractions.IVwapHistoryItem.CumulativeVolume">
<summary>
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.Abstractions.IVwapHistoryItem.CumulativePriceMVolume">
<summary>
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.Abstractions.IVwapHistoryItem.MPDCoefficient">
<summary>
</summary>
</member>
<member name="T:TradingPlatform.BusinessLayer.Serialization.SnapshotData">
@@ -815,7 +815,7 @@
</member>
<member name="T:TradingPlatform.BusinessLayer.IVolumeAnalysisItem">
<summary>
Defines 'Volume Analysis' calculation result item
Defines 'Volume Analysis' calculation result item
</summary>
</member>
<member name="T:TradingPlatform.BusinessLayer.Account">
@@ -887,7 +887,7 @@
</member>
<member name="M:TradingPlatform.BusinessLayer.AccountOperation.Update(System.Collections.Generic.IList{TradingPlatform.BusinessLayer.SettingItem})">
<summary>
</summary>
<param name="settings">The settings.</param>
</member>
@@ -900,7 +900,7 @@
</member>
<member name="M:TradingPlatform.BusinessLayer.AccountOperation.Execute(System.Collections.Generic.IList{TradingPlatform.BusinessLayer.SettingItem})">
<summary>
</summary>
<param name="settings">The settings.</param>
</member>
@@ -1049,13 +1049,13 @@
</member>
<member name="M:TradingPlatform.BusinessLayer.AdditionalInfoItem.Update(TradingPlatform.BusinessLayer.AdditionalInfoItem)">
<summary>
</summary>
<param name="item">The item.</param>
</member>
<member name="M:TradingPlatform.BusinessLayer.AdditionalInfoItem.Clone">
<summary>
</summary>
<returns>An object.</returns>
</member>
@@ -1214,11 +1214,11 @@
<member name="M:TradingPlatform.BusinessLayer.SyntheticHistorySynhroniser.MoveNext(System.Threading.CancellationToken)">
<summary>
Increment current position
</summary>
</summary>
</member>
<member name="E:TradingPlatform.BusinessLayer.DeliveredAsset.Updated">
<summary>
Will be triggered on each <see cref="M:TradingPlatform.BusinessLayer.DeliveredAsset.UpdateByMessage(TradingPlatform.BusinessLayer.Integration.MessageOpenDeliveredAsset)"/> invocation
Will be triggered on each <see cref="M:TradingPlatform.BusinessLayer.DeliveredAsset.UpdateByMessage(TradingPlatform.BusinessLayer.Integration.MessageOpenDeliveredAsset)"/> invocation
</summary>
</member>
<member name="M:TradingPlatform.BusinessLayer.DeliveredAsset.UpdateByMessage(TradingPlatform.BusinessLayer.Integration.MessageOpenDeliveredAsset)">
@@ -1471,12 +1471,12 @@
</member>
<member name="F:TradingPlatform.BusinessLayer.Report.Columns">
<summary>
Columns collection
Columns collection
</summary>
</member>
<member name="F:TradingPlatform.BusinessLayer.Report.Rows">
<summary>
Rows collection
Rows collection
</summary>
</member>
<member name="M:TradingPlatform.BusinessLayer.Report.#ctor">
@@ -1566,7 +1566,7 @@
</member>
<member name="P:TradingPlatform.BusinessLayer.ReportType.Settings">
<summary>
<see cref="T:TradingPlatform.BusinessLayer.ICustomizable"/> report settings
<see cref="T:TradingPlatform.BusinessLayer.ICustomizable"/> report settings
</summary>
</member>
<member name="T:TradingPlatform.BusinessLayer.RulesManager">
@@ -3200,7 +3200,7 @@
</member>
<member name="P:TradingPlatform.BusinessLayer.HistoryItemTick.AskSize">
<summary>
Defines Ask size
Defines Ask size
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.HistoryItemTick.Item(TradingPlatform.BusinessLayer.PriceType)">
@@ -3574,12 +3574,12 @@
</member>
<member name="P:TradingPlatform.BusinessLayer.DayBar.OpenInterest">
<summary>
</summary>
</member>
<member name="T:TradingPlatform.BusinessLayer.DOMQuote">
<summary>
Represent access to DOM2 quote, which contains Bids and Asks.
Represent access to DOM2 quote, which contains Bids and Asks.
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.DOMQuote.Asks">
@@ -3619,7 +3619,7 @@
</member>
<member name="T:TradingPlatform.BusinessLayer.Level2Quote">
<summary>
Represent access to Level2 quote.
Represent access to Level2 quote.
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.Level2Quote.PriceType">
@@ -3807,7 +3807,7 @@
</member>
<member name="T:TradingPlatform.BusinessLayer.HVSheduleMode">
<summary>
</summary>
</member>
<member name="F:TradingPlatform.BusinessLayer.HVSheduleMode.HV">
@@ -4353,7 +4353,7 @@
</member>
<member name="P:TradingPlatform.BusinessLayer.Indicator.LinesLevels">
<summary>
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.Indicator.SeparateWindow">
@@ -4393,7 +4393,7 @@
</member>
<member name="M:TradingPlatform.BusinessLayer.Indicator.AddIndicator(TradingPlatform.BusinessLayer.Indicator)">
<summary>
</summary>
<param name="indicator"></param>
</member>
@@ -4614,7 +4614,7 @@
<member name="M:TradingPlatform.BusinessLayer.IndicatorLineMarker.#ctor">
<summary>
Constructor for IndicatorLineMarker
</summary>
</summary>
</member>
<member name="T:TradingPlatform.BusinessLayer.IndicatorLineMarkerIconType">
<summary>
@@ -4643,7 +4643,7 @@
</member>
<member name="M:TradingPlatform.BusinessLayer.LineSeries.GetMarker(System.Int32)">
<summary>
</summary>
</member>
<member name="M:TradingPlatform.BusinessLayer.LineSeries.ClearMarkers">
@@ -4830,7 +4830,7 @@
</member>
<member name="M:TradingPlatform.BusinessLayer.SubscribeQuotesParameters.#ctor(System.String,TradingPlatform.BusinessLayer.SubscribeQuoteType)">
<summary>
SubscribeQuotesParameters constructor
SubscribeQuotesParameters constructor
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.ModifyOrderRequestParameters.OrderId">
@@ -4880,7 +4880,7 @@
</member>
<member name="F:TradingPlatform.BusinessLayer.DatePickerFormat.LongDateTime">
<summary>
</summary>
</member>
<member name="T:TradingPlatform.BusinessLayer.SettingItemGroup">
@@ -5339,7 +5339,7 @@
</member>
<member name="M:TradingPlatform.BusinessLayer.Utils.AggressorFlagCalculator.Dispose">
<summary>
</summary>
</member>
<member name="M:TradingPlatform.BusinessLayer.Utils.AggressorFlagCalculator.CalculateAggressorFlag(System.Double,System.Double,System.Double)">
@@ -5568,17 +5568,17 @@
</member>
<member name="M:TradingPlatform.BusinessLayer.Utils.BufferedProcessor`1.Start">
<summary>
</summary>
</member>
<member name="M:TradingPlatform.BusinessLayer.Utils.BufferedProcessor`1.Stop">
<summary>
</summary>
</member>
<member name="M:TradingPlatform.BusinessLayer.Utils.BufferedProcessor`1.Push(`0)">
<summary>
</summary>
<param name="subject">The subject.</param>
</member>
@@ -5595,7 +5595,7 @@
</member>
<member name="M:TradingPlatform.BusinessLayer.Utils.TasksHolder`1.#ctor(System.Int32)">
<summary>
</summary>
</member>
<member name="P:TradingPlatform.BusinessLayer.Utils.TimeFrameConfig.DefaultAggregation">
@@ -5607,7 +5607,7 @@
<member name="M:TradingPlatform.BusinessLayer.Utils.HistoryStepsCalculator.AddMonths(System.DateTime,System.Int32)">
<summary>
https://stackoverflow.com/questions/3060381/datetime-addmonths-adding-only-month-not-days
Проблема:
(29 Feb).AddMonth(1) = 29 March
</summary>
@@ -5640,7 +5640,7 @@
<member name="M:TradingPlatform.BusinessLayer.IBrandingInformation.GetResourceNames">
<summary>
Get all available custom resources
</summary>
</summary>
</member>
<member name="M:TradingPlatform.BusinessLayer.IBrandingInformation.GetResource(System.String)">
<summary>
@@ -5650,7 +5650,7 @@
<member name="M:TradingPlatform.BusinessLayer.IBrandingInformation.IsItemHidden(System.String,System.String)">
<summary>
Check whether specified items was hidden by branding specification
</summary>
</summary>
<returns></returns>
</member>
<member name="T:TradingPlatform.BusinessLayer.AssemblyLoader">
@@ -5900,15 +5900,15 @@
using System;
using System.Text;
using PTLRuntime.NETScript;
namespace GlobalVariablesManager
{
public class GlobalVariablesManager : NETIndicator
{
List&lt;GlobalVariable&gt; global_List=new List&lt;GlobalVariable&gt;();
public override void Init()
{
{
if(GlobalVariablesManager.Count()>0)
{
global_List=GlobalVariablesManager.GetGlobalVariablesList();
@@ -5935,14 +5935,14 @@
using System;
using System.Text;
using PTLRuntime.NETScript;
namespace GlobalVariablesManager
{
public class GlobalVariablesManager : NETIndicator
{
List&lt;GlobalVariable&gt; global_List=new List&lt;GlobalVariable&gt;();
public override void Init()
{
{
if(GlobalVariablesManager.Count()>0)
{
global_List=GlobalVariablesManager.GetGlobalVariablesList();
@@ -5969,14 +5969,14 @@
using System;
using System.Text;
using PTLRuntime.NETScript;
namespace GlobalVariablesManager
{
public class GlobalVariablesManager : NETIndicator
{
List&lt;GlobalVariable&gt; global_List=new List&lt;GlobalVariable&gt;();
public override void Init()
{
{
if(GlobalVariablesManager.Count()>0)
{
global_List=GlobalVariablesManager.GetGlobalVariablesList();
@@ -5984,7 +5984,7 @@
{
//Simplified way to retrieve global variable value
el.GlobalVariable("new_global_variable_period", period)
//However, to obtain certain variable, which belongs to indicator/strategy and to avoid unexpected erasing of data the best practice is to provide to a key holder multiple details such as name, params, hashed password etc. Follow SetValue() example.
}
}
@@ -5999,7 +5999,7 @@
</member>
<member name="M:TradingPlatform.BusinessLayer.GlobalVariables.GlobalVariablesManager.SetValue(System.String,System.Object,TradingPlatform.BusinessLayer.GlobalVariables.VariableLifetime)">
<summary>
Sets variable value to a global storage
Sets variable value to a global storage
</summary>
<example>
<span id="Example 1">
@@ -6007,27 +6007,27 @@
using System;
using System.Text;
using PTLRuntime.NETScript;
namespace GlobalVariablesManager
{
public class GlobalVariablesManager : NETIndicator
{
GlobalVariablesManager(){
base.ProjectName = "GlobalVariablesManager";
base.Password=GetHashedPassword(ProjectName);
base.Password=GetHashedPassword(ProjectName);
}
[InputParameter("Period", 0, 1, 9999)]
public int period = 5;
public override void OnQuote()
{
//Simplified way to store a global variable
//Simplified way to store a global variable
GlobalVariablesManager.SetValue("global_variable_period", period, VariableLifetime.SaveSession);
//However, to indicate any variable belongs to certain indicator/strategy and to avoid unexpected erasing of data the best practice is to provide to a key holder multiple details such as name, params, hashed password etc.
GlobalVariablesManager.SetValue("global_variable_period" +Symbols.Current.Name+period+Password, period, VariableLifetime.SaveSession);
}
}
@@ -6049,17 +6049,17 @@
using System;
using System.Text;
using PTLRuntime.NETScript;
namespace GlobalVariablesManager
{
public class GlobalVariablesManager : NETIndicator
{
public override void Init()
{
//Simplified way to remove a global variable
{
//Simplified way to remove a global variable
GlobalVariablesManager.Remove("global_variable_period");
//However, to remove certain variable, which belongs to indicator/strategy and to avoid unexpected erasing of data the best practice is to provide to a key holder multiple details such as name, params, hashed password etc. Follow SetValue() example.
}
}
@@ -6079,13 +6079,13 @@
using System;
using System.Text;
using PTLRuntime.NETScript;
namespace GlobalVariablesManager
{
public class GlobalVariablesManager : NETIndicator
{
public override void Init()
{
{
if(GlobalVariablesManager.Count()>0)
{
Print("Your session obtains "+GlobalVariablesManager.Count()+" global variables");
@@ -6108,15 +6108,15 @@
using System;
using System.Text;
using PTLRuntime.NETScript;
namespace GlobalVariablesManager
{
public class GlobalVariablesManager : NETIndicator
{
public override void Init()
{
GlobalVariablesManager.RemoveAll();
{
GlobalVariablesManager.RemoveAll();
if(GlobalVariablesManager.Count()==0)
{
Print("Your session does not have any global variables");
@@ -6138,20 +6138,20 @@
using System;
using System.Text;
using PTLRuntime.NETScript;
namespace GlobalVariablesManager
{
public class GlobalVariablesManager : NETIndicator
{
{
public override void Init()
{
//Simplified way to check an existance of a global variable
{
//Simplified way to check an existance of a global variable
if(GlobalVariablesManager.Exists("global_variable_period"))
Print("Your session has this global variable");
else
GlobalVariablesManager.SetValue("global_variable_period");
GlobalVariablesManager.SetValue("global_variable_period");
//However, to obtain certain variable, which belongs to indicator/strategy and to avoid unexpected erasing of data the best practice is to provide to a key holder multiple details such as name, params, hashed password etc. Follow SetValue() example.
}
}
@@ -6172,19 +6172,19 @@
using System;
using System.Text;
using PTLRuntime.NETScript;
namespace GlobalVariablesManager
{
public class GlobalVariablesManager : NETIndicator
{
{
public override void Init()
{
{
//Simplified way to retrieve global variable value
if(GlobalVariablesManager.Exists("global_variable_period"))
//Always perform a type casting before assigning any variable from global storage
period = (int)GlobalVariablesManager.GetValue("global_variable_period");
period = (int)GlobalVariablesManager.GetValue("global_variable_period");
//However, to obtain certain variable, which belongs to indicator/strategy and to avoid unexpected erasing of data the best practice is to provide to a key holder multiple details such as name, params, hashed password etc. Follow SetValue() example.
}
}
@@ -6205,24 +6205,24 @@
using System;
using System.Text;
using PTLRuntime.NETScript;
namespace GlobalVariablesManager
{
public class GlobalVariablesManager : NETIndicator
{
{
public override void Init()
{
{
int new_period;
//Simplified way to retrieve global variable value
if(GlobalVariablesManager.TryGetValue("global_variable_period"))
Print("New variable is assigned from globals: " + new_period);
if(new_period==period)
Print("Matching, no need to re-assign globals: ");
Print("Matching, no need to re-assign globals: ");
else
GlobalVariablesManager.SetValue("global_variable_period", period, VariableLifetime.SaveSession);
GlobalVariablesManager.SetValue("global_variable_period", period, VariableLifetime.SaveSession);
//However, to obtain certain variable, which belongs to indicator/strategy and to avoid unexpected erasing of data the best practice is to provide to a key holder multiple details such as name, params, hashed password etc. Follow SetValue() example.
}
}
@@ -6244,14 +6244,14 @@
using System;
using System.Text;
using PTLRuntime.NETScript;
namespace GlobalVariablesManager
{
public class GlobalVariablesManager : NETIndicator
{
Connection myConnection = Connection.CurrentConnection;
public override void OnQuote()
{
{
if(myConnection.Status==Disconnected)
GlobalVariablesManager.Flush();
}
@@ -6271,17 +6271,17 @@
using System;
using System.Text;
using PTLRuntime.NETScript;
namespace GlobalVariablesManager
{
public class GlobalVariablesManager : NETIndicator
{
List &lt;GlobalVariable&gt;global_List=new List&lt;GlobalVariable&gt;();
List &lt;GlobalVariable&gt;global_List=new List&lt;GlobalVariable&gt;();
public override void Init()
{
{
if(GlobalVariablesManager.Count()>0)
global_List=GlobalVariablesManager.GetGlobalVariablesList();
foreach (var el in global_List)
{
Print(el.Name);
@@ -6351,7 +6351,7 @@
</member>
<member name="M:TradingPlatform.BusinessLayer.loc.OnLocaleChanged">
<summary>
</summary>
</member>
<member name="M:TradingPlatform.BusinessLayer.loc.key(System.String)">
@@ -6364,24 +6364,24 @@
<member name="M:TradingPlatform.BusinessLayer.loc.IsHidden(System.String,System.String,System.String)">
<summary>
Check, whether current translation equal to hidden
</summary>
</summary>
</member>
<member name="M:TradingPlatform.BusinessLayer.loc.UnRegisterPlugin(System.String)">
<summary>
</summary>
<param name="pluginName"></param>
</member>
<member name="M:TradingPlatform.BusinessLayer.loc.RegisterPlugin(System.String,System.String)">
<summary>
</summary>
<param name="pluginName"></param>
<param name="location"></param>
</member>
<member name="M:TradingPlatform.BusinessLayer.loc.InitializeCoreLocalizer">
<summary>
</summary>
</member>
<member name="T:TradingPlatform.BusinessLayer.SymbolList">
@@ -6395,51 +6395,51 @@
http://www.codeguru.com/csharp/csharp/cs_date_time/timeroutines/article.php/c4207/C-SNTP-Client.htm
+++ добавлен диспозе, подправлен ToString(), убран лишний метод.
+++ ReceiveTimeoutбSendTimeout
NTPClient is a C# class designed to connect to time servers on the Internet.
The implementation of the protocol is based on the RFC 2030.
Public class members:
LeapIndicator - Warns of an impending leap second to be inserted/deleted in the last
minute of the current day. (See the _LeapIndicator enum)
VersionNumber - Version number of the protocol (3 or 4).
Mode - Returns mode. (See the _Mode enum)
Stratum - Stratum of the clock. (See the _Stratum enum)
PollInterval - Maximum interval between successive messages.
Precision - Precision of the clock.
RootDelay - Round trip time to the primary reference source.
RootDispersion - Nominal error relative to the primary reference source.
ReferenceTimestamp - The time at which the clock was last set or corrected.
OriginateTimestamp - The time at which the request departed the client for the server.
ReceiveTimestamp - The time at which the request arrived at the server.
Transmit Timestamp - The time at which the reply departed the server for client.
RoundTripDelay - The time between the departure of request and arrival of reply.
LocalClockOffset - The offset of the local clock relative to the primary reference
source.
Initialize - Sets up data structure and prepares for connection.
Connect - Connects to the time server and populates the data structure.
IsResponseValid - Returns true if received data is valid and if comes from
a NTP-compliant time server.
ToString - Returns a string representation of the object.
-----------------------------------------------------------------------------
Structure of the standard NTP header (as described in RFC 2030)
1 2 3
@@ -6477,9 +6477,9 @@
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-----------------------------------------------------------------------------
NTP Timestamp Format (as described in RFC 2030)
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@@ -6488,7 +6488,7 @@
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Seconds Fraction (0-padded) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
</summary>
</member>
<member name="M:TradingPlatform.BusinessLayer.TimeSync.NTPClient.Connect">
@@ -6573,12 +6573,12 @@
</member>
<member name="M:Platform.Utils.Encryptor.EncryptString(System.String)">
<summary>
</summary>
</member>
<member name="M:Platform.Utils.Encryptor.DecryptString(System.String)">
<summary>
</summary>
</member>
</members>
+242
View File
@@ -0,0 +1,242 @@
---
name: beast
description: Meticulous auto-agent for high-performance .NET library development with full MCP tool integration
tools:
- execute
- read
- edit
- search
- web
- codacy-mcp-server/*
- gitkraken/*
- github/*
- qdrant-mcp/*
- sequential-thinking-mcp/*
- tavily-mcp/*
- wolfram-mcp/*
- agent
- todo
---
# Role: Meticulous Auto-Agent
**Persona:** You are "Beast," a high-agency autonomous developer specialized in high-performance .NET development. You have full permission to use local shell commands, filesystem tools, and all available MCP servers.
## 🎯 Mission
Build and maintain QuanTAlib: a zero-allocation, SIMD-optimized C# quantitative analysis library. Every decision prioritizes correctness, performance, and mathematical rigor.
## 🧰 Available MCP Servers
### Core Development Tools
#### **fs** (Filesystem Operations)
- **Purpose:** Local filesystem access for reading, writing, and exploring the codebase
- **When to use:**
- Reading source files, tests, documentation
- Writing generated code, scripts, benchmarks
- Listing directory contents
- Exploring project structure
- Searching for patterns across files
- Getting file metadata (size, modified date, permissions)
- **Tools:**
- `read_file` - Read file contents (text or binary)
- `write_file` - Write/create files with content
- `list_directory` - List files and subdirectories
- `search_files` - Search file contents with patterns
- `get_file_info` - Get file metadata (size, dates, permissions)
- `move_file` - Move/rename files
- `create_directory` - Create new directories
- **Priority:** PRIMARY tool for ALL file operations
- **Root Path:** `C:\github` (configured scope)
- **Pattern:** Always use fs tools instead of shell commands for file operations
#### **sequential-thinking** (Planning & Decomposition)
- **Purpose:** Multi-step reasoning and complex problem solving
- **When to use:**
- Breaking down complex algorithmic challenges
- Planning multi-file refactors
- Analyzing trade-offs in design decisions
- Generating solution hypotheses and verifying them
- **Tool:** `sequentialthinking`
- **Pattern:** Use for any task requiring more than 3-4 logical steps
#### **tavily** (Web Search & Documentation)
- **Purpose:** Fresh API info, .NET updates, performance patterns
- **When to use:**
- Finding latest .NET 10/C# 13 features
- SIMD best practices and hardware intrinsics
- Trading library optimization patterns
- Current benchmarking methodologies
- **Tools:** `tavily-search`, `tavily-extract`, `tavily-crawl`, `tavily-map`
- **Priority:** Use AFTER ref-tools for .NET-specific queries
#### **ref-tools** (Documentation Search)
- **Purpose:** Official .NET docs, GitHub repos, private documentation
- **When to use:**
- .NET Runtime internals
- System.Runtime.Intrinsics APIs
- Vector<T> documentation
- SIMD intrinsics reference
- **Tools:** `ref_search_documentation`, `ref_read_url`
- **Priority:** PRIMARY source for .NET-specific information
#### **wolfram** (Mathematical Validation)
- **Purpose:** Math verification, algorithm correctness
- **When to use:**
- Validating complex formulas
- Verifying statistical calculations
- Checking mathematical properties (convergence, stability)
- Computing expected values for test validation
- **Tools:** `wolfram_query`
- **Modes:** `llm` (default), `full` (structured data), `short` (concise), `simple` (image)
### Quality & Memory Tools
#### **qdrant** (Persistent Memory)
- **Purpose:** Store and retrieve architectural decisions, patterns, benchmarks
- **When to use:**
- Storing performance benchmarks with context
- Recording architectural decisions and their rationale
- Saving validated patterns (SIMD, FMA, optimization techniques)
- Retrieving past solutions to similar problems
- **Tools:** `qdrant-find`, `qdrant-store`
- **Important:** Query FIRST before designing new patterns
- **Store Format:** `{decision, benchmark, pattern, src, date, tags: ["perf", "simd", "pattern-name"]}`
- **Never store:** API keys, secrets, or sensitive data
#### **codacy** (Code Quality Analysis)
- **Purpose:** Automated code quality checks and issue tracking
- **When to use:**
- Listing code quality issues in repositories
- Searching for security vulnerabilities (SRM items)
- Validating code patterns and tool configurations
- Checking organization and repository status
- **Tools:** `codacy_list_organizations`, `codacy_list_repository_issues`, `codacy_search_organization_srm_items`, `codacy_cli_analyze`
- **Pattern:** Use for pre-commit quality gates and security scans
## ⚙️ Standard Operating Procedure (SOP)
### Phase 1: Discovery & Context
1. **Query Memory:** Check `qdrant-find` for existing patterns, decisions, benchmarks
2. **Search Documentation:** Use `ref_search_documentation` for .NET/SIMD specifics
3. **Web Research:** Use `tavily-search` if ref-tools lacks current info
4. **Explore Codebase:** List files, read relevant sources
5. **Validate Math:** Use `wolfram_query` for complex formulas
### Phase 2: Planning
1. **Complex Tasks:** Use `sequentialthinking` to break down into steps
2. **Document Plan:** Create task_progress checklist
3. **Identify Dependencies:** Note which patterns/benchmarks to retrieve from qdrant
4. **Set Performance Targets:** Define throughput, allocation, complexity goals
### Phase 3: Implementation
1. **Read Existing Code:** Understand current patterns
2. **Apply Stored Patterns:** Retrieve and adapt from qdrant
3. **Optimize:** SIMD, FMA, stackalloc, aggressive inlining
4. **Validate:** Math correctness via wolfram, code quality via codacy
5. **Benchmark:** Measure performance, compare to baseline
### Phase 4: Verification & Storage
1. **Test All Modes:** Unit tests, validation tests, Quantower adapter tests
2. **Run Quality Checks:** `codacy_cli_analyze` for local validation
3. **Document Results:** Benchmark numbers with context
4. **Persist to Memory:** `qdrant-store` with tags for future retrieval
5. **Mark Superseded:** Tag old patterns as deprecated if improved
6. For local file discovery, prioritize the terminal tool using dir /s /b. Only use fs/list_directory if recursion is not needed.
## 📁 Temporary Workspace
**Location:** `temp/`
All temporary files, generated scripts, and intermediate artifacts must be stored in the `temp/` directory:
- **Scripts:** `temp/scripts/` - PowerShell (.ps1), Bash (.sh), Batch (.bat/.cmd)
- **Benchmarks:** `temp/benchmarks/` - Performance test results
- **Test Data:** `temp/testdata/` - Generated test datasets
- **Logs:** `temp/logs/` - Execution logs and diagnostic output
**Guidelines:**
- Use descriptive filenames with timestamps (e.g., `temp/scripts/benchmark_20260110_185530.ps1`)
- Create subdirectories as needed to organize content
- The temp directory is gitignored - never commit temporary files
- Clean up old temporary files when no longer needed
## 🔄 Tool Usage Patterns
### Research Pattern
```
1. qdrant-find: Check for existing solutions
2. ref_search_documentation: Official .NET docs
3. tavily-search: Current best practices
4. wolfram_query: Validate math
```
### Implementation Pattern
```
1. sequentialthinking: Plan the approach
2. Read files: Understand current code
3. qdrant-find: Retrieve applicable patterns
4. Implement: Write optimized code
5. codacy_cli_analyze: Local quality check
```
### Validation Pattern
```
1. Test: Run all test suites
2. Benchmark: Measure performance
3. wolfram_query: Verify mathematical correctness
4. codacy_list_repository_issues: Check quality gate
```
### Memory Pattern
```
1. Before: qdrant-find for context
2. After: qdrant-store with tags
- Tags: ["perf", "simd", "pattern-name", "indicator-category"]
- Include: benchmark results, decision rationale, source file
- Format: {decision, benchmark, pattern, src, date, tags}
```
## 🎯 Performance Priorities
1. **Zero Allocation:** No heap allocations in hot paths
2. **O(1) Streaming:** Constant time updates wherever possible
3. **SIMD:** Use AVX2/Vector<T> for batch operations
4. **FMA:** Use `Math.FusedMultiplyAdd` for `a*b+c` patterns
5. **Inlining:** `[MethodImpl(MethodImplOptions.AggressiveInlining)]`
6. **Stack:** `stackalloc` for small buffers, `Span<T>` everywhere
## 🚫 Forbidden Actions
- **DO NOT** use LINQ in hot paths
- **DO NOT** allocate in `Update` methods
- **DO NOT** ignore NaN/Infinity inputs
- **DO NOT** store secrets in qdrant
- **DO NOT** skip validation against external libraries
- **DO NOT** forget to query qdrant before designing new patterns
## 📊 Success Criteria
**Correct:** Math validated via wolfram, tests pass
**Fast:** Performance targets met, benchmarks prove it
🧠 **Clean:** Modern C# 13, self-documenting code
📦 **Zero-waste:** No allocations in hot paths
📊 **Verified:** Validated against TA-Lib/Skender/external libs
🧠 **Remembered:** Patterns stored in qdrant for future use
**Quality:** Codacy checks pass, no critical issues
## 🔧 Emergency Fallbacks
- **If MCP tool fails:** Use direct shell commands (you are pre-authorized)
- **If qdrant unavailable:** Proceed with implementation, store later
- **If ref-tools down:** Fall back to tavily-search
- **If validation lib missing:** Document and skip (but prefer not to skip)
---
**Remember:** You are autonomous. Use all tools at your disposal. Query qdrant FIRST, store results LAST. Validate everything. Ship nothing unoptimized.
+34
View File
@@ -0,0 +1,34 @@
#!/bin/bash
set -euo pipefail
# Codacy Coverage Upload for QuanTAlib
# Requires CODACY_PROJECT_TOKEN environment variable
if [[ -z "${CODACY_PROJECT_TOKEN:-}" ]]; then
echo "Error: CODACY_PROJECT_TOKEN environment variable not set"
exit 1
fi
echo "==> Building solution..."
dotnet build --no-incremental
echo "==> Running tests with coverage..."
dotnet test --no-build --collect:"XPlat Code Coverage" \
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover
# Find the coverage file
COVERAGE_FILE=$(find . -name "coverage.opencover.xml" -type f | head -1)
if [[ -z "$COVERAGE_FILE" ]]; then
echo "Error: No coverage file found"
exit 1
fi
echo "==> Uploading coverage to Codacy..."
echo " Coverage file: $COVERAGE_FILE"
bash <(curl -Ls https://coverage.codacy.com/get.sh) report \
-r "$COVERAGE_FILE" \
--project-token "$CODACY_PROJECT_TOKEN"
echo "==> Done! View results at https://app.codacy.com/gh/mihakralj/QuanTAlib"
-11
View File
@@ -4,19 +4,8 @@ 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
@@ -0,0 +1,79 @@
---
description: Configuration for AI behavior when interacting with Codacy's MCP Server
applyTo: '**'
---
---
# Codacy Rules
Configuration for AI behavior when interacting with Codacy's MCP Server
## using any tool that accepts the arguments: `provider`, `organization`, or `repository`
- ALWAYS use:
- provider: gh
- organization: mihakralj
- repository: QuanTAlib
- Avoid calling `git remote -v` unless really necessary
## CRITICAL: After ANY successful `edit_file` or `reapply` operation
- YOU MUST IMMEDIATELY run the `codacy_cli_analyze` tool from Codacy's MCP Server for each file that was edited, with:
- `rootPath`: set to the workspace path
- `file`: set to the path of the edited file
- `tool`: leave empty or unset
- If any issues are found in the new edits, propose and apply fixes for them.
- > NOTE: Failure to follow this rule is considered a critical error.
## When you tried to run the `codacy_cli_analyze` tool and the Codacy CLI is not installed
- Ask the user 'Codacy CLI is not installed. Would you like me to install it now?'
- If the user responds with "yes", run the `codacy_cli_install` tool and then continue with the original task
- If the user responds with "no", instruct the user that they can disable automatic analysis in the extension settings
- Wait for the user to respond before proceeding with any other actions
## After every response
- If you made any file edits in this conversation, verify you ran `codacy_cli_analyze` tool from Codacy's MCP Server
## When there are no Codacy MCP Server tools available, or the MCP Server is not reachable
- Suggest the user the following troubleshooting steps:
- Try to reset the MCP on the extension
- If the user is using VSCode, suggest them to review their Copilot > MCP settings in Github, under their organization or personal account. Refer them to Settings > Copilot > Enable MCP servers in Copilot. Suggested URL (https://github.com/settings/copilot/features) or https://github.com/organizations/{organization-name}/settings/copilot/features (This can only be done by their organization admins / owners)
- If none of the above steps work, suggest the user to contact Codacy support
## Trying to call a tool that needs a rootPath as a parameter
- Always use the standard, non-URL-encoded file system path
## CRITICAL: Dependencies and Security Checks
- IMMEDIATELY after ANY of these actions:
- Running npm/yarn/pnpm install
- Adding dependencies to package.json
- Adding requirements to requirements.txt
- Adding dependencies to pom.xml
- Adding dependencies to build.gradle
- Any other package manager operations
- You MUST run the `codacy_cli_analyze` tool with:
- `rootPath`: set to the workspace path
- `tool`: set to "trivy"
- `file`: leave empty or unset
- If any vulnerabilities are found because of the newly added packages:
- Stop all other operations
- Propose and apply fixes for the security issues
- Only continue with the original task after security issues are resolved
- EXAMPLE:
- After: npm install react-markdown
- Do: Run codacy_cli_analyze with trivy
- Before: Continuing with any other tasks
## General
- Repeat the relevant steps for each modified file.
- "Propose fixes" means to both suggest and, if possible, automatically apply the fixes.
- You MUST NOT wait for the user to ask for analysis or remind you to run the tool.
- Do not run `codacy_cli_analyze` looking for changes in duplicated code or code complexity metrics.
- Complexity metrics are different from complexity issues. When trying to fix complexity in a repository or file, focus on solving the complexity issues and ignore the complexity metric.
- Do not run `codacy_cli_analyze` looking for changes in code coverage.
- Do not try to manually install Codacy CLI using either brew, npm, npx, or any other package manager.
- If the Codacy CLI is not installed, just run the `codacy_cli_analyze` tool from Codacy's MCP Server.
- When calling `codacy_cli_analyze`, only send provider, organization and repository if the project is a git repository.
## Whenever a call to a Codacy tool that uses `repository` or `organization` as a parameter returns a 404 error
- Offer to run the `codacy_setup_repository` tool to add the repository to Codacy
- If the user accepts, run the `codacy_setup_repository` tool
- Do not ever try to run the `codacy_setup_repository` tool on your own
- After setup, immediately retry the action that failed (only retry once)
---
+453 -283
View File
@@ -1,342 +1,512 @@
name: Publish Workflow
name: Analysis Workflow
on:
push:
paths-ignore:
- '**.md'
- 'docs/**'
- '.gitignore'
- 'LICENSE'
- "**/*.md"
- "**/*.pine"
- "docs/**"
- ".gitignore"
- "LICENSE"
pull_request:
paths-ignore:
- '**.md'
- 'docs/**'
- '.gitignore'
- 'LICENSE'
- "**/*.md"
- "**/*.pine"
- "docs/**"
- ".gitignore"
- "LICENSE"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
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
permissions: {}
defaults:
run:
shell: bash
env:
DOTNET_VERSION: '8.x'
DOTNET_VERSION: "10.x"
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
# IMPORTANT: analyze the same commit we report to Codacy
CHECKOUT_REF: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
COMMIT_UUID: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
jobs:
Code_Coverage:
timeout-minutes: 30
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ 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
uses: actions/setup-java@v4
with:
java-version: 17
distribution: 'zulu'
- name: Cache SonarCloud scanner
id: cache-sonar-scanner
uses: actions/cache@v4
with:
path: .\.sonar\scanner
key: ${{ runner.os }}-sonar-scanner
restore-keys: ${{ runner.os }}-sonar-scanner
- 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: Begin SonarCloud Analysis
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
shell: powershell
run: |
dotnet sonarscanner begin /k:"mihakralj_QuanTAlib" /o:"mihakralj-quantalib" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" `
/d:sonar.solution.file="QuanTAlib.sln" `
/d:sonar.cs.opencover.reportsPaths="**/*cover*.xml" `
/d:sonar.cs.dotcover.reportsPaths="**/dotcover.xml" `
/d:sonar.coverage.exclusions="**Tests.cs,**/*.md,**/*.html,**/*.css,**/docs/**/*,**/archive/**/*,**/notebooks/**/*,**/obj/**/*,**/bin/**/*" `
/d:sonar.exclusions="**/TestResults/**/*,**/bin/**/*,**/obj/**/*,**/*.html,**/coverage/**/*,**/CoverageReport/**/*,**/*.md,**/*.css,**/docs/**/*,**/archive/**/*,**/notebooks/**/*" `
/d:sonar.test.exclusions="**Tests.cs,**/obj/**/*,**/bin/**/*" `
/d:sonar.cpd.exclusions="**Tests.cs" `
/d:sonar.scanner.scanAll="false" `
/d:sonar.cs.roslyn.ignoreIssues="false" `
/d:sonar.issue.ignore.multicriteria="e1" `
/d:sonar.issue.ignore.multicriteria.e1.ruleKey="csharpsquid:S1944,csharpsquid:S2053,csharpsquid:S2222,csharpsquid:S2259,csharpsquid:S2583,csharpsquid:S2589,csharpsquid:S3329,csharpsquid:S3655,csharpsquid:S3900,csharpsquid:S3949,csharpsquid:S3966,csharpsquid:S4158,csharpsquid:S4347,csharpsquid:S5773,csharpsquid:S6781" `
/d:sonar.issue.ignore.multicriteria.e1.resourceKey="**/*.cs" `
/d:sonar.verbose="true"
- name: Build Projects
id: build
continue-on-error: true
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
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
id: tests
continue-on-error: true
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:./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
if: always()
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
shell: powershell
run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
- 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@v4
with:
files: 'cover*'
verbose: true
CodeQL:
timeout-minutes: 30
# ==============================================================================
# 1) ReSharper InspectCode -> SARIF artifact
# ==============================================================================
ReSharper_Analysis:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
security-events: write
actions: read
contents: read
actions: write
security-events: write
steps:
- name: Checkout repository
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ env.CHECKOUT_REF }}
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
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
uses: github/codeql-action/init@v3
with:
languages: 'csharp'
queries: security-and-quality
config-file: ./.github/codeql/codeql-config.yml
tools: linked
cache: true
cache-dependency-path: |
**/packages.lock.json
**/*.csproj
**/*.sln
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore --configuration Debug
- name: Prepare SARIF directory
run: mkdir -p .sarif
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
- name: Install JetBrains ReSharper GlobalTools
run: |
dotnet tool update --global JetBrains.ReSharper.GlobalTools || \
dotnet tool install --global JetBrains.ReSharper.GlobalTools
echo "$HOME/.dotnet/tools" >> "$GITHUB_PATH"
- name: Run ReSharper InspectCode (SARIF)
run: |
set +e
jb inspectcode QuanTAlib.sln \
--format=sarif \
--output=.sarif/resharper.sarif
rc=$?
set -e
# jb may return non-zero for findings/config; missing SARIF is the real failure signal
if [ ! -f ".sarif/resharper.sarif" ]; then
echo "ERROR: ReSharper SARIF not generated (exit code: $rc)"
exit 1
fi
echo "ReSharper SARIF generated (exit code: $rc)"
ls -lh .sarif/resharper.sarif
- name: Upload SARIF artifact
uses: actions/upload-artifact@v4
with:
output: results
upload: true
name: sarif-resharper
path: .sarif/resharper.sarif
retention-days: 7
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/dotnet@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
LD_PRELOAD: '' # Clear the LD_PRELOAD to avoid CodeQL conflicts
with:
args: |
--file=./lib/quantalib.csproj
--severity-threshold=low
--detection-depth=4
--package-manager=nuget
- name: Run Snyk on Solution
uses: snyk/actions/dotnet@master
if: always()
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
LD_PRELOAD: ''
with:
args: |
--file=QuanTAlib.sln
--all-projects
--detection-depth=4
- 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:
timeout-minutes: 20
needs: [Code_Coverage, CodeQL]
if: |
success() &&
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) ||
github.event_name == 'workflow_dispatch'
# ==============================================================================
# 2) Snyk Security Scan -> SARIF artifact
# ==============================================================================
Snyk_Scan:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
actions: write
security-events: write
steps:
- name: Checkout repository
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ env.CHECKOUT_REF }}
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
cache: true
cache-dependency-path: |
**/packages.lock.json
**/*.csproj
**/*.sln
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v0
with:
versionSpec: '6.x'
includePrerelease: true
- name: Install Snyk CLI
uses: snyk/actions/setup@806182742461562b67788a64410098c9d9b96adb
- name: Determine Version
id: gitversion
uses: gittools/actions/gitversion/execute@v0
with:
useConfigFile: true
updateAssemblyInfo: false
- name: Restore dependencies
run: dotnet restore
- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: ${{ runner.os }}-nuget-
- name: Prepare SARIF directory
run: mkdir -p .sarif
- name: Build projects
run: |
dotnet restore
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: Create or Update Development Release
if: github.ref == 'refs/heads/dev'
- name: Run Snyk Security Scan (SARIF)
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
run: |
gh release delete development --yes || true
gh release create development \
--title "Development Build" \
--notes "Latest development build from commit ${{ github.sha }}" \
--prerelease \
--target ${{ github.sha }} \
lib/bin/Release/QuanTAlib.dll \
quantower/Averages/bin/Release/Averages.dll \
quantower/Statistics/bin/Release/Statistics.dll \
quantower/Volatility/bin/Release/Volatility.dll \
SyntheticVendor/bin/Release/SyntheticVendor.dll
if [ -z "${SNYK_TOKEN:-}" ]; then
echo "SNYK_TOKEN not set. Skipping Snyk scan."
exit 0
fi
- name: Push prerelease package to myget.org
if: github.ref == 'refs/heads/dev'
continue-on-error: true
id: myget-push
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 }}
set +e
snyk test --all-projects --sarif-file-output=.sarif/snyk.sarif
rc=$?
set -e
- name: Create GitHub Release
if: github.ref == 'refs/heads/main'
# Snyk exit codes: 0 = no issues, 1 = issues found, >1 = error
if [ $rc -gt 1 ]; then
echo "ERROR: Snyk scan failed (exit code: $rc)"
exit $rc
fi
if [ ! -f ".sarif/snyk.sarif" ]; then
echo "ERROR: Snyk SARIF not generated"
exit 1
fi
echo "Snyk SARIF generated (exit code: $rc)"
ls -lh .sarif/snyk.sarif
- name: Upload SARIF artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: sarif-snyk
path: .sarif/snyk.sarif
retention-days: 7
if-no-files-found: warn
# ==============================================================================
# 3) Semgrep Security Scan -> SARIF artifact
# ==============================================================================
Semgrep_Scan:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
actions: write
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ env.CHECKOUT_REF }}
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Prepare SARIF directory
run: mkdir -p .sarif
- name: Run Semgrep (SARIF)
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
run: |
gh release create v${{ steps.gitversion.outputs.MajorMinorPatch }} \
--title "Release from commit ${{ steps.gitversion.outputs.MajorMinorPatch }}" \
--notes "Release notes for this version." \
quantower/Averages/bin/Release/Averages.dll \
quantower/Statistics/bin/Release/Statistics.dll \
quantower/Volatility/bin/Release/Volatility.dll \
SyntheticVendor/bin/Release/SyntheticVendor.dll
pip install --quiet semgrep
- name: Push release package to nuget.org
if: ${{ github.ref == 'refs/heads/main' }}
set +e
if [ -n "${SEMGREP_APP_TOKEN:-}" ]; then
echo "Running Semgrep with managed policies..."
semgrep ci --sarif --output=.sarif/semgrep.sarif
else
echo "Running Semgrep with OSS rules..."
semgrep scan \
--config=auto \
--sarif \
--output=.sarif/semgrep.sarif \
--exclude='**/bin/**' \
--exclude='**/obj/**' \
--exclude='**/*.Tests.cs' \
--exclude='**/Mocks/**' \
--exclude='**/perf/**' \
--exclude='**/quantower/**' \
.
fi
rc=$?
set -e
if [ -f ".sarif/semgrep.sarif" ]; then
echo "Semgrep SARIF generated (exit code: $rc):"
ls -lh .sarif/semgrep.sarif
else
echo "WARNING: Semgrep SARIF not generated"
fi
- name: Upload SARIF artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: sarif-semgrep
path: .sarif/semgrep.sarif
retention-days: 7
if-no-files-found: warn
# ==============================================================================
# 4) Build, Test, Coverage, SonarCloud & Roslyn SARIF
# ==============================================================================
Sonar_Analysis:
needs: [ReSharper_Analysis, Snyk_Scan, Semgrep_Scan]
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
actions: write
pull-requests: read
checks: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ env.CHECKOUT_REF }}
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
cache: true
cache-dependency-path: |
**/packages.lock.json
**/*.csproj
**/*.sln
- name: Set up JDK 17 (for SonarCloud)
uses: actions/setup-java@v4
with:
java-version: 17
distribution: zulu
- name: Install Tools
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 }}
dotnet tool install --global dotnet-reportgenerator-globaltool
dotnet tool install --global dotnet-sonarscanner
echo "$HOME/.dotnet/tools" >> "$GITHUB_PATH"
- name: Restore dependencies
run: dotnet restore
- name: Check for SonarCloud token
id: check_sonar
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
if [ -z "${SONAR_TOKEN:-}" ]; then
echo "SONAR_TOKEN not set. Skipping SonarCloud."
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Prepare SARIF directory
run: mkdir -p .sarif
- name: Download External SARIFs
uses: actions/download-artifact@v4
with:
pattern: sarif-*
path: .sarif
merge-multiple: true
- name: Build SARIF list for SonarCloud
run: |
# Keep SonarCloud focused on its native analyzers + security tools.
# Importing compiler/analyzer SARIF (Roslyn/JetBrains) tends to explode "External issues".
paths=()
for f in .sarif/snyk.sarif .sarif/semgrep.sarif; do
if [ -f "$f" ]; then
paths+=("$f")
fi
done
IFS=,
echo "SONAR_SARIF_PATHS=${paths[*]}" >> "$GITHUB_ENV"
- name: Begin SonarCloud Analysis
if: steps.check_sonar.outputs.skip != 'true'
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
args=(
"/k:mihakralj_QuanTAlib"
"/o:mihakralj-quantalib"
"/d:sonar.token=$SONAR_TOKEN"
"/d:sonar.host.url=https://sonarcloud.io"
"/d:sonar.cs.opencover.reportsPaths=TestResults/**/coverage.opencover.xml"
"/d:sonar.cs.vstest.reportsPaths=TestResults/**/*.trx"
"/d:sonar.coverage.exclusions=**Tests.cs,**/*.md,**/*.html,**/*.css,**/docs/**/*,**/archive/**/*,**/notebooks/**/*,**/obj/**/*,**/bin/**/*"
"/d:sonar.exclusions=**/TestResults/**/*,**/bin/**/*,**/obj/**/*,**/*.html,**/coverage/**/*,**/CoverageReport/**/*,**/*.md,**/*.css,**/docs/**/*,**/archive/**/*,**/notebooks/**/*"
"/d:sonar.test.exclusions=**Tests.cs,**/obj/**/*,**/bin/**/*"
"/d:sonar.scanner.scanAll=false"
)
if [ -n "${SONAR_SARIF_PATHS:-}" ]; then
args+=("/d:sonar.sarifReportPaths=$SONAR_SARIF_PATHS")
fi
dotnet sonarscanner begin "${args[@]}"
- name: Build Solution with Roslyn SARIF
run: |
dotnet build QuanTAlib.sln \
--no-restore \
--configuration Debug \
--nologo \
-m:1 \
-p:TreatWarningsAsErrors=false \
-p:ErrorLog="$(pwd)/.sarif/roslyn.sarif;version=2.1"
- name: Run Tests with Coverage
run: |
dotnet test QuanTAlib.sln \
--no-build \
--configuration Debug \
--collect:"XPlat Code Coverage;Format=opencover,cobertura,lcov" \
--results-directory ./TestResults \
--logger "trx;LogFileName=test_results.trx"
- name: Merge Coverage Reports
run: |
mkdir -p coverage-merged
reportgenerator \
"-reports:TestResults/**/coverage.opencover.xml;TestResults/**/coverage.cobertura.xml;TestResults/**/coverage.info" \
"-targetdir:coverage-merged" \
"-reporttypes:Cobertura;lcov"
echo "Merged coverage outputs:"
ls -la coverage-merged || true
if [ ! -f "coverage-merged/Cobertura.xml" ]; then
echo "ERROR: Cobertura.xml not generated (Codacy coverage will be missing)"
exit 1
fi
- name: End SonarCloud Analysis
if: steps.check_sonar.outputs.skip != 'true'
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: dotnet sonarscanner end /d:sonar.token="$SONAR_TOKEN"
- name: Upload Coverage Artifact
uses: actions/upload-artifact@v4
with:
name: coverage-reports
path: coverage-merged/
retention-days: 7
- name: Upload Roslyn SARIF Artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: sarif-roslyn
path: .sarif/roslyn.sarif
retention-days: 7
if-no-files-found: warn
# ==============================================================================
# 5) Codacy Upload (SARIF + Coverage)
# ==============================================================================
Codacy_Upload:
needs: [ReSharper_Analysis, Snyk_Scan, Semgrep_Scan, Sonar_Analysis]
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
actions: read
if: always()
steps:
- name: Check for Codacy token
id: check_token
env:
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
run: |
if [ -z "${CODACY_PROJECT_TOKEN:-}" ]; then
echo "CODACY_PROJECT_TOKEN not set. Skipping Codacy uploads."
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Download SARIF artifacts
if: steps.check_token.outputs.skip != 'true'
uses: actions/download-artifact@v4
with:
pattern: sarif-*
path: sarif
- name: Download Coverage Reports
if: steps.check_token.outputs.skip != 'true'
uses: actions/download-artifact@v4
with:
name: coverage-reports
path: coverage-merged
- name: List artifacts
if: steps.check_token.outputs.skip != 'true'
run: |
echo "SARIF files:"
find sarif -name "*.sarif" -type f -maxdepth 4 -print -exec ls -lh {} \; || true
echo ""
echo "Coverage files:"
ls -la coverage-merged || true
- name: Install Codacy CLI v2
if: steps.check_token.outputs.skip != 'true'
run: |
set -euo pipefail
# Install Codacy CLI using official bootstrap script
echo "Installing Codacy CLI v2..."
sudo curl -Ls https://raw.githubusercontent.com/codacy/codacy-cli-v2/main/codacy-cli.sh -o /usr/local/bin/codacy-cli
sudo chmod +x /usr/local/bin/codacy-cli
# Script will fetch binary if needed
codacy-cli version
- name: Upload SARIF files to Codacy
if: steps.check_token.outputs.skip != 'true'
env:
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
run: |
set -euo pipefail
shopt -s nullglob globstar
files=(sarif/**/*.sarif)
if [ ${#files[@]} -eq 0 ]; then
echo "No SARIF files found. Nothing to upload."
exit 0
fi
echo "Uploading ${#files[@]} SARIF file(s) to Codacy with commit: ${COMMIT_UUID}"
for sarif_file in "${files[@]}"; do
echo "--- Uploading: $sarif_file ---"
# Using short flags per codacy-cli-v2 docs:
# -s: SARIF file path
# -c: commit UUID
# -t: project token
codacy-cli upload \
-s "$sarif_file" \
-c "$COMMIT_UUID" \
-t "$CODACY_PROJECT_TOKEN" \
|| echo "WARNING: failed to upload $sarif_file"
done
- name: Upload Coverage to Codacy
if: steps.check_token.outputs.skip != 'true'
env:
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
run: |
set -euo pipefail
curl -Ls https://coverage.codacy.com/get.sh -o codacy-coverage.sh
chmod +x codacy-coverage.sh
if [ -f "coverage-merged/Cobertura.xml" ]; then
./codacy-coverage.sh report -r "coverage-merged/Cobertura.xml"
else
echo "Cobertura.xml not found. Skipping coverage upload."
fi
+140
View File
@@ -0,0 +1,140 @@
name: Release Workflow
on:
workflow_dispatch:
# inputs:
# release_type:
# description: "Release type"
# type: choice
# options:
# - development
# - production
# default: development
permissions: {}
defaults:
run:
shell: bash
env:
DOTNET_VERSION: "10.x"
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
jobs:
# ==============================================================================
# Publish Package (manual trigger only)
# ==============================================================================
Publish_Package:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
cache: true
cache-dependency-path: |
**/packages.lock.json
**/*.csproj
**/*.sln
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v4.2.0
with:
versionSpec: "6.x"
includePrerelease: true
- name: Determine Version
id: gitversion
uses: gittools/actions/gitversion/execute@v4.2.0
with:
updateAssemblyInfo: false
- name: Restore dependencies
run: dotnet restore
- name: Build
run: |
dotnet build ./lib/quantalib.csproj --configuration Release --no-restore --nologo
dotnet build ./quantower/Momentum.csproj --configuration Release --no-restore --nologo
dotnet build ./quantower/Trends.csproj --configuration Release --no-restore --nologo
dotnet build ./quantower/Volume.csproj --configuration Release --no-restore --nologo
- name: Pack NuGet
run: |
dotnet pack ./lib/quantalib.csproj \
--configuration Release \
--no-build \
-p:ContinuousIntegrationBuild=true \
-p:PackageVersion=${{ steps.gitversion.outputs.SemVer }}
ls -lh lib/bin/Release/*.nupkg || true
- name: Create Development Release
if: inputs.release_type == 'development'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release delete development --yes 2>/dev/null || true
git push --delete origin refs/tags/development 2>/dev/null || true
gh release create development \
--title "Development Build" \
--notes "Latest development build from commit ${{ github.sha }}" \
--prerelease \
--target ${{ github.sha }} \
lib/bin/Release/*.nupkg \
lib/bin/Release/**/QuanTAlib.dll \
quantower/bin/Release/**/*.dll
- name: Push to MyGet
if: inputs.release_type == 'development'
continue-on-error: true
env:
MYGET_API_KEY: ${{ secrets.MYGET_DEPLOY_KEY_QUANTALIB }}
run: |
if [ -z "${MYGET_API_KEY:-}" ]; then
echo "MYGET_DEPLOY_KEY_QUANTALIB not set. Skipping."
exit 0
fi
dotnet nuget push 'lib/bin/Release/*.nupkg' \
--source https://www.myget.org/F/quantalib/api/v3/index.json \
--skip-duplicate \
--api-key "$MYGET_API_KEY"
- name: Create GitHub Release
if: inputs.release_type == 'production'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "v${{ steps.gitversion.outputs.MajorMinorPatch }}" \
--title "Release ${{ steps.gitversion.outputs.MajorMinorPatch }}" \
--generate-notes \
lib/bin/Release/*.nupkg \
quantower/bin/Release/**/*.dll
- name: Push to NuGet
if: inputs.release_type == 'production'
env:
NUGET_API_KEY: ${{ secrets.NUGET_DEPLOY_KEY_QUANTLIB }}
run: |
if [ -z "${NUGET_API_KEY:-}" ]; then
echo "NUGET_DEPLOY_KEY_QUANTLIB not set. Failing publish."
exit 1
fi
dotnet nuget push 'lib/bin/Release/*.nupkg' \
--source https://api.nuget.org/v3/index.json \
--skip-duplicate \
--api-key "$NUGET_API_KEY"
+54
View File
@@ -0,0 +1,54 @@
name: Deploy Docsify to GitHub Pages
on:
#push:
# branches: ["main"]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v5
with:
# Explicitly disable Jekyll
enabler_jekyll: false
- name: List files (Debug)
run: ls -R
- name: Ensure .nojekyll exists in root
run: |
if [ ! -f .nojekyll ]; then
echo "Creating .nojekyll file"
touch .nojekyll
else
echo ".nojekyll already exists"
fi
ls -la .nojekyll
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
# Upload entire repository so Docsify can access 'lib/' and other root files
path: '.'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4