qbtrade/pkg/strategy/grid2/profit_stats.go

190 lines
4.7 KiB
Go
Raw Normal View History

2024-06-27 14:42:38 +00:00
package grid2
import (
"fmt"
"strconv"
"time"
"github.com/slack-go/slack"
"git.qtrade.icu/lychiyu/qbtrade/pkg/fixedpoint"
"git.qtrade.icu/lychiyu/qbtrade/pkg/style"
"git.qtrade.icu/lychiyu/qbtrade/pkg/types"
)
type GridProfitStats struct {
Symbol string `json:"symbol"`
TotalBaseProfit fixedpoint.Value `json:"totalBaseProfit,omitempty"`
TotalQuoteProfit fixedpoint.Value `json:"totalQuoteProfit,omitempty"`
FloatProfit fixedpoint.Value `json:"floatProfit,omitempty"`
GridProfit fixedpoint.Value `json:"gridProfit,omitempty"`
ArbitrageCount int `json:"arbitrageCount,omitempty"`
TotalFee map[string]fixedpoint.Value `json:"totalFee,omitempty"`
Volume fixedpoint.Value `json:"volume,omitempty"`
Market types.Market `json:"market,omitempty"`
Since *time.Time `json:"since,omitempty"`
InitialOrderID uint64 `json:"initialOrderID"`
// ttl is the ttl to keep in persistence
ttl time.Duration
}
func newGridProfitStats(market types.Market) *GridProfitStats {
return &GridProfitStats{
Symbol: market.Symbol,
TotalBaseProfit: fixedpoint.Zero,
TotalQuoteProfit: fixedpoint.Zero,
FloatProfit: fixedpoint.Zero,
GridProfit: fixedpoint.Zero,
ArbitrageCount: 0,
TotalFee: make(map[string]fixedpoint.Value),
Volume: fixedpoint.Zero,
Market: market,
}
}
func (s *GridProfitStats) SetTTL(ttl time.Duration) {
if ttl.Nanoseconds() <= 0 {
return
}
s.ttl = ttl
}
func (s *GridProfitStats) Expiration() time.Duration {
return s.ttl
}
func (s *GridProfitStats) AddTrade(trade types.Trade) {
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
}
if s.Since == nil {
t := trade.Time.Time()
s.Since = &t
}
}
func (s *GridProfitStats) AddProfit(profit *GridProfit) {
// increase arbitrage count per profit round
s.ArbitrageCount++
switch profit.Currency {
case s.Market.QuoteCurrency:
s.TotalQuoteProfit = s.TotalQuoteProfit.Add(profit.Profit)
case s.Market.BaseCurrency:
s.TotalBaseProfit = s.TotalBaseProfit.Add(profit.Profit)
}
}
func (s *GridProfitStats) SlackAttachment() slack.Attachment {
var fields = []slack.AttachmentField{
{
Title: "Arbitrage Count",
Value: strconv.Itoa(s.ArbitrageCount),
Short: true,
},
}
if !s.FloatProfit.IsZero() {
fields = append(fields, slack.AttachmentField{
Title: "Float Profit",
Value: style.PnLSignString(s.FloatProfit),
Short: true,
})
}
if !s.GridProfit.IsZero() {
fields = append(fields, slack.AttachmentField{
Title: "Total Grid Profit",
Value: style.PnLSignString(s.GridProfit),
Short: true,
})
}
if !s.TotalQuoteProfit.IsZero() {
fields = append(fields, slack.AttachmentField{
Title: "Total Quote Profit",
Value: style.PnLSignString(s.TotalQuoteProfit),
Short: true,
})
}
if !s.TotalBaseProfit.IsZero() {
fields = append(fields, slack.AttachmentField{
Title: "Total Base Profit",
Value: style.PnLSignString(s.TotalBaseProfit),
Short: true,
})
}
if len(s.TotalFee) > 0 {
for feeCurrency, fee := range s.TotalFee {
fields = append(fields, slack.AttachmentField{
Title: fmt.Sprintf("Fee (%s)", feeCurrency),
Value: fee.String() + " " + feeCurrency,
Short: true,
})
}
}
footer := "Total grid profit stats"
if s.Since != nil {
footer += fmt.Sprintf(" since %s", s.Since.String())
}
title := fmt.Sprintf("%s Grid Profit Stats", s.Symbol)
return slack.Attachment{
Title: title,
Color: "warning",
Fields: fields,
Footer: footer,
}
}
func (s *GridProfitStats) String() string {
return s.PlainText()
}
func (s *GridProfitStats) PlainText() string {
var o string
o = fmt.Sprintf("%s Grid Profit Stats", s.Symbol)
o += fmt.Sprintf(" Arbitrage count: %d", s.ArbitrageCount)
if !s.FloatProfit.IsZero() {
o += " Float profit: " + style.PnLSignString(s.FloatProfit)
}
if !s.GridProfit.IsZero() {
o += " Grid profit: " + style.PnLSignString(s.GridProfit)
}
if !s.TotalQuoteProfit.IsZero() {
o += " Total quote profit: " + style.PnLSignString(s.TotalQuoteProfit) + " " + s.Market.QuoteCurrency
}
if !s.TotalBaseProfit.IsZero() {
o += " Total base profit: " + style.PnLSignString(s.TotalBaseProfit) + " " + s.Market.BaseCurrency
}
if len(s.TotalFee) > 0 {
for feeCurrency, fee := range s.TotalFee {
o += fmt.Sprintf(" Fee (%s)", feeCurrency) + fee.String() + " " + feeCurrency
}
}
if s.Since != nil {
o += fmt.Sprintf(" Since %s", s.Since.String())
}
return o
}