Repository: ranaroussi/yfinance

Issue:
Several tickers return Exception when getting historical data with `period="max"` and `interval="1mo"`
# Several tickers return Exception when getting historical data with `period="max"` and `interval="1mo"`

I had code that used yfinance to get monthly max period close price data for a small number of tickers. The code worked fine for yfinance version 0.1, but I ran it again using yfinance version 0.2.9 and for several of the tickers it was returning the exception below. It worked just fine for several of the tickers, but then returned the exception below for others. I checked the yahoo! finance website and the data is all there for those tickers that are returning the exception. Oddly enough, it seemed to work fine when I changed either the period or interval - it just didn't seem to like having both `period="max"` and `interval="1mo"` for some reason.

# Examples
## Works fine

`yf.Ticker("ABBV").history(period="10y", interval="1mo")["Close"]`
`yf.Ticker("ABBV").history(period="max", interval="1wk")["Close"]`

## Returns Exception

`yf.Ticker("ABBV").history(period="max", interval="1mo")["Close"]`

---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_13864/234900509.py in <module>
----> 1 yf.Ticker('ABBV').history(period="max", interval="1mo")["Close"]

~\Anaconda3\lib\site-packages\yfinance\base.py in history(self, period, interval, start, end, prepost, actions, auto_adjust, back_adjust, repair, keepna, proxy, rounding, timeout, debug, raise_errors)
    709         df = quotes.sort_index()
    710         if dividends.shape[0] > 0:
--> 711             df = utils.safe_merge_dfs(df, dividends, interval)
    712         if "Dividends" in df.columns:
    713             df.loc[df["Dividends"].isna(), "Dividends"] = 0

~\Anaconda3\lib\site-packages\yfinance\utils.py in safe_merge_dfs(df_main, df_sub, interval)
    631             df = _pd.concat([df, df_sub_missing], sort=True)[col_ordering]
    632         else:
--> 633             raise Exception("Lost data during merge despite all attempts to align data (see above)")
    634 
    635     return df

Exception: Lost data during merge despite all attempts to align data (see above)


Discussion:

Resolving patch:
diff --git a/yfinance/base.py b/yfinance/base.py
--- a/yfinance/base.py
+++ b/yfinance/base.py
@@ -669,30 +669,28 @@ def history(self, period="1mo", interval="1d",
         if not expect_capital_gains:
             capital_gains = None
 
+        if splits is not None:
+            splits = utils.set_df_tz(splits, interval, tz_exchange)
+        if dividends is not None:
+            dividends = utils.set_df_tz(dividends, interval, tz_exchange)
+        if capital_gains is not None:
+            capital_gains = utils.set_df_tz(capital_gains, interval, tz_exchange)
         if start is not None:
-            # Note: use pandas Timestamp as datetime.utcfromtimestamp has bugs on windows
-            # https://github.com/python/cpython/issues/81708
-            startDt = _pd.Timestamp(start, unit='s')
+            startDt = quotes.index[0]
             if dividends is not None:
-                dividends = dividends[dividends.index>=startDt]
+                dividends = dividends.loc[startDt:]
             if capital_gains is not None:
-                capital_gains = capital_gains[capital_gains.index>=startDt]
+                capital_gains = capital_gains.loc[startDt:]
             if splits is not None:
-                splits = splits[splits.index >= startDt]
+                splits = splits.loc[startDt:]
         if end is not None:
-            endDt = _pd.Timestamp(end, unit='s')
+            endDt = _pd.Timestamp(end, unit='s').tz_localize(tz)
             if dividends is not None:
-                dividends = dividends[dividends.index<endDt]
+                dividends = dividends[dividends.index < endDt]
             if capital_gains is not None:
-                capital_gains = capital_gains[capital_gains.index<endDt]
+                capital_gains = capital_gains[capital_gains.index < endDt]
             if splits is not None:
                 splits = splits[splits.index < endDt]
-        if splits is not None:
-            splits = utils.set_df_tz(splits, interval, tz_exchange)
-        if dividends is not None:
-            dividends = utils.set_df_tz(dividends, interval, tz_exchange)
-        if capital_gains is not None:
-            capital_gains = utils.set_df_tz(capital_gains, interval, tz_exchange)
 
         # Prepare for combine
         intraday = params["interval"][-1] in ("m", 'h')


Test patch:
diff --git a/tests/prices.py b/tests/prices.py
--- a/tests/prices.py
+++ b/tests/prices.py
@@ -228,6 +228,11 @@ def test_monthlyWithEvents(self):
                 print("{}-without-events missing these dates: {}".format(tkr, missing_from_df2))
                 raise
 
+    def test_monthlyWithEvents2(self):
+        # Simply check no exception from internal merge
+        tkr = "ABBV"
+        yf.Ticker("ABBV").history(period="max", interval="1mo")
+
     def test_tz_dst_ambiguous(self):
         # Reproduce issue #1100