siat 3.1.12__py3-none-any.whl → 3.1.13__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/common.py +0 -78
- siat/exchange_bond_china.pickle +0 -0
- siat/fund_china.pickle +0 -0
- siat/fund_china.py +80 -18
- siat/markowitz2.py +122 -47
- siat/sector_china.py +6 -3
- siat/security_price2.py +43 -9
- siat/security_prices.py +31 -16
- siat/security_trend2.py +10 -2
- siat/stock.py +20 -3
- siat/stock_info.pickle +0 -0
- siat/translate.py +18 -14
- siat/translate_20240606.py +4206 -0
- {siat-3.1.12.dist-info → siat-3.1.13.dist-info}/METADATA +1 -1
- {siat-3.1.12.dist-info → siat-3.1.13.dist-info}/RECORD +17 -16
- {siat-3.1.12.dist-info → siat-3.1.13.dist-info}/WHEEL +0 -0
- {siat-3.1.12.dist-info → siat-3.1.13.dist-info}/top_level.txt +0 -0
siat/markowitz2.py
CHANGED
@@ -154,10 +154,10 @@ def cumulative_returns_plot(retgroup,name_list="",titletxt="投资组合策略
|
|
154
154
|
#取出观察期
|
155
155
|
hstart0=retgroup.index[0]
|
156
156
|
#hstart=str(hstart0.date())
|
157
|
-
hstart=str(hstart0)
|
157
|
+
hstart=str(hstart0.strftime("%Y-%m-%d"))
|
158
158
|
hend0=retgroup.index[-1]
|
159
159
|
#hend=str(hend0.date())
|
160
|
-
hend=str(hend0)
|
160
|
+
hend=str(hend0.strftime("%Y-%m-%d"))
|
161
161
|
|
162
162
|
lang = check_language()
|
163
163
|
import datetime as dt; stoday=dt.date.today()
|
@@ -222,28 +222,37 @@ def portfolio_hpr(portfolio,thedate,pastyears=1, \
|
|
222
222
|
功能:套壳函数portfolio_build
|
223
223
|
"""
|
224
224
|
dflist=portfolio_build(portfolio=portfolio,thedate=thedate,pastyears=pastyears, \
|
225
|
-
|
226
|
-
printout=printout,graph=graph)
|
225
|
+
printout=printout,graph=graph)
|
227
226
|
|
228
227
|
return dflist
|
229
228
|
|
230
229
|
#==============================================================================
|
231
230
|
if __name__=='__main__':
|
231
|
+
#测试1
|
232
232
|
Market={'Market':('US','^GSPC')}
|
233
233
|
Market={'Market':('US','^GSPC','我的组合001')}
|
234
234
|
Stocks1={'AAPL':.3,'MSFT':.15,'AMZN':.15,'GOOG':.01}
|
235
235
|
Stocks2={'XOM':.02,'JNJ':.02,'JPM':.01,'TSLA':.3,'SBUX':.03}
|
236
236
|
portfolio=dict(Market,**Stocks1,**Stocks2)
|
237
|
-
|
238
|
-
ticker_name(portfolio)
|
239
237
|
|
240
|
-
|
238
|
+
#测试2
|
239
|
+
Market={'Market':('China','000300.SS','养猪1号组合')}
|
240
|
+
porkbig={'000876.SZ':0.20,#新希望
|
241
|
+
'300498.SZ':0.15,#温氏股份
|
242
|
+
}
|
243
|
+
porksmall={'002124.SZ':0.10,#天邦股份
|
244
|
+
'600975.SS':0.10,#新五丰
|
245
|
+
'603477.SS':0.10,#巨星股份
|
246
|
+
'000735.SZ':0.07,#罗牛山
|
247
|
+
}
|
248
|
+
portfolio=dict(Market,**porkbig,**porksmall)
|
249
|
+
|
241
250
|
thedate='2024-5-30'
|
242
251
|
pastyears=1
|
243
252
|
printout=True
|
244
|
-
graph=
|
253
|
+
graph=False
|
245
254
|
|
246
|
-
pf_info=portfolio_build(portfolio,
|
255
|
+
pf_info=portfolio_build(portfolio,thedate,pastyears,printout,graph)
|
247
256
|
|
248
257
|
"""
|
249
258
|
def portfolio_cumret(portfolio,thedate,pastyears=1, \
|
@@ -262,7 +271,7 @@ def portfolio_build(portfolio,thedate='default',pastyears=1, \
|
|
262
271
|
if thedate=='default':
|
263
272
|
thedate=str(stoday)
|
264
273
|
else:
|
265
|
-
if not check_date(
|
274
|
+
if not check_date(thedate):
|
266
275
|
print(" #Warning(portfolio_build): invalid date",thedate)
|
267
276
|
return None
|
268
277
|
|
@@ -275,8 +284,8 @@ def portfolio_build(portfolio,thedate='default',pastyears=1, \
|
|
275
284
|
import numpy as np
|
276
285
|
totalshares=np.sum(sharelist0)
|
277
286
|
if abs(totalshares - 1) >= 0.00001:
|
278
|
-
print("
|
279
|
-
print(" Action: automatically converted into total weights 1.0")
|
287
|
+
print(" #Warning(portfolio_build): total weights is",totalshares,"\b, expecting 1.0 here")
|
288
|
+
print(" Action taken: automatically converted into total weights 1.0")
|
280
289
|
sharelist=list(sharelist0/totalshares)
|
281
290
|
else:
|
282
291
|
sharelist=sharelist0
|
@@ -502,8 +511,8 @@ def portfolio_correlate(pf_info):
|
|
502
511
|
pname=portfolio_name(portfolio)
|
503
512
|
|
504
513
|
#取出观察期
|
505
|
-
hstart0=stock_return.index[0]; hstart=str(hstart0)
|
506
|
-
hend0=stock_return.index[-1]; hend=str(hend0)
|
514
|
+
hstart0=stock_return.index[0]; hstart=str(hstart0.strftime("%Y-%m-%d"))
|
515
|
+
hend0=stock_return.index[-1]; hend=str(hend0.strftime("%Y-%m-%d"))
|
507
516
|
|
508
517
|
sr=stock_return.copy()
|
509
518
|
collist=list(sr)
|
@@ -550,8 +559,8 @@ def portfolio_covar(pf_info):
|
|
550
559
|
pname=portfolio_name(portfolio)
|
551
560
|
|
552
561
|
#取出观察期
|
553
|
-
hstart0=stock_return.index[0]; hstart=str(hstart0)
|
554
|
-
hend0=stock_return.index[-1]; hend=str(hend0)
|
562
|
+
hstart0=stock_return.index[0]; hstart=str(hstart0.strftime("%Y-%m-%d"))
|
563
|
+
hend0=stock_return.index[-1]; hend=str(hend0.strftime("%Y-%m-%d"))
|
555
564
|
|
556
565
|
# 计算协方差矩阵
|
557
566
|
cov_mat = stock_return.cov()
|
@@ -613,10 +622,10 @@ def portfolio_expectation_universal(pname,member_returns,portfolio_weights,membe
|
|
613
622
|
#观察期
|
614
623
|
hstart0=member_returns.index[0]
|
615
624
|
#hstart=str(hstart0.date())
|
616
|
-
hstart=str(hstart0)
|
625
|
+
hstart=str(hstart0.strftime("%Y-%m-%d"))
|
617
626
|
hend0=member_returns.index[-1]
|
618
627
|
#hend=str(hend0.date())
|
619
|
-
hend=str(hend0)
|
628
|
+
hend=str(hend0.strftime("%Y-%m-%d"))
|
620
629
|
tickerlist=list(member_returns)
|
621
630
|
|
622
631
|
#合成投资组合的历史收益率,按行横向加权求和
|
@@ -652,7 +661,7 @@ def portfolio_expectation_universal(pname,member_returns,portfolio_weights,membe
|
|
652
661
|
print(" 年化收益率:",round(annual_return,4))
|
653
662
|
print(" 年化标准差:",round(annual_std,4))
|
654
663
|
print(" ***投资组合持仓策略***")
|
655
|
-
print_tickerlist_sharelist(tickerlist,portfolio_weights,4)
|
664
|
+
print_tickerlist_sharelist(tickerlist,portfolio_weights,leading_blanks=4,ticker_type='bond')
|
656
665
|
|
657
666
|
print(" *来源:Sina/EM/stooq,"+str(stoday)+"统计")
|
658
667
|
else:
|
@@ -1013,18 +1022,21 @@ def portfolio_ranks_en(portfolio_returns,pname):
|
|
1013
1022
|
if __name__=='__main__':
|
1014
1023
|
simulation=1000
|
1015
1024
|
simulation=50000
|
1025
|
+
|
1026
|
+
portfolio_eset(pf_info,simulation=50000)
|
1016
1027
|
|
1017
|
-
def portfolio_eset(pf_info,simulation=
|
1028
|
+
def portfolio_eset(pf_info,simulation=1000,convex_hull=False):
|
1018
1029
|
"""
|
1019
1030
|
功能:基于随机数,生成大量可能的投资组合,计算各个投资组合的年均收益率和标准差,绘制投资组合的可行集
|
1031
|
+
默认绘制散点图凸包:convex_hull=True
|
1020
1032
|
"""
|
1021
1033
|
[[portfolio,thedate,stock_return,_,_],_]=pf_info
|
1022
1034
|
pname=portfolio_name(portfolio)
|
1023
1035
|
_,_,tickerlist,_=decompose_portfolio(portfolio)
|
1024
1036
|
|
1025
1037
|
#取出观察期
|
1026
|
-
hstart0=stock_return.index[0]; hstart=str(hstart0)
|
1027
|
-
hend0=stock_return.index[-1]; hend=str(hend0)
|
1038
|
+
hstart0=stock_return.index[0]; hstart=str(hstart0.strftime("%Y-%m-%d"))
|
1039
|
+
hend0=stock_return.index[-1]; hend=str(hend0.strftime("%Y-%m-%d"))
|
1028
1040
|
|
1029
1041
|
#获得成份股个数
|
1030
1042
|
numstocks=len(tickerlist)
|
@@ -1078,9 +1090,46 @@ def portfolio_eset(pf_info,simulation=50000):
|
|
1078
1090
|
|
1079
1091
|
#plt.style.use('seaborn-dark') #不支持中文
|
1080
1092
|
#plt.figure(figsize=(9, 5))
|
1081
|
-
plt.scatter(pf_volatilities,
|
1093
|
+
plt.scatter(pf_volatilities,pf_returns,c=pf_ratio,cmap='RdYlGn',edgecolors='black',marker='o')
|
1082
1094
|
#plt.grid(True)
|
1083
1095
|
|
1096
|
+
#绘制散点图轮廓线凸包(convex hull)
|
1097
|
+
if convex_hull:
|
1098
|
+
from scipy.spatial import ConvexHull
|
1099
|
+
|
1100
|
+
#构造散点对的列表
|
1101
|
+
pf_volatilities_list=list(pf_volatilities)
|
1102
|
+
pf_returns_list=list(pf_returns)
|
1103
|
+
points=[]
|
1104
|
+
for x in pf_volatilities_list:
|
1105
|
+
pos=pf_volatilities_list.index(x)
|
1106
|
+
y=pf_returns_list[pos]
|
1107
|
+
points=points+[[x,y]]
|
1108
|
+
|
1109
|
+
# 计算散点集的外轮廓
|
1110
|
+
hull = ConvexHull(points)
|
1111
|
+
# 绘制外轮廓线
|
1112
|
+
for simplex in hull.simplices:
|
1113
|
+
plt.plot([points[simplex[0]][0], points[simplex[1]][0]],
|
1114
|
+
[points[simplex[0]][1], points[simplex[1]][1]], 'k-')
|
1115
|
+
|
1116
|
+
"""
|
1117
|
+
#滚动法寻找上边沿
|
1118
|
+
points_sorted=points
|
1119
|
+
points_sorted.sort(key=lambda x: x[0])
|
1120
|
+
points_df=pd.DataFrame(points_sorted,columns=['x','y'])
|
1121
|
+
|
1122
|
+
window=100
|
1123
|
+
nwindow=int(len(points_df)/window)
|
1124
|
+
upper_points=[]
|
1125
|
+
for n in range(nwindow):
|
1126
|
+
tmp_df=points_df[n*window:n*window+window]
|
1127
|
+
max_y=max(tmp_df['y'])
|
1128
|
+
max_x=tmp_df[tmp_df['y']==max_y]['x'].values[0]
|
1129
|
+
|
1130
|
+
upper_points=upper_points+[[max_x,max_y]]
|
1131
|
+
"""
|
1132
|
+
|
1084
1133
|
import datetime as dt; stoday=dt.date.today()
|
1085
1134
|
lang = check_language()
|
1086
1135
|
if lang == 'Chinese':
|
@@ -1139,8 +1188,8 @@ def portfolio_es_sharpe(pf_info,simulation=1000,RF=0):
|
|
1139
1188
|
scope,_,tickerlist,_=decompose_portfolio(portfolio)
|
1140
1189
|
|
1141
1190
|
#取出观察期
|
1142
|
-
hstart0=stock_return0.index[0]; hstart=str(hstart0)
|
1143
|
-
hend0=stock_return0.index[-1]; hend=str(hend0)
|
1191
|
+
hstart0=stock_return0.index[0]; hstart=str(hstart0.strftime("%Y-%m-%d"))
|
1192
|
+
hend0=stock_return0.index[-1]; hend=str(hend0.strftime("%Y-%m-%d"))
|
1144
1193
|
|
1145
1194
|
import pandas as pd
|
1146
1195
|
#处理无风险利率
|
@@ -1233,8 +1282,8 @@ def portfolio_es_sortino(pf_info,simulation=1000,RF=0):
|
|
1233
1282
|
scope,_,tickerlist,_=decompose_portfolio(portfolio)
|
1234
1283
|
|
1235
1284
|
#取出观察期
|
1236
|
-
hstart0=stock_return0.index[0]; hstart=str(hstart0)
|
1237
|
-
hend0=stock_return0.index[-1]; hend=str(hend0)
|
1285
|
+
hstart0=stock_return0.index[0]; hstart=str(hstart0.strftime("%Y-%m-%d"))
|
1286
|
+
hend0=stock_return0.index[-1]; hend=str(hend0.strftime("%Y-%m-%d"))
|
1238
1287
|
|
1239
1288
|
import pandas as pd
|
1240
1289
|
#处理无风险利率
|
@@ -1333,8 +1382,8 @@ def portfolio_es_alpha(pf_info,simulation=1000,RF=0):
|
|
1333
1382
|
scope,mktidx,tickerlist,_=decompose_portfolio(portfolio)
|
1334
1383
|
|
1335
1384
|
#取出观察期
|
1336
|
-
hstart0=stock_return0.index[0]; hstart=str(hstart0)
|
1337
|
-
hend0=stock_return0.index[-1]; hend=str(hend0)
|
1385
|
+
hstart0=stock_return0.index[0]; hstart=str(hstart0.strftime("%Y-%m-%d"))
|
1386
|
+
hend0=stock_return0.index[-1]; hend=str(hend0.strftime("%Y-%m-%d"))
|
1338
1387
|
|
1339
1388
|
#计算市场指数的收益率
|
1340
1389
|
import pandas as pd
|
@@ -1449,8 +1498,8 @@ def portfolio_es_treynor(pf_info,simulation=1000,RF=0):
|
|
1449
1498
|
scope,mktidx,tickerlist,_=decompose_portfolio(portfolio)
|
1450
1499
|
|
1451
1500
|
#取出观察期
|
1452
|
-
hstart0=stock_return0.index[0]; hstart=str(hstart0)
|
1453
|
-
hend0=stock_return0.index[-1]; hend=str(hend0)
|
1501
|
+
hstart0=stock_return0.index[0]; hstart=str(hstart0.strftime("%Y-%m-%d"))
|
1502
|
+
hend0=stock_return0.index[-1]; hend=str(hend0.strftime("%Y-%m-%d"))
|
1454
1503
|
|
1455
1504
|
#计算市场指数的收益率
|
1456
1505
|
import pandas as pd
|
@@ -1549,7 +1598,7 @@ if __name__=='__main__':
|
|
1549
1598
|
#==============================================================================
|
1550
1599
|
def RandomPortfolios_plot(RandomPortfolios,col_x,col_y,colorbartxt,title_ext, \
|
1551
1600
|
ylabeltxt,x_axis_name,pname,simulation,hstart,hend, \
|
1552
|
-
|
1601
|
+
hiret_point,lorisk_point,convex_hull=True):
|
1553
1602
|
"""
|
1554
1603
|
功能:将生成的马科维茨可行集RandomPortfolios绘制成彩色散点图
|
1555
1604
|
"""
|
@@ -1587,6 +1636,27 @@ def RandomPortfolios_plot(RandomPortfolios,col_x,col_y,colorbartxt,title_ext, \
|
|
1587
1636
|
plt.scatter(pf_volatilities, pf_returns, c=pf_ratio,cmap='RdYlGn', edgecolors='black',marker='o')
|
1588
1637
|
plt.colorbar(label=colorbartxt)
|
1589
1638
|
|
1639
|
+
#绘制散点图轮廓线凸包(convex hull)
|
1640
|
+
if convex_hull:
|
1641
|
+
from scipy.spatial import ConvexHull
|
1642
|
+
|
1643
|
+
#构造散点对的列表
|
1644
|
+
pf_volatilities_list=list(pf_volatilities)
|
1645
|
+
pf_returns_list=list(pf_returns)
|
1646
|
+
points=[]
|
1647
|
+
for x in pf_volatilities_list:
|
1648
|
+
pos=pf_volatilities_list.index(x)
|
1649
|
+
y=pf_returns_list[pos]
|
1650
|
+
points=points+[[x,y]]
|
1651
|
+
|
1652
|
+
# 计算散点集的外轮廓
|
1653
|
+
hull = ConvexHull(points)
|
1654
|
+
# 绘制外轮廓线
|
1655
|
+
for simplex in hull.simplices:
|
1656
|
+
plt.plot([points[simplex[0]][0], points[simplex[1]][0]],
|
1657
|
+
[points[simplex[0]][1], points[simplex[1]][1]], 'k-')
|
1658
|
+
|
1659
|
+
|
1590
1660
|
lang = check_language()
|
1591
1661
|
if lang == 'Chinese':
|
1592
1662
|
if pname == '': pname='投资组合'
|
@@ -1695,7 +1765,7 @@ def cvt_portfolio_name(pname,portfolio_returns):
|
|
1695
1765
|
|
1696
1766
|
#==============================================================================
|
1697
1767
|
|
1698
|
-
def portfolio_optimize_sharpe(es_info,graph=True):
|
1768
|
+
def portfolio_optimize_sharpe(es_info,graph=True,convex_hull=False):
|
1699
1769
|
"""
|
1700
1770
|
功能:计算投资组合的最高夏普比率组合,并绘图
|
1701
1771
|
MSR: Maximium Sharpe Rate, 最高夏普指数方案
|
@@ -1748,7 +1818,8 @@ def portfolio_optimize_sharpe(es_info,graph=True):
|
|
1748
1818
|
#计算指数,寻找最大指数点和风险最低点,并绘图标注两个点
|
1749
1819
|
hiret_weights,lorisk_weights,portfolio_returns = \
|
1750
1820
|
portfolio_optimize_rar(es_info,col_ratio,col_y,col_x,name_hiret,name_lorisk, \
|
1751
|
-
colorbartxt,title_ext,ylabeltxt,x_axis_name,graph=graph
|
1821
|
+
colorbartxt,title_ext,ylabeltxt,x_axis_name,graph=graph, \
|
1822
|
+
convex_hull=convex_hull)
|
1752
1823
|
|
1753
1824
|
print("【注释】")
|
1754
1825
|
print("★MSR : Maximized Sharpe Ratio,最大夏普比率点")
|
@@ -1771,7 +1842,7 @@ if __name__=='__main__':
|
|
1771
1842
|
|
1772
1843
|
#==============================================================================
|
1773
1844
|
|
1774
|
-
def portfolio_optimize_sortino(es_info,graph=True):
|
1845
|
+
def portfolio_optimize_sortino(es_info,graph=True,convex_hull=False):
|
1775
1846
|
"""
|
1776
1847
|
功能:计算投资组合的最高索替诺比率组合,并绘图
|
1777
1848
|
MSO: Maximium Sortino ratio, 最高索替诺比率方案
|
@@ -1796,7 +1867,8 @@ def portfolio_optimize_sortino(es_info,graph=True):
|
|
1796
1867
|
#计算指数,寻找最大指数点和风险最低点,并绘图标注两个点
|
1797
1868
|
hiret_weights,lorisk_weights,portfolio_returns = \
|
1798
1869
|
portfolio_optimize_rar(es_info,col_ratio,col_y,col_x,name_hiret,name_lorisk, \
|
1799
|
-
colorbartxt,title_ext,ylabeltxt,x_axis_name,graph=graph
|
1870
|
+
colorbartxt,title_ext,ylabeltxt,x_axis_name,graph=graph, \
|
1871
|
+
convex_hull=convex_hull)
|
1800
1872
|
|
1801
1873
|
print("【注释】")
|
1802
1874
|
print("★MSO : Maximum SOrtino ratio,最大索替诺比率点")
|
@@ -1819,7 +1891,7 @@ if __name__=='__main__':
|
|
1819
1891
|
|
1820
1892
|
#==============================================================================
|
1821
1893
|
|
1822
|
-
def portfolio_optimize_alpha(es_info,graph=True):
|
1894
|
+
def portfolio_optimize_alpha(es_info,graph=True,convex_hull=False):
|
1823
1895
|
"""
|
1824
1896
|
功能:计算投资组合的最高詹森阿尔法组合,并绘图
|
1825
1897
|
MAR: Maximium Alpha Ratio, 最高阿尔法指数方案
|
@@ -1843,7 +1915,8 @@ def portfolio_optimize_alpha(es_info,graph=True):
|
|
1843
1915
|
#计算指数,寻找最大指数点和风险最低点,并绘图标注两个点
|
1844
1916
|
hiret_weights,lorisk_weights,portfolio_returns = \
|
1845
1917
|
portfolio_optimize_rar(es_info,col_ratio,col_y,col_x,name_hiret,name_lorisk, \
|
1846
|
-
colorbartxt,title_ext,ylabeltxt,x_axis_name,graph=graph
|
1918
|
+
colorbartxt,title_ext,ylabeltxt,x_axis_name,graph=graph, \
|
1919
|
+
convex_hull=convex_hull)
|
1847
1920
|
|
1848
1921
|
print("【注释】")
|
1849
1922
|
print("★MAR : Maximum Alpha Ratio,最大阿尔法点")
|
@@ -1865,7 +1938,7 @@ if __name__=='__main__':
|
|
1865
1938
|
|
1866
1939
|
#==============================================================================
|
1867
1940
|
|
1868
|
-
def portfolio_optimize_treynor(es_info,graph=True):
|
1941
|
+
def portfolio_optimize_treynor(es_info,graph=True,convex_hull=False):
|
1869
1942
|
"""
|
1870
1943
|
功能:计算投资组合的最高特雷诺比率组合,并绘图
|
1871
1944
|
MTR: Maximium Treynor Ratio, 最高特雷诺指数方案
|
@@ -1889,7 +1962,8 @@ def portfolio_optimize_treynor(es_info,graph=True):
|
|
1889
1962
|
#计算指数,寻找最大指数点和风险最低点,并绘图标注两个点
|
1890
1963
|
hiret_weights,lorisk_weights,portfolio_returns = \
|
1891
1964
|
portfolio_optimize_rar(es_info,col_ratio,col_y,col_x,name_hiret,name_lorisk, \
|
1892
|
-
colorbartxt,title_ext,ylabeltxt,x_axis_name,graph=graph
|
1965
|
+
colorbartxt,title_ext,ylabeltxt,x_axis_name,graph=graph, \
|
1966
|
+
convex_hull=convex_hull)
|
1893
1967
|
|
1894
1968
|
print("【注释】")
|
1895
1969
|
print("★MTR : Maximum Treynor Ratio,最大特雷诺比率点")
|
@@ -1901,7 +1975,8 @@ def portfolio_optimize_treynor(es_info,graph=True):
|
|
1901
1975
|
|
1902
1976
|
|
1903
1977
|
def portfolio_optimize_rar(es_info,col_ratio,col_y,col_x,name_hiret,name_lorisk, \
|
1904
|
-
colorbartxt,title_ext,ylabeltxt,x_axis_name,graph=True
|
1978
|
+
colorbartxt,title_ext,ylabeltxt,x_axis_name,graph=True, \
|
1979
|
+
convex_hull=False):
|
1905
1980
|
"""
|
1906
1981
|
功能:提供rar比率优化的共同处理部分
|
1907
1982
|
基于RandomPortfolios中的随机投资组合,计算相应的指数,寻找最大指数点和风险最小点,并绘图标注两个点
|
@@ -1925,8 +2000,8 @@ def portfolio_optimize_rar(es_info,col_ratio,col_y,col_x,name_hiret,name_lorisk,
|
|
1925
2000
|
pname=portfolio_name(portfolio)
|
1926
2001
|
|
1927
2002
|
#取出观察期
|
1928
|
-
hstart0=StockReturns.index[0]; hstart=str(hstart0)
|
1929
|
-
hend0=StockReturns.index[-1]; hend=str(hend0)
|
2003
|
+
hstart0=StockReturns.index[0]; hstart=str(hstart0.strftime("%Y-%m-%d"))
|
2004
|
+
hend0=StockReturns.index[-1]; hend=str(hend0.strftime("%Y-%m-%d"))
|
1930
2005
|
|
1931
2006
|
#识别并计算指数..........................................................
|
1932
2007
|
if col_ratio in ['Alpha']:
|
@@ -1975,8 +2050,8 @@ def portfolio_optimize_rar(es_info,col_ratio,col_y,col_x,name_hiret,name_lorisk,
|
|
1975
2050
|
lorisk_point=[lorisk_x,lorisk_y,name_lorisk+point_txt]
|
1976
2051
|
if graph:
|
1977
2052
|
RandomPortfolios_plot(RandomPortfolios,col_x,col_y,colorbartxt,title_ext, \
|
1978
|
-
|
1979
|
-
hiret_point,lorisk_point)
|
2053
|
+
ylabeltxt,x_axis_name,pname,simulation,hstart,hend, \
|
2054
|
+
hiret_point,lorisk_point,convex_hull=convex_hull)
|
1980
2055
|
|
1981
2056
|
#返回数据,供进一步分析
|
1982
2057
|
portfolio_returns=StockReturns.copy()
|
@@ -2011,7 +2086,7 @@ if __name__=='__main__':
|
|
2011
2086
|
graph=True;hirar_return=False;lorisk=True
|
2012
2087
|
|
2013
2088
|
def portfolio_optimize(pf_info,ratio='sharpe',simulation=10000,RF=0, \
|
2014
|
-
graph=True,hirar_return=False,lorisk=True):
|
2089
|
+
graph=True,hirar_return=False,lorisk=True,convex_hull=False):
|
2015
2090
|
"""
|
2016
2091
|
功能:集成式投资组合优化策略
|
2017
2092
|
注意:实验发现RF较小时对于结果的影响极其微小难以观察,默认设为不使用无风险利率调整收益
|
@@ -2041,7 +2116,7 @@ def portfolio_optimize(pf_info,ratio='sharpe',simulation=10000,RF=0, \
|
|
2041
2116
|
eval(func_optimize)(es_info=es_info,RF=RF,graph=graph)
|
2042
2117
|
"""
|
2043
2118
|
name_hiret,hiret_weights,name_lorisk,lorisk_weights,portfolio_returns= \
|
2044
|
-
eval(func_optimize)(es_info=es_info,graph=graph)
|
2119
|
+
eval(func_optimize)(es_info=es_info,graph=graph,convex_hull=convex_hull)
|
2045
2120
|
|
2046
2121
|
|
2047
2122
|
lang = check_language()
|
siat/sector_china.py
CHANGED
@@ -3057,9 +3057,12 @@ if __name__=='__main__':
|
|
3057
3057
|
|
3058
3058
|
find_industry_sw(ticker)
|
3059
3059
|
|
3060
|
-
def find_industry_sw(ticker,level='1',ticker_order=True):
|
3060
|
+
def find_industry_sw(ticker,level='1',ticker_order=True,max_sleep=8):
|
3061
3061
|
"""
|
3062
|
-
|
3062
|
+
功能:寻找一只或一组股票所属的申万行业,支持股票代码和股票名称。
|
3063
|
+
level='1':默认只查找申万1级行业,以便节省时间
|
3064
|
+
ticker_order=True:默认输出结果按照ticker中的顺序,而非按照所属行业排序
|
3065
|
+
max_sleep=8:为防止反爬虫,默认每次爬虫后睡眠最多几秒钟
|
3063
3066
|
"""
|
3064
3067
|
print(" Searching shenwan industries for securities ... ...")
|
3065
3068
|
|
@@ -3140,7 +3143,7 @@ def find_industry_sw(ticker,level='1',ticker_order=True):
|
|
3140
3143
|
if len(result) == len(tickerlist): break
|
3141
3144
|
|
3142
3145
|
#生成随机数睡眠,试图防止被反爬虫,不知是否管用!
|
3143
|
-
random_int=random.randint(1,
|
3146
|
+
random_int=random.randint(1,max_sleep)
|
3144
3147
|
time.sleep(random_int)
|
3145
3148
|
|
3146
3149
|
#排序
|
siat/security_price2.py
CHANGED
@@ -43,6 +43,10 @@ if __name__=='__main__':
|
|
43
43
|
ticker_type='auto'
|
44
44
|
ticker_type='bond'
|
45
45
|
|
46
|
+
ticker='000418'
|
47
|
+
ticker='180202.SZ'
|
48
|
+
ticker_type='fund'
|
49
|
+
|
46
50
|
source='auto'
|
47
51
|
source='yahoo'
|
48
52
|
|
@@ -50,15 +54,15 @@ if __name__=='__main__':
|
|
50
54
|
fill=True
|
51
55
|
|
52
56
|
price,found=get_price_1ticker(ticker=ticker,fromdate=fromdate,todate=todate, \
|
53
|
-
ticker_type=ticker_type
|
54
|
-
adjust=adjust,fill=fill)
|
57
|
+
ticker_type=ticker_type)
|
55
58
|
|
56
59
|
def get_price_1ticker(ticker,fromdate,todate, \
|
57
60
|
ticker_type='auto',source='auto', \
|
58
61
|
adjust='',fill=False):
|
59
62
|
"""
|
60
63
|
功能:抓取一只证券的价格序列,不处理列表,不处理投资组合
|
61
|
-
|
64
|
+
类型优先顺序:ticker_type,auto-自动,stock-指定股票,fund-指定基金,bond-指定债券
|
65
|
+
数据源优先顺序:1-source,2-ticker属地,3-ticker_type
|
62
66
|
adjust:""-未复权,qfq-前复权,hfq-后复权,qfq-factor:前复权因子和调整,hfq-factor: 后复权因子和调整
|
63
67
|
返回值:
|
64
68
|
df: None-未找到ticker,空df-找到ticker但规定时间段内无数据
|
@@ -112,7 +116,30 @@ def get_price_1ticker(ticker,fromdate,todate, \
|
|
112
116
|
adjust='qfq' if adjust != '' else ''
|
113
117
|
dft=get_price_ak_us(ticker1,fromdate,todate,adjust=adjust)
|
114
118
|
found=df_have_data(dft)
|
115
|
-
|
119
|
+
"""
|
120
|
+
if ticker_type in ['fund']:
|
121
|
+
#变换代码格式
|
122
|
+
ticker2=tickers_cvt2ak(ticker1)
|
123
|
+
try:
|
124
|
+
#优先抓取开放式基金单位净值
|
125
|
+
dft =get_price_oef_china(ticker2,fromdate,todate)
|
126
|
+
dft['Date']=dft.index
|
127
|
+
except:
|
128
|
+
dft=None
|
129
|
+
found=df_have_data(dft)
|
130
|
+
|
131
|
+
if ticker_type in ['bond']:
|
132
|
+
#变换代码格式
|
133
|
+
ticker2=tickers_cvt2ak(ticker1)
|
134
|
+
try:
|
135
|
+
#最后抓取交易所债券行情
|
136
|
+
dft = exchange_bond_price(ticker2,fromdate,todate,graph=False,data_crop=False)
|
137
|
+
dft['Date']=dft.index
|
138
|
+
except:
|
139
|
+
#print(" #Error(get_price_ak_cn): failed to find prices for",ticker)
|
140
|
+
return None
|
141
|
+
found=df_have_data(dft)
|
142
|
+
"""
|
116
143
|
#数据源情形2:stooq
|
117
144
|
if source in ['auto','stooq'] and found not in ['Found','Empty']:
|
118
145
|
dft=get_price_stooq(ticker1,fromdate,todate)
|
@@ -193,8 +220,10 @@ if __name__=='__main__':
|
|
193
220
|
ticker=['801002.SW',"600519.SS","sh510050","sh010504"] #申万指数,股票,ETF基金,国债
|
194
221
|
ticker_type='bond'
|
195
222
|
|
223
|
+
ticker=["180801.SZ","180101.SZ"]
|
196
224
|
fromdate="2024-3-1"
|
197
225
|
todate="2024-4-1"
|
226
|
+
ticker_type='fund'
|
198
227
|
|
199
228
|
adjust=''
|
200
229
|
adjust=['','qfq']
|
@@ -460,14 +489,16 @@ if __name__=='__main__':
|
|
460
489
|
ticker=[pf,'000002.SZ','002594.SZ','sh018003','sh010504']
|
461
490
|
ticker_type=[['auto','stock'],'auto','auto','bond'] #不足部分自动延续最后一个类型
|
462
491
|
|
492
|
+
ticker=["180801.SZ","180101.SZ"]
|
493
|
+
ticker_type='fund'
|
494
|
+
|
463
495
|
fromdate='2024-1-1'
|
464
496
|
todate='2024-4-1'
|
465
497
|
adjust=''
|
466
498
|
source='auto'
|
467
499
|
fill=True
|
468
500
|
|
469
|
-
mix,found=get_price_mticker_mixed(ticker=ticker,fromdate=fromdate,todate=todate,
|
470
|
-
adjust=adjust,source=source,ticker_type=ticker_type,fill=fill)
|
501
|
+
mix,found=get_price_mticker_mixed(ticker=ticker,fromdate=fromdate,todate=todate,ticker_type=ticker_type)
|
471
502
|
|
472
503
|
def get_price_mticker_mixed(ticker,fromdate,todate, \
|
473
504
|
adjust='',source='auto',ticker_type='auto',fill=False):
|
@@ -565,14 +596,17 @@ if __name__=='__main__':
|
|
565
596
|
ticker='sh018003'
|
566
597
|
ticker_type='bond'
|
567
598
|
|
568
|
-
|
569
|
-
|
599
|
+
ticker='180202.SZ'
|
600
|
+
ticker_type='fund'
|
601
|
+
|
602
|
+
fromdate='2021-1-1'
|
603
|
+
todate='2024-5-30'
|
570
604
|
adjust=''
|
571
605
|
source='auto'
|
572
606
|
fill=True
|
573
607
|
|
574
608
|
mixed,found=get_price_1ticker_mixed(ticker=ticker,fromdate=fromdate,todate=todate, \
|
575
|
-
|
609
|
+
ticker_type=ticker_type)
|
576
610
|
|
577
611
|
def get_price_1ticker_mixed(ticker,fromdate,todate, \
|
578
612
|
adjust='',source='auto',ticker_type='auto',fill=False):
|
siat/security_prices.py
CHANGED
@@ -716,6 +716,10 @@ if __name__=='__main__':
|
|
716
716
|
ticker='100303.SZ'
|
717
717
|
ticker_type='auto'
|
718
718
|
|
719
|
+
ticker='000418'
|
720
|
+
ticker='180202.SZ'
|
721
|
+
ticker_type='fund'
|
722
|
+
|
719
723
|
fromdate='2024-1-1'; todate='2024-3-31'
|
720
724
|
adjust=''
|
721
725
|
|
@@ -768,14 +772,15 @@ def get_price_ak_cn(ticker,fromdate,todate,adjust='',ticker_type='auto'):
|
|
768
772
|
df=None
|
769
773
|
found=df_have_data(df)
|
770
774
|
|
771
|
-
|
775
|
+
#股票(无复权)指数/基金/债券
|
772
776
|
if found != 'Found':
|
773
777
|
if ticker_type in ['auto','stock'] and suffix not in ['SW']:
|
774
778
|
try:
|
775
779
|
#指数/股票/基金
|
776
780
|
df = ak.stock_zh_index_daily(symbol=ticker2)
|
777
781
|
df['Date']=df['date'].apply(lambda x: pd.to_datetime(x))
|
778
|
-
except:
|
782
|
+
except:
|
783
|
+
df=None
|
779
784
|
found=df_have_data(df)
|
780
785
|
|
781
786
|
if found != 'Found':
|
@@ -783,7 +788,8 @@ def get_price_ak_cn(ticker,fromdate,todate,adjust='',ticker_type='auto'):
|
|
783
788
|
#特殊函数(不考虑复权)
|
784
789
|
df=ak.stock_zh_a_cdr_daily(ticker2,start1,end1)
|
785
790
|
df['Date']=pd.to_datetime(df['date'])
|
786
|
-
except:
|
791
|
+
except:
|
792
|
+
df=None
|
787
793
|
found=df_have_data(df)
|
788
794
|
|
789
795
|
if found != 'Found':
|
@@ -806,7 +812,8 @@ def get_price_ak_cn(ticker,fromdate,todate,adjust='',ticker_type='auto'):
|
|
806
812
|
#优先抓取交易所债券行情
|
807
813
|
df = exchange_bond_price(ticker2,fromdate,todate,graph=False,data_crop=False)
|
808
814
|
df['Date']=df.index
|
809
|
-
except:
|
815
|
+
except:
|
816
|
+
df=None
|
810
817
|
found=df_have_data(df)
|
811
818
|
|
812
819
|
#已找到证券信息,但在规定时段无数据
|
@@ -818,7 +825,8 @@ def get_price_ak_cn(ticker,fromdate,todate,adjust='',ticker_type='auto'):
|
|
818
825
|
df=ak.stock_zh_a_daily(ticker2,start1,end1,adjust=adjust)
|
819
826
|
df['Date']=df['date']
|
820
827
|
df['Date']=df['Date'].dt.tz_localize(None)
|
821
|
-
except:
|
828
|
+
except:
|
829
|
+
df=None
|
822
830
|
found=df_have_data(df)
|
823
831
|
|
824
832
|
if found != 'Found':
|
@@ -826,7 +834,8 @@ def get_price_ak_cn(ticker,fromdate,todate,adjust='',ticker_type='auto'):
|
|
826
834
|
#接着查找指数
|
827
835
|
df = ak.stock_zh_index_daily(symbol=ticker2)
|
828
836
|
df['Date']=df['date'].apply(lambda x: pd.to_datetime(x))
|
829
|
-
except:
|
837
|
+
except:
|
838
|
+
df=None
|
830
839
|
found=df_have_data(df)
|
831
840
|
|
832
841
|
if found != 'Found':
|
@@ -834,7 +843,8 @@ def get_price_ak_cn(ticker,fromdate,todate,adjust='',ticker_type='auto'):
|
|
834
843
|
#最后查找开放式基金
|
835
844
|
df =get_price_oef_china(ticker2,fromdate,todate)
|
836
845
|
df['Date']=df.index
|
837
|
-
except:
|
846
|
+
except:
|
847
|
+
df=None
|
838
848
|
found=df_have_data(df)
|
839
849
|
|
840
850
|
#基金。因部分债券代码(特别是国债)与基金代码重合,需要甄别!
|
@@ -843,18 +853,20 @@ def get_price_ak_cn(ticker,fromdate,todate,adjust='',ticker_type='auto'):
|
|
843
853
|
#优先抓取开放式基金单位净值
|
844
854
|
df =get_price_oef_china(ticker2,fromdate,todate)
|
845
855
|
df['Date']=df.index
|
846
|
-
except:
|
856
|
+
except:
|
857
|
+
df=None
|
847
858
|
found=df_have_data(df)
|
848
859
|
|
849
860
|
#已找到证券信息,但在规定时段无数据
|
850
|
-
if found=='Empty': return df
|
861
|
+
#if found=='Empty': return df
|
851
862
|
|
852
|
-
if found != 'Found':
|
863
|
+
if found != 'Found': #未找到,其次从股票爬虫抓取基金行情
|
853
864
|
try:
|
854
865
|
df=ak.stock_zh_a_daily(ticker2,start1,end1,adjust=adjust)
|
855
866
|
df['Date']=df['date']
|
856
867
|
df['Date']=df['Date'].dt.tz_localize(None)
|
857
|
-
except:
|
868
|
+
except:
|
869
|
+
df=None
|
858
870
|
found=df_have_data(df)
|
859
871
|
|
860
872
|
if found != 'Found':
|
@@ -862,23 +874,26 @@ def get_price_ak_cn(ticker,fromdate,todate,adjust='',ticker_type='auto'):
|
|
862
874
|
#再次查找股票指数
|
863
875
|
df = ak.stock_zh_index_daily(symbol=ticker2)
|
864
876
|
df['Date']=df['date'].apply(lambda x: pd.to_datetime(x))
|
865
|
-
except:
|
877
|
+
except:
|
878
|
+
df=None
|
866
879
|
found=df_have_data(df)
|
867
880
|
|
868
881
|
if found != 'Found':
|
869
882
|
try:
|
870
|
-
|
883
|
+
#最后从债券爬虫查找基金信息
|
871
884
|
df = exchange_bond_price(ticker2,fromdate,todate,graph=False,data_crop=False)
|
872
885
|
df['Date']=df.index
|
873
|
-
except:
|
886
|
+
except:
|
887
|
+
df=None
|
874
888
|
found=df_have_data(df)
|
875
889
|
|
876
|
-
|
890
|
+
#申万指数
|
877
891
|
if suffix in ['SW']:
|
878
892
|
try:
|
879
893
|
df = fetch_price_swindex(prefix,fromdate,todate)
|
880
894
|
df['Date']=df.index
|
881
|
-
except:
|
895
|
+
except:
|
896
|
+
df=None
|
882
897
|
#print(" #Error(get_price_ak_cn): failed to retrieve prices for",ticker)
|
883
898
|
found=df_have_data(df)
|
884
899
|
|