bbgo_origin/bbgo/pnl.go

132 lines
2.9 KiB
Go
Raw Normal View History

2020-06-08 02:42:50 +00:00
package bbgo
2020-07-11 03:23:48 +00:00
import (
2020-07-11 04:42:28 +00:00
"github.com/c9s/bbgo/pkg/types"
2020-07-11 03:23:48 +00:00
log "github.com/sirupsen/logrus"
2020-07-11 04:37:09 +00:00
"strings"
2020-07-11 03:23:48 +00:00
"time"
)
2020-06-08 02:42:50 +00:00
2020-07-11 03:23:48 +00:00
type ProfitAndLossCalculator struct {
Symbol string
StartTime time.Time
CurrentPrice float64
2020-07-11 04:42:28 +00:00
Trades []types.Trade
2020-07-11 04:37:09 +00:00
CurrencyPrice map[string]float64
2020-07-11 03:23:48 +00:00
}
2020-07-11 04:42:28 +00:00
func (c *ProfitAndLossCalculator) AddTrade(trade types.Trade) {
2020-07-11 03:23:48 +00:00
c.Trades = append(c.Trades, trade)
}
2020-07-11 04:37:09 +00:00
func (c *ProfitAndLossCalculator) SetCurrencyPrice(symbol string, price float64) {
if c.CurrencyPrice == nil {
c.CurrencyPrice = map[string]float64{}
}
c.CurrencyPrice[symbol] = price
}
2020-07-11 03:23:48 +00:00
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
2020-06-08 02:42:50 +00:00
var bidVolume = 0.0
var bidAmount = 0.0
var bidFee = 0.0
// find the first buy trade
var firstBidIndex = -1
for idx, t := range trades {
if t.IsBuyer {
firstBidIndex = idx
break
}
}
if firstBidIndex > 0 {
trades = trades[firstBidIndex:]
}
2020-06-08 02:42:50 +00:00
for _, t := range trades {
if t.IsBuyer {
bidVolume += t.Volume
bidAmount += t.Price * t.Volume
2020-07-11 04:37:09 +00:00
// since we use USDT as the quote currency, we simply check if it matches the currency symbol
if strings.HasPrefix(t.Symbol, t.FeeCurrency) {
2020-06-08 02:42:50 +00:00
bidFee += t.Price * t.Fee
2020-07-11 04:37:09 +00:00
} else if t.FeeCurrency == "USDT" {
bidFee += t.Fee
2020-06-08 02:42:50 +00:00
}
}
}
log.Infof("average bid price = (total amount %f + total fee %f) / volume %f", bidAmount, bidFee, bidVolume)
2020-07-11 03:23:48 +00:00
profit := 0.0
averageBidPrice := (bidAmount + bidFee) / bidVolume
2020-06-08 02:42:50 +00:00
var feeRate = 0.001
var askVolume = 0.0
var askFee = 0.0
for _, t := range trades {
if !t.IsBuyer {
profit += (t.Price - averageBidPrice) * t.Volume
askVolume += t.Volume
switch t.FeeCurrency {
case "USDT":
askFee += t.Fee
}
}
}
profit -= askFee
2020-07-11 03:23:48 +00:00
stock := bidVolume - askVolume
2020-06-08 02:42:50 +00:00
futureFee := 0.0
if stock > 0 {
2020-07-11 03:23:48 +00:00
stockFee := c.CurrentPrice * feeRate * stock
profit += (c.CurrentPrice-averageBidPrice)*stock - stockFee
futureFee += stockFee
2020-06-08 02:42:50 +00:00
}
2020-07-11 03:23:48 +00:00
fee := bidFee + askFee + futureFee
return &ProfitAndLossReport{
2020-07-11 04:07:24 +00:00
Symbol: c.Symbol,
StartTime: c.StartTime,
CurrentPrice: c.CurrentPrice,
NumTrades: len(trades),
2020-07-11 03:23:48 +00:00
Profit: profit,
AverageBidPrice: averageBidPrice,
Stock: stock,
Fee: fee,
}
}
type ProfitAndLossReport struct {
CurrentPrice float64
StartTime time.Time
2020-07-11 04:07:24 +00:00
Symbol string
2020-07-11 03:23:48 +00:00
NumTrades int
Profit float64
AverageBidPrice float64
Stock float64
Fee float64
}
func (report ProfitAndLossReport) Print() {
log.Infof("trades since: %v", report.StartTime)
log.Infof("average bid price: %s", USD.FormatMoneyFloat64(report.AverageBidPrice))
2020-07-11 04:07:24 +00:00
log.Infof("stock volume: %f", report.Stock)
2020-07-11 03:23:48 +00:00
log.Infof("current price: %s", USD.FormatMoneyFloat64(report.CurrentPrice))
log.Infof("overall profit: %s", USD.FormatMoneyFloat64(report.Profit))
}