siat 3.10.25__py3-none-any.whl → 3.10.75__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/bond.py +57 -23
- siat/capm_beta.py +2 -1
- siat/capm_beta2.py +34 -3
- siat/common.py +7 -1
- siat/economy.py +3 -3
- siat/fama_french.py +99 -8
- siat/financials.py +52 -16
- siat/fund_china.py +46 -17
- siat/future_china.py +47 -59
- siat/grafix.py +218 -155
- siat/market_china.py +2 -1
- siat/option_china.py +49 -15
- siat/option_pricing.py +13 -6
- siat/risk_adjusted_return.py +105 -54
- siat/risk_adjusted_return2.py +3 -1
- siat/risk_evaluation.py +46 -5
- siat/sector_china.py +12 -2
- siat/security_prices.py +6 -5
- siat/security_trend2.py +11 -11
- siat/stock.py +6 -3
- siat/translate.py +2 -1
- {siat-3.10.25.dist-info → siat-3.10.75.dist-info}/METADATA +1 -1
- {siat-3.10.25.dist-info → siat-3.10.75.dist-info}/RECORD +26 -26
- {siat-3.10.25.dist-info → siat-3.10.75.dist-info}/LICENSE +0 -0
- {siat-3.10.25.dist-info → siat-3.10.75.dist-info}/WHEEL +0 -0
- {siat-3.10.25.dist-info → siat-3.10.75.dist-info}/top_level.txt +0 -0
siat/bond.py
CHANGED
@@ -201,12 +201,14 @@ if __name__=='__main__':
|
|
201
201
|
|
202
202
|
|
203
203
|
#==============================================================================
|
204
|
-
def interbank_bond_quote(
|
204
|
+
def interbank_bond_quote(rank=10,option='1'):
|
205
205
|
"""
|
206
206
|
功能:获得银行间债券市场现券报价
|
207
207
|
输入:从头开始显示的个数num;选项option:默认1按照收益率从高到低排列,
|
208
208
|
2按照发行时间从早到晚排列,3按照报价机构排列。其他选项按照默认排列。
|
209
209
|
"""
|
210
|
+
num=rank
|
211
|
+
|
210
212
|
#抓取银行间市场债券报价
|
211
213
|
import akshare as ak
|
212
214
|
try:
|
@@ -230,8 +232,8 @@ def interbank_bond_quote(num,option='1'):
|
|
230
232
|
df.sort_values(by=['报价机构'],ascending=[True],inplace=True)
|
231
233
|
optiontxt=texttranslate("报价机构排序")
|
232
234
|
#重新索引
|
233
|
-
df.reset_index(drop=True)
|
234
|
-
|
235
|
+
df.reset_index(drop=True,inplace=True)
|
236
|
+
"""
|
235
237
|
print("\n"+texttranslate("中国银行间市场债券现券即时报价")+"("+optiontxt+texttranslate(",前")+str(num)+texttranslate("名)"))
|
236
238
|
import pandas as pd
|
237
239
|
pd.set_option('display.unicode.ambiguous_as_wide', True)
|
@@ -243,6 +245,14 @@ def interbank_bond_quote(num,option='1'):
|
|
243
245
|
today = datetime.date.today().strftime("%Y-%m-%d")
|
244
246
|
footnote="\n"+texttranslate("数据来源:中国银行间市场交易商协会(NAFMII),")+today
|
245
247
|
print(footnote)
|
248
|
+
"""
|
249
|
+
titletxt=texttranslate("中国银行间市场债券现券即时报价")+"("+optiontxt+texttranslate(",前")+str(num)+texttranslate("名)")
|
250
|
+
import datetime
|
251
|
+
todaydt = datetime.date.today().strftime("%Y-%m-%d")
|
252
|
+
footnote="\n"+texttranslate("数据来源:中国银行间市场交易商协会(NAFMII),")+str(todaydt)
|
253
|
+
df_display_CSS(df.head(num),titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=2, \
|
254
|
+
first_col_align='left',second_col_align='left', \
|
255
|
+
last_col_align='center',other_col_align='center')
|
246
256
|
|
247
257
|
return df
|
248
258
|
|
@@ -383,7 +393,7 @@ if __name__=='__main__':
|
|
383
393
|
num=10
|
384
394
|
option='1'
|
385
395
|
|
386
|
-
def interbank_bond_deal(
|
396
|
+
def interbank_bond_deal(rank=10,option='1'):
|
387
397
|
"""
|
388
398
|
功能:获得银行间债券市场现券成交行情
|
389
399
|
输入:从头开始显示的个数num;选项option:默认1按照收益率从高到低排列,
|
@@ -391,6 +401,8 @@ def interbank_bond_deal(num,option='1'):
|
|
391
401
|
5按照涨跌幅从低到高。
|
392
402
|
其他选项按照默认排列。
|
393
403
|
"""
|
404
|
+
num=rank
|
405
|
+
|
394
406
|
#抓取银行间市场债券报价,需要akshare-1.4.47版及以后
|
395
407
|
import akshare as ak
|
396
408
|
df=ak.bond_spot_deal()
|
@@ -492,17 +504,21 @@ def interbank_bond_deal(num,option='1'):
|
|
492
504
|
else:
|
493
505
|
df1=df[collist].tail(-num)
|
494
506
|
|
507
|
+
# 输出表格标题
|
495
508
|
if lang == 'Chinese':
|
496
509
|
if num > 0:
|
497
|
-
print("\n=== 全国银行间债券市场现券成交状况当前快照("+optiontxt+",前"+str(num)+"名)\n")
|
510
|
+
#print("\n=== 全国银行间债券市场现券成交状况当前快照("+optiontxt+",前"+str(num)+"名)\n")
|
511
|
+
titletxt="全国银行间债券市场现券成交状况当前快照("+optiontxt+",前"+str(num)+"名)"
|
498
512
|
else:
|
499
|
-
print("\n=== 全国银行间债券市场现券成交状况当前快照("+optiontxt+",后"+str(-num)+"名)\n")
|
500
|
-
|
513
|
+
#print("\n=== 全国银行间债券市场现券成交状况当前快照("+optiontxt+",后"+str(-num)+"名)\n")
|
514
|
+
titletxt="全国银行间债券市场现券成交状况当前快照("+optiontxt+",后"+str(-num)+"名)"
|
501
515
|
else:
|
502
516
|
if num > 0:
|
503
|
-
print("\n=== Interbank Bond Market: Deal Price ("+optiontxt+", Top "+str(num)+")\n")
|
517
|
+
#print("\n=== Interbank Bond Market: Deal Price ("+optiontxt+", Top "+str(num)+")\n")
|
518
|
+
titletxt="Interbank Bond Market: Deal Price ("+optiontxt+", Top "+str(num)+")"
|
504
519
|
else:
|
505
|
-
print("\n=== Interbank Bond Market: Deal Price ("+optiontxt+", Bottom "+str(-num)+")\n")
|
520
|
+
#print("\n=== Interbank Bond Market: Deal Price ("+optiontxt+", Bottom "+str(-num)+")\n")
|
521
|
+
titletxt="Interbank Bond Market: Deal Price ("+optiontxt+", Bottom "+str(-num)+")"
|
506
522
|
|
507
523
|
"""
|
508
524
|
import pandas as pd
|
@@ -524,18 +540,24 @@ def interbank_bond_deal(num,option='1'):
|
|
524
540
|
df1.reset_index(drop=True,inplace=True)
|
525
541
|
df1.index=df1.index + 1
|
526
542
|
|
543
|
+
"""
|
527
544
|
numOfCol=len(list(df1))
|
528
545
|
alignlist=['right','left']+['center']*(numOfCol - 1)
|
529
546
|
print(df1.to_markdown(index=True,tablefmt='plain',colalign=alignlist))
|
530
|
-
|
547
|
+
"""
|
531
548
|
import datetime as dt
|
532
549
|
nowstr0=str(dt.datetime.now())
|
533
550
|
nowstr=nowstr0[:19]
|
534
551
|
|
535
552
|
if lang == 'Chinese':
|
536
|
-
print("\n*** 数据来源:全国银行间同业拆借中心,统计时间,",nowstr)
|
553
|
+
#print("\n*** 数据来源:全国银行间同业拆借中心,统计时间,",nowstr)
|
554
|
+
footnote="数据来源:全国银行间同业拆借中心,统计时间, "+str(nowstr)
|
537
555
|
else:
|
538
|
-
print("\n*** Data source:NAFMII. Delayed information,",nowstr)
|
556
|
+
#print("\n*** Data source:NAFMII. Delayed information,",nowstr)
|
557
|
+
footnote="Data source:NAFMII. Delayed information, "+str(nowstr)
|
558
|
+
df_display_CSS(df1,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=2, \
|
559
|
+
first_col_align='left',second_col_align='center', \
|
560
|
+
last_col_align='center',other_col_align='center')
|
539
561
|
|
540
562
|
return df
|
541
563
|
|
@@ -564,15 +586,18 @@ if __name__=='__main__':
|
|
564
586
|
num=10
|
565
587
|
option='1'
|
566
588
|
|
567
|
-
def exchange_bond_deal(
|
589
|
+
def exchange_bond_deal(rank=10,option='1'):
|
568
590
|
"""
|
569
591
|
功能:获得沪深债券市场现券成交行情
|
570
|
-
输入:从头开始显示的个数num
|
592
|
+
输入:从头开始显示的个数num;
|
593
|
+
选项option:默认1按照交易时间排列,
|
571
594
|
2按照发行时间从早到晚排列,3按照发行时间从晚到早排列,4按照涨跌幅从高到低,
|
572
595
|
5按照涨跌幅从低到高,6按照成交量从高到低排列,7按照成交量从低到高排列。
|
573
596
|
其他选项按照默认排列。
|
574
597
|
"""
|
575
|
-
|
598
|
+
num=rank
|
599
|
+
|
600
|
+
print(" Searching data, may take long time ...")
|
576
601
|
#定义标准输出关闭类,在Spyder中无效
|
577
602
|
import os, sys
|
578
603
|
class HiddenPrints:
|
@@ -671,22 +696,31 @@ def exchange_bond_deal(num,option='1'):
|
|
671
696
|
'涨跌幅':'Change%','昨收':'Last Close','成交量':'Volume'})
|
672
697
|
|
673
698
|
if lang=='Chinese':
|
674
|
-
print("\n"+texttranslate("交易所市场债券成交价(")+optiontxt+texttranslate(",前")+str(num)+texttranslate("名)"))
|
699
|
+
#print("\n"+texttranslate("交易所市场债券成交价(")+optiontxt+texttranslate(",前")+str(num)+texttranslate("名)"))
|
700
|
+
titletxt=texttranslate("交易所市场债券成交价(")+optiontxt+texttranslate(",前")+str(num)+texttranslate("名)")
|
675
701
|
else:
|
676
|
-
print("\nExchange Bond Market: Deal Price ("+optiontxt+", Top"+str(num)+")\n")
|
677
|
-
|
702
|
+
#print("\nExchange Bond Market: Deal Price ("+optiontxt+", Top"+str(num)+")\n")
|
703
|
+
titletxt="Exchange Bond Market: Deal Price ("+optiontxt+", Top"+str(num)+")"
|
704
|
+
|
705
|
+
"""
|
678
706
|
pd.set_option('display.unicode.ambiguous_as_wide', True)
|
679
707
|
pd.set_option('display.unicode.east_asian_width', True)
|
680
708
|
pd.set_option('display.width', 200) # 设置打印宽度(**重要**)
|
681
709
|
print(df2.head(num).to_string(index=False))
|
682
|
-
|
710
|
+
"""
|
683
711
|
import datetime
|
684
|
-
|
712
|
+
todaydt = datetime.date.today().strftime("%Y-%m-%d")
|
685
713
|
if lang=='Chinese':
|
686
|
-
footnote="\n"+texttranslate("数据来源:新浪财经,")+today
|
714
|
+
#footnote="\n"+texttranslate("数据来源:新浪财经,")+today
|
715
|
+
footnote=texttranslate("数据来源:新浪财经,")+str(todaydt)
|
687
716
|
else:
|
688
|
-
footnote="\n"+texttranslate("Source: Sina Finance, ")+today
|
689
|
-
|
717
|
+
#footnote="\n"+texttranslate("Source: Sina Finance, ")+today
|
718
|
+
footnote=texttranslate("Source: Sina Finance, ")+str(todaydt)
|
719
|
+
#print(footnote)
|
720
|
+
|
721
|
+
df_display_CSS(df2.head(num),titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=3, \
|
722
|
+
first_col_align='left',second_col_align='left', \
|
723
|
+
last_col_align='center',other_col_align='center')
|
690
724
|
|
691
725
|
return df1
|
692
726
|
|
siat/capm_beta.py
CHANGED
@@ -128,7 +128,7 @@ def prepare_capm_data(stkcd,mktidx,start,end):
|
|
128
128
|
return R
|
129
129
|
|
130
130
|
#==============================================================================
|
131
|
-
def capm_beta(ticker,mktidx,start,end):
|
131
|
+
def capm_beta(ticker,mktidx,start,end='today'):
|
132
132
|
"""
|
133
133
|
函数功能:计算一只股票的静态CAPM模型贝塔系数
|
134
134
|
输入参数:
|
@@ -140,6 +140,7 @@ def capm_beta(ticker,mktidx,start,end):
|
|
140
140
|
显示CAPM市场模型回归的alpha, beta, 以及显著性和拟合优度
|
141
141
|
无返回数据
|
142
142
|
"""
|
143
|
+
start,end=start_end_preprocess(start,end)
|
143
144
|
|
144
145
|
#读取股价并准备好收益率数据
|
145
146
|
R=prepare_capm_data(ticker,mktidx,start,end)
|
siat/capm_beta2.py
CHANGED
@@ -451,7 +451,7 @@ def compare_mticker_1beta(ticker,start,end, \
|
|
451
451
|
annotate=annotate,annotate_value=annotate, \
|
452
452
|
mark_top=mark_top,mark_bottom=mark_bottom, \
|
453
453
|
mark_start=mark_start,mark_end=mark_end, \
|
454
|
-
facecolor=facecolor,loc=loc)
|
454
|
+
facecolor=facecolor,loc=loc,precision=4)
|
455
455
|
|
456
456
|
return df
|
457
457
|
|
@@ -590,7 +590,8 @@ def compare_1ticker_mRF(ticker,start,end, \
|
|
590
590
|
annotate=annotate,annotate_value=annotate, \
|
591
591
|
mark_top=mark_top,mark_bottom=mark_bottom, \
|
592
592
|
mark_start=mark_start,mark_end=mark_end, \
|
593
|
-
facecolor=facecolor,loc=loc
|
593
|
+
facecolor=facecolor,loc=loc, \
|
594
|
+
precision=4)
|
594
595
|
|
595
596
|
return df
|
596
597
|
|
@@ -723,7 +724,7 @@ def compare_1ticker_mregression_period(ticker,start,end, \
|
|
723
724
|
annotate=annotate,annotate_value=annotate, \
|
724
725
|
mark_top=mark_top,mark_bottom=mark_bottom, \
|
725
726
|
mark_start=mark_start,mark_end=mark_end, \
|
726
|
-
facecolor=facecolor,loc=loc)
|
727
|
+
facecolor=facecolor,loc=loc,precision=4)
|
727
728
|
|
728
729
|
return df
|
729
730
|
|
@@ -749,6 +750,36 @@ if __name__=='__main__':
|
|
749
750
|
|
750
751
|
betas=compare_beta_security(ticker,start,end,RF)
|
751
752
|
|
753
|
+
def compare_beta(ticker,start,end, \
|
754
|
+
adjust='qfq', \
|
755
|
+
RF=0,regression_period=365, \
|
756
|
+
attention_value='',attention_value_area='', \
|
757
|
+
attention_point='',attention_point_area='', \
|
758
|
+
band_area='', \
|
759
|
+
graph=True,facecolor='whitesmoke', \
|
760
|
+
annotate=False,annotate_value=False, \
|
761
|
+
mark_high=False,mark_low=False, \
|
762
|
+
mark_start=False,mark_end=False, \
|
763
|
+
mktidx='auto',source='auto', \
|
764
|
+
ticker_type='auto',loc="best"):
|
765
|
+
"""
|
766
|
+
功能:组合情况,可能多只股票、多个投资组合或投资组合与股票的混合,多个无风险收益率
|
767
|
+
|
768
|
+
"""
|
769
|
+
df=compare_beta_security(ticker=ticker,start=start,end=end, \
|
770
|
+
adjust=adjust, \
|
771
|
+
RF=RF,regression_period=regression_period, \
|
772
|
+
attention_value=attention_value,attention_value_area=attention_value_area, \
|
773
|
+
attention_point=attention_point,attention_point_area=attention_point_area, \
|
774
|
+
band_area=band_area, \
|
775
|
+
graph=graph,facecolor=facecolor, \
|
776
|
+
annotate=annotate,annotate_value=annotate_value, \
|
777
|
+
mark_top=mark_high,mark_bottom=mark_low, \
|
778
|
+
mark_start=mark_start,mark_end=mark_end, \
|
779
|
+
mktidx=mktidx,source=source, \
|
780
|
+
ticker_type=ticker_type,loc=loc)
|
781
|
+
|
782
|
+
|
752
783
|
def compare_beta_security(ticker,start,end, \
|
753
784
|
adjust='qfq', \
|
754
785
|
RF=0,regression_period=365, \
|
siat/common.py
CHANGED
@@ -4918,7 +4918,13 @@ async def jupyter2pdf2(notebook_dir, notebook_file):
|
|
4918
4918
|
|
4919
4919
|
import os
|
4920
4920
|
from nbconvert import HTMLExporter
|
4921
|
-
|
4921
|
+
|
4922
|
+
try:
|
4923
|
+
from playwright.async_api import async_playwright
|
4924
|
+
except:
|
4925
|
+
print(" #Warning(jupyter2pdf2): playwright seems not fully installed yet")
|
4926
|
+
print(" [Solution] execute the command before re-run: playwright install")
|
4927
|
+
return
|
4922
4928
|
|
4923
4929
|
html_file = ""
|
4924
4930
|
|
siat/economy.py
CHANGED
@@ -1435,8 +1435,8 @@ def macro_trend(ticker,indicator,start='L10Y',end='today', \
|
|
1435
1435
|
if 'YoY PPI' in indicator:
|
1436
1436
|
attention_value=0
|
1437
1437
|
|
1438
|
-
df=compare_economy(
|
1439
|
-
|
1438
|
+
df=compare_economy(ticker=ticker,indicator=indicator, \
|
1439
|
+
start=fromdate,end=todate, \
|
1440
1440
|
power=power,twinx=twinx, \
|
1441
1441
|
yline=attention_value, \
|
1442
1442
|
loc1=loc1,loc2=loc2,facecolor=facecolor)
|
@@ -1451,7 +1451,7 @@ def macro_trend(ticker,indicator,start='L10Y',end='today', \
|
|
1451
1451
|
if 'YoY PPI' in indicator:
|
1452
1452
|
attention_value=0
|
1453
1453
|
|
1454
|
-
df=
|
1454
|
+
df=economy_trend0(start=fromdate,end=todate,ticker=ticker,indicator=indicator, \
|
1455
1455
|
datatag=datatag,power=power, \
|
1456
1456
|
zeroline=zeroline,yline=attention_value,facecolor=facecolor)
|
1457
1457
|
# 计算增长率
|
siat/fama_french.py
CHANGED
@@ -32,14 +32,95 @@ if czxt in ['linux']: #website Jupyter
|
|
32
32
|
# 解决保存图像时'-'显示为方块的问题
|
33
33
|
plt.rcParams['axes.unicode_minus'] = False
|
34
34
|
#==============================================================================
|
35
|
+
def convert2freq(df,new_freq='daily'):
|
36
|
+
"""
|
37
|
+
功能:将月度或年度频度的数据均匀化为日度数据
|
38
|
+
"""
|
39
|
+
dfcols=list(df)
|
40
|
+
|
41
|
+
import pandas as pd
|
42
|
+
df['datetmp']=df.index
|
43
|
+
df['Date']=df['datetmp'].apply(lambda x: x.to_timestamp())
|
44
|
+
df.set_index('Date',inplace=True)
|
45
|
+
#df['Date']=df['date']
|
46
|
+
if not isinstance(df.index, pd.DatetimeIndex):
|
47
|
+
df.index = pd.to_datetime(df.index)
|
48
|
+
|
49
|
+
if new_freq == 'daily':
|
50
|
+
df = df.asfreq('D')
|
51
|
+
elif new_freq == 'monthly':
|
52
|
+
df = df.asfreq('M')
|
53
|
+
else:
|
54
|
+
df = df.asfreq('Y')
|
55
|
+
|
56
|
+
for c in dfcols:
|
57
|
+
df[c] = df[c].ffill()
|
58
|
+
df[c] = df[c].bfill()
|
59
|
+
|
60
|
+
df.drop(columns=['datetmp'], inplace=True)
|
61
|
+
|
62
|
+
#df=df[['Date']+dfcols]
|
63
|
+
|
64
|
+
return df
|
65
|
+
#==============================================================================
|
66
|
+
|
35
67
|
if __name__=='__main__':
|
36
|
-
start='
|
37
|
-
end='
|
68
|
+
start='2025-1-1'
|
69
|
+
end='2025-6-13'
|
70
|
+
|
38
71
|
scope='Europe'
|
39
72
|
factor='Mom'
|
40
73
|
freq='yearly'
|
74
|
+
|
75
|
+
scope='US'
|
76
|
+
factor='FF3'
|
77
|
+
freq='daily'
|
78
|
+
|
79
|
+
ff3d=get_ff_factors(start,end,scope,factor,freq='daily')
|
80
|
+
ff3mth=get_ff_factors(start,end,scope,factor,freq='monthly')
|
81
|
+
ff3y=get_ff_factors(start,end,scope,factor,freq='yearly')
|
41
82
|
|
42
|
-
def get_ff_factors(start,end,scope='US',factor='FF3',freq='
|
83
|
+
def get_ff_factors(start,end,scope='US',factor='FF3',freq='monthly'):
|
84
|
+
"""
|
85
|
+
功能:套壳函数get_ff_factors0,应对freq='daily'经常失败的变通方法
|
86
|
+
"""
|
87
|
+
import pandas as pd
|
88
|
+
startpd=pd.to_datetime(start)
|
89
|
+
endpd=pd.to_datetime(end)
|
90
|
+
|
91
|
+
fff=get_ff_factors0(start=start,end=end,scope=scope,factor=factor,freq=freq)
|
92
|
+
if fff is None:
|
93
|
+
if freq == 'daily':
|
94
|
+
start1=date_adjust(start,adjust=-31)
|
95
|
+
end1=date_adjust(end,adjust=31)
|
96
|
+
fff=get_ff_factors0(start=start1,end=end1,scope=scope,factor=factor,freq='monthly')
|
97
|
+
if not (fff is None):
|
98
|
+
ff_factors0=convert2freq(fff,new_freq='daily')
|
99
|
+
ff_factors=ff_factors0[(ff_factors0.index >=startpd) & (ff_factors0.index <=endpd)]
|
100
|
+
else:
|
101
|
+
ff_factors=fff
|
102
|
+
|
103
|
+
elif freq == 'monthly':
|
104
|
+
start1=date_adjust(start,adjust=-365)
|
105
|
+
end1=date_adjust(end,adjust=365)
|
106
|
+
fff=get_ff_factors0(start=start1,end=end1,scope=scope,factor=factor,freq='yearly')
|
107
|
+
if not (fff is None):
|
108
|
+
ff_factors=convert2freq(fff,new_freq='monthly')
|
109
|
+
else:
|
110
|
+
ff_factors=fff
|
111
|
+
|
112
|
+
else:
|
113
|
+
start1=date_adjust(start,adjust=-365)
|
114
|
+
end1=date_adjust(end,adjust=365)
|
115
|
+
fff=get_ff_factors0(start=start1,end=end1,scope=scope,factor=factor,freq='yearly')
|
116
|
+
ff_factors=fff
|
117
|
+
else:
|
118
|
+
ff_factors=fff
|
119
|
+
|
120
|
+
return ff_factors
|
121
|
+
|
122
|
+
|
123
|
+
def get_ff_factors0(start,end,scope='US',factor='FF3',freq='yearly'):
|
43
124
|
"""
|
44
125
|
【支持的因子种类(factor)】
|
45
126
|
FF3: FF3各个因子
|
@@ -167,7 +248,7 @@ def get_ff_factors(start,end,scope='US',factor='FF3',freq='yearly'):
|
|
167
248
|
try:
|
168
249
|
ds = web.DataReader(symbol, source, start, end)
|
169
250
|
except:
|
170
|
-
print(" #
|
251
|
+
print(f" #Warning(get_ff_factors): time out to get {freq} data, working around ...")
|
171
252
|
return None
|
172
253
|
|
173
254
|
#提取希望的资产定价因子
|
@@ -887,7 +968,14 @@ if __name__=='__main__':
|
|
887
968
|
|
888
969
|
|
889
970
|
#==============================================================================
|
890
|
-
|
971
|
+
if __name__=='__main__':
|
972
|
+
ticker='BIDU'
|
973
|
+
start='2025-1-1'
|
974
|
+
end='2025-5-30'
|
975
|
+
scope='US'
|
976
|
+
graph=True
|
977
|
+
|
978
|
+
|
891
979
|
def reg_ff3_betas(ticker,start,end,scope='US',graph=True):
|
892
980
|
"""
|
893
981
|
功能:测试一只股票对于FF3各个因子的系数大小、符号方向和显著性
|
@@ -1051,7 +1139,10 @@ def reg_ffc4_betas(ticker,start,end,scope='US',graph=True):
|
|
1051
1139
|
#回归FF3模型
|
1052
1140
|
import statsmodels.api as sm
|
1053
1141
|
y=sample['dRet']
|
1054
|
-
|
1142
|
+
try:
|
1143
|
+
X=sample[['Mkt-RF','SMB','HML','MOM']]
|
1144
|
+
except:
|
1145
|
+
X=sample[['Mkt-RF','SMB','HML','Mom']]
|
1055
1146
|
X1=sm.add_constant(X)
|
1056
1147
|
results=sm.OLS(y,X1).fit()
|
1057
1148
|
|
@@ -1061,7 +1152,7 @@ def reg_ffc4_betas(ticker,start,end,scope='US',graph=True):
|
|
1061
1152
|
#输出结果并绘制横向柱状图
|
1062
1153
|
gparms=parms.iloc[[1,2,3,4]]
|
1063
1154
|
if graph == True:
|
1064
|
-
|
1155
|
+
print("\n",parms)
|
1065
1156
|
title=ticker_name(ticker)+": FFC4模型的贝塔系数"
|
1066
1157
|
plt.title(title,fontsize=12,fontweight='bold')
|
1067
1158
|
plt.ylabel("贝塔系数",fontsize=12,fontweight='bold')
|
@@ -1178,7 +1269,7 @@ def reg_ff5_betas(ticker,start,end,scope='US',graph=True):
|
|
1178
1269
|
#输出结果并绘制横向柱状图
|
1179
1270
|
gparms=parms.iloc[[1,2,3,4,5]]
|
1180
1271
|
if graph == True:
|
1181
|
-
|
1272
|
+
print("\n",parms)
|
1182
1273
|
title=ticker_name(ticker)+":FF5模型的贝塔系数"
|
1183
1274
|
plt.title(title,fontsize=12,fontweight='bold')
|
1184
1275
|
plt.ylabel("贝塔系数",fontsize=12,fontweight='bold')
|
siat/financials.py
CHANGED
@@ -61,14 +61,19 @@ if czxt in ['linux']: #website Jupyter
|
|
61
61
|
plt.rcParams['axes.unicode_minus'] = False
|
62
62
|
#==============================================================================
|
63
63
|
if __name__ == '__main__':
|
64
|
-
|
65
|
-
|
64
|
+
ticker=['AAPL','MSFT']
|
65
|
+
indicator=['Current Ratio','Quick Ratio']
|
66
|
+
|
67
|
+
ticker=['BABA','JD']
|
68
|
+
indicator='Cashflow per Share'
|
69
|
+
|
66
70
|
datatag=False
|
67
71
|
power=0
|
68
72
|
zeroline=False
|
69
73
|
twinx=False
|
74
|
+
loc1=loc2='best'
|
70
75
|
|
71
|
-
def compare_history(
|
76
|
+
def compare_history(ticker,indicator, \
|
72
77
|
datatag=False,power=0,zeroline=False,twinx=False, \
|
73
78
|
loc1='best',loc2='best',graph=True):
|
74
79
|
"""
|
@@ -77,6 +82,9 @@ def compare_history(tickers,items, \
|
|
77
82
|
zeroline=False:不绘制水平零线
|
78
83
|
twinx=False:单纵轴
|
79
84
|
"""
|
85
|
+
tickers=ticker
|
86
|
+
items=indicator
|
87
|
+
|
80
88
|
#检查power的范围是否合理
|
81
89
|
if not (power in range(0,80)):
|
82
90
|
print(" #Error(compare_history): invalid parameter, power =",power)
|
@@ -147,8 +155,12 @@ def compare_history(tickers,items, \
|
|
147
155
|
#抓取数据
|
148
156
|
info1=get_financial_rates(ticker1)
|
149
157
|
if info1 is None:
|
150
|
-
print(" #
|
151
|
-
|
158
|
+
print(f" #Warning(compare_history): unable to get data for {ticker1}, retrying ...")
|
159
|
+
sleep_random(max_sleep=30)
|
160
|
+
info1=get_financial_rates(ticker1)
|
161
|
+
if info1 is None:
|
162
|
+
print(" #Error(compare_history): failed to retrieved financials for",ticker1)
|
163
|
+
return None,None
|
152
164
|
|
153
165
|
cols1=['ticker','endDate','periodType',item1]
|
154
166
|
df1=info1[cols1]
|
@@ -166,14 +178,18 @@ def compare_history(tickers,items, \
|
|
166
178
|
item2=item1
|
167
179
|
info2=get_financial_rates(ticker2)
|
168
180
|
if info2 is None:
|
169
|
-
print(" #
|
170
|
-
|
181
|
+
print(f" #Warning(compare_history): unable to get data for {ticker2}, retrying ...")
|
182
|
+
sleep_random(max_sleep=30)
|
183
|
+
info2=get_financial_rates(ticker2)
|
184
|
+
if info2 is None:
|
185
|
+
print(" #Error(compare_history): failed to retrieved financials for",ticker2)
|
186
|
+
return None,None
|
171
187
|
|
172
188
|
df2=info2[cols1]
|
173
189
|
df2['date']=df2['endDate']
|
174
190
|
df2.set_index('date',inplace=True)
|
175
191
|
|
176
|
-
import datetime;
|
192
|
+
import datetime; todaydt=datetime.date.today()
|
177
193
|
#绘图:T1I1,单折线
|
178
194
|
if mode == 'T1I1'and graph:
|
179
195
|
df=df1
|
@@ -183,7 +199,7 @@ def compare_history(tickers,items, \
|
|
183
199
|
#titletxt=ticker_name(ticker1)+texttranslate(": 基于年(季)报的业绩历史")
|
184
200
|
titletxt=ticker_name(ticker1)+": 财报业绩历史"
|
185
201
|
#footnote=texttranslate("数据来源: 雅虎财经,")+' '+str(today)
|
186
|
-
footnote="数据来源: 雅虎财经,"+' '+str(
|
202
|
+
footnote="数据来源: 雅虎财经,"+' '+str(todaydt)
|
187
203
|
|
188
204
|
plot_line(df,colname,collabel,ylabeltxt,titletxt,footnote, \
|
189
205
|
datatag=datatag,power=power,zeroline=zeroline,resample_freq='3M', \
|
@@ -245,10 +261,19 @@ def compare_history(tickers,items, \
|
|
245
261
|
#titletxt=ticker_name(ticker1)+" vs "+ticker_name(ticker2)+texttranslate(": 基于年(季)报的业绩历史对比")
|
246
262
|
titletxt=ticker_name(ticker1)+" vs "+ticker_name(ticker2)+": 财报业绩历史对比"
|
247
263
|
#footnote=texttranslate("数据来源: 雅虎财经,")+' '+str(today)
|
248
|
-
footnote="数据来源: 雅虎财经,"+' '+str(
|
264
|
+
footnote="数据来源: 雅虎财经,"+' '+str(todaydt)
|
249
265
|
|
250
|
-
|
251
|
-
|
266
|
+
#克服双线绘制时第2条线错乱问题:两个df日期强制取齐,能解决问题,但原因不明
|
267
|
+
tname1=ticker_name(ticker1)
|
268
|
+
df1.rename(columns={item1:tname1},inplace=True)
|
269
|
+
tname2=ticker_name(ticker2)
|
270
|
+
df2.rename(columns={item2:ticker_name(ticker2)},inplace=True)
|
271
|
+
df12=pd.merge(df1,df2,how='inner',left_index=True,right_index=True)
|
272
|
+
df1t=df12[[tname1]]
|
273
|
+
df2t=df12[[tname2]]
|
274
|
+
|
275
|
+
plot_line2(df1t,ticker1,tname1,label1, \
|
276
|
+
df2t,ticker2,tname2,label2, \
|
252
277
|
ylabeltxt,titletxt,footnote, \
|
253
278
|
power=power,zeroline=zeroline,twinx=twinx,resample_freq='3M', \
|
254
279
|
loc1=loc1,loc2=loc2)
|
@@ -362,7 +387,7 @@ def compare_snapshot(ticker,indicator, \
|
|
362
387
|
|
363
388
|
notfoundlist=[]
|
364
389
|
total0=len(tickers)
|
365
|
-
print(" Searching",itemk,"for
|
390
|
+
print(" Searching",itemk,"for designated companies ...")
|
366
391
|
for t in tickers:
|
367
392
|
|
368
393
|
current=tickers.index(t)
|
@@ -1970,7 +1995,7 @@ def compare_dupont(tickerlist,fsdate='latest', \
|
|
1970
1995
|
"""
|
1971
1996
|
功能:获得tickerlist中每只股票的杜邦分析项目,绘制柱状叠加比较图
|
1972
1997
|
tickerlist:股票代码列表,建议在10只以内
|
1973
|
-
fsdate
|
1998
|
+
fsdate:财报日期,默认为最新一期季报/年报,或具体日期,格式:YYYY-MM-DD
|
1974
1999
|
scale1:用于放大销售净利率,避免与权益乘数数量级不一致导致绘图难看问题,可自行调整
|
1975
2000
|
scale2:用于放大总资产周转率,避免与权益乘数数量级不一致导致绘图难看问题,可自行调整
|
1976
2001
|
hatchlist:绘制柱状图的纹理,用于黑白打印时区分,可自定义,
|
@@ -2009,7 +2034,7 @@ def compare_dupont(tickerlist,fsdate='latest', \
|
|
2009
2034
|
dpidflist,dpilist,fsdatelist,fstypelist=[],[],[],[]
|
2010
2035
|
name1list,name2list,name3list,name4list,name5list,name6list=[],[],[],[],[],[]
|
2011
2036
|
newtickerlist=[]
|
2012
|
-
print("Working on DuPont factsheet for specified stocks ...")
|
2037
|
+
print(" Working on DuPont factsheet for specified stocks ...")
|
2013
2038
|
for t in tickerlist:
|
2014
2039
|
try:
|
2015
2040
|
with HiddenPrints():
|
@@ -2017,12 +2042,23 @@ def compare_dupont(tickerlist,fsdate='latest', \
|
|
2017
2042
|
except:
|
2018
2043
|
print(" #Warning(compare_dupont): lack of some accounting items for",t)
|
2019
2044
|
continue
|
2045
|
+
|
2046
|
+
#未出错,但未抓取到数据,再试
|
2047
|
+
if dpidf is None:
|
2048
|
+
print(f" #Warning(compare_dupont): failed to get data for {t}, retrying ...")
|
2049
|
+
sleep_random(max_sleep=30)
|
2050
|
+
with HiddenPrints():
|
2051
|
+
dpidf=calc_dupont(t)
|
2052
|
+
|
2053
|
+
if dpidf is None: continue
|
2054
|
+
|
2020
2055
|
if fsdate == 'latest':
|
2021
2056
|
try:
|
2022
2057
|
dpi=dpidf.tail(1)
|
2023
2058
|
except:
|
2024
|
-
print(" #Warning(compare_dupont):
|
2059
|
+
print(" #Warning(compare_dupont): got empty data for",t)
|
2025
2060
|
continue
|
2061
|
+
|
2026
2062
|
else: dpi=dpidf[dpidf['endDate']==fsdate]
|
2027
2063
|
if len(dpi) == 0:
|
2028
2064
|
print(" #Warning(compare_dupont): lack of some accounting items for",t,'@',fsdate)
|