add deposit2transfer strategy

This commit is contained in:
c9s 2023-08-05 19:03:14 +08:00
parent 85201d0b57
commit 0c6b68c4f6
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
2 changed files with 242 additions and 0 deletions

View 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
// }]
// }
// }
}
}

View 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
}