Merge pull request #956 from c9s/improve/max-borrowable

improve: bbgo: use margin asset borrowable amount to adjust the quantity
This commit is contained in:
Yo-An Lin 2022-09-19 09:47:23 +08:00 committed by GitHub
commit 8e8979645d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 27 deletions

View File

@ -66,36 +66,35 @@ func (e *GeneralOrderExecutor) startMarginAssetUpdater(ctx context.Context) {
go e.marginAssetMaxBorrowableUpdater(ctx, 30*time.Minute, marginService, e.position.Market) go e.marginAssetMaxBorrowableUpdater(ctx, 30*time.Minute, marginService, e.position.Market)
} }
func (e *GeneralOrderExecutor) updateMarginAssetMaxBorrowable(ctx context.Context, marginService types.MarginBorrowRepayService, market types.Market) {
maxBorrowable, err := marginService.QueryMarginAssetMaxBorrowable(ctx, market.BaseCurrency)
if err != nil {
log.WithError(err).Errorf("can not query margin base asset max borrowable")
} else {
log.Infof("updating margin base asset %s max borrowable amount: %f", market.BaseCurrency, maxBorrowable.Float64())
e.marginBaseMaxBorrowable = maxBorrowable
}
maxBorrowable, err = marginService.QueryMarginAssetMaxBorrowable(ctx, market.QuoteCurrency)
if err != nil {
log.WithError(err).Errorf("can not query margin base asset max borrowable")
} else {
log.Infof("updating margin quote asset %s max borrowable amount: %f", market.QuoteCurrency, maxBorrowable.Float64())
e.marginQuoteMaxBorrowable = maxBorrowable
}
}
func (e *GeneralOrderExecutor) marginAssetMaxBorrowableUpdater(ctx context.Context, interval time.Duration, marginService types.MarginBorrowRepayService, market types.Market) { func (e *GeneralOrderExecutor) marginAssetMaxBorrowableUpdater(ctx context.Context, interval time.Duration, marginService types.MarginBorrowRepayService, market types.Market) {
t1 := time.NewTicker(util.MillisecondsJitter(30*time.Minute, 500)) t := time.NewTicker(util.MillisecondsJitter(interval, 500))
t2 := time.NewTicker(util.MillisecondsJitter(30*time.Minute, 500)) defer t.Stop()
defer t1.Stop()
defer t2.Stop()
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return
case <-t1.C: case <-t.C:
maxBorrowable, err := marginService.QueryMarginAssetMaxBorrowable(ctx, market.BaseCurrency) e.updateMarginAssetMaxBorrowable(ctx, marginService, market)
if err != nil {
log.WithError(err).Errorf("can not query margin base asset max borrowable")
continue
}
log.Infof("updating margin base asset %s max borrowable amount: %f", market.BaseCurrency, maxBorrowable.Float64())
e.marginBaseMaxBorrowable = maxBorrowable
case <-t2.C:
maxBorrowable, err := marginService.QueryMarginAssetMaxBorrowable(ctx, market.QuoteCurrency)
if err != nil {
log.WithError(err).Errorf("can not query margin base asset max borrowable")
continue
}
log.Infof("updating margin quote asset %s max borrowable amount: %f", market.QuoteCurrency, maxBorrowable.Float64())
e.marginQuoteMaxBorrowable = maxBorrowable
} }
} }
} }
@ -257,6 +256,12 @@ func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPos
quantity = quoteQuantity.Div(price) quantity = quoteQuantity.Div(price)
} }
quoteQuantity := quantity.Mul(price)
if quoteQuantity.Compare(e.marginQuoteMaxBorrowable) > 0 {
log.Warnf("adjusting quantity %f according to the max margin quote borrowable amount: %f", quantity.Float64(), e.marginQuoteMaxBorrowable.Float64())
quantity = AdjustQuantityByMaxAmount(quantity, price, e.marginQuoteMaxBorrowable)
}
submitOrder.Side = types.SideTypeBuy submitOrder.Side = types.SideTypeBuy
submitOrder.Quantity = quantity submitOrder.Quantity = quantity
@ -265,7 +270,8 @@ func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPos
if err2 != nil { if err2 != nil {
return err2 return err2
} }
_ = createdOrder
log.Infof("created order: %+v", createdOrder)
return nil return nil
} else if options.Short { } else if options.Short {
if quantity.IsZero() { if quantity.IsZero() {
@ -276,6 +282,11 @@ func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPos
} }
} }
if quantity.Compare(e.marginBaseMaxBorrowable) > 0 {
log.Warnf("adjusting %f quantity according to the max margin base borrowable amount: %f", quantity.Float64(), e.marginBaseMaxBorrowable.Float64())
quantity = fixedpoint.Min(quantity, e.marginBaseMaxBorrowable)
}
submitOrder.Side = types.SideTypeSell submitOrder.Side = types.SideTypeSell
submitOrder.Quantity = quantity submitOrder.Quantity = quantity
@ -284,7 +295,8 @@ func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPos
if err2 != nil { if err2 != nil {
return err2 return err2
} }
_ = createdOrder
log.Infof("created order: %+v", createdOrder)
return nil return nil
} }

View File

@ -1,8 +1,9 @@
package bbgo package bbgo
import ( import (
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/c9s/bbgo/pkg/fixedpoint"
) )
var ( var (
@ -14,7 +15,7 @@ var (
ErrAssetBalanceLevelTooHigh = errors.New("asset balance level too high") ErrAssetBalanceLevelTooHigh = errors.New("asset balance level too high")
) )
// AdjustQuantityByMaxAmount adjusts the quantity to make the amount greater than the given minAmount // AdjustQuantityByMaxAmount adjusts the quantity to make the amount less than the given maxAmount
func AdjustQuantityByMaxAmount(quantity, currentPrice, maxAmount fixedpoint.Value) fixedpoint.Value { func AdjustQuantityByMaxAmount(quantity, currentPrice, maxAmount fixedpoint.Value) fixedpoint.Value {
// modify quantity for the min amount // modify quantity for the min amount
amount := currentPrice.Mul(quantity) amount := currentPrice.Mul(quantity)