mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 08:45:16 +00:00
Merge pull request #67 from c9s/feature/add-telegram-bot-notifier
feature: add telegram bot notifier
This commit is contained in:
commit
1b17cba2eb
18
README.md
18
README.md
|
@ -40,6 +40,9 @@ Add your dotenv file:
|
|||
```
|
||||
SLACK_TOKEN=
|
||||
|
||||
TELEGRAM_BOT_TOKEN=
|
||||
TELEGRAM_AUTH_TOKEN=
|
||||
|
||||
BINANCE_API_KEY=
|
||||
BINANCE_API_SECRET=
|
||||
|
||||
|
@ -210,6 +213,21 @@ streambook := types.NewStreamBook(symbol)
|
|||
streambook.BindStream(stream)
|
||||
```
|
||||
|
||||
## Telegram Integration
|
||||
|
||||
- In telegram: @botFather
|
||||
- /newbot
|
||||
- input bot display name. ex. `bbgo_bot`
|
||||
- input bot username. This should be global unique. ex. `PeqFqJxP_bbgo_bot`
|
||||
- Botfather return bot token. Keep bot token safe
|
||||
- Set `TELEGRAM_BOT_TOKEN` in `.env.local`
|
||||
- Set `TELEGRAM_AUTH_TOKEN` in `.env.local`. Generate your own auth token. ex. 92463901, or kx2UX@eM
|
||||
- Run bbgo
|
||||
- In telegram: search your bot `PeqFqJxP_bbgo_bot`
|
||||
- /start
|
||||
- /auth 92463901
|
||||
- done! your session will route to telegram
|
||||
|
||||
## Support
|
||||
|
||||
### By contributing pull requests
|
||||
|
|
1
go.mod
1
go.mod
|
@ -43,6 +43,7 @@ require (
|
|||
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
|
||||
gonum.org/v1/gonum v0.8.1
|
||||
gopkg.in/tucnak/telebot.v2 v2.3.5
|
||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c
|
||||
)
|
||||
|
|
3
go.sum
3
go.sum
|
@ -276,6 +276,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
|
@ -443,6 +444,8 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/tucnak/telebot.v2 v2.3.5 h1:TdMJTlG8kvepsvZdy/gPeYEBdwKdwFFjH1AQTua9BOU=
|
||||
gopkg.in/tucnak/telebot.v2 v2.3.5/go.mod h1:BgaIIx50PSRS9pG59JH+geT82cfvoJU/IaI5TJdN3v8=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
|
@ -39,6 +39,9 @@ func init() {
|
|||
RootCmd.PersistentFlags().String("slack-channel", "dev-bbgo", "slack trading channel")
|
||||
RootCmd.PersistentFlags().String("slack-error-channel", "bbgo-error", "slack error channel")
|
||||
|
||||
RootCmd.PersistentFlags().String("telegram-bot-token", "", "telegram bot token from bot father")
|
||||
RootCmd.PersistentFlags().String("telegram-auth-token", "", "telegram auth token")
|
||||
|
||||
RootCmd.PersistentFlags().String("binance-api-key", "", "binance api key")
|
||||
RootCmd.PersistentFlags().String("binance-api-secret", "", "binance api secret")
|
||||
|
||||
|
@ -54,18 +57,18 @@ func Execute() {
|
|||
|
||||
// setup the config paths for looking up the config file
|
||||
/*
|
||||
viper.AddConfigPath("config")
|
||||
viper.AddConfigPath("$HOME/.bbgo")
|
||||
viper.AddConfigPath("/etc/bbgo")
|
||||
viper.AddConfigPath("config")
|
||||
viper.AddConfigPath("$HOME/.bbgo")
|
||||
viper.AddConfigPath("/etc/bbgo")
|
||||
|
||||
// set the config file name and format for loading the config file.
|
||||
viper.SetConfigName("bbgo")
|
||||
viper.SetConfigType("yaml")
|
||||
// set the config file name and format for loading the config file.
|
||||
viper.SetConfigName("bbgo")
|
||||
viper.SetConfigType("yaml")
|
||||
|
||||
err := viper.ReadInConfig()
|
||||
if err != nil {
|
||||
log.WithError(err).Fatal("failed to load config file")
|
||||
}
|
||||
err := viper.ReadInConfig()
|
||||
if err != nil {
|
||||
log.WithError(err).Fatal("failed to load config file")
|
||||
}
|
||||
*/
|
||||
|
||||
// Once the flags are defined, we can bind config keys with flags.
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/cmd/cmdutil"
|
||||
"github.com/c9s/bbgo/pkg/notifier/slacknotifier"
|
||||
"github.com/c9s/bbgo/pkg/notifier/telegramnotifier"
|
||||
"github.com/c9s/bbgo/pkg/slack/slacklog"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
@ -121,6 +122,20 @@ func runConfig(basectx context.Context, userConfig *bbgo.Config) error {
|
|||
}
|
||||
}
|
||||
|
||||
// for telegram
|
||||
telegramBotToken := viper.GetString("telegram-bot-token")
|
||||
telegramAuthToken := viper.GetString("telegram-auth-token")
|
||||
if len(telegramBotToken) > 0 && len(telegramAuthToken) > 0 {
|
||||
|
||||
log.Infof("adding telegram notifier")
|
||||
var notifier = telegramnotifier.New(telegramBotToken, telegramAuthToken)
|
||||
|
||||
// start telegram bot
|
||||
go notifier.Bot.Start()
|
||||
|
||||
notification.AddNotifier(notifier)
|
||||
}
|
||||
|
||||
environ.Notifiability = notification
|
||||
|
||||
if userConfig.Notifications != nil {
|
||||
|
|
108
pkg/notifier/telegramnotifier/telegram.go
Normal file
108
pkg/notifier/telegramnotifier/telegram.go
Normal file
|
@ -0,0 +1,108 @@
|
|||
package telegramnotifier
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
tb "gopkg.in/tucnak/telebot.v2"
|
||||
)
|
||||
|
||||
type Notifier struct {
|
||||
Bot *tb.Bot
|
||||
chatUser *tb.User
|
||||
channel string
|
||||
}
|
||||
|
||||
type NotifyOption func(notifier *Notifier)
|
||||
|
||||
// start bot daemon
|
||||
func New(botToken, authToken string, options ...NotifyOption) *Notifier {
|
||||
|
||||
notifier := &Notifier{
|
||||
chatUser: &tb.User{},
|
||||
Bot: &tb.Bot{},
|
||||
}
|
||||
|
||||
for _, o := range options {
|
||||
o(notifier)
|
||||
}
|
||||
|
||||
bot, err := tb.NewBot(tb.Settings{
|
||||
// You can also set custom API URL.
|
||||
// If field is empty it equals to "https://api.telegram.org".
|
||||
// URL: "http://195.129.111.17:8012",
|
||||
|
||||
Token: botToken,
|
||||
Poller: &tb.LongPoller{Timeout: 10 * time.Second},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bot.Handle("/help", func(m *tb.Message) {
|
||||
helpMsg := `
|
||||
help - print help message
|
||||
auth - authorize current telegram user to access telegram bot with authToken. ex. /auth my-token
|
||||
info - print information about current chat
|
||||
`
|
||||
bot.Send(m.Sender, helpMsg)
|
||||
})
|
||||
|
||||
// auth check authToken and then set sender id
|
||||
bot.Handle("/auth", func(m *tb.Message) {
|
||||
log.Info("Receive message: ", m) //debug
|
||||
if m.Payload == authToken {
|
||||
notifier.chatUser = m.Sender
|
||||
bot.Send(m.Sender, "User authorized")
|
||||
} else {
|
||||
bot.Send(m.Sender, "Error: User authorization failed. Auth token does not match!")
|
||||
}
|
||||
})
|
||||
|
||||
bot.Handle("/info", func(m *tb.Message) {
|
||||
if m.Sender.ID == notifier.chatUser.ID {
|
||||
bot.Send(notifier.chatUser,
|
||||
fmt.Sprintf("Welcome! your username: %s, user ID: %d",
|
||||
notifier.chatUser.Username,
|
||||
notifier.chatUser.ID,
|
||||
))
|
||||
} else {
|
||||
log.Warningf("Incorrect user tried to access bot! sender username: %s id: %d", m.Sender.Username, m.Sender.ID)
|
||||
}
|
||||
})
|
||||
|
||||
notifier.Bot = bot
|
||||
|
||||
return notifier
|
||||
}
|
||||
|
||||
func (n *Notifier) Notify(format string, args ...interface{}) {
|
||||
n.NotifyTo(n.channel, format, args...)
|
||||
}
|
||||
|
||||
func (n *Notifier) NotifyTo(channel, format string, args ...interface{}) {
|
||||
if n.chatUser.ID == 0 {
|
||||
log.Warningf("Telegram bot has no authenticated user. Skip notification")
|
||||
return
|
||||
}
|
||||
|
||||
var telegramArgsOffset = -1
|
||||
|
||||
var nonTelegramArgs = args
|
||||
if telegramArgsOffset > -1 {
|
||||
nonTelegramArgs = args[:telegramArgsOffset]
|
||||
}
|
||||
|
||||
log.Infof(format, nonTelegramArgs...)
|
||||
|
||||
_, err := n.Bot.Send(n.chatUser, fmt.Sprintf(format, nonTelegramArgs...))
|
||||
if err != nil {
|
||||
log.WithError(err).
|
||||
WithField("chatUser", n.chatUser).
|
||||
Errorf("telegram error: %s", err.Error())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue
Block a user