LLN & CLT
Law of Large Numbers (LLN)
Suppose are i.i.d. random variables from some distribution with mean and variance . Define , the LLN states that as goes to infinity, the probability that is close to goes to 1.
Central Limit Theorem (CLT)
As goes to infinty, the distribution of converges to . Thus we can compute the confidence intervals using the normal distribution.
We can estimate both and using the same sample: . And the standard error of the mean is .
A 95% confidence interval for is then
that is
It also can be interpreted that, if we draw a sample of size , then 95% of the time the true will fall within this CI.
We can increase to make this as narrow as we wish.
For example, if we require the precision is 0.01, i.e. , then
If we know the distribution for i.i.d variables, we can compute the easily, and then decide the based on the precision. However, sometimes we do not know the distributionβs in the beginning. Under such scenario, to decide , we can first start with a small to compute the and use it as an approximation to the . Then substitute into to compute the we need to achieve required precision.
Simulation for European Options
According to the Black-Scholes-Merton model
That is, a small change in a stockβs price at time is driven by
- A known return (the risk-free return )
- Stochastic volatility, , where is the volatility of the stock and is a standard Brownian motion (Weiner Process)
- A Weiner process is following , given , then
Taking as now and as some future time, and substituing for , we have
The price of a Europen option at time is the discounted expected value of the payoff at time , thus
from which we can compute and corresponding
Codes of Simulation for European Options
## European Call def simPrice_n(self, n): np.random.seed(0) z = np.random.standard_normal(n) ST = self._S0 * np.exp((self._r - 0.5 * self._sigma ** 2) * self._T + self._sigma * np.sqrt(self._T) * z) payoff = np.maximum(ST - self._K, 0) price_estimate = np.exp(-self._r * self._T) * payoff return price_estimate def simPrice(self, precision = 0.005): # start with 10,000 to get an initial sigma hat init_sim_n = 10000 Ci1 = self.simPrice_n(init_sim_n) C1 = np.mean(Ci1) se = np.std(Ci1) / np.sqrt(init_sim_n) CI95 = 1.96 * se print(f"CI95 for init_n = {init_sim_n} is {C1} +/- {CI95}") new_sim_n = int((1.96 * np.std(Ci1) / precision) ** 2 * 1.2) Ci2 = self.simPrice_n(new_sim_n) C2 = np.mean(Ci2) se2 = np.std(Ci2) / np.sqrt(new_sim_n) CI95 = 1.96 * se2 print(f"CI95 for revised_n = {new_sim_n} is {C2} +/- {CI95}") return C2
## European Put def simPrice_n(self, n): np.random.seed(0) z = np.random.standard_normal(n) ST = self._S0 * np.exp((self._r - 0.5 * self._sigma ** 2) * self._T + self._sigma * np.sqrt(self._T) * z) payoff = np.maximum(self._K - ST, 0) price_estimate = np.exp(-self._r * self._T) * payoff return price_estimate def simPrice(self, precision = 0.005): # start with 10,000 to get an initial sigma hat init_sim_n = 10000 Pi1 = self.simPrice_n(init_sim_n) P1 = np.mean(Pi1) se = np.std(Pi1) / np.sqrt(init_sim_n) CI95 = 1.96 * se print(f"CI95 for init_n = {init_sim_n} is {P1} +/- {CI95}") new_sim_n = int((1.96 * np.std(Pi1) / precision) ** 2 * 1.2) Pi2 = self.simPrice_n(new_sim_n) P2 = np.mean(Pi2) se2 = np.std(Pi2) / np.sqrt(new_sim_n) CI95 = 1.96 * se2 print(f"CI95 for revised_n = {new_sim_n} is {P2} +/- {CI95}") return P2
Simulation for Asian Options
Payoff and Exercise time
For European options:
- Time payoff:
- Call:
- Put:
- Exercise time:
For American options:
- Time payoff:
- Call:
- Put:
- Exercise time:
For Asian options:
- Time payoff:
- Call:
- Put:
- Exercise time:
To simulate for Asian options, we need to simulate the stock price path. Recall that under BSM assumptions
for time steps of , we can write
Due to weekends, holidays, there are 252 trading days per year approximately. There are 21 days per month on average, so 5 months have about 105 trading days.
105 trading days = 5 months = 0.4167 years, so 1 trading day = 0.003968 years = .
Codes of Simulation for Asian Options
## Asian Call import numpy as np def Asian_Call_Sim_n(S0, K, r, sigma, tdays, dt, npaths): zi = np.random.randn(npaths, tdays) price_paths = np.zeros((npaths, tdays+1)) price_paths[:, 0] = S0 for i in range(tdays): price_paths[:, i+1] = price_paths[:, i] * np.exp((r - sigma ** 2 / 2) * dt \ + sigma * dt ** 0.5 * zi[:, i]) Ci = np.exp(-r * tdays * dt) * np.maximum(np.mean(price_paths[:, 1:], axis=1) - K, 0) return Ci S0, K, r, sigma = 50, 50, 0.1, 0.4 tdays, dt = 105, 0.003968 def Asian_Call_sim(precision): init_n = 10000 np.random.seed(0) Ci1 = Asian_Call_Sim_n(S0, K, r, sigma, tdays, dt, init_n) C1 = np.mean(Ci1) se = np.std(Ci1) / np.sqrt(init_n) CI95 = 1.96 * se print(f"CI95 for init_n = {init_n} is {C1} +/- {CI95}") new_sim_n = int((1.96 * np.std(Ci1) / precision) ** 2 * 1.2) Ci2 = Asian_Call_Sim_n(S0, K, r, sigma, tdays, dt, new_sim_n) C2 = np.mean(Ci2) se2 = np.std(Ci2) / np.sqrt(new_sim_n) CI95 = 1.96 * se2 print(f"CI95 for revised_n = {new_sim_n} is {C2} +/- {CI95}") return C2
## Asian Put import numpy as np def Asian_Put_Sim_n(S0, K, r, sigma, tdays, dt, npaths): zi = np.random.randn(npaths, tdays) price_paths = np.zeros((npaths, tdays+1)) price_paths[:, 0] = S0 for i in range(tdays): price_paths[:, i+1] = price_paths[:, i] * np.exp((r - sigma ** 2 / 2) * dt \ + sigma * dt ** 0.5 * zi[:, i]) Pi = np.exp(-r * tdays * dt) * np.maximum(K - np.mean(price_paths[:, 1:], axis=1), 0) return Pi S0, K, r, sigma = 50, 50, 0.1, 0.4 tdays, dt = 105, 0.003968 def Asian_Put_sim(precision): init_n = 10000 np.random.seed(0) Pi1 = Asian_Put_Sim_n(S0, K, r, sigma, tdays, dt, init_n) P1 = np.mean(Pi1) se = np.std(Pi1) / np.sqrt(init_n) CI95 = 1.96 * se print(f"CI95 for init_n = {init_n} is {P1} +/- {CI95}") new_sim_n = int((1.96 * np.std(Pi1) / precision) ** 2 * 1.2) Pi2 = Asian_Put_Sim_n(S0, K, r, sigma, tdays, dt, new_sim_n) P2 = np.mean(Pi2) se2 = np.std(Pi2) / np.sqrt(new_sim_n) CI95 = 1.96 * se2 print(f"CI95 for revised_n = {new_sim_n} is {P2} +/- {CI95}") return P2
Loading Comments...