mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 08:15:15 +00:00
strategy/autoborrow: add margin level alert
This commit is contained in:
parent
c2568ab22c
commit
a9d0242a9d
|
@ -21,10 +21,6 @@ type notifyTask struct {
|
||||||
Opts []slack.MsgOption
|
Opts []slack.MsgOption
|
||||||
}
|
}
|
||||||
|
|
||||||
type slackAttachmentCreator interface {
|
|
||||||
SlackAttachment() slack.Attachment
|
|
||||||
}
|
|
||||||
|
|
||||||
type Notifier struct {
|
type Notifier struct {
|
||||||
client *slack.Client
|
client *slack.Client
|
||||||
channel string
|
channel string
|
||||||
|
@ -59,6 +55,7 @@ func (n *Notifier) worker() {
|
||||||
|
|
||||||
case task := <-n.taskC:
|
case task := <-n.taskC:
|
||||||
limiter.Wait(ctx)
|
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 {
|
||||||
log.WithError(err).
|
log.WithError(err).
|
||||||
|
@ -86,7 +83,7 @@ func filterSlackAttachments(args []interface{}) (slackAttachments []slack.Attach
|
||||||
|
|
||||||
slackAttachments = append(slackAttachments, a)
|
slackAttachments = append(slackAttachments, a)
|
||||||
|
|
||||||
case slackAttachmentCreator:
|
case types.SlackAttachmentCreator:
|
||||||
if firstAttachmentOffset == -1 {
|
if firstAttachmentOffset == -1 {
|
||||||
firstAttachmentOffset = idx
|
firstAttachmentOffset = idx
|
||||||
}
|
}
|
||||||
|
@ -132,7 +129,7 @@ func (n *Notifier) NotifyTo(channel string, obj interface{}, args ...interface{}
|
||||||
case slack.Attachment:
|
case slack.Attachment:
|
||||||
opts = append(opts, slack.MsgOptionAttachments(append([]slack.Attachment{a}, slackAttachments...)...))
|
opts = append(opts, slack.MsgOptionAttachments(append([]slack.Attachment{a}, slackAttachments...)...))
|
||||||
|
|
||||||
case slackAttachmentCreator:
|
case types.SlackAttachmentCreator:
|
||||||
// convert object to slack attachment (if supported)
|
// convert object to slack attachment (if supported)
|
||||||
opts = append(opts, slack.MsgOptionAttachments(append([]slack.Attachment{a.SlackAttachment()}, slackAttachments...)...))
|
opts = append(opts, slack.MsgOptionAttachments(append([]slack.Attachment{a.SlackAttachment()}, slackAttachments...)...))
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ func init() {
|
||||||
bbgo.RegisterStrategy(ID, &Strategy{})
|
bbgo.RegisterStrategy(ID, &Strategy{})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
- on: binance
|
- on: binance
|
||||||
autoborrow:
|
autoborrow:
|
||||||
interval: 30m
|
interval: 30m
|
||||||
|
@ -32,15 +32,51 @@ func init() {
|
||||||
# minMarginLevel for triggering auto borrow
|
# minMarginLevel for triggering auto borrow
|
||||||
minMarginLevel: 1.5
|
minMarginLevel: 1.5
|
||||||
assets:
|
assets:
|
||||||
|
|
||||||
- asset: ETH
|
- asset: ETH
|
||||||
low: 3.0
|
low: 3.0
|
||||||
maxQuantityPerBorrow: 1.0
|
maxQuantityPerBorrow: 1.0
|
||||||
maxTotalBorrow: 10.0
|
maxTotalBorrow: 10.0
|
||||||
|
|
||||||
- asset: USDT
|
- asset: USDT
|
||||||
low: 1000.0
|
low: 1000.0
|
||||||
maxQuantityPerBorrow: 100.0
|
maxQuantityPerBorrow: 100.0
|
||||||
maxTotalBorrow: 10.0
|
maxTotalBorrow: 10.0
|
||||||
*/
|
*/
|
||||||
|
type MarginAlert struct {
|
||||||
|
CurrentMarginLevel fixedpoint.Value
|
||||||
|
MinimalMarginLevel fixedpoint.Value
|
||||||
|
SlackMentions []string
|
||||||
|
SessionName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MarginAlert) SlackAttachment() slack.Attachment {
|
||||||
|
return slack.Attachment{
|
||||||
|
Color: "red",
|
||||||
|
Title: fmt.Sprintf("Margin Level Alert: %s session - current margin level %f < required margin level %f",
|
||||||
|
m.SessionName, m.CurrentMarginLevel.Float64(), m.MinimalMarginLevel.Float64()),
|
||||||
|
Text: strings.Join(m.SlackMentions, " "),
|
||||||
|
Fields: []slack.AttachmentField{
|
||||||
|
{
|
||||||
|
Title: "Session",
|
||||||
|
Value: m.SessionName,
|
||||||
|
Short: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Title: "Current Margin Level",
|
||||||
|
Value: m.CurrentMarginLevel.String(),
|
||||||
|
Short: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Title: "Minimal Margin Level",
|
||||||
|
Value: m.MinimalMarginLevel.String(),
|
||||||
|
Short: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Footer: "",
|
||||||
|
// FooterIcon: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type MarginAsset struct {
|
type MarginAsset struct {
|
||||||
Asset string `json:"asset"`
|
Asset string `json:"asset"`
|
||||||
|
@ -57,6 +93,8 @@ type Strategy struct {
|
||||||
MaxMarginLevel fixedpoint.Value `json:"maxMarginLevel"`
|
MaxMarginLevel fixedpoint.Value `json:"maxMarginLevel"`
|
||||||
AutoRepayWhenDeposit bool `json:"autoRepayWhenDeposit"`
|
AutoRepayWhenDeposit bool `json:"autoRepayWhenDeposit"`
|
||||||
|
|
||||||
|
MarginLevelAlertInterval types.Duration `json:"marginLevelAlertInterval"`
|
||||||
|
MarginLevelAlertMinMargin fixedpoint.Value `json:"marginLevelAlertMinMargin"`
|
||||||
MarginLevelAlertSlackMentions []string `json:"marginLevelAlertSlackMentions"`
|
MarginLevelAlertSlackMentions []string `json:"marginLevelAlertSlackMentions"`
|
||||||
|
|
||||||
Assets []MarginAsset `json:"assets"`
|
Assets []MarginAsset `json:"assets"`
|
||||||
|
@ -510,6 +548,39 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !s.MarginLevelAlertMinMargin.IsZero() {
|
||||||
|
alertInterval := time.Minute * 5
|
||||||
|
if s.MarginLevelAlertInterval > 0 {
|
||||||
|
alertInterval = s.MarginLevelAlertInterval.Duration()
|
||||||
|
}
|
||||||
|
|
||||||
|
go s.marginAlertWorker(ctx, alertInterval)
|
||||||
|
}
|
||||||
|
|
||||||
go s.run(ctx, s.Interval.Duration())
|
go s.run(ctx, s.Interval.Duration())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) marginAlertWorker(ctx context.Context, alertInterval time.Duration) {
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(alertInterval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
account := s.ExchangeSession.GetAccount()
|
||||||
|
if account.MarginLevel.Compare(s.MarginLevelAlertMinMargin) <= 0 {
|
||||||
|
bbgo.Notify(&MarginAlert{
|
||||||
|
CurrentMarginLevel: account.MarginLevel,
|
||||||
|
MinimalMarginLevel: s.MarginLevelAlertMinMargin,
|
||||||
|
SlackMentions: s.MarginLevelAlertSlackMentions,
|
||||||
|
SessionName: s.ExchangeSession.Name,
|
||||||
|
})
|
||||||
|
bbgo.Notify(account.Balances().Debts())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
|
@ -89,6 +89,7 @@ func ParseSimpleDuration(s string) (*SimpleDuration, error) {
|
||||||
return nil, errors.Wrapf(ErrNotSimpleDuration, "input %q is not a simple duration", s)
|
return nil, errors.Wrapf(ErrNotSimpleDuration, "input %q is not a simple duration", s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Duration
|
||||||
type Duration time.Duration
|
type Duration time.Duration
|
||||||
|
|
||||||
func (d *Duration) Duration() time.Duration {
|
func (d *Duration) Duration() time.Duration {
|
||||||
|
|
7
pkg/types/slack.go
Normal file
7
pkg/types/slack.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import "github.com/slack-go/slack"
|
||||||
|
|
||||||
|
type SlackAttachmentCreator interface {
|
||||||
|
SlackAttachment() slack.Attachment
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user