Skip to content

Commit

Permalink
Triple Exponential Average (TRIX).
Browse files Browse the repository at this point in the history
  • Loading branch information
cinar committed Dec 29, 2023
1 parent e433fc7 commit 89c419e
Show file tree
Hide file tree
Showing 11 changed files with 506 additions and 15 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ The following list of indicators are currently supported by this package:
- [Since Change](helper/README.md#func-since)
- [Triple Exponential Moving Average (TEMA)](trend/README.md#type-tema)
- [Triangular Moving Average (TRIMA)](trend/README.md#type-trima)
- Triple Exponential Average (TRIX)
- [Triple Exponential Average (TRIX)](trend/README.md#type-trix)
- [Typical Price](trend/README.md#type-typicalprice)
- [Volume Weighted Moving Average (VWMA)](trend/README.md#type-vwma)
- Vortex Indicator
Expand Down
18 changes: 18 additions & 0 deletions helper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The information provided on this project is strictly for informational purposes
- [func ChanToSlice\[T any\]\(c \<\-chan T\) \[\]T](<#ChanToSlice>)
- [func Change\[T Number\]\(c \<\-chan T, before int\) \<\-chan T](<#Change>)
- [func ChangePercent\[T Number\]\(c \<\-chan T, before int\) \<\-chan T](<#ChangePercent>)
- [func ChangeRatio\[T Number\]\(c \<\-chan T, before int\) \<\-chan T](<#ChangeRatio>)
- [func CheckEquals\[T comparable\]\(inputs ...\<\-chan T\) error](<#CheckEquals>)
- [func DecrementBy\[T Number\]\(c \<\-chan T, d T\) \<\-chan T](<#DecrementBy>)
- [func Divide\[T Number\]\(ac, bc \<\-chan T\) \<\-chan T](<#Divide>)
Expand Down Expand Up @@ -244,6 +245,23 @@ actual := helper.ChangePercent(c, 2))
fmt.Println(helper.ChanToSlice(actual)) // [400, 150, 60, -60, -87.5, -50, 200, 300]
```

<a name="ChangeRatio"></a>
## func [ChangeRatio](<https://github.com/cinar/indicator/blob/v2/helper/change_ratio.go#L15>)

```go
func ChangeRatio[T Number](c <-chan T, before int) <-chan T
```

ChangeRatio calculates the ratio change between the current value and the value N positions before.

Example:

```
c := helper.ChanToSlice([]float64{1, 2, 5, 5, 8, 2, 1, 1, 3, 4})
actual := helper.ChangeRatio(c, 2))
fmt.Println(helper.ChanToSlice(actual)) // [400, 150, 60, -60, -87.5, -50, 200, 300]
```

<a name="CheckEquals"></a>
## func [CheckEquals](<https://github.com/cinar/indicator/blob/v2/helper/check.go#L14>)

Expand Down
4 changes: 1 addition & 3 deletions helper/change_percent.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,5 @@ package helper
// actual := helper.ChangePercent(c, 2))
// fmt.Println(helper.ChanToSlice(actual)) // [400, 150, 60, -60, -87.5, -50, 200, 300]
func ChangePercent[T Number](c <-chan T, before int) <-chan T {
cs := Duplicate(c, 2)
cs[1] = Buffered(cs[1], before)
return MultiplyBy(Divide(Change(cs[0], before), cs[1]), 100)
return MultiplyBy(ChangeRatio(c, before), 100)
}
19 changes: 19 additions & 0 deletions helper/change_ratio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) 2021-2023 Onur Cinar.
// The source code is provided under GNU AGPLv3 License.
// https://github.com/cinar/indicator

package helper

// ChangeRatio calculates the ratio change between the current
// value and the value N positions before.
//
// Example:
//
// c := helper.ChanToSlice([]float64{1, 2, 5, 5, 8, 2, 1, 1, 3, 4})
// actual := helper.ChangeRatio(c, 2))
// fmt.Println(helper.ChanToSlice(actual)) // [400, 150, 60, -60, -87.5, -50, 200, 300]
func ChangeRatio[T Number](c <-chan T, before int) <-chan T {
cs := Duplicate(c, 2)
cs[1] = Buffered(cs[1], before)
return Divide(Change(cs[0], before), cs[1])
}
23 changes: 23 additions & 0 deletions helper/change_ratio_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) 2021-2023 Onur Cinar.
// The source code is provided under GNU AGPLv3 License.
// https://github.com/cinar/indicator

package helper_test

import (
"testing"

"github.com/cinar/indicator/helper"
)

func TestChangeRatio(t *testing.T) {
input := helper.SliceToChan([]float64{1, 2, 5, 5, 8, 2, 1, 1, 3, 4})
expected := helper.SliceToChan([]float64{4, 1.5, 0.6, -0.6, -0.875, -0.5, 2, 3})

actual := helper.ChangeRatio(input, 2)

err := helper.CheckEquals(actual, expected)
if err != nil {
t.Fatal(err)
}
}
82 changes: 79 additions & 3 deletions trend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ The information provided on this project is strictly for informational purposes
- [func \(d \*Dema\[T\]\) IdlePeriod\(\) int](<#Dema[T].IdlePeriod>)
- [type Ema](<#Ema>)
- [func NewEma\[T helper.Number\]\(\) \*Ema\[T\]](<#NewEma>)
- [func NewEmaWithPeriod\[T helper.Number\]\(period int\) \*Ema\[T\]](<#NewEmaWithPeriod>)
- [func \(ema \*Ema\[T\]\) Compute\(c \<\-chan T\) \<\-chan T](<#Ema[T].Compute>)
- [type Kdj](<#Kdj>)
- [func NewKdj\[T helper.Number\]\(\) \*Kdj\[T\]](<#NewKdj>)
Expand Down Expand Up @@ -76,6 +77,10 @@ The information provided on this project is strictly for informational purposes
- [func NewTrima\[T helper.Number\]\(\) \*Trima\[T\]](<#NewTrima>)
- [func \(t \*Trima\[T\]\) Compute\(c \<\-chan T\) \<\-chan T](<#Trima[T].Compute>)
- [func \(t \*Trima\[T\]\) IdlePeriod\(\) int](<#Trima[T].IdlePeriod>)
- [type Trix](<#Trix>)
- [func NewTrix\[T helper.Number\]\(\) \*Trix\[T\]](<#NewTrix>)
- [func \(t \*Trix\[T\]\) Compute\(c \<\-chan T\) \<\-chan T](<#Trix[T].Compute>)
- [func \(t \*Trix\[T\]\) IdlePeriod\(\) int](<#Trix[T].IdlePeriod>)
- [type TypicalPrice](<#TypicalPrice>)
- [func NewTypicalPrice\[T helper.Number\]\(\) \*TypicalPrice\[T\]](<#NewTypicalPrice>)
- [func \(\*TypicalPrice\[T\]\) Compute\(high, low, closing \<\-chan T\) \<\-chan T](<#TypicalPrice[T].Compute>)
Expand Down Expand Up @@ -199,6 +204,15 @@ const (
)
```

<a name="DefaultTrixPeriod"></a>

```go
const (
// DefaultTrixPeriod is the default time period for TRIX.
DefaultTrixPeriod = 15
)
```

<a name="DefaultVwmaPeriod"></a>

```go
Expand Down Expand Up @@ -398,7 +412,7 @@ func (d *Dema[T]) IdlePeriod() int
IdlePeriod is the initial period that DEMA won't yield any results.

<a name="Ema"></a>
## type [Ema](<https://github.com/cinar/indicator/blob/v2/trend/ema.go#L26-L32>)
## type [Ema](<https://github.com/cinar/indicator/blob/v2/trend/ema.go#L25-L31>)

Ema represents the parameters for calculating the Exponential Moving Average.

Expand All @@ -422,16 +436,25 @@ type Ema[T helper.Number] struct {
```

<a name="NewEma"></a>
### func [NewEma](<https://github.com/cinar/indicator/blob/v2/trend/ema.go#L36>)
### func [NewEma](<https://github.com/cinar/indicator/blob/v2/trend/ema.go#L34>)

```go
func NewEma[T helper.Number]() *Ema[T]
```

NewEma function initializes a new EMA instance with the default parameters.

<a name="NewEmaWithPeriod"></a>
### func [NewEmaWithPeriod](<https://github.com/cinar/indicator/blob/v2/trend/ema.go#L42>)

```go
func NewEmaWithPeriod[T helper.Number](period int) *Ema[T]
```

NewEmaWithPeriod function initializes a new EMA instance with the given period.

<a name="Ema[T].Compute"></a>
### func \(\*Ema\[T\]\) [Compute](<https://github.com/cinar/indicator/blob/v2/trend/ema.go#L45>)
### func \(\*Ema\[T\]\) [Compute](<https://github.com/cinar/indicator/blob/v2/trend/ema.go#L50>)

```go
func (ema *Ema[T]) Compute(c <-chan T) <-chan T
Expand Down Expand Up @@ -878,6 +901,59 @@ func (t *Trima[T]) IdlePeriod() int

IdlePeriod is the initial period that TRIMA won't yield any results.

<a name="Trix"></a>
## type [Trix](<https://github.com/cinar/indicator/blob/v2/trend/trix.go#L29-L32>)

Trix represents the configuration parameters for calculating the Triple Exponential Average \(TRIX\). TRIX indicator is an oscillator used to identify oversold and overbought markets, and it can also be used as a momentum indicator. Like many oscillators, TRIX oscillates around a zero line.

```
EMA1 = EMA(period, values)
EMA2 = EMA(period, EMA1)
EMA3 = EMA(period, EMA2)
TRIX = (EMA3 - Previous EMA3) / Previous EMA3
```

Example:

```
trix := trend.NewTrix[float64]()
result := trix.Compute(values)
```

```go
type Trix[T helper.Number] struct {
// Time period.
Period int
}
```

<a name="NewTrix"></a>
### func [NewTrix](<https://github.com/cinar/indicator/blob/v2/trend/trix.go#L35>)

```go
func NewTrix[T helper.Number]() *Trix[T]
```

NewTrix function initializes a new TRIX instance with the default parameters.

<a name="Trix[T].Compute"></a>
### func \(\*Trix\[T\]\) [Compute](<https://github.com/cinar/indicator/blob/v2/trend/trix.go#L42>)

```go
func (t *Trix[T]) Compute(c <-chan T) <-chan T
```

Compute function takes a channel of numbers and computes the TRIX and the signal line.

<a name="Trix[T].IdlePeriod"></a>
### func \(\*Trix\[T\]\) [IdlePeriod](<https://github.com/cinar/indicator/blob/v2/trend/trix.go#L59>)

```go
func (t *Trix[T]) IdlePeriod() int
```

IdlePeriod is the initial period that TRIX won't yield any results.

<a name="TypicalPrice"></a>
## type [TypicalPrice](<https://github.com/cinar/indicator/blob/v2/trend/typical_price.go#L16-L17>)

Expand Down
17 changes: 11 additions & 6 deletions trend/ema.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ const (
DefaultEmaSmoothing = 2
)

// Ema represents the parameters for calculating
// the Exponential Moving Average.
// Ema represents the parameters for calculating the Exponential Moving Average.
//
// Example:
//
Expand All @@ -31,17 +30,23 @@ type Ema[T helper.Number] struct {
Smoothing T
}

// NewEma function initializes a new EMA instance
// with the default parameters.
// NewEma function initializes a new EMA instance with the default parameters.
func NewEma[T helper.Number]() *Ema[T] {
return &Ema[T]{
Period: DefaultEmaPeriod,
Smoothing: DefaultEmaSmoothing,
}
}

// Compute function takes a channel of numbers and computes the EMA
// over the specified period.
// NewEmaWithPeriod function initializes a new EMA instance with the given period.
func NewEmaWithPeriod[T helper.Number](period int) *Ema[T] {
ema := NewEma[T]()
ema.Period = period

return ema
}

// Compute function takes a channel of numbers and computes the EMA over the specified period.
func (ema *Ema[T]) Compute(c <-chan T) <-chan T {
result := make(chan T, cap(c))

Expand Down
3 changes: 1 addition & 2 deletions trend/ema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ func TestEma(t *testing.T) {
23.23, 23.08, 22.92,
}

ema := trend.NewEma[float64]()
ema.Period = 10
ema := trend.NewEmaWithPeriod[float64](10)
ema.Smoothing = 2

actual := helper.ChanToSlice(helper.RoundDigits(ema.Compute(input), 2))
Expand Down
Loading

0 comments on commit 89c419e

Please sign in to comment.