Skip to content

Commit 2051596

Browse files
committed
Add number of datapoints check
1 parent de42f85 commit 2051596

File tree

5 files changed

+63
-8
lines changed

5 files changed

+63
-8
lines changed

pyindicators/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
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
7+
from .exceptions import PyIndicatorException
78

89
__all__ = [
910
'sma',
@@ -30,4 +31,5 @@
3031
'has_any_lower_then_threshold',
3132
'has_values_above_threshold',
3233
'has_values_below_threshold',
34+
'PyIndicatorException',
3335
]

pyindicators/indicators/crossover.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ def crossover(
3535

3636
# Restrict data to the last `data_points` rows if specified
3737
if number_of_data_points is not None:
38+
39+
if number_of_data_points < 2:
40+
raise PyIndicatorException(
41+
"The number of data points must be greater or equal than 2 for"
42+
" crossover detection."
43+
)
44+
3845
data = data.tail(number_of_data_points) \
3946
if isinstance(data, PdDataFrame) \
4047
else data.slice(-number_of_data_points)
@@ -100,6 +107,14 @@ def is_crossover(
100107
if len(data) < 2:
101108
return False
102109

110+
if number_of_data_points is None:
111+
number_of_data_points = len(data)
112+
elif number_of_data_points < 2:
113+
raise PyIndicatorException(
114+
"The number of data points must be greater or equal than 2 for"
115+
" crossover detection."
116+
)
117+
103118
if crossover_column is None:
104119
crossover_column = f"{first_column}_crossover_{second_column}"
105120
data = crossover(
@@ -111,9 +126,6 @@ def is_crossover(
111126
strict=strict
112127
)
113128

114-
if number_of_data_points is None:
115-
number_of_data_points = len(data)
116-
117129
# If crossunder_column is set, check for a value of 1
118130
# in the last data points
119131
if isinstance(data, PdDataFrame):

pyindicators/indicators/crossunder.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ def crossunder(
1717

1818
if number_of_data_points is not None:
1919

20+
if number_of_data_points < 2:
21+
raise PyIndicatorException(
22+
"The number of data points must be greater or equal than 2 for"
23+
" crossunder detection."
24+
)
25+
2026
if isinstance(data, PdDataFrame):
2127
data = data.tail(number_of_data_points).copy()
2228
else:
@@ -63,6 +69,14 @@ def is_crossunder(
6369
if len(data) < 2:
6470
return False
6571

72+
if number_of_data_points is None:
73+
number_of_data_points = len(data)
74+
elif number_of_data_points < 2:
75+
raise PyIndicatorException(
76+
"The number of data points must be greater or equal than 2 for"
77+
" crossover detection."
78+
)
79+
6680
if crossunder_column is None:
6781
crossunder_column = f"{first_column}_crossunder_{second_column}"
6882
data = crossunder(
@@ -74,9 +88,6 @@ def is_crossunder(
7488
strict=strict
7589
)
7690

77-
if number_of_data_points is None:
78-
number_of_data_points = len(data)
79-
8091
if isinstance(data, PdDataFrame):
8192
return data[crossunder_column].tail(number_of_data_points)\
8293
.eq(1).any()

tests/indicators/test_crossover.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import polars as pl
33
from unittest import TestCase
44

5-
from pyindicators import is_crossover
5+
from pyindicators import is_crossover, PyIndicatorException
66

77

88
class TestCrossover(TestCase):
@@ -106,3 +106,18 @@ def test_crossover_polars(self):
106106
number_of_data_points=3
107107
)
108108
)
109+
110+
def test_throws_exception_when_number_of_data_points_is_less_than_2(self):
111+
df = pd.DataFrame({
112+
"EMA_50": [200, 201, 202, 203, 204, 205, 206, 208, 208, 210],
113+
"EMA_200": [200, 201, 202, 203, 204, 205, 206, 207, 209, 209],
114+
"DateTime": pd.date_range("2021-01-01", periods=10, freq="D")
115+
})
116+
117+
# Set index to DateTime
118+
df.set_index("DateTime", inplace=True)
119+
120+
with self.assertRaises(PyIndicatorException):
121+
is_crossover(
122+
df, first_column="EMA_50", second_column="EMA_200", number_of_data_points=1
123+
)

tests/indicators/test_crossunder.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import polars as pl
33
from unittest import TestCase
44

5-
from pyindicators import is_crossunder
5+
from pyindicators import is_crossunder, PyIndicatorException
66

77

88
class TestCrossover(TestCase):
@@ -174,3 +174,18 @@ def test_crossunder_polars(self):
174174
strict=False
175175
)
176176
)
177+
178+
def test_throws_exception_when_number_of_data_points_is_less_than_2(self):
179+
df = pd.DataFrame({
180+
"EMA_50": [200, 201, 202, 203, 204, 205, 206, 208, 208, 210],
181+
"EMA_200": [200, 201, 202, 203, 204, 205, 206, 207, 209, 209],
182+
"DateTime": pd.date_range("2021-01-01", periods=10, freq="D")
183+
})
184+
185+
# Set index to DateTime
186+
df.set_index("DateTime", inplace=True)
187+
188+
with self.assertRaises(PyIndicatorException):
189+
is_crossunder(
190+
df, first_column="EMA_50", second_column="EMA_200", number_of_data_points=1
191+
)

0 commit comments

Comments
 (0)