Метод Монте-Карло

Содержание

  • Прогнозирование цены биткоина с помощью независимого от пути моделирования по методу Монте-Карло и библиотеки Python Numpy
  • Моделирование рисков с помощью Python
  • Построение симулятора цены акций по методу Монте-Карло с геометрическим броуновским движением и бутстрап-выборкой
  • Оптимизации параметров и анализа чувствительности качества процессов в Python
  • Расширенный анализ инвестиционных рисков

Прогнозирование цены биткоина с помощью независимого от пути моделирования по методу Монте-Карло и библиотеки Python Numpy

Мотивация

Чтобы предсказать цену биткоина через год после даты оценки (т.е. 26 ноября 2021 года) с помощью независимого от пути моделирования по методу Монте-Карло и библиотеки Python Numpy, я выбрал набор исторических цен на биткоин, который был получен из Yahoo Finance. Этот набор данных был основан на исторических ценах биткоина в период с 26 ноября 2020 года по 25 ноября 2021 года.

Дата оценки: 26 ноября 2021 г.

Прогноз: 26 ноября 2022 г.

1. Деловое понимание

На этом этапе я дам краткий обзор моделирования методом Монте-Карло.

Моделирование методом Монте-Карло (MCS) может применяться в различных областях, в частности, при моделировании поведения систем, в которых присутствует определенная степень неопределенности.

В нашем случае цель состоит в том, чтобы смоделировать поведение цены биткоина, сгенерировав множество возможных путей.

Чтобы сгенерировать траектории, необходимо сделать предположение о статистическом процессе, который управляет ценой биткоина — в случае с финансовыми активами это часто предполагается геометрическим броуновским движением.

Рассмотрим модель базовой цены биткоина:

dS = μ ⋅ S ⋅ dt + σ ⋅ S ⋅ dz

Где μ — скорость дрейфа, σ — волатильность доходности цен на биткоин, а dz — это процесс Винера.

Используя модель для цены биткоина, мы можем определить, как цена биткоина изменяется со временем, основываясь на приведенных выше параметрах.

На практике; Ниже перечислены шаги, необходимые для проведения MCS:

  1. «Смоделировать» реальный случайный путь актива, используя стандартную нормальную случайную величину, взятую из нормального распределения вероятностей. Эта переменная будет иметь среднее значение 0 и дисперсию, равную 1 (так как она была получена из нормального распределения).
  2. Сгенерировать n случайных путей для актива (обычно это от 1 000 до 1 000 000 раз или более, чем больше путей генерируется, тем точнее становится моделирование — однако это также подразумевает более длительное время, необходимое для запуска моделирования).
  3. Рассчитайте цену биткоина на целевую дату для каждого из этих случайных путей.
  4. Среднее значение всех цен биткоина по всем сгенерированным путям, и это значение является прогнозируемой ценой биткоина на целевую дату.

Следует отметить, что стандартное нормальное случайное число, используемое в большинстве случаев MCS, на самом деле является «псевдослучайным» числом, т.е. оно не является по-настоящему случайным.

2. Понимание данных

На этом шаге я оценю ожидаемую нормативную волатильность биткоина на один год.

Ожидаемая волатильность — это ожидаемое колебание доходности цены биткоина в течение целевого горизонта. Еще один способ определить волатильность цены биткоина — это годовое стандартное отклонение непрерывно начисляемых норм доходности цены биткоина за определенный период времени.

Ожидаемая волатильность была оценена на основе исторической волатильности на основе ежедневных наблюдений за 1 год, предшествующих дате оценки (с 26 ноября 2020 г. по 25 ноября 2021 г.).

По моей оценке, последний 1 год истории должен дать адекватную оценку будущей волатильности в течение следующего 1 года.

Во-первых, давайте импортируем соответствующие библиотеки:import pandas as pd
import numpy as np
from pandas_datareader import data as pdr
import yfinance as yfin
yfin.pdr_override()

Во-вторых, давайте выберем тикер, дату начала и дату окончания окна:Ticker = “BTC-USD”
Start_Date = “2020–11–27”
End_Date = “2021–11–26”

В-третьих, давайте проанализируем исторические цены и создадим датафреймdf = pdr.get_data_yahoo(Ticker, start=Start_Date , end=End_Date))
df = df.reindex(index=df.index[::-1])
df

Поскольку, нас интересуют только цены закрытия, опустим остальные столбцыdf.drop([‘Open’, ‘High’, ‘Low’, ‘Adj Close’,’Volume’],axis=1,inplace=True)

Затем давайте переименуем метод «Закрыть»df.rename(columns={“Close”: “Price”},inplace=True)
df

Поскольку нас интересует волатильность доходности, а не волатильность цены, давайте рассчитаем дневную доходность, используя дневные цены.df[‘Return’] = 0.000
for x in range(364):
df[‘Return’][x]=np.log(df[‘Price’][x]/df[‘Price’][x+1])
df

После того, как у нас есть ежедневная доходность, мы можем рассчитать дневную волатильностьdaily_volatility = np.std(df[‘Return’][:-1])
print(“The daily volatility of the bitcoin is:”, “{:.2%}”.format(daily_volatility))

Ежедневная волатильность биткоина составляет: 4.20%annual_volatility = daily_volatility*np.sqrt(252)
print(“The annualized volatility of the bitcoin is:”, “{:.2%}”.format(annual_volatility))

Волатильность биткоина в годовом исчислении составляет: 66.70%

Итак, мы получили оценку параметра σ, которая составляет 66,70%.

3. Подготовка данных

На этом шаге я оценю ожидаемую нормативную доходность биткоина за один год.

Ожидаемая доходность биткоина была оценена на основе модели CAPM.

Согласно модели, требуемая инвесторами норма доходности, k, получается из следующей формулы:

CAPM: k = Rf + β ⋅ E(Rm-Rf)

где:

Rf: безрисковая ставка. Поскольку цена биткоина номинирована в долларах США, следовательно, мы должны использовать безрисковый курс в долларах США. Мы рассмотрели доходность к погашению процентных ставок по казначейским ценным бумагам США (непрерывно сложным), срок действия которых составлял один год, с доходностью к погашению примерно 0,20% на дату оценки.

rf = 0.0020

E(Rm-Rf): премия за рыночный риск. Чтобы оценить эту премию, мы рассмотрели среднюю избыточную доходность индекса S&P 500 над долгосрочной безрисковой ставкой. На дату оценки этот компонент оценивался примерно в 4,38%.

mrp = 0.0438

β: «Бета» отражает интенсивность волатильности доходности биткоина по отношению к колебаниям доходности рыночного портфеля (т.е. индекса S&P 500) и является мерой систематического риска биткоина. Мы оценили коэффициент бета, используя линейную регрессию по отношению к доходности рыночного портфеля (на ежедневной основе) в качестве независимой переменной по отношению к доходности биткоина за два года до даты оценки.

Во-первых, давайте импортируем соответствующие библиотеки:import statsmodels.api as sm
from statsmodels import regression
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import datetime
from scipy import stats
from pandas_datareader import data as pdr
from sklearn.linear_model import LinearRegression

Во-вторых, давайте выберем тикеры, дату начала и дату окончания окна:df1 = pdr.get_data_yahoo([“BTC-USD”], start=”2019–11–26″, end=”2021–11–26″)
df2 = pdr.get_data_yahoo([“^GSPC”], start=”2019–11–26″, end=”2021–11–26″)

В-третьих, давайте объединим цены закрытия двух наборов данныхdaily_prices = pd.concat([df1[‘Adj Close’], df2[‘Adj Close’]], axis=1)
daily_prices.columns = [‘BTC-USD’, ‘^GSPC’]# check the head of the dataframe
daily_prices = daily_prices.reindex(index=daily_prices.index[::-1])
daily_prices

В-четвертых, посчитаем дневную доходностьdaily_returns = daily_prices.pct_change(1)
clean_daily_returns = daily_returns.dropna(axis=0)
clean_daily_returns

В-пятых, разделим зависимую и независимую переменныеX = clean_daily_returns[‘^GSPC’]
y = clean_daily_returns[‘BTC-USD’]# Add a constant to the independent value
X1 = sm.add_constant(X)# make regression model
model = sm.OLS(y, X1)# fit model and print results
results = model.fit()
print(results.summary())

results.params

beta = results.params[1]
print(“The beta of the bitcoin is:”, “{:.2}”.format(beta))

Бета биткоина составляет: 0.94mu = rf + beta * mrp
print(“The expected return of the bitcoin is:”, “{:.2%}”.format(mu))

Ожидаемая доходность биткоина составляет: 4.32%

4. Моделирование

На этом шаге я построю модель Монте-Карло.

Модель Монте-Карло широко используется в ситуациях, когда отсутствует аналитическое решение. Эта модель использует моделирование факторов риска в соответствии с предполагаемым распределением вероятностей, а затем вычисляет будущую цену в конце каждого пути отдельно. Подсчитывается каждая будущая цена. Среднее значение называется прогнозируемой ценой. В этом вычислении я буду использовать 5 000 случайных путей.

Во-первых, давайте импортируем соответствующие библиотеки:import numpy as np
import pandas as pd
from scipy.stats import norm
from numpy.random import randn
from numpy import random as rn
from matplotlib import pyplot as plt
%matplotlib inline

Во-вторых, я возьму рыночную цену биткоина по состоянию на 31 ноября 2021 года в качестве спотовой цены

S0 = 54332.22

В-третьих, установим горизонт прогноза в 1 годsigma = annual_volatility
T = 1

В-четвертых, установим количество путей на 5 000M = 5000
N = 1
h = T/N
Z = rn.randn(M)
data = S0*np.ones(M)# initialize list of lists
data1 = {‘S0’:data,
‘Normsinv’:Z}
# Create the pandas DataFrame
df = pd.DataFrame(data1)

# print dataframe.
df

В-пятых, создадим вектор цены биткоина на целевую дату.df[‘ST’] = df[‘S0’]*np.exp((mu-sigma**2/2)*h+sigma*np.sqrt(h)*df[‘Normsinv’])

