Autor: L. Kapera Použití: Kasino (především čistě náhodné hry např. ruleta a kostky), určité integrály Přístup: Náhodné údaje, z toho pravděpodobnost Náhodná dvojice (x, y) je vzorek. Po zpracování vzorků je pravděpodobnost , kde F je počet vzorků patřící do plochy , která je podmnožinou celé plochy. Odchylka: n = počet simulací (aritmetický průměr z dat) Směrodatná odchylka je odmocnina všech rozdílů hodnot od matematického průměru poděleným o počet pokusů mínus 1
Příklad na směrodatnou odchylku
Máme data 3, 3.15, 3.2, 3.5. Směrodatná odchylka? Průměr je 3,2125. Spočítáme rozdíl u každého data od průměru. Druhé mocniny: Suma: 0,131 875
Fresnelovy integrály - dálnice, horské dráhy - eulerova spirála Výpočet ceny opce (právo něco koupit a něco prodat v nějaký čas za nějakou cenu)
Opce
= 100 akcií (počet) = 40 euro (aktuální) Nákupní garantovaná cena = 42 euro (za kolik nakupuju) = 1 rok (čas) = 300 eur (3/akcie) (cena za opci) Akcie (výpočet) Drift - střední hodnot relativního výnosu [%] (za jak dlouho šla nahoru za rok) Volatilita - směrodatná odchylka driftu r (den má 252 dní) [%] - krátkodobé Platí že minulost počítáme, budoucnost odhadujeme. *Fedora → Desktop/python/monte_carlo
import numpy as np
# Parametry
S0 = 100 # Aktuální cena akcie
K = 105 # Strike cena (realizační cena)
T = 0.25 # Čas do splatnosti (3 měsíce = 0.25 roku)
r = 0.05 # Roční Drift(5 %)
sigma = 0.20 # Roční volatilita (20 %)
n_simulations = 100000
# 1. Generování náhodných šoků
z = np.random.standard_normal(n_simulations)
# 2. Výpočet koncových cen ST
# Všimni si, že T figuruje v driftu i v části s volatilitou
ST = S0 * np.exp((r - 0.5 * sigma**2) * T + sigma * np.sqrt(T) * z)
# 3. Výpočet výplaty (payoff)
# Výplata je max(S_T - K, 0)
payoffs = np.maximum(ST - K, 0)
# 4. Průměr a diskontování k dnešku
option_price = np.exp(-r * T) * np.mean(payoffs)
print(f"Odhadovaná cena evropské call opce (T=0.25): {option_price:.2f} €"
Minulost
- historický výnos z lze mít taky jako náhodný šok Brownův model (více zde - NA VLASTNÍ NEBEZPEČÍ ) Black-Scholes model (zde) Používá Gaussovu distribuci (Gaussův vzorec) Viz Monte Carlo na moji Fedoře
import pandas as pd
import matplotlib
matplotlib.use('module://matplotlib_inline.backend_inline')
from collections import Counter
import matplotlib.pyplot as plt
import math
import random
def count_volatility_and_drift(prices):
# Máš historické ceny: [100, 102, 98, 103, 101...]
# Spočítáš logaritmické výnosy
returns = []
for i in range(1, len(prices)):
r = math.log(prices[i] / prices[i-1])
returns.append(r)
# Drift = průměrný výnos * 252 (trading days)
drift = sum(returns) / len(returns) * 252
# Volatilita = std. odchylka výnosů * sqrt(252)
volatility = miss(returns) * math.sqrt(252) # tvoje miss funkce je std. odchylka
return drift, volatility
def miss(lis):
number = 0
for x in lis:
number +=x
average = number/len(lis)
semi_list = []
for x in lis:
if (x-average)**2 < 0:
semi_list.append((average-x)**2)
else:
semi_list.append((x-average)**2)
number = 0
for x in semi_list:
number+=x
return math.sqrt(number/len(lis))
def count(stock_price, strike_price, time, volatility, drift, simulation):
stock_prices = []
for x in range(simulation):
z = random.gauss(0,1)
u = time*(drift-0.5*volatility**2)+volatility*math.sqrt(time)*z
new_stock = stock_price*math.e**(u)
stock_prices.append(new_stock)
mis = 0
mis = miss(stock_prices)
ave = 0
for x in stock_prices:
ave+=x
return ave/(len(stock_prices)+1), mis
def count_all_data(stock_price, strike_price, time, volatility, drift, simulation):
stock_prices = []
for x in range(simulation):
z = random.gauss(0,1)
u = time*(drift-0.5*volatility**2)+volatility*math.sqrt(time)*z
new_stock = stock_price*math.e**(u)
stock_prices.append(new_stock)
return stock_prices
def filter_outliers(data, percentile_low=1, percentile_high=99):
"""
Odfiltruje extrémní hodnoty mimo percentily
"""
data_sorted = sorted(data)
n = len(data_sorted)
low_idx = int(n * percentile_low / 100) # ← PŘIDEJ /100
high_idx = int(n * percentile_high / 100) # ← PŘIDEJ /100
low_bound = data_sorted[low_idx]
high_bound = data_sorted[high_idx]
return [x for x in data if low_bound <= x <= high_bound]
def get_values():
type = 0
while type not in ["1","2"]:
type = input("Chceš zadat volatilitu manuálně [1] nebo ze souboru [2]: ")
if type == "1":
drift = None
while drift is None:
user_input = input("Drift v procentech: ")
try:
drift = float(user_input) / 100
except:
print("Napiš číslo.")
continue
volatility = None
while volatility is None:
user_input = input("Volatilita v procentech: ")
try:
volatility = float(user_input) / 100
except:
print("Napiš číslo.")
continue
else:
prices = None # Inicializuj na začátku!
answear = False
while not answear:
user = input("Chceš načíst z Excel xlsx [1], csv souboru [2] nebo txt souboru - oddělené řádky [3] \n")
if user == "1":
file_type = "excel"
print("Ujisti se, že sloupec s cenou se jmenuje 'Price'")
answear = True
elif user == "2":
file_type = "csv"
print("Ujisti se, že sloupec s cenou se jmenuje 'Price'")
answear = True
elif user == "3":
file_type = "text"
answear = True
abc = input("Zadej platný název souboru. Nezadávej příponu.\n")
try:
if file_type == "excel":
df = pd.read_excel(f'{abc}.xlsx')
prices = df['Price'].tolist()
elif file_type == "csv":
df = pd.read_csv(f'{abc}.csv')
prices = df['Price'].tolist()
elif file_type == "text":
prices = []
with open(f'{abc}.txt', 'r') as file:
for line in file:
prices.append(float(line.strip()))
# ↓↓↓ PŘIDEJ TENHLE KÓD ↓↓↓
# Vyčisti data od NaN a neplatných hodnot
prices = [p for p in prices if pd.notna(p) and p > 0]
if len(prices) < 2:
print(f"Chyba: Soubor má jen {len(prices)} platných cen. Potřebuješ aspoň 2.")
return get_values()
print(f"Načteno {len(prices)} platných cen z rozmezí {min(prices):.2f} - {max(prices):.2f}")
# ↑↑↑ KONEC NOVÉHO KÓDU ↑↑↑
except Exception as e:
print(f"Chyba při načítání souboru: {e}")
print("Zkus to prosím znovu.")
return get_values()
# Teď můžeš bezpečně použít prices
returns = []
for i in range(1, len(prices)):
r = math.log(prices[i] / prices[i-1])
returns.append(r)
drift = sum(returns) / len(returns) * 252
volatility = miss(returns) * math.sqrt(252)
# ↓↓↓ PŘIDEJ DEBUG INFO ↓↓↓
print(f"Drift: {drift:.4f} ({drift*100:.2f}%)")
print(f"Volatilita: {volatility:.4f} ({volatility*100:.2f}%)")
while True:
try:
stock_price = float(input("Zadej cenu akcie: "))
break
except:
print("Zadej prosím platné číslo.")
while True:
try:
strike_price = float(input("Zadej strike price: "))
break
except:
print("Zadej prosím platné číslo.")
while True:
try:
time = int(input("Zadej časové období (roky): "))
time = time*12+1
break
except:
print("Zadej prosím platné číslo.")
return drift, volatility, stock_price, strike_price, time
drift, volatility, stock_price, strike_price, month = get_values()
print("Úspěšně inicializováno. Počkej na grafy")
simulation = 150000
#drift = 0.05 #5% výnosnost
#stock_price = 100
#strike_price = 115
#volatility = 0.20
times = []
#month = 7*12+1
for x in range(month):
times.append(x/12)
price = []
mis = []
for x in times:
prices = count(stock_price, strike_price, x, volatility, drift, int(simulation))
prices = list(prices)
price.append(prices[0])
mis.append(prices[1])
prices_low = []
prices_high = []
strike_prices = []
for x in range(month):
if price[x] - mis[x] > 0:
prices_low.append(price[x] - mis[x])
else:
prices_low.append(0)
prices_high.append(price[x] + mis[x])
strike_prices.append(strike_price)
plt.figure() # ← PŘIDEJ TUHLE ŘÁDKU
plt.xlabel("čas (roky)")
plt.ylabel("odhadovaná cena stocku (EUR)")
plt.grid()
plt.plot(times, prices_low, label='Minimální cena akcie v čase')
plt.plot(times, prices_high, label='Maximální cena akcie v čase')
plt.plot(times, price, label='Cena akcie v čase')
plt.plot(times, strike_prices, label="strike price")
plt.legend()
plt.show(block=True)
# Výpočet v určitých časech
times = [round(0.55*month/12,2), round(month/12, 2), round(1.45*month/12, 2)]
# Vytvoř 1 řádek, 3 sloupce
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(20, 6), dpi=550)
for x in times:
# GRAF 1
data = count_all_data(stock_price, strike_price, x, volatility, drift, int(simulation*100*volatility))
data = filter_outliers(data, percentile_low=0.1, percentile_high=99.8)
for y in range(len(data)):
data[y] = int(data[y])
cetnosti = Counter(data)
values = sorted(cetnosti.keys())
counts = [cetnosti[v]/len(data) for v in values]
ax1.plot(values, counts, label=f"{x} roky")
# GRAF 2 - Přesný s logaritmickou osou (stejná data jako graf 1)
ax2.plot(values, counts, label=f"{x} roky")
# GRAF 3 - Histogram
ax3.hist(data, bins=50, alpha=0.5, density=True, label=f'{x} roky')
ax1.set_xlabel('Cena akcie')
ax1.axvline(x=strike_price, color='red', linestyle='--', label='Strike price')
ax1.set_ylabel('Relativní četnost')
ax1.set_title('Distribuce - lineární škála')
ax1.legend()
# Nastavení pro graf 2 (logaritmická osa)
ax2.set_yscale('log') # Tohle je klíčové - logaritmická Y osa
ax2.set_xlabel('Cena akcie')
ax2.axvline(x=strike_price, color='red', linestyle='--', label='Strike price')
ax2.set_ylabel('Relativní četnost (log škála)')
ax2.set_title('Distribuce - logaritmická škála')
ax2.legend()
# Nastavení pro graf 3 (histogram)
ax3.set_xlabel('Cena akcie')
ax3.set_ylabel('Četnost')
ax3.axvline(x=strike_price, color='red', linestyle='--', label='Strike price')
ax3.set_title('Histogram')
ax3.legend()
plt.tight_layout()
plt.show()