Fear and Greed indicators¶
AIM: Find indicators to estimate the current market sentiment, and for each one curate a Perplexity Page commenting the rationale and critics about it.
In [1]:
import os
import dotenv # pip install python-dotenv
import pandas as pd
import yfinance as yf # pip install yfinance
from fredapi import Fred # pip install fredapi
dotenv.load_dotenv()
print("yfinance version:", yf.__version__)
F&G Indicator #1: margin borrowing¶
https://www.perplexity.ai/page/margin-debt-as-percentage-of-m-9lQvy1AIRXC1pvm0J45Z3A
In [2]:
sp500tr_raw = yf.Ticker('^SP500TR').history(period='max', auto_adjust=True)
display(sp500tr_raw)
sp500tr_ss = sp500tr_raw["Close"]
sp500tr_ss.index = sp500tr_ss.index.date
In [3]:
fred = Fred(api_key=os.getenv("FRED_API_KEY"))
m2_raw = fred.get_series('M2SL')
display(m2_raw)
m2_ss = pd.Series(m2_raw)
m2_ss.index = pd.to_datetime(m2_ss.index)
In [4]:
margin_raw = pd.read_excel('https://www.finra.org/sites/default/files/2021-03/margin-statistics.xlsx')
display(margin_raw)
margin_ss = margin_raw.set_index('Year-Month')["Debit Balances in Customers' Securities Margin Accounts"]
margin_ss.index = pd.to_datetime(margin_ss.index)
In [5]:
df = (
sp500tr_ss
.div(sp500tr_ss.iloc[-1]/10) # rescale to be 10 as last value
.rename("S&P 500 Total Returns")
.to_frame()
.join(margin_ss.div(1e6).rename("Margin (T$)")) # raw is in M$
.join(m2_ss.div(1e3).rename("M2 (T$)")) # raw is in B$
.ffill()
.assign(**{
"%Margin/M2": lambda x: x["Margin (T$)"] / x["M2 (T$)"] * 100
})
)
df
Out[5]:
In [6]:
TITLE = "Fear&Greed indicator #1: % Margin debt over M2"
INCLUDE = ["S&P 500 Total Returns", "%Margin/M2"]
# plotly
import plotly.express as px # pip install plotly
fig = px.line(
df.dropna()[INCLUDE].reset_index().melt(id_vars="index"),
x="index",
y="value",
color="variable",
title=TITLE,
).update_layout(
yaxis_type="log",
width=800,
).show()
# matplotlib
import matplotlib.pyplot as plt
df_plot = df.dropna()[INCLUDE]
fig, ax = plt.subplots(figsize=(10, 5))
for col in df_plot.columns:
ax.plot(df_plot.index, df_plot[col], label=col)
ax.set_yscale('log')
ax.set_title(TITLE)
ax.legend()
ax.grid()
plt.show()