Skip to content

Commit b7674cf

Browse files
authored
Implement Pivot Point indicator. (#302) (#335)
This PR implements the Pivot Point indicator in the trend package. It supports Standard, Woodie, Camarilla, and Fibonacci calculation methods. The indicator uses the previous period's OHLC data to calculate support and resistance levels for the current period. Fixed #302
1 parent a180074 commit b7674cf

4 files changed

Lines changed: 398 additions & 1 deletion

File tree

trend/GEMINI.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The `trend` package provides a collection of indicators used for identifying and
66

77
- **Moving Averages:** `Sma` (Simple), `Ema` (Exponential), `Dema` (Double), `Tema` (Triple), `Wma` (Weighted), `Hma` (Hull), `Kama` (Kaufman), `Smma` (Smoothed), `Vwma` (Volume Weighted).
88
- **Oscillators:** `Apo` (Absolute Price Oscillator), `Cci` (Commodity Channel Index), `Dpo` (Detrended Price Oscillator), `Trix` (Triple Exponential Average).
9-
- **Indicators:** `Aroon` (Aroon Oscillator), `Bop` (Balance of Power), `Macd` (Moving Average Convergence Divergence), `Roc` (Rate of Change), `Tsi` (True Strength Index).
9+
- **Indicators:** `Aroon` (Aroon Oscillator), `Bop` (Balance of Power), `Macd` (Moving Average Convergence Divergence), `PivotPoint` (Standard, Woodie, Camarilla, Fibonacci), `Roc` (Rate of Change), `Tsi` (True Strength Index).
1010
- **Utilities:** `MovingMax`, `MovingMin`, `MovingSum`, `TypicalPrice`.
1111

1212
## Common Pattern

trend/README.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,14 @@ The information provided on this project is strictly for informational purposes
127127
- [func NewMovingSumWithPeriod\[T helper.Number\]\(period int\) \*MovingSum\[T\]](<#NewMovingSumWithPeriod>)
128128
- [func \(m \*MovingSum\[T\]\) Compute\(c \<\-chan T\) \<\-chan T](<#MovingSum[T].Compute>)
129129
- [func \(m \*MovingSum\[T\]\) IdlePeriod\(\) int](<#MovingSum[T].IdlePeriod>)
130+
- [type PivotPoint](<#PivotPoint>)
131+
- [func NewPivotPoint\[T helper.Float\]\(\) \*PivotPoint\[T\]](<#NewPivotPoint>)
132+
- [func NewPivotPointWithMethod\[T helper.Float\]\(method PivotPointMethod\) \*PivotPoint\[T\]](<#NewPivotPointWithMethod>)
133+
- [func \(p \*PivotPoint\[T\]\) Compute\(opens, highs, lows, closings \<\-chan T\) \<\-chan PivotPointResult\[T\]](<#PivotPoint[T].Compute>)
134+
- [func \(p \*PivotPoint\[T\]\) IdlePeriod\(\) int](<#PivotPoint[T].IdlePeriod>)
135+
- [func \(p \*PivotPoint\[T\]\) String\(\) string](<#PivotPoint[T].String>)
136+
- [type PivotPointMethod](<#PivotPointMethod>)
137+
- [type PivotPointResult](<#PivotPointResult>)
130138
- [type Rma](<#Rma>)
131139
- [func NewRma\[T helper.Number\]\(\) \*Rma\[T\]](<#NewRma>)
132140
- [func NewRmaWithPeriod\[T helper.Number\]\(period int\) \*Rma\[T\]](<#NewRmaWithPeriod>)
@@ -1790,6 +1798,109 @@ func (m *MovingSum[T]) IdlePeriod() int
17901798

17911799
IdlePeriod is the initial period that Moving Sum won't yield any results.
17921800

1801+
<a name="PivotPoint"></a>
1802+
## type [PivotPoint](<https://github.com/cinar/indicator/blob/master/trend/pivot_point.go#L47-L50>)
1803+
1804+
PivotPoint represents the configuration parameters for calculating Pivot Points. Pivot points are calculated based on the previous period's high, low, and close, and are used to predict support and resistance levels for the current period.
1805+
1806+
```go
1807+
type PivotPoint[T helper.Float] struct {
1808+
// Method is the pivot point calculation method.
1809+
Method PivotPointMethod
1810+
}
1811+
```
1812+
1813+
<a name="NewPivotPoint"></a>
1814+
### func [NewPivotPoint](<https://github.com/cinar/indicator/blob/master/trend/pivot_point.go#L53>)
1815+
1816+
```go
1817+
func NewPivotPoint[T helper.Float]() *PivotPoint[T]
1818+
```
1819+
1820+
NewPivotPoint function initializes a new Pivot Point instance with the standard method.
1821+
1822+
<a name="NewPivotPointWithMethod"></a>
1823+
### func [NewPivotPointWithMethod](<https://github.com/cinar/indicator/blob/master/trend/pivot_point.go#L58>)
1824+
1825+
```go
1826+
func NewPivotPointWithMethod[T helper.Float](method PivotPointMethod) *PivotPoint[T]
1827+
```
1828+
1829+
NewPivotPointWithMethod function initializes a new Pivot Point instance with the given method.
1830+
1831+
<a name="PivotPoint[T].Compute"></a>
1832+
### func \(\*PivotPoint\[T\]\) [Compute](<https://github.com/cinar/indicator/blob/master/trend/pivot_point.go#L67>)
1833+
1834+
```go
1835+
func (p *PivotPoint[T]) Compute(opens, highs, lows, closings <-chan T) <-chan PivotPointResult[T]
1836+
```
1837+
1838+
Compute function takes channels for open, high, low, and closing prices and returns a channel of PivotPointResult. It uses the values from the previous period to calculate levels for the current period.
1839+
1840+
<a name="PivotPoint[T].IdlePeriod"></a>
1841+
### func \(\*PivotPoint\[T\]\) [IdlePeriod](<https://github.com/cinar/indicator/blob/master/trend/pivot_point.go#L150>)
1842+
1843+
```go
1844+
func (p *PivotPoint[T]) IdlePeriod() int
1845+
```
1846+
1847+
IdlePeriod is the initial period that Pivot Point won't yield any results.
1848+
1849+
<a name="PivotPoint[T].String"></a>
1850+
### func \(\*PivotPoint\[T\]\) [String](<https://github.com/cinar/indicator/blob/master/trend/pivot_point.go#L155>)
1851+
1852+
```go
1853+
func (p *PivotPoint[T]) String() string
1854+
```
1855+
1856+
String is the string representation of the Pivot Point instance.
1857+
1858+
<a name="PivotPointMethod"></a>
1859+
## type [PivotPointMethod](<https://github.com/cinar/indicator/blob/master/trend/pivot_point.go#L14>)
1860+
1861+
PivotPointMethod represents the method used for calculating pivot points.
1862+
1863+
```go
1864+
type PivotPointMethod int
1865+
```
1866+
1867+
<a name="PivotPointStandard"></a>
1868+
1869+
```go
1870+
const (
1871+
// PivotPointStandard is the standard pivot point calculation.
1872+
PivotPointStandard PivotPointMethod = iota
1873+
1874+
// PivotPointWoodie is the Woodie pivot point calculation.
1875+
PivotPointWoodie
1876+
1877+
// PivotPointCamarilla is the Camarilla pivot point calculation.
1878+
PivotPointCamarilla
1879+
1880+
// PivotPointFibonacci is the Fibonacci pivot point calculation.
1881+
PivotPointFibonacci
1882+
)
1883+
```
1884+
1885+
<a name="PivotPointResult"></a>
1886+
## type [PivotPointResult](<https://github.com/cinar/indicator/blob/master/trend/pivot_point.go#L32-L42>)
1887+
1888+
PivotPointResult represents the result of the pivot point calculation, including the pivot point itself, and its associated resistance \(R\) and support \(S\) levels.
1889+
1890+
```go
1891+
type PivotPointResult[T helper.Float] struct {
1892+
P T
1893+
R1 T
1894+
R2 T
1895+
R3 T
1896+
R4 T
1897+
S1 T
1898+
S2 T
1899+
S3 T
1900+
S4 T
1901+
}
1902+
```
1903+
17931904
<a name="Rma"></a>
17941905
## type [Rma](<https://github.com/cinar/indicator/blob/master/trend/rma.go#L25-L28>)
17951906

trend/pivot_point.go

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// Copyright (c) 2021-2026 Onur Cinar.
2+
// The source code is provided under GNU AGPLv3 License.
3+
// https://github.com/cinar/indicator
4+
5+
package trend
6+
7+
import (
8+
"fmt"
9+
10+
"github.com/cinar/indicator/v2/helper"
11+
)
12+
13+
// PivotPointMethod represents the method used for calculating pivot points.
14+
type PivotPointMethod int
15+
16+
const (
17+
// PivotPointStandard is the standard pivot point calculation.
18+
PivotPointStandard PivotPointMethod = iota
19+
20+
// PivotPointWoodie is the Woodie pivot point calculation.
21+
PivotPointWoodie
22+
23+
// PivotPointCamarilla is the Camarilla pivot point calculation.
24+
PivotPointCamarilla
25+
26+
// PivotPointFibonacci is the Fibonacci pivot point calculation.
27+
PivotPointFibonacci
28+
)
29+
30+
// PivotPointResult represents the result of the pivot point calculation, including
31+
// the pivot point itself, and its associated resistance (R) and support (S) levels.
32+
type PivotPointResult[T helper.Float] struct {
33+
P T
34+
R1 T
35+
R2 T
36+
R3 T
37+
R4 T
38+
S1 T
39+
S2 T
40+
S3 T
41+
S4 T
42+
}
43+
44+
// PivotPoint represents the configuration parameters for calculating Pivot Points.
45+
// Pivot points are calculated based on the previous period's high, low, and close,
46+
// and are used to predict support and resistance levels for the current period.
47+
type PivotPoint[T helper.Float] struct {
48+
// Method is the pivot point calculation method.
49+
Method PivotPointMethod
50+
}
51+
52+
// NewPivotPoint function initializes a new Pivot Point instance with the standard method.
53+
func NewPivotPoint[T helper.Float]() *PivotPoint[T] {
54+
return NewPivotPointWithMethod[T](PivotPointStandard)
55+
}
56+
57+
// NewPivotPointWithMethod function initializes a new Pivot Point instance with the given method.
58+
func NewPivotPointWithMethod[T helper.Float](method PivotPointMethod) *PivotPoint[T] {
59+
return &PivotPoint[T]{
60+
Method: method,
61+
}
62+
}
63+
64+
// Compute function takes channels for open, high, low, and closing prices and
65+
// returns a channel of PivotPointResult. It uses the values from the previous
66+
// period to calculate levels for the current period.
67+
func (p *PivotPoint[T]) Compute(opens, highs, lows, closings <-chan T) <-chan PivotPointResult[T] {
68+
result := make(chan PivotPointResult[T], cap(closings))
69+
70+
go func() {
71+
defer close(result)
72+
73+
var prevH, prevL, prevC T
74+
first := true
75+
76+
for {
77+
o, okO := <-opens
78+
h, okH := <-highs
79+
l, okL := <-lows
80+
c, okC := <-closings
81+
82+
if !okO || !okH || !okL || !okC {
83+
break
84+
}
85+
86+
if !first {
87+
result <- p.calculate(prevH, prevL, prevC, o)
88+
}
89+
90+
prevH, prevL, prevC = h, l, c
91+
first = false
92+
}
93+
}()
94+
95+
return result
96+
}
97+
98+
// calculate calculates the pivot points using the specified method.
99+
func (p *PivotPoint[T]) calculate(h, l, c, currO T) PivotPointResult[T] {
100+
var res PivotPointResult[T]
101+
102+
switch p.Method {
103+
case PivotPointStandard:
104+
res.P = (h + l + c) / 3
105+
res.R1 = 2*res.P - l
106+
res.S1 = 2*res.P - h
107+
res.R2 = res.P + (h - l)
108+
res.S2 = res.P - (h - l)
109+
res.R3 = h + 2*(res.P-l)
110+
res.S3 = l - 2*(h-res.P)
111+
res.R4 = h + 3*(res.P-l)
112+
res.S4 = l - 3*(h-res.P)
113+
114+
case PivotPointWoodie:
115+
res.P = (h + l + 2*currO) / 4
116+
res.R1 = 2*res.P - l
117+
res.S1 = 2*res.P - h
118+
res.R2 = res.P + (h - l)
119+
res.S2 = res.P - (h - l)
120+
res.R3 = h + 2*(res.P-l)
121+
res.S3 = l - 2*(h-res.P)
122+
123+
case PivotPointCamarilla:
124+
diff := h - l
125+
res.P = (h + l + c) / 3
126+
res.R1 = c + diff*T(1.1)/12
127+
res.R2 = c + diff*T(1.1)/6
128+
res.R3 = c + diff*T(1.1)/4
129+
res.R4 = c + diff*T(1.1)/2
130+
res.S1 = c - diff*T(1.1)/12
131+
res.S2 = c - diff*T(1.1)/6
132+
res.S3 = c - diff*T(1.1)/4
133+
res.S4 = c - diff*T(1.1)/2
134+
135+
case PivotPointFibonacci:
136+
diff := h - l
137+
res.P = (h + l + c) / 3
138+
res.R1 = res.P + diff*T(0.382)
139+
res.S1 = res.P - diff*T(0.382)
140+
res.R2 = res.P + diff*T(0.618)
141+
res.S2 = res.P - diff*T(0.618)
142+
res.R3 = res.P + diff*T(1.000)
143+
res.S3 = res.P - diff*T(1.000)
144+
}
145+
146+
return res
147+
}
148+
149+
// IdlePeriod is the initial period that Pivot Point won't yield any results.
150+
func (p *PivotPoint[T]) IdlePeriod() int {
151+
return 1
152+
}
153+
154+
// String is the string representation of the Pivot Point instance.
155+
func (p *PivotPoint[T]) String() string {
156+
var methodStr string
157+
switch p.Method {
158+
case PivotPointStandard:
159+
methodStr = "Standard"
160+
case PivotPointWoodie:
161+
methodStr = "Woodie"
162+
case PivotPointCamarilla:
163+
methodStr = "Camarilla"
164+
case PivotPointFibonacci:
165+
methodStr = "Fibonacci"
166+
}
167+
return fmt.Sprintf("PivotPoint(%s)", methodStr)
168+
}

0 commit comments

Comments
 (0)