Skip to content

Commit 95342d3

Browse files
authored
Merge pull request #782 from c9s/strategy/pivotshort
refactor: moving exit methods from pivotshort to the core
2 parents 6e9993c + fc3e762 commit 95342d3

9 files changed

+74
-40
lines changed

pkg/strategy/pivotshort/exit.go pkg/bbgo/exit.go

+24-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
package pivotshort
1+
package bbgo
22

3-
import "github.com/c9s/bbgo/pkg/bbgo"
3+
import (
4+
"reflect"
5+
6+
"github.com/c9s/bbgo/pkg/types"
7+
)
48

59
type ExitMethod struct {
610
RoiStopLoss *RoiStopLoss `json:"roiStopLoss"`
@@ -10,7 +14,24 @@ type ExitMethod struct {
1014
CumulatedVolumeTakeProfit *CumulatedVolumeTakeProfit `json:"cumulatedVolumeTakeProfit"`
1115
}
1216

13-
func (m *ExitMethod) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
17+
func (m *ExitMethod) Subscribe() {
18+
// TODO: pull out this implementation as a simple function to reflect.go
19+
rv := reflect.ValueOf(m)
20+
rt := reflect.TypeOf(m)
21+
22+
rv = rv.Elem()
23+
rt = rt.Elem()
24+
infType := reflect.TypeOf((*types.Subscriber)(nil)).Elem()
25+
for i := 0; i < rt.NumField(); i++ {
26+
fieldType := rt.Field(i)
27+
if fieldType.Type.Implements(infType) {
28+
method := rv.Field(i).MethodByName("Subscribe")
29+
method.Call(nil)
30+
}
31+
}
32+
}
33+
34+
func (m *ExitMethod) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExecutor) {
1435
if m.ProtectiveStopLoss != nil {
1536
m.ProtectiveStopLoss.Bind(session, orderExecutor)
1637
} else if m.RoiStopLoss != nil {

pkg/strategy/pivotshort/cumulated_volume_take_profit.go pkg/bbgo/exit_cumulated_volume_take_profit.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
package pivotshort
1+
package bbgo
22

33
import (
44
"context"
55

6-
"github.com/c9s/bbgo/pkg/bbgo"
76
"github.com/c9s/bbgo/pkg/fixedpoint"
87
"github.com/c9s/bbgo/pkg/types"
98
)
@@ -20,11 +19,11 @@ type CumulatedVolumeTakeProfit struct {
2019
Ratio fixedpoint.Value `json:"ratio"`
2120
MinQuoteVolume fixedpoint.Value `json:"minQuoteVolume"`
2221

23-
session *bbgo.ExchangeSession
24-
orderExecutor *bbgo.GeneralOrderExecutor
22+
session *ExchangeSession
23+
orderExecutor *GeneralOrderExecutor
2524
}
2625

27-
func (s *CumulatedVolumeTakeProfit) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
26+
func (s *CumulatedVolumeTakeProfit) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExecutor) {
2827
s.session = session
2928
s.orderExecutor = orderExecutor
3029

@@ -57,7 +56,7 @@ func (s *CumulatedVolumeTakeProfit) Bind(session *bbgo.ExchangeSession, orderExe
5756
}
5857

5958
if cqv.Compare(s.MinQuoteVolume) > 0 {
60-
bbgo.Notify("%s TakeProfit triggered by cumulated volume (window: %d) %f > %f, price = %f",
59+
Notify("%s TakeProfit triggered by cumulated volume (window: %d) %f > %f, price = %f",
6160
position.Symbol,
6261
s.Window,
6362
cqv.Float64(),

pkg/strategy/pivotshort/lower_shadow_take_profit.go pkg/bbgo/exit_lower_shadow_take_profit.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1-
package pivotshort
1+
package bbgo
22

33
import (
44
"context"
55

6-
"github.com/c9s/bbgo/pkg/bbgo"
76
"github.com/c9s/bbgo/pkg/fixedpoint"
87
"github.com/c9s/bbgo/pkg/types"
98
)
109

1110
type LowerShadowTakeProfit struct {
1211
Ratio fixedpoint.Value `json:"ratio"`
1312

14-
session *bbgo.ExchangeSession
15-
orderExecutor *bbgo.GeneralOrderExecutor
13+
session *ExchangeSession
14+
orderExecutor *GeneralOrderExecutor
1615
}
1716

18-
func (s *LowerShadowTakeProfit) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
17+
func (s *LowerShadowTakeProfit) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExecutor) {
1918
s.session = session
2019
s.orderExecutor = orderExecutor
2120

@@ -40,7 +39,7 @@ func (s *LowerShadowTakeProfit) Bind(session *bbgo.ExchangeSession, orderExecuto
4039
}
4140

4241
if kline.GetLowerShadowHeight().Div(kline.Close).Compare(s.Ratio) > 0 {
43-
bbgo.Notify("%s TakeProfit triggered by shadow ratio %f, price = %f",
42+
Notify("%s TakeProfit triggered by shadow ratio %f, price = %f",
4443
position.Symbol,
4544
kline.GetLowerShadowRatio().Float64(),
4645
kline.Close.Float64(),

pkg/strategy/pivotshort/protection_stop.go pkg/bbgo/exit_protective_stop_loss.go

+13-10
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
package pivotshort
1+
package bbgo
22

33
import (
44
"context"
55

6-
"github.com/c9s/bbgo/pkg/bbgo"
6+
log "github.com/sirupsen/logrus"
7+
78
"github.com/c9s/bbgo/pkg/fixedpoint"
89
"github.com/c9s/bbgo/pkg/types"
910
)
@@ -21,12 +22,14 @@ type ProtectiveStopLoss struct {
2122
// PlaceStopOrder places the stop order on exchange and lock the balance
2223
PlaceStopOrder bool `json:"placeStopOrder"`
2324

24-
session *bbgo.ExchangeSession
25-
orderExecutor *bbgo.GeneralOrderExecutor
25+
session *ExchangeSession
26+
orderExecutor *GeneralOrderExecutor
2627
stopLossPrice fixedpoint.Value
2728
stopLossOrder *types.Order
2829
}
2930

31+
var one = fixedpoint.One
32+
3033
func (s *ProtectiveStopLoss) shouldActivate(position *types.Position, closePrice fixedpoint.Value) bool {
3134
if position.IsLong() {
3235
r := one.Add(s.ActivationRatio)
@@ -42,7 +45,7 @@ func (s *ProtectiveStopLoss) shouldActivate(position *types.Position, closePrice
4245
return false
4346
}
4447

45-
func (s *ProtectiveStopLoss) placeStopOrder(ctx context.Context, position *types.Position, orderExecutor bbgo.OrderExecutor) error {
48+
func (s *ProtectiveStopLoss) placeStopOrder(ctx context.Context, position *types.Position, orderExecutor OrderExecutor) error {
4649
if s.stopLossOrder != nil {
4750
if err := orderExecutor.CancelOrders(ctx, *s.stopLossOrder); err != nil {
4851
log.WithError(err).Errorf("failed to cancel stop limit order: %+v", s.stopLossOrder)
@@ -75,14 +78,14 @@ func (s *ProtectiveStopLoss) shouldStop(closePrice fixedpoint.Value) bool {
7578
return closePrice.Compare(s.stopLossPrice) >= 0
7679
}
7780

78-
func (s *ProtectiveStopLoss) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
81+
func (s *ProtectiveStopLoss) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExecutor) {
7982
s.session = session
8083
s.orderExecutor = orderExecutor
8184

8285
orderExecutor.TradeCollector().OnPositionUpdate(func(position *types.Position) {
8386
if position.IsClosed() {
8487
s.stopLossOrder = nil
85-
s.stopLossPrice = zero
88+
s.stopLossPrice = fixedpoint.Zero
8689
}
8790
})
8891

@@ -95,7 +98,7 @@ func (s *ProtectiveStopLoss) Bind(session *bbgo.ExchangeSession, orderExecutor *
9598
switch order.Status {
9699
case types.OrderStatusFilled, types.OrderStatusCanceled:
97100
s.stopLossOrder = nil
98-
s.stopLossPrice = zero
101+
s.stopLossPrice = fixedpoint.Zero
99102
}
100103
}
101104
})
@@ -112,7 +115,7 @@ func (s *ProtectiveStopLoss) Bind(session *bbgo.ExchangeSession, orderExecutor *
112115
}
113116
})
114117

115-
if !bbgo.IsBackTesting {
118+
if !IsBackTesting {
116119
session.MarketDataStream.OnMarketTrade(func(trade types.Trade) {
117120
if trade.Symbol != position.Symbol {
118121
return
@@ -127,7 +130,7 @@ func (s *ProtectiveStopLoss) Bind(session *bbgo.ExchangeSession, orderExecutor *
127130
}
128131
}
129132

130-
func (s *ProtectiveStopLoss) handleChange(ctx context.Context, position *types.Position, closePrice fixedpoint.Value, orderExecutor *bbgo.GeneralOrderExecutor) {
133+
func (s *ProtectiveStopLoss) handleChange(ctx context.Context, position *types.Position, closePrice fixedpoint.Value, orderExecutor *GeneralOrderExecutor) {
131134
if s.stopLossOrder != nil {
132135
// use RESTful to query the order status
133136
// orderQuery := orderExecutor.Session().Exchange.(types.ExchangeOrderQueryService)

pkg/strategy/pivotshort/roi_stop.go pkg/bbgo/exit_roi_stop_loss.go

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1-
package pivotshort
1+
package bbgo
22

33
import (
44
"context"
55

6-
"github.com/c9s/bbgo/pkg/bbgo"
76
"github.com/c9s/bbgo/pkg/fixedpoint"
87
"github.com/c9s/bbgo/pkg/types"
98
)
109

1110
type RoiStopLoss struct {
1211
Percentage fixedpoint.Value `json:"percentage"`
1312

14-
session *bbgo.ExchangeSession
15-
orderExecutor *bbgo.GeneralOrderExecutor
13+
session *ExchangeSession
14+
orderExecutor *GeneralOrderExecutor
1615
}
1716

18-
func (s *RoiStopLoss) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
17+
func (s *RoiStopLoss) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExecutor) {
1918
s.session = session
2019
s.orderExecutor = orderExecutor
2120

@@ -28,7 +27,7 @@ func (s *RoiStopLoss) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Ge
2827
s.checkStopPrice(kline.Close, position)
2928
})
3029

31-
if !bbgo.IsBackTesting {
30+
if !IsBackTesting {
3231
session.MarketDataStream.OnMarketTrade(func(trade types.Trade) {
3332
if trade.Symbol != position.Symbol {
3433
return
@@ -47,7 +46,7 @@ func (s *RoiStopLoss) checkStopPrice(closePrice fixedpoint.Value, position *type
4746
roi := position.ROI(closePrice)
4847
if roi.Compare(s.Percentage.Neg()) < 0 {
4948
// stop loss
50-
bbgo.Notify("[RoiStopLoss] %s stop loss triggered by ROI %s/%s, price: %f", position.Symbol, roi.Percentage(), s.Percentage.Neg().Percentage(), closePrice.Float64())
49+
Notify("[RoiStopLoss] %s stop loss triggered by ROI %s/%s, price: %f", position.Symbol, roi.Percentage(), s.Percentage.Neg().Percentage(), closePrice.Float64())
5150
_ = s.orderExecutor.ClosePosition(context.Background(), fixedpoint.One, "roiStopLoss")
5251
return
5352
}

pkg/strategy/pivotshort/roi_take_profit.go pkg/bbgo/exit_roi_take_profit.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
package pivotshort
1+
package bbgo
22

33
import (
44
"context"
55

6-
"github.com/c9s/bbgo/pkg/bbgo"
76
"github.com/c9s/bbgo/pkg/fixedpoint"
87
"github.com/c9s/bbgo/pkg/types"
98
)
109

10+
// RoiTakeProfit force takes the profit by the given ROI percentage.
1111
type RoiTakeProfit struct {
1212
Percentage fixedpoint.Value `json:"percentage"`
1313

14-
session *bbgo.ExchangeSession
15-
orderExecutor *bbgo.GeneralOrderExecutor
14+
session *ExchangeSession
15+
orderExecutor *GeneralOrderExecutor
1616
}
1717

18-
func (s *RoiTakeProfit) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
18+
func (s *RoiTakeProfit) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExecutor) {
1919
s.session = session
2020
s.orderExecutor = orderExecutor
2121

@@ -33,7 +33,7 @@ func (s *RoiTakeProfit) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.
3333
roi := position.ROI(closePrice)
3434
if roi.Compare(s.Percentage) > 0 {
3535
// stop loss
36-
bbgo.Notify("[RoiTakeProfit] %s take profit is triggered by ROI %s/%s, price: %f", position.Symbol, roi.Percentage(), s.Percentage.Percentage(), kline.Close.Float64())
36+
Notify("[RoiTakeProfit] %s take profit is triggered by ROI %s/%s, price: %f", position.Symbol, roi.Percentage(), s.Percentage.Percentage(), kline.Close.Float64())
3737
_ = orderExecutor.ClosePosition(context.Background(), fixedpoint.One, "roiTakeProfit")
3838
return
3939
}

pkg/bbgo/exit_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package bbgo
2+
3+
import "testing"
4+
5+
func TestExitMethod(t *testing.T) {
6+
em := &ExitMethod{}
7+
em.Subscribe()
8+
}

pkg/strategy/pivotshort/strategy.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ type Strategy struct {
8787

8888
BounceShort *BounceShort `json:"bounceShort"`
8989

90-
Entry Entry `json:"entry"`
91-
ExitMethods []ExitMethod `json:"exits"`
90+
Entry Entry `json:"entry"`
91+
ExitMethods []bbgo.ExitMethod `json:"exits"`
9292

9393
session *bbgo.ExchangeSession
9494
orderExecutor *bbgo.GeneralOrderExecutor

pkg/types/subscribe.go

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package types
2+
3+
type Subscriber interface {
4+
Subscribe()
5+
}

0 commit comments

Comments
 (0)