Merge pull request #960 from c9s/refactor/notification

improve: improve the existing notification switch settings
This commit is contained in:
Yo-An Lin 2022-09-20 12:25:06 +08:00 committed by GitHub
commit 17b5e3566a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 102 additions and 338 deletions

View File

@ -3,19 +3,10 @@ notifications:
slack:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# if you want to route channel by symbol
symbolChannels:
"^BTC": "btc"
"^ETH": "eth"
"^BNB": "bnb"
# object routing rules
routing:
trade: "$symbol"
order: "$symbol"
submitOrder: "$session" # not supported yet
pnL: "bbgo-pnl"
switches:
trade: true
orderUpdate: true
submitOrder: true
sessions:
# binance:

View File

@ -4,17 +4,10 @@ notifications:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# if you want to route channel by symbol
symbolChannels:
"^BTC": "btc"
"^ETH": "eth"
# object routing rules
routing:
trade: "$symbol"
order: "$symbol"
submitOrder: "$session" # not supported yet
pnL: "bbgo-pnl"
switches:
trade: true
orderUpdate: true
submitOrder: true
sessions:
binance:

View File

@ -3,6 +3,11 @@ notifications:
slack:
defaultChannel: "bbgo"
errorChannel: "bbgo-error"
switches:
trade: true
orderUpdate: true
submitOrder: true
exchangeStrategies:
- on: max

View File

@ -4,17 +4,10 @@ notifications:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# if you want to route channel by symbol
symbolChannels:
"^BTC": "btc"
"^ETH": "eth"
# object routing rules
routing:
trade: "$symbol"
order: "$symbol"
submitOrder: "$session" # not supported yet
pnL: "bbgo-pnl"
switches:
trade: true
orderUpdate: true
submitOrder: true
sessions:
binance:

View File

@ -3,16 +3,10 @@ notifications:
slack:
defaultChannel: "bbgo"
errorChannel: "bbgo-error"
reportPnL:
- averageCostBySymbols:
- "BTCUSDT"
- "ETHUSDT"
- "BNBUSDT"
of: binance
when:
- "@daily"
- "@hourly"
switches:
trade: true
orderUpdate: true
submitOrder: true
sessions:
binance:

View File

@ -3,6 +3,10 @@ notifications:
slack:
defaultChannel: "bbgo"
errorChannel: "bbgo-error"
switches:
trade: true
orderUpdate: true
submitOrder: true
exchangeStrategies:
- on: max

View File

@ -4,18 +4,10 @@ notifications:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# if you want to route channel by symbol
symbolChannels:
"^BTC": "btc"
"^ETH": "eth"
"^BNB": "bnb"
# object routing rules
routing:
trade: "$symbol"
order: "$symbol"
submitOrder: "$session" # not supported yet
pnL: "bbgo-pnl"
switches:
trade: true
orderUpdate: true
submitOrder: true
sessions:
binance_margin_linkusdt:

View File

@ -3,11 +3,10 @@ notifications:
slack:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# object routing rules
routing:
trade: "$symbol"
order: "$symbol"
submitOrder: "$session" # not supported yet
switches:
trade: true
orderUpdate: true
submitOrder: true
sessions:
binance:

View File

@ -4,18 +4,10 @@ notifications:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# if you want to route channel by symbol
symbolChannels:
"^BTC": "btc"
"^ETH": "eth"
"^BNB": "bnb"
# object routing rules
routing:
trade: "$symbol"
order: "$symbol"
submitOrder: "$session" # not supported yet
pnL: "bbgo-pnl"
switches:
trade: true
orderUpdate: true
submitOrder: true
sessions:
binance:

View File

@ -4,22 +4,10 @@ notifications:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# if you want to route channel by symbol
symbolChannels:
"^BTC": "btc"
"^ETH": "eth"
# if you want to route channel by exchange session
sessionChannels:
max: "bbgo-max"
binance: "bbgo-binance"
# routing rules
routing:
trade: "$symbol"
order: "$slient"
submitOrder: "$slient"
pnL: "bbgo-pnl"
switches:
trade: true
orderUpdate: true
submitOrder: true
sessions:
max:

View File

@ -4,22 +4,10 @@ notifications:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# if you want to route channel by symbol
symbolChannels:
"^BTC": "btc"
"^ETH": "eth"
# if you want to route channel by exchange session
sessionChannels:
max: "bbgo-max"
binance: "bbgo-binance"
# routing rules
routing:
trade: "$silent"
order: "$silent"
submitOrder: "$silent"
pnL: "bbgo-pnl"
switches:
trade: true
orderUpdate: true
submitOrder: true
persistence:
json:

View File

@ -4,22 +4,10 @@ notifications:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# if you want to route channel by symbol
symbolChannels:
"^BTC": "btc"
"^ETH": "eth"
# if you want to route channel by exchange session
sessionChannels:
max: "bbgo-max"
binance: "bbgo-binance"
# routing rules
routing:
trade: "$symbol"
order: "$silent"
submitOrder: "$silent"
pnL: "bbgo-pnl"
switches:
trade: true
orderUpdate: true
submitOrder: true
reportPnL:
- averageCostBySymbols:

View File

@ -4,22 +4,10 @@ notifications:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# if you want to route channel by symbol
symbolChannels:
"^BTC": "btc"
"^ETH": "eth"
# if you want to route channel by exchange session
sessionChannels:
max: "bbgo-max"
binance: "bbgo-binance"
# routing rules
routing:
trade: "$symbol"
order: "$silent"
submitOrder: "$silent"
pnL: "bbgo-pnl"
switches:
trade: true
orderUpdate: false
submitOrder: false
persistence:
json:

View File

@ -4,11 +4,10 @@ notifications:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# routing rules
routing:
trade: "$silent"
order: "$silent"
submitOrder: "$silent"
switches:
trade: true
orderUpdate: false
submitOrder: false
persistence:
json:

View File

@ -4,22 +4,10 @@ notifications:
defaultChannel: "dev-bbgo"
errorChannel: "bbgo-error"
# if you want to route channel by symbol
symbolChannels:
"^BTC": "btc"
"^ETH": "eth"
# if you want to route channel by exchange session
sessionChannels:
max: "bbgo-max"
binance: "bbgo-binance"
# routing rules
routing:
trade: "$symbol"
order: "$slient"
submitOrder: "$slient"
pnL: "bbgo-pnl"
switches:
trade: true
orderUpdate: true
submitOrder: true
sessions:
max:

View File

@ -4,14 +4,10 @@ notifications:
defaultChannel: "bbgo"
errorChannel: "bbgo-error"
reportPnL:
- averageCostBySymbols:
- "BTCUSDT"
- "BNBUSDT"
of: binance
when:
- "@daily"
- "@hourly"
switches:
trade: true
orderUpdate: true
submitOrder: true
sessions:
max:

View File

