From 7506fb63a8616e42bfa01711810695a76d9a79de Mon Sep 17 00:00:00 2001 From: c9s Date: Sat, 5 Oct 2024 14:22:13 +0800 Subject: [PATCH] refactor account value calculator --- pkg/bbgo/account_value_calc.go | 35 +++++++++++++++++++---------- pkg/strategy/harmonic/strategy.go | 8 ++++++- pkg/strategy/irr/strategy.go | 9 +++++++- pkg/strategy/supertrend/strategy.go | 9 +++++++- pkg/strategy/xmaker/strategy.go | 7 ++++-- 5 files changed, 51 insertions(+), 17 deletions(-) diff --git a/pkg/bbgo/account_value_calc.go b/pkg/bbgo/account_value_calc.go index bc0e6d598..6cd6f9fd0 100644 --- a/pkg/bbgo/account_value_calc.go +++ b/pkg/bbgo/account_value_calc.go @@ -3,7 +3,6 @@ package bbgo import ( "context" "fmt" - "time" "github.com/pkg/errors" log "github.com/sirupsen/logrus" @@ -21,13 +20,9 @@ var maxIsolatedMarginLeverage = fixedpoint.NewFromInt(10) var maxCrossMarginLeverage = fixedpoint.NewFromInt(3) type AccountValueCalculator struct { - priceSolver *pricesolver.SimplePriceSolver - + priceSolver *pricesolver.SimplePriceSolver session *ExchangeSession quoteCurrency string - prices map[string]fixedpoint.Value - tickers map[string]types.Ticker - updateTime time.Time } func NewAccountValueCalculator( @@ -39,15 +34,15 @@ func NewAccountValueCalculator( priceSolver: priceSolver, session: session, quoteCurrency: quoteCurrency, - tickers: make(map[string]types.Ticker), } } +// UpdatePrices updates the price index from the existing balances func (c *AccountValueCalculator) UpdatePrices(ctx context.Context) error { balances := c.session.Account.Balances() currencies := balances.Currencies() + markets := c.session.Markets() - // TODO: improve this part var symbols []string for _, currency := range currencies { if currency == c.quoteCurrency { @@ -55,7 +50,12 @@ func (c *AccountValueCalculator) UpdatePrices(ctx context.Context) error { } symbol := currency + c.quoteCurrency - symbols = append(symbols, symbol) + reversedSymbol := c.quoteCurrency + currency + if _, ok := markets[symbol]; ok { + symbols = append(symbols, symbol) + } else if _, ok2 := markets[reversedSymbol]; ok2 { + symbols = append(symbols, reversedSymbol) + } } return c.priceSolver.UpdateFromTickers(ctx, c.session.Exchange, symbols...) @@ -209,12 +209,17 @@ func CalculateBaseQuantity( usdBalances, restBalances := usdFiatBalances(balances) - // for isolated margin we can calculate from these two pair + // for isolated margin, we can calculate from these two pair totalUsdValue := fixedpoint.Zero if len(restBalances) == 1 && types.IsUSDFiatCurrency(market.QuoteCurrency) { totalUsdValue = aggregateUsdNetValue(balances) } else if len(restBalances) > 1 { - accountValue := NewAccountValueCalculator(session, nil, "USDT") + priceSolver := pricesolver.NewSimplePriceResolver(session.Markets()) + accountValue := NewAccountValueCalculator(session, priceSolver, "USDT") + if err := accountValue.UpdatePrices(context.Background()); err != nil { + return fixedpoint.Zero, err + } + netValue := accountValue.NetValue() totalUsdValue = netValue } else { @@ -317,7 +322,13 @@ func CalculateQuoteQuantity( } // using leverage -- starts from here - accountValue := NewAccountValueCalculator(session, nil, quoteCurrency) + priceSolver := pricesolver.NewSimplePriceResolver(session.Markets()) + + accountValue := NewAccountValueCalculator(session, priceSolver, quoteCurrency) + if err := accountValue.UpdatePrices(ctx); err != nil { + return fixedpoint.Zero, err + } + availableQuote, err := accountValue.AvailableQuote() if err != nil { log.WithError(err).Errorf("can not update available quote") diff --git a/pkg/strategy/harmonic/strategy.go b/pkg/strategy/harmonic/strategy.go index 942922be6..ae7bd2628 100644 --- a/pkg/strategy/harmonic/strategy.go +++ b/pkg/strategy/harmonic/strategy.go @@ -13,6 +13,7 @@ import ( "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/indicator" + "github.com/c9s/bbgo/pkg/pricesolver" "github.com/c9s/bbgo/pkg/types" ) @@ -259,7 +260,12 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se s.orderExecutor.BindTradeStats(s.TradeStats) // AccountValueCalculator - s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, nil, s.Market.QuoteCurrency) + priceSolver := pricesolver.NewSimplePriceResolver(session.Markets()) + priceSolver.BindStream(s.session.MarketDataStream) + s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, priceSolver, s.Market.QuoteCurrency) + if err := s.AccountValueCalculator.UpdatePrices(ctx); err != nil { + return err + } // Accumulated profit report if bbgo.IsBackTesting { diff --git a/pkg/strategy/irr/strategy.go b/pkg/strategy/irr/strategy.go index 458cdca75..4fd82526b 100644 --- a/pkg/strategy/irr/strategy.go +++ b/pkg/strategy/irr/strategy.go @@ -11,6 +11,7 @@ import ( "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/indicator" + "github.com/c9s/bbgo/pkg/pricesolver" "github.com/c9s/bbgo/pkg/types" "github.com/sirupsen/logrus" @@ -255,7 +256,13 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se s.orderExecutor.BindTradeStats(s.TradeStats) // AccountValueCalculator - s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, nil, s.Market.QuoteCurrency) + priceSolver := pricesolver.NewSimplePriceResolver(session.Markets()) + priceSolver.BindStream(session.MarketDataStream) + + s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, priceSolver, s.Market.QuoteCurrency) + if err := s.AccountValueCalculator.UpdatePrices(ctx); err != nil { + return err + } // Accumulated profit report if bbgo.IsBackTesting { diff --git a/pkg/strategy/supertrend/strategy.go b/pkg/strategy/supertrend/strategy.go index d7410de96..04f9b26b8 100644 --- a/pkg/strategy/supertrend/strategy.go +++ b/pkg/strategy/supertrend/strategy.go @@ -11,6 +11,7 @@ import ( "github.com/sirupsen/logrus" "github.com/c9s/bbgo/pkg/datatype/floats" + "github.com/c9s/bbgo/pkg/pricesolver" "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/fixedpoint" @@ -383,8 +384,14 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se s.ProfitStatsTracker.Bind(s.session, s.orderExecutor.TradeCollector()) } + priceSolver := pricesolver.NewSimplePriceResolver(session.Markets()) + priceSolver.BindStream(session.MarketDataStream) + // AccountValueCalculator - s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, nil, s.Market.QuoteCurrency) + s.AccountValueCalculator = bbgo.NewAccountValueCalculator(s.session, priceSolver, s.Market.QuoteCurrency) + if err := s.AccountValueCalculator.UpdatePrices(ctx); err != nil { + return err + } // For drawing profitSlice := floats.Slice{1., 1.} diff --git a/pkg/strategy/xmaker/strategy.go b/pkg/strategy/xmaker/strategy.go index 295e9ac45..dc113ee6a 100644 --- a/pkg/strategy/xmaker/strategy.go +++ b/pkg/strategy/xmaker/strategy.go @@ -1413,8 +1413,6 @@ func (s *Strategy) CrossRun( return fmt.Errorf("maker session market %s is not defined", s.Symbol) } - s.accountValueCalculator = bbgo.NewAccountValueCalculator(s.sourceSession, nil, s.sourceMarket.QuoteCurrency) - indicators := s.sourceSession.Indicators(s.Symbol) s.boll = indicators.BOLL(types.IntervalWindow{ @@ -1474,6 +1472,11 @@ func (s *Strategy) CrossRun( s.priceSolver = pricesolver.NewSimplePriceResolver(sourceMarkets) s.priceSolver.BindStream(s.sourceSession.MarketDataStream) + s.accountValueCalculator = bbgo.NewAccountValueCalculator(s.sourceSession, s.priceSolver, s.sourceMarket.QuoteCurrency) + if err := s.accountValueCalculator.UpdatePrices(ctx); err != nil { + return err + } + s.sourceSession.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, types.Interval1m, func(k types.KLine) { s.priceSolver.Update(k.Symbol, k.Close) feeToken := s.sourceSession.Exchange.PlatformFeeCurrency()