siat 3.1.6__py3-none-any.whl → 3.1.12__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/fund_china.py +47 -20
- siat/markowitz2.py +158 -75
- siat/sector_china.py +124 -13
- siat/stock_technical.py +2 -2
- {siat-3.1.6.dist-info → siat-3.1.12.dist-info}/METADATA +1 -1
- {siat-3.1.6.dist-info → siat-3.1.12.dist-info}/RECORD +8 -8
- {siat-3.1.6.dist-info → siat-3.1.12.dist-info}/WHEEL +0 -0
- {siat-3.1.6.dist-info → siat-3.1.12.dist-info}/top_level.txt +0 -0
siat/fund_china.py
CHANGED
@@ -20,18 +20,23 @@ from siat.translate import *
|
|
20
20
|
from siat.grafix import *
|
21
21
|
from siat.bond_base import *
|
22
22
|
#==============================================================================
|
23
|
-
def compare_fund_holding_china(ticker,quarters,rank=10):
|
23
|
+
def compare_fund_holding_china(ticker,quarters,rank=10,font_size='14px'):
|
24
24
|
"""
|
25
25
|
功能:套壳函数fund_stock_holding_compare_china
|
26
26
|
"""
|
27
27
|
if len(quarters) < 2:
|
28
28
|
print(" #Warning(compare_fund_holding_china): need 2 quarters to compare at",quarters)
|
29
29
|
return None
|
30
|
+
"""
|
30
31
|
if quarters[0] >= quarters[1]:
|
31
32
|
print(" #Warning(compare_fund_holding_china):",quarters[0],"is supposed to be earlier than",quarters[1])
|
32
33
|
return None
|
33
|
-
|
34
|
-
|
34
|
+
"""
|
35
|
+
#保证较早的季度排在前面
|
36
|
+
quarters.sort()
|
37
|
+
|
38
|
+
df=fund_stock_holding_compare_china(fund=ticker,quarter1=quarters[0],quarter2=quarters[1], \
|
39
|
+
rank=rank,font_size=font_size)
|
35
40
|
|
36
41
|
return df
|
37
42
|
|
@@ -43,13 +48,18 @@ if __name__=='__main__':
|
|
43
48
|
df=fund_stock_holding_compare_china(fund,quarter1,quarter2,rank=10)
|
44
49
|
|
45
50
|
#比较两个季度之间的基金持仓变化
|
46
|
-
def fund_stock_holding_compare_china(fund,quarter1,quarter2,rank=10
|
51
|
+
def fund_stock_holding_compare_china(fund,quarter1,quarter2,rank=10, \
|
52
|
+
font_size='14px'):
|
47
53
|
"""
|
48
54
|
功能:基金fund在两个季度quarter1和quarter2的持仓股票对比(股数和金额),前rank名股票
|
49
55
|
参数:
|
50
56
|
fund,str,基金代码;
|
51
57
|
quarter1,str,靠前的季度, 格式为 'YYYYQ1',例如: '2021Q2';
|
52
58
|
quarter2,str,靠后的季度, 格式为 'YYYYQ1',例如: '2021Q2';
|
59
|
+
|
60
|
+
注意:监管仅要求基金披露前十大重仓股,因此其持仓比例之和一般小于100%;若大于100%,
|
61
|
+
则为基金以其净资产作为抵押加了杠杆融资,买进更多成份股,导致成份股总价值(基金总资产)超过了基金的净资产。
|
62
|
+
基金总资产 = 基金负债 + 基金净资产
|
53
63
|
"""
|
54
64
|
print("Searching fund holding info, which may take time, please wait ...\n")
|
55
65
|
|
@@ -112,6 +122,7 @@ def fund_stock_holding_compare_china(fund,quarter1,quarter2,rank=10):
|
|
112
122
|
|
113
123
|
df1 = df1[['股票代码', '股票名称','持股数','持仓市值','占净值比例']]
|
114
124
|
df1 = df1.rename(columns={'持股数':s1_share,'持仓市值':s1_value,'占净值比例':s1_ratio})
|
125
|
+
num1=len(df1)
|
115
126
|
|
116
127
|
df2 =data[data['季度']==s2]
|
117
128
|
if len(df2)==0:
|
@@ -120,6 +131,7 @@ def fund_stock_holding_compare_china(fund,quarter1,quarter2,rank=10):
|
|
120
131
|
|
121
132
|
df2 = df2[['股票代码', '股票名称','持股数','持仓市值','占净值比例']]
|
122
133
|
df2 = df2.rename(columns={'持股数':s2_share,'持仓市值':s2_value,'占净值比例':s2_ratio})
|
134
|
+
num2=len(df2)
|
123
135
|
|
124
136
|
df_merge = pd.merge(df1,df2,on=['股票代码','股票名称'],how='outer')
|
125
137
|
|
@@ -196,16 +208,17 @@ def fund_stock_holding_compare_china(fund,quarter1,quarter2,rank=10):
|
|
196
208
|
# 替换空值
|
197
209
|
df.fillna('---')
|
198
210
|
"""
|
199
|
-
print("===== 中国基金持仓股票分析:"+name+','+s1+"对比"+s2,"(按后者持仓比例高低排列,"+order+str(rank)+"
|
211
|
+
print("===== 中国基金持仓股票分析:"+name+','+s1+"对比"+s2,"(按后者持仓比例高低排列,"+order+str(rank)+"名重仓股) =====\n")
|
200
212
|
print(df.to_string(index=False))
|
201
213
|
import datetime; today = datetime.date.today()
|
202
214
|
print("\n*** 注:持股数为万股,持仓市值为万元,持仓比例为占基金资产净值比例%,包括A股与非A股")
|
203
215
|
print(" 数据来源:天天基金/东方财富, 期间持仓股票总计"+str(len(df_merge))+"只,",today)
|
204
216
|
"""
|
205
|
-
titletxt="
|
217
|
+
titletxt="基金持仓转移明细:"+name+'基金,'+s1+"对比"+s2+"(按后者持仓比例降序排列,"+order+str(rank)+"名重仓股)"
|
206
218
|
|
207
|
-
footnote1="
|
208
|
-
footnote2="
|
219
|
+
footnote1="【注】持仓数单位为万股,持仓市值单位为万元,持仓比例为成份股价值为占基金资产净值%(以最新期间为准列示)\n"
|
220
|
+
#footnote2=s1+'/'+s2+"期末持仓证券数"+str(num1)+'/'+str(num2)+"只"+'\n'
|
221
|
+
footnote2='监管仅要求披露前十大重仓股,其持仓比例之和一般小于100%;若大于100%则为基金加了杠杆,总资产多于净资产\n'
|
209
222
|
import datetime; todaydt = datetime.date.today()
|
210
223
|
footnote9="数据来源:天天基金/东方财富,"+str(todaydt)+"统计"
|
211
224
|
footnote=footnote1+footnote2+footnote9
|
@@ -227,21 +240,27 @@ def fund_stock_holding_compare_china(fund,quarter1,quarter2,rank=10):
|
|
227
240
|
df=df[collist1]
|
228
241
|
"""
|
229
242
|
df.replace(0,'---',inplace=True); df.replace('0','---',inplace=True)
|
243
|
+
|
244
|
+
#确定表格字体大小
|
245
|
+
titile_font_size=font_size
|
246
|
+
heading_font_size=data_font_size=str(int(font_size.replace('px',''))-2)+'px'
|
230
247
|
|
231
248
|
df_display_CSS(df,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=2, \
|
232
249
|
first_col_align='center',second_col_align='left', \
|
233
250
|
last_col_align='right',other_col_align='right', \
|
234
|
-
titile_font_size=
|
235
|
-
|
251
|
+
titile_font_size=titile_font_size, \
|
252
|
+
heading_font_size=heading_font_size, \
|
253
|
+
data_font_size=data_font_size)
|
236
254
|
|
237
255
|
return df_merge
|
238
256
|
|
239
257
|
#==============================================================================
|
240
|
-
def fund_holding_china(ticker,rank=10,pastyears=2):
|
258
|
+
def fund_holding_china(ticker,rank=10,pastyears=2,reverse=False,font_size='16px'):
|
241
259
|
"""
|
242
260
|
功能:套壳函数fund_stock_holding_rank_china
|
243
261
|
"""
|
244
|
-
df,data=fund_stock_holding_rank_china(fund=ticker,rank=rank,year_num=pastyears
|
262
|
+
df,data=fund_stock_holding_rank_china(fund=ticker,rank=rank,year_num=pastyears, \
|
263
|
+
reverse=reverse,font_size=font_size)
|
245
264
|
|
246
265
|
return df,data
|
247
266
|
|
@@ -253,8 +272,10 @@ if __name__=='__main__':
|
|
253
272
|
df=fund_stock_holding_rank_china(fund,year_num=2)
|
254
273
|
|
255
274
|
# 获取单只基金的十大股票名称信息
|
256
|
-
def fund_stock_holding_rank_china(fund,rank=10,year_num=2
|
275
|
+
def fund_stock_holding_rank_china(fund,rank=10,year_num=2, \
|
276
|
+
reverse=False,font_size='16px'):
|
257
277
|
"""
|
278
|
+
基金的成份股持仓转移矩阵
|
258
279
|
比较股票型基金fund近year_num年持仓的前10大股票排名变化
|
259
280
|
"""
|
260
281
|
print("Searching fund stock holding info, which takes time, please wait ...\n")
|
@@ -373,21 +394,27 @@ def fund_stock_holding_rank_china(fund,rank=10,year_num=2):
|
|
373
394
|
name=get_fund_name_china2(fund)
|
374
395
|
|
375
396
|
#print("=== 基金持仓股票排行分析:"+name+",按照占净值比例高低排列 ===\n")
|
376
|
-
titletxt="
|
397
|
+
titletxt="基金持仓转移矩阵:"+name+"基金,按照占净值比例降序排列,前"+str(rank)+"名重仓股"
|
377
398
|
import datetime; todaydt = datetime.date.today()
|
378
399
|
#print("\n*** 注:包括A股与非A股。持股结构:股票简称(占净值比例%,持股数万股),",str(todaydt))
|
379
400
|
footnote="【注】持仓结构:证券简称(占净值比例%,持仓数万股),"+str(todaydt)+"统计"
|
380
401
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
402
|
+
if reverse:
|
403
|
+
#最新的日期放前面
|
404
|
+
collist=list(df)
|
405
|
+
collist.sort(reverse=True)
|
406
|
+
df=df[collist]
|
407
|
+
|
408
|
+
#确定表格字体大小
|
409
|
+
titile_font_size=font_size
|
410
|
+
heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
|
385
411
|
|
386
412
|
df_display_CSS(df,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=3, \
|
387
413
|
first_col_align='center',second_col_align='left', \
|
388
414
|
last_col_align='left',other_col_align='left', \
|
389
|
-
titile_font_size=
|
390
|
-
|
415
|
+
titile_font_size=titile_font_size, \
|
416
|
+
heading_font_size=heading_font_size, \
|
417
|
+
data_font_size=data_font_size)
|
391
418
|
|
392
419
|
"""
|
393
420
|
alignlist=['center']+['left']*(len(list(df))-1)
|
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
@@ -3033,38 +3033,149 @@ def industry_scan_china(sw_level='F', \
|
|
3033
3033
|
|
3034
3034
|
return df2
|
3035
3035
|
|
3036
|
+
|
3037
|
+
#==============================================================================
|
3038
|
+
if __name__=='__main__':
|
3039
|
+
ticker='600791.SS'
|
3040
|
+
ticker='东阿阿胶'
|
3041
|
+
|
3042
|
+
contains_chinese(ticker)
|
3043
|
+
|
3044
|
+
def contains_chinese(text):
|
3045
|
+
"""
|
3046
|
+
功能:判断字符串是否含有汉字
|
3047
|
+
"""
|
3048
|
+
import re
|
3049
|
+
return re.search(r'[\u4e00-\u9fff]', text) is not None
|
3050
|
+
|
3036
3051
|
#==============================================================================
|
3037
3052
|
if __name__=='__main__':
|
3038
3053
|
ticker='600791.SS'
|
3054
|
+
|
3055
|
+
ticker=['600791.SS','东阿阿胶']
|
3056
|
+
level='1'
|
3057
|
+
|
3039
3058
|
find_industry_sw(ticker)
|
3040
3059
|
|
3041
|
-
def find_industry_sw(ticker):
|
3060
|
+
def find_industry_sw(ticker,level='1',ticker_order=True):
|
3042
3061
|
"""
|
3043
|
-
|
3062
|
+
功能:寻找一只股票所属的申万行业
|
3044
3063
|
"""
|
3045
|
-
|
3064
|
+
print(" Searching shenwan industries for securities ... ...")
|
3065
|
+
|
3066
|
+
if isinstance(ticker,str):
|
3067
|
+
ticker=[ticker]
|
3068
|
+
|
3069
|
+
tickerlist=[]
|
3070
|
+
for t in ticker:
|
3071
|
+
if not contains_chinese(t):
|
3072
|
+
tt=t[:6]
|
3073
|
+
tickerlist=tickerlist+[tt]
|
3074
|
+
else:
|
3075
|
+
tickerlist=tickerlist+[t]
|
3046
3076
|
|
3047
3077
|
import akshare as ak
|
3048
|
-
|
3049
|
-
|
3050
|
-
|
3051
|
-
|
3078
|
+
if level == '3':
|
3079
|
+
df = ak.sw_index_third_info()
|
3080
|
+
elif level == '2':
|
3081
|
+
df = ak.sw_index_second_info()
|
3082
|
+
else:
|
3083
|
+
df = ak.sw_index_first_info()
|
3084
|
+
|
3085
|
+
df['industry_code']=df['行业代码'].apply(lambda x: x[:6])
|
3086
|
+
industry_list=list(df['industry_code'])
|
3087
|
+
|
3088
|
+
import pandas as pd; import random; import time
|
3089
|
+
result=pd.DataFrame(columns=['序号','证券名称','证券代码','行业名称','行业代码'])
|
3052
3090
|
|
3053
3091
|
for i in industry_list:
|
3054
|
-
|
3055
|
-
|
3092
|
+
print_progress_percent2(i,industry_list,steps=10,leading_blanks=2)
|
3093
|
+
|
3094
|
+
iname=df[df['industry_code']==i]['行业名称'].values[0]
|
3095
|
+
|
3096
|
+
try:
|
3097
|
+
cdf = ak.index_component_sw(i)
|
3098
|
+
except:
|
3099
|
+
print(" #Warning(find_industry_sw): server banned this ip becos of too many requests")
|
3100
|
+
print(" Solution: change to another ip or another computer, or try a few hours later.")
|
3101
|
+
return
|
3102
|
+
"""
|
3103
|
+
component_list=list(cdf['证券代码'])
|
3056
3104
|
|
3057
3105
|
if ticker6 in component_list:
|
3058
3106
|
stock_name=cdf[cdf["证券代码"]==ticker6]['证券名称'].values[0]
|
3059
|
-
print("
|
3107
|
+
print("\n\n股票代码:"+ticker+","+stock_name)
|
3060
3108
|
|
3061
3109
|
isi=i+'.SI'
|
3062
|
-
industry_name=
|
3063
|
-
print("
|
3110
|
+
industry_name=df[df['行业代码']==isi]['行业名称'].values[0]
|
3111
|
+
print("申万"+str(level)+"级行业代码:"+i+".SW,"+industry_name)
|
3064
3112
|
|
3065
3113
|
break
|
3114
|
+
"""
|
3115
|
+
for t in tickerlist:
|
3116
|
+
torder=tickerlist.index(t)+1
|
3117
|
+
|
3118
|
+
if not contains_chinese(t):
|
3119
|
+
dft=cdf[cdf['证券代码']==t]
|
3120
|
+
if len(dft)==0: continue
|
3121
|
+
else:
|
3122
|
+
tname=cdf[cdf['证券代码']==t]['证券名称'].values[0]
|
3123
|
+
s=pd.Series({'序号':torder,'证券名称':tname,'证券代码':t,'行业名称':iname,'行业代码':i})
|
3124
|
+
try:
|
3125
|
+
result=result.append(s,ignore_index=True)
|
3126
|
+
except:
|
3127
|
+
result=result._append(s,ignore_index=True)
|
3128
|
+
else:
|
3129
|
+
dft=cdf[cdf['证券名称']==t]
|
3130
|
+
if len(dft)==0: continue
|
3131
|
+
else:
|
3132
|
+
tcode=cdf[cdf['证券名称']==t]['证券代码'].values[0]
|
3133
|
+
s=pd.Series({'序号':torder,'证券名称':t,'证券代码':tcode,'行业名称':iname,'行业代码':i})
|
3134
|
+
try:
|
3135
|
+
result=result.append(s,ignore_index=True)
|
3136
|
+
except:
|
3137
|
+
result=result._append(s,ignore_index=True)
|
3138
|
+
|
3139
|
+
#是否都找到了?
|
3140
|
+
if len(result) == len(tickerlist): break
|
3066
3141
|
|
3067
|
-
|
3142
|
+
#生成随机数睡眠,试图防止被反爬虫,不知是否管用!
|
3143
|
+
random_int=random.randint(1,5)
|
3144
|
+
time.sleep(random_int)
|
3145
|
+
|
3146
|
+
#排序
|
3147
|
+
if not ticker_order:
|
3148
|
+
#按行业代码排序
|
3149
|
+
result.sort_values(by='行业代码',inplace=True)
|
3150
|
+
else:
|
3151
|
+
#按ticker顺序排序
|
3152
|
+
result.sort_values(by='序号',inplace=True)
|
3153
|
+
"""
|
3154
|
+
if contains_chinese(tickerlist[0]):
|
3155
|
+
result.sort_values(by='证券名称',key=lambda x: x.map(dict(zip(tickerlist,range(len(tickerlist))))))
|
3156
|
+
else:
|
3157
|
+
result.sort_values(by='证券代码',key=lambda x: x.map(dict(zip(tickerlist,range(len(tickerlist))))))
|
3158
|
+
"""
|
3159
|
+
#result.reset_index(drop=True,inplace=True)
|
3160
|
+
|
3161
|
+
#显示结果
|
3162
|
+
titletxt="证券所属行业:申万"+str(level)+"级行业"
|
3163
|
+
import datetime; todaydt = datetime.date.today()
|
3164
|
+
footnote="数据来源:申万宏源,"+str(todaydt)+"统计"
|
3165
|
+
"""
|
3166
|
+
collist=list(result)
|
3167
|
+
result['序号']=result.index+1
|
3168
|
+
result=result[['序号']+collist]
|
3169
|
+
"""
|
3170
|
+
print('')
|
3171
|
+
df_display_CSS(result,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=2, \
|
3172
|
+
first_col_align='center',second_col_align='left', \
|
3173
|
+
last_col_align='left',other_col_align='left', \
|
3174
|
+
titile_font_size='16px',heading_font_size='15px', \
|
3175
|
+
data_font_size='15px')
|
3176
|
+
|
3177
|
+
return result
|
3178
|
+
|
3068
3179
|
#==============================================================================
|
3069
3180
|
#==============================================================================
|
3070
3181
|
#==============================================================================
|
siat/stock_technical.py
CHANGED
@@ -2009,7 +2009,7 @@ def security_bollinger(ticker,fromdate,todate,boll_days=20, \
|
|
2009
2009
|
print(" #Error(security_bollinger): price info not found for",ticker)
|
2010
2010
|
return None
|
2011
2011
|
if found not in ['Found']:
|
2012
|
-
print(" #Error(): ticker info either inaccessible or not found for",ticker)
|
2012
|
+
print(" #Error(security_bollinger): ticker info either inaccessible or not found for",ticker)
|
2013
2013
|
return None
|
2014
2014
|
|
2015
2015
|
# 滚动均值与标准差
|
@@ -2045,7 +2045,7 @@ def security_bollinger(ticker,fromdate,todate,boll_days=20, \
|
|
2045
2045
|
data_label=False,resample_freq='6H',smooth=smooth, \
|
2046
2046
|
date_range=date_range,date_freq=date_freq,date_fmt='%Y-%m-%d', \
|
2047
2047
|
colorlist=colorlist,lslist=lslist,lwlist=lwlist, \
|
2048
|
-
band_area=['上(压力)线','下(支撑)线'],mark_end=mark_end)
|
2048
|
+
band_area=['上(压力)线','下(支撑)线'],mark_end=mark_end,loc=loc)
|
2049
2049
|
|
2050
2050
|
return df1
|
2051
2051
|
|
@@ -52,7 +52,7 @@ siat/financials_test.py,sha256=HJ3CPo_Xckz2wXi3AEP6ZNWCF1Duc1pLi0Y10USiImc,23829
|
|
52
52
|
siat/fred_test.py,sha256=KF50ssSbsfpa_kT6iuomD0vG4eXztAcOasZxg1OGX5w,1201
|
53
53
|
siat/fund.py,sha256=wMDORsCBV8ZXfgwbtq-0bu3qqWY66dHnbqgllW0gWCo,24637
|
54
54
|
siat/fund_china.pickle,sha256=QI3IjV46EeJ5ryO3xocmByc-6b_6_nDxgcXDhBHzop0,2380915
|
55
|
-
siat/fund_china.py,sha256=
|
55
|
+
siat/fund_china.py,sha256=5ZgF4G9GFQa7hPufqol-qDg_EZj8CtmYd0UR9L2zIDI,99025
|
56
56
|
siat/fund_china_test.py,sha256=-Bh6m0J0GPpIbYXx-H2vpzJoNFI6pE2C2jVPa8DazgE,6649
|
57
57
|
siat/fund_test.py,sha256=V4ADb8Gsp8gyeFTwcgRsJBpnUih_O-Q2V1ILc5oKjK8,1116
|
58
58
|
siat/future_china.py,sha256=F-HsIf2Op8Z22RzTjet1g8COzldgnMjFNSXsAkeGyWo,17595
|
@@ -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=o8t4amM6NKGwYiT4N1Vqb3UdDpky_JY_jQwL-Q2Ygd8,117754
|
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
|
@@ -112,7 +112,7 @@ siat/stock_list_china_test.py,sha256=gv14UwMMvkZqtb6G7DCTSuehIwVHuVwu7w60p6gyHoo
|
|
112
112
|
siat/stock_prices_kneighbors.py,sha256=WfZvo5EyeBsm-T37zDj7Sl9dPSRq5Bx4JxIJ9IUum6s,36738
|
113
113
|
siat/stock_prices_linear.py,sha256=-OUKRr27L2aStQgJSlJOrJ4gay_G7P-m-7t7cU2Yoqk,13991
|
114
114
|
siat/stock_profile.py,sha256=B3eIwzEmiCqiCaxIlhfdEPsQBoW1PFOe1hkiY3mVF6Y,26038
|
115
|
-
siat/stock_technical.py,sha256=
|
115
|
+
siat/stock_technical.py,sha256=YGfvsV5Uu9xaZgJO7dwl1FsvszwX3jsGyJxqJgNamQk,112859
|
116
116
|
siat/stock_test.py,sha256=E9YJAvOw1VEGJSDI4IZuEjl0tGoisOIlN-g9UqA_IZE,19475
|
117
117
|
siat/stooq.py,sha256=dOc_S5HLrYg48YAKTCs1eX8UTJOOkPM8qLL2KupqlLY,2470
|
118
118
|
siat/temp.py,sha256=gbJ0ioauuo4koTPH6WKUkqcXiQPafnbhU5eKJ6lpdLA,1571
|
@@ -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.12.dist-info/METADATA,sha256=rgKgLVsy_yr30SZbLNHZCCzjVMz2_TOVSuGIV2HVOAM,1448
|
136
|
+
siat-3.1.12.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
137
|
+
siat-3.1.12.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
|
138
|
+
siat-3.1.12.dist-info/RECORD,,
|
File without changes
|
File without changes
|