@ -76,15 +76,17 @@ type TelegramNotification struct {
Broadcast bool `json:"broadcast" yaml:"broadcast"`
}
type NotificationSwitches struct {
Trade bool `json:"trade" yaml:"trade"`
Position bool `json:"position" yaml:"position"`
OrderUpdate bool `json:"orderUpdate" yaml:"orderUpdate"`
SubmitOrder bool `json:"submitOrder" yaml:"submitOrder"`
}
type NotificationConfig struct {
Slack *SlackNotification `json:"slack,omitempty" yaml:"slack,omitempty"`
Slack *SlackNotification `json:"slack,omitempty" yaml:"slack,omitempty"`
Telegram *TelegramNotification `json:"telegram,omitempty" yaml:"telegram,omitempty"`
SymbolChannels map[string]string `json:"symbolChannels,omitempty" yaml:"symbolChannels,omitempty"`
SessionChannels map[string]string `json:"sessionChannels,omitempty" yaml:"sessionChannels,omitempty"`
Routing *SlackNotificationRouting `json:"routing,omitempty" yaml:"routing,omitempty"`
Switches *NotificationSwitches `json:"switches" yaml:"switches"`
}
type Session struct {

View File

@ -48,13 +48,6 @@ func TestLoadConfig(t *testing.T) {
wantErr: false,
f: func(t *testing.T, config *Config) {
assert.NotNil(t, config.Notifications)
assert.NotNil(t, config.Notifications.SessionChannels)
assert.NotNil(t, config.Notifications.SymbolChannels)
assert.Equal(t, map[string]string{
"^BTC": "#btc",
"^ETH": "#eth",
}, config.Notifications.SymbolChannels)
assert.NotNil(t, config.Notifications.Routing)
assert.Equal(t, "#dev-bbgo", config.Notifications.Slack.DefaultChannel)
assert.Equal(t, "#error", config.Notifications.Slack.ErrorChannel)
},

View File

@ -30,7 +30,6 @@ import (
"github.com/c9s/bbgo/pkg/slack/slacklog"
"github.com/c9s/bbgo/pkg/types"
"github.com/c9s/bbgo/pkg/util"
"github.com/c9s/bbgo/pkg/util/templateutil"
)
func init() {
@ -302,153 +301,6 @@ func (environ *Environment) ConfigurePersistence(conf *PersistenceConfig) error
return nil
}
// ConfigureNotificationRouting configures the notification rules
// for symbol-based routes, we should register the same symbol rules for each session.
// for session-based routes, we should set the fixed callbacks for each session
func (environ *Environment) ConfigureNotificationRouting(conf *NotificationConfig) error {
// configure routing here
if conf.SymbolChannels != nil {
Notification.SymbolChannelRouter.AddRoute(conf.SymbolChannels)
}
if conf.SessionChannels != nil {
Notification.SessionChannelRouter.AddRoute(conf.SessionChannels)
}
if conf.Routing != nil {
// configure passive object notification routing
switch conf.Routing.Trade {
case "$silent": // silent, do not setup notification
case "$session":
defaultTradeUpdateHandler := func(trade types.Trade) {
Notify(&trade)
}
for name := range environ.sessions {
session := environ.sessions[name]
// if we can route session name to channel successfully...
channel, ok := Notification.SessionChannelRouter.Route(name)
if ok {
session.UserDataStream.OnTradeUpdate(func(trade types.Trade) {
Notification.NotifyTo(channel, &trade)
})
} else {
session.UserDataStream.OnTradeUpdate(defaultTradeUpdateHandler)
}
}
case "$symbol":
// configure object routes for Trade
Notification.ObjectChannelRouter.Route(func(obj interface{}) (channel string, ok bool) {
trade, matched := obj.(*types.Trade)
if !matched {
return
}
channel, ok = Notification.SymbolChannelRouter.Route(trade.Symbol)
return
})
// use same handler for each session
handler := func(trade types.Trade) {
channel, ok := Notification.RouteObject(&trade)
if ok {
NotifyTo(channel, &trade)
} else {
Notify(&trade)
}
}
for _, session := range environ.sessions {
session.UserDataStream.OnTradeUpdate(handler)
}
}
switch conf.Routing.Order {
case "$silent": // silent, do not setup notification
case "$session":
defaultOrderUpdateHandler := func(order types.Order) {
text := templateutil.Render(TemplateOrderReport, order)
Notify(text, &order)
}
for name := range environ.sessions {
session := environ.sessions[name]
// if we can route session name to channel successfully...
channel, ok := Notification.SessionChannelRouter.Route(name)
if ok {
session.UserDataStream.OnOrderUpdate(func(order types.Order) {
text := templateutil.Render(TemplateOrderReport, order)
NotifyTo(channel, text, &order)
})
} else {
session.UserDataStream.OnOrderUpdate(defaultOrderUpdateHandler)
}
}
case "$symbol":
// add object route
Notification.ObjectChannelRouter.Route(func(obj interface{}) (channel string, ok bool) {
order, matched := obj.(*types.Order)
if !matched {
return
}
channel, ok = Notification.SymbolChannelRouter.Route(order.Symbol)
return
})
// use same handler for each session
handler := func(order types.Order) {
text := templateutil.Render(TemplateOrderReport, order)
channel, ok := Notification.RouteObject(&order)
if ok {
NotifyTo(channel, text, &order)
} else {
Notify(text, &order)
}
}
for _, session := range environ.sessions {
session.UserDataStream.OnOrderUpdate(handler)
}
}
switch conf.Routing.SubmitOrder {
case "$silent": // silent, do not setup notification
case "$symbol":
// add object route
Notification.ObjectChannelRouter.Route(func(obj interface{}) (channel string, ok bool) {
order, matched := obj.(*types.SubmitOrder)
if !matched {
return
}
channel, ok = Notification.SymbolChannelRouter.Route(order.Symbol)
return
})
}
// currently, not used
// FIXME: this is causing cyclic import
/*
switch conf.Routing.PnL {
case "$symbol":
environ.ObjectChannelRouter.Route(func(obj interface{}) (channel string, ok bool) {
report, matched := obj.(*pnl.AverageCostPnlReport)
if !matched {
return
}
channel, ok = environ.SymbolChannelRouter.Route(report.Symbol)
return
})
}
*/
}
return nil
}
func (environ *Environment) SetStartTime(t time.Time) *Environment {
environ.startTime = t
return environ
@ -773,16 +625,9 @@ func (environ *Environment) syncSession(ctx context.Context, session *ExchangeSe
}
func (environ *Environment) ConfigureNotificationSystem(userConfig *Config) error {
// setup default notification config
if userConfig.Notifications == nil {
userConfig.Notifications = &NotificationConfig{
Routing: &SlackNotificationRouting{
Trade: "$session",
Order: "$silent",
SubmitOrder: "$silent",
},
}
userConfig.Notifications = &NotificationConfig{}
}
var persistence = PersistenceServiceFacade.Get()
@ -807,7 +652,7 @@ func (environ *Environment) ConfigureNotificationSystem(userConfig *Config) erro
}
if userConfig.Notifications != nil {
if err := environ.ConfigureNotificationRouting(userConfig.Notifications); err != nil {
if err := environ.ConfigureNotification(userConfig.Notifications); err != nil {
return err
}
}
@ -815,6 +660,32 @@ func (environ *Environment) ConfigureNotificationSystem(userConfig *Config) erro
return nil
}
func (environ *Environment) ConfigureNotification(config *NotificationConfig) error {
if config.Switches != nil {
if config.Switches.Trade {
tradeHandler := func(trade types.Trade) {
Notify(trade)
}
for _, session := range environ.sessions {
session.UserDataStream.OnTradeUpdate(tradeHandler)
}
}
if config.Switches.OrderUpdate {
orderUpdateHandler := func(order types.Order) {
Notify(order)
}
for _, session := range environ.sessions {
session.UserDataStream.OnOrderUpdate(orderUpdateHandler)
}
}
}
return nil
}
// getAuthStoreID returns the authentication store id
// if telegram bot token is defined, the bot id will be used.
// if not, env var $USER will be used.