refactor account value calculator

This commit is contained in:
c9s 2024-10-05 14:22:13 +08:00
parent 6079e7b06a
commit 7506fb63a8
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
5 changed files with 51 additions and 17 deletions

View File

@ -3,7 +3,6 @@ package bbgo
import ( import (
"context" "context"
"fmt" "fmt"
"time"
"github.com/pkg/errors" "github.com/pkg/errors"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -22,12 +21,8 @@ var maxCrossMarginLeverage = fixedpoint.NewFromInt(3)
type AccountValueCalculator struct { type AccountValueCalculator struct {
priceSolver *pricesolver.SimplePriceSolver priceSolver *pricesolver.SimplePriceSolver
session *ExchangeSession session *ExchangeSession
quoteCurrency string quoteCurrency string
prices map[string]fixedpoint.Value
tickers map[string]types.Ticker
updateTime time.Time
} }
func NewAccountValueCalculator( func NewAccountValueCalculator(
@ -39,15 +34,15 @@ func NewAccountValueCalculator(
priceSolver: priceSolver, priceSolver: priceSolver,
session: session, session: session,
quoteCurrency: quoteCurrency, 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 { func (c *AccountValueCalculator) UpdatePrices(ctx context.Context) error {
balances := c.session.Account.Balances() balances := c.session.Account.Balances()
currencies := balances.Currencies() currencies := balances.Currencies()
markets := c.session.Markets()
// TODO: improve this part
var symbols []string var symbols []string
for _, currency := range currencies { for _, currency := range currencies {
if currency == c.quoteCurrency { if currency == c.quoteCurrency {
@ -55,7 +50,12 @@ func (c *AccountValueCalculator) UpdatePrices(ctx context.Context) error {
} }
symbol := currency + c.quoteCurrency symbol := currency + c.quoteCurrency
reversedSymbol := c.quoteCurrency + currency
if _, ok := markets[symbol]; ok {
symbols = append(symbols, symbol) symbols = append(symbols, symbol)
} else if _, ok2 := markets[reversedSymbol]; ok2 {
symbols = append(symbols, reversedSymbol)
}
} }
return c.priceSolver.UpdateFromTickers(ctx, c.session.Exchange, symbols...) return c.priceSolver.UpdateFromTickers(ctx, c.session.Exchange, symbols...)
@ -209,12 +209,17 @@ func CalculateBaseQuantity(
usdBalances, restBalances := usdFiatBalances(balances) 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 totalUsdValue := fixedpoint.Zero
if len(restBalances) == 1 && types.IsUSDFiatCurrency(market.QuoteCurrency) { if len(restBalances) == 1 && types.IsUSDFiatCurrency(market.QuoteCurrency) {
totalUsdValue = aggregateUsdNetValue(balances) totalUsdValue = aggregateUsdNetValue(balances)
} else if len(restBalances) > 1 { } 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() netValue := accountValue.NetValue()
totalUsdValue = netValue totalUsdValue = netValue
} else { } else {
@ -317,7 +322,13 @@ func CalculateQuoteQuantity(
} }
// using leverage -- starts from here // 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() availableQuote, err := accountValue.AvailableQuote()
if err != nil { if err != nil {
log.WithError(err).Errorf("can not update available quote") log.WithError(err).Errorf("can not update available quote")

View File

@ -13,6 +13,7 @@ import (
"github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/datatype/floats"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/indicator"
"github.com/c9s/bbgo/pkg/pricesolver"
"github.com/c9s/bbgo/pkg/types" "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) s.orderExecutor.BindTradeStats(s.TradeStats)
// AccountValueCalculator // 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 // Accumulated profit report
if bbgo.IsBackTesting { if bbgo.IsBackTesting {

View File

@ -11,6 +11,7 @@ import (
"github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/datatype/floats"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/indicator"
"github.com/c9s/bbgo/pkg/pricesolver"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -255,7 +256,13 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
s.orderExecutor.BindTradeStats(s.TradeStats) s.orderExecutor.BindTradeStats(s.TradeStats)
// AccountValueCalculator // 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 // Accumulated profit report
if bbgo.IsBackTesting { if bbgo.IsBackTesting {

View File

@ -11,6 +11,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/datatype/floats"
"github.com/c9s/bbgo/pkg/pricesolver"
"github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/fixedpoint" "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()) s.ProfitStatsTracker.Bind(s.session, s.orderExecutor.TradeCollector())
} }
priceSolver := pricesolver.NewSimplePriceResolver(session.Markets())
priceSolver.BindStream(session.MarketDataStream)
// AccountValueCalculator // 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 // For drawing
profitSlice := floats.Slice{1., 1.} profitSlice := floats.Slice{1., 1.}

View File

@ -1413,8 +1413,6 @@ func (s *Strategy) CrossRun(
return fmt.Errorf("maker session market %s is not defined", s.Symbol) 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) indicators := s.sourceSession.Indicators(s.Symbol)
s.boll = indicators.BOLL(types.IntervalWindow{ s.boll = indicators.BOLL(types.IntervalWindow{
@ -1474,6 +1472,11 @@ func (s *Strategy) CrossRun(
s.priceSolver = pricesolver.NewSimplePriceResolver(sourceMarkets) s.priceSolver = pricesolver.NewSimplePriceResolver(sourceMarkets)
s.priceSolver.BindStream(s.sourceSession.MarketDataStream) 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.sourceSession.MarketDataStream.OnKLineClosed(types.KLineWith(s.Symbol, types.Interval1m, func(k types.KLine) {
s.priceSolver.Update(k.Symbol, k.Close) s.priceSolver.Update(k.Symbol, k.Close)
feeToken := s.sourceSession.Exchange.PlatformFeeCurrency() feeToken := s.sourceSession.Exchange.PlatformFeeCurrency()