Skip to content

Commit 1e726d4

Browse files
committed
Fix devergence multitime frame check
1 parent ae6f55e commit 1e726d4

3 files changed

Lines changed: 161 additions & 2 deletions

File tree

pyindicators/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,20 @@
1010
from .exceptions import PyIndicatorException
1111
from .date_range import DateRange
1212

13+
# Version information
14+
__version__ = "0.15.0"
15+
__version_info__ = tuple(int(x) for x in __version__.split("."))
16+
17+
18+
def get_version():
19+
"""Return the version string of pyindicators."""
20+
return __version__
21+
22+
1323
__all__ = [
24+
'__version__',
25+
'__version_info__',
26+
'get_version',
1427
'sma',
1528
'wma',
1629
'is_crossover',

pyindicators/indicators/divergence.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,17 @@ def check_divergence_pattern(series_a, series_b, target_a=-1, target_b=1):
215215
Returns:
216216
bool: True if pattern is found, False otherwise
217217
"""
218+
# Convert to flat numpy arrays for consistent integer indexing
219+
# This handles pandas Series with DatetimeIndex correctly
220+
if hasattr(series_a, 'values'):
221+
series_a = series_a.values.flatten()
222+
elif hasattr(series_a, 'flatten'):
223+
series_a = series_a.flatten()
224+
if hasattr(series_b, 'values'):
225+
series_b = series_b.values.flatten()
226+
elif hasattr(series_b, 'flatten'):
227+
series_b = series_b.flatten()
228+
218229
try:
219230
# Find the first index of `target_a` (e.g., -1 in the indicator)
220231
a_index = next(i for i, val in enumerate(series_a) if val == target_a)
@@ -223,9 +234,13 @@ def check_divergence_pattern(series_a, series_b, target_a=-1, target_b=1):
223234

224235
# From that point forward, check if series_b has a target_b
225236
for j in range(a_index, len(series_b)):
226-
if series_b[j] == -1:
237+
val = series_b[j]
238+
# Handle numpy scalar comparison explicitly
239+
if hasattr(val, 'item'):
240+
val = val.item()
241+
if val == -1:
227242
return False # Higher low before lower low — invalid
228-
if series_b[j] == target_b:
243+
if val == target_b:
229244
return True # Valid divergence pattern
230245
return False
231246

tests/indicators/test_divergence.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,3 +830,134 @@ def test_standard_situations(self):
830830
window_size=7
831831
)
832832
self.assertTrue(any(df["bearish_divergence"]))
833+
834+
835+
class TestCheckDivergencePatternWithDatetimeIndex(TestCase):
836+
"""Tests to verify divergence functions work correctly with DatetimeIndex."""
837+
838+
def test_check_divergence_pattern_with_datetime_index(self):
839+
"""Test that check_divergence_pattern works with DatetimeIndex Series."""
840+
from pyindicators.indicators.divergence import check_divergence_pattern
841+
842+
series_a = pd.Series(
843+
[np.nan, -1, np.nan],
844+
index=pd.date_range('2024-01-01', periods=3, freq='1h')
845+
)
846+
series_b = pd.Series(
847+
[np.nan, np.nan, 1],
848+
index=pd.date_range('2024-01-01', periods=3, freq='1h')
849+
)
850+
851+
result = check_divergence_pattern(series_a, series_b, target_a=-1, target_b=1)
852+
self.assertTrue(result)
853+
854+
def test_check_divergence_pattern_with_integer_index(self):
855+
"""Test that check_divergence_pattern still works with integer index."""
856+
from pyindicators.indicators.divergence import check_divergence_pattern
857+
858+
series_a = pd.Series([np.nan, -1, np.nan])
859+
series_b = pd.Series([np.nan, np.nan, 1])
860+
861+
result = check_divergence_pattern(series_a, series_b, target_a=-1, target_b=1)
862+
self.assertTrue(result)
863+
864+
def test_check_divergence_pattern_with_numpy_arrays(self):
865+
"""Test that check_divergence_pattern works with numpy arrays."""
866+
from pyindicators.indicators.divergence import check_divergence_pattern
867+
868+
series_a = np.array([np.nan, -1, np.nan])
869+
series_b = np.array([np.nan, np.nan, 1])
870+
871+
result = check_divergence_pattern(series_a, series_b, target_a=-1, target_b=1)
872+
self.assertTrue(result)
873+
874+
def test_bearish_divergence_multi_dataframe_with_datetime_index(self):
875+
"""Test bearish_divergence_multi_dataframe with DatetimeIndex DataFrames."""
876+
from pyindicators import macd, detect_peaks
877+
878+
# Data with DatetimeIndex (common when loading from CSV or APIs)
879+
df = pd.DataFrame({
880+
'Close': [100, 101, 102, 101, 100, 99, 100, 101, 102, 103, 102, 101]
881+
}, index=pd.date_range('2024-01-01', periods=12, freq='1h'))
882+
883+
# Apply indicators
884+
macd_data = macd(
885+
df.copy(),
886+
source_column="Close",
887+
short_period=3,
888+
long_period=6,
889+
signal_period=3
890+
)
891+
close_data = detect_peaks(
892+
df.copy(),
893+
source_column="Close",
894+
number_of_neighbors_to_compare=2,
895+
min_consecutive=1
896+
)
897+
macd_data = detect_peaks(
898+
macd_data,
899+
source_column="macd_histogram",
900+
number_of_neighbors_to_compare=2,
901+
min_consecutive=1
902+
)
903+
904+
# This should not raise ValueError with DatetimeIndex
905+
divergence_data = bearish_divergence_multi_dataframe(
906+
first_df=macd_data,
907+
second_df=close_data,
908+
result_df=close_data.copy(),
909+
first_column="macd_histogram",
910+
second_column="Close",
911+
window_size=5,
912+
result_column="bearish_divergence"
913+
)
914+
915+
# Verify the result has the expected column and index
916+
self.assertIn("bearish_divergence", divergence_data.columns)
917+
self.assertIsInstance(divergence_data.index, pd.DatetimeIndex)
918+
919+
def test_bullish_divergence_multi_dataframe_with_datetime_index(self):
920+
"""Test bullish_divergence_multi_dataframe with DatetimeIndex DataFrames."""
921+
from pyindicators import macd, detect_peaks
922+
923+
# Data with DatetimeIndex
924+
df = pd.DataFrame({
925+
'Close': [103, 102, 101, 100, 99, 100, 101, 102, 101, 100, 99, 98]
926+
}, index=pd.date_range('2024-01-01', periods=12, freq='1h'))
927+
928+
# Apply indicators
929+
macd_data = macd(
930+
df.copy(),
931+
source_column="Close",
932+
short_period=3,
933+
long_period=6,
934+
signal_period=3
935+
)
936+
close_data = detect_peaks(
937+
df.copy(),
938+
source_column="Close",
939+
number_of_neighbors_to_compare=2,
940+
min_consecutive=1
941+
)
942+
macd_data = detect_peaks(
943+
macd_data,
944+
source_column="macd_histogram",
945+
number_of_neighbors_to_compare=2,
946+
min_consecutive=1
947+
)
948+
949+
# This should not raise ValueError with DatetimeIndex
950+
divergence_data = bullish_divergence_multi_dataframe(
951+
first_df=macd_data,
952+
second_df=close_data,
953+
result_df=close_data.copy(),
954+
first_column="macd_histogram",
955+
second_column="Close",
956+
window_size=5,
957+
result_column="bullish_divergence"
958+
)
959+
960+
# Verify the result has the expected column and index
961+
self.assertIn("bullish_divergence", divergence_data.columns)
962+
self.assertIsInstance(divergence_data.index, pd.DatetimeIndex)
963+

0 commit comments

Comments
 (0)