xmaker: improve balance checking

This commit is contained in:
c9s 2021-03-21 12:43:41 +08:00
parent 948e555f51
commit 814a77ea39
7 changed files with 36 additions and 10 deletions

View File

@ -72,7 +72,7 @@ riskControls:
crossExchangeStrategies: crossExchangeStrategies:
- mobydick: - xmaker:
symbol: BTCUSDT symbol: BTCUSDT
sourceExchange: binance sourceExchange: binance
makerExchange: max makerExchange: max

View File

@ -63,11 +63,11 @@ riskControls:
crossExchangeStrategies: crossExchangeStrategies:
- mobydick: - xmaker:
symbol: ETHUSDT symbol: ETHUSDT
sourceExchange: binance sourceExchange: binance
makerExchange: max makerExchange: max
updateInterval: 1s updateInterval: 2s
# disableHedge disables the hedge orders on the source exchange # disableHedge disables the hedge orders on the source exchange
# disableHedge: true # disableHedge: true
@ -78,7 +78,7 @@ crossExchangeStrategies:
askMargin: 0.004 askMargin: 0.004
bidMargin: 0.004 bidMargin: 0.004
quantity: 0.1 quantity: 0.01
quantityMultiplier: 2 quantityMultiplier: 2
# numLayers means how many order we want to place on each side. 3 means we want 3 bid orders and 3 ask orders # numLayers means how many order we want to place on each side. 3 means we want 3 bid orders and 3 ask orders

View File

@ -49,7 +49,7 @@ sessions:
crossExchangeStrategies: crossExchangeStrategies:
- mobydick: - xmaker:
symbol: "BTCUSDT" symbol: "BTCUSDT"
sourceExchange: binance sourceExchange: binance
makerExchange: max makerExchange: max

View File

@ -173,6 +173,8 @@ func (trader *Trader) Subscribe() {
for _, strategy := range strategies { for _, strategy := range strategies {
if subscriber, ok := strategy.(ExchangeSessionSubscriber); ok { if subscriber, ok := strategy.(ExchangeSessionSubscriber); ok {
subscriber.Subscribe(session) subscriber.Subscribe(session)
} else {
log.Errorf("strategy %s does not implement ExchangeSessionSubscriber", strategy.ID())
} }
} }
} }
@ -180,6 +182,8 @@ func (trader *Trader) Subscribe() {
for _, strategy := range trader.crossExchangeStrategies { for _, strategy := range trader.crossExchangeStrategies {
if subscriber, ok := strategy.(CrossExchangeSessionSubscriber); ok { if subscriber, ok := strategy.(CrossExchangeSessionSubscriber); ok {
subscriber.CrossSubscribe(trader.environment.sessions) subscriber.CrossSubscribe(trader.environment.sessions)
} else {
log.Errorf("strategy %s does not implement CrossExchangeSessionSubscriber", strategy.ID())
} }
} }
} }

View File

@ -11,5 +11,6 @@ import (
_ "github.com/c9s/bbgo/pkg/strategy/support" _ "github.com/c9s/bbgo/pkg/strategy/support"
_ "github.com/c9s/bbgo/pkg/strategy/swing" _ "github.com/c9s/bbgo/pkg/strategy/swing"
_ "github.com/c9s/bbgo/pkg/strategy/trailingstop" _ "github.com/c9s/bbgo/pkg/strategy/trailingstop"
_ "github.com/c9s/bbgo/pkg/strategy/xmaker"
_ "github.com/c9s/bbgo/pkg/strategy/xpuremaker" _ "github.com/c9s/bbgo/pkg/strategy/xpuremaker"
) )

View File

@ -501,7 +501,7 @@ func (r *CreateOrderRequest) Do(ctx context.Context) (order *Order, err error) {
payload["group_id"] = r.groupID payload["group_id"] = r.groupID
} }
req, err := r.client.newAuthenticatedRequest("POST", "v2/orders", &payload) req, err := r.client.newAuthenticatedRequest("POST", "v2/orders", payload)
if err != nil { if err != nil {
return order, errors.Wrapf(err, "order create error") return order, errors.Wrapf(err, "order create error")
} }

View File

