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,98 @@
package backtest
import (
"math"
"testing"
)
func TestComputeMetrics_Empty(t *testing.T) {
m := ComputeMetrics(nil)
if m.TradeDays != 0 {
t.Errorf("expected 0 trade days, got %d", m.TradeDays)
}
}
func TestComputeMetrics_SinglePoint(t *testing.T) {
curve := []EquityPoint{{Date: "2020-01-02", Value: 100000, Return: 0}}
m := ComputeMetrics(curve)
if m.TotalReturn != 0 {
t.Errorf("expected 0 total return, got %f", m.TotalReturn)
}
}
func TestComputeMetrics_SteadyGrowth(t *testing.T) {
// 10 个交易日,每天涨 1%
curve := make([]EquityPoint, 11)
curve[0] = EquityPoint{Date: "2020-01-02", Value: 100000, Return: 0}
for i := 1; i <= 10; i++ {
val := curve[i-1].Value * 1.01
curve[i] = EquityPoint{
Date: "2020-01-02",
Value: val,
Return: val/100000 - 1,
}
}
m := ComputeMetrics(curve)
expectedReturn := 100000*math.Pow(1.01, 10)/100000 - 1
if math.Abs(m.TotalReturn-expectedReturn) > 0.0001 {
t.Errorf("total return: expected %f, got %f", expectedReturn, m.TotalReturn)
}
if m.WinRatio != 1.0 {
t.Errorf("win ratio: expected 1.0, got %f", m.WinRatio)
}
if m.MaxDrawdown > 0.0001 {
t.Errorf("max drawdown: expected 0, got %f", m.MaxDrawdown)
}
if m.TradeDays != 11 {
t.Errorf("trade days: expected 11, got %d", m.TradeDays)
}
}
func TestComputeMetrics_Drawdown(t *testing.T) {
// 先涨后跌:100000 → 110000 → 99000
curve := []EquityPoint{
{Date: "2020-01-02", Value: 100000, Return: 0},
{Date: "2020-01-03", Value: 110000, Return: 0.1},
{Date: "2020-01-06", Value: 99000, Return: -0.01},
}
m := ComputeMetrics(curve)
if m.TotalReturn != -0.01 {
t.Errorf("total return: expected -0.01, got %f", m.TotalReturn)
}
// 峰值 110000, 谷 99000, 回撤 = (110000-99000)/110000 = 0.1
expectedDD := 0.1
if math.Abs(m.MaxDrawdown-expectedDD) > 0.0001 {
t.Errorf("max drawdown: expected %f, got %f", expectedDD, m.MaxDrawdown)
}
}
func TestComputeMetrics_MixedPerformance(t *testing.T) {
// 模拟实际场景:混合涨跌
curve := []EquityPoint{
{Date: "2020-01-02", Value: 100000, Return: 0},
{Date: "2020-01-03", Value: 101000, Return: 0.01}, // +1%
{Date: "2020-01-06", Value: 100500, Return: 0.005}, // -0.5%
{Date: "2020-01-07", Value: 102000, Return: 0.02}, // +1.5%
{Date: "2020-01-08", Value: 101500, Return: 0.015}, // -0.5%
{Date: "2020-01-09", Value: 103000, Return: 0.03}, // +1.5%
}
m := ComputeMetrics(curve)
if m.TotalReturn != 0.03 {
t.Errorf("total return: expected 0.03, got %f", m.TotalReturn)
}
if m.TradeDays != 6 {
t.Errorf("trade days: expected 6, got %d", m.TradeDays)
}
// 3 个正收益日 / 5 个交易日
if math.Abs(m.WinRatio-0.6) > 0.0001 {
t.Errorf("win ratio: expected 0.6, got %f", m.WinRatio)
}
// 年化收益应 > 0
if m.AnnualReturn <= 0 {
t.Errorf("annual return should be positive, got %f", m.AnnualReturn)
}
// 波动率应 > 0
if m.Volatility <= 0 {
t.Errorf("volatility should be positive, got %f", m.Volatility)
}
}