siat 3.7.7__py3-none-any.whl → 3.7.9__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/allin.py +3 -0
- siat/common.py +249 -1
- siat/fin_stmt2_yahoo.py +982 -0
- siat/financials2.py +41 -18
- siat/grafix.py +39 -2
- siat/stock.py +5 -5
- siat/translate.py +301 -1
- siat/valuation.py +12 -8
- {siat-3.7.7.dist-info → siat-3.7.9.dist-info}/METADATA +3 -1
- {siat-3.7.7.dist-info → siat-3.7.9.dist-info}/RECORD +13 -12
- {siat-3.7.7.dist-info → siat-3.7.9.dist-info}/LICENSE +0 -0
- {siat-3.7.7.dist-info → siat-3.7.9.dist-info}/WHEEL +0 -0
- {siat-3.7.7.dist-info → siat-3.7.9.dist-info}/top_level.txt +0 -0
siat/financials2.py
CHANGED
@@ -104,17 +104,38 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
104
104
|
category='profile',business_period='annual', \
|
105
105
|
scale1=10,scale2=10,dupont_sort='PM',
|
106
106
|
printout=True, \
|
107
|
-
|
107
|
+
#entry_sort=False, \
|
108
108
|
facecolor='papayawhip',font_size='16px'
|
109
109
|
):
|
110
110
|
"""
|
111
|
-
|
111
|
+
|
112
|
+
功能:分析境外上市公司财报信息
|
113
|
+
|
114
|
+
参数:
|
115
|
+
tickers:股票列表,对比分析时需要多个股票,单列财报时仅取第一个股票
|
116
|
+
fsdates:财报日期,可为单个日期或日期列表,注意境外上市公司财报日期与中国大陆的不同
|
117
|
+
|
118
|
+
analysis_type:分析类型,可为企业概况('profile')、资产负债表简表('balance sheet')、
|
119
|
+
利润表简表('income statement')、现金流量表简表('cash flow')、财报概况('financial summary')、
|
120
|
+
财务比率('financial indicator')、杜邦分析('dupont identity')
|
121
|
+
|
122
|
+
category:企业概况分类,,仅当analysis_type='profile'时有效,
|
123
|
+
可为基本信息'profile'、高管概况('officers')、分红('dividend')、股票分拆('split')、市场表现('market')、
|
124
|
+
财务状况('financial')、一般风险('risk')、ESG风险('esg')
|
125
|
+
|
126
|
+
business_period:业务期间类型,可为季报'quarterly',年报'annual'、最近的6次报告'recent', 所有'all'
|
127
|
+
scale1:仅用于杜邦分析,放大倍数(以便缩小与EM之间的数量级差异),用于Profit Margin,默认10
|
128
|
+
scale2:仅用于杜邦分析,放大倍数,用于Total Asset Turnover,默认10
|
129
|
+
dupont_sort:仅用于杜邦分析,用于排序指标,默认净利润率'PM',还可为总资产周转率'TAT'或权益乘数'EM'
|
130
|
+
printout:是否显示数据表,默认是True
|
131
|
+
facecolor:背景颜色,默认小麦黄'papayawhip'
|
132
|
+
font_size:标题字体大小,默认'16px'
|
133
|
+
|
112
134
|
注意1:仅从雅虎财经获取数据
|
113
135
|
注意2:不同经济体上市公司报表币种可能不同,金额项目仅进行同公司对比,不进行公司间对比
|
114
|
-
注意3
|
136
|
+
注意3:公司间仅对比财务比率和杜邦分析
|
115
137
|
注意4:不同经济体上市公司年报季报日期不同,需要列示报表日期和类型(年报或季报)
|
116
|
-
|
117
|
-
business_period:取季报'quarterly',年报'annual',最近的6次报告'recent', 所有'all'
|
138
|
+
|
118
139
|
"""
|
119
140
|
import numpy as np
|
120
141
|
|
@@ -177,9 +198,11 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
177
198
|
info=get_stock_profile(tickers,info_type=category)
|
178
199
|
|
179
200
|
elif contains_any(category,['risk']):
|
201
|
+
#这里的是风险指标,数值越大风险越高,数值越小越好
|
180
202
|
category='risk_general'
|
181
203
|
info=get_stock_profile(tickers,info_type=category)
|
182
204
|
elif contains_any(category,['esg']):
|
205
|
+
#这里的ESG为风险指标,数值越大风险越高,数值越小越好
|
183
206
|
category='risk_esg'
|
184
207
|
info=get_stock_profile(tickers,info_type=category)
|
185
208
|
else:
|
@@ -200,7 +223,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
200
223
|
# 分析资产负债表
|
201
224
|
fsdf=get_balance_sheet(symbol=tickers)
|
202
225
|
if fsdf is None:
|
203
|
-
print(" #Warning(fs_analysis): financial info unaccessible for",tickers,"\b, which needs connection to Yahoo
|
226
|
+
print(" #Warning(fs_analysis): financial info unaccessible for",tickers,"\b, which needs connection to Yahoo")
|
204
227
|
return None
|
205
228
|
|
206
229
|
fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
|
@@ -245,7 +268,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
245
268
|
fsdf4.replace(0,'---',inplace=True)
|
246
269
|
|
247
270
|
#titletxt="\n***** "+ticker_name(tickers)+": BALANCE SHEET"+' *****\n'
|
248
|
-
titletxt=ticker_name(tickers,'stock')+": BALANCE SHEET"
|
271
|
+
titletxt=ticker_name(tickers,'stock')+text_lang(":资产负债简表",": BALANCE SHEET")
|
249
272
|
#print(titletxt)
|
250
273
|
"""
|
251
274
|
tablefmt_list=["plain","simple","github","grid","simple_grid","rounded_grid", \
|
@@ -347,7 +370,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
347
370
|
fsdf4.replace(0,'---',inplace=True)
|
348
371
|
|
349
372
|
#titletxt="\n***** "+ticker_name(tickers)+": INCOME STATEMENTS"+' *****\n'
|
350
|
-
titletxt=ticker_name(tickers,'stock')+": INCOME STATEMENTS"
|
373
|
+
titletxt=ticker_name(tickers,'stock')+text_lang(":利润简表",": INCOME STATEMENTS")
|
351
374
|
#print(titletxt)
|
352
375
|
|
353
376
|
collist=list(fsdf4)
|
@@ -427,7 +450,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
427
450
|
fsdf4.replace(0,'---',inplace=True)
|
428
451
|
|
429
452
|
#titletxt="\n***** "+ticker_name(tickers)+": CASHFLOW STATEMENTS"+' *****\n'
|
430
|
-
titletxt=ticker_name(tickers,'stock')+": CASHFLOW STATEMENTS"
|
453
|
+
titletxt=ticker_name(tickers,'stock')+text_lang(":现金流量简表",": CASHFLOW STATEMENTS")
|
431
454
|
#print(titletxt)
|
432
455
|
|
433
456
|
collist=list(fsdf4)
|
@@ -536,7 +559,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
536
559
|
fsdf4.replace(0,'---',inplace=True)
|
537
560
|
|
538
561
|
#titletxt="\n***** "+ticker_name(tickers)+": FINANCIAL STATEMENT SUMMARY"+' *****\n'
|
539
|
-
titletxt=ticker_name(tickers,'stock')+": FINANCIAL STATEMENT SUMMARY"
|
562
|
+
titletxt=ticker_name(tickers,'stock')+text_lang(":财报摘要",": FINANCIAL STATEMENT SUMMARY")
|
540
563
|
#print(titletxt)
|
541
564
|
|
542
565
|
collist=list(fsdf4)
|
@@ -638,7 +661,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
638
661
|
fsdf4.replace(0,'---',inplace=True)
|
639
662
|
|
640
663
|
#titletxt="\n***** PEER COMPARISON OF FINANCIAL STATEMENT SUMMARY *****\n"
|
641
|
-
titletxt="FINANCIAL STATEMENT SUMMARY:
|
664
|
+
titletxt=text_lang("财报摘要对比","FINANCIAL STATEMENT SUMMARY: COMPARISON")
|
642
665
|
#print(titletxt)
|
643
666
|
|
644
667
|
collist=list(fsdf4)
|
@@ -746,7 +769,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
746
769
|
fsdf4.replace(0,'---',inplace=True)
|
747
770
|
|
748
771
|
#titletxt="\n***** "+ticker_name(tickers)+": FINANCIAL INDICATORS"+' *****\n'
|
749
|
-
titletxt=ticker_name(tickers,'stock')+": FINANCIAL INDICATORS"
|
772
|
+
titletxt=ticker_name(tickers,'stock')+text_lang(":财务比率",": FINANCIAL INDICATORS")
|
750
773
|
#print(titletxt)
|
751
774
|
|
752
775
|
collist=list(fsdf4)
|
@@ -849,7 +872,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
849
872
|
fsdf4.replace(0,'---',inplace=True)
|
850
873
|
|
851
874
|
#titletxt="\n***** PEER COMPARISON OF FINANCIAL INDICATORS *****\n"
|
852
|
-
titletxt="FINANCIAL INDICATORS:
|
875
|
+
titletxt=text_lang("财务比率对比","FINANCIAL INDICATORS: COMPARISON")
|
853
876
|
#print(titletxt)
|
854
877
|
|
855
878
|
collist=list(fsdf4)
|
@@ -963,21 +986,21 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
963
986
|
plt.ylabel("Items (Amplified)")
|
964
987
|
|
965
988
|
footnote1="[Bar amplifier] "+name1+':x'+str(scale1)+','+name2+':x'+str(scale2)
|
966
|
-
footnote2='
|
989
|
+
footnote2='Statement period: '+fin_period+'. Bar height does not indicate ROE value.'
|
967
990
|
footnote3="Data source: Yahoo Finance,"+todaydt
|
968
991
|
footnote ='\n'+footnote1+'\n'+footnote2+'\n'+footnote3
|
969
992
|
plt.xlabel(footnote,fontsize=10)
|
970
993
|
|
971
994
|
plt.legend(loc='best',fontsize=10)
|
972
|
-
plt.title("Dupont Identity Analysis")
|
995
|
+
plt.title(text_lang("杜邦分析对比","Dupont Identity Analysis"))
|
973
996
|
plt.xlim([min(tick_pos)-w,max(tick_pos)+w])
|
974
997
|
|
975
|
-
plt.gca().set_facecolor(
|
998
|
+
plt.gca().set_facecolor(facecolor)
|
976
999
|
plt.show()
|
977
1000
|
|
978
1001
|
if printout:
|
979
1002
|
#title_txt="\n***** Dupont Identity Fact Sheet *****\n"
|
980
|
-
titletxt="Dupont Identity Fact Sheet"
|
1003
|
+
titletxt=text_lang("杜邦分析数据表","Dupont Identity Fact Sheet")
|
981
1004
|
#print(titletxt)
|
982
1005
|
|
983
1006
|
# 保留四位小数
|
@@ -998,7 +1021,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
998
1021
|
footnote2="Data source: Yahoo Finance, "+str(todaydt)
|
999
1022
|
footnote='Note:\n'+footnote1+'\n'+footnote2
|
1000
1023
|
#print('\n',footnote1,'\b.',footnote2)
|
1001
|
-
df_display_CSS(df,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
|
1024
|
+
df_display_CSS(df,titletxt=titletxt,footnote=footnote,facecolor=facecolor,decimals=4, \
|
1002
1025
|
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
1003
1026
|
data_font_size=data_font_size)
|
1004
1027
|
return df2
|
siat/grafix.py
CHANGED
@@ -1448,6 +1448,25 @@ def plot_line2_twinx2(df01,ticker1,colname1,label1, \
|
|
1448
1448
|
return
|
1449
1449
|
|
1450
1450
|
#==============================================================================
|
1451
|
+
if __name__ =="__main__":
|
1452
|
+
df0=security_trend(['PDD','JD'],annotate=True,graph=False)
|
1453
|
+
|
1454
|
+
y_label=''; x_label='Footnote'
|
1455
|
+
axhline_value=0; axhline_label=''
|
1456
|
+
title_txt='Title'
|
1457
|
+
data_label=False
|
1458
|
+
resample_freq='H'; smooth=True
|
1459
|
+
linewidth=1.5
|
1460
|
+
loc='best'
|
1461
|
+
annotate=True; annotate_value=True
|
1462
|
+
plus_sign=False
|
1463
|
+
attention_value=''; attention_value_area=''
|
1464
|
+
attention_point=''; attention_point_area=''
|
1465
|
+
mark_top=False; mark_bottom=False; mark_end=False
|
1466
|
+
ticker_type='auto'
|
1467
|
+
facecolor='whitesmoke'
|
1468
|
+
|
1469
|
+
|
1451
1470
|
def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
|
1452
1471
|
data_label=True,resample_freq='H',smooth=True,linewidth=1.5, \
|
1453
1472
|
loc='best',annotate=False,annotate_value=False,plus_sign=False, \
|
@@ -1758,8 +1777,24 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
|
|
1758
1777
|
|
1759
1778
|
# 若不绘制annotate,则绘制图例
|
1760
1779
|
#if not annotate:
|
1761
|
-
|
1780
|
+
#检查是否存在可绘制的标签,若有则绘制
|
1781
|
+
if DEBUG:
|
1782
|
+
have_label=False
|
1783
|
+
for line in plt.gca().lines:
|
1784
|
+
print(f" DEBUG: plt.gca().lines, line={line.get_label()}")
|
1785
|
+
if line.get_label() != '':
|
1786
|
+
have_label=True
|
1762
1787
|
|
1788
|
+
#plt.legend没有图例标签时会提示信息No artists...
|
1789
|
+
if not annotate or attention_value !='' or attention_point !='':
|
1790
|
+
plt.legend(loc=loc,fontsize=legend_txt_size)
|
1791
|
+
|
1792
|
+
"""
|
1793
|
+
if any([line.get_label() != '' for line in plt.gca().lines]):
|
1794
|
+
tuli=plt.legend(loc=loc,fontsize=legend_txt_size)
|
1795
|
+
if DEBUG:
|
1796
|
+
print(f" DEBUG: result of plt.legend is {tuli}")
|
1797
|
+
"""
|
1763
1798
|
if plus_sign:
|
1764
1799
|
# 尝试改变纵轴刻度格式:给正数添加正号+,以便突出显示增减幅度
|
1765
1800
|
import matplotlib.ticker as ticker
|
@@ -2072,7 +2107,9 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
|
|
2072
2107
|
plt.gca().set_facecolor("whitesmoke")
|
2073
2108
|
|
2074
2109
|
#if not annotate:
|
2075
|
-
plt.legend
|
2110
|
+
#plt.legend没有图例标签时会提示信息No artists...
|
2111
|
+
if not annotate or attention_value !='' or attention_point !='':
|
2112
|
+
plt.legend(loc=loc,fontsize=legend_txt_size)
|
2076
2113
|
|
2077
2114
|
#设置绘图风格:关闭网格虚线
|
2078
2115
|
plt.rcParams['axes.grid']=False
|
siat/stock.py
CHANGED
@@ -2654,10 +2654,10 @@ def stock_dividend(ticker,start="L3Y",end="today",facecolor='whitesmoke',fontcol
|
|
2654
2654
|
try:
|
2655
2655
|
div=stock.dividends
|
2656
2656
|
except:
|
2657
|
-
print(" #Error(stock_dividend): no
|
2657
|
+
print(" #Error(stock_dividend): no dividend information found for",ticker)
|
2658
2658
|
return None
|
2659
2659
|
if len(div)==0:
|
2660
|
-
print(" #Warning(stock_dividend): no
|
2660
|
+
print(" #Warning(stock_dividend): no dividend information found for",ticker)
|
2661
2661
|
return None
|
2662
2662
|
|
2663
2663
|
# 去掉时区信息,避免合并中的日期时区冲突问题
|
@@ -2795,10 +2795,10 @@ def stock_split(ticker,start="L10Y",end="today",facecolor='whitesmoke',fontcolor
|
|
2795
2795
|
try:
|
2796
2796
|
div=stock.splits
|
2797
2797
|
except:
|
2798
|
-
print(" #Error(stock_split): no split
|
2798
|
+
print(" #Error(stock_split): no split information found for",ticker)
|
2799
2799
|
return None
|
2800
2800
|
if len(div)==0:
|
2801
|
-
print(" #Warning(stock_split): no split
|
2801
|
+
print(" #Warning(stock_split): no split information found for",ticker)
|
2802
2802
|
return None
|
2803
2803
|
|
2804
2804
|
# 去掉时区信息,避免合并中的日期时区冲突问题
|
@@ -2810,7 +2810,7 @@ def stock_split(ticker,start="L10Y",end="today",facecolor='whitesmoke',fontcolor
|
|
2810
2810
|
div1=div[div.index >= startdt]
|
2811
2811
|
div2=div1[div1.index <= enddt]
|
2812
2812
|
if len(div2)==0:
|
2813
|
-
print(" #Warning(stock_split): no split
|
2813
|
+
print(" #Warning(stock_split): no split information in period",fromdate,todate)
|
2814
2814
|
return None
|
2815
2815
|
|
2816
2816
|
#对齐打印
|
siat/translate.py
CHANGED
@@ -4554,6 +4554,306 @@ if __name__=='__main__':
|
|
4554
4554
|
industry_sw_name(icode)
|
4555
4555
|
|
4556
4556
|
#==============================================================================
|
4557
|
-
|
4557
|
+
#实现简单中英文短语互译
|
4558
|
+
#==============================================================================
|
4559
|
+
if __name__ == '__main__':
|
4560
|
+
chntext='市盈率'
|
4561
|
+
engtext="PE ratio"
|
4562
|
+
engtext="P/E ratio"
|
4563
|
+
|
4564
|
+
zh2en(chntext)
|
4565
|
+
|
4566
|
+
en2zh(engtext)
|
4567
|
+
|
4568
|
+
|
4569
|
+
def zh2en(text):
|
4570
|
+
'''英文转换成中文'''
|
4571
|
+
|
4572
|
+
from translate import Translator
|
4573
|
+
translator = Translator(from_lang="zh", to_lang="en")
|
4574
|
+
translation = translator.translate(text)
|
4575
|
+
|
4576
|
+
return translation
|
4577
|
+
|
4578
|
+
def en2zh(text):
|
4579
|
+
'''中文转换成英文'''
|
4580
|
+
|
4581
|
+
from translate import Translator
|
4582
|
+
translator = Translator(from_lang="en", to_lang="zh")
|
4583
|
+
translation = translator.translate(text)
|
4584
|
+
|
4585
|
+
return translation
|
4586
|
+
|
4587
|
+
if __name__ == '__main__':
|
4588
|
+
chntext='市盈率'
|
4589
|
+
engtext1="PE ratio"
|
4590
|
+
engtext2="P/E ratio"
|
4591
|
+
|
4592
|
+
lang_auto(chntext)
|
4593
|
+
lang_auto(engtext1)
|
4594
|
+
lang_auto(engtext2)
|
4595
|
+
|
4596
|
+
lang_auto(text)
|
4597
|
+
|
4598
|
+
|
4599
|
+
def lang_auto(text):
|
4600
|
+
'''转换字符串text至当前语言环境,基于translate'''
|
4601
|
+
|
4602
|
+
#注意:这个翻译模块只能每天提供有限单词翻译服务
|
4603
|
+
from translate import Translator
|
4604
|
+
|
4605
|
+
lang_env=check_language()
|
4606
|
+
lang_text=detect_language(text)
|
4607
|
+
|
4608
|
+
#字符串语言与当前环境语言相同,无需翻译,节省运行时间
|
4609
|
+
if lang_env==lang_text:
|
4610
|
+
return text
|
4611
|
+
|
4612
|
+
provider_list=['mymemory']
|
4613
|
+
|
4614
|
+
if lang_env=='Chinese':
|
4615
|
+
#translator = Translator(from_lang="en", to_lang="zh")
|
4616
|
+
#translator = Translator(to_lang="zh")
|
4617
|
+
translator = Translator(to_lang="zh",provider="mymemory")
|
4618
|
+
elif lang_env=='English':
|
4619
|
+
translator = Translator(to_lang="en")
|
4620
|
+
else:
|
4621
|
+
return text
|
4622
|
+
|
4623
|
+
translation = translator.translate(text)
|
4624
|
+
|
4625
|
+
return translation
|
4626
|
+
|
4627
|
+
if __name__ == '__main__':
|
4628
|
+
text='市盈率'
|
4629
|
+
text='贵州茅台'
|
4630
|
+
text='五粮液'
|
4631
|
+
text='Dividend Payout Ratio'
|
4632
|
+
text='asOfDate'
|
4633
|
+
text='Cash And Cash Equivalents'
|
4634
|
+
text='AccountsReceivableNetSalesAllowance'
|
4635
|
+
text='Accounts Receivable Net of Sales Allowance'
|
4636
|
+
text='Accounts Payable'
|
4637
|
+
|
4638
|
+
language_detect=True
|
4639
|
+
language_engine=['google','baidu','bing']
|
4640
|
+
|
4641
|
+
chntext='市盈率'
|
4642
|
+
engtext1="PE ratio"
|
4643
|
+
engtext2="P/E ratio"
|
4644
|
+
|
4645
|
+
lang_auto2(text)
|
4646
|
+
lang_auto2(text,language_detect=True)
|
4647
|
+
|
4648
|
+
lang_auto2(chntext)
|
4649
|
+
lang_auto2(engtext1)
|
4650
|
+
lang_auto2(engtext2)
|
4651
|
+
|
4652
|
+
|
4653
|
+
def lang_auto2(text,language_detect=True,language_engine=['alibaba','google','bing','sogou']):
|
4654
|
+
'''转换字符串text至当前语言环境,基于translators,可指定翻译服务器,准确度更高'''
|
4655
|
+
|
4656
|
+
import translators as ts
|
4657
|
+
|
4658
|
+
lang_env=check_language()
|
4659
|
+
|
4660
|
+
if language_detect:
|
4661
|
+
lang_text=detect_language(text)
|
4662
|
+
|
4663
|
+
#字符串语言与当前环境语言相同,无需翻译,节省运行时间
|
4664
|
+
if lang_env==lang_text:
|
4665
|
+
return text
|
4666
|
+
|
4667
|
+
success=False
|
4668
|
+
if lang_env=='Chinese':
|
4669
|
+
#translator支持baidu/bing/google
|
4670
|
+
if isinstance(language_engine,str):
|
4671
|
+
language_engine=[language_engine]
|
4672
|
+
|
4673
|
+
for le in language_engine:
|
4674
|
+
try:
|
4675
|
+
translation = ts.translate_text(text,from_language='en',to_language='zh', translator=le)
|
4676
|
+
success=True
|
4677
|
+
break
|
4678
|
+
except:
|
4679
|
+
continue
|
4680
|
+
elif lang_env=='English':
|
4681
|
+
for le in language_engine:
|
4682
|
+
try:
|
4683
|
+
translation = ts.translate_text(text,from_language='zh',to_language='en', translator=le)
|
4684
|
+
success=True
|
4685
|
+
break
|
4686
|
+
except:
|
4687
|
+
continue
|
4688
|
+
else:
|
4689
|
+
return text
|
4690
|
+
|
4691
|
+
if not success:
|
4692
|
+
translation = text
|
4693
|
+
|
4694
|
+
return translation
|
4695
|
+
|
4696
|
+
|
4697
|
+
if __name__ == '__main__':
|
4698
|
+
chntext='市盈率'
|
4699
|
+
engtext1="PE ratio"
|
4700
|
+
|
4701
|
+
detect_language(chntext)
|
4702
|
+
detect_language(engtext)
|
4703
|
+
|
4704
|
+
def detect_language(text):
|
4705
|
+
'''判断字符串text是中文还是英文'''
|
4706
|
+
|
4707
|
+
import re
|
4708
|
+
chinese_pattern = re.compile(r'[\u4e00-\u9fa5]')
|
4709
|
+
english_pattern = re.compile(r'[a-zA-Z]')
|
4710
|
+
|
4711
|
+
chinese_count = len(chinese_pattern.findall(text))
|
4712
|
+
english_count = len(english_pattern.findall(text))
|
4713
|
+
total_count = chinese_count + english_count
|
4714
|
+
|
4715
|
+
if total_count == 0:
|
4716
|
+
result='Unknown'
|
4717
|
+
|
4718
|
+
if chinese_count > english_count:
|
4719
|
+
result='Chinese'
|
4720
|
+
elif english_count > chinese_count:
|
4721
|
+
result='English'
|
4722
|
+
else:
|
4723
|
+
result='Both'
|
4724
|
+
|
4725
|
+
return result
|
4726
|
+
|
4727
|
+
|
4728
|
+
if __name__ == '__main__':
|
4729
|
+
text='DividendPayoutRatio'
|
4730
|
+
text='CashAndCashEquivalents'
|
4731
|
+
text='asOfDate'
|
4732
|
+
|
4733
|
+
text='GrossPPE'
|
4734
|
+
|
4735
|
+
text='Cash And Cash Equivalents'
|
4736
|
+
|
4737
|
+
words_split_yahoo(text)
|
4738
|
+
|
4739
|
+
def words_split_yahoo(text,split_improve=True):
|
4740
|
+
'''将雅虎英文财报术语拆分为带空格的词组'''
|
4741
|
+
|
4742
|
+
|
4743
|
+
#替换基于大写字母无法分词的短语
|
4744
|
+
text=text.replace("periodType","PeriodType")
|
4745
|
+
text=text.replace("Tradeand","TradeAnd")
|
4746
|
+
|
4747
|
+
words_list=[]
|
4748
|
+
start=0
|
4749
|
+
|
4750
|
+
for i in range(len(text)):
|
4751
|
+
c=text[i]
|
4752
|
+
|
4753
|
+
if (c>='A' and c<='Z') or c==' ':
|
4754
|
+
words_list=words_list+[text[start:i].strip(' ')]
|
4755
|
+
start=i
|
4756
|
+
|
4757
|
+
#添加最后一个单词
|
4758
|
+
words_list=words_list+[text[start:i+1]]
|
4759
|
+
|
4760
|
+
special_words=['and','of','in','at','as','for','non','from']
|
4761
|
+
words_list2=[]
|
4762
|
+
for w in words_list:
|
4763
|
+
if text.index(w) == 0:
|
4764
|
+
words_list2=words_list2+[w.title()]
|
4765
|
+
elif w.lower() in special_words:
|
4766
|
+
words_list2=words_list2+[w.lower()]
|
4767
|
+
else:
|
4768
|
+
words_list2=words_list2+[w]
|
4769
|
+
|
4770
|
+
text_new=''
|
4771
|
+
for w in words_list2:
|
4772
|
+
text_new=text_new+' '+w
|
4773
|
+
|
4774
|
+
#若出现多个空格则替换为单个空格
|
4775
|
+
import re
|
4776
|
+
text_new=re.sub(r' +', ' ', text_new)
|
4777
|
+
|
4778
|
+
#去掉首尾的空格
|
4779
|
+
text_new=text_new.strip(' ')
|
4780
|
+
|
4781
|
+
|
4782
|
+
#判断大写字母缩写合并
|
4783
|
+
prev_c1=''; prev_c2=''
|
4784
|
+
text_new2=''
|
4785
|
+
for c in text_new:
|
4786
|
+
if c>='A' and c<='Z':
|
4787
|
+
if prev_c1==' ' and (prev_c2>='A' and prev_c2<='Z'):
|
4788
|
+
text_new2=text_new2.strip(' ')+c
|
4789
|
+
else:
|
4790
|
+
text_new2=text_new2+c
|
4791
|
+
else:
|
4792
|
+
text_new2=text_new2+c
|
4793
|
+
|
4794
|
+
prev_c2=prev_c1; prev_c1=c
|
4795
|
+
|
4796
|
+
#弥补大写字母合并后继词的逻辑缺陷
|
4797
|
+
for upl in ['PPE']:
|
4798
|
+
text_new2=text_new2.replace(upl,upl+' ')
|
4799
|
+
text_new2=re.sub(r' +', ' ', text_new2)
|
4800
|
+
text_new2=text_new2.strip(' ')
|
4801
|
+
|
4802
|
+
|
4803
|
+
#替换缩写/简写/容易翻译出错的词,强行规避翻译错误。
|
4804
|
+
#注意:不影响未拆分科目名称,仅为翻译用途
|
4805
|
+
if split_improve:
|
4806
|
+
text_new3=text_new2.replace("PPE","Plant Property and Equipment")
|
4807
|
+
|
4808
|
+
text_new3=text_new3.replace("Treasury Shares Number","Treasury Shares")
|
4809
|
+
text_new3=text_new3.replace("Ordinary Shares Number","Ordinary Shares")
|
4810
|
+
text_new3=text_new3.replace(" Gross "," and ")
|
4811
|
+
text_new3=text_new3.replace("non Current","Non-current")
|
4812
|
+
text_new3=text_new3.replace("Non Current","Non-current")
|
4813
|
+
text_new3=text_new3.replace("Short Term","Short-term")
|
4814
|
+
text_new3=text_new3.replace("Long Term","Long-term")
|
4815
|
+
text_new3=text_new3.replace("Available for Sale","Available-for-sale")
|
4816
|
+
|
4817
|
+
text_new3=text_new3.replace(" Com "," Common ")
|
4818
|
+
text_new3=text_new3.replace(" Net "," Net of ")
|
4819
|
+
text_new3=text_new3.replace("Net Income","Net Profit")
|
4820
|
+
|
4821
|
+
text_new3=text_new3.replace("EBITDA","XXX")
|
4822
|
+
text_new3=text_new3.replace("EBIT","Earnings before Interest and Tax")
|
4823
|
+
text_new3=text_new3.replace("XXX","EBITDA")
|
4824
|
+
|
4825
|
+
text_new3=text_new3.replace("Tax Provision","Tax Accrued")
|
4826
|
+
text_new3=text_new3.replace("non Operating","Non-operating")
|
4827
|
+
|
4828
|
+
text_new3=text_new3.replace("Operating Income","Operating Profit")
|
4829
|
+
text_new3=text_new3.replace("Pretax Income","Pretax Profit")
|
4830
|
+
|
4831
|
+
text_new3=text_new3.replace("Current Provisions","Current Reserve")
|
4832
|
+
|
4833
|
+
text_new3=text_new3.replace("Duefrom ","Due from ")
|
4834
|
+
text_new3=text_new3.replace("Dueto ","Due to ")
|
4835
|
+
|
4836
|
+
text_new3=text_new3.replace("Investmentin ","Investment in ")
|
4837
|
+
text_new3=text_new3.replace("Diluted NIAvailto ","Diluted Net Profit Avail to ")
|
4838
|
+
text_new3=text_new3.replace(" Noncontrolling "," Non-controlling ")
|
4839
|
+
text_new3=text_new3.replace("Other Gand A","Other General and Administrative Expense")
|
4840
|
+
text_new3=text_new3.replace("Otherunder ","Other under ")
|
4841
|
+
text_new3=text_new3.replace("Mergern Acquisition","Merger and Acquisition")
|
4842
|
+
text_new3=text_new3.replace("Write Off","Write-off")
|
4843
|
+
|
4844
|
+
text_new3=text_new3.replace("Cash Flow From ","Cash Flow from ")
|
4845
|
+
text_new3=text_new3.replace("Cash From ","Cash Flow from ")
|
4846
|
+
text_new3=text_new3.replace(" From "," from ")
|
4847
|
+
text_new3=text_new3.replace("Provisionand","Provision and")
|
4848
|
+
text_new3=text_new3.replace("Write-offof","Write-off of")
|
4849
|
+
text_new3=text_new3.replace("non Cash","non-Cash")
|
4850
|
+
text_new3=text_new3.replace("Changein","Change in")
|
4851
|
+
|
4852
|
+
else:
|
4853
|
+
text_new3=text_new2
|
4854
|
+
|
4855
|
+
return text_new3
|
4856
|
+
|
4857
|
+
#==============================================================================
|
4558
4858
|
#==============================================================================
|
4559
4859
|
#==============================================================================
|
siat/valuation.py
CHANGED
@@ -1177,9 +1177,10 @@ def security_valuation(tickers,indicators,start,end, \
|
|
1177
1177
|
|
1178
1178
|
#==============================================================================
|
1179
1179
|
if __name__=='__main__':
|
1180
|
-
|
1180
|
+
bank_big=find_peers_china('国有大型银行Ⅱ',top=25)
|
1181
|
+
df=security_trend(bank_big,indicator='PE',start='MRY',graph=False)
|
1181
1182
|
indicator='PE'
|
1182
|
-
base=''
|
1183
|
+
base='601398.SS'
|
1183
1184
|
|
1184
1185
|
|
1185
1186
|
def print_valuation(df,indicator='PE',base='',facecolor='whitesmoke'):
|
@@ -1189,14 +1190,15 @@ def print_valuation(df,indicator='PE',base='',facecolor='whitesmoke'):
|
|
1189
1190
|
try:
|
1190
1191
|
df1=df[indicator]
|
1191
1192
|
except:
|
1192
|
-
print(" #Warning:
|
1193
|
+
print(f" #Warning(print_valuation): unsupported indicator {indicator} in current dataframe")
|
1193
1194
|
return
|
1194
1195
|
|
1195
1196
|
collist=list(df1)
|
1196
1197
|
base=base.upper()
|
1198
|
+
base=ticker_name(base)
|
1197
1199
|
if not (base in collist):
|
1198
1200
|
"""
|
1199
|
-
print(" #Warning: invalid item",base,"for current dataframe")
|
1201
|
+
print(" #Warning(print_valuation): invalid item",base,"for current dataframe")
|
1200
1202
|
print(" Valid items in current dataframe:\n",collist)
|
1201
1203
|
return
|
1202
1204
|
"""
|
@@ -1256,7 +1258,8 @@ def print_valuation(df,indicator='PE',base='',facecolor='whitesmoke'):
|
|
1256
1258
|
#df4=df3[['序号','证券名称',col_mean,col_mean_rel,'均值对比',col_latest_date,col_latest_rel,'对比@'+col_latest_date]]
|
1257
1259
|
df4=df3[['证券名称',col_mean,'均值排名',col_latest_date,'排名@'+col_latest_date,col_mean_rel,col_latest_rel,'均值对比','对比@'+col_latest_date]]
|
1258
1260
|
|
1259
|
-
titletxt="
|
1261
|
+
#titletxt="估值对比:"+ectranslate(indicator)+",降序排列"
|
1262
|
+
titletxt="证券估值对比:{0}({1}),降序排列".format(ectranslate(indicator),indicator)
|
1260
1263
|
"""
|
1261
1264
|
print("\n",titletxt,'\n')
|
1262
1265
|
alignlist=['left','right','center','right','center']+['right']*(len(list(df4))-5)
|
@@ -1273,16 +1276,17 @@ def print_valuation(df,indicator='PE',base='',facecolor='whitesmoke'):
|
|
1273
1276
|
#设置列数值对齐
|
1274
1277
|
dispf=dispt.set_properties(**{'text-align':'center'})
|
1275
1278
|
#设置前景背景颜色
|
1276
|
-
dispf2=dispf.set_properties(**{'background-color':facecolor,'color':fontcolor})
|
1279
|
+
#dispf2=dispf.set_properties(**{'background-color':facecolor,'color':fontcolor})
|
1280
|
+
dispf2=dispf.set_properties(**{'background-color':facecolor})
|
1277
1281
|
|
1278
1282
|
from IPython.display import display
|
1279
1283
|
display(dispf2)
|
1280
1284
|
|
1281
|
-
print(" ")
|
1285
|
+
#print(" ")
|
1282
1286
|
if diff > 0:
|
1283
1287
|
print("【注】未列出"+str(diff)+"只估值为非正数的证券:"+str(diff_list))
|
1284
1288
|
import datetime; todaydt = datetime.date.today()
|
1285
|
-
footnote="
|
1289
|
+
footnote="估值期间:"+col_start_date+"至"+col_latest_date+",数据来源: baidu/stooq/funddb/swhysc,"+str(todaydt)
|
1286
1290
|
print(footnote)
|
1287
1291
|
|
1288
1292
|
return
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: siat
|
3
|
-
Version: 3.7.
|
3
|
+
Version: 3.7.9
|
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
|
@@ -35,6 +35,8 @@ Requires-Dist: pendulum
|
|
35
35
|
Requires-Dist: itables
|
36
36
|
Requires-Dist: py-trans
|
37
37
|
Requires-Dist: bottleneck
|
38
|
+
Requires-Dist: translate
|
39
|
+
Requires-Dist: translators
|
38
40
|
|
39
41
|
|
40
42
|
# What is siat?
|