97 lines
3.0 KiB
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()
|
||
|
}
|