Utiliser ce que l'on sait déjà
En simulant un call, vous simulez aussi le prix de l'action à l'échéance S_T, dont la vraie moyenne S0 * exp(r * T) est exactement connue. Dans votre échantillon, la moyenne de S_T est sortie un peu fausse, disons trop haute. Comme le gain du call et S_T évoluent ensemble, la moyenne empirique du call est probablement trop haute aussi. Une variable de contrôle exploite cela : elle retranche à l'estimation de la quantité voulue un multiple de l'erreur observée sur la quantité connue.
import numpy as np
rng = np.random.default_rng(1)
z = rng.standard_normal(2000)
s_t = 100.0 * np.exp((0.05 - 0.5 * 0.2 ** 2) + 0.2 * z) # terminal prices
call = np.maximum(s_t - 100.0, 0.0) # the payoff we want
known = 100.0 * np.exp(0.05) # E[S_T], exactly
print(round(float(s_t.mean()), 3), round(known, 3)) # the sample mean of S_T vs its true mean
print(round(float(s_t.mean() - known), 3)) # the observed error of the controlLe meilleur multiple
Quelle part de l'erreur du contrôle faut-il retrancher ? Le multiple b qui minimise la variance de payoff - b * control vaut b = cov(payoff, control) / var(control), exactement la pente de la régression du gain sur le contrôle (les mêmes sommes que le bêta du sujet MEDAF). L'estimation contrôlée est mean(payoff) - b * (mean(control) - known_mean). Elle est sans biais, car le terme retranché est d'espérance nulle.
import numpy as np
def control_coefficient(payoff, control):
dev = control - control.mean()
return float(np.sum(dev * (payoff - payoff.mean())) / np.sum(dev ** 2))
rng = np.random.default_rng(1)
z = rng.standard_normal(2000)
s_t = 100.0 * np.exp((0.05 - 0.5 * 0.2 ** 2) + 0.2 * z)
call = np.maximum(s_t - 100.0, 0.0)
known = 100.0 * np.exp(0.05)
b = control_coefficient(call, s_t)
controlled = call.mean() - b * (s_t.mean() - known)
print(round(b, 4), round(float(call.mean()), 4), round(float(controlled), 4)) # the plain mean and the corrected one# A payoff that is exactly proportional to the control is estimated without any error
import numpy as np
x = np.random.default_rng(2).standard_normal(50) + 5.0 # the control, known mean 5.0
y = 2.0 * x # the payoff
dev = x - x.mean()
b = np.sum(dev * (y - y.mean())) / np.sum(dev ** 2)
print(round(float(b), 6), round(float(y.mean() - b * (x.mean() - 5.0)), 6)) # 2.0 and exactly 10.0Combien d'erreur est économisée
Les échantillons ajustés payoff - b * control portent le bruit, donc l'erreur standard de l'estimation contrôlée est leur écart-type (ddof=1) divisé par sqrt(n). Avec une corrélation rho entre gain et contrôle, la variance diminue d'un facteur 1 - rho^2 : une corrélation de 0,9 en supprime 81 %, et 0,99 en supprime 98 %. Le contrôle ne coûte aucune simulation supplémentaire, seulement quelques lignes de plus.
import numpy as np
def control_variate_error(payoff, control):
dev = control - control.mean()
b = np.sum(dev * (payoff - payoff.mean())) / np.sum(dev ** 2)
return float((payoff - b * control).std(ddof=1) / np.sqrt(len(payoff)))
rng = np.random.default_rng(1)
z = rng.standard_normal(20000)
s_t = 100.0 * np.exp((0.05 - 0.5 * 0.2 ** 2) + 0.2 * z)
for strike in (80.0, 100.0, 120.0):
call = np.maximum(s_t - strike, 0.0)
plain = float(call.std(ddof=1) / np.sqrt(len(call)))
print(strike, round(plain, 4), round(control_variate_error(call, s_t), 4), round(plain / control_variate_error(call, s_t), 2))b est proche de 0 et rien n'est gagné) et sa moyenne exacte doit être connue (sinon la correction n'est qu'une hypothèse). Pour la moyenne arithmétique d'une option asiatique, de bons contrôles sont la moyenne géométrique, dont le prix a une formule, ou le prix terminal lui-même. On peut utiliser plusieurs contrôles à la fois, les coefficients provenant alors d'une régression multiple.- Une variable de contrôle est une quantité simulée de moyenne connue ; on retranche à l'estimation un multiple de son erreur observée :
mean(Y) - b * (mean(X) - E[X]). - Le meilleur multiple est la pente de régression
b = cov(Y, X) / var(X); l'erreur est l'écart-type deY - b * Xdivisé parsqrt(n). - La variance diminue de
1 - rho^2; un bon contrôle est très corrélé au gain et de moyenne exactement connue, et ne coûte aucune simulation supplémentaire.
À suivre : les pipelines scikit-learn pour les rendements, ajuster et évaluer des modèles prédictifs sur des rendements.
Lab : ce qui est noté
- Choisir le bon multiple avec
control_coefficient25 pts - Corriger l'estimation avec
control_variate_estimate25 pts - Réduire la barre d'erreur avec
control_variate_error25 pts - Compter le gain avec
error_reduction25 pts