В-шестых, создадим визуализацию будущего распределения цен биткоинаimport numpy as np
import matplotlib.pyplot as plt
import seaborn as snsclass Histplot:
def __init__(self, x_data, num_bins, linetype=’ro-’, title=None, xlabel=None, ylabels=None, fsize=(20, 20), df_line=1):
“””
:param x_data: data x list
:param num_bins: the number of x groups
:param linetype: The style of the cumulative frequency curve, the default is red solid point
:param legends: legend name, default is “linear fitting result”, “actual measured value”
:param xlabel: the name of the x axis title, default is “data x”
:param ylabels: double y axis title name, the default is “count”, “cumulative frequency”
:param df_line: Whether to display the cumulative frequency curve
“””
if title is None:
title = “Frequency / Cumulative Chart”
if xlabel is None:
xlabel = “Bitcoin Price One-Year from Today”
if ylabels is None:
ylabels = [“Frequency”, “Probability”]
self.x_data = x_data
self.num_bins = num_bins
self.linetype = linetype
self.fsize = fsize
self.title = title
self.xlabel = xlabel
self.ylabels = ylabels
self.df_line = df_linedef change_title(self, new_title):
# Change the title name to new_legends
self.title = new_titledef change_ylabel(self, new_labels):
# Change the title of the dual y axis to new_labels
self.ylabels = new_labelsdef change_xlabel(self, new_label):
# Change the x-axis axis title to new_label
self.xlabel = new_labeldef change_linetype(self, new_linetype):
# Change the format of the cumulative frequency line to new_lintype
self.linetype = new_linetypedef draw_plot(self):
fs = self.fsize # Canvas size
# Use the seaborn library to set the font size uniformly, which is 0.12 times of fgsize[1], that is, when the vertical size of the canvas is 1000, font_scale=1.2
sns.set_style(“ticks”)
sns.set_context(“talk”, font_scale=fs[1]*0.2)# Set canvas
fig, ax = plt.subplots(figsize=fs)# ax: draw frequency histogram, not selectable
n, bins, patches = ax.hist(self.x_data, self.num_bins, color = “red”, rwidth=0.9, label=self.title[0])
ax.set_title(self.title, fontsize=20)
ax.set_xlabel(self.xlabel, fontsize=16)
ax.set_ylabel(self.ylabels[0], fontsize=16)# ax2: Draw cumulative frequency curve, optional
if self.df_line:
leiji_n = [sum(n[:i]) / M for i in range(len(n) + 1)]
ax2 = ax.twinx()
ax2.plot(bins, leiji_n, self.linetype, ms=fs[0]*0.2, color=”firebrick”, linewidth=4, label=self.title[0])
ax2.set_ylim(0, 1)
ax2.set_ylabel(self.ylabels[1], fontsize=16)# Display multiple legends
# fig.legend(loc=1, bbox_to_anchor=(1, 1), bbox_transform=ax.transAxes)
# fig.tight_layout()
plt.grid()
plt.show()if __name__ == “__main__”:
bins = 100 # Data grouping
plot1 = Histplot(df[‘ST’], num_bins=bins, fsize=(10, 6))
plot1.draw_plot()

df

Наконец, давайте разработаем прогноз цены биткоина через годPredictedPrice = np.mean(df[‘ST’])
print(“The bitcoin predicted price one-year from today is:”, “${:,}”.format(round(PredictedPrice,2)))

Прогнозируемая цена биткоина через год с сегодняшнего дня составляет: $56 615,66

5. Оценка

На этом шаге я проверю уровень точности модели.

Стандартная ошибка выборочного среднего, как правило, служит показателем уровня точности модели. Поскольку эта стандартная ошибка уменьшается очень медленно с увеличением количества путей, обычно необходимо использовать тысячи (или даже десятки тысяч) путей выборки, чтобы достичь приемлемого уровня точности.PredictedError = np.std(df[‘ST’]) / np.sqrt(len(df[‘ST’]))
print(“The bitcoin predicted error is:”, “${:,}”.format(round(PredictedError,2)))

Прогнозируемая ошибка биткоина: $613.47PredictedErrorPct = PredictedError / PredictedPrice
print(“The predicted error is:”, “{:.2%}”.format(PredictedErrorPct))

Прогнозируемая погрешность: 1.08%

6. Развертывание

На этом шаге я построю 95-процентные доверительные интервалы вокруг прогнозируемого значения. Это:

Во-первых, давайте импортируем соответствующие библиотеки:import numpy as np
import pandas as pd
from scipy.stats import norm
from numpy.random import randn
from numpy import random as rn
import scipy.stats as si
from matplotlib import pyplot as plt
from IPython.display import Image
%matplotlib inline

Во-вторых, давайте создадим функцию, которая предоставляет значение Z для кумулятивной вероятности, используя стандартное нормальное распределение. Если мы предполагаем, что наши данные нормально распределены, и заинтересованы в знании значения Z для заданной вероятности, эта функция обеспечит это, используя кумулятивные вероятности распределения.def normsinv(x):
x = si.norm.ppf(x)
return (x)

В-третьих, вычислим значение Z для 95% доверительного интервалаz = normsinv(0.975)
z

1.959963984540054

В-четвертых, вычислим нижний уровень доверительного интервалаLowerBoundary = PredictedPrice — z*PredictedError
LowerBoundary

55413.28681329845

В-четвертых, вычислим верхний уровень доверительного интервалаUpperBoundary = PredictedPrice + z*PredictedError
UpperBoundary

57818.03429712247print(“The 95% confidence interval for the bitcoin predicted price one-year from today is between”, “${:,}”.format(round(LowerBoundary,2)), “and”, “${:,}”.format(round(UpperBoundary,2)))

Доверительный интервал 95% для прогнозируемой цены биткоина через год с сегодняшнего дня составляет от $55 413,29 до $57 818,03

Результаты. По моим оценкам, прогнозируемая цена биткоина через год составляет от $55 413,29 до $57 818,03. Средняя стоимость прогнозируемой цены биткоина через год с сегодняшнего дня составляет $56 615,66 за биткоин на дату оценки.

Моделирование рисков с помощью Python

Посмотрев сериал «Миллиарды» и написав свою первую статью на Medium о моделях стоимости под риском (VaR), изображенных в сериале, у меня появился интерес к моделированию рисков, в этой статье мы попытаемся построить еще один вариант нашей ранее использованной модели VaR, чтобы еще раз приблизиться к воздействию Axe Capital. Прочтите наш предыдущий сценарий здесь

https://medium.com/@mnyandenilunga/value-at-risk-var-models-how-big-financial-institutions-manage-risk-4ba0c9dce4cd

Что такое моделирование методом Монте-Карло?

Моделирование методом Монте-Карло — это вычислительные методы, которые включают генерацию случайных выборок или симуляций для моделирования и анализа сложных систем. Они используются в различных областях для аппроксимации поведения системы и результатов. Процесс включает в себя определение проблемы, установление входных распределений, генерацию случайных выборок, выполнение моделирования, анализ результатов и формулирование выводов. Моделирование методом Монте-Карло обеспечивает вероятностный подход к пониманию систем и ценно для принятия решений и оценки рисков.

Монте-Карло (VaR) с Python

  1. Загрузка и предварительная обработка данных
import numpy as np #we are importing our modules needed to preprocess our data
import pandas as pd
#we are reading in our price data from a csv file
#the data is mostly going to me OHLC prices
df=pd.read_csv('GasPrices2023.csv')
#we are gonna be using our Close price for any further calculations
prices = df['Close']

2. Рассчитайте наши параметры

Наш первый расчет — это %returns. Практика расчета процентной доходности в финансовом анализе и моделировании служит нескольким целям. Выражение доходности в процентах позволяет стандартизировать сравнение различных активов, обеспечивает согласованность в измерении относительных изменений стоимости, передает величину изменений, обеспечивает сопоставимость по периодам времени и инвестициям и облегчает применение статистического анализа. Используя проценты, становится легче понять и интерпретировать эффективность инвестиций и проанализировать их влияние на различные размеры инвестиций.

returns =prices.pct_change().dropna()

Наш второй расчет — это стандартное отклонение (сигма) и среднее значение нашей доходности. Расчет стандартного отклонения и среднего значения доходности в финансовом анализе важен по разным причинам. Стандартное отклонение помогает измерить риск и волатильность, позволяя инвесторам оценить потенциальную изменчивость доходности. Это имеет решающее значение для построения портфеля, управления рисками и оценки исторических результатов. Средняя доходность дает представление о средней производительности, в то время как стандартное отклонение помогает понять последовательность или волатильность доходности. Эти показатели используются в статистическом анализе, оптимизации портфеля и оценке доходности с поправкой на риск. В целом, расчет стандартного отклонения и среднего значения доходности предоставляет ценную информацию для оценки рисков, принятия решений и оценки эффективности в финансах.

volatility = returns.std()
mean_return = returns.mean()

3.Инициализируйте параметры, необходимые для симуляции

# Define the parameters for gas prices simulation
initial_price =prices.iloc[-1] # Use the last price as the initial price
num_simulations = 10000 # Number of simulations
confidence_level = 0.95 # Confidence level for VaR estimation

4. Да начнётся симуляция!

#we are going to do a thousand simulations for a whole year
for i in range(num_simulations):
price_paths[i, 0] = initial_price

for day in range(1, 365):
drift = mean_return * (1 / 365)
shock = volatility * np.random.randn() * np.sqrt(1 / 365)
price_paths[i, day] = price_paths[i, day - 1] * (1 + drift + shock)

5. Просмотрите и проанализируйте

На этом этапе мы проанализируем результаты нашего моделирования и посмотрим, как работает наш портфель.

# Calculate daily returns for each simulation
returns = (price_paths[:, 1:] - price_paths[:, :-1]) / price_paths[:, :-1]

# Calculate the portfolio value at the end of 2023
portfolio_value = 1000000 # Example portfolio value
portfolio_returns = portfolio_value * returns

# Calculate the VaR
sorted_portfolio_returns = np.sort(portfolio_returns)
var_index = int(num_simulations * (1 - confidence_level))
var = -sorted_portfolio_returns[var_index]

# Print the VaR estimation
print(f"VaR ({confidence_level * 100}% confidence level) for 2023 gas prices: {var:.2f}")

Заключение

Моделирование Python и методом Монте-Карло представляет собой мощную комбинацию для анализа и моделирования данных финансовых временных рядов. Гибкость и эффективность Python, наряду с такими библиотеками, как NumPy и pandas, позволяют легко манипулировать, анализировать и визуализировать финансовые данные. Моделирование методом Монте-Карло помогает оценить вероятности, оценить риски и получить представление о потенциальных результатах. Они позволяют оценивать риски, оценивать эффективность, анализировать сценарии и итеративно улучшать финансовые модели. Используя моделирование Python и Монте-Карло, аналитики и исследователи могут принимать более обоснованные решения и эффективно управлять рисками в финансовой сфере.

Построение симулятора цены акций по методу Монте-Карло с геометрическим броуновским движением и бутстрап-выборкой

Введение

Я создал веб-приложение с использованием Python Flask, которое позволяет моделировать будущие движения цен на акции с помощью метода, называемого моделированием по методу Монте-Карло, с выбором двух «разновидностей»: геометрического броуновского движения (GBM) и начальной выборки.

Содержание

  • Геометрическое броуновское движение (GBM)
  • Моделирование по методу Монте-Карло
  • Моделирование одной заготовки с помощью GBM
  • Моделирование нескольких акций в портфеле с помощью GBM
  • Альтернативный подход с использованием выборки Bootstrap
  • Bootstrap против GBM: что работает лучше?
  • Заключение

