Skip to content

Commit 3aa9636

Browse files
authored
Merge pull request #904 from c9s/strategy/pivotshort-failed-break-high
strategy/pivotshort: add failed break high
2 parents 251d1b7 + 51972e9 commit 3aa9636

File tree

7 files changed

+364
-24
lines changed

7 files changed

+364
-24
lines changed

pkg/bbgo/standard_indicator_set.go

+28-15
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,23 @@ type StandardIndicatorSet struct {
2424
// Standard indicators
2525
// interval -> window
2626
iwbIndicators map[types.IntervalWindowBandWidth]*indicator.BOLL
27-
iwIndicators map[types.IntervalWindow]indicator.KLinePusher
27+
iwIndicators map[indicatorKey]indicator.KLinePusher
2828

2929
stream types.Stream
3030
store *MarketDataStore
3131
}
3232

33+
type indicatorKey struct {
34+
iw types.IntervalWindow
35+
id string
36+
}
37+
3338
func NewStandardIndicatorSet(symbol string, stream types.Stream, store *MarketDataStore) *StandardIndicatorSet {
3439
return &StandardIndicatorSet{
3540
Symbol: symbol,
3641
store: store,
3742
stream: stream,
38-
iwIndicators: make(map[types.IntervalWindow]indicator.KLinePusher),
43+
iwIndicators: make(map[indicatorKey]indicator.KLinePusher),
3944
iwbIndicators: make(map[types.IntervalWindowBandWidth]*indicator.BOLL),
4045
}
4146
}
@@ -50,69 +55,77 @@ func (s *StandardIndicatorSet) initAndBind(inc indicator.KLinePusher, interval t
5055
s.stream.OnKLineClosed(types.KLineWith(s.Symbol, interval, inc.PushK))
5156
}
5257

