mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-21 22:43:52 +00:00
all: add livenote and livenoteposter, move all example strategy into pkg/strategy/example
This commit is contained in:
parent
d8150a17b9
commit
e310ea9e4e
|
@ -392,10 +392,10 @@ persistence:
|
||||||
|
|
||||||
Check out the strategy directory [strategy](pkg/strategy) for all built-in strategies:
|
Check out the strategy directory [strategy](pkg/strategy) for all built-in strategies:
|
||||||
|
|
||||||
- `pricealert` strategy demonstrates how to use the notification system [pricealert](pkg/strategy/pricealert). See
|
- `pricealert` strategy demonstrates how to use the notification system [pricealert](pkg/strategy/example/pricealert). See
|
||||||
[document](./doc/strategy/pricealert.md).
|
[document](./doc/strategy/pricealert.md).
|
||||||
- `buyandhold` strategy demonstrates how to subscribe kline events and submit market
|
- `buyandhold` strategy demonstrates how to subscribe kline events and submit market
|
||||||
order [buyandhold](pkg/strategy/pricedrop)
|
order [buyandhold](pkg/strategy/example/pricedrop)
|
||||||
- `bollgrid` strategy implements a basic grid strategy with the built-in bollinger
|
- `bollgrid` strategy implements a basic grid strategy with the built-in bollinger
|
||||||
indicator [bollgrid](pkg/strategy/bollgrid)
|
indicator [bollgrid](pkg/strategy/bollgrid)
|
||||||
- `grid` strategy implements the fixed price band grid strategy [grid](pkg/strategy/grid). See
|
- `grid` strategy implements the fixed price band grid strategy [grid](pkg/strategy/grid). See
|
||||||
|
|
|
@ -370,8 +370,8 @@ persistence:
|
||||||
|
|
||||||
查看策略目錄 [strategy](pkg/strategy) 以獲得所有內置策略:
|
查看策略目錄 [strategy](pkg/strategy) 以獲得所有內置策略:
|
||||||
|
|
||||||
- `pricealert` 策略演示如何使用通知系統 [pricealert](pkg/strategy/pricealert)。參見[文件](./doc/strategy/pricealert.md).
|
- `pricealert` 策略演示如何使用通知系統 [pricealert](pkg/strategy/example/pricealert)。參見[文件](./doc/strategy/pricealert.md).
|
||||||
- `buyandhold` 策略演示如何訂閱 kline 事件並提交市場訂單 [buyandhold](pkg/strategy/pricedrop)
|
- `buyandhold` 策略演示如何訂閱 kline 事件並提交市場訂單 [buyandhold](pkg/strategy/example/pricedrop)
|
||||||
- `bollgrid` 策略實現了一個基本的網格策略,使用內置的布林通道指標 [bollgrid](pkg/strategy/bollgrid)
|
- `bollgrid` 策略實現了一個基本的網格策略,使用內置的布林通道指標 [bollgrid](pkg/strategy/bollgrid)
|
||||||
- `grid` 策略實現了固定價格帶網格策略 [grid](pkg/strategy/grid)。參見[文件](./doc/strategy/grid.md).
|
- `grid` 策略實現了固定價格帶網格策略 [grid](pkg/strategy/grid)。參見[文件](./doc/strategy/grid.md).
|
||||||
- `supertrend` 策略使用 Supertrend 指標作為趨勢,並使用 DEMA 指標作為噪聲
|
- `supertrend` 策略使用 Supertrend 指標作為趨勢,並使用 DEMA 指標作為噪聲
|
||||||
|
|
21
pkg/bbgo/livenote.go
Normal file
21
pkg/bbgo/livenote.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package bbgo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PostLiveNote posts a live note to slack or other services
|
||||||
|
// The MessageID will be set after the message is posted if it's not set.
|
||||||
|
func PostLiveNote(note *types.LiveNote) {
|
||||||
|
for _, poster := range Notification.liveNotePosters {
|
||||||
|
if err := poster.PostLiveNote(note); err != nil {
|
||||||
|
logrus.WithError(err).Errorf("unable to post live note: %+v", note)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type LiveNotePoster interface {
|
||||||
|
PostLiveNote(note *types.LiveNote) error
|
||||||
|
}
|
|
@ -48,7 +48,9 @@ func (n *NullNotifier) SendPhoto(buffer *bytes.Buffer) {}
|
||||||
func (n *NullNotifier) SendPhotoTo(channel string, buffer *bytes.Buffer) {}
|
func (n *NullNotifier) SendPhotoTo(channel string, buffer *bytes.Buffer) {}
|
||||||
|
|
||||||
type Notifiability struct {
|
type Notifiability struct {
|
||||||
notifiers []Notifier
|
notifiers []Notifier
|
||||||
|
liveNotePosters []LiveNotePoster
|
||||||
|
|
||||||
SessionChannelRouter *PatternChannelRouter `json:"-"`
|
SessionChannelRouter *PatternChannelRouter `json:"-"`
|
||||||
SymbolChannelRouter *PatternChannelRouter `json:"-"`
|
SymbolChannelRouter *PatternChannelRouter `json:"-"`
|
||||||
ObjectChannelRouter *ObjectChannelRouter `json:"-"`
|
ObjectChannelRouter *ObjectChannelRouter `json:"-"`
|
||||||
|
@ -81,6 +83,10 @@ func (m *Notifiability) RouteObject(obj interface{}) (channel string, ok bool) {
|
||||||
// AddNotifier adds the notifier that implements the Notifier interface.
|
// AddNotifier adds the notifier that implements the Notifier interface.
|
||||||
func (m *Notifiability) AddNotifier(notifier Notifier) {
|
func (m *Notifiability) AddNotifier(notifier Notifier) {
|
||||||
m.notifiers = append(m.notifiers, notifier)
|
m.notifiers = append(m.notifiers, notifier)
|
||||||
|
|
||||||
|
if poster, ok := notifier.(LiveNotePoster); ok {
|
||||||
|
m.liveNotePosters = append(m.liveNotePosters, poster)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Notifiability) Notify(obj interface{}, args ...interface{}) {
|
func (m *Notifiability) Notify(obj interface{}, args ...interface{}) {
|
||||||
|
|
|
@ -54,7 +54,8 @@ func (n *Notifier) worker() {
|
||||||
return
|
return
|
||||||
|
|
||||||
case task := <-n.taskC:
|
case task := <-n.taskC:
|
||||||
limiter.Wait(ctx)
|
// ignore the wait error
|
||||||
|
_ = limiter.Wait(ctx)
|
||||||
|
|
||||||
_, _, err := n.client.PostMessageContext(ctx, task.Channel, task.Opts...)
|
_, _, err := n.client.PostMessageContext(ctx, task.Channel, task.Opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -66,7 +67,40 @@ func (n *Notifier) worker() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Notifier) PostLiveNote(note *types.LiveNote) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
channel := note.ChannelID
|
||||||
|
if channel == "" {
|
||||||
|
channel = n.channel
|
||||||
|
}
|
||||||
|
|
||||||
|
if note.MessageID != "" {
|
||||||
|
// UpdateMessageContext returns channel, timestamp, text, err
|
||||||
|
_, _, _, err := n.client.UpdateMessageContext(ctx, channel, note.MessageID, slack.MsgOptionText(note.ObjectID(), true))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
respCh, respTs, err := n.client.PostMessageContext(ctx, channel)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).
|
||||||
|
WithField("channel", n.channel).
|
||||||
|
Errorf("slack api error: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
note.SetChannelID(respCh)
|
||||||
|
note.SetMessageID(respTs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (n *Notifier) Notify(obj interface{}, args ...interface{}) {
|
func (n *Notifier) Notify(obj interface{}, args ...interface{}) {
|
||||||
|
// TODO: filter args for the channel option
|
||||||
n.NotifyTo(n.channel, obj, args...)
|
n.NotifyTo(n.channel, obj, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
33
pkg/types/livenote.go
Normal file
33
pkg/types/livenote.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
type LiveNoteObject interface {
|
||||||
|
ObjectID() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type LiveNote struct {
|
||||||
|
// MessageID is the unique identifier of the message
|
||||||
|
// for slack, it's the timestamp of the message
|
||||||
|
MessageID string `json:"messageId"`
|
||||||
|
|
||||||
|
ChannelID string `json:"channelId"`
|
||||||
|
|
||||||
|
Object LiveNoteObject
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLiveNote(object LiveNoteObject) *LiveNote {
|
||||||
|
return &LiveNote{
|
||||||
|
Object: object,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *LiveNote) ObjectID() string {
|
||||||
|
return n.Object.ObjectID()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *LiveNote) SetMessageID(messageID string) {
|
||||||
|
n.MessageID = messageID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *LiveNote) SetChannelID(channelID string) {
|
||||||
|
n.ChannelID = channelID
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user