Геометрическое броуновское движение

Возможно, вы знакомы с броуновским движением из школьной физики. Это, казалось бы, случайное движение частиц воздуха, когда они сталкиваются друг с другом. Хотя мы, возможно, не в состоянии охарактеризовать поведение отдельной частицы, физика и статистика дают нам возможность описать вероятность того, где в конечном итоге окажется вся система.

Источник изображения: Википедия

Точно так же геометрическое броуновское движение является моделью доходности активов, в которой цена (или доходность) актива/акции/инвестиции может быть смоделирована как случайное блуждание (т.е. процесс, в котором изменения цен на акции имеют одинаковое распределение и независимы друг от друга). Таким образом, он предполагает, что прошлое движение или тенденция цены акций или рынка не могут быть использованы для прогнозирования их будущего движения (Источник: Investopedia)

Вместо того, чтобы с головой погружаться в какие-то достаточно сложные стохастические дифференциальные уравнения, интуиция того, как это работает,

где:

  • S= цена акции
  • dSt=изменение цены акции
  • μ=ожидаемая доходность
  • σ=стандартное отклонение доходности
  • t = случайная величина Винеровского процессагде приращения за t времени имеют нормальное распределение N с центром в нуле (т.е. W t -W₀~ N(0,t) )
  • dt=истекший период времени

По сути, модель GBM позволяет нам моделировать будущие цены, основываясь на комбинации «дрейфа», который обусловлен средним значением (т.е. средним значением логарифмической доходности), и «шока», который является случайным, но все же может быть охарактеризован волатильностью (т.е. стандартным отклонением логарифмической доходности).

https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgfycat.com%2Fifr%2FJealousPoliticalIlladopsis&display_name=Gfycat&url=https%3A%2F%2Fthumbs.gfycat.com%2FJealousPoliticalIlladopsis-mobile.mp4&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=gfycat

Однако следует отметить, что модель делает несколько КЛЮЧЕВЫХ допущений:

  • Логарифмическое изменение цены акции нормально распределено *
  • Волатильность (т.е. стандартное отклонение логарифмической доходности) постоянна
  • Ожидаемая доходность (т.е. среднее значение логарифмической доходности) не зависит от динамики акций

(*Вам может быть интересно, почему мы используем доходность вместо цены — это потому, что доходность не зависит от масштаба (в процентах, а не в абсолютных значениях) и часто имеет более «стабильные» статистические свойства (например, постоянное среднее и дисперсия). Кроме того, логарифмические доходы имеют преимущество перед простыми, потому что логарифм логарифмически нормально распределенной случайной величины будет нормально распределен. Эти три поста (1) , (2) и (3) от statsexchange более подробно описаны.)

Однако, как мы увидим позже, эти условия не всегда могут быть верными, поэтому достоверность любых предсказаний должна быть оценена очень тщательно.

Моделирование по методу Монте-Карло

Как упоминалось ранее, у меня уже есть отдельная статья на эту тему, но в двух словах: моделирование по методу Монте-Карло — это метод прогнозирования путем многократного запуска моделей со случайными величинами и агрегирования всех результатов для понимания диапазона результатов.

https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgfycat.com%2Fifr%2Flivelyobviousanhinga&display_name=Gfycat&url=https%3A%2F%2Fgfycat.com%2Flivelyobviousanhinga&image=https%3A%2F%2Fthumbs.gfycat.com%2FLivelyObviousAnhinga-size_restricted.gif&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=gfycat

Поэтому, несмотря на то, что каждая итерация прогноза GBM будет немного отличаться, мы можем сделать несколько прогнозов и агрегировать все результаты, чтобы увидеть общий диапазон потенциальных изменений цены в течение желаемого периода времени.

Как и следовало ожидать, чем дальше в будущее, тем шире диапазон возможных цен (т.е. от P10 до P90). (Как правило, существует научная работа, в которой говорится, что GBM лучше всего подходит для прогнозирования, когда он ограничен максимум 2-недельным прогнозом)

Моделирование одной модели с помощью GBM

Веб-приложение было создано путем расширения некоторого кода, созданного другим автором, как показано в статье ниже, где я объединил его с Python Flask, чтобы пользователи могли выбрать счетчик запасов, а также желаемый диапазон исторических данных и продолжительность прогноза через веб-сайт.

Код выглядит примерно так, как показано ниже, где есть функция для извлечения цен на акции из Yahoo Finance с помощью pandasDataReaderimport pandas as pd
from pandas_datareader import dataimport numpy as np, numpy.random
from numpy import meanimport random
import matplotlib.pyplot as pltfrom datetime import datetimefrom scipy.stats import norm
from scipy.stats import kstest
from scipy.stats import skew
from scipy.stats import kurtosis
from scipy import statsdef extract_prices(start_date,end_date,symbols,backtestduration=0):
dim=len(symbols)
for symbol in symbols:
dfprices = data.DataReader(symbols, start=start_date, end=end_date, data_source=’yahoo’)
dfprices = dfprices[[‘Adj Close’]]
dfprices.columns=[‘ ‘.join(col).strip() for col in dfprices.columns.values] for i in range(0,len(symbols)):
noOfShares.append(portfolioValPerSymbol[i]/priceAtEndDate[i])
noOfShares=[round(element, 5) for element in noOfShares]
listOfColumns=dfprices.columns.tolist()
dfprices[«Adj Close Portfolio»]=dfprices[listOfColumns].mul(noOfShares).sum(1)

print(f»Extracted {len(dfprices)} days worth of data for {len(symbols)} counters with {dfprices.isnull().sum().sum()} missing data»)

return dfprices

После чего другая функция преобразует цены в Log Returnsdef calc_returns(dfprices,symbols):
dfreturns=pd.DataFrame()
columns = list(dfprices)
mean=[]
stdev=[]
for column in columns:
dfreturns[f’Log Daily Returns {column}’]=np.log(dfprices[column]).diff()
mean.append(dfreturns[f’Log Daily Returns {column}’][1:].mean())
stdev.append(dfreturns[f’Log Daily Returns {column}’][1:].std())
dfreturns=dfreturns.dropna()

if len(dfreturns.columns)==1:
df_mean_stdev=pd.DataFrame(list(zip(symbols,mean,stdev)),columns =[‘Stock’, ‘Mean Log Daily Return’,’StdDev Log Daily Return’])
else:
df_mean_stdev=pd.DataFrame(list(zip(symbols+[«Portfolio»],mean,stdev)),columns =[‘Stock’, ‘Mean Log Daily Return’,’StdDev Log Daily Return’])

return dfreturns ,df_mean_stdev

Эти логарифмические доходы передаются в качестве входных данных в другую функцию, которая оценивает среднее значение , стандартное отклонение, которое затем передается вместе с начальной ценой в функцию, которая вписывает входные данные в уравнение, рассмотренное в предыдущем разделеdef GBMsimulatorUniVar(So, mu, sigma, T, N):
«»»
Parameters
So: initial stocks’ price
mu: expected return
sigma: volatility
Cov: covariance matrix
T: time period
N: number of increments
«»» dim = np.size(So)
t = np.linspace(0., T, int(N))
S = np.zeros([dim, int(N)])
S[:, 0] = So
for i in range(1, int(N)):
drift = (mu — 0.5 * sigma**2) * (t[i] — t[i-1])
Z = np.random.normal(0., 1., dim)
diffusion = sigma* Z * (np.sqrt(t[i] — t[i-1]))
S[:, i] = S[:, i-1]*np.exp(drift + diffusion)
return S, t

Однако есть важное предостережение относительно достоверности результатов. В коде наиболее подходящее нормальное распределение оценивается на основе исторических данных, но что более важно, так это то, насколько «нормальными» являются доходы.

Поэтому я привил ряд статистических тестов на нормальность, которые я не буду подробно останавливать в этой статье. Достаточно сказать, что эти тесты генерируют статистику и p-значение, которые могут быть проверены на соответствие выбранному уровню значимости, чтобы проверить «нормальность» (*) исторических данных о доходности. В частности, я внедрил два теста: критерий Колмогорова-Смирнова и тест Шапиро Уилка с уровнем значимости 5%. (Почему 5% ? Здесь читайте это)

(* Строго говоря, это не совсем «проверка» как таковая, но я бы не хотел пока вдаваться в механику того, как работает проверка гипотез)

К сожалению, анализ нескольких различных акций (с использованием исторических данных за период от 6 месяцев до года) показывает, что доходность не всегда является «нормальной» в соответствии с произвольным примером ниже для акций CRM (Salesforce) и NFLX (Netflix) за период с января 2019 года по июль 2020 года.

Результаты журнала CRM НЕ являются нормальными (значение P 0,0048 < альфа 0,05), но возвраты журнала NFLX являются нормальными (значение P 0,068 > 0,05)

Однако пока давайте просто предположим, что акции, на которых мы будем использовать этот метод, будут вести себя «хорошо».

Моделирование нескольких акций в портфеле с помощью GBM

Более реалистичной задачей является моделирование портфеля акций, состоящего из нескольких счетчиков.

К сожалению, вы не можете просто запустить отдельные симуляции GBM для 2 разных акций, а затем объединить их, потому что, хотя движение доходности для каждой акции является случайным, доходность(*) по акциям коррелирует.

(*Как упоминалось в предыдущем разделе, оценивается соотношение доходности, а не цены. В этой статье объясняется, почему)

<ВНИМАНИЕ: НЕМНОГО МАТЕМАТИКИ ВХОДИТ! >

<Нажмите здесь, если хотите пропустить теорию>

Поэтому, чтобы включить этот корреляционный эффект обратно в модель GBM, мы используем модифицированную форму предыдущего уравнения, которая теперь включает новый член Aij, фактор Холецкого матрицы ковариации между доходностью акций

Источник: Глассерман. А. «Методы Монте-Карло в финансовом инжиниринге». Т. 53 (2013)

Этот член разложения Холецкого используется на матрице ковариации возвратов и умножается на матрицу некоррелированных случайных величин, чтобы «индуцировать» корреляцию между ними.

В качестве примера ниже приведена ковариационная матрица для того же примера, составленная ранее из 3-х элементов — счетчиков запасов CRM и NFLX за один и тот же период. Как правило, ковариационные матрицы немного сложнее интерпретировать, потому что они отражают «абсолютную» совместную изменчивость, поэтому еще один способ визуализировать связь между переменными — использовать корреляционную матрицу, которая является «нормализованной» версией ковариационной матрицы, где каждое значение находится в диапазоне от -1 (полностью отрицательно коррелировано) до 0 (нет корреляции) и +1 (идеально положительно коррелировано)

