integrate AverageCostPnLReporter

This commit is contained in:
c9s 2020-10-22 15:57:50 +08:00
parent 897d882c35
commit aea6a7c03d
6 changed files with 89 additions and 6 deletions

View File

@ -112,11 +112,10 @@ var pnlCmd = &cobra.Command{
calculator := &pnl.AverageCostCalculator{ calculator := &pnl.AverageCostCalculator{
TradingFeeCurrency: tradingFeeCurrency, TradingFeeCurrency: tradingFeeCurrency,
Symbol: symbol,
StartTime: startTime, StartTime: startTime,
} }
report := calculator.Calculate(trades, currentPrice) report := calculator.Calculate(symbol, trades, currentPrice)
report.Print() report.Print()
return nil return nil
}, },

View File

@ -79,6 +79,9 @@ var runCmd = &cobra.Command{
trader.AttachCrossExchangeStrategy(strategy) trader.AttachCrossExchangeStrategy(strategy)
} }
trader.ReportPnL(notifier).
AverageCostBySymbols("BTCUSDT", "BNBUSDT").Of("max", "binance")
err = trader.Run(ctx) err = trader.Run(ctx)
if err != nil { if err != nil {
return err return err

1
go.mod
View File

@ -26,6 +26,7 @@ require (
github.com/onsi/gomega v1.7.1 // indirect github.com/onsi/gomega v1.7.1 // indirect
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
github.com/robfig/cron/v3 v3.0.0
github.com/shopspring/decimal v1.2.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect
github.com/sirupsen/logrus v1.4.2 github.com/sirupsen/logrus v1.4.2
github.com/slack-go/slack v0.6.6-0.20200602212211-b04b8521281b github.com/slack-go/slack v0.6.6-0.20200602212211-b04b8521281b

2
go.sum
View File

@ -228,6 +228,8 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=

View File

@ -15,7 +15,7 @@ type AverageCostCalculator struct {
TradingFeeCurrency string TradingFeeCurrency string
} }
func (c *AverageCostCalculator) Calculate(trades []types.Trade, currentPrice float64) *AverageCostPnlReport { func (c *AverageCostCalculator) Calculate(symbol string, trades []types.Trade, currentPrice float64) *AverageCostPnlReport {
// copy trades, so that we can truncate it. // copy trades, so that we can truncate it.
var bidVolume = 0.0 var bidVolume = 0.0
var bidAmount = 0.0 var bidAmount = 0.0
@ -29,7 +29,7 @@ func (c *AverageCostCalculator) Calculate(trades []types.Trade, currentPrice flo
var currencyFees = map[string]float64{} var currencyFees = map[string]float64{}
for _, trade := range trades { for _, trade := range trades {
if trade.Symbol == c.Symbol { if trade.Symbol == symbol {
if trade.IsBuyer { if trade.IsBuyer {
bidVolume += trade.Quantity bidVolume += trade.Quantity
bidAmount += trade.Price * trade.Quantity bidAmount += trade.Price * trade.Quantity
@ -66,7 +66,7 @@ func (c *AverageCostCalculator) Calculate(trades []types.Trade, currentPrice flo
averageCost := (bidAmount + bidFeeUSD) / bidVolume averageCost := (bidAmount + bidFeeUSD) / bidVolume
for _, t := range trades { for _, t := range trades {
if t.Symbol != c.Symbol { if t.Symbol != symbol {
continue continue
} }
@ -88,7 +88,7 @@ func (c *AverageCostCalculator) Calculate(trades []types.Trade, currentPrice flo
} }
return &AverageCostPnlReport{ return &AverageCostPnlReport{
Symbol: c.Symbol, Symbol: symbol,
StartTime: c.StartTime, StartTime: c.StartTime,
CurrentPrice: currentPrice, CurrentPrice: currentPrice,
NumTrades: len(trades), NumTrades: len(trades),

View File

@ -2,10 +2,13 @@ package bbgo
import ( import (
"context" "context"
"time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/robfig/cron/v3"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/accounting/pnl"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
@ -31,6 +34,77 @@ type CrossExchangeStrategy interface {
Run(ctx context.Context, orderExecutionRouter types.OrderExecutionRouter, sessions map[string]*ExchangeSession) error Run(ctx context.Context, orderExecutionRouter types.OrderExecutionRouter, sessions map[string]*ExchangeSession) error
} }
type PnLReporter interface {
Run()
}
type baseReporter struct {
notifier Notifier
cron *cron.Cron
environment *Environment
}
type PnLReporterManager struct {
baseReporter
reporters []PnLReporter
}
func NewPnLReporter(notifier Notifier) *PnLReporterManager {
return &PnLReporterManager{
baseReporter: baseReporter{
notifier: notifier,
cron: cron.New(),
},
}
}
func (manager *PnLReporterManager) AverageCostBySymbols(symbols ...string) *AverageCostPnLReporter {
reporter := &AverageCostPnLReporter{
baseReporter: manager.baseReporter,
Symbols: symbols,
}
manager.reporters = append(manager.reporters, reporter)
return reporter
}
type AverageCostPnLReporter struct {
baseReporter
Sessions []string
Symbols []string
}
func (reporter *AverageCostPnLReporter) Of(sessions ...string) *AverageCostPnLReporter {
reporter.Sessions = sessions
return reporter
}
func (reporter *AverageCostPnLReporter) When(spec string) *AverageCostPnLReporter {
_, err := reporter.cron.AddJob(spec, reporter)
if err != nil {
panic(err)
}
return reporter
}
func (reporter *AverageCostPnLReporter) Run() {
for _, sessionName := range reporter.Sessions {
session := reporter.environment.sessions[sessionName]
calculator := &pnl.AverageCostCalculator{
StartTime: time.Time{},
TradingFeeCurrency: session.Exchange.PlatformFeeCurrency(),
}
for _, symbol := range reporter.Symbols {
report := calculator.Calculate(symbol, session.Trades[symbol], session.lastPrices[symbol])
report.Print()
}
}
}
type Trader struct { type Trader struct {
Notifiability Notifiability
@ -219,6 +293,10 @@ func (trader *Trader) reportPnL() {
} }
*/ */
func (trader *Trader) ReportPnL(notifier Notifier) *PnLReporterManager {
return NewPnLReporter(notifier)
}
func (trader *Trader) SubmitOrder(ctx context.Context, order types.SubmitOrder) { func (trader *Trader) SubmitOrder(ctx context.Context, order types.SubmitOrder) {
trader.Notify(":memo: Submitting %s %s %s order with quantity: %s", order.Symbol, order.Type, order.Side, order.QuantityString, order) trader.Notify(":memo: Submitting %s %s %s order with quantity: %s", order.Symbol, order.Type, order.Side, order.QuantityString, order)