siat 3.8.36__py3-none-any.whl → 3.8.42__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
@@ -66,10 +66,10 @@ class HiddenPrints:
66
66
  sys.stdout = self._original_stdout
67
67
 
68
68
  if not restart:
69
- print("Successfully enabled siat v{}".format(current_version))
69
+ print(" Successfully enabled siat v{}".format(current_version))
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 run this command again")
74
74
 
75
75
  #==============================================================================
siat/common.py CHANGED
@@ -4697,7 +4697,7 @@ def df_save(df,file="df"):
4697
4697
  df.to_pickle(file_name)
4698
4698
 
4699
4699
  import os; path=os.getcwd()
4700
- print(" Data is saved to file",path+"\\"+file_name)
4700
+ print(" Saved to",path+"\\"+file_name)
4701
4701
  except:
4702
4702
  print(" #Error(df_save): failed to save data to file",file_name)
4703
4703
 
siat/financials.py CHANGED
@@ -90,7 +90,7 @@ def compare_history(tickers,items, \
90
90
  ticker2=tickers[1]
91
91
  ticker_num=2
92
92
  if len(tickers) == 0:
93
- print(" #Error(): no stock code found",tickers)
93
+ print(" #Error(compare_history): no stock code found",tickers)
94
94
  return None,None
95
95
  else:
96
96
  ticker1=tickers
@@ -103,7 +103,7 @@ def compare_history(tickers,items, \
103
103
  item2=items[1]
104
104
  item_num=2
105
105
  if len(items) == 0:
106
- print(" #Error(): no analytical item found",items)
106
+ print(" #Error(compare_history): no analytical item found",items)
107
107
  return None,None
108
108
  else:
109
109
  item1=items
@@ -181,7 +181,7 @@ def compare_history(tickers,items, \
181
181
  collabel=ectranslate(item1)
182
182
  ylabeltxt=''
183
183
  #titletxt=ticker_name(ticker1)+texttranslate(": 基于年(季)报的业绩历史")
184
- titletxt=ticker_name(ticker1)+": 基于财务报表的业绩历史"
184
+ titletxt=ticker_name(ticker1)+": 财报业绩历史"
185
185
  #footnote=texttranslate("数据来源: 雅虎财经,")+' '+str(today)
186
186
  footnote="数据来源: 雅虎财经,"+' '+str(today)
187
187
 
@@ -205,7 +205,7 @@ def compare_history(tickers,items, \
205
205
  label2=ectranslate(item2)
206
206
  ylabeltxt=''
207
207
  #titletxt=ticker_name(ticker1)+texttranslate(": 基于年(季)报的业绩历史对比")
208
- titletxt=ticker_name(ticker1)+": 基于财务报表的业绩历史对比"
208
+ titletxt=ticker_name(ticker1)+": 财报业绩历史对比"
209
209
  #footnote=texttranslate("数据来源: 雅虎财经,")+' '+str(today)
210
210
  footnote="数据来源: 雅虎财经,"+' '+str(today)
211
211
 
@@ -243,7 +243,7 @@ def compare_history(tickers,items, \
243
243
  label2=ectranslate(item2)
244
244
  ylabeltxt=''
245
245
  #titletxt=ticker_name(ticker1)+" vs "+ticker_name(ticker2)+texttranslate(": 基于年(季)报的业绩历史对比")
246
- titletxt=ticker_name(ticker1)+" vs "+ticker_name(ticker2)+": 基于财务报表的业绩历史对比"
246
+ titletxt=ticker_name(ticker1)+" vs "+ticker_name(ticker2)+": 财报业绩历史对比"
247
247
  #footnote=texttranslate("数据来源: 雅虎财经,")+' '+str(today)
248
248
  footnote="数据来源: 雅虎财经,"+' '+str(today)
249
249
 
@@ -260,25 +260,26 @@ if __name__ == '__main__':
260
260
 
261
261
  #==============================================================================
262
262
  if __name__ == '__main__':
263
- tickers=['AAPL','MSFT','WMT']
263
+ ticker=['AAPL','MSFT','WMT']
264
264
  itemk='Current Ratio'
265
265
  itemk='Employees'
266
+ indicator=itemk='PEG'
266
267
 
267
268
  multicolor=False
268
269
 
269
270
  tickers=['AMZN','EBAY']
270
271
  itemk='IGR'
272
+
271
273
  datatag=True
272
274
  tag_offset=0.01
273
275
  graph=True
274
276
  axisamp=1.3
275
277
 
276
-
277
- itemk='IGR'
278
278
 
279
- def compare_snapshot(tickers,itemk, \
279
+ def compare_snapshot(ticker,indicator, \
280
+ facecolor='lightblue',
280
281
  datatag=True,tag_offset=0.01, \
281
- graph=True,axisamp=1.2,px=False, \
282
+ graph=True,axisamp=1.2,px=True, \
282
283
  printout=True,numberPerLine=10):
283
284
  """
284
285
  功能:比较多个股票的快照数据,绘制水平柱状图
@@ -287,10 +288,13 @@ def compare_snapshot(tickers,itemk, \
287
288
  tag_offset=0.01:标记的数值距离图形的距离,若不理想可以手动调节,可为最大值1%-5%
288
289
  graph:是否将结果绘图,默认True
289
290
  axisamp:绘图时横轴放大系数,默认1.2。若标记数值超出右边界则增加数值,也可能需要负数数值
290
- px:是否使用plotly-express工具绘图,默认False。其优点是无需调整axisamp,缺点是无法保存绘图结果在Jupyter Notebook中
291
+ px:是否使用plotly-express工具绘图,默认True。
292
+ 其优点是无需调整axisamp,缺点是无法保存绘图结果在Jupyter Notebook中。
291
293
  printout:是否显示哪些股票找到或未找到相关数据,默认True
292
294
  numberPerLine:在显示相关数据时,每行显示的股票代码或名称个数,默认10
293
295
  """
296
+ tickers=ticker; itemk=indicator
297
+
294
298
  #检查股票代码列表
295
299
  if not isinstance(tickers,list):
296
300
  print(" #Error(compare_snapshot): need more stock codes in",tickers)
@@ -336,13 +340,18 @@ def compare_snapshot(tickers,itemk, \
336
340
  'TTM Price to Sales':'priceToSalesTrailing12Months', \
337
341
  'beta':'beta','52-Week Change':'52WeekChange', \
338
342
  'Trailing PE':'trailingPE','Forward PE':'forwardPE', \
339
- 'PEG':'pegRatio',
340
- #'IGR':'IGR','SGR':'SGR',
343
+ #'PEG':'pegRatio',#经常取不到数据
344
+ #'IGR':'IGR','SGR':'SGR',#另起其他命令处理
341
345
  }
346
+
342
347
  itemlist=list(itemdict.keys())
343
348
  if itemk not in itemlist:
344
- print(" #Error(compare_snapshot): unsupported rate for",itemk)
345
- print(" Supported rates are as follows:\n",itemlist)
349
+ print(" #Error(compare_snapshot): unsupported indicator",itemk)
350
+ #print(" Supported indicators:\n",itemlist)
351
+ print(" Supported indicators:")
352
+ #printInLine(itemlist,numberPerLine=5,leadingBlanks=2)
353
+ printInLine_md(itemlist,numberPerLine=5,colalign='left',font_size='16px')
354
+
346
355
  return None
347
356
 
348
357
  item=itemdict[itemk]
@@ -353,7 +362,7 @@ def compare_snapshot(tickers,itemk, \
353
362
 
354
363
  notfoundlist=[]
355
364
  total0=len(tickers)
356
- print("Searching info of",itemk,"for specified stocks ...")
365
+ print(" Searching",itemk,"for specified stocks ...")
357
366
  for t in tickers:
358
367
 
359
368
  current=tickers.index(t)
@@ -389,10 +398,86 @@ def compare_snapshot(tickers,itemk, \
389
398
  df=df.append(row,ignore_index=True)
390
399
  except:
391
400
  df=df._append(row,ignore_index=True)
392
-
401
+
402
+ # 尝试恢复失败的股票信息 1
403
+ if len(notfoundlist) > 0:
404
+ print("\n Recovering info of",itemk,"for",notfoundlist,"...")
405
+ total0=len(notfoundlist)
406
+ tickers2=notfoundlist.copy(); notfoundlist=[]
407
+ for t in tickers2:
408
+
409
+ current=tickers2.index(t)
410
+ total=total0 - len(notfoundlist)
411
+ print_progress_percent(current,total,steps=10,leading_blanks=2)
412
+
413
+ try:
414
+ info=stock_info(t)
415
+ except:
416
+ notfoundlist=notfoundlist+[t]
417
+ continue
418
+ if (info is None) or (len(info)==0):
419
+ notfoundlist=notfoundlist+[t]
420
+ continue
421
+ try:
422
+ value=info[info.index == item]['Value'][0]
423
+ except:
424
+ try:
425
+ itemp=proxydict[item]
426
+ value=info[info.index == itemp]['Value'][0]
427
+ notfoundlist=notfoundlist+[t]
428
+ except:
429
+ notfoundlist=notfoundlist+[t]
430
+ continue
431
+
432
+ name=ticker_name(t)
433
+ row=pd.Series({'ticker':t,'item':item,'value':value,'name':name})
434
+ try:
435
+ df=df.append(row,ignore_index=True)
436
+ except:
437
+ df=df._append(row,ignore_index=True)
438
+
439
+
440
+ # 尝试恢复失败的股票信息 2
441
+ if len(notfoundlist) > 0:
442
+ print("\n Recovering info of",itemk,"for",notfoundlist,"...")
443
+ total0=len(notfoundlist)
444
+ tickers3=notfoundlist.copy(); notfoundlist=[]
445
+ for t in tickers3:
446
+
447
+ current=tickers3.index(t)
448
+ total=total0 - len(notfoundlist)
449
+ print_progress_percent(current,total,steps=10,leading_blanks=2)
450
+
451
+ try:
452
+ info=stock_info(t)
453
+ except:
454
+ notfoundlist=notfoundlist+[t]
455
+ continue
456
+ if (info is None) or (len(info)==0):
457
+ notfoundlist=notfoundlist+[t]
458
+ continue
459
+ try:
460
+ value=info[info.index == item]['Value'][0]
461
+ except:
462
+ try:
463
+ itemp=proxydict[item]
464
+ value=info[info.index == itemp]['Value'][0]
465
+ notfoundlist=notfoundlist+[t]
466
+ except:
467
+ notfoundlist=notfoundlist+[t]
468
+ continue
469
+
470
+ name=ticker_name(t)
471
+ row=pd.Series({'ticker':t,'item':item,'value':value,'name':name})
472
+ try:
473
+ df=df.append(row,ignore_index=True)
474
+ except:
475
+ df=df._append(row,ignore_index=True)
476
+
477
+ # 未找到任何股票信息
393
478
  if len(df) == 0:
394
- print("\n #Warning(compare_snapshot): no stock info not found for specified stocks")
395
- print(" Possible reasons: no internet access to data source - Yahoo Finance")
479
+ print("\n #Warning(compare_snapshot): no stock info found for specified stocks")
480
+ print(" Possible reasons: failed to access to or fetch info from Yahoo Finance")
396
481
  return None
397
482
 
398
483
  #处理小数点
@@ -406,12 +491,12 @@ def compare_snapshot(tickers,itemk, \
406
491
 
407
492
  #绘图
408
493
  if graph:
409
- print("Calculating and drawing graph, please wait ...")
494
+ print(" Calculating and rendering graph, please wait ...")
410
495
  colname='value'
411
496
 
412
497
  lang=check_language()
413
498
  if lang == 'Chinese':
414
- titletxt="企业横向对比: 业绩快照"
499
+ titletxt="企业对比: 指标快照"
415
500
  notestxt="注:财务指标为TTM数值"
416
501
  else:
417
502
  titletxt="Company Snapshot Comparison"
@@ -433,9 +518,9 @@ def compare_snapshot(tickers,itemk, \
433
518
  plot_barh(df,colname,titletxt,footnote,datatag=datatag,tag_offset=tag_offset,axisamp=axisamp)
434
519
  else:
435
520
  #在Spyder中可能无法显示
436
- titletxt="企业业绩快照:"+ectranslate(itemk)
521
+ titletxt="企业快照:"+ectranslate(itemk)
437
522
  footnote=notestxt+','+footnote1+str(today)
438
- plot_barh2(df,colname,titletxt,footnote)
523
+ plot_barh2(df,colname,titletxt,footnote,facecolor=facecolor)
439
524
 
440
525
  if (len(notfoundlist) > 0):
441
526
  foundlist=[]
@@ -453,9 +538,10 @@ def compare_snapshot(tickers,itemk, \
453
538
  printInLine(foundlist,numberPerLine=numberPerLine,leadingBlanks=2)
454
539
  """
455
540
  if (len(notfoundlist) > 0):
456
- print("Warning:",itemk,"info not found for the stocks below")
541
+ print(" [Warning]",itemk,"info not found for the stocks below:")
457
542
  notfoundlist_names=ticker_name(notfoundlist)
458
543
  printInLine(notfoundlist_names,numberPerLine=numberPerLine,leadingBlanks=2)
544
+ print(" [Solution] re-run the command with more stable internet connection")
459
545
 
460
546
  return df
461
547
 
@@ -463,11 +549,15 @@ if __name__ == '__main__':
463
549
  df=compare_snapshot(tickers,itemk)
464
550
 
465
551
  #==============================================================================
466
- def compare_snapshot2(tickers,itemk,graph=True):
552
+ def compare_snapshot2(ticker,indicator,graph=True):
467
553
  """
468
554
  功能:比较多个股票的快照数据,绘制水平柱状图
469
555
  itemk需要通过对照表转换为内部的item
556
+
557
+ 特点:与compare_snapshot相比如何?
470
558
  """
559
+ tickers=ticker; itemk=indicator
560
+
471
561
  #检查股票代码列表
472
562
  if not isinstance(tickers,list):
473
563
  print(" #Error(compare_snapshot2): need more stock codes in",tickers)
@@ -510,10 +600,11 @@ def compare_snapshot2(tickers,itemk,graph=True):
510
600
  'EV to Revenue':'enterpriseToRevenue','EV to EBITDA':'enterpriseToEbitda', \
511
601
  #市场看法
512
602
  'Current Price':'currentPrice','Price to Book':'priceToBook', \
513
- 'TTM Price to Sales':'priceToSalesTrailing12Months', \
603
+ #'TTM Price to Sales':'priceToSalesTrailing12Months', \
604
+ 'Price to Sales':'priceToSalesTrailing12Months', \
514
605
  'beta':'beta','52-Week Change':'52WeekChange', \
515
606
  'Trailing PE':'trailingPE','Forward PE':'forwardPE', \
516
- 'PEG':'pegRatio',
607
+ #'PEG':'pegRatio',
517
608
  #'IGR':'IGR','SGR':'SGR'
518
609
  }
519
610
  itemlist=list(itemdict.keys())
@@ -526,7 +617,10 @@ def compare_snapshot2(tickers,itemk,graph=True):
526
617
  import pandas as pd
527
618
  #import siat.stock_base as sb
528
619
  df=pd.DataFrame(columns=('ticker','item','value','name'))
620
+ print(f" Working on {indicator} for specified stocks ...")
529
621
  for t in tickers:
622
+ print_progress_percent2(t,tickers,steps=5,leading_blanks=4)
623
+
530
624
  try:
531
625
  info=stock_info(t)
532
626
  except:
@@ -568,14 +662,14 @@ def compare_snapshot2(tickers,itemk,graph=True):
568
662
 
569
663
  #绘图
570
664
  if graph:
571
- print("...Calculating and drawing graph, please wait ...")
665
+ print(" Calculating and rendering graph, please wait ...")
572
666
 
573
667
  df.rename(columns={'value':itemk},inplace=True)
574
668
  colname=itemk
575
669
  #titletxt="企业横向对比: "+ectranslate(itemk)+"(TTM)"
576
- titletxt="企业横向对比: "+ectranslate(itemk)
670
+ titletxt=text_lang("企业对比: ","Comparing Company: ")+ectranslate(itemk)
577
671
  import datetime; today=datetime.date.today()
578
- footnote="注:财务比率为TTM,数据来源: 雅虎财经, "+str(today)
672
+ footnote=text_lang("注:财务比率为TTM,数据来源: 雅虎财经, ","Note: TTM data, source: Yahoo Finance, ")+str(today)
579
673
  plot_barh2(df,colname,titletxt,footnote)
580
674
 
581
675
  return df
@@ -589,10 +683,12 @@ if __name__ == '__main__':
589
683
  tickers=["0883.HK","0857.HK","0386.HK",'XOM','2222.SR','OXY','BP','RDSA.AS']
590
684
  graph=True
591
685
 
592
- def compare_tax(tickers,graph=True,axisamp=1.3,px=False):
686
+ def compare_tax(ticker,graph=True,axisamp=1.3,px=True):
593
687
  """
594
688
  功能:比较公司最新的实际所得税率
595
689
  """
690
+ tickers=ticker
691
+
596
692
  #检查股票代码列表
597
693
  if not isinstance(tickers,list):
598
694
  print(" #Error(compare_tax): need more stock codes in",tickers)
@@ -604,7 +700,10 @@ def compare_tax(tickers,graph=True,axisamp=1.3,px=False):
604
700
  import siat.beta_adjustment as badj
605
701
  import pandas as pd
606
702
  df=pd.DataFrame(columns=('ticker','name','date','tax rate'))
703
+ print(" Working on tax info for specified stocks ...")
607
704
  for t in tickers:
705
+ print_progress_percent2(t,tickers,steps=5,leading_blanks=4)
706
+
608
707
  try:
609
708
  df0=badj.prepare_hamada_yahoo(t)
610
709
  except:
@@ -625,15 +724,15 @@ def compare_tax(tickers,graph=True,axisamp=1.3,px=False):
625
724
  df.set_index('key',inplace=True)
626
725
  #绘图
627
726
  if graph:
628
- print("...Calculating and drawing graph, please wait ...")
727
+ print(" Calculating and rendering graph, please wait ...")
629
728
  lang=check_language()
630
729
  colname='tax rate'
631
730
  if lang == 'Chinese':
632
- titletxt="企业横向对比: 实际所得税率"
731
+ titletxt="企业对比: 实际所得税率"
633
732
  itemk="实际所得税率"
634
733
  source_txt="数据来源: 雅虎财经,"
635
734
  else:
636
- titletxt=texttranslate("企业横向对比: 实际税率")
735
+ titletxt=texttranslate("企业对比: 实际税率")
637
736
  itemk=texttranslate("实际所得税率")
638
737
  source_txt=texttranslate("数据来源: 雅虎财经,")
639
738
 
@@ -654,7 +753,7 @@ def calc_igr_sgr(ticker):
654
753
 
655
754
 
656
755
  import siat.stock as stk
657
- sub_info=stk.get_stock_profile(ticker,info_type='fin_rates',graph=False)
756
+ sub_info=stk.get_stock_profile(ticker,info_type='fin_rates',printout=False)
658
757
  """
659
758
  #应对各种出错情形:执行出错,返回NoneType,返回空值
660
759
  try:
@@ -690,10 +789,12 @@ def calc_igr_sgr(ticker):
690
789
 
691
790
  return igr,sgr
692
791
 
693
- def compare_igr_sgr(tickers,graph=True,axisamp=1.0,px=False):
792
+ def compare_igr_sgr(ticker,graph=True,axisamp=1.0,px=True):
694
793
  """
695
794
  功能:比较公司TTM的IGR和SGR
696
795
  """
796
+ tickers=ticker
797
+
697
798
  #检查股票代码列表
698
799
  if not isinstance(tickers,list):
699
800
  print(" #Error(compare_igr_sgr): need more stock codes in",tickers)
@@ -704,7 +805,10 @@ def compare_igr_sgr(tickers,graph=True,axisamp=1.0,px=False):
704
805
 
705
806
  import pandas as pd
706
807
  df=pd.DataFrame(columns=('ticker','name','date','IGR','SGR'))
808
+ print(" Working on IGR & SGR for specified stocks ...")
707
809
  for t in tickers:
810
+ print_progress_percent2(t,tickers,steps=5,leading_blanks=4)
811
+
708
812
  try:
709
813
  igr,sgr=calc_igr_sgr(t)
710
814
  except:
@@ -727,11 +831,11 @@ def compare_igr_sgr(tickers,graph=True,axisamp=1.0,px=False):
727
831
  #绘图
728
832
  lang=check_language()
729
833
  if graph:
730
- print("\n...Calculating and drawing graph, please wait ...")
834
+ print("\n Calculating and rendering graph, please wait ...")
731
835
 
732
836
  colname='IGR'
733
837
  if lang == "Chinese":
734
- titletxt="企业横向对比: 内部增长率"
838
+ titletxt="企业对比: 内部增长率IGR"
735
839
  itemk="内部增长率(IGR)"
736
840
  source_txt="数据来源: 雅虎财经,"
737
841
  else:
@@ -755,7 +859,7 @@ def compare_igr_sgr(tickers,graph=True,axisamp=1.0,px=False):
755
859
  if graph:
756
860
  colname='SGR'
757
861
  if lang == 'Chinese':
758
- titletxt="企业横向对比: 可持续增长率"
862
+ titletxt="企业对比: 可持续增长率SGR"
759
863
  itemk="可持续增长率(SGR)"
760
864
  else:
761
865
  titletxt="Company Sustainable Growth Rate (SGR TTM)"
@@ -794,11 +898,11 @@ def get_PE(fsdf):
794
898
  import siat.security_prices as ssp
795
899
  prices=ssp.get_price(ticker, fromdate, todate)
796
900
  if prices is None:
797
- print("#Error(get_PE): retrieving stock price failed for",ticker,fromdate,todate,"\b, recovering...")
901
+ print(" #Error(get_PE): retrieving stock price failed for",ticker,fromdate,todate,"\b, recovering...")
798
902
  import time; time.sleep(5)
799
903
  prices=ssp.get_price(ticker, fromdate, todate)
800
904
  if prices is None:
801
- print("#Error(get_PE): failed retrieving stock price, retrying stopped")
905
+ print(" #Error(get_PE): failed retrieving stock price, retrying stopped")
802
906
  import numpy as np
803
907
  fsdf['BasicPE']=np.nan
804
908
  fsdf['DilutedPE']=np.nan
@@ -873,13 +977,13 @@ def calc_DebtToAsset(fsdf):
873
977
  try:
874
978
  fsdf1['Debt to Asset']=round(fsdf1['TotalLiabilities']/fsdf1['TotalAssets'],4)
875
979
  except:
876
- print("#Error(get_DebtToAsset): failed in calculating DebtToAsset")
980
+ print(" #Error(get_DebtToAsset): failed in calculating DebtToAsset")
877
981
 
878
982
  #计算Debt to Equity
879
983
  try:
880
984
  fsdf1['Debt to Equity']=round(fsdf1['TotalLiabilities']/fsdf1['TotalEquities'],4)
881
985
  except:
882
- print("#Error(get_DebtToAsset): failed in calculating DebtToEquity")
986
+ print(" #Error(get_DebtToAsset): failed in calculating DebtToEquity")
883
987
 
884
988
  return fsdf1
885
989
 
@@ -1068,7 +1172,7 @@ def get_financial_rates(ticker):
1068
1172
  财务比率:短期还债能力,长期还债能力,营运能力,盈利能力,发展能力
1069
1173
  返回:报表+比率
1070
1174
  """
1071
- print("\n Analyzing financial rates of",ticker,"\b, it may take time......")
1175
+ print("\n Analyzing financial rates of",ticker,"......")
1072
1176
 
1073
1177
  # 变换港股代码5位-->4位
1074
1178
  result,prefix,suffix=split_prefix_suffix(ticker)
@@ -1080,13 +1184,13 @@ def get_financial_rates(ticker):
1080
1184
  try:
1081
1185
  fsdf=get_financial_statements(ticker)
1082
1186
  except:
1083
- print(" ......Failed to get financial statements of",ticker,"\b, recovering")
1187
+ print(" Failed to get financial statements of",ticker,"\b, recovering")
1084
1188
  import time; time.sleep(5)
1085
1189
  try:
1086
1190
  fsdf=get_financial_statements(ticker)
1087
1191
  except:
1088
- print(" ......Failed to get financial statements of",ticker,"\b!")
1089
- print(" ......If the stock code",ticker,"\b is correct, please try a few minutes later.")
1192
+ print(" Failed to get financial statements of",ticker,"\b!")
1193
+ print(" If the stock code",ticker,"\b is correct, please try a few minutes later.")
1090
1194
  return None
1091
1195
 
1092
1196
  #抓取股票的稀释后EPS,计算财务比率
@@ -1859,7 +1963,9 @@ if __name__=='__main__':
1859
1963
  scale2 = 10
1860
1964
  hatchlist=['.', 'o', '\\']
1861
1965
 
1862
- def compare_dupont(tickerlist,fsdate='latest',scale1 = 10,scale2 = 10,hatchlist=['.', 'o', '\\']):
1966
+ def compare_dupont(tickerlist,fsdate='latest', \
1967
+ sort='PM',facecolor='whitesmoke',font_size='16px', \
1968
+ scale1 = 10,scale2 = 10,hatchlist=['.', 'o', '\\']):
1863
1969
  """
1864
1970
  功能:获得tickerlist中每只股票的杜邦分析项目,绘制柱状叠加比较图
1865
1971
  tickerlist:股票代码列表,建议在10只以内
@@ -1888,13 +1994,25 @@ def compare_dupont(tickerlist,fsdate='latest',scale1 = 10,scale2 = 10,hatchlist=
1888
1994
  name4 = '净资产收益率'
1889
1995
  name5 = '财报日期'
1890
1996
  name6 = '财报类型'
1997
+
1998
+ import os, sys
1999
+ class HiddenPrints:
2000
+ def __enter__(self):
2001
+ self._original_stdout = sys.stdout
2002
+ sys.stdout = open(os.devnull, 'w')
2003
+
2004
+ def __exit__(self, exc_type, exc_val, exc_tb):
2005
+ sys.stdout.close()
2006
+ sys.stdout = self._original_stdout
1891
2007
 
1892
2008
  dpidflist,dpilist,fsdatelist,fstypelist=[],[],[],[]
1893
2009
  name1list,name2list,name3list,name4list,name5list,name6list=[],[],[],[],[],[]
1894
2010
  newtickerlist=[]
2011
+ print("Working on DuPont factsheet for specified stocks ...")
1895
2012
  for t in tickerlist:
1896
2013
  try:
1897
- dpidf=calc_dupont(t)
2014
+ with HiddenPrints():
2015
+ dpidf=calc_dupont(t)
1898
2016
  except:
1899
2017
  print(" #Warning(compare_dupont): lack of some accounting items for",t)
1900
2018
  continue
@@ -1921,6 +2039,9 @@ def compare_dupont(tickerlist,fsdate='latest',scale1 = 10,scale2 = 10,hatchlist=
1921
2039
  name4list=name4list+[dpi['ROE'][0]]
1922
2040
  name5list=name5list+[dpi['endDate'][0]]
1923
2041
  name6list=name6list+[dpi['periodType'][0]]
2042
+
2043
+ #显示进度
2044
+ print_progress_percent2(t,tickerlist,steps=5,leading_blanks=4)
1924
2045
 
1925
2046
  tickerlist=newtickerlist
1926
2047
  raw_data = {ticker:tickerlist,
@@ -1936,7 +2057,22 @@ def compare_dupont(tickerlist,fsdate='latest',scale1 = 10,scale2 = 10,hatchlist=
1936
2057
  for i in range(num):
1937
2058
  code=df.loc[i,'公司']
1938
2059
  df.loc[i,'公司']=ticker_name(code)
1939
-
2060
+
2061
+ # 排序
2062
+ if sort=='PM':
2063
+ df.sort_values(name1,ascending=False,inplace=True)
2064
+ sorttxt=text_lang(":按照"+name1+"降序排列",": By Descending"+name1)
2065
+ elif sort=='TAT':
2066
+ df.sort_values(name2,ascending=False,inplace=True)
2067
+ sorttxt=text_lang(":按照"+name2+"降序排列",": By Descending"+name2)
2068
+ elif sort=='EM':
2069
+ df.sort_values(name3,ascending=False,inplace=True)
2070
+ sorttxt=text_lang(":按照"+name3+"降序排列",": By Descending"+name3)
2071
+ else:
2072
+ df.sort_values(name1,ascending=False,inplace=True)
2073
+ sorttxt=text_lang(":按照"+name1+"降序排列",": By Descending"+name1)
2074
+
2075
+ # 绘图
1940
2076
  #f,ax1 = plt.subplots(1,figsize=(10,5))
1941
2077
  f,ax1 = plt.subplots(1,figsize=(12.8,6.4))
1942
2078
  w = 0.75
@@ -1997,9 +2133,9 @@ def compare_dupont(tickerlist,fsdate='latest',scale1 = 10,scale2 = 10,hatchlist=
1997
2133
 
1998
2134
  plt.legend(loc='best',fontsize=legend_txt_size)
1999
2135
  if lang == 'Chinese':
2000
- plt.title("杜邦分析对比图",fontsize=title_txt_size,fontweight='bold')
2136
+ plt.title("杜邦分析对比图"+sorttxt,fontsize=title_txt_size,fontweight='bold')
2001
2137
  else:
2002
- plt.title(texttranslate("杜邦分析对比图"),fontsize=title_txt_size,fontweight='bold')
2138
+ plt.title(texttranslate("杜邦分析对比图")+sorttxt,fontsize=title_txt_size,fontweight='bold')
2003
2139
  plt.xlim([min(tick_pos)-w,max(tick_pos)+w])
2004
2140
 
2005
2141
  plt.gca().set_facecolor('whitesmoke')
@@ -2011,10 +2147,7 @@ def compare_dupont(tickerlist,fsdate='latest',scale1 = 10,scale2 = 10,hatchlist=
2011
2147
  pd.set_option('display.max_colwidth', 1000)
2012
2148
  pd.set_option('display.unicode.ambiguous_as_wide', True)
2013
2149
  pd.set_option('display.unicode.east_asian_width', True)
2014
- if lang == 'Chinese':
2015
- print("===== "+"杜邦分析分项数据表"+" =====")
2016
- else:
2017
- print("===== "+texttranslate("杜邦分析分项数据表")+" =====")
2150
+
2018
2151
  df[name1]=df[name1]/scale1
2019
2152
  df[name2]=df[name2]/scale2
2020
2153
 
@@ -2032,12 +2165,17 @@ def compare_dupont(tickerlist,fsdate='latest',scale1 = 10,scale2 = 10,hatchlist=
2032
2165
  df[ectranslate('财报类型')]=df['财报类型'].apply(lambda x:'Quarterly' if x=='季报' else 'Annual')
2033
2166
  dfe=df[dfecols]
2034
2167
 
2035
- if lang == 'Chinese':
2036
- print(df.to_string(index=False))
2037
- print("*** "+"数据来源: 雅虎财经,"+' '+str(today))
2038
- else:
2039
- print(dfe.to_string(index=False))
2040
- print("*** "+texttranslate("数据来源: 雅虎财经,")+' '+str(today))
2168
+ titletxt=text_lang("杜邦分析分项数据表","Du Pont Identity Fact Sheet")
2169
+ footnote=text_lang("数据来源: 雅虎财经","Data source: Yahoo Finance")+', '+str(today)
2170
+ #确定表格字体大小
2171
+ titile_font_size=font_size
2172
+ heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
2173
+
2174
+ df_display_CSS(df=df,titletxt=titletxt,footnote=footnote, \
2175
+ facecolor=facecolor,decimals=4, \
2176
+ titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
2177
+ data_font_size=data_font_size)
2178
+
2041
2179
 
2042
2180
  #合并所有历史记录
2043
2181
  alldf=pd.concat(dpidflist)
siat/financials2.py CHANGED
@@ -265,7 +265,8 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
265
265
  # 分析资产负债表
266
266
  fsdf=get_balance_sheet(symbol=tickers)
267
267
  if fsdf is None:
268
- print(" #Warning(fs_analysis): financial info unaccessible for",tickers,"\b, which needs connection to Yahoo")
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)
269
270
  return None
270
271
 
271
272
  fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
@@ -368,7 +369,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
368
369
  # 分析利润表
369
370
  fsdf=get_income_statements(symbol=tickers)
370
371
  if fsdf is None:
371
- print(" #Warning(fs_analysis): financial info unaccessible for",tickers,"\b, which needs connection to Yahoo Finance")
372
+ print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
372
373
  return None
373
374
 
374
375
  fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
@@ -448,7 +449,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
448
449
  # 分析现金流量表
449
450
  fsdf=get_cashflow_statements(symbol=tickers)
450
451
  if fsdf is None:
451
- print(" #Warning(fs_analysis): financial info unaccessible for",tickers,"\b, which needs connection to Yahoo Finance")
452
+ print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
452
453
  return None
453
454
 
454
455
  fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
@@ -546,7 +547,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
546
547
  with HiddenPrints():
547
548
  fsdf=get_financial_rates(tickers)
548
549
  if fsdf is None:
549
- print(" #Warning(fs_analysis): financial info unaccessible for",tickers,"\b, which needs connection to Yahoo Finance")
550
+ print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
550
551
  return None
551
552
 
552
553
  fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
@@ -636,7 +637,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
636
637
  with HiddenPrints():
637
638
  dftmp=get_financial_rates(t)
638
639
  if dftmp is None:
639
- print(" #Warning(fs_analysis): financial info unaccessible for",t,"\b, which needs connection to Yahoo Finance")
640
+ print(" #Warning(fs_analysis): financial info unaccessible for",t)
640
641
  return None
641
642
 
642
643
  if business_period=='recent':
@@ -759,7 +760,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
759
760
  with HiddenPrints():
760
761
  fsdf=get_financial_rates(tickers)
761
762
  if fsdf is None:
762
- print(" #Warning(fs_analysis): financial info unaccessible for",tickers,"\b, which needs connection to Yahoo Finance")
763
+ print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
763
764
  return None
764
765
 
765
766
  fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
@@ -846,7 +847,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
846
847
  with HiddenPrints():
847
848
  dftmp=get_financial_rates(t)
848
849
  if dftmp is None:
849
- print(" #Warning(fs_analysis): financial info unaccessible for",t,"\b, which needs connection to Yahoo Finance")
850
+ print(" #Warning(fs_analysis): financial info unaccessible for",t)
850
851
  return None
851
852
 
852
853
  if dftmp is None:
@@ -953,7 +954,7 @@ def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
953
954
  with HiddenPrints():
954
955
  dftmp=get_financial_rates(t)
955
956
  if dftmp is None:
956
- print(" #Warning(fs_analysis): financial info unaccessible for",t,"\b, which needs connection to Yahoo Finance")
957
+ print(" #Warning(fs_analysis): financial info unaccessible for",t)
957
958
  return None
958
959
 
959
960
  if business_period=='recent':
siat/grafix.py CHANGED
@@ -476,6 +476,17 @@ def plot_line2(df1,ticker1,colname1,label1, \
476
476
  loc1=loc1,loc2=loc2, \
477
477
  color1=color1,color2=color2,facecolor=facecolor, \
478
478
  maxticks=maxticks)
479
+ elif twinx == False: # twinx == False # 正常绘图
480
+ plot_line2_coaxial(df1,ticker1,colname1,label1, \
481
+ df2,ticker2,colname2,label2, \
482
+ ylabeltxt,titletxt,footnote,power,datatag1,datatag2,zeroline, \
483
+ yline=yline,attention_value_area=attention_value_area, \
484
+ xline=xline,attention_point_area=attention_point_area, \
485
+ resample_freq=resample_freq, \
486
+ loc1=loc1,loc2=loc2, \
487
+ color1=color1,color2=color2,facecolor=facecolor, \
488
+ maxticks=maxticks)
489
+
479
490
  elif 'LR' in twinx.upper(): # 左右双图
480
491
  plot_line2_LR(df1,ticker1,colname1,label1, \
481
492
  df2,ticker2,colname2,label2, \
@@ -2895,7 +2906,7 @@ if __name__=='__main__':
2895
2906
  titletxt="This is a title"
2896
2907
  footnote="This is a footnote"
2897
2908
 
2898
- def plot_barh2(df,colname,titletxt,footnote,facecolor='whitesmoke'):
2909
+ def plot_barh2(df,colname,titletxt,footnote,facecolor='lightblue'):
2899
2910
  """
2900
2911
  功能:绘制水平单值柱状图,并在外侧标注数据标签。
2901
2912
  输入:数据集df;列名colname;标题titletxt;脚注footnote;
@@ -2913,7 +2924,8 @@ def plot_barh2(df,colname,titletxt,footnote,facecolor='whitesmoke'):
2913
2924
  xlabel=colname+'颜色棒'
2914
2925
  df[xlabel]=df[colname]
2915
2926
 
2916
- import plotly_express as px
2927
+ #import plotly_express as px
2928
+ import plotly.express as px
2917
2929
 
2918
2930
  fig=px.bar(data_frame = df,
2919
2931
  y='ycolname', #纵轴绘制的字段
@@ -2924,7 +2936,10 @@ def plot_barh2(df,colname,titletxt,footnote,facecolor='whitesmoke'):
2924
2936
  labels={'ycolname':'',colname:footnote,xlabel:''} #将字段改名作为纵轴、横轴或颜色棒的标注
2925
2937
  )
2926
2938
 
2927
- fig.update_traces(textposition='outside') #直方图顶端的数值标在外侧
2939
+ fig.update_coloraxes(showscale=False) # 隐藏颜色条
2940
+
2941
+ fig.update_traces(textposition='outside',#直方图顶端的数值标在外侧
2942
+ )
2928
2943
 
2929
2944
  fig.update_layout(
2930
2945
  title={
@@ -2933,14 +2948,10 @@ def plot_barh2(df,colname,titletxt,footnote,facecolor='whitesmoke'):
2933
2948
  'x':0.5,
2934
2949
  'xanchor': 'center', # 相对位置
2935
2950
  'yanchor': 'top'},
2951
+ plot_bgcolor=facecolor, #设置画布背景颜色
2952
+ coloraxis_showscale=False, #彻底移除颜色条,需要升级plotly!
2936
2953
  )
2937
-
2938
- try:
2939
- fig.gca().set_facecolor(facecolor)
2940
- except:
2941
- print(" #Warning(plot_barh2): color",facecolor,"is unsupported, changed to default setting")
2942
- fig.gca().set_facecolor("whitesmoke")
2943
-
2954
+
2944
2955
  fig.show()
2945
2956
 
2946
2957
  return
siat/sector_china.py CHANGED
@@ -394,7 +394,8 @@ def sector_rank_china(comp="涨跌幅",indicator="新浪行业",num=10):
394
394
  titletxt="中国股票市场:板块"+comp+"排行榜(按照"+indtag+"分类)"
395
395
  import datetime; stoday = datetime.date.today()
396
396
  footnote1="注:代表个股是指板块中涨幅最高或跌幅最低的股票\n"
397
- footnote2="板块总数"+str(len(df))+",数据来源:新浪财经,"+str(stoday)+"(截至昨日)"
397
+ #footnote2="板块总数"+str(len(df))+",数据来源:新浪财经,"+str(stoday)+"(截至昨日)"
398
+ footnote2="板块总数"+str(len(df))+",数据来源:新浪财经,"+str(stoday)
398
399
  footnote=footnote1+footnote2
399
400
 
400
401
  df_display_CSS(df4,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=2, \
@@ -556,10 +557,12 @@ def sector_detail_china(sector="new_dlhy",comp="涨跌幅",num=10):
556
557
  import datetime; stoday = datetime.date.today()
557
558
  if "流通市值" in df3_collist:
558
559
  footnote1="市值单位:亿元,板块成份股:"+str(len(df))+'\n'
559
- footnote2="数据来源:新浪财经,"+str(stoday)+"(截至昨日)"
560
+ #footnote2="数据来源:新浪财经,"+str(stoday)+"(截至昨日)"
561
+ footnote2="数据来源:新浪财经,"+str(stoday)
560
562
  else:
561
563
  footnote1="板块成份股:"+str(len(df))+','
562
- footnote2="数据来源:新浪财经,"+str(stoday)+"(截至昨日)"
564
+ #footnote2="数据来源:新浪财经,"+str(stoday)+"(截至昨日)"
565
+ footnote2="数据来源:新浪财经,"+str(stoday)
563
566
  footnote=footnote1+footnote2
564
567
 
565
568
  df_display_CSS(df4,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=2, \
@@ -568,7 +571,8 @@ def sector_detail_china(sector="new_dlhy",comp="涨跌幅",num=10):
568
571
  titile_font_size='16px',heading_font_size='15px', \
569
572
  data_font_size='15px')
570
573
 
571
- return df2
574
+ #return df2
575
+ return df4
572
576
 
573
577
  #==============================================================================
574
578
  if __name__=='__main__':
@@ -717,7 +721,8 @@ def sector_position_china(ticker,sector="new_dlhy"):
717
721
  titletxt="\n上市公司地位分析:"+sname+","+sector_name+"行业/板块("+indicator+"分类)"
718
722
  import datetime; stoday = datetime.date.today()
719
723
  footnote1=""
720
- footnote2="成分股总数:"+str(len(df))+",数据来源:新浪财经,"+str(stoday)+"(截至昨日)"
724
+ #footnote2="成分股总数:"+str(len(df))+",数据来源:新浪财经,"+str(stoday)+"(截至昨日)"
725
+ footnote2="成分股总数:"+str(len(df))+",数据来源:新浪财经,"+str(stoday)
721
726
  footnote=footnote1+footnote2
722
727
 
723
728
  #print("") #空一行
siat/stock.py CHANGED
@@ -125,8 +125,8 @@ def get_profile(ticker):
125
125
  tp=yf.Ticker(ticker1)
126
126
  try:
127
127
  dic=tp.info
128
- except:
129
- print(" #Error(get_profile): failed to access Yahoo Finance for",ticker)
128
+ except ValueError as e:
129
+ print(" #Error(get_profile): {e} when processing",ticker)
130
130
  return None
131
131
 
132
132
  #将字典转换为数据框
@@ -346,7 +346,7 @@ def stock_profile(ticker,option='basic',verbose=False):
346
346
  返回:证券快照信息数据表。
347
347
  注意:放弃
348
348
  """
349
- print("..Searching for security snapshot information, please wait ...")
349
+ print(" Searching for security snapshot information, please wait ...")
350
350
  #抓取证券静态信息
351
351
  try:
352
352
  df=get_profile(ticker)
@@ -2009,7 +2009,7 @@ def compare_msecurity(tickers,measure,start,end, \
2009
2009
  if isinstance(measure,list):
2010
2010
  measure=measure[0]
2011
2011
 
2012
- print(" Searching for multiple securities for",measure,"...")
2012
+ print(" Searching securities for",measure,"...")
2013
2013
  #屏蔽函数内print信息输出的类
2014
2014
  import os, sys
2015
2015
  class HiddenPrints:
@@ -2973,7 +2973,9 @@ def stock_info(symbol):
2973
2973
  if result & (suffix=='HK'):
2974
2974
  symbol=prefix[-4:]+'.'+suffix
2975
2975
 
2976
- from yahooquery import Ticker #如果出现类似于{'AAPL': 'Invalid Cookie'}错误,则需要升级
2976
+ from yahooquery import Ticker
2977
+ #如果出现类似于{'AAPL': 'Invalid Cookie'}错误,则需要升级yahooquery
2978
+ #如果出现crump相关的错误,则需要更换lxml的版本以便与当前的yahooquery版本匹配
2977
2979
  stock = Ticker(symbol)
2978
2980
 
2979
2981
  """
@@ -2991,12 +2993,12 @@ def stock_info(symbol):
2991
2993
  #如果出现类似于{'AAPL': 'Invalid Cookie'}错误,则需要升级yahooquery
2992
2994
  adict=stock.asset_profile
2993
2995
  except:
2994
- print(" #Error(stock_info): failed to get the profile of",symbol)
2995
- print(" Possible reasons: Wrong stock code, or unstable internet connection")
2996
+ print(" #Error(stock_info): failed to get info of",symbol)
2997
+ print(" Reasons: Wrong stock code, or poor internet connection, or need to upgrade yahooquery")
2996
2998
  return None
2997
2999
 
2998
3000
  if adict[symbol] == 'Invalid Cookie':
2999
- print(" #Error(stock_info): failed in retrieving info of",symbol,"\b. Try upgrade yahooquery and do again")
3001
+ print(" #Error(stock_info): failed in retrieving info of",symbol,"\b. Try upgrade yahooquery and run again")
3000
3002
  return None
3001
3003
 
3002
3004
  keylist=list(adict[symbol].keys())
@@ -3524,7 +3526,7 @@ def get_stock_profile(ticker,info_type='basic',printout=True):
3524
3526
  try:
3525
3527
  info=stock_info(ticker)
3526
3528
  except:
3527
- print(" #Warning(get_stock_profile): failed to access Yahoo for",ticker,"\b, recovering...")
3529
+ print(" #Warning(get_stock_profile): recovering info for",ticker,"...")
3528
3530
  import time; time.sleep(5)
3529
3531
  try:
3530
3532
  info=stock_info(ticker)
siat/translate.py CHANGED
@@ -156,7 +156,7 @@ def ectranslate_c(eword):
156
156
  ['exchangeTimezoneShortName','交易所时区简称'],['quoteType','证券类别'],
157
157
  ['symbol','证券代码'],['messageBoardId','证券留言板编号'],
158
158
  ['market','证券市场'],['annualHoldingsTurnover','一年內转手率'],
159
- ['enterpriseToRevenue','市售率(EV/Revenue)'],['EV to Revenue','市售率(EV/Revenue)'],
159
+ ['enterpriseToRevenue','市售率(EV/Revenue)'],['EV to Revenue','企业价值收入比'],
160
160
  ['Price to Book','市净率'],['beta3Year','3年贝塔系数'],
161
161
  ['profitMargins','净利润率'],['enterpriseToEbitda','企业价值/EBITDA'],
162
162
  ['EV to EBITDA','企业价值倍数(EV/EBITDA)'],
@@ -212,7 +212,8 @@ def ectranslate_c(eword):
212
212
  ['BasicEPS','基本每股收益'],['Cashflow per Share','每股现金流量'],
213
213
  ['Profit Margin','净利润率'],['Gross Margin','毛利润率'],
214
214
  ['EBITDA Margin','EBITDA利润率'],['Operating Margin','营业利润率'],
215
- ['Trailing EPS','每股收益TTM'],['Trailing PE','市盈率TTM'],['Forward PE','预期市盈率'],
215
+ ['Trailing EPS','每股收益TTM'],['Forward EPS','预期每股收益'],
216
+ ['Trailing PE','市盈率TTM'],['Forward PE','预期市盈率'],
216
217
  ['Revenue Growth','销售收入增长率'],['Earnings Growth','年度盈余增长率'],
217
218
  ['Earnings Quarterly Growth','季度盈余增长率'],
218
219
  ['IGR','内部增长率(IGR)'],['SGR','可持续增长率(SGR)'],
@@ -507,7 +508,8 @@ def ectranslate_e(eword):
507
508
  ['BasicEPS','Basic EPS'],['Cashflow per Share','Cashflow per share'],
508
509
  ['Profit Margin','Profit margins'],['Gross Margin','Gross margins'],
509
510
  ['EBITDA Margin','EBITDA margins'],['Operating Margin','Operating margins'],
510
- ['Trailing EPS','EPS TTM'],['Trailing PE','PE TTM'],['Forward PE','Forward PE'],
511
+ ['Trailing EPS','EPS TTM'],['Forward EPS','Forward EPS'],
512
+ ['Trailing PE','PE TTM'],['Forward PE','Forward PE'],
511
513
  ['Revenue Growth','Revenue growth'],['Earnings Growth','Earnings growth(annual)'],
512
514
  ['Earnings Quarterly Growth','Earnings growth(quarterly)'],
513
515
  ['IGR','Internal growth rate'],['SGR','Sustainable growth rate'],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: siat
3
- Version: 3.8.36
3
+ Version: 3.8.42
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=N2D1ydfh_lejim0z6eQR17utNF7-5lk04c1esGO71_E,2223
2
+ siat/__init__.py,sha256=tpSBf8BYpWOzBDF2iNQ4tlVxjx7bmkVQ3kPUu9X3iog,2227
3
3
  siat/__init__.py.backup_20250214.py,sha256=pIo4CV3lNPKIhitmhIh_6aAfZrmzQWGNDcEnvZ7GXoc,3216
4
4
  siat/allin.py,sha256=9xwa97S6KPHXGuqDtyN9b6Y4lCSM1VdBqpFBrlRvV8I,3001
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=z_oMRdzzA05OJnN0kJ9ZFwYCdEfiyeR59a1OCZiblYE,181182
22
+ siat/common.py,sha256=XDt269wDd8L_sd4FWqFw2N5bPA6v051c2YnIxIJ_2V0,181169
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
@@ -42,9 +42,9 @@ siat/fin_stmt2_yahoo.py,sha256=LGmspk0nKyz4X87MtcovZXUfMQkAvrWINuxR4HQ8PI8,41178
42
42
  siat/financial_base.py,sha256=A1rV7XQOVFpCXCV-T6Ge0QeF897hINiu0olN1XWeaFk,41287
43
43
  siat/financial_statements.py,sha256=xx0SMpFqAMKm6cj8uYeG2RpJE6G-RoJ3NWa33UyaVMk,25414
44
44
  siat/financial_statements_test.py,sha256=FLhx8JD-tVVWSBGux6AMz1jioXX4U4bp9DmgFHYXb_w,716
45
- siat/financials.py,sha256=6mmcOI03rJuz3xmrX_H46wTudgXLGtNqrwfuFZCiwaE,80739
45
+ siat/financials.py,sha256=fYnMF66xkO0DKSzDoXRb3acYQUYkepXaM5SG6e8gEeY,86168
46
46
  siat/financials2 - 副本.py,sha256=dKlNjIfKeoSy055fQ6E6TUj9HEoO5Ney9grD84J5kfk,14389
47
- siat/financials2.py,sha256=N2qOfVQ2SE7T5kmMkAcccCOHIEwGylFDvB5_GxxOin0,51039
47
+ siat/financials2.py,sha256=YF-A-5iSTzLXTFI0sDGju4_6T87wWC9IlFd4fSXbJXw,50805
48
48
  siat/financials_china.py,sha256=Hu85JOKnCmcTHgblIvHhsV-6c-Y15HFGNR_ZaaJt8nM,191974
49
49
  siat/financials_china2.py,sha256=VvkzkjZeH84zwypR7ReldgJeZ7jnNw0qkzebvWMPm10,94956
50
50
  siat/financials_china2_test.py,sha256=Erz5k4LyOplBBvYls2MypuqHpVNJ3daiLdyeJezNPu0,2722
@@ -64,7 +64,7 @@ siat/future_china.py,sha256=F-HsIf2Op8Z22RzTjet1g8COzldgnMjFNSXsAkeGyWo,17595
64
64
  siat/future_china_test.py,sha256=BrSzmDVaOHki6rntOtosmRn-6dkfOBuLulJNqh7MOpc,1163
65
65
  siat/global_index_test.py,sha256=hnFp3wqqzzL-kAP8mgxDZ54Bd5Ijf6ENi5YJlGBgcXw,2402
66
66
  siat/google_authenticator.py,sha256=ZUbZR8OW0IAKDbcYtlqGqIpZdERpFor9NccFELxg9yI,1637
67
- siat/grafix.py,sha256=Noy_gIwVGjktPgfUIx-KZQJ-pjtwR3o7iBI030m4wzs,139126
67
+ siat/grafix.py,sha256=X9eWpD6ndQSAkOEcbfC9b8KrY-rlYEhz63kE8JALs8E,139802
68
68
  siat/grafix_test.py,sha256=kXvcpLgQNO7wd30g_bWljLj5UH7bIVI0_dUtXbfiKR0,3150
69
69
  siat/holding_risk.py,sha256=uWRtMMJqKr-puQn26g6Fq5N3mFB70c0B99zLQug8hAo,30774
70
70
  siat/holding_risk_test.py,sha256=FRlw_9wFG98BYcg_cSj95HX5WZ1TvkGaOUdXD7-V86s,474
@@ -98,7 +98,7 @@ siat/risk_evaluation.py,sha256=HK6U2G85-AxjSoeARbmTuiCNwTVdPdB9Znfgvslo0Os,76455
98
98
  siat/risk_evaluation_test.py,sha256=YEXM96gKzTfwN4U61AS4Rr1tV7KgUvn4rRC6f3iMw9s,3731
99
99
  siat/risk_free_rate.py,sha256=IBuRqA2kppdZsW4D4fapW7vnM5HMEXOn95A5r9Pkwlo,12384
100
100
  siat/risk_free_rate_test.py,sha256=CpmhUf8aEAEZeNu4gvWP2Mz2dLoIgBX5bI41vfUBEr8,4285
101
- siat/sector_china.py,sha256=HbU3SokSWuwNKYFrbamS6qlXE8J8ZAyM3fWo4RskhEU,157074
101
+ siat/sector_china.py,sha256=9zjdORWx5ia_gUezidhOKWmCnVDwWcnnjjugHudelaQ,157411
102
102
  siat/sector_china_test.py,sha256=1wq7ef8Bb_L8F0h0W6FvyBrIcBTEbrTV7hljtpj49U4,5843
103
103
  siat/security_price.py,sha256=2oHskgiw41KMGfqtnA0i2YjNNV6cYgtlUK0j3YeuXWs,29185
104
104
  siat/security_price2.py,sha256=dYwvz9H-uWp-Gyc1g_MId9k8cITS6ZHmjW-Fc2ypp-0,26587
@@ -109,7 +109,7 @@ siat/security_trend2-20240620.py,sha256=QVnEcb7AyVbO77jVqfFsJffGXrX8pgJ9xCfoAKmW
109
109
  siat/security_trend2.py,sha256=8-Z-PWaX8fjnyAyfxEp3qXdVllgDpRISOASKEn7Zeoc,30706
110
110
  siat/setup.py,sha256=up65rQGLmTBkhtaMLowjoQXYmIsnycnm4g1SYmeQS6o,1335
111
111
  siat/shenwan index history test.py,sha256=JCVAzOSEldHalhSFa3pqD8JI_8_djPMQOxpkuYU-Esg,1418
112
- siat/stock.py,sha256=W3JhjfRwqb9luNydrKyGd97uRmTsZD5FvRdqJ3DynVo,159509
112
+ siat/stock.py,sha256=bXG1FIwNTNvzHGNDH3ZNWFmXCMyD5dy-CTsHI2OKGWM,159614
113
113
  siat/stock_advice_linear.py,sha256=-twT7IGP-NEplkL1WPSACcNJjggRB2j4mlAQCkzOAuo,31655
114
114
  siat/stock_base.py,sha256=uISvbRyOGy8p9QREA96CVydgflBkn5L3OXOGKl8oanc,1312
115
115
  siat/stock_china.py,sha256=85Ggb21E2mrCYMdSSTTrkoyyLGXMK2V-BtlweHomSRg,93460
@@ -135,7 +135,7 @@ siat/transaction_test.py,sha256=Z8g1LJCN4-mnUByXMUMoFmN0t105cbmsz2QmvSuIkbU,1858
135
135
  siat/translate-20230125.py,sha256=NPPSXhT38s5t9fzMvl_fvi4ckSB73ThLmZetVI-xGdU,117953
136
136
  siat/translate-20230206.py,sha256=-vtI125WyaJhmPotOpDAmclt_XnYVaWU9ByLWZ6FyYE,118133
137
137
  siat/translate-20230215.py,sha256=TJgtPE3n8IjljmZ4Pefy8dmHoNdFF-1zpML6BhA9FKE,121657
138
- siat/translate.py,sha256=t4SM4QWE7mCfY5GWPJ8SSquNRFrPAKHxJbpKsCWnneU,262247
138
+ siat/translate.py,sha256=6kIzzzdh04J2BkR2XSnKkl4rTZWSHarW-4AdarTZJvI,262334
139
139
  siat/translate_20240606.py,sha256=63IyHWEU3Uz9mjwyuAX3fqY4nUMdwh0ICQAgmgPXP7Y,215121
140
140
  siat/translate_241003_keep.py,sha256=un7Fqe1v35MXsja5exZgjmLzrZtt66NARZIGlyFuGGU,218747
141
141
  siat/universal_test.py,sha256=CDAOffW1Rvs-TcNN5giWVvHMlch1w4dp-w5SIV9jXL0,3936
@@ -144,8 +144,8 @@ siat/valuation_china.py,sha256=eSKIDckyjG8QkENlW_OKkqbQHno8pzDcomBO9iGNJVM,83079
144
144
  siat/valuation_market_china_test.py,sha256=gbJ0ioauuo4koTPH6WKUkqcXiQPafnbhU5eKJ6lpdLA,1571
145
145
  siat/var_model_validation.py,sha256=R0caWnuZarrRg9939hxh3vJIIpIyPfvelYmzFNZtPbo,14910
146
146
  siat/yf_name.py,sha256=laNKMTZ9hdenGX3IZ7G0a2RLBKEWtUQJFY9CWuk_fp8,24058
147
- siat-3.8.36.dist-info/LICENSE,sha256=NTEMMROY9_4U1szoKC3N2BLHcDd_o5uTgqdVH8tbApw,1071
148
- siat-3.8.36.dist-info/METADATA,sha256=e4VCORGHR9rk7kDQKISHBuK7_TeZzGpi7M7ZaImKCu0,8321
149
- siat-3.8.36.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
150
- siat-3.8.36.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
151
- siat-3.8.36.dist-info/RECORD,,
147
+ siat-3.8.42.dist-info/LICENSE,sha256=NTEMMROY9_4U1szoKC3N2BLHcDd_o5uTgqdVH8tbApw,1071
148
+ siat-3.8.42.dist-info/METADATA,sha256=fXxjQCNXJFoLw_cm0qw_P46eOWOqLHrXZsvxJ-F5-6g,8321
149
+ siat-3.8.42.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
150
+ siat-3.8.42.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
151
+ siat-3.8.42.dist-info/RECORD,,
File without changes
File without changes