什么是蒙特卡罗模拟?
蒙特卡罗模拟是一种利用重复随机采样来获得数值结果的计算算法。该方法的基本原理是利用随机性来解决原则上可能是确定性的问题。它以摩纳哥蒙特卡洛赌场命名,因为该方法固有的机会元素,类似于赌博。这种方法在包括金融和贸易在内的许多领域特别有用,可用于对涉及不确定性的场景进行建模并预测风险的影响。
我对它在金融中的应用特别感兴趣。在股票和加密货币市场的背景下,蒙特卡罗模拟用于通过模拟资产价格的各种可能结果来预测未来的价格变动。鉴于金融市场的随机性,这种方法非常适合评估投资固有的风险和不确定性。投资者和分析师使用它来模拟不同盈利潜力的概率,帮助他们通过了解可能结果的范围以及实现不同回报水平的可能性来做出明智的决策。
股票和加密货币的蒙特卡罗模拟
对于股票和加密货币,模拟通常涉及根据历史波动性和价格趋势预测未来价格。该过程通常涉及以下内容:
- 历史数据分析: 分析历史价格数据(例如开盘价、最高价、最低价、收盘价(OHLC)数据)以确定平均收益和波动性。
- 随机样本生成: 根据历史平均回报和波动率,使用统计模型生成随机每日回报。
- 价格模拟: 通过将随机生成的收益应用到当前价格来重复计算未来的价格路径。
- 结果分析: 评估模拟未来价格的分布,以估计不同结果的概率。
用 Python 演示蒙特卡洛模拟
我想分两部分向您展示它是如何工作的,这样更容易理解。
Part 1
第一步是检索一些历史交易数据以供使用。我订阅了EODHD APIs,这就是我检索数据进行分析的地方。他们还有一个名为“ eodhd ”的 Python 库,使检索数据成为一项微不足道的任务。在本演示中,我将检索 S&P 500 每日股票数据。
python3 -m pip install eodhd -U
1 2 3 4 5 6 7 8
| 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)
|
1 2 3
| daily_returns = df["adjusted_close"].pct_change().dropna() print(daily_returns)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| num_simulations = 1000 forecast_days = 365
simulations = np.zeros((num_simulations, forecast_days))
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)
|
绘制结果…
1 2 3 4 5 6 7
| 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()
|
这看起来不错,但它真正向我们展示了什么?
- 波动性表示: 模拟根据历史波动性捕获可能的价格变动范围,提供不确定性的直观表示。然而,它假设过去的波动模式将继续下去,但情况可能并非总是如此。
- 预测局限性: 虽然模拟有助于理解潜在结果,但无法预测具体的未来价格。市场状况、经济因素和不可预见的事件都会极大地影响实际结果。
- 情景规划: 模拟结果的分布可以帮助投资者规划各种情景,评估收益潜力和损失风险。它鼓励对未来市场走势采取概率性而非确定性的观点。
- 模型假设: 模拟的准确性在很大程度上取决于对回报分布和波动性的假设。不同的模型(例如,假设正态回报与对数正态回报)可能会产生不同的结果,这凸显了模型选择和校准的重要性。
Part 2
在第 1 部分中,我想向您介绍基础知识。我不指望你能用它做任何有用的事情。这就是我现在要向您展示的内容。
蒙特卡罗模拟在评估投资风险和制定投资决策方面的实际应用涉及几个关键步骤。通过了解第 1 部分中所示的模拟生成的潜在未来价格的范围和分布,投资者可以量化投资的风险和潜在回报。下面是它的实际应用方式:
1. 明确投资目标和风险承受能力
投资者或投资组合经理首先要确定他们的投资目标,包括预期回报和他们愿意承受的风险水平。风险承受能力可能受到投资期限、财务目标以及投资者个人对不确定性的接受程度等因素的影响。
2. 运行蒙特卡罗模拟
使用历史数据和统计模型,进行大量模拟来预测所考虑的投资(股票、加密货币等)的未来价格路径。每个模拟都代表了基于每日收益随机发生的未来可能的场景,反映了历史波动性和收益模式。希望第 1 部分已经清楚这一点。
3. 分析仿真输出
蒙特卡罗模拟的输出提供了未来指定时间的一系列可能的未来价格。然后分析该范围以了解投资的潜在结果。模拟得出的关键指标包括:
- 概率分布: 投资者将查看模拟最终价格的分布,以了解结果的分布。例如,价差较大表明波动性较高,因此风险较高。.
- 风险价值 (VaR): 该指标估计给定置信水平下指定时间范围内的最大潜在损失。例如,95% VaR 为 1,000 英镑意味着投资者在指定期间内损失不会超过 1,000 英镑的可能性为 95%。
- 预期尾部损失 (ETL): 也称为条件 VaR,ETL 提供超出 VaR 阈值的平均损失,从而深入了解最坏情况下的潜在损失。
4. 做出明智的决定
根据分析,投资者可以通过将蒙特卡罗模拟揭示的风险和回报状况与其投资目标和风险承受能力进行比较,做出明智的决策。例如:
- 如果实现预期回报的概率超过投资者的成功门槛,并且相关风险(VaR、ETL)在其风险承受范围内,则该投资可能被认为是可接受的。
- 如果模拟显示回报达不到目标或风险超出投资者的承受能力的可能性很大,他们可能会决定调整投资策略。这可能涉及投资组合多元化、选择具有不同风险回报状况的投资或改变投资期限。
实际例子:
我想考虑在标准普尔 500 指数中投资 10,000 英镑,并且我想使用蒙特卡罗模拟来评估风险。模拟应表明,在 95% 的置信度下,投资明年的损失不会超过 2,000 英镑 (95% VaR)。此外,模拟应表明有 50% 的机会实现至少 10% 的回报。
举个例子,我的风险承受能力允许潜在的 2,000 英镑损失,而目标是 10% 的回报,这项投资可能被认为在可接受的风险参数范围内。然而,如果潜在损失超出投资者的风险承受能力,或者认为实现预期回报的可能性太低,投资者可能会寻找替代方案或修改投资金额。
该过程说明了蒙特卡罗模拟在投资风险评估和决策中的实际应用。它提供了一种结构化的方法来考虑上行潜力和下行风险,支持与特定风险回报目标相一致的更细致的投资策略。
这在 Python 中会是什么样子?
首先,我想对我的模拟参数进行一些调整。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| daily_returns = df["adjusted_close"].pct_change().dropna()
initial_investment = 10000 num_simulations = 1000 forecast_days = 365 desired_return = 0.10
average_daily_return = daily_returns.mean()
volatility = daily_returns.std()
print(f"Average Daily Return: {average_daily_return}") print(f"Volatility: {volatility}")
|
只是为了兴趣,如果您更喜欢对数正态回报,您可以这样做……
1
| daily_returns = np.log(df["adjusted_close"] / df["adjusted_close"].shift(1)).dropna()
|
我改进了模拟逻辑……
1 2 3 4 5 6 7 8 9 10 11
| 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
final_investment_values = simulated_end_returns
print(final_investment_values)
|
此屏幕截图仅显示“final_investment_values”数组的一个子集,让您了解它的外观。
计算风险价值 (VaR) 和预期尾部损失(条件 VaR)
1 2 3 4 5 6 7 8
| 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}")
|
这告诉我什么?
风险价值 (VaR) 和预期尾部损失(条件 VaR)是用于了解投资损失潜力的衡量标准,但它们的理解方式略有不同。
风险价值 (VaR)
当我们说“风险价值(95% 置信度):-1,926.81 英镑”时,这意味着根据过去的表现和当前条件,您的投资在指定时间段内损失不会超过 1,926.81 英镑的可能性为 95% 。简单来说,这就像说:“我们非常确定(95% 确定)在大多数情况下,您会做的最糟糕的事情就是损失 1,926.81 英镑。”
预期尾部损失(条件 VaR)
另一方面,“预期尾部损失(条件 VaR):-1,301.08 英镑”着眼于那些超出我们刚才谈到的 95% 置信水平的非常糟糕的日子。它问的是,“如果事情确实比我们预期的更糟,而我们又处于那不幸的 5% 中,那么我们预计情况平均会变得多糟?”这个数字告诉我们,平均而言,在最坏的情况下,您可能会损失约 1,301.08 英镑。
把它放在一起
这两个指标都为您提供了一种以熟悉的货币术语来思考风险的方法,这非常有帮助。 VaR 为您提供了一个阈值,表示“情况不太可能变得比这更糟”,而预期尾部损失告诉您,“但如果情况确实变得更糟,这就是您可能期望的情况。”
这就像在计划一次野餐时说:“有 95% 的可能性,下雨不会超过小毛毛雨,但如果我们真的不走运,下起了倾盆大雨,我们预计会是中雨,而不是倾盆大雨。 ”它不仅可以帮助您为可能的结果做好准备,还可以帮助您了解并计划最坏的情况,即使它们发生的可能性较小。
让我们继续……
1 2 3 4
| 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 图形代码进行了调整以显示直方图。
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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
- 解释:红线回答了这个问题:“我希望我的投资至少最终会在哪里?”它代表了我的投资目标。查看直方图时,该线右侧的任何结果(或直方图中的条形)都意味着我已经达到或超过了我的预期回报。相反,左侧的结果表明未达到我的目标。
绿色虚线
- 目的:此线标记指定置信水平(在本例中为 95%)的风险价值 (VaR)。
- 计算:如图所示initial_investment - var。var这里代表我在 95% 的置信度下损失的英镑金额,这意味着我的损失只有 5% 的机会超过这个金额。
- 解释:绿线为风险评估提供了视觉提示。它告诉我,“考虑到我所意识到的风险,这是我在相当高的信心下可能损失的金额。”在直方图的背景下,它让我了解我的投资的潜在结果中有多少涉及损失超过我相对满意的范围。如果许多结果落在这条线的左边,我的投资可能比我愿意接受的风险更大。
查看直方图时:
红线右侧的区域表示我的投资的最终价值达到或超过我的目标回报的成功结果。
绿线左侧的区域突出显示了损失在 95% 的情况下超过我预期的结果部分,表明结果有比预期更糟糕的风险。
这些线共同有助于直观地体现模拟结果中利润潜力(红线)和损失风险(绿线)之间的平衡。
希望您发现这很有用…
如果您希望我的代码在不同的市场上试用,这里是……
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| 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()
daily_returns = df["adjusted_close"].pct_change().dropna()
initial_investment = 10000 num_simulations = 1000 forecast_days = 365 desired_return = 0.10
average_daily_return = daily_returns.mean()
volatility = daily_returns.std()
print(f"Average Daily Return: {average_daily_return}") print(f"Volatility: {volatility}")
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
final_investment_values = simulated_end_returns
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()
"""
|