mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
Merge pull request #1712 from c9s/c9s/xmaker/add-profit-fixer
FEATURE: [xmaker] add profit fixer
This commit is contained in:
commit
866751cc3d
|
@ -59,6 +59,9 @@ crossExchangeStrategies:
|
||||||
# 0.1 pip is 0.01, here we use 10, so we will get 18000.00, 18001.00 and
|
# 0.1 pip is 0.01, here we use 10, so we will get 18000.00, 18001.00 and
|
||||||
# 18002.00
|
# 18002.00
|
||||||
pips: 10
|
pips: 10
|
||||||
|
## profitFixer is used for fixing the profit stats and the position
|
||||||
|
# profitFixer:
|
||||||
|
# tradesSince: "2024-08-01T15:00:00.000+08:00"
|
||||||
circuitBreaker:
|
circuitBreaker:
|
||||||
enabled: true
|
enabled: true
|
||||||
maximumConsecutiveTotalLoss: 36.0
|
maximumConsecutiveTotalLoss: 36.0
|
||||||
|
|
|
@ -75,6 +75,8 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type BasicCircuitBreaker struct {
|
type BasicCircuitBreaker struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
|
||||||
MaximumConsecutiveTotalLoss fixedpoint.Value `json:"maximumConsecutiveTotalLoss"`
|
MaximumConsecutiveTotalLoss fixedpoint.Value `json:"maximumConsecutiveTotalLoss"`
|
||||||
|
|
||||||
MaximumConsecutiveLossTimes int `json:"maximumConsecutiveLossTimes"`
|
MaximumConsecutiveLossTimes int `json:"maximumConsecutiveLossTimes"`
|
||||||
|
@ -117,14 +119,17 @@ type BasicCircuitBreaker struct {
|
||||||
|
|
||||||
func NewBasicCircuitBreaker(strategyID, strategyInstance string) *BasicCircuitBreaker {
|
func NewBasicCircuitBreaker(strategyID, strategyInstance string) *BasicCircuitBreaker {
|
||||||
b := &BasicCircuitBreaker{
|
b := &BasicCircuitBreaker{
|
||||||
|
Enabled: true,
|
||||||
MaximumConsecutiveLossTimes: 8,
|
MaximumConsecutiveLossTimes: 8,
|
||||||
MaximumHaltTimes: 3,
|
MaximumHaltTimes: 3,
|
||||||
MaximumHaltTimesExceededPanic: false,
|
MaximumHaltTimesExceededPanic: false,
|
||||||
|
|
||||||
HaltDuration: types.Duration(1 * time.Hour),
|
HaltDuration: types.Duration(1 * time.Hour),
|
||||||
strategyID: strategyID,
|
strategyID: strategyID,
|
||||||
strategyInstance: strategyInstance,
|
strategyInstance: strategyInstance,
|
||||||
metricsLabels: prometheus.Labels{"strategy": strategyID, "strategyInstance": strategyInstance},
|
metricsLabels: prometheus.Labels{"strategy": strategyID, "strategyInstance": strategyInstance},
|
||||||
}
|
}
|
||||||
|
|
||||||
b.updateMetrics()
|
b.updateMetrics()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
@ -182,7 +187,7 @@ func (b *BasicCircuitBreaker) RecordProfit(profit fixedpoint.Value, now time.Tim
|
||||||
b.winRatio = float64(b.winTimes) / float64(b.lossTimes)
|
b.winRatio = float64(b.winTimes) / float64(b.lossTimes)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.updateMetrics()
|
defer b.updateMetrics()
|
||||||
|
|
||||||
if b.MaximumConsecutiveLossTimes > 0 && b.consecutiveLossTimes >= b.MaximumConsecutiveLossTimes {
|
if b.MaximumConsecutiveLossTimes > 0 && b.consecutiveLossTimes >= b.MaximumConsecutiveLossTimes {
|
||||||
b.halt(now, "exceeded MaximumConsecutiveLossTimes")
|
b.halt(now, "exceeded MaximumConsecutiveLossTimes")
|
||||||
|
@ -224,6 +229,10 @@ func (b *BasicCircuitBreaker) reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BasicCircuitBreaker) IsHalted(now time.Time) (string, bool) {
|
func (b *BasicCircuitBreaker) IsHalted(now time.Time) (string, bool) {
|
||||||
|
if !b.Enabled {
|
||||||
|
return "disabled", false
|
||||||
|
}
|
||||||
|
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
|
@ -251,6 +260,8 @@ func (b *BasicCircuitBreaker) halt(now time.Time, reason string) {
|
||||||
haltCounterMetrics.With(labels).Set(float64(b.haltCounter))
|
haltCounterMetrics.With(labels).Set(float64(b.haltCounter))
|
||||||
haltMetrics.With(labels).Set(1.0)
|
haltMetrics.With(labels).Set(1.0)
|
||||||
|
|
||||||
|
defer b.updateMetrics()
|
||||||
|
|
||||||
if b.MaximumHaltTimesExceededPanic && b.haltCounter > b.MaximumHaltTimes {
|
if b.MaximumHaltTimesExceededPanic && b.haltCounter > b.MaximumHaltTimes {
|
||||||
panic(fmt.Errorf("total %d halt times > maximumHaltTimesExceededPanic %d", b.haltCounter, b.MaximumHaltTimes))
|
panic(fmt.Errorf("total %d halt times > maximumHaltTimesExceededPanic %d", b.haltCounter, b.MaximumHaltTimes))
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,16 @@ import (
|
||||||
indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2"
|
indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2"
|
||||||
"github.com/c9s/bbgo/pkg/pricesolver"
|
"github.com/c9s/bbgo/pkg/pricesolver"
|
||||||
"github.com/c9s/bbgo/pkg/risk/circuitbreaker"
|
"github.com/c9s/bbgo/pkg/risk/circuitbreaker"
|
||||||
|
"github.com/c9s/bbgo/pkg/strategy/common"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
"github.com/c9s/bbgo/pkg/util"
|
"github.com/c9s/bbgo/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultMargin = fixedpoint.NewFromFloat(0.003)
|
var defaultMargin = fixedpoint.NewFromFloat(0.003)
|
||||||
var Two = fixedpoint.NewFromInt(2)
|
var two = fixedpoint.NewFromInt(2)
|
||||||
|
|
||||||
|
var lastPriceModifier = fixedpoint.NewFromFloat(1.001)
|
||||||
|
var minGap = fixedpoint.NewFromFloat(1.02)
|
||||||
|
|
||||||
const priceUpdateTimeout = 30 * time.Second
|
const priceUpdateTimeout = 30 * time.Second
|
||||||
|
|
||||||
|
@ -89,6 +93,9 @@ type Strategy struct {
|
||||||
// Pips is the pips of the layer prices
|
// Pips is the pips of the layer prices
|
||||||
Pips fixedpoint.Value `json:"pips"`
|
Pips fixedpoint.Value `json:"pips"`
|
||||||
|
|
||||||
|
// ProfitFixerConfig is the profit fixer configuration
|
||||||
|
ProfitFixerConfig *common.ProfitFixerConfig `json:"profitFixer,omitempty"`
|
||||||
|
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
// private field
|
// private field
|
||||||
|
|
||||||
|
@ -215,7 +222,7 @@ func (s *Strategy) updateQuote(ctx context.Context, orderExecutionRouter bbgo.Or
|
||||||
}
|
}
|
||||||
|
|
||||||
// use mid-price for the last price
|
// use mid-price for the last price
|
||||||
s.lastPrice = bestBid.Price.Add(bestAsk.Price).Div(Two)
|
s.lastPrice = bestBid.Price.Add(bestAsk.Price).Div(two)
|
||||||
|
|
||||||
s.priceSolver.Update(s.Symbol, s.lastPrice)
|
s.priceSolver.Update(s.Symbol, s.lastPrice)
|
||||||
|
|
||||||
|
@ -543,9 +550,6 @@ func (s *Strategy) updateQuote(ctx context.Context, orderExecutionRouter bbgo.Or
|
||||||
_ = createdOrders
|
_ = createdOrders
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastPriceModifier = fixedpoint.NewFromFloat(1.001)
|
|
||||||
var minGap = fixedpoint.NewFromFloat(1.02)
|
|
||||||
|
|
||||||
func (s *Strategy) Hedge(ctx context.Context, pos fixedpoint.Value) {
|
func (s *Strategy) Hedge(ctx context.Context, pos fixedpoint.Value) {
|
||||||
side := types.SideTypeBuy
|
side := types.SideTypeBuy
|
||||||
if pos.IsZero() {
|
if pos.IsZero() {
|
||||||
|
@ -852,6 +856,47 @@ func (s *Strategy) CrossRun(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.ProfitFixerConfig != nil {
|
||||||
|
bbgo.Notify("Fixing %s profitStats and position...", s.Symbol)
|
||||||
|
|
||||||
|
log.Infof("profitFixer is enabled, checking checkpoint: %+v", s.ProfitFixerConfig.TradesSince)
|
||||||
|
|
||||||
|
if s.ProfitFixerConfig.TradesSince.Time().IsZero() {
|
||||||
|
return errors.New("tradesSince time can not be zero")
|
||||||
|
}
|
||||||
|
|
||||||
|
makerMarket, _ := makerSession.Market(s.Symbol)
|
||||||
|
position := types.NewPositionFromMarket(makerMarket)
|
||||||
|
profitStats := types.NewProfitStats(makerMarket)
|
||||||
|
|
||||||
|
fixer := common.NewProfitFixer()
|
||||||
|
// fixer.ConverterManager = s.ConverterManager
|
||||||
|
|
||||||
|
if ss, ok := makerSession.Exchange.(types.ExchangeTradeHistoryService); ok {
|
||||||
|
log.Infof("adding makerSession %s to profitFixer", makerSession.Name)
|
||||||
|
fixer.AddExchange(makerSession.Name, ss)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ss, ok := sourceSession.Exchange.(types.ExchangeTradeHistoryService); ok {
|
||||||
|
log.Infof("adding hedgeSession %s to profitFixer", sourceSession.Name)
|
||||||
|
fixer.AddExchange(sourceSession.Name, ss)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err2 := fixer.Fix(ctx, makerMarket.Symbol,
|
||||||
|
s.ProfitFixerConfig.TradesSince.Time(),
|
||||||
|
time.Now(),
|
||||||
|
profitStats,
|
||||||
|
position); err2 != nil {
|
||||||
|
return err2
|
||||||
|
}
|
||||||
|
|
||||||
|
bbgo.Notify("Fixed %s position", s.Symbol, position)
|
||||||
|
bbgo.Notify("Fixed %s profitStats", s.Symbol, profitStats)
|
||||||
|
|
||||||
|
s.Position = position
|
||||||
|
s.ProfitStats.ProfitStats = profitStats
|
||||||
|
}
|
||||||
|
|
||||||
s.book = types.NewStreamBook(s.Symbol, s.sourceSession.ExchangeName)
|
s.book = types.NewStreamBook(s.Symbol, s.sourceSession.ExchangeName)
|
||||||
s.book.BindStream(s.sourceSession.MarketDataStream)
|
s.book.BindStream(s.sourceSession.MarketDataStream)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user