106 lines
2.6 KiB
Go
106 lines
2.6 KiB
Go
|
package grid2
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"time"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
"github.com/sirupsen/logrus"
|
||
|
|
||
|
"git.qtrade.icu/lychiyu/bbgo/pkg/exchange/batch"
|
||
|
"git.qtrade.icu/lychiyu/bbgo/pkg/fixedpoint"
|
||
|
"git.qtrade.icu/lychiyu/bbgo/pkg/types"
|
||
|
)
|
||
|
|
||
|
type ProfitFixer struct {
|
||
|
symbol string
|
||
|
grid *Grid
|
||
|
historyService types.ExchangeTradeHistoryService
|
||
|
|
||
|
logger logrus.FieldLogger
|
||
|
}
|
||
|
|
||
|
func newProfitFixer(grid *Grid, symbol string, historyService types.ExchangeTradeHistoryService) *ProfitFixer {
|
||
|
return &ProfitFixer{
|
||
|
symbol: symbol,
|
||
|
grid: grid,
|
||
|
historyService: historyService,
|
||
|
logger: logrus.StandardLogger(),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (f *ProfitFixer) SetLogger(logger logrus.FieldLogger) {
|
||
|
f.logger = logger
|
||
|
}
|
||
|
|
||
|
// Fix fixes the total quote profit of the given grid
|
||
|
func (f *ProfitFixer) Fix(parent context.Context, since, until time.Time, initialOrderID uint64, profitStats *GridProfitStats) error {
|
||
|
// reset profit
|
||
|
profitStats.TotalQuoteProfit = fixedpoint.Zero
|
||
|
profitStats.ArbitrageCount = 0
|
||
|
|
||
|
defer f.logger.Infof("profitFixer: done")
|
||
|
|
||
|
if profitStats.Since != nil && !profitStats.Since.IsZero() && profitStats.Since.Before(since) {
|
||
|
f.logger.Infof("profitFixer: profitStats.since %s is earlier than the given since %s, setting since to %s", profitStats.Since, since, profitStats.Since)
|
||
|
since = *profitStats.Since
|
||
|
}
|
||
|
|
||
|
ctx, cancel := context.WithTimeout(parent, 15*time.Minute)
|
||
|
defer cancel()
|
||
|
|
||
|
q := &batch.ClosedOrderBatchQuery{ExchangeTradeHistoryService: f.historyService}
|
||
|
orderC, errC := q.Query(ctx, f.symbol, since, until, initialOrderID)
|
||
|
|
||
|
defer func() {
|
||
|
f.logger.Infof("profitFixer: fixed profitStats=%#v", profitStats)
|
||
|
}()
|
||
|
|
||
|
for {
|
||
|
select {
|
||
|
case <-ctx.Done():
|
||
|
if errors.Is(ctx.Err(), context.Canceled) {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
return ctx.Err()
|
||
|
|
||
|
case order, ok := <-orderC:
|
||
|
if !ok {
|
||
|
return <-errC
|
||
|
}
|
||
|
|
||
|
if !f.grid.HasPrice(order.Price) {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if profitStats.InitialOrderID == 0 || order.OrderID < profitStats.InitialOrderID {
|
||
|
profitStats.InitialOrderID = order.OrderID
|
||
|
}
|
||
|
|
||
|
if profitStats.Since == nil || profitStats.Since.IsZero() || order.CreationTime.Time().Before(*profitStats.Since) {
|
||
|
ct := order.CreationTime.Time()
|
||
|
profitStats.Since = &ct
|
||
|
}
|
||
|
|
||
|
if order.Status != types.OrderStatusFilled {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if order.Type != types.OrderTypeLimit {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if order.Side != types.SideTypeSell {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
quoteProfit := order.Quantity.Mul(f.grid.Spread)
|
||
|
profitStats.TotalQuoteProfit = profitStats.TotalQuoteProfit.Add(quoteProfit)
|
||
|
profitStats.ArbitrageCount++
|
||
|
|
||
|
f.logger.Debugf("profitFixer: filledSellOrder=%#v", order)
|
||
|
}
|
||
|
}
|
||
|
}
|