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 +2 -2
- siat/common.py +1 -1
- siat/financials.py +200 -62
- siat/financials2.py +9 -8
- siat/grafix.py +21 -10
- siat/sector_china.py +10 -5
- siat/stock.py +11 -9
- siat/translate.py +5 -3
- {siat-3.8.36.dist-info → siat-3.8.42.dist-info}/METADATA +1 -1
- {siat-3.8.36.dist-info → siat-3.8.42.dist-info}/RECORD +13 -13
- {siat-3.8.36.dist-info → siat-3.8.42.dist-info}/LICENSE +0 -0
- {siat-3.8.36.dist-info → siat-3.8.42.dist-info}/WHEEL +0 -0
- {siat-3.8.36.dist-info → siat-3.8.42.dist-info}/top_level.txt +0 -0
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("
|
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
|
-
|
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(
|
279
|
+
def compare_snapshot(ticker,indicator, \
|
280
|
+
facecolor='lightblue',
|
280
281
|
datatag=True,tag_offset=0.01, \
|
281
|
-
graph=True,axisamp=1.2,px=
|
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工具绘图,默认
|
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
|
345
|
-
print(" Supported
|
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
|
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
|
395
|
-
print(" Possible reasons:
|
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
|
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="
|
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
|
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(
|
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("
|
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="
|
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(
|
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("
|
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',
|
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(
|
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
|
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,"
|
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("
|
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("
|
1089
|
-
print("
|
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',
|
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
|
-
|
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
|
-
|
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
|
-
|
2036
|
-
|
2037
|
-
|
2038
|
-
|
2039
|
-
|
2040
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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='
|
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.
|
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):
|
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("
|
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
|
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
|
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
|
2995
|
-
print("
|
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
|
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):
|
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','
|
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'],['
|
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'],['
|
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,5 +1,5 @@
|
|
1
1
|
siat/__init__ -20240701.py,sha256=gP5uajXnJesnH5SL0ZPwq_Qhv59AG1bs4qwZv26Fo2Y,2894
|
2
|
-
siat/__init__.py,sha256=
|
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=
|
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=
|
45
|
+
siat/financials.py,sha256=fYnMF66xkO0DKSzDoXRb3acYQUYkepXaM5SG6e8gEeY,86168
|
46
46
|
siat/financials2 - 副本.py,sha256=dKlNjIfKeoSy055fQ6E6TUj9HEoO5Ney9grD84J5kfk,14389
|
47
|
-
siat/financials2.py,sha256=
|
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=
|
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=
|
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=
|
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=
|
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.
|
148
|
-
siat-3.8.
|
149
|
-
siat-3.8.
|
150
|
-
siat-3.8.
|
151
|
-
siat-3.8.
|
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
|
File without changes
|