Skip to content

Commit

Permalink
Outcome added.
Browse files Browse the repository at this point in the history
  • Loading branch information
cinar committed Dec 15, 2023
1 parent 64bcbfb commit 94e2768
Show file tree
Hide file tree
Showing 11 changed files with 3,250 additions and 17 deletions.
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,11 @@ The following list of indicators are currently supported by this package:

## Strategies Provided

Strategies relies on the following:
The following list of strategies are currently supported by this package:

- [Action](strategy/README.md#type-action)
- [Snapshot](asset/README.md#type-snapshot)
- Strategy Function
- Buy and Hold Strategy
### Base Strategies

The following list of strategies are currently supported by this package:
- Buy and Hold Strategy

### Trend Strategies

Expand Down Expand Up @@ -137,14 +134,17 @@ The following list of strategies are currently supported by this package:
- Separate Strategies
- MACD and RSI Strategy

### Strategy Helpers

- [Action](strategy/README.md#type-action)
- [Outcome](strategy/README.md#func-outcome)
- [Snapshot](asset/README.md#type-snapshot)

## Backtest

Backtesting is the method for seeing how well a strategy would have done. The following backtesting functions are provided for evaluating strategies.

- Apply Actions
- Count Transactions
- Normalize Actions
- Normalize Gains

## Usage

Expand All @@ -164,7 +164,7 @@ import (

## Contributing to the Project

Anyone can contribute to Checkers library. Please make sure to read our [Contributor Covenant Code of Conduct](./CODE_OF_CONDUCT.md) guide first. Follow the [How to Contribute to Checker](./CONTRIBUTING.md) to contribute.
Anyone can contribute to Indicator library. Please make sure to read our [Contributor Covenant Code of Conduct](./CODE_OF_CONDUCT.md) guide first. Follow the [How to Contribute to Checker](./CONTRIBUTING.md) to contribute.

## Disclaimer

Expand Down
4 changes: 2 additions & 2 deletions helper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ The information provided on this project is strictly for informational purposes
- [func Map\[F, T any\]\(c \<\-chan F, f func\(F\) T\) \<\-chan T](<#Map>)
- [func Multiply\[T Number\]\(ac, bc \<\-chan T\) \<\-chan T](<#Multiply>)
- [func MultiplyBy\[T Number\]\(c \<\-chan T, m T\) \<\-chan T](<#MultiplyBy>)
- [func Operate\[T Number, R any\]\(ac, bc \<\-chan T, o func\(T, T\) R\) \<\-chan R](<#Operate>)
- [func Operate\[A any, B any, R any\]\(ac \<\-chan A, bc \<\-chan B, o func\(A, B\) R\) \<\-chan R](<#Operate>)
- [func Pipe\[T any\]\(f \<\-chan T, t chan\<\- T\)](<#Pipe>)
- [func Pow\[T Number\]\(c \<\-chan T, y T\) \<\-chan T](<#Pow>)
- [func ReadFromCsvFile\[T any\]\(fileName string, hasHeader bool\) \(\<\-chan \*T, error\)](<#ReadFromCsvFile>)
Expand Down Expand Up @@ -470,7 +470,7 @@ fmt.Println(helper.ChanToSlice(twoTimes)) // [2, 4, 6, 8]
## func [Operate](<https://github.com/cinar/indicator/blob/v2/helper/operate.go#L15>)

```go
func Operate[T Number, R any](ac, bc <-chan T, o func(T, T) R) <-chan R
func Operate[A any, B any, R any](ac <-chan A, bc <-chan B, o func(A, B) R) <-chan R
```

Operate applies the provided operate function to corresponding values from two numeric input channels and sends the resulting values to an output channel.
Expand Down
2 changes: 1 addition & 1 deletion helper/operate.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ package helper
// add := helper.Operate(ac, bc, func(a, b int) int {
// return a + b
// })
func Operate[T Number, R any](ac, bc <-chan T, o func(T, T) R) <-chan R {
func Operate[A any, B any, R any](ac <-chan A, bc <-chan B, o func(A, B) R) <-chan R {
oc := make(chan R)

go func() {
Expand Down
30 changes: 30 additions & 0 deletions strategy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ The information provided on this project is strictly for informational purposes
## Index

- [func ActionsToAnnotations\(ac \<\-chan Action\) \<\-chan string](<#ActionsToAnnotations>)
- [func NormalizeActions\(ac \<\-chan Action\) \<\-chan Action](<#NormalizeActions>)
- [func Outcome\(values \<\-chan float64, actions \<\-chan Action\) \<\-chan float64](<#Outcome>)
- [func SpreadActions\(ac \<\-chan Action\) \<\-chan Action](<#SpreadActions>)
- [type Action](<#Action>)
- [func \(a Action\) Annotation\(\) string](<#Action.Annotation>)
- [type ApoStrategy](<#ApoStrategy>)
Expand All @@ -42,6 +45,33 @@ func ActionsToAnnotations(ac <-chan Action) <-chan string

ActionsToAnnotations takes a channel of action recommendations and returns a new channel containing corresponding annotations for those actions.

<a name="NormalizeActions"></a>
## func [NormalizeActions](<https://github.com/cinar/indicator/blob/v2/strategy/action.go#L55>)

```go
func NormalizeActions(ac <-chan Action) <-chan Action
```

NormalizeActions transforms the given channel of actions to ensure a consistent and predictable sequence. It eliminates consecutive occurrences of the same action \(Buy/Sell\), ensuring the order follows a pattern of Hold, Buy, Hold, Sell.

<a name="Outcome"></a>
## func [Outcome](<https://github.com/cinar/indicator/blob/v2/strategy/outcome.go#L10>)

```go
func Outcome(values <-chan float64, actions <-chan Action) <-chan float64
```

Outcome simulates the potential result of executing the given actions based on the provided values.

<a name="SpreadActions"></a>
## func [SpreadActions](<https://github.com/cinar/indicator/blob/v2/strategy/action.go#L72>)

```go
func SpreadActions(ac <-chan Action) <-chan Action
```

SpreadActions simplifies the representation of the action sequence and facilitates subsequent processing by transforming the given channel of actions. It retains Hold actions until the first Buy or Sell action appears. Subsequently, it replaces all remaining Hold actions with the preceding Buy or Sell action, effectively merging consecutive actions.

<a name="Action"></a>
## type [Action](<https://github.com/cinar/indicator/blob/v2/strategy/action.go#L11>)

Expand Down
32 changes: 32 additions & 0 deletions strategy/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,35 @@ func ActionsToAnnotations(ac <-chan Action) <-chan string {
return a.Annotation()
})
}

// NormalizeActions transforms the given channel of actions to ensure a consistent and
// predictable sequence. It eliminates consecutive occurrences of the same action
// (Buy/Sell), ensuring the order follows a pattern of Hold, Buy, Hold, Sell.
func NormalizeActions(ac <-chan Action) <-chan Action {
last := Sell

return helper.Map(ac, func(a Action) Action {
if a != Hold && a != last {
last = a
return a
}

return Hold
})
}

// SpreadActions simplifies the representation of the action sequence and facilitates subsequent
// processing by transforming the given channel of actions. It retains Hold actions until the
// first Buy or Sell action appears. Subsequently, it replaces all remaining Hold actions with
// the preceding Buy or Sell action, effectively merging consecutive actions.
func SpreadActions(ac <-chan Action) <-chan Action {
last := Hold

return helper.Map(ac, func(a Action) Action {
if a != Hold && a != last {
last = a
}

return last
})
}
38 changes: 38 additions & 0 deletions strategy/action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,41 @@ func TestActionsToAnnotations(t *testing.T) {
t.Fatal(err)
}
}

func TestNormalizeActions(t *testing.T) {
actions := helper.SliceToChan([]strategy.Action{
strategy.Hold, strategy.Sell, strategy.Sell, strategy.Buy, strategy.Hold,
strategy.Buy, strategy.Buy, strategy.Sell, strategy.Sell, strategy.Buy,
})

expected := helper.SliceToChan([]strategy.Action{
strategy.Hold, strategy.Hold, strategy.Hold, strategy.Buy, strategy.Hold,
strategy.Hold, strategy.Hold, strategy.Sell, strategy.Hold, strategy.Buy,
})

actual := strategy.NormalizeActions(actions)

err := helper.CheckEquals(actual, expected)
if err != nil {
t.Fatal(err)
}
}

func TestSpreadActions(t *testing.T) {
actions := helper.SliceToChan([]strategy.Action{
strategy.Hold, strategy.Hold, strategy.Hold, strategy.Buy, strategy.Hold,
strategy.Hold, strategy.Hold, strategy.Sell, strategy.Hold, strategy.Buy,
})

expected := helper.SliceToChan([]strategy.Action{
strategy.Hold, strategy.Hold, strategy.Hold, strategy.Buy, strategy.Buy,
strategy.Buy, strategy.Buy, strategy.Sell, strategy.Sell, strategy.Buy,
})

actual := strategy.SpreadActions(actions)

err := helper.CheckEquals(actual, expected)
if err != nil {
t.Fatal(err)
}
}
12 changes: 10 additions & 2 deletions strategy/apo_strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,27 @@ func (a *ApoStrategy[T]) Compute(c <-chan T) <-chan Action {
// Report takes input channels containing dates and values, computes the recommended actions
// based on the data, and generates a report annotated with those actions.
func (a *ApoStrategy[T]) Report(dates <-chan time.Time, c <-chan T) *helper.Report {
cs := helper.Duplicate(c, 3)
cs := helper.Duplicate(c, 4)

dates = helper.Skip(dates, a.Apo.SlowPeriod-1)
cs[0] = helper.Skip(cs[0], a.Apo.SlowPeriod-1)
cs[3] = helper.Skip(cs[3], a.Apo.SlowPeriod-1)
apo := a.Apo.Compute(cs[1])
annotations := ActionsToAnnotations(a.Compute(cs[2]))

actions := helper.Duplicate(a.Compute(cs[2]), 2)
annotations := ActionsToAnnotations(actions[0])

outcome := Outcome(cs[3], actions[1])

report := helper.NewReport("APO Strategy", dates)
report.AddChart()
report.AddChart()

report.AddColumn(helper.NewNumericReportColumn("Close", cs[0]))
report.AddColumn(helper.NewNumericReportColumn("APO", apo), 1)
report.AddColumn(helper.NewAnnotationReportColumn(annotations), 0, 1)

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

return report
}
Loading

0 comments on commit 94e2768

Please sign in to comment.