siat 3.1.11__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 +127 -38
- siat/markowitz2.py +122 -47
- siat/sector_china.py +100 -33
- 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/stock_technical.py +2 -2
- siat/translate.py +18 -14
- siat/translate_20240606.py +4206 -0
- {siat-3.1.11.dist-info → siat-3.1.13.dist-info}/METADATA +1 -1
- {siat-3.1.11.dist-info → siat-3.1.13.dist-info}/RECORD +18 -17
- {siat-3.1.11.dist-info → siat-3.1.13.dist-info}/WHEEL +0 -0
- {siat-3.1.11.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
@@ -3033,49 +3033,49 @@ def industry_scan_china(sw_level='F', \
|
|
3033
3033
|
|
3034
3034
|
return df2
|
3035
3035
|
|
3036
|
+
|
3036
3037
|
#==============================================================================
|
3037
3038
|
if __name__=='__main__':
|
3038
3039
|
ticker='600791.SS'
|
3039
|
-
|
3040
|
-
|
3041
|
-
|
3040
|
+
ticker='东阿阿胶'
|
3041
|
+
|
3042
|
+
contains_chinese(ticker)
|
3043
|
+
|
3044
|
+
def contains_chinese(text):
|
3042
3045
|
"""
|
3043
|
-
|
3046
|
+
功能:判断字符串是否含有汉字
|
3044
3047
|
"""
|
3045
|
-
|
3046
|
-
|
3047
|
-
import akshare as ak
|
3048
|
-
#df3 = ak.sw_index_third_info()
|
3049
|
-
df2 = ak.sw_index_second_info()
|
3050
|
-
df2['industry_code']=df2['行业代码'].apply(lambda x: x[:6])
|
3051
|
-
industry_list=list(df2['industry_code'])
|
3052
|
-
|
3053
|
-
for i in industry_list:
|
3054
|
-
cdf = ak.index_component_sw(i)
|
3055
|
-
component_list=list(cdf)
|
3056
|
-
|
3057
|
-
if ticker6 in component_list:
|
3058
|
-
stock_name=cdf[cdf["证券代码"]==ticker6]['证券名称'].values[0]
|
3059
|
-
print("股票:",ticker,",",stock_name)
|
3060
|
-
|
3061
|
-
isi=i+'.SI'
|
3062
|
-
industry_name=df3[df3[行业代码]==isi]['行业名称'].values[0]
|
3063
|
-
print("申万三级行业代码:",i+".SW",",",industry_name)
|
3064
|
-
|
3065
|
-
break
|
3066
|
-
|
3067
|
-
return
|
3048
|
+
import re
|
3049
|
+
return re.search(r'[\u4e00-\u9fff]', text) is not None
|
3068
3050
|
|
3069
3051
|
#==============================================================================
|
3070
3052
|
if __name__=='__main__':
|
3071
3053
|
ticker='600791.SS'
|
3054
|
+
|
3055
|
+
ticker=['600791.SS','东阿阿胶']
|
3056
|
+
level='1'
|
3057
|
+
|
3072
3058
|
find_industry_sw(ticker)
|
3073
3059
|
|
3074
|
-
def find_industry_sw(ticker,level='
|
3060
|
+
def find_industry_sw(ticker,level='1',ticker_order=True,max_sleep=8):
|
3075
3061
|
"""
|
3076
|
-
|
3062
|
+
功能:寻找一只或一组股票所属的申万行业,支持股票代码和股票名称。
|
3063
|
+
level='1':默认只查找申万1级行业,以便节省时间
|
3064
|
+
ticker_order=True:默认输出结果按照ticker中的顺序,而非按照所属行业排序
|
3065
|
+
max_sleep=8:为防止反爬虫,默认每次爬虫后睡眠最多几秒钟
|
3077
3066
|
"""
|
3078
|
-
|
3067
|
+
print(" Searching shenwan industries for securities ... ...")
|
3068
|
+
|
3069
|
+
if isinstance(ticker,str):
|
3070
|
+
ticker=[ticker]
|
3071
|
+
|
3072
|
+
tickerlist=[]
|
3073
|
+
for t in ticker:
|
3074
|
+
if not contains_chinese(t):
|
3075
|
+
tt=t[:6]
|
3076
|
+
tickerlist=tickerlist+[tt]
|
3077
|
+
else:
|
3078
|
+
tickerlist=tickerlist+[t]
|
3079
3079
|
|
3080
3080
|
import akshare as ak
|
3081
3081
|
if level == '3':
|
@@ -3088,8 +3088,13 @@ def find_industry_sw(ticker,level='2'):
|
|
3088
3088
|
df['industry_code']=df['行业代码'].apply(lambda x: x[:6])
|
3089
3089
|
industry_list=list(df['industry_code'])
|
3090
3090
|
|
3091
|
+
import pandas as pd; import random; import time
|
3092
|
+
result=pd.DataFrame(columns=['序号','证券名称','证券代码','行业名称','行业代码'])
|
3093
|
+
|
3091
3094
|
for i in industry_list:
|
3092
|
-
print_progress_percent2(i,industry_list,steps=10,leading_blanks=
|
3095
|
+
print_progress_percent2(i,industry_list,steps=10,leading_blanks=2)
|
3096
|
+
|
3097
|
+
iname=df[df['industry_code']==i]['行业名称'].values[0]
|
3093
3098
|
|
3094
3099
|
try:
|
3095
3100
|
cdf = ak.index_component_sw(i)
|
@@ -3097,7 +3102,7 @@ def find_industry_sw(ticker,level='2'):
|
|
3097
3102
|
print(" #Warning(find_industry_sw): server banned this ip becos of too many requests")
|
3098
3103
|
print(" Solution: change to another ip or another computer, or try a few hours later.")
|
3099
3104
|
return
|
3100
|
-
|
3105
|
+
"""
|
3101
3106
|
component_list=list(cdf['证券代码'])
|
3102
3107
|
|
3103
3108
|
if ticker6 in component_list:
|
@@ -3109,8 +3114,70 @@ def find_industry_sw(ticker,level='2'):
|
|
3109
3114
|
print("申万"+str(level)+"级行业代码:"+i+".SW,"+industry_name)
|
3110
3115
|
|
3111
3116
|
break
|
3117
|
+
"""
|
3118
|
+
for t in tickerlist:
|
3119
|
+
torder=tickerlist.index(t)+1
|
3120
|
+
|
3121
|
+
if not contains_chinese(t):
|
3122
|
+
dft=cdf[cdf['证券代码']==t]
|
3123
|
+
if len(dft)==0: continue
|
3124
|
+
else:
|
3125
|
+
tname=cdf[cdf['证券代码']==t]['证券名称'].values[0]
|
3126
|
+
s=pd.Series({'序号':torder,'证券名称':tname,'证券代码':t,'行业名称':iname,'行业代码':i})
|
3127
|
+
try:
|
3128
|
+
result=result.append(s,ignore_index=True)
|
3129
|
+
except:
|
3130
|
+
result=result._append(s,ignore_index=True)
|
3131
|
+
else:
|
3132
|
+
dft=cdf[cdf['证券名称']==t]
|
3133
|
+
if len(dft)==0: continue
|
3134
|
+
else:
|
3135
|
+
tcode=cdf[cdf['证券名称']==t]['证券代码'].values[0]
|
3136
|
+
s=pd.Series({'序号':torder,'证券名称':t,'证券代码':tcode,'行业名称':iname,'行业代码':i})
|
3137
|
+
try:
|
3138
|
+
result=result.append(s,ignore_index=True)
|
3139
|
+
except:
|
3140
|
+
result=result._append(s,ignore_index=True)
|
3141
|
+
|
3142
|
+
#是否都找到了?
|
3143
|
+
if len(result) == len(tickerlist): break
|
3112
3144
|
|
3113
|
-
|
3145
|
+
#生成随机数睡眠,试图防止被反爬虫,不知是否管用!
|
3146
|
+
random_int=random.randint(1,max_sleep)
|
3147
|
+
time.sleep(random_int)
|
3148
|
+
|
3149
|
+
#排序
|
3150
|
+
if not ticker_order:
|
3151
|
+
#按行业代码排序
|
3152
|
+
result.sort_values(by='行业代码',inplace=True)
|
3153
|
+
else:
|
3154
|
+
#按ticker顺序排序
|
3155
|
+
result.sort_values(by='序号',inplace=True)
|
3156
|
+
"""
|
3157
|
+
if contains_chinese(tickerlist[0]):
|
3158
|
+
result.sort_values(by='证券名称',key=lambda x: x.map(dict(zip(tickerlist,range(len(tickerlist))))))
|
3159
|
+
else:
|
3160
|
+
result.sort_values(by='证券代码',key=lambda x: x.map(dict(zip(tickerlist,range(len(tickerlist))))))
|
3161
|
+
"""
|
3162
|
+
#result.reset_index(drop=True,inplace=True)
|
3163
|
+
|
3164
|
+
#显示结果
|
3165
|
+
titletxt="证券所属行业:申万"+str(level)+"级行业"
|
3166
|
+
import datetime; todaydt = datetime.date.today()
|
3167
|
+
footnote="数据来源:申万宏源,"+str(todaydt)+"统计"
|
3168
|
+
"""
|
3169
|
+
collist=list(result)
|
3170
|
+
result['序号']=result.index+1
|
3171
|
+
result=result[['序号']+collist]
|
3172
|
+
"""
|
3173
|
+
print('')
|
3174
|
+
df_display_CSS(result,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=2, \
|
3175
|
+
first_col_align='center',second_col_align='left', \
|
3176
|
+
last_col_align='left',other_col_align='left', \
|
3177
|
+
titile_font_size='16px',heading_font_size='15px', \
|
3178
|
+
data_font_size='15px')
|
3179
|
+
|
3180
|
+
return result
|
3114
3181
|
|
3115
3182
|
#==============================================================================
|
3116
3183
|
#==============================================================================
|
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):
|