- 实时行情:东财push2主源 + 腾讯批量报价备用源(自动切换) - 历史K线:东财push2his主源 + 腾讯web子域备用源(含熔断机制) - 增量同步:支持 -incr/-since 参数按存档日期增量入库 - 策略回测:净值曲线/10指标/基准对比,含基本面过滤 - 用户认证:用户名密码 + 邮箱验证码双登录方式 - 前端:三Tab SPA(实时行情/策略回测/数据管理)
86 lines
1.8 KiB
Go
86 lines
1.8 KiB
Go
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
|
||
}
|