rename ProfitAndLossCalculator to AverageCostCalculator

This commit is contained in:
c9s 2020-10-16 10:16:42 +08:00
parent ee86a71ebb
commit a6b99f6828
6 changed files with 127 additions and 123 deletions

View File

@ -9,7 +9,7 @@ import (
"github.com/spf13/cobra"
"github.com/c9s/bbgo/cmd/cmdutil"
"github.com/c9s/bbgo/pkg/accounting"
"github.com/c9s/bbgo/pkg/accounting/pnl"
"github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/service"
"github.com/c9s/bbgo/pkg/types"
@ -110,7 +110,7 @@ var pnlCmd = &cobra.Command{
currentPrice, err := exchange.QueryAveragePrice(ctx, symbol)
calculator := &accounting.ProfitAndLossCalculator{
calculator := &pnl.AverageCostCalculator{
TradingFeeCurrency: tradingFeeCurrency,
Symbol: symbol,
StartTime: startTime,

1
go.mod
View File

@ -30,6 +30,7 @@ require (
github.com/sirupsen/logrus v1.4.2
github.com/slack-go/slack v0.6.6-0.20200602212211-b04b8521281b
github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.3
github.com/spf13/viper v1.7.0
github.com/stretchr/testify v1.6.1
github.com/tebeka/strftime v0.1.3 // indirect

View File

@ -1,117 +1,2 @@
package accounting
import (
"strings"
"time"
"github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/types"
)
type ProfitAndLossCalculator struct {
Symbol string
StartTime time.Time
CurrentPrice float64
Trades []types.Trade
TradingFeeCurrency string
}
func (c *ProfitAndLossCalculator) AddTrade(trade types.Trade) {
c.Trades = append(c.Trades, trade)
}
func (c *ProfitAndLossCalculator) SetCurrentPrice(price float64) {
c.CurrentPrice = price
}
func (c *ProfitAndLossCalculator) Calculate() *ProfitAndLossReport {
// copy trades, so that we can truncate it.
var trades = c.Trades
var bidVolume = 0.0
var bidAmount = 0.0
var askVolume = 0.0
var feeUSD = 0.0
var bidFeeUSD = 0.0
var feeRate = 0.0015
var currencyFees = map[string]float64{}
for _, trade := range trades {
if trade.Symbol == c.Symbol {
if trade.IsBuyer {
bidVolume += trade.Quantity
bidAmount += trade.Price * trade.Quantity
}
// since we use USDT as the quote currency, we simply check if it matches the currency symbol
if strings.HasPrefix(trade.Symbol, trade.FeeCurrency) {
bidVolume -= trade.Fee
feeUSD += trade.Price * trade.Fee
if trade.IsBuyer {
bidFeeUSD += trade.Price * trade.Fee
}
} else if trade.FeeCurrency == "USDT" {
feeUSD += trade.Fee
if trade.IsBuyer {
bidFeeUSD += trade.Fee
}
}
} else {
if trade.FeeCurrency == c.TradingFeeCurrency {
bidVolume -= trade.Fee
}
}
if _, ok := currencyFees[trade.FeeCurrency]; !ok {
currencyFees[trade.FeeCurrency] = 0.0
}
currencyFees[trade.FeeCurrency] += trade.Fee
}
logrus.Infof("average bid price = (total amount %f + total feeUSD %f) / volume %f", bidAmount, bidFeeUSD, bidVolume)
profit := 0.0
averageCost := (bidAmount + bidFeeUSD) / bidVolume
for _, t := range trades {
if t.Symbol != c.Symbol {
continue
}
if t.IsBuyer {
continue
}
profit += (t.Price - averageCost) * t.Quantity
askVolume += t.Quantity
}
profit -= feeUSD
unrealizedProfit := profit
stock := bidVolume - askVolume
if stock > 0 {
stockFee := c.CurrentPrice * stock * feeRate
unrealizedProfit += (c.CurrentPrice-averageCost)*stock - stockFee
}
return &ProfitAndLossReport{
Symbol: c.Symbol,
StartTime: c.StartTime,
CurrentPrice: c.CurrentPrice,
NumTrades: len(trades),
BidVolume: bidVolume,
AskVolume: askVolume,
Stock: stock,
Profit: profit,
UnrealizedProfit: unrealizedProfit,
AverageBidCost: averageCost,
FeeUSD: feeUSD,
CurrencyFees: currencyFees,
}
}

View File

@ -0,0 +1,118 @@
package pnl
import (
"strings"
"time"
"github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/accounting"
"github.com/c9s/bbgo/pkg/types"
)
type AverageCostCalculator struct {
Symbol string
StartTime time.Time
CurrentPrice float64
Trades []types.Trade
TradingFeeCurrency string
}
func (c *AverageCostCalculator) AddTrade(trade types.Trade) {
c.Trades = append(c.Trades, trade)
}
func (c *AverageCostCalculator) SetCurrentPrice(price float64) {
c.CurrentPrice = price
}
func (c *AverageCostCalculator) Calculate() *accounting.ProfitAndLossReport {
// copy trades, so that we can truncate it.
var trades = c.Trades
var bidVolume = 0.0
var bidAmount = 0.0
var askVolume = 0.0
var feeUSD = 0.0
var bidFeeUSD = 0.0
var feeRate = 0.0015
var currencyFees = map[string]float64{}
for _, trade := range trades {
if trade.Symbol == c.Symbol {
if trade.IsBuyer {
bidVolume += trade.Quantity
bidAmount += trade.Price * trade.Quantity
}
// since we use USDT as the quote currency, we simply check if it matches the currency symbol
if strings.HasPrefix(trade.Symbol, trade.FeeCurrency) {
bidVolume -= trade.Fee
feeUSD += trade.Price * trade.Fee
if trade.IsBuyer {
bidFeeUSD += trade.Price * trade.Fee
}
} else if trade.FeeCurrency == "USDT" {
feeUSD += trade.Fee
if trade.IsBuyer {
bidFeeUSD += trade.Fee
}
}
} else {
if trade.FeeCurrency == c.TradingFeeCurrency {
bidVolume -= trade.Fee
}
}
if _, ok := currencyFees[trade.FeeCurrency]; !ok {
currencyFees[trade.FeeCurrency] = 0.0
}
currencyFees[trade.FeeCurrency] += trade.Fee
}
logrus.Infof("average bid price = (total amount %f + total feeUSD %f) / volume %f", bidAmount, bidFeeUSD, bidVolume)
profit := 0.0
averageCost := (bidAmount + bidFeeUSD) / bidVolume
for _, t := range trades {
if t.Symbol != c.Symbol {
continue
}
if t.IsBuyer {
continue
}
profit += (t.Price - averageCost) * t.Quantity
askVolume += t.Quantity
}
profit -= feeUSD
unrealizedProfit := profit
stock := bidVolume - askVolume
if stock > 0 {
stockFee := c.CurrentPrice * stock * feeRate
unrealizedProfit += (c.CurrentPrice-averageCost)*stock - stockFee
}
return &accounting.ProfitAndLossReport{
Symbol: c.Symbol,
StartTime: c.StartTime,
CurrentPrice: c.CurrentPrice,
NumTrades: len(trades),
BidVolume: bidVolume,
AskVolume: askVolume,
Stock: stock,
Profit: profit,
UnrealizedProfit: unrealizedProfit,
AverageBidCost: averageCost,
FeeUSD: feeUSD,
CurrencyFees: currencyFees,
}
}

View File

@ -3,7 +3,7 @@ package bbgo
import (
"context"
"github.com/c9s/bbgo/pkg/accounting"
"github.com/c9s/bbgo/pkg/accounting/pnl"
"github.com/c9s/bbgo/pkg/types"
)
@ -23,7 +23,7 @@ type BackTestTrader struct {
// Context is trading Context
Context *Context
SourceKLines []types.KLine
ProfitAndLossCalculator *accounting.ProfitAndLossCalculator
ProfitAndLossCalculator *pnl.AverageCostCalculator
doneOrders []types.SubmitOrder
pendingOrders []types.SubmitOrder
@ -125,7 +125,7 @@ func (trader *BackTestTrader) RunStrategy(ctx context.Context, strategy SingleEx
}
tradeID++
trader.ProfitAndLossCalculator.AddTrade(trade)
trader.AverageCostCalculator.AddTrade(trade)
trader.doneOrders = append(trader.doneOrders, order)
}
@ -135,7 +135,7 @@ func (trader *BackTestTrader) RunStrategy(ctx context.Context, strategy SingleEx
}
fmt.Print("\n")
report := trader.ProfitAndLossCalculator.Calculate()
report := trader.AverageCostCalculator.Calculate()
report.Print()
logrus.Infof("wallet balance:")

View File

@ -3,7 +3,7 @@ package bbgo
import (
"sync"
"github.com/c9s/bbgo/pkg/accounting"
"github.com/c9s/bbgo/pkg/accounting/pnl"
"github.com/c9s/bbgo/pkg/types"
)
@ -19,7 +19,7 @@ type Context struct {
CurrentPrice float64
Balances map[string]types.Balance
ProfitAndLossCalculator *accounting.ProfitAndLossCalculator
ProfitAndLossCalculator *pnl.AverageCostCalculator
StockManager *StockDistribution
}