Ковариационная матрица; Декомпозиция ковариационной матрицы Холецкого ; и корреляционная матрица для акций CRM и NFLX за период с января 2019 г. по июль 2020 г.

К сожалению, с этим новым членом в уравнении, в дополнение к тому, являются ли доходы «нормально распределенными», требуется еще одна проверка того, является ли ковариационная матрица симметричной положительно определенной.

Особенно для больших портфелей с десятками, если не разными акциями, это становится более сложным, потому что мы должны беспокоиться не только о корреляции между двумя разными акциями, но и обо всех корреляциях между НЕСКОЛЬКИМИ акциями, чтобы отношения оставались «последовательными»

Как следствие, иногда алгоритм может выдавать сообщение об ошибке LinAlgError: Matrix is not positive definite — разложение Холецкого не может быть вычислено. (Эта положительная определенность является характеристикой матрицы, позволяющей многократно умножать ее без изменения знака векторов)

Это связано с тем, что на практике данные о доходности акций могут иметь шум или, особенно для больших портфелей с большим количеством акций (т.е. высокая размерность), некоторые акции могут быть мультиколлинеарными (где могут быть взаимозависимости между доходностью акций).

Обратите внимание, что многомерная форма GBM предполагает, что ковариация ТАКЖЕ постоянна с течением времени (Примечание: К сожалению, на практике, как и среднее значение и дисперсия, корреляция также может меняться с течением времени)

<МАТЕМАТИЧЕСКОЕ ПРЕДУПРЕЖДЕНИЕ ЗАКАНЧИВАЕТСЯ>

Таким образом, объединение всего этого в виде кода выглядит примерно так, как показано ниже, где есть еще одна новая функция для вычисления ковариации логарифмической доходности между различными акциями, а функция GBM имеет дополнительный ковариационный член в качестве входных данных.def create_covar(dfreturns):
try:
returns=[]
arrOfReturns=[]
columns = list(dfreturns)
for column in columns:
returns=dfreturns[column].values.tolist()
arrOfReturns.append(returns)
Cov = np.cov(np.array(arrOfReturns))
return Cov
except LinAlgError :
Cov = nearPD(np.array(arrOfReturns), nit=10)
print(«WARNING -Original Covariance Matrix is NOT Positive Semi Definite And Has Been Adjusted To Allow For Cholesky Decomposition «)
return Covdef GBMsimulatorMultiVar(So, mu, sigma, Cov, T, N):
«»»
Parameters
So: initial stocks’ price
mu: expected return
sigma: volatility
Cov: covariance matrix
T: time period
N: number of increments
«»» dim = np.size(So)
t = np.linspace(0., T, int(N))
A = np.linalg.cholesky(Cov)
S = np.zeros([dim, int(N)])
S[:, 0] = So
for i in range(1, int(N)):
drift = (mu — 0.5 * sigma**2) * (t[i] — t[i-1])
Z = np.random.normal(0., 1., dim)
diffusion = np.matmul(A, Z) * (np.sqrt(t[i] — t[i-1]))
S[:, i] = S[:, i-1]*np.exp(drift + diffusion)
return S, t

Альтернатива GBM — Bootstrap Sampling

К сожалению, метод GBM должен делать много предположений о форме базового распределения, чтобы он работал. Поэтому я хотел поделиться альтернативным подходом под названием Bootstrap Sampling With Replacement

Этот метод берет случайные выборки из исторических данных для создания новых «синтетических» наборов данных для прогнозирования будущих цен. Таким образом, бутстреппинг обходит необходимость в явной теоретической модели для генерации прогнозов (поэтому он и называется бутстреппингом после выражения «подтяни себя за бутстрапы», что означает улучшить свою ситуацию без посторонней помощи).

В коде я смоделировал эту выборку с поведением замены, используя random.randint numpy для «выбора» случайной метки времени для извлечения исторических результатов журнала. Затем это делается несколько раз, чтобы создать последовательность случайных возвратов журнала для построения прогноза.def bootstrap_w_replc_singleval(dfreturns):
columns=dfreturns.columns ____singlesample=pd.DataFrame(dfreturns.values[np.random.randint(len(dfreturns), size=1)], columns=columns)
return singlesampledef bootstrapforecast(dfreturns,T):
columnlist=dfreturns.columns
X=[]
for i in range(0,T):
____X.append(bootstrap_w_replc_singleval(dfreturns).values.tolist()[0])
Y=pd.DataFrame(X)
Y.columns=columnlist
Y.loc[-1] = [0]*len(columnlist) # adding a row
Y.index = Y.index + 1 # shifting index
Y = Y.sort_index() # sorting by index

return Y

Тем не менее, этот подход по-прежнему опирается на извлеченные исторические данные о доходности, которые являются объективным представлением базового поведения доходности акций.

Кроме того, несмотря на то, что данные больше не должны быть нормально распределены, бутстреппинг предполагает, что среднее значение и дисперсия являются гомоскедастическими (т.е. неизменными с течением времени). Другими словами, мы предполагаем, что любое наблюдение (из набора данных исторической доходности) с равной вероятностью будет выбрано, и его выбор является независимым.

Этот метод также работает для портфелей из нескольких акций, но в отличие от другого метода с GBM, с Bootstrap Sampling , нет необходимости оценивать ковариации, потому что вместо этого мы будем выбирать «целую строку» доходностей из исторических данных, тем самым неявно фиксируя любые корреляции между ними.

Bootstrap против GBM: что работает лучше?

Итак, какой из двух методов, какой из них работает лучше? Ну, это зависит от обстоятельств….

Сравнение метода GBM и метода начальной загрузки для агрегированных результатов за 100 итераций

Основная первая проверка должна состоять в том, чтобы проверить нормальность и асимметрию распределения возвращаемых значений (поскольку GBM необходимо это предположение для того, чтобы результаты были достоверными)

Однако в приведенном выше примере форма распределения логарифмической доходности, по-видимому, указывала на то, что доходность акций соответствовала предположениям о нормальности и имела довольно ровную симметричную форму (что подразумевало, что GBM должен был быть допустимым подходом)

Однако, по сравнению с Bootstrap Sampling за тот же период тестирования на истории в 30 дней, метод GBM дал большую среднеквадратическую ошибку. Поэтому я бы посоветовал поэкспериментировать с обоими на разной длительности тестирования на истории и сравнить RMSE-s (или, если вы используете версию этого файла для Jupyter Notebook напрямую, я думаю, вы также можете написать свой собственный сценарий для тестирования MAE, MAPE или любой другой метрики точности прогнозирования, которую вы предпочитаете)

Заключение

Итак, после всего этого, большой вопрос… Можно ли использовать эти методы для прогнозирования будущих цен на акции и получения прибыли?

Короткий ответ: ….не совсем (к сожалению). Большинство реальных доходностей акций имеют распределение «толстого хвоста» и демонстрируют поведение кластеризации волатильности (т.е. стандартное отклонение и дисперсия не остаются хорошими и фиксированными с течением времени), что нарушает предположения, которые мы делали ранее.

Тем не менее, для некоторых акций в определенных временных рамках, где предположения все еще могут быть справедливыми (или близкими к тому, чтобы быть верными), этот метод предоставляет структурированный способ оценки относительного наихудшего и наилучшего варианта краткосрочной доходности (~1–2 недели).

Если вы посещали веб-сайт, вы, возможно, заметили, что, помимо GBM и Bootstrap Sampling, веб-приложение также позволяет делать прогнозы, используя другие «традиционные» статистические подходы к прогнозированию временных рядов, такие как ARIMA, Holt Winters и Vector Auto Regression. Дайте мне знать в комментариях ниже, если вы хотите, чтобы я рассказал о любом из этих других методов.

Оптимизации параметров и анализа чувствительности качества процессов в Python

Моделирование методом Монте-Карло является мощным методом, используемым в различных областях для моделирования и анализа сложных систем. Одним из его применений является моделирование влияния входных переменных на качество выходных данных. В сочетании с анализом чувствительности, который определяет входные данные, оказывающие наибольшее влияние на процесс, моделирование методом Монте-Карло дает ценную информацию для принятия обоснованных решений и улучшения процесса. Python, универсальный язык программирования, предоставляет удобную платформу для реализации моделирования по методу Монте-Карло и анализа чувствительности. В этой статье рассматривается использование Python для моделирования по методу Монте-Карло и анализа чувствительности для повышения качества процесса.

Рассмотрим производственный процесс, в ходе которого производится критически важный компонент, используемый в промышленном применении. Качество этого компонента имеет жизненно важное значение, так как любые дефекты или отклонения могут привести к эксплуатационным сбоям и значительным финансовым потерям. Чтобы обеспечить устойчивый и надежный процесс, организация стремится оптимизировать качество своих процессов. В настоящее время процесс имеет индекс производительности процесса (Ppk) 0,92 и коэффициент несоответствия спецификациям 0,6%. Для повышения качества процесса крайне важно определить ключевые факторы, влияющие на целевой показатель, и контролировать вариативность входных данных.

Регрессионный анализ является ключевым шагом в понимании взаимосвязи между выходными и входными переменными в производственном процессе. Проводя регрессионный анализ, мы можем получить ценную информацию о том, какие входные переменные оказывают значительное влияние на цель. Эта информация позволяет нам определить ключевые факторы, которые оптимизируют процесс и достигают желаемого качества продукции. С помощью Python мы можем эффективно и результативно выполнять регрессионный анализ, что позволяет нам извлекать значимую информацию из собранных данных о процессах и направлять наши усилия по улучшению процессов.

Ниже приведен регрессионный анализ данных процесса. Y — это выход процесса (отклик), а X1, X2, X3 и X4 — входные данные процесса (предикторы) процесса.

Изучение корреляционной матрицы перед выполнением регрессионного анализа является обычной практикой для понимания взаимосвязей между переменными в наборе данных. Корреляционная матрица помогает нам идентифицировать переменные, которые сильно коррелируют и могут привести к проблемам мультиколлинеарности.

Тепловая карта корреляции показывает, что корреляция между X2 и X4 составляет -0,97, что указывает на сильную отрицательную линейную зависимость между предикторами. Сильная отрицательная корреляция между двумя предикторами говорит о том, что они предоставляют аналогичную информацию для модели. В регрессионном анализе эта высокая корреляция между предикторами известна как мультиколлинеарность. Это может повлиять на стабильность коэффициентов регрессии и затруднить интерпретацию индивидуальных эффектов каждого предиктора. Удаление одного из предикторов может помочь уменьшить мультиколлинеарность и упростить интерпретацию модели. Решение о том, какой предиктор удалить, может быть основано на пошаговой регрессии для определения наиболее подходящего подмножества предикторов.

