mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 17:13:51 +00:00
113 lines
2.4 KiB
Go
113 lines
2.4 KiB
Go
package pnl
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/c9s/bbgo/pkg/types"
|
|
)
|
|
|
|
type AverageCostCalculator struct {
|
|
TradingFeeCurrency string
|
|
}
|
|
|
|
func (c *AverageCostCalculator) Calculate(symbol string, trades []types.Trade, currentPrice float64) *AverageCostPnlReport {
|
|
// copy trades, so that we can truncate it.
|
|
var bidVolume = 0.0
|
|
var bidAmount = 0.0
|
|
|
|
var askVolume = 0.0
|
|
|
|
var feeUSD = 0.0
|
|
var bidFeeUSD = 0.0
|
|
var feeRate = 0.0015
|
|
|
|
if len(trades) == 0 {
|
|
return &AverageCostPnlReport{
|
|
Symbol: symbol,
|
|
CurrentPrice: currentPrice,
|
|
NumTrades: 0,
|
|
BuyVolume: bidVolume,
|
|
SellVolume: askVolume,
|
|
FeeInUSD: feeUSD,
|
|
}
|
|
}
|
|
|
|
var currencyFees = map[string]float64{}
|
|
|
|
for _, trade := range trades {
|
|
if trade.Symbol == symbol {
|
|
if trade.IsBuyer && trade.Side != types.SideTypeSelf {
|
|
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
|
|
}
|
|
|
|
profit := 0.0
|
|
averageCost := (bidAmount + bidFeeUSD) / bidVolume
|
|
|
|
for _, t := range trades {
|
|
if t.Symbol != symbol {
|
|
continue
|
|
}
|
|
|
|
if t.IsBuyer || t.Side == types.SideTypeSelf {
|
|
continue
|
|
}
|
|
|
|
profit += (t.Price - averageCost) * t.Quantity
|
|
askVolume += t.Quantity
|
|
}
|
|
|
|
profit -= feeUSD
|
|
unrealizedProfit := profit
|
|
|
|
stock := bidVolume - askVolume
|
|
if stock > 0 {
|
|
stockFee := currentPrice * stock * feeRate
|
|
unrealizedProfit += (currentPrice-averageCost)*stock - stockFee
|
|
}
|
|
|
|
return &AverageCostPnlReport{
|
|
Symbol: symbol,
|
|
CurrentPrice: currentPrice,
|
|
NumTrades: len(trades),
|
|
StartTime: time.Time(trades[0].Time),
|
|
|
|
BuyVolume: bidVolume,
|
|
SellVolume: askVolume,
|
|
|
|
Stock: stock,
|
|
Profit: profit,
|
|
UnrealizedProfit: unrealizedProfit,
|
|
AverageBidCost: averageCost,
|
|
FeeInUSD: feeUSD,
|
|
CurrencyFees: currencyFees,
|
|
}
|
|
}
|