-
-
Notifications
You must be signed in to change notification settings - Fork 111
/
Copy pathtsi.go
101 lines (85 loc) · 2.59 KB
/
tsi.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// 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/helper"
)
const (
// DefaultTsiFirstSmoothingPeriod is the default first smoothing period of 25.
DefaultTsiFirstSmoothingPeriod = 25
// DefaultTsiSecondSmoothingPeriod is the default second smoothing period of 13.
DefaultTsiSecondSmoothingPeriod = 13
)
// Tsi represents the parameters needed to calculate the True Strength Index (TSI). It is a technical momentum
// oscillator used in financial analysis. The TSI helps identify trends and potential trend reversals.
//
// PCDS = Ema(13, Ema(25, (Current - Prior)))
// APCDS = Ema(13, Ema(25, Abs(Current - Prior)))
// TSI = (PCDS / APCDS) * 100
//
// Example:
//
// tsi := trend.NewTsi[float64]()
// result := tsi.Compute(closings)
type Tsi[T helper.Number] struct {
// FirstSmoothing is the first smoothing moving average.
FirstSmoothing Ma[T]
// SecondSmoothing is the second smoothing moving average.
SecondSmoothing Ma[T]
}
// NewTsi function initializes a new TSI instance with the default parameters.
func NewTsi[T helper.Number]() *Tsi[T] {
return NewTsiWith[T](
DefaultTsiFirstSmoothingPeriod,
DefaultTsiSecondSmoothingPeriod,
)
}
// NewTsiWith function initializes a new TSI instance with the given parameters.
func NewTsiWith[T helper.Number](firstSmoothingPeriod, secondSmoothingPeriod int) *Tsi[T] {
return &Tsi[T]{
FirstSmoothing: NewEmaWithPeriod[T](firstSmoothingPeriod),
SecondSmoothing: NewEmaWithPeriod[T](secondSmoothingPeriod),
}
}
// Compute function takes a channel of numbers and computes the TSI over the specified period.
func (t *Tsi[T]) Compute(closings <-chan T) <-chan T {
// Price change
pcsSplice := helper.Duplicate(
helper.Change(closings, 1),
2,
)
// PCDS = Ema(13, Ema(25, (Current - Prior)))
pcds := t.FirstSmoothing.Compute(
t.SecondSmoothing.Compute(
pcsSplice[0],
),
)
// APCDS = Ema(13, Ema(25, Abs(Current - Prior)))
apcds := t.FirstSmoothing.Compute(
t.SecondSmoothing.Compute(
helper.Abs(pcsSplice[1]),
),
)
// TSI = (PCDS / APCDS) * 100
tsi := helper.MultiplyBy(
helper.Divide(
pcds,
apcds,
),
T(100),
)
return tsi
}
// IdlePeriod is the initial period that TSI yield any results.
func (t *Tsi[T]) IdlePeriod() int {
return t.FirstSmoothing.IdlePeriod() + t.SecondSmoothing.IdlePeriod() + 1
}
// String is the string representation of the TSI.
func (t *Tsi[T]) String() string {
return fmt.Sprintf("TSI(%s,%s)",
t.FirstSmoothing.String(),
t.SecondSmoothing.String(),
)
}