投资组合–蒙特卡洛模拟(Python)

首先import需要用到的库

from numpy import *
from numpy.linalg import multi_dot
import pandas as pd
import matplotlib.pyplot as plt
from tqdm import *

加载画图的库并忽略告警

import cufflinks as cf
cf.set_config_file(
    offline = True,
    dimensions = ((800, 600)),
    theme = 'ggplot')

import plotly.express as px
px.defaults.width = 800
px.defaults.height = 600

import warnings
warnings.filterwarnings('ignore')

# 解决中文和负号问题
plt.rcParams['font.sans-serif'] = ['SimHei']

plt.rcParams['axes.unicode_minus'] = False

导入外部数据(https://download.csdn.net/download/weixin_55618145/87666946)

file_name = '2017_2021_daily.csv'
data = pd.DataFrame(pd.read_csv(file_name, index_col=0, parse_dates=True)).dropna()
data.head()

 展示历史价格走势

(data/data.iloc[0]).plot(figsize = (10,6))
plt.xlabel('日期')
plt.ylabel('价格走势(起始为1)')
plt.title('6只股票历史价格走势')
plt.show()

 显示如下:

计算历史回报及波动

returns = log(data/data.shift(1)).dropna()

# 年化收益率及波动
pd.DataFrame({
    '年化收益率(%)': round(returns.mean()*250*100, 2),
    '年化波动率(%)': round(returns.std()*sqrt(250)*100, 2),
    '夏普比率': round(returns.mean()/returns.std()*sqrt(250), 2)
}).iplot(kind='bar', title='年化收益率(%)、年化波动率(%)及夏普比率', shared_xaxes=True, subplots=True)

 结果如下

 有效边界及市场组合——蒙特卡洛模拟

 运行10000次随机构建的组合比例(不做空任何一只股票)

# 组合的股票构成
symbols = ['顺发恒业', '贵州茅台', '重庆啤酒', '中南传媒', '海天味业', '五粮液']
numofasset = len(symbols)

# 定义一个组合的函数
def portfolio_simulation(returns):
    rets = []; vols=[]; wts=[]
    
    # 模拟10000次6只股票不同权重的组合
    for i in tqdm(range(10000)):
        # 产生随机权重
        weights = random.random(numofasset)[:, newaxis]
        weights = weights/weights.sum()
        
        # 记录组合的收益、波动、权重
        rets.append(weights.T @ array(returns.mean()*250)[:,newaxis])
        vols.append(sqrt(multi_dot([weights.T, returns.cov()*250, weights])))
        wts.append(weights.flatten())
        
    # 记录组合各数据
    portdf = 100 * pd.DataFrame({
        'port_rets': array(rets).flatten(),
        'port_vols': array(vols).flatten(),
        'weights': list(array(wts))
        })
    portdf['Sharp_ratio']=portdf['port_rets']/portdf['port_vols']  #假设rf为0
    
    return round(portdf, 2)
# 用6只股票组成投资组合并模拟
temp = portfolio_simulation(returns)
temp.head(10)

 获取全部模拟中夏普比率最大值

temp.iloc[temp.Sharp_ratio.idxmax()]

最后把结果可视化

# 绘制模拟组合(每个组合一个点)
fig = px.scatter(
    temp, x='port_vols', y='port_rets', color='Sharp_ratio',
    labels={'port_vols': '预期波动(%)','port_rets': '预期收益(%)', 'Sharp_ratio':
           '夏普比率'},
    title='投资组合蒙特卡洛模拟'
            ).update_traces(mode='markers', marker=dict(symbol='circle'))

# 标记最大夏普比率的组合(市场组合)
fig.add_scatter(mode='markers',
                x=[temp.iloc[temp.Sharp_ratio.idxmax()]['port_vols']],
                y=[temp.iloc[temp.Sharp_ratio.idxmax()]['port_rets']],
                marker=dict(color='Blue', size=14, symbol='square'),
                name = '市场组合'
               ).update(layout_showlegend=False)

fig.update_xaxes(showspikes=True)
fig.update_yaxes(showspikes=True)
fig.show()

模拟结果如下(右上角蓝色方块对应夏普比率最大的组合)

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2023年11月10日
下一篇 2023年11月10日

相关推荐