В этом регрессионном анализе используется обратное исключение, которое представляет собой пошаговый регрессионный подход, при котором модель запускается с включением всех предикторов и итеративно удаляет наименее значимый предиктор по одному за раз до тех пор, пока не будет достигнут желаемый критерий (например, определенный порог p-значения). Этот метод оценивает индивидуальный вклад каждого предиктора в модель с учетом их взаимосвязей.

Метод обратного исключения исключил предикторы X3 и X4 из модели, в конечном итоге выбрав предикторы X1 и X2 для модели. Это снижает мультиколлинеарность и упрощает интерпретацию модели. Для проверки мультиколлинеарности в регрессионной модели в качестве меры коллинеарности между переменными-предикторами можно использовать коэффициент инфляции дисперсии (VIF). VIF количественно определяет, насколько дисперсия оцениваемых коэффициентов регрессии завышена из-за мультиколлинеарности. Значение VIF больше 1 указывает на наличие мультиколлинеарности, а более высокие значения указывают на более сильный эффект коллинеарности.

Значения VIF (1,055) указывают на то, что мультиколлинеарность в модели отсутствует.

Сгенерируйте уравнение регрессии для оценки взаимосвязи между ответом Y и предикторами X1 и X2.

Коэффициент для X1 в уравнении равен 1,47, что указывает на то, что Y увеличится на 1,47 единицы при увеличении X1 на одну единицу, предполагая, что X2 остается постоянным. Это говорит о том, что X1 оказывает положительное влияние на значение Y.

Аналогичным образом, коэффициент для X2, равный 0,66, предполагает, что при увеличении X2 на одну единицу Y увеличится на 0,66 единицы, предполагая, что X1 остается постоянным. Это указывает на положительную связь между X2 и значением Y.

Создайте сводку модели для оценки сведений о модели регрессии.

Вот интерпретация ключевых статистических данных:

1. R-квадрат и скорректированный R-квадрат: Значение R-квадрата равно 0,979, что означает, что 97,9% изменчивости в Y объясняется X1 и X2. Скорректированный R-квадрат корректирует количество предикторов в модели. Скорректированное значение R-квадрата равно 0,979, что указывает на то, что регрессионная модель хорошо соответствует данным.

2. F-статистика и Prob (F-статистика): F-статистика проверяет общую значимость регрессионной модели. Большая F-статистика (229,5) с малым p-значением (4,41e-09) указывает на то, что модель является статистически значимой, предполагая, что по крайней мере один из предикторов значимо связан с реакцией.

3. Коэффициенты: Коэффициент const (52,5773) представляет собой пересечение или математическое ожидание Y, когда X1 и X2 равны нулю. Коэффициенты для X1 (1,4683) и X2 (0,6623) показывают, как изменение на одну единицу в каждом предикторе связано с изменением зависимой переменной.

4. P-значения: P-значения, связанные с каждым коэффициентом, проверяют нулевую гипотезу о том, что коэффициент равен нулю. При этом все коэффициенты имеют крайне малые p-значения (близкие к нулю), указывающие на то, что X1 и X2 значимо связаны с Y.

5. Омнибус: Омнибусный тест — это проверка предположения о нормальности остатков. В этом случае статистика Omnibus равна 1,509, а связанное с ней p-значение равно 0,470. Поскольку p-значение больше 0,05, нет существенных доказательств отклонения от нормы в остатках. Это указывает на то, что предположение о нормальности является разумным для модели.

6. Тест Жака-Бера: Тест Жака-Бера является еще одной проверкой предположения о нормальности остатков. Он исследует как асимметрию, так и эксцесс, чтобы оценить, следуют ли остатки нормальному распределению. В этом случае статистика Жака-Бера равна 1,104, а связанное с ней p-значение равно 0,576. Как и в омнибусном тесте, p-значение больше 0,05, что указывает на отсутствие существенных признаков отклонения от нормы.

7. Дурбин-Уотсон: Статистика Дурбина-Уотсона используется для определения наличия автокорреляции (корреляции невязок во времени) в модели. Значение Дурбина-Уотсона, равное 1,922, указывает на положительную автокорреляцию, что означает, что остатки положительно коррелируют с их запаздывающими значениями. Значение от 1 до 2 указывает на слабую положительную автокорреляцию.

В то время как статистические тесты, такие как Омнибус, Жака-Бера и Дурбин-Уотсон, могут дать представление о нормальности невязок и автокорреляции остатков, они могут не дать детального представления о природе и величине отклонений. Для получения более полного понимания гистограммы, Q-Q графики и диаграммы рассеяния будут использоваться в сочетании со статистическими тестами для тщательной оценки предположений.

График QQ (квантиль-квантиль) сравнивает квантили наблюдаемых невязок с квантилями, ожидаемыми при нормальном распределении. Этот график КК демонстрирует небольшие отклонения от прямой линии, что указывает на незначительные отклонения от нормы. Это распространенная проблема в моделях с небольшими размерами выборки.

Гистограмма также показывает небольшое отклонение от ожидаемой колоколообразной кривой нормального распределения.

Диаграмма рассеяния невязок в зависимости от порядка наблюдения оценивает независимость наблюдения, которая является предположением критерия Дурбина-Уотсона. Эта диаграмма рассеяния невязок в зависимости от порядка наблюдения демонстрирует случайный разброс точек без различимой закономерности или тенденции, что предполагает независимость.

Диаграмма рассеяния невязок и аппроксимированных значений проверяет, является ли разброс (дисперсия) невязок согласованным на разных уровнях прогнозируемых значений. Диаграмма рассеяния невязок и аппроксимированных значений показывает случайный разброс точек с постоянным разбросом вокруг нуля, что указывает на постоянную дисперсию остатков.

Прочтите эту статью, чтобы получить подробное руководство по проверке регрессионной модели с помощью графиков и статистических тестов.

https://medium.com/@chenchungwai/a-comprehensive-guide-to-regression-model-validation-with-visual-tools-and-statistical-tests-in-f86d4ff6efbb

В целом, модель хорошо подходит для данных. Полученные результаты свидетельствуют о том, что X1 и X2 имеют сильную положительную связь с Y, на что указывают положительные коэффициенты и их статистическая значимость. Остатки в модели распределены приблизительно нормально без существенных отклонений от нормы.

Несмотря на то, что регрессионный анализ дает ценную информацию о взаимосвязи между переменными и позволяет нам достичь целевого результата, установив X1 и X2, он имеет определенные ограничения. Уравнение регрессии представляет собой среднее отношение между входными и выходными переменными, предполагая фиксированные значения входных переменных. Однако в реальных сценариях существует неотъемлемая изменчивость, связанная с входными переменными, что приводит к изменчивости выходной переменной.

Моделирование методом Монте-Карло является мощным методом, который устраняет это ограничение, включая присущую входным переменным изменчивость. Он позволяет оценить возможные результаты для выходной переменной путем моделирования многочисленных итераций с различными значениями входных переменных в зависимости от их наблюдаемой изменчивости. Такой подход позволяет сформировать распределение возможных результатов для выходной переменной и определить влияние на качество процесса.

Для оценки качества процесса с помощью моделирования по методу Монте-Карло мы анализируем значения выходных переменных, полученные в результате моделирования, чтобы определить индекс производительности процесса (Ppk) и частоту выхода за пределы спецификации. Эти метрики дают представление о вероятности того, что процесс соответствует спецификациям.

Для выполнения моделирования по методу Монте-Карло необходимо выполнить следующие шаги:

  1. Определите распределение вероятностей входных переменных:

Используйте исторические данные для определения среднего значения и стандартного отклонения входных переменных X1 и X2:

Среднее значение X1: 7.5
Стандартное отклонение X1: 0,6
X2 в среднем: 48
Стандартное отклонение X2: 1,6

2. Определите количество симуляций, которые необходимо выполнить:

Количество симуляций зависит от требуемого уровня точности и имеющихся вычислительных ресурсов. Увеличение количества симуляций, как правило, повышает точность и надежность результатов. Тем не менее, может наблюдаться убывающая отдача с точки зрения дополнительных аналитических сведений, получаемых от каждой дополнительной итерации. Важно найти правильный баланс между вычислительными ресурсами и желаемой точностью.

В данном случае мы выполним 1 000 000 симуляций.

Во время каждого моделирования генерируются случайные выборки для X1 и X2 на основе их соответствующих распределений вероятностей с использованием заданных средних значений и стандартных отклонений. Выходная переменная (Y) вычисляется с помощью уравнения регрессии Y = 52,58 + 1,47 * X1 + 0,66 * X2. Значения выходных переменных (Y), полученные в результате каждого моделирования, собираются для анализа распределения значений выходных переменных. Сравнивая смоделированные значения Y с заданным целевым значением (95,4) и нижним и верхним пределами спецификации (92,4 и 98,4), мы можем оценить индекс производительности процесса (Ppk) и коэффициент выхода за пределы спецификации. Этот анализ помогает нам определить вероятность соответствия спецификациям и выявить любые потенциальные проблемы с качеством процесса.

Выполняя моделирование по методу Монте-Карло, мы получаем лучшее понимание изменчивости выходной переменной и можем принимать более обоснованные решения относительно улучшения процесса и мер контроля качества.

Это скрипт Python для моделирования по методу Монте-Карло.import numpy as np

# Define the regression equation coefficients
intercept = 52.58
coef_x1 = 1.468
coef_x2 = 0.6623

# Define the target value, lower spec, and upper spec for y
target_y = 95.4
lower_spec = 91.6
upper_spec = 99.2

# Define the mean and standard deviation for X1 and X2
mean_x1 = 7.5
std_x1 = 0.6
mean_x2 = 48
std_x2 = 1.3

# Set the number of iterations for the Monte Carlo simulation
num_iterations = 1000000

# Initialize array to store the simulated y values
simulated_y = np.zeros(num_iterations)

# Perform the Monte Carlo simulation
for i in range(num_iterations):
# Generate random samples for X1 and X2
x1 = np.random.normal(mean_x1, std_x1)
x2 = np.random.normal(mean_x2, std_x2)

# Calculate the predicted value of y using the regression equation
y_predicted = intercept + coef_x1 * x1 + coef_x2 * x2

# Store the predicted value of y
simulated_y[i] = y_predicted

# Calculate the mean and standard deviation of the simulated y values
mean_simulated_y = np.mean(simulated_y)
std_simulated_y = np.std(simulated_y)

# Calculate the count and percentage of out-of-specification values
out_of_spec_count = np.sum((simulated_y < lower_spec) | (simulated_y > upper_spec))
out_of_spec_percentage = out_of_spec_count / num_iterations * 100

# Calculate the process capability (Cp)
cp = (upper_spec — lower_spec) / (6 * np.std(simulated_y))

# Calculate the process centering (Cpk)
cpk = min((upper_spec — mean_simulated_y) / (3 * np.std(simulated_y)),
(mean_simulated_y — lower_spec) / (3 * np.std(simulated_y)))

