Skip to content

Commit 7c67bf1

Browse files
committed
Add crossunder indicator
1 parent ceae32b commit 7c67bf1

File tree

6 files changed

+338
-64
lines changed

6 files changed

+338
-64
lines changed

README.md

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ pip install pyindicators
3737
* [Indicator helpers](#indicator-helpers)
3838
* [Crossover](#crossover)
3939
* [Is Crossover](#is-crossover)
40+
* [Crossunder](#crossunder)
41+
* [Is Crossunder](#is-crossunder)
4042

4143
## Indicators
4244

@@ -207,6 +209,19 @@ pd_df.tail(10)
207209

208210
#### Relative Strength Index (RSI)
209211

212+
The Relative Strength Index (RSI) is a momentum oscillator that measures the speed and change of price movements. It moves between 0 and 100 and is used to identify overbought or oversold conditions in a market.
213+
214+
```python
215+
def rsi(
216+
data: Union[pd.DataFrame, pl.DataFrame],
217+
source_column: str,
218+
period: int = 14,
219+
result_column: str = None,
220+
) -> Union[pd.DataFrame, pl.DataFrame]:
221+
```
222+
223+
Example
224+
210225
```python
211226
from investing_algorithm_framework import CSVOHLCVMarketDataSource
212227

@@ -232,6 +247,19 @@ pd_df.tail(10)
232247

233248
#### Wilders Relative Strength Index (Wilders RSI)
234249

250+
The Wilders Relative Strength Index (RSI) is a momentum oscillator that measures the speed and change of price movements. It moves between 0 and 100 and is used to identify overbought or oversold conditions in a market. The Wilders RSI uses a different calculation method than the standard RSI.
251+
252+
```python
253+
def wilders_rsi(
254+
data: Union[pd.DataFrame, pl.DataFrame],
255+
source_column: str,
256+
period: int = 14,
257+
result_column: str = None,
258+
) -> Union[pd.DataFrame, pl.DataFrame]:
259+
```
260+
261+
Example
262+
235263
```python
236264
from investing_algorithm_framework import CSVOHLCVMarketDataSource
237265

@@ -259,7 +287,6 @@ pd_df.tail(10)
259287

260288
Williams %R (Williams Percent Range) is a momentum indicator used in technical analysis to measure overbought and oversold conditions in a market. It moves between 0 and -100 and helps traders identify potential reversal points.
261289

262-
263290
```python
264291
def willr(
265292
data: Union[pd.DataFrame, pl.DataFrame],
@@ -300,6 +327,21 @@ pd_df.tail(10)
300327

301328
#### Crossover
302329

330+
The crossover function is used to calculate the crossover between two columns in a DataFrame. It returns a new DataFrame with an additional column that contains the crossover values. A crossover occurs when the first column crosses above or below the second column. This can happen in two ways, a strict crossover or a non-strict crossover. In a strict crossover, the first column must cross above or below the second column. In a non-strict crossover, the first column must cross above or below the second column, but the values can be equal.
331+
332+
```python
333+
def crossover(
334+
data: Union[PdDataFrame, PlDataFrame],
335+
first_column: str,
336+
second_column: str,
337+
result_column="crossover",
338+
data_points: int = None,
339+
strict: bool = True,
340+
) -> Union[PdDataFrame, PlDataFrame]:
341+
```
342+
343+
Example
344+
303345
```python
304346
from polars import DataFrame as plDataFrame
305347
from pandas import DataFrame as pdDataFrame
@@ -341,6 +383,21 @@ pd_df.tail(10)
341383

342384
#### Is Crossover
343385

386+
The is_crossover function is used to determine if a crossover occurred in the last N data points. It returns a boolean value indicating if a crossover occurred in the last N data points. The function can be used to check for crossovers in a DataFrame that was previously calculated using the crossover function.
387+
388+
```python
389+
def is_crossover(
390+
data: Union[PdDataFrame, PlDataFrame],
391+
first_column: str = None,
392+
second_column: str = None,
393+
crossover_column: str = None,
394+
number_of_data_points: int = None,
395+
strict=True,
396+
) -> bool:
397+
```
398+
399+
Example
400+
344401
```python
345402
from polars import DataFrame as plDataFrame
346403
from pandas import DataFrame as pdDataFrame
@@ -395,3 +452,125 @@ if is_crossover(
395452
if is_crossover(pd_df, crossover_column="Crossover_EMA", data_points=3):
396453
print("Crossover detected in Pandas DataFrame in the last 3 data points")
397454
```
455+
456+
#### Crossunder
457+
458+
The crossunder function is used to calculate the crossunder between two columns in a DataFrame. It returns a new DataFrame with an additional column that contains the crossunder values. A crossunder occurs when the first column crosses below the second column. This can happen in two ways, a strict crossunder or a non-strict crossunder. In a strict crossunder, the first column must cross below the second column. In a non-strict crossunder, the first column must cross below the second column, but the values can be equal.
459+
460+
```python
461+
def crossunder(
462+
data: Union[PdDataFrame, PlDataFrame],
463+
first_column: str,
464+
second_column: str,
465+
result_column="crossunder",
466+
data_points: int = None,
467+
strict: bool = True,
468+
) -> Union[PdDataFrame, PlDataFrame]:
469+
```
470+
471+
Example
472+
473+
```python
474+
from polars import DataFrame as plDataFrame
475+
from pandas import DataFrame as pdDataFrame
476+
477+
from investing_algorithm_framework import CSVOHLCVMarketDataSource
478+
from pyindicators import crossunder, ema
479+
480+
# For this example the investing algorithm framework is used for dataframe creation,
481+
csv_path = "./tests/test_data/OHLCV_BTC-EUR_BINANCE_15m_2023-12-01:00:00_2023-12-25:00:00.csv"
482+
data_source = CSVOHLCVMarketDataSource(csv_file_path=csv_path)
483+
484+
pl_df = data_source.get_data()
485+
pd_df = data_source.get_data(pandas=True)
486+
487+
# Calculate EMA and crossunder for Polars DataFrame
488+
pl_df = ema(pl_df, source_column="Close", period=200, result_column="EMA_200")
489+
pl_df = ema(pl_df, source_column="Close", period=50, result_column="EMA_50")
490+
pl_df = crossunder(
491+
pl_df,
492+
first_column="EMA_50",
493+
second_column="EMA_200",
494+
result_column="Crossunder_EMA"
495+
)
496+
pl_df.show(10)
497+
498+
# Calculate EMA and crossunder for Pandas DataFrame
499+
pd_df = ema(pd_df, source_column="Close", period=200, result_column="EMA_200")
500+
pd_df = ema(pd_df, source_column="Close", period=50, result_column="EMA_50")
501+
pd_df = crossunder(
502+
pd_df,
503+
first_column="EMA_50",
504+
second_column="EMA_200",
505+
result_column="Crossunder_EMA"
506+
)
507+
pd_df.tail(10)
508+
```
509+
510+
![CROSSUNDER](https://github.com/coding-kitties/PyIndicators/blob/main/static/images/indicators/crossunder.png)
511+
512+
#### Is Crossunder
513+
514+
The is_crossunder function is used to determine if a crossunder occurred in the last N data points. It returns a boolean value indicating if a crossunder occurred in the last N data points. The function can be used to check for crossunders in a DataFrame that was previously calculated using the crossunder function.
515+
516+
```python
517+
def is_crossunder(
518+
data: Union[PdDataFrame, PlDataFrame],
519+
first_column: str = None,
520+
second_column: str = None,
521+
crossunder_column: str = None,
522+
number_of_data_points: int = None,
523+
strict: bool = True,
524+
) -> bool:
525+
```
526+
527+
Example
528+
529+
```python
530+
from polars import DataFrame as plDataFrame
531+
from pandas import DataFrame as pdDataFrame
532+
533+
from investing_algorithm_framework import CSVOHLCVMarketDataSource
534+
from pyindicators import crossunder, ema, is_crossunder
535+
536+
# For this example the investing algorithm framework is used for dataframe creation,
537+
csv_path = "./tests/test_data/OHLCV_BTC-EUR_BINANCE_15m_2023-12-01:00:00_2023-12-25:00:00.csv"
538+
data_source = CSVOHLCVMarketDataSource(csv_file_path=csv_path)
539+
540+
pl_df = data_source.get_data()
541+
pd_df = data_source.get_data(pandas=True)
542+
543+
# Calculate EMA and crossunders for Polars DataFrame
544+
pl_df = ema(pl_df, source_column="Close", period=200, result_column="EMA_200")
545+
pl_df = ema(pl_df, source_column="Close", period=50, result_column="EMA_50")
546+
pl_df = crossunder(
547+
pl_df,
548+
first_column="EMA_50",
549+
second_column="EMA_200",
550+
result_column="Crossunder_EMA"
551+
)
552+
553+
# If you want the function to calculate the crossunders in the function
554+
if is_crossunder(
555+
pl_df, first_column="EMA_50", second_column="EMA_200", data_points=3
556+
):
557+
print("Crossunder detected in Pandas DataFrame in the last 3 data points")
558+
559+
# If you want to use the result of a previous crossunders calculation
560+
if is_crossunder(pl_df, crossunder_column="Crossunder_EMA", data_points=3):
561+
print("Crossunder detected in Pandas DataFrame in the last 3 data points")
562+
563+
# Calculate EMA and crossunders for Pandas DataFrame
564+
pd_df = ema(pd_df, source_column="Close", period=200, result_column="EMA_200")
565+
pd_df = ema(pd_df, source_column="Close", period=50, result_column="EMA_50")
566+
567+
# If you want the function to calculate the crossunders in the function
568+
if is_crossunder(
569+
pd_df, first_column="EMA_50", second_column="EMA_200", data_points=3
570+
):
571+
print("Crossunders detected in Pandas DataFrame in the last 3 data points")
572+
573+
# If you want to use the result of a previous crossover calculation
574+
if is_crossunder(pd_df, crossover_column="Crossunder_EMA", data_points=3):
575+
print("Crossunder detected in Pandas DataFrame in the last 3 data points")
576+
```

pyindicators/indicators/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from .simple_moving_average import sma
22
from .weighted_moving_average import wma
33
from .crossover import is_crossover, crossover
4-
from .crossunder import crossunder
4+
from .crossunder import crossunder, is_crossunder
55
from .exponential_moving_average import ema
66
from .rsi import rsi, wilders_rsi
77
from .macd import macd
@@ -13,6 +13,7 @@
1313
'is_crossover',
1414
"crossover",
1515
'crossunder',
16+
'is_crossunder',
1617
'ema',
1718
'rsi',
1819
'wilders_rsi',

0 commit comments

Comments
 (0)