Skip to content

Commit 2f2e411

Browse files
whencanibecinar
andauthored
Williams R Strategy added. Issue 337 (#351)
# Describe Request Implements the Williams %R strategy as requested in issue #337. The Williams %R indicator already exists in the `momentum` package. This PR adds the strategy layer on top of it, following the existing patterns in `strategy/momentum`. Fixed #337 # Change Type New strategy. Co-authored-by: Onur Cinar <onur.cinar@gmail.com>
1 parent 57d7860 commit 2f2e411

4 files changed

Lines changed: 429 additions & 0 deletions

File tree

strategy/momentum/momentum.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@ func AllStrategies() []strategy.Strategy {
2828
NewRsiStrategy(),
2929
NewStochasticRsiStrategy(),
3030
NewTripleRsiStrategy(),
31+
NewWilliamsRStrategy(),
3132
}
3233
}
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
Action
2+
0
3+
0
4+
0
5+
0
6+
0
7+
0
8+
0
9+
0
10+
0
11+
0
12+
0
13+
0
14+
0
15+
1
16+
0
17+
0
18+
0
19+
0
20+
0
21+
0
22+
0
23+
0
24+
0
25+
-1
26+
0
27+
-1
28+
0
29+
-1
30+
-1
31+
-1
32+
-1
33+
0
34+
0
35+
1
36+
0
37+
0
38+
0
39+
0
40+
0
41+
0
42+
1
43+
0
44+
0
45+
0
46+
0
47+
0
48+
-1
49+
0
50+
1
51+
0
52+
-1
53+
0
54+
0
55+
0
56+
0
57+
1
58+
1
59+
0
60+
0
61+
0
62+
0
63+
0
64+
0
65+
-1
66+
-1
67+
0
68+
0
69+
0
70+
0
71+
1
72+
0
73+
1
74+
0
75+
1
76+
0
77+
0
78+
0
79+
0
80+
0
81+
0
82+
0
83+
-1
84+
-1
85+
-1
86+
-1
87+
-1
88+
-1
89+
-1
90+
-1
91+
-1
92+
-1
93+
-1
94+
-1
95+
-1
96+
-1
97+
-1
98+
-1
99+
-1
100+
-1
101+
-1
102+
0
103+
-1
104+
-1
105+
-1
106+
0
107+
0
108+
1
109+
0
110+
0
111+
0
112+
0
113+
0
114+
0
115+
0
116+
0
117+
0
118+
-1
119+
0
120+
0
121+
0
122+
1
123+
1
124+
1
125+
0
126+
0
127+
0
128+
0
129+
0
130+
-1
131+
-1
132+
-1
133+
-1
134+
0
135+
-1
136+
-1
137+
-1
138+
-1
139+
-1
140+
-1
141+
0
142+
0
143+
0
144+
0
145+
0
146+
0
147+
-1
148+
-1
149+
-1
150+
-1
151+
0
152+
0
153+
-1
154+
-1
155+
-1
156+
0
157+
-1
158+
-1
159+
0
160+
-1
161+
0
162+
-1
163+
0
164+
-1
165+
-1
166+
-1
167+
-1
168+
-1
169+
-1
170+
-1
171+
0
172+
-1
173+
-1
174+
0
175+
0
176+
0
177+
0
178+
0
179+
0
180+
0
181+
0
182+
1
183+
1
184+
0
185+
0
186+
0
187+
0
188+
0
189+
-1
190+
-1
191+
-1
192+
0
193+
0
194+
0
195+
-1
196+
-1
197+
-1
198+
-1
199+
-1
200+
-1
201+
-1
202+
-1
203+
0
204+
0
205+
1
206+
0
207+
1
208+
1
209+
1
210+
1
211+
1
212+
1
213+
1
214+
1
215+
0
216+
1
217+
0
218+
0
219+
0
220+
0
221+
0
222+
0
223+
1
224+
1
225+
1
226+
0
227+
0
228+
0
229+
1
230+
1
231+
0
232+
0
233+
0
234+
-1
235+
-1
236+
0
237+
0
238+
0
239+
0
240+
-1
241+
-1
242+
-1
243+
-1
244+
-1
245+
-1
246+
-1
247+
-1
248+
-1
249+
-1
250+
-1
251+
-1
252+
0
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// Copyright (c) 2021-2026 Onur Cinar.
2+
// The source code is provided under GNU AGPLv3 License.
3+
// https://github.com/cinar/indicator
4+
5+
package momentum
6+
7+
import (
8+
"fmt"
9+
10+
"github.com/cinar/indicator/v2/asset"
11+
"github.com/cinar/indicator/v2/helper"
12+
"github.com/cinar/indicator/v2/momentum"
13+
"github.com/cinar/indicator/v2/strategy"
14+
)
15+
16+
const (
17+
// DefaultWilliamsRStrategyBuyAt defines the default Williams R level at which a Buy action is generated.
18+
DefaultWilliamsRStrategyBuyAt = -80.0
19+
20+
// DefaultWilliamsRStrategySellAt defines the default Williams R level at which a Sell action is generated.
21+
DefaultWilliamsRStrategySellAt = -20.0
22+
)
23+
24+
// WilliamsRStrategy represents the configuration parameters for calculating the Williams R strategy.
25+
type WilliamsRStrategy struct {
26+
// WilliamsR represents the configuration parameters for calculating the Williams %R.
27+
WilliamsR *momentum.WilliamsR[float64]
28+
29+
// BuyAt defines the Williams R level at which a Buy action is generated.
30+
BuyAt float64
31+
32+
// SellAt defines the Williams R level at which a Sell action is generated.
33+
SellAt float64
34+
}
35+
36+
// NewWilliamsRStrategy function initializes a new Williams R strategy instance with the default parameters.
37+
func NewWilliamsRStrategy() *WilliamsRStrategy {
38+
return NewWilliamsRStrategyWith(
39+
DefaultWilliamsRStrategyBuyAt,
40+
DefaultWilliamsRStrategySellAt,
41+
)
42+
}
43+
44+
// NewWilliamsRStrategyWith function initializes a new Williams R strategy instance with the given parameters.
45+
func NewWilliamsRStrategyWith(buyAt, sellAt float64) *WilliamsRStrategy {
46+
return &WilliamsRStrategy{
47+
WilliamsR: momentum.NewWilliamsR[float64](),
48+
BuyAt: buyAt,
49+
SellAt: sellAt,
50+
}
51+
}
52+
53+
// Name returns the name of the strategy.
54+
func (r *WilliamsRStrategy) Name() string {
55+
return fmt.Sprintf("Williams R Strategy (%.0f,%.0f)", r.BuyAt, r.SellAt)
56+
}
57+
58+
// Compute processes the provided asset snapshots and generates a stream of actionable recommendations.
59+
func (r *WilliamsRStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan strategy.Action {
60+
snapshotsSplice := helper.Duplicate(snapshots, 3)
61+
62+
highs := asset.SnapshotsAsHighs(snapshotsSplice[0])
63+
lows := asset.SnapshotsAsLows(snapshotsSplice[1])
64+
closings := asset.SnapshotsAsClosings(snapshotsSplice[2])
65+
66+
wr := r.WilliamsR.Compute(highs, lows, closings)
67+
68+
actions := helper.Map(wr, func(value float64) strategy.Action {
69+
if value <= r.BuyAt {
70+
return strategy.Buy
71+
}
72+
73+
if value >= r.SellAt {
74+
return strategy.Sell
75+
}
76+
77+
return strategy.Hold
78+
})
79+
80+
// Williams R starts only after the idle period.
81+
actions = helper.Shift(actions, r.WilliamsR.IdlePeriod(), strategy.Hold)
82+
83+
return actions
84+
}
85+
86+
// Report processes the provided asset snapshots and generates a report annotated with the recommended actions.
87+
func (r *WilliamsRStrategy) Report(c <-chan *asset.Snapshot) *helper.Report {
88+
//
89+
// snapshots[0] -> dates
90+
// snapshots[1] -> Compute -> actions -> annotations
91+
// snapshots[2] -> closings -> close
92+
// snapshots[3] -> highs -|
93+
// snapshots[4] -> lows -+-> WilliamsR.Compute -> wr
94+
// snapshots[5] -> closings-|
95+
//
96+
snapshots := helper.Duplicate(c, 6)
97+
98+
dates := asset.SnapshotsAsDates(snapshots[0])
99+
closings := asset.SnapshotsAsClosings(snapshots[2])
100+
highs := asset.SnapshotsAsHighs(snapshots[3])
101+
lows := asset.SnapshotsAsLows(snapshots[4])
102+
closingsForWR := asset.SnapshotsAsClosings(snapshots[5])
103+
104+
wr := helper.Shift(r.WilliamsR.Compute(highs, lows, closingsForWR), r.WilliamsR.IdlePeriod(), 0)
105+
106+
actions, outcomes := strategy.ComputeWithOutcome(r, snapshots[1])
107+
annotations := strategy.ActionsToAnnotations(actions)
108+
outcomes = helper.MultiplyBy(outcomes, 100)
109+
110+
report := helper.NewReport(r.Name(), dates)
111+
report.AddChart()
112+
report.AddChart()
113+
114+
report.AddColumn(helper.NewNumericReportColumn("Close", closings))
115+
report.AddColumn(helper.NewNumericReportColumn("Williams R", wr), 1)
116+
report.AddColumn(helper.NewAnnotationReportColumn(annotations), 0, 1)
117+
118+
report.AddColumn(helper.NewNumericReportColumn("Outcome", outcomes), 2)
119+
120+
return report
121+
}

0 commit comments

Comments
 (0)