This document defines the mandatory coding standards for the Quant.Infra.Net project. All contributors must adhere to these guidelines to ensure code quality, maintainability, and consistency.
- SOLID Principles
- XML Documentation Standards
- Parameter Validation
- Coding Language Standards
- Time Handling Standards
- Enum Management
- Network Resilience (Polly Retry)
- README Maintenance
- Sensitive Data Protection
- Code Review Checklist
All code must comply with SOLID design principles:
- Each class should have only one reason to change
- Methods should perform a single, well-defined task
- Example:
AnalysisServicehandles statistical analysis only, not data fetching
- Classes should be open for extension but closed for modification
- Use interfaces and abstract classes to enable extensibility
- Example:
IBrokerServiceinterface allows adding new brokers without modifying existing code
- Derived classes must be substitutable for their base classes
- Do not violate base class contracts in derived implementations
- Example: All broker implementations must honor the
ExchangeEnvironmentproperty contract
- Clients should not be forced to depend on interfaces they do not use
- Prefer multiple small, specific interfaces over large, general-purpose ones
- Example: Separate
IHistoricalDataSourceServiceandIRealtimeDataSourceServiceinstead of one monolithic interface
- High-level modules should not depend on low-level modules
- Depend on abstractions, not concretions
- Example: Services depend on
IConfigurationabstraction, not concrete configuration implementations
/// <summary>
/// 方法的中文描述。
/// English description of the method.
/// </summary>
/// <param name="paramName">参数的中文说明 / English parameter description.</param>
/// <returns>返回值的中文说明 / English return value description.</returns>
/// <exception cref="ArgumentException">当参数无效时抛出 / Thrown when parameter is invalid.</exception>Good:
/// <summary>
/// 计算两个时间序列的 Pearson 相关性。
/// Calculates the Pearson correlation between two time series.
/// </summary>
/// <param name="seriesA">时间序列A / Time series A.</param>
/// <param name="seriesB">时间序列B / Time series B.</param>
/// <returns>相关性系数 / The correlation coefficient.</returns>
/// <exception cref="ArgumentNullException">当参数为 null 时抛出 / Thrown when parameters are null.</exception>
public double CalculateCorrelation(IEnumerable<double> seriesA, IEnumerable<double> seriesB)Bad:
// Missing XML documentation
public double CalculateCorrelation(IEnumerable<double> seriesA, IEnumerable<double> seriesB)- Every
publicclass, interface, method, property, and field must have XML documentation - Both Chinese and English descriptions are mandatory
- Use consistent formatting: Chinese first, then English separated by "/"
- Document all parameters, return values, and exceptions
Null Checks:
if (param == null)
throw new ArgumentNullException(nameof(param));String Validation:
if (string.IsNullOrWhiteSpace(param))
throw new ArgumentException("Parameter must not be null or empty.", nameof(param));Range Validation:
if (param <= 0)
throw new ArgumentOutOfRangeException(nameof(param), "Parameter must be positive.");Date Validation:
if (startDt > endDt)
throw new ArgumentException("Start date must be earlier than or equal to end date.", nameof(startDt));public async Task<List<Ohlcv>> GetOhlcvListAsync(string symbol, DateTime startDt, DateTime endDt)
{
// Parameter validation - MUST be at the beginning
if (string.IsNullOrWhiteSpace(symbol))
throw new ArgumentException("Symbol must not be null or empty.", nameof(symbol));
if (startDt > endDt)
throw new ArgumentException("Start date must be earlier than or equal to end date.", nameof(startDt));
// Business logic follows...
}- All error messages must be in English to prevent encoding issues
- Include the parameter name using
nameof()operator - Be specific about what validation failed
Console.WriteLine()messages- Log messages (
Log.Information(),Log.Error(), etc.) - Exception messages
- User-facing strings
Good:
Console.WriteLine($"Window is full, total {window.Count} elements");
Log.Error("Download failed, please check network connection");
throw new InvalidOperationException("CoinMarketCap: Response missing status field.");Bad:
Console.WriteLine($"窗口已满,共 {window.Count} 个元素");
Log.Error("下载失败,请检查网络连接");
throw new InvalidOperationException("CoinMarketCap: 响应缺少 status 字段。");- Prevents character encoding issues (乱码)
- Ensures compatibility across different systems and locales
- Facilitates international collaboration
- Code comments should remain bilingual (Chinese + English) for better understanding by Chinese developers
Use DateTime.UtcNow:
var timestamp = DateTime.UtcNow; // ✅ Correct
var record = new Record { CreatedAt = DateTime.UtcNow };Avoid DateTime.Now:
var timestamp = DateTime.Now; // ❌ Wrong - uses local timeUnix Timestamp Calculation:
// Correct way to calculate Unix timestamp
var timestamp = ((DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks) / 10000).ToString();- Database timestamps
- File modification times
- API request/response timestamps
- Log timestamps
- Cache expiry times
- Ensures consistency across different time zones
- Prevents daylight saving time issues
- Simplifies time comparison and sorting
- Centralization: No enums should be defined outside
Shared/Model/Enums.cs - Documentation: Every enum and enum value must have bilingual XML documentation
- Naming: Use PascalCase for enum names and values
- Explicit Values: Always specify explicit integer values for enum members
/// <summary>
/// 交易所环境:测试网、实盘、模拟盘。
/// Exchange environment: testnet, live, or paper trading.
/// </summary>
public enum ExchangeEnvironment
{
/// <summary>
/// 测试网环境,用于开发和测试 / Testnet environment for development and testing.
/// </summary>
Testnet = 0,
/// <summary>
/// 实盘环境,使用真实资金进行交易 / Live environment with real funds for trading.
/// </summary>
Live = 1,
/// <summary>
/// 模拟盘环境,使用虚拟资金模拟实盘 / Paper trading environment with virtual funds simulating live trading.
/// </summary>
Paper = 2
}ExchangeEnvironment- Trading environment typesStartMode- Timer trigger modesMarketType- Market classificationsBroker- Supported brokersOrderStatus- Order lifecycle statesAssetType- Asset classificationsResolutionLevel- Time series resolutionsDataSource- Data source providersTradeDirection- Long/Short positionsCurrency- Currency types- And more...
Network calls are inherently unreliable -- timeouts, rate limits, and transient failures happen regularly in production. Quantitative trading requires high certainty, so every network operation must be wrapped with a retry policy.
- Network latency spikes can cause false-negative results
- API rate limits require exponential backoff
- Broker data feeds can temporarily become unavailable
- A single missed order or stale market data point can cost real money
Every service that makes network calls MUST define a Polly retry policy and wrap all outbound calls:
using Polly;
using Polly.Retry;
/// <summary>
/// Network request retry policy to handle transient failures and API rate limiting.
/// 网络请求重试策略,应对暂时性失败和 API 限流。
/// </summary>
private readonly AsyncRetryPolicy _retryPolicy;
// In constructor:
_retryPolicy = Policy
.Handle<HttpRequestException>()
.OrResult<HttpStatusCode>(
code => code == HttpStatusCode.TooManyRequests
|| code == HttpStatusCode.BadGateway
|| code >= 500 && code < 600
)
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: retries => TimeSpan.FromSeconds(Math.Pow(2, retries)),
onRetry: (response, span, retry, context) =>
{
UtilityService.LogAndWriteLine(
$"[Retry] Attempt {{retry}}/{{retryCount}} after {{span.TotalSeconds}}s");
}
);
// Usage example:
public async Task<ResultType> SomeNetworkCallAsync(params)
{
// Parameter validation first
return await _retryPolicy.ExecuteAsync(async () => {
// Actual network call here
});
}- Every service with network calls defines a
_retryPolicyor equivalent Polly policy - The retry policy handles HTTP 429 (Too Many Requests), 5xx errors, and
HttpRequestException - Exponential backoff is used (not fixed delay) to avoid overwhelming the remote server
- Retry logs are written via
UtilityService.LogAndWriteLinewith attempt number, delay, and error info - After all retries are exhausted, a meaningful error message and log entry are produced
- All broker services (Binance, Alpaca, Schwab, Interactive Brokers)
- Data source services (Yahoo Finance, Binance kline fetchers, CSV/MySQL/MongoDB readers)
- Notification services (DingTalk, WeChat, Email) when sending via external APIs
- Any service that uses
HttpClient,RestSharp, or similar HTTP clients
-
Version History: Add new entry for each release with:
- Version number (SemVer format: MAJOR.MINOR.PATCH)
- Release date (YYYY-MM-DD format)
- Concise description of changes
-
Bilingual Consistency: Both English and Chinese sections must be updated simultaneously
-
API Changes: Any change to public APIs must be reflected in:
- Quick Start section
- Usage scenarios
- Code examples
-
Structure Preservation: Maintain standard Markdown formatting; do not restructure arbitrarily
| 1.5.0 | 2024-06-01 | Added Schwab broker integration and enhanced error handling |- Current version: 1.4.0
- Last updated: 2024-05-16
appsettings.jsonappsettings.*.json(exceptappsettings.example.json)*.secret*.envsecrets.json
- API keys and secrets
- Database connection strings
- Email credentials
- Broker authentication tokens
- Private keys and certificates
-
Use Environment Variables:
var apiKey = Environment.GetEnvironmentVariable("BINANCE_API_KEY");
-
Use User Secrets (Development):
dotnet user-secrets set "Exchange:ApiKey" "your-key-here"
-
Use Example Files:
- Create
appsettings.example.jsonwith placeholder values - Document required configuration structure
- Never include real credentials
- Create
-
Review Before Commit:
- Check for accidental credential exposure
- Use pre-commit hooks if available
- Review git diff before pushing
Use this checklist when reviewing pull requests or your own code:
- All public members have bilingual XML documentation
- Documentation follows the Chinese + English format
- Parameters, return values, and exceptions are documented
- README is updated if public APIs changed
- All public methods validate parameters at the beginning
- Null checks use
ArgumentNullException - String checks use
ArgumentExceptionwithnameof() - Range checks use
ArgumentOutOfRangeException - Error messages are in English
- Console/Log/Exception messages are in English
- No Chinese characters in runtime output
- Code comments are bilingual where helpful
- SOLID principles are followed
- All persistence operations use
DateTime.UtcNow - No usage of
DateTime.Nowfor timestamps - Unix timestamp calculations use UTC
- All enums are in
Shared/Model/Enums.cs - Enums have bilingual XML documentation
- Enum values have explicit integer assignments
- Every network call is wrapped with Polly retry policy
- Retry handles HTTP 429, 5xx errors, and HttpRequestException
- Exponential backoff is used
- Retry logs include attempt number and error details
- No sensitive data in code
- Configuration uses secure patterns
-
.gitignoreexcludes sensitive files
- Unit tests pass:
dotnet test - No breaking changes to existing functionality
- New features have corresponding tests
Consider implementing:
- Roslyn Analyzers for XML documentation enforcement
- StyleCop rules for code style
- Pre-commit hooks for sensitive data detection
- CI/CD pipeline checks for test coverage
- Code reviews must verify compliance with these standards
- Reject PRs that violate critical standards
- Provide constructive feedback for improvements
| Version | Date | Description |
|---|---|---|
| 1.0.0 | 2024-05-16 | Initial code standards document created |
If you have questions about these standards or need clarification:
- Open an issue on GitHub
- Contact: rex.fan18@gmail.com
- Join Telegram group: https://t.me/+VPy-VLis8gVmYWM1
Disclaimer: See DISCLAIMER.md for full disclaimer and limitation of liability / 详见 免责声明 了解完整免责条款与责任限制。