def metriques_fenetre(panneau_local, debut, fin):
lignes = {}
for t in UNIVERS:
complet = panneau_local[("Close", t)].dropna()
if len(complet) < 5:
continue
h = panneau_local[("High", t)].reindex(complet.index)
l = panneau_local[("Low", t)].reindex(complet.index)
v = panneau_local[("Volume", t)].reindex(complet.index)
r = complet.pct_change()
# L'estimateur a besoin d'une fenetre glissante de 21 seances : on le calcule sur le
# panneau ENTIER puis on echantillonne la periode. Le calculer sur fevrier seul (19
# seances) rendrait NaN -- la fenetre n'y tient pas, et le ratio serait indefini.
ecart = spread_corwin_schultz(h, l).loc[debut:fin]
lignes[t] = {
"adv_musd": float((complet.loc[debut:fin] * v.loc[debut:fin]).mean() / 1e6),
"ecart_cs_bp": float(ecart.median() * 1e4),
"vol_jour_bp": float(r.loc[debut:fin].std() * 1e4),
}
return pd.DataFrame(lignes).T
panneau_2020 = yf.download(UNIVERS, start="2020-01-02", end="2020-07-01",
auto_adjust=False, progress=False, threads=True)
fevrier = metriques_fenetre(panneau_2020, "2020-02-01", "2020-02-29")
mars = metriques_fenetre(panneau_2020, "2020-03-01", "2020-03-31")
commun = fevrier.index.intersection(mars.index)
stress = pd.DataFrame(index=commun)
stress["adv_fev_musd"] = fevrier.loc[commun, "adv_musd"]
stress["ratio_adv"] = mars.loc[commun, "adv_musd"] / fevrier.loc[commun, "adv_musd"]
stress["ecart_fev_bp"] = fevrier.loc[commun, "ecart_cs_bp"]
stress["ratio_ecart"] = mars.loc[commun, "ecart_cs_bp"] / fevrier.loc[commun, "ecart_cs_bp"]
# Meme calibrage que la partie 4 : ratio a l'ancre du titre le plus liquide de l'univers.
ancre = proxys["ecart_cs_bp"].min()
demi_fev = fevrier.loc[commun, "ecart_cs_bp"] / ancre * ANCRE_DEMI_ECART_BP
demi_mars = mars.loc[commun, "ecart_cs_bp"] / ancre * ANCRE_DEMI_ECART_BP
stress["capacite_fev_musd"] = participation_max(demi_fev, fevrier.loc[commun, "vol_jour_bp"]) * fevrier.loc[commun, "adv_musd"]
stress["capacite_mars_musd"] = participation_max(demi_mars, mars.loc[commun, "vol_jour_bp"]) * mars.loc[commun, "adv_musd"]
stress["ratio_capacite"] = stress["capacite_mars_musd"] / stress["capacite_fev_musd"]
print("=== stress COVID reel : fevrier -> mars 2020 (memes titres, meme formule) ===")
print(stress.round(3).to_string())
print(f"\nmediane ratio ADV : {stress['ratio_adv'].median():.2f}")
print(f"mediane ratio ecart : {stress['ratio_ecart'].median():.2f}")
print(f"mediane ratio capacite : {stress['ratio_capacite'].median():.3f}")
n_adv_hausse = int((stress["ratio_adv"] > 1).sum())
n_capacite_baisse = int((stress["ratio_capacite"] < 1).sum())
print(f"titres dont l'ADV a augmente : {n_adv_hausse} / {len(stress)}")
print(f"titres dont la capacite a baisse : {n_capacite_baisse} / {len(stress)}")
fig, ax = plt.subplots(figsize=(7.5, 5))
ax.axhline(1, color="gray", lw=0.8, ls="--")
ax.axvline(1, color="gray", lw=0.8, ls="--")
ax.scatter(stress["ratio_adv"], stress["ratio_ecart"], s=55, color="#c44e52", zorder=3)
for t in stress.index:
ax.annotate(t, (stress["ratio_adv"][t], stress["ratio_ecart"][t]),
textcoords="offset points", xytext=(6, 4), fontsize=9)
limite = max(2.0, float(stress["ratio_ecart"].max()) * 1.05)
ax.plot([1, limite], [1, limite], color="gray", lw=0.8, ls=":", label="volume et ecart bougeraient ensemble")
ax.set_xlim(0.5, float(stress["ratio_adv"].max()) * 1.1)
ax.set_ylim(0.5, limite)
ax.set_xlabel("ratio du volume echange (mars / fevrier 2020)")
ax.set_ylabel("ratio de l'ecart estime (mars / fevrier 2020)")
ax.set_title("En crise, le volume monte et l'ecart explose : les deux proxys divergent")
ax.legend(fontsize=8)
ax.grid(alpha=0.25)
plt.tight_layout()
plt.show()