@@ -14,13 +14,17 @@ import (
14
14
"github.com/c9s/bbgo/pkg/core"
15
15
"github.com/c9s/bbgo/pkg/fixedpoint"
16
16
"github.com/c9s/bbgo/pkg/indicator"
17
+ "github.com/c9s/bbgo/pkg/risk/circuitbreaker"
17
18
"github.com/c9s/bbgo/pkg/types"
18
19
"github.com/c9s/bbgo/pkg/util"
19
20
)
20
21
21
22
var defaultMargin = fixedpoint .NewFromFloat (0.003 )
22
23
var Two = fixedpoint .NewFromInt (2 )
23
24
25
+ // circuitBreakerAlertLimiter is for CircuitBreaker alerts
26
+ var circuitBreakerAlertLimiter = rate .NewLimiter (rate .Every (3 * time .Minute ), 2 )
27
+
24
28
const priceUpdateTimeout = 30 * time .Second
25
29
26
30
const ID = "xmaker"
@@ -98,6 +102,8 @@ type Strategy struct {
98
102
99
103
state * State
100
104
105
+ CircuitBreaker * circuitbreaker.BasicCircuitBreaker `json:"circuitBreaker"`
106
+
101
107
// persistence fields
102
108
Position * types.Position `json:"position,omitempty" persistence:"position"`
103
109
ProfitStats * ProfitStats `json:"profitStats,omitempty" persistence:"profit_stats"`
@@ -187,6 +193,19 @@ func (s *Strategy) updateQuote(ctx context.Context, orderExecutionRouter bbgo.Or
187
193
return
188
194
}
189
195
196
+ if s .CircuitBreaker != nil {
197
+ now := time .Now ()
198
+ if reason , halted := s .CircuitBreaker .IsHalted (now ); halted {
199
+ log .Warnf ("[arbWorker] strategy is halted, reason: %s" , reason )
200
+
201
+ if circuitBreakerAlertLimiter .AllowN (now , 1 ) {
202
+ bbgo .Notify ("Strategy is halted, reason: %s" , reason )
203
+ }
204
+
205
+ return
206
+ }
207
+ }
208
+
190
209
bestBid , bestAsk , hasPrice := s .book .BestBidAndAsk ()
191
210
if ! hasPrice {
192
211
return
@@ -570,6 +589,8 @@ func (s *Strategy) Hedge(ctx context.Context, pos fixedpoint.Value) {
570
589
571
590
log .Infof ("submitting %s hedge order %s %v" , s .Symbol , side .String (), quantity )
572
591
bbgo .Notify ("Submitting %s hedge order %s %v" , s .Symbol , side .String (), quantity )
592
+
593
+ // TODO: improve order executor
573
594
orderExecutor := & bbgo.ExchangeOrderExecutor {Session : s .sourceSession }
574
595
returnOrders , err := orderExecutor .SubmitOrders (ctx , types.SubmitOrder {
575
596
Market : s .sourceMarket ,
@@ -630,6 +651,14 @@ func (s *Strategy) tradeRecover(ctx context.Context) {
630
651
}
631
652
}
632
653
654
+ func (s * Strategy ) Defaults () error {
655
+ if s .CircuitBreaker == nil {
656
+ s .CircuitBreaker = circuitbreaker .NewBasicCircuitBreaker (ID , s .InstanceID ())
657
+ }
658
+
659
+ return nil
660
+ }
661
+
633
662
func (s * Strategy ) Validate () error {
634
663
if s .Quantity .IsZero () || s .QuantityScale == nil {
635
664
return errors .New ("quantity or quantityScale can not be empty" )
@@ -813,6 +842,10 @@ func (s *Strategy) CrossRun(
813
842
s .ProfitStats .AddProfit (p )
814
843
815
844
s .Environment .RecordPosition (s .Position , trade , & p )
845
+
846
+ if s .CircuitBreaker != nil {
847
+ s .CircuitBreaker .RecordProfit (profit , trade .Time .Time ())
848
+ }
816
849
}
817
850
})
818
851
0 commit comments