From 6079e7b06a2abbb6c15c89f102be006bc8ade42c Mon Sep 17 00:00:00 2001 From: c9s Date: Sat, 5 Oct 2024 13:09:31 +0800 Subject: [PATCH] all: refactor NewAccountValueCalculator --- pkg/bbgo/account_value_calc.go | 158 ++++++++++------------------ pkg/bbgo/account_value_calc_test.go | 59 +++-------- pkg/pricesolver/simple.go | 9 +- pkg/strategy/harmonic/strategy.go | 9 +- pkg/strategy/irr/strategy.go | 2 +- pkg/strategy/supertrend/strategy.go | 6 +- pkg/strategy/xmaker/strategy.go | 80 +++++++------- pkg/testing/testhelper/ticker.go | 13 ++- 8 files changed, 144 insertions(+), 192 deletions(-) diff --git a/pkg/bbgo/account_value_calc.go b/pkg/bbgo/account_value_calc.go index bdd60cc04..bc0e6d598 100644 --- a/pkg/bbgo/account_value_calc.go +++ b/pkg/bbgo/account_value_calc.go @@ -39,7 +39,6 @@ func NewAccountValueCalculator( priceSolver: priceSolver, session: session, quoteCurrency: quoteCurrency, - prices: make(map[string]fixedpoint.Value), tickers: make(map[string]types.Ticker), } } @@ -62,99 +61,69 @@ func (c *AccountValueCalculator) UpdatePrices(ctx context.Context) error { return c.priceSolver.UpdateFromTickers(ctx, c.session.Exchange, symbols...) } -func (c *AccountValueCalculator) DebtValue(ctx context.Context) (fixedpoint.Value, error) { - debtValue := fixedpoint.Zero - - if len(c.prices) == 0 { - if err := c.UpdatePrices(ctx); err != nil { - return debtValue, err - } - } - +func (c *AccountValueCalculator) DebtValue() fixedpoint.Value { balances := c.session.Account.Balances() - for _, b := range balances { - symbol := b.Currency + c.quoteCurrency - price, ok := c.prices[symbol] - if !ok { - continue - } - - debtValue = debtValue.Add(b.Debt().Mul(price)) - } - - return debtValue, nil + return totalValueInQuote(balances, c.priceSolver, c.quoteCurrency, func( + prev fixedpoint.Value, b types.Balance, price fixedpoint.Value, + ) fixedpoint.Value { + return prev.Add(b.Debt().Mul(price)) + }) } -func (c *AccountValueCalculator) MarketValue(ctx context.Context) (fixedpoint.Value, error) { - marketValue := fixedpoint.Zero - - if len(c.prices) == 0 { - if err := c.UpdatePrices(ctx); err != nil { - return marketValue, err - } - } - +func (c *AccountValueCalculator) MarketValue() fixedpoint.Value { balances := c.session.Account.Balances() - for _, b := range balances { - if b.Currency == c.quoteCurrency { - marketValue = marketValue.Add(b.Total()) - continue - } + return totalValueInQuote(balances, c.priceSolver, c.quoteCurrency, func( + prev fixedpoint.Value, b types.Balance, price fixedpoint.Value, + ) fixedpoint.Value { + return prev.Add(b.Total().Mul(price)) + }) - if c.priceSolver != nil { - if price, ok := c.priceSolver.ResolvePrice(b.Currency, c.quoteCurrency); ok { - marketValue = marketValue.Add(b.Total().Mul(price)) - } - } else { - symbol := b.Currency + c.quoteCurrency - if price, ok := c.prices[symbol]; ok { - marketValue = marketValue.Add(b.Total().Mul(price)) - } - } - } - - return marketValue, nil } -func (c *AccountValueCalculator) NetValue(ctx context.Context) (fixedpoint.Value, error) { - if len(c.prices) == 0 { - if err := c.UpdatePrices(ctx); err != nil { - return fixedpoint.Zero, err +func (c *AccountValueCalculator) NetValue() fixedpoint.Value { + balances := c.session.Account.Balances() + return totalValueInQuote(balances, c.priceSolver, c.quoteCurrency, func( + prev fixedpoint.Value, b types.Balance, price fixedpoint.Value, + ) fixedpoint.Value { + return prev.Add(b.Net().Mul(price)) + }) +} + +func totalValueInQuote( + balances types.BalanceMap, + priceSolver *pricesolver.SimplePriceSolver, + quoteCurrency string, + algo func(prev fixedpoint.Value, b types.Balance, price fixedpoint.Value) fixedpoint.Value, +) (totalValue fixedpoint.Value) { + totalValue = fixedpoint.Zero + + for _, b := range balances { + if b.Currency == quoteCurrency { + totalValue = algo(totalValue, b, fixedpoint.One) + continue + } else if price, ok := priceSolver.ResolvePrice(b.Currency, quoteCurrency); ok { + totalValue = algo(totalValue, b, price) } } - balances := c.session.Account.Balances() - accountValue := calculateNetValueInQuote(balances, c.priceSolver, c.quoteCurrency) - return accountValue, nil + return totalValue } func calculateNetValueInQuote( - balances types.BalanceMap, priceSolver *pricesolver.SimplePriceSolver, quoteCurrency string, -) (accountValue fixedpoint.Value) { - accountValue = fixedpoint.Zero - for _, b := range balances { - if b.Currency == quoteCurrency { - accountValue = accountValue.Add(b.Net()) - continue - } - - if price, ok := priceSolver.ResolvePrice(b.Currency, quoteCurrency); ok { - accountValue = accountValue.Add(b.Net().Mul(price)) - } - } - - return accountValue + balances types.BalanceMap, + priceSolver *pricesolver.SimplePriceSolver, + quoteCurrency string, +) fixedpoint.Value { + return totalValueInQuote(balances, priceSolver, quoteCurrency, func( + prev fixedpoint.Value, b types.Balance, price fixedpoint.Value, + ) fixedpoint.Value { + return prev.Add(b.Net().Mul(price)) + }) } -func (c *AccountValueCalculator) AvailableQuote(ctx context.Context) (fixedpoint.Value, error) { +func (c *AccountValueCalculator) AvailableQuote() (fixedpoint.Value, error) { accountValue := fixedpoint.Zero - if len(c.prices) == 0 { - if err := c.UpdatePrices(ctx); err != nil { - return accountValue, err - } - } - balances := c.session.Account.Balances() for _, b := range balances { if b.Currency == c.quoteCurrency { @@ -162,13 +131,9 @@ func (c *AccountValueCalculator) AvailableQuote(ctx context.Context) (fixedpoint continue } - symbol := b.Currency + c.quoteCurrency - price, ok := c.prices[symbol] - if !ok { - continue + if price, ok := c.priceSolver.ResolvePrice(b.Currency, c.quoteCurrency); ok { + accountValue = accountValue.Add(b.Net().Mul(price)) } - - accountValue = accountValue.Add(b.Net().Mul(price)) } return accountValue, nil @@ -176,20 +141,15 @@ func (c *AccountValueCalculator) AvailableQuote(ctx context.Context) (fixedpoint // MarginLevel calculates the margin level from the asset market value and the debt value // See https://www.binance.com/en/support/faq/360030493931 -func (c *AccountValueCalculator) MarginLevel(ctx context.Context) (fixedpoint.Value, error) { - marginLevel := fixedpoint.Zero - marketValue, err := c.MarketValue(ctx) - if err != nil { - return marginLevel, err +func (c *AccountValueCalculator) MarginLevel() (fixedpoint.Value, error) { + marketValue := c.MarketValue() + debtValue := c.DebtValue() + + if marketValue.IsZero() || debtValue.IsZero() { + return fixedpoint.NewFromFloat(999.0), nil } - debtValue, err := c.DebtValue(ctx) - if err != nil { - return marginLevel, err - } - - marginLevel = marketValue.Div(debtValue) - return marginLevel, nil + return marketValue.Div(debtValue), nil } func aggregateUsdNetValue(balances types.BalanceMap) fixedpoint.Value { @@ -255,11 +215,7 @@ func CalculateBaseQuantity( totalUsdValue = aggregateUsdNetValue(balances) } else if len(restBalances) > 1 { accountValue := NewAccountValueCalculator(session, nil, "USDT") - netValue, err := accountValue.NetValue(context.Background()) - if err != nil { - return quantity, err - } - + netValue := accountValue.NetValue() totalUsdValue = netValue } else { // TODO: translate quote currency like BTC of ETH/BTC to usd value @@ -362,7 +318,7 @@ func CalculateQuoteQuantity( // using leverage -- starts from here accountValue := NewAccountValueCalculator(session, nil, quoteCurrency) - availableQuote, err := accountValue.AvailableQuote(ctx) + availableQuote, err := accountValue.AvailableQuote() if err != nil { log.WithError(err).Errorf("can not update available quote") return fixedpoint.Zero, err diff --git a/pkg/bbgo/account_value_calc_test.go b/pkg/bbgo/account_value_calc_test.go index f709ee9ad..f9c06a43f 100644 --- a/pkg/bbgo/account_value_calc_test.go +++ b/pkg/bbgo/account_value_calc_test.go @@ -3,7 +3,6 @@ package bbgo import ( "context" "testing" - "time" "github.com/stretchr/testify/assert" "go.uber.org/mock/gomock" @@ -15,19 +14,6 @@ import ( "github.com/c9s/bbgo/pkg/types/mocks" ) -func newTestTicker() types.Ticker { - return types.Ticker{ - Time: time.Now(), - Volume: fixedpoint.Zero, - Last: fixedpoint.NewFromFloat(19000.0), - Open: fixedpoint.NewFromFloat(19500.0), - High: fixedpoint.NewFromFloat(19900.0), - Low: fixedpoint.NewFromFloat(18800.0), - Buy: fixedpoint.NewFromFloat(19500.0), - Sell: fixedpoint.NewFromFloat(18900.0), - } -} - func TestAccountValueCalculator_NetValue(t *testing.T) { symbol := "BTCUSDT" markets := AllMarkets() @@ -36,12 +22,11 @@ func TestAccountValueCalculator_NetValue(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() + ticker := Ticker(symbol) mockEx := mocks.NewMockExchange(mockCtrl) // for market data stream and user data stream mockEx.EXPECT().NewStream().Return(&types.StandardStream{}).Times(2) - mockEx.EXPECT().QueryTickers(gomock.Any(), []string{symbol}).Return(map[string]types.Ticker{ - "BTCUSDT": Ticker(symbol), - }, nil) + mockEx.EXPECT().QueryTicker(gomock.Any(), symbol).Return(&ticker, nil).AnyTimes() session := NewExchangeSession("test", mockEx) session.Account.UpdateBalances(types.BalanceMap{ @@ -64,14 +49,12 @@ func TestAccountValueCalculator_NetValue(t *testing.T) { }) assert.NotNil(t, session) - ctx := context.Background() priceSolver := pricesolver.NewSimplePriceResolver(markets) + priceSolver.Update(symbol, ticker.GetValidPrice()) cal := NewAccountValueCalculator(session, priceSolver, "USDT") - assert.NotNil(t, cal) - netValue, err := cal.NetValue(ctx) - assert.NoError(t, err) + netValue := cal.NetValue() assert.Equal(t, "20000", netValue.String()) }) @@ -79,12 +62,12 @@ func TestAccountValueCalculator_NetValue(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() + ticker := Ticker(symbol) + mockEx := mocks.NewMockExchange(mockCtrl) // for market data stream and user data stream mockEx.EXPECT().NewStream().Return(&types.StandardStream{}).Times(2) - mockEx.EXPECT().QueryTickers(gomock.Any(), []string{symbol}).Return(map[string]types.Ticker{ - symbol: Ticker(symbol), - }, nil) + mockEx.EXPECT().QueryTicker(gomock.Any(), symbol).Return(&ticker, nil).AnyTimes() session := NewExchangeSession("test", mockEx) session.Account.UpdateBalances(types.BalanceMap{ @@ -105,16 +88,12 @@ func TestAccountValueCalculator_NetValue(t *testing.T) { NetAsset: fixedpoint.Zero, }, }) - assert.NotNil(t, session) - ctx := context.Background() priceSolver := pricesolver.NewSimplePriceResolver(markets) + priceSolver.Update(symbol, ticker.GetValidPrice()) cal := NewAccountValueCalculator(session, priceSolver, "USDT") - assert.NotNil(t, cal) - - netValue, err := cal.NetValue(ctx) - assert.NoError(t, err) + netValue := cal.NetValue() assert.Equal(t, "2000", netValue.String()) // 21000-19000 }) } @@ -123,14 +102,13 @@ func TestNewAccountValueCalculator_MarginLevel(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() - ticker := newTestTicker() + symbol := "BTCUSDT" + ticker := Ticker(symbol) mockEx := mocks.NewMockExchange(mockCtrl) // for market data stream and user data stream mockEx.EXPECT().NewStream().Return(&types.StandardStream{}).Times(2) - mockEx.EXPECT().QueryTickers(gomock.Any(), []string{"BTCUSDT"}).Return(map[string]types.Ticker{ - "BTCUSDT": ticker, - }, nil) + mockEx.EXPECT().QueryTicker(gomock.Any(), symbol).Return(&ticker, nil).AnyTimes() session := NewExchangeSession("test", mockEx) session.Account.UpdateBalances(types.BalanceMap{ @@ -142,27 +120,20 @@ func TestNewAccountValueCalculator_MarginLevel(t *testing.T) { Interest: fixedpoint.NewFromFloat(0.003), NetAsset: fixedpoint.Zero, }, - "USDT": { - Currency: "USDT", - Available: fixedpoint.NewFromFloat(21000.0), - Locked: fixedpoint.Zero, - Borrowed: fixedpoint.Zero, - Interest: fixedpoint.Zero, - NetAsset: fixedpoint.Zero, - }, + "USDT": Balance("USDT", Number(21000.0)), }) assert.NotNil(t, session) ctx := context.Background() markets := AllMarkets() priceSolver := pricesolver.NewSimplePriceResolver(markets) - err := priceSolver.UpdateFromTickers(ctx, mockEx, "BTCUSDT") + err := priceSolver.UpdateFromTickers(ctx, mockEx, symbol) assert.NoError(t, err) cal := NewAccountValueCalculator(session, priceSolver, "USDT") assert.NotNil(t, cal) - marginLevel, err := cal.MarginLevel(ctx) + marginLevel, err := cal.MarginLevel() assert.NoError(t, err) // expected (21000 / 19000 * 1.003) diff --git a/pkg/pricesolver/simple.go b/pkg/pricesolver/simple.go index 826952380..d551f8c99 100644 --- a/pkg/pricesolver/simple.go +++ b/pkg/pricesolver/simple.go @@ -99,7 +99,6 @@ func (m *SimplePriceSolver) UpdateFromTickers(ctx context.Context, ex types.Exch } func (m *SimplePriceSolver) inferencePrice(asset string, assetPrice fixedpoint.Value, preferredFiats ...string) (fixedpoint.Value, bool) { - // log.Infof("inferencePrice %s = %f", asset, assetPrice.Float64()) quotePrices, ok := m.pricesByBase[asset] if ok { for quote, price := range quotePrices { @@ -122,10 +121,8 @@ func (m *SimplePriceSolver) inferencePrice(asset string, assetPrice fixedpoint.V basePrices, ok := m.pricesByQuote[asset] if ok { for base, basePrice := range basePrices { - // log.Infof("base %s @ %s", base, basePrice.String()) for _, fiat := range preferredFiats { if base == fiat { - // log.Infof("ret %f / %f = %f", assetPrice.Float64(), basePrice.Float64(), assetPrice.Div(basePrice).Float64()) return assetPrice.Div(basePrice), true } } @@ -142,6 +139,12 @@ func (m *SimplePriceSolver) inferencePrice(asset string, assetPrice fixedpoint.V } func (m *SimplePriceSolver) ResolvePrice(asset string, preferredFiats ...string) (fixedpoint.Value, bool) { + if len(preferredFiats) == 0 { + return fixedpoint.Zero, false + } else if asset == preferredFiats[0] { + return fixedpoint.One, true + } + m.mu.Lock() defer m.mu.Unlock() return m.inferencePrice(asset, fixedpoint.One, preferredFiats...) diff --git a/pkg/strategy/harmonic/strategy.go b/pkg/strategy/harmonic/strategy.go index e45d66525..942922be6 100644 --- a/pkg/strategy/harmonic/strategy.go +++ b/pkg/strategy/harmonic/strategy.go @@ -6,13 +6,14 @@ import ( "os" "sync" + "github.com/sirupsen/logrus" + "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/data/tsv" "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" - "github.com/sirupsen/logrus" ) const ID = "harmonic" @@ -29,7 +30,7 @@ type Strategy struct { Market types.Market types.IntervalWindow - //bbgo.OpenPositionOptions + // bbgo.OpenPositionOptions // persistence fields Position *types.Position `persistence:"position"` @@ -239,7 +240,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se // Cancel active orders _ = s.orderExecutor.GracefulCancel(ctx) // Close 100% position - //_ = s.ClosePosition(ctx, fixedpoint.One) + // _ = s.ClosePosition(ctx, fixedpoint.One) }) s.session = session @@ -258,7 +259,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se s.orderExecutor.BindTradeStats(s.TradeStats) // AccountValueCalculator - s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, s.Market.QuoteCurrency) + s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, nil, s.Market.QuoteCurrency) // Accumulated profit report if bbgo.IsBackTesting { diff --git a/pkg/strategy/irr/strategy.go b/pkg/strategy/irr/strategy.go index 0e7616c95..458cdca75 100644 --- a/pkg/strategy/irr/strategy.go +++ b/pkg/strategy/irr/strategy.go @@ -255,7 +255,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se s.orderExecutor.BindTradeStats(s.TradeStats) // AccountValueCalculator - s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, s.Market.QuoteCurrency) + s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, nil, s.Market.QuoteCurrency) // Accumulated profit report if bbgo.IsBackTesting { diff --git a/pkg/strategy/supertrend/strategy.go b/pkg/strategy/supertrend/strategy.go index 2d7898004..d7410de96 100644 --- a/pkg/strategy/supertrend/strategy.go +++ b/pkg/strategy/supertrend/strategy.go @@ -255,7 +255,9 @@ func (s *Strategy) getSide(stSignal types.Direction, demaSignal types.Direction, return side } -func (s *Strategy) generateOrderForm(side types.SideType, quantity fixedpoint.Value, marginOrderSideEffect types.MarginOrderSideEffectType) types.SubmitOrder { +func (s *Strategy) generateOrderForm( + side types.SideType, quantity fixedpoint.Value, marginOrderSideEffect types.MarginOrderSideEffectType, +) types.SubmitOrder { orderForm := types.SubmitOrder{ Symbol: s.Symbol, Market: s.Market, @@ -382,7 +384,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se } // AccountValueCalculator - s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, s.Market.QuoteCurrency) + s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, nil, s.Market.QuoteCurrency) // For drawing profitSlice := floats.Slice{1., 1.} diff --git a/pkg/strategy/xmaker/strategy.go b/pkg/strategy/xmaker/strategy.go index 10ee5ecf1..295e9ac45 100644 --- a/pkg/strategy/xmaker/strategy.go +++ b/pkg/strategy/xmaker/strategy.go @@ -187,6 +187,8 @@ type Strategy struct { logger logrus.FieldLogger metricsLabels prometheus.Labels + + connectivityGroup *types.ConnectivityGroup } func (s *Strategy) ID() string { @@ -654,40 +656,37 @@ func (s *Strategy) updateQuote(ctx context.Context) error { hedgeAccount.MarginLevel.String(), s.MinMarginLevel.String()) - netValueInUsd, calcErr := s.accountValueCalculator.NetValue(ctx) - if calcErr != nil { - s.logger.WithError(calcErr).Errorf("unable to calculate the net value") - } else { - // calculate credit buffer - s.logger.Infof("hedge account net value in usd: %f", netValueInUsd.Float64()) + netValueInUsd := s.accountValueCalculator.NetValue() - maximumValueInUsd := netValueInUsd.Mul(s.MaxHedgeAccountLeverage) + // calculate credit buffer + s.logger.Infof("hedge account net value in usd: %f", netValueInUsd.Float64()) - s.logger.Infof("hedge account maximum leveraged value in usd: %f (%f x)", maximumValueInUsd.Float64(), s.MaxHedgeAccountLeverage.Float64()) + maximumValueInUsd := netValueInUsd.Mul(s.MaxHedgeAccountLeverage) - if quote, ok := hedgeAccount.Balance(s.sourceMarket.QuoteCurrency); ok { - debt := quote.Debt() - quota := maximumValueInUsd.Sub(debt) + s.logger.Infof("hedge account maximum leveraged value in usd: %f (%f x)", maximumValueInUsd.Float64(), s.MaxHedgeAccountLeverage.Float64()) - s.logger.Infof("hedge account quote balance: %s, debt: %s, quota: %s", - quote.String(), - debt.String(), - quota.String()) + if quote, ok := hedgeAccount.Balance(s.sourceMarket.QuoteCurrency); ok { + debt := quote.Debt() + quota := maximumValueInUsd.Sub(debt) - hedgeQuota.QuoteAsset.Add(quota) - } + s.logger.Infof("hedge account quote balance: %s, debt: %s, quota: %s", + quote.String(), + debt.String(), + quota.String()) - if base, ok := hedgeAccount.Balance(s.sourceMarket.BaseCurrency); ok { - debt := base.Debt() - quota := maximumValueInUsd.Div(bestAsk.Price).Sub(debt) + hedgeQuota.QuoteAsset.Add(quota) + } - s.logger.Infof("hedge account base balance: %s, debt: %s, quota: %s", - base.String(), - debt.String(), - quota.String()) + if base, ok := hedgeAccount.Balance(s.sourceMarket.BaseCurrency); ok { + debt := base.Debt() + quota := maximumValueInUsd.Div(bestAsk.Price).Sub(debt) - hedgeQuota.BaseAsset.Add(quota) - } + s.logger.Infof("hedge account base balance: %s, debt: %s, quota: %s", + base.String(), + debt.String(), + quota.String()) + + hedgeQuota.BaseAsset.Add(quota) } } } else { @@ -1322,12 +1321,7 @@ func (s *Strategy) accountUpdater(ctx context.Context) { return } - netValue, err := s.accountValueCalculator.NetValue(ctx) - if err != nil { - log.WithError(err).Errorf("unable to update account") - return - } - + netValue := s.accountValueCalculator.NetValue() s.logger.Infof("hedge session net value ~= %f USD", netValue.Float64()) } } @@ -1419,7 +1413,7 @@ func (s *Strategy) CrossRun( return fmt.Errorf("maker session market %s is not defined", s.Symbol) } - s.accountValueCalculator = bbgo.NewAccountValueCalculator(s.sourceSession, s.sourceMarket.QuoteCurrency) + s.accountValueCalculator = bbgo.NewAccountValueCalculator(s.sourceSession, nil, s.sourceMarket.QuoteCurrency) indicators := s.sourceSession.Indicators(s.Symbol) @@ -1622,13 +1616,27 @@ func (s *Strategy) CrossRun( s.stopC = make(chan struct{}) + sourceConnectivity := types.NewConnectivity() + sourceConnectivity.Bind(s.sourceSession.UserDataStream) + + s.connectivityGroup = types.NewConnectivityGroup(sourceConnectivity) + if s.RecoverTrade { go s.tradeRecover(ctx) } - go s.accountUpdater(ctx) - go s.hedgeWorker(ctx) - go s.quoteWorker(ctx) + go func() { + select { + case <-ctx.Done(): + case <-s.connectivityGroup.AllAuthedC(ctx, 15*time.Second): + } + + s.logger.Infof("all user data streams are connected, starting workers...") + + go s.accountUpdater(ctx) + go s.hedgeWorker(ctx) + go s.quoteWorker(ctx) + }() bbgo.OnShutdown(ctx, func(ctx context.Context, wg *sync.WaitGroup) { // the ctx here is the shutdown context (not the strategy context) diff --git a/pkg/testing/testhelper/ticker.go b/pkg/testing/testhelper/ticker.go index 8ee72934f..7876efcc1 100644 --- a/pkg/testing/testhelper/ticker.go +++ b/pkg/testing/testhelper/ticker.go @@ -30,12 +30,23 @@ var _tickers = map[string]types.Ticker{ Buy: fixedpoint.NewFromFloat(2519.0), Sell: fixedpoint.NewFromFloat(2521.0), }, + + "USDTTWD": { + Time: time.Now(), + Volume: fixedpoint.Zero, + Open: fixedpoint.NewFromFloat(32.1), + High: fixedpoint.NewFromFloat(32.31), + Low: fixedpoint.NewFromFloat(32.01), + Last: fixedpoint.NewFromFloat(32.0), + Buy: fixedpoint.NewFromFloat(32.0), + Sell: fixedpoint.NewFromFloat(32.01), + }, } func Ticker(symbol string) types.Ticker { ticker, ok := _tickers[symbol] if !ok { - panic(fmt.Errorf("%s test ticker not found, valid tickers: %+v", symbol, []string{"BTCUSDT", "ETHUSDT"})) + panic(fmt.Errorf("%s test ticker not found, valid tickers: %+v", symbol, []string{"BTCUSDT", "ETHUSDT", "USDTTWD"})) } return ticker