Skip to content

Commit ea20faa

Browse files
Reduce data queries from yfinance, since queries are limited. Debug failing tests for _bollinger_signals.
1 parent 0a7f0a1 commit ea20faa

File tree

3 files changed

+21
-50
lines changed

3 files changed

+21
-50
lines changed

src/backtest_bay/data/download_data.py

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,6 @@ def _validate_symbol(symbol):
2424
error_msg = "Symbol must be a non-empty string."
2525
raise TypeError(error_msg)
2626

27-
is_symbol_existent = not yf.Ticker(symbol).history(period="1d").empty
28-
if not is_symbol_existent:
29-
error_msg = (
30-
f"Invalid symbol: '{symbol}'. Please provide a valid ticker symbol "
31-
"from https://finance.yahoo.com/"
32-
)
33-
raise ValueError(error_msg)
34-
3527

3628
def _validate_interval(interval):
3729
valid_intervals = {
@@ -73,16 +65,8 @@ def _validate_date_range(start_date, end_date):
7365

7466
def _validate_output(data, symbol, start_date, end_date, interval):
7567
if data.empty:
76-
# Since we already checked for a valid symbol, we check if input dates
77-
# fit to historic available data.
78-
ticker = yf.Ticker(symbol)
79-
hist = ticker.history(period="max")
80-
min_date = hist.index.min().strftime("%Y-%m-%d")
81-
max_date = hist.index.max().strftime("%Y-%m-%d")
82-
8368
error_msg = (
8469
f"No data found for {symbol} between {start_date} and {end_date} "
85-
f"with interval '{interval}'.\n"
86-
f"Available data range for {symbol}: {min_date} to {max_date}."
70+
f"with interval '{interval}'."
8771
)
8872
raise ValueError(error_msg)

tests/analysis/test_generate_signals.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,25 @@
33

44
from backtest_bay.analysis.generate_signals import _bollinger_signals
55

6-
# Tests for _bollinger_signals
7-
86

7+
# Tests for _bollinger_signals
98
def test_bollinger_signals_constant_prices():
109
prices = pd.Series([100] * 30)
11-
signals = _bollinger_signals(prices)
10+
signals = _bollinger_signals(prices, window=20, num_std_dev=2)
1211
expected = pd.Series([0] * 30, index=prices.index)
1312
pd.testing.assert_series_equal(signals, expected)
1413

1514

1615
def test_bollinger_signals_buy_signal():
17-
prices = pd.Series([100] * 20 + [90])
18-
signals = _bollinger_signals(prices)
16+
prices = pd.Series([100] * 20 + [90] + [100])
17+
signals = _bollinger_signals(prices, window=20, num_std_dev=2)
1918
buy_signal = 2
2019
assert signals.iloc[-1] == buy_signal
2120

2221

2322
def test_bollinger_signals_sell_signal():
24-
prices = pd.Series([100] * 20 + [110])
25-
signals = _bollinger_signals(prices)
23+
prices = pd.Series([100] * 20 + [110] + [100])
24+
signals = _bollinger_signals(prices, window=20, num_std_dev=2)
2625
assert signals.iloc[-1] == 1
2726

2827

@@ -31,3 +30,10 @@ def test_bollinger_signals_window_effect():
3130
signals_small_window = _bollinger_signals(prices, window=2, num_std_dev=1)
3231
signals_large_window = _bollinger_signals(prices, window=20, num_std_dev=1)
3332
assert not signals_small_window.equals(signals_large_window)
33+
34+
35+
def test_bollinger_signals_single_price():
36+
prices = pd.Series([100])
37+
signals = _bollinger_signals(prices, window=20, num_std_dev=2)
38+
expected = pd.Series([0], index=prices.index)
39+
pd.testing.assert_series_equal(signals, expected)

tests/data/test_download_data.py

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,6 @@
1111

1212

1313
# Tests for _validate_symbol
14-
def test_validate_symbol_valid_cases():
15-
_validate_symbol("AAPL")
16-
17-
18-
def test_validate_symbol_invalid_invalid_symbol():
19-
with pytest.raises(ValueError, match="Invalid symbol: 'INVALID'"):
20-
_validate_symbol("INVALID")
21-
22-
23-
def test_validate_symbol_invalid_empty_string():
24-
with pytest.raises(ValueError, match="Invalid symbol: ''"):
25-
_validate_symbol("")
26-
27-
2814
def test_validate_symbol_invalid_non_string():
2915
with pytest.raises(TypeError, match="Symbol must be a non-empty string."):
3016
_validate_symbol(123)
@@ -131,18 +117,13 @@ def test_validate_output_valid_input():
131117
def test_validate_output_empty_input():
132118
# generate typical Yahoo Finance output format
133119
symbol = "AAPL"
134-
arrays = [
135-
["Close", "High", "Low", "Open", "Volume"],
136-
[symbol, symbol, symbol, symbol, symbol],
137-
]
138-
index = pd.MultiIndex.from_tuples(
139-
list(zip(*arrays, strict=False)), names=["Price", "Ticker"]
120+
empty_data = pd.DataFrame()
121+
start_date = "1800-01-01"
122+
end_date = "1800-05-01"
123+
interval = "1d"
124+
match = (
125+
f"No data found for {symbol} between {start_date} and {end_date} "
126+
f"with interval '{interval}'."
140127
)
141-
142-
empty_data = pd.DataFrame(columns=index)
143-
144-
empty_data.index.name = "Date"
145-
146-
match = "No data found for AAPL between 1800-01-01 and 1800-05-01."
147128
with pytest.raises(ValueError, match=match):
148129
_validate_output(empty_data, symbol, "1800-01-01", "1800-05-01", "1d")

0 commit comments

Comments
 (0)