-
-
Notifications
You must be signed in to change notification settings - Fork 111
/
Copy pathstop_loss_strategy.go
82 lines (63 loc) · 2.71 KB
/
stop_loss_strategy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright (c) 2021-2024 Onur Cinar.
// The source code is provided under GNU AGPLv3 License.
// https://github.com/cinar/indicator
package decorator
import (
"fmt"
"github.com/cinar/indicator/v2/asset"
"github.com/cinar/indicator/v2/helper"
"github.com/cinar/indicator/v2/strategy"
)
// StopLossStrategy prevents a loss by recommending a sell action when the assets drop below the given threshold.
type StopLossStrategy struct {
// InnertStrategy is the inner strategy.
InnertStrategy strategy.Strategy
// Percentage is the loss threshold in percentage.
Percentage float64
}
// NewStopLossStrategy function initializes a new stop loss strategy instance.
func NewStopLossStrategy(innerStrategy strategy.Strategy, percentage float64) *StopLossStrategy {
return &StopLossStrategy{
InnertStrategy: innerStrategy,
Percentage: percentage,
}
}
// Name returns the name of the strategy.
func (s *StopLossStrategy) Name() string {
return fmt.Sprintf("Stop Loss Strategy (%s)", s.InnertStrategy.Name())
}
// Compute processes the provided asset snapshots and generates a stream of actionable recommendations.
func (s *StopLossStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan strategy.Action {
snapshotsSplice := helper.Duplicate(snapshots, 2)
innerActions := s.InnertStrategy.Compute(snapshotsSplice[0])
closings := asset.SnapshotsAsClosings(snapshotsSplice[1])
stopLossAt := 0.0
return helper.Operate(innerActions, closings, func(action strategy.Action, closing float64) strategy.Action {
// If action is Buy and the asset is not yet bought, buy it as recommended.
if action == strategy.Buy && stopLossAt == 0.0 {
stopLossAt = closing * (1 - s.Percentage)
return strategy.Buy
}
// If asset is bought and action is sell or closing is less than or equal to stop loss at, recommend sell.
if stopLossAt != 0 && (action == strategy.Sell || closing <= stopLossAt) {
stopLossAt = 0.0
return strategy.Sell
}
return strategy.Hold
})
}
// Report processes the provided asset snapshots and generates a report annotated with the recommended actions.
func (s *StopLossStrategy) Report(c <-chan *asset.Snapshot) *helper.Report {
snapshots := helper.Duplicate(c, 3)
dates := asset.SnapshotsAsDates(snapshots[0])
closings := asset.SnapshotsAsClosings(snapshots[1])
actions, outcomes := strategy.ComputeWithOutcome(s, snapshots[2])
annotations := strategy.ActionsToAnnotations(actions)
outcomes = helper.MultiplyBy(outcomes, 100)
report := helper.NewReport(s.Name(), dates)
report.AddChart()
report.AddColumn(helper.NewNumericReportColumn("Close", closings))
report.AddColumn(helper.NewAnnotationReportColumn(annotations))
report.AddColumn(helper.NewNumericReportColumn("Outcome", outcomes), 1)
return report
}