siat 3.9.21__py3-none-any.whl → 3.9.32__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/__init__.py +2 -2
- siat/common.py +74 -1
- siat/financial_statements.py +14 -12
- siat/financials.py +1 -1
- siat/financials2.py +196 -25
- siat/stock.py +2 -1
- {siat-3.9.21.dist-info → siat-3.9.32.dist-info}/METADATA +1 -1
- {siat-3.9.21.dist-info → siat-3.9.32.dist-info}/RECORD +11 -11
- {siat-3.9.21.dist-info → siat-3.9.32.dist-info}/LICENSE +0 -0
- {siat-3.9.21.dist-info → siat-3.9.32.dist-info}/WHEEL +0 -0
- {siat-3.9.21.dist-info → siat-3.9.32.dist-info}/top_level.txt +0 -0
siat/__init__.py
CHANGED
@@ -40,7 +40,7 @@ if os == 'windows':
|
|
40
40
|
srcfile=srcpath1+'/'+tagfile
|
41
41
|
else:
|
42
42
|
srcpath1=srcpath
|
43
|
-
srcfile=srcpath1+'/'+
|
43
|
+
srcfile=srcpath1+'/'+tagfile
|
44
44
|
|
45
45
|
try:
|
46
46
|
with open(srcfile,'rb') as file:
|
@@ -70,6 +70,6 @@ if not restart:
|
|
70
70
|
else:
|
71
71
|
with HiddenPrints():
|
72
72
|
fix_package()
|
73
|
-
print(" Please RESTART Python kernel and run this command again")
|
73
|
+
print(" Please RESTART Python kernel and then run this command again")
|
74
74
|
|
75
75
|
#==============================================================================
|
siat/common.py
CHANGED
@@ -3501,7 +3501,7 @@ if __name__=='__main__':
|
|
3501
3501
|
|
3502
3502
|
test_website(url)
|
3503
3503
|
|
3504
|
-
def test_website(url):
|
3504
|
+
def test_website(url="https://finance.yahoo.com"):
|
3505
3505
|
"""
|
3506
3506
|
功能:测试一个网址是否可访问
|
3507
3507
|
"""
|
@@ -5000,6 +5000,79 @@ def shift_column_position(df,col_name,position=1):
|
|
5000
5000
|
|
5001
5001
|
return df
|
5002
5002
|
#==============================================================================
|
5003
|
+
if __name__ == '__main__':
|
5004
|
+
text='accountsReceivable'
|
5005
|
+
text='periodType'
|
5006
|
+
text='reportDate'
|
5007
|
+
text='currencyCode'
|
5008
|
+
text='BasicEPS'
|
5009
|
+
text='EBITDA'
|
5010
|
+
text='CashAndCashEquivalents'
|
5011
|
+
text='Debt to Asset'
|
5012
|
+
|
5013
|
+
text_separate(text)
|
5014
|
+
|
5015
|
+
def text_separate(text):
|
5016
|
+
"""
|
5017
|
+
功能:将连写在一起的专业术语拆分成为正常的形式
|
5018
|
+
参数:
|
5019
|
+
text:待拆分短语,例如accountsReceivable
|
5020
|
+
输出:拆分后短语,例如Accounts Receivable
|
5021
|
+
"""
|
5022
|
+
DEBUG=False
|
5023
|
+
|
5024
|
+
if not text:
|
5025
|
+
return ""
|
5026
|
+
|
5027
|
+
articles={"and","from","in","on","the","of","to","for","not","non","as","per"}
|
5028
|
+
|
5029
|
+
words = []
|
5030
|
+
current_word = [text[0].upper()] # 首字母默认大写
|
5031
|
+
for i in range(1, len(text)):
|
5032
|
+
prev_char, curr_char = text[i-1], text[i]
|
5033
|
+
|
5034
|
+
# 分割条件:当前大写且前一个字符为小写,或当前大写后跟小写(保留连续大写)
|
5035
|
+
if (curr_char.isupper() and prev_char.islower()) or \
|
5036
|
+
(curr_char.isupper() and prev_char.isupper() and i < len(text)-1 and text[i+1].islower()):
|
5037
|
+
words.append(''.join(current_word))
|
5038
|
+
current_word = [curr_char]
|
5039
|
+
else:
|
5040
|
+
current_word.append(curr_char)
|
5041
|
+
words.append(''.join(current_word))
|
5042
|
+
|
5043
|
+
# 处理虚词:除首单词外,虚词首字母小写
|
5044
|
+
formatted_words = [words[0]]
|
5045
|
+
for word in words[1:]:
|
5046
|
+
lower_word = word.lower()
|
5047
|
+
formatted_words.append(lower_word if lower_word in articles else word)
|
5048
|
+
|
5049
|
+
words2=' '.join(formatted_words)
|
5050
|
+
|
5051
|
+
if DEBUG:
|
5052
|
+
print(f"BEFORE: {text}, AFTER: {words2}")
|
5053
|
+
|
5054
|
+
return words2
|
5055
|
+
|
5056
|
+
#==============================================================================
|
5057
|
+
if __name__ == '__main__':
|
5058
|
+
alist=['a','b','c']
|
5059
|
+
element='b'
|
5060
|
+
element='c'
|
5061
|
+
|
5062
|
+
last_in_list(element,alist)
|
5063
|
+
|
5064
|
+
def last_in_list(element,alist):
|
5065
|
+
"""
|
5066
|
+
功能:测试element是否alist的最后一个元素
|
5067
|
+
参数:
|
5068
|
+
element:alist的元素,用于循环
|
5069
|
+
alist:列表,用于循环
|
5070
|
+
"""
|
5071
|
+
result=False
|
5072
|
+
if alist.index(element) == len(alist)-1:
|
5073
|
+
result=True
|
5074
|
+
|
5075
|
+
return result
|
5003
5076
|
#==============================================================================
|
5004
5077
|
#==============================================================================
|
5005
5078
|
#==============================================================================
|
siat/financial_statements.py
CHANGED
@@ -53,7 +53,8 @@ def get_balance_sheet(symbol):
|
|
53
53
|
stmta=stock.balance_sheet() # Defaults to Annual
|
54
54
|
except:
|
55
55
|
print(" Searching for annual report failed, recovering......")
|
56
|
-
|
56
|
+
sleep_random(max_sleep=60)
|
57
|
+
|
57
58
|
try:
|
58
59
|
stmta=stock.balance_sheet()
|
59
60
|
except:
|
@@ -76,7 +77,8 @@ def get_balance_sheet(symbol):
|
|
76
77
|
stmtq=stock.balance_sheet(frequency="q")
|
77
78
|
except:
|
78
79
|
print(" Searching for quarterly report failed, recovering......")
|
79
|
-
|
80
|
+
sleep_random(max_sleep=60)
|
81
|
+
|
80
82
|
try:
|
81
83
|
stmtq=stock.balance_sheet(frequency="q")
|
82
84
|
except:
|
@@ -195,7 +197,7 @@ def get_income_statements(symbol):
|
|
195
197
|
stmta=stock.income_statement() # Defaults to Annual
|
196
198
|
except:
|
197
199
|
print(" Searching for annual report failed, recovering......")
|
198
|
-
|
200
|
+
sleep_random(max_sleep=60)
|
199
201
|
try:
|
200
202
|
stmta=stock.income_statement()
|
201
203
|
except:
|
@@ -218,7 +220,7 @@ def get_income_statements(symbol):
|
|
218
220
|
stmtq=stock.income_statement(frequency="q")
|
219
221
|
except:
|
220
222
|
print(" Searching for quarterly report failed, recovering......")
|
221
|
-
|
223
|
+
sleep_random(max_sleep=60)
|
222
224
|
try:
|
223
225
|
stmtq=stock.income_statement(frequency="q")
|
224
226
|
except:
|
@@ -310,7 +312,7 @@ def get_cashflow_statements(symbol):
|
|
310
312
|
stmta=stock.cash_flow() # Defaults to Annual
|
311
313
|
except:
|
312
314
|
print(" Searching for annual report failed, recovering......")
|
313
|
-
|
315
|
+
sleep_random(max_sleep=60)
|
314
316
|
try:
|
315
317
|
stmta=stock.cash_flow()
|
316
318
|
except:
|
@@ -333,7 +335,7 @@ def get_cashflow_statements(symbol):
|
|
333
335
|
stmtq=stock.cash_flow(frequency="q")
|
334
336
|
except:
|
335
337
|
print(" Searching for quarterly report failed, recovering......")
|
336
|
-
|
338
|
+
sleep_random(max_sleep=60)
|
337
339
|
try:
|
338
340
|
stmtq=stock.cash_flow(frequency="q")
|
339
341
|
except:
|
@@ -407,11 +409,11 @@ def get_financial_statements(ticker):
|
|
407
409
|
fbs = get_balance_sheet(ticker)
|
408
410
|
except:
|
409
411
|
print(" Retrieving fin info failed, trying to recover...")
|
410
|
-
|
412
|
+
sleep_random(max_sleep=60)
|
411
413
|
try:
|
412
414
|
fbs = get_balance_sheet(ticker)
|
413
415
|
except:
|
414
|
-
|
416
|
+
sleep_random(max_sleep=60)
|
415
417
|
try:
|
416
418
|
fbs = get_balance_sheet(ticker)
|
417
419
|
except:
|
@@ -426,11 +428,11 @@ def get_financial_statements(ticker):
|
|
426
428
|
fis = get_income_statements(ticker)
|
427
429
|
except:
|
428
430
|
print(" Failed, recovering...")
|
429
|
-
|
431
|
+
sleep_random(max_sleep=60)
|
430
432
|
try:
|
431
433
|
fis = get_income_statements(ticker)
|
432
434
|
except:
|
433
|
-
|
435
|
+
sleep_random(max_sleep=60)
|
434
436
|
try:
|
435
437
|
fis = get_income_statements(ticker)
|
436
438
|
except:
|
@@ -445,11 +447,11 @@ def get_financial_statements(ticker):
|
|
445
447
|
fcf = get_cashflow_statements(ticker)
|
446
448
|
except:
|
447
449
|
print(" Failed, recovering...")
|
448
|
-
|
450
|
+
sleep_random(max_sleep=60)
|
449
451
|
try:
|
450
452
|
fcf = get_cashflow_statements(ticker)
|
451
453
|
except:
|
452
|
-
|
454
|
+
sleep_random(max_sleep=60)
|
453
455
|
try:
|
454
456
|
fcf = get_cashflow_statements(ticker)
|
455
457
|
except:
|
siat/financials.py
CHANGED
@@ -1186,7 +1186,7 @@ def get_financial_rates(ticker):
|
|
1186
1186
|
fsdf=get_financial_statements(ticker)
|
1187
1187
|
except:
|
1188
1188
|
print(" Failed to get financial statements of",ticker,"\b, recovering")
|
1189
|
-
|
1189
|
+
sleep_random(max_sleep=60)
|
1190
1190
|
try:
|
1191
1191
|
fsdf=get_financial_statements(ticker)
|
1192
1192
|
except:
|
siat/financials2.py
CHANGED
@@ -103,6 +103,7 @@ if __name__=='__main__':
|
|
103
103
|
|
104
104
|
def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
105
105
|
category='profile',business_period='annual', \
|
106
|
+
items_included='all', \
|
106
107
|
scale1=10,scale2=10,dupont_sort='PM',
|
107
108
|
printout=True, \
|
108
109
|
#entry_sort=False, \
|
@@ -124,7 +125,8 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
124
125
|
可为基本信息'profile'、高管概况('officers')、分红('dividend')、股票分拆('split')、市场表现('market')、
|
125
126
|
财务状况('financial')、一般风险('risk')、ESG风险('esg')
|
126
127
|
|
127
|
-
business_period:业务期间类型,可为季报'quarterly'
|
128
|
+
business_period:业务期间类型,可为季报'quarterly',默认年报'annual'、最近的6次报告'recent', 所有'all'
|
129
|
+
items_included:默认输出所有报表项目,可以列表形式选择其中一部分。
|
128
130
|
scale1:仅用于杜邦分析,放大倍数(以便缩小与EM之间的数量级差异),用于Profit Margin,默认10
|
129
131
|
scale2:仅用于杜邦分析,放大倍数,用于Total Asset Turnover,默认10
|
130
132
|
dupont_sort:仅用于杜邦分析,用于排序指标,默认净利润率'PM',还可为总资产周转率'TAT'或权益乘数'EM'
|
@@ -179,7 +181,10 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
179
181
|
注意4:不同经济体上市公司年报季报日期不同,需要列示报表日期和类型(年报或季报)
|
180
182
|
|
181
183
|
"""
|
184
|
+
DEBUG=False
|
185
|
+
|
182
186
|
import numpy as np
|
187
|
+
import pandas as pd
|
183
188
|
|
184
189
|
#屏蔽函数内print信息输出的类
|
185
190
|
import os, sys
|
@@ -265,8 +270,11 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
265
270
|
# 分析资产负债表
|
266
271
|
fsdf=get_balance_sheet(symbol=tickers)
|
267
272
|
if fsdf is None:
|
268
|
-
|
269
|
-
|
273
|
+
print(f" #Warning(fs_analysis): failed to access financial info for {tickers}")
|
274
|
+
if test_yahoo_access():
|
275
|
+
print(f" Solution: if {tickers} are correct, then try again later")
|
276
|
+
else:
|
277
|
+
print(" Problem: no internet connection to Yahoo for retrieveing data")
|
270
278
|
return None
|
271
279
|
|
272
280
|
fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
|
@@ -302,8 +310,9 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
302
310
|
fsdf4=fsdf3[fsdf3['periodType']=='Quarterly']
|
303
311
|
elif business_period == 'annual':
|
304
312
|
fsdf4=fsdf3[fsdf3['periodType']=='Annual']
|
305
|
-
else:
|
306
|
-
fsdf4=fsdf3[fsdf3['periodType']
|
313
|
+
else: #'all'
|
314
|
+
#fsdf4=fsdf3[fsdf3['periodType'].isin(['Annual','Quarterly'])]
|
315
|
+
fsdf4=fsdf3
|
307
316
|
|
308
317
|
# 转置
|
309
318
|
fsdf4=fsdf4.T
|
@@ -349,7 +358,22 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
349
358
|
footnote2="Data source: Yahoo Finance, "+str(todaydt)
|
350
359
|
footnote='Note:\n'+footnote1+'\n'+footnote2
|
351
360
|
#print('\n',footnote1,'\n',footnote2)
|
352
|
-
|
361
|
+
|
362
|
+
# 将Item科目名称拆分加空格和转大写
|
363
|
+
fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
|
364
|
+
|
365
|
+
# 判断是否仅输出部分科目
|
366
|
+
if 'all' in items_included:
|
367
|
+
fsdf7=fsdf6
|
368
|
+
else:
|
369
|
+
mask=fsdf6['Item'].isin(items_included)
|
370
|
+
fsdf7=fsdf6[mask]
|
371
|
+
# 将Item列转为分类类型,指定顺序
|
372
|
+
fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
|
373
|
+
# 按分类顺序排序
|
374
|
+
fsdf7=fsdf7.sort_values(by='Item')
|
375
|
+
|
376
|
+
df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
|
353
377
|
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
354
378
|
data_font_size=data_font_size)
|
355
379
|
|
@@ -370,6 +394,11 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
370
394
|
fsdf=get_income_statements(symbol=tickers)
|
371
395
|
if fsdf is None:
|
372
396
|
print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
|
397
|
+
if test_yahoo_access():
|
398
|
+
print(f" Solution: if {tickers} are correct, then try again later")
|
399
|
+
else:
|
400
|
+
print(" Problem: no internet connection to Yahoo for retrieveing data")
|
401
|
+
|
373
402
|
return None
|
374
403
|
|
375
404
|
fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
|
@@ -430,7 +459,22 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
430
459
|
footnote2="Data source: Yahoo Finance, "+str(todaydt)
|
431
460
|
footnote='Note:\n'+footnote1+'\n'+footnote2
|
432
461
|
#print('\n',footnote1,'\n',footnote2)
|
433
|
-
|
462
|
+
|
463
|
+
# 将Item科目名称拆分加空格和转大写
|
464
|
+
fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
|
465
|
+
|
466
|
+
# 判断是否仅输出部分科目
|
467
|
+
if 'all' in items_included:
|
468
|
+
fsdf7=fsdf6
|
469
|
+
else:
|
470
|
+
mask=fsdf6['Item'].isin(items_included)
|
471
|
+
fsdf7=fsdf6[mask]
|
472
|
+
# 将Item列转为分类类型,指定顺序
|
473
|
+
fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
|
474
|
+
# 按分类顺序排序
|
475
|
+
fsdf7=fsdf7.sort_values(by='Item')
|
476
|
+
|
477
|
+
df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
|
434
478
|
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
435
479
|
data_font_size=data_font_size)
|
436
480
|
|
@@ -450,6 +494,11 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
450
494
|
fsdf=get_cashflow_statements(symbol=tickers)
|
451
495
|
if fsdf is None:
|
452
496
|
print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
|
497
|
+
if test_yahoo_access():
|
498
|
+
print(f" Solution: if {tickers} are correct, then try again later")
|
499
|
+
else:
|
500
|
+
print(" Problem: no internet connection to Yahoo for retrieveing data")
|
501
|
+
|
453
502
|
return None
|
454
503
|
|
455
504
|
fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
|
@@ -510,7 +559,22 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
510
559
|
footnote2="Data source: Yahoo Finance, "+str(todaydt)
|
511
560
|
footnote='Note:\n'+footnote1+'\n'+footnote2
|
512
561
|
#print('\n',footnote1,'\n',footnote2)
|
513
|
-
|
562
|
+
|
563
|
+
# 将Item科目名称拆分加空格和转大写
|
564
|
+
fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
|
565
|
+
|
566
|
+
# 判断是否仅输出部分科目
|
567
|
+
if 'all' in items_included:
|
568
|
+
fsdf7=fsdf6
|
569
|
+
else:
|
570
|
+
mask=fsdf6['Item'].isin(items_included)
|
571
|
+
fsdf7=fsdf6[mask]
|
572
|
+
# 将Item列转为分类类型,指定顺序
|
573
|
+
fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
|
574
|
+
# 按分类顺序排序
|
575
|
+
fsdf7=fsdf7.sort_values(by='Item')
|
576
|
+
|
577
|
+
df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
|
514
578
|
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
515
579
|
data_font_size=data_font_size)
|
516
580
|
return fsdf6
|
@@ -543,11 +607,16 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
543
607
|
|
544
608
|
# 股票可为单只股票(单只股票深度分析)
|
545
609
|
if isinstance(tickers,str):
|
546
|
-
print(" Getting financial rates for financial summary of",tickers,"
|
610
|
+
print(" Getting financial rates for financial summary of",tickers,"...")
|
547
611
|
with HiddenPrints():
|
548
612
|
fsdf=get_financial_rates(tickers)
|
549
613
|
if fsdf is None:
|
550
614
|
print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
|
615
|
+
if test_yahoo_access():
|
616
|
+
print(f" Solution: if {tickers} are correct, then try again later")
|
617
|
+
else:
|
618
|
+
print(" Problem: no internet connection to Yahoo for retrieveing data")
|
619
|
+
|
551
620
|
return None
|
552
621
|
|
553
622
|
fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
|
@@ -593,8 +662,10 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
593
662
|
fsdf4=fsdf3[fsdf3['periodType']=='Annual']
|
594
663
|
elif business_period == 'all':
|
595
664
|
fsdf4=fsdf3
|
665
|
+
#fsdf4=fsdf3[fsdf3['periodType'].isin(['Annual','Quarterly'])]
|
596
666
|
else:
|
597
|
-
fsdf4=fsdf3[fsdf3['periodType']=='Annual']
|
667
|
+
#fsdf4=fsdf3[fsdf3['periodType']=='Annual']
|
668
|
+
fsdf4=fsdf3
|
598
669
|
|
599
670
|
# 转置
|
600
671
|
fsdf4=fsdf4.T
|
@@ -620,7 +691,22 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
620
691
|
footnote3="Data source: Yahoo Finance, "+todaydt
|
621
692
|
footnote='Note:\n'+footnote1+'\n'+footnote2+'\n'+footnote3
|
622
693
|
#print('\n',footnote1,'\n',footnote2,'\n',footnote3)
|
623
|
-
|
694
|
+
|
695
|
+
# 将Item科目名称拆分加空格和转大写
|
696
|
+
fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
|
697
|
+
|
698
|
+
# 判断是否仅输出部分科目
|
699
|
+
if 'all' in items_included:
|
700
|
+
fsdf7=fsdf6
|
701
|
+
else:
|
702
|
+
mask=fsdf6['Item'].isin(items_included)
|
703
|
+
fsdf7=fsdf6[mask]
|
704
|
+
# 将Item列转为分类类型,指定顺序
|
705
|
+
fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
|
706
|
+
# 按分类顺序排序
|
707
|
+
fsdf7=fsdf7.sort_values(by='Item')
|
708
|
+
|
709
|
+
df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
|
624
710
|
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
625
711
|
data_font_size=data_font_size)
|
626
712
|
return fsdf6
|
@@ -633,13 +719,20 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
633
719
|
business_period=business_period.lower()
|
634
720
|
fsdf=pd.DataFrame()
|
635
721
|
for t in tickers:
|
636
|
-
print(" Getting financial rates for financial summary of",t,"
|
722
|
+
print(" Getting financial rates for financial summary of",t,"...")
|
637
723
|
with HiddenPrints():
|
638
724
|
dftmp=get_financial_rates(t)
|
639
725
|
if dftmp is None:
|
640
726
|
print(" #Warning(fs_analysis): financial info unaccessible for",t)
|
727
|
+
if test_yahoo_access():
|
728
|
+
print(f" Solution: if {t} are correct, then try again later")
|
729
|
+
else:
|
730
|
+
print(" Problem: no internet connection to Yahoo for retrieveing data")
|
641
731
|
return None
|
642
732
|
|
733
|
+
if not last_in_list(t,tickers):
|
734
|
+
sleep_random(max_sleep=60)
|
735
|
+
|
643
736
|
if business_period=='recent':
|
644
737
|
dftmp2=dftmp.tail(1)
|
645
738
|
elif business_period=='annual':
|
@@ -721,8 +814,23 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
721
814
|
footnote2="ROx/EM/turnover rates are based on periodic mean, others on end-term"
|
722
815
|
footnote3="Data source: Yahoo Finance, "+str(todaydt)
|
723
816
|
footnote='Note:\n'+footnote1+'\n'+footnote2+'\n'+footnote3
|
724
|
-
#print('\n',footnote1,'\n',footnote2,'\n',footnote3)
|
725
|
-
|
817
|
+
#print('\n',footnote1,'\n',footnote2,'\n',footnote3)
|
818
|
+
|
819
|
+
# 将Item科目名称拆分加空格和转大写
|
820
|
+
fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
|
821
|
+
|
822
|
+
# 判断是否仅输出部分科目
|
823
|
+
if 'all' in items_included:
|
824
|
+
fsdf7=fsdf6
|
825
|
+
else:
|
826
|
+
mask=fsdf6['Item'].isin(items_included)
|
827
|
+
fsdf7=fsdf6[mask]
|
828
|
+
# 将Item列转为分类类型,指定顺序
|
829
|
+
fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
|
830
|
+
# 按分类顺序排序
|
831
|
+
fsdf7=fsdf7.sort_values(by='Item')
|
832
|
+
|
833
|
+
df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
|
726
834
|
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
727
835
|
data_font_size=data_font_size)
|
728
836
|
return fsdf6
|
@@ -756,11 +864,16 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
756
864
|
|
757
865
|
# 股票可为单只股票(单只股票深度分析)
|
758
866
|
if isinstance(tickers,str):
|
759
|
-
print(" Getting financial rates for financial indicators of",tickers,"
|
867
|
+
print(" Getting financial rates for financial indicators of",tickers,"...")
|
760
868
|
with HiddenPrints():
|
761
869
|
fsdf=get_financial_rates(tickers)
|
762
870
|
if fsdf is None:
|
763
871
|
print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
|
872
|
+
if test_yahoo_access():
|
873
|
+
print(f" Solution: if {tickers} are correct, then try again later")
|
874
|
+
else:
|
875
|
+
print(" Problem: no internet connection to Yahoo for retrieveing data")
|
876
|
+
|
764
877
|
return None
|
765
878
|
|
766
879
|
fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
|
@@ -803,8 +916,10 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
803
916
|
fsdf4=fsdf3[fsdf3['periodType']=='Annual']
|
804
917
|
elif business_period == 'all':
|
805
918
|
fsdf4=fsdf3
|
919
|
+
#fsdf4=fsdf3[fsdf3['periodType'].isin(['Annual','Quarterly'])]
|
806
920
|
else:
|
807
|
-
fsdf4=fsdf3[fsdf3['periodType']=='Annual']
|
921
|
+
#fsdf4=fsdf3[fsdf3['periodType']=='Annual']
|
922
|
+
fsdf4=fsdf3
|
808
923
|
|
809
924
|
# 转置
|
810
925
|
fsdf4=fsdf4.T
|
@@ -829,8 +944,23 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
829
944
|
footnote2="ROx/EM/turnover rates are based on periodic mean, others on end-term"
|
830
945
|
footnote3="Data source: Yahoo Finance, "+str(todaydt)
|
831
946
|
footnote='Note:\n'+footnote1+'\n'+footnote2+'\n'+footnote3
|
832
|
-
#print('\n',footnote1,'\n',footnote2,'\n',footnote3)
|
833
|
-
|
947
|
+
#print('\n',footnote1,'\n',footnote2,'\n',footnote3)
|
948
|
+
|
949
|
+
# 将Item科目名称拆分加空格和转大写
|
950
|
+
fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
|
951
|
+
|
952
|
+
# 判断是否仅输出部分科目
|
953
|
+
if 'all' in items_included:
|
954
|
+
fsdf7=fsdf6
|
955
|
+
else:
|
956
|
+
mask=fsdf6['Item'].isin(items_included)
|
957
|
+
fsdf7=fsdf6[mask]
|
958
|
+
# 将Item列转为分类类型,指定顺序
|
959
|
+
fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
|
960
|
+
# 按分类顺序排序
|
961
|
+
fsdf7=fsdf7.sort_values(by='Item')
|
962
|
+
|
963
|
+
df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
|
834
964
|
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
835
965
|
data_font_size=data_font_size)
|
836
966
|
return fsdf6
|
@@ -842,18 +972,28 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
842
972
|
|
843
973
|
business_period=business_period.lower()
|
844
974
|
fsdf=pd.DataFrame()
|
975
|
+
print(" Working on financial rates, it may take long time ...")
|
976
|
+
|
845
977
|
for t in tickers:
|
846
|
-
print(" Getting financial rates for financial indicators of",t,"
|
978
|
+
print(" Getting financial rates for financial indicators of",t,"...")
|
847
979
|
with HiddenPrints():
|
848
980
|
dftmp=get_financial_rates(t)
|
849
981
|
if dftmp is None:
|
850
982
|
print(" #Warning(fs_analysis): financial info unaccessible for",t)
|
983
|
+
if test_yahoo_access():
|
984
|
+
print(f" Solution: if {t} are correct, then try again later")
|
985
|
+
else:
|
986
|
+
print(" Problem: no internet connection to Yahoo for retrieveing data")
|
987
|
+
|
851
988
|
return None
|
852
989
|
|
853
|
-
if dftmp
|
854
|
-
print(" #Warning(fs_analysis):
|
990
|
+
if len(dftmp) == 0:
|
991
|
+
print(" #Warning(fs_analysis): zero financial indicators found for stock",t)
|
855
992
|
continue
|
856
993
|
|
994
|
+
if not last_in_list(t,tickers):
|
995
|
+
sleep_random(max_sleep=60)
|
996
|
+
|
857
997
|
if business_period=='recent':
|
858
998
|
dftmp2=dftmp.tail(1)
|
859
999
|
elif business_period=='annual':
|
@@ -932,8 +1072,26 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
932
1072
|
footnote2="ROx/EM/turnover rates are based on periodic mean, others on end-term"
|
933
1073
|
footnote3="Data source: Yahoo Finance, "+str(todaydt)
|
934
1074
|
footnote='Note:\n'+footnote1+'\n'+footnote2+'\n'+footnote3
|
935
|
-
#print('\n',footnote1,'\n',footnote2,'\n',footnote3)
|
936
|
-
|
1075
|
+
#print('\n',footnote1,'\n',footnote2,'\n',footnote3)
|
1076
|
+
|
1077
|
+
# 将Item科目名称拆分加空格和转大写
|
1078
|
+
fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
|
1079
|
+
|
1080
|
+
# 将Item科目名称拆分加空格和转大写
|
1081
|
+
fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
|
1082
|
+
|
1083
|
+
# 判断是否仅输出部分科目
|
1084
|
+
if 'all' in items_included:
|
1085
|
+
fsdf7=fsdf6
|
1086
|
+
else:
|
1087
|
+
mask=fsdf6['Item'].isin(items_included)
|
1088
|
+
fsdf7=fsdf6[mask]
|
1089
|
+
# 将Item列转为分类类型,指定顺序
|
1090
|
+
fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
|
1091
|
+
# 按分类顺序排序
|
1092
|
+
fsdf7=fsdf7.sort_values(by='Item')
|
1093
|
+
|
1094
|
+
df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
|
937
1095
|
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
938
1096
|
data_font_size=data_font_size)
|
939
1097
|
return fsdf6
|
@@ -949,14 +1107,23 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
949
1107
|
|
950
1108
|
business_period=business_period.lower()
|
951
1109
|
fsdf=pd.DataFrame()
|
1110
|
+
print(" Working on dupont identity, it may take long time ...")
|
952
1111
|
for t in tickers:
|
953
|
-
print(" Getting financial rates for dupont identity of",t,"
|
1112
|
+
print(" Getting financial rates for dupont identity of",t,"...")
|
954
1113
|
with HiddenPrints():
|
955
1114
|
dftmp=get_financial_rates(t)
|
956
1115
|
if dftmp is None:
|
957
1116
|
print(" #Warning(fs_analysis): financial info unaccessible for",t)
|
1117
|
+
if test_yahoo_access():
|
1118
|
+
print(f" Solution: if {t} are correct, then try again later")
|
1119
|
+
else:
|
1120
|
+
print(" Problem: no internet connection to Yahoo for retrieveing data")
|
1121
|
+
|
958
1122
|
return None
|
959
1123
|
|
1124
|
+
if not last_in_list(t,tickers):
|
1125
|
+
sleep_random(max_sleep=60)
|
1126
|
+
|
960
1127
|
if business_period=='recent':
|
961
1128
|
dftmp2=dftmp.tail(1)
|
962
1129
|
elif business_period=='annual':
|
@@ -1064,7 +1231,11 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
|
|
1064
1231
|
footnote1="Based on exchange's local accounting standards, EM/TAT are on periodic mean"
|
1065
1232
|
footnote2="Data source: Yahoo Finance, "+str(todaydt)
|
1066
1233
|
footnote='Note:\n'+footnote1+'\n'+footnote2
|
1067
|
-
#print('\n',footnote1,'\b.',footnote2)
|
1234
|
+
#print('\n',footnote1,'\b.',footnote2)
|
1235
|
+
|
1236
|
+
# 将Item科目名称拆分加空格和转大写
|
1237
|
+
df['Item']=df['Item'].apply(lambda x: text_separate(x))
|
1238
|
+
|
1068
1239
|
df_display_CSS(df,titletxt=titletxt,footnote=footnote,facecolor=facecolor,decimals=4, \
|
1069
1240
|
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
1070
1241
|
data_font_size=data_font_size)
|
siat/stock.py
CHANGED
@@ -127,7 +127,7 @@ def get_profile(ticker):
|
|
127
127
|
dic=tp.info
|
128
128
|
except:
|
129
129
|
print(f" #Error(get_profile): failed to retrieve info for {ticker}")
|
130
|
-
print(" Solution:
|
130
|
+
print(" Solution: try get_stock_profile instead")
|
131
131
|
return None
|
132
132
|
|
133
133
|
if dic is None:
|
@@ -3542,6 +3542,7 @@ def get_stock_profile(ticker,info_type='basic',printout=True):
|
|
3542
3542
|
return None
|
3543
3543
|
if info is None:
|
3544
3544
|
print(" #Error(get_stock_profile): retrieved none info of",ticker)
|
3545
|
+
print(f" Solution: if {ticker} is correct, try again later!")
|
3545
3546
|
return None
|
3546
3547
|
if len(info) == 0:
|
3547
3548
|
print(" #Error(get_stock_profile): retrieved empty info of",ticker)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
siat/__init__ -20240701.py,sha256=gP5uajXnJesnH5SL0ZPwq_Qhv59AG1bs4qwZv26Fo2Y,2894
|
2
|
-
siat/__init__.py,sha256=
|
2
|
+
siat/__init__.py,sha256=LZKNrzk9Ibuzpox_Fy4zzxvAZLvtgVFeKMEY5go6ns0,2235
|
3
3
|
siat/__init__.py.backup_20250214.py,sha256=pIo4CV3lNPKIhitmhIh_6aAfZrmzQWGNDcEnvZ7GXoc,3216
|
4
4
|
siat/allin.py,sha256=--32Bt2Mfg7l38w7X9cLJCdWtYRB3tTtVHnS9WnqKDI,3035
|
5
5
|
siat/alpha_vantage_test.py,sha256=tKr-vmuFH3CZAqwmISz6jzjPHzV1JJl3sPfZdz8aTfM,747
|
@@ -19,7 +19,7 @@ siat/capm_beta.py,sha256=cxXdRVBQBllhbfz1LeTJAIWvyRYhW54nhtNUXv4HwS0,29063
|
|
19
19
|
siat/capm_beta2.py,sha256=wGF_HmK_AiGWjpSAx79XHIxDghtI_ueYozvh06-2JEQ,33707
|
20
20
|
siat/capm_beta_test.py,sha256=ImR0c5mc4hIl714XmHztdl7qg8v1E2lycKyiqnFj6qs,1745
|
21
21
|
siat/cmat_commons.py,sha256=Nj9Kf0alywaztVoMVeVVL_EZk5jRERJy8R8kBw88_Tg,38116
|
22
|
-
siat/common.py,sha256=
|
22
|
+
siat/common.py,sha256=J0qSvKtPS1gAfb2_GJNKxFkWJJaNbkQzg4fzaBvKwjM,183440
|
23
23
|
siat/compare_cross.py,sha256=3iP9TH2h3w27F2ARZc7FjKcErYCzWRc-TPiymOyoVtw,24171
|
24
24
|
siat/compare_cross_test.py,sha256=xra5XYmQGEtfIZL2h-GssdH2hLdFIhG3eoCrkDrL3gY,3473
|
25
25
|
siat/concepts_iwencai.py,sha256=m1YEDtECRT6FqtzlKm91pt2I9d3Z_XoP59BtWdRdu8I,3061
|
@@ -40,11 +40,11 @@ siat/fama_french.py,sha256=aUTC-67t_CEPbLk4u79woW_zfZ7OCP6Fo4z5EdWCSkQ,48051
|
|
40
40
|
siat/fama_french_test.py,sha256=M4O23lBKsJxhWHRluwCb3l7HSEn3OFTjzGMpehcevRg,4678
|
41
41
|
siat/fin_stmt2_yahoo.py,sha256=LGmspk0nKyz4X87MtcovZXUfMQkAvrWINuxR4HQ8PI8,41178
|
42
42
|
siat/financial_base.py,sha256=A1rV7XQOVFpCXCV-T6Ge0QeF897hINiu0olN1XWeaFk,41287
|
43
|
-
siat/financial_statements.py,sha256=
|
43
|
+
siat/financial_statements.py,sha256=7cv0z3djnfWsbnvW04ScrWSjCLEyUFrbGgQ6NtclyD0,25512
|
44
44
|
siat/financial_statements_test.py,sha256=FLhx8JD-tVVWSBGux6AMz1jioXX4U4bp9DmgFHYXb_w,716
|
45
|
-
siat/financials.py,sha256=
|
45
|
+
siat/financials.py,sha256=jIkK8nhjQa5Z1SLeJ2rSQsSBswMgredvX2lZ6-1-Y7E,86267
|
46
46
|
siat/financials2 - 副本.py,sha256=dKlNjIfKeoSy055fQ6E6TUj9HEoO5Ney9grD84J5kfk,14389
|
47
|
-
siat/financials2.py,sha256=
|
47
|
+
siat/financials2.py,sha256=xCxqubwCNdfS7WyIb5IXTFonMZfw8FM9F8TCIkAruhk,58795
|
48
48
|
siat/financials_china.py,sha256=iHF3lEESTK9DLWLBHFpyxn3S_dO2sNBE89xqaVYpNCw,192459
|
49
49
|
siat/financials_china2.py,sha256=VvkzkjZeH84zwypR7ReldgJeZ7jnNw0qkzebvWMPm10,94956
|
50
50
|
siat/financials_china2_test.py,sha256=Erz5k4LyOplBBvYls2MypuqHpVNJ3daiLdyeJezNPu0,2722
|
@@ -110,7 +110,7 @@ siat/security_trend2-20240620.py,sha256=QVnEcb7AyVbO77jVqfFsJffGXrX8pgJ9xCfoAKmW
|
|
110
110
|
siat/security_trend2.py,sha256=8-Z-PWaX8fjnyAyfxEp3qXdVllgDpRISOASKEn7Zeoc,30706
|
111
111
|
siat/setup.py,sha256=up65rQGLmTBkhtaMLowjoQXYmIsnycnm4g1SYmeQS6o,1335
|
112
112
|
siat/shenwan index history test.py,sha256=JCVAzOSEldHalhSFa3pqD8JI_8_djPMQOxpkuYU-Esg,1418
|
113
|
-
siat/stock.py,sha256=
|
113
|
+
siat/stock.py,sha256=ixl9NWhFS-z9cQUnBOaQ_u2gqsCiG02zZZrLVBSqPwQ,159941
|
114
114
|
siat/stock_advice_linear.py,sha256=-twT7IGP-NEplkL1WPSACcNJjggRB2j4mlAQCkzOAuo,31655
|
115
115
|
siat/stock_base.py,sha256=uISvbRyOGy8p9QREA96CVydgflBkn5L3OXOGKl8oanc,1312
|
116
116
|
siat/stock_china.py,sha256=85Ggb21E2mrCYMdSSTTrkoyyLGXMK2V-BtlweHomSRg,93460
|
@@ -145,8 +145,8 @@ siat/valuation_china.py,sha256=eSKIDckyjG8QkENlW_OKkqbQHno8pzDcomBO9iGNJVM,83079
|
|
145
145
|
siat/valuation_market_china_test.py,sha256=gbJ0ioauuo4koTPH6WKUkqcXiQPafnbhU5eKJ6lpdLA,1571
|
146
146
|
siat/var_model_validation.py,sha256=R0caWnuZarrRg9939hxh3vJIIpIyPfvelYmzFNZtPbo,14910
|
147
147
|
siat/yf_name.py,sha256=laNKMTZ9hdenGX3IZ7G0a2RLBKEWtUQJFY9CWuk_fp8,24058
|
148
|
-
siat-3.9.
|
149
|
-
siat-3.9.
|
150
|
-
siat-3.9.
|
151
|
-
siat-3.9.
|
152
|
-
siat-3.9.
|
148
|
+
siat-3.9.32.dist-info/LICENSE,sha256=NTEMMROY9_4U1szoKC3N2BLHcDd_o5uTgqdVH8tbApw,1071
|
149
|
+
siat-3.9.32.dist-info/METADATA,sha256=nrawbbVkm08ig_snc7NU6XTo8pCuFWPU2FmgDCBhKxk,8396
|
150
|
+
siat-3.9.32.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
151
|
+
siat-3.9.32.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
|
152
|
+
siat-3.9.32.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|