mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-21 14:33:53 +00:00
livenote: add test and generate diff summary for object change
This commit is contained in:
parent
c4c6a73774
commit
c289c2daf5
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
. "github.com/c9s/bbgo/pkg/testing/testhelper"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
|
@ -94,6 +95,52 @@ func Test_Compare(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "kline",
|
||||
wantErr: assert.NoError,
|
||||
a: types.KLine{
|
||||
Open: Number(60000),
|
||||
High: Number(61000),
|
||||
Low: Number(59500),
|
||||
Close: Number(60100),
|
||||
},
|
||||
b: types.KLine{
|
||||
Open: Number(60000),
|
||||
High: Number(61000),
|
||||
Low: Number(59500),
|
||||
Close: Number(60200),
|
||||
},
|
||||
want: []Diff{
|
||||
{
|
||||
Field: "Close",
|
||||
Before: "60200",
|
||||
After: "60100",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "kline ptr",
|
||||
wantErr: assert.NoError,
|
||||
a: &types.KLine{
|
||||
Open: Number(60000),
|
||||
High: Number(61000),
|
||||
Low: Number(59500),
|
||||
Close: Number(60100),
|
||||
},
|
||||
b: &types.KLine{
|
||||
Open: Number(60000),
|
||||
High: Number(61000),
|
||||
Low: Number(59500),
|
||||
Close: Number(60200),
|
||||
},
|
||||
want: []Diff{
|
||||
{
|
||||
Field: "Close",
|
||||
Before: "60200",
|
||||
After: "60100",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deposit and order",
|
||||
wantErr: assert.NoError,
|
||||
|
|
|
@ -56,6 +56,21 @@ func NewPool(size int64) *Pool {
|
|||
}
|
||||
}
|
||||
|
||||
func (p *Pool) Get(obj Object) *LiveNote {
|
||||
objID := obj.ObjectID()
|
||||
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
for _, note := range p.notes {
|
||||
if note.ObjectID() == objID {
|
||||
return note
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Pool) Update(obj Object) *LiveNote {
|
||||
objID := obj.ObjectID()
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
"golang.org/x/time/rate"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/dynamic"
|
||||
"github.com/c9s/bbgo/pkg/livenote"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
|
||||
|
@ -229,12 +230,49 @@ func (n *Notifier) translateHandle(ctx context.Context, handle string) (string,
|
|||
}
|
||||
|
||||
func (n *Notifier) PostLiveNote(obj livenote.Object, opts ...livenote.Option) error {
|
||||
note := n.liveNotePool.Update(obj)
|
||||
ctx := n.ctx
|
||||
var slackOpts []slack.MsgOption
|
||||
|
||||
channel := note.ChannelID
|
||||
if channel == "" {
|
||||
channel = n.channel
|
||||
var firstTimeHandles []string
|
||||
var commentHandles []string
|
||||
var comments []string
|
||||
var shouldCompare bool
|
||||
for _, opt := range opts {
|
||||
switch val := opt.(type) {
|
||||
case *livenote.OptionOneTimeMention:
|
||||
firstTimeHandles = append(firstTimeHandles, val.Users...)
|
||||
case *livenote.OptionComment:
|
||||
comments = append(comments, val.Text)
|
||||
commentHandles = append(commentHandles, val.Users...)
|
||||
case *livenote.OptionCompare:
|
||||
shouldCompare = val.Value
|
||||
}
|
||||
}
|
||||
|
||||
var ctx = n.ctx
|
||||
var curObj, prevObj any
|
||||
if shouldCompare {
|
||||
if prevNote := n.liveNotePool.Get(obj); prevNote != nil {
|
||||
prevObj = prevNote.Object
|
||||
}
|
||||
}
|
||||
|
||||
channel := n.channel
|
||||
note := n.liveNotePool.Update(obj)
|
||||
curObj = note.Object
|
||||
|
||||
if shouldCompare && prevObj != nil {
|
||||
diffs, err := dynamic.Compare(curObj, prevObj)
|
||||
if err != nil {
|
||||
log.WithError(err).Warnf("unable to compare objects: %T and %T", curObj, prevObj)
|
||||
} else {
|
||||
if comment := diffsToComment(curObj, diffs); len(comment) > 0 {
|
||||
comments = append(comments, comment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if note.ChannelID != "" {
|
||||
channel = note.ChannelID
|
||||
}
|
||||
|
||||
var attachment slack.Attachment
|
||||
|
@ -244,35 +282,18 @@ func (n *Notifier) PostLiveNote(obj livenote.Object, opts ...livenote.Option) er
|
|||
return fmt.Errorf("livenote object does not support types.SlackAttachmentCreator interface")
|
||||
}
|
||||
|
||||
var slackOpts []slack.MsgOption
|
||||
slackOpts = append(slackOpts, slack.MsgOptionAttachments(attachment))
|
||||
|
||||
var firstTimeHandles []string
|
||||
var commentHandles []string
|
||||
var comments []string
|
||||
for _, opt := range opts {
|
||||
switch val := opt.(type) {
|
||||
case *livenote.OptionOneTimeMention:
|
||||
firstTimeHandles = append(firstTimeHandles, val.Users...)
|
||||
case *livenote.OptionComment:
|
||||
comments = append(comments, val.Text)
|
||||
commentHandles = append(commentHandles, val.Users...)
|
||||
}
|
||||
}
|
||||
|
||||
firstTimeTags, err := n.translateHandles(context.Background(), firstTimeHandles)
|
||||
firstTimeTags, err := n.translateHandles(n.ctx, firstTimeHandles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
commentTags, err := n.translateHandles(context.Background(), commentHandles)
|
||||
commentTags, err := n.translateHandles(n.ctx, commentHandles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// format: mention slack user
|
||||
// <@U012AB3CD>
|
||||
|
||||
if note.MessageID != "" {
|
||||
// If compare is enabled, we need to attach the comments
|
||||
|
||||
|
@ -312,7 +333,7 @@ func (n *Notifier) PostLiveNote(obj livenote.Object, opts ...livenote.Option) er
|
|||
note.SetMessageID(respTs)
|
||||
|
||||
if len(firstTimeTags) > 0 {
|
||||
n.queueTask(context.Background(), notifyTask{
|
||||
n.queueTask(n.ctx, notifyTask{
|
||||
channel: respCh,
|
||||
threadTs: respTs,
|
||||
opts: []slack.MsgOption{
|
||||
|
@ -321,7 +342,7 @@ func (n *Notifier) PostLiveNote(obj livenote.Object, opts ...livenote.Option) er
|
|||
},
|
||||
}, 100*time.Millisecond)
|
||||
}
|
||||
|
||||
|
||||
if len(comments) > 0 {
|
||||
var text string
|
||||
if len(commentTags) > 0 {
|
||||
|
@ -329,7 +350,7 @@ func (n *Notifier) PostLiveNote(obj livenote.Object, opts ...livenote.Option) er
|
|||
}
|
||||
|
||||
text += joinComments(comments)
|
||||
n.queueTask(context.Background(), notifyTask{
|
||||
n.queueTask(n.ctx, notifyTask{
|
||||
channel: respCh,
|
||||
threadTs: respTs,
|
||||
opts: []slack.MsgOption{
|
||||
|
@ -463,3 +484,17 @@ func joinTags(tags []string) string {
|
|||
func joinComments(comments []string) string {
|
||||
return strings.Join(comments, "\n")
|
||||
}
|
||||
|
||||
func diffsToComment(obj any, diffs []dynamic.Diff) (text string) {
|
||||
if len(diffs) == 0 {
|
||||
return text
|
||||
}
|
||||
|
||||
text += fmt.Sprintf("%T updated\n", obj)
|
||||
|
||||
for _, diff := range diffs {
|
||||
text += fmt.Sprintf("- %s: `%s` transited to `%s`\n", diff.Field, diff.Before, diff.After)
|
||||
}
|
||||
|
||||
return text
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
log.Info(k)
|
||||
bbgo.PostLiveNote(&k,
|
||||
livenote.OneTimeMention(s.UserID),
|
||||
livenote.Comment("please check the deposit", s.UserID),
|
||||
livenote.Comment("please check the deposit"),
|
||||
livenote.CompareObject(true))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user