feat: subscribe to RabbitMQ trade signals and notify by rules
Consume configurable queues, format signals (including period), share NotifyService with HTTP, and drop duplicate bodies within 1h.
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
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) == "" {
|
||||
return "", nil, fmt.Errorf("%w: missing action", ErrInvalidSignal)
|
||||
}
|
||||
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(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(sig *Signal) (map[string]interface{}, error) {
|
||||
raw, err := json.Marshal(sig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data := make(map[string]interface{})
|
||||
if err := json.Unmarshal(raw, &data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
Reference in New Issue
Block a user