Skip to content

Commit 8c47c8e

Browse files
authored
Ichimoku Cloud Strategy added. Issue 336 (#350)
# Describe Request Ichimoku Cloud Strategy added. Fixed #336 # Change Type New strategy.
1 parent 77c6ac5 commit 8c47c8e

File tree

6 files changed

+598
-128
lines changed

6 files changed

+598
-128
lines changed

README.md

Lines changed: 130 additions & 128 deletions
Large diffs are not rendered by default.

strategy/momentum/README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ The information provided on this project is strictly for informational purposes
3131
- [func \(a \*AwesomeOscillatorStrategy\) Compute\(snapshots \<\-chan \*asset.Snapshot\) \<\-chan strategy.Action](<#AwesomeOscillatorStrategy.Compute>)
3232
- [func \(\*AwesomeOscillatorStrategy\) Name\(\) string](<#AwesomeOscillatorStrategy.Name>)
3333
- [func \(a \*AwesomeOscillatorStrategy\) Report\(c \<\-chan \*asset.Snapshot\) \*helper.Report](<#AwesomeOscillatorStrategy.Report>)
34+
- [type IchimokuCloudStrategy](<#IchimokuCloudStrategy>)
35+
- [func NewIchimokuCloudStrategy\(\) \*IchimokuCloudStrategy](<#NewIchimokuCloudStrategy>)
36+
- [func \(i \*IchimokuCloudStrategy\) Compute\(snapshots \<\-chan \*asset.Snapshot\) \<\-chan strategy.Action](<#IchimokuCloudStrategy.Compute>)
37+
- [func \(\*IchimokuCloudStrategy\) Name\(\) string](<#IchimokuCloudStrategy.Name>)
38+
- [func \(i \*IchimokuCloudStrategy\) Report\(c \<\-chan \*asset.Snapshot\) \*helper.Report](<#IchimokuCloudStrategy.Report>)
3439
- [type RsiStrategy](<#RsiStrategy>)
3540
- [func NewRsiStrategy\(\) \*RsiStrategy](<#NewRsiStrategy>)
3641
- [func NewRsiStrategyWith\(buyAt, sellAt float64\) \*RsiStrategy](<#NewRsiStrategyWith>)
@@ -159,6 +164,54 @@ func (a *AwesomeOscillatorStrategy) Report(c <-chan *asset.Snapshot) *helper.Rep
159164

160165
Report processes the provided asset snapshots and generates a report annotated with the recommended actions.
161166

167+
<a name="IchimokuCloudStrategy"></a>
168+
## type [IchimokuCloudStrategy](<https://github.com/cinar/indicator/blob/master/strategy/momentum/ichimoku_cloud_strategy.go#L15-L18>)
169+
170+
IchimokuCloudStrategy represents the configuration parameters for calculating the Ichimoku Cloud strategy.
171+
172+
```go
173+
type IchimokuCloudStrategy struct {
174+
// IchimokuCloud represents the configuration parameters for calculating the Ichimoku Cloud.
175+
IchimokuCloud *momentum.IchimokuCloud[float64]
176+
}
177+
```
178+
179+
<a name="NewIchimokuCloudStrategy"></a>
180+
### func [NewIchimokuCloudStrategy](<https://github.com/cinar/indicator/blob/master/strategy/momentum/ichimoku_cloud_strategy.go#L21>)
181+
182+
```go
183+
func NewIchimokuCloudStrategy() *IchimokuCloudStrategy
184+
```
185+
186+
NewIchimokuCloudStrategy function initializes a new Ichimoku Cloud strategy with the default parameters.
187+
188+
<a name="IchimokuCloudStrategy.Compute"></a>
189+
### func \(\*IchimokuCloudStrategy\) [Compute](<https://github.com/cinar/indicator/blob/master/strategy/momentum/ichimoku_cloud_strategy.go#L33>)
190+
191+
```go
192+
func (i *IchimokuCloudStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan strategy.Action
193+
```
194+
195+
Compute processes the provided asset snapshots and generates a stream of actionable recommendations.
196+
197+
<a name="IchimokuCloudStrategy.Name"></a>
198+
### func \(\*IchimokuCloudStrategy\) [Name](<https://github.com/cinar/indicator/blob/master/strategy/momentum/ichimoku_cloud_strategy.go#L28>)
199+
200+
```go
201+
func (*IchimokuCloudStrategy) Name() string
202+
```
203+
204+
Name returns the name of the strategy.
205+
206+
<a name="IchimokuCloudStrategy.Report"></a>
207+
### func \(\*IchimokuCloudStrategy\) [Report](<https://github.com/cinar/indicator/blob/master/strategy/momentum/ichimoku_cloud_strategy.go#L71>)
208+
209+
```go
210+
func (i *IchimokuCloudStrategy) Report(c <-chan *asset.Snapshot) *helper.Report
211+
```
212+
213+
Report processes the provided asset snapshots and generates a report annotated with the recommended actions.
214+
162215
<a name="RsiStrategy"></a>
163216
## type [RsiStrategy](<https://github.com/cinar/indicator/blob/master/strategy/momentum/rsi_strategy.go#L25-L34>)
164217

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
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+
"github.com/cinar/indicator/v2/asset"
9+
"github.com/cinar/indicator/v2/helper"
10+
"github.com/cinar/indicator/v2/momentum"
11+
"github.com/cinar/indicator/v2/strategy"
12+
)
13+
14+
// IchimokuCloudStrategy represents the configuration parameters for calculating the Ichimoku Cloud strategy.
15+
type IchimokuCloudStrategy struct {
16+
// IchimokuCloud represents the configuration parameters for calculating the Ichimoku Cloud.
17+
IchimokuCloud *momentum.IchimokuCloud[float64]
18+
}
19+
20+
// NewIchimokuCloudStrategy function initializes a new Ichimoku Cloud strategy with the default parameters.
21+
func NewIchimokuCloudStrategy() *IchimokuCloudStrategy {
22+
return &IchimokuCloudStrategy{
23+
IchimokuCloud: momentum.NewIchimokuCloud[float64](),
24+
}
25+
}
26+
27+
// Name returns the name of the strategy.
28+
func (*IchimokuCloudStrategy) Name() string {
29+
return "Ichimoku Cloud Strategy"
30+
}
31+
32+
// Compute processes the provided asset snapshots and generates a stream of actionable recommendations.
33+
func (i *IchimokuCloudStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan strategy.Action {
34+
snapshotsSplice := helper.Duplicate(snapshots, 3)
35+
36+
highs := asset.SnapshotsAsHighs(snapshotsSplice[0])
37+
lows := asset.SnapshotsAsLows(snapshotsSplice[1])
38+
closings := asset.SnapshotsAsClosings(snapshotsSplice[2])
39+
40+
closingsSplice := helper.Duplicate(closings, 2)
41+
42+
cl, bl, lsa, lsb, ll := i.IchimokuCloud.Compute(highs, lows, closingsSplice[0])
43+
44+
// Lagging line is not used in the core logic, drain it to prevent blocking
45+
go helper.Drain(ll)
46+
47+
actions := helper.Operate5(
48+
helper.Skip(closingsSplice[1], i.IchimokuCloud.IdlePeriod()),
49+
cl,
50+
bl,
51+
lsa,
52+
lsb,
53+
func(c, conversion, base, spanA, spanB float64) strategy.Action {
54+
if c > spanA && c > spanB && conversion > base && spanA > spanB {
55+
return strategy.Buy
56+
}
57+
58+
if c < spanA && c < spanB && conversion < base && spanA < spanB {
59+
return strategy.Sell
60+
}
61+
62+
return strategy.Hold
63+
},
64+
)
65+
66+
// Shift the actions to account for the idle period
67+
return helper.Shift(actions, i.IchimokuCloud.IdlePeriod(), strategy.Hold)
68+
}
69+
70+
// Report processes the provided asset snapshots and generates a report annotated with the recommended actions.
71+
func (i *IchimokuCloudStrategy) Report(c <-chan *asset.Snapshot) *helper.Report {
72+
snapshots := helper.Duplicate(c, 6)
73+
74+
dates := asset.SnapshotsAsDates(snapshots[0])
75+
closings := asset.SnapshotsAsClosings(snapshots[2])
76+
highs := asset.SnapshotsAsHighs(snapshots[3])
77+
lows := asset.SnapshotsAsLows(snapshots[4])
78+
closingsForCloud := asset.SnapshotsAsClosings(snapshots[5])
79+
80+
cl, bl, lsa, lsb, ll := i.IchimokuCloud.Compute(highs, lows, closingsForCloud)
81+
82+
// Lagging line is not used in the report right now, drain it.
83+
go helper.Drain(ll)
84+
85+
clShifted := helper.Shift(cl, i.IchimokuCloud.IdlePeriod(), 0)
86+
blShifted := helper.Shift(bl, i.IchimokuCloud.IdlePeriod(), 0)
87+
lsaShifted := helper.Shift(lsa, i.IchimokuCloud.IdlePeriod(), 0)
88+
lsbShifted := helper.Shift(lsb, i.IchimokuCloud.IdlePeriod(), 0)
89+
90+
actions, outcomes := strategy.ComputeWithOutcome(i, snapshots[1])
91+
annotations := strategy.ActionsToAnnotations(actions)
92+
outcomes = helper.MultiplyBy(outcomes, 100)
93+
94+
report := helper.NewReport(i.Name(), dates)
95+
report.AddChart()
96+
97+
report.AddColumn(helper.NewNumericReportColumn("Close", closings))
98+
report.AddColumn(helper.NewNumericReportColumn("Conversion Line", clShifted))
99+
report.AddColumn(helper.NewNumericReportColumn("Base Line", blShifted))
100+
report.AddColumn(helper.NewNumericReportColumn("Leading Span A", lsaShifted))
101+
report.AddColumn(helper.NewNumericReportColumn("Leading Span B", lsbShifted))
102+
report.AddColumn(helper.NewAnnotationReportColumn(annotations), 0, 1)
103+
104+
report.AddColumn(helper.NewNumericReportColumn("Outcome", outcomes), 1)
105+
106+
return report
107+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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_test
6+
7+
import (
8+
"testing"
9+
10+
"github.com/cinar/indicator/v2/asset"
11+
"github.com/cinar/indicator/v2/helper"
12+
"github.com/cinar/indicator/v2/strategy"
13+
"github.com/cinar/indicator/v2/strategy/momentum"
14+
)
15+
16+
func TestIchimokuCloudStrategy(t *testing.T) {
17+
snapshots, err := helper.ReadFromCsvFile[asset.Snapshot]("testdata/brk-b.csv")
18+
if err != nil {
19+
t.Fatal(err)
20+
}
21+
22+
results, err := helper.ReadFromCsvFile[strategy.Result]("testdata/ichimoku_cloud_strategy.csv")
23+
if err != nil {
24+
t.Fatal(err)
25+
}
26+
27+
expected := helper.Map(results, func(r *strategy.Result) strategy.Action { return r.Action })
28+
29+
ic := momentum.NewIchimokuCloudStrategy()
30+
actual := ic.Compute(snapshots)
31+
32+
err = helper.CheckEquals(actual, expected)
33+
if err != nil {
34+
t.Fatal(err)
35+
}
36+
}
37+
38+
func TestIchimokuCloudStrategyReport(t *testing.T) {
39+
snapshots, err := helper.ReadFromCsvFile[asset.Snapshot]("testdata/brk-b.csv")
40+
if err != nil {
41+
t.Fatal(err)
42+
}
43+
44+
ic := momentum.NewIchimokuCloudStrategy()
45+
46+
report := ic.Report(snapshots)
47+
48+
fileName := "ichimoku_cloud_strategy.html"
49+
defer helper.Remove(t, fileName)
50+
51+
err = report.WriteToFile(fileName)
52+
if err != nil {
53+
t.Fatal(err)
54+
}
55+
}

strategy/momentum/momentum.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import "github.com/cinar/indicator/v2/strategy"
2424
func AllStrategies() []strategy.Strategy {
2525
return []strategy.Strategy{
2626
NewAwesomeOscillatorStrategy(),
27+
NewIchimokuCloudStrategy(),
2728
NewRsiStrategy(),
2829
NewStochasticRsiStrategy(),
2930
NewTripleRsiStrategy(),

0 commit comments

Comments
 (0)