Files
aiaa-notification-server/internal/subscriber/tradesignal/convert.go
T
ryan f7ea2e7cf9 feat(crypto策略): 支持巴菲特策略纯 rawMessage 信号推送
Motivation:
新增巴菲特激进/稳健策略(PUTEJJ/PUTEWJ)的跟单推送能力。该类信号仅有 rawMessage、无 action 字段,需按原文直接推送,并过滤启动文案、本地化时间字段。

Changes:

* 支持无 action 的纯 rawMessage 信号,映射为 trade.message 事件
* 新增 not_contains 条件操作符,用于过滤启动文案
* 新增 replace 模板函数,将 Time: 替换为推送时间:
* 补充巴菲特策略模板、规则与渠道配置文档
2026-08-17 16:38:09 +08:00

89 lines
2.0 KiB
Go

package tradesignal
import (
"encoding/json"
"errors"
"fmt"
"strings"
"aiaa-notification-service/internal/config"
)
var ErrInvalidSignal = errors.New("invalid signal")
type Converter struct {
overrides map[string]config.StrategyOverride
positions *Tracker
}
func NewConverter(overrides map[string]config.StrategyOverride) *Converter {
return &Converter{
overrides: overrides,
positions: NewTracker(),
}
}
func (c *Converter) Convert(body []byte) (string, map[string]interface{}, error) {
var sig Signal
if err := json.Unmarshal(body, &sig); err != nil {
return "", nil, fmt.Errorf("%w: %v", ErrInvalidSignal, err)
}
if strings.TrimSpace(sig.Action) == "" {
if strings.TrimSpace(sig.RawMessage) == "" {
return "", nil, fmt.Errorf("%w: missing action", ErrInvalidSignal)
}
data, err := toData(body, &sig)
if err != nil {
return "", nil, err
}
return "trade.message", data, nil
}
out := Apply(&sig, c.overrideFor(sig.StrategyCode))
snap := c.positions.Apply(out)
var opts FormatOptions
if snap.HasAvg {
avg := snap.AvgPrice
opts.AvgPrice = &avg
}
text := Format(out, opts)
data, err := toData(body, out)
if err != nil {
return "", nil, err
}
data["formatted"] = text
if snap.HasAvg {
data["avgPrice"] = snap.AvgPrice
}
return "trade." + strings.ToLower(out.Action), data, nil
}
func (c *Converter) overrideFor(code string) *config.StrategyOverride {
if c == nil || len(c.overrides) == 0 || code == "" {
return nil
}
override, ok := c.overrides[code]
if !ok {
return nil
}
return &override
}
func toData(body []byte, sig *Signal) (map[string]interface{}, error) {
data := make(map[string]interface{})
if err := json.Unmarshal(body, &data); err != nil {
return nil, err
}
raw, err := json.Marshal(sig)
if err != nil {
return nil, err
}
overlay := make(map[string]interface{})
if err := json.Unmarshal(raw, &overlay); err != nil {
return nil, err
}
for k, v := range overlay {
data[k] = v
}
return data, nil
}