mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
add deposit2transfer strategy
This commit is contained in:
parent
85201d0b57
commit
0c6b68c4f6
138
pkg/strategy/deposit2transfer/strategy.go
Normal file
138
pkg/strategy/deposit2transfer/strategy.go
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
package deposit2transfer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
"github.com/c9s/bbgo/pkg/exchange/binance"
|
||||||
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ID = "deposit2transfer"
|
||||||
|
|
||||||
|
var log = logrus.WithField("strategy", ID)
|
||||||
|
|
||||||
|
var errNotBinanceExchange = errors.New("not binance exchange, currently only support binance exchange")
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Register the pointer of the strategy struct,
|
||||||
|
// so that bbgo knows what struct to be used to unmarshal the configs (YAML or JSON)
|
||||||
|
// Note: built-in strategies need to imported manually in the bbgo cmd package.
|
||||||
|
bbgo.RegisterStrategy(ID, &Strategy{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Strategy struct {
|
||||||
|
Environment *bbgo.Environment
|
||||||
|
|
||||||
|
Interval types.Interval `json:"interval"`
|
||||||
|
|
||||||
|
SpotSession string `json:"spotSession"`
|
||||||
|
FuturesSession string `json:"futuresSession"`
|
||||||
|
|
||||||
|
spotSession, futuresSession *bbgo.ExchangeSession
|
||||||
|
|
||||||
|
binanceFutures, binanceSpot *binance.Exchange
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) ID() string {
|
||||||
|
return ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {}
|
||||||
|
|
||||||
|
func (s *Strategy) Defaults() error {
|
||||||
|
if s.Interval == "" {
|
||||||
|
s.Interval = types.Interval1m
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) Validate() error {
|
||||||
|
if len(s.SpotSession) == 0 {
|
||||||
|
return errors.New("spotSession name is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.FuturesSession) == 0 {
|
||||||
|
return errors.New("futuresSession name is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) InstanceID() string {
|
||||||
|
return fmt.Sprintf("%s", ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
|
||||||
|
var ok bool
|
||||||
|
s.binanceFutures, ok = session.Exchange.(*binance.Exchange)
|
||||||
|
if !ok {
|
||||||
|
return errNotBinanceExchange
|
||||||
|
}
|
||||||
|
|
||||||
|
s.binanceSpot, ok = session.Exchange.(*binance.Exchange)
|
||||||
|
if !ok {
|
||||||
|
return errNotBinanceExchange
|
||||||
|
}
|
||||||
|
|
||||||
|
// instanceID := s.InstanceID()
|
||||||
|
/*
|
||||||
|
if err := s.transferIn(ctx, s.binanceSpot, s.spotMarket.BaseCurrency, fixedpoint.Zero); err != nil {
|
||||||
|
log.WithError(err).Errorf("futures asset transfer in error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.transferOut(ctx, s.binanceSpot, s.spotMarket.BaseCurrency, fixedpoint.Zero); err != nil {
|
||||||
|
log.WithError(err).Errorf("futures asset transfer out error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := backoff.RetryGeneral(ctx, func() error {
|
||||||
|
return s.transferIn(ctx, s.binanceSpot, s.spotMarket.BaseCurrency, trade.Quantity)
|
||||||
|
}); err != nil {
|
||||||
|
log.WithError(err).Errorf("spot-to-futures transfer in retry failed")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := backoff.RetryGeneral(ctx, func() error {
|
||||||
|
return s.transferOut(ctx, s.binanceSpot, s.spotMarket.BaseCurrency, quantity)
|
||||||
|
}); err != nil {
|
||||||
|
log.WithError(err).Errorf("spot-to-futures transfer in retry failed")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if binanceStream, ok := s.futuresSession.UserDataStream.(*binance.Stream); ok {
|
||||||
|
binanceStream.OnAccountUpdateEvent(func(e *binance.AccountUpdateEvent) {
|
||||||
|
s.handleAccountUpdate(ctx, e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) handleAccountUpdate(ctx context.Context, e *binance.AccountUpdateEvent) {
|
||||||
|
switch e.AccountUpdate.EventReasonType {
|
||||||
|
case binance.AccountUpdateEventReasonDeposit:
|
||||||
|
case binance.AccountUpdateEventReasonWithdraw:
|
||||||
|
case binance.AccountUpdateEventReasonFundingFee:
|
||||||
|
// EventBase:{
|
||||||
|
// Event:ACCOUNT_UPDATE
|
||||||
|
// Time:1679760000932
|
||||||
|
// }
|
||||||
|
// Transaction:1679760000927
|
||||||
|
// AccountUpdate:{
|
||||||
|
// EventReasonType:FUNDING_FEE
|
||||||
|
// Balances:[{
|
||||||
|
// Asset:USDT
|
||||||
|
// WalletBalance:56.64251742
|
||||||
|
// CrossWalletBalance:56.64251742
|
||||||
|
// BalanceChange:-0.00037648
|
||||||
|
// }]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
104
pkg/strategy/deposit2transfer/transfer.go
Normal file
104
pkg/strategy/deposit2transfer/transfer.go
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
package deposit2transfer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FuturesTransfer interface {
|
||||||
|
TransferFuturesAccountAsset(ctx context.Context, asset string, amount fixedpoint.Value, io types.TransferDirection) error
|
||||||
|
QueryAccountBalances(ctx context.Context) (types.BalanceMap, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) resetTransfer(ctx context.Context, ex FuturesTransfer, asset string) error {
|
||||||
|
balances, err := s.futuresSession.Exchange.QueryAccountBalances(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, ok := balances[asset]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
amount := b.MaxWithdrawAmount
|
||||||
|
if amount.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("transfering out futures account asset %s %s", amount, asset)
|
||||||
|
|
||||||
|
err = ex.TransferFuturesAccountAsset(ctx, asset, amount, types.TransferOut)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) transferOut(ctx context.Context, ex FuturesTransfer, asset string, quantity fixedpoint.Value) error {
|
||||||
|
balances, err := s.futuresSession.Exchange.QueryAccountBalances(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, ok := balances[asset]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("%s balance not found", asset)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("found futures balance: %+v", b)
|
||||||
|
|
||||||
|
// add the previous pending base transfer and the current trade quantity
|
||||||
|
amount := b.MaxWithdrawAmount
|
||||||
|
|
||||||
|
// try to transfer more if we enough balance
|
||||||
|
amount = fixedpoint.Min(amount, b.MaxWithdrawAmount)
|
||||||
|
|
||||||
|
// TODO: according to the fee, we might not be able to get enough balance greater than the trade quantity, we can adjust the quantity here
|
||||||
|
if amount.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// de-leverage and get the collateral base quantity
|
||||||
|
collateralBase := s.FuturesPosition.GetBase().Abs().Div(s.Leverage)
|
||||||
|
_ = collateralBase
|
||||||
|
|
||||||
|
// if s.State.TotalBaseTransfer.Compare(collateralBase)
|
||||||
|
|
||||||
|
log.Infof("transfering out futures account asset %s %s", amount, asset)
|
||||||
|
if err := ex.TransferFuturesAccountAsset(ctx, asset, amount, types.TransferOut); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) transferIn(ctx context.Context, ex FuturesTransfer, asset string, quantity fixedpoint.Value) error {
|
||||||
|
balances, err := s.spotSession.Exchange.QueryAccountBalances(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, ok := balances[asset]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("%s balance not found", asset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: according to the fee, we might not be able to get enough balance greater than the trade quantity, we can adjust the quantity here
|
||||||
|
if !quantity.IsZero() && b.Available.Compare(quantity) < 0 {
|
||||||
|
log.Infof("adding to pending base transfer: %s %s", quantity, asset)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
amount := b.Available
|
||||||
|
|
||||||
|
log.Infof("transfering in futures account asset %s %s", amount, asset)
|
||||||
|
if err := ex.TransferFuturesAccountAsset(ctx, asset, amount, types.TransferIn); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user