Initial commit: 可转债轮动分析系统

- 实时行情:东财push2主源 + 腾讯批量报价备用源(自动切换)
- 历史K线:东财push2his主源 + 腾讯web子域备用源(含熔断机制)
- 增量同步:支持 -incr/-since 参数按存档日期增量入库
- 策略回测:净值曲线/10指标/基准对比,含基本面过滤
- 用户认证:用户名密码 + 邮箱验证码双登录方式
- 前端:三Tab SPA(实时行情/策略回测/数据管理)
This commit is contained in:
2026-08-17 20:23:22 +08:00
commit e28bfec957
45 changed files with 7889 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
package backtest
import "math"
// Metrics 回测绩效指标。
type Metrics struct {
TotalReturn float64 // 累计收益率
AnnualReturn float64 // 年化收益率
MaxDrawdown float64 // 最大回撤(正值)
Sharpe float64 // 年化夏普比率(无风险利率为 0)
Volatility float64 // 年化波动率
WinRatio float64 // 正收益交易日占比
TradeDays int // 回测交易日数
}
const tradingDaysPerYear = 252.0
// ComputeMetrics 从净值曲线计算绩效指标。
func ComputeMetrics(curve []EquityPoint) Metrics {
m := Metrics{TradeDays: len(curve)}
if len(curve) == 0 {
return m
}
m.TotalReturn = curve[len(curve)-1].Return
// 日收益率序列。
rets := make([]float64, 0, len(curve)-1)
for i := 1; i < len(curve); i++ {
if curve[i-1].Value > 0 {
rets = append(rets, curve[i].Value/curve[i-1].Value-1)
}
}
// 最大回撤:遍历峰值。
var peak, maxDD float64
for _, p := range curve {
if p.Value > peak {
peak = p.Value
}
if dd := peak - p.Value; dd > maxDD {
maxDD = dd
}
}
if peak > 0 {
m.MaxDrawdown = maxDD / peak
}
n := len(rets)
if n == 0 {
return m
}
// 年化收益率。
years := float64(n) / tradingDaysPerYear
if years > 0 && 1+m.TotalReturn > 0 {
m.AnnualReturn = math.Pow(1+m.TotalReturn, 1/years) - 1
}
// 波动率与夏普。
mean := 0.0
for _, r := range rets {
mean += r
}
mean /= float64(n)
var variance float64
for _, r := range rets {
variance += (r - mean) * (r - mean)
}
variance /= float64(n - 1)
m.Volatility = math.Sqrt(variance) * math.Sqrt(tradingDaysPerYear)
if m.Volatility > 0 {
m.Sharpe = mean * tradingDaysPerYear / m.Volatility
}
// 正收益日占比。
win := 0
for _, r := range rets {
if r > 0 {
win++
}
}
m.WinRatio = float64(win) / float64(n)
return m
}