@ -82,11 +82,16 @@ type Strategy struct {
func (s *Strategy) CrossSubscribe(sessions map[string]*bbgo.ExchangeSession) { func (s *Strategy) CrossSubscribe(sessions map[string]*bbgo.ExchangeSession) {
sourceSession, ok := sessions[s.SourceExchange] sourceSession, ok := sessions[s.SourceExchange]
if !ok { if !ok {
panic(fmt.Errorf("source exchange %s is not defined", s.SourceExchange)) panic(fmt.Errorf("source session %s is not defined", s.SourceExchange))
} }
log.Infof("subscribing %s from %s", s.Symbol, s.SourceExchange)
sourceSession.Subscribe(types.BookChannel, s.Symbol, types.SubscribeOptions{}) sourceSession.Subscribe(types.BookChannel, s.Symbol, types.SubscribeOptions{})
makerSession, ok := sessions[s.MakerExchange]
if !ok {
panic(fmt.Errorf("maker session %s is not defined", s.MakerExchange))
}
makerSession.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: "1m"})
} }
func (s *Strategy) updateQuote(ctx context.Context) { func (s *Strategy) updateQuote(ctx context.Context) {
@ -104,7 +109,7 @@ func (s *Strategy) updateQuote(ctx context.Context) {
} }
if valid, err := sourceBook.IsValid(); !valid { if valid, err := sourceBook.IsValid(); !valid {
log.WithError(err).Error("invalid order book: %v", err) log.WithError(err).Errorf("invalid order book: %v", err)
return return
} }
@ -131,9 +136,18 @@ func (s *Strategy) updateQuote(ctx context.Context) {
makerQuota := &bbgo.QuotaTransaction{} makerQuota := &bbgo.QuotaTransaction{}
if b, ok := makerBalances[s.makerMarket.BaseCurrency]; ok { if b, ok := makerBalances[s.makerMarket.BaseCurrency]; ok {
makerQuota.BaseAsset.Add(b.Available) makerQuota.BaseAsset.Add(b.Available)
if b.Available.Float64() <= s.makerMarket.MinQuantity {
disableMakerAsk = true
} }
}
if b, ok := makerBalances[s.makerMarket.QuoteCurrency]; ok { if b, ok := makerBalances[s.makerMarket.QuoteCurrency]; ok {
makerQuota.QuoteAsset.Add(b.Available) makerQuota.QuoteAsset.Add(b.Available)
if b.Available.Float64() <= s.makerMarket.MinNotional {
disableMakerBid = true
}
} }
hedgeBalances := s.sourceSession.Account.Balances() hedgeBalances := s.sourceSession.Account.Balances()
@ -141,6 +155,7 @@ func (s *Strategy) updateQuote(ctx context.Context) {
if b, ok := hedgeBalances[s.sourceMarket.BaseCurrency]; ok { if b, ok := hedgeBalances[s.sourceMarket.BaseCurrency]; ok {
hedgeQuota.BaseAsset.Add(b.Available) hedgeQuota.BaseAsset.Add(b.Available)
// to make bid orders, we need enough base asset in the foreign exchange,
// if the base asset balance is not enough for selling // if the base asset balance is not enough for selling
if b.Available.Float64() <= s.sourceMarket.MinQuantity { if b.Available.Float64() <= s.sourceMarket.MinQuantity {
disableMakerBid = true disableMakerBid = true
@ -150,12 +165,18 @@ func (s *Strategy) updateQuote(ctx context.Context) {
if b, ok := hedgeBalances[s.sourceMarket.QuoteCurrency]; ok { if b, ok := hedgeBalances[s.sourceMarket.QuoteCurrency]; ok {
hedgeQuota.QuoteAsset.Add(b.Available) hedgeQuota.QuoteAsset.Add(b.Available)
// to make ask orders, we need enough quote asset in the foreign exchange,
// if the quote asset balance is not enough for buying // if the quote asset balance is not enough for buying
if b.Available.Float64() <= s.sourceMarket.MinNotional { if b.Available.Float64() <= s.sourceMarket.MinNotional {
disableMakerAsk = true disableMakerAsk = true
} }
} }
if disableMakerAsk && disableMakerBid {
log.Warn("maker is disabled due to insufficient balances")
return
}
for i := 0; i < s.NumLayers; i++ { for i := 0; i < s.NumLayers; i++ {
// for maker bid orders // for maker bid orders
if !disableMakerBid { if !disableMakerBid {
@ -376,7 +397,7 @@ func (s *Strategy) CrossRun(ctx context.Context, _ bbgo.OrderExecutionRouter, se
} }
// restore state // restore state
instanceID := fmt.Sprintf("%s-%s-%s", ID, s.Symbol) instanceID := fmt.Sprintf("%s-%s", ID, s.Symbol)
s.groupID = generateGroupID(instanceID) s.groupID = generateGroupID(instanceID)
log.Infof("using group id %d from fnv(%s)", s.groupID, instanceID) log.Infof("using group id %d from fnv(%s)", s.groupID, instanceID)