<jupyter_start><jupyter_text>MonteCarlo pricing of European options Standard geometric process<jupyter_code># parameters
strike = 75
init_price = 80
time_to_maturity = 1/2
vol = 0.25
r = 0.05 # risk free rate
q = 0.01 # cont. yield div rate
price_proc = Gaussian([10000, 1000], T=time_to_maturity).to_geometric(r-q, vol)
plt.figure()
plt.hist(price_proc.returns(), 80, density=True, histtype='step');
plt.figure()
plt.plot(price_proc.t, price_proc.process[:, :400]*init_price);
call_price = np.exp(-r*time_to_maturity)*np.sum(np.maximum(price_proc.process[-1, :]*init_price - strike, 0)) / price_proc.process.shape[1]
print(f"Call price: {round(call_price, 3)}")<jupyter_output>Call price: 9.144<jupyter_text>This approximately matches the B-S price for the same call option:<jupyter_code>def bs_call(x, k, ttm, r, q, sigma):
    d1 = (np.log(x/k) + (r-q + sigma**2/2)*ttm) / (sigma*np.sqrt(ttm))
    d2 = d1 - sigma*np.sqrt(ttm)
    return x*np.exp(-q*ttm)* norm.cdf(d1) - k*np.exp(-r*ttm)*norm.cdf(d2)

bs_call(init_price, strike, time_to_maturity, r, q, vol)<jupyter_output><empty_output><jupyter_text>Levy process<jupyter_code>price_proc = Levy(1.6, 0.7, [10000, 1000], T=time_to_maturity).to_geometric(r-q, vol)
plt.figure()
plt.hist(price_proc.returns(), 80, density=True, histtype='step', range=[-0.05, 0.05]);
plt.figure()
plt.plot(price_proc.t, np.log(price_proc.process[:, :50]*init_price))
plt.ylabel(r"$\log S_t$");<jupyter_output>/home/bora/.local/lib/python3.8/site-packages/price_process/process.py:55: RuntimeWarning: overflow encountered in exp
  self.process = normalize(np.exp(self.log_process*vol*np.sqrt(self.dt)+self.dt*(drift-0.5*vol**2)),0)<jupyter_text>Clearly there is a problem with enormous price moves that are not going to actually be realized. We can impose a hard price-move cutoff on our valid paths so that we count only *tame* jump price processes. The cutoff would then be estimated by fitting empirical option prices.<jupyter_code>gamma = 3
call_price_ = []
filtered_paths = []
for i in range(len (price_proc.process[0, :])):
    max_move = np.abs((price_proc.process[:, i]*init_price).max()-(price_proc.process[:, i]*init_price).min())
    if max_move < gamma*vol*init_price:
        call_price_.append(np.exp(-r*time_to_maturity)*(np.maximum(price_proc.process[-1, i]*init_price - strike, 0))) 
        filtered_paths.append(price_proc.process[:, i]*init_price)
print(f"Call price: {round(np.mean(call_price_), 3)}")


plt.plot(np.array(filtered_paths).T[:400]);<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1635717107862505, 'fraction_numerical': 0.032793362307388385, 'mean_word_length': 5.994475138121547, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '49621', 'license': 'MIT', 'n_tokens_mistral': 1032, 'n_tokens_neox': 952, 'n_words': 188, 'path': 'QuantitativeFinance/.ipynb_checkpoints/MCoption pricing-checkpoint.ipynb', 'repo_name': 'borab96/misc-notebooks', 'size': '2531'}