mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
integrate livenote and slack alert into deposit2transfer
This commit is contained in:
parent
85cb99802f
commit
9e2cb4bd7f
|
@ -654,6 +654,7 @@ func (e *Exchange) QueryDepositHistory(ctx context.Context, asset string, since,
|
||||||
RawStatus: strconv.Itoa(int(d.Status)),
|
RawStatus: strconv.Itoa(int(d.Status)),
|
||||||
UnlockConfirm: d.UnlockConfirm,
|
UnlockConfirm: d.UnlockConfirm,
|
||||||
Confirmation: d.ConfirmTimes,
|
Confirmation: d.ConfirmTimes,
|
||||||
|
Network: d.Network,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
"github.com/c9s/bbgo/pkg/exchange/retry"
|
"github.com/c9s/bbgo/pkg/exchange/retry"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
|
"github.com/c9s/bbgo/pkg/livenote"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -40,6 +41,10 @@ func init() {
|
||||||
bbgo.RegisterStrategy(ID, &Strategy{})
|
bbgo.RegisterStrategy(ID, &Strategy{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SlackAlert struct {
|
||||||
|
Mentions []string `json:"mentions"`
|
||||||
|
}
|
||||||
|
|
||||||
type Strategy struct {
|
type Strategy struct {
|
||||||
Environment *bbgo.Environment
|
Environment *bbgo.Environment
|
||||||
|
|
||||||
|
@ -48,6 +53,8 @@ type Strategy struct {
|
||||||
Interval types.Duration `json:"interval"`
|
Interval types.Duration `json:"interval"`
|
||||||
TransferDelay types.Duration `json:"transferDelay"`
|
TransferDelay types.Duration `json:"transferDelay"`
|
||||||
|
|
||||||
|
SlackAlert *SlackAlert `json:"slackAlert"`
|
||||||
|
|
||||||
marginTransferService marginTransferService
|
marginTransferService marginTransferService
|
||||||
depositHistoryService types.ExchangeTransferService
|
depositHistoryService types.ExchangeTransferService
|
||||||
|
|
||||||
|
@ -137,7 +144,7 @@ func (s *Strategy) tickWatcher(ctx context.Context, interval time.Duration) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) checkDeposits(ctx context.Context) {
|
func (s *Strategy) checkDeposits(ctx context.Context) {
|
||||||
accountLimiter := rate.NewLimiter(rate.Every(3*time.Second), 1)
|
accountLimiter := rate.NewLimiter(rate.Every(5*time.Second), 1)
|
||||||
|
|
||||||
for _, asset := range s.Assets {
|
for _, asset := range s.Assets {
|
||||||
logger := s.logger.WithField("asset", asset)
|
logger := s.logger.WithField("asset", asset)
|
||||||
|
@ -204,16 +211,39 @@ func (s *Strategy) checkDeposits(ctx context.Context) {
|
||||||
d.Amount.String(), d.Asset,
|
d.Amount.String(), d.Asset,
|
||||||
amount.String(), d.Asset)
|
amount.String(), d.Asset)
|
||||||
|
|
||||||
|
if s.SlackAlert != nil {
|
||||||
|
bbgo.PostLiveNote(&d,
|
||||||
|
livenote.Comment(fmt.Sprintf("Transferring deposit asset %s %s into the margin account", amount.String(), d.Asset)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
err2 := retry.GeneralBackoff(ctx, func() error {
|
err2 := retry.GeneralBackoff(ctx, func() error {
|
||||||
return s.marginTransferService.TransferMarginAccountAsset(ctx, d.Asset, amount, types.TransferIn)
|
return s.marginTransferService.TransferMarginAccountAsset(ctx, d.Asset, amount, types.TransferIn)
|
||||||
})
|
})
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
logger.WithError(err2).Errorf("unable to transfer deposit asset into the margin account")
|
logger.WithError(err2).Errorf("unable to transfer deposit asset into the margin account")
|
||||||
|
|
||||||
|
if s.SlackAlert != nil {
|
||||||
|
bbgo.PostLiveNote(&d,
|
||||||
|
livenote.Comment(fmt.Sprintf("Margin account transfer error: %+v", err2)),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) addWatchingDeposit(deposit types.Deposit) {
|
||||||
|
s.watchingDeposits[deposit.TransactionID] = deposit
|
||||||
|
|
||||||
|
if s.SlackAlert != nil {
|
||||||
|
bbgo.PostLiveNote(&deposit,
|
||||||
|
livenote.CompareObject(true),
|
||||||
|
livenote.OneTimeMention(s.SlackAlert.Mentions...),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Strategy) scanDepositHistory(ctx context.Context, asset string, duration time.Duration) ([]types.Deposit, error) {
|
func (s *Strategy) scanDepositHistory(ctx context.Context, asset string, duration time.Duration) ([]types.Deposit, error) {
|
||||||
logger := s.logger.WithField("asset", asset)
|
logger := s.logger.WithField("asset", asset)
|
||||||
logger.Debugf("scanning %s deposit history...", asset)
|
logger.Debugf("scanning %s deposit history...", asset)
|
||||||
|
@ -239,6 +269,7 @@ func (s *Strategy) scanDepositHistory(ctx context.Context, asset string, duratio
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
// update the watching deposits
|
||||||
for _, deposit := range deposits {
|
for _, deposit := range deposits {
|
||||||
logger.Debugf("checking deposit: %+v", deposit)
|
logger.Debugf("checking deposit: %+v", deposit)
|
||||||
|
|
||||||
|
@ -246,18 +277,22 @@ func (s *Strategy) scanDepositHistory(ctx context.Context, asset string, duratio
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the deposit record is already in the watch list, update it
|
||||||
if _, ok := s.watchingDeposits[deposit.TransactionID]; ok {
|
if _, ok := s.watchingDeposits[deposit.TransactionID]; ok {
|
||||||
// if the deposit record is in the watch list, update it
|
s.addWatchingDeposit(deposit)
|
||||||
s.watchingDeposits[deposit.TransactionID] = deposit
|
|
||||||
} else {
|
} else {
|
||||||
|
// if the deposit record is not in the watch list, we need to check the status
|
||||||
|
// here the deposit is outside the watching list
|
||||||
switch deposit.Status {
|
switch deposit.Status {
|
||||||
|
|
||||||
case types.DepositSuccess:
|
case types.DepositSuccess:
|
||||||
|
// if the deposit is in success status, we need to check if it's newer than the latest deposit time
|
||||||
|
// this usually happens when the deposit is credited to the account very quickly
|
||||||
if depositTime, ok := s.lastAssetDepositTimes[asset]; ok {
|
if depositTime, ok := s.lastAssetDepositTimes[asset]; ok {
|
||||||
// if it's newer than the latest deposit time, then we just add it the monitoring list
|
// if it's newer than the latest deposit time, then we just add it the monitoring list
|
||||||
if deposit.Time.After(depositTime) {
|
if deposit.Time.After(depositTime) {
|
||||||
logger.Infof("adding new success deposit: %s", deposit.TransactionID)
|
logger.Infof("adding new success deposit: %s", deposit.TransactionID)
|
||||||
s.watchingDeposits[deposit.TransactionID] = deposit
|
s.addWatchingDeposit(deposit)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// ignore all initial deposits that are already in success status
|
// ignore all initial deposits that are already in success status
|
||||||
|
@ -266,7 +301,7 @@ func (s *Strategy) scanDepositHistory(ctx context.Context, asset string, duratio
|
||||||
|
|
||||||
case types.DepositCredited, types.DepositPending:
|
case types.DepositCredited, types.DepositPending:
|
||||||
logger.Infof("adding pending deposit: %s", deposit.TransactionID)
|
logger.Infof("adding pending deposit: %s", deposit.TransactionID)
|
||||||
s.watchingDeposits[deposit.TransactionID] = deposit
|
s.addWatchingDeposit(deposit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,10 +316,12 @@ func (s *Strategy) scanDepositHistory(ctx context.Context, asset string, duratio
|
||||||
}
|
}
|
||||||
|
|
||||||
var succeededDeposits []types.Deposit
|
var succeededDeposits []types.Deposit
|
||||||
for _, deposit := range s.watchingDeposits {
|
|
||||||
if deposit.Status == types.DepositSuccess {
|
|
||||||
logger.Infof("found pending -> success deposit: %+v", deposit)
|
|
||||||
|
|
||||||
|
// find the succeeded deposits
|
||||||
|
for _, deposit := range s.watchingDeposits {
|
||||||
|
switch deposit.Status {
|
||||||
|
case types.DepositSuccess:
|
||||||
|
logger.Infof("found pending -> success deposit: %+v", deposit)
|
||||||
current, required := deposit.GetCurrentConfirmation()
|
current, required := deposit.GetCurrentConfirmation()
|
||||||
if required > 0 && deposit.UnlockConfirm > 0 && current < deposit.UnlockConfirm {
|
if required > 0 && deposit.UnlockConfirm > 0 && current < deposit.UnlockConfirm {
|
||||||
logger.Infof("deposit %s unlock confirm %d is not reached, current: %d, required: %d, skip this round", deposit.TransactionID, deposit.UnlockConfirm, current, required)
|
logger.Infof("deposit %s unlock confirm %d is not reached, current: %d, required: %d, skip this round", deposit.TransactionID, deposit.UnlockConfirm, current, required)
|
||||||
|
|
|
@ -46,6 +46,8 @@ type Deposit struct {
|
||||||
|
|
||||||
// Confirmation format = "current/required", for example: "7/16"
|
// Confirmation format = "current/required", for example: "7/16"
|
||||||
Confirmation string `json:"confirmation"`
|
Confirmation string `json:"confirmation"`
|
||||||
|
|
||||||
|
Network string `json:"network,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Deposit) GetCurrentConfirmation() (current int, required int) {
|
func (d Deposit) GetCurrentConfirmation() (current int, required int) {
|
||||||
|
@ -109,9 +111,35 @@ func (d *Deposit) SlackAttachment() slack.Attachment {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(d.Confirmation) > 0 {
|
||||||
|
text := d.Confirmation
|
||||||
|
if d.UnlockConfirm > 0 {
|
||||||
|
text = fmt.Sprintf("%s (unlock %d)", d.Confirmation, d.UnlockConfirm)
|
||||||
|
}
|
||||||
|
fields = append(fields, slack.AttachmentField{
|
||||||
|
Title: "Confirmation",
|
||||||
|
Value: text,
|
||||||
|
Short: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(d.Network) > 0 {
|
||||||
|
fields = append(fields, slack.AttachmentField{
|
||||||
|
Title: "Network",
|
||||||
|
Value: d.Network,
|
||||||
|
Short: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fields = append(fields, slack.AttachmentField{
|
||||||
|
Title: "Amount",
|
||||||
|
Value: d.Amount.String() + " " + d.Asset,
|
||||||
|
Short: false,
|
||||||
|
})
|
||||||
|
|
||||||
return slack.Attachment{
|
return slack.Attachment{
|
||||||
Color: depositStatusSlackColor(d.Status),
|
Color: depositStatusSlackColor(d.Status),
|
||||||
Title: fmt.Sprintf("Deposit %s %s To %s", d.Amount.String(), d.Asset, d.Address),
|
Title: fmt.Sprintf("Deposit %s %s To %s (%s)", d.Amount.String(), d.Asset, d.Address, d.Exchange),
|
||||||
// TitleLink: "",
|
// TitleLink: "",
|
||||||
Pretext: "",
|
Pretext: "",
|
||||||
Text: "",
|
Text: "",
|
||||||
|
@ -119,9 +147,9 @@ func (d *Deposit) SlackAttachment() slack.Attachment {
|
||||||
// ServiceIcon: "",
|
// ServiceIcon: "",
|
||||||
// FromURL: "",
|
// FromURL: "",
|
||||||
// OriginalURL: "",
|
// OriginalURL: "",
|
||||||
Fields: fields,
|
Fields: fields,
|
||||||
Footer: fmt.Sprintf("Apply Time: %s", d.Time.Time().Format(time.RFC3339)),
|
Footer: fmt.Sprintf("Apply Time: %s", d.Time.Time().Format(time.RFC3339)),
|
||||||
// FooterIcon: "",
|
FooterIcon: ExchangeFooterIcon(d.Exchange),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user