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()
No description has been provided for this image
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 [ ]: