bbgo_origin/pkg/strategy/common/strategy.go

102 lines
3.3 KiB
Go
Raw Normal View History

2023-07-09 11:55:36 +00:00
package common
import (
"context"
"time"
log "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/risk/circuitbreaker"
"github.com/c9s/bbgo/pkg/risk/riskcontrol"
"github.com/c9s/bbgo/pkg/types"
)
2023-07-10 07:27:36 +00:00
type RiskController struct {
PositionHardLimit fixedpoint.Value `json:"positionHardLimit"`
MaxPositionQuantity fixedpoint.Value `json:"maxPositionQuantity"`
CircuitBreakLossThreshold fixedpoint.Value `json:"circuitBreakLossThreshold"`
CircuitBreakEMA types.IntervalWindow `json:"circuitBreakEMA"`
positionRiskControl *riskcontrol.PositionRiskControl
circuitBreakRiskControl *circuitbreaker.BasicCircuitBreaker
2023-07-10 07:27:36 +00:00
}
2023-07-09 08:04:27 +00:00
// Strategy provides the core functionality that is required by a long/short strategy.
type Strategy struct {
Position *types.Position `json:"position,omitempty" persistence:"position"`
ProfitStats *types.ProfitStats `json:"profitStats,omitempty" persistence:"profit_stats"`
parent, ctx context.Context
cancel context.CancelFunc
Environ *bbgo.Environment
Session *bbgo.ExchangeSession
OrderExecutor *bbgo.GeneralOrderExecutor
2023-07-10 07:27:36 +00:00
RiskController
}
2024-11-04 08:06:17 +00:00
func (s *Strategy) Initialize(
ctx context.Context, environ *bbgo.Environment, session *bbgo.ExchangeSession, market types.Market, strategyID, instanceID string,
) {
s.parent = ctx
s.ctx, s.cancel = context.WithCancel(ctx)
s.Environ = environ
s.Session = session
if s.ProfitStats == nil {
s.ProfitStats = types.NewProfitStats(market)
}
if s.Position == nil {
s.Position = types.NewPositionFromMarket(market)
}
// Always update the position fields
s.Position.Strategy = strategyID
s.Position.StrategyInstanceID = instanceID
// if anyone of the fee rate is defined, this assumes that both are defined.
// so that zero maker fee could be applied
if session.MakerFeeRate.Sign() > 0 || session.TakerFeeRate.Sign() > 0 {
s.Position.SetExchangeFeeRate(session.ExchangeName, types.ExchangeFee{
MakerFeeRate: session.MakerFeeRate,
TakerFeeRate: session.TakerFeeRate,
})
}
s.OrderExecutor = bbgo.NewGeneralOrderExecutor(session, market.Symbol, strategyID, instanceID, s.Position)
s.OrderExecutor.BindEnvironment(environ)
s.OrderExecutor.BindProfitStats(s.ProfitStats)
s.OrderExecutor.Bind()
if !s.PositionHardLimit.IsZero() && !s.MaxPositionQuantity.IsZero() {
log.Infof("positionHardLimit and maxPositionQuantity are configured, setting up PositionRiskControl...")
s.positionRiskControl = riskcontrol.NewPositionRiskControl(s.OrderExecutor, s.PositionHardLimit, s.MaxPositionQuantity)
s.positionRiskControl.Initialize(ctx, session)
}
if !s.CircuitBreakLossThreshold.IsZero() {
log.Infof("circuitBreakLossThreshold is configured, setting up CircuitBreakRiskControl...")
s.circuitBreakRiskControl = circuitbreaker.NewBasicCircuitBreaker(strategyID, instanceID, market.Symbol)
s.OrderExecutor.TradeCollector().OnProfit(func(trade types.Trade, profit *types.Profit) {
if profit != nil && s.circuitBreakRiskControl != nil {
s.circuitBreakRiskControl.RecordProfit(profit.Profit, trade.Time.Time())
}
})
}
}
2023-09-21 06:57:55 +00:00
func (s *Strategy) IsHalted(t time.Time) bool {
2023-09-28 17:12:53 +00:00
if s.circuitBreakRiskControl == nil {
return false
}
2024-11-04 08:06:17 +00:00
_, isHalted := s.circuitBreakRiskControl.IsHalted(t)
return isHalted
2023-09-21 06:57:55 +00:00
}