53-
func (s *StandardIndicatorSet) allocateSimpleIndicator(t indicator.KLinePusher, iw types.IntervalWindow) indicator.KLinePusher {
54-
inc, ok := s.iwIndicators[iw]
58+
func (s *StandardIndicatorSet) allocateSimpleIndicator(t indicator.KLinePusher, iw types.IntervalWindow, id string) indicator.KLinePusher {
59+
k := indicatorKey{
60+
iw: iw,
61+
id: id,
62+
}
63+
inc, ok := s.iwIndicators[k]
5564
if ok {
5665
return inc
5766
}
5867

5968
inc = t
6069
s.initAndBind(inc, iw.Interval)
61-
s.iwIndicators[iw] = inc
70+
s.iwIndicators[k] = inc
6271
return t
6372
}
6473

6574
// SMA is a helper function that returns the simple moving average indicator of the given interval and the window size.
6675
func (s *StandardIndicatorSet) SMA(iw types.IntervalWindow) *indicator.SMA {
67-
inc := s.allocateSimpleIndicator(&indicator.SMA{IntervalWindow: iw}, iw)
76+
inc := s.allocateSimpleIndicator(&indicator.SMA{IntervalWindow: iw}, iw, "sma")
6877
return inc.(*indicator.SMA)
6978
}
7079

7180
// EWMA is a helper function that returns the exponential weighed moving average indicator of the given interval and the window size.
7281
func (s *StandardIndicatorSet) EWMA(iw types.IntervalWindow) *indicator.EWMA {
73-
inc := s.allocateSimpleIndicator(&indicator.EWMA{IntervalWindow: iw}, iw)
82+
inc := s.allocateSimpleIndicator(&indicator.EWMA{IntervalWindow: iw}, iw, "ewma")
7483
return inc.(*indicator.EWMA)
7584
}
7685

7786
// VWMA
7887
func (s *StandardIndicatorSet) VWMA(iw types.IntervalWindow) *indicator.VWMA {
79-
inc := s.allocateSimpleIndicator(&indicator.VWMA{IntervalWindow: iw}, iw)
88+
inc := s.allocateSimpleIndicator(&indicator.VWMA{IntervalWindow: iw}, iw, "vwma")
8089
return inc.(*indicator.VWMA)
8190
}
8291

92+
func (s *StandardIndicatorSet) PivotHigh(iw types.IntervalWindow) *indicator.PivotHigh {
93+
inc := s.allocateSimpleIndicator(&indicator.PivotHigh{IntervalWindow: iw}, iw, "pivothigh")
94+
return inc.(*indicator.PivotHigh)
95+
}
8396

8497
func (s *StandardIndicatorSet) PivotLow(iw types.IntervalWindow) *indicator.PivotLow {
85-
inc := s.allocateSimpleIndicator(&indicator.PivotLow{IntervalWindow: iw}, iw)
98+
inc := s.allocateSimpleIndicator(&indicator.PivotLow{IntervalWindow: iw}, iw, "pivotlow")
8699
return inc.(*indicator.PivotLow)
87100
}
88101

89102
func (s *StandardIndicatorSet) ATR(iw types.IntervalWindow) *indicator.ATR {
90-
inc := s.allocateSimpleIndicator(&indicator.ATR{IntervalWindow: iw}, iw)
103+
inc := s.allocateSimpleIndicator(&indicator.ATR{IntervalWindow: iw}, iw, "atr")
91104
return inc.(*indicator.ATR)
92105
}
93106

94107
func (s *StandardIndicatorSet) ATRP(iw types.IntervalWindow) *indicator.ATRP {
95-
inc := s.allocateSimpleIndicator(&indicator.ATRP{IntervalWindow: iw}, iw)
108+
inc := s.allocateSimpleIndicator(&indicator.ATRP{IntervalWindow: iw}, iw, "atrp")
96109
return inc.(*indicator.ATRP)
97110
}
98111

99112
func (s *StandardIndicatorSet) EMV(iw types.IntervalWindow) *indicator.EMV {
100-
inc := s.allocateSimpleIndicator(&indicator.EMV{IntervalWindow: iw}, iw)
113+
inc := s.allocateSimpleIndicator(&indicator.EMV{IntervalWindow: iw}, iw, "emv")
101114
return inc.(*indicator.EMV)
102115
}
103116

104117
func (s *StandardIndicatorSet) CCI(iw types.IntervalWindow) *indicator.CCI {
105-
inc := s.allocateSimpleIndicator(&indicator.CCI{IntervalWindow: iw}, iw)
118+
inc := s.allocateSimpleIndicator(&indicator.CCI{IntervalWindow: iw}, iw, "cci")
106119
return inc.(*indicator.CCI)
107120
}
108121

109122
func (s *StandardIndicatorSet) HULL(iw types.IntervalWindow) *indicator.HULL {
110-
inc := s.allocateSimpleIndicator(&indicator.HULL{IntervalWindow: iw}, iw)
123+
inc := s.allocateSimpleIndicator(&indicator.HULL{IntervalWindow: iw}, iw, "hull")
111124
return inc.(*indicator.HULL)
112125
}
113126

114127
func (s *StandardIndicatorSet) STOCH(iw types.IntervalWindow) *indicator.STOCH {
115-
inc := s.allocateSimpleIndicator(&indicator.STOCH{IntervalWindow: iw}, iw)
128+
inc := s.allocateSimpleIndicator(&indicator.STOCH{IntervalWindow: iw}, iw, "stoch")
116129
return inc.(*indicator.STOCH)
117130
}
118131

pkg/indicator/pivothigh.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package indicator
2+
3+
import (
4+
"time"
5+
6+
"github.com/c9s/bbgo/pkg/datatype/floats"
7+
"github.com/c9s/bbgo/pkg/types"
8+
)
9+
10+
//go:generate callbackgen -type PivotHigh
11+
type PivotHigh struct {
12+
types.SeriesBase
13+
14+
types.IntervalWindow
15+
16+
Highs floats.Slice
17+
Values floats.Slice
18+
EndTime time.Time
19+
20+
updateCallbacks []func(value float64)
21+
}
22+
23+
func (inc *PivotHigh) Length() int {
24+
return inc.Values.Length()
25+
}
26+
27+
func (inc *PivotHigh) Last() float64 {
28+
if len(inc.Values) == 0 {
29+
return 0.0
30+
}
31+
32+
return inc.Values.Last()
33+
}
34+
35+
func (inc *PivotHigh) Update(value float64) {
36+
if len(inc.Highs) == 0 {
37+
inc.SeriesBase.Series = inc
38+
}
39+
40+
inc.Highs.Push(value)
41+
42+
if len(inc.Highs) < inc.Window {
43+
return
44+
}
45+
46+
low, ok := calculatePivotHigh(inc.Highs, inc.Window, inc.RightWindow)
47+
if !ok {
48+
return
49+
}
50+
51+
if low > 0.0 {
52+
inc.Values.Push(low)
53+
}
54+
}
55+
56+
func (inc *PivotHigh) PushK(k types.KLine) {
57+
if k.EndTime.Before(inc.EndTime) {
58+
return
59+
}
60+
61+
inc.Update(k.Low.Float64())
62+
inc.EndTime = k.EndTime.Time()
63+
inc.EmitUpdate(inc.Last())
64+
}
65+

pkg/indicator/pivothigh_callbacks.go

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)