mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 00:05:15 +00:00
rename ProfitAndLossCalculator to AverageCostCalculator
This commit is contained in:
parent
ee86a71ebb
commit
a6b99f6828
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/cmd/cmdutil"
|
"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/bbgo"
|
||||||
"github.com/c9s/bbgo/pkg/service"
|
"github.com/c9s/bbgo/pkg/service"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
@ -110,7 +110,7 @@ var pnlCmd = &cobra.Command{
|
||||||
|
|
||||||
currentPrice, err := exchange.QueryAveragePrice(ctx, symbol)
|
currentPrice, err := exchange.QueryAveragePrice(ctx, symbol)
|
||||||
|
|
||||||
calculator := &accounting.ProfitAndLossCalculator{
|
calculator := &pnl.AverageCostCalculator{
|
||||||
TradingFeeCurrency: tradingFeeCurrency,
|
TradingFeeCurrency: tradingFeeCurrency,
|
||||||
Symbol: symbol,
|
Symbol: symbol,
|
||||||
StartTime: startTime,
|
StartTime: startTime,
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -30,6 +30,7 @@ require (
|
||||||
github.com/sirupsen/logrus v1.4.2
|
github.com/sirupsen/logrus v1.4.2
|
||||||
github.com/slack-go/slack v0.6.6-0.20200602212211-b04b8521281b
|
github.com/slack-go/slack v0.6.6-0.20200602212211-b04b8521281b
|
||||||
github.com/spf13/cobra v1.0.0
|
github.com/spf13/cobra v1.0.0
|
||||||
|
github.com/spf13/pflag v1.0.3
|
||||||
github.com/spf13/viper v1.7.0
|
github.com/spf13/viper v1.7.0
|
||||||
github.com/stretchr/testify v1.6.1
|
github.com/stretchr/testify v1.6.1
|
||||||
github.com/tebeka/strftime v0.1.3 // indirect
|
github.com/tebeka/strftime v0.1.3 // indirect
|
||||||
|
|
|
@ -1,117 +1,2 @@
|
||||||
package accounting
|
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
118
pkg/accounting/pnl/avg_cost.go
Normal file
118
pkg/accounting/pnl/avg_cost.go
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ package bbgo
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/accounting"
|
"github.com/c9s/bbgo/pkg/accounting/pnl"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ type BackTestTrader struct {
|
||||||
// Context is trading Context
|
// Context is trading Context
|
||||||
Context *Context
|
Context *Context
|
||||||
SourceKLines []types.KLine
|
SourceKLines []types.KLine
|
||||||
ProfitAndLossCalculator *accounting.ProfitAndLossCalculator
|
ProfitAndLossCalculator *pnl.AverageCostCalculator
|
||||||
|
|
||||||
doneOrders []types.SubmitOrder
|
doneOrders []types.SubmitOrder
|
||||||
pendingOrders []types.SubmitOrder
|
pendingOrders []types.SubmitOrder
|
||||||
|
@ -125,7 +125,7 @@ func (trader *BackTestTrader) RunStrategy(ctx context.Context, strategy SingleEx
|
||||||
}
|
}
|
||||||
|
|
||||||
tradeID++
|
tradeID++
|
||||||
trader.ProfitAndLossCalculator.AddTrade(trade)
|
trader.AverageCostCalculator.AddTrade(trade)
|
||||||
|
|
||||||
trader.doneOrders = append(trader.doneOrders, order)
|
trader.doneOrders = append(trader.doneOrders, order)
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ func (trader *BackTestTrader) RunStrategy(ctx context.Context, strategy SingleEx
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Print("\n")
|
fmt.Print("\n")
|
||||||
report := trader.ProfitAndLossCalculator.Calculate()
|
report := trader.AverageCostCalculator.Calculate()
|
||||||
report.Print()
|
report.Print()
|
||||||
|
|
||||||
logrus.Infof("wallet balance:")
|
logrus.Infof("wallet balance:")
|
||||||
|
|
|
@ -3,7 +3,7 @@ package bbgo
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/accounting"
|
"github.com/c9s/bbgo/pkg/accounting/pnl"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ type Context struct {
|
||||||
CurrentPrice float64
|
CurrentPrice float64
|
||||||
|
|
||||||
Balances map[string]types.Balance
|
Balances map[string]types.Balance
|
||||||
ProfitAndLossCalculator *accounting.ProfitAndLossCalculator
|
ProfitAndLossCalculator *pnl.AverageCostCalculator
|
||||||
StockManager *StockDistribution
|
StockManager *StockDistribution
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user