backtest,accounting: add position info to the average cost pnl report

This commit is contained in:
c9s 2022-09-01 19:02:18 +08:00
parent 45fb87f2b8
commit d2f9a352a2
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
5 changed files with 27 additions and 14 deletions

View File

@ -14,7 +14,7 @@ type AverageCostCalculator struct {
Market types.Market
}
func (c *AverageCostCalculator) Calculate(symbol string, trades []types.Trade, currentPrice fixedpoint.Value) *AverageCostPnlReport {
func (c *AverageCostCalculator) Calculate(symbol string, trades []types.Trade, currentPrice fixedpoint.Value) *AverageCostPnLReport {
// copy trades, so that we can truncate it.
var bidVolume = fixedpoint.Zero
var askVolume = fixedpoint.Zero
@ -23,7 +23,7 @@ func (c *AverageCostCalculator) Calculate(symbol string, trades []types.Trade, c
var grossLoss = fixedpoint.Zero
if len(trades) == 0 {
return &AverageCostPnlReport{
return &AverageCostPnLReport{
Symbol: symbol,
Market: c.Market,
LastPrice: currentPrice,
@ -90,12 +90,13 @@ func (c *AverageCostCalculator) Calculate(symbol string, trades []types.Trade, c
unrealizedProfit := currentPrice.Sub(position.AverageCost).
Mul(position.GetBase())
return &AverageCostPnlReport{
return &AverageCostPnLReport{
Symbol: symbol,
Market: c.Market,
LastPrice: currentPrice,
NumTrades: len(trades),
StartTime: time.Time(trades[0].Time),
Position: position,
BuyVolume: bidVolume,
SellVolume: askVolume,

View File

@ -14,7 +14,7 @@ import (
"github.com/c9s/bbgo/pkg/types"
)
type AverageCostPnlReport struct {
type AverageCostPnLReport struct {
LastPrice fixedpoint.Value `json:"lastPrice"`
StartTime time.Time `json:"startTime"`
Symbol string `json:"symbol"`
@ -27,6 +27,7 @@ type AverageCostPnlReport struct {
NetProfit fixedpoint.Value `json:"netProfit"`
GrossProfit fixedpoint.Value `json:"grossProfit"`
GrossLoss fixedpoint.Value `json:"grossLoss"`
Position *types.Position `json:"position,omitempty"`
AverageCost fixedpoint.Value `json:"averageCost"`
BuyVolume fixedpoint.Value `json:"buyVolume,omitempty"`
@ -36,14 +37,14 @@ type AverageCostPnlReport struct {
CurrencyFees map[string]fixedpoint.Value `json:"currencyFees"`
}
func (report *AverageCostPnlReport) JSON() ([]byte, error) {
func (report *AverageCostPnLReport) JSON() ([]byte, error) {
return json.MarshalIndent(report, "", " ")
}
func (report AverageCostPnlReport) Print() {
func (report AverageCostPnLReport) Print() {
color.Green("TRADES SINCE: %v", report.StartTime)
color.Green("NUMBER OF TRADES: %d", report.NumTrades)
color.Green(report.Position.String())
color.Green("AVERAGE COST: %s", types.USD.FormatMoney(report.AverageCost))
color.Green("BASE ASSET POSITION: %s", report.BaseAssetPosition.String())
@ -69,7 +70,7 @@ func (report AverageCostPnlReport) Print() {
}
}
func (report AverageCostPnlReport) SlackAttachment() slack.Attachment {
func (report AverageCostPnLReport) SlackAttachment() slack.Attachment {
var color = slackstyle.Red
if report.UnrealizedProfit.Sign() > 0 {

View File

@ -277,9 +277,15 @@ func (m *SimplePriceMatching) executeTrade(trade types.Trade) {
if trade.IsBuyer {
err = m.account.UseLockedBalance(m.Market.QuoteCurrency, trade.QuoteQuantity)
// here the fee currency is the base currency
// all-in buy trade, we can only deduct the fee from the quote quantity and re-calculate the base quantity
q := trade.Quantity
if trade.FeeCurrency == m.Market.BaseCurrency {
qq := trade.QuoteQuantity
switch trade.FeeCurrency {
case m.Market.QuoteCurrency:
quoteFee := trade.Fee
qq = qq.Sub(quoteFee)
q = qq.Div(trade.Price) // re-calculate the base quantity according to the quote quantity and fee.
case m.Market.BaseCurrency:
q = q.Sub(trade.Fee)
}
@ -287,11 +293,17 @@ func (m *SimplePriceMatching) executeTrade(trade types.Trade) {
} else {
err = m.account.UseLockedBalance(m.Market.BaseCurrency, trade.Quantity)
// here the fee currency is the quote currency
// all-in sell trade
q := trade.Quantity
qq := trade.QuoteQuantity
if trade.FeeCurrency == m.Market.QuoteCurrency {
switch trade.FeeCurrency {
case m.Market.QuoteCurrency:
qq = qq.Sub(trade.Fee)
case m.Market.BaseCurrency:
q = q.Sub(trade.Fee)
qq = q.Div(trade.Price)
}
m.account.AddBalance(m.Market.QuoteCurrency, qq)
}

View File

@ -75,7 +75,7 @@ type SessionSymbolReport struct {
Market types.Market `json:"market"`
LastPrice fixedpoint.Value `json:"lastPrice,omitempty"`
StartPrice fixedpoint.Value `json:"startPrice,omitempty"`
PnL *pnl.AverageCostPnlReport `json:"pnl,omitempty"`
PnL *pnl.AverageCostPnLReport `json:"pnl,omitempty"`
InitialBalances types.BalanceMap `json:"initialBalances,omitempty"`
FinalBalances types.BalanceMap `json:"finalBalances,omitempty"`
Manifests Manifests `json:"manifests,omitempty"`

View File

@ -583,7 +583,6 @@ var BacktestCmd = &cobra.Command{
color.Green("END TIME: %s\n", endTime.Format(time.RFC1123))
color.Green("INITIAL TOTAL BALANCE: %v\n", initTotalBalances)
color.Green("FINAL TOTAL BALANCE: %v\n", finalTotalBalances)
for _, symbolReport := range summaryReport.SymbolReports {
symbolReport.Print(wantBaseAssetBaseline)
}