Dmitry Beresnev commited on
Commit
42b622f
·
1 Parent(s): a4fc70c

fix data downloader

Browse files
Files changed (1) hide show
  1. portfolio_calculator.py +30 -42
portfolio_calculator.py CHANGED
@@ -40,27 +40,21 @@ MAX_TICKERS = 20
40
  retry=retry_if_exception_type((ConnectionError, TimeoutError)), # Only retry on network errors
41
  reraise=True
42
  )
43
- def _fetch_with_retry(ticker_obj, method: str, period: str = "1y"):
44
  """
45
  Internal function with retry logic for fetching data.
46
 
 
 
 
47
  Args:
48
  ticker_obj: yfinance Ticker object
49
- method: Which method to use ('period', 'short', 'dates')
50
- period: Time period
51
 
52
  Returns:
53
  Historical data or None
54
  """
55
- if method == 'period':
56
- return ticker_obj.history(period=period)
57
- elif method == 'short':
58
- return ticker_obj.history(period="6mo")
59
- else: # dates
60
- import datetime
61
- end_date = datetime.datetime.now()
62
- start_date = end_date - datetime.timedelta(days=365)
63
- return ticker_obj.history(start=start_date, end=end_date)
64
 
65
 
66
  def fetch_single_ticker(ticker: str, period: str = "1y") -> Tuple[str, Optional[pd.Series], Optional[str]]:
@@ -70,9 +64,12 @@ def fetch_single_ticker(ticker: str, period: str = "1y") -> Tuple[str, Optional[
70
  This function runs in a separate process for parallel execution.
71
  Uses tenacity for exponential backoff and ratelimit for request throttling.
72
 
 
 
 
73
  Args:
74
  ticker: Ticker symbol
75
- period: Time period for historical data
76
 
77
  Returns:
78
  Tuple of (ticker, price_series, error_message)
@@ -81,35 +78,26 @@ def fetch_single_ticker(ticker: str, period: str = "1y") -> Tuple[str, Optional[
81
  # Create fresh Ticker object in this process
82
  ticker_obj = yf.Ticker(ticker)
83
 
84
- # Try Method 1: Standard period with retry logic
85
- try:
86
- hist = _fetch_with_retry(ticker_obj, 'period', period)
87
- if not hist.empty:
88
- logger.info(f"✅ {ticker}: Fetched {len(hist)} days (method: period)")
89
- return ticker, hist['Close'], None
90
- except Exception as e:
91
- logger.warning(f"⚠️ {ticker}: Method 1 failed - {str(e)}")
92
-
93
- # Try Method 2: Shorter period
94
- try:
95
- hist = _fetch_with_retry(ticker_obj, 'short', period)
96
- if not hist.empty:
97
- logger.info(f"✅ {ticker}: Fetched {len(hist)} days (method: short)")
98
- return ticker, hist['Close'], None
99
- except Exception as e:
100
- logger.warning(f"⚠️ {ticker}: Method 2 failed - {str(e)}")
101
-
102
- # Try Method 3: Explicit dates (most reliable)
103
- try:
104
- hist = _fetch_with_retry(ticker_obj, 'dates', period)
105
- if not hist.empty:
106
- logger.info(f"✅ {ticker}: Fetched {len(hist)} days (method: dates)")
107
- return ticker, hist['Close'], None
108
- except Exception as e:
109
- logger.warning(f"⚠️ {ticker}: Method 3 failed - {str(e)}")
110
-
111
- # All methods failed
112
- logger.error(f"❌ {ticker}: All methods exhausted")
113
  return ticker, None, "No data available after all retry attempts"
114
 
115
  except Exception as e:
 
40
  retry=retry_if_exception_type((ConnectionError, TimeoutError)), # Only retry on network errors
41
  reraise=True
42
  )
43
+ def _fetch_with_retry(ticker_obj, period: str):
44
  """
45
  Internal function with retry logic for fetching data.
46
 
47
+ IMPORTANT: Only uses 'period' parameter (not start/end dates) to avoid
48
+ yfinance timezone request that incorrectly handles 429 errors.
49
+
50
  Args:
51
  ticker_obj: yfinance Ticker object
52
+ period: Time period (e.g., '1y', '6mo', '3mo', '1mo')
 
53
 
54
  Returns:
55
  Historical data or None
56
  """
57
+ return ticker_obj.history(period=period)
 
 
 
 
 
 
 
 
58
 
59
 
60
  def fetch_single_ticker(ticker: str, period: str = "1y") -> Tuple[str, Optional[pd.Series], Optional[str]]:
 
64
  This function runs in a separate process for parallel execution.
65
  Uses tenacity for exponential backoff and ratelimit for request throttling.
66
 
67
+ IMPORTANT: Only uses 'period' parameter (not start/end dates) to avoid
68
+ yfinance timezone request that incorrectly handles 429 errors.
69
+
70
  Args:
71
  ticker: Ticker symbol
72
+ period: Time period for historical data (default: '1y')
73
 
74
  Returns:
75
  Tuple of (ticker, price_series, error_message)
 
78
  # Create fresh Ticker object in this process
79
  ticker_obj = yf.Ticker(ticker)
80
 
81
+ # Fallback periods to try (from longest to shortest)
82
+ # Avoid 'max' as it may trigger timezone request
83
+ periods_to_try = [period, '6mo', '3mo', '1mo']
84
+
85
+ for idx, try_period in enumerate(periods_to_try, 1):
86
+ try:
87
+ hist = _fetch_with_retry(ticker_obj, try_period)
88
+ if not hist.empty and len(hist) > 0:
89
+ logger.info(f"✅ {ticker}: Fetched {len(hist)} days (period: {try_period})")
90
+ return ticker, hist['Close'], None
91
+ except Exception as e:
92
+ logger.warning(f"⚠️ {ticker}: Period '{try_period}' failed - {str(e)}")
93
+ if idx == len(periods_to_try):
94
+ # Last attempt failed
95
+ logger.error(f"❌ {ticker}: All periods exhausted")
96
+ return ticker, None, f"All periods failed. Last error: {str(e)}"
97
+ # Continue to next period
98
+
99
+ # All periods failed
100
+ logger.error(f"❌ {ticker}: No data available after trying all periods")
 
 
 
 
 
 
 
 
 
101
  return ticker, None, "No data available after all retry attempts"
102
 
103
  except Exception as e: