techsignal: add funding rate checker

This commit is contained in:
c9s 2021-10-14 23:01:10 +08:00
parent e7fe443cbe
commit 4523135012
2 changed files with 86 additions and 4 deletions

View File

@ -911,19 +911,35 @@ func (e *Exchange) BatchQueryKLines(ctx context.Context, symbol string, interval
return allKLines, nil
}
func (e *Exchange) QueryLastFundingRate(ctx context.Context, symbol string) (fixedpoint.Value, error) {
type FundingRate struct {
FundingRate fixedpoint.Value
FundingTime time.Time
Time time.Time
}
func (e *Exchange) QueryLastFundingRate(ctx context.Context, symbol string) (*FundingRate, error) {
futuresClient := binance.NewFuturesClient(e.key, e.secret)
rates, err := futuresClient.NewFundingRateService().
Symbol(symbol).
Limit(1).
Do(ctx)
if err != nil {
return 0, err
return nil, err
}
if len(rates) == 0 {
return 0, errors.New("empty funding rate data")
return nil, errors.New("empty funding rate data")
}
return fixedpoint.NewFromString(rates[0].FundingRate)
rate := rates[0]
fundingRate, err := fixedpoint.NewFromString(rate.FundingRate)
if err != nil {
return nil, err
}
return &FundingRate{
FundingRate: fundingRate,
FundingTime: time.Unix(0, rate.FundingTime*int64(time.Millisecond)),
Time: time.Unix(0, rate.Time*int64(time.Millisecond)),
}, nil
}

View File

@ -4,10 +4,12 @@ import (
"context"
"errors"
"fmt"
"github.com/c9s/bbgo/pkg/exchange/binance"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/leekchan/accounting"
"github.com/sirupsen/logrus"
"strings"
"time"
"github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/types"
@ -31,6 +33,12 @@ type Strategy struct {
Symbol string `json:"symbol"`
Market types.Market `json:"-"`
FundingRate *struct {
High fixedpoint.Value `json:"high"`
Neutral fixedpoint.Value `json:"neutral"`
DiffThreshold fixedpoint.Value `json:"diffThreshold"`
} `json:"fundingRate"`
SupportDetection []struct {
Interval types.Interval `json:"interval"`
@ -74,12 +82,70 @@ func (s *Strategy) Validate() error {
return nil
}
func (s *Strategy) listenToFundingRate(ctx context.Context, exchange *binance.Exchange) {
var previousFundingRate, fundingRate24HoursLow *binance.FundingRate
fundingRateTicker := time.NewTicker(1 * time.Hour)
defer fundingRateTicker.Stop()
for {
select {
case <-ctx.Done():
return
case <-fundingRateTicker.C:
fundingRate, err := exchange.QueryLastFundingRate(ctx, s.Symbol)
if err != nil {
log.WithError(err).Error("can not query last funding rate")
continue
}
if fundingRate.FundingRate >= s.FundingRate.High {
s.Notifiability.Notify("%s funding rate is too high! %s > %s",
s.Symbol,
fundingRate.FundingRate.Percentage(),
s.FundingRate.High.Percentage(),
)
}
if previousFundingRate != nil {
diff := fundingRate.FundingRate - previousFundingRate.FundingRate
if diff > fixedpoint.NewFromFloat(0.001*0.01) {
s.Notifiability.Notify("%s funding rate changed %s -> %s",
s.Symbol,
diff.Percentage(),
fundingRate.FundingRate.Percentage(),
)
}
}
previousFundingRate = fundingRate
if fundingRate24HoursLow != nil {
if fundingRate24HoursLow.Time.Before(time.Now().Add(24 * time.Hour)) {
fundingRate24HoursLow = fundingRate
}
if fundingRate.FundingRate < fundingRate24HoursLow.FundingRate {
fundingRate24HoursLow = fundingRate
}
} else {
fundingRate24HoursLow = fundingRate
}
}
}
}
func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
standardIndicatorSet, ok := session.StandardIndicatorSet(s.Symbol)
if !ok {
return fmt.Errorf("standardIndicatorSet is nil, symbol %s", s.Symbol)
}
if s.FundingRate != nil {
if binanceExchange, ok := session.Exchange.(*binance.Exchange); ok {
go s.listenToFundingRate(ctx, binanceExchange)
} else {
log.Error("exchange does not support funding rate api")
}
}
session.MarketDataStream.OnKLineClosed(func(kline types.KLine) {
// skip k-lines from other symbols
if kline.Symbol != s.Symbol {