siat 3.1.6__py3-none-any.whl → 3.1.11__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.
- siat/markowitz2.py +158 -75
- siat/sector_china.py +47 -0
- {siat-3.1.6.dist-info → siat-3.1.11.dist-info}/METADATA +1 -1
- {siat-3.1.6.dist-info → siat-3.1.11.dist-info}/RECORD +6 -6
- {siat-3.1.6.dist-info → siat-3.1.11.dist-info}/WHEEL +0 -0
- {siat-3.1.6.dist-info → siat-3.1.11.dist-info}/top_level.txt +0 -0
siat/markowitz2.py
CHANGED
@@ -152,8 +152,12 @@ def cumulative_returns_plot(retgroup,name_list="",titletxt="投资组合策略
|
|
152
152
|
|
153
153
|
if xlabeltxt=="":
|
154
154
|
#取出观察期
|
155
|
-
hstart0=retgroup.index[0]
|
156
|
-
|
155
|
+
hstart0=retgroup.index[0]
|
156
|
+
#hstart=str(hstart0.date())
|
157
|
+
hstart=str(hstart0)
|
158
|
+
hend0=retgroup.index[-1]
|
159
|
+
#hend=str(hend0.date())
|
160
|
+
hend=str(hend0)
|
157
161
|
|
158
162
|
lang = check_language()
|
159
163
|
import datetime as dt; stoday=dt.date.today()
|
@@ -227,31 +231,41 @@ def portfolio_hpr(portfolio,thedate,pastyears=1, \
|
|
227
231
|
if __name__=='__main__':
|
228
232
|
Market={'Market':('US','^GSPC')}
|
229
233
|
Market={'Market':('US','^GSPC','我的组合001')}
|
230
|
-
Stocks1={'AAPL':.3,'MSFT':.15,'AMZN':.15,'
|
234
|
+
Stocks1={'AAPL':.3,'MSFT':.15,'AMZN':.15,'GOOG':.01}
|
231
235
|
Stocks2={'XOM':.02,'JNJ':.02,'JPM':.01,'TSLA':.3,'SBUX':.03}
|
232
236
|
portfolio=dict(Market,**Stocks1,**Stocks2)
|
233
237
|
|
234
238
|
ticker_name(portfolio)
|
235
239
|
|
236
|
-
|
240
|
+
portfolio=dict(Market,**Stocks1)
|
241
|
+
thedate='2024-5-30'
|
237
242
|
pastyears=1
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
243
|
+
printout=True
|
244
|
+
graph=True
|
245
|
+
|
246
|
+
pf_info=portfolio_build(portfolio,'2024-5-30')
|
242
247
|
|
243
248
|
"""
|
244
249
|
def portfolio_cumret(portfolio,thedate,pastyears=1, \
|
245
250
|
RF=0, \
|
246
251
|
printout=True,graph=True):
|
247
252
|
"""
|
248
|
-
def portfolio_build(portfolio,thedate,pastyears=1, \
|
249
|
-
|
250
|
-
printout=True,graph=True):
|
253
|
+
def portfolio_build(portfolio,thedate='default',pastyears=1, \
|
254
|
+
printout=True,graph=False):
|
251
255
|
"""
|
252
256
|
功能:收集投资组合成份股数据,绘制收益率趋势图,并与等权和期间内交易额加权策略组合比较
|
253
|
-
|
257
|
+
注意:此处无需RF,待到优化策略时再指定
|
258
|
+
printout=True控制获取股价时是否逐个显示
|
254
259
|
"""
|
260
|
+
import datetime
|
261
|
+
stoday = datetime.date.today()
|
262
|
+
if thedate=='default':
|
263
|
+
thedate=str(stoday)
|
264
|
+
else:
|
265
|
+
if not check_date(adate):
|
266
|
+
print(" #Warning(portfolio_build): invalid date",thedate)
|
267
|
+
return None
|
268
|
+
|
255
269
|
print("\n Searching for portfolio info, which may take time ...")
|
256
270
|
# 解构投资组合
|
257
271
|
scope,_,tickerlist,sharelist0=decompose_portfolio(portfolio)
|
@@ -271,13 +285,13 @@ def portfolio_build(portfolio,thedate,pastyears=1, \
|
|
271
285
|
# 计算历史数据的开始日期
|
272
286
|
start=get_start_date(thedate,pastyears)
|
273
287
|
|
274
|
-
|
288
|
+
#处理无风险利率,不再需要,但为兼容考虑仍保留,根据手动输入的RF构造rf_df以便后续改动量较小
|
275
289
|
import pandas as pd
|
276
|
-
date_series = pd.date_range(start=start,
|
290
|
+
date_series = pd.date_range(start=start,end=thedate,freq='D')
|
277
291
|
rf_df=pd.DataFrame(index=date_series)
|
278
292
|
rf_df['date']=rf_df.index
|
279
293
|
rf_df['date']=rf_df['date'].apply(lambda x: x.strftime('%Y-%m-%d'))
|
280
|
-
rf_df['RF']=RF
|
294
|
+
rf_df['RF']=RF=0
|
281
295
|
rf_df['rf_daily']=RF/365
|
282
296
|
"""
|
283
297
|
#一次性获得无风险利率,传递给后续函数,避免后续每次获取,耗费时间
|
@@ -308,19 +322,32 @@ def portfolio_build(portfolio,thedate,pastyears=1, \
|
|
308
322
|
#prices=get_prices(tickerlist,start,thedate)
|
309
323
|
|
310
324
|
if printout:
|
311
|
-
prices=get_prices_simple(tickerlist,start,thedate) #有待改造?
|
325
|
+
#prices=get_prices_simple(tickerlist,start,thedate) #有待改造?
|
326
|
+
#债券优先
|
327
|
+
prices,found=get_price_mticker(tickerlist,start,thedate, \
|
328
|
+
adjust='',source='auto',ticker_type='bond',fill=False)
|
312
329
|
else:
|
313
330
|
with HiddenPrints():
|
314
|
-
prices=get_prices_simple(tickerlist,start,thedate) #有待改造?
|
315
|
-
|
316
|
-
|
331
|
+
#prices=get_prices_simple(tickerlist,start,thedate) #有待改造?
|
332
|
+
prices,found=get_price_mticker(tickerlist,start,thedate, \
|
333
|
+
adjust='',source='auto',ticker_type='bond',fill=False)
|
334
|
+
|
335
|
+
if found == 'Found':
|
336
|
+
ntickers=len(list(prices['Close']))
|
337
|
+
nrecords=len(prices)
|
317
338
|
#print(" Successfully retrieved",ntickers,"stocks with",nrecords,"record(s) respectively")
|
318
|
-
print(" Successfully retrieved prices of",ntickers,"
|
339
|
+
print(" Successfully retrieved prices of",ntickers,"securities for",pname)
|
340
|
+
|
341
|
+
if ntickers != len(tickerlist):
|
342
|
+
print(" However, failed to access some securities, unable to build portfolio",pname)
|
343
|
+
return None
|
319
344
|
|
320
|
-
if prices is None:
|
345
|
+
#if prices is None:
|
346
|
+
if found == 'None':
|
321
347
|
print(" #Error(portfolio_build): failed to get portfolio prices",pname)
|
322
348
|
return None
|
323
|
-
if len(prices) == 0:
|
349
|
+
#if len(prices) == 0:
|
350
|
+
if found == 'Empty':
|
324
351
|
print(" #Error(portfolio_build): retrieved empty prices for",pname)
|
325
352
|
return None
|
326
353
|
#..........................................................................
|
@@ -367,9 +394,9 @@ def portfolio_build(portfolio,thedate,pastyears=1, \
|
|
367
394
|
plt.gca().set_facecolor('whitesmoke')
|
368
395
|
|
369
396
|
plt.legend(); plt.show(); plt.close()
|
370
|
-
|
371
|
-
|
372
|
-
|
397
|
+
#..........................................................................
|
398
|
+
|
399
|
+
# 计算原投资组合的持有收益率,并绘图
|
373
400
|
name_list=["Portfolio"]
|
374
401
|
label_list=[pname]
|
375
402
|
|
@@ -475,8 +502,8 @@ def portfolio_correlate(pf_info):
|
|
475
502
|
pname=portfolio_name(portfolio)
|
476
503
|
|
477
504
|
#取出观察期
|
478
|
-
hstart0=stock_return.index[0]; hstart=str(hstart0
|
479
|
-
hend0=stock_return.index[-1]; hend=str(hend0
|
505
|
+
hstart0=stock_return.index[0]; hstart=str(hstart0)
|
506
|
+
hend0=stock_return.index[-1]; hend=str(hend0)
|
480
507
|
|
481
508
|
sr=stock_return.copy()
|
482
509
|
collist=list(sr)
|
@@ -523,8 +550,8 @@ def portfolio_covar(pf_info):
|
|
523
550
|
pname=portfolio_name(portfolio)
|
524
551
|
|
525
552
|
#取出观察期
|
526
|
-
hstart0=stock_return.index[0]; hstart=str(hstart0
|
527
|
-
hend0=stock_return.index[-1]; hend=str(hend0
|
553
|
+
hstart0=stock_return.index[0]; hstart=str(hstart0)
|
554
|
+
hend0=stock_return.index[-1]; hend=str(hend0)
|
528
555
|
|
529
556
|
# 计算协方差矩阵
|
530
557
|
cov_mat = stock_return.cov()
|
@@ -584,8 +611,12 @@ def portfolio_expectation_universal(pname,member_returns,portfolio_weights,membe
|
|
584
611
|
"""
|
585
612
|
|
586
613
|
#观察期
|
587
|
-
hstart0=member_returns.index[0]
|
588
|
-
|
614
|
+
hstart0=member_returns.index[0]
|
615
|
+
#hstart=str(hstart0.date())
|
616
|
+
hstart=str(hstart0)
|
617
|
+
hend0=member_returns.index[-1]
|
618
|
+
#hend=str(hend0.date())
|
619
|
+
hend=str(hend0)
|
589
620
|
tickerlist=list(member_returns)
|
590
621
|
|
591
622
|
#合成投资组合的历史收益率,按行横向加权求和
|
@@ -623,7 +654,7 @@ def portfolio_expectation_universal(pname,member_returns,portfolio_weights,membe
|
|
623
654
|
print(" ***投资组合持仓策略***")
|
624
655
|
print_tickerlist_sharelist(tickerlist,portfolio_weights,4)
|
625
656
|
|
626
|
-
print(" *来源:Sina/EM/stooq,"+str(stoday))
|
657
|
+
print(" *来源:Sina/EM/stooq,"+str(stoday)+"统计")
|
627
658
|
else:
|
628
659
|
print("\n ======= Investment Portfolio: Return and Risk =======")
|
629
660
|
print(" Investment portfolio:",pname)
|
@@ -703,7 +734,7 @@ def portfolio_ranks_cn(portfolio_returns,pname,facecolor='whitesmoke'):
|
|
703
734
|
#以pname组合作为基准
|
704
735
|
import numpy as np
|
705
736
|
mean_return_pname=pr[pname].mean(axis=0)
|
706
|
-
annual_return_pname=round(((1 + mean_return_pname)**252 - 1)*100,
|
737
|
+
annual_return_pname=round(((1 + mean_return_pname)**252 - 1)*100,4)
|
707
738
|
"""
|
708
739
|
if annual_return_pname > 0:
|
709
740
|
pct_style=True #百分比模式
|
@@ -713,22 +744,23 @@ def portfolio_ranks_cn(portfolio_returns,pname,facecolor='whitesmoke'):
|
|
713
744
|
pct_style=False
|
714
745
|
|
715
746
|
std_return_pname=pr[pname].std(axis=0)
|
716
|
-
annual_std_pname= round((std_return_pname*np.sqrt(252))*100,
|
747
|
+
annual_std_pname= round((std_return_pname*np.sqrt(252))*100,4)
|
717
748
|
|
718
749
|
import pandas as pd
|
719
750
|
#prr=pd.DataFrame(columns=["名称","年化收益率","收益率变化","年化标准差","标准差变化","收益/风险"])
|
720
|
-
prr=pd.DataFrame(columns=["名称","年化收益率%","收益率变化","年化标准差%","标准差变化","收益/风险"])
|
751
|
+
#prr=pd.DataFrame(columns=["名称","年化收益率%","收益率变化","年化标准差%","标准差变化","收益/风险"])
|
752
|
+
prr=pd.DataFrame(columns=["名称","年化收益率%","收益率变化","年化标准差%","标准差变化","收益率/标准差"])
|
721
753
|
cols=list(pr)
|
722
754
|
for c in cols:
|
723
755
|
|
724
756
|
#年化收益率:按列求均值
|
725
757
|
mean_return=pr[c].mean(axis=0)
|
726
|
-
annual_return = round(((1 + mean_return)**252 - 1)*100,
|
758
|
+
annual_return = round(((1 + mean_return)**252 - 1)*100,4)
|
727
759
|
|
728
760
|
if pct_style:
|
729
|
-
return_chg=round((annual_return - annual_return_pname) / annual_return_pname * 100,
|
761
|
+
return_chg=round((annual_return - annual_return_pname) / annual_return_pname * 100,4)
|
730
762
|
else:
|
731
|
-
return_chg=round((annual_return - annual_return_pname),
|
763
|
+
return_chg=round((annual_return - annual_return_pname),4)
|
732
764
|
|
733
765
|
#收益率变化
|
734
766
|
if return_chg==0:
|
@@ -746,14 +778,15 @@ def portfolio_ranks_cn(portfolio_returns,pname,facecolor='whitesmoke'):
|
|
746
778
|
|
747
779
|
#年化标准差
|
748
780
|
std_return=pr[c].std(axis=0)
|
749
|
-
annual_std = round((std_return*np.sqrt(252))*100,
|
781
|
+
annual_std = round((std_return*np.sqrt(252))*100,4)
|
750
782
|
|
751
|
-
sharpe_ratio=round(annual_return / annual_std,2)
|
783
|
+
#sharpe_ratio=round(annual_return / annual_std,2)
|
784
|
+
sharpe_ratio=round((annual_return) / annual_std,4)
|
752
785
|
|
753
786
|
if pct_style:
|
754
|
-
std_chg=round((annual_std - annual_std_pname) / annual_std_pname * 100,
|
787
|
+
std_chg=round((annual_std - annual_std_pname) / annual_std_pname * 100,4)
|
755
788
|
else:
|
756
|
-
std_chg=round((annual_std - annual_std_pname),
|
789
|
+
std_chg=round((annual_std - annual_std_pname),4)
|
757
790
|
|
758
791
|
#标准差变化
|
759
792
|
if std_chg==0:
|
@@ -771,7 +804,7 @@ def portfolio_ranks_cn(portfolio_returns,pname,facecolor='whitesmoke'):
|
|
771
804
|
|
772
805
|
row=pd.Series({"名称":c,"年化收益率%":annual_return, \
|
773
806
|
"收益率变化":return_chg_str, \
|
774
|
-
"年化标准差%":annual_std,"标准差变化":std_chg_str,"
|
807
|
+
"年化标准差%":annual_std,"标准差变化":std_chg_str,"收益率/标准差":sharpe_ratio})
|
775
808
|
try:
|
776
809
|
prr=prr.append(row,ignore_index=True)
|
777
810
|
except:
|
@@ -790,7 +823,7 @@ def portfolio_ranks_cn(portfolio_returns,pname,facecolor='whitesmoke'):
|
|
790
823
|
#prr2=prr[["名称","收益排名","风险排名","年化收益率","年化标准差","收益率变化","标准差变化","收益/风险"]]
|
791
824
|
prr2=prr[["名称","收益排名","年化收益率%","收益率变化", \
|
792
825
|
"风险排名","年化标准差%","标准差变化", \
|
793
|
-
"
|
826
|
+
"收益率/标准差"]]
|
794
827
|
prr2.sort_values(by="年化收益率%",ascending=False,inplace=True)
|
795
828
|
#prr2.reset_index(inplace=True)
|
796
829
|
|
@@ -816,7 +849,7 @@ def portfolio_ranks_cn(portfolio_returns,pname,facecolor='whitesmoke'):
|
|
816
849
|
prr2.rename(columns={'名称':'投资组合名称/策略'},inplace=True)
|
817
850
|
for c in list(prr2):
|
818
851
|
try:
|
819
|
-
prr2[c]=prr2[c].apply(lambda x: str(round(x,
|
852
|
+
prr2[c]=prr2[c].apply(lambda x: str(round(x,4)) if isinstance(x,float) else str(x))
|
820
853
|
except: pass
|
821
854
|
|
822
855
|
titletxt='投资组合策略排名:平衡收益与风险'
|
@@ -829,6 +862,14 @@ def portfolio_ranks_cn(portfolio_returns,pname,facecolor='whitesmoke'):
|
|
829
862
|
from IPython.display import display
|
830
863
|
display(dispf)
|
831
864
|
"""
|
865
|
+
|
866
|
+
df_display_CSS(prr2,titletxt=titletxt,footnote='',facecolor='papayawhip',decimals=4, \
|
867
|
+
first_col_align='left',second_col_align='center', \
|
868
|
+
last_col_align='right',other_col_align='right', \
|
869
|
+
titile_font_size='16px',heading_font_size='15px', \
|
870
|
+
data_font_size='15px')
|
871
|
+
|
872
|
+
"""
|
832
873
|
print(' ') #空一行
|
833
874
|
|
834
875
|
disph=prr2.style.hide() #不显示索引列
|
@@ -853,7 +894,7 @@ def portfolio_ranks_cn(portfolio_returns,pname,facecolor='whitesmoke'):
|
|
853
894
|
display(dispf2)
|
854
895
|
|
855
896
|
print('') #空一行
|
856
|
-
|
897
|
+
"""
|
857
898
|
return prr2
|
858
899
|
|
859
900
|
if __name__=='__main__':
|
@@ -910,12 +951,12 @@ def portfolio_ranks_en(portfolio_returns,pname):
|
|
910
951
|
std_return=pr[c].std(axis=0)
|
911
952
|
annual_std = std_return*np.sqrt(252)
|
912
953
|
|
913
|
-
sharpe_ratio=round(annual_return / annual_std,
|
954
|
+
sharpe_ratio=round(annual_return / annual_std,4)
|
914
955
|
|
915
956
|
if pct_style:
|
916
|
-
std_chg=round((annual_std - annual_std_pname) / annual_std_pname *100,
|
957
|
+
std_chg=round((annual_std - annual_std_pname) / annual_std_pname *100,4)
|
917
958
|
else:
|
918
|
-
std_chg=round((annual_std - annual_std_pname),
|
959
|
+
std_chg=round((annual_std - annual_std_pname),4)
|
919
960
|
if std_chg==0:
|
920
961
|
std_chg_str="base"
|
921
962
|
elif std_chg > 0:
|
@@ -982,8 +1023,8 @@ def portfolio_eset(pf_info,simulation=50000):
|
|
982
1023
|
_,_,tickerlist,_=decompose_portfolio(portfolio)
|
983
1024
|
|
984
1025
|
#取出观察期
|
985
|
-
hstart0=stock_return.index[0]; hstart=str(hstart0
|
986
|
-
hend0=stock_return.index[-1]; hend=str(hend0
|
1026
|
+
hstart0=stock_return.index[0]; hstart=str(hstart0)
|
1027
|
+
hend0=stock_return.index[-1]; hend=str(hend0)
|
987
1028
|
|
988
1029
|
#获得成份股个数
|
989
1030
|
numstocks=len(tickerlist)
|
@@ -1098,8 +1139,8 @@ def portfolio_es_sharpe(pf_info,simulation=1000,RF=0):
|
|
1098
1139
|
scope,_,tickerlist,_=decompose_portfolio(portfolio)
|
1099
1140
|
|
1100
1141
|
#取出观察期
|
1101
|
-
hstart0=stock_return0.index[0]; hstart=str(hstart0
|
1102
|
-
hend0=stock_return0.index[-1]; hend=str(hend0
|
1142
|
+
hstart0=stock_return0.index[0]; hstart=str(hstart0)
|
1143
|
+
hend0=stock_return0.index[-1]; hend=str(hend0)
|
1103
1144
|
|
1104
1145
|
import pandas as pd
|
1105
1146
|
#处理无风险利率
|
@@ -1192,8 +1233,8 @@ def portfolio_es_sortino(pf_info,simulation=1000,RF=0):
|
|
1192
1233
|
scope,_,tickerlist,_=decompose_portfolio(portfolio)
|
1193
1234
|
|
1194
1235
|
#取出观察期
|
1195
|
-
hstart0=stock_return0.index[0]; hstart=str(hstart0
|
1196
|
-
hend0=stock_return0.index[-1]; hend=str(hend0
|
1236
|
+
hstart0=stock_return0.index[0]; hstart=str(hstart0)
|
1237
|
+
hend0=stock_return0.index[-1]; hend=str(hend0)
|
1197
1238
|
|
1198
1239
|
import pandas as pd
|
1199
1240
|
#处理无风险利率
|
@@ -1292,8 +1333,8 @@ def portfolio_es_alpha(pf_info,simulation=1000,RF=0):
|
|
1292
1333
|
scope,mktidx,tickerlist,_=decompose_portfolio(portfolio)
|
1293
1334
|
|
1294
1335
|
#取出观察期
|
1295
|
-
hstart0=stock_return0.index[0]; hstart=str(hstart0
|
1296
|
-
hend0=stock_return0.index[-1]; hend=str(hend0
|
1336
|
+
hstart0=stock_return0.index[0]; hstart=str(hstart0)
|
1337
|
+
hend0=stock_return0.index[-1]; hend=str(hend0)
|
1297
1338
|
|
1298
1339
|
#计算市场指数的收益率
|
1299
1340
|
import pandas as pd
|
@@ -1408,8 +1449,8 @@ def portfolio_es_treynor(pf_info,simulation=1000,RF=0):
|
|
1408
1449
|
scope,mktidx,tickerlist,_=decompose_portfolio(portfolio)
|
1409
1450
|
|
1410
1451
|
#取出观察期
|
1411
|
-
hstart0=stock_return0.index[0]; hstart=str(hstart0
|
1412
|
-
hend0=stock_return0.index[-1]; hend=str(hend0
|
1452
|
+
hstart0=stock_return0.index[0]; hstart=str(hstart0)
|
1453
|
+
hend0=stock_return0.index[-1]; hend=str(hend0)
|
1413
1454
|
|
1414
1455
|
#计算市场指数的收益率
|
1415
1456
|
import pandas as pd
|
@@ -1588,6 +1629,31 @@ def RandomPortfolios_plot(RandomPortfolios,col_x,col_y,colorbartxt,title_ext, \
|
|
1588
1629
|
|
1589
1630
|
return
|
1590
1631
|
#==============================================================================
|
1632
|
+
#==============================================================================
|
1633
|
+
if __name__=='__main__':
|
1634
|
+
pname="MSR组合"
|
1635
|
+
modify_portfolio_name(pname)
|
1636
|
+
|
1637
|
+
def modify_portfolio_name(pname):
|
1638
|
+
"""
|
1639
|
+
功能:将原来的类似于MSR组合修改为更易懂的名称,仅供打印时使用
|
1640
|
+
"""
|
1641
|
+
pclist=['等权重组合','交易额加权组合','MSR组合','GMVS组合','MSO组合','GML组合', \
|
1642
|
+
'MAR组合','GMBA组合', 'MTR组合','GMBT组合']
|
1643
|
+
|
1644
|
+
pclist1=['等权重组合','交易额加权组合', \
|
1645
|
+
'最佳夏普比率组合(MSR)','夏普比率最小风险组合(GMVS)', \
|
1646
|
+
'最佳索替诺比率组合(MSO)','索替诺比率最小风险组合(GML)', \
|
1647
|
+
'最佳阿尔法指标组合(MAR)','阿尔法指标最小风险组合(GMBA)', \
|
1648
|
+
'最佳特雷诺比率组合(MTR)','特雷诺比率最小风险组合(GMBT)']
|
1649
|
+
|
1650
|
+
if pname not in pclist:
|
1651
|
+
return pname
|
1652
|
+
|
1653
|
+
pos=pclist.index(pname)
|
1654
|
+
|
1655
|
+
return pclist1[pos]
|
1656
|
+
|
1591
1657
|
#==============================================================================
|
1592
1658
|
def cvt_portfolio_name(pname,portfolio_returns):
|
1593
1659
|
"""
|
@@ -1601,8 +1667,16 @@ def cvt_portfolio_name(pname,portfolio_returns):
|
|
1601
1667
|
|
1602
1668
|
lang=check_language()
|
1603
1669
|
if lang == "Chinese":
|
1670
|
+
"""
|
1604
1671
|
pclist=[pname,'等权重组合','交易额加权组合','MSR组合','GMVS组合','MSO组合','GML组合', \
|
1605
1672
|
'MAR组合','GMBA组合', 'MTR组合','GMBT组合']
|
1673
|
+
"""
|
1674
|
+
pclist=[pname,'等权重组合','交易额加权组合', \
|
1675
|
+
'最佳夏普比率组合(MSR)','夏普比率最小风险组合(GMVS)', \
|
1676
|
+
'最佳索替诺比率组合(MSO)','索替诺比率最小风险组合(GML)', \
|
1677
|
+
'最佳阿尔法指标组合(MAR)','阿尔法指标最小风险组合(GMBA)', \
|
1678
|
+
'最佳特雷诺比率组合(MTR)','特雷诺比率最小风险组合(GMBT)']
|
1679
|
+
|
1606
1680
|
else:
|
1607
1681
|
pclist=[pname,'Equal-weight','Amount-weight','MSR','GMVS','MSO','GML', \
|
1608
1682
|
'MAR','GMBA', 'MTR','GMBT']
|
@@ -1621,7 +1695,7 @@ def cvt_portfolio_name(pname,portfolio_returns):
|
|
1621
1695
|
|
1622
1696
|
#==============================================================================
|
1623
1697
|
|
1624
|
-
def portfolio_optimize_sharpe(es_info,
|
1698
|
+
def portfolio_optimize_sharpe(es_info,graph=True):
|
1625
1699
|
"""
|
1626
1700
|
功能:计算投资组合的最高夏普比率组合,并绘图
|
1627
1701
|
MSR: Maximium Sharpe Rate, 最高夏普指数方案
|
@@ -1697,7 +1771,7 @@ if __name__=='__main__':
|
|
1697
1771
|
|
1698
1772
|
#==============================================================================
|
1699
1773
|
|
1700
|
-
def portfolio_optimize_sortino(es_info,
|
1774
|
+
def portfolio_optimize_sortino(es_info,graph=True):
|
1701
1775
|
"""
|
1702
1776
|
功能:计算投资组合的最高索替诺比率组合,并绘图
|
1703
1777
|
MSO: Maximium Sortino ratio, 最高索替诺比率方案
|
@@ -1745,7 +1819,7 @@ if __name__=='__main__':
|
|
1745
1819
|
|
1746
1820
|
#==============================================================================
|
1747
1821
|
|
1748
|
-
def portfolio_optimize_alpha(es_info,
|
1822
|
+
def portfolio_optimize_alpha(es_info,graph=True):
|
1749
1823
|
"""
|
1750
1824
|
功能:计算投资组合的最高詹森阿尔法组合,并绘图
|
1751
1825
|
MAR: Maximium Alpha Ratio, 最高阿尔法指数方案
|
@@ -1791,7 +1865,7 @@ if __name__=='__main__':
|
|
1791
1865
|
|
1792
1866
|
#==============================================================================
|
1793
1867
|
|
1794
|
-
def portfolio_optimize_treynor(es_info,
|
1868
|
+
def portfolio_optimize_treynor(es_info,graph=True):
|
1795
1869
|
"""
|
1796
1870
|
功能:计算投资组合的最高特雷诺比率组合,并绘图
|
1797
1871
|
MTR: Maximium Treynor Ratio, 最高特雷诺指数方案
|
@@ -1851,8 +1925,8 @@ def portfolio_optimize_rar(es_info,col_ratio,col_y,col_x,name_hiret,name_lorisk,
|
|
1851
1925
|
pname=portfolio_name(portfolio)
|
1852
1926
|
|
1853
1927
|
#取出观察期
|
1854
|
-
hstart0=StockReturns.index[0]; hstart=str(hstart0
|
1855
|
-
hend0=StockReturns.index[-1]; hend=str(hend0
|
1928
|
+
hstart0=StockReturns.index[0]; hstart=str(hstart0)
|
1929
|
+
hend0=StockReturns.index[-1]; hend=str(hend0)
|
1856
1930
|
|
1857
1931
|
#识别并计算指数..........................................................
|
1858
1932
|
if col_ratio in ['Alpha']:
|
@@ -1932,12 +2006,16 @@ if __name__=='__main__':
|
|
1932
2006
|
ratio='treynor'
|
1933
2007
|
simulation=1000
|
1934
2008
|
simulation=50000
|
2009
|
+
|
2010
|
+
RF=0
|
2011
|
+
graph=True;hirar_return=False;lorisk=True
|
1935
2012
|
|
1936
|
-
def portfolio_optimize(pf_info,ratio='sharpe',simulation=
|
1937
|
-
graph=True,
|
2013
|
+
def portfolio_optimize(pf_info,ratio='sharpe',simulation=10000,RF=0, \
|
2014
|
+
graph=True,hirar_return=False,lorisk=True):
|
1938
2015
|
"""
|
1939
2016
|
功能:集成式投资组合优化策略
|
1940
|
-
注意:实验发现RF
|
2017
|
+
注意:实验发现RF较小时对于结果的影响极其微小难以观察,默认设为不使用无风险利率调整收益
|
2018
|
+
但RF较大时对于结果的影响明显变大,已经不能忽略!
|
1941
2019
|
"""
|
1942
2020
|
|
1943
2021
|
ratio_list=['treynor','sharpe','sortino','alpha']
|
@@ -1956,11 +2034,16 @@ def portfolio_optimize(pf_info,ratio='sharpe',simulation=50000,RF=0, \
|
|
1956
2034
|
es_info=eval(func_es)(pf_info=pf_info,simulation=simulation,RF=RF)
|
1957
2035
|
|
1958
2036
|
|
1959
|
-
|
2037
|
+
#寻找比率最优点:最大比率策略和最小风险策略
|
1960
2038
|
func_optimize="portfolio_optimize_"+ratio
|
2039
|
+
"""
|
1961
2040
|
name_hiret,hiret_weights,name_lorisk,lorisk_weights,portfolio_returns= \
|
1962
2041
|
eval(func_optimize)(es_info=es_info,RF=RF,graph=graph)
|
1963
|
-
|
2042
|
+
"""
|
2043
|
+
name_hiret,hiret_weights,name_lorisk,lorisk_weights,portfolio_returns= \
|
2044
|
+
eval(func_optimize)(es_info=es_info,graph=graph)
|
2045
|
+
|
2046
|
+
|
1964
2047
|
lang = check_language()
|
1965
2048
|
if lang == 'Chinese':
|
1966
2049
|
zhuhe_txt='组合'
|
@@ -1974,11 +2057,11 @@ def portfolio_optimize(pf_info,ratio='sharpe',simulation=50000,RF=0, \
|
|
1974
2057
|
ylabeltxt="Holding Return"
|
1975
2058
|
|
1976
2059
|
#打印投资组合构造和业绩表现
|
1977
|
-
hi_name=name_hiret+zhuhe_txt
|
1978
|
-
lo_name=name_lorisk+zhuhe_txt
|
2060
|
+
hi_name=modify_portfolio_name(name_hiret+zhuhe_txt)
|
2061
|
+
lo_name=modify_portfolio_name(name_lorisk+zhuhe_txt)
|
1979
2062
|
portfolio_expectation(hi_name,pf_info,hiret_weights)
|
1980
2063
|
|
1981
|
-
if
|
2064
|
+
if hirar_return:
|
1982
2065
|
scope,mktidx,tickerlist,_=decompose_portfolio(portfolio)
|
1983
2066
|
hwdf=pd.DataFrame(hiret_weights)
|
1984
2067
|
hwdft=hwdf.T
|
@@ -1993,7 +2076,7 @@ def portfolio_optimize(pf_info,ratio='sharpe',simulation=50000,RF=0, \
|
|
1993
2076
|
Market={'Market':(scope,mktidx,pname)}
|
1994
2077
|
portfolio_new=dict(Market,**stocks_new)
|
1995
2078
|
|
1996
|
-
if
|
2079
|
+
if lorisk:
|
1997
2080
|
portfolio_expectation(lo_name,pf_info,lorisk_weights)
|
1998
2081
|
|
1999
2082
|
#现有投资组合的排名
|
@@ -2011,7 +2094,7 @@ def portfolio_optimize(pf_info,ratio='sharpe',simulation=50000,RF=0, \
|
|
2011
2094
|
if graph:
|
2012
2095
|
portfolio_expret_plot(portfolio_returns,name_list,titletxt=titletxt,ylabeltxt=ylabeltxt)
|
2013
2096
|
|
2014
|
-
if
|
2097
|
+
if hirar_return:
|
2015
2098
|
return portfolio_new
|
2016
2099
|
else:
|
2017
2100
|
return
|
siat/sector_china.py
CHANGED
@@ -3065,6 +3065,53 @@ def find_industry_sw(ticker):
|
|
3065
3065
|
break
|
3066
3066
|
|
3067
3067
|
return
|
3068
|
+
|
3069
|
+
#==============================================================================
|
3070
|
+
if __name__=='__main__':
|
3071
|
+
ticker='600791.SS'
|
3072
|
+
find_industry_sw(ticker)
|
3073
|
+
|
3074
|
+
def find_industry_sw(ticker,level='2'):
|
3075
|
+
"""
|
3076
|
+
功能:寻找一只股票所属的申万行业
|
3077
|
+
"""
|
3078
|
+
ticker6=ticker[:6]
|
3079
|
+
|
3080
|
+
import akshare as ak
|
3081
|
+
if level == '3':
|
3082
|
+
df = ak.sw_index_third_info()
|
3083
|
+
elif level == '2':
|
3084
|
+
df = ak.sw_index_second_info()
|
3085
|
+
else:
|
3086
|
+
df = ak.sw_index_first_info()
|
3087
|
+
|
3088
|
+
df['industry_code']=df['行业代码'].apply(lambda x: x[:6])
|
3089
|
+
industry_list=list(df['industry_code'])
|
3090
|
+
|
3091
|
+
for i in industry_list:
|
3092
|
+
print_progress_percent2(i,industry_list,steps=10,leading_blanks=0)
|
3093
|
+
|
3094
|
+
try:
|
3095
|
+
cdf = ak.index_component_sw(i)
|
3096
|
+
except:
|
3097
|
+
print(" #Warning(find_industry_sw): server banned this ip becos of too many requests")
|
3098
|
+
print(" Solution: change to another ip or another computer, or try a few hours later.")
|
3099
|
+
return
|
3100
|
+
|
3101
|
+
component_list=list(cdf['证券代码'])
|
3102
|
+
|
3103
|
+
if ticker6 in component_list:
|
3104
|
+
stock_name=cdf[cdf["证券代码"]==ticker6]['证券名称'].values[0]
|
3105
|
+
print("\n\n股票代码:"+ticker+","+stock_name)
|
3106
|
+
|
3107
|
+
isi=i+'.SI'
|
3108
|
+
industry_name=df[df['行业代码']==isi]['行业名称'].values[0]
|
3109
|
+
print("申万"+str(level)+"级行业代码:"+i+".SW,"+industry_name)
|
3110
|
+
|
3111
|
+
break
|
3112
|
+
|
3113
|
+
return
|
3114
|
+
|
3068
3115
|
#==============================================================================
|
3069
3116
|
#==============================================================================
|
3070
3117
|
#==============================================================================
|
@@ -66,7 +66,7 @@ siat/holding_risk_test.py,sha256=FRlw_9wFG98BYcg_cSj95HX5WZ1TvkGaOUdXD7-V86s,474
|
|
66
66
|
siat/local_debug_test.py,sha256=CDAOffW1Rvs-TcNN5giWVvHMlch1w4dp-w5SIV9jXL0,3936
|
67
67
|
siat/market_china.py,sha256=nabx24qm7N51OafTrwUw542pNeFJ3JaQ1wqyv-nLN5I,37883
|
68
68
|
siat/markowitz.py,sha256=c06gCRhMABnrb30F-npJsKVv8nFfEoNNR3bzrkMCyGg,97406
|
69
|
-
siat/markowitz2.py,sha256=
|
69
|
+
siat/markowitz2.py,sha256=r8lqLhp0MrswkaPeLMEQvk4b5qC_Wc8U04PlJ45Y9o4,104269
|
70
70
|
siat/markowitz_ccb_test.py,sha256=xBkkoaNHdq9KSUrNuHGgKTdNYUvgi84kNYcf719eoyE,1593
|
71
71
|
siat/markowitz_ef_test.py,sha256=wjNlICkgRIqnonPeSIHo4Mu2GRtb9dr21wDt2kMNEcI,4032
|
72
72
|
siat/markowitz_old.py,sha256=Lf7O_4QWT8RsdkHiUyc_7kKY3eZjKDtFR89Fz3pwYnY,33046
|
@@ -91,7 +91,7 @@ siat/risk_evaluation.py,sha256=I6B3gty-t--AkDCO0tKF-291YfpnF-IkXcFjqNKCt9I,76286
|
|
91
91
|
siat/risk_evaluation_test.py,sha256=YEXM96gKzTfwN4U61AS4Rr1tV7KgUvn4rRC6f3iMw9s,3731
|
92
92
|
siat/risk_free_rate.py,sha256=ZMr4cHikPvXvywr54gGqiI3Nvb69am6tq3zj2hwzANE,12384
|
93
93
|
siat/risk_free_rate_test.py,sha256=CpmhUf8aEAEZeNu4gvWP2Mz2dLoIgBX5bI41vfUBEr8,4285
|
94
|
-
siat/sector_china.py,sha256=
|
94
|
+
siat/sector_china.py,sha256=ijczadqHt4wEvNYjzDFllanxBLfXJy10v5th09KBEpI,115049
|
95
95
|
siat/sector_china_test.py,sha256=1wq7ef8Bb_L8F0h0W6FvyBrIcBTEbrTV7hljtpj49U4,5843
|
96
96
|
siat/security_price.py,sha256=2oHskgiw41KMGfqtnA0i2YjNNV6cYgtlUK0j3YeuXWs,29185
|
97
97
|
siat/security_price2.py,sha256=kuYh0V5cqclkM6MjZUd-N361fv3oxGVVerYINuTzZrE,24622
|
@@ -132,7 +132,7 @@ siat/valuation.py,sha256=NKfeZMdDJOW42oLVHob6eSVBXUqlN1OCnnzwyGAst8c,48855
|
|
132
132
|
siat/valuation_china.py,sha256=Tde2LzPDQy3Z7xOQQDw4ckQMPdROp_z0-GjFE6Z5_lI,67639
|
133
133
|
siat/valuation_market_china_test.py,sha256=gbJ0ioauuo4koTPH6WKUkqcXiQPafnbhU5eKJ6lpdLA,1571
|
134
134
|
siat/var_model_validation.py,sha256=f-oDewg7bPzyNanz_Y_jLH68NowAA3gXFehW_weKGG0,14898
|
135
|
-
siat-3.1.
|
136
|
-
siat-3.1.
|
137
|
-
siat-3.1.
|
138
|
-
siat-3.1.
|
135
|
+
siat-3.1.11.dist-info/METADATA,sha256=lFu29swamLdB_jdSJNZqMhgIwlHI80JQffc5qHAj7f4,1448
|
136
|
+
siat-3.1.11.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
137
|
+
siat-3.1.11.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
|
138
|
+
siat-3.1.11.dist-info/RECORD,,
|
File without changes
|
File without changes
|