bbgo/pkg/strategy/dca2/profit_stats.go

97 lines
3.0 KiB
Go

package dca2
import (
"fmt"
"strings"
"git.qtrade.icu/lychiyu/bbgo/pkg/fixedpoint"
"git.qtrade.icu/lychiyu/bbgo/pkg/types"
)
type ProfitStats struct {
Symbol string `json:"symbol"`
Market types.Market `json:"market,omitempty"`
FromOrderID uint64 `json:"fromOrderID,omitempty"`
Round int64 `json:"round,omitempty"`
QuoteInvestment fixedpoint.Value `json:"quoteInvestment,omitempty"`
CurrentRoundProfit fixedpoint.Value `json:"currentRoundProfit,omitempty"`
CurrentRoundFee map[string]fixedpoint.Value `json:"currentRoundFee,omitempty"`
TotalProfit fixedpoint.Value `json:"totalProfit,omitempty"`
TotalFee map[string]fixedpoint.Value `json:"totalFee,omitempty"`
// used to flexible recovery
OpenPositionPVs []types.PriceVolume `json:"openPositionPVs,omitempty"`
types.PersistenceTTL
}
func newProfitStats(market types.Market, quoteInvestment fixedpoint.Value) *ProfitStats {
return &ProfitStats{
Symbol: market.Symbol,
Market: market,
Round: 1,
QuoteInvestment: quoteInvestment,
CurrentRoundFee: make(map[string]fixedpoint.Value),
TotalFee: make(map[string]fixedpoint.Value),
}
}
func (s *ProfitStats) AddTrade(trade types.Trade) {
if s.CurrentRoundFee == nil {
s.CurrentRoundFee = make(map[string]fixedpoint.Value)
}
if fee, ok := s.CurrentRoundFee[trade.FeeCurrency]; ok {
s.CurrentRoundFee[trade.FeeCurrency] = fee.Add(trade.Fee)
} else {
s.CurrentRoundFee[trade.FeeCurrency] = trade.Fee
}
if s.TotalFee == nil {
s.TotalFee = make(map[string]fixedpoint.Value)
}
if fee, ok := s.TotalFee[trade.FeeCurrency]; ok {
s.TotalFee[trade.FeeCurrency] = fee.Add(trade.Fee)
} else {
s.TotalFee[trade.FeeCurrency] = trade.Fee
}
quoteQuantity := trade.QuoteQuantity
if trade.Side == types.SideTypeBuy {
quoteQuantity = quoteQuantity.Neg()
}
s.CurrentRoundProfit = s.CurrentRoundProfit.Add(quoteQuantity)
s.TotalProfit = s.TotalProfit.Add(quoteQuantity)
if s.Market.QuoteCurrency == trade.FeeCurrency {
s.CurrentRoundProfit = s.CurrentRoundProfit.Sub(trade.Fee)
s.TotalProfit = s.TotalProfit.Sub(trade.Fee)
}
}
func (s *ProfitStats) NewRound() {
s.Round++
s.CurrentRoundProfit = fixedpoint.Zero
s.CurrentRoundFee = make(map[string]fixedpoint.Value)
}
func (s *ProfitStats) String() string {
var sb strings.Builder
sb.WriteString("[------------------ Profit Stats ------------------]\n")
sb.WriteString(fmt.Sprintf("Round: %d\n", s.Round))
sb.WriteString(fmt.Sprintf("From Order ID: %d\n", s.FromOrderID))
sb.WriteString(fmt.Sprintf("Quote Investment: %s\n", s.QuoteInvestment))
sb.WriteString(fmt.Sprintf("Current Round Profit: %s\n", s.CurrentRoundProfit))
sb.WriteString(fmt.Sprintf("Total Profit: %s\n", s.TotalProfit))
for currency, fee := range s.CurrentRoundFee {
sb.WriteString(fmt.Sprintf("FEE (%s): %s\n", currency, fee))
}
sb.WriteString("[------------------ Profit Stats ------------------]\n")
return sb.String()
}