# Calculate the Process Performance Index (Ppk)
ppk = min(cp, cpk)

# Print the simulation results
print(«Mean of simulated y values:», mean_simulated_y)
print(«Standard deviation of simulated y values:», std_simulated_y)
print(«Out-of-Specification Count:», out_of_spec_count)
print(«Out-of-Specification Percentage:», out_of_spec_percentage)
print(«Process Capability (Cp):», cp)
print(«Process Centering (Cpk):», cpk)
print(«Process Performance Index (Ppk):», ppk)

Это результаты, полученные в результате моделирования методом Монте-Карло

Среднее значение равно 95,38, что указывает на то, что среднее прогнозируемое значение Y близко к целевому значению 95,4.
Стандартное отклонение равно 1,378, что говорит о некоторой изменчивости прогнозируемых значений Y.
Количество нестандартных значений равно 58453, что указывает на то, что из 1 миллиона симуляций 58453 смоделированных значений Y выходят за пределы указанного диапазона нижнего и верхнего пределов спецификации.
Процент несоответствия спецификации составляет 0,58 %, что дает представление о доле смоделированных значений, которые не соответствуют заданным требованиям к качеству.
Значение Cp равно 0,919, что говорит о том, что процесс имеет некоторую потенциальную способность соответствовать спецификациям.
Значение Cpk равно 0,914, что указывает на то, что процесс немного смещен в сторону одного из пределов спецификации.
Значение Ppk равно 0,914, что соответствует общей производительности процесса 0,914.

Результаты моделирования, полученные с помощью моделирования методом Монте-Карло, полностью соответствуют текущим характеристикам технологического процесса. Текущий индекс производительности процесса (Ppk) соответствует смоделированному значению Ppk, указывая на то, что моделирование точно отражает поведение процесса. Однако, поскольку нашей целью является достижение значения Ppk 1,67 или выше, мы признаем необходимость совершенствования процесса. Чтобы определить конкретные входные переменные, которые достигают этой цели, обратимся к оптимизации параметров. Оптимизация параметров — это метод, используемый для нахождения оптимальных значений входных переменных процесса, которые приводят к желаемым результатам или целям. Используя методы оптимизации, мы можем определить оптимальную комбинацию входных переменных, которая приведет к желаемому значению Ppk.

Для выполнения оптимизации параметров необходимо выполнить следующие шаги:

  1. Определите диапазон X1 и X2: задайте допустимый диапазон или границы, в пределах которых значения X1 и X2 могут изменяться.

Диапазон Х1 от 7,3 до 7,7
Диапазон X2 составляет от 47,8 до 48,2

2. Определите целевую функцию: Целевая функция максимизирует индекс эффективности процесса (Ppk).

3. Выполните моделирование по методу Монте-Карло: В цикле с заданным числом итераций, равным 1 000 000, генерируются случайные выборки X1 и X2 в пределах заданных диапазонов. Прогнозируемое значение y вычисляется с помощью уравнения регрессии. Вычисляется значение Cpk для смоделированного среднего значения y. Если вычисленное значение Cpk выше, чем текущее максимальное значение Cpk, обновляется самое высокое значение Cpk и соответствующие значения X1 и X2.

Выполнив оптимизацию параметров, мы можем определить оптимальные значения X1 и X2, которые максимизируют индекс производительности процесса (Ppk)

Это скрипт Python для оптимизации параметров.# Define the range of X1 and X2
x1_range = [7.3, 7.7]
x2_range = [47.8, 48.2]

# Set the number of iterations for the Monte Carlo simulation
num_iterations = 1000000

def calculate_cpk(mean_y, std_y):
cp = (upper_spec — lower_spec) / (6 * std_y)
cpk = min((upper_spec — mean_y) / (3 * std_y),
(mean_y — lower_spec) / (3 * std_y))
return cpk

# Initialize variables to store the highest Cpk and its corresponding X1 and X2
highest_cpk = 0.0
best_x1 = 0.0
best_x2 = 0.0

# Perform Monte Carlo Simulation
for i in range(num_iterations):
# Generate random samples for X1 and X2 within the specified range
x1 = np.random.uniform(*x1_range)
x2 = np.random.uniform(*x2_range)

# Calculate the predicted value of y using the regression equation
y_predicted = intercept + coef_x1 * x1 + coef_x2 * x2

# Calculate the standard deviation of y assuming a normal distribution
std_y = (upper_spec — lower_spec) / (6 * np.sqrt(3))

# Calculate the Cpk value for the simulated mean value of y
cpk = calculate_cpk(y_predicted, std_y)

# Update the highest Cpk and its corresponding X1 and X2 if necessary
if cpk > highest_cpk:
highest_cpk = cpk
optimized_x1 = x1
optimized_x2 = x2

# Calculate additional values based on the highest Cpk, optimized X1, and optimized X2
mean_simulated_y = intercept + coef_x1 * optimized_x1 + coef_x2 * optimized_x2
std_simulated_y = (upper_spec — lower_spec) / (6 * np.sqrt(3))
out_of_spec_count = np.sum((simulated_y < lower_spec) | (simulated_y > upper_spec))
out_of_spec_percentage = out_of_spec_count / num_iterations * 100
cp = (upper_spec — lower_spec) / (6 * std_simulated_y)
ppk = min(cp, highest_cpk)

# # Print the highest Cpk value and its corresponding X1 and X2
print(«Highest Cpk value:», highest_cpk)
print(«Optimized X1 value:», optimized_x1)
print(«Optimized X2 value:», optimized_x2)
# Print the optimized results
print(«Optimized Results:»)
print(«Mean of simulated y values:», mean_simulated_y)
print(«Standard deviation of simulated y values:», std_simulated_y)
print(«Out-of-Specification Count:», out_of_spec_count)
print(«Out-of-Specification Percentage:», out_of_spec_percentage)
print(«Process Capability (Cp):», cp)
Print(«Process Capability Index (Cpk):», highest_cpk)
print(«Process Performance Index (Ppk):», ppk)

Это результаты, полученные в результате оптимизации параметров

Процесс оптимизации параметров дал существенное улучшение качества процесса, о чем свидетельствуют следующие результаты:

Максимальное достигнутое значение Cpk составляет 1,73, превысив целевое значение 1,63. Это свидетельствует о существенном улучшении технологических возможностей и способности стабильно соответствовать спецификациям.

Оптимизированное значение X1 равно 7,46, а оптимизированное значение X2 — 48,13. Эти значения представляют собой оптимальные настройки входных переменных, которые максимизируют производительность процесса.

Среднее значение смоделированных значений y составляет 95,40, что соответствует целевому значению 95,4. Это указывает на то, что процесс был точно настроен для достижения желаемого результата.

Стандартное отклонение смоделированных значений y составляет 0,73, что свидетельствует о значительном снижении вариабельности выходных данных.

Количество выходящих за пределы спецификации равно 0, что указывает на то, что ни одно из смоделированных значений y не выходит за пределы указанного диапазона нижнего и верхнего пределов спецификации. Это означает значительное улучшение управления технологическим процессом и способность постоянно соответствовать желаемым требованиям к качеству.

Процент несоответствия спецификации составляет 0,0%.

Значение возможности процесса (Cp) теперь равно 1,73, процесс центрируется, когда Cp совпадает с Cpk.

Значение индекса производительности процесса (Ppk) соответствует самому высокому значению Cpk, равному 1,73, что отражает общую производительность процесса и его способность постоянно соответствовать спецификациям.

Процесс оптимизации параметров привел к значительному улучшению качества процесса, о чем свидетельствует более высокое значение Cpk, сниженная вариативность и отсутствие экземпляров, выходящих за рамки спецификации. Оптимизированные значения X1 и X2 привели к созданию процесса, который отличается высокой производительностью и неизменно соответствует требуемым спецификациям.

Анализ чувствительности, являющийся дополнительным методом оптимизации параметров, еще больше расширяет наше понимание процесса, изучая влияние входных переменных на выходные данные процесса. В отличие от оптимизации параметров, которая фокусируется на нахождении оптимальных значений для конкретных входных переменных, анализ чувствительности обеспечивает более широкое понимание того, как изменения различных входных переменных влияют на выход. Этот анализ особенно полезен на ранних стадиях разработки процесса или когда конкретные оптимальные значения входных переменных неизвестны.

Анализ чувствительности помогает нам определить ключевые факторы, которые вносят значительный вклад в изменчивость, позволяя нам расставить приоритеты входных переменных для дальнейшего исследования, выделяя входные данные, которые оказывают наибольшее влияние на выход.

Основываясь на выводах, полученных в результате оптимизации параметров, мы теперь обратимся к анализу чувствительности, чтобы оценить влияние изменения стандартных отклонений входных переменных X1 и X2 на процент значений, выходящих за пределы спецификации, для выходной переменной Y.

Для выполнения анализа чувствительности необходимо выполнить следующие шаги:

1. Определите диапазон процентных изменений для стандартных отклонений. Этот диапазон определяет степень, в которой будут скорректированы стандартные отклонения.

Диапазон процентных изменений для стандартных отклонений составляет от -20% до 20%.

2. Выполните моделирование по методу Монте-Карло, сгенерировав случайные выборки для X1 и X2 и скорректировав их стандартные отклонения на основе заданных диапазонов.

3. Рассчитайте процент значений, выходящих за рамки спецификации, как для X1, так и для X2. Это позволяет количественно оценить влияние изменения стандартных отклонений на значения, выходящие за рамки спецификации.

4. Постройте диаграмму рассеяния, чтобы визуализировать результаты анализа чувствительности.

Это скрипт Python для анализа чувствительности.# Define the range of percentage changes for standard deviations
percentage_changes = np.linspace(-0.20, 0.20, num=9)

# Initialize lists to store the out-of-specification percentages for X1 and X2
out_of_spec_percentage_x1 = []
out_of_spec_percentage_x2 = []

# Perform the Monte Carlo simulation for different standard deviations of X1 while holding X2 constant
for percentage_change in percentage_changes:
# Calculate the adjusted standard deviation for X1
std_x1_adjusted = std_x1 * (1 + percentage_change)

# Initialize counter for out-of-specification instances
out_of_spec_count_x1 = 0

# Perform the Monte Carlo simulation
for i in range(num_iterations):
# Generate random sample for X1 with fixed values
x1 = np.random.normal(mean_x1, std_x1_adjusted)

# Calculate the predicted value of y using the regression equation
y_predicted = intercept + coef_x1 * x1 + coef_x2 * mean_x2

# Check if the predicted value of y is out of specification for X1
if y_predicted < lower_spec or y_predicted > upper_spec:
out_of_spec_count_x1 += 1

# Calculate the percentage out-of-specification for X1
out_of_spec_percentage_x1.append((out_of_spec_count_x1 / num_iterations) * 100)

