In [108]:
!pip install yfinance
Requirement already satisfied: yfinance in c:\users\alexx\anaconda\lib\site-packages (0.2.65) Requirement already satisfied: pandas>=1.3.0 in c:\users\alexx\anaconda\lib\site-packages (from yfinance) (2.2.2) Requirement already satisfied: numpy>=1.16.5 in c:\users\alexx\anaconda\lib\site-packages (from yfinance) (1.26.4) Requirement already satisfied: requests>=2.31 in c:\users\alexx\anaconda\lib\site-packages (from yfinance) (2.32.3) Requirement already satisfied: multitasking>=0.0.7 in c:\users\alexx\anaconda\lib\site-packages (from yfinance) (0.0.12) Requirement already satisfied: platformdirs>=2.0.0 in c:\users\alexx\anaconda\lib\site-packages (from yfinance) (3.10.0) Requirement already satisfied: pytz>=2022.5 in c:\users\alexx\anaconda\lib\site-packages (from yfinance) (2024.1) Requirement already satisfied: frozendict>=2.3.4 in c:\users\alexx\anaconda\lib\site-packages (from yfinance) (2.4.2) Requirement already satisfied: peewee>=3.16.2 in c:\users\alexx\anaconda\lib\site-packages (from yfinance) (3.18.2) Requirement already satisfied: beautifulsoup4>=4.11.1 in c:\users\alexx\anaconda\lib\site-packages (from yfinance) (4.12.3) Requirement already satisfied: curl_cffi>=0.7 in c:\users\alexx\anaconda\lib\site-packages (from yfinance) (0.13.0) Requirement already satisfied: protobuf>=3.19.0 in c:\users\alexx\anaconda\lib\site-packages (from yfinance) (4.25.3) Requirement already satisfied: websockets>=13.0 in c:\users\alexx\anaconda\lib\site-packages (from yfinance) (15.0.1) Requirement already satisfied: soupsieve>1.2 in c:\users\alexx\anaconda\lib\site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.5) Requirement already satisfied: cffi>=1.12.0 in c:\users\alexx\anaconda\lib\site-packages (from curl_cffi>=0.7->yfinance) (1.17.1) Requirement already satisfied: certifi>=2024.2.2 in c:\users\alexx\anaconda\lib\site-packages (from curl_cffi>=0.7->yfinance) (2024.8.30) Requirement already satisfied: python-dateutil>=2.8.2 in c:\users\alexx\anaconda\lib\site-packages (from pandas>=1.3.0->yfinance) (2.9.0.post0) Requirement already satisfied: tzdata>=2022.7 in c:\users\alexx\anaconda\lib\site-packages (from pandas>=1.3.0->yfinance) (2023.3) Requirement already satisfied: charset-normalizer<4,>=2 in c:\users\alexx\anaconda\lib\site-packages (from requests>=2.31->yfinance) (3.3.2) Requirement already satisfied: idna<4,>=2.5 in c:\users\alexx\anaconda\lib\site-packages (from requests>=2.31->yfinance) (3.7) Requirement already satisfied: urllib3<3,>=1.21.1 in c:\users\alexx\anaconda\lib\site-packages (from requests>=2.31->yfinance) (2.2.3) Requirement already satisfied: pycparser in c:\users\alexx\anaconda\lib\site-packages (from cffi>=1.12.0->curl_cffi>=0.7->yfinance) (2.21) Requirement already satisfied: six>=1.5 in c:\users\alexx\anaconda\lib\site-packages (from python-dateutil>=2.8.2->pandas>=1.3.0->yfinance) (1.16.0)
In [109]:
from datetime import datetime
import yfinance as yf
import pandas as pd
# Set dynamic date range
start_date = '2015-01-01'
end_date = datetime.today().strftime('%Y-%m-%d') # this gives today's date
# Define your tickers
tickers = ['XLF', 'XLK', 'XLY', 'XLE', 'XLV', 'XLI', 'XLC', 'XLB', 'XLRE', 'XLP']
# Download data grouped by ticker
data = yf.download(tickers, start=start_date, end=end_date, group_by='ticker', auto_adjust=True)
# Extract close prices into a new DataFrame
adj_close = pd.DataFrame({ticker: data[ticker]['Close'] for ticker in tickers})
adj_close.dropna(inplace=True)
from datetime import datetime
print(datetime.today().strftime('%Y-%m-%d')) # Prints today's date
adj_close.index.max()
[*********************100%***********************] 10 of 10 completed
2025-08-13
Out[109]:
Timestamp('2025-08-12 00:00:00')
In [110]:
data['XLF'].columns
Out[110]:
Index(['Open', 'High', 'Low', 'Close', 'Volume'], dtype='object', name='Price')
In [111]:
print("Last date in data:", adj_close.index.max().date())
print("Today:", datetime.today().date())
Last date in data: 2025-08-12 Today: 2025-08-13
In [116]:
print(adj_close.index.min(), adj_close.index.max())
2018-06-19 00:00:00 2025-08-12 00:00:00
In [118]:
print(adj_close.tail(10))
XLF XLK XLY XLE XLV \ Date 2025-07-30 52.700001 264.679993 223.199997 87.680000 134.190002 2025-07-31 52.369999 262.739990 221.429993 87.209999 130.429993 2025-08-01 51.400002 257.070007 216.089996 85.589996 131.130005 2025-08-04 51.910000 262.290009 218.630005 85.400002 133.009995 2025-08-05 51.700001 260.119995 218.910004 85.510002 132.500000 2025-08-06 51.950001 263.049988 223.460007 84.720001 130.509995 2025-08-07 51.369999 263.290009 223.389999 84.389999 129.009995 2025-08-08 51.849998 265.920013 223.779999 84.930000 130.160004 2025-08-11 51.830002 264.119995 224.360001 84.250000 130.289993 2025-08-12 52.459999 268.209991 226.740005 84.660004 131.190002 XLI XLC XLB XLRE XLP Date 2025-07-30 152.000000 106.449997 88.849998 42.150002 80.470001 2025-07-31 152.009995 107.410004 87.730003 41.410000 79.779999 2025-08-01 149.740005 106.120003 86.720001 41.290001 80.160004 2025-08-04 151.119995 108.160004 87.870003 41.639999 80.550003 2025-08-05 150.809998 107.320000 88.489998 41.779999 80.470001 2025-08-06 150.929993 107.730003 87.529999 41.430000 81.620003 2025-08-07 150.710007 107.269997 87.910004 41.590000 82.239998 2025-08-08 150.830002 107.629997 88.349998 41.250000 82.480003 2025-08-11 150.339996 108.180000 88.150002 41.009998 82.410004 2025-08-12 151.899994 110.250000 89.300003 41.080002 82.629997
In [ ]:
In [120]:
for ticker in tickers:
print(f"{ticker}: {data[ticker]['Close'].dropna().shape}")
XLF: (2668,) XLK: (2668,) XLY: (2668,) XLE: (2668,) XLV: (2668,) XLI: (2668,) XLC: (1797,) XLB: (2668,) XLRE: (2475,) XLP: (2668,)
In [122]:
valid_tickers = adj_close.columns[adj_close.isnull().mean() < 0.25]
adj_close = adj_close[valid_tickers]
In [124]:
import matplotlib.pyplot as plt
# Plot the last 30 days
adj_close_last30 = adj_close.tail(30)
plt.figure(figsize=(14, 6))
for ticker in adj_close_last30.columns:
plt.plot(adj_close_last30.index, adj_close_last30[ticker], label=ticker)
plt.title('Last 30 Days - Close Prices')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend(loc='upper left')
plt.xticks(rotation=45)
plt.grid(True)
plt.tight_layout()
plt.show()
In [126]:
# Daily returns
returns = adj_close.pct_change()
# 30-day moving average
moving_avg = adj_close.rolling(window=30).mean()
# Display samples
print("Sample Daily Returns:")
print(returns.tail())
print("\nSample 30-Day Moving Averages:")
print(moving_avg.tail())
Sample Daily Returns: XLF XLK XLY XLE XLV XLI \ Date 2025-08-06 0.004836 0.011264 0.020785 -0.009239 -0.015019 0.000796 2025-08-07 -0.011165 0.000912 -0.000313 -0.003895 -0.011493 -0.001458 2025-08-08 0.009344 0.009989 0.001746 0.006399 0.008914 0.000796 2025-08-11 -0.000386 -0.006769 0.002592 -0.008007 0.000999 -0.003249 2025-08-12 0.012155 0.015485 0.010608 0.004867 0.006908 0.010376 XLC XLB XLRE XLP Date 2025-08-06 0.003820 -0.010849 -0.008377 0.014291 2025-08-07 -0.004270 0.004341 0.003862 0.007596 2025-08-08 0.003356 0.005005 -0.008175 0.002918 2025-08-11 0.005110 -0.002264 -0.005818 -0.000849 2025-08-12 0.019135 0.013046 0.001707 0.002670 Sample 30-Day Moving Averages: XLF XLK XLY XLE XLV \ Date 2025-08-06 52.399333 258.129333 220.662999 86.641666 134.059999 2025-08-07 52.398000 258.594000 221.007666 86.636666 133.896999 2025-08-08 52.400000 259.089000 221.299999 86.609333 133.761666 2025-08-11 52.396333 259.534000 221.492332 86.574333 133.640333 2025-08-12 52.399333 260.033333 221.805999 86.569333 133.520333 XLI XLC XLB XLRE XLP Date 2025-08-06 150.330666 107.113000 89.921333 41.788000 80.990667 2025-08-07 150.561666 107.181667 89.957667 41.800000 81.057334 2025-08-08 150.744667 107.221667 89.976667 41.809333 81.134334 2025-08-11 150.863000 107.238333 89.985334 41.805666 81.196334 2025-08-12 151.009000 107.295667 90.035000 41.794333 81.251667
In [130]:
# 📦 Libraries
import yfinance as yf
import pandas as pd
import plotly.graph_objs as go
from datetime import datetime
# 🧠 Tickers
tickers = ["XLK", "XLE", "XLF", "XLV", "XLY", "XLU", "XLI", "XLB", "XLRE", "XLC", "XLP"]
# 📅 Date range
start_date = "2015-01-01"
end_date = datetime.today().strftime('%Y-%m-%d')
# 📥 Download Data
data = yf.download(tickers, start=start_date, end=end_date, group_by='ticker', auto_adjust=True)
# 📊 Create Adjusted Close DataFrame
adj_close = pd.DataFrame({ticker: data[ticker]['Close'] for ticker in tickers})
adj_close = adj_close.dropna()
# 📈 Calculate Monthly Returns
monthly_returns = adj_close.resample('M').ffill().pct_change().dropna()
# 📉 Cumulative Returns
cumulative_returns = (1 + monthly_returns).cumprod()
# 📊 Summary Stats
summary = monthly_returns.describe().T
summary["Mean"] = monthly_returns.mean()
summary["StdDev"] = monthly_returns.std()
summary["Min"] = monthly_returns.min()
summary["Max"] = monthly_returns.max()
summary = summary[["Mean", "StdDev", "Min", "Max"]].round(4)
# 📅 Most Recent Date Check
latest_date = adj_close.index[-1].strftime('%Y-%m-%d')
[*********************100%***********************] 11 of 11 completed C:\Users\Alexx\AppData\Local\Temp\ipykernel_28348\3178523120.py:22: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead. monthly_returns = adj_close.resample('M').ffill().pct_change().dropna()
In [132]:
import plotly.express as px
fig = px.line(cumulative_returns,
title=f"Cumulative Returns of S&P 500 Sector ETFs (2015 - {latest_date})")
fig.update_layout(autosize=True, template="plotly_white")
fig.show()
In [134]:
import plotly.figure_factory as ff
table_fig = ff.create_table(summary.reset_index().rename(columns={"index": "Sector"}))
table_fig.update_layout(width=900)
table_fig.show()
In [ ]: