mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
Merge pull request #559 from c9s/feature/binance-margin-api
feature: autoborrow strategy
This commit is contained in:
commit
a663a891bf
25
config/autoborrow.yaml
Normal file
25
config/autoborrow.yaml
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
exchangeStrategies:
|
||||
- on: binance
|
||||
autoborrow:
|
||||
interval: 30m
|
||||
autoRepayWhenDeposit: true
|
||||
|
||||
# minMarginRatio for triggering auto borrow
|
||||
# we trigger auto borrow only when the margin ratio is above the number
|
||||
minMarginRatio: 1.5
|
||||
|
||||
# maxMarginRatio for stop auto-repay
|
||||
# if the margin ratio is high enough, we don't have the urge to repay
|
||||
maxMarginRatio: 10.0
|
||||
|
||||
assets:
|
||||
- asset: ETH
|
||||
low: 3.0
|
||||
maxQuantityPerBorrow: 1.0
|
||||
maxTotalBorrow: 10.0
|
||||
- asset: USDT
|
||||
low: 1000.0
|
||||
maxQuantityPerBorrow: 100.0
|
||||
maxTotalBorrow: 10.0
|
||||
minMarginRatio: 1.3
|
|
@ -114,7 +114,7 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
|
|||
}
|
||||
|
||||
message := "Your balances\n"
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
for _, balance := range balances {
|
||||
if balance.Total().IsZero() {
|
||||
continue
|
||||
|
|
|
@ -136,7 +136,7 @@ type BasicRiskController struct {
|
|||
// 2. Decrease the quantity by risk controls
|
||||
// 3. If the quantity does not meet minimal requirement, we should ignore the submit order.
|
||||
func (c *BasicRiskController) ProcessOrders(session *ExchangeSession, orders ...types.SubmitOrder) (outOrders []types.SubmitOrder, errs []error) {
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
|
||||
addError := func(err error) {
|
||||
errs = append(errs, err)
|
||||
|
|
|
@ -282,6 +282,13 @@ func NewExchangeSession(name string, exchange types.Exchange) *ExchangeSession {
|
|||
return session
|
||||
}
|
||||
|
||||
func (session *ExchangeSession) GetAccount() (a *types.Account) {
|
||||
session.accountMutex.Lock()
|
||||
a = session.Account
|
||||
session.accountMutex.Unlock()
|
||||
return a
|
||||
}
|
||||
|
||||
// UpdateAccount locks the account mutex and update the account object
|
||||
func (session *ExchangeSession) UpdateAccount(ctx context.Context) error {
|
||||
account, err := session.Exchange.QueryAccount(ctx)
|
||||
|
@ -641,7 +648,7 @@ func (session *ExchangeSession) UpdatePrices(ctx context.Context) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
|
||||
var symbols []string
|
||||
for _, b := range balances {
|
||||
|
@ -681,7 +688,7 @@ func (session *ExchangeSession) FindPossibleSymbols() (symbols []string, err err
|
|||
}, nil
|
||||
}
|
||||
|
||||
var balances = session.Account.Balances()
|
||||
var balances = session.GetAccount().Balances()
|
||||
var fiatAssets []string
|
||||
|
||||
for _, currency := range types.FiatCurrencies {
|
||||
|
|
|
@ -161,13 +161,13 @@ func (e *TwapExecution) newBestPriceOrder() (orderForm types.SubmitOrder, err er
|
|||
switch e.Side {
|
||||
case types.SideTypeSell:
|
||||
// check base balance for sell, try to sell as more as possible
|
||||
if b, ok := e.Session.Account.Balance(e.market.BaseCurrency); ok {
|
||||
if b, ok := e.Session.GetAccount().Balance(e.market.BaseCurrency); ok {
|
||||
orderQuantity = fixedpoint.Min(b.Available, orderQuantity)
|
||||
}
|
||||
|
||||
case types.SideTypeBuy:
|
||||
// check base balance for sell, try to sell as more as possible
|
||||
if b, ok := e.Session.Account.Balance(e.market.QuoteCurrency); ok {
|
||||
if b, ok := e.Session.GetAccount().Balance(e.market.QuoteCurrency); ok {
|
||||
orderQuantity = AdjustQuantityByMaxAmount(orderQuantity, newPrice, b.Available)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -380,7 +380,7 @@ var BacktestCmd = &cobra.Command{
|
|||
report.Print()
|
||||
|
||||
initBalances := userConfig.Backtest.Account[exchangeName].Balances.BalanceMap()
|
||||
finalBalances := session.Account.Balances()
|
||||
finalBalances := session.GetAccount().Balances()
|
||||
|
||||
log.Infof("INITIAL BALANCES:")
|
||||
initBalances.Print()
|
||||
|
|
|
@ -2,6 +2,7 @@ package cmd
|
|||
|
||||
// import built-in strategies
|
||||
import (
|
||||
_ "github.com/c9s/bbgo/pkg/strategy/autoborrow"
|
||||
_ "github.com/c9s/bbgo/pkg/strategy/bollgrid"
|
||||
_ "github.com/c9s/bbgo/pkg/strategy/bollmaker"
|
||||
_ "github.com/c9s/bbgo/pkg/strategy/emastop"
|
||||
|
|
|
@ -249,6 +249,7 @@ func (e *Exchange) RepayMarginAsset(ctx context.Context, asset string, amount fi
|
|||
req.IsolatedSymbol(e.IsolatedMarginSymbol)
|
||||
}
|
||||
|
||||
log.Infof("repaying margin asset %s amount %f", asset, amount.Float64())
|
||||
resp, err := req.Do(ctx)
|
||||
log.Debugf("margin repayed %f %s, transaction id = %d", amount.Float64(), asset, resp.TranID)
|
||||
return err
|
||||
|
@ -262,6 +263,7 @@ func (e *Exchange) BorrowMarginAsset(ctx context.Context, asset string, amount f
|
|||
req.IsolatedSymbol(e.IsolatedMarginSymbol)
|
||||
}
|
||||
|
||||
log.Infof("borrowing margin asset %s amount %f", asset, amount.Float64())
|
||||
resp, err := req.Do(ctx)
|
||||
log.Debugf("margin borrowed %f %s, transaction id = %d", amount.Float64(), asset, resp.TranID)
|
||||
return err
|
||||
|
|
|
@ -380,7 +380,7 @@ func (s *Server) getSessionAccount(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"account": session.Account})
|
||||
c.JSON(http.StatusOK, gin.H{"account": session.GetAccount()})
|
||||
}
|
||||
|
||||
func (s *Server) getSessionAccountBalance(c *gin.Context) {
|
||||
|
@ -397,7 +397,7 @@ func (s *Server) getSessionAccountBalance(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"balances": session.Account.Balances()})
|
||||
c.JSON(http.StatusOK, gin.H{"balances": session.GetAccount().Balances()})
|
||||
}
|
||||
|
||||
func (s *Server) listSessionOpenOrders(c *gin.Context) {
|
||||
|
@ -458,7 +458,7 @@ func (s *Server) listAssets(c *gin.Context) {
|
|||
|
||||
totalAssets := types.AssetMap{}
|
||||
for _, session := range s.Environ.Sessions() {
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
|
||||
if err := session.UpdatePrices(c); err != nil {
|
||||
logrus.WithError(err).Error("price update failed")
|
||||
|
|
215
pkg/strategy/autoborrow/strategy.go
Normal file
215
pkg/strategy/autoborrow/strategy.go
Normal file
|
@ -0,0 +1,215 @@
|
|||
package autoborrow
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/exchange/binance"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
const ID = "autoborrow"
|
||||
|
||||
var log = logrus.WithField("strategy", ID)
|
||||
|
||||
func init() {
|
||||
bbgo.RegisterStrategy(ID, &Strategy{})
|
||||
}
|
||||
|
||||
/**
|
||||
- on: binance
|
||||
autoborrow:
|
||||
interval: 30m
|
||||
repayWhenDeposit: true
|
||||
|
||||
# minMarginRatio for triggering auto borrow
|
||||
minMarginRatio: 1.5
|
||||
assets:
|
||||
- asset: ETH
|
||||
low: 3.0
|
||||
maxQuantityPerBorrow: 1.0
|
||||
maxTotalBorrow: 10.0
|
||||
- asset: USDT
|
||||
low: 1000.0
|
||||
maxQuantityPerBorrow: 100.0
|
||||
maxTotalBorrow: 10.0
|
||||
*/
|
||||
|
||||
type MarginAsset struct {
|
||||
Asset string `json:"asset"`
|
||||
Low fixedpoint.Value `json:"low"`
|
||||
MaxTotalBorrow fixedpoint.Value `json:"maxTotalBorrow"`
|
||||
MaxQuantityPerBorrow fixedpoint.Value `json:"maxQuantityPerBorrow"`
|
||||
MinQuantityPerBorrow fixedpoint.Value `json:"minQuantityPerBorrow"`
|
||||
}
|
||||
|
||||
type Strategy struct {
|
||||
Interval types.Interval `json:"interval"`
|
||||
MinMarginRatio fixedpoint.Value `json:"minMarginRatio"`
|
||||
MaxMarginRatio fixedpoint.Value `json:"maxMarginRatio"`
|
||||
AutoRepayWhenDeposit bool `json:"autoRepayWhenDeposit"`
|
||||
|
||||
Assets []MarginAsset `json:"assets"`
|
||||
|
||||
ExchangeSession *bbgo.ExchangeSession
|
||||
|
||||
marginBorrowRepay types.MarginBorrowRepay
|
||||
}
|
||||
|
||||
func (s *Strategy) ID() string {
|
||||
return ID
|
||||
}
|
||||
|
||||
func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
|
||||
// session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: "1m"})
|
||||
}
|
||||
|
||||
func (s *Strategy) checkAndBorrow(ctx context.Context) {
|
||||
if s.MinMarginRatio.IsZero() {
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.ExchangeSession.UpdateAccount(ctx) ; err != nil {
|
||||
log.WithError(err).Errorf("can not update account")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// if margin ratio is too low, do not borrow
|
||||
if s.ExchangeSession.GetAccount().MarginRatio.Compare(s.MinMarginRatio) < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
balances := s.ExchangeSession.GetAccount().Balances()
|
||||
for _, marginAsset := range s.Assets {
|
||||
if marginAsset.Low.IsZero() {
|
||||
log.Warnf("margin asset low balance is not set: %+v", marginAsset)
|
||||
continue
|
||||
}
|
||||
|
||||
b, ok := balances[marginAsset.Asset]
|
||||
if ok {
|
||||
toBorrow := marginAsset.Low.Sub(b.Total())
|
||||
if toBorrow.Sign() < 0 {
|
||||
log.Debugf("no need to borrow asset %+v", marginAsset)
|
||||
continue
|
||||
}
|
||||
|
||||
if !marginAsset.MaxQuantityPerBorrow.IsZero() {
|
||||
toBorrow = fixedpoint.Min(toBorrow, marginAsset.MaxQuantityPerBorrow)
|
||||
}
|
||||
|
||||
if !marginAsset.MaxTotalBorrow.IsZero() {
|
||||
// check if we over borrow
|
||||
if toBorrow.Add(b.Borrowed).Compare(marginAsset.MaxTotalBorrow) > 0 {
|
||||
toBorrow = toBorrow.Sub( toBorrow.Add(b.Borrowed).Sub(marginAsset.MaxTotalBorrow) )
|
||||
if toBorrow.Sign() < 0 {
|
||||
log.Warnf("margin asset %s is over borrowed, skip", marginAsset.Asset)
|
||||
continue
|
||||
}
|
||||
}
|
||||
toBorrow = fixedpoint.Min(toBorrow.Add(b.Borrowed), marginAsset.MaxTotalBorrow)
|
||||
}
|
||||
|
||||
s.marginBorrowRepay.BorrowMarginAsset(ctx, marginAsset.Asset, toBorrow)
|
||||
} else {
|
||||
// available balance is less than marginAsset.Low, we should trigger borrow
|
||||
toBorrow := marginAsset.Low
|
||||
|
||||
if !marginAsset.MaxQuantityPerBorrow.IsZero() {
|
||||
toBorrow = fixedpoint.Min(toBorrow, marginAsset.MaxQuantityPerBorrow)
|
||||
}
|
||||
|
||||
s.marginBorrowRepay.BorrowMarginAsset(ctx, marginAsset.Asset, toBorrow)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Strategy) run(ctx context.Context, interval time.Duration) {
|
||||
ticker := time.NewTicker(interval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
case <-ticker.C:
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Strategy) handleBalanceUpdate(balances types.BalanceMap) {
|
||||
if s.MinMarginRatio.IsZero() {
|
||||
return
|
||||
}
|
||||
|
||||
if s.ExchangeSession.GetAccount().MarginRatio.Compare(s.MinMarginRatio) > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, b := range balances {
|
||||
if b.Available.IsZero() && b.Borrowed.IsZero() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Strategy) handleBinanceBalanceUpdateEvent(event *binance.BalanceUpdateEvent) {
|
||||
if s.MinMarginRatio.IsZero() {
|
||||
return
|
||||
}
|
||||
|
||||
if s.ExchangeSession.GetAccount().MarginRatio.Compare(s.MinMarginRatio) > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
delta := fixedpoint.MustNewFromString(event.Delta)
|
||||
|
||||
// ignore outflow
|
||||
if delta.Sign() < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if b, ok := s.ExchangeSession.GetAccount().Balance(event.Asset); ok {
|
||||
if b.Available.IsZero() || b.Borrowed.IsZero() {
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.marginBorrowRepay.RepayMarginAsset(context.Background(), event.Asset, b.Available); err != nil {
|
||||
log.WithError(err).Errorf("margin repay error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This strategy simply spent all available quote currency to buy the symbol whenever kline gets closed
|
||||
func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
|
||||
if s.MinMarginRatio.IsZero() {
|
||||
log.Warnf("minMarginRatio is 0, you should configure this minimal margin ratio for controlling the liquidation risk")
|
||||
}
|
||||
|
||||
marginBorrowRepay, ok := session.Exchange.(types.MarginBorrowRepay)
|
||||
if !ok {
|
||||
return fmt.Errorf("exchange %s does not implement types.MarginBorrowRepay", session.ExchangeName)
|
||||
}
|
||||
|
||||
s.marginBorrowRepay = marginBorrowRepay
|
||||
|
||||
if s.AutoRepayWhenDeposit {
|
||||
binanceStream, ok := session.UserDataStream.(*binance.Stream)
|
||||
if ok {
|
||||
binanceStream.OnBalanceUpdateEvent(s.handleBinanceBalanceUpdateEvent)
|
||||
} else {
|
||||
session.UserDataStream.OnBalanceUpdate(s.handleBalanceUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
go s.run(ctx, s.Interval.Duration())
|
||||
return nil
|
||||
}
|
|
@ -116,7 +116,7 @@ func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
|
|||
}
|
||||
|
||||
func (s *Strategy) generateGridBuyOrders(session *bbgo.ExchangeSession) ([]types.SubmitOrder, error) {
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
quoteBalance := balances[s.Market.QuoteCurrency].Available
|
||||
if quoteBalance.Sign() <= 0 {
|
||||
return nil, fmt.Errorf("quote balance %s is zero: %v", s.Market.QuoteCurrency, quoteBalance)
|
||||
|
@ -181,7 +181,7 @@ func (s *Strategy) generateGridBuyOrders(session *bbgo.ExchangeSession) ([]types
|
|||
}
|
||||
|
||||
func (s *Strategy) generateGridSellOrders(session *bbgo.ExchangeSession) ([]types.SubmitOrder, error) {
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
baseBalance := balances[s.Market.BaseCurrency].Available
|
||||
if baseBalance.Sign() <= 0 {
|
||||
return nil, fmt.Errorf("base balance %s is zero: %+v", s.Market.BaseCurrency, baseBalance)
|
||||
|
@ -288,7 +288,7 @@ func (s *Strategy) updateOrders(orderExecutor bbgo.OrderExecutor, session *bbgo.
|
|||
}
|
||||
|
||||
func (s *Strategy) submitReverseOrder(order types.Order, session *bbgo.ExchangeSession) {
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
|
||||
var side = order.Side.Reverse()
|
||||
var price = order.Price
|
||||
|
|
|
@ -354,7 +354,7 @@ func (s *Strategy) placeOrders(ctx context.Context, orderExecutor bbgo.OrderExec
|
|||
askPrice := midPrice.Mul(fixedpoint.One.Add(askSpread))
|
||||
bidPrice := midPrice.Mul(fixedpoint.One.Sub(bidSpread))
|
||||
base := s.state.Position.GetBase()
|
||||
balances := s.session.Account.Balances()
|
||||
balances := s.session.GetAccount().Balances()
|
||||
|
||||
log.Infof("mid price:%v spread: %s ask:%v bid: %v position: %s",
|
||||
midPrice,
|
||||
|
|
|
@ -138,7 +138,7 @@ func (s *Strategy) place(ctx context.Context, orderExecutor bbgo.OrderExecutor,
|
|||
quantity := s.Quantity
|
||||
if s.BalancePercentage.Sign() > 0 {
|
||||
|
||||
if balance, ok := session.Account.Balance(market.BaseCurrency); ok {
|
||||
if balance, ok := session.GetAccount().Balance(market.BaseCurrency); ok {
|
||||
quantity = balance.Available.Mul(s.BalancePercentage)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@ package etf
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"time"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
|
@ -73,7 +75,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
quantity := askPrice.Div(amount)
|
||||
|
||||
// execute orders
|
||||
quoteBalance, ok := session.Account.Balance(s.Market.QuoteCurrency)
|
||||
quoteBalance, ok := session.GetAccount().Balance(s.Market.QuoteCurrency)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
|
|
@ -394,7 +394,7 @@ func (s *Strategy) validateOrder(order *types.SubmitOrder) bool {
|
|||
return false
|
||||
}
|
||||
if order.Side == types.SideTypeSell {
|
||||
baseBalance, ok := s.Session.Account.Balance(s.Market.BaseCurrency)
|
||||
baseBalance, ok := s.Session.GetAccount().Balance(s.Market.BaseCurrency)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
@ -416,7 +416,7 @@ func (s *Strategy) validateOrder(order *types.SubmitOrder) bool {
|
|||
}
|
||||
return true
|
||||
} else if order.Side == types.SideTypeBuy {
|
||||
quoteBalance, ok := s.Session.Account.Balance(s.Market.QuoteCurrency)
|
||||
quoteBalance, ok := s.Session.GetAccount().Balance(s.Market.QuoteCurrency)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
@ -492,7 +492,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
log.Errorf("cannot get last price")
|
||||
return
|
||||
}
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
baseBalance := balances[s.Market.BaseCurrency].Available
|
||||
quoteBalance := balances[s.Market.QuoteCurrency].Available
|
||||
/*if buyPrice.IsZero() {
|
||||
|
@ -580,7 +580,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
buyall = true
|
||||
}
|
||||
if sellall {
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
baseBalance := balances[s.Market.BaseCurrency].Available.Mul(modifier)
|
||||
order := types.SubmitOrder{
|
||||
Symbol: s.Symbol,
|
||||
|
@ -602,7 +602,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
}
|
||||
|
||||
if buyall {
|
||||
quoteBalance, ok := session.Account.Balance(s.Market.QuoteCurrency)
|
||||
quoteBalance, ok := session.GetAccount().Balance(s.Market.QuoteCurrency)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -664,7 +664,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
} else {
|
||||
price = kline.Low
|
||||
}
|
||||
quoteBalance, ok := session.Account.Balance(s.Market.QuoteCurrency)
|
||||
quoteBalance, ok := session.GetAccount().Balance(s.Market.QuoteCurrency)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -691,7 +691,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
} else {
|
||||
price = kline.High
|
||||
}
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
baseBalance := balances[s.Market.BaseCurrency].Available.Mul(modifier)
|
||||
order := types.SubmitOrder{
|
||||
Symbol: s.Symbol,
|
||||
|
|
|
@ -71,7 +71,7 @@ func (s *Strategy) updateOrders(orderExecutor bbgo.OrderExecutor, session *bbgo.
|
|||
|
||||
func (s *Strategy) updateBidOrders(orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) {
|
||||
quoteCurrency := s.Market.QuoteCurrency
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
|
||||
balance, ok := balances[quoteCurrency]
|
||||
if !ok || balance.Available.Sign() <= 0 {
|
||||
|
|
|
@ -4,10 +4,12 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/exchange/binance"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/sirupsen/logrus"
|
||||
"strings"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
|
@ -178,7 +180,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
)
|
||||
s.Notifiability.Notify(kline)
|
||||
|
||||
baseBalance, ok := session.Account.Balance(s.Market.BaseCurrency)
|
||||
baseBalance, ok := session.GetAccount().Balance(s.Market.BaseCurrency)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ func (s *Strategy) generateGridSellOrders(session *bbgo.ExchangeSession) ([]type
|
|||
s.UpperPrice)
|
||||
}
|
||||
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
baseBalance, ok := balances[s.Market.BaseCurrency]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("base balance %s not found", s.Market.BaseCurrency)
|
||||
|
@ -268,7 +268,7 @@ func (s *Strategy) generateGridBuyOrders(session *bbgo.ExchangeSession) ([]types
|
|||
s.UpperPrice)
|
||||
}
|
||||
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
balance, ok := balances[s.Market.QuoteCurrency]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("quote balance %s not found", s.Market.QuoteCurrency)
|
||||
|
|
|
@ -91,7 +91,7 @@ func (s *Strategy) rebalance(ctx context.Context, orderExecutor bbgo.OrderExecut
|
|||
return
|
||||
}
|
||||
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
quantities := s.getQuantities(balances)
|
||||
marketValues := prices.Mul(quantities)
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
// execute orders
|
||||
switch side {
|
||||
case types.SideTypeBuy:
|
||||
quoteBalance, ok := session.Account.Balance(s.Market.QuoteCurrency)
|
||||
quoteBalance, ok := session.GetAccount().Balance(s.Market.QuoteCurrency)
|
||||
if !ok {
|
||||
log.Errorf("can not place scheduled %s order, quote balance %s is empty", s.Symbol, s.Market.QuoteCurrency)
|
||||
return
|
||||
|
@ -153,7 +153,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
}
|
||||
|
||||
case types.SideTypeSell:
|
||||
baseBalance, ok := session.Account.Balance(s.Market.BaseCurrency)
|
||||
baseBalance, ok := session.GetAccount().Balance(s.Market.BaseCurrency)
|
||||
if !ok {
|
||||
log.Errorf("can not place scheduled %s order, base balance %s is empty", s.Symbol, s.Market.BaseCurrency)
|
||||
return
|
||||
|
|
|
@ -41,7 +41,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
return nil
|
||||
}
|
||||
callback := func(kline types.KLine) {
|
||||
quoteBalance, ok := session.Account.Balance(market.QuoteCurrency)
|
||||
quoteBalance, ok := session.GetAccount().Balance(market.QuoteCurrency)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -388,7 +388,7 @@ func (s *Strategy) calculateQuantity(session *bbgo.ExchangeSession, side types.S
|
|||
quantity = fixedpoint.NewFromFloat(q)
|
||||
}
|
||||
|
||||
baseBalance, _ := session.Account.Balance(s.Market.BaseCurrency)
|
||||
baseBalance, _ := session.GetAccount().Balance(s.Market.BaseCurrency)
|
||||
if side == types.SideTypeSell {
|
||||
// quantity = bbgo.AdjustQuantityByMaxAmount(quantity, closePrice, quota)
|
||||
if s.MinBaseAssetBalance.Sign() > 0 &&
|
||||
|
@ -404,7 +404,7 @@ func (s *Strategy) calculateQuantity(session *bbgo.ExchangeSession, side types.S
|
|||
quantity = bbgo.AdjustQuantityByMaxAmount(quantity, closePrice, quota)
|
||||
}
|
||||
|
||||
quoteBalance, ok := session.Account.Balance(s.Market.QuoteCurrency)
|
||||
quoteBalance, ok := session.GetAccount().Balance(s.Market.QuoteCurrency)
|
||||
if !ok {
|
||||
return fixedpoint.Zero, fmt.Errorf("quote balance %s not found", s.Market.QuoteCurrency)
|
||||
}
|
||||
|
|
|
@ -7,14 +7,15 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/slack-go/slack"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/c9s/bbgo/pkg/service"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
"github.com/c9s/bbgo/pkg/util"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/slack-go/slack"
|
||||
)
|
||||
|
||||
const ID = "xbalance"
|
||||
|
@ -174,7 +175,7 @@ func (s *Strategy) checkBalance(ctx context.Context, sessions map[string]*bbgo.E
|
|||
|
||||
var total fixedpoint.Value
|
||||
for _, session := range sessions {
|
||||
if b, ok := session.Account.Balance(s.Asset); ok {
|
||||
if b, ok := session.GetAccount().Balance(s.Asset); ok {
|
||||
total = total.Add(b.Total())
|
||||
}
|
||||
}
|
||||
|
@ -296,7 +297,7 @@ func (s *Strategy) findHighestBalanceLevelSession(sessions map[string]*bbgo.Exch
|
|||
return nil, balance, fmt.Errorf("session %s does not exist", sessionID)
|
||||
}
|
||||
|
||||
if b, ok := session.Account.Balance(s.Asset); ok {
|
||||
if b, ok := session.GetAccount().Balance(s.Asset); ok {
|
||||
if b.Available.Sub(requiredAmount).Compare(s.Low) > 0 && b.Available.Compare(maxBalanceLevel) > 0 {
|
||||
maxBalanceLevel = b.Available
|
||||
maxBalanceSession = session
|
||||
|
@ -316,7 +317,7 @@ func (s *Strategy) findLowBalanceLevelSession(sessions map[string]*bbgo.Exchange
|
|||
return nil, balance, fmt.Errorf("session %s does not exist", sessionID)
|
||||
}
|
||||
|
||||
balance, ok = session.Account.Balance(s.Asset)
|
||||
balance, ok = session.GetAccount().Balance(s.Asset)
|
||||
if ok {
|
||||
if balance.Available.Compare(s.Low) <= 0 {
|
||||
return session, balance, nil
|
||||
|
|
|
@ -316,7 +316,7 @@ func (s *Strategy) CrossRun(ctx context.Context, _ bbgo.OrderExecutionRouter, se
|
|||
|
||||
log.Infof("mid price %v", midPrice)
|
||||
|
||||
var balances = s.tradingSession.Account.Balances()
|
||||
var balances = s.tradingSession.GetAccount().Balances()
|
||||
var quantity = s.tradingMarket.MinQuantity
|
||||
|
||||
if s.Quantity.Sign() > 0 {
|
||||
|
|
|
@ -209,7 +209,7 @@ func (s *Strategy) updateQuote(ctx context.Context, orderExecutionRouter bbgo.Or
|
|||
// check maker's balance quota
|
||||
// we load the balances from the account while we're generating the orders,
|
||||
// the balance may have a chance to be deducted by other strategies or manual orders submitted by the user
|
||||
makerBalances := s.makerSession.Account.Balances()
|
||||
makerBalances := s.makerSession.GetAccount().Balances()
|
||||
makerQuota := &bbgo.QuotaTransaction{}
|
||||
if b, ok := makerBalances[s.makerMarket.BaseCurrency]; ok {
|
||||
if b.Available.Compare(s.makerMarket.MinQuantity) > 0 {
|
||||
|
@ -227,7 +227,7 @@ func (s *Strategy) updateQuote(ctx context.Context, orderExecutionRouter bbgo.Or
|
|||
}
|
||||
}
|
||||
|
||||
hedgeBalances := s.sourceSession.Account.Balances()
|
||||
hedgeBalances := s.sourceSession.GetAccount().Balances()
|
||||
hedgeQuota := &bbgo.QuotaTransaction{}
|
||||
if b, ok := hedgeBalances[s.sourceMarket.BaseCurrency]; ok {
|
||||
// to make bid orders, we need enough base asset in the foreign exchange,
|
||||
|
@ -503,7 +503,7 @@ func (s *Strategy) Hedge(ctx context.Context, pos fixedpoint.Value) {
|
|||
}
|
||||
|
||||
// adjust quantity according to the balances
|
||||
account := s.sourceSession.Account
|
||||
account := s.sourceSession.GetAccount()
|
||||
switch side {
|
||||
|
||||
case types.SideTypeBuy:
|
||||
|
|
|
@ -79,7 +79,7 @@ func (s *Strategy) recordNetAssetValue(ctx context.Context, sessions map[string]
|
|||
totalBalances := types.BalanceMap{}
|
||||
lastPrices := map[string]fixedpoint.Value{}
|
||||
for _, session := range sessions {
|
||||
balances := session.Account.Balances()
|
||||
balances := session.GetAccount().Balances()
|
||||
if err := session.UpdatePrices(ctx); err != nil {
|
||||
log.WithError(err).Error("price update failed")
|
||||
return
|
||||
|
|
|
@ -49,12 +49,12 @@ type MarginExchange interface {
|
|||
UseMargin()
|
||||
UseIsolatedMargin(symbol string)
|
||||
GetMarginSettings() MarginSettings
|
||||
// QueryMarginAccount(ctx context.Context) (*binance.MarginAccount, error)
|
||||
}
|
||||
|
||||
type MarginBorrowRepay interface {
|
||||
RepayMarginAsset(ctx context.Context, asset string, amount fixedpoint.Value) error
|
||||
BorrowMarginAsset(ctx context.Context, asset string, amount fixedpoint.Value) error
|
||||
QueryMarginAssetMaxBorrowable(ctx context.Context, asset string) (amount fixedpoint.Value, err error)
|
||||
}
|
||||
|
||||
type MarginSettings struct {
|
||||
|
|
Loading…
Reference in New Issue
Block a user