From 4d3b1ec938eca61a03f7de55b98762452d930f74 Mon Sep 17 00:00:00 2001 From: c9s Date: Sat, 13 Mar 2021 20:49:51 +0800 Subject: [PATCH] fix QueryWithdrawHistory and QueryDepositHistory --- pkg/exchange/binance/exchange.go | 20 +++++++++++- pkg/exchange/max/exchange.go | 56 +++++++++++++++++++++++++------- pkg/service/reward.go | 2 +- pkg/service/sync.go | 5 +-- pkg/service/withdraw.go | 34 +++++++++++++++++++ pkg/types/withdraw.go | 5 +++ 6 files changed, 106 insertions(+), 16 deletions(-) diff --git a/pkg/exchange/binance/exchange.go b/pkg/exchange/binance/exchange.go index f6fc5d480..43f16f44f 100644 --- a/pkg/exchange/binance/exchange.go +++ b/pkg/exchange/binance/exchange.go @@ -194,9 +194,27 @@ func (e *Exchange) QueryIsolatedMarginAccount(ctx context.Context, symbols ...st return toGlobalIsolatedMarginAccount(account), nil } -func (e *Exchange) QueryWithdrawHistory(ctx context.Context, asset string, since, until time.Time) (allWithdraws []types.Withdraw, err error) { +func (e *Exchange) getLaunchDate() (time.Time, error) { + // binance launch date 12:00 July 14th, 2017 + loc, err := time.LoadLocation("Asia/Shanghai") + if err != nil { + return time.Time{}, err + } + return time.Date(2017, time.July, 14, 0, 0, 0, 0, loc), nil +} + +func (e *Exchange) QueryWithdrawHistory(ctx context.Context, asset string, since, until time.Time) (allWithdraws []types.Withdraw, err error) { startTime := since + + var emptyTime = time.Time{} + if startTime == emptyTime { + startTime, err = e.getLaunchDate() + if err != nil { + return nil, err + } + } + txIDs := map[string]struct{}{} for startTime.Before(until) { diff --git a/pkg/exchange/max/exchange.go b/pkg/exchange/max/exchange.go index 129f7d454..2eed16286 100644 --- a/pkg/exchange/max/exchange.go +++ b/pkg/exchange/max/exchange.go @@ -377,6 +377,16 @@ func (e *Exchange) PlatformFeeCurrency() string { return toGlobalCurrency("max") } +func (e *Exchange) getLaunchDate() (time.Time, error) { + // MAX launch date June 21th, 2018 + loc, err := time.LoadLocation("Asia/Taipei") + if err != nil { + return time.Time{}, err + } + + return time.Date(2018, time.June, 21, 0, 0, 0, 0, loc), nil +} + func (e *Exchange) QueryAccount(ctx context.Context) (*types.Account, error) { if err := accountQueryLimiter.Wait(ctx); err != nil { return nil, err @@ -407,10 +417,19 @@ func (e *Exchange) QueryAccount(ctx context.Context) (*types.Account, error) { func (e *Exchange) QueryWithdrawHistory(ctx context.Context, asset string, since, until time.Time) (allWithdraws []types.Withdraw, err error) { startTime := since + limit := 1000 txIDs := map[string]struct{}{} + emptyTime := time.Time{} + if startTime == emptyTime { + startTime, err = e.getLaunchDate() + if err != nil { + return nil, err + } + } + for startTime.Before(until) { - // startTime ~ endTime must be in 90 days + // startTime ~ endTime must be in 60 days endTime := startTime.AddDate(0, 0, 60) if endTime.After(until) { endTime = until @@ -425,12 +444,18 @@ func (e *Exchange) QueryWithdrawHistory(ctx context.Context, asset string, since withdraws, err := req. From(startTime.Unix()). To(endTime.Unix()). + Limit(limit). Do(ctx) if err != nil { return allWithdraws, err } + if len(withdraws) == 0 { + startTime = endTime + continue + } + for _, d := range withdraws { if _, ok := txIDs[d.TxID]; ok { continue @@ -456,7 +481,7 @@ func (e *Exchange) QueryWithdrawHistory(ctx context.Context, asset string, since } txIDs[d.TxID] = struct{}{} - allWithdraws = append(allWithdraws, types.Withdraw{ + withdraw := types.Withdraw{ Exchange: types.ExchangeMax, ApplyTime: datatype.Time(time.Unix(d.CreatedAt, 0)), Asset: toGlobalCurrency(d.Currency), @@ -468,10 +493,17 @@ func (e *Exchange) QueryWithdrawHistory(ctx context.Context, asset string, since // WithdrawOrderID: d.WithdrawOrderID, // Network: d.Network, Status: status, - }) + } + allWithdraws = append(allWithdraws, withdraw) + } + + // go next time frame + if len(withdraws) < limit { + startTime = endTime + } else { + startTime = time.Unix(withdraws[len(withdraws)-1].UpdatedAt, 0) } - startTime = endTime } return allWithdraws, nil @@ -507,14 +539,14 @@ func (e *Exchange) QueryDepositHistory(ctx context.Context, asset string, since, } allDeposits = append(allDeposits, types.Deposit{ - Exchange: types.ExchangeMax, - Time: datatype.Time(time.Unix(d.CreatedAt, 0)), - Amount: util.MustParseFloat(d.Amount), - Asset: toGlobalCurrency(d.Currency), - Address: "", // not supported - AddressTag: "", // not supported - TransactionID: d.TxID, - Status: toGlobalDepositStatus(d.State), + Exchange: types.ExchangeMax, + Time: datatype.Time(time.Unix(d.CreatedAt, 0)), + Amount: util.MustParseFloat(d.Amount), + Asset: toGlobalCurrency(d.Currency), + Address: "", // not supported + AddressTag: "", // not supported + TransactionID: d.TxID, + Status: toGlobalDepositStatus(d.State), }) } diff --git a/pkg/service/reward.go b/pkg/service/reward.go index fee94e911..8d09c8a16 100644 --- a/pkg/service/reward.go +++ b/pkg/service/reward.go @@ -36,7 +36,7 @@ func (s *RewardService) QueryLast(ex types.ExchangeName, limit int) ([]types.Rew func (s *RewardService) Sync(ctx context.Context, exchange types.Exchange) error { service, ok := exchange.(types.ExchangeRewardService) if !ok { - return ErrNotImplemented + return ErrExchangeRewardServiceNotImplemented } var rewardKeys = map[string]struct{}{} diff --git a/pkg/service/sync.go b/pkg/service/sync.go index 23b2e7970..74cae1181 100644 --- a/pkg/service/sync.go +++ b/pkg/service/sync.go @@ -8,7 +8,8 @@ import ( "github.com/c9s/bbgo/pkg/types" ) -var ErrNotImplemented = errors.New("exchange does not implement ExchangeRewardService interface") +var ErrNotImplemented = errors.New("not implemented") +var ErrExchangeRewardServiceNotImplemented = errors.New("exchange does not implement ExchangeRewardService interface") type SyncService struct { TradeService *TradeService @@ -31,7 +32,7 @@ func (s *SyncService) SyncSessionSymbols(ctx context.Context, exchange types.Exc } if err := s.RewardService.Sync(ctx, exchange); err != nil { - if err != ErrNotImplemented { + if err != ErrExchangeRewardServiceNotImplemented { return err } } diff --git a/pkg/service/withdraw.go b/pkg/service/withdraw.go index 3091cc645..7c2fe8f14 100644 --- a/pkg/service/withdraw.go +++ b/pkg/service/withdraw.go @@ -1,6 +1,9 @@ package service import ( + "context" + "time" + "github.com/jmoiron/sqlx" "github.com/c9s/bbgo/pkg/types" @@ -10,6 +13,37 @@ type WithdrawService struct { DB *sqlx.DB } +func (s *WithdrawService) Sync(ctx context.Context, ex types.Exchange) error { + txnIDs := map[string]struct{}{} + + records, err := s.QueryLast(ex.Name(), 10) + if err != nil { + return err + } + + for _, record := range records { + txnIDs[record.TransactionID] = struct{}{} + } + + transferApi, ok := ex.(types.ExchangeTransferService) + if !ok { + return ErrNotImplemented + } + + withdraws, err := transferApi.QueryWithdrawHistory(ctx, "", records[0].ApplyTime.Time(), time.Now()) + if err != nil { + return err + } + + for _, withdraw := range withdraws { + if _, exists := txnIDs[withdraw.TransactionID] ; exists { + continue + } + } + + return nil +} + func (s *WithdrawService) QueryLast(ex types.ExchangeName, limit int) ([]types.Withdraw, error) { sql := "SELECT * FROM `withdraws` WHERE `exchange` = :exchange ORDER BY `time` DESC LIMIT :limit" rows, err := s.DB.NamedQuery(sql, map[string]interface{}{ diff --git a/pkg/types/withdraw.go b/pkg/types/withdraw.go index 02748fe9f..d3ea2501d 100644 --- a/pkg/types/withdraw.go +++ b/pkg/types/withdraw.go @@ -1,6 +1,7 @@ package types import ( + "fmt" "time" "github.com/c9s/bbgo/pkg/datatype" @@ -23,6 +24,10 @@ type Withdraw struct { Network string `json:"network" db:"network"` } +func (w Withdraw) String() string { + return fmt.Sprintf("withdraw %s %f to %s at %s", w.Asset, w.Amount, w.Address, w.ApplyTime.Time()) +} + func (w Withdraw) EffectiveTime() time.Time { return w.ApplyTime.Time() }