# Perform the Monte Carlo simulation for different standard deviations of X2 while holding X1 constant
for percentage_change in percentage_changes:
# Calculate the adjusted standard deviation for X2
std_x2_adjusted = std_x2 * (1 + percentage_change)

# Initialize counter for out-of-specification instances
out_of_spec_count_x2 = 0

# Perform the Monte Carlo simulation
for i in range(num_iterations):
# Generate random sample for X2 with fixed values
x2 = np.random.normal(mean_x2, std_x2_adjusted)

# Calculate the predicted value of y using the regression equation
y_predicted = intercept + coef_x1 * mean_x1 + coef_x2 * x2

# Check if the predicted value of y is out of specification for X2
if y_predicted < lower_spec or y_predicted > upper_spec:
out_of_spec_count_x2 += 1

# Calculate the percentage out-of-specification for X2
out_of_spec_percentage_x2.append((out_of_spec_count_x2 / num_iterations) * 100)

# Plot the scatterplot for both X1 and X2 simulations
plt.scatter(percentage_changes, out_of_spec_percentage_x1, color=’red’, label=’X1′)
plt.plot(percentage_changes, out_of_spec_percentage_x1, color=’red’, linestyle=’-‘, linewidth=2)
plt.scatter(percentage_changes, out_of_spec_percentage_x2, color=’blue’, label=’X2′)
plt.plot(percentage_changes, out_of_spec_percentage_x2, color=’blue’, linestyle=’-‘, linewidth=2)

plt.xlabel(«Change in Percentage of Standard Deviation»)
plt.ylabel(«% Out-of-Specification»)
plt.title(«Simulation Results: % Out-of-Specification vs Change in Standard Deviation»)
plt.legend()
plt.show()

На графике видно, что изменение процента стандартного отклонения X2 оказывает гораздо более существенное влияние на процент несоответствия спецификации по сравнению с изменением процента стандартного отклонения X1. Этот график дает ценную информацию о вкладе изменчивости X1 и X2 в процент несоответствия спецификации, что позволяет нам принимать обоснованные решения относительно контроля и улучшения процента несоответствия спецификации. Понимая это, мы можем стратегически сосредоточить наши усилия на оптимизации и управлении изменчивостью X2 для эффективного решения проблем, связанных с несоответствиями спецификациям.

Выполняя анализ чувствительности в сочетании с оптимизацией параметров, мы получаем полное представление о динамике процесса. В конечном счете, совместное использование анализа чувствительности и оптимизации параметров позволяет нам постоянно совершенствовать процессы и достигать их превосходного качества.

Расширенный анализ инвестиционных рисков

Раскрытие стратегий и управление рисками с помощью практических методов моделирования

Что такое моделирование по методу Монте-Карло?

Моделирование по методу Монте-Карло — это вычислительный алгоритм, который использует повторяющуюся случайную выборку для получения численных результатов. Фундаментальным принципом, лежащим в основе этого метода, является использование случайности для решения задач, которые в принципе могут быть детерминированными. Он назван в честь казино Монте-Карло в Монако из-за присущего методу элемента случайности, похожего на азартные игры. Этот подход особенно полезен во многих областях, включая финансы и торговлю, для моделирования сценариев, связанных с неопределенностью, и прогнозирования влияния риска.

Меня особенно интересует, как он используется в финансах. В контексте фондовых рынков и криптовалют моделирование по методу Монте-Карло используется для прогнозирования будущих движений цен путем моделирования широкого диапазона возможных исходов для цен на активы. Учитывая случайный характер финансовых рынков, этот метод хорошо подходит для оценки рисков и неопределенностей, присущих инвестированию. Инвесторы и аналитики используют его для моделирования вероятности различных потенциалов заработка, помогая им принимать обоснованные решения, понимая диапазон возможных результатов и вероятность достижения различных уровней доходности.

Моделирование по методу Монте-Карло для акций и криптовалют

Для акций и криптовалют моделирование часто включает в себя прогнозирование будущих цен на основе исторической волатильности и ценовых тенденций. Этот процесс обычно включает в себя следующее:

  1. Анализ исторических данных: Анализ исторических данных о ценах (таких как данные об открытии, максимуме, минимуме, закрытии (OHLC)) для определения средней доходности и волатильности.
  2. Генерация случайной выборки: Использование статистических моделей для получения случайной ежедневной доходности на основе исторической средней доходности и волатильности.
  3. Симуляция цены: многократный расчет будущих ценовых траекторий путем применения случайно сгенерированной доходности к текущей цене.
  4. Анализ результатов: Оценка распределения смоделированных будущих цен для оценки вероятности различных исходов.

Демонстрация моделирования по методу Монте-Карло на Python

Я хочу показать вам, как это работает, в двух частях, чтобы было проще понять.

Часть 1

Первым шагом является получение некоторых исторических торговых данных для работы. У меня есть подписка на API EODHD, и именно там я получаю свои данные для анализа. У них также есть библиотека Python под названием «eodhd», которая делает получение данных тривиальной задачей. Для этой демонстрации я собираюсь получить ежедневные данные по акциям S&P 500.

python3 -m pip install eodhd -U
import numpy as np
import matplotlib.pyplot as plt
from eodhd import APIClient

API_KEY = "<YOUR_KEY>"

api = APIClient(API_KEY)
df = api.get_historical_data("GSPC.INDX", "d", results=365)

print(df)
Скриншот автора
# Calculate daily returns
daily_returns = df["adjusted_close"].pct_change().dropna()
print(daily_returns)
Скриншот автора
# Simulation parameters
num_simulations = 1000
forecast_days = 365

# Initialise simulation array, all zeros
simulations = np.zeros((num_simulations, forecast_days))

# Simulate future paths
last_price = df["adjusted_close"].iloc[-1]
for i in range(num_simulations):
cumulative_returns = np.random.choice(daily_returns, size=forecast_days, replace=True).cumsum()
simulations[i, :] = last_price * (1 + cumulative_returns)

print(simulations)
Скриншот автора

Подводим итоги…

# Plotting the results
plt.figure(figsize=(10, 6))
plt.plot(simulations.T, color="blue", alpha=0.025)
plt.title("Monte Carlo Simulation of Future Prices")
plt.xlabel("Day")
plt.ylabel("Price")
plt.show()
Скриншот автора

Это выглядит красиво и все такое, но что это показывает нам на самом деле?

  1. Представление волатильности: Симуляция фиксирует диапазон возможных движений цены на основе исторической волатильности, обеспечивая визуальное представление неопределенности. Тем не менее, он предполагает, что прошлые модели волатильности сохранятся, что может быть не всегда так.
  2. Прогностические ограничения: Несмотря на то, что моделирование полезно для понимания потенциальных результатов, оно не может предсказать конкретные будущие цены. Рыночные условия, экономические факторы и непредвиденные события могут сильно повлиять на фактические результаты.
  3. Сценарное планирование: Распределение смоделированных результатов может помочь инвесторам планировать различные сценарии, оценивая потенциал прибыли по сравнению с риском потерь. Он поощряет вероятностный, а не детерминистский взгляд на будущие движения рынка.
  4. Допущения модели: Точность моделирования в значительной степени зависит от предположений, сделанных о распределении доходности и волатильности. Различные модели (например, предполагающие нормальную vs. log-нормальную доходность) могут давать разные результаты, что подчеркивает важность выбора и калибровки моделей.

Часть 2

В части 1 я хотел бы познакомить вас с основами. Я не думаю, что вы сможете сделать с ним что-то полезное. Это то, что я собираюсь вам сейчас показать.

Практическое применение моделирования по методу Монте-Карло для оценки инвестиционного риска и принятия инвестиционных решений включает в себя несколько ключевых этапов. Понимая диапазон и распределение потенциальных будущих цен, генерируемых моделированием, показанным в части 1, инвесторы могут количественно оценить риск и потенциальную доходность инвестиций. Вот как это применяется на практике:

1. Определение инвестиционных целей и толерантности к риску

Инвестор или портфельный менеджер начинает с определения своих инвестиционных целей, включая ожидаемую доходность и уровень риска, который они готовы терпеть. На толерантность к риску могут влиять такие факторы, как горизонт инвестирования, финансовые цели и личный комфорт инвестора в условиях неопределенности.

2. Запуск симуляции по методу Монте-Карло

Используя исторические данные и статистические модели, проводится большое количество симуляций для прогнозирования будущих ценовых траекторий рассматриваемых инвестиций (акций, криптовалют и т. д.). Каждая симуляция представляет собой возможный сценарий будущего, основанный на случайном возникновении ежедневных доходностей, отражающих историческую волатильность и модели доходности. Надеюсь, это было понятно из Части 1.

3. Анализ результатов моделирования

Результаты моделирования по методу Монте-Карло предоставляют диапазон возможных будущих цен в указанное время в будущем. Затем этот диапазон анализируется, чтобы понять потенциальные результаты инвестиций. Ключевые показатели, полученные в результате моделирования, включают:

  • Распределение вероятностей: Инвесторы будут смотреть на распределение смоделированных конечных цен, чтобы понять разброс результатов. Например, широкий спред указывает на высокую волатильность и, следовательно, на более высокий риск.
  • Value at Risk (VaR): Эта метрика оценивает максимальный потенциальный убыток за определенный период времени при заданном уровне достоверности. Например, 95% VaR в размере 1 000 фунтов стерлингов означает, что существует 95% вероятность того, что инвестор не потеряет более 1 000 фунтов стерлингов за указанный период.
  • Ожидаемый хвостовой убыток (ETL): ETL, также известный как условный VaR, предоставляет среднее значение потерь, которые происходят за пределами порога VaR, давая представление о потенциальных потерях в наихудших сценариях.

4. Принятие обоснованных решений

Основываясь на анализе, инвесторы могут принимать обоснованные решения, сравнивая профиль риска и доходности, выявленный с помощью моделирования по методу Монте-Карло, со своими инвестиционными целями и толерантностью к риску. Например:

  • Если вероятность достижения желаемой доходности превышает порог успеха инвестора, а связанные с этим риски (VaR, ETL) находятся в пределах его толерантности к риску, инвестиция может считаться приемлемой.
  • Если моделирование показывает высокую вероятность того, что доходность не достигнет целей или риски превысят допустимые для инвестора условия, он может принять решение о корректировке своей инвестиционной стратегии. Это может включать в себя диверсификацию портфеля, выбор инвестиций с различными профилями риска и доходности или изменение инвестиционного горизонта.

Практический пример:

Я хочу рассмотреть возможность инвестирования 10 000 фунтов стерлингов в S&P 500 и использовать моделирование по методу Монте-Карло для оценки риска. Моделирование должно показать, что с 95% уверенностью инвестиции не потеряют более 2000 фунтов стерлингов в течение следующего года (95% VaR). Кроме того, моделирование должно показать, что вероятность получения не менее 10% прибыли составляет 50%.

