Skip to content

Commit f88c34e

Browse files
committed
Add bollinger bands and atr
1 parent 0664e80 commit f88c34e

File tree

8 files changed

+336
-59
lines changed

8 files changed

+336
-59
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,5 @@ bumpversion.egg-info/
144144

145145
.vscode/
146146

147-
test.ipynb
147+
test.ipynb
148+
/resources

README.md

Lines changed: 168 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# PyIndicators
22

3-
PyIndicators is a powerful and user-friendly Python library for technical analysis indicators, metrics and helper functions. Written entirely in Python, it requires no external dependencies, ensuring seamless integration and ease of use.
3+
PyIndicators is a powerful and user-friendly Python library for financial technical analysis indicators, metrics and helper functions. Written entirely in Python, it requires no external dependencies, ensuring seamless integration and ease of use.
44

55
## Sponsors
66

@@ -29,13 +29,16 @@ pip install pyindicators
2929
* [Weighted Moving Average (WMA)](#weighted-moving-average-wma)
3030
* [Simple Moving Average (SMA)](#simple-moving-average-sma)
3131
* [Exponential Moving Average (EMA)](#exponential-moving-average-ema)
32-
* [Stochastic Oscillator (STO)](#stochastic-oscillator-sto)
33-
* [Momentum indicators](#momentum-indicators)
32+
* [Momentum and Oscillators](#momentum-and-oscillators)
3433
* [Moving Average Convergence Divergence (MACD)](#moving-average-convergence-divergence-macd)
3534
* [Relative Strength Index (RSI)](#relative-strength-index-rsi)
3635
* [Relative Strength Index Wilders method (Wilders RSI)](#wilders-relative-strength-index-wilders-rsi)
3736
* [Williams %R](#williams-r)
3837
* [Average Directional Index (ADX)](#average-directional-index-adx)
38+
* [Stochastic Oscillator (STO)](#stochastic-oscillator-sto)
39+
* [Volatility indicators](#volatility-indicators)
40+
* [Bollinger Bands (BB)](#bollinger-bands-bb)
41+
* [Average True Range (ATR)](#average-true-range-atr)
3942
* [Pattern recognition](#pattern-recognition)
4043
* [Detect Peaks](#detect-peaks)
4144
* [Detect Bullish Divergence](#detect-bullish-divergence)
@@ -208,57 +211,7 @@ pd_df.tail(10)
208211

209212
![EMA](https://github.com/coding-kitties/PyIndicators/blob/main/static/images/indicators/ema.png)
210213

211-
#### Stochastic Oscillator (STO)
212-
The Stochastic Oscillator (STO) is a momentum indicator that compares a particular closing price of an asset to a range of its prices over a certain period. It is used to identify overbought or oversold conditions in a market. The STO consists of two lines: %K and %D, where %K is the main line and %D is the signal line.
213-
214-
```python
215-
def stochastic_oscillator(
216-
data: Union[pd.DataFrame, pl.DataFrame],
217-
high_column: str = "High",
218-
low_column: str = "Low",
219-
close_column: str = "Close",
220-
k_period: int = 14,
221-
k_slowing: int = 3,
222-
d_period: int = 3,
223-
result_column: Optional[str] = None
224-
) -> Union[pd.DataFrame, pl.DataFrame]:
225-
```
226-
227-
Example
228-
229-
```python
230-
from investing_algorithm_framework import download
231-
from pyindicators import stochastic_oscillator
232-
pl_df = download(
233-
symbol="btc/eur",
234-
market="binance",
235-
time_frame="1d",
236-
start_date="2023-12-01",
237-
end_date="2023-12-25",
238-
save=True,
239-
storage_path="./data"
240-
)
241-
pd_df = download(
242-
symbol="btc/eur",
243-
market="binance",
244-
time_frame="1d",
245-
start_date="2023-12-01",
246-
end_date="2023-12-25",
247-
pandas=True,
248-
save=True,
249-
storage_path="./data"
250-
)
251-
# Calculate Stochastic Oscillator for Polars DataFrame
252-
pl_df = stochastic_oscillator(pl_df, high_column="High", low_column="Low", close_column="Close", k_period=14, k_slowing=3, d_period=3, result_column="STO")
253-
pl_df.show(10)
254-
# Calculate Stochastic Oscillator for Pandas DataFrame
255-
pd_df = stochastic_oscillator(pd_df, high_column="High", low_column="Low", close_column="Close", k_period=14, k_slowing=3, d_period=3, result_column="STO")
256-
pd_df.tail(10)
257-
```
258-
259-
![STO](https://github.com/coding-kitties/PyIndicators/blob/main/static/images/indicators/sto.png)
260-
261-
### Momentum Indicators
214+
### Momentum and Oscillators
262215

263216
Indicators that measure the strength and speed of price movements rather than the direction.
264217

@@ -528,6 +481,167 @@ pd_df.tail(10)
528481

529482
![ADX](https://github.com/coding-kitties/PyIndicators/blob/main/static/images/indicators/adx.png)
530483

484+
#### Stochastic Oscillator (STO)
485+
The Stochastic Oscillator (STO) is a momentum indicator that compares a particular closing price of an asset to a range of its prices over a certain period. It is used to identify overbought or oversold conditions in a market. The STO consists of two lines: %K and %D, where %K is the main line and %D is the signal line.
486+
487+
```python
488+
def stochastic_oscillator(
489+
data: Union[pd.DataFrame, pl.DataFrame],
490+
high_column: str = "High",
491+
low_column: str = "Low",
492+
close_column: str = "Close",
493+
k_period: int = 14,
494+
k_slowing: int = 3,
495+
d_period: int = 3,
496+
result_column: Optional[str] = None
497+
) -> Union[pd.DataFrame, pl.DataFrame]:
498+
```
499+
500+
Example
501+
502+
```python
503+
from investing_algorithm_framework import download
504+
from pyindicators import stochastic_oscillator
505+
pl_df = download(
506+
symbol="btc/eur",
507+
market="binance",
508+
time_frame="1d",
509+
start_date="2023-12-01",
510+
end_date="2023-12-25",
511+
save=True,
512+
storage_path="./data"
513+
)
514+
pd_df = download(
515+
symbol="btc/eur",
516+
market="binance",
517+
time_frame="1d",
518+
start_date="2023-12-01",
519+
end_date="2023-12-25",
520+
pandas=True,
521+
save=True,
522+
storage_path="./data"
523+
)
524+
# Calculate Stochastic Oscillator for Polars DataFrame
525+
pl_df = stochastic_oscillator(pl_df, high_column="High", low_column="Low", close_column="Close", k_period=14, k_slowing=3, d_period=3, result_column="STO")
526+
pl_df.show(10)
527+
# Calculate Stochastic Oscillator for Pandas DataFrame
528+
pd_df = stochastic_oscillator(pd_df, high_column="High", low_column="Low", close_column="Close", k_period=14, k_slowing=3, d_period=3, result_column="STO")
529+
pd_df.tail(10)
530+
```
531+
532+
![STO](https://github.com/coding-kitties/PyIndicators/blob/main/static/images/indicators/sto.png)
533+
534+
### Volatility indicators
535+
536+
Indicators that measure the rate of price movement, regardless of direction. They help to identify
537+
periods of high and low volatility in the market.
538+
539+
#### Bollinger Bands (BB)
540+
541+
Bollinger Bands are a volatility indicator that consists of a middle band (SMA) and two outer bands (standard deviations). They help traders identify overbought and oversold conditions.
542+
543+
```python
544+
def bollinger_bands(
545+
data: Union[PdDataFrame, PlDataFrame],
546+
source_column='Close',
547+
period=20,
548+
std_dev=2,
549+
middle_band_column_result_column='bollinger_middle',
550+
upper_band_column_result_column='bollinger_upper',
551+
lower_band_column_result_column='bollinger_lower'
552+
) -> Union[PdDataFrame, PlDataFrame]:
553+
```
554+
555+
Example
556+
557+
```python
558+
from investing_algorithm_framework import download
559+
560+
from pyindicators import ema
561+
562+
pl_df = download(
563+
symbol="btc/eur",
564+
market="binance",
565+
time_frame="1d",
566+
start_date="2023-12-01",
567+
end_date="2023-12-25",
568+
save=True,
569+
storage_path="./data"
570+
)
571+
pd_df = download(
572+
symbol="btc/eur",
573+
market="binance",
574+
time_frame="1d",
575+
start_date="2023-12-01",
576+
end_date="2023-12-25",
577+
pandas=True,
578+
save=True,
579+
storage_path="./data"
580+
)
581+
582+
# Calculate bollinger bands for Polars DataFrame
583+
pl_df = bollinger_bands(pl_df, source_column="Close")
584+
pl_df.show(10)
585+
586+
# Calculate bollinger bands for Pandas DataFrame
587+
pd_df = bollinger_bands(pd_df, source_column="Close")
588+
pd_df.tail(10)
589+
```
590+
591+
![BOLLINGER_BANDS](https://github.com/coding-kitties/PyIndicators/blob/main/static/images/indicators/bollinger_bands.png)
592+
593+
#### Average True Range (ATR)
594+
595+
The Average True Range (ATR) is a volatility indicator that measures the average range between the high and low prices over a specified period. It helps traders identify potential price fluctuations and adjust their strategies accordingly.
596+
597+
```python
598+
def atr(
599+
data: Union[PdDataFrame, PlDataFrame],
600+
source_column="Close",
601+
period=14,
602+
result_column="ATR"
603+
) -> Union[PdDataFrame, PlDataFrame]:
604+
```
605+
606+
Example
607+
608+
```python
609+
from investing_algorithm_framework import download
610+
611+
from pyindicators import ema
612+
613+
pl_df = download(
614+
symbol="btc/eur",
615+
market="binance",
616+
time_frame="1d",
617+
start_date="2023-12-01",
618+
end_date="2023-12-25",
619+
save=True,
620+
storage_path="./data"
621+
)
622+
pd_df = download(
623+
symbol="btc/eur",
624+
market="binance",
625+
time_frame="1d",
626+
start_date="2023-12-01",
627+
end_date="2023-12-25",
628+
pandas=True,
629+
save=True,
630+
storage_path="./data"
631+
)
632+
633+
# Calculate average true range for Polars DataFrame
634+
pl_df = atr(pl_df, source_column="Close")
635+
pl_df.show(10)
636+
637+
# Calculate average true range for Pandas DataFrame
638+
pd_df = atr(pd_df, source_column="Close")
639+
pd_df.tail(10)
640+
```
641+
642+
![ATR](https://github.com/coding-kitties/PyIndicators/blob/main/static/images/indicators/atr.png)
643+
644+
531645
### Pattern Recognition
532646

533647
#### Detect Peaks

pyindicators/__init__.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from .indicators import sma, rsi, ema, wilders_rsi, adx, \
22
crossover, is_crossover, wma, macd, willr, is_crossunder, crossunder, \
3-
is_lower_low_detected, is_divergence, \
3+
is_lower_low_detected, is_divergence, bollinger_width, \
44
is_below, is_above, get_slope, has_any_higher_then_threshold, \
55
has_slope_above_threshold, has_any_lower_then_threshold, \
66
has_values_above_threshold, has_values_below_threshold, is_down_trend, \
7-
is_up_trend, up_and_downtrends, detect_peaks, \
7+
is_up_trend, up_and_downtrends, detect_peaks, atr, bollinger_bands, \
88
bearish_divergence, bullish_divergence, stochastic_oscillator, \
99
bearish_divergence_multi_dataframe, bullish_divergence_multi_dataframe
1010
from .exceptions import PyIndicatorException
@@ -44,5 +44,8 @@
4444
'is_divergence',
4545
'stochastic_oscillator',
4646
'bearish_divergence_multi_dataframe',
47-
'bullish_divergence_multi_dataframe'
47+
'bullish_divergence_multi_dataframe',
48+
'bollinger_bands',
49+
'bollinger_width',
50+
'atr'
4851
]

pyindicators/indicators/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
bullish_divergence, bearish_divergence_multi_dataframe, \
2020
bullish_divergence_multi_dataframe
2121
from .stochastic_oscillator import stochastic_oscillator
22+
from .average_true_range import atr
23+
from .bollinger_bands import bollinger_bands, bollinger_width
2224

2325
__all__ = [
2426
'sma',
@@ -52,5 +54,8 @@
5254
'is_divergence',
5355
'stochastic_oscillator',
5456
'bearish_divergence_multi_dataframe',
55-
'bullish_divergence_multi_dataframe'
57+
'bullish_divergence_multi_dataframe',
58+
'atr',
59+
'bollinger_bands',
60+
'bollinger_width'
5661
]
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from typing import Union
2+
3+
from pandas import DataFrame as PdDataFrame
4+
from polars import DataFrame as PlDataFrame
5+
import polars as pl
6+
import pandas as pd
7+
8+
from pyindicators.exceptions import PyIndicatorException
9+
10+
11+
def atr(
12+
data: Union[PdDataFrame, PlDataFrame],
13+
source_column="Close",
14+
period=14,
15+
result_column="ATR"
16+
) -> Union[PdDataFrame, PlDataFrame]:
17+
"""
18+
Calculate the Average True Range (ATR) for a given dataset.
19+
20+
Parameters:
21+
data (Union[PdDataFrame, PlDataFrame]): The input data
22+
containing OHLC prices.
23+
source_column (str): The column to use as the source
24+
for ATR calculation.
25+
period (int): The number of periods to use for the ATR calculation.
26+
27+
Returns:
28+
Union[PdDataFrame, PlDataFrame]: The calculated ATR values
29+
contained in a DataFrame.
30+
"""
31+
if isinstance(data, PdDataFrame):
32+
high = data['High']
33+
low = data['Low']
34+
close = data[source_column]
35+
36+
tr = pd.concat([
37+
high - low,
38+
(high - close.shift(1)).abs(),
39+
(low - close.shift(1)).abs()
40+
], axis=1).max(axis=1)
41+
42+
atr = tr.rolling(window=period, min_periods=1).mean()
43+
data[result_column] = atr
44+
return data
45+
46+
elif isinstance(data, PlDataFrame):
47+
# Polars version
48+
df = data.with_columns([
49+
(pl.col("High") - pl.col("Low")).alias("H_L"),
50+
(pl.col("High") - pl.col(source_column).shift(1)).abs().alias("H_Cp"),
51+
(pl.col("Low") - pl.col(source_column).shift(1)).abs().alias("L_Cp"),
52+
])
53+
54+
# True Range = max of H-L, H-Cprev, L-Cprev
55+
df = df.with_columns([
56+
pl.max_horizontal(["H_L", "H_Cp", "L_Cp"]).alias("TR")
57+
])
58+
59+
# Rolling mean ATR
60+
df = df.with_columns([
61+
pl.col("TR").rolling_mean(window_size=period).alias(result_column)
62+
])
63+
64+
return df.drop(["H_L", "H_Cp", "L_Cp"]) # optional cleanup
65+
66+
else:
67+
raise PyIndicatorException(
68+
"Input data must be a pandas or polars DataFrame."
69+
)

0 commit comments

Comments
 (0)