2022-06-28 17:58:15 +00:00
|
|
|
package bbgo
|
2022-06-26 08:31:48 +00:00
|
|
|
|
2022-06-28 17:58:15 +00:00
|
|
|
import (
|
2022-08-17 04:42:01 +00:00
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2022-06-30 07:13:42 +00:00
|
|
|
"reflect"
|
|
|
|
|
2022-06-30 06:32:33 +00:00
|
|
|
"github.com/pkg/errors"
|
2022-06-28 17:58:15 +00:00
|
|
|
|
2022-06-29 10:49:42 +00:00
|
|
|
"github.com/c9s/bbgo/pkg/dynamic"
|
2023-06-21 10:01:22 +00:00
|
|
|
"github.com/c9s/bbgo/pkg/util"
|
2022-06-28 17:58:15 +00:00
|
|
|
)
|
2022-06-26 08:31:48 +00:00
|
|
|
|
2023-06-21 10:01:22 +00:00
|
|
|
var enableMarketTradeStop = true
|
|
|
|
|
|
|
|
func init() {
|
2023-06-29 06:26:12 +00:00
|
|
|
if v, defined := util.GetEnvVarBool("DISABLE_MARKET_TRADE_STOP"); defined && v {
|
|
|
|
enableMarketTradeStop = false
|
2023-06-21 10:01:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-30 07:13:42 +00:00
|
|
|
type ExitMethodSet []ExitMethod
|
|
|
|
|
|
|
|
func (s *ExitMethodSet) SetAndSubscribe(session *ExchangeSession, parent interface{}) {
|
|
|
|
for i := range *s {
|
|
|
|
m := (*s)[i]
|
|
|
|
|
|
|
|
// manually inherit configuration from strategy
|
|
|
|
m.Inherit(parent)
|
|
|
|
m.Subscribe(session)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-06 18:23:55 +00:00
|
|
|
func (s *ExitMethodSet) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExecutor) {
|
|
|
|
for _, method := range *s {
|
|
|
|
method.Bind(session, orderExecutor)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-26 08:31:48 +00:00
|
|
|
type ExitMethod struct {
|
2023-03-16 10:39:27 +00:00
|
|
|
RoiStopLoss *RoiStopLoss `json:"roiStopLoss"`
|
|
|
|
ProtectiveStopLoss *ProtectiveStopLoss `json:"protectiveStopLoss"`
|
|
|
|
RoiTakeProfit *RoiTakeProfit `json:"roiTakeProfit"`
|
|
|
|
TrailingStop *TrailingStop2 `json:"trailingStop"`
|
|
|
|
HigherHighLowerLowStop *HigherHighLowerLowStop `json:"higherHighLowerLowStopLoss"`
|
2022-08-26 10:11:45 +00:00
|
|
|
|
|
|
|
// Exit methods for short positions
|
|
|
|
// =================================================
|
2022-06-27 11:54:58 +00:00
|
|
|
LowerShadowTakeProfit *LowerShadowTakeProfit `json:"lowerShadowTakeProfit"`
|
2022-06-26 08:31:48 +00:00
|
|
|
CumulatedVolumeTakeProfit *CumulatedVolumeTakeProfit `json:"cumulatedVolumeTakeProfit"`
|
2023-03-16 10:39:27 +00:00
|
|
|
SupportTakeProfit *SupportTakeProfit `json:"supportTakeProfit"`
|
2022-06-26 08:31:48 +00:00
|
|
|
}
|
|
|
|
|
2022-08-17 04:42:01 +00:00
|
|
|
func (e ExitMethod) String() string {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
if e.RoiStopLoss != nil {
|
|
|
|
b, _ := json.Marshal(e.RoiStopLoss)
|
2022-08-17 08:40:18 +00:00
|
|
|
buf.WriteString("roiStopLoss: " + string(b) + ", ")
|
2022-08-17 04:42:01 +00:00
|
|
|
}
|
2022-08-26 10:11:45 +00:00
|
|
|
|
2022-08-17 04:42:01 +00:00
|
|
|
if e.ProtectiveStopLoss != nil {
|
|
|
|
b, _ := json.Marshal(e.ProtectiveStopLoss)
|
2022-08-17 08:40:18 +00:00
|
|
|
buf.WriteString("protectiveStopLoss: " + string(b) + ", ")
|
2022-08-17 04:42:01 +00:00
|
|
|
}
|
2022-08-26 10:11:45 +00:00
|
|
|
|
2022-08-17 04:42:01 +00:00
|
|
|
if e.RoiTakeProfit != nil {
|
|
|
|
b, _ := json.Marshal(e.RoiTakeProfit)
|
2022-08-17 08:40:18 +00:00
|
|
|
buf.WriteString("rioTakeProft: " + string(b) + ", ")
|
2022-08-17 04:42:01 +00:00
|
|
|
}
|
2022-08-26 10:11:45 +00:00
|
|
|
|
2022-08-17 08:40:18 +00:00
|
|
|
if e.LowerShadowTakeProfit != nil {
|
2022-08-17 04:42:01 +00:00
|
|
|
b, _ := json.Marshal(e.LowerShadowTakeProfit)
|
2022-08-17 08:40:18 +00:00
|
|
|
buf.WriteString("lowerShadowTakeProft: " + string(b) + ", ")
|
2022-08-17 04:42:01 +00:00
|
|
|
}
|
2022-08-26 10:11:45 +00:00
|
|
|
|
2022-08-17 08:40:18 +00:00
|
|
|
if e.CumulatedVolumeTakeProfit != nil {
|
2022-08-17 04:42:01 +00:00
|
|
|
b, _ := json.Marshal(e.CumulatedVolumeTakeProfit)
|
2022-08-17 08:40:18 +00:00
|
|
|
buf.WriteString("cumulatedVolumeTakeProfit: " + string(b) + ", ")
|
2022-08-17 04:42:01 +00:00
|
|
|
}
|
2022-08-26 10:11:45 +00:00
|
|
|
|
2022-08-17 08:40:18 +00:00
|
|
|
if e.TrailingStop != nil {
|
2022-08-17 04:42:01 +00:00
|
|
|
b, _ := json.Marshal(e.TrailingStop)
|
2022-08-17 08:40:18 +00:00
|
|
|
buf.WriteString("trailingStop: " + string(b) + ", ")
|
2022-08-17 04:42:01 +00:00
|
|
|
}
|
2022-08-26 10:11:45 +00:00
|
|
|
|
|
|
|
if e.SupportTakeProfit != nil {
|
|
|
|
b, _ := json.Marshal(e.SupportTakeProfit)
|
|
|
|
buf.WriteString("supportTakeProfit: " + string(b) + ", ")
|
|
|
|
}
|
|
|
|
|
2023-03-16 10:39:27 +00:00
|
|
|
if e.HigherHighLowerLowStop != nil {
|
|
|
|
b, _ := json.Marshal(e.HigherHighLowerLowStop)
|
|
|
|
buf.WriteString("hhllStop: " + string(b) + ", ")
|
|
|
|
}
|
|
|
|
|
2022-08-17 04:42:01 +00:00
|
|
|
return buf.String()
|
|
|
|
}
|
|
|
|
|
2022-06-30 07:13:42 +00:00
|
|
|
// Inherit is used for inheriting properties from the given strategy struct
|
|
|
|
// for example, some exit method requires the default interval and symbol name from the strategy param object
|
|
|
|
func (m *ExitMethod) Inherit(parent interface{}) {
|
|
|
|
// we need to pass some information from the strategy configuration to the exit methods, like symbol, interval and window
|
|
|
|
rt := reflect.TypeOf(m).Elem()
|
|
|
|
rv := reflect.ValueOf(m).Elem()
|
|
|
|
for j := 0; j < rv.NumField(); j++ {
|
|
|
|
if !rt.Field(j).IsExported() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
fieldValue := rv.Field(j)
|
|
|
|
if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-06-30 10:29:02 +00:00
|
|
|
dynamic.InheritStructValues(fieldValue.Interface(), parent)
|
2022-06-30 07:13:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-29 07:16:56 +00:00
|
|
|
func (m *ExitMethod) Subscribe(session *ExchangeSession) {
|
2022-06-30 06:32:33 +00:00
|
|
|
if err := dynamic.CallStructFieldsMethod(m, "Subscribe", session); err != nil {
|
2022-06-30 07:13:42 +00:00
|
|
|
panic(errors.Wrap(err, "dynamic Subscribe call failed"))
|
2022-06-28 17:58:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *ExitMethod) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExecutor) {
|
2022-06-28 17:31:56 +00:00
|
|
|
if m.ProtectiveStopLoss != nil {
|
|
|
|
m.ProtectiveStopLoss.Bind(session, orderExecutor)
|
2022-06-30 06:32:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if m.RoiStopLoss != nil {
|
2022-06-26 08:31:48 +00:00
|
|
|
m.RoiStopLoss.Bind(session, orderExecutor)
|
2022-06-30 06:32:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if m.RoiTakeProfit != nil {
|
2022-06-26 08:31:48 +00:00
|
|
|
m.RoiTakeProfit.Bind(session, orderExecutor)
|
2022-06-30 06:32:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if m.LowerShadowTakeProfit != nil {
|
2022-06-26 08:31:48 +00:00
|
|
|
m.LowerShadowTakeProfit.Bind(session, orderExecutor)
|
2022-06-30 06:32:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if m.CumulatedVolumeTakeProfit != nil {
|
2022-06-26 08:31:48 +00:00
|
|
|
m.CumulatedVolumeTakeProfit.Bind(session, orderExecutor)
|
|
|
|
}
|
2022-07-06 13:50:38 +00:00
|
|
|
|
2022-08-26 10:11:45 +00:00
|
|
|
if m.SupportTakeProfit != nil {
|
|
|
|
m.SupportTakeProfit.Bind(session, orderExecutor)
|
|
|
|
}
|
|
|
|
|
2022-07-06 13:50:38 +00:00
|
|
|
if m.TrailingStop != nil {
|
|
|
|
m.TrailingStop.Bind(session, orderExecutor)
|
|
|
|
}
|
2023-03-16 10:39:27 +00:00
|
|
|
|
|
|
|
if m.HigherHighLowerLowStop != nil {
|
|
|
|
m.HigherHighLowerLowStop.Bind(session, orderExecutor)
|
|
|
|
}
|
2022-06-26 08:31:48 +00:00
|
|
|
}
|