Например, моя толерантность к риску допускает потенциальный убыток в размере 2 000 фунтов стерлингов, а целью является доходность 10%, эту инвестицию можно рассматривать в пределах приемлемых параметров риска. Однако, если потенциальный убыток превышает допустимый риск инвестора или если вероятность достижения желаемой доходности считается слишком низкой, инвестор может искать альтернативы или изменять сумму инвестиций.

Этот процесс иллюстрирует практическое использование моделирования по методу Монте-Карло в оценке рисков и принятии инвестиционных решений. Он обеспечивает структурированный способ рассмотрения как потенциала роста, так и риска падения, поддерживая более тонкие инвестиционные стратегии, которые соответствуют конкретным целям риска и доходности.

Как это будет выглядеть в Python?

Во-первых, я хочу внести некоторые изменения в параметры моделирования.

# Calculate daily returns
daily_returns = df["adjusted_close"].pct_change().dropna()

# Simulation parameters
initial_investment = 10000 # Initial investment amount
num_simulations = 1000 # Number of simulations
forecast_days = 365 # Investment horizon in days
desired_return = 0.10 # Desired return (10%)

# Calculate the average daily return
average_daily_return = daily_returns.mean()

# Calculate volatility as the standard deviation of daily returns
volatility = daily_returns.std()

print(f"Average Daily Return: {average_daily_return}")
print(f"Volatility: {volatility}")
Скриншот автора

Просто ради интереса, если вы предпочитаете логарифмическую нормальную доходность, вы можете сделать это…

daily_returns = np.log(df["adjusted_close"] / df["adjusted_close"].shift(1)).dropna()

Я усовершенствовал логику симуляции…

# Simulating future returns
simulated_end_returns = np.zeros(num_simulations)
for i in range(num_simulations):
random_returns = np.random.normal(average_daily_return, volatility, forecast_days)
cumulative_return = np.prod(1 + random_returns)
simulated_end_returns[i] = initial_investment * cumulative_return

# Calculate the final investment values
final_investment_values = simulated_end_returns

print(final_investment_values)
Скриншот автора

На этом снимке экрана просто показано подмножество массива «final_investment_values», чтобы дать вам представление о том, как он выглядит.

Вычислить стоимость под риском (VaR) и ожидаемый убыток хвоста (условный VaR)

confidence_level = 0.95
sorted_returns = np.sort(final_investment_values)
index_at_var = int((1-confidence_level) * num_simulations)
var = initial_investment - sorted_returns[index_at_var]
conditional_var = initial_investment - sorted_returns[:index_at_var].mean()

print(f"Value at Risk (95% confidence): £{var:,.2f}")
print(f"Expected Tail Loss (Conditional VaR): £{conditional_var:,.2f}")
Скриншот автора

О чем это говорит?

Value at Risk (VaR) и Expected Tail Loss (Conditional VaR) — это показатели, используемые для понимания потенциальных потерь в инвестициях, но они подходят к этому пониманию немного по-разному.

Ценность под риском (VaR)

Когда мы говорим «Стоимость под риском (95% уверенность): £-1,926.81», это означает, что, основываясь на прошлых показателях и учитывая текущие условия, существует 95%-ная вероятность того, что ваши инвестиции не потеряют более £1,926.81 за указанный период времени. Проще говоря, это все равно, что сказать: «Мы уверены (уверены на 95%), что худшее, что вы сделаете, в большинстве случаев, это потеряете 1 926,81 фунта стерлингов».

Ожидаемая потеря хвоста (условный VaR)

С другой стороны, в статье «Expected Tail Loss (Conditional VaR): £-1,301.08» рассматриваются те действительно плохие дни, которые выходят за пределы 95%-го уровня достоверности, о котором мы только что говорили. Он спрашивает: «Если дела пойдут хуже, чем мы ожидали, и мы окажемся в этих несчастливых 5%, насколько плохо мы ожидаем в среднем?» Эта цифра говорит нам о том, что в среднем при наихудшем сценарии вы можете ожидать потери около 1 301,08 фунта стерлингов.

Собираем все воедино

Обе эти метрики дают вам возможность думать о риске в привычных денежных терминах, что может быть очень полезно. VaR дает вам пороговое значение, говоря, что «вряд ли станет хуже, чем это», в то время как ожидаемая потеря хвоста говорит вам: «Но если ситуация ухудшится, вот что вы можете ожидать».

Это все равно, что планировать пикник и говорить: «С вероятностью 95% дождь не будет больше, чем легкий моросящий дождь, но если нам действительно не повезет, и пойдет дождь, мы ожидаем, что это будет умеренный дождь, а не проливной ливень». Это поможет вам не только подготовиться к вероятным результатам, но и понять и спланировать наихудшие сценарии, даже если они менее вероятны.

Продолжим…

num_success = np.sum(final_investment_values >= initial_investment * (1 + desired_return))
probability_of_success = num_success / num_simulations

print(f"Probability of achieving at least a {desired_return*100}% return: {probability_of_success*100:.2f}%")
Скриншот автора

Я также внес корректировку в код графика matplotlib, чтобы вместо этого отображать гистограмму.

  plt.figure(figsize=(10, 6))
plt.hist(final_investment_values, bins=50, alpha=0.75)
plt.axvline(
initial_investment * (1 + desired_return),
color="r",
linestyle="dashed",
linewidth=2,
)
plt.axvline(initial_investment - var, color="g", linestyle="dashed", linewidth=2)
plt.title("Distribution of Final Investment Values")
plt.xlabel("Final Investment Value")
plt.ylabel("Frequency")
plt.show()
Скриншот автора

Важно понимать, что означают красная и зеленая пунктирные линии выше.

Пунктирная красная линия

  • Назначение: В этой строке указывается стоимость инвестиций, которая соответствует желаемой доходности.
  • Расчет: Рассчитывается как initial_investment * (1 + desired_return). По сути, если вы начинали с определенной суммы денег (initial_investment), эта строка показывает, где бы вы закончили, если бы ваши инвестиции выросли на процент желаемой доходности (desired_return).
  • Интерпретация: Красная линия отвечает на вопрос: «Где, как я надеюсь, окажутся мои инвестиции, как минимум?» Он представляет собой мою цель или задачу для инвестиций. При взгляде на гистограмму любые результаты (или столбцы на гистограмме) справа от этой линии означают, что я достиг или превысил желаемую доходность. И наоборот, результаты слева указывают на то, что я не достиг своей цели.

Пунктирная зеленая линия

  • Назначение: Этой линией обозначает значение под риском (VaR) на указанном уровне достоверности (в данном случае 95%).
  • Расчет: Отображается как initial_investment - varvar здесь представляет собой сумму в фунтах, которую я могу потерять с вероятностью 95%, а это означает, что вероятность того, что мои убытки превысят эту сумму, составляет всего 5%.
  • Интерпретация: Зеленая линия служит визуальной подсказкой для оценки рисков. Он говорит мне: «Учитывая риски, о которых я знаю, это то, сколько я могу потерять с довольно высокой степенью уверенности». В контексте гистограммы она дает мне представление о том, какая часть потенциальных результатов моих инвестиций включает в себя потерю больше, чем то, что меня относительно устраивает. Если многие исходы окажутся слева от этой линии, мои инвестиции могут оказаться более рискованными, чем я готов принять.

При взгляде на гистограмму:

  • Области справа от красной линии показывают успешные результаты, при которых конечная стоимость моих инвестиций соответствует или превышает целевую доходность.
  • Область слева от зеленой линии выделяет ту часть исходов, где потери превышают ожидаемые в 95% случаев, что указывает на риск худших, чем ожидалось, результатов.

Вместе эти линии помогают визуально контекстуализировать баланс между потенциальной прибылью (красная линия) и риском убытка (зеленая линия) в результатах моделирования.

Надеюсь, вы нашли эту статью полезной…

Если вы хотите, чтобы мой код был опробован на разных рынках, вот он…

import numpy as np
import matplotlib.pyplot as plt
from eodhd import APIClient
import config as cfg

api = APIClient(cfg.API_KEY)


def get_ohlc_data():
df = api.get_historical_data("GSPC.INDX", "d", results=365)
return df


if __name__ == "__main__":
df = get_ohlc_data()

# Calculate daily returns
daily_returns = df["adjusted_close"].pct_change().dropna()

# Simulation parameters
initial_investment = 10000 # Initial investment amount
num_simulations = 1000 # Number of simulations
forecast_days = 365 # Investment horizon in days
desired_return = 0.10 # Desired return (10%)

# Calculate the average daily return
average_daily_return = daily_returns.mean()

# Calculate volatility as the standard deviation of daily returns
volatility = daily_returns.std()

print(f"Average Daily Return: {average_daily_return}")
print(f"Volatility: {volatility}")

# Simulating future returns
simulated_end_returns = np.zeros(num_simulations)
for i in range(num_simulations):
random_returns = np.random.normal(
average_daily_return, volatility, forecast_days
)
cumulative_return = np.prod(1 + random_returns)
simulated_end_returns[i] = initial_investment * cumulative_return

# Calculate the final investment values
final_investment_values = simulated_end_returns

# Calculate Value at Risk (VaR) and Expected Tail Loss (Conditional VaR)
confidence_level = 0.95
sorted_returns = np.sort(final_investment_values)
index_at_var = int((1 - confidence_level) * num_simulations)
var = initial_investment - sorted_returns[index_at_var]
conditional_var = initial_investment - sorted_returns[:index_at_var].mean()

print(f"Value at Risk (95% confidence): £{var:,.2f}")
print(f"Expected Tail Loss (Conditional VaR): £{conditional_var:,.2f}")

num_success = np.sum(
final_investment_values >= initial_investment * (1 + desired_return)
)
probability_of_success = num_success / num_simulations

print(
f"Probability of achieving at least a {desired_return*100}% return: {probability_of_success*100:.2f}%"
)

plt.figure(figsize=(10, 6))
plt.hist(final_investment_values, bins=50, alpha=0.75)
plt.axvline(
initial_investment * (1 + desired_return),
color="r",
linestyle="dashed",
linewidth=2,
)
plt.axvline(initial_investment - var, color="g", linestyle="dashed", linewidth=2)
plt.title("Distribution of Final Investment Values")
plt.xlabel("Final Investment Value")
plt.ylabel("Frequency")
plt.show()

"""
# Plotting the results
plt.figure(figsize=(10, 6))
plt.plot(simulations.T, color="blue", alpha=0.025)
plt.title("Monte Carlo Simulation of Future Prices")
plt.xlabel("Day")
plt.ylabel("Price")
plt.show()
"""

Источник

Источник

Источник

Источник

Источник