|
| 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 | +} |
0 commit comments