fix(消息去重): 去重键加入来源维度,避免跨来源信号被误去重

Motivation:
不同来源(如 crypto-strategy 与 trade-signal)可能产生策略、币种、周期、方向、价格完全一致的信号,旧去重键仅按这五维计算,导致后到的不同来源信号被误判为重复而漏推,无法支撑跟单策略等新增来源并行推送。

Changes:

* 信号去重键新增来源(source)维度,不同来源的相同信号不再互相去重
* 信号哈希计算时透传来源名称,同一来源内的重复消息仍正常去重
* 补充跟单策略文案模板的渲染测试与接口创建文档
This commit is contained in:
2026-08-17 15:39:20 +08:00
parent a2c0590353
commit 33b2a96bcf
7 changed files with 177 additions and 11 deletions
+69
View File
@@ -108,3 +108,72 @@ func TestRendererCaseDefault(t *testing.T) {
t.Fatalf("got %q", out)
}
}
func TestCopyTradeTemplate(t *testing.T) {
tmpl := "{{case .side \"LONG\" \"多单\" \"SHORT\" \"空单\"}}{{case .action \"OPEN\" \"开仓\" \"ADD\" \"加仓\" \"CLOSE\" \"平仓\" \"REDUCE\" \"减仓\"}}\n交易品种: {{case .symbol \"ETHUSDT\" \"ETH\" \"BTCUSDT\" \"BTC\" \"SOLUSDT\" \"SOL\" \"BNBUSDT\" \"BNB\" .symbol}}\n{{case .action \"OPEN\" \"开仓价格\" \"ADD\" \"加仓价格\" \"CLOSE\" \"平仓价格\" \"REDUCE\" \"减仓价格\"}}: {{printf \"%.2f\" .price}}\n{{case .action \"OPEN\" \"开仓数量\" \"ADD\" \"加仓数量\" \"CLOSE\" \"平仓数量\" \"REDUCE\" \"减仓数量\"}}: {{printf \"%.2f\" .quantity}}\n平均单价: {{printf \"%.2f\" .avgPrice}}\n{{if or (eq .action \"OPEN\") (eq .action \"ADD\")}}{{if .leverage}}杠杆: {{.leverage}}x\n{{end}}{{end}}策略: {{case .strategyCode \"BLONG\" \"B龙策略\" .strategyCode}}\n推送时间: {{.pushedAt}}"
r := NewRenderer()
cases := []struct {
name string
data map[string]interface{}
want []string
not []string
}{
{
name: "open",
data: map[string]interface{}{
"side": "SHORT", "action": "OPEN", "symbol": "ETHUSDT",
"price": 1898.76, "quantity": 2.0, "avgPrice": 1898.76,
"leverage": 100, "strategyCode": "BLONG", "pushedAt": "2026.08.13 13:15:42",
},
want: []string{"空单开仓", "交易品种: ETH", "开仓价格: 1898.76", "开仓数量: 2.00", "平均单价: 1898.76", "杠杆: 100x", "策略: B龙策略", "推送时间: 2026.08.13 13:15:42"},
},
{
name: "close",
data: map[string]interface{}{
"side": "SHORT", "action": "CLOSE", "symbol": "ETHUSDT",
"price": 1883.35, "quantity": 2.0, "avgPrice": 1898.76,
"leverage": 100, "strategyCode": "BLONG", "pushedAt": "2026.08.13 17:14:31",
},
want: []string{"空单平仓", "平仓价格: 1883.35", "平仓数量: 2.00", "策略: B龙策略", "推送时间: 2026.08.13 17:14:31"},
not: []string{"杠杆:"},
},
{
name: "reduce",
data: map[string]interface{}{
"side": "SHORT", "action": "REDUCE", "symbol": "ETHUSDT",
"price": 1889.43, "quantity": 3.1, "avgPrice": 1899.03,
"strategyCode": "BLONG", "pushedAt": "2026.08.12 22:05:02",
},
want: []string{"空单减仓", "减仓价格: 1889.43", "减仓数量: 3.10", "平均单价: 1899.03", "策略: B龙策略"},
not: []string{"杠杆:"},
},
{
name: "add",
data: map[string]interface{}{
"side": "SHORT", "action": "ADD", "symbol": "ETHUSDT",
"price": 1933.05, "quantity": 3.8, "avgPrice": 1933.05,
"leverage": 100, "strategyCode": "BLONG", "pushedAt": "2026.08.10 06:14:28",
},
want: []string{"空单加仓", "加仓价格: 1933.05", "加仓数量: 3.80", "杠杆: 100x", "策略: B龙策略", "推送时间: 2026.08.10 06:14:28"},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
out, err := r.Render(tmpl, tc.data)
if err != nil {
t.Fatal(err)
}
t.Logf("\n%s", out)
for _, w := range tc.want {
if !strings.Contains(out, w) {
t.Errorf("missing %q in\n%s", w, out)
}
}
for _, n := range tc.not {
if strings.Contains(out, n) {
t.Errorf("unexpected %q in\n%s", n, out)
}
}
})
}
}