siat 3.3.1__py3-none-any.whl → 3.3.10__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/capm_beta2.py CHANGED
@@ -202,6 +202,79 @@ def regression_capm(ticker,start2,end, \
202
202
 
203
203
  return reg_result,dretdf3
204
204
 
205
+
206
+ def regression_capm_df(marketdf,pricedf,mktidx,adjust='',RF=0,regtrddays=252):
207
+ """
208
+ 功能:进行CAPM回归,R-Rf=beta*(Rm-Rf),无截距项回归
209
+ x为(Rm-Rf),y为R-Rf,均为日收益率,默认回归样本长度一年(365日历日或252交易日)
210
+ 返回:beta系数
211
+ 注意:回归基于传统的日收益率,而非滚动收益率
212
+ """
213
+
214
+ #合并股票和大盘指数日收益率
215
+ dretdf1=pd.merge(marketdf,pricedf,how='inner',left_index=True,right_index=True)
216
+
217
+ #准备CAPM回归文件
218
+ if adjust == '':
219
+ dretname='Daily Ret'
220
+ else:
221
+ dretname='Daily Adj Ret'
222
+
223
+ #计算日无风险利率
224
+ RF_daily=RF / 365
225
+
226
+ dretx=dretname+'_x' #指数日收益率
227
+ drety=dretname+'_y' #股票日收益率
228
+ dretdf2=dretdf1[[dretx,drety]]
229
+ dretdf2.dropna(inplace=True)
230
+
231
+ #计算股票和指数收益率的风险溢价R-RF
232
+ dretdfcols=list(dretdf2)
233
+ for c in dretdfcols:
234
+ dretdf2[c]=dretdf2[c].apply(lambda x: x-RF_daily)
235
+ dretdf2=dretdf2.reset_index()
236
+ #dretdf2.rename(columns={'index':'Date'},inplace=True)
237
+ if 'Date' not in list(dretdf2):
238
+ dretdf2['Date']=dretdf2['index']
239
+
240
+ #CAPM回归,计算贝塔系数
241
+ dretnum=len(dretdf2)
242
+ if regtrddays >= dretnum:
243
+ regtrddays=dretnum - 31 *2
244
+
245
+ import statsmodels.api as sm
246
+ reg_result=pd.DataFrame(columns=('Date','beta'))
247
+ for i in range(dretnum):
248
+ i2=dretnum-i
249
+ i1=i2-regtrddays
250
+ if i1 < 0: break
251
+
252
+ regdf=dretdf2[i1:i2]
253
+ lastdate=regdf.tail(1)['Date'].values[0]
254
+
255
+ X=regdf[dretx] #无截距项回归
256
+ Y=regdf[drety]
257
+ model = sm.OLS(Y,X) #定义回归模型R-Rf=beta(Rm-Rf),X可为多元矩阵
258
+ results = model.fit() #进行OLS回归
259
+ beta=results.params[0] #提取回归系数
260
+
261
+ row=pd.Series({'Date':lastdate,'beta':beta})
262
+ try:
263
+ reg_result=reg_result.append(row,ignore_index=True)
264
+ except:
265
+ reg_result=reg_result._append(row,ignore_index=True)
266
+
267
+ reg_result.set_index(['Date'],inplace=True)
268
+ reg_result.sort_index(inplace=True) #按日期升序排列
269
+
270
+ dretdf3=dretdf2.set_index(['Date'])
271
+ if 'index' in list(dretdf3):
272
+ del dretdf3['index']
273
+
274
+ reg_result['mktidx']=mktidx
275
+
276
+ return reg_result,dretdf3
277
+
205
278
  #==============================================================================
206
279
  if __name__=='__main__':
207
280
  ticker="600519.SS"
@@ -328,16 +401,19 @@ def compare_mticker_1beta(ticker,start,end, \
328
401
  #df1.rename(columns={c:ticker_name(c)},inplace=True)
329
402
 
330
403
  #共同脚注
331
- footnote1="注:"
404
+ footnote1=text_lang("注:","Notes: ")
405
+ """
332
406
  if RF !=0:
333
- footnote2="年化无风险利率为"+str(round(RF*100,4))+'%。'
407
+ footnote2=text_lang("年化无风险利率为","RF = ")+str(round(RF*100,4))+text_lang('%。','% pa. ')
334
408
  else:
335
409
  footnote2="假设年化无风险利率为零。"
336
-
337
- footnote3="基于"+mktidx_name+",回归期间为"+str(regression_period)+"个自然日。"
410
+ """
411
+ footnote2=text_lang("年化无风险利率为","RF = ")+str(round(RF*100,4))+text_lang('%。','% pa. ')
412
+
413
+ footnote3=text_lang("基于","Beta using ")+mktidx_name+text_lang(",CAPM回归期间为",", CAPM rolling ")+str(regression_period)+text_lang("个自然日"," days")
338
414
 
339
415
  import datetime; todaydt = datetime.date.today()
340
- footnote4="数据来源: 综合新浪/stooq/Yahoo,"+str(todaydt)+"统计"
416
+ footnote4=text_lang("数据来源: 综合新浪/Stooq/Yahoo,","Data source: Sina/Stooq/Yahoo, ")+str(todaydt)+text_lang("统计",'')
341
417
  if footnote3 !='':
342
418
  footnotex=footnote1+footnote2+footnote3+'\n'+footnote4
343
419
  else:
@@ -345,8 +421,8 @@ def compare_mticker_1beta(ticker,start,end, \
345
421
 
346
422
  #绘图
347
423
  if graph:
348
- title_txt="CAPM贝塔系数"
349
- y_label="贝塔系数"
424
+ title_txt=text_lang("CAPM贝塔系数","CAPM Beta Coefficient")
425
+ y_label=text_lang("贝塔系数","Beta")
350
426
 
351
427
  draw_lines(df1,y_label,x_label=footnotex, \
352
428
  axhline_value=axhline_value,axhline_label=axhline_label, \
siat/common.py CHANGED
@@ -2437,15 +2437,15 @@ def descriptive_statistics2(df,titletxt,footnote,decimals=4,sortby='tpw_mean', \
2437
2437
  heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
2438
2438
 
2439
2439
  dst6.rename(columns={"比较对象":text_lang("比较对象","Securities"), \
2440
- "最小值":text_lang("最小值","Minimum"), \
2441
- "最大值":text_lang("最大值","Maximum"), \
2440
+ "最小值":text_lang("最小值","Min"), \
2441
+ "最大值":text_lang("最大值","Max"), \
2442
2442
  "中位数":text_lang("中位数","Median"), \
2443
2443
  "平均值":text_lang("平均值","Mean"), \
2444
2444
  "标准差":text_lang("标准差","Std Dev"), \
2445
2445
  "近期优先加权平均":text_lang("近期优先加权平均","RWA"), \
2446
- "期间趋势":text_lang("期间趋势","Periodic Trend"), \
2446
+ "期间趋势":text_lang("期间趋势","Period Trend"), \
2447
2447
  "近期趋势":text_lang("近期趋势","Recent Trend"), \
2448
- "推荐标记":text_lang("推荐标记","Recommendation")},inplace=True)
2448
+ "推荐标记":text_lang("推荐标记","Recommend")},inplace=True)
2449
2449
 
2450
2450
  df_display_CSS(dst6,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
2451
2451
  titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
siat/fund_china.pickle CHANGED
Binary file
siat/markowitz.py CHANGED
@@ -159,10 +159,10 @@ def cumulative_returns_plot(retgroup,name_list="",titletxt="投资组合策略
159
159
  import datetime as dt; stoday=dt.date.today()
160
160
  if lang == 'Chinese':
161
161
  footnote1="观察期间: "+hstart+'至'+hend
162
- footnote2="\n来源:Sina/EM/stooq,"+str(stoday)
162
+ footnote2="\n数据来源:Sina/EM/Stooq/Yahoo, "+str(stoday)
163
163
  else:
164
164
  footnote1="Period of observation: "+hstart+' to '+hend
165
- footnote2="\nSource: sina/eastmoney/stooq, "+str(stoday)
165
+ footnote2="\nData source: Sina/EM/Stooq/Yahoo, "+str(stoday)
166
166
 
167
167
  xlabeltxt=footnote1+footnote2
168
168
 
@@ -344,11 +344,11 @@ def portfolio_cumret(portfolio,thedate,pastyears=1, \
344
344
  if lang == 'Chinese':
345
345
  title_txt="投资组合: 日收益率的变化趋势"
346
346
  ylabel_txt="日收益率"
347
- source_txt="来源: Sina/EM/stooq, "
347
+ source_txt="数据来源: Sina/EM/Stooq/Yahoo, "
348
348
  else:
349
349
  title_txt="Investment Portfolio: Daily Return"
350
350
  ylabel_txt="Daily Return"
351
- source_txt="Source: sina/eastmoney/stooq, "
351
+ source_txt="Data source: Sina/EM/Stooq/Yahoo, "
352
352
 
353
353
  plt.title(title_txt)
354
354
  plt.ylabel(ylabel_txt)
@@ -368,11 +368,11 @@ def portfolio_cumret(portfolio,thedate,pastyears=1, \
368
368
  if lang == 'Chinese':
369
369
  titletxt="投资组合: 持有收益率的变化趋势"
370
370
  ylabeltxt="持有收益率"
371
- xlabeltxt="来源: Sina/EM/stooq, "+str(stoday)
371
+ xlabeltxt="数据来源: Sina/EM/Stooq/Yahoo, "+str(stoday)
372
372
  else:
373
373
  titletxt="Investment Portfolio: Holding Return"
374
374
  ylabeltxt="Holding Return"
375
- xlabeltxt="Source: sina/eastmoney/stooq, "+str(stoday)
375
+ xlabeltxt="Data source: Sina/EM/Stooq/Yahoo, "+str(stoday)
376
376
 
377
377
  #绘制持有收益率曲线
378
378
  if graph:
@@ -497,7 +497,7 @@ def portfolio_corr(pf_info):
497
497
 
498
498
  footnote1="观察期间: "+hstart+'至'+hend
499
499
  import datetime as dt; stoday=dt.date.today()
500
- footnote2="\n来源:Sina/EM/stooq,"+str(stoday)
500
+ footnote2="\n数据来源:Sina/EM/Stooq/Yahoo, "+str(stoday)
501
501
  plt.xlabel(footnote1+footnote2)
502
502
  plt.xticks(rotation=90); plt.yticks(rotation=0)
503
503
 
@@ -541,7 +541,7 @@ def portfolio_covar(pf_info):
541
541
 
542
542
  footnote1="观察期间: "+hstart+'至'+hend
543
543
  import datetime as dt; stoday=dt.date.today()
544
- footnote2="\n来源:Sina/EM/stooq,"+str(stoday)
544
+ footnote2="\n数据来源:Sina/EM/Stooq/Yahoo, "+str(stoday)
545
545
  plt.xlabel(footnote1+footnote2)
546
546
  plt.xticks(rotation=90)
547
547
  plt.yticks(rotation=0)
@@ -623,7 +623,7 @@ def portfolio_expectation_universal(pname,member_returns,portfolio_weights,membe
623
623
  print(" ***投资组合持仓策略***")
624
624
  print_tickerlist_sharelist(tickerlist,portfolio_weights,4)
625
625
 
626
- print(" *来源:Sina/EM/stooq,"+str(stoday))
626
+ print(" *数据来源:Sina/EM/Stooq/Yahoo, "+str(stoday))
627
627
  else:
628
628
  print("\n ======= Investment Portfolio: Return and Risk =======")
629
629
  print(" Investment portfolio:",pname)
@@ -635,7 +635,7 @@ def portfolio_expectation_universal(pname,member_returns,portfolio_weights,membe
635
635
  print(" ***Portfolio Constructing Strategy***")
636
636
  print_tickerlist_sharelist(tickerlist,portfolio_weights,4)
637
637
 
638
- print(" *Source: sina/eastmoney/stooq,"+str(stoday))
638
+ print(" *Data source: Sina/EM/Stooq/Yahoo, "+str(stoday))
639
639
 
640
640
  return
641
641
 
@@ -1007,7 +1007,7 @@ def portfolio_es(pf_info,simulation=50000):
1007
1007
  footnote1="年化收益率标准差-->"
1008
1008
  footnote2="\n\n基于给定的成份证券构造"+str(simulation)+"个投资组合"
1009
1009
  footnote3="\n观察期间:"+hstart+"至"+hend
1010
- footnote4="\n来源: Sina/EM/stooq, "+str(stoday)
1010
+ footnote4="\n数据来源: Sina/EM/Stooq/Yahoo, "+str(stoday)
1011
1011
  else:
1012
1012
  if pname == '': pname='Investment Portfolio'
1013
1013
 
@@ -1017,8 +1017,8 @@ def portfolio_es(pf_info,simulation=50000):
1017
1017
 
1018
1018
  footnote1="Annualized Std -->\n\n"
1019
1019
  footnote2="Based on given component securities, constructed "+str(simulation)+" portfolios\n"
1020
- footnote3="Period of observation: "+hstart+" to "+hend
1021
- footnote4="\nSource: sina/eastmoney/stooq, "+str(stoday)
1020
+ footnote3="Period of sample: "+hstart+" to "+hend
1021
+ footnote4="\nData Source: Sina/EM/Stooq/Yahoo, "+str(stoday)
1022
1022
 
1023
1023
  plt.xlabel(footnote1+footnote2+footnote3+footnote4,fontsize=xlabel_txt_size)
1024
1024
 
@@ -1481,7 +1481,7 @@ def RandomPortfolios_plot(RandomPortfolios,col_x,col_y,colorbartxt,title_ext, \
1481
1481
  footnote1=x_axis_name+" -->\n\n"
1482
1482
  footnote2="基于设定的成份证券构造"+str(simulation)+"个投资组合"
1483
1483
  footnote3="\n观察期间:"+hstart+"至"+hend
1484
- footnote4="\n来源: Sina/EM/stooq/FRED, "+str(stoday)
1484
+ footnote4="\n数据来源: Sina/EM/Stooq/Yahoo, "+str(stoday)
1485
1485
  else:
1486
1486
  if pname == '': pname='Investment Portfolio'
1487
1487
 
@@ -1491,8 +1491,8 @@ def RandomPortfolios_plot(RandomPortfolios,col_x,col_y,colorbartxt,title_ext, \
1491
1491
  import datetime as dt; stoday=dt.date.today()
1492
1492
  footnote1=x_axis_name+" -->\n\n"
1493
1493
  footnote2="Based on given component securities, constructed "+str(simulation)+" portfolios"
1494
- footnote3="\nPeriod of observation: "+hstart+" to "+hend
1495
- footnote4="\nSource: sina/eastmoney/stooq/FRED, "+str(stoday)
1494
+ footnote3="\nPeriod of sample: "+hstart+" to "+hend
1495
+ footnote4="\nData source: Sina/EM/Stooq/Yahoo, "+str(stoday)
1496
1496
 
1497
1497
  plt.xlabel(footnote1+footnote2+footnote3+footnote4,fontsize=xlabel_txt_size)
1498
1498
 
@@ -2267,7 +2267,7 @@ def security_correlation(tickers,start,end,info_type='Close'):
2267
2267
 
2268
2268
  footnote3="\n观察期间: "+start+'至'+end
2269
2269
  import datetime as dt; stoday=dt.date.today()
2270
- footnote4=";来源:Sina/EM/stooq/Yahoo,"+str(stoday)
2270
+ footnote4=";数据来源:Sina/EM/Stooq/Yahoo,"+str(stoday)
2271
2271
 
2272
2272
  fontxlabel={'size':6}
2273
2273
  plt.xlabel(footnote1+footnote2+footnote3+footnote4,fontxlabel)
@@ -32,15 +32,15 @@ import numpy as np
32
32
  #==============================================================================
33
33
  #==============================================================================
34
34
  if __name__=='__main__':
35
- ticker="600519.SS"
35
+ ticker="AAPL"
36
36
  ticker={'Market':('US','^SPX','中概教培组合'),'EDU':0.7,'TAL':0.3}
37
37
 
38
38
  start="2024-1-1"
39
- end="2024-3-15"
39
+ end="2024-6-30"
40
40
  rar_name="sharpe"
41
- ret_type="Monthly Ret%"
42
- RF=0
43
- source='auto'
41
+ ret_type="Annual Adj Ret%"
42
+ RF=0.055
43
+ source='auto'; ticker_type='auto'
44
44
 
45
45
  sharpe1m0=get_rolling_sharpe_sortino(ticker,start,end,rar_name="sharpe",ret_type="Monthly Ret%",RF=0)
46
46
  sharpe2w=get_rolling_sharpe_sortino(ticker,start,end,rar_name="sharpe",ret_type="Weekly Ret%",RF=0.01759)
@@ -52,7 +52,7 @@ if __name__=='__main__':
52
52
  sortino2=get_rolling_sharpe_sortino(ticker,start,end,rar_name="sortino",ret_type="Monthly Ret%",RF=0.01759)
53
53
 
54
54
  def get_rolling_sharpe_sortino(ticker,start,end,rar_name="sharpe", \
55
- ret_type="Monthly Ret%",RF=0,source='auto', \
55
+ ret_type="Monthly Adj Ret%",RF=0,source='auto', \
56
56
  ticker_type='auto'):
57
57
  """
58
58
  功能:获取一只股票的夏普比率或索替诺比率,基于给定的滚动收益率类型,在指定期间内
@@ -116,7 +116,6 @@ def get_rolling_sharpe_sortino(ticker,start,end,rar_name="sharpe", \
116
116
  #收益率减去一个常数其实不影响其标准差的数值,即std(ret-RF)=std(ret)
117
117
  rardf2[ret_type]=rardf2[ret_type] - RF_period
118
118
  rardf3=rolling_ret_volatility(rardf2, period=ret_period)
119
- #收益率减去一个常数应该影响其下偏标准差的数值,即lpsd(ret-RF)!=lpsd(ret),实际上却未影响,有点奇怪
120
119
  rardf4=rolling_ret_lpsd(rardf3, period=ret_period)
121
120
 
122
121
  #开始日期富余一段时间,有助于绘图时显示出期望的开始日期
@@ -171,7 +170,7 @@ if __name__=='__main__':
171
170
  sortino2=get_expanding_sharpe_sortino(ticker,start,end,rar_name="sortino",RF=0.01759)
172
171
 
173
172
  def get_expanding_sharpe_sortino(ticker,start,end,rar_name="sharpe", \
174
- ret_type="Exp Ret%",RF=0,source='auto',ticker_type='auto'):
173
+ ret_type="Exp Adj Ret%",RF=0,source='auto',ticker_type='auto'):
175
174
  """
176
175
  功能:获取一只股票的夏普比率或索替诺比率,基于扩展收益率,在指定期间内
177
176
  支持股票和投资组合
@@ -252,16 +251,16 @@ def get_expanding_sharpe_sortino(ticker,start,end,rar_name="sharpe", \
252
251
 
253
252
  #==============================================================================
254
253
  if __name__=='__main__':
255
- ticker="600519.SS"
254
+ ticker="AAPL"
256
255
  ticker={'Market':('US','^SPX','中概教培组合'),'EDU':0.7,'TAL':0.3}
257
256
 
258
257
  start="2024-1-1"
259
- end="2024-3-15"
260
- rar_name="alpha"
261
- ret_type="Monthly Ret%"
262
- RF=0.01759
258
+ end="2024-6-30"
259
+ rar_name="treynor"
260
+ ret_type="Annual Adj Ret%"
261
+ RF=0.055
263
262
  regression_period=365
264
- mktidx='auto'; source='auto'
263
+ mktidx='auto'; source='auto'; ticker_type='auto'
265
264
 
266
265
  alpha1m0=get_rolling_treynor_alpha(ticker,start,end,rar_name="alpha",ret_type="Monthly Ret%",RF=0)
267
266
  alpha2w=get_rolling_treynor_alpha(ticker,start,end,rar_name="alpha",ret_type="Weekly Ret%",RF=0.01759)
@@ -277,6 +276,7 @@ def get_rolling_treynor_alpha(ticker,start,end,rar_name="alpha", \
277
276
  支持股票和投资组合
278
277
  RF: 年化利率,不带百分数
279
278
  计算CAPM的期间:默认一年,252个交易日
279
+ ***废弃!!!指标计算有问题
280
280
  """
281
281
 
282
282
  #估计需要的日期提前量
@@ -284,19 +284,19 @@ def get_rolling_treynor_alpha(ticker,start,end,rar_name="alpha", \
284
284
  if 'weekly' in ret_type_lower:
285
285
  dateahead=7*2+7 #考虑收益率标准差和节假日
286
286
  ret_period='Weekly'
287
- period_days=5
287
+ period_days=7
288
288
  elif 'monthly' in ret_type_lower:
289
289
  dateahead=31*2+7 #考虑收益率标准差和节假日
290
290
  ret_period='Monthly'
291
- period_days=21
291
+ period_days=30
292
292
  elif 'quarterly' in ret_type_lower:
293
293
  dateahead=(31*3+7)*2 #考虑收益率标准差和节假日
294
294
  ret_period='Quarterly'
295
- period_days=63
295
+ period_days=90
296
296
  else:
297
297
  dateahead=(366+7*3)*2 #考虑收益率标准差和节假日
298
298
  ret_period='Annual'
299
- period_days=252
299
+ period_days=365
300
300
 
301
301
  #计算日历日regression_period对应的交易日数
302
302
  regtrddays=int(252 / 365 * regression_period)
@@ -321,8 +321,8 @@ def get_rolling_treynor_alpha(ticker,start,end,rar_name="alpha", \
321
321
  source=source,ticker_type=ticker_type)
322
322
 
323
323
  #计算股票和指数的滚动收益率
324
- varx=ret_type+'_x'
325
- vary=ret_type+'_y'
324
+ varx=ret_type+'_x' #指数收益率
325
+ vary=ret_type+'_y' #股票收益率
326
326
 
327
327
  pretdf=dretdf3.copy()
328
328
  pretdfcols=list(pretdf)
@@ -331,6 +331,7 @@ def get_rolling_treynor_alpha(ticker,start,end,rar_name="alpha", \
331
331
 
332
332
  #对数法计算滚动收益率
333
333
  RF_period=RF/365 * period_days
334
+
334
335
  if '%' in ret_type_lower:
335
336
  pretdf[lndretx]=pretdf[pretdfcols[0]].apply(lambda x: np.log(1+x/100))
336
337
  pretdf[lndrety]=pretdf[pretdfcols[1]].apply(lambda x: np.log(1+x/100))
@@ -338,7 +339,6 @@ def get_rolling_treynor_alpha(ticker,start,end,rar_name="alpha", \
338
339
  pretdf[varx]=pretdf[lndretx].rolling(window=period_days).apply(lambda x: (np.exp(sum(x))-1)*100)
339
340
  pretdf[vary]=pretdf[lndrety].rolling(window=period_days).apply(lambda x: (np.exp(sum(x))-1)*100)
340
341
 
341
- RF_period=(RF/365 * period_days)*100
342
342
  else:
343
343
  pretdf[lndretx]=pretdf[pretdfcols[0]].apply(lambda x: np.log(1+x))
344
344
  pretdf[lndrety]=pretdf[pretdfcols[1]].apply(lambda x: np.log(1+x))
@@ -366,16 +366,145 @@ def get_rolling_treynor_alpha(ticker,start,end,rar_name="alpha", \
366
366
 
367
367
  return pretdf3
368
368
 
369
+
370
+ def get_rolling_treynor_alpha2(ticker,start,end,rar_name="alpha", \
371
+ ret_type="Monthly Adj Ret%",RF=0, \
372
+ regression_period=365,mktidx='auto',source='auto',ticker_type='auto'):
373
+ """
374
+ 功能:获取一只股票的特雷诺比率或阿尔法指数,基于给定的滚动收益率类型,在指定期间内
375
+ 支持股票和投资组合
376
+ RF: 年化利率,不带百分数
377
+ 计算CAPM的期间:默认一年,252个交易日
378
+ """
379
+
380
+ #估计滚动窗口日期的提前量
381
+ ret_type_lower=ret_type.lower()
382
+ if 'weekly' in ret_type_lower:
383
+ dateahead=7*2+7 #考虑收益率标准差和节假日
384
+ ret_period='Weekly'
385
+ period_days=5
386
+ elif 'monthly' in ret_type_lower:
387
+ dateahead=31*2+7 #考虑收益率标准差和节假日
388
+ ret_period='Monthly'
389
+ period_days=21
390
+ elif 'quarterly' in ret_type_lower:
391
+ dateahead=(31*3+7)*2 #考虑收益率标准差和节假日
392
+ ret_period='Quarterly'
393
+ period_days=63
394
+ else:
395
+ dateahead=(366+7*3)*2 #考虑收益率标准差和节假日
396
+ ret_period='Annual'
397
+ period_days=252
398
+
399
+ #计算滚动查看需要的日期提前量
400
+ start1=date_adjust(start,adjust=-dateahead)
401
+ #计算CAPM需要的日期提前量
402
+ start2=date_adjust(start1,adjust=-regression_period-7*2)
403
+
404
+ #判断复权价
405
+ ret_type=ret_type.title()
406
+ if ('Adj' in ret_type):
407
+ adjust='qfq'
408
+ else:
409
+ adjust=''
410
+
411
+ #获取股票收益率
412
+ if '%' in ret_type:
413
+ if 'Adj' in ret_type:
414
+ dret_type="Daily Adj Ret%"
415
+ else:
416
+ dret_type="Daily Ret%"
417
+ else:
418
+ if 'Adj' in ret_type:
419
+ dret_type="Daily Adj Ret"
420
+ else:
421
+ dret_type="Daily Ret"
422
+
423
+ #抓取股价
424
+ pricedfs,found=get_price_1ticker_mixed(ticker=ticker,fromdate=start2,todate=end, \
425
+ adjust=adjust, \
426
+ source=source,ticker_type=ticker_type)
427
+ if found !='Found':
428
+ print(" #Error(get_rolling_treynor_alpha2): no records found for",ticker)
429
+ return None
430
+
431
+ #计算股票收益率
432
+ rardf1s=calc_daily_return(pricedfs)
433
+ rardf2s=calc_rolling_return(rardf1s,period=ret_period)
434
+
435
+ #抓取指数
436
+ if isinstance(ticker,dict):
437
+ _,mktidx,pftickerlist,_,ticker_type=decompose_portfolio(ticker)
438
+ if 'auto' in mktidx.lower():
439
+ mktidx=get_market_index_code(pftickerlist[0])
440
+ else:
441
+ if 'auto' in mktidx.lower():
442
+ mktidx=get_market_index_code(ticker)
443
+
444
+ marketdf,found=get_price_1ticker_mixed(ticker=mktidx,fromdate=start2,todate=end, \
445
+ adjust=adjust, \
446
+ source=source,ticker_type=ticker_type)
447
+ if found !='Found':
448
+ print(" #Error(get_rolling_treynor_alpha2): no records found for",mktidx)
449
+ return None
450
+
451
+ #计算指数收益率
452
+ rardf1m=calc_daily_return(marketdf)
453
+ rardf2m=calc_rolling_return(rardf1m,period=ret_period)
454
+
455
+
456
+ #计算日历日regression_period对应的交易日数
457
+ regtrddays=int(252 / 365 * regression_period)
458
+
459
+ #CAPM回归,计算贝塔系数
460
+ reg_result,dretdf3=regression_capm_df(rardf1m,rardf1s,mktidx=mktidx,adjust=adjust,RF=RF,regtrddays=regtrddays)
461
+
462
+ #合成滚动收益率与贝塔系数:_x为指数收益率,_y为股票收益率
463
+ pretdfms=pd.merge(rardf2m[[ret_type]],rardf2s[[ret_type]],how='inner',left_index=True,right_index=True)
464
+ pretdf1=pd.merge(pretdfms,reg_result,how='inner',left_index=True,right_index=True)
465
+
466
+ if '%' in ret_type:
467
+ RF=RF*100
468
+ if ret_period=='Weekly':
469
+ RF_period=RF/52
470
+ elif ret_period=='Monthly':
471
+ RF_period=RF/12
472
+ elif ret_period=='Quarterly':
473
+ RF_period=RF/4
474
+ else:
475
+ RF_period=RF
476
+
477
+ #计算特雷诺比率和阿尔法指标
478
+ if 'treynor' in rar_name.lower():
479
+ pretdf1[rar_name]=pretdf1.apply(lambda x: (x[ret_type+'_y']-RF_period)/x['beta'],axis=1)
480
+
481
+ elif 'alpha' in rar_name.lower():
482
+ vary_pred=ret_type+'_pred'
483
+ pretdf1[vary_pred]=pretdf1.apply(lambda x: RF_period+x['beta']*(x[ret_type+'_x']-RF_period),axis=1)
484
+ pretdf1[rar_name]=pretdf1.apply(lambda x: x[ret_type+'_y']-x[vary_pred],axis=1)
485
+
486
+ if '%' in ret_type:
487
+ pretdf1[rar_name]=pretdf1[rar_name]/100
488
+
489
+ #开始日期富余一段时间,有助于绘图时显示出期望的开始日期
490
+ startpd=pd.to_datetime(date_adjust(start,adjust=-7))
491
+ endpd=pd.to_datetime(end)
492
+ pretdf2=pretdf1[(pretdf1.index >=startpd) & (pretdf1.index <=endpd)]
493
+
494
+ pretdf3=pretdf2[[rar_name,'beta']]
495
+
496
+ return pretdf3
497
+
369
498
  #==============================================================================
370
499
  if __name__=='__main__':
371
- ticker="600519.SS"
500
+ ticker="AAPL"
372
501
  ticker={'Market':('US','^SPX','中概教培组合'),'EDU':0.7,'TAL':0.3}
373
502
 
374
503
  start="2024-1-1"
375
- end="2024-3-15"
504
+ end="2024-6-30"
376
505
  rar_name="alpha"
377
- ret_type="Exp Ret%"
378
- RF=0.01759
506
+ ret_type="Exp Adj Ret%"
507
+ RF=0.055
379
508
  regression_period=365
380
509
  mktidx='auto'; source='auto'
381
510
 
@@ -384,13 +513,14 @@ if __name__=='__main__':
384
513
 
385
514
 
386
515
  def get_expanding_treynor_alpha(ticker,start,end,rar_name="alpha", \
387
- ret_type="Exp Ret%",RF=0, \
516
+ ret_type="Exp Adj Ret%",RF=0, \
388
517
  regression_period=365,mktidx='auto',source='auto',ticker_type='auto'):
389
518
  """
390
519
  功能:获取一只股票的特雷诺比率或阿尔法指数,基于扩展收益率类型,在指定期间内
391
520
  支持股票和投资组合
392
521
  RF: 年化利率,不带百分数
393
522
  计算CAPM的期间:默认一年,252个交易日=365个日历日
523
+ ***废弃!!!收益率计算有问题
394
524
  """
395
525
  ret_type_lower=ret_type.lower()
396
526
  #计算日历日regression_period对应的交易日数
@@ -479,6 +609,109 @@ def get_expanding_treynor_alpha(ticker,start,end,rar_name="alpha", \
479
609
  return pretdf3
480
610
 
481
611
 
612
+ def get_expanding_treynor_alpha2(ticker,start,end,rar_name="alpha", \
613
+ ret_type="Exp Adj Ret%",RF=0, \
614
+ regression_period=365,mktidx='auto',source='auto',ticker_type='auto'):
615
+ """
616
+ 功能:获取一只股票的特雷诺比率或阿尔法指数,基于扩展收益率类型,在指定期间内
617
+ 支持股票和投资组合
618
+ RF: 年化利率,不带百分数
619
+ 计算CAPM的期间:默认一年,252个交易日=365个日历日
620
+ """
621
+ ret_type_lower=ret_type.lower()
622
+
623
+ #计算滚动查看需要的日期提前量:无滚动
624
+ start1=date_adjust(start,adjust=0)
625
+ #计算CAPM需要的日期提前量
626
+ start2=date_adjust(start1,adjust=-regression_period-7*2)
627
+
628
+ #判断复权价
629
+ ret_type=ret_type.title()
630
+ if ('Adj' in ret_type):
631
+ adjust='qfq'
632
+ else:
633
+ adjust=''
634
+
635
+ #抓取股价
636
+ pricedfs,found=get_price_1ticker_mixed(ticker=ticker,fromdate=start2,todate=end, \
637
+ adjust=adjust, \
638
+ source=source,ticker_type=ticker_type)
639
+ if found !='Found':
640
+ print(" #Error(get_expanding_treynor_alpha2): no records found for",ticker)
641
+ return None
642
+
643
+ #计算股票扩展收益率
644
+ rardf1s=calc_daily_return(pricedfs)
645
+ rardf2s=calc_expanding_return(pricedfs,start)
646
+
647
+ if '%' in ret_type:
648
+ RF=RF*100
649
+ RF_daily=RF/365
650
+
651
+ #增加距离开始日期的天数
652
+ date0=pd.to_datetime(rardf2s.index[0])
653
+ if 'date' not in list(rardf2s):
654
+ if 'Date' in list(rardf2s):
655
+ rardf2s['date']=rardf2s['Date']
656
+ else:
657
+ rardf2s['date']=rardf2s.index
658
+
659
+ rardf2s['days']=rardf2s['date'].apply(lambda x: days_between_dates(date0,pd.to_datetime(x)))
660
+ rardf2s[ret_type+'_RP']=rardf2s.apply(lambda x: x[ret_type] - RF_daily*x['days'],axis=1)
661
+
662
+ #抓取指数
663
+ if isinstance(ticker,dict):
664
+ _,mktidx,pftickerlist,_,ticker_type=decompose_portfolio(ticker)
665
+ if 'auto' in mktidx.lower():
666
+ mktidx=get_market_index_code(pftickerlist[0])
667
+ else:
668
+ if 'auto' in mktidx.lower():
669
+ mktidx=get_market_index_code(ticker)
670
+
671
+ marketdf,found=get_price_1ticker_mixed(ticker=mktidx,fromdate=start2,todate=end, \
672
+ adjust=adjust, \
673
+ source=source,ticker_type=ticker_type)
674
+ if found !='Found':
675
+ print(" #Error(get_expanding_treynor_alpha2): no records found for",mktidx)
676
+ return None
677
+
678
+ #计算指数扩展收益率
679
+ rardf1m=calc_daily_return(marketdf)
680
+ rardf2m=calc_expanding_return(marketdf,start)
681
+ #增加距离开始日期的天数
682
+ date0=pd.to_datetime(rardf2m.index[0])
683
+ if 'date' not in list(rardf2m):
684
+ if 'Date' in list(rardf2m):
685
+ rardf2m['date']=rardf2m['Date']
686
+ else:
687
+ rardf2m['date']=rardf2m.index
688
+
689
+ rardf2m['days']=rardf2m['date'].apply(lambda x: days_between_dates(date0,pd.to_datetime(x)))
690
+ rardf2m[ret_type+'_RP']=rardf2m.apply(lambda x: x[ret_type] - RF_daily*x['days'],axis=1)
691
+
692
+ #计算日历日regression_period对应的交易日数
693
+ regtrddays=int(252 / 365 * regression_period)
694
+ #CAPM回归,计算贝塔系数
695
+ reg_result,dretdf3=regression_capm_df(rardf1m,rardf1s,mktidx=mktidx,adjust=adjust,RF=RF,regtrddays=regtrddays)
696
+
697
+ #合成扩展收益率与贝塔系数:_x为指数收益率,_y为股票收益率,_RP为股票风险溢价
698
+ pretdfms=pd.merge(rardf2m[[ret_type,ret_type+'_RP','days']],rardf2s[[ret_type,ret_type+'_RP']],how='inner',left_index=True,right_index=True)
699
+ pretdf1=pd.merge(pretdfms,reg_result,how='inner',left_index=True,right_index=True)
700
+
701
+ #计算特雷诺比率和阿尔法指标
702
+ if 'treynor' in rar_name.lower():
703
+ pretdf1[rar_name]=pretdf1.apply(lambda x: x[ret_type+'_RP_y']/x['beta'],axis=1)
704
+ elif 'alpha' in rar_name.lower():
705
+ vary_pred=ret_type+'_y_pred'
706
+ pretdf1[vary_pred]=pretdf1.apply(lambda x: RF_daily*x['days']+x['beta']*x[ret_type+'_RP_x'],axis=1)
707
+ pretdf1[rar_name]=pretdf1.apply(lambda x: x[ret_type+'_y']-x[vary_pred],axis=1)
708
+
709
+ if '%' in ret_type:
710
+ pretdf1[rar_name]=pretdf1[rar_name]/100
711
+
712
+ pretdf3=pretdf1[[rar_name,'beta']]
713
+
714
+ return pretdf3
482
715
  #==============================================================================
483
716
  if __name__=='__main__':
484
717
  ticker="600519.SS"
@@ -524,7 +757,7 @@ def get_rar(ticker,start,end,rar_name="sharpe",ret_type="Monthly Ret%", \
524
757
  ret_type=ret_type_title,RF=RF, \
525
758
  source=source,ticker_type=ticker_type)
526
759
  elif ('alpha' in rar_name_lower) or ('treynor' in rar_name_lower):
527
- rardf=get_rolling_treynor_alpha(ticker=ticker,start=start,end=end, \
760
+ rardf=get_rolling_treynor_alpha2(ticker=ticker,start=start,end=end, \
528
761
  rar_name=rar_name_lower, \
529
762
  ret_type=ret_type_title,RF=RF, \
530
763
  regression_period=regression_period, \
@@ -537,7 +770,7 @@ def get_rar(ticker,start,end,rar_name="sharpe",ret_type="Monthly Ret%", \
537
770
  ret_type=ret_type_title,RF=RF, \
538
771
  source=source,ticker_type=ticker_type)
539
772
  elif ('alpha' in rar_name_lower) or ('treynor' in rar_name_lower):
540
- rardf=get_expanding_treynor_alpha(ticker=ticker,start=start,end=end, \
773
+ rardf=get_expanding_treynor_alpha2(ticker=ticker,start=start,end=end, \
541
774
  rar_name=rar_name_lower, \
542
775
  ret_type=ret_type_title,RF=RF, \
543
776
  regression_period=regression_period, \
@@ -633,15 +866,21 @@ def compare_1ticker_mrar(ticker,start,end,rar=['sharpe','sortino','treynor','alp
633
866
 
634
867
  df1.rename(columns={c:ectranslate(c)},inplace=True)
635
868
 
636
- footnote1="注:基于"+ectranslate(ret_type)+""
869
+ footnote1=text_lang("注:基于","Note: RaR based on ")+ectranslate(ret_type)+text_lang("",". ")
637
870
  if RF !=0:
638
- footnote2="年化无风险利率为"+str(round(RF*100,4))+text_lang('%。','%')
871
+ footnote2=text_lang("年化无风险利率为","RF = ")+str(round(RF*100,4))+text_lang('%。','% pa')
639
872
  else:
640
- footnote2="不考虑年化无风险利率时。"
873
+ footnote2=text_lang("不考虑年化无风险利率时。","RF = 0 pa")
641
874
 
642
875
  footnote3=''
643
876
  if 'treynor' in rar or 'alpha' in rar:
644
- footnote3="贝塔系数回归期间"+str(regression_period)+"个自然日"
877
+ if mktidx != 'auto':
878
+ mktidx_text=ticker_name(mktidx)
879
+ footnote3x=text_lang(",市场指数基于",", using ")+mktidx_text
880
+ footnote3=text_lang("\nCAPM回归期间","\nCAPM rolling ")+str(regression_period)+text_lang("个自然日"," days, ")+footnote3x
881
+ else:
882
+ footnote3=text_lang("CAPM回归期间",", CAPM rolling ")+str(regression_period)+text_lang("个自然日"," days")
883
+
645
884
 
646
885
  import datetime; todaydt = datetime.date.today()
647
886
  footnote4=text_lang("数据来源: 综合新浪/Stooq/Yahoo,","Data source: Sina/Stooq/Yahoo, ")+str(todaydt)
@@ -661,7 +900,7 @@ def compare_1ticker_mrar(ticker,start,end,rar=['sharpe','sortino','treynor','alp
661
900
  axhline_value=axhline_value,axhline_label=axhline_label, \
662
901
  title_txt=title_txt,data_label=False, \
663
902
  annotate=annotate,annotate_value=annotate, \
664
- mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end, \
903
+ mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end, \
665
904
  facecolor=facecolor,loc=loc1)
666
905
 
667
906
  #制表
@@ -679,10 +918,10 @@ def compare_1ticker_mrar(ticker,start,end,rar=['sharpe','sortino','treynor','alp
679
918
  sortby_txt=text_lang('按推荐标记+短期均值走势降序排列',"by Recommend + Recent Trend, Descending")
680
919
 
681
920
  #title_txt='***** 风险调整收益评估:'+tname+','+sortby_txt+' *****'
682
- title_txt=text_lang('风险调整收益评估:基于',"Risk-adjusted Return Evaluation: Based on ")+ectranslate(rar)+text_lang(',',', ')+sortby_txt
921
+ title_txt=text_lang('风险调整收益评估:',"RaR Evaluation: ")+ectranslate(rar)+text_lang(',',', ')+sortby_txt
683
922
 
684
- footnote6=text_lang('期间为',"Period: ")+str(start)+text_lang('至'," to ")+str(end)+text_lang(";近期指近","; Recent = ")+str(trailing)+text_lang("个交易日。趋势变化率阈值:", " days. Trend threshhold ")+str(trend_threshold)
685
- footnote7=text_lang("近期优先趋势和星号为风险调整收益指标加趋势等多项因素综合研判,最多五颗星","Recommend max 5 stars. RWA = Recent Weighted Average")
923
+ footnote6=text_lang('期间为',"Period: ")+str(start)+text_lang('至'," to ")+str(end)+text_lang(";近期指近","\nRecent trend: ")+str(trailing)+text_lang("个交易日。趋势变化率阈值:", " days. Trend threshhold ")+str(trend_threshold)
924
+ footnote7=text_lang("近期优先趋势和星号为风险调整收益指标加趋势等多项因素综合研判,最多五颗星","Recommend max 5 stars. RWA = Recent-priority Weighted Average")
686
925
  footnotey=footnote6+footnote7+'\n'+footnotex
687
926
 
688
927
  recommenddf=descriptive_statistics2(df1,title_txt,footnotey,decimals=4, \
@@ -801,12 +1040,15 @@ def compare_mticker_1rar(ticker,start,end,rar='sharpe', \
801
1040
  #rar_text=rar_text.title()
802
1041
  rar_text="Jensen Alpha"
803
1042
 
804
- footnote1=text_lang("注:","")+rar_text.capitalize()+text_lang("基于"," is based on ")+ectranslate(ret_type)+text_lang("。",", ")
1043
+ footnote1=text_lang("注:","Note: ")+rar_text.capitalize()+text_lang("基于"," based on ")+ectranslate(ret_type)+text_lang("。",", ")
1044
+ """
805
1045
  if RF !=0:
806
- footnote2=text_lang("年化无风险利率","annual RF = ")+str(round(RF*100,4))+text_lang('%。','%')
1046
+ footnote2=text_lang("年化无风险利率","RF = ")+str(round(RF*100,4))+text_lang('%。','% pa')
807
1047
  else:
808
- footnote2=text_lang("假设年化无风险利率为零。","assuming annual RF = 0.")
809
-
1048
+ footnote2=text_lang("假设年化无风险利率为零。","assuming RF = 0 pa.")
1049
+ """
1050
+ footnote2=text_lang("年化无风险利率","RF = ")+str(round(RF*100,4))+text_lang('%。','% pa')
1051
+
810
1052
  footnote3=''
811
1053
  if rar.lower() in ['treynor','alpha']:
812
1054
  mktidx_text=''
@@ -814,10 +1056,10 @@ def compare_mticker_1rar(ticker,start,end,rar='sharpe', \
814
1056
  mktidx_text=ticker_name(mktidx)
815
1057
 
816
1058
  if mktidx != 'auto':
817
- footnote3=text_lang("CAPM回归期间","\nCAPM regression period ")+str(regression_period)+text_lang("个自然日,"," days, ")+ \
1059
+ footnote3=text_lang("CAPM回归期间","\nCAPM rolling ")+str(regression_period)+text_lang("个自然日,"," days, ")+ \
818
1060
  text_lang("市场指数基于","using ")+mktidx_text
819
1061
  else:
820
- footnote3=text_lang("CAPM回归期间","\nCAPM regression period ")+str(regression_period)+text_lang("个自然日"," days")
1062
+ footnote3=text_lang("CAPM回归期间","\nCAPM rolling ")+str(regression_period)+text_lang("个自然日"," days")
821
1063
 
822
1064
  import datetime; todaydt = datetime.date.today()
823
1065
  footnote4=text_lang("数据来源: 综合新浪/Stooq/Yahoo,","Data source: Sina/Stooq/Yahoo, ")+str(todaydt)
@@ -854,10 +1096,10 @@ def compare_mticker_1rar(ticker,start,end,rar='sharpe', \
854
1096
  sortby_txt=text_lang('按推荐标记+短期均值走势降序排列',"by Recommend + Recent Trend, Descending")
855
1097
 
856
1098
  #title_txt='***** 风险调整收益评估:基于'+ectranslate(rar)+','+sortby_txt+' *****'
857
- title_txt=text_lang('风险调整收益评估:基于',"Risk-adjusted Return Evaluation: Based on ")+rar_text+text_lang(',',', ')+sortby_txt
1099
+ title_txt=text_lang('风险调整收益评估:',"RaR Evaluation: ")+rar_text+text_lang(',',', ')+sortby_txt
858
1100
 
859
- footnote6=text_lang('期间为',"Period: ")+str(start)+text_lang('至'," to ")+str(end)+text_lang(";近期指近","; Recent = ")+str(trailing)+text_lang("个交易日。趋势变化率阈值:", " days. Trend threshhold ")+str(trend_threshhold)
860
- footnote7=text_lang("近期优先趋势和星号为风险调整收益指标加趋势等多项因素综合研判,最多五颗星","Recommend max 5 stars. RWA = Recent Weighted Average")
1101
+ footnote6=text_lang('期间为',"Period: ")+str(start)+text_lang('至'," to ")+str(end)+text_lang(";近期指近","\nRecent trend: ")+str(trailing)+text_lang("个交易日。趋势变化率阈值:", " trading days. Trend change threshhold: ")+str(trend_threshhold)
1102
+ footnote7=text_lang("近期优先趋势和星号为风险调整收益指标加趋势等多项因素综合研判,最多五颗星","Recommend max 5 stars. RWA = Recent-priority Weighted Average")
861
1103
  footnotey=footnote6+'\n'+footnote7+'\n'+footnotex
862
1104
 
863
1105
  #不能简单删除含有Nan的行,否则导致清空df1,应该进行填充
@@ -1037,18 +1279,21 @@ def compare_mticker_mrar(ticker,start,end,rar=['sharpe','alpha','sortino','treyn
1037
1279
  """
1038
1280
 
1039
1281
  #脚注
1040
- footnote1=text_lang("风险调整收益基于","Based on ")+ectranslate(ret_type)+text_lang(",",', ')
1282
+ footnote1=text_lang("风险调整收益基于","RaR based on ")+ectranslate(ret_type)+text_lang(",",', ')
1283
+ """
1041
1284
  if RF !=0:
1042
- footnote2=text_lang("年化无风险利率","annual RF = ")+str(round(RF*100,4))+'%'
1285
+ footnote2=text_lang("年化无风险利率","RF = ")+str(round(RF*100,4))+text_lang('%','% pa')
1043
1286
  else:
1044
- footnote2=text_lang("假设年化无风险利率为零","assuming annual RF = 0")
1045
-
1287
+ footnote2=text_lang("假设年化无风险利率为零","assuming RF = 0 pa")
1288
+ """
1289
+ footnote2=text_lang("年化无风险利率","RF = ")+str(round(RF*100,4))+text_lang('%','% pa')
1290
+
1046
1291
  footnote3=''
1047
1292
  if 'treynor' in rar or 'alpha' in rar:
1048
1293
  if mktidx=='auto':
1049
1294
  mktidx=get_market_index_code(ticker[0] if isinstance(ticker,list) else ticker)
1050
1295
  mktidx_name=ticker_name(mktidx)
1051
- footnote3=text_lang("CAPM基于","CAPM based on ")+mktidx_name+text_lang(",回归期间",", regression in ")+str(regression_period)+text_lang("个自然日"," days")
1296
+ footnote3=text_lang("CAPM基于","CAPM using ")+mktidx_name+text_lang(",回归期间",", rolling ")+str(regression_period)+text_lang("个自然日"," days")
1052
1297
 
1053
1298
  import datetime; todaydt = datetime.date.today()
1054
1299
  footnote4=text_lang("数据来源: 综合新浪/Stooq/Yahoo,","Data source: Sina/Stooq/Yahoo, ")+str(todaydt)+text_lang("统计",'')
@@ -1060,7 +1305,7 @@ def compare_mticker_mrar(ticker,start,end,rar=['sharpe','alpha','sortino','treyn
1060
1305
  #print("\n"+footnotex)
1061
1306
  #print(footnotex)
1062
1307
  if check_language()=="English":
1063
- df1.rename(columns={"比较对象":"Securities","sharpe":"Sharpe Ratio","sortino":"Sortino Ratio","alpha":"Jensen Alpha","treynor":"Treynor Ratio","综合推荐":"Overall Recommendation"},inplace=True)
1308
+ df1.rename(columns={"比较对象":"Securities","sharpe":"Sharpe Ratio","sortino":"Sortino Ratio","alpha":"Jensen Alpha","treynor":"Treynor Ratio","综合推荐":"Overall Recommend"},inplace=True)
1064
1309
 
1065
1310
  df_display_CSS(df1,titletxt=titletxt,footnote=footnotex,decimals=4, \
1066
1311
  first_col_align='left',second_col_align='center', \
@@ -1154,15 +1399,18 @@ def compare_1ticker_1rar_mret(ticker,start,end,rar='sharpe', \
1154
1399
  #df1.rename(columns={c:"基于"+ectranslate(c)},inplace=True)
1155
1400
 
1156
1401
  #共同脚注
1157
- footnote1="注:"
1402
+ footnote1=text_lang("注:","Note: ")
1403
+ """
1158
1404
  if RF !=0:
1159
- footnote2="年化无风险利率为"+str(round(RF*100,4))+text_lang('%。','%')
1405
+ footnote2=text_lang("年化无风险利率为","RF = ")+str(round(RF*100,4))+text_lang('%。','% pa. ')
1160
1406
  else:
1161
- footnote2=text_lang("假设年化无风险利率为零。","Assume annual RF = 0")
1162
-
1407
+ footnote2=text_lang("假设年化无风险利率为零。","Assuming RF = 0 pa")
1408
+ """
1409
+ footnote2=text_lang("年化无风险利率为","RF = ")+str(round(RF*100,4))+text_lang('%。','% pa. ')
1410
+
1163
1411
  footnote3=''
1164
1412
  if rar.lower() in ['treynor','alpha']:
1165
- footnote3="贝塔系数回归期间"+str(regression_period)+"个自然日"
1413
+ footnote3=text_lang("CAPM回归期间","CAPM rolling ")+str(regression_period)+text_lang("个自然日"," days")
1166
1414
 
1167
1415
  import datetime; todaydt = datetime.date.today()
1168
1416
  footnote4=text_lang("数据来源: 综合新浪/Stooq/Yahoo,","Data source: Sina/Stooq/Yahoo, ")+str(todaydt)
@@ -1199,10 +1447,10 @@ def compare_1ticker_1rar_mret(ticker,start,end,rar='sharpe', \
1199
1447
  sortby_txt=text_lang('按推荐标记+短期均值走势降序排列',"by Recommend + Recent Trend, Descending")
1200
1448
 
1201
1449
  #title_txt='***** 风险调整收益评估:'+'基于'+ectranslate(rar)+','+ticker_name(ticker,ticker_type)+','+sortby_txt+' *****'
1202
- title_txt=text_lang('风险调整收益评估:基于',"Risk-adjusted Return Evaluation: Based on ")+ectranslate(rar)+text_lang(',',', ')+sortby_txt
1450
+ title_txt=text_lang('风险调整收益评估:',"RaR Evaluation: ")+ectranslate(rar)+text_lang(',',', ')+sortby_txt
1203
1451
 
1204
- footnote6=text_lang('期间为',"Period: ")+str(start)+text_lang('至'," to ")+str(end)+text_lang(";近期指近","; Recent = ")+str(trailing)+text_lang("个交易日。趋势变化率阈值:", " days. Trend threshhold ")+str(trend_threshhold)
1205
- footnote7=text_lang("近期优先趋势和星号为风险调整收益指标加趋势等多项因素综合研判,最多五颗星","Recommend max 5 stars. RWA = Recent Weighted Average")
1452
+ footnote6=text_lang('期间为',"Period: ")+str(start)+text_lang('至'," to ")+str(end)+text_lang(";近期指近","\nRecent trend: ")+str(trailing)+text_lang("个交易日。趋势变化率阈值:", " days. Trend threshhold ")+str(trend_threshhold)
1453
+ footnote7=text_lang("近期优先趋势和星号为风险调整收益指标加趋势等多项因素综合研判,最多五颗星","Recommend max 5 stars. RWA = Recent-priority Weighted Average")
1206
1454
  footnotey=footnote6+footnote7+'\n'+footnotex
1207
1455
 
1208
1456
  #删除含有Nan的行
@@ -1301,7 +1549,7 @@ def compare_1ticker_1rar_1ret_mRF(ticker,start,end,rar='sharpe', \
1301
1549
  #df1.rename(columns={c:"基于无风险利率"+c},inplace=True)
1302
1550
 
1303
1551
  #共同脚注
1304
- footnote1=text_lang("注:","")+ectranslate(rar)+text_lang("基于"," is based on ")+ectranslate(ret_type)+'。'
1552
+ footnote1=text_lang("注:","Note: ")+ectranslate(rar)+text_lang("基于"," based on ")+ectranslate(ret_type)+text_lang('。','')
1305
1553
  footnote2=""
1306
1554
 
1307
1555
  footnote3=""
@@ -1343,10 +1591,10 @@ def compare_1ticker_1rar_1ret_mRF(ticker,start,end,rar='sharpe', \
1343
1591
  sortby_txt=text_lang('按推荐标记+短期均值走势降序排列',"by Recommend + Recent Trend, Descending")
1344
1592
 
1345
1593
  #title_txt='***** 风险调整收益评估:'+'基于'+ectranslate(rar)+','+ticker_name(ticker,ticker_type)+','+sortby_txt+' *****'
1346
- title_txt=text_lang('风险调整收益评估:基于',"Risk-adjusted Return Evaluation: Based on ")+ectranslate(rar)+text_lang(',',', ')+sortby_txt
1594
+ title_txt=text_lang('风险调整收益评估:',"RaR Evaluation: ")+ectranslate(rar)+text_lang(',',', ')+sortby_txt
1347
1595
 
1348
- footnote6=text_lang('期间为',"Period: ")+str(start)+text_lang('至'," to ")+str(end)+text_lang(";近期指近","; Recent = ")+str(trailing)+text_lang("个交易日。趋势变化率阈值:", " days. Trend threshhold ")+str(trend_threshhold)
1349
- footnote7=text_lang("近期优先趋势和星号为风险调整收益指标加趋势等多项因素综合研判,最多五颗星","Recommend max 5 stars. RWA = Recent Weighted Average")
1596
+ footnote6=text_lang('期间为',"Period: ")+str(start)+text_lang('至'," to ")+str(end)+text_lang(";近期指近","\nRecent trend: ")+str(trailing)+text_lang("个交易日。趋势变化率阈值:", " days. Trend threshhold ")+str(trend_threshhold)
1597
+ footnote7=text_lang("近期优先趋势和星号为风险调整收益指标加趋势等多项因素综合研判,最多五颗星","Recommend max 5 stars. RWA = Recent-priority Weighted Average")
1350
1598
  footnotey=footnote6+footnote7+'\n'+footnotex
1351
1599
 
1352
1600
  #删除含有Nan的行
siat/stock.py CHANGED
@@ -920,30 +920,31 @@ def security_mindicators(ticker,measures,
920
920
 
921
921
  df['ticker']=ticker
922
922
 
923
- # 翻译指标名称
924
- for c in list(df):
925
- df.rename(columns={c:ectranslate(c)},inplace=True)
926
-
927
- y_label=text_lang('证券指标',"Indicator")
928
- import datetime; todaydt = datetime.date.today()
929
- x_label=text_lang("数据来源:综合新浪/东方财富/stooq/yahoo,","Data source: Sina/EM/Stooq/Yahoo, ")+str(todaydt)
930
-
931
- axhline_value=0
932
- axhline_label=''
933
- for c in measures:
934
- if 'Ret%' in c:
935
- axhline_value=0
936
- axhline_label='零线'
937
- break
923
+ if graph:
924
+ # 翻译指标名称
925
+ for c in list(df):
926
+ df.rename(columns={c:ectranslate(c)},inplace=True)
927
+
928
+ y_label=text_lang('证券指标',"Indicator")
929
+ import datetime; todaydt = datetime.date.today()
930
+ x_label=text_lang("数据来源:综合新浪/东方财富/stooq/yahoo,","Data source: Sina/EM/Stooq/Yahoo, ")+str(todaydt)
931
+
932
+ axhline_value=0
933
+ axhline_label=''
934
+ for c in measures:
935
+ if 'Ret%' in c:
936
+ axhline_value=0
937
+ axhline_label='零线'
938
+ break
939
+
940
+ titletxt=text_lang("证券趋势分析:","Security Trend: ")+ticker_name(ticker,ticker_type=ticker_type)
938
941
 
939
- titletxt=text_lang("证券趋势分析:","Security Trend: ")+ticker_name(ticker,ticker_type=ticker_type)
940
-
941
- draw_lines2(df,y_label,x_label,axhline_value,axhline_label,titletxt, \
942
- data_label=False,resample_freq='6H',smooth=smooth, \
943
- date_range=date_range,date_freq=date_freq,date_fmt='%Y-%m-%d', \
944
- annotate=annotate,annotate_value=annotate_value, \
945
- mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end,facecolor=facecolor, \
946
- band_area=band_area,loc=loc)
942
+ draw_lines2(df,y_label,x_label,axhline_value,axhline_label,titletxt, \
943
+ data_label=False,resample_freq='6H',smooth=smooth, \
944
+ date_range=date_range,date_freq=date_freq,date_fmt='%Y-%m-%d', \
945
+ annotate=annotate,annotate_value=annotate_value, \
946
+ mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end,facecolor=facecolor, \
947
+ band_area=band_area,loc=loc)
947
948
 
948
949
  return df
949
950
 
siat/stock_info.pickle CHANGED
Binary file
siat/translate.py CHANGED
@@ -3108,11 +3108,22 @@ def update_all_names2files():
3108
3108
  功能:更新股票(中港美)、基金(沪深)和债券(沪深)名称至文件中(S:/siat)
3109
3109
  """
3110
3110
  print(" Updating stock names in China, China HK and US markets ... ...")
3111
- df1=update_stock_names()
3112
- print(" Updating exchange fund names in China markets ... ...")
3113
- df2=update_fund_names_china()
3114
- print(" Updating exchange bond names in China markets ... ...")
3115
- df3=update_exchange_bond_name_china()
3111
+ try:
3112
+ df1=update_stock_names()
3113
+ except:
3114
+ pass
3115
+
3116
+ print("\n Updating exchange fund names in China markets ... ...")
3117
+ try:
3118
+ df2=update_fund_names_china()
3119
+ except:
3120
+ pass
3121
+
3122
+ print("\n Updating exchange bond names in China markets ... ...")
3123
+ try:
3124
+ df3=update_exchange_bond_name_china()
3125
+ except:
3126
+ pass
3116
3127
 
3117
3128
  return
3118
3129
 
@@ -3292,6 +3303,7 @@ def ticker1_name(ticker,ticker_type='auto'):
3292
3303
  ttlist=['bond','stock','fund']
3293
3304
 
3294
3305
  #循环查询,查到则跳出
3306
+ lang=check_language()
3295
3307
  tname=symbol
3296
3308
  for tt in ttlist:
3297
3309
  #查找证券名称文件:优先股票
@@ -3302,7 +3314,10 @@ def ticker1_name(ticker,ticker_type='auto'):
3302
3314
  if '.HK' in symbol and len(symbol)==8: symbol=symbol[1:]
3303
3315
 
3304
3316
  try:
3305
- tname=df1[df1['SYMBOL']==symbol]['CNAME'].values[0]
3317
+ if lang == "Chinese":
3318
+ tname=df1[df1['SYMBOL']==symbol]['CNAME'].values[0]
3319
+ else:
3320
+ tname=df1[df1['SYMBOL']==symbol]['ENAME'].values[0]
3306
3321
  except: pass
3307
3322
  if tname != symbol: break
3308
3323
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: siat
3
- Version: 3.3.1
3
+ Version: 3.3.10
4
4
  Summary: Securities Investment Analysis Tools (siat)
5
5
  Home-page: https://pypi.org/project/siat/
6
6
  Author: Prof. WANG Dehong, International Business School, Beijing Foreign Studies University
@@ -15,10 +15,10 @@ siat/bond_china.py,sha256=eYv-nMoWSS5fZ4VxnuJ29QFY9GUS6meGiIc0Xjm1fQI,3038
15
15
  siat/bond_test.py,sha256=yUOFw7ddGU-kb1rJdnsjkJWziDNgUR7OLDA7F7Ub91A,5246
16
16
  siat/bond_zh_sina.py,sha256=26BohGcS120utwqg9dJvdGm5OkuNpNu5bco80uOuQpU,4423
17
17
  siat/capm_beta.py,sha256=cxXdRVBQBllhbfz1LeTJAIWvyRYhW54nhtNUXv4HwS0,29063
18
- siat/capm_beta2.py,sha256=d7lZ-VXVVmBkMVGDPlozL-9gAU3cYpHG23X1WSRCOgY,26907
18
+ siat/capm_beta2.py,sha256=lUuCPVSxebkA2yye1PXu1V2Jd2UKEwD_kIA25DCIDTs,29750
19
19
  siat/capm_beta_test.py,sha256=ImR0c5mc4hIl714XmHztdl7qg8v1E2lycKyiqnFj6qs,1745
20
20
  siat/cmat_commons.py,sha256=Nj9Kf0alywaztVoMVeVVL_EZk5jRERJy8R8kBw88_Tg,38116
21
- siat/common.py,sha256=VU4AhQZGQmTCcw-lbiuG7jSz7Dsy1psOi9ayaAbBDdY,151635
21
+ siat/common.py,sha256=Uc_BLjlp6njmGFBMSaM45fcHKgk9kjnKacFcFYljrmE,151620
22
22
  siat/compare_cross.py,sha256=3iP9TH2h3w27F2ARZc7FjKcErYCzWRc-TPiymOyoVtw,24171
23
23
  siat/compare_cross_test.py,sha256=xra5XYmQGEtfIZL2h-GssdH2hLdFIhG3eoCrkDrL3gY,3473
24
24
  siat/concepts_iwencai.py,sha256=m1YEDtECRT6FqtzlKm91pt2I9d3Z_XoP59BtWdRdu8I,3061
@@ -52,7 +52,7 @@ siat/financials_china_test2_fin_indicator.py,sha256=WkNlVW_0hGegdw1rzg4BP_dKR-sm
52
52
  siat/financials_test.py,sha256=HJ3CPo_Xckz2wXi3AEP6ZNWCF1Duc1pLi0Y10USiImc,23829
53
53
  siat/fred_test.py,sha256=KF50ssSbsfpa_kT6iuomD0vG4eXztAcOasZxg1OGX5w,1201
54
54
  siat/fund.py,sha256=wMDORsCBV8ZXfgwbtq-0bu3qqWY66dHnbqgllW0gWCo,24637
55
- siat/fund_china.pickle,sha256=wJIIvEjWuZylcaQ3c5kvIdKedpFF5T53cJlG-1LVoms,2410657
55
+ siat/fund_china.pickle,sha256=x_nPPdwy7wzIhtZQOplgDyTSyyUdXy9lbNxWysq7N6k,2437771
56
56
  siat/fund_china.py,sha256=rPGnYSPkbZUqtBoJnxLZLIQ8MjD8vD3TovCMfletBP4,111839
57
57
  siat/fund_china_test.py,sha256=-Bh6m0J0GPpIbYXx-H2vpzJoNFI6pE2C2jVPa8DazgE,6649
58
58
  siat/fund_test.py,sha256=V4ADb8Gsp8gyeFTwcgRsJBpnUih_O-Q2V1ILc5oKjK8,1116
@@ -67,7 +67,7 @@ siat/holding_risk_test.py,sha256=FRlw_9wFG98BYcg_cSj95HX5WZ1TvkGaOUdXD7-V86s,474
67
67
  siat/local_debug_test.py,sha256=CDAOffW1Rvs-TcNN5giWVvHMlch1w4dp-w5SIV9jXL0,3936
68
68
  siat/luchy_draw.py,sha256=8Ue-NKnvSVqINPY1eXat0NJat5MR-gex_K62aOYFdmA,20486
69
69
  siat/market_china.py,sha256=EOO-RvdnzJThTrgNHWW3TlWhx4k4rfdjbooOnQsYdQU,50299
70
- siat/markowitz.py,sha256=glHikhabFAF6Hb6df1pYfhkxid2IZXBYAVQng5wd9Wk,97526
70
+ siat/markowitz.py,sha256=DsfS6vG9TAfdJP4GgN-CCArujPi84XjD23CWbxaA2o4,97627
71
71
  siat/markowitz2-20240620.py,sha256=irZAPnjaatFsKQmFRMENP-cO6bEUl2narYtkU5NKTWI,108019
72
72
  siat/markowitz2.py,sha256=oStv4V74OiqBk-rnBPo6QJTUSNe1FCyT1Yl6-Fx_mHc,113934
73
73
  siat/markowitz_ccb_test.py,sha256=xBkkoaNHdq9KSUrNuHGgKTdNYUvgi84kNYcf719eoyE,1593
@@ -88,7 +88,7 @@ siat/option_sina_api_test.py,sha256=dn-k_wrQnAaNKHoROvWJEc7lqlU0bwiV2Aa4usWAFGM,
88
88
  siat/proxy_test.py,sha256=erQJrmGs2X46z8Gb1h-7GYQ0rTUcaR8dxHExWoBz2eM,2610
89
89
  siat/quandl_test.py,sha256=EcPoXnLuqzPl5dKyVEZi3j3PJZFpsnU_iNPhLWC9p-A,1552
90
90
  siat/risk_adjusted_return.py,sha256=oRUOagpQlGB56R1xIHZoYwAi42RqcZl0R-JCVBCKVe0,55086
91
- siat/risk_adjusted_return2.py,sha256=_ZJvinGmURdT37vgEtpd0DJIAI23HlC02oEmv_By4mA,70523
91
+ siat/risk_adjusted_return2.py,sha256=Gdbgn_mIeNnPnUL89pss6c9gDtrNQqWCx7HBlQdpEQo,80800
92
92
  siat/risk_adjusted_return_test.py,sha256=m_VHL5AtT74cJv5i7taTeTfnkX48y0AFJk5phawyYWg,3416
93
93
  siat/risk_evaluation.py,sha256=I6B3gty-t--AkDCO0tKF-291YfpnF-IkXcFjqNKCt9I,76286
94
94
  siat/risk_evaluation_test.py,sha256=YEXM96gKzTfwN4U61AS4Rr1tV7KgUvn4rRC6f3iMw9s,3731
@@ -105,12 +105,12 @@ siat/security_trend2-20240620.py,sha256=QVnEcb7AyVbO77jVqfFsJffGXrX8pgJ9xCfoAKmW
105
105
  siat/security_trend2.py,sha256=lUMab8HilXIUPo_z9ZkztMiZ5kf3jAbbCwPPkYbQ1TI,25288
106
106
  siat/setup.py,sha256=up65rQGLmTBkhtaMLowjoQXYmIsnycnm4g1SYmeQS6o,1335
107
107
  siat/shenwan index history test.py,sha256=JCVAzOSEldHalhSFa3pqD8JI_8_djPMQOxpkuYU-Esg,1418
108
- siat/stock.py,sha256=D8S2nAeDOdGv4EymfIH1rZnWGNV82sJgYA4wb88f0nI,152460
108
+ siat/stock.py,sha256=cKtez5i9G143rSw7rRll6rRIFTWnQ3RaHF7CVnu7qk8,152571
109
109
  siat/stock_advice_linear.py,sha256=-twT7IGP-NEplkL1WPSACcNJjggRB2j4mlAQCkzOAuo,31655
110
110
  siat/stock_base.py,sha256=uISvbRyOGy8p9QREA96CVydgflBkn5L3OXOGKl8oanc,1312
111
111
  siat/stock_china.py,sha256=zyUyghIrkkkYWlHRRP7Hoblxzfp-jrck60pTJpwMahg,91553
112
112
  siat/stock_china_test.py,sha256=eO4HWsSvc6qezl0LndjtL24lViEyrBjH_sx2c2Y2Q2M,1294
113
- siat/stock_info.pickle,sha256=YZJmavrPmKC6DrHlE-aCTBQwnV-G2ozYiLB_p0j8gao,1310060
113
+ siat/stock_info.pickle,sha256=XqcFwQrXoBXAzZnE6rnfpI7zETXZS2usqzsx2ff7MEg,1319005
114
114
  siat/stock_info_test.py,sha256=gfG3DbhDACbtD8wnv_R6zhj0t11XaC8NX8uLD9Qv3Fo,6122
115
115
  siat/stock_list_china_test.py,sha256=gv14UwMMvkZqtb6G7DCTSuehIwVHuVwu7w60p6gyHoo,1014
116
116
  siat/stock_prices_kneighbors.py,sha256=WfZvo5EyeBsm-T37zDj7Sl9dPSRq5Bx4JxIJ9IUum6s,36738
@@ -131,7 +131,7 @@ siat/transaction_test.py,sha256=Z8g1LJCN4-mnUByXMUMoFmN0t105cbmsz2QmvSuIkbU,1858
131
131
  siat/translate-20230125.py,sha256=NPPSXhT38s5t9fzMvl_fvi4ckSB73ThLmZetVI-xGdU,117953
132
132
  siat/translate-20230206.py,sha256=-vtI125WyaJhmPotOpDAmclt_XnYVaWU9ByLWZ6FyYE,118133
133
133
  siat/translate-20230215.py,sha256=TJgtPE3n8IjljmZ4Pefy8dmHoNdFF-1zpML6BhA9FKE,121657
134
- siat/translate.py,sha256=GjuJTXsZKpmAEtljUxs1T-TT-aGZ726zWCAqQM03ElU,217888
134
+ siat/translate.py,sha256=_3fOZozd4RsJGJaITSn7Kil4PvmQFGpKVKHbcLRiBZI,218193
135
135
  siat/translate_20240606.py,sha256=63IyHWEU3Uz9mjwyuAX3fqY4nUMdwh0ICQAgmgPXP7Y,215121
136
136
  siat/universal_test.py,sha256=CDAOffW1Rvs-TcNN5giWVvHMlch1w4dp-w5SIV9jXL0,3936
137
137
  siat/valuation.py,sha256=NKfeZMdDJOW42oLVHob6eSVBXUqlN1OCnnzwyGAst8c,48855
@@ -139,7 +139,7 @@ siat/valuation_china.py,sha256=EkZQaVkoBjM0c4MCNbaX-bMnlG0e3FXeaWczZDnkptU,67784
139
139
  siat/valuation_market_china_test.py,sha256=gbJ0ioauuo4koTPH6WKUkqcXiQPafnbhU5eKJ6lpdLA,1571
140
140
  siat/var_model_validation.py,sha256=R0caWnuZarrRg9939hxh3vJIIpIyPfvelYmzFNZtPbo,14910
141
141
  siat/yf_name.py,sha256=H1EM8YYXA8nQHIqsJlso0I3HKPiJLT3QujO4gRVQXWs,13945
142
- siat-3.3.1.dist-info/METADATA,sha256=vdhsH9jtHlGhPaJ_YFcUYY7skJN7j4b663c9NWnTQRg,7309
143
- siat-3.3.1.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
144
- siat-3.3.1.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
145
- siat-3.3.1.dist-info/RECORD,,
142
+ siat-3.3.10.dist-info/METADATA,sha256=P7aiODOfU2l5p8yo_YUAiCS6vm5qQAGiM_iZdCRs79Y,7310
143
+ siat-3.3.10.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
144
+ siat-3.3.10.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
145
+ siat-3.3.10.dist-info/RECORD,,
File without changes