siat 3.10.125__py3-none-any.whl → 3.10.126__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. siat/common.py +106 -2
  2. siat/exchange_bond_china.pickle +0 -0
  3. siat/fund_china.pickle +0 -0
  4. siat/stock.py +10 -2
  5. siat/stock_info.pickle +0 -0
  6. {siat-3.10.125.dist-info → siat-3.10.126.dist-info}/METADATA +234 -226
  7. siat-3.10.126.dist-info/RECORD +76 -0
  8. {siat-3.10.125.dist-info → siat-3.10.126.dist-info}/WHEEL +1 -1
  9. {siat-3.10.125.dist-info → siat-3.10.126.dist-info/licenses}/LICENSE +0 -0
  10. {siat-3.10.125.dist-info → siat-3.10.126.dist-info}/top_level.txt +0 -0
  11. siat/__init__ -20240701.py +0 -65
  12. siat/__init__.py.backup_20250214.py +0 -73
  13. siat/alpha_vantage_test.py +0 -24
  14. siat/assets_liquidity_test.py +0 -44
  15. siat/barrons_scraping_test.py +0 -276
  16. siat/beta_adjustment_test.py +0 -77
  17. siat/bond_test.py +0 -142
  18. siat/capm_beta_test.py +0 -49
  19. siat/cmat_commons.py +0 -961
  20. siat/compare_cross_test.py +0 -117
  21. siat/concepts_iwencai.py +0 -86
  22. siat/concepts_kpl.py +0 -93
  23. siat/cryptocurrency_test.py +0 -71
  24. siat/derivative.py +0 -1111
  25. siat/economy-20230125.py +0 -1206
  26. siat/economy_test.py +0 -360
  27. siat/esg_test.py +0 -63
  28. siat/fama_french_test.py +0 -115
  29. siat/financial_statements_test.py +0 -31
  30. siat/financials2 - /321/205/320/231/320/277/321/206/320/254/320/274.py" +0 -341
  31. siat/financials_china2_test.py +0 -67
  32. siat/financials_china2_test2.py +0 -88
  33. siat/financials_china2_test3.py +0 -87
  34. siat/financials_china_test.py +0 -475
  35. siat/financials_china_test2.py +0 -197
  36. siat/financials_china_test2_fin_indicator.py +0 -197
  37. siat/financials_test.py +0 -713
  38. siat/fred_test.py +0 -40
  39. siat/fund_china_test.py +0 -175
  40. siat/fund_test.py +0 -40
  41. siat/future_china_test.py +0 -37
  42. siat/global_index_test.py +0 -66
  43. siat/grafix_test.py +0 -112
  44. siat/holding_risk_test.py +0 -13
  45. siat/local_debug_test.py +0 -100
  46. siat/markowitz2-20240620.py +0 -2614
  47. siat/markowitz_ccb_test.py +0 -37
  48. siat/markowitz_ef_test.py +0 -136
  49. siat/markowitz_old.py +0 -871
  50. siat/markowitz_simple-20230709.py +0 -370
  51. siat/markowitz_test.py +0 -164
  52. siat/markowitz_test2.py +0 -69
  53. siat/ml_cases_example1.py +0 -60
  54. siat/option_china_test.py +0 -447
  55. siat/option_pricing_test.py +0 -81
  56. siat/option_sina_api_test.py +0 -112
  57. siat/proxy_test.py +0 -84
  58. siat/quandl_test.py +0 -39
  59. siat/risk_adjusted_return_test.py +0 -81
  60. siat/risk_evaluation_test.py +0 -96
  61. siat/risk_free_rate_test.py +0 -127
  62. siat/sector_china_test.py +0 -203
  63. siat/security_price.py +0 -831
  64. siat/security_prices_test.py +0 -310
  65. siat/security_trend2-20240620.py +0 -493
  66. siat/setup.py +0 -41
  67. siat/shenwan index history test.py +0 -41
  68. siat/stock_china_test.py +0 -38
  69. siat/stock_info_test.py +0 -189
  70. siat/stock_list_china_test.py +0 -33
  71. siat/stock_technical-20240620.py +0 -2736
  72. siat/stock_test.py +0 -487
  73. siat/temp.py +0 -36
  74. siat/test2_graphviz.py +0 -484
  75. siat/test_graphviz.py +0 -411
  76. siat/test_markowitz_simple.py +0 -198
  77. siat/test_markowitz_simple_revised.py +0 -215
  78. siat/test_markowitz_simple_revised2.py +0 -218
  79. siat/transaction_test.py +0 -436
  80. siat/translate-20230125.py +0 -2107
  81. siat/translate-20230206.py +0 -2109
  82. siat/translate-20230215.py +0 -2158
  83. siat/translate_20240606.py +0 -4206
  84. siat/translate_241003_keep.py +0 -4300
  85. siat/universal_test.py +0 -100
  86. siat/valuation_market_china_test.py +0 -36
  87. siat-3.10.125.dist-info/RECORD +0 -152
