diff --git a/README.md b/README.md
index 0a0b314..82cd787 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,7 @@ The following list of indicators are currently supported by this package:
- Rolling Moving Average (RMA)
- [Simple Moving Average (SMA)](trend/README.md#type-sma)
- [Since Change](helper/README.md#func-since)
-- Triple Exponential Moving Average (TEMA)
+- [Triple Exponential Moving Average (TEMA)](trend/README.md#type-tema)
- Triangular Moving Average (TRIMA)
- Triple Exponential Average (TRIX)
- Typical Price
diff --git a/trend/README.md b/trend/README.md
index a3b874a..1055c2c 100644
--- a/trend/README.md
+++ b/trend/README.md
@@ -65,6 +65,10 @@ The information provided on this project is strictly for informational purposes
- [type Sma](<#Sma>)
- [func NewSma\[T helper.Number\]\(\) \*Sma\[T\]](<#NewSma>)
- [func \(s \*Sma\[T\]\) Compute\(c \<\-chan T\) \<\-chan T](<#Sma[T].Compute>)
+- [type Tema](<#Tema>)
+ - [func NewTema\[T helper.Number\]\(\) \*Tema\[T\]](<#NewTema>)
+ - [func \(t \*Tema\[T\]\) Compute\(c \<\-chan T\) \<\-chan T](<#Tema[T].Compute>)
+ - [func \(t \*Tema\[T\]\) IdlePeriod\(\) int](<#Tema[T].IdlePeriod>)
## Constants
@@ -691,4 +695,51 @@ func (s *Sma[T]) Compute(c <-chan T) <-chan T
Compute function takes a channel of numbers and computes the SMA over the specified period.
+
+## type [Tema]()
+
+Tema represents the configuration parameters for calculating the Triple Exponential Moving Average \(TEMA\).
+
+```
+TEMA = (3 * EMA1) - (3 * EMA2) + EMA3
+EMA1 = EMA(values)
+EMA2 = EMA(EMA1)
+EMA3 = EMA(EMA2)
+```
+
+```go
+type Tema[T helper.Number] struct {
+ Ema1 *Ema[T]
+ Ema2 *Ema[T]
+ Ema3 *Ema[T]
+}
+```
+
+
+### func [NewTema]()
+
+```go
+func NewTema[T helper.Number]() *Tema[T]
+```
+
+NewTema function initializes a new TEMA instance with the default parameters.
+
+
+### func \(\*Tema\[T\]\) [Compute]()
+
+```go
+func (t *Tema[T]) Compute(c <-chan T) <-chan T
+```
+
+Compute function takes a channel of numbers and computes the TEMA and the signal line.
+
+
+### func \(\*Tema\[T\]\) [IdlePeriod]()
+
+```go
+func (t *Tema[T]) IdlePeriod() int
+```
+
+IdlePeriod is the initial period that TEMA won't yield any results.
+
Generated by [gomarkdoc]()
diff --git a/trend/tema.go b/trend/tema.go
new file mode 100644
index 0000000..d0883cb
--- /dev/null
+++ b/trend/tema.go
@@ -0,0 +1,67 @@
+// Copyright (c) 2021-2023 Onur Cinar.
+// The source code is provided under GNU AGPLv3 License.
+// https://github.com/cinar/indicator
+
+package trend
+
+import (
+ "github.com/cinar/indicator/helper"
+)
+
+// Tema represents the configuration parameters for calculating the
+// Triple Exponential Moving Average (TEMA).
+//
+// TEMA = (3 * EMA1) - (3 * EMA2) + EMA3
+// EMA1 = EMA(values)
+// EMA2 = EMA(EMA1)
+// EMA3 = EMA(EMA2)
+type Tema[T helper.Number] struct {
+ Ema1 *Ema[T]
+ Ema2 *Ema[T]
+ Ema3 *Ema[T]
+}
+
+// NewTema function initializes a new TEMA instance
+// with the default parameters.
+func NewTema[T helper.Number]() *Tema[T] {
+ return &Tema[T]{
+ Ema1: NewEma[T](),
+ Ema2: NewEma[T](),
+ Ema3: NewEma[T](),
+ }
+}
+
+// Compute function takes a channel of numbers and computes the TEMA
+// and the signal line.
+func (t *Tema[T]) Compute(c <-chan T) <-chan T {
+ ema1 := helper.Duplicate(
+ t.Ema1.Compute(c),
+ 2,
+ )
+
+ ema2 := helper.Duplicate(
+ t.Ema2.Compute(ema1[0]),
+ 2,
+ )
+
+ ema1[1] = helper.Skip(ema1[1], t.Ema2.Period-1)
+
+ ema3 := t.Ema3.Compute(ema2[0])
+ ema1[1] = helper.Skip(ema1[1], t.Ema3.Period-1)
+ ema2[1] = helper.Skip(ema2[1], t.Ema3.Period-1)
+
+ tema := helper.Add(
+ helper.Subtract(
+ helper.MultiplyBy(ema1[1], 3),
+ helper.MultiplyBy(ema2[1], 3),
+ ),
+ ema3,
+ )
+
+ return tema
+}
+
+// IdlePeriod is the initial period that TEMA won't yield any results.
+func (t *Tema[T]) IdlePeriod() int {
+ return t.Ema1.Period + t.Ema2.Period + t.Ema3.Period - 3
+}
diff --git a/trend/tema_test.go b/trend/tema_test.go
new file mode 100644
index 0000000..a760b2c
--- /dev/null
+++ b/trend/tema_test.go
@@ -0,0 +1,40 @@
+// Copyright (c) 2021-2023 Onur Cinar.
+// The source code is provided under GNU AGPLv3 License.
+// https://github.com/cinar/indicator
+
+package trend_test
+
+import (
+ "testing"
+
+ "github.com/cinar/indicator/helper"
+ "github.com/cinar/indicator/trend"
+)
+
+func TestTema(t *testing.T) {
+ type Data struct {
+ Close float64
+ Tema float64
+ }
+
+ input, err := helper.ReadFromCsvFile[Data]("testdata/tema.csv", true)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ inputs := helper.Duplicate(input, 2)
+ closing := helper.Map(inputs[0], func(d *Data) float64 { return d.Close })
+ expected := helper.Map(inputs[1], func(d *Data) float64 { return d.Tema })
+
+ tema := trend.NewTema[float64]()
+
+ actual := tema.Compute(closing)
+ actual = helper.RoundDigits(actual, 2)
+
+ expected = helper.Skip(expected, tema.IdlePeriod())
+
+ err = helper.CheckEquals(actual, expected)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/trend/testdata/tema.csv b/trend/testdata/tema.csv
new file mode 100644
index 0000000..4ecae97
--- /dev/null
+++ b/trend/testdata/tema.csv
@@ -0,0 +1,252 @@
+Close,Tema
+318.600006,0
+315.839996,0
+316.149994,0
+310.570007,0
+307.779999,0
+305.820007,0
+305.98999,0
+306.390015,0
+311.450012,0
+312.329987,0
+309.290009,0
+301.910004,0
+300,0
+300.029999,0
+302,0
+307.820007,0
+302.690002,0
+306.48999,0
+305.549988,0
+303.429993,0
+309.059998,0
+308.899994,0
+309.910004,0
+314.549988,0
+312.899994,0
+318.690002,0
+315.529999,0
+316.350006,0
+320.369995,0
+318.929993,0
+317.640015,0
+314.859985,0
+308.299988,0
+305.230011,0
+309.869995,0
+310.420013,0
+311.299988,0
+311.899994,0
+310.950012,0
+309.170013,0
+307.329987,0
+311.519989,0
+310.570007,0
+311.859985,0
+308.51001,0
+308.429993,0
+312.970001,0
+308.480011,0
+307.209991,0
+309.890015,0
+313.73999,0
+310.790009,0
+309.630005,0
+308.179993,0
+308.23999,0
+302.720001,0
+303.160004,0
+303.070007,305.1
+304.019989,304.46
+304.660004,304.13
+305.179993,304.03
+304.619995,303.82
+307.75,304.5
+312.450012,306.29
+316.970001,308.95
+311.119995,309.61
+311.369995,310.21
+304.820007,309
+303.630005,307.68
+302.880005,306.42
+305.329987,306.02
+297.880005,303.78
+302.01001,303.03
+293.51001,300.24
+301.059998,299.94
+303.850006,300.46
+299.730011,299.85
+298.369995,299.04
+298.920013,298.55
+302.140015,299.02
+302.320007,299.49
+305.299988,300.67
+305.079987,301.61
+308.769989,303.35
+310.309998,305.19
+309.070007,306.36
+310.390015,307.66
+312.51001,309.26
+312.619995,310.57
+313.700012,311.89
+314.549988,313.16
+318.049988,315.07
+319.73999,317.02
+323.790009,319.61
+324.630005,321.88
+323.089996,323.27
+323.820007,324.52
+324.329987,325.59
+326.049988,326.83
+324.339996,327.32
+320.529999,326.64
+326.230011,327.49
+328.549988,328.71
+330.170013,330.05
+325.859985,329.95
+323.220001,329.1
+320,327.51
+323.880005,327.15
+326.140015,327.39
+324.869995,327.21
+322.98999,326.53
+322.640015,325.84
+322.48999,325.21
+323.529999,324.93
+323.75,324.74
+327.390015,325.51
+329.76001,326.73
+330.390015,327.88
+329.130005,328.46
+323.109985,327.34
+320.200012,325.65
+319.019989,323.94
+320.600006,322.94
+322.190002,322.54
+321.079987,321.93
+323.119995,321.96
+329.480011,323.65
+328.579987,324.81
+333.410004,327
+335.420013,329.31
+335.950012,331.32
+335.290009,332.75
+333.600006,333.45
+336.390015,334.71
+335.899994,335.56
+339.820007,337.23
+338.309998,338.16
+338.670013,338.95
+338.609985,339.53
+336.959991,339.52
+335.25,339.01
+334.119995,338.25
+335.339996,337.9
+334.149994,337.27
+336.910004,337.44
+341,338.61
+342,339.79
+341.559998,340.61
+341.459991,341.22
+340.899994,341.54
+341.130005,341.81
+343.369995,342.58
+345.350006,343.69
+343.540009,344.09
+341.089996,343.73
+344.25,344.22
+345.339996,344.87
+342.429993,344.61
+346.609985,345.44
+345.76001,345.87
+349.630005,347.19
+347.579987,347.7
+349.799988,348.65
+349.309998,349.26
+349.809998,349.84
+351.959991,350.84
+352.26001,351.68
+351.190002,352.05
+353.809998,352.99
+349.98999,352.71
+362.579987,355.71
+363.730011,358.41
+358.019989,359.08
+356.980011,359.29
+358.350006,359.75
+358.480011,360.1
+354.5,359.29
+354.109985,358.47
+353.190002,357.51
+352.559998,356.53
+352.089996,355.56
+350.570007,354.36
+354.26001,354.31
+354.299988,354.27
+355.929993,354.65
+355.549988,354.85
+358.290009,355.72
+361.059998,357.14
+360.200012,358.05
+362.459991,359.37
+360.470001,359.9
+361.670013,360.62
+361.799988,361.22
+363.149994,362.02
+365.519989,363.26
+367.779999,364.82
+367.820007,366.07
+369.5,367.48
+367.859985,368.16
+370.429993,369.34
+370.480011,370.25
+366.820007,370
+363.279999,368.82
+360.160004,366.99
+361.709991,365.86
+359.420013,364.32
+357.779999,362.62
+357.059998,361.03
+350.299988,357.98
+348.079987,354.92
+343.040009,351.14
+343.690002,348.27
+345.059998,346.33
+346.339996,345.16
+345.450012,344.04
+348.559998,344.01
+348.429993,344.04
+345.660004,343.42
+345.089996,342.83
+346.230011,342.72
+345.390015,342.49
+340.890015,341.19
+338.660004,339.62
+335.859985,337.68
+336.839996,336.43
+338.630005,335.95
+336.899994,335.18
+336.160004,334.45
+331.709991,332.77
+337.410004,332.95
+341.329987,334.2
+343.75,335.93
+349.019989,338.76
+351.809998,341.85
+346.630005,343.06
+346.170013,343.94
+346.299988,344.7
+348.179993,345.81
+350.559998,347.33
+350.01001,348.41
+354.25,350.38
+356.790009,352.63
+359.859985,355.22
+358.929993,357.06
+361.329987,359.12
+361,360.66
+361.799988,362.05
+362.679993,363.35
+361.339996,363.98
+360.049988,364.08
+358.690002,363.73