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 CHANGED
@@ -40,7 +40,7 @@ if os == 'windows':
40
40
  srcfile=srcpath1+'/'+tagfile
41
41
  else:
42
42
  srcpath1=srcpath
43
- srcfile=srcpath1+'/'+file
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
  #==============================================================================
@@ -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
- time.sleep(5)
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
- time.sleep(5)
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
- time.sleep(5)
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
- time.sleep(5)
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
- time.sleep(5)
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
- time.sleep(5)
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
- import time; time.sleep(3)
412
+ sleep_random(max_sleep=60)
411
413
  try:
412
414
  fbs = get_balance_sheet(ticker)
413
415
  except:
414
- import time; time.sleep(5)
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
- import time; time.sleep(3)
431
+ sleep_random(max_sleep=60)
430
432
  try:
431
433
  fis = get_income_statements(ticker)
432
434
  except:
433
- import time; time.sleep(5)
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
- import time; time.sleep(3)
450
+ sleep_random(max_sleep=60)
449
451
  try:
450
452
  fcf = get_cashflow_statements(ticker)
451
453
  except:
452
- import time; time.sleep(5)
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
- import time; time.sleep(5)
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',年报'annual'、最近的6次报告'recent', 所有'all'
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
- #print(" #Warning(fs_analysis): financial info unaccessible for",tickers,"\b, which needs connection to Yahoo")
269
- print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
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']=='Annual']
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
- df_display_CSS(fsdf6,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
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
- df_display_CSS(fsdf6,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
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
- df_display_CSS(fsdf6,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
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
- df_display_CSS(fsdf6,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
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
- df_display_CSS(fsdf6,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
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
- df_display_CSS(fsdf6,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
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 is None:
854
- print(" #Warning(fs_analysis): none of financial indicators found for stock",t)
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
- df_display_CSS(fsdf6,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
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: need access to Yahoo")
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,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: siat
3
- Version: 3.9.21
3
+ Version: 3.9.32
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
@@ -1,5 +1,5 @@
1
1
  siat/__init__ -20240701.py,sha256=gP5uajXnJesnH5SL0ZPwq_Qhv59AG1bs4qwZv26Fo2Y,2894
2
- siat/__init__.py,sha256=tpSBf8BYpWOzBDF2iNQ4tlVxjx7bmkVQ3kPUu9X3iog,2227
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=XDt269wDd8L_sd4FWqFw2N5bPA6v051c2YnIxIJ_2V0,181169
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=xx0SMpFqAMKm6cj8uYeG2RpJE6G-RoJ3NWa33UyaVMk,25414
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=hcXcwozYhfMtW6cTE2bDp5R80-IEKAyUHFO6mJ87GXQ,86267
45
+ siat/financials.py,sha256=jIkK8nhjQa5Z1SLeJ2rSQsSBswMgredvX2lZ6-1-Y7E,86267
46
46
  siat/financials2 - 副本.py,sha256=dKlNjIfKeoSy055fQ6E6TUj9HEoO5Ney9grD84J5kfk,14389
47
- siat/financials2.py,sha256=YF-A-5iSTzLXTFI0sDGju4_6T87wWC9IlFd4fSXbJXw,50805
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=itQquZpB8B086nmzzGadppGKsTE6Y7aGizhamGIXs0I,159860
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.21.dist-info/LICENSE,sha256=NTEMMROY9_4U1szoKC3N2BLHcDd_o5uTgqdVH8tbApw,1071
149
- siat-3.9.21.dist-info/METADATA,sha256=BlxRIjZzBPns5W-qJOwLmdZkrEvbSYlMHwXZT5AF51E,8396
150
- siat-3.9.21.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
151
- siat-3.9.21.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
152
- siat-3.9.21.dist-info/RECORD,,
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