Skip to content
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

Smoothed Moving Average (SMMA) Strategy added. #248

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ The following list of indicators are currently supported by this package:
- [Rolling Moving Average (RMA)](trend/README.md#type-rma)
- [Simple Moving Average (SMA)](trend/README.md#type-sma)
- [Since Change](helper/README.md#func-since)
- [Smoothed Moving Average (SMMA)](trend/README.md#type-smma)
- [Triple Exponential Moving Average (TEMA)](trend/README.md#type-tema)
- [Triangular Moving Average (TRIMA)](trend/README.md#type-trima)
- [Triple Exponential Average (TRIX)](trend/README.md#type-trix)
Expand Down Expand Up @@ -121,6 +122,7 @@ The following list of strategies are currently supported by this package:
- [Moving Average Convergence Divergence (MACD) Strategy](strategy/trend/README.md#type-macdstrategy)
- [Qstick Strategy](strategy/trend/README.md#type-qstickstrategy)
- [Random Index (KDJ) Strategy](strategy/trend/README.md#type-kdjstrategy)
- [Smoothed Moving Average (SMMA) Strategy](strategy/trend/README.md#type-smmastrategy)
- [Triangular Moving Average (TRIMA) Strategy](strategy/trend/README.md#type-trimastrategy)
- [Triple Exponential Average (TRIX) Strategy](strategy/trend/README.md#type-trixstrategy)
- [Triple Moving Average Crossover Strategy](strategy/trend/README.md#type-triplemovingaveragecrossoverstrategy)
Expand Down
1 change: 0 additions & 1 deletion strategy/testdata/x

This file was deleted.

80 changes: 80 additions & 0 deletions strategy/trend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ The information provided on this project is strictly for informational purposes
- [func \(q \*QstickStrategy\) Compute\(c \<\-chan \*asset.Snapshot\) \<\-chan strategy.Action](<#QstickStrategy.Compute>)
- [func \(\*QstickStrategy\) Name\(\) string](<#QstickStrategy.Name>)
- [func \(q \*QstickStrategy\) Report\(c \<\-chan \*asset.Snapshot\) \*helper.Report](<#QstickStrategy.Report>)
- [type SmmaStrategy](<#SmmaStrategy>)
- [func NewSmmaStrategy\(\) \*SmmaStrategy](<#NewSmmaStrategy>)
- [func NewSmmaStrategyWith\(shortPeriod, longPeriod int\) \*SmmaStrategy](<#NewSmmaStrategyWith>)
- [func \(s \*SmmaStrategy\) Compute\(snapshots \<\-chan \*asset.Snapshot\) \<\-chan strategy.Action](<#SmmaStrategy.Compute>)
- [func \(s \*SmmaStrategy\) Name\(\) string](<#SmmaStrategy.Name>)
- [func \(s \*SmmaStrategy\) Report\(c \<\-chan \*asset.Snapshot\) \*helper.Report](<#SmmaStrategy.Report>)
- [type TrimaStrategy](<#TrimaStrategy>)
- [func NewTrimaStrategy\(\) \*TrimaStrategy](<#NewTrimaStrategy>)
- [func \(t \*TrimaStrategy\) Compute\(c \<\-chan \*asset.Snapshot\) \<\-chan strategy.Action](<#TrimaStrategy.Compute>)
Expand Down Expand Up @@ -141,6 +147,18 @@ const (
)
```

<a name="DefaultSmmaStrategyShortPeriod"></a>

```go
const (
// DefaultSmmaStrategyShortPeriod is the default short-term SMMA period of 20.
DefaultSmmaStrategyShortPeriod = 20

// DefaultSmmaStrategyLongPeriod is the default short-term SMMA period of 50.
DefaultSmmaStrategyLongPeriod = 50
)
```

<a name="DefaultTrimaStrategyShortPeriod"></a>

```go
Expand Down Expand Up @@ -772,6 +790,68 @@ func (q *QstickStrategy) Report(c <-chan *asset.Snapshot) *helper.Report

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

<a name="SmmaStrategy"></a>
## type [SmmaStrategy](<https://github.com/cinar/indicator/blob/master/strategy/trend/smma_strategy.go#L28-L36>)

SmmaStrategy represents the configuration parameters for calculating the Smooted Moving Averge \(SMMA\) strategy. A short\-term SMMA crossing above the long\-term SMMA suggests a bullish trend, while crossing below the long\-term SMMA indicates a bearish trend.

```go
type SmmaStrategy struct {
// ShortSmma represents the configuration parameters for calculating the
// short-term Smooted Moving Averge (SMMA).
ShortSmma *trend.Smma[float64]

// LongSmma represents the configuration parameters for calculating the
// long-term Smooted Moving Averge (SMMA).
LongSmma *trend.Smma[float64]
}
```

<a name="NewSmmaStrategy"></a>
### func [NewSmmaStrategy](<https://github.com/cinar/indicator/blob/master/strategy/trend/smma_strategy.go#L39>)

```go
func NewSmmaStrategy() *SmmaStrategy
```

NewSmmaStrategy function initializes a new SMMA strategy instance.

<a name="NewSmmaStrategyWith"></a>
### func [NewSmmaStrategyWith](<https://github.com/cinar/indicator/blob/master/strategy/trend/smma_strategy.go#L47>)

```go
func NewSmmaStrategyWith(shortPeriod, longPeriod int) *SmmaStrategy
```

NewSmmaStrategyWith function initializes a new SMMA strategy instance with the given parameters.

<a name="SmmaStrategy.Compute"></a>
### func \(\*SmmaStrategy\) [Compute](<https://github.com/cinar/indicator/blob/master/strategy/trend/smma_strategy.go#L63>)

```go
func (s *SmmaStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan strategy.Action
```

Compute processes the provided asset snapshots and generates a stream of actionable recommendations.

<a name="SmmaStrategy.Name"></a>
### func \(\*SmmaStrategy\) [Name](<https://github.com/cinar/indicator/blob/master/strategy/trend/smma_strategy.go#L55>)

```go
func (s *SmmaStrategy) Name() string
```

Name returns the name of the strategy.

<a name="SmmaStrategy.Report"></a>
### func \(\*SmmaStrategy\) [Report](<https://github.com/cinar/indicator/blob/master/strategy/trend/smma_strategy.go#L95>)

```go
func (s *SmmaStrategy) Report(c <-chan *asset.Snapshot) *helper.Report
```

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

<a name="TrimaStrategy"></a>
## type [TrimaStrategy](<https://github.com/cinar/indicator/blob/master/strategy/trend/trima_strategy.go#L25-L31>)

Expand Down
136 changes: 136 additions & 0 deletions strategy/trend/smma_strategy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// 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"
)

const (
// DefaultSmmaStrategyShortPeriod is the default short-term SMMA period of 20.
DefaultSmmaStrategyShortPeriod = 20

// DefaultSmmaStrategyLongPeriod is the default short-term SMMA period of 50.
DefaultSmmaStrategyLongPeriod = 50
Comment on lines +20 to +21
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct the mismatch in documentation for DefaultSmmaStrategyLongPeriod.
The comment incorrectly states that 50 is the default “short-term” period, but this constant is intended for the “long-term” period.

- // DefaultSmmaStrategyLongPeriod is the default short-term SMMA period of 50.
+ // DefaultSmmaStrategyLongPeriod is the default long-term SMMA period of 50.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// DefaultSmmaStrategyLongPeriod is the default short-term SMMA period of 50.
DefaultSmmaStrategyLongPeriod = 50
// DefaultSmmaStrategyLongPeriod is the default long-term SMMA period of 50.
DefaultSmmaStrategyLongPeriod = 50

)

// SmmaStrategy represents the configuration parameters for calculating the
// Smooted Moving Averge (SMMA) strategy. A short-term SMMA crossing above
// the long-term SMMA suggests a bullish trend, while crossing below the
// long-term SMMA indicates a bearish trend.
type SmmaStrategy struct {
// ShortSmma represents the configuration parameters for calculating the
// short-term Smooted Moving Averge (SMMA).
ShortSmma *trend.Smma[float64]

// LongSmma represents the configuration parameters for calculating the
// long-term Smooted Moving Averge (SMMA).
LongSmma *trend.Smma[float64]
}

// NewSmmaStrategy function initializes a new SMMA strategy instance.
func NewSmmaStrategy() *SmmaStrategy {
return NewSmmaStrategyWith(
DefaultSmmaStrategyShortPeriod,
DefaultSmmaStrategyLongPeriod,
)
}

// NewSmmaStrategyWith function initializes a new SMMA strategy instance with the given parameters.
func NewSmmaStrategyWith(shortPeriod, longPeriod int) *SmmaStrategy {
return &SmmaStrategy{
ShortSmma: trend.NewSmmaWithPeriod[float64](shortPeriod),
LongSmma: trend.NewSmmaWithPeriod[float64](longPeriod),
}
}

// Name returns the name of the strategy.
func (s *SmmaStrategy) Name() string {
return fmt.Sprintf("SMMA Strategy (%d,%d)",
s.ShortSmma.Period,
s.LongSmma.Period,
)
}

// Compute processes the provided asset snapshots and generates a stream of actionable recommendations.
func (s *SmmaStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan strategy.Action {
closingsSplice := helper.Duplicate(asset.SnapshotsAsClosings(snapshots), 2)

shortSmmas := s.ShortSmma.Compute(closingsSplice[0])
longSmmas := s.LongSmma.Compute(closingsSplice[1])

commonPeriod := helper.CommonPeriod(s.ShortSmma.Period, s.LongSmma.Period)
shortSmmas = helper.SyncPeriod(commonPeriod, s.ShortSmma.Period, shortSmmas)
longSmmas = helper.SyncPeriod(commonPeriod, s.LongSmma.Period, longSmmas)

actions := helper.Operate(shortSmmas, longSmmas, func(shortSmma, longSmma float64) strategy.Action {
// A short-perios SMMA value crossing above long-period SMMA suggests a bullish trend.
if shortSmma > longSmma {
return strategy.Buy
}

// A short-period SMMA value crossing below long-period SMMA suggests a bearish trend.
if longSmma > shortSmma {
return strategy.Sell
}

return strategy.Hold
})

// SMMA strategy starts only after a full period.
actions = helper.Shift(actions, commonPeriod, strategy.Hold)

return actions
}

// Report processes the provided asset snapshots and generates a
// report annotated with the recommended actions.
func (s *SmmaStrategy) Report(c <-chan *asset.Snapshot) *helper.Report {
//
// snapshots[0] -> dates
// snapshots[1] -> closings[0] -> closings
// closings[1] -> short-period SMMA
// closings[2] -> long-period SMMA
// snapshots[2] -> actions -> annotations
// -> outcomes
//
snapshots := helper.Duplicate(c, 3)

dates := asset.SnapshotsAsDates(snapshots[0])
closings := helper.Duplicate(asset.SnapshotsAsClosings(snapshots[1]), 3)

shortSmmas := s.ShortSmma.Compute(closings[1])
longSmmas := s.LongSmma.Compute(closings[2])

actions, outcomes := strategy.ComputeWithOutcome(s, snapshots[2])
annotations := strategy.ActionsToAnnotations(actions)
outcomes = helper.MultiplyBy(outcomes, 100)

commonPeriod := helper.CommonPeriod(s.ShortSmma.Period, s.LongSmma.Period)
dates = helper.SyncPeriod(commonPeriod, 0, dates)
closings[0] = helper.Skip(closings[0], commonPeriod)
shortSmmas = helper.SyncPeriod(commonPeriod, s.ShortSmma.Period, shortSmmas)
longSmmas = helper.SyncPeriod(commonPeriod, s.LongSmma.Period, longSmmas)
annotations = helper.Skip(annotations, commonPeriod)
outcomes = helper.Skip(outcomes, commonPeriod)

report := helper.NewReport(s.Name(), dates)
report.AddChart()
report.AddChart()

report.AddColumn(helper.NewNumericReportColumn("Close", closings[0]))
report.AddColumn(helper.NewNumericReportColumn("MACD", shortSmmas), 1)
report.AddColumn(helper.NewNumericReportColumn("Signal", longSmmas), 1)
report.AddColumn(helper.NewAnnotationReportColumn(annotations), 0, 1)

report.AddColumn(helper.NewNumericReportColumn("Outcome", outcomes), 2)

return report
}
Loading
Loading