mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-21 22:43:52 +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/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
|
. "github.com/c9s/bbgo/pkg/testing/testhelper"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"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",
|
name: "deposit and order",
|
||||||
wantErr: assert.NoError,
|
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 {
|
func (p *Pool) Update(obj Object) *LiveNote {
|
||||||
objID := obj.ObjectID()
|
objID := obj.ObjectID()
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/dynamic"
|
||||||
"github.com/c9s/bbgo/pkg/livenote"
|
"github.com/c9s/bbgo/pkg/livenote"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"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 {
|
func (n *Notifier) PostLiveNote(obj livenote.Object, opts ...livenote.Option) error {
|
||||||
note := n.liveNotePool.Update(obj)
|
var slackOpts []slack.MsgOption
|
||||||
ctx := n.ctx
|
|
||||||
|
|
||||||
channel := note.ChannelID
|
var firstTimeHandles []string
|
||||||
if channel == "" {
|
var commentHandles []string
|
||||||
channel = n.channel
|
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
|
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")
|
return fmt.Errorf("livenote object does not support types.SlackAttachmentCreator interface")
|
||||||
}
|
}
|
||||||
|
|
||||||
var slackOpts []slack.MsgOption
|
|
||||||
slackOpts = append(slackOpts, slack.MsgOptionAttachments(attachment))
|
slackOpts = append(slackOpts, slack.MsgOptionAttachments(attachment))
|
||||||
|
|
||||||
var firstTimeHandles []string
|
firstTimeTags, err := n.translateHandles(n.ctx, firstTimeHandles)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
commentTags, err := n.translateHandles(context.Background(), commentHandles)
|
commentTags, err := n.translateHandles(n.ctx, commentHandles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// format: mention slack user
|
|
||||||
// <@U012AB3CD>
|
|
||||||
|
|
||||||
if note.MessageID != "" {
|
if note.MessageID != "" {
|
||||||
// If compare is enabled, we need to attach the comments
|
// 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)
|
note.SetMessageID(respTs)
|
||||||
|
|
||||||
if len(firstTimeTags) > 0 {
|
if len(firstTimeTags) > 0 {
|
||||||
n.queueTask(context.Background(), notifyTask{
|
n.queueTask(n.ctx, notifyTask{
|
||||||
channel: respCh,
|
channel: respCh,
|
||||||
threadTs: respTs,
|
threadTs: respTs,
|
||||||
opts: []slack.MsgOption{
|
opts: []slack.MsgOption{
|
||||||
|
@ -321,7 +342,7 @@ func (n *Notifier) PostLiveNote(obj livenote.Object, opts ...livenote.Option) er
|
||||||
},
|
},
|
||||||
}, 100*time.Millisecond)
|
}, 100*time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(comments) > 0 {
|
if len(comments) > 0 {
|
||||||
var text string
|
var text string
|
||||||
if len(commentTags) > 0 {
|
if len(commentTags) > 0 {
|
||||||
|
@ -329,7 +350,7 @@ func (n *Notifier) PostLiveNote(obj livenote.Object, opts ...livenote.Option) er
|
||||||
}
|
}
|
||||||
|
|
||||||
text += joinComments(comments)
|
text += joinComments(comments)
|
||||||
n.queueTask(context.Background(), notifyTask{
|
n.queueTask(n.ctx, notifyTask{
|
||||||
channel: respCh,
|
channel: respCh,
|
||||||
threadTs: respTs,
|
threadTs: respTs,
|
||||||
opts: []slack.MsgOption{
|
opts: []slack.MsgOption{
|
||||||
|
@ -463,3 +484,17 @@ func joinTags(tags []string) string {
|
||||||
func joinComments(comments []string) string {
|
func joinComments(comments []string) string {
|
||||||
return strings.Join(comments, "\n")
|
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)
|
log.Info(k)
|
||||||
bbgo.PostLiveNote(&k,
|
bbgo.PostLiveNote(&k,
|
||||||
livenote.OneTimeMention(s.UserID),
|
livenote.OneTimeMention(s.UserID),
|
||||||
livenote.Comment("please check the deposit", s.UserID),
|
livenote.Comment("please check the deposit"),
|
||||||
livenote.CompareObject(true))
|
livenote.CompareObject(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user