Quant.Infra.Net is a .NET quantitative trading infrastructure library that lets you fetch data, run statistical analysis, execute trades, and send notifications with minimal code.
| Version | Date | Description |
|---|---|---|
| 1.0.0 | 2024-01-15 | Initial release with core features: data acquisition, statistical analysis, trade execution, and notifications |
| 1.1.0 | 2024-02-20 | Added support for Schwab broker integration and enhanced portfolio performance metrics |
| 1.2.0 | 2024-03-10 | Improved Python integration stability and added new statistical analysis methods |
| 1.3.0 | 2024-04-05 | Enhanced notification services with email templates and improved error handling |
| 1.4.0 | 2024-05-16 | Updated API integrations to handle recent broker changes, added comprehensive documentation |
| 1.5.0 | 2026-05-28 | Interactive Brokers (InterReact) full integration — order, market data, account management via TWS/Gateway; Charles Schwab full broker service — quotes, option chains, orders, positions; license changed to MIT; enhanced analysis service unit tests |
Website: https://www.alpha-wealth-lab.com/
| Challenge | How Pro Edition Solves It |
|---|---|
| Complex OAuth 2.0 authentication, high developer registration barrier | ✅ Full process guidance — Detailed registration guide + one-click authorization, automatic token refresh |
| Account, positions, quotes, option chains scattered across APIs | ✅ Unified Web UI Dashboard — All data in one place, no coding required |
| High development cost, lots of boilerplate code | ✅ Out-of-the-box — Configure 3 settings and run |
| Credential security concerns, no third-party trust | ✅ 100% self-hosted — Credentials stored on your machine only |
| Option data requires handling many technical details | ✅ Full option chain with Greeks — Delta, Gamma, Theta, Vega, Rho, IV, OI |
Try it now: https://www.alpha-wealth-lab.com/
When developing quantitative trading systems, you likely face these recurring problems:
| Problem | What this library provides |
|---|---|
| Stock / crypto data APIs are scattered with inconsistent formats | Unified ITraditionalFinanceSourceDataService and ICryptoSourceDataService with standardized OHLCV models |
| Pair trading requires ADF test, OLS regression, Z-Score, correlation | IAnalysisService provides ready-to-use methods in one line |
| Integrating Binance, Alpaca, etc. means rewriting boilerplate | IBinanceUsdFutureService, IUSEquityBrokerService unified abstractions |
| No notification pipeline after strategy runs | DingTalk IDingtalkService, WeChat IWeChatService, Email EmailService |
| CAGR, Sharpe, Calmar, max drawdown must be coded from scratch | StrategyPerformanceAnalyzer with all metrics built in |
| Timers and rolling windows rewritten every project | IntervalTrigger, RollingWindow<T> ready to use |
In short: stop reinventing the wheel — focus on your strategy.
- Data Acquisition — Download stock daily bars from Yahoo Finance, batch-download crypto klines from Binance, read local data from CSV/MySQL/MongoDB.
- Statistical Analysis — Correlation, ADF stationarity test, OLS regression, Z-Score, Shapiro-Wilk normality test, pair-trading spread calculation.
- Trade Execution — Binance futures spot/order/liquidate, Alpaca US equity order/liquidate, Charles Schwab US equity/options trading, Interactive Brokers via TWS/Gateway (InterReact), with Testnet/Paper/Live environment switching.
- Notifications — DingTalk bot, WeChat Work webhook, personal/commercial bulk email.
- Portfolio & Performance — Portfolio snapshots, equity curve charting, CAGR/Sharpe/Calmar/MaxDrawdown calculation.
- Utilities — Rolling window, interval trigger, resolution conversion, DataFrame I/O.
Note on Data Sources
The C# package
YahooFinanceApicannot keep up with Yahoo Finance's frequent API changes and often returns401 Unauthorized. The Pythonyfinancepackage is maintained more actively by a large community. This project usespythonnetto callyfinancefrom C# via a local Anaconda virtual environment.
dotnet new console -n MyQuantApp
cd MyQuantApp
dotnet add package Quant.Infra.Net
dotnet add package pythonnet
dotnet add package Microsoft.Extensions.DependencyInjectionOr use a ProjectReference when developing inside the repo:
<ProjectReference Include="..\Quant.Infra.Net\Quant.Infra.Net.csproj" />Why Python? The C# package
YahooFinanceApicannot keep up with Yahoo Finance's frequent API changes and often returns401 Unauthorized. The Pythonyfinancepackage is maintained more actively by a large community. This project usespythonnetto callyfinancefrom C# via a local Anaconda virtual environment.
conda create -n quant python=3.9 -y
conda activate quant
pip install yfinance- Note the environment path and Python DLL filename for the code:
# Windows example
Env path: D:\ProgramData\PythonVirtualEnvs\pair_trading
or C:\Users\<you>\miniconda3\envs\quant
Python DLL: python39.dll (for Python 3.9)
Set these two constants to match your environment:
private const string CondaEnvPath = @"D:\ProgramData\PythonVirtualEnvs\pair_trading";
private const string PythonDllName = "python39.dll";using Microsoft.Extensions.DependencyInjection;
using Python.Runtime;
using Quant.Infra.Net.Analysis.Service;
using Quant.Infra.Net.Shared.Model;
class Program
{
private const string CondaEnvPath = @"D:\ProgramData\PythonVirtualEnvs\pair_trading";
private const string PythonDllName = "python39.dll";
static async Task Main(string[] args)
{
// 1. Register services
var services = new ServiceCollection();
services.AddScoped<IAnalysisService, AnalysisService>();
var provider = services.BuildServiceProvider();
var analysis = provider.GetRequiredService<IAnalysisService>();
// 2. Download AAPL & MSFT via Python yfinance
var end = DateTime.UtcNow;
var start = end.AddYears(-1);
InitializePython();
Console.WriteLine("Downloading AAPL daily OHLCV via yfinance...");
var aaplClose = DownloadCloseViaYFinance("AAPL", start, end);
Console.WriteLine($"AAPL rows: {aaplClose.Count}");
Console.WriteLine("Downloading MSFT daily OHLCV via yfinance...");
var msftClose = DownloadCloseViaYFinance("MSFT", start, end);
Console.WriteLine($"MSFT rows: {msftClose.Count}");
// 3. Correlation
int minLen = Math.Min(aaplClose.Count, msftClose.Count);
aaplClose = aaplClose.Take(minLen).ToList();
msftClose = msftClose.Take(minLen).ToList();
double corr = analysis.CalculateCorrelation(aaplClose, msftClose);
Console.WriteLine($"AAPL vs MSFT correlation: {corr:F4}");
// 4. OLS regression
var (slope, intercept) = analysis.PerformOLSRegression(aaplClose, msftClose);
Console.WriteLine($"OLS regression: Slope={slope:F4}, Intercept={intercept:F4}");
// 5. ADF stationarity test
var spread = msftClose
.Zip(aaplClose, (m, a) => m - slope * a - intercept).ToList();
bool isStationary = analysis.AugmentedDickeyFullerTest(spread, adfTestStatisticThreshold: -2.86);
Console.WriteLine($"Spread ADF stationary: {isStationary}");
// 6. Z-Score
double zScore = analysis.CalculateZScores(spread, spread.Last());
Console.WriteLine($"Latest Z-Score: {zScore:F4}");
await Task.CompletedTask;
}
private static bool _pythonInitialized;
private static readonly object _initLock = new();
private static void InitializePython()
{
if (_pythonInitialized) return;
lock (_initLock)
{
if (_pythonInitialized) return;
var infra = PythonNetInfra.GetPythonInfra(CondaEnvPath, PythonDllName);
Runtime.PythonDLL = infra.PythonDLL;
PythonEngine.PythonHome = infra.PythonHome;
PythonEngine.PythonPath = infra.PythonPath;
PythonEngine.Initialize();
_pythonInitialized = true;
}
}
private static List<double> DownloadCloseViaYFinance(string symbol, DateTime start, DateTime end)
{
using (Py.GIL())
{
dynamic yf = Py.Import("yfinance");
string startStr = start.ToString("yyyy-MM-dd");
string endStr = end.ToString("yyyy-MM-dd");
dynamic df = yf.download(symbol, start: startStr, end: endStr, auto_adjust: true);
dynamic closeSeries = df.__getitem__("Close");
dynamic pyList = closeSeries.values.flatten().tolist();
var result = new List<double>();
foreach (dynamic item in pyList)
result.Add((double)item);
return result;
}
}
}Run:
dotnet runExpected output:
Downloading AAPL daily OHLCV via yfinance...
AAPL rows: 251
Downloading MSFT daily OHLCV via yfinance...
MSFT rows: 251
AAPL vs MSFT correlation: 0.9213
OLS regression: Slope=1.8472, Intercept=23.5610
Spread ADF stationary: True
Latest Z-Score: -0.3172
var dataService = provider.GetRequiredService<ITraditionalFinanceSourceDataService>();
var symbols = await dataService.GetSp500SymbolsAsync();
Console.WriteLine($"S&P 500 count: {symbols.Count()}");var futureService = provider.GetRequiredService<IBinanceUsdFutureService>();
futureService.ExchangeEnvironment = ExchangeEnvironment.Testnet;
decimal balance = await futureService.GetusdFutureAccountBalanceAsync();
Console.WriteLine($"Balance: {balance}");
await futureService.SetUsdFutureHoldingsAsync("BTCUSDT", 0.10, PositionSide.Long);
var positions = await futureService.GetHoldingPositionAsync();
Console.WriteLine($"Positions: {positions.Count()}");
await futureService.LiquidateUsdFutureAsync("BTCUSDT");var broker = provider.GetRequiredService<IUSEquityBrokerService>();
broker.ExchangeEnvironment = ExchangeEnvironment.Paper;
decimal equity = await broker.GetAccountEquityAsync();
Console.WriteLine($"Account equity: {equity}");
await broker.SetHoldingsAsync("AAPL", 0.05m);
await broker.LiquidateAsync("AAPL");var schwab = provider.GetRequiredService<ISchwabBrokerService>();
// Account summary
var account = await schwab.GetAccountAsync();
Console.WriteLine($"Equity: {account.TotalEquity}");
// Get stock quote
var quote = await schwab.GetQuoteAsync("AAPL");
Console.WriteLine($"AAPL: {quote.Last}");
// Get option chain
var chain = await schwab.GetOptionChainAsync("AAPL");
// Place market order
var orderId = await schwab.PlaceOrderAsync(new SchwabOrderRequest
{
Symbol = "AAPL", Side = "BUY", Quantity = 10
});
// Check open/close status
bool isOpen = await schwab.IsMarketOpenAsync();var dingtalk = provider.GetRequiredService<IDingtalkService>();
await dingtalk.SendNotificationAsync("Signal: Buy AAPL", accessToken, secret);
var wechat = provider.GetRequiredService<IWeChatService>();
await wechat.SendTextNotificationAsync("Order filled", webHookUrl);var analysis = provider.GetRequiredService<IAnalysisService>();
double corr = analysis.CalculateCorrelation(seriesA, seriesB);
var (slope, intercept) = analysis.PerformOLSRegression(seriesA, seriesB);
bool isStationary = analysis.AugmentedDickeyFullerTest(spread);
AdfTestResult adfResult = analysis.AugmentedDickeyFullerTestPython(spread);
double z = analysis.CalculateZScores(spread, currentValue);
bool isNormal = analysis.PerformShapiroWilkTest(spread);var window = new RollingWindow<double>(20);
window.Add(100.5);
window.Add(101.2);
if (window.IsReady)
Console.WriteLine($"Window full, count={window.Count}");
var trigger = new IntervalTrigger(StartMode.NextHour, TimeSpan.FromMinutes(-1));
trigger.IntervalTriggered += (sender, e) =>
{
Console.WriteLine($"Triggered at {DateTime.UtcNow}");
};
trigger.Start();double cagr = StrategyPerformanceAnalyzer.CalculateCAGR(marketValueDict);
double sharpe = StrategyPerformanceAnalyzer.CalculateSharpeRatio(marketValueDict, riskFreeRate);
double calmar = StrategyPerformanceAnalyzer.CalculateCalmarRatio(marketValueDict);
double maxDD = StrategyPerformanceAnalyzer.CalculateMaximumDrawdown(values);
Console.WriteLine($"CAGR={cagr:P2}, Sharpe={sharpe:F2}, Calmar={calmar:F2}, MaxDD={maxDD:P2}");cd src
dotnet restore
dotnet build
dotnet testRun a specific test class:
dotnet test --filter "FullyQualifiedName~AnalysisServiceTests"Quant.Infra.Net/
├── Analysis/ # Statistical analysis: ADF, OLS, correlation, Z-Score, pair trading
├── Broker/ # Broker integration: Binance, Alpaca, Schwab, InteractiveBrokers (InterReact)
├── Notification/ # Notifications: DingTalk, WeChat Work, Email
├── Order/ # Order models
├── Portfolio/ # Portfolio snapshots, performance analysis, equity curves
├── Shared/ # Common models, enums, RollingWindow, IntervalTrigger, UtilityService
└── SourceData/ # Data: Yahoo Finance, Binance, CSV, MySQL, MongoDB
- ADF Python mode:
AugmentedDickeyFullerTestPythonrequires a local Python environment withnumpy,pandas, andstatsmodels. If Python is not available, useAugmentedDickeyFullerTest(pure .NET implementation). - API Key configuration: Binance / Alpaca / Schwab live trading requires API Key and Secret in
appsettings.jsonor User Secrets. - Interactive Brokers: The InterReact integration connects to TWS or IB Gateway via local socket (port 7496 for TWS, 4001 for IB Gateway). Ensure TWS/Gateway is running with API enabled before using.
- ExchangeEnvironment: Supports
Testnet,Paper, andLive. Use Testnet or Paper during development. - Binance IP Restrictions: The Binance API restricts access from certain countries/regions. If you encounter connection errors when running Binance-related unit tests, this is not a code issue. Please refer to the Binance official documentation for the list of restricted regions.
- Compliance Disclaimer: This project provides quantitative trading infrastructure tools only and does not constitute investment advice. Users are solely responsible for ensuring compliance with all applicable laws, regulations, and exchange rules in their jurisdiction. The authors assume no liability for any legal or financial consequences arising from the use of this library.
Quant.Infra.Net will continue to maintain this public repository as the Community Edition (free / open-source). Existing open-source features will remain available here.
The Pro Edition is now officially live at https://www.alpha-wealth-lab.com/. It provides an out-of-the-box Charles Schwab integration experience:
- Web UI Dashboard — Account, positions, quotes, option chains in one place
- Web API (Swagger) — Full RESTful API for programmatic access
- Self-Hosted — 100% local, credentials never leave your machine
- Zero Configuration — Download, configure 3 settings, run
Pricing: See Pricing Page
Note: All existing Community Edition features remain free and will continue to be maintained. The Pro Edition is a separate product for those who need a ready-to-use Schwab integration.
See the Deployment Guide for details.
如果你是 Charles Schwab 用户,你可能正面临这些痛点:
| 痛点 | Pro Edition 如何解决 |
|---|---|
| OAuth 2.0 认证流程复杂,开发者注册门槛高 | ✅ 完整流程引导 — 详细注册指南 + 一键授权,自动处理 Token 刷新 |
| 账户、持仓、行情、期权数据分散在不同 API 端点 | ✅ 统一 Web UI 仪表盘 — 所有数据在一个界面查看,无需编程 |
| 自行开发成本高,需要大量胶水代码 | ✅ 开箱即用 — 配置 3 个参数即可运行 |
| 担心凭证安全,不愿上传到第三方云服务 | ✅ 100% 本地自托管 — 凭证仅保存在你的机器上 |
| 期权数据分析需要处理大量技术细节 | ✅ 完整期权链含希腊字母 — Delta、Gamma、Theta、Vega、Rho、IV、OI 一目了然 |
立即体验: https://www.alpha-wealth-lab.com/
在量化交易开发中,你可能反复遇到这些问题:
| 你遇到的问题 | 本库提供的方案 |
|---|---|
| 股票 / 加密货币数据接口分散、格式不统一 | 统一的 ITraditionalFinanceSourceDataService 和 ICryptoSourceDataService,标准化 OHLCV 模型 |
| 配对交易需要 ADF 检验、OLS 回归、Z-Score、相关性分析 | IAnalysisService 提供现成方法,一行代码调用 |
| 对接 Binance、Alpaca 等券商时重复造轮子 | IBinanceUsdFutureService、IUSEquityBrokerService 等统一抽象 |
| 策略运行后缺少通知链路 | 钉钉 IDingtalkService、企业微信 IWeChatService、邮件 EmailService |
| 评估 CAGR、Sharpe、Calmar、最大回撤要自己写 | StrategyPerformanceAnalyzer 内置全部指标 |
| 定时器、滚动窗口每次都重写 | IntervalTrigger、RollingWindow<T> 开箱即用 |
简而言之:不重复造轮子,专注策略本身。
- 数据获取 — 从 Yahoo Finance 下载股票日线,从 Binance 批量下载加密货币 K 线,从 CSV/MySQL/MongoDB 读取本地历史数据。
- 统计分析 — 相关性、ADF 平稳性检验、OLS 线性回归、Z-Score、Shapiro-Wilk 正态性检验、配对交易价差计算。
- 交易执行 — Binance 合约下单 / 清仓、Alpaca 美股下单 / 清仓,支持 Testnet / Paper / Live 环境切换。
- 通知推送 — 钉钉群机器人、企业微信 Webhook、个人邮箱 / 商业邮件批量发送。
- 组合与绩效 — 投资组合快照、净值曲线绘图、CAGR / Sharpe / Calmar / 最大回撤计算。
- 工具类 — 滚动窗口、定时触发器、分辨率转换、DataFrame 读写。
关于数据源的说明
C# 包
YahooFinanceApi的更新速度跟不上 Yahoo Finance API 的频繁变动,经常出现401 Unauthorized等错误。 Python 社区的yfinance包更新更快、更稳定。因此本项目通过pythonnet在 C# 中调用本地 Anaconda 虚拟环境中的yfinance来获取行情数据。
dotnet new console -n MyQuantApp
cd MyQuantApp
dotnet add package Quant.Infra.Net
dotnet add package pythonnet
dotnet add package Microsoft.Extensions.DependencyInjection如果你在仓库内开发,也可以用 ProjectReference:
<ProjectReference Include="..\Quant.Infra.Net\Quant.Infra.Net.csproj" />conda create -n quant python=3.9 -y
conda activate quant
pip install yfinance- 记录虚拟环境路径和 Python DLL 文件名,后续代码中需要用到:
# Windows 示例
环境路径: D:\ProgramData\PythonVirtualEnvs\pair_trading
或 C:\Users\<你的用户名>\miniconda3\envs\quant
Python DLL:python39.dll (对应 Python 3.9)
将以下两个常量修改为你的实际路径:
private const string CondaEnvPath = @"D:\ProgramData\PythonVirtualEnvs\pair_trading";
private const string PythonDllName = "python39.dll";using Microsoft.Extensions.DependencyInjection;
using Python.Runtime;
using Quant.Infra.Net.Analysis.Service;
using Quant.Infra.Net.Shared.Model;
class Program
{
private const string CondaEnvPath = @"D:\ProgramData\PythonVirtualEnvs\pair_trading";
private const string PythonDllName = "python39.dll";
static async Task Main(string[] args)
{
// 1. Register services
var services = new ServiceCollection();
services.AddScoped<IAnalysisService, AnalysisService>();
var provider = services.BuildServiceProvider();
var analysis = provider.GetRequiredService<IAnalysisService>();
// 2. Download AAPL & MSFT via Python yfinance
var end = DateTime.UtcNow;
var start = end.AddYears(-1);
InitializePython();
Console.WriteLine("Downloading AAPL daily OHLCV via yfinance...");
var aaplClose = DownloadCloseViaYFinance("AAPL", start, end);
Console.WriteLine($"AAPL rows: {aaplClose.Count}");
Console.WriteLine("Downloading MSFT daily OHLCV via yfinance...");
var msftClose = DownloadCloseViaYFinance("MSFT", start, end);
Console.WriteLine($"MSFT rows: {msftClose.Count}");
// 3. Correlation
int minLen = Math.Min(aaplClose.Count, msftClose.Count);
aaplClose = aaplClose.Take(minLen).ToList();
msftClose = msftClose.Take(minLen).ToList();
double corr = analysis.CalculateCorrelation(aaplClose, msftClose);
Console.WriteLine($"AAPL vs MSFT correlation: {corr:F4}");
// 4. OLS regression
var (slope, intercept) = analysis.PerformOLSRegression(aaplClose, msftClose);
Console.WriteLine($"OLS regression: Slope={slope:F4}, Intercept={intercept:F4}");
// 5. ADF stationarity test
var spread = msftClose
.Zip(aaplClose, (m, a) => m - slope * a - intercept).ToList();
bool isStationary = analysis.AugmentedDickeyFullerTest(spread, adfTestStatisticThreshold: -2.86);
Console.WriteLine($"Spread ADF stationary: {isStationary}");
// 6. Z-Score
double zScore = analysis.CalculateZScores(spread, spread.Last());
Console.WriteLine($"Latest Z-Score: {zScore:F4}");
await Task.CompletedTask;
}
private static bool _pythonInitialized;
private static readonly object _initLock = new();
private static void InitializePython()
{
if (_pythonInitialized) return;
lock (_initLock)
{
if (_pythonInitialized) return;
var infra = PythonNetInfra.GetPythonInfra(CondaEnvPath, PythonDllName);
Runtime.PythonDLL = infra.PythonDLL;
PythonEngine.PythonHome = infra.PythonHome;
PythonEngine.PythonPath = infra.PythonPath;
PythonEngine.Initialize();
_pythonInitialized = true;
}
}
private static List<double> DownloadCloseViaYFinance(string symbol, DateTime start, DateTime end)
{
using (Py.GIL())
{
dynamic yf = Py.Import("yfinance");
string startStr = start.ToString("yyyy-MM-dd");
string endStr = end.ToString("yyyy-MM-dd");
dynamic df = yf.download(symbol, start: startStr, end: endStr, auto_adjust: true);
dynamic closeSeries = df.__getitem__("Close");
dynamic pyList = closeSeries.values.flatten().tolist();
var result = new List<double>();
foreach (dynamic item in pyList)
result.Add((double)item);
return result;
}
}
}运行:
dotnet run预期输出示例:
Downloading AAPL daily OHLCV via yfinance...
AAPL rows: 251
Downloading MSFT daily OHLCV via yfinance...
MSFT rows: 251
AAPL vs MSFT correlation: 0.9213
OLS regression: Slope=1.8472, Intercept=23.5610
Spread ADF stationary: True
Latest Z-Score: -0.3172
var dataService = provider.GetRequiredService<ITraditionalFinanceSourceDataService>();
var symbols = await dataService.GetSp500SymbolsAsync();
Console.WriteLine($"S&P 500 成分股数量: {symbols.Count()}");var futureService = provider.GetRequiredService<IBinanceUsdFutureService>();
futureService.ExchangeEnvironment = ExchangeEnvironment.Testnet; // 先用测试网
// 查询余额
decimal balance = await futureService.GetusdFutureAccountBalanceAsync();
Console.WriteLine($"账户余额: {balance}");
// 按比例建仓
await futureService.SetUsdFutureHoldingsAsync("BTCUSDT", 0.10, PositionSide.Long);
// 查看持仓
var positions = await futureService.GetHoldingPositionAsync();
Console.WriteLine($"持仓数量: {positions.Count()}");
// 清仓
await futureService.LiquidateUsdFutureAsync("BTCUSDT");var broker = provider.GetRequiredService<IUSEquityBrokerService>();
broker.ExchangeEnvironment = ExchangeEnvironment.Paper; // 模拟盘
decimal equity = await broker.GetAccountEquityAsync();
Console.WriteLine($"账户权益: {equity}");
await broker.SetHoldingsAsync("AAPL", 0.05m); // 5% 仓位
await broker.LiquidateAsync("AAPL"); // 清仓var schwab = provider.GetRequiredService<ISchwabBrokerService>();
// 账户摘要
var account = await schwab.GetAccountAsync();
Console.WriteLine($"账户权益: {account.TotalEquity}");
// 获取报价
var quote = await schwab.GetQuoteAsync("AAPL");
Console.WriteLine($"AAPL: {quote.Last}");
// 获取期权链
var chain = await schwab.GetOptionChainAsync("AAPL");
// 下单
var orderId = await schwab.PlaceOrderAsync(new SchwabOrderRequest
{
Symbol = "AAPL", Side = "BUY", Quantity = 10
});
// 检查市场是否开盘
bool isOpen = await schwab.IsMarketOpenAsync();// 钉钉
var dingtalk = provider.GetRequiredService<IDingtalkService>();
await dingtalk.SendNotificationAsync("策略信号:买入 AAPL", accessToken, secret);
// 企业微信
var wechat = provider.GetRequiredService<IWeChatService>();
await wechat.SendTextNotificationAsync("订单已成交", webHookUrl);var analysis = provider.GetRequiredService<IAnalysisService>();
// 相关性
double corr = analysis.CalculateCorrelation(seriesA, seriesB);
// OLS 回归:diff = B - Slope * A - Intercept
var (slope, intercept) = analysis.PerformOLSRegression(seriesA, seriesB);
// ADF 平稳性检验(返回 bool)
bool isStationary = analysis.AugmentedDickeyFullerTest(spread);
// ADF 平稳性检验(返回详细结果,需要 Python 环境)
AdfTestResult adfResult = analysis.AugmentedDickeyFullerTestPython(spread);
// Z-Score
double z = analysis.CalculateZScores(spread, currentValue);
// Shapiro-Wilk 正态性检验
bool isNormal = analysis.PerformShapiroWilkTest(spread);// 滚动窗口:保持最近 20 根 K 线
var window = new RollingWindow<double>(20);
window.Add(100.5);
window.Add(101.2);
// ... 持续添加
if (window.IsReady)
{
Console.WriteLine($"窗口已满,共 {window.Count} 个元素");
}
// 定时触发器:每小时整点前 1 分钟触发
var trigger = new IntervalTrigger(StartMode.NextHour, TimeSpan.FromMinutes(-1));
trigger.IntervalTriggered += (sender, e) =>
{
Console.WriteLine($"触发! {DateTime.UtcNow}");
};
trigger.Start();// marketValueDict: Dictionary<DateTime, decimal> — 每日净值
double cagr = StrategyPerformanceAnalyzer.CalculateCAGR(marketValueDict);
double sharpe = StrategyPerformanceAnalyzer.CalculateSharpeRatio(marketValueDict, riskFreeRate);
double calmar = StrategyPerformanceAnalyzer.CalculateCalmarRatio(marketValueDict);
double maxDD = StrategyPerformanceAnalyzer.CalculateMaximumDrawdown(values);
Console.WriteLine($"CAGR={cagr:P2}, Sharpe={sharpe:F2}, Calmar={calmar:F2}, MaxDD={maxDD:P2}");cd src
dotnet restore
dotnet build
dotnet test运行指定测试类:
dotnet test --filter "FullyQualifiedName~AnalysisServiceTests"Quant.Infra.Net/
├── Analysis/ # 统计分析:ADF、OLS、相关性、Z-Score、配对交易
├── Broker/ # 券商接入:Binance、Alpaca、Schwab、InteractiveBrokers (InterReact)
├── Notification/ # 通知:钉钉、企业微信、邮件
├── Order/ # 订单模型
├── Portfolio/ # 投资组合快照、绩效分析、净值曲线
├── Shared/ # 公共模型、枚举、RollingWindow、IntervalTrigger、UtilityService
└── SourceData/ # 数据采集:Yahoo Finance、Binance、CSV、MySQL、MongoDB
- ADF Python 模式:
AugmentedDickeyFullerTestPython方法依赖本机 Python 环境,需安装numpy、pandas、statsmodels。如果没有 Python 环境,请使用AugmentedDickeyFullerTest(纯 .NET 实现)。 - API Key 配置:Binance / Alpaca / Schwab 等实盘接口需要在
appsettings.json或 User Secrets 中配置 API Key 和 Secret。 - Interactive Brokers:InterReact 集成通过本地 Socket 连接 TWS 或 IB Gateway(TWS 端口 7496,IB Gateway 端口 4001)。使用前需确保 TWS/Gateway 已启动并启用 API 连接。
- ExchangeEnvironment:支持
Testnet(测试网)、Paper(模拟盘)、Live(实盘)三种环境,建议开发阶段使用 Testnet 或 Paper。 - Binance IP 限制:Binance API 对部分国家/地区的 IP 存在访问限制,如果你在运行 Binance 相关单元测试时遇到连接错误,这并非代码问题,请查阅 Binance 官方文档 了解受限地区列表。
- 合规免责声明:本项目仅提供量化交易基础设施工具,不构成任何投资建议。用户需自行确保使用本库时符合所在国家/地区的法律法规及交易所合规要求,因使用本库产生的任何法律或财务后果由用户自行承担。
Quant.Infra.Net 将继续维护当前公开仓库作为 Community Edition(免费版 / 开源版),现有开源功能会继续保留在这里。Charles Schwab 和 Interactive Brokers(InterReact)的集成在 Community Edition 中仍然可用。
Pro Edition 现已正式上线,官网:https://www.alpha-wealth-lab.com/。它提供开箱即用的 Charles Schwab 集成体验:
- Web UI 仪表盘 — 账户总览、持仓列表、行情查询、期权链一站式查看
- Web API(Swagger) — 完整的 RESTful API,方便编程集成
- 100% 本地自托管 — 凭证仅保存在你的机器上,数据不上传任何第三方
- 零配置 — 下载解压、配置 3 个核心参数、运行即可
定价: 详见定价页面
温馨提示: 所有 Community Edition 功能保持免费,会继续维护和更新。Pro Edition 是独立产品,适合需要开箱即用 Schwab 对接的用户。
查看部署指南了解详情。
See LICENSE for details.
See DISCLAIMER for full disclaimer and limitation of liability / 详见 免责声明 了解完整免责条款与责任限制。