-
-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Envelope trend indicator and Envelope strategy are added. #233
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// Copyright (c) 2021-2024 Onur Cinar. | ||
// The source code is provided under GNU AGPLv3 License. | ||
// https://github.com/cinar/indicator | ||
|
||
package trend | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/cinar/indicator/v2/asset" | ||
"github.com/cinar/indicator/v2/helper" | ||
"github.com/cinar/indicator/v2/strategy" | ||
"github.com/cinar/indicator/v2/trend" | ||
) | ||
|
||
// EnvelopeStrategy represents the configuration parameters for calculating the Envelope strategy. When the closing | ||
// is above the upper band suggests a Sell recommendation, and when the closing is below the lower band suggests a | ||
// buy recommendation. | ||
type EnvelopeStrategy struct { | ||
// Envelope is the envelope indicator instance. | ||
Envelope *trend.Envelope[float64] | ||
} | ||
|
||
// NewEnvelopeStrategy function initializes a new Envelope strategy with the default parameters. | ||
func NewEnvelopeStrategy() *EnvelopeStrategy { | ||
return NewEnvelopeStrategyWith( | ||
trend.NewEnvelopeWithSma[float64](), | ||
) | ||
} | ||
|
||
// NewEnvelopeStrategyWith function initializes a new Envelope strategy with the given Envelope instance. | ||
func NewEnvelopeStrategyWith(envelope *trend.Envelope[float64]) *EnvelopeStrategy { | ||
return &EnvelopeStrategy{ | ||
Envelope: envelope, | ||
} | ||
} | ||
|
||
// Name returns the name of the strategy. | ||
func (e *EnvelopeStrategy) Name() string { | ||
return fmt.Sprintf("Envelope Strategy (%s)", e.Envelope.String()) | ||
} | ||
|
||
// Compute processes the provided asset snapshots and generates a stream of actionable recommendations. | ||
func (e *EnvelopeStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan strategy.Action { | ||
closingsSplice := helper.Duplicate( | ||
asset.SnapshotsAsClosings(snapshots), | ||
2, | ||
) | ||
|
||
closingsSplice[1] = helper.Skip(closingsSplice[1], e.Envelope.IdlePeriod()) | ||
|
||
uppers, middles, lowers := e.Envelope.Compute(closingsSplice[0]) | ||
go helper.Drain(middles) | ||
|
||
actions := helper.Operate3(uppers, lowers, closingsSplice[1], func(upper, lower, closing float64) strategy.Action { | ||
// When the closing is below the lower band suggests a buy recommendation. | ||
if closing < lower { | ||
return strategy.Buy | ||
} | ||
|
||
// When the closing is above the upper band suggests a Sell recommendation. | ||
if closing > upper { | ||
return strategy.Sell | ||
} | ||
|
||
return strategy.Hold | ||
}) | ||
|
||
// Envelope start only after a full period. | ||
actions = helper.Shift(actions, e.Envelope.IdlePeriod(), strategy.Hold) | ||
|
||
return actions | ||
} | ||
|
||
// Report processes the provided asset snapshots and generates a report annotated with the recommended actions. | ||
func (e *EnvelopeStrategy) Report(c <-chan *asset.Snapshot) *helper.Report { | ||
// | ||
// snapshots[0] -> dates | ||
// snapshots[1] -> closings[0] -> closings | ||
// closings[1] -> envelope -> upper | ||
// -> middle | ||
// -> lower | ||
// snapshots[2] -> actions -> annotations | ||
// -> outcomes | ||
// | ||
snapshotsSplice := helper.Duplicate(c, 3) | ||
|
||
dates := helper.Skip( | ||
asset.SnapshotsAsDates(snapshotsSplice[0]), | ||
e.Envelope.IdlePeriod(), | ||
) | ||
|
||
closingsSplice := helper.Duplicate(asset.SnapshotsAsClosings(snapshotsSplice[1]), 2) | ||
closingsSplice[0] = helper.Skip(closingsSplice[0], e.Envelope.IdlePeriod()) | ||
|
||
uppers, middles, lowers := e.Envelope.Compute(closingsSplice[1]) | ||
|
||
actions, outcomes := strategy.ComputeWithOutcome(e, snapshotsSplice[2]) | ||
actions = helper.Skip(actions, e.Envelope.IdlePeriod()) | ||
outcomes = helper.Skip(outcomes, e.Envelope.IdlePeriod()) | ||
|
||
annotations := strategy.ActionsToAnnotations(actions) | ||
outcomes = helper.MultiplyBy(outcomes, 100) | ||
|
||
report := helper.NewReport(e.Name(), dates) | ||
report.AddChart() | ||
|
||
report.AddColumn(helper.NewNumericReportColumn("Close", closingsSplice[0])) | ||
report.AddColumn(helper.NewNumericReportColumn("Upper", uppers)) | ||
report.AddColumn(helper.NewNumericReportColumn("Middle", middles)) | ||
report.AddColumn(helper.NewNumericReportColumn("Lower", lowers)) | ||
report.AddColumn(helper.NewAnnotationReportColumn(annotations)) | ||
|
||
report.AddColumn(helper.NewNumericReportColumn("Outcome", outcomes), 1) | ||
|
||
return report | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Copyright (c) 2021-2024 Onur Cinar. | ||
// The source code is provided under GNU AGPLv3 License. | ||
// https://github.com/cinar/indicator | ||
|
||
package trend_test | ||
|
||
import ( | ||
"os" | ||
"testing" | ||
|
||
"github.com/cinar/indicator/v2/asset" | ||
"github.com/cinar/indicator/v2/helper" | ||
"github.com/cinar/indicator/v2/strategy" | ||
"github.com/cinar/indicator/v2/strategy/trend" | ||
) | ||
|
||
func TestEnvelopeStrategy(t *testing.T) { | ||
snapshots, err := helper.ReadFromCsvFile[asset.Snapshot]("testdata/brk-b.csv", true) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
results, err := helper.ReadFromCsvFile[strategy.Result]("testdata/envelope_strategy.csv", true) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
expected := helper.Map(results, func(r *strategy.Result) strategy.Action { return r.Action }) | ||
|
||
envelope := trend.NewEnvelopeStrategy() | ||
actual := envelope.Compute(snapshots) | ||
|
||
err = helper.CheckEquals(actual, expected) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestEnvelopeStrategyReport(t *testing.T) { | ||
snapshots, err := helper.ReadFromCsvFile[asset.Snapshot]("testdata/brk-b.csv", true) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
envelope := trend.NewEnvelopeStrategy() | ||
report := envelope.Report(snapshots) | ||
|
||
fileName := "envelope_strategy.html" | ||
defer os.Remove(fileName) | ||
|
||
err = report.WriteToFile(fileName) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Update
NewOrStrategy
Usages to Match New Signature and Revise DocumentationThe
NewOrStrategy
function signature has been updated to accept a variadicstrategies
parameter, but existing usages instrategy/or_strategy_test.go
have not been updated accordingly. This discrepancy can lead to compilation errors or unexpected behavior.Function Description Update:
Update Existing Usages:
🔗 Analysis chain
Update description for
NewOrStrategy
and consider backwards compatibilityThe function signature has been changed to accept multiple strategies, but the description hasn't been updated to reflect this change.
To assess the impact of this change, let's check for existing usages of
NewOrStrategy
:This will help determine the extent of necessary updates in the codebase.
Also applies to: 350-350
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
Length of output: 277