mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 00:35:15 +00:00
Merge pull request #542 from andycheng123/feature/strategy-controller
feature: strategy controller
This commit is contained in:
commit
b4d7af3708
|
@ -21,24 +21,6 @@ type PositionReader interface {
|
|||
CurrentPosition() *types.Position
|
||||
}
|
||||
|
||||
type StrategyStatusProvider interface {
|
||||
GetStatus() types.StrategyStatus
|
||||
}
|
||||
|
||||
type Suspender interface {
|
||||
Suspend(ctx context.Context) error
|
||||
Resume(ctx context.Context) error
|
||||
}
|
||||
|
||||
type StrategyController interface {
|
||||
StrategyStatusProvider
|
||||
Suspender
|
||||
}
|
||||
|
||||
type EmergencyStopper interface {
|
||||
EmergencyStop(ctx context.Context) error
|
||||
}
|
||||
|
||||
type closePositionContext struct {
|
||||
signature string
|
||||
closer PositionCloser
|
||||
|
@ -61,12 +43,21 @@ func NewCoreInteraction(environment *Environment, trader *Trader) *CoreInteracti
|
|||
}
|
||||
}
|
||||
|
||||
func (it *CoreInteraction) FilterStrategyByInterface(checkInterface interface{}) (strategies []string, found bool) {
|
||||
func getStrategySignatures(exchangeStrategies map[string]SingleExchangeStrategy) []string {
|
||||
var strategies []string
|
||||
for signature := range exchangeStrategies {
|
||||
strategies = append(strategies, signature)
|
||||
}
|
||||
|
||||
return strategies
|
||||
}
|
||||
|
||||
func filterStrategyByInterface(checkInterface interface{}, exchangeStrategies map[string]SingleExchangeStrategy) (strategies map[string]SingleExchangeStrategy, found bool) {
|
||||
found = false
|
||||
rt := reflect.TypeOf(checkInterface).Elem()
|
||||
for signature, strategy := range it.exchangeStrategies {
|
||||
for signature, strategy := range exchangeStrategies {
|
||||
if ok := reflect.TypeOf(strategy).Implements(rt); ok {
|
||||
strategies = append(strategies, signature)
|
||||
strategies[signature] = strategy
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +65,7 @@ func (it *CoreInteraction) FilterStrategyByInterface(checkInterface interface{})
|
|||
return strategies, found
|
||||
}
|
||||
|
||||
func GenerateStrategyButtonsForm(strategies []string) [][3]string {
|
||||
func generateStrategyButtonsForm(strategies []string) [][3]string {
|
||||
var buttonsForm [][3]string
|
||||
for _, strategy := range strategies {
|
||||
buttonsForm = append(buttonsForm, [3]string{strategy, "strategy", strategy})
|
||||
|
@ -130,11 +121,11 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
|
|||
i.PrivateCommand("/position", "Show Position", func(reply interact.Reply) error {
|
||||
// it.trader.exchangeStrategies
|
||||
// send symbol options
|
||||
if strategies, found := it.FilterStrategyByInterface((*PositionReader)(nil)); found {
|
||||
reply.AddMultipleButtons(GenerateStrategyButtonsForm(strategies))
|
||||
if strategies, found := filterStrategyByInterface((*PositionReader)(nil), it.exchangeStrategies); found {
|
||||
reply.AddMultipleButtons(generateStrategyButtonsForm(getStrategySignatures(strategies)))
|
||||
reply.Message("Please choose one strategy")
|
||||
} else {
|
||||
reply.Message("No any strategy supports PositionReader")
|
||||
reply.Message("No strategy supports PositionReader")
|
||||
}
|
||||
return nil
|
||||
}).Cycle(func(signature string, reply interact.Reply) error {
|
||||
|
@ -171,11 +162,11 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
|
|||
i.PrivateCommand("/closeposition", "Close position", func(reply interact.Reply) error {
|
||||
// it.trader.exchangeStrategies
|
||||
// send symbol options
|
||||
if strategies, found := it.FilterStrategyByInterface((*PositionCloser)(nil)); found {
|
||||
reply.AddMultipleButtons(GenerateStrategyButtonsForm(strategies))
|
||||
if strategies, found := filterStrategyByInterface((*PositionCloser)(nil), it.exchangeStrategies); found {
|
||||
reply.AddMultipleButtons(generateStrategyButtonsForm(getStrategySignatures(strategies)))
|
||||
reply.Message("Please choose one strategy")
|
||||
} else {
|
||||
reply.Message("No any strategy supports PositionCloser")
|
||||
reply.Message("No strategy supports PositionCloser")
|
||||
}
|
||||
return nil
|
||||
}).Next(func(signature string, reply interact.Reply) error {
|
||||
|
@ -240,11 +231,11 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
|
|||
i.PrivateCommand("/status", "Strategy Status", func(reply interact.Reply) error {
|
||||
// it.trader.exchangeStrategies
|
||||
// send symbol options
|
||||
if strategies, found := it.FilterStrategyByInterface((*StrategyStatusProvider)(nil)); found {
|
||||
reply.AddMultipleButtons(GenerateStrategyButtonsForm(strategies))
|
||||
reply.Message("Please choose one strategy")
|
||||
if strategies, found := filterStrategyByInterface((*StrategyStatusReader)(nil), it.exchangeStrategies); found {
|
||||
reply.AddMultipleButtons(generateStrategyButtonsForm(getStrategySignatures(strategies)))
|
||||
reply.Message("Please choose a strategy")
|
||||
} else {
|
||||
reply.Message("No any strategy supports StrategyStatusProvider")
|
||||
reply.Message("No strategy supports StrategyStatusReader")
|
||||
}
|
||||
return nil
|
||||
}).Next(func(signature string, reply interact.Reply) error {
|
||||
|
@ -254,10 +245,10 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
|
|||
return fmt.Errorf("strategy %s not found", signature)
|
||||
}
|
||||
|
||||
controller, implemented := strategy.(StrategyStatusProvider)
|
||||
controller, implemented := strategy.(StrategyStatusReader)
|
||||
if !implemented {
|
||||
reply.Message(fmt.Sprintf("Strategy %s does not support strategy status provider", signature))
|
||||
return fmt.Errorf("strategy %s does not implement StrategyStatusProvider interface", signature)
|
||||
reply.Message(fmt.Sprintf("Strategy %s does not support StrategyStatusReader", signature))
|
||||
return fmt.Errorf("strategy %s does not implement StrategyStatusReader", signature)
|
||||
}
|
||||
|
||||
status := controller.GetStatus()
|
||||
|
@ -278,11 +269,11 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
|
|||
i.PrivateCommand("/suspend", "Suspend Strategy", func(reply interact.Reply) error {
|
||||
// it.trader.exchangeStrategies
|
||||
// send symbol options
|
||||
if strategies, found := it.FilterStrategyByInterface((*StrategyController)(nil)); found {
|
||||
reply.AddMultipleButtons(GenerateStrategyButtonsForm(strategies))
|
||||
if strategies, found := filterStrategyByInterface((*StrategyToggler)(nil), it.exchangeStrategies); found {
|
||||
reply.AddMultipleButtons(generateStrategyButtonsForm(getStrategySignatures(strategies)))
|
||||
reply.Message("Please choose one strategy")
|
||||
} else {
|
||||
reply.Message("No any strategy supports StrategyController")
|
||||
reply.Message("No strategy supports StrategyToggler")
|
||||
}
|
||||
return nil
|
||||
}).Next(func(signature string, reply interact.Reply) error {
|
||||
|
@ -292,26 +283,23 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
|
|||
return fmt.Errorf("strategy %s not found", signature)
|
||||
}
|
||||
|
||||
controller, implemented := strategy.(StrategyController)
|
||||
controller, implemented := strategy.(StrategyToggler)
|
||||
if !implemented {
|
||||
reply.Message(fmt.Sprintf("Strategy %s does not support strategy suspend", signature))
|
||||
return fmt.Errorf("strategy %s does not implement StrategyController interface", signature)
|
||||
reply.Message(fmt.Sprintf("Strategy %s does not support StrategyToggler", signature))
|
||||
return fmt.Errorf("strategy %s does not implement StrategyToggler", signature)
|
||||
}
|
||||
|
||||
// Check strategy status before suspend
|
||||
status := controller.GetStatus()
|
||||
if status != types.StrategyStatusRunning {
|
||||
if controller.GetStatus() != types.StrategyStatusRunning {
|
||||
reply.Message(fmt.Sprintf("Strategy %s is not running.", signature))
|
||||
return nil
|
||||
}
|
||||
|
||||
err := controller.Suspend(context.Background())
|
||||
|
||||
if kc, ok := reply.(interact.KeyboardController); ok {
|
||||
kc.RemoveKeyboard()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err := controller.Suspend(); err != nil {
|
||||
reply.Message(fmt.Sprintf("Failed to suspend the strategy, %s", err.Error()))
|
||||
return err
|
||||
}
|
||||
|
@ -323,11 +311,11 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
|
|||
i.PrivateCommand("/resume", "Resume Strategy", func(reply interact.Reply) error {
|
||||
// it.trader.exchangeStrategies
|
||||
// send symbol options
|
||||
if strategies, found := it.FilterStrategyByInterface((*StrategyController)(nil)); found {
|
||||
reply.AddMultipleButtons(GenerateStrategyButtonsForm(strategies))
|
||||
if strategies, found := filterStrategyByInterface((*StrategyToggler)(nil), it.exchangeStrategies); found {
|
||||
reply.AddMultipleButtons(generateStrategyButtonsForm(getStrategySignatures(strategies)))
|
||||
reply.Message("Please choose one strategy")
|
||||
} else {
|
||||
reply.Message("No any strategy supports StrategyController")
|
||||
reply.Message("No strategy supports StrategyToggler")
|
||||
}
|
||||
return nil
|
||||
}).Next(func(signature string, reply interact.Reply) error {
|
||||
|
@ -337,26 +325,23 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
|
|||
return fmt.Errorf("strategy %s not found", signature)
|
||||
}
|
||||
|
||||
controller, implemented := strategy.(StrategyController)
|
||||
controller, implemented := strategy.(StrategyToggler)
|
||||
if !implemented {
|
||||
reply.Message(fmt.Sprintf("Strategy %s does not support strategy resume", signature))
|
||||
return fmt.Errorf("strategy %s does not implement StrategyController interface", signature)
|
||||
reply.Message(fmt.Sprintf("Strategy %s does not support StrategyToggler", signature))
|
||||
return fmt.Errorf("strategy %s does not implement StrategyToggler", signature)
|
||||
}
|
||||
|
||||
// Check strategy status before resume
|
||||
status := controller.GetStatus()
|
||||
if status != types.StrategyStatusStopped {
|
||||
// Check strategy status before suspend
|
||||
if controller.GetStatus() != types.StrategyStatusStopped {
|
||||
reply.Message(fmt.Sprintf("Strategy %s is running.", signature))
|
||||
return nil
|
||||
}
|
||||
|
||||
err := controller.Resume(context.Background())
|
||||
|
||||
if kc, ok := reply.(interact.KeyboardController); ok {
|
||||
kc.RemoveKeyboard()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err := controller.Resume(); err != nil {
|
||||
reply.Message(fmt.Sprintf("Failed to resume the strategy, %s", err.Error()))
|
||||
return err
|
||||
}
|
||||
|
@ -368,11 +353,11 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
|
|||
i.PrivateCommand("/emergencystop", "Emergency Stop", func(reply interact.Reply) error {
|
||||
// it.trader.exchangeStrategies
|
||||
// send symbol options
|
||||
if strategies, found := it.FilterStrategyByInterface((*EmergencyStopper)(nil)); found {
|
||||
reply.AddMultipleButtons(GenerateStrategyButtonsForm(strategies))
|
||||
if strategies, found := filterStrategyByInterface((*EmergencyStopper)(nil), it.exchangeStrategies); found {
|
||||
reply.AddMultipleButtons(generateStrategyButtonsForm(getStrategySignatures(strategies)))
|
||||
reply.Message("Please choose one strategy")
|
||||
} else {
|
||||
reply.Message("No any strategy supports EmergencyStopper")
|
||||
reply.Message("No strategy supports EmergencyStopper")
|
||||
}
|
||||
return nil
|
||||
}).Next(func(signature string, reply interact.Reply) error {
|
||||
|
@ -384,18 +369,16 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
|
|||
|
||||
controller, implemented := strategy.(EmergencyStopper)
|
||||
if !implemented {
|
||||
reply.Message(fmt.Sprintf("Strategy %s does not support emergency stop", signature))
|
||||
return fmt.Errorf("strategy %s does not implement EmergencyStopper interface", signature)
|
||||
reply.Message(fmt.Sprintf("Strategy %s does not support EmergencyStopper", signature))
|
||||
return fmt.Errorf("strategy %s does not implement EmergencyStopper", signature)
|
||||
}
|
||||
|
||||
err := controller.EmergencyStop(context.Background())
|
||||
|
||||
if kc, ok := reply.(interact.KeyboardController); ok {
|
||||
kc.RemoveKeyboard()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
reply.Message(fmt.Sprintf("Failed to stop the strategy, %s", err.Error()))
|
||||
if err := controller.EmergencyStop(); err != nil {
|
||||
reply.Message(fmt.Sprintf("Failed to emergency stop the strategy, %s", err.Error()))
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
57
pkg/bbgo/strategy_controller.go
Normal file
57
pkg/bbgo/strategy_controller.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package bbgo
|
||||
|
||||
import (
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
//go:generate callbackgen -type StrategyController -interface
|
||||
type StrategyController struct {
|
||||
Status types.StrategyStatus
|
||||
|
||||
// Callbacks
|
||||
suspendCallbacks []func()
|
||||
resumeCallbacks []func()
|
||||
emergencyStopCallbacks []func()
|
||||
}
|
||||
|
||||
func (s *StrategyController) GetStatus() types.StrategyStatus {
|
||||
return s.Status
|
||||
}
|
||||
|
||||
func (s *StrategyController) Suspend() error {
|
||||
s.Status = types.StrategyStatusStopped
|
||||
|
||||
s.EmitSuspend()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StrategyController) Resume() error {
|
||||
s.Status = types.StrategyStatusRunning
|
||||
|
||||
s.EmitResume()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StrategyController) EmergencyStop() error {
|
||||
s.Status = types.StrategyStatusStopped
|
||||
|
||||
s.EmitEmergencyStop()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type StrategyStatusReader interface {
|
||||
GetStatus() types.StrategyStatus
|
||||
}
|
||||
|
||||
type StrategyToggler interface {
|
||||
StrategyStatusReader
|
||||
Suspend() error
|
||||
Resume() error
|
||||
}
|
||||
|
||||
type EmergencyStopper interface {
|
||||
EmergencyStop() error
|
||||
}
|
35
pkg/bbgo/strategycontroller_callbacks.go
Normal file
35
pkg/bbgo/strategycontroller_callbacks.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Code generated by "callbackgen -type StrategyController strategy_controller.go"; DO NOT EDIT.
|
||||
|
||||
package bbgo
|
||||
|
||||
import ()
|
||||
|
||||
func (s *StrategyController) OnSuspend(cb func()) {
|
||||
s.suspendCallbacks = append(s.suspendCallbacks, cb)
|
||||
}
|
||||
|
||||
func (s *StrategyController) EmitSuspend() {
|
||||
for _, cb := range s.suspendCallbacks {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StrategyController) OnResume(cb func()) {
|
||||
s.resumeCallbacks = append(s.resumeCallbacks, cb)
|
||||
}
|
||||
|
||||
func (s *StrategyController) EmitResume() {
|
||||
for _, cb := range s.resumeCallbacks {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StrategyController) OnEmergencyStop(cb func()) {
|
||||
s.emergencyStopCallbacks = append(s.emergencyStopCallbacks, cb)
|
||||
}
|
||||
|
||||
func (s *StrategyController) EmitEmergencyStop() {
|
||||
for _, cb := range s.emergencyStopCallbacks {
|
||||
cb()
|
||||
}
|
||||
}
|
|
@ -170,8 +170,9 @@ type Strategy struct {
|
|||
|
||||
tradeCollector *bbgo.TradeCollector
|
||||
|
||||
orderStore *bbgo.OrderStore
|
||||
state *State
|
||||
orderStore *bbgo.OrderStore
|
||||
activeOrders *bbgo.LocalActiveOrderBook
|
||||
state *State
|
||||
|
||||
triggerEMA *indicator.EWMA
|
||||
longTermEMA *indicator.EWMA
|
||||
|
@ -181,7 +182,7 @@ type Strategy struct {
|
|||
trailingStopControl *TrailingStopControl
|
||||
|
||||
// StrategyController
|
||||
status types.StrategyStatus
|
||||
bbgo.StrategyController
|
||||
}
|
||||
|
||||
func (s *Strategy) ID() string {
|
||||
|
@ -249,55 +250,7 @@ func (s *Strategy) ClosePosition(ctx context.Context, percentage fixedpoint.Valu
|
|||
}
|
||||
|
||||
s.orderStore.Add(createdOrders...)
|
||||
return err
|
||||
}
|
||||
|
||||
// StrategyController
|
||||
|
||||
func (s *Strategy) GetStatus() types.StrategyStatus {
|
||||
return s.status
|
||||
}
|
||||
|
||||
func (s *Strategy) Suspend(ctx context.Context) error {
|
||||
s.status = types.StrategyStatusStopped
|
||||
|
||||
var err error
|
||||
// Cancel all order
|
||||
for _, order := range s.orderStore.Orders() {
|
||||
err = s.cancelOrder(order.OrderID, ctx, s.orderExecutor)
|
||||
}
|
||||
if err != nil {
|
||||
errMsg := "Not all orders are cancelled! Please check again."
|
||||
log.WithError(err).Errorf(errMsg)
|
||||
s.Notify(errMsg)
|
||||
} else {
|
||||
s.Notify("All orders cancelled.")
|
||||
}
|
||||
|
||||
// Save state
|
||||
if err2 := s.SaveState(); err2 != nil {
|
||||
log.WithError(err2).Errorf("can not save state: %+v", s.state)
|
||||
} else {
|
||||
log.Infof("%s position is saved.", s.Symbol)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Strategy) Resume(ctx context.Context) error {
|
||||
s.status = types.StrategyStatusRunning
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Strategy) EmergencyStop(ctx context.Context) error {
|
||||
// Close 100% position
|
||||
percentage, _ := fixedpoint.NewFromString("100%")
|
||||
err := s.ClosePosition(ctx, percentage)
|
||||
|
||||
// Suspend strategy
|
||||
_ = s.Suspend(ctx)
|
||||
|
||||
s.activeOrders.Add(createdOrders...)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -352,6 +305,7 @@ func (s *Strategy) submitOrders(ctx context.Context, orderExecutor bbgo.OrderExe
|
|||
}
|
||||
|
||||
s.orderStore.Add(createdOrders...)
|
||||
s.activeOrders.Add(createdOrders...)
|
||||
s.tradeCollector.Emit()
|
||||
return createdOrders, nil
|
||||
}
|
||||
|
@ -439,7 +393,41 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
s.orderExecutor = orderExecutor
|
||||
|
||||
// StrategyController
|
||||
s.status = types.StrategyStatusRunning
|
||||
s.Status = types.StrategyStatusRunning
|
||||
|
||||
s.OnSuspend(func() {
|
||||
// Cancel all order
|
||||
if err := s.activeOrders.GracefulCancel(ctx, session.Exchange); err != nil {
|
||||
errMsg := fmt.Sprintf("Not all %s orders are cancelled! Please check again.", s.Symbol)
|
||||
log.WithError(err).Errorf(errMsg)
|
||||
s.Notify(errMsg)
|
||||
} else {
|
||||
s.Notify("All %s orders are cancelled.", s.Symbol)
|
||||
}
|
||||
|
||||
// Save state
|
||||
if err := s.SaveState(); err != nil {
|
||||
log.WithError(err).Errorf("can not save state: %+v", s.state)
|
||||
} else {
|
||||
log.Infof("%s state is saved.", s.Symbol)
|
||||
}
|
||||
})
|
||||
|
||||
s.OnEmergencyStop(func() {
|
||||
// Close 100% position
|
||||
percentage := fixedpoint.NewFromFloat(1.0)
|
||||
if err := s.ClosePosition(context.Background(), percentage); err != nil {
|
||||
errMsg := "failed to close position"
|
||||
log.WithError(err).Errorf(errMsg)
|
||||
s.Notify(errMsg)
|
||||
}
|
||||
|
||||
if err := s.Suspend(); err != nil {
|
||||
errMsg := "failed to suspend strategy"
|
||||
log.WithError(err).Errorf(errMsg)
|
||||
s.Notify(errMsg)
|
||||
}
|
||||
})
|
||||
|
||||
// set default values
|
||||
if s.Interval == "" {
|
||||
|
@ -487,6 +475,9 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
s.orderStore = bbgo.NewOrderStore(s.Symbol)
|
||||
s.orderStore.BindStream(session.UserDataStream)
|
||||
|
||||
s.activeOrders = bbgo.NewLocalActiveOrderBook(s.Symbol)
|
||||
s.activeOrders.BindStream(session.UserDataStream)
|
||||
|
||||
if !s.TrailingStopTarget.TrailingStopCallbackRatio.IsZero() {
|
||||
s.trailingStopControl = &TrailingStopControl{
|
||||
symbol: s.Symbol,
|
||||
|
@ -510,7 +501,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
// Update trailing stop when the position changes
|
||||
s.tradeCollector.OnPositionUpdate(func(position *types.Position) {
|
||||
// StrategyController
|
||||
if s.status != types.StrategyStatusRunning {
|
||||
if s.Status != types.StrategyStatusRunning {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -562,7 +553,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
|
||||
session.MarketDataStream.OnKLineClosed(func(kline types.KLine) {
|
||||
// StrategyController
|
||||
if s.status != types.StrategyStatusRunning {
|
||||
if s.Status != types.StrategyStatusRunning {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -757,9 +748,15 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
|
||||
// Cancel trailing stop order
|
||||
if s.TrailingStopTarget.TrailingStopCallbackRatio.Sign() > 0 {
|
||||
if err := s.cancelOrder(s.trailingStopControl.OrderID, ctx, orderExecutor); err != nil {
|
||||
log.WithError(err).Errorf("Can not cancel the trailing stop order!")
|
||||
// Cancel all orders
|
||||
if err := s.activeOrders.GracefulCancel(ctx, session.Exchange); err != nil {
|
||||
errMsg := "Not all {s.Symbol} orders are cancelled! Please check again."
|
||||
log.WithError(err).Errorf(errMsg)
|
||||
s.Notify(errMsg)
|
||||
} else {
|
||||
s.Notify("All {s.Symbol} orders are cancelled.")
|
||||
}
|
||||
|
||||
s.trailingStopControl.OrderID = 0
|
||||
}
|
||||
|
||||
|
|
|
@ -6,4 +6,5 @@ type StrategyStatus string
|
|||
const (
|
||||
StrategyStatusRunning StrategyStatus = "RUNNING"
|
||||
StrategyStatusStopped StrategyStatus = "STOPPED"
|
||||
StrategyStatusUnknown StrategyStatus = "UNKNOWN"
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user