Skip to content

Commit 866751c

Browse files
authored
Merge pull request #1712 from c9s/c9s/xmaker/add-profit-fixer
FEATURE: [xmaker] add profit fixer
2 parents 80949bf + 7fdb3f6 commit 866751c

File tree

3 files changed

+69
-10
lines changed

3 files changed

+69
-10
lines changed

config/xmaker.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ crossExchangeStrategies:
5959
# 0.1 pip is 0.01, here we use 10, so we will get 18000.00, 18001.00 and
6060
# 18002.00
6161
pips: 10
62+
## profitFixer is used for fixing the profit stats and the position
63+
# profitFixer:
64+
# tradesSince: "2024-08-01T15:00:00.000+08:00"
6265
circuitBreaker:
6366
enabled: true
6467
maximumConsecutiveTotalLoss: 36.0

pkg/risk/circuitbreaker/basic.go

+16-5
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ func init() {
7575
}
7676

7777
type BasicCircuitBreaker struct {
78+
Enabled bool `json:"enabled"`
79+
7880
MaximumConsecutiveTotalLoss fixedpoint.Value `json:"maximumConsecutiveTotalLoss"`
7981

8082
MaximumConsecutiveLossTimes int `json:"maximumConsecutiveLossTimes"`
@@ -117,14 +119,17 @@ type BasicCircuitBreaker struct {
117119

118120
func NewBasicCircuitBreaker(strategyID, strategyInstance string) *BasicCircuitBreaker {
119121
b := &BasicCircuitBreaker{
122+
Enabled: true,
120123
MaximumConsecutiveLossTimes: 8,
121124
MaximumHaltTimes: 3,
122125
MaximumHaltTimesExceededPanic: false,
123-
HaltDuration: types.Duration(1 * time.Hour),
124-
strategyID: strategyID,
125-
strategyInstance: strategyInstance,
126-
metricsLabels: prometheus.Labels{"strategy": strategyID, "strategyInstance": strategyInstance},
126+
127+
HaltDuration: types.Duration(1 * time.Hour),
128+
strategyID: strategyID,
129+
strategyInstance: strategyInstance,
130+
metricsLabels: prometheus.Labels{"strategy": strategyID, "strategyInstance": strategyInstance},
127131
}
132+
128133
b.updateMetrics()
129134
return b
130135
}
@@ -182,7 +187,7 @@ func (b *BasicCircuitBreaker) RecordProfit(profit fixedpoint.Value, now time.Tim
182187
b.winRatio = float64(b.winTimes) / float64(b.lossTimes)
183188
}
184189

185-
b.updateMetrics()
190+
defer b.updateMetrics()
186191

187192
if b.MaximumConsecutiveLossTimes > 0 && b.consecutiveLossTimes >= b.MaximumConsecutiveLossTimes {
188193
b.halt(now, "exceeded MaximumConsecutiveLossTimes")
@@ -224,6 +229,10 @@ func (b *BasicCircuitBreaker) reset() {
224229
}
225230

226231
func (b *BasicCircuitBreaker) IsHalted(now time.Time) (string, bool) {
232+
if !b.Enabled {
233+
return "disabled", false
234+
}
235+
227236
b.mu.Lock()
228237
defer b.mu.Unlock()
229238

@@ -251,6 +260,8 @@ func (b *BasicCircuitBreaker) halt(now time.Time, reason string) {
251260
haltCounterMetrics.With(labels).Set(float64(b.haltCounter))
252261
haltMetrics.With(labels).Set(1.0)
253262

263+
defer b.updateMetrics()
264+
254265
if b.MaximumHaltTimesExceededPanic && b.haltCounter > b.MaximumHaltTimes {
255266
panic(fmt.Errorf("total %d halt times > maximumHaltTimesExceededPanic %d", b.haltCounter, b.MaximumHaltTimes))
256267
}

pkg/strategy/xmaker/strategy.go

+50-5
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@ import (
1717
indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2"
1818
"github.com/c9s/bbgo/pkg/pricesolver"
1919
"github.com/c9s/bbgo/pkg/risk/circuitbreaker"
20+
"github.com/c9s/bbgo/pkg/strategy/common"
2021
"github.com/c9s/bbgo/pkg/types"
2122
"github.com/c9s/bbgo/pkg/util"
2223
)
2324

2425
var defaultMargin = fixedpoint.NewFromFloat(0.003)
25-
var Two = fixedpoint.NewFromInt(2)
26+
var two = fixedpoint.NewFromInt(2)
27+
28+
var lastPriceModifier = fixedpoint.NewFromFloat(1.001)
29+
var minGap = fixedpoint.NewFromFloat(1.02)
2630

2731
const priceUpdateTimeout = 30 * time.Second
2832

@@ -89,6 +93,9 @@ type Strategy struct {
8993
// Pips is the pips of the layer prices
9094
Pips fixedpoint.Value `json:"pips"`
9195

96+
// ProfitFixerConfig is the profit fixer configuration
97+
ProfitFixerConfig *common.ProfitFixerConfig `json:"profitFixer,omitempty"`
98+
9299
// --------------------------------
93100
// private field
94101

@@ -215,7 +222,7 @@ func (s *Strategy) updateQuote(ctx context.Context, orderExecutionRouter bbgo.Or
215222
}
216223

217224
// use mid-price for the last price
218-
s.lastPrice = bestBid.Price.Add(bestAsk.Price).Div(Two)
225+
s.lastPrice = bestBid.Price.Add(bestAsk.Price).Div(two)
219226

220227
s.priceSolver.Update(s.Symbol, s.lastPrice)
221228

@@ -543,9 +550,6 @@ func (s *Strategy) updateQuote(ctx context.Context, orderExecutionRouter bbgo.Or
543550
_ = createdOrders
544551
}
545552

546-
var lastPriceModifier = fixedpoint.NewFromFloat(1.001)
547-
var minGap = fixedpoint.NewFromFloat(1.02)
548-
549553
func (s *Strategy) Hedge(ctx context.Context, pos fixedpoint.Value) {
550554
side := types.SideTypeBuy
551555
if pos.IsZero() {
@@ -852,6 +856,47 @@ func (s *Strategy) CrossRun(
852856
})
853857
}
854858

859+
if s.ProfitFixerConfig != nil {
860+
bbgo.Notify("Fixing %s profitStats and position...", s.Symbol)
861+
862+
log.Infof("profitFixer is enabled, checking checkpoint: %+v", s.ProfitFixerConfig.TradesSince)
863+
864+
if s.ProfitFixerConfig.TradesSince.Time().IsZero() {
865+
return errors.New("tradesSince time can not be zero")
866+
}
867+
868+
makerMarket, _ := makerSession.Market(s.Symbol)
869+
position := types.NewPositionFromMarket(makerMarket)
870+
profitStats := types.NewProfitStats(makerMarket)
871+
872+
fixer := common.NewProfitFixer()
873+
// fixer.ConverterManager = s.ConverterManager
874+
875+
if ss, ok := makerSession.Exchange.(types.ExchangeTradeHistoryService); ok {
876+
log.Infof("adding makerSession %s to profitFixer", makerSession.Name)
877+
fixer.AddExchange(makerSession.Name, ss)
878+
}
879+
880+
if ss, ok := sourceSession.Exchange.(types.ExchangeTradeHistoryService); ok {
881+
log.Infof("adding hedgeSession %s to profitFixer", sourceSession.Name)
882+
fixer.AddExchange(sourceSession.Name, ss)
883+
}
884+
885+
if err2 := fixer.Fix(ctx, makerMarket.Symbol,
886+
s.ProfitFixerConfig.TradesSince.Time(),
887+
time.Now(),
888+
profitStats,
889+
position); err2 != nil {
890+
return err2
891+
}
892+
893+
bbgo.Notify("Fixed %s position", s.Symbol, position)
894+
bbgo.Notify("Fixed %s profitStats", s.Symbol, profitStats)
895+
896+
s.Position = position
897+
s.ProfitStats.ProfitStats = profitStats
898+
}
899+
855900
s.book = types.NewStreamBook(s.Symbol, s.sourceSession.ExchangeName)
856901
s.book.BindStream(s.sourceSession.MarketDataStream)
857902

0 commit comments

Comments
 (0)