Checks / verify (push) Failing after 9m52s
统一单入口 Go 工程与前端依赖目录,增加后台供应商配置、候选审核、计划预算、成交冲正、持仓复盘和站内通知。接入策略版本、Python 回测、可配置 A 股公开行情及 zap 文件轮转日志,补充迁移、契约与验证。
56 lines
2.1 KiB
Go
56 lines
2.1 KiB
Go
package research
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"git.sundynix.cn/Blizzard/Veyra/internal/model"
|
|
"os/exec"
|
|
"testing"
|
|
)
|
|
|
|
func TestNoLookaheadAndExactCash(t *testing.T) {
|
|
python, e := exec.LookPath("python3")
|
|
if e != nil {
|
|
t.Fatal("Python 3 is required for research tests")
|
|
}
|
|
values := []string{"10.00", "9.00", "8.00", "20.00", "21.00", "7.00", "6.00", "5.00"}
|
|
bars := make([]model.HistoricalBar, len(values))
|
|
for i, p := range values {
|
|
bars[i] = model.HistoricalBar{Date: []string{"2025-01-01", "2025-01-02", "2025-01-03", "2025-01-04", "2025-01-05", "2025-01-06", "2025-01-07", "2025-01-08"}[i], Open: p, High: p, Low: p, Close: p}
|
|
}
|
|
input := model.ResearchInput{BacktestInput: model.BacktestInput{InitialCash: "10000.00", Bars: bars}, Parameters: model.StrategyParameters{ShortWindow: 2, LongWindow: 3, FeeBPS: 10, SlippageBPS: 0, LotSize: 100}}
|
|
data, _ := json.Marshal(input)
|
|
result, e := New(python).Execute(context.Background(), data)
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
var got struct {
|
|
FinalEquity string `json:"final_equity"`
|
|
Trades []struct{ Date, Side, Quantity, Price, Fee string }
|
|
}
|
|
if e := json.Unmarshal(result, &got); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
if len(got.Trades) != 2 || got.Trades[0].Date != "2025-01-05" || got.Trades[0].Side != "BUY" || got.Trades[0].Quantity != "400" || got.Trades[0].Fee != "8.40" || got.Trades[1].Date != "2025-01-07" || got.FinalEquity != "3989.20" {
|
|
t.Fatalf("unexpected result: %s", result)
|
|
}
|
|
// Changing the current close cannot change a trade at that day's open.
|
|
input.Bars[4].Close = "1.00"
|
|
data, _ = json.Marshal(input)
|
|
result, e = New(python).Execute(context.Background(), data)
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
var changed struct {
|
|
Trades []struct{ Date, Side, Quantity, Price, Fee string }
|
|
}
|
|
if json.Unmarshal(result, &changed) != nil || len(changed.Trades) == 0 || changed.Trades[0] != got.Trades[0] {
|
|
t.Fatal("current close leaked into open execution")
|
|
}
|
|
}
|
|
func TestMissingInterpreter(t *testing.T) {
|
|
if _, e := New("/not/an/interpreter").Execute(context.Background(), json.RawMessage(`{}`)); e == nil {
|
|
t.Fatal("missing Python must fail")
|
|
}
|
|
}
|