Files
aiaa-notification-server/internal/engine/renderer.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

99 lines
1.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package engine
import (
"bytes"
"fmt"
"strings"
"text/template"
)
type Renderer struct{}
func NewRenderer() *Renderer {
return &Renderer{}
}
func (r *Renderer) Render(tmplContent string, data map[string]interface{}) (string, error) {
tmpl, err := template.New("notify").
Option("missingkey=zero").
Funcs(template.FuncMap{
"line": templateLine,
"case": templateCase,
"replace": strings.ReplaceAll,
}).
Parse(tmplContent)
if err != nil {
return "", fmt.Errorf("parse template: %w", err)
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil {
return "", fmt.Errorf("execute template: %w", err)
}
return buf.String(), nil
}
// templateLine renders "labelvalue\n" or empty if value is missing/zero.
func templateLine(label string, v any) string {
if isEmptyValue(v) {
return ""
}
return strings.TrimRight(label, ":") + "" + fmt.Sprint(v) + "\n"
}
func templateCase(value any, pairs ...any) string {
got := stringify(value)
n := len(pairs)
def := got
if n%2 == 1 {
def = stringify(pairs[n-1])
pairs = pairs[:n-1]
}
for i := 0; i+1 < len(pairs); i += 2 {
if caseKeyMatch(got, stringify(pairs[i])) {
return stringify(pairs[i+1])
}
}
return def
}
func caseKeyMatch(value, key string) bool {
v := strings.ToLower(strings.TrimSpace(value))
k := strings.ToLower(strings.TrimSpace(key))
k = strings.TrimPrefix(k, ".")
vSeg := v
if i := strings.LastIndex(v, "."); i >= 0 {
vSeg = v[i+1:]
}
return k == v || k == strings.TrimPrefix(v, ".") || k == vSeg
}
func stringify(v any) string {
if v == nil {
return ""
}
return fmt.Sprint(v)
}
func isEmptyValue(v any) bool {
switch t := v.(type) {
case nil:
return true
case string:
return strings.TrimSpace(t) == ""
case bool:
return !t
case int:
return t == 0
case int32:
return t == 0
case int64:
return t == 0
case float32:
return t == 0
case float64:
return t == 0
default:
return false
}
}