siat/markowitz_old.py DELETED
@@ -1,871 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- 本模块功能:证券投资组合理论计算函数包
4
- 所属工具包:证券投资分析工具SIAT
5
- SIAT:Security Investment Analysis Tool
6
- 创建日期:2020年7月1日
7
- 最新修订日期:2020年7月29日
8
- 作者:王德宏 (WANG Dehong, Peter)
9
- 作者单位:北京外国语大学国际商学院
10
- 作者邮件:wdehong2000@163.com
11
- 版权所有:王德宏
12
- 用途限制:仅限研究与教学使用,不可商用!商用需要额外授权。
13
- 特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
14
- """
15
- #==============================================================================
16
- #统一屏蔽一般性警告
17
- import warnings; warnings.filterwarnings("ignore")
18
- #==============================================================================
19
-
20
- from siat.common import *
21
- from siat.translate import *
22
- from siat.security_prices import *
23
-
24
- import pandas as pd
25
- import datetime
26
- #==============================================================================
27
- import matplotlib.pyplot as plt
28
-
29
- #处理绘图汉字乱码问题
30
- import sys; czxt=sys.platform
31
- if czxt in ['win32','win64']:
32
- plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体
33
- mpfrc={'font.family': 'SimHei'}
34
-
35
- if czxt in ['darwin']: #MacOSX
36
- plt.rcParams['font.family']= ['Heiti TC']
37
- mpfrc={'font.family': 'Heiti TC'}
38
-
39
- if czxt in ['linux']: #website Jupyter
40
- plt.rcParams['font.family']= ['Heiti TC']
41
- mpfrc={'font.family':'Heiti TC'}
42
-
43
- # 解决保存图像时'-'显示为方块的问题
44
- plt.rcParams['axes.unicode_minus'] = False
45
- #==============================================================================
46
- #==============================================================================
47
- def portfolio_config(tickerlist,sharelist):
48
- """
49
- 将股票列表tickerlist和份额列表sharelist合成为一个字典
50
- """
51
- #整理sharelist的小数点
52
- ratiolist=[]
53
- for s in sharelist:
54
- ss=round(s,4); ratiolist=ratiolist+[ss]
55
- #合成字典
56
- new_dict=dict(zip(tickerlist,ratiolist))
57
- return new_dict
58
-
59
- #==============================================================================
60
- def ratiolist_round(sharelist,num=4):
61
- """
62
- 将股票份额列表sharelist中的数值四舍五入
63
- """
64
- #整理sharelist的小数点
65
- ratiolist=[]
66
- for s in sharelist:
67
- ss=round(s,num); ratiolist=ratiolist+[ss]
68
- return ratiolist
69
-
70
- #==============================================================================
71
- def varname(p):
72
- """
73
- 功能:获得变量的名字本身。
74
- """
75
- import inspect
76
- import re
77
- for line in inspect.getframeinfo(inspect.currentframe().f_back)[3]:
78
- m = re.search(r'\bvarname\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)', line)
79
- if m:
80
- return m.group(1)
81
-
82
- #==============================================================================
83
- def get_start_date(end_date,pastyears=1):
84
- """
85
- 输入参数:一个日期,年数
86
- 输出参数:几年前的日期
87
- start_date, end_date是datetime类型
88
- """
89
- import pandas as pd
90
- try:
91
- end_date=pd.to_datetime(end_date)
92
- except:
93
- print("#Error(): invalid date,",end_date)
94
- return None
95
-
96
- from datetime import datetime,timedelta
97
- start_date=datetime(end_date.year-pastyears,end_date.month,end_date.day)
98
- start_date=start_date-timedelta(days=1)
99
- # 日期-1是为了保证计算收益率时得到足够的样本数量
100
- return start_date
101
-
102
- #==============================================================================
103
- if __name__=='__main__':
104
- retgroup=StockReturns
105
-
106
- def cumulative_returns_plot(retgroup,name_list,titletxt,ylabeltxt,xlabeltxt, \
107
- label_list=[]):
108
- """
109
- 功能:基于传入的name_list绘制多条累计收益率曲线,并从label_list中取出曲线标记
110
- 注意:最多绘制四条曲线,否则在黑白印刷时无法区分曲线
111
- """
112
- if len(label_list) < len(name_list):
113
- label_list=name_list
114
-
115
- # 累积收益曲线绘制函数
116
- lslist=['-','--',':','-.']
117
- for name in name_list:
118
- pos=name_list.index(name)
119
- rlabel=label_list[pos]
120
- if pos < 4: thisls=lslist[pos]
121
- else: thisls=(45,(55,20))
122
-
123
- CumulativeReturns = ((1+retgroup[name]).cumprod()-1)*100.0
124
- CumulativeReturns.plot(label=ectranslate(rlabel),ls=thisls)
125
- #plt.axhline(y=0,ls=":",c="red")
126
- plt.legend(loc='best')
127
- plt.title(titletxt); plt.ylabel(ylabeltxt); plt.xlabel(xlabeltxt)
128
- plt.show()
129
-
130
- return
131
-
132
- if __name__=='__main__':
133
- retgroup=StockReturns
134
- cumulative_returns_plot(retgroup,name_list,titletxt,ylabeltxt,xlabeltxt, \
135
- label_list=[])
136
- #==============================================================================
137
- if __name__=='__main__':
138
- Market={'Market':('US','^GSPC','我的组合001')}
139
- Stocks={'BABA':.7,'JD':.3}
140
- portfolio=dict(Market,**Stocks)
141
-
142
- today='2021-1-28'
143
- pastyears=1
144
-
145
- def portfolio_cumret(portfolio,today,pastyears=1):
146
- """
147
- 功能:绘制投资组合的累计收益率趋势图,并与等权和市值加权组合比较
148
- """
149
- print("\n Searching for portfolio info, which may take time ...")
150
- # 解构投资组合
151
- _,_,tickerlist,sharelist=decompose_portfolio(portfolio)
152
- pname=portfolio_name(portfolio)
153
-
154
- totalshares=round(sum(sharelist),4)
155
- if totalshares != 1.0:
156
- print("\n #Error(portfolio_cumret): total weights is",totalshares,", it requires 1.0 here")
157
- return None
158
-
159
- # 计算历史数据的开始日期
160
- start=get_start_date(today,pastyears)
161
-
162
- # 抓取投资组合股价
163
- """
164
- StockReturns=get_portfolio_prices(portfolio,start,today)
165
- """
166
- prices=get_prices(tickerlist,start,today)
167
- if prices is None:
168
- print("\n #Error(portfolio_cumret): failed to get portfolio prices",pname)
169
- return None
170
- if len(prices) == 0:
171
- print("\n #Error(portfolio_cumret): retrieved empty prices for",pname)
172
- return None
173
-
174
- # 复权后收盘价
175
- aclose=prices['Close']
176
- #print(aclose.head())
177
- # 计算每日收益率,并丢弃缺失值
178
- StockReturns = aclose.pct_change().dropna()
179
- if len(StockReturns) == 0:
180
- print("\n #Error(portfolio_cumret): retrieved empty returns for",pname)
181
- return None
182
- #print(StockReturns.head())
183
- # 将收益率数据拷贝到新的变量 stock_return 中,为了后续调用的方便
184
- stock_return = StockReturns.copy()
185
- #..........................................................................
186
-
187
- # 设置组合权重,存储为numpy数组类型
188
- import numpy as np
189
- portfolio_weights = np.array(sharelist)
190
- # 计算portfolio的股票收益
191
- WeightedReturns = stock_return.mul(portfolio_weights, axis=1)
192
- # 计算投资组合的收益
193
- StockReturns['Portfolio'] = WeightedReturns.sum(axis=1)
194
-
195
- # 绘制portfolio随时间变化的图
196
- #仅用于绘图,以便使用收益率%来显示
197
- plotsr = StockReturns['Portfolio']*100.0
198
- #plotsr = StockReturns['Ret%']
199
- #plotsr.plot(label='Portfolio')
200
- plotsr.plot(label=pname)
201
- plt.axhline(y=0,ls=":",c="red")
202
-
203
- plt.title("投资组合: 日收益率的变化趋势")
204
- plt.ylabel("日收益率%")
205
-
206
- stoday = datetime.date.today()
207
- plt.xlabel("数据来源: 新浪/stooq/FRED, "+str(stoday))
208
- plt.legend()
209
- plt.show()
210
- #..........................................................................
211
-
212
- # 计算持有收益率的组合收益,并绘图
213
- name_list=["Portfolio"]
214
- label_list=[pname]
215
- titletxt="投资组合: 持有收益率的变化趋势"
216
- ylabeltxt="持有收益率%"
217
- stoday = datetime.date.today()
218
- xlabeltxt="数据来源: 新浪/stooq/FRED, "+str(stoday)
219
- #由函数去处理百分号放大
220
- cumulative_returns_plot(StockReturns,name_list,titletxt,ylabeltxt,xlabeltxt,label_list)
221
- #..........................................................................
222
-
223
- # 构造等权重组合Portfolio_EW
224
- numstocks = len(tickerlist)
225
- # 平均分配每一项的权重
226
- portfolio_weights_ew = np.repeat(1/numstocks, numstocks)
227
- # 计算等权重组合的收益
228
- StockReturns['Portfolio_EW']=stock_return.mul(portfolio_weights_ew,axis=1).sum(axis=1)
229
- #StockReturns['Portfolio_name']=pname
230
- #name_list=['Portfolio','Portfolio_EW']
231
- #cumulative_returns_plot(StockReturns,name_list,titletxt,ylabeltxt,xlabeltxt)
232
- #..........................................................................
233
-
234
- # 创建流动性组合:按照成交金额计算流动性
235
- MCap=prices['Close']*prices['Volume']
236
- #MCaplist=MCap.iloc[-1]
237
- MCaplist=MCap.mean(axis=0) #求列的均值
238
- market_capitalizations = np.array(MCaplist)
239
- # 计算成交金额权重
240
- mcap_weights = market_capitalizations / np.sum(market_capitalizations)
241
- # 计算成交金额加权的组合收益
242
- StockReturns['Portfolio_LW'] = stock_return.mul(mcap_weights, axis=1).sum(axis=1)
243
-
244
- #绘制累计收益率对比曲线
245
- name_list=['Portfolio', 'Portfolio_EW', 'Portfolio_LW']
246
- label_list=[pname, '等权重组合', '流动性组合']
247
- titletxt="投资组合: 不同组合策略的持有收益率对比"
248
- cumulative_returns_plot(StockReturns,name_list,titletxt,ylabeltxt,xlabeltxt,label_list)
249
-
250
- return [tickerlist,sharelist,StockReturns,stock_return,today, \
251
- [portfolio_weights,portfolio_weights_ew,mcap_weights]]
252
-
253
- if __name__=='__main__':
254
- X=portfolio_cumret(portfolio,'2021-1-28')
255
-
256
- if __name__=='__main__':
257
- Market={'Market':('US','^GSPC','我的组合001')}
258
- Stocks1={'AAPL':.1,'MSFT':.13,'XOM':.09,'JNJ':.09,'JPM':.09}
259
- Stocks2={'AMZN':.15,'GE':.08,'FB':.13,'T':.14}
260
- portfolio=dict(Market,**Stocks1,**Stocks2)
261
- pf_info=portfolio_cumret(portfolio,'2019-12-31')
262
-
263
-
264
- def portfolio_expret(portfolio,today,pastyears=1):
265
- """
266
- 功能:绘制投资组合的持有期收益率趋势图,并与等权和市值加权组合比较
267
- 套壳原来的portfolio_cumret函数,以维持兼容性
268
- expret: expanding return,以维持与前述章节名词的一致性
269
- hpr: holding period return, 持有(期)收益率
270
- """
271
- [tickerlist,sharelist,StockReturns,stock_return,today, \
272
- [portfolio_weights,portfolio_weights_ew,mcap_weights]] = \
273
- portfolio_cumret(portfolio,today,pastyears)
274
-
275
- return [tickerlist,sharelist,StockReturns,stock_return,today, \
276
- [portfolio_weights,portfolio_weights_ew,mcap_weights]]
277
-
278
- if __name__=='__main__':
279
- Market={'Market':('US','^GSPC','我的组合001')}
280
- Stocks1={'AAPL':.1,'MSFT':.13,'XOM':.09,'JNJ':.09,'JPM':.09}
281
- Stocks2={'AMZN':.15,'GE':.08,'FB':.13,'T':.14}
282
- portfolio=dict(Market,**Stocks1,**Stocks2)
283
-
284
- pf_info=portfolio_expret(portfolio,'2019-12-31')
285
-
286
-
287
- #==============================================================================
288
- def portfolio_corr(pf_info):
289
- """
290
- 功能:绘制投资组合成分股之间相关关系的热力图
291
- """
292
- [_,_,StockReturns,stock_return,today,_]=pf_info
293
- pname=StockReturns['Portfolio_name'].values[0]
294
-
295
- sr=stock_return.copy()
296
- collist=list(sr)
297
- for col in collist:
298
- sr.rename(columns={col:codetranslate(col)},inplace=True)
299
-
300
- # 计算相关矩阵
301
- #correlation_matrix = stock_return.corr()
302
- correlation_matrix = sr.corr()
303
-
304
- # 导入seaborn
305
- import seaborn as sns
306
- # 创建热图
307
- sns.heatmap(correlation_matrix,annot=True,cmap="YlGnBu",linewidths=0.3,
308
- annot_kws={"size": 8})
309
- plt.title(pname+": 成分股收益率之间的相关系数")
310
- plt.ylabel("成分股票")
311
- import datetime as dt; stoday=dt.date.today()
312
- plt.xlabel("数据来源:新浪/EM/stooq,"+str(stoday))
313
- plt.xticks(rotation=90); plt.yticks(rotation=0)
314
- plt.show()
315
-
316
- return
317
-
318
- if __name__=='__main__':
319
- Market={'Market':('US','^GSPC','我的组合001')}
320
- Stocks1={'AAPL':.1,'MSFT':.13,'XOM':.09,'JNJ':.09,'JPM':.09}
321
- Stocks2={'AMZN':.15,'GE':.08,'FB':.13,'T':.14}
322
- portfolio=dict(Market,**Stocks1,**Stocks2)
323
- pf_info=portfolio_expret(portfolio,'2019-12-31')
324
-
325
- portfolio_corr(pf_info)
326
- #==============================================================================
327
- def portfolio_covar(pf_info):
328
- """
329
- 功能:计算投资组合成分股之间的协方差
330
- """
331
- [_,_,StockReturns,stock_return,today,_]=pf_info
332
- pname=StockReturns['Portfolio_name'].values[0]
333
-
334
- # 计算协方差矩阵
335
- cov_mat = stock_return.cov()
336
- # 年化协方差矩阵,252个交易日
337
- cov_mat_annual = cov_mat * 252
338
-
339
- # 导入seaborn
340
- import seaborn as sns
341
- # 创建热图
342
- sns.heatmap(cov_mat_annual,annot=True,cmap="YlGnBu",linewidths=0.3,
343
- annot_kws={"size": 8})
344
- plt.title(pname+": 成分股之间的协方差")
345
- plt.ylabel("成分股票")
346
-
347
- import datetime as dt; stoday=dt.date.today()
348
- plt.xlabel("数据来源:新浪/EM/stooq,"+str(stoday))
349
- plt.xticks(rotation=90)
350
- plt.yticks(rotation=0)
351
- plt.show()
352
-
353
- return
354
-
355
- #==============================================================================
356
- def portfolio_expectation(pf_info):
357
- """
358
- 功能:计算投资组合的标准差
359
- """
360
- [tickerlist,sharelist,StockReturns,stock_return,today,[portfolio_weights,_,_]]=pf_info
361
- pname=StockReturns['Portfolio_name'].values[0]
362
-
363
- #取出观察期
364
- hstart0=StockReturns.index[0]
365
- hstart=str(hstart0.date())
366
- hend0=StockReturns.index[-1]
367
- hend=str(hend0.date())
368
-
369
- mean_return=stock_return.mul(portfolio_weights,axis=1).sum(axis=1).mean()
370
- annual_return = (1 + mean_return)**252 - 1
371
-
372
- # 计算协方差矩阵
373
- cov_mat = stock_return.cov()
374
- # 年化协方差矩阵
375
- cov_mat_annual = cov_mat * 252
376
-
377
- # 计算投资组合的标准差
378
- import numpy as np
379
- portfolio_volatility = np.sqrt(np.dot(portfolio_weights.T,
380
- np.dot(cov_mat_annual, portfolio_weights)))
381
- print("\n ===== 投资组合的预期收益与预期风险 =====")
382
- print(" 投资组合:",pname)
383
- #print(" 成分股:",codetranslate(tickerlist))
384
- #print(" 权重:",sharelist)
385
- print(" 观察期 :",hstart+'至'+hend)
386
- print(" 预期收益:",round(annual_return,4))
387
- print(" 预期风险:",round(portfolio_volatility,4))
388
-
389
- import datetime as dt; stoday=dt.date.today()
390
- print(" *数据来源:新浪/EM/stooq,"+str(stoday))
391
-
392
- return
393
-
394
- if __name__=='__main__':
395
- Market={'Market':('US','^GSPC','我的组合001')}
396
- Stocks1={'AAPL':.1,'MSFT':.13,'XOM':.09,'JNJ':.09,'JPM':.09}
397
- Stocks2={'AMZN':.15,'GE':.08,'FB':.13,'T':.14}
398
- portfolio=dict(Market,**Stocks1,**Stocks2)
399
- pf_info=portfolio_expret(portfolio,'2019-12-31')
400
-
401
- portfolio_expectation(pf_info)
402
- #==============================================================================
403
- if __name__=='__main__':
404
- simulation=1000
405
-
406
- def portfolio_es(pf_info,simulation=1000):
407
- """
408
- 功能:计算投资组合的标准差,绘制投资组合的有效集
409
- """
410
- [tickerlist,_,StockReturns,stock_return,today,_]=pf_info
411
- pname=StockReturns['Portfolio_name'].values[0]
412
- #通过列名列表获得成分股个数
413
- numstocks=len(tickerlist)
414
-
415
- # 计算协方差矩阵
416
- cov_mat = stock_return.cov()
417
- # 年化协方差矩阵
418
- cov_mat_annual = cov_mat * 252
419
-
420
- # 设置模拟的次数
421
- number = simulation
422
- # 设置空的numpy数组,用于存储每次模拟得到的成分股权重、组合的收益率和标准差
423
- import numpy as np
424
- random_p = np.empty((number,numstocks+2))
425
- # 设置随机数种子,这里是为了结果可重复
426
- np.random.seed(123)
427
-
428
- # 循环模拟n次随机的投资组合
429
- print("\n Calculating possible portfolio combinations, please wait ...")
430
- for i in range(number):
431
- # 生成numstocks个随机数,并归一化,得到一组随机的权重数据
432
- random9 = np.random.random(numstocks)
433
- random_weight = random9 / np.sum(random9)
434
-
435
- # 计算年化平均收益率
436
- mean_return=stock_return.mul(random_weight,axis=1).sum(axis=1).mean()
437
- annual_return = (1 + mean_return)**252 - 1
438
-
439
- # 计算年化的标准差,也称为波动率
440
- random_volatility=np.sqrt(np.dot(random_weight.T,
441
- np.dot(cov_mat_annual,random_weight)))
442
-
443
- # 将上面生成的权重,和计算得到的收益率、标准差存入数组random_p中
444
- random_p[i][:numstocks] = random_weight
445
- random_p[i][numstocks] = annual_return
446
- random_p[i][numstocks+1] = random_volatility
447
-
448
- # 将numpy数组转化成DataFrame数据框
449
- import pandas as pd
450
- RandomPortfolios = pd.DataFrame(random_p)
451
- # 设置数据框RandomPortfolios每一列的名称
452
- RandomPortfolios.columns = [ticker + "_weight" for ticker in tickerlist] \
453
- + ['Returns', 'Volatility']
454
-
455
- # 绘制散点图
456
- RandomPortfolios.plot('Volatility','Returns',kind='scatter',color='y',edgecolors='k')
457
- """
458
- plt.style.use('seaborn-dark')
459
- RandomPortfolios.plot.scatter(x='Volatility', y='Returns', c='Returns',
460
- cmap='RdYlGn', edgecolors='black')
461
- """
462
- plt.title("投资组合: 马科维茨可行集")
463
- plt.ylabel("预期收益")
464
-
465
- import datetime as dt; stoday=dt.date.today()
466
- footnote1="预期风险-->"
467
- footnote2="\n基于"+pname+"之成分股构造,共"+str(simulation)+"个"
468
- footnote3="\n数据来源: 新浪/EM/stooq, "+str(stoday)
469
- plt.xlabel(footnote1+footnote2+footnote3)
470
- plt.show()
471
-
472
- return [pf_info,RandomPortfolios]
473
-
474
- if __name__=='__main__':
475
- Market={'Market':('US','^GSPC','我的组合001')}
476
- Stocks1={'AAPL':.1,'MSFT':.13,'XOM':.09,'JNJ':.09,'JPM':.09}
477
- Stocks2={'AMZN':.15,'GE':.08,'FB':.13,'T':.14}
478
- portfolio=dict(Market,**Stocks1,**Stocks2)
479
- pf_info=portfolio_expret(portfolio,'2019-12-31')
480
-
481
- es_info=portfolio_es(pf_info,simulation=50000)
482
- #==============================================================================
483
- def portfolio_GMV(es_info):
484
- """
485
- 功能:计算投资组合的最小风险组合
486
- GMV=Global Minimium Variance
487
- """
488
- [[tickerlist,sharelist,StockReturns,stock_return,today, \
489
- [portfolio_weights,portfolio_weights_ew,mcap_weights]], \
490
- RandomPortfolios]=es_info
491
- pname=StockReturns['Portfolio_name'].values[0]
492
- numstocks=len(tickerlist)
493
-
494
- #取出观察期
495
- hstart0=StockReturns.index[0]
496
- hstart=str(hstart0.date())
497
- hend0=StockReturns.index[-1]
498
- hend=str(hend0.date())
499
-
500
- # 绘制散点图
501
- RandomPortfolios.plot('Volatility','Returns',kind='scatter',color='y',edgecolors='k')
502
-
503
- # 找到标准差最小数据的索引值
504
- min_index = RandomPortfolios.Volatility.idxmin()
505
- # 在收益-风险散点图中突出风险最小的点
506
- x = RandomPortfolios.loc[min_index,'Volatility']
507
- y = RandomPortfolios.loc[min_index,'Returns']
508
- plt.scatter(x, y, color='m',marker='8',s=100,label="GMV Point",edgecolors='r')
509
-
510
- plt.title("投资组合: GMV点的位置")
511
- plt.ylabel("预期收益")
512
- plt.xlabel("预期风险-->\nGMV表示风险最低的组合方式(Global Minimium Variance). \
513
- \n数据来源: 新浪/stooq, "+str(today))
514
- plt.legend()
515
- plt.show()
516
-
517
- # 提取最小波动组合对应的权重, 并转换成Numpy数组
518
- import numpy as np
519
- GMV_weights = np.array(RandomPortfolios.iloc[min_index, 0:numstocks])
520
- # 计算GMV投资组合收益
521
- StockReturns['Portfolio_GMV'] = stock_return.mul(GMV_weights, axis=1).sum(axis=1)
522
- # 绘制累积收益曲线
523
- namelist=['Portfolio_GMV', 'Portfolio']
524
- titletxt="投资组合: 累计收益率的比较"
525
- ylabeltxt="累计收益率"
526
- xlabeltxt="数据来源: 新浪/stooq, "+str(today)
527
- cumulative_returns_plot(StockReturns,namelist,titletxt,ylabeltxt,xlabeltxt)
528
-
529
- #输出GMV投资组合构成比例
530
- print("\n===== GMV组合方式: 构造风险最低的投资组合 =====")
531
- print("成分股:",codetranslate(tickerlist))
532
- GMV_weights_new=ratiolist_round(GMV_weights,num=3)
533
- print("权重:",GMV_weights_new)
534
- print("观察期:",hstart+'至'+hend)
535
- print("预期收益:",round(y,4))
536
- print("预期风险:",round(x,4))
537
-
538
- import datetime as dt; today=dt.date.today()
539
- print("*数据来源:新浪/stooq,"+str(today))
540
-
541
- return
542
-
543
- #==============================================================================
544
-
545
-
546
-
547
-
548
- def portfolio_MSR_GMV(es_info,RF=0):
549
- """
550
- 功能:计算投资组合的最高夏普比率组合
551
- MSR: Maximium Sharpe Rate, 最高夏普指数方案
552
- GMV: Global Minimum Volatility, 全局最小波动方案
553
- """
554
- [[tickerlist,sharelist,StockReturns,stock_return,today, \
555
- [portfolio_weights,portfolio_weights_ew,mcap_weights]], \
556
- RandomPortfolios]=es_info
557
- numstocks=len(tickerlist)
558
- pname=StockReturns['Portfolio_name'].values[0]
559
-
560
- #取出观察期
561
- hstart0=StockReturns.index[0]
562
- hstart=str(hstart0.date())
563
- hend0=StockReturns.index[-1]
564
- hend=str(hend0.date())
565
-
566
- # 设置无风险回报率
567
- risk_free = RF
568
- # 计算每项资产的夏普比率
569
- RandomPortfolios['Sharpe'] = (RandomPortfolios.Returns - risk_free) \
570
- / RandomPortfolios.Volatility
571
-
572
- # 绘制收益-标准差的散点图,并用颜色描绘夏普比率
573
- # 绘制散点图
574
- RandomPortfolios.plot('Volatility','Returns',kind='scatter',alpha=0.3)
575
- plt.scatter(RandomPortfolios.Volatility, RandomPortfolios.Returns,
576
- c=RandomPortfolios.Sharpe)
577
- plt.colorbar(label='Colored in Sharpe Ratio')
578
- plt.title("投资组合: 马科维茨可行集的夏普比率分布")
579
- plt.ylabel("预期收益")
580
- plt.xlabel("预期风险-->"+ \
581
- "\n观察期:"+hstart+"至"+hend+ \
582
- "\n数据来源: 新浪/stooq, "+str(today))
583
- plt.show()
584
-
585
- #绘制有效集
586
- RandomPortfolios.plot('Volatility','Returns',kind='scatter',color='y',edgecolors='k')
587
-
588
- # 找到夏普比率最大数据对应的索引值
589
- max_index = RandomPortfolios.Sharpe.idxmax()
590
- # 在收益-风险散点图中突出夏普比率最大的点
591
- MSR_x = RandomPortfolios.loc[max_index,'Volatility']
592
- MSR_y = RandomPortfolios.loc[max_index,'Returns']
593
- plt.scatter(MSR_x, MSR_y, color='red',marker='*',s=150,label="MSR Point")
594
- # 提取最大夏普比率组合对应的权重,并转化为numpy数组
595
- import numpy as np
596
- MSR_weights = np.array(RandomPortfolios.iloc[max_index, 0:numstocks])
597
- # 计算MSR组合的收益
598
- StockReturns['Portfolio_MSR'] = stock_return.mul(MSR_weights, axis=1).sum(axis=1)
599
-
600
- # 找到标准差最小数据的索引值
601
- min_index = RandomPortfolios.Volatility.idxmin()
602
- # 提取最小波动组合对应的权重, 并转换成Numpy数组
603
- # 在收益-风险散点图中突出风险最小的点
604
- GMV_x = RandomPortfolios.loc[min_index,'Volatility']
605
- GMV_y = RandomPortfolios.loc[min_index,'Returns']
606
- plt.scatter(GMV_x, GMV_y, color='m',marker='8',s=100,label="GMV Point")
607
- # 提取最小风险组合对应的权重,并转化为numpy数组
608
- GMV_weights = np.array(RandomPortfolios.iloc[min_index, 0:numstocks])
609
- # 计算GMV投资组合收益
610
- StockReturns['Portfolio_GMV'] = stock_return.mul(GMV_weights, axis=1).sum(axis=1)
611
-
612
- plt.title("投资组合: MSR点和GMV点的位置")
613
- plt.ylabel("预期收益")
614
- plt.xlabel("预期风险-->"+ \
615
- "\n观察期:"+hstart+"至"+hend+ \
616
- "\n数据来源: 新浪/stooq, "+str(today))
617
- plt.legend()
618
- plt.show()
619
-
620
- # 绘制累积收益曲线
621
- namelist=['Portfolio_MSR','Portfolio_GMV','Portfolio']
622
- titletxt="投资组合: 累计收益率的比较"
623
- ylabeltxt="累计收益率"
624
- xlabeltxt="观察期:"+hstart+"至"+hend+ \
625
- "\n数据来源: 新浪/stooq, "+str(today)
626
- cumulative_returns_plot(StockReturns,namelist,titletxt,ylabeltxt,xlabeltxt)
627
-
628
- #输出MSR投资组合构成比例
629
- print("\n===== 投资组合的构造方式: 最高夏普比率(MSR) =====")
630
- print("成分股:",codetranslate(tickerlist))
631
- MSR_weights_new=ratiolist_round(MSR_weights,3)
632
- print("权重:",MSR_weights_new)
633
- print("观察期:",hstart+"至"+hend)
634
- print("预期收益:",round(MSR_y*100.0,2),'\b%')
635
- print("预期风险:",round(MSR_x*100.0,2),'\b%')
636
-
637
- #import datetime as dt; today=dt.date.today()
638
- print("*数据来源:新浪/stooq,"+str(today))
639
-
640
- #输出GMV投资组合构成比例
641
- print("\n===== 投资组合的构造方式: 风险最小化(GMV) =====")
642
- print("成分股:",codetranslate(tickerlist))
643
- GMV_weights_new=ratiolist_round(GMV_weights,3)
644
- print("权重:",GMV_weights_new)
645
- print("观察期:",hstart+"至"+hend)
646
- print("预期收益:",round(GMV_y*100.0,2),'\b%')
647
- print("预期风险:",round(GMV_x*100.0,2),'\b%')
648
- print("*数据来源:新浪/stooq,"+str(today))
649
-
650
- return StockReturns
651
-
652
- #==============================================================================
653
- def translate_tickerlist(tickerlist):
654
- newlist=[]
655
- for t in tickerlist:
656
- name=codetranslate(t)
657
- newlist=newlist+[name]
658
-
659
- return newlist
660
- #==============================================================================
661
- # 绘制马科维茨有效边界
662
- #==============================================================================
663
- def ret_monthly(ticker,prices):
664
- """
665
- 功能:
666
- """
667
- price=prices['Adj Close'][ticker]
668
-
669
- import numpy as np
670
- div=price.pct_change()+1
671
- logret=np.log(div)
672
- import pandas as pd
673
- lrdf=pd.DataFrame(logret)
674
- lrdf['ymd']=lrdf.index.astype("str")
675
- lrdf['ym']=lrdf['ymd'].apply(lambda x:x[0:7])
676
- lrdf.dropna(inplace=True)
677
-
678
- mret=lrdf.groupby(by=['ym'])[ticker].sum()
679
-
680
- return mret
681
-
682
- if __name__=='__main__':
683
- ticker='MSFT'
684
- fromdate,todate='2019-1-1','2020-8-1'
685
-
686
- #==============================================================================
687
- def objFunction(W,R,target_ret):
688
-
689
- import numpy as np
690
- stock_mean=np.mean(R,axis=0)
691
- port_mean=np.dot(W,stock_mean) # portfolio mean
692
-
693
- cov=np.cov(R.T) # var-cov matrix
694
- port_var=np.dot(np.dot(W,cov),W.T) # portfolio variance
695
- penalty = 2000*abs(port_mean-target_ret)# penalty 4 deviation
696
-
697
- objfunc=np.sqrt(port_var) + penalty # objective function
698
-
699
- return objfunc
700
-
701
- #==============================================================================
702
- def portfolio_ef_0(stocks,fromdate,todate):
703
- """
704
- 功能:绘制马科维茨有效前沿,不区分上半沿和下半沿
705
- """
706
- #Code for getting stock prices
707
- prices=get_prices(stocks,fromdate,todate)
708
-
709
- #Code for generating a return matrix R
710
- R0=ret_monthly(stocks[0],prices) # starting from 1st stock
711
- n_stock=len(stocks) # number of stocks
712
- import pandas as pd
713
- import numpy as np
714
- for i in range(1,n_stock): # merge with other stocks
715
- x=ret_monthly(stocks[i],prices)
716
- R0=pd.merge(R0,x,left_index=True,right_index=True)
717
- R=np.array(R0)
718
-
719
- #Code for estimating optimal portfolios for a given return
720
- out_mean,out_std,out_weight=[],[],[]
721
- import numpy as np
722
- stockMean=np.mean(R,axis=0)
723
-
724
- from scipy.optimize import minimize
725
- for r in np.linspace(np.min(stockMean),np.max(stockMean),num=100):
726
- W = np.ones([n_stock])/n_stock # starting from equal weights
727
- b_ = [(0,1) for i in range(n_stock)] # bounds, here no short
728
- c_ = ({'type':'eq', 'fun': lambda W: sum(W)-1. }) #constraint
729
- result=minimize(objFunction,W,(R,r),method='SLSQP'
730
- ,constraints=c_, bounds=b_)
731
- if not result.success: # handle error raise
732
- BaseException(result.message)
733
-
734
- out_mean.append(round(r,4)) # 4 decimal places
735
- std_=round(np.std(np.sum(R*result.x,axis=1)),6)
736
- out_std.append(std_)
737
- out_weight.append(result.x)
738
-
739
- #Code for plotting the efficient frontier
740
-
741
- plt.title('Efficient Frontier of Portfolio')
742
- plt.xlabel('Standard Deviation of portfolio (Risk))')
743
- plt.ylabel('Return of portfolio')
744
-
745
- out_std_min=min(out_std)
746
- pos=out_std.index(out_std_min)
747
- out_mean_min=out_mean[pos]
748
- x_left=out_std_min+0.25
749
- y_left=out_mean_min+0.5
750
-
751
- #plt.figtext(x_left,y_left,str(n_stock)+' stock are used: ')
752
- plt.figtext(x_left,y_left,"投资组合由"+str(n_stock)+'种证券构成: ')
753
- plt.figtext(x_left,y_left-0.05,' '+str(stocks))
754
- plt.figtext(x_left,y_left-0.1,'观察期间:'+str(fromdate)+'至'+str(todate))
755
- plt.plot(out_std,out_mean,color='r',ls=':',lw=4)
756
- plt.show()
757
-
758
- return
759
-
760
- if __name__=='__main__':
761
- stocks=['IBM','WMT','AAPL','C','MSFT']
762
- fromdate,todate='2019-1-1','2020-8-1'
763
-
764
- #==============================================================================
765
- def portfolio_ef(stocks,fromdate,todate):
766
- """
767
- 功能:多只股票的马科维茨有效边界,区分上半沿和下半沿,标记风险极小点
768
- """
769
- print("\n...Searching for portfolio information, please wait...")
770
- #Code for getting stock prices
771
- prices=get_prices(stocks,fromdate,todate)
772
-
773
- #Code for generating a return matrix R
774
- R0=ret_monthly(stocks[0],prices) # starting from 1st stock
775
- n_stock=len(stocks) # number of stocks
776
-
777
- import pandas as pd
778
- import numpy as np
779
- for i in range(1,n_stock): # merge with other stocks
780
- x=ret_monthly(stocks[i],prices)
781
- R0=pd.merge(R0,x,left_index=True,right_index=True)
782
- R=np.array(R0)
783
-
784
- #Code for estimating optimal portfolios for a given return
785
- out_mean,out_std,out_weight=[],[],[]
786
- stockMean=np.mean(R,axis=0)
787
-
788
- from scipy.optimize import minimize
789
- for r in np.linspace(np.min(stockMean),np.max(stockMean),num=100):
790
- W = np.ones([n_stock])/n_stock # starting from equal weights
791
- b_ = [(0,1) for i in range(n_stock)] # bounds, here no short
792
- c_ = ({'type':'eq', 'fun': lambda W: sum(W)-1. }) #constraint
793
- result=minimize(objFunction,W,(R,r),method='SLSQP'
794
- ,constraints=c_, bounds=b_)
795
- if not result.success: # handle error raise
796
- BaseException(result.message)
797
-
798
- out_mean.append(round(r,4)) # 4 decimal places
799
- std_=round(np.std(np.sum(R*result.x,axis=1)),6)
800
- out_std.append(std_)
801
- out_weight.append(result.x)
802
-
803
- #Code for positioning
804
- out_std_min=min(out_std)
805
- pos=out_std.index(out_std_min)
806
- out_mean_min=out_mean[pos]
807
- x_left=out_std_min+0.25
808
- y_left=out_mean_min+0.5
809
-
810
- import pandas as pd
811
- out_df=pd.DataFrame(out_mean,out_std,columns=['mean'])
812
- out_df_ef=out_df[out_df['mean']>=out_mean_min]
813
- out_df_ief=out_df[out_df['mean']<out_mean_min]
814
-
815
- #Code for plotting the efficient frontier
816
-
817
- plt.title('投资组合:马科维茨有效边界')
818
-
819
- import datetime as dt; today=dt.date.today()
820
- plt.xlabel('预期风险-->'+"\n数据来源:新浪/stooq, "+str(today))
821
- plt.ylabel('预期收益')
822
-
823
- plt.figtext(x_left,y_left,"投资组合由"+str(n_stock)+'种证券构成: ')
824
- plt.figtext(x_left,y_left-0.05,' '+str(stocks))
825
- plt.figtext(x_left,y_left-0.1,'观察期间:'+str(fromdate)+'至'+str(todate))
826
- plt.plot(out_df_ef.index,out_df_ef['mean'],color='r',ls='--',lw=2,label='有效边界')
827
- plt.plot(out_df_ief.index,out_df_ief['mean'],color='k',ls=':',lw=2,label='无效边界')
828
- plt.plot(out_std_min,out_mean_min,'g*-',markersize=16,label='风险最低点')
829
-
830
- plt.legend(loc='best')
831
- plt.show()
832
-
833
- return out_df
834
-
835
- if __name__=='__main__':
836
- stocks=['IBM','WMT','AAPL','C','MSFT']
837
- fromdate,todate='2019-1-1','2020-8-1'
838
-
839
-
840
-
841
-
842
-
843
-
844
-
845
-
846
-
847
-
848
-
849
-
850
-
851
-
852
-
853
-
854
-
855
-
856
-
857
-
858
-
859
-
860
-
861
-
862
-
863
-
864
-
865
-
866
-
867
-
868
-
869
-
870
-
871
-