From 36a746d415c2b1c609c97698baeaafce9047b9e4 Mon Sep 17 00:00:00 2001 From: zenix Date: Fri, 25 Feb 2022 12:30:40 +0900 Subject: [PATCH 1/3] add binance paper trade endpoint --- pkg/exchange/binance/exchange.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pkg/exchange/binance/exchange.go b/pkg/exchange/binance/exchange.go index 204871045..71b38f34a 100644 --- a/pkg/exchange/binance/exchange.go +++ b/pkg/exchange/binance/exchange.go @@ -29,9 +29,13 @@ import ( const BNB = "BNB" const BinanceUSBaseURL = "https://api.binance.us" +const BinanceTestBaseURL = "https://testnet.binance.vision" const BinanceUSWebSocketURL = "wss://stream.binance.us:9443" const WebSocketURL = "wss://stream.binance.com:9443" +const WebSocketTestURL = "wss://testnet.binance.vision" +const FutureTestBaseURL = "https://testnet.binancefuture.com" const FuturesWebSocketURL = "wss://fstream.binance.com" +const FuturesWebSocketTestURL = "wss://stream.binancefuture.com" // 5 per second and a 2 initial bucket var orderLimiter = rate.NewLimiter(5, 2) @@ -56,6 +60,11 @@ func isBinanceUs() bool { return err == nil && v } +func paperTrade() bool { + v, err := strconv.ParseBool(os.Getenv("PAPER_TRADE")) + return err == nil && v +} + type Exchange struct { types.MarginSettings types.FuturesSettings @@ -80,6 +89,11 @@ func New(key, secret string) *Exchange { client.BaseURL = BinanceUSBaseURL } + if paperTrade() { + client.BaseURL = BinanceTestBaseURL + futuresClient.BaseURL = FutureTestBaseURL + } + var err error if len(key) > 0 && len(secret) > 0 { timeSetter.Do(func() { From 9cf835728c9e24a94f2f538e18e362c76642b3e0 Mon Sep 17 00:00:00 2001 From: zenix Date: Thu, 17 Mar 2022 21:06:40 +0900 Subject: [PATCH 2/3] fix: don't sync on reward/withdraw/deposit records when using testnet --- pkg/service/order.go | 1 - pkg/service/sync.go | 48 ++++++++++++++++++++++++++------------------ 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/pkg/service/order.go b/pkg/service/order.go index a32c368a1..7d6835022 100644 --- a/pkg/service/order.go +++ b/pkg/service/order.go @@ -40,7 +40,6 @@ func (s *OrderService) Sync(ctx context.Context, exchange types.Exchange, symbol symbol = futuresSettings.IsolatedFuturesSymbol } } - records, err := s.QueryLast(exchange.Name(), symbol, isMargin, isFutures, isIsolated, 50) if err != nil { diff --git a/pkg/service/sync.go b/pkg/service/sync.go index 5cbbc8380..f19dacaa1 100644 --- a/pkg/service/sync.go +++ b/pkg/service/sync.go @@ -3,6 +3,8 @@ package service import ( "context" "errors" + "os" + "strconv" "time" "github.com/c9s/bbgo/pkg/cache" @@ -23,6 +25,11 @@ type SyncService struct { DepositService *DepositService } +func paperTrade() bool { + v, err := strconv.ParseBool(os.Getenv("PAPER_TRADE")) + return err == nil && v +} + // SyncSessionSymbols syncs the trades from the given exchange session func (s *SyncService) SyncSessionSymbols(ctx context.Context, exchange types.Exchange, startTime time.Time, symbols ...string) error { markets, err := cache.LoadExchangeMarketsWithCache(ctx, exchange) @@ -44,27 +51,28 @@ func (s *SyncService) SyncSessionSymbols(ctx context.Context, exchange types.Exc } } - log.Infof("syncing %s deposit records...", exchange.Name()) - if err := s.DepositService.Sync(ctx, exchange); err != nil { - if err != ErrNotImplemented { - return err + if !paperTrade() { + log.Infof("syncing %s deposit records...", exchange.Name()) + if err := s.DepositService.Sync(ctx, exchange); err != nil { + if err != ErrNotImplemented { + return err + } + } + + log.Infof("syncing %s withdraw records...", exchange.Name()) + if err := s.WithdrawService.Sync(ctx, exchange); err != nil { + if err != ErrNotImplemented { + return err + } + } + + log.Infof("syncing %s reward records...", exchange.Name()) + if err := s.RewardService.Sync(ctx, exchange); err != nil { + if err != ErrExchangeRewardServiceNotImplemented { + log.Infof("%s reward service is not supported", exchange.Name()) + return err + } } } - - log.Infof("syncing %s withdraw records...", exchange.Name()) - if err := s.WithdrawService.Sync(ctx, exchange); err != nil { - if err != ErrNotImplemented { - return err - } - } - - log.Infof("syncing %s reward records...", exchange.Name()) - if err := s.RewardService.Sync(ctx, exchange); err != nil { - if err != ErrExchangeRewardServiceNotImplemented { - log.Infof("%s reward service is not supported", exchange.Name()) - return err - } - } - return nil } From 84dbae159226adcc6bf4d258ada4484bcd8fabbe Mon Sep 17 00:00:00 2001 From: zenix Date: Thu, 17 Mar 2022 21:15:25 +0900 Subject: [PATCH 3/3] add readme content about testnet, fix code syntax --- README.md | 9 ++++++ pkg/exchange/binance/exchange.go | 5 ++-- pkg/service/sync.go | 50 +++++++++++++++++--------------- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index b99e832db..0ae2f1216 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,15 @@ bbgo pnl --exchange binance --asset BTC --since "2019-01-01" ## Advanced Configuration +### Testnet (Paper Trading) + +Currently only supports binance testnet. +To run bbgo in testnet, apply new API keys from [Binance Test Network](https://testnet.binance.vision), and set the following env before you start bbgo: +```bash +export PAPER_TRADE=1 +export DISABLE_MARKET_CACHE=1 # the symbols supported in testnet is far less than the mainnet +``` + ### Notification - [Setting up Telegram notification](./doc/configuration/telegram.md) diff --git a/pkg/exchange/binance/exchange.go b/pkg/exchange/binance/exchange.go index 71b38f34a..31ead73dc 100644 --- a/pkg/exchange/binance/exchange.go +++ b/pkg/exchange/binance/exchange.go @@ -24,6 +24,7 @@ import ( "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" + "github.com/c9s/bbgo/pkg/util" ) const BNB = "BNB" @@ -61,8 +62,8 @@ func isBinanceUs() bool { } func paperTrade() bool { - v, err := strconv.ParseBool(os.Getenv("PAPER_TRADE")) - return err == nil && v + v, ok := util.GetEnvVarBool("PAPER_TRADE") + return ok && v } type Exchange struct { diff --git a/pkg/service/sync.go b/pkg/service/sync.go index f19dacaa1..5a072a0a9 100644 --- a/pkg/service/sync.go +++ b/pkg/service/sync.go @@ -3,8 +3,6 @@ package service import ( "context" "errors" - "os" - "strconv" "time" "github.com/c9s/bbgo/pkg/cache" @@ -12,6 +10,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/c9s/bbgo/pkg/types" + "github.com/c9s/bbgo/pkg/util" ) var ErrNotImplemented = errors.New("not implemented") @@ -26,8 +25,8 @@ type SyncService struct { } func paperTrade() bool { - v, err := strconv.ParseBool(os.Getenv("PAPER_TRADE")) - return err == nil && v + v, ok := util.GetEnvVarBool("PAPER_TRADE") + return ok && v } // SyncSessionSymbols syncs the trades from the given exchange session @@ -51,28 +50,31 @@ func (s *SyncService) SyncSessionSymbols(ctx context.Context, exchange types.Exc } } - if !paperTrade() { - log.Infof("syncing %s deposit records...", exchange.Name()) - if err := s.DepositService.Sync(ctx, exchange); err != nil { - if err != ErrNotImplemented { - return err - } - } + if paperTrade() { + return nil + } - log.Infof("syncing %s withdraw records...", exchange.Name()) - if err := s.WithdrawService.Sync(ctx, exchange); err != nil { - if err != ErrNotImplemented { - return err - } - } - - log.Infof("syncing %s reward records...", exchange.Name()) - if err := s.RewardService.Sync(ctx, exchange); err != nil { - if err != ErrExchangeRewardServiceNotImplemented { - log.Infof("%s reward service is not supported", exchange.Name()) - return err - } + log.Infof("syncing %s deposit records...", exchange.Name()) + if err := s.DepositService.Sync(ctx, exchange); err != nil { + if err != ErrNotImplemented { + return err } } + + log.Infof("syncing %s withdraw records...", exchange.Name()) + if err := s.WithdrawService.Sync(ctx, exchange); err != nil { + if err != ErrNotImplemented { + return err + } + } + + log.Infof("syncing %s reward records...", exchange.Name()) + if err := s.RewardService.Sync(ctx, exchange); err != nil { + if err != ErrExchangeRewardServiceNotImplemented { + log.Infof("%s reward service is not supported", exchange.Name()) + return err + } + } + return nil }