siat 3.10.132__py3-none-any.whl → 3.11.1__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.
Files changed (221) hide show
  1. siat/__init__.py +0 -0
  2. siat/allin.py +8 -0
  3. siat/assets_liquidity.py +0 -0
  4. siat/beta_adjustment.py +0 -0
  5. siat/beta_adjustment_china.py +0 -0
  6. siat/blockchain.py +0 -0
  7. siat/bond.py +0 -0
  8. siat/bond_base.py +0 -0
  9. siat/bond_china.py +0 -0
  10. siat/bond_zh_sina.py +0 -0
  11. siat/capm_beta.py +0 -0
  12. siat/capm_beta2.py +4 -4
  13. siat/common.py +9 -6
  14. siat/compare_cross.py +0 -0
  15. siat/copyrights.py +0 -0
  16. siat/cryptocurrency.py +0 -0
  17. siat/economy.py +0 -0
  18. siat/economy2.py +0 -0
  19. siat/esg.py +0 -0
  20. siat/event_study.py +0 -0
  21. siat/exchange_bond_china.pickle +0 -0
  22. siat/fama_french.py +0 -0
  23. siat/fin_stmt2_yahoo.py +0 -0
  24. siat/financial_base.py +0 -0
  25. siat/financial_statements.py +0 -0
  26. siat/financials.py +0 -0
  27. siat/financials2.py +0 -0
  28. siat/financials_china.py +0 -0
  29. siat/financials_china2.py +0 -0
  30. siat/fund.py +0 -0
  31. siat/fund_china.pickle +0 -0
  32. siat/fund_china.py +0 -0
  33. siat/future_china.py +0 -0
  34. siat/google_authenticator.py +0 -0
  35. siat/grafix.py +55 -4
  36. siat/holding_risk.py +0 -0
  37. siat/luchy_draw.py +0 -0
  38. siat/market_china.py +0 -0
  39. siat/markowitz.py +0 -0
  40. siat/markowitz2.py +1 -0
  41. siat/markowitz2_20250704.py +0 -0
  42. siat/markowitz2_20250705.py +0 -0
  43. siat/markowitz_simple.py +0 -0
  44. siat/ml_cases.py +0 -0
  45. siat/ml_cases_example.py +0 -0
  46. siat/option_china.py +0 -0
  47. siat/option_pricing.py +0 -0
  48. siat/other_indexes.py +0 -0
  49. siat/risk_adjusted_return.py +0 -0
  50. siat/risk_adjusted_return2.py +8 -4
  51. siat/risk_evaluation.py +0 -0
  52. siat/risk_free_rate.py +0 -0
  53. siat/save2docx.py +345 -0
  54. siat/save2pdf.py +145 -0
  55. siat/sector_china.py +0 -0
  56. siat/security_price2.py +0 -0
  57. siat/security_prices.py +168 -6
  58. siat/security_trend.py +0 -0
  59. siat/security_trend2.py +2 -2
  60. siat/stock.py +11 -1
  61. siat/stock_advice_linear.py +0 -0
  62. siat/stock_base.py +0 -0
  63. siat/stock_china.py +0 -0
  64. siat/stock_info.pickle +0 -0
  65. siat/stock_prices_kneighbors.py +0 -0
  66. siat/stock_prices_linear.py +0 -0
  67. siat/stock_profile.py +0 -0
  68. siat/stock_technical.py +0 -0
  69. siat/stooq.py +0 -0
  70. siat/transaction.py +0 -0
  71. siat/translate.py +0 -0
  72. siat/valuation.py +0 -0
  73. siat/valuation_china.py +0 -0
  74. siat/var_model_validation.py +0 -0
  75. siat/yf_name.py +0 -0
  76. {siat-3.10.132.dist-info/licenses → siat-3.11.1.dist-info}/LICENSE +0 -0
  77. {siat-3.10.132.dist-info → siat-3.11.1.dist-info}/METADATA +234 -235
  78. siat-3.11.1.dist-info/RECORD +80 -0
  79. {siat-3.10.132.dist-info → siat-3.11.1.dist-info}/WHEEL +1 -1
  80. {siat-3.10.132.dist-info → siat-3.11.1.dist-info}/top_level.txt +0 -1
  81. build/lib/build/lib/siat/__init__.py +0 -75
  82. build/lib/build/lib/siat/allin.py +0 -137
  83. build/lib/build/lib/siat/assets_liquidity.py +0 -915
  84. build/lib/build/lib/siat/beta_adjustment.py +0 -1058
  85. build/lib/build/lib/siat/beta_adjustment_china.py +0 -548
  86. build/lib/build/lib/siat/blockchain.py +0 -143
  87. build/lib/build/lib/siat/bond.py +0 -2900
  88. build/lib/build/lib/siat/bond_base.py +0 -992
  89. build/lib/build/lib/siat/bond_china.py +0 -100
  90. build/lib/build/lib/siat/bond_zh_sina.py +0 -143
  91. build/lib/build/lib/siat/capm_beta.py +0 -783
  92. build/lib/build/lib/siat/capm_beta2.py +0 -887
  93. build/lib/build/lib/siat/common.py +0 -5360
  94. build/lib/build/lib/siat/compare_cross.py +0 -642
  95. build/lib/build/lib/siat/copyrights.py +0 -18
  96. build/lib/build/lib/siat/cryptocurrency.py +0 -667
  97. build/lib/build/lib/siat/economy.py +0 -1471
  98. build/lib/build/lib/siat/economy2.py +0 -1853
  99. build/lib/build/lib/siat/esg.py +0 -536
  100. build/lib/build/lib/siat/event_study.py +0 -815
  101. build/lib/build/lib/siat/fama_french.py +0 -1521
  102. build/lib/build/lib/siat/fin_stmt2_yahoo.py +0 -982
  103. build/lib/build/lib/siat/financial_base.py +0 -1160
  104. build/lib/build/lib/siat/financial_statements.py +0 -598
  105. build/lib/build/lib/siat/financials.py +0 -2339
  106. build/lib/build/lib/siat/financials2.py +0 -1278
  107. build/lib/build/lib/siat/financials_china.py +0 -4433
  108. build/lib/build/lib/siat/financials_china2.py +0 -2212
  109. build/lib/build/lib/siat/fund.py +0 -629
  110. build/lib/build/lib/siat/fund_china.py +0 -3307
  111. build/lib/build/lib/siat/future_china.py +0 -551
  112. build/lib/build/lib/siat/google_authenticator.py +0 -47
  113. build/lib/build/lib/siat/grafix.py +0 -3636
  114. build/lib/build/lib/siat/holding_risk.py +0 -867
  115. build/lib/build/lib/siat/luchy_draw.py +0 -638
  116. build/lib/build/lib/siat/market_china.py +0 -1168
  117. build/lib/build/lib/siat/markowitz.py +0 -2363
  118. build/lib/build/lib/siat/markowitz2.py +0 -3150
  119. build/lib/build/lib/siat/markowitz2_20250704.py +0 -2969
  120. build/lib/build/lib/siat/markowitz2_20250705.py +0 -3158
  121. build/lib/build/lib/siat/markowitz_simple.py +0 -373
  122. build/lib/build/lib/siat/ml_cases.py +0 -2291
  123. build/lib/build/lib/siat/ml_cases_example.py +0 -60
  124. build/lib/build/lib/siat/option_china.py +0 -3069
  125. build/lib/build/lib/siat/option_pricing.py +0 -1925
  126. build/lib/build/lib/siat/other_indexes.py +0 -409
  127. build/lib/build/lib/siat/risk_adjusted_return.py +0 -1576
  128. build/lib/build/lib/siat/risk_adjusted_return2.py +0 -1900
  129. build/lib/build/lib/siat/risk_evaluation.py +0 -2218
  130. build/lib/build/lib/siat/risk_free_rate.py +0 -351
  131. build/lib/build/lib/siat/sector_china.py +0 -4140
  132. build/lib/build/lib/siat/security_price2.py +0 -727
  133. build/lib/build/lib/siat/security_prices.py +0 -3408
  134. build/lib/build/lib/siat/security_trend.py +0 -402
  135. build/lib/build/lib/siat/security_trend2.py +0 -646
  136. build/lib/build/lib/siat/stock.py +0 -4284
  137. build/lib/build/lib/siat/stock_advice_linear.py +0 -934
  138. build/lib/build/lib/siat/stock_base.py +0 -26
  139. build/lib/build/lib/siat/stock_china.py +0 -2095
  140. build/lib/build/lib/siat/stock_prices_kneighbors.py +0 -910
  141. build/lib/build/lib/siat/stock_prices_linear.py +0 -386
  142. build/lib/build/lib/siat/stock_profile.py +0 -707
  143. build/lib/build/lib/siat/stock_technical.py +0 -3305
  144. build/lib/build/lib/siat/stooq.py +0 -74
  145. build/lib/build/lib/siat/transaction.py +0 -347
  146. build/lib/build/lib/siat/translate.py +0 -5183
  147. build/lib/build/lib/siat/valuation.py +0 -1378
  148. build/lib/build/lib/siat/valuation_china.py +0 -2076
  149. build/lib/build/lib/siat/var_model_validation.py +0 -444
  150. build/lib/build/lib/siat/yf_name.py +0 -811
  151. build/lib/siat/__init__.py +0 -75
  152. build/lib/siat/allin.py +0 -137
  153. build/lib/siat/assets_liquidity.py +0 -915
  154. build/lib/siat/beta_adjustment.py +0 -1058
  155. build/lib/siat/beta_adjustment_china.py +0 -548
  156. build/lib/siat/blockchain.py +0 -143
  157. build/lib/siat/bond.py +0 -2900
  158. build/lib/siat/bond_base.py +0 -992
  159. build/lib/siat/bond_china.py +0 -100
  160. build/lib/siat/bond_zh_sina.py +0 -143
  161. build/lib/siat/capm_beta.py +0 -783
  162. build/lib/siat/capm_beta2.py +0 -887
  163. build/lib/siat/common.py +0 -5360
  164. build/lib/siat/compare_cross.py +0 -642
  165. build/lib/siat/copyrights.py +0 -18
  166. build/lib/siat/cryptocurrency.py +0 -667
  167. build/lib/siat/economy.py +0 -1471
  168. build/lib/siat/economy2.py +0 -1853
  169. build/lib/siat/esg.py +0 -536
  170. build/lib/siat/event_study.py +0 -815
  171. build/lib/siat/fama_french.py +0 -1521
  172. build/lib/siat/fin_stmt2_yahoo.py +0 -982
  173. build/lib/siat/financial_base.py +0 -1160
  174. build/lib/siat/financial_statements.py +0 -598
  175. build/lib/siat/financials.py +0 -2339
  176. build/lib/siat/financials2.py +0 -1278
  177. build/lib/siat/financials_china.py +0 -4433
  178. build/lib/siat/financials_china2.py +0 -2212
  179. build/lib/siat/fund.py +0 -629
  180. build/lib/siat/fund_china.py +0 -3307
  181. build/lib/siat/future_china.py +0 -551
  182. build/lib/siat/google_authenticator.py +0 -47
  183. build/lib/siat/grafix.py +0 -3636
  184. build/lib/siat/holding_risk.py +0 -867
  185. build/lib/siat/luchy_draw.py +0 -638
  186. build/lib/siat/market_china.py +0 -1168
  187. build/lib/siat/markowitz.py +0 -2363
  188. build/lib/siat/markowitz2.py +0 -3150
  189. build/lib/siat/markowitz2_20250704.py +0 -2969
  190. build/lib/siat/markowitz2_20250705.py +0 -3158
  191. build/lib/siat/markowitz_simple.py +0 -373
  192. build/lib/siat/ml_cases.py +0 -2291
  193. build/lib/siat/ml_cases_example.py +0 -60
  194. build/lib/siat/option_china.py +0 -3069
  195. build/lib/siat/option_pricing.py +0 -1925
  196. build/lib/siat/other_indexes.py +0 -409
  197. build/lib/siat/risk_adjusted_return.py +0 -1576
  198. build/lib/siat/risk_adjusted_return2.py +0 -1900
  199. build/lib/siat/risk_evaluation.py +0 -2218
  200. build/lib/siat/risk_free_rate.py +0 -351
  201. build/lib/siat/sector_china.py +0 -4140
  202. build/lib/siat/security_price2.py +0 -727
  203. build/lib/siat/security_prices.py +0 -3408
  204. build/lib/siat/security_trend.py +0 -402
  205. build/lib/siat/security_trend2.py +0 -646
  206. build/lib/siat/stock.py +0 -4284
  207. build/lib/siat/stock_advice_linear.py +0 -934
  208. build/lib/siat/stock_base.py +0 -26
  209. build/lib/siat/stock_china.py +0 -2095
  210. build/lib/siat/stock_prices_kneighbors.py +0 -910
  211. build/lib/siat/stock_prices_linear.py +0 -386
  212. build/lib/siat/stock_profile.py +0 -707
  213. build/lib/siat/stock_technical.py +0 -3305
  214. build/lib/siat/stooq.py +0 -74
  215. build/lib/siat/transaction.py +0 -347
  216. build/lib/siat/translate.py +0 -5183
  217. build/lib/siat/valuation.py +0 -1378
  218. build/lib/siat/valuation_china.py +0 -2076
  219. build/lib/siat/var_model_validation.py +0 -444
  220. build/lib/siat/yf_name.py +0 -811
  221. siat-3.10.132.dist-info/RECORD +0 -218
build/lib/siat/stock.py DELETED
@@ -1,4284 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- 本模块功能:提供全球证券信息,应用层,以股票为基础,兼容雅虎财经上的大多数其他证券产品
4
- 所属工具包:证券投资分析工具SIAT
5
- SIAT:Security Investment Analysis Tool
6
- 创建日期:2018年6月16日
7
- 最新修订日期:2020年8月28日
8
- 作者:王德宏 (WANG Dehong, Peter)
9
- 作者单位:北京外国语大学国际商学院
10
- 作者邮件:wdehong2000@163.com
11
- 版权所有:王德宏
12
- 用途限制:仅限研究与教学使用,不可商用!商用需要额外授权。
13
- 特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
14
- """
15
- #==============================================================================
16
- #关闭所有警告
17
- import warnings; warnings.filterwarnings('ignore')
18
-
19
- from siat.common import *
20
- from siat.translate import *
21
- from siat.grafix import *
22
- from siat.security_prices import *
23
- from siat.security_price2 import *
24
-
25
- #==============================================================================
26
- import matplotlib.pyplot as plt
27
- #plt.rcParams['figure.figsize']=(12.8,7.2)
28
- plt.rcParams['figure.figsize']=(12.8,6.4)
29
- plt.rcParams['figure.dpi']=300
30
- plt.rcParams['font.size'] = 13
31
- plt.rcParams['xtick.labelsize']=11 #横轴字体大小
32
- plt.rcParams['ytick.labelsize']=11 #纵轴字体大小
33
-
34
- title_txt_size=16
35
- ylabel_txt_size=14
36
- xlabel_txt_size=14
37
- legend_txt_size=14
38
-
39
- import mplfinance as mpf
40
-
41
- #处理绘图汉字乱码问题
42
- import sys; czxt=sys.platform
43
- if czxt in ['win32','win64']:
44
- plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体
45
- mpfrc={'font.family': 'SimHei'}
46
-
47
- if czxt in ['darwin']: #MacOSX
48
- plt.rcParams['font.family']= ['Heiti TC']
49
- mpfrc={'font.family': 'Heiti TC'}
50
-
51
- if czxt in ['linux']: #website Jupyter
52
- plt.rcParams['font.family']= ['Heiti TC']
53
- mpfrc={'font.family':'Heiti TC'}
54
-
55
- # 解决保存图像时'-'显示为方块的问题
56
- plt.rcParams['axes.unicode_minus'] = False
57
-
58
- #设置绘图风格:关闭网格虚线
59
- plt.rcParams['axes.grid']=False
60
-
61
- #==============================================================================
62
- def reset_plt():
63
- """
64
- 功能:用于使用完mplfinance可能造成的绘图乱码问题,但不能恢复默认绘图尺寸
65
- """
66
- import matplotlib.pyplot as plt
67
- if czxt in ['win32','win64']:
68
- plt.rcParams['font.sans-serif'] = ['SimHei']
69
- if czxt in ['darwin']:
70
- plt.rcParams['font.sans-serif']=['Arial Unicode MS']
71
- plt.rcParams['axes.unicode_minus'] = False
72
-
73
- #尝试恢复绘图尺寸
74
- #统一设定绘制的图片大小:数值为英寸,1英寸=100像素
75
- #plt.rcParams['figure.figsize']=(12.8,7.2)
76
- plt.rcParams['figure.figsize']=(12.8,6.4)
77
- plt.rcParams['figure.dpi']=300
78
- plt.rcParams['font.size'] = 13
79
- plt.rcParams['xtick.labelsize']=11 #横轴字体大小
80
- plt.rcParams['ytick.labelsize']=11 #纵轴字体大小
81
-
82
- title_txt_size=16
83
- ylabel_txt_size=14
84
- xlabel_txt_size=14
85
- legend_txt_size=14
86
-
87
- #设置绘图风格:网格虚线
88
- plt.rcParams['axes.grid']=False
89
- #plt.rcParams['grid.color']='steelblue'
90
- #plt.rcParams['grid.linestyle']='dashed'
91
- #plt.rcParams['grid.linewidth']=0.5
92
- #plt.rcParams['axes.facecolor']='whitesmoke'
93
-
94
- return
95
-
96
- #==============================================================================
97
- #以下使用新浪/stooq数据源
98
- #==============================================================================
99
-
100
- if __name__ =="__main__":
101
- ticker='AAPL'
102
- ticker='00700.HK'
103
-
104
- def get_profile(ticker):
105
- """
106
- 功能:按照证券代码抓取证券基本信息。
107
- 输入:证券代码ticker。
108
- 返回:证券基本信息,数据框
109
- 注意:经常出现无规律失败,放弃!!!
110
- """
111
- #引入插件
112
- try:
113
- import yfinance as yf
114
- except:
115
- print(" #Error(get_profile): need to install yfinance")
116
- return None
117
-
118
- ticker1=ticker
119
- result,prefix,suffix=split_prefix_suffix(ticker)
120
- if result & (suffix=='HK'):
121
- if len(prefix)==5:
122
- ticker1=ticker[1:]
123
-
124
- #抓取证券信息,结果为字典
125
- tp=yf.Ticker(ticker1)
126
- try:
127
- dic=tp.info
128
- except:
129
- print(f" #Error(get_profile): failed to retrieve info for {ticker}")
130
- print(" Solution: try get_stock_profile instead")
131
- return None
132
-
133
- if dic is None:
134
- print(f" #Error(get_profile): none retrieved for {ticker}")
135
- print(" Solution: upgrade yfinance if already accessible to Yahoo")
136
- return None
137
-
138
-
139
- #将字典转换为数据框
140
- import pandas as pd
141
- df=pd.DataFrame([dic])
142
-
143
- #转换特殊列的内容:10位时间戳-->日期
144
- cols=list(df)
145
- import time
146
- if ('exDividendDate' in cols):
147
- df['exDividendDate']=int10_to_date(df['exDividendDate'][0])
148
- if ('lastSplitDate' in cols):
149
- df['lastSplitDate']=int10_to_date(df['lastSplitDate'][0])
150
- if ('sharesShortPreviousMonthDate' in cols):
151
- df['sharesShortPreviousMonthDate']=int10_to_date(df['sharesShortPreviousMonthDate'][0])
152
- if ('dateShortInterest' in cols):
153
- df['dateShortInterest']=int10_to_date(df['dateShortInterest'][0])
154
- if ('mostRecentQuarter' in cols):
155
- df['mostRecentQuarter']=int10_to_date(df['mostRecentQuarter'][0])
156
- if ('lastFiscalYearEnd' in cols):
157
- df['lastFiscalYearEnd']=int10_to_date(df['lastFiscalYearEnd'][0])
158
- if ('nextFiscalYearEnd' in cols):
159
- df['nextFiscalYearEnd']=int10_to_date(df['nextFiscalYearEnd'][0])
160
-
161
- #转换特殊列的内容:可交易标志
162
- """
163
- if df['tradeable'][0]: df['tradeable']="Yes"
164
- else: df['tradeable']="No"
165
- """
166
-
167
- return df
168
-
169
- if __name__ =="__main__":
170
- ticker='AAPL'
171
- df=get_profile('AAPL')
172
- #==============================================================================
173
- def print_profile_detail(df,option='basic'):
174
- """
175
- 功能:按照选项显示证券信息,更多细节。
176
- 输入:证券基本信息df;分段选项option。
177
- 输出:按照选项打印证券信息
178
- 返回:证券信息,数据框
179
- 注意:放弃
180
- """
181
- #检查数据框的有效性
182
- if (df is None) or (len(df)==0):
183
- print("...Error #1(print_profile), data input invalid!")
184
- return None
185
-
186
- options=["basic","financial","market"]
187
- if not(option in options):
188
- print("...Error #2(print_profile), 仅支持选项: basic, financial, market")
189
- return None
190
-
191
- #遍历数据框,清洗数据
192
- cols=list(df) #取得数据框的列名
193
- import numpy as np
194
- for c in cols:
195
- dfc0=df[c][0]
196
- #删除空值列
197
- if dfc0 is None:
198
- del df[c]; continue
199
- if dfc0 is np.nan:
200
- del df[c]; continue
201
- #删除空表列
202
- if isinstance(dfc0,list):
203
- if len(dfc0)==0: del df[c]; continue
204
-
205
- #分类型清洗内容
206
- if isinstance(dfc0,float): df[c]=round(dfc0,4)
207
- if isinstance(dfc0,str): df[c]=dfc0.strip()
208
- newcols=list(df) #取得清洗后数据框的列名
209
-
210
- #需要打印的字段,只要抓取到就打印
211
- basiccols=['symbol','quoteType','shortName','longName','sector','industry', \
212
- 'fullTimeEmployees','address1','city','state','country','zip', \
213
- 'phone','fax','website','currency','exchange','market']
214
- financialcols=['symbol','shortName','currency','dividendRate',
215
- 'trailingAnnualDividendRate','exDividendDate', \
216
- 'dividendYield','trailingAnnualDividendYield', \
217
- 'fiveYearAvgDividendYield','payoutRatio', \
218
- 'lastSplitDate','lastSplitFactor','trailingPE','forwardPE', \
219
- 'trailingEps','forwardEps','profitMargins','earningsQuarterlyGrowth', \
220
- 'pegRatio','priceToSalesTrailing12Months','priceToBook', \
221
- 'enterpriseToRevenue','enterpriseToEbitda','netIncomeToCommon','bookValue', \
222
- 'lastFiscalYearEnd', \
223
- 'mostRecentQuarter','nextFiscalYearEnd']
224
- marketcols=['symbol','shortName','currency','beta','tradeable','open', \
225
- 'regularMarketOpen','dayHigh','regularMarketDayHigh', \
226
- 'dayLow','regularMarketLow','previousClose', \
227
- 'regularMarketPreviousClose','regularMarketPrice','ask','bid', \
228
- 'fiftyDayAvergae','twoHundredDayAverage','fiftyTwoWeekHigh', \
229
- 'fiftyTwoWeekLow','52WeekChange','SandP52Change','volume', \
230
- 'regularMarketVolume','averageVolume','averageDailyVolume10Day', \
231
- 'averageVolume10days', \
232
- 'sharesShortPriorMonth','sharesShortPreviousMonthDate', \
233
- 'dateShortInterest','sharesPercentSharesOut', \
234
- 'sharesOutstanding','floatShares','heldPercentInstitutions', \
235
- 'heldPercentInsiders','enterpriseValue','marketCap', \
236
- 'sharesShort','shortRatio','shortPercentOfFloat']
237
-
238
- typecn=["公司信息","财务信息","市场信息"]
239
- typeinfo=typecn[options.index(option)]
240
- print("\n===",texttranslate("证券快照:")+typeinfo,"===")
241
- typecols=[basiccols,financialcols,marketcols]
242
- cols=typecols[options.index(option)]
243
-
244
- from pandas.api.types import is_numeric_dtype
245
- for i in cols:
246
- if i in newcols:
247
- cn=ectranslate(i)
248
- if is_numeric_dtype(df[i][0]):
249
- if abs(df[i][0]) >= 0.0001:
250
- print(cn+':',format(df[i][0],','))
251
- else:
252
- print(cn+':',df[i][0])
253
-
254
- import datetime as dt; todaydt=dt.date.today()
255
- print('\n'+texttranslate("数据来源:雅虎,")+str(todaydt))
256
-
257
- return df
258
-
259
- if __name__ =="__main__":
260
- option='basic'
261
- df=print_profile_detail(df, option='basic')
262
- df=print_profile_detail(df, option='financial')
263
- df=print_profile_detail(df, option='market')
264
-
265
- #==============================================================================
266
- def print_profile(df,option='basic'):
267
- """
268
- 功能:按照选项显示证券信息,简化版。
269
- 输入:证券基本信息df;分段选项option。
270
- 输出:按照选项打印证券信息
271
- 返回:证券信息,数据框
272
- 注意:放弃
273
- """
274
- #检查数据框的有效性
275
- if (df is None) or (len(df)==0):
276
- print(" #Error(print_profile), data set input invalid!")
277
- return None
278
-
279
- options=["basic","financial","market"]
280
- if not(option in options):
281
- print(" #Error(print_profile), only support types of basic, financial, market")
282
- return None
283
-
284
- #遍历数据框,清洗数据
285
- cols=list(df) #取得数据框的列名
286
- import numpy as np
287
- for c in cols:
288
- dfc0=df[c][0]
289
- #删除空值列
290
- if dfc0 is None:
291
- del df[c]; continue
292
- if dfc0 is np.nan:
293
- del df[c]; continue
294
- #删除空表列
295
- if isinstance(dfc0,list):
296
- if len(dfc0)==0: del df[c]; continue
297
-
298
- #分类型清洗内容
299
- if isinstance(dfc0,float): df[c]=round(dfc0,4)
300
- if isinstance(dfc0,str): df[c]=dfc0.strip()
301
- newcols=list(df) #取得清洗后数据框的列名
302
-
303
- basiccols=['symbol','quoteType','shortName','sector','industry', \
304
- 'fullTimeEmployees','city','state','country', \
305
- 'website','currency','exchange']
306
- financialcols=['symbol','dividendRate',
307
- 'dividendYield', \
308
- 'payoutRatio', \
309
- 'trailingPE','forwardPE', \
310
- 'trailingEps','forwardEps','profitMargins','earningsQuarterlyGrowth', \
311
- 'pegRatio','priceToSalesTrailing12Months','priceToBook', \
312
- 'bookValue', \
313
- 'lastFiscalYearEnd']
314
- marketcols=['symbol','beta','open', \
315
- 'dayHigh', \
316
- 'dayLow','previousClose', \
317
- 'fiftyTwoWeekHigh', \
318
- 'fiftyTwoWeekLow','52WeekChange','SandP52Change','volume', \
319
- 'averageDailyVolume10Day', \
320
- 'sharesOutstanding','floatShares','heldPercentInstitutions', \
321
- 'heldPercentInsiders','marketCap']
322
-
323
- typecn=["公司信息","财务信息","市场信息"]
324
- typeinfo=typecn[options.index(option)]
325
- print("\n===",texttranslate("证券快照TTM:")+typeinfo,"===")
326
- typecols=[basiccols,financialcols,marketcols]
327
- cols=typecols[options.index(option)]
328
-
329
- from pandas.api.types import is_numeric_dtype
330
- for i in cols:
331
- if i in newcols:
332
- cn=ectranslate(i)
333
- if is_numeric_dtype(df[i][0]):
334
- print(cn+':',format(df[i][0],','))
335
- else:
336
- print(cn+':',df[i][0])
337
-
338
- import datetime as dt; today=dt.date.today()
339
- print(texttranslate("数据来源:Yahoo Finance,")+str(today))
340
- return df
341
-
342
- if __name__ =="__main__":
343
- option='basic'
344
- df=print_profile(df, option='basic')
345
- df=print_profile(df, option='financial')
346
- df=print_profile(df, option='market')
347
- #==============================================================================
348
- def stock_profile(ticker,option='basic',verbose=False):
349
- """
350
- 功能:抓取证券快照信息,包括静态公司信息、财务信息和市场信息。
351
- 输入:证券代码ticker;选项verbose表示是否显示详细信息,默认否。
352
- 输出:一次性打印公司信息、财务信息和市场信息。
353
- 返回:证券快照信息数据表。
354
- 注意:放弃
355
- """
356
- print(" Searching for security snapshot information, please wait ...")
357
- #抓取证券静态信息
358
- try:
359
- df=get_profile(ticker)
360
- except:
361
- print(" #Error(stock_profile), failed to retrieve or decode profile info of",ticker)
362
- return None
363
-
364
- #检查抓取到的数据表
365
- if (df is None) or (len(df)==0):
366
- print(" #Error(stock_profile), retrieved empty profile info of",ticker)
367
- return None
368
-
369
- df=print_profile(df, option='basic')
370
- #详细版输出信息
371
- if verbose:
372
- df=print_profile_detail(df, option='financial')
373
- df=print_profile_detail(df, option='market')
374
-
375
- return df
376
-
377
-
378
- #==============================================================================
379
-
380
- if __name__ =="__main__":
381
- #美股
382
- info=stock_profile("MSFT")
383
- info=stock_profile("MSFT",option="market")
384
- info=stock_profile("MSFT",option="financial")
385
- #大陆股票
386
- info=stock_profile("000002.SZ")
387
- info=stock_profile("000002.SZ",option="financial")
388
- info=stock_profile("000002.SZ",option="market")
389
- #港股
390
- info=stock_profile("00700.HK",option="financial")
391
- info=stock_profile("00700.HK",option="market")
392
- info=stock_profile("00700.HK",option="basic")
393
- #印度股票
394
- info=stock_profile("TCS.NS",option="financial")
395
- info=stock_profile("TCS.NS",option="market")
396
- info=stock_profile("TCS.NS",option="basic")
397
- #德国股票
398
- info=stock_profile("BMW.DE",option="financial")
399
- info=stock_profile("BMW.DE",option="market")
400
- info=stock_profile("BMW.DE",option="basic")
401
- #日本股票
402
- info=stock_profile("6758.t",option="financial")
403
- info=stock_profile("6758.t",option="market")
404
- info=stock_profile("6758.t",option="basic")
405
- info=stock_profile("9501.t",option="financial")
406
- #ETF指数基金
407
- info=stock_profile("SPY")
408
- info=stock_profile("SPY",option="market")
409
- info=stock_profile("SPY",option="financial")
410
- #债券期货
411
- info=stock_profile("US=F")
412
- info=stock_profile("US=F",option="market")
413
- info=stock_profile("US=F",option="financial")
414
- #债券基金
415
- info=stock_profile("LBNDX",option="basic")
416
- info=stock_profile("LBNDX",option="market")
417
- info=stock_profile("LBNDX",option="financial")
418
- #期货
419
- info=stock_profile("VXX",option="basic")
420
- info=stock_profile("VXX",option="market")
421
- info=stock_profile("VXX",option="financial")
422
-
423
- #==============================================================================
424
- def security_price(ticker,fromdate,todate,adj=False, \
425
- datatag=False,power=0,source='auto'):
426
- """
427
- 功能:绘制证券价格折线图。为维持兼容性,套壳函数stock_price
428
- """
429
- df=stock_price(ticker=ticker,fromdate=fromdate,todate=todate, \
430
- adj=adj,datatag=datatag,power=power,source=source)
431
-
432
- return df
433
-
434
- if __name__ =="__main__":
435
- # 测试获取股价:沪深指数
436
- df=security_price("000001.SS","2022-11-1","2022-12-15")
437
- df=security_price("000300.SS","2022-11-1","2022-12-15")
438
- df=security_price("399001.SZ","2022-11-1","2022-12-15")
439
- df=security_price("399106.SZ","2022-11-1","2022-12-15")
440
-
441
- # 测试获取股价:上交所
442
- df=security_price("000001.SS","2022-11-1","2022-12-15")
443
-
444
- # 测试获取股价:深交所
445
- df=security_price("000001.SZ","2022-11-1","2022-12-15")
446
-
447
- # 测试获取股价:北交所
448
- df=security_price("430047.BJ","2022-11-1","2022-12-15")
449
- df=security_price("872925.BJ","2022-11-1","2022-12-15")
450
-
451
- # 测试获取股价:港股
452
- df=security_price("00700.HK","2022-11-1","2022-12-15")
453
- df=security_price("01810.HK","2022-11-1","2022-12-15")
454
-
455
- # 测试获取股价:美股
456
- df=security_price("JD","2022-11-1","2022-12-15")
457
- df=security_price("AAPL","2022-11-1","2022-12-15")
458
-
459
- #==============================================================================
460
- if __name__ =="__main__":
461
- ticker="185851.SS"
462
- fromdate="2023-1-1"
463
- todate="2023-5-20"
464
-
465
-
466
- def stock_price(ticker,fromdate,todate,adj=False, \
467
- datatag=False,power=0,source='auto',facecolor='whitesmoke'):
468
- """
469
- 功能:绘制证券价格折线图。
470
- 输入:证券代码ticker;开始日期fromdate,结束日期todate;
471
- 是否标注数据标签datatag,默认否;多项式趋势线的阶数,若为0则不绘制趋势线。
472
- 输出:绘制证券价格折线图
473
- 返回:证券价格数据表
474
- """
475
- #抓取证券价格
476
- from siat.security_prices import get_price
477
- df=get_price(ticker,fromdate,todate,adj=adj,source=source)
478
-
479
- if not (df is None):
480
- tickername=ticker_name(ticker)
481
-
482
- import datetime; today = datetime.date.today()
483
- lang=check_language()
484
- if lang == 'English':
485
- titletxt=texttranslate("Security Price Trend:")+tickername
486
- footnote=texttranslate("Data source: Sina/EM/Stooq/Yahoo/SWHY, ")+str(today)
487
- else:
488
- titletxt=texttranslate("证券价格走势图:")+tickername
489
- footnote=texttranslate("数据来源:Sina/EM/Stooq/Yahoo/SWHY,")+str(today)
490
-
491
- pricetype='Close'
492
- import pandas as pd
493
- df1=pd.DataFrame(df[pricetype])
494
- df1.dropna(inplace=True)
495
-
496
- collabel=ectranslate(pricetype)
497
- ylabeltxt=collabel
498
- plot_line(df1,pricetype,collabel,ylabeltxt,titletxt,footnote, \
499
- datatag=datatag,power=power,facecolor=facecolor)
500
-
501
- return df
502
-
503
- if __name__ =="__main__":
504
- priceinfo=stock_price("AAPL","2023-1-1","2023-6-16",power=3)
505
-
506
- #==============================================================================
507
- if __name__ =="__main__":
508
- fromdate='2023-1-1'
509
- fromdate1=date_adjust(fromdate,adjust=-730)
510
- pricedf=get_price("AAPL",fromdate1,'2023-6-16')
511
-
512
-
513
- def ret_calculate(pricedf,fromdate):
514
- """
515
- 功能:单纯计算各种收益率指标
516
- """
517
- #加入日收益率
518
- from siat.security_prices import calc_daily_return,calc_rolling_return,calc_expanding_return
519
- drdf=calc_daily_return(pricedf)
520
- #加入滚动收益率
521
- prdf1=calc_rolling_return(drdf, "Weekly")
522
- prdf2=calc_rolling_return(prdf1, "Monthly")
523
- prdf3=calc_rolling_return(prdf2, "Quarterly")
524
- prdf4=calc_rolling_return(prdf3, "Annual")
525
-
526
- #加入扩展收益率
527
- try:
528
- erdf=calc_expanding_return(prdf4,fromdate)
529
- except:
530
- print(" #Error(ret_calculate): A problem happens while calculating expanding returns based on",fromdate,prdf4)
531
- return None
532
-
533
- return erdf
534
-
535
- if __name__ =="__main__":
536
- pricedf=get_price("AAPL",'2023-1-1','2023-6-16',adj=True)
537
- allind=all_calculate(pricedf,"AAPL",'2023-1-1','2023-6-16')
538
- list(allind)
539
-
540
- def all_calculate(pricedf,ticker1,fromdate,todate,ticker_type='auto'):
541
- """
542
- 功能:单纯计算所有基于证券价格的指标
543
-
544
- 注意:对于滚动指标,起始日期需要提前至少一年以上
545
- """
546
-
547
- #计算其各种期间的收益率
548
- try:
549
- df1a=ret_calculate(pricedf,fromdate)
550
- except:
551
- print(" #Error(all_calculate): A problem occurs for calculating returns of",ticker1)
552
- return None
553
- if df1a is None:
554
- print(" #Warning(all_calculate): insufficient data for",ticker1,'\b, ignored.')
555
- return None
556
-
557
- #加入价格波动指标
558
- #df1b=price_volatility2(df1a,ticker1,fromdate,todate,graph=False)
559
- df1b=price_volatility2(pricedf,ticker1,fromdate,todate,graph=False,ticker_type=ticker_type)
560
-
561
- #加入收益率波动指标
562
- df1c=ret_volatility2(pricedf,ticker1,fromdate,todate,graph=False,ticker_type=ticker_type)
563
-
564
- #加入收益率下偏标准差指标
565
- df1d=ret_lpsd2(pricedf,ticker1,fromdate,todate,graph=False,ticker_type=ticker_type)
566
-
567
- # 横向拼接合并
568
- result=pd.concat([df1a,df1b,df1c,df1d],axis=1,join='outer')
569
-
570
- # 去掉重复的列,但要避免仅仅因为数值相同而去掉有用的列,比如误删'Close'列
571
- result1=result.T
572
- result1['item']=result1.index #在行中增加临时列名,避免误删
573
- result2=result1.drop_duplicates(subset=None,keep='first',ignore_index=False)
574
- result2.drop("item", axis=1, inplace=True) #去掉临时列名
575
- result3=result2.T
576
-
577
- return result3
578
-
579
-
580
- if __name__ =="__main__":
581
- # 测试组1
582
- ticker='NVDA'
583
- indicator="Exp Ret%"
584
- indicator="Annual Ret Volatility%"
585
-
586
- # 测试组2
587
- ticker='GCZ25.CMX'
588
- fromdate='2020-1-1'
589
- todate='2020-6-30'
590
- indicator="Close"
591
-
592
- # 测试组3
593
- ticker='GEM24.CME'
594
- fromdate='2023-7-1'
595
- todate='2023-9-17'
596
- indicator="Close"
597
-
598
- # 公共参数
599
- datatag=False
600
- power=0
601
- graph=True
602
- source='auto'
603
- zeroline=False
604
- average_value=False
605
-
606
- # 其他测试
607
- ticker='600519.SS'; indicator='Exp Ret Volatility%'
608
-
609
- ticker='180202.SZ'
610
- ticker_type='fund'
611
-
612
- fromdate='2024-1-1'; todate='2024-5-25'
613
-
614
- # 测试组4
615
- ticker='AAPL'
616
- indicator='Adj Close'
617
- fromdate='2024-5-1'; todate='2024-5-20'
618
- adjust=''
619
- zeroline=False; average_value=False; datatag=False; power=0; graph=True
620
- source='auto'
621
- mark_top=True; mark_bottom=True; mark_end=True
622
- ticker_type='auto'
623
- facecolor='whitesmoke'
624
-
625
- # 测试组5
626
- ticker='851242.SW'
627
- ticker='807110.SW'
628
- indicator='Close'
629
- fromdate='2024-5-1'; todate='2024-5-20'
630
- adjust=''
631
- zeroline=False; average_value=False; datatag=False; power=0; graph=True
632
- source='auto'
633
- mark_top=True; mark_bottom=True; mark_end=True
634
- ticker_type='auto'
635
- facecolor='whitesmoke'
636
-
637
- # 测试组6
638
- ticker='XAUUSD'
639
- indicator='Close'
640
- fromdate='2024-5-1'; todate='2024-5-20'
641
-
642
- # 测试组7
643
- ticker='BMW.DE'
644
- indicator='Close'
645
- fromdate='2025-6-1'; todate='2025-6-15'
646
-
647
- # 测试组8
648
- ticker='GEM25.CME'
649
- indicator='Close'
650
- fromdate='2025-1-1'; todate='2025-6-15'
651
-
652
- zeroline=False
653
- attention_value='';attention_value_area=''
654
- attention_point='';attention_point_area=''
655
- average_value=False
656
- datatag=False;power=0;graph=True;source='auto'
657
- mark_top=True;mark_bottom=True;mark_end=True
658
- ticker_type='auto';facecolor='whitesmoke';loc='best'
659
-
660
-
661
- df=security_indicator(ticker,indicator,fromdate,todate,ticker_type=ticker_type)
662
-
663
- def security_indicator(ticker,indicator='Close', \
664
- fromdate='MRM',todate='today',adjust='', \
665
- zeroline=False, \
666
- attention_value='',attention_value_area='', \
667
- attention_point='',attention_point_area='', \
668
- average_value=False, \
669
- datatag=False,power=0,graph=True,source='auto', \
670
- mark_top=True,mark_bottom=True, \
671
- mark_start=True,mark_end=True, \
672
- ticker_type='auto',facecolor='whitesmoke',loc='best'):
673
- """
674
- 功能:单只证券的全部指标
675
- """
676
- fromdate,todate=start_end_preprocess(fromdate,todate)
677
-
678
- #判断复权价
679
- adjust_list=['','qfq','hfq']
680
- if adjust not in adjust_list:
681
- print(" #Warning(security_indicator): invalid adjust",adjust)
682
- print(" Supported adjust:",adjust_list)
683
- adjust='qfq'
684
-
685
- if ('Adj' not in indicator):
686
- adjust=''
687
- if ('Adj' in indicator) and (adjust == ''):
688
- adjust='qfq'
689
-
690
- fromdate1=date_adjust(fromdate,adjust=-365*3)
691
-
692
- from siat.security_price2 import get_price_1ticker_mixed
693
- #pricedf=get_prices_all(ticker,fromdate1,todate,source=source,ticker_type=ticker_type)
694
- pricedf,found=get_price_1ticker_mixed(ticker=ticker, \
695
- fromdate=fromdate1,todate=todate, \
696
- adjust=adjust, \
697
- source=source,ticker_type=ticker_type)
698
- if pricedf is None:
699
- print(" #Error(security_indicator): security info not found for",ticker)
700
- return None
701
- if len(pricedf) == 0:
702
- print(" #Error(security_indicator): zero record found for",ticker)
703
- return None
704
-
705
- #奇怪错误:仅仅抓取到1个记录,应对办法:改变开始时间,貌似仅存在于REIT基金
706
- if len(pricedf)==1:
707
- fromdate1=date_adjust(fromdate,adjust=-365*2)
708
- pricedf,found=get_price_1ticker_mixed(ticker=ticker,fromdate=fromdate1, \
709
- adjust=adjust, \
710
- todate=todate,source=source,ticker_type=ticker_type)
711
- if len(pricedf)==1:
712
- fromdate1=date_adjust(fromdate,adjust=-365*1)
713
- pricedf,found=get_price_1ticker_mixed(ticker=ticker,fromdate=fromdate1, \
714
- adjust=adjust, \
715
- todate=todate,source=source,ticker_type=ticker_type)
716
- if len(pricedf)==1:
717
- fromdate1=fromdate
718
- pricedf,found=get_price_1ticker_mixed(ticker=ticker,fromdate=fromdate1, \
719
- adjust=adjust, \
720
- todate=todate,source=source,ticker_type=ticker_type)
721
-
722
- if not found == "Found":
723
- print(" #Error(security_indicator): no security info found for",ticker)
724
- return None
725
-
726
- # 去掉时区信息,避免日期时区冲突问题
727
- pricedf=df_index_timezone_remove(pricedf)
728
- """
729
- import pandas as pd
730
- pricedf.index = pd.to_datetime(pricedf.index)
731
- pricedf.index = pricedf.index.tz_localize(None)
732
- """
733
- # 检查是否存在满足给定日期的记录
734
- fromdate_pd=pd.to_datetime(fromdate)
735
- tmp_df=pricedf[pricedf.index >= fromdate_pd]
736
- if len(tmp_df)==0:
737
- print(" #Warning(security_indicator): zero record exists from",fromdate,"for",ticker)
738
- return None
739
-
740
- erdf=all_calculate(pricedf,ticker,fromdate,todate)
741
- erdf2=erdf[erdf.index >= fromdate_pd]
742
-
743
- # 若indicator为Exp Ret%类指标,此处需要首行置零
744
- colList=list(erdf2)
745
- index1=erdf2.head(1).index.values[0]
746
- for c in colList:
747
- #if 'Exp Ret%' in c:
748
- if c == 'Exp Ret%':
749
- erdf2.loc[erdf2[erdf2.index==index1].index.tolist(),c]=0
750
-
751
- #erdf3=pd.DataFrame(erdf2[indicator])
752
- erdf3=erdf2
753
-
754
- # 绘图
755
- if not graph:
756
- return erdf3
757
-
758
- #titletxt=texttranslate("证券指标运动趋势:")+ticker_name(ticker)
759
- titletxt1=text_lang("证券趋势分析:","Security Trend: ")
760
- titletxt=titletxt1+ticker_name(ticker,ticker_type=ticker_type)
761
- import datetime; todaydt = datetime.date.today()
762
- sourcetxt=text_lang("数据来源:Sina/EM/Stooq/Yahoo/SWHY,","Data source: Sina/EM/Stooq/Yahoo/SWHY, ")
763
- footnote=sourcetxt+str(todaydt)
764
- collabel=ectranslate(indicator)
765
-
766
- ylabeltxt=ectranslate(indicator)
767
- try:
768
- tickersplit=ticker.split('.')
769
- if (len(tickersplit) > 1) and (indicator == 'Close'):
770
- if tickersplit[1].upper() in ['M','B']:
771
- ylabeltxt="stooq_MB" #特殊标志,告知绘图函数不显示某些标记
772
- except: pass
773
-
774
- ind_max=erdf3[indicator].max(); ind_min=erdf3[indicator].min()
775
- if ind_max * ind_min <0:
776
- #if 'Ret%' in indicator:
777
- zeroline=True
778
-
779
- plot_line(erdf3,indicator,collabel,ylabeltxt,titletxt,footnote,datatag=datatag, \
780
- power=power,zeroline=zeroline, \
781
- average_value=average_value, \
782
- attention_value=attention_value,attention_value_area=attention_value_area, \
783
- attention_point=attention_point,attention_point_area=attention_point_area, \
784
- mark_top=mark_top,mark_bottom=mark_bottom, \
785
- mark_start=mark_start,mark_end=mark_end, \
786
- facecolor=facecolor,loc=loc)
787
-
788
- return erdf3
789
-
790
-
791
- def stock_ret(ticker,fromdate,todate, \
792
- adjust='', \
793
- rtype="Daily Ret%", \
794
- datatag=False,power=0,graph=True,source='auto',ticker_type='auto'):
795
- """
796
- 功能:绘制证券收益率折线图,单个证券,单个指标。
797
- 输入:证券代码ticker;开始日期fromdate,结束日期todate;收益率类型type;
798
- 是否标注数据标签datatag,默认否;多项式趋势线的阶数,若为0则不绘制趋势线。
799
- 输出:绘制证券价格折线图
800
- 返回:证券价格数据表
801
- """
802
- #调整抓取样本的开始日期366*2=732,以便保证有足够的样本供后续计算
803
- fromdate1=date_adjust(fromdate, -732)
804
-
805
- #判断复权价
806
- adjust_list=['','qfq','hfq']
807
- if adjust not in adjust_list:
808
- print(" #Warning(stock_ret): invalid adjust",adjust)
809
- print(" Supported adjust:",adjust_list)
810
- adjust='qfq'
811
- if 'Adj' in rtype: adjust='qfq'
812
-
813
- #抓取证券价格
814
- from siat.security_price2 import get_price_1ticker_mixed
815
- #pricedf=get_price(ticker,fromdate1,todate,adj=adj,source=source)
816
- pricedf,found=get_price_1ticker_mixed(ticker=ticker,fromdate=fromdate1, \
817
- todate=todate,adjust=adjust, \
818
- source=source,ticker_type=ticker_type)
819
- if pricedf is None:
820
- print(" #Error(stock_ret): failed to find price info for",ticker,fromdate,todate)
821
- return None
822
- pricedfcols=list(pricedf)
823
-
824
- #加入日收益率
825
- from siat.security_prices import calc_daily_return
826
- drdf=calc_daily_return(pricedf)
827
- #加入滚动收益率
828
- prdf1=calc_rolling_return(drdf, "Weekly")
829
- prdf2=calc_rolling_return(prdf1, "Monthly")
830
- prdf3=calc_rolling_return(prdf2, "Quarterly")
831
- prdf4=calc_rolling_return(prdf3, "Annual")
832
-
833
- #加入扩展收益率:从fromdate开始而不是fromdate1
834
- erdf=calc_expanding_return(prdf4,fromdate)
835
-
836
- #如果不绘图则直接返回数据表
837
- if not graph: return erdf
838
-
839
- #获得支持的收益率类型列名
840
- colnames=list(erdf)
841
- for c in pricedfcols:
842
- colnames.remove(c)
843
-
844
- #检查type是否在支持的收益率列名中
845
- if not (rtype in colnames):
846
- print(" #Error(stock_ret):only support return types of",colnames)
847
- return
848
-
849
- import datetime; todaydt = datetime.date.today()
850
- footnote=text_lang("数据来源:Sina/EM/Stooq/Yahoo/SWHY,","Data source: Sina/EM/Stooq/Yahoo/SWHY, ")+str(todaydt)
851
- collabel=ectranslate(rtype)
852
- ylabeltxt=ectranslate(rtype)
853
- titletxt=text_lang("证券趋势分析:","Security Trend: ")+ticker_name(ticker,ticker_type=ticker_type)+text_lang(",收益率",", Rate of Return")
854
-
855
- pltdf=erdf[erdf.index >= fromdate]
856
- plot_line(pltdf,rtype,collabel,ylabeltxt,titletxt,footnote,datatag=datatag, \
857
- power=power,zeroline=True)
858
-
859
- return erdf
860
-
861
- if __name__ =="__main__":
862
- ticker="000002.SZ"
863
- fromdate="2020-1-1"
864
- todate="2020-3-16"
865
- type="Daily Ret%"
866
- datatag=False
867
- power=3
868
- retinfo=stock_ret("000002.SZ","2020-1-1","2020-3-16",power=3)
869
- retinfo=stock_ret("000002.SZ","2020-1-1","2020-3-16","Daily Adj Ret%",power=3)
870
- retinfo=stock_ret("000002.SZ","2020-1-1","2020-3-16","Weekly Ret%",power=3)
871
- retinfo=stock_ret("000002.SZ","2020-1-1","2020-3-16","Monthly Ret%",power=4)
872
- retinfo=stock_ret("000002.SZ","2020-1-1","2020-3-16","Quarterly Ret%",power=4)
873
- retinfo=stock_ret("000002.SZ","2019-1-1","2020-3-16","Annual Ret%",power=4)
874
- retinfo=stock_ret("000002.SZ","2019-1-1","2020-3-16","Cum Ret%",power=4)
875
-
876
- #==============================================================
877
- if __name__ =="__main__":
878
- ticker='600519.SS'
879
- ticker='OR.PA'
880
- measures=['Monthly Ret%','Quarterly Ret%','Annual Ret%','XYZ']
881
-
882
- ticker='NVDA'
883
- measures=['Close','Adj Close']
884
-
885
- fromdate='2024-5-20'
886
- todate='2024-6-20'
887
- adjust=''
888
- band_area=''
889
- graph=True
890
- smooth=True
891
- loc='best'
892
- facecolor='whitesmoke'
893
- date_range=False
894
- date_freq=False
895
- annotate=False
896
- annotate_value=False
897
- source='auto'
898
- mark_top=True; mark_bottom=True; mark_end=True
899
- ticker_type='auto'
900
-
901
- df=security_mindicators(ticker,measures,fromdate,todate)
902
-
903
- def security_mindicators(ticker,measures,
904
- fromdate,todate, \
905
- attention_value='',attention_value_area='', \
906
- attention_point='',attention_point_area='', \
907
- adjust='', \
908
- band_area='', \
909
- graph=True,smooth=True,loc='best',facecolor='whitesmoke', \
910
- date_range=False,date_freq=False, \
911
- annotate=False,annotate_value=False, \
912
- source='auto', \
913
- mark_top=True,mark_bottom=True, \
914
- mark_start=True,mark_end=True, \
915
- ticker_type='auto'):
916
- """
917
- 功能:单个证券,多个指标对比
918
- date_range=False:指定开始结束日期绘图
919
- date_freq=False:指定横轴日期间隔,例如'D'、'2D'、'W'、'M'等,横轴一般不超过25个标注,否则会重叠
920
- 注意:
921
- annotate:这里仅为预留,暂时未作处理
922
- smooth:样本数目超过一定数量就默认忽略
923
- """
924
- DEBUG=False
925
-
926
- # 提前开始日期
927
- #fromdate1=date_adjust(fromdate,adjust=-365*3)
928
-
929
- #处理ticker,允许1个
930
- if isinstance(ticker,list):
931
- if len(ticker) >= 1:
932
- ticker=ticker[0]
933
- else:
934
- print(" #Error(security_mindicators): need a ticker for proceed")
935
- return None
936
-
937
- #处理measures,允许多个
938
- if isinstance(measures,str):
939
- measures=[measures]
940
-
941
- #屏蔽函数内print信息输出的类
942
- import os, sys
943
- class HiddenPrints:
944
- def __enter__(self):
945
- self._original_stdout = sys.stdout
946
- sys.stdout = open(os.devnull, 'w')
947
-
948
- def __exit__(self, exc_type, exc_val, exc_tb):
949
- sys.stdout.close()
950
- sys.stdout = self._original_stdout
951
-
952
- df=pd.DataFrame()
953
- for m in measures:
954
- print(" Searching",ticker,"for",m,"info ... ...")
955
- #复权价判断
956
- adjustm=adjust
957
- if ('Adj' in m) and (adjust ==''):
958
- adjustm='qfq'
959
-
960
- with HiddenPrints():
961
- #security_indicator未能做到同时获得Close和Adj Close
962
- dftmp=security_indicator(ticker=ticker,indicator=m,adjust=adjustm, \
963
- fromdate=fromdate,todate=todate, \
964
- source=source, \
965
- ticker_type=ticker_type, \
966
- graph=False)
967
- if dftmp is None:
968
- print(" #Error(security_mindicators): info not found for",ticker)
969
- return None
970
- if len(dftmp) ==0:
971
- print(" #Error(security_mindicators): empty record found for",ticker)
972
- return None
973
-
974
- try:
975
- dftmp1= dftmp[[m]]
976
- except:
977
- print(" #Error(security_mindicators): unsupported measure for",m)
978
- return None
979
-
980
- if len(df)==0:
981
- df=dftmp1
982
- else:
983
- df=pd.merge(df,dftmp1,left_index=True,right_index=True)
984
-
985
- df['ticker']=ticker
986
-
987
- if graph:
988
- # 翻译指标名称
989
- for c in list(df):
990
- df.rename(columns={c:ectranslate(c)},inplace=True)
991
-
992
- y_label=text_lang('证券指标',"Indicator")
993
- import datetime; todaydt = datetime.date.today()
994
- x_label=text_lang("数据来源:Sina/EM/Stooq/Yahoo/SWHY,","Data source: Sina/EM/Stooq/Yahoo/SWHY, ")+str(todaydt)
995
-
996
- axhline_value=0; axhline_label=''
997
- above_zero=0; below_zero=0
998
- for c in list(df):
999
- c_max=df[c].max(); c_min=df[c].min()
1000
- try:
1001
- if c_max>0 or c_min>0: above_zero+=1
1002
- if c_max<0 or c_min<0: below_zero+=1
1003
- except: continue
1004
-
1005
- if above_zero>0 and below_zero>0: #有正有负
1006
- if DEBUG:
1007
- print("DEBUG: draw axhline=0")
1008
- #if 'Ret%' in c:
1009
- axhline_value=0
1010
- axhline_label='零线'
1011
-
1012
- titletxt=text_lang("证券趋势分析:","Security Trend: ")+ticker_name(ticker,ticker_type=ticker_type)
1013
-
1014
- draw_lines2(df,y_label,x_label,axhline_value,axhline_label,titletxt, \
1015
- data_label=False,resample_freq='1D',smooth=smooth, \
1016
- date_range=date_range,date_freq=date_freq,date_fmt='%Y-%m-%d', \
1017
- attention_value=attention_value,attention_value_area=attention_value_area, \
1018
- attention_point=attention_point,attention_point_area=attention_point_area, \
1019
- annotate=annotate,annotate_value=annotate_value, \
1020
- mark_top=mark_top,mark_bottom=mark_bottom, \
1021
- mark_start=mark_start,mark_end=mark_end, \
1022
- facecolor=facecolor, \
1023
- band_area=band_area,loc=loc)
1024
-
1025
- return df
1026
-
1027
- #==============================================================================
1028
- def stock_price_volatility(ticker,fromdate,todate,type="Weekly Price Volatility", \
1029
- datatag=False,power=0,graph=True):
1030
- """
1031
- 功能:绘制证券价格波动风险折线图。
1032
- 输入:证券代码ticker;开始日期fromdate,结束日期todate;期间类型type;
1033
- 是否标注数据标签datatag,默认否;多项式趋势线的阶数,若为0则不绘制趋势线。
1034
- 输出:绘制证券价格波动折线图
1035
- 返回:证券价格数据表
1036
- """
1037
- #调整抓取样本的开始日期,以便保证有足够的样本供后续计算
1038
- fromdate1=date_adjust(fromdate, -400)
1039
-
1040
- #抓取证券价格
1041
- adj=False
1042
- if 'Adj' in type: adj=True
1043
- from siat.security_prices import get_price
1044
- pricedf=get_price(ticker,fromdate1,todate,adj=adj)
1045
- if pricedf is None:
1046
- print(" #Error(stock_price_volatility):failed to find price info for",ticker,fromdate,todate)
1047
- return
1048
- pricedfcols=list(pricedf)
1049
-
1050
- #加入滚动价格波动风险
1051
- prdf1=rolling_price_volatility(pricedf, "Weekly")
1052
- prdf2=rolling_price_volatility(prdf1, "Monthly")
1053
- prdf3=rolling_price_volatility(prdf2, "Quarterly")
1054
- prdf4=rolling_price_volatility(prdf3, "Annual")
1055
-
1056
- #加入累计价格波动风险
1057
- erdf=expanding_price_volatility(prdf4,fromdate)
1058
-
1059
- #如果不绘图则直接返回数据表
1060
- if not graph: return erdf
1061
-
1062
- #获得支持的价格波动风险类型列名,去掉不需要的列名
1063
- colnames=list(erdf)
1064
- for c in pricedfcols:
1065
- colnames.remove(c)
1066
-
1067
- #检查type是否在支持的收益率列名中
1068
- if not (type in colnames):
1069
- print(" #Error(stock_price_volatility):only support price risk types of",colnames)
1070
- return
1071
-
1072
- titletxt=texttranslate("证券价格波动风险走势图:")+ticker_name(ticker)
1073
- import datetime; today = datetime.date.today()
1074
- footnote=texttranslate("数据来源:Sina/EM/Stooq/Yahoo/SWHY,")+str(today)
1075
- collabel=ectranslate(type)
1076
- ylabeltxt=ectranslate(type)
1077
- pltdf=erdf[erdf.index >= fromdate]
1078
- plot_line(pltdf,type,collabel,ylabeltxt,titletxt,footnote,datatag=datatag, \
1079
- power=power,zeroline=True)
1080
-
1081
- return erdf
1082
-
1083
- if __name__ =="__main__":
1084
- ticker="000002.SZ"
1085
- fromdate="2020-1-1"
1086
- todate="2020-3-16"
1087
- type="Daily Ret%"
1088
- datatag=False
1089
- power=3
1090
-
1091
- pv=stock_price_volatility("000002.SZ","2019-1-1","2020-3-16","Annual Price Volatility")
1092
- pv=stock_price_volatility("000002.SZ","2019-1-1","2020-3-16","Annual Exp Price Volatility")
1093
-
1094
- #==============================================================================
1095
- def price_volatility2(pricedf,ticker,fromdate,todate, \
1096
- type="Weekly Price Volatility",datatag=False, \
1097
- power=4,graph=True,ticker_type='auto'):
1098
- """
1099
- 功能:绘制证券价格波动风险折线图。与函数price_volatility的唯一区别是不抓取股价。
1100
- 输入:股价数据集pricedf;证券代码ticker;开始日期fromdate,结束日期todate;期间类型type;
1101
- 是否标注数据标签datatag,默认否;多项式趋势线的阶数,若为0则不绘制趋势线。
1102
- 输出:绘制证券价格波动折线图
1103
- 返回:证券价格数据表
1104
- """
1105
- pricedfcols=list(pricedf)
1106
- #加入滚动价格波动风险
1107
- from siat.security_prices import rolling_price_volatility,expanding_price_volatility
1108
- prdf1=rolling_price_volatility(pricedf, "Weekly")
1109
- prdf2=rolling_price_volatility(prdf1, "Monthly")
1110
- prdf3=rolling_price_volatility(prdf2, "Quarterly")
1111
- prdf4=rolling_price_volatility(prdf3, "Annual")
1112
-
1113
- #加入累计价格波动风险
1114
- erdf=expanding_price_volatility(prdf4,fromdate)
1115
-
1116
- #如果不绘图则直接返回数据表
1117
- if not graph: return erdf
1118
-
1119
- #获得支持的价格波动风险类型列名,去掉不需要的列名
1120
- colnames=list(erdf)
1121
- for c in pricedfcols:
1122
- colnames.remove(c)
1123
-
1124
- #检查type是否在支持的收益率列名中
1125
- if not (type in colnames):
1126
- print(" #Error(price_volatility2):only support price risk types of",colnames)
1127
- return
1128
-
1129
- titletxt=text_lang("证券趋势分析:","Security Trend: ")+ticker_name(ticker,ticker_type=ticker_type)+text_lang(",价格波动风险",", Price Volatility Risk")
1130
- import datetime; todaydt = datetime.date.today()
1131
- footnote=texttranslate("数据来源:Sina/EM/Stooq/Yahoo/SWHY,")+str(todaydt)
1132
- collabel=ectranslate(type)
1133
- ylabeltxt=ectranslate(type)
1134
- pltdf=erdf[erdf.index >= fromdate]
1135
- plot_line(pltdf,type,collabel,ylabeltxt,titletxt,footnote,datatag=datatag, \
1136
- power=power,zeroline=True)
1137
-
1138
- return erdf
1139
-
1140
- if __name__ =="__main__":
1141
- ticker="000002.SZ"
1142
- fromdate="2020-1-1"
1143
- todate="2020-3-16"
1144
- type="Daily Ret%"
1145
- datatag=False
1146
- power=3
1147
-
1148
- df=get_price("000002.SZ","2019-1-1","2020-3-16")
1149
- pv=price_volatility2(df,"000002.SZ","2019-1-1","2020-3-16","Annual Price Volatility")
1150
- pv=price_volatility2(df,"000002.SZ","2019-1-1","2020-3-16","Annual Exp Price Volatility")
1151
-
1152
- #==============================================================================
1153
- def stock_ret_volatility(ticker,fromdate,todate,type="Weekly Ret Volatility%",datatag=False,power=4,graph=True):
1154
- """
1155
- 功能:绘制证券收益率波动风险折线图。
1156
- 输入:证券代码ticker;开始日期fromdate,结束日期todate;期间类型type;
1157
- 是否标注数据标签datatag,默认否;多项式趋势线的阶数,若为0则不绘制趋势线。
1158
- 输出:绘制证券收益率波动折线图
1159
- 返回:证券收益率波动数据表
1160
- """
1161
- #调整抓取样本的开始日期,以便保证有足够的样本供后续计算
1162
- fromdate1=date_adjust(fromdate, -400)
1163
- retdf=stock_ret(ticker,fromdate1,todate,graph=False)
1164
- pricedfcols=list(retdf)
1165
-
1166
- #加入滚动收益率波动风险
1167
- prdf1=rolling_ret_volatility(retdf, "Weekly")
1168
- prdf2=rolling_ret_volatility(prdf1, "Monthly")
1169
- prdf3=rolling_ret_volatility(prdf2, "Quarterly")
1170
- prdf4=rolling_ret_volatility(prdf3, "Annual")
1171
-
1172
- #加入累计收益率波动风险
1173
- erdf=expanding_ret_volatility(prdf4,fromdate)
1174
-
1175
- #如果不绘图则直接返回数据表
1176
- if not graph: return erdf
1177
-
1178
- #获得支持的收益率波动风险类型列名,去掉不需要的列名
1179
- colnames=list(erdf)
1180
- for c in pricedfcols:
1181
- colnames.remove(c)
1182
-
1183
- #检查type是否在支持的收益率波动指标列名中
1184
- if not (type in colnames):
1185
- print(" #Error(stock_ret_volatility),only support return risk types of",colnames)
1186
- return
1187
-
1188
- titletxt=texttranslate("证券收益率波动风险走势图:")+ticker_name(ticker)
1189
- import datetime; today = datetime.date.today()
1190
- footnote=texttranslate("数据来源:Sina/EM/Stooq/Yahoo/SWHY,")+str(today)
1191
- collabel=ectranslate(type)
1192
- ylabeltxt=ectranslate(type)
1193
- pltdf=erdf[erdf.index >= fromdate]
1194
- plot_line(pltdf,type,collabel,ylabeltxt,titletxt,footnote,datatag=datatag, \
1195
- power=power,zeroline=True)
1196
-
1197
- return erdf
1198
-
1199
- if __name__ =="__main__":
1200
- ticker="000002.SZ"
1201
- fromdate="2020-1-1"
1202
- todate="2020-3-16"
1203
- type="Daily Ret%"
1204
- datatag=False
1205
- power=3
1206
-
1207
- pv=stock_ret_volatility("000002.SZ","2019-1-1","2020-3-16","Annual Ret Volatility%")
1208
- pv=stock_ret_volatility("000002.SZ","2019-1-1","2020-3-16","Annual Exp Ret Volatility%")
1209
-
1210
-
1211
- #==============================================================================
1212
- def ret_volatility2(retdf,ticker,fromdate,todate, \
1213
- type="Weekly Ret Volatility%",datatag=False, \
1214
- power=4,graph=True,ticker_type='auto'):
1215
- """
1216
- 功能:绘制证券收益率波动风险折线图。与函数ret_volatility的唯一区别是不抓取股价。
1217
- 输入:股价数据集pricedf;证券代码ticker;开始日期fromdate,结束日期todate;期间类型type;
1218
- 是否标注数据标签datatag,默认否;多项式趋势线的阶数,若为0则不绘制趋势线。
1219
- 输出:绘制证券收益率波动折线图
1220
- 返回:证券收益率波动数据表
1221
- """
1222
- retdfcols=list(retdf)
1223
-
1224
- #retdf=calc_daily_return(pricedf)
1225
- #加入滚动价格波动风险
1226
- from siat.security_prices import rolling_ret_volatility,expanding_ret_volatility
1227
- prdf1=rolling_ret_volatility(retdf, "Weekly")
1228
- prdf2=rolling_ret_volatility(prdf1, "Monthly")
1229
- prdf3=rolling_ret_volatility(prdf2, "Quarterly")
1230
- prdf4=rolling_ret_volatility(prdf3, "Annual")
1231
-
1232
- #加入累计价格波动风险
1233
- erdf=expanding_ret_volatility(prdf4,fromdate)
1234
-
1235
- #如果不绘图则直接返回数据表
1236
- if not graph: return erdf
1237
-
1238
- #获得支持的价格波动风险类型列名,去掉不需要的列名
1239
- colnames=list(erdf)
1240
- for c in retdfcols:
1241
- colnames.remove(c)
1242
-
1243
- #检查type是否在支持的收益率列名中
1244
- if not (type in colnames):
1245
- print(" #Error(ret_volatility2): only support return risk types of",colnames)
1246
- return
1247
-
1248
- titletxt=text_lang("证券趋势分析:","Security Trend: ")+ticker_name(ticker,ticker_type=ticker_type)+text_lang(",收益率波动风险",", Return Volatility Risk")
1249
- import datetime; todaydt = datetime.date.today()
1250
- footnote=text_lang("数据来源:Sina/EM/Stooq/Yahoo/SWHY,","Data source: Sina/EM/Stooq/Yahoo/SWHY, ")+str(todaydt)
1251
- collabel=ectranslate(type)
1252
- ylabeltxt=ectranslate(type)
1253
- pltdf=erdf[erdf.index >= fromdate]
1254
- plot_line(pltdf,type,collabel,ylabeltxt,titletxt,footnote,datatag=datatag, \
1255
- power=power,zeroline=True)
1256
-
1257
- return erdf
1258
-
1259
- if __name__ =="__main__":
1260
- ticker="000002.SZ"
1261
- fromdate="2020-1-1"
1262
- todate="2020-3-16"
1263
- type="Daily Ret%"
1264
- datatag=False
1265
- power=3
1266
-
1267
- df=get_price("000002.SZ","2019-1-1","2020-3-16")
1268
- pv=price_volatility2(df,"000002.SZ","2019-1-1","2020-3-16","Annual Price Volatility")
1269
- pv=price_volatility2(df,"000002.SZ","2019-1-1","2020-3-16","Annual Exp Price Volatility")
1270
-
1271
- #==============================================================================
1272
- def ret_lpsd(ticker,fromdate,todate,type="Weekly Ret Volatility%",datatag=False,power=4,graph=True):
1273
- """
1274
- 功能:绘制证券收益率波动损失风险折线图。
1275
- 输入:证券代码ticker;开始日期fromdate,结束日期todate;期间类型type;
1276
- 是否标注数据标签datatag,默认否;多项式趋势线的阶数,若为0则不绘制趋势线。
1277
- 输出:绘制证券收益率下偏标准差折线图
1278
- 返回:证券收益率下偏标准差数据表
1279
- """
1280
- #调整抓取样本的开始日期,以便保证有足够的样本供后续计算
1281
- fromdate1=date_adjust(fromdate, -400)
1282
- retdf=stock_ret(ticker,fromdate1,todate,graph=False)
1283
- pricedfcols=list(retdf)
1284
-
1285
- #加入滚动收益率下偏标准差
1286
- prdf1=rolling_ret_lpsd(retdf, "Weekly")
1287
- prdf2=rolling_ret_lpsd(prdf1, "Monthly")
1288
- prdf3=rolling_ret_lpsd(prdf2, "Quarterly")
1289
- prdf4=rolling_ret_lpsd(prdf3, "Annual")
1290
-
1291
- #加入扩展收益率下偏标准差
1292
- erdf=expanding_ret_lpsd(prdf4,fromdate)
1293
-
1294
- #如果不绘图则直接返回数据表
1295
- if not graph: return erdf
1296
-
1297
- #获得支持的收益率波动风险类型列名,去掉不需要的列名
1298
- colnames=list(erdf)
1299
- for c in pricedfcols:
1300
- colnames.remove(c)
1301
-
1302
- #检查type是否在支持的收益率波动指标列名中
1303
- if not (type in colnames):
1304
- print(" #Error(ret_lpsd): only support return risk types of",colnames)
1305
- return
1306
-
1307
- titletxt=texttranslate("证券收益率波动损失风险走势图:")+ticker_name(ticker)
1308
- import datetime; today = datetime.date.today()
1309
- footnote=texttranslate("数据来源:Sina/EM/Stooq/Yahoo/SWHY,")+str(today)
1310
- collabel=ectranslate(type)
1311
- ylabeltxt=ectranslate(type)
1312
- pltdf=erdf[erdf.index >= fromdate]
1313
- plot_line(pltdf,type,collabel,ylabeltxt,titletxt,footnote,datatag=datatag, \
1314
- power=power,zeroline=True)
1315
-
1316
- return erdf
1317
-
1318
- if __name__ =="__main__":
1319
- ticker="000002.SZ"
1320
- fromdate="2020-1-1"
1321
- todate="2020-3-16"
1322
- type="Daily Ret%"
1323
- datatag=False
1324
- power=3
1325
-
1326
- pv=ret_lpsd("000002.SZ","2019-1-1","2020-3-16","Annual Ret Volatility%")
1327
- pv=ret_lpsd("000002.SZ","2019-1-1","2020-3-16","Annual Exp Ret Volatility%")
1328
-
1329
- #==============================================================================
1330
- def ret_lpsd2(retdf,ticker,fromdate,todate, \
1331
- rtype="Weekly Ret Volatility%",datatag=False, \
1332
- power=4,graph=True,ticker_type='auto'):
1333
- """
1334
- 功能:绘制证券收益率波动损失风险折线图。与函数ret_lpsd的唯一区别是不抓取股价。
1335
- 输入:股价数据集pricedf;证券代码ticker;开始日期fromdate,结束日期todate;期间类型type;
1336
- 是否标注数据标签datatag,默认否;多项式趋势线的阶数,若为0则不绘制趋势线。
1337
- 输出:绘制证券收益率下偏标准差折线图。
1338
- 返回:证券收益率下偏标准差数据表。
1339
- """
1340
- retdfcols=list(retdf)
1341
- #retdf=calc_daily_return(pricedf)
1342
- #加入滚动价格波动风险
1343
- from siat.security_prices import rolling_ret_lpsd,expanding_ret_lpsd
1344
- prdf1=rolling_ret_lpsd(retdf, "Weekly")
1345
- prdf2=rolling_ret_lpsd(prdf1, "Monthly")
1346
- prdf3=rolling_ret_lpsd(prdf2, "Quarterly")
1347
- prdf4=rolling_ret_lpsd(prdf3, "Annual")
1348
-
1349
- #加入扩展收益率下偏标准差
1350
- erdf=expanding_ret_lpsd(prdf4,fromdate)
1351
-
1352
- #如果不绘图则直接返回数据表
1353
- if not graph: return erdf
1354
-
1355
- #获得支持的价格波动风险类型列名,去掉不需要的列名
1356
- colnames=list(erdf)
1357
- for c in retdfcols:
1358
- colnames.remove(c)
1359
-
1360
- #检查type是否在支持的收益率列名中
1361
- if not (rtype in colnames):
1362
- print(" #Error(ret_lpsd2): only support return risk types of",colnames)
1363
- return
1364
-
1365
- titletxt=text_lang("证券趋势分析:","Security Trend: ")+ticker_name(ticker,ticker_type=ticker_type)+text_lang("波动损失风险","Volatility Loss Risk")
1366
- import datetime; todaydt = datetime.date.today()
1367
- footnote=text_lang("数据来源:Sina/EM/Stooq/Yahoo/SWHY,","Data source: Sina/EM/Stooq/Yahoo/SWHY, ")+str(todaydt)
1368
- collabel=ectranslate(rtype)
1369
- ylabeltxt=ectranslate(rtype)
1370
- pltdf=erdf[erdf.index >= fromdate]
1371
- plot_line(pltdf,rtype,collabel,ylabeltxt,titletxt,footnote,datatag=datatag, \
1372
- power=power,zeroline=True)
1373
-
1374
- return erdf
1375
-
1376
- if __name__ =="__main__":
1377
- ticker="000002.SZ"
1378
- fromdate="2020-1-1"
1379
- todate="2020-3-16"
1380
- type="Daily Ret%"
1381
- datatag=False
1382
- power=3
1383
-
1384
- df=get_price("000002.SZ","2019-1-1","2020-3-16")
1385
- pv=price_lpsd2(df,"000002.SZ","2019-1-1","2020-3-16","Annual Price Volatility")
1386
- pv=price_lpsd2(df,"000002.SZ","2019-1-1","2020-3-16","Annual Exp Price Volatility")
1387
- #==============================================================================
1388
- def comp_1security_2measures(df,measure1,measure2,twinx=False, \
1389
- attention_value='',attention_value_area='', \
1390
- attention_point='',attention_point_area='', \
1391
- loc1='upper left',loc2='lower left', \
1392
- graph=True,facecolor='whitesmoke', \
1393
- ticker_type='auto'):
1394
- """
1395
- 功能:对比绘制一只证券两个指标的折线图。
1396
- 输入:证券指标数据集df;行情类别measure1/2。
1397
- 输出:绘制证券行情双折线图,基于twinx判断使用单轴或双轴坐标
1398
- 返回:无
1399
- """
1400
- DEBUG=False
1401
-
1402
- #筛选证券指标,检验是否支持指标
1403
- dfcols=list(df)
1404
- #nouselist=['date','Weekday','ticker']
1405
- #for c in nouselist: dfcols.remove(c)
1406
-
1407
- if not (measure1 in dfcols):
1408
- print(" #Error(comp_1security_2measures): unsupported measures: ",measure1)
1409
- print(" Supporting measures: ",dfcols)
1410
- return
1411
- if not (measure2 in dfcols):
1412
- print(" #Error(comp_1security_2measures): unsupported measures: ",measure2)
1413
- print(" Supporting measures: ",dfcols)
1414
- return
1415
-
1416
- #判断是否绘制水平0线
1417
- pricelist=['High','Low','Open','Close','Volume','Adj Close']
1418
- if (measure1 in pricelist) or (measure2 in pricelist):
1419
- zeroline=False
1420
- else: zeroline=True
1421
-
1422
- #提取信息
1423
- ticker=df['ticker'][0]
1424
- fromdate=str(df.index[0].date())
1425
- todate=str(df.index[-1].date())
1426
- label1=ectranslate(measure1)
1427
- label2=ectranslate(measure2)
1428
- ylabeltxt=""
1429
-
1430
- tname=ticker_name(ticker,ticker_type=ticker_type)
1431
- titletxt=text_lang("证券趋势分析:","Security Trend: ")+tname
1432
-
1433
- import datetime; todaydt = datetime.date.today()
1434
- footnote1=text_lang("数据来源:Sina/EM/Stooq/Yahoo/SWHY,","Source: Sina/EM/Stooq/Yahoo/SWHY, ")
1435
- footnote=footnote1+str(todaydt)
1436
-
1437
- #绘图
1438
- if DEBUG:
1439
- print("plot_line2")
1440
- print("attention_value=",attention_value)
1441
- print("attention_point=",attention_point)
1442
-
1443
- plot_line2(df,ticker,measure1,label1,df,ticker,measure2,label2, \
1444
- ylabeltxt,titletxt,footnote,zeroline=zeroline,twinx=twinx, \
1445
- yline=attention_value,attention_value_area=attention_value_area, \
1446
- xline=attention_point,attention_point_area=attention_point_area, \
1447
- loc1=loc1,loc2=loc2,facecolor=facecolor)
1448
-
1449
- return
1450
-
1451
- if __name__ =="__main__":
1452
- ticker='000002.SZ'
1453
- measure1='Daily Ret%'
1454
- measure2='Daily Adj Ret%'
1455
- fromdate='2020-1-1'
1456
- todate='2020-3-16'
1457
- df=stock_ret(ticker,fromdate,todate,graph=False)
1458
- comp_1security_2measures(df,measure1,measure2)
1459
- #==============================================================================
1460
- def comp_2securities_1measure(df1,df2,measure,twinx=False, \
1461
- attention_value='',attention_value_area='', \
1462
- attention_point='',attention_point_area='', \
1463
- loc1='best',loc2='best',graph=True, \
1464
- ticker_type=['auto','auto'],facecolor='whitesmoke'):
1465
- """
1466
- 功能:对比绘制两只证券的相同指标折线图。
1467
- 输入:指标数据集df1/2;证券代码ticker1/2;指标类别measure。
1468
- 输出:绘制证券指标双折线图,基于twinx判断使用单轴或双轴坐标。
1469
- 返回:无
1470
- """
1471
-
1472
- #筛选证券指标,检验是否支持指标
1473
- dfcols=list(df1)
1474
- #nouselist=['date','Weekday','ticker']
1475
- #for c in nouselist: dfcols.remove(c)
1476
-
1477
- if not (measure in dfcols):
1478
- print(" #Error(comp_2securities_1measure):only support measurement types of",dfcols)
1479
- return
1480
-
1481
- #判断是否绘制水平0线
1482
- pricelist=['High','Low','Open','Close','Volume','Adj Close']
1483
- if measure in pricelist: zeroline=False
1484
- else:
1485
- df_max=max([df1[measure].max(),df2[measure].max()])
1486
- df_min=min([df1[measure].min(),df2[measure].min()])
1487
- if df_max * df_min >0: #同正同负
1488
- zeroline=False
1489
- else:
1490
- zeroline=True
1491
-
1492
- #提取信息
1493
- try:
1494
- ticker1=df1['ticker'][0]
1495
- except:
1496
- print(" #Error(comp_2securities_1measure): none info found for the 1st symbol")
1497
- return
1498
- try:
1499
- ticker2=df2['ticker'][0]
1500
- except:
1501
- print(" #Error(comp_2securities_1measure): none info found for the 2nd symbol")
1502
- return
1503
-
1504
- fromdate=str(df1.index[0].date())
1505
- todate=str(df1.index[-1].date())
1506
- label=ectranslate(measure)
1507
- ylabeltxt=ectranslate(measure)
1508
-
1509
- tname1=ticker_name(ticker1,ticker_type=ticker_type[0])
1510
- tname2=ticker_name(ticker2,ticker_type=ticker_type[1])
1511
-
1512
- #绘图
1513
- print('')
1514
-
1515
- titletxt1=text_lang("证券趋势分析:","Security Trend: ")
1516
- titletxt=titletxt1+tname1+" vs "+tname2
1517
-
1518
- import datetime; todaydt = datetime.date.today()
1519
- footnote1=text_lang("数据来源:Sina/EM/Stooq/Yahoo/SWHY,","Data source: Sina/EM/Stooq/Yahoo/SWHY, ")
1520
- footnote=footnote1+str(todaydt)+text_lang("统计","")
1521
-
1522
- plot_line2(df1,ticker1,measure,label,df2,ticker2,measure,label, \
1523
- ylabeltxt,titletxt,footnote,zeroline=zeroline,twinx=twinx, \
1524
- yline=attention_value,attention_value_area=attention_value_area, \
1525
- xline=attention_point,attention_point_area=attention_point_area, \
1526
- loc1=loc1,loc2=loc2,facecolor=facecolor)
1527
-
1528
- return
1529
-
1530
- if __name__ =="__main__":
1531
- ticker1='000002.SZ'
1532
- ticker2='600266.SS'
1533
- measure='Daily Ret%'
1534
- fromdate='2020-1-1'
1535
- todate='2020-3-16'
1536
- df1=stock_ret(ticker1,fromdate,todate,graph=False)
1537
- df2=stock_ret(ticker2,fromdate,todate,graph=False)
1538
- comp_2securities_1measure(df1,df2,measure)
1539
- #==============================================================================
1540
- if __name__ =="__main__":
1541
- tickers=['MSFT','AAPL']
1542
- measures='Annual Ret Volatility%'
1543
-
1544
- tickers='MSFT'
1545
- measures=['Annual Ret Volatility%','Annual Ret%']
1546
-
1547
- tickers='NVDA'
1548
- tickers='AAPL'
1549
- measures=['Close','Adj Close']
1550
-
1551
- tickers=['000001.SS','^DJI']
1552
- measures='Close'
1553
-
1554
- fromdate='2024-5-1'
1555
- todate='2025-6-23'
1556
- adjust=''
1557
- twinx=False
1558
- loc1='best'
1559
- loc2='lower left'
1560
- graph=True
1561
- source='auto'
1562
- ticker_type='auto'
1563
- facecolor='whitesmoke'
1564
-
1565
- attention_value=''; attention_value_area=''
1566
- attention_point=''; attention_point_area=''
1567
-
1568
-
1569
- def compare_security(tickers,measures,fromdate,todate, \
1570
- adjust='', \
1571
- twinx=False, \
1572
- attention_value='',attention_value_area='', \
1573
- attention_point='',attention_point_area='', \
1574
- loc1='best',loc2='lower left',graph=True,source='auto', \
1575
- ticker_type='auto',facecolor='whitesmoke'):
1576
- """
1577
- 功能:函数克隆compare_stock,只能处理两个ticker一个measure,或一个ticker两个measure
1578
- 可以处理twinx=True
1579
- """
1580
- """
1581
- # 应对导入失灵的函数
1582
- from siat.security_prices import upper_ticker
1583
- tickers=upper_ticker(tickers)
1584
- result=compare_stock(tickers=tickers,measures=measures, \
1585
- fromdate=fromdate,todate=todate, \
1586
- adjust=adjust, \
1587
- twinx=twinx, \
1588
- loc1=loc1,loc2=loc2,graph=graph,source=source, \
1589
- ticker_type=ticker_type,facecolor=facecolor)
1590
-
1591
- return result
1592
- """
1593
- #调试开关
1594
- DEBUG=False
1595
-
1596
- # 应对导入失灵的函数
1597
- from siat.common import upper_ticker
1598
- tickers=upper_ticker(tickers)
1599
-
1600
- #判断证券代码个数
1601
- #如果tickers只是一个字符串
1602
- security_num = 0
1603
- if isinstance(tickers,str):
1604
- security_num = 1
1605
- ticker1 = tickers
1606
- #如果tickers是一个列表
1607
- if isinstance(tickers,list):
1608
- security_num = len(tickers)
1609
- if security_num != 0:
1610
- if security_num >= 1: ticker1 = tickers[0]
1611
- if security_num >= 2: ticker2 = tickers[1]
1612
- else:
1613
- print(" #Error(compare_security):security code/codes needed.")
1614
- return None,None
1615
-
1616
- #判断测度个数
1617
- #如果measures只是一个字符串
1618
- measure_num = 0
1619
- if isinstance(measures,str):
1620
- measure_num = 1
1621
- #measure1 = measures
1622
- measure1 = measure2 = measures
1623
- #如果measures是一个列表
1624
- if isinstance(measures,list):
1625
- measure_num = len(measures)
1626
- if measure_num != 0:
1627
- if measure_num >= 1: measure1 = measures[0]
1628
- if measure_num >= 2: measure2 = measures[1]
1629
- else:
1630
- print(" #Error(compare_security): a measurement indicator needed.")
1631
- return None,None
1632
-
1633
- #解析ticker_type
1634
- if isinstance(ticker_type,str):
1635
- ticker_type1=ticker_type2=ticker_type
1636
- if isinstance(ticker_type,list) and len(ticker_type)==1:
1637
- ticker_type1=ticker_type2=ticker_type[0]
1638
- if isinstance(ticker_type,list) and len(ticker_type) >= 2:
1639
- ticker_type1=ticker_type[0]
1640
- ticker_type2=ticker_type[1]
1641
- ticker_type_list=[ticker_type1,ticker_type2]
1642
-
1643
- #屏蔽函数内print信息输出的类
1644
- import os, sys
1645
- class HiddenPrints:
1646
- def __enter__(self):
1647
- self._original_stdout = sys.stdout
1648
- sys.stdout = open(os.devnull, 'w')
1649
-
1650
- def __exit__(self, exc_type, exc_val, exc_tb):
1651
- sys.stdout.close()
1652
- sys.stdout = self._original_stdout
1653
-
1654
- #单一证券代码+两个测度指标
1655
- if (security_num == 1) and (measure_num >= 2):
1656
-
1657
- print(" Searching",ticker1,"for",measure1,"info ... ...")
1658
- #复权价判断1
1659
- adjust1=adjust
1660
- if ('Adj' in measure1) and (adjust1 ==''):
1661
- adjust1='qfq'
1662
-
1663
- with HiddenPrints():
1664
- #security_indicator未能做到同时获得Close和Adj Close
1665
- df1tmp=security_indicator(ticker=ticker1,indicator=measure1,adjust=adjust1, \
1666
- fromdate=fromdate,todate=todate, \
1667
- source=source, \
1668
- ticker_type=ticker_type, \
1669
- graph=False)
1670
-
1671
- if df_have_data(df1tmp)=="Found":
1672
- pltdf1= df1tmp[[measure1]]
1673
- else:
1674
- print(" #Error(compare_security):no info found for",ticker1,"on",measure1)
1675
- return None,None
1676
-
1677
- print(" Searching",ticker1,"for",measure2,"info ... ...")
1678
- #复权价判断2
1679
- adjust2=adjust
1680
- if ('Adj' in measure2) and (adjust2 ==''):
1681
- adjust2='qfq'
1682
-
1683
- with HiddenPrints():
1684
- #security_indicator未能做到同时获得Close和Adj Close
1685
- df2tmp=security_indicator(ticker=ticker1,indicator=measure2,adjust=adjust2, \
1686
- fromdate=fromdate,todate=todate, \
1687
- source=source, \
1688
- ticker_type=ticker_type, \
1689
- graph=False)
1690
-
1691
- if df_have_data(df2tmp)=="Found":
1692
- pltdf2= df2tmp[[measure2]]
1693
- else:
1694
- print(" #Error(compare_security):no info found for",ticker1,"on",measure2)
1695
- return None,None
1696
-
1697
- pltdf=pd.merge(pltdf1,pltdf2,left_index=True,right_index=True)
1698
- pltdf['ticker']=ticker1
1699
-
1700
- #绘制单个证券的双指标对比图
1701
- if graph:
1702
- if DEBUG:
1703
- print("In compare_security:")
1704
- print("Going to comp_1security_2measures ...")
1705
- print("attention_value=",attention_value)
1706
- print("attention_point=",attention_point)
1707
-
1708
- comp_1security_2measures(pltdf,measure1,measure2,twinx=twinx, \
1709
- attention_value=attention_value,attention_value_area=attention_value_area, \
1710
- attention_point=attention_point,attention_point_area=attention_point_area, \
1711
- loc1=loc1,loc2=loc2,graph=graph, \
1712
- ticker_type=ticker_type[0],facecolor=facecolor)
1713
-
1714
- try:
1715
- result1=pltdf[['ticker',measure1]]
1716
- except:
1717
- result1=None
1718
- try:
1719
- result2=pltdf[['ticker',measure2]]
1720
- except:
1721
- result2=None
1722
- return result1,result2
1723
-
1724
- elif (security_num >= 2) and (measure_num >= 1):
1725
- #双证券+单个测度指标
1726
- if ('Adj' in measure1) and (adjust ==''):
1727
- adjust='qfq'
1728
-
1729
- df1tmp=security_indicator(ticker=ticker1,indicator=measure1,adjust=adjust, \
1730
- fromdate=fromdate,todate=todate, \
1731
- source=source, \
1732
- ticker_type=ticker_type, \
1733
- graph=False)
1734
- if df_have_data(df1tmp)=="Found":
1735
- pltdf1=df1tmp[['ticker',measure1]]
1736
- else:
1737
- print(" #Error(compare_security):no info found for",ticker1,"on",measure1)
1738
- return None,None
1739
-
1740
- df2tmp=security_indicator(ticker=ticker2,indicator=measure1,adjust=adjust, \
1741
- fromdate=fromdate,todate=todate, \
1742
- source=source, \
1743
- ticker_type=ticker_type, \
1744
- graph=False)
1745
- if df_have_data(df2tmp)=="Found":
1746
- pltdf2=df2tmp[['ticker',measure1]]
1747
- else:
1748
- print(" #Error(compare_security):no info found for",ticker2,"on",measure1)
1749
- return None,None
1750
-
1751
- #绘制双证券单指标对比图
1752
- if graph:
1753
- if DEBUG:
1754
- print("In compare_security ...")
1755
- print("Going to comp_2securities_1measure")
1756
- print("attention_value=",attention_value)
1757
- print("attention_point=",attention_point)
1758
-
1759
- comp_2securities_1measure(pltdf1,pltdf2,measure1,twinx=twinx, \
1760
- attention_value=attention_value,attention_value_area=attention_value_area, \
1761
- attention_point=attention_point,attention_point_area=attention_point_area, \
1762
- loc1=loc1,loc2=loc2,graph=graph, \
1763
- ticker_type=ticker_type_list,facecolor=facecolor)
1764
-
1765
- try:
1766
- result1=pltdf1[[measure1]]
1767
- except:
1768
- print(" #Error(compare_secuirty): measure",measure1,"not found for",ticker1)
1769
- result1=None
1770
- try:
1771
- result2=pltdf2[[measure1]]
1772
- except:
1773
- print(" #Error(compare_secuirty): measure",measure1,"not found for",ticker2)
1774
- result2=None
1775
- return result1,result2
1776
-
1777
- else:
1778
- print(" #Warning(compare_secuirty):only support 1 ticker + 2 measures or 2 tickers + 1 measure.")
1779
- return None,None
1780
-
1781
-
1782
- #==============================================================================
1783
- if __name__ =="__main__":
1784
- tickers=['MSFT','AAPL']
1785
- measures='Annual Ret Volatility%'
1786
- fromdate='2023-1-1'
1787
- todate='2023-12-31'
1788
- adjust=''
1789
- twinx=False
1790
- loc1='best'
1791
- loc2='lower left'
1792
- graph=True
1793
- source='auto'
1794
- ticker_type='auto'
1795
- facecolor='whitesmoke'
1796
-
1797
-
1798
- def compare_stock(tickers,measures,fromdate,todate, \
1799
- adjust='', \
1800
- twinx=False, \
1801
- loc1='best',loc2='lower left',graph=True,source='auto', \
1802
- ticker_type='auto',facecolor='whitesmoke'):
1803
- """
1804
- 功能:对比绘制折线图:一只证券的两种测度,或两只证券的同一个测度。
1805
- 输入:
1806
- 证券代码tickers,如果是一个列表且内含两个证券代码,则认为希望比较两个证券的
1807
- 同一个测度指标。如果是一个列表但只内含一个证券代码或只是一个证券代码的字符串,
1808
- 则认为希望比较一个证券的两个测度指标。
1809
- 测度指标measures:如果是一个列表且内含两个测度指标,则认为希望比较一个证券的
1810
- 两个测度指标。如果是一个列表但只内含一个测度指标或只是一个测度指标的字符串,
1811
- 则认为希望比较两个证券的同一个测度指标。
1812
- 如果两个判断互相矛盾,以第一个为准。
1813
- 开始日期fromdate,结束日期todate。
1814
- 输出:绘制证券价格折线图,手动指定是否使用单轴或双轴坐标。
1815
- 返回:无
1816
-
1817
- 打算废弃?
1818
- """
1819
- #调试开关
1820
- DEBUG=False
1821
- # 应对导入失灵的函数
1822
- from siat.common import upper_ticker
1823
- tickers=upper_ticker(tickers)
1824
-
1825
- #判断证券代码个数
1826
- #如果tickers只是一个字符串
1827
- security_num = 0
1828
- if isinstance(tickers,str):
1829
- security_num = 1
1830
- ticker1 = tickers
1831
- #如果tickers是一个列表
1832
- if isinstance(tickers,list):
1833
- security_num = len(tickers)
1834
- if security_num == 0:
1835
- print(" #Error(compare_stock):security code/codes needed.")
1836
- return None,None
1837
- if security_num >= 1: ticker1 = tickers[0]
1838
- if security_num >= 2: ticker2 = tickers[1]
1839
-
1840
- #判断测度个数
1841
- #如果measures只是一个字符串
1842
- measure_num = 0
1843
- if isinstance(measures,str):
1844
- measure_num = 1
1845
- measure1 = measures
1846
- #如果measures是一个列表
1847
- if isinstance(measures,list):
1848
- measure_num = len(measures)
1849
- if measure_num == 0:
1850
- print(" #Error(compare_stock): a measurement indicator needed.")
1851
- return None,None
1852
- if measure_num >= 1: measure1 = measures[0]
1853
- if measure_num >= 2: measure2 = measures[1]
1854
-
1855
- #延伸开始日期
1856
- fromdate1=date_adjust(fromdate,adjust=-365)
1857
-
1858
- #单一证券代码+两个测度指标
1859
- if (security_num == 1) and (measure_num >= 2):
1860
- if (('Adj' in measure1) or ('Adj' in measure2)) and (adjust ==''):
1861
- adjust='qfq'
1862
-
1863
- #证券ticker1:抓取行情,并计算其各种期间的收益率
1864
- df1a=stock_ret(ticker1,fromdate1,todate,adjust=adjust,graph=False,source=source,ticker_type=ticker_type)
1865
- if df1a is None: return None,None
1866
- if DEBUG: print("compare|df1a first date:",df1a.index[0])
1867
- #加入价格波动指标
1868
- df1b=price_volatility2(df1a,ticker1,fromdate1,todate,graph=False,ticker_type=ticker_type)
1869
- if DEBUG: print("compare|df1b first date:",df1b.index[0])
1870
- #加入收益率波动指标
1871
- df1c=ret_volatility2(df1b,ticker1,fromdate1,todate,graph=False,ticker_type=ticker_type)
1872
- if DEBUG: print("compare|df1c first date:",df1c.index[0])
1873
- #加入收益率下偏标准差指标
1874
- df1d=ret_lpsd2(df1c,ticker1,fromdate1,todate,graph=False,ticker_type=ticker_type)
1875
- if DEBUG: print("compare|df1d first date:",df1d.index[0])
1876
-
1877
- #去掉开始日期以前的数据
1878
- pltdf1=df1d[df1d.index >= fromdate1]
1879
- #绘制单个证券的双指标对比图
1880
- if graph:
1881
- comp_1security_2measures(pltdf1,measure1,measure2,twinx=twinx, \
1882
- loc1=loc1,loc2=loc2,graph=graph, \
1883
- ticker_type=ticker_type,facecolor=facecolor)
1884
-
1885
- try:
1886
- result1=pltdf1[[measure1]]
1887
- except:
1888
- return None,None
1889
- try:
1890
- result2=pltdf1[[measure2]]
1891
- except:
1892
- return result1,None
1893
-
1894
- elif (security_num >= 2) and (measure_num >= 1):
1895
- #双证券+单个测度指标
1896
- if ('Adj' in measure1) and (adjust ==''):
1897
- adjust='qfq'
1898
-
1899
- #解析ticker_type
1900
- if isinstance(ticker_type,str):
1901
- ticker_type1=ticker_type2=ticker_type
1902
- if isinstance(ticker_type,list) and len(ticker_type)==1:
1903
- ticker_type1=ticker_type2=ticker_type[0]
1904
- if isinstance(ticker_type,list) and len(ticker_type) > 1:
1905
- ticker_type1=ticker_type[0]
1906
- ticker_type2=ticker_type[1]
1907
- ticker_type_list=[ticker_type1,ticker_type2]
1908
-
1909
- #证券ticker1:抓取行情,并计算其各种期间的收益率
1910
- df1a=stock_ret(ticker1,fromdate1,todate,adjust=adjust,graph=False,source=source,ticker_type=ticker_type1)
1911
- if df1a is None: return None,None
1912
- #加入价格波动指标
1913
- df1b=price_volatility2(df1a,ticker1,fromdate1,todate,graph=False,ticker_type=ticker_type1)
1914
- #加入收益率波动指标
1915
- df1c=ret_volatility2(df1b,ticker1,fromdate1,todate,graph=False,ticker_type=ticker_type1)
1916
- #加入收益率下偏标准差指标
1917
- df1d=ret_lpsd2(df1c,ticker1,fromdate1,todate,graph=False,ticker_type=ticker_type1)
1918
- #去掉开始日期以前的数据
1919
- pltdf1=df1d[df1d.index >= fromdate1]
1920
-
1921
- #证券ticker2:
1922
- df2a=stock_ret(ticker2,fromdate1,todate,adjust=adjust,graph=False,source=source,ticker_type=ticker_type2)
1923
- if df2a is None: return None,None
1924
- df2b=price_volatility2(df2a,ticker2,fromdate1,todate,graph=False,ticker_type=ticker_type2)
1925
- df2c=ret_volatility2(df2b,ticker2,fromdate1,todate,graph=False,ticker_type=ticker_type2)
1926
- df2d=ret_lpsd2(df2c,ticker2,fromdate1,todate,graph=False,ticker_type=ticker_type2)
1927
- pltdf2=df2d[df2d.index >= fromdate1]
1928
-
1929
- #绘制双证券单指标对比图
1930
- if graph:
1931
- comp_2securities_1measure(pltdf1,pltdf2,measure1,twinx=twinx, \
1932
- loc1=loc1,loc2=loc2,graph=graph, \
1933
- ticker_type=ticker_type_list,facecolor=facecolor)
1934
-
1935
- try:
1936
- result1=pltdf1[[measure1]]
1937
- result2=pltdf2[[measure1]]
1938
- except:
1939
- print(" #Error(compare_stock): unknown measure",measure1)
1940
- return None,None
1941
-
1942
- else:
1943
- print(" #Error(compare_stock):do not understand what to compare.")
1944
- return None,None
1945
-
1946
- return result1,result2
1947
-
1948
- if __name__ =="__main__":
1949
- tickers='000002.SZ'
1950
- measures=['Close','Adj Close']
1951
- fromdate='2020-1-1'
1952
- todate='2020-3-16'
1953
- compare_stock(tickers,measures,fromdate,todate)
1954
-
1955
- tickers2=['000002.SZ','600266.SS']
1956
- measures2=['Close','Adj Close']
1957
- compare_stock(tickers2,measures2,fromdate,todate)
1958
-
1959
- tickers3=['000002.SZ','600266.SS']
1960
- measures3='Close'
1961
- compare_stock(tickers3,measures3,fromdate,todate)
1962
-
1963
- tickers4=['000002.SZ','600606.SS','600266.SS']
1964
- measures4=['Close','Adj Close','Daily Return']
1965
- compare_stock(tickers4,measures4,fromdate,todate)
1966
-
1967
- #==============================================================================
1968
- if __name__ =="__main__":
1969
- # 测试组1
1970
- tickers=["AMZN","EBAY","SHOP","BABA","JD"]
1971
- tickers=["AMZN","EBAY","SHOP","BABA","JD","PDD"]
1972
- tickers=['000001.SS',"399001.SZ","000300.SS"]
1973
- tickers=['000001.SS','^N225','^KS11']
1974
- measure="Annual Ret%"
1975
- measure="Exp Ret%"
1976
- measure="Close"
1977
- measure="Annual Ret Volatility%"
1978
-
1979
- start="2020-1-1"
1980
- end="2022-7-31"
1981
-
1982
- preprocess='scaling'
1983
- linewidth=1.5
1984
- scaling_option='start'
1985
-
1986
- # 测试组2
1987
- tickers=["GCZ25.CMX","GCZ24.CMX"]
1988
- measure='Close'
1989
- start="2020-1-1"
1990
- end="2020-6-30"
1991
-
1992
- # 测试组3
1993
- tickers=["MBG.DE", "BMW.DE"]
1994
- measure='Close'
1995
- start="2025-6-1"
1996
- end="2025-6-15"
1997
-
1998
- attention_value='';attention_value_area=''
1999
- attention_point='';attention_point_area=''
2000
- adjust=''
2001
- axhline_value=0;axhline_label=''
2002
- preprocess='none';linewidth=1.5
2003
- scaling_option='start'
2004
- plus_sign=False
2005
- band_area=''
2006
- graph=True;loc='best';facecolor='whitesmoke'
2007
- annotate=False;annotate_value=False
2008
- smooth=True
2009
- source='auto'
2010
- mark_top=True;mark_bottom=True
2011
- mark_start=False;mark_end=False
2012
- ticker_type='auto'
2013
-
2014
- def compare_msecurity(tickers,measure,start,end, \
2015
- attention_value='',attention_value_area='', \
2016
- attention_point='',attention_point_area='', \
2017
- adjust='', \
2018
- axhline_value=0,axhline_label='', \
2019
- preprocess='none',linewidth=1.5, \
2020
- scaling_option='start', \
2021
- plus_sign=False, \
2022
- band_area='', \
2023
- graph=True,loc='best',facecolor='whitesmoke', \
2024
- annotate=False,annotate_value=False, \
2025
- smooth=True, \
2026
- source='auto', \
2027
- mark_top=True,mark_bottom=True, \
2028
- mark_start=False,mark_end=False, \
2029
- ticker_type='auto'):
2030
- """
2031
- 功能:比较并绘制多条证券指标曲线(多于2条),个数可为双数或单数
2032
- 注意:
2033
- tickers中须含有2个及以上股票代码,
2034
- measure为单一指标,
2035
- axhline_label不为空时绘制水平线
2036
-
2037
- preprocess:是否对绘图数据进行预处理,仅适用于股价等数量级差异较大的数据,
2038
- 不适用于比例、比率和百分比等数量级较为一致的指标。
2039
- standardize: 标准化处理,(x - mean(x))/std(x)
2040
- normalize: 归一化处理,(x - min(x))/(max(x) - min(x))
2041
- logarithm: 对数处理,np.log(x)
2042
- scaling:缩放处理,五种选项scaling_option
2043
- (mean均值,min最小值,start开始值,percentage相对每条曲线起点值的百分比,
2044
- change%相对每条曲线起点值变化的百分比)
2045
- change%方式的图形更接近于持有收益率(Exp Ret%),设为默认的缩放方式。
2046
-
2047
- """
2048
- DEBUG=False
2049
-
2050
- # 应对导入失灵的函数
2051
- from siat.common import upper_ticker
2052
- tickers=upper_ticker(tickers)
2053
- if not isinstance(tickers,list):
2054
- tickers=[tickers]
2055
-
2056
- # 去掉重复代码:有必要,重复代码将导致后续处理出错KeyError: 0!
2057
- tickers=list(set(tickers))
2058
- """
2059
- num=len(tickers)
2060
- if num <2:
2061
- print(" #Error(compare_msecurity): need more tickers")
2062
- return None
2063
- """
2064
- if isinstance(measure,list):
2065
- measure=measure[0]
2066
-
2067
- print(" Searching securities for",measure,"...")
2068
- #屏蔽函数内print信息输出的类
2069
- import os, sys
2070
- class HiddenPrints:
2071
- def __enter__(self):
2072
- self._original_stdout = sys.stdout
2073
- sys.stdout = open(os.devnull, 'w')
2074
-
2075
- def __exit__(self, exc_type, exc_val, exc_tb):
2076
- sys.stdout.close()
2077
- sys.stdout = self._original_stdout
2078
-
2079
- #循环获取证券指标
2080
- import pandas as pd
2081
- from functools import reduce
2082
-
2083
- #预处理ticker_type成为列表ticker_type_list
2084
- if isinstance(ticker_type,str):
2085
- ticker_type_list=[ticker_type] * len(tickers)
2086
- if isinstance(ticker_type,list):
2087
- ticker_type_list=ticker_type
2088
- if len(ticker_type_list) < len(tickers): #延续最后项的ticker_type
2089
- ticker_type_list=ticker_type_list+[ticker_type_list[-1]]*(len(tickers)-len(ticker_type_list))
2090
-
2091
- dfs=pd.DataFrame()
2092
- for t in tickers:
2093
- print(" Looking security info for",t,'...')
2094
- pos=tickers.index(t)
2095
- tt=ticker_type_list[pos]
2096
-
2097
- with HiddenPrints():
2098
- df_tmp=security_indicator(t,measure,start,end,adjust=adjust,graph=False,source=source,ticker_type=tt)
2099
- if df_tmp is None:
2100
- print(" #Warning(compare_msecurity): security info not found for",t)
2101
- continue
2102
- if len(df_tmp)==0:
2103
- print(" #Warning(compare_msecurity): security info not found for",t,'between',start,'and',end)
2104
- continue
2105
-
2106
- df_tmp1=pd.DataFrame(df_tmp[measure])
2107
-
2108
- tname=ticker_name(t,tt)
2109
- df_tmp1.rename(columns={measure:tname},inplace=True)
2110
-
2111
- # 将band_area中的ticker替换为tname
2112
- if band_area != '':
2113
- for index, item in enumerate(band_area):
2114
- if item == t:
2115
- band_area[index] = tname
2116
-
2117
- if len(dfs)==0:
2118
- dfs=df_tmp1
2119
- else:
2120
- dfs=pd.concat([dfs,df_tmp1],axis=1,join='outer')
2121
-
2122
- if dfs is None:
2123
- print(" #Error(compare_msecurity): no records found for",tickers)
2124
- return None
2125
- if len(dfs)==0:
2126
- print(" #Error(compare_msecurity): zero records found for",tickers)
2127
- return None
2128
-
2129
- dfs.sort_index(ascending=True,inplace=True)
2130
-
2131
- # 若不绘图则返回原始数据
2132
- if not graph:
2133
- return dfs
2134
-
2135
- #绘制多条曲线
2136
- y_label=ectranslate(measure)
2137
- tickersplit=tickers[0].split('.')
2138
- if (len(tickersplit) > 1) and (measure == 'Close'):
2139
- if tickersplit[1].upper() in ['M','B']:
2140
- #y_label='指标'
2141
- y_label='指标对比'
2142
-
2143
- x_label1cn="数据来源: Sina/EM/Stooq/Yahoo/SWHY,"
2144
- x_label1en="Source: Sina/EM/Stooq/Yahoo/SWHY, "
2145
- x_label1=text_lang(x_label1cn,x_label1en)
2146
- import datetime; todaydt = datetime.date.today()
2147
- x_label=x_label1+str(todaydt)
2148
-
2149
- title_txt1=text_lang("证券趋势分析","Security Trend")
2150
- if y_label != '':
2151
- title_txt=title_txt1+": "+y_label
2152
- else:
2153
- title_txt=title_txt1
2154
-
2155
- if preprocess == 'scaling' and scaling_option == 'change%':
2156
- title_txt2=text_lang("涨跌幅度","Changes")
2157
- if ':' in title_txt:
2158
- title_txt=title_txt+', '+title_txt2
2159
- else:
2160
- title_txt=title_txt+': '+title_txt2
2161
-
2162
- axhline_value=0
2163
- axhline_label="零线"
2164
-
2165
- # 标准化处理
2166
- try:
2167
- dfs2,axhline_label,x_label,y_label,plus_sign=df_preprocess(dfs,measure, \
2168
- axhline_label=axhline_label,x_label=x_label,y_label=y_label, \
2169
- preprocess=preprocess,scaling_option=scaling_option)
2170
- except:
2171
- print(" #Error(compare_msecurity): preprocess failed, returning dfs for further check")
2172
- #df_display_CSS(dfs,titletxt='Unexpected Data in dfs')
2173
- return dfs
2174
-
2175
- # 填充非交易日的缺失值,使得绘制的曲线连续
2176
- dfs2.fillna(axis=0,method='ffill',inplace=True)
2177
- #dfs2.fillna(axis=0,method='bfill',inplace=True)
2178
-
2179
- if DEBUG:
2180
- print("DEBUG: dfs2=",list(dfs2))
2181
-
2182
- above_zero=0; below_zero=0
2183
- for c in list(dfs2):
2184
- c_max=dfs2[c].max(); c_min=dfs2[c].min()
2185
- try:
2186
- if c_max>0 or c_min>0: above_zero+=1
2187
- if c_max<0 or c_min<0: below_zero+=1
2188
- except: continue
2189
-
2190
- if DEBUG:
2191
- print("DEBUG: above_zero=",above_zero,'below_zero=',below_zero)
2192
-
2193
- if above_zero>0 and below_zero>0: #有正有负
2194
- #if 'Ret%' in measure:
2195
- if axhline_label=='':
2196
- axhline_label='零线'
2197
-
2198
- #持有类指标的首行置为零
2199
- colList=list(dfs2)
2200
- index1=dfs2.head(1).index.values[0]
2201
- for c in colList:
2202
- if 'Exp Ret%' in c:
2203
- dfs2.loc[dfs2[dfs2.index==index1].index.tolist(),c]=0
2204
-
2205
- draw_lines(dfs2,y_label,x_label,axhline_value,axhline_label,title_txt, \
2206
- data_label=False,resample_freq='H',smooth=smooth,linewidth=linewidth,loc=loc, \
2207
- attention_value=attention_value,attention_value_area=attention_value_area, \
2208
- attention_point=attention_point,attention_point_area=attention_point_area, \
2209
- band_area=band_area, \
2210
- annotate=annotate,annotate_value=annotate_value,plus_sign=plus_sign, \
2211
- mark_top=mark_top,mark_bottom=mark_bottom, \
2212
- mark_start=mark_start,mark_end=mark_end,facecolor=facecolor)
2213
-
2214
- return dfs2
2215
-
2216
- if __name__ =="__main__":
2217
- tickers=['000001.SS',"^HSI","^TWII"]
2218
- df=compare_msecurity(tickers,'Close','2020-1-1','2022-12-14',preprocess='standardize')
2219
- df=compare_msecurity(tickers,'Close','2020-1-1','2022-12-14',preprocess='normalize')
2220
- df=compare_msecurity(tickers,'Close','2020-1-1','2022-12-14',preprocess='logarithm')
2221
- df=compare_msecurity(tickers,'Close','2020-1-1','2022-12-14',preprocess='scaling')
2222
-
2223
- #==============================================================================
2224
- if __name__ =="__main__":
2225
- tickers=['JD','BABA','BIDU','VIPS','PDD']
2226
- start='2023-5-1'
2227
- end='2023-6-16'
2228
- ret_measure='Exp Ret%'
2229
- ret_measure='Annual Ret%'
2230
-
2231
- risk_type='Volatility'
2232
- annotate=True
2233
- graph=True
2234
- smooth=False
2235
-
2236
-
2237
- def compare_mrrr(tickers,start,end,ret_measure='Exp Ret%',risk_type='Volatility', \
2238
- annotate=False,graph=True,smooth=True,winsorize_limits=[0.05,0.05], \
2239
- facecolor='whitesmoke'):
2240
- """
2241
- 功能:rrr = return-risk ratio
2242
- 比较多个证券的简单收益-风险性价比,基于compare_msecurity
2243
- ret_measure='Exp Ret%':可以为持有收益率,或滚动收益率
2244
- risk_type='Volatility':可以为标准差,或下偏标准差
2245
-
2246
- winsorize_limits=[0.05,0.05]:去掉最低的5%(第一个参数),去掉最高的5%(第二个参数)
2247
- """
2248
- #print("Searching for return-risk performance based on",ret_measure,"it takes great time, please wait ...")
2249
-
2250
- try:
2251
- df_ret=compare_msecurity(tickers,ret_measure,start,end,graph=False)
2252
- except:
2253
- return None
2254
- cols=list(df_ret)
2255
-
2256
- risk_measure=ret_measure[:-1]+' '+risk_type+'%'
2257
- try:
2258
- df_risk=compare_msecurity(tickers,risk_measure,start,end,graph=False)
2259
- except:
2260
- return None
2261
-
2262
- import pandas as pd
2263
- df=pd.merge(df_ret,df_risk,left_index=True,right_index=True)
2264
- #df.fillna(axis=0,method='ffill',inplace=True)
2265
- #df.fillna(axis=0,method='bfill',inplace=True)
2266
-
2267
- for c in cols:
2268
- df[c]=df[c+'_x']/df[c+'_y']
2269
-
2270
- df2=df[cols]
2271
-
2272
- from scipy.stats.mstats import winsorize
2273
- # 若,ret_measure为Exp类指标,此处需要首行置零
2274
- colList=list(df2)
2275
- index1=df2.head(1).index.values[0]
2276
- for c in colList:
2277
- if 'Exp' in ret_measure:
2278
- df2.loc[df2[df2.index==index1].index.tolist(),c]=0
2279
-
2280
- # 缩尾处理:先转换为数值类型,以防万一
2281
- df2[c]=df2[c].astype('float')
2282
- df2[c]=winsorize(df2[c],limits=winsorize_limits)
2283
-
2284
- #df2.interpolate(method='polynomial',order=2,axis=0,inplace=True)
2285
-
2286
- y_label="收益-风险性价比"
2287
-
2288
- measure1=ectranslate(ret_measure)[:-1]
2289
- measure2=ectranslate(risk_measure)[:-1]
2290
- footnote1="注:图中的收益-风险性价比定义为"+measure1+"与"+measure2+"之比"
2291
- import datetime; today = datetime.date.today()
2292
- footnote2="数据来源:新浪财经/雅虎财经/stooq,"+str(today)
2293
- x_label=footnote1+"\n"+footnote2
2294
-
2295
- #title_txt="比较多只证券的简单收益-风险性价比"
2296
- title_txt="收益-风险性价比走势"
2297
-
2298
- print("Rendering graphics ...")
2299
- draw_lines(df2,y_label,x_label,axhline_value=0,axhline_label='',title_txt=title_txt, \
2300
- data_label=False,resample_freq='D',smooth=smooth,annotate=annotate, \
2301
- facecolor=facecolor)
2302
-
2303
- return df2
2304
-
2305
-
2306
- #==============================================================================
2307
- if __name__ =="__main__":
2308
- tickers1=["AMZN","EBAY","SHOP","BABA","JD"]
2309
- tickers2=["AMZN","EBAY","SHOP","BABA","JD","PDD"]
2310
- measure1="Annual Ret%"
2311
- measure2="Exp Ret%"
2312
- start="2022-1-1"
2313
- end="2022-7-31"
2314
- df=compare_msecurity(tickers1,measure1,start,end)
2315
- df=compare_msecurity(tickers1,measure2,start,end)
2316
-
2317
- df=compare_msecurity(tickers2,measure1,start,end)
2318
- df=compare_msecurity(tickers2,measure2,start,end)
2319
- #==============================================================================
2320
- def stock_Kline(ticker,start='default',end='default',volume=True, \
2321
- style='China',facecolor='whitesmoke', \
2322
- mav=[5,10]):
2323
- """
2324
- 套壳函数,为了与stock_MACD等函数相似
2325
- """
2326
-
2327
- #=========== 日期转换与检查
2328
- # 检查日期:截至日期
2329
- import datetime as dt; today=dt.date.today()
2330
- if end in ['default','today']:
2331
- end=today
2332
- else:
2333
- validdate,end=check_date2(end)
2334
- if not validdate:
2335
- print(" #Warning(stock_Kline): invalid date for",end)
2336
- end=today
2337
-
2338
- # 检查日期:开始日期
2339
- if start in ['default']:
2340
- start=date_adjust(end,adjust=-31)
2341
- else:
2342
- validdate,start=check_date2(start)
2343
- if not validdate:
2344
- print(" #Warning(stock_Kline): invalid date for",start)
2345
- start=date_adjust(todate,adjust=-31)
2346
-
2347
- df=candlestick(stkcd=ticker,fromdate=start,todate=end,volume=volume, \
2348
- style=style,facecolor=facecolor,mav=mav)
2349
-
2350
- return df
2351
-
2352
- if __name__ =="__main__":
2353
- stkcd="BABA"
2354
- fromdate="2024-5-1"
2355
- todate="2024-6-20"
2356
- volume=True
2357
- style='China'
2358
- mav=[5,10]
2359
- ticker_type='auto'
2360
- facecolor='whitesmoke'
2361
- loc='best'
2362
-
2363
-
2364
-
2365
- def candlestick(stkcd,start,end,volume=True,style='China',mav=[5,10], \
2366
- ticker_type='auto',facecolor='whitesmoke',loc='best'):
2367
- """
2368
- 功能:绘制证券价格K线图。
2369
- 输入:证券代码ticker;开始日期fromdate,结束日期todate;
2370
- 绘图类型type:默认为蜡烛图;
2371
- 是否绘制交易量volume:默认否;
2372
- 绘图风格style:默认为黑白图;
2373
- 输出:绘制证券价格蜡烛图线图
2374
- 返回:证券价格数据表
2375
- """
2376
- fromdate=start; todate=end
2377
-
2378
- #找出mav的最长天数
2379
- mav_max=0
2380
- for mm in mav:
2381
- # 移除移动平均步数1,否则出错
2382
- if mm == 1:
2383
- mav.remove(mm)
2384
- print(" Warning: moving average at pace=1 is invalid and removed")
2385
-
2386
- if mm > mav_max:
2387
- mav_max=mm
2388
- # 如果mav为空,则默认为2
2389
- if len(mav) == 0:
2390
- mav=[2]
2391
-
2392
- #延长开始日期,以便绘制长期均线
2393
- #fromdate1=date_adjust(fromdate, adjust=-mav_max*2)
2394
- fromdate1=fromdate
2395
-
2396
- #检查命令参数
2397
- stylelist=['binance','China','blueskies','brasil','charles','checkers','classic','default', \
2398
- 'mike','nightclouds','sas','starsandstripes','yahoo']
2399
- if not (style in stylelist):
2400
- print(" #Error(candlestick),only support graphics styles of",stylelist)
2401
- return
2402
- if style != 'China':
2403
- s = mpf.make_mpf_style(base_mpf_style=style,rc=mpfrc)
2404
- else:
2405
- #按照中国习惯:红涨绿跌
2406
- mc = mpf.make_marketcolors(
2407
- up="red", # 上涨K线的颜色
2408
- down="green", # 下跌K线的颜色
2409
- edge="inherit", # 蜡烛图箱体的颜色
2410
- volume="inherit", # 成交量柱子的颜色
2411
- wick="inherit" # 蜡烛图影线的颜色
2412
- )
2413
- s = mpf.make_mpf_style(
2414
- #gridaxis='both',
2415
- #gridstyle='-.',
2416
- y_on_right=True,
2417
- marketcolors=mc,
2418
- edgecolor='black',
2419
- figcolor='white',
2420
- facecolor=facecolor,
2421
- #gridcolor='cyan',
2422
- rc=mpfrc)
2423
-
2424
- #抓取证券价格
2425
- """
2426
- from siat.security_prices import get_prices_all
2427
- daily=get_prices_all(stkcd,fromdate1,todate,ticker_type=ticker_type)
2428
- """
2429
- from siat.security_price2 import get_price_mticker_mixed
2430
- daily,found=get_price_1ticker_mixed(ticker=stkcd,fromdate=fromdate1, \
2431
- todate=todate,ticker_type=ticker_type)
2432
- """
2433
- if daily is None:
2434
- print(" #Error(candlestick): failed to get price info of",stkcd)
2435
- return
2436
- if len(daily) == 0:
2437
- print(" #Warning(candlestick): zero price info to draw K-line for",stkcd)
2438
- return
2439
- """
2440
- if found == 'None':
2441
- print(" #Error(candlestick): failed to get price info of",stkcd)
2442
- return
2443
- if found == 'Empty':
2444
- print(" #Warning(candlestick): zero price info to draw K-line for",stkcd)
2445
- return
2446
-
2447
- #如果抓取到的数据没有Volume字段,创造一个但填充为零
2448
- if 'Volume' not in list(daily):
2449
- daily['Volume']=0
2450
-
2451
- #绘制蜡烛图
2452
- ylabel_txt=text_lang('价格','Price')
2453
- ylabel_lower_txt=text_lang('成交量','Volume')
2454
-
2455
- #titletxt=ticker_name(stkcd)
2456
- titletxt=ticker_name(stkcd,ticker_type=ticker_type)
2457
-
2458
- #空一行
2459
- print('')
2460
-
2461
- fig, axlist = mpf.plot(daily,type='candle',
2462
- volume=volume,
2463
- show_nontrading=False,#自动剔除非交易日空白
2464
- style=s,
2465
- #title=titletxt,
2466
- datetime_format='%Y-%m-%d',
2467
- tight_layout=True,
2468
- #tight_layout=False,
2469
- xrotation=15,
2470
- ylabel=texttranslate(ylabel_txt),
2471
- ylabel_lower=texttranslate(ylabel_lower_txt),
2472
- mav=mav,
2473
- figratio=(12.8,7.2),
2474
- #figscale=1.5,
2475
- returnfig=True
2476
- )
2477
-
2478
- # add a title the the correct axes, 0=first subfigure
2479
- titletxt=titletxt+text_lang(":K线图走势,日移动均线=",": Candlestick Chart, MAV Days=")+str(mav)
2480
- axlist[0].set_title(titletxt,
2481
- fontsize=16,
2482
- #style='italic',
2483
- #fontfamily='fantasy',
2484
- loc='center')
2485
-
2486
- #设置图例,注意前两个为图中期间开始日期的线和柱子
2487
- mav_labels=[text_lang('期间首日线','Day 1(line)'),text_lang('期间首日柱','Day 1(bar)')]
2488
- #mav_labels=[None,None]
2489
- for d in mav:
2490
- mav_labels=mav_labels+[str(d)+text_lang("日移动均线","-day MAV line")]
2491
- axlist[0].legend(labels=mav_labels,loc=loc)
2492
- #axlist[0].legend(mav_labels[2:],loc=loc)
2493
- """
2494
- #去掉前两个无用的图例
2495
- handles, labels = axlist[0].get_legend_handles_labels()
2496
- axlist[0].legend(handles=handles[2:],labels=labels[2:],loc=loc)
2497
- """
2498
- fig.show()
2499
- reset_plt()
2500
-
2501
- return daily
2502
-
2503
- if __name__ =="__main__":
2504
- stkcd='000002.SZ'
2505
- fromdate='2020-2-1'
2506
- todate='2020-3-10'
2507
- type='candle'
2508
- volume=True
2509
- style='default'
2510
- mav=0
2511
- line=False
2512
- price=candlestick("000002.SZ","2020-2-1","2020-2-29")
2513
-
2514
- #==============================================================================
2515
- def candlestick_pro(stkcd,start,end, \
2516
- colorup='#00ff00',colordown='#ff00ff',style='nightclouds', \
2517
- ticker_type='auto'):
2518
- """
2519
- 功能:绘制证券价格K线图。
2520
- 输入:证券代码ticker;开始日期fromdate,结束日期todate;
2521
- 绘图类型type:默认为蜡烛图;
2522
- 是否绘制交易量volume:默认否;
2523
- 绘图风格style:nightclouds修改版;
2524
- 输出:绘制证券价格蜡烛图线图
2525
- 返回:证券价格数据表
2526
- 注意:可能导致其后的matplotlib绘图汉字乱码
2527
- """
2528
- fromdate=start; todate=end
2529
-
2530
- #抓取证券价格
2531
- from siat.security_price2 import get_price_1ticker_mixed
2532
- daily,found=get_price_1ticker_mixed(ticker=stkcd,fromdate=fromdate, \
2533
- todate=todate,ticker_type=ticker_type)
2534
-
2535
- if found in ['None','Empty']:
2536
- print(" #Error(candlestick_pro): failed to get price info of",stkcd,fromdate,todate)
2537
- return None
2538
-
2539
- #绘制蜡烛图
2540
- #在原有的风格nightclouds基础上定制阳线和阴线柱子的色彩,形成自定义风格s
2541
- mc = mpf.make_marketcolors(up=colorup,down=colordown,inherit=True)
2542
- s = mpf.make_mpf_style(base_mpf_style=style,marketcolors=mc,rc=mpfrc)
2543
- #kwargs = dict(type='candle',mav=(2,4,6),volume=True,figratio=(10,8),figscale=0.75)
2544
- #kwargs = dict(type='candle',mav=(2,4,6),volume=True,figscale=0.75)
2545
- kwargs = dict(type='candle',mav=5,volume=True)
2546
-
2547
- #titletxt=ticker_name(stkcd)
2548
- titletxt=ticker_name(stkcd,ticker_type=ticker_type)
2549
-
2550
- mpf.plot(daily,**kwargs,
2551
- style=s,
2552
- datetime_format='%Y-%m-%d',
2553
- tight_layout=True,
2554
- xrotation=15,
2555
- title=titletxt,
2556
- ylabel=text_lang("价格","Price"),
2557
- ylabel_lower=text_lang("成交量","Volume"),
2558
- figratio=(12.8,7.2)
2559
- )
2560
- reset_plt()
2561
-
2562
- return daily
2563
-
2564
- if __name__ =="__main__":
2565
- stkcd='000002.SZ'
2566
- fromdate='2020-2-1'
2567
- todate='2020-3-10'
2568
- type='candle'
2569
- volume=True
2570
- style='default'
2571
- mav=0
2572
- line=False
2573
- price=candlestick_pro("000002.SZ","2020-2-1","2020-2-29")
2574
- #==============================================================================
2575
- def stock_Kline_demo(ticker,start='default',end='default', \
2576
- colorup='red',colordown='green',width=0.5, \
2577
- ticker_type='auto',facecolor='whitesmoke'):
2578
- """
2579
- 套壳函数,为了与stock_Kline保持一致
2580
- """
2581
-
2582
- #=========== 日期转换与检查
2583
- # 检查日期:截至日期
2584
- import datetime as dt; today=dt.date.today()
2585
- if end in ['default','today']:
2586
- end=today
2587
- else:
2588
- validdate,end=check_date2(end)
2589
- if not validdate:
2590
- print(" #Warning(stock_Kline_demo): invalid date for",end)
2591
- end=today
2592
-
2593
- # 检查日期:开始日期
2594
- if start in ['default']:
2595
- start=date_adjust(end,adjust=-7)
2596
- else:
2597
- validdate,start=check_date2(start)
2598
- if not validdate:
2599
- print(" #Warning(stock_Kline_demo): invalid date for",start)
2600
- start=date_adjust(todate,adjust=-7)
2601
-
2602
- df=candlestick_demo(stkcd=ticker,fromdate=start,todate=end, \
2603
- colorup=colorup,colordown=colordown,width=width, \
2604
- ticker_type=ticker_type,facecolor=facecolor)
2605
-
2606
- return df
2607
-
2608
-
2609
- if __name__ =="__main__":
2610
- stkcd='BABA'
2611
- fromdate='2023-6-5'
2612
- todate='2023-6-9'
2613
-
2614
- colorup='red';colordown='green';width=0.7
2615
-
2616
- def candlestick_demo(stkcd,start,end, \
2617
- colorup='red',colordown='green',width=0.7, \
2618
- ticker_type='auto',facecolor='whitesmoke'):
2619
- """
2620
- 功能:绘制证券价格K线图,叠加收盘价。
2621
- 输入:证券代码ticker;开始日期fromdate,结束日期todate;
2622
- 阳线颜色colorup='red',阴线颜色colordown='green',柱子宽度width=0.7
2623
- 输出:绘制证券价格蜡烛图线图
2624
- 返回:证券价格数据表
2625
- """
2626
- fromdate=start; todate=end
2627
-
2628
- #抓取证券价格
2629
- from siat.security_price2 import get_price_1ticker_mixed
2630
- p,found=get_price_1ticker_mixed(ticker=stkcd,fromdate=fromdate, \
2631
- todate=todate,ticker_type=ticker_type)
2632
- if found in ['None','Empty']:
2633
- print(" #Error(candlestick_demo): failed to get prices for:",stkcd,'\b,',fromdate,'-',todate)
2634
- return p
2635
-
2636
- p['Date']=p.index
2637
-
2638
- import numpy as np
2639
- #b= np.array(p.reset_index()[['Date','Open','High','Low','Close']])
2640
- b= np.array(p[['Date','Open','High','Low','Close']])
2641
-
2642
- #change 1st column of b to number type
2643
- import matplotlib.dates as dt2
2644
- b[:,0] = dt2.date2num(b[:,0])
2645
-
2646
- print('')
2647
- #specify the size of the graph
2648
- #fig,ax=plt.subplots(figsize=(12.8,6.4))
2649
- fig,ax=plt.subplots()
2650
-
2651
- #绘制各个价格的折线图
2652
- open_txt=text_lang('开盘价','Open')
2653
- high_txt=text_lang('最高价','High')
2654
- low_txt=text_lang('最低价','Low')
2655
- close_txt=text_lang('收盘价','Close')
2656
-
2657
- plt.plot(p.index,p['Open'],color='green',ls="--",label=open_txt,marker='>',markersize=10,linewidth=2,alpha=0.5)
2658
- plt.plot(p.index,p['High'],color='cyan',ls="-.",label=high_txt,marker='^',markersize=10,linewidth=2,alpha=0.5)
2659
- plt.plot(p.index,p['Low'],color='k',ls=":",label=low_txt,marker='v',markersize=10,linewidth=2,alpha=0.5)
2660
- plt.plot(p.index,p['Close'],color='blue',ls="-",label=close_txt,marker='<',markersize=10,linewidth=2,alpha=0.5)
2661
-
2662
- #绘制蜡烛图
2663
- try:
2664
- from mplfinance.original_flavor import candlestick_ohlc
2665
- except:
2666
- print(" #Error(candlestick_demo): please install plugin mplfinance.")
2667
- print(" Method:")
2668
- print(" In Anaconda Prompt, key in a command: pip install mplfinance")
2669
- return None
2670
-
2671
- #candlestick_ohlc(ax,b,colorup=colorup,colordown=colordown,width=width,alpha=0.5)
2672
- candlestick_ohlc(ax,b,colorup=colorup,colordown=colordown,width=width,alpha=0.5)
2673
-
2674
- ax.xaxis_date() #draw dates in x axis
2675
- ax.autoscale_view()
2676
- fig.autofmt_xdate()
2677
- fig.gca().set_facecolor(facecolor)
2678
-
2679
- titletxt0=text_lang("K线图/蜡烛图演示:","Candlestick Chart Demo: ")
2680
- titletxt=titletxt0 + ticker_name(str(stkcd),ticker_type=ticker_type)
2681
- price_txt=text_lang('价格','Price')
2682
- source_txt=text_lang("数据来源: Sina/EM/Stooq/Yahoo/SWHY","Data source: Sina/Stooq/Yahoo")
2683
-
2684
- plt.title(titletxt,fontsize=title_txt_size,fontweight='bold')
2685
- plt.ylabel(price_txt,fontsize=ylabel_txt_size)
2686
-
2687
- plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
2688
- plt.gca().set_facecolor(facecolor)
2689
- #plt.xticks(rotation=30)
2690
- plt.legend(loc="best",fontsize=legend_txt_size)
2691
- plt.xlabel(source_txt,fontsize=xlabel_txt_size)
2692
- plt.show()
2693
-
2694
- return p
2695
-
2696
- if __name__ =="__main__":
2697
- price=candlestick_demo("000002.SZ","2020-3-1","2020-3-6")
2698
-
2699
- #==============================================================================
2700
- #==============================================================================
2701
- #==============================================================================
2702
- if __name__ =="__main__":
2703
- ticker="000001.SZ"
2704
- fromdate="2021-1-1"
2705
- todate="2022-9-26"
2706
-
2707
-
2708
- def security_dividend(ticker,start="L5Y",end="today",facecolor='whitesmoke',fontcolor='black'):
2709
- """
2710
- 功能:套壳函数stock_dividend
2711
- """
2712
- df=stock_dividend(ticker,start,end,facecolor,fontcolor)
2713
- return df
2714
-
2715
-
2716
- def stock_dividend(ticker,start="L3Y",end="today",facecolor='whitesmoke',fontcolor='black'):
2717
- """
2718
- 功能:显示股票的分红历史
2719
- 输入:单一股票代码
2720
- 输出:分红历史
2721
- """
2722
- start,end=start_end_preprocess(start,end)
2723
-
2724
- fromdate,todate=start,end
2725
-
2726
- print(" Searching for dividend info of stock",ticker,"...")
2727
- result,startdt,enddt=check_period(fromdate,todate)
2728
- if not result:
2729
- print(" #Error(stock_dividend): invalid period",fromdate,todate)
2730
- return None
2731
-
2732
- result,prefix,suffix=split_prefix_suffix(ticker)
2733
- if result & (suffix=='HK'):
2734
- if len(prefix)==5:
2735
- ticker=ticker[1:]
2736
-
2737
- import yfinance as yf
2738
- stock = yf.Ticker(ticker)
2739
- try:
2740
- div=stock.dividends
2741
- except:
2742
- print(f" #Error(stock_dividend): dividend info inaccessible for {ticker}")
2743
- return None
2744
- if len(div)==0:
2745
- print(f" #Warning(stock_dividend): failed to get dividend info for {ticker}")
2746
- return None
2747
-
2748
- # 去掉时区信息,避免合并中的日期时区冲突问题
2749
- import pandas as pd
2750
- div.index = pd.to_datetime(div.index)
2751
- div.index = div.index.tz_localize(None)
2752
-
2753
- #过滤期间
2754
- div1=div[div.index >= startdt]
2755
- div2=div1[div1.index <= enddt]
2756
- if len(div2)==0:
2757
- print(f" #Warning(stock_dividend): no dividends found from {fromdate} to {todate}")
2758
- return None
2759
-
2760
- #对齐打印
2761
- import pandas as pd
2762
- pd.set_option('display.unicode.ambiguous_as_wide', True)
2763
- pd.set_option('display.unicode.east_asian_width', True)
2764
- pd.set_option('display.width', 180) # 设置打印宽度(**重要**)
2765
- pd.set_option('display.colheader_justify', 'center')
2766
- """
2767
- pd.set_option('display.max_columns', 1000)
2768
- pd.set_option('display.width', 1000)
2769
- pd.set_option('display.max_colwidth', 1000)
2770
- """
2771
- divdf=pd.DataFrame(div2)
2772
- divdf['Index Date']=divdf.index
2773
- datefmt=lambda x : x.strftime('%Y-%m-%d')
2774
- divdf['Dividend Date']= divdf['Index Date'].apply(datefmt)
2775
-
2776
- #增加星期
2777
- from datetime import datetime
2778
- weekdayfmt=lambda x : x.isoweekday()
2779
- divdf['Weekdayiso']= divdf['Index Date'].apply(weekdayfmt)
2780
- #wdlist=['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
2781
- #wdlist=['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday']
2782
- #wdlist=['星期一','星期二','星期三','星期四','星期五','星期六','星期日']
2783
- wdlist=[text_lang('星期一','Mon'),text_lang('星期二','Tue'),text_lang('星期三','Wed'), \
2784
- text_lang('星期四','Thu'),text_lang('星期五','Fri'),text_lang('星期六','Sat'),text_lang('星期日','Sun')]
2785
-
2786
- wdfmt=lambda x : wdlist[x-1]
2787
- divdf['Weekday']= divdf['Weekdayiso'].apply(wdfmt)
2788
-
2789
- #增加序号
2790
- divdf['Seq']=divdf['Dividend Date'].rank(ascending=1)
2791
- divdf['Seq']=divdf['Seq'].astype('int')
2792
- divprt=divdf[['Seq','Dividend Date','Weekday','Dividends']]
2793
-
2794
- lang=check_language()
2795
- tname=ticker_name(ticker,'stock')
2796
- fromdatey2md=startdt.strftime('%Y/%m/%d')
2797
- todatey2md=enddt.strftime('%Y/%m/%d')
2798
-
2799
- titletxt=text_lang("证券分红","Stock Dividend")+': '+tname
2800
- periodtxt=text_lang("期间:","Period:")+' '+fromdatey2md+"-"+todatey2md
2801
- #sourcetxt=text_lang("数据来源: 雅虎财经,","Data source: Yahoo Finance,")
2802
- sourcetxt=text_lang("数据来源: Yahoo/Sina","Data source: Yahoo/Sina")
2803
- footnote=periodtxt+'\n'+sourcetxt
2804
-
2805
- #修改列命为英文
2806
- divprt.columns = [text_lang('序号','No.'),text_lang('日期','Date'),text_lang('星期','Weekday'),text_lang('每股(份)红利','Dividend/share')]
2807
-
2808
- """
2809
- print(divprt.to_string(index=False))
2810
- """
2811
- #print('') #空一行
2812
-
2813
- df_display_CSS(divprt,titletxt=titletxt,footnote=footnote,facecolor=facecolor,decimals=4, \
2814
- first_col_align='center',second_col_align='center', \
2815
- last_col_align='right',other_col_align='center')
2816
-
2817
- """
2818
- disph=divprt.style.hide() #不显示索引列
2819
- dispp=disph.format(precision=4) #设置带有小数点的列精度调整为小数点后2位
2820
- #设置标题/列名对齐
2821
- dispt=dispp.set_caption(titletxt).set_table_styles(
2822
- [{'selector':'caption', #设置标题
2823
- 'props':[('color','black'),('font-size','16px'),('font-weight','bold')]}, \
2824
- {'selector':'th.col_heading', #设置列名
2825
- 'props':[('color','black'),('text-align','center'),('margin','auto')]}])
2826
- #设置列数值对齐
2827
- dispf=dispt.set_properties(**{'text-align':'center'})
2828
- #设置前景背景颜色
2829
- dispf2=dispf.set_properties(**{'background-color':facecolor,'color':fontcolor})
2830
-
2831
- from IPython.display import display
2832
- display(dispf2)
2833
-
2834
- print(periodtxt)
2835
- import datetime; todaydt=datetime.date.today(); todayy2md=todaydt.strftime('%y/%m/%d')
2836
- #print('\n*** '+sourcetxt,today)
2837
- print(sourcetxt,todayy2md)
2838
- """
2839
-
2840
- return divdf
2841
-
2842
-
2843
- if __name__ =="__main__":
2844
- ticker='AAPL'
2845
- fromdate='2019-1-1'
2846
- todate='2020-6-30'
2847
-
2848
- #==============================================================================
2849
- def security_split(ticker,start="L10Y",end="today",facecolor='whitesmoke',fontcolor='black'):
2850
- """
2851
- 功能:套壳函数stock_split
2852
- """
2853
- df=stock_split(ticker,start,end,facecolor,fontcolor)
2854
- return df
2855
-
2856
-
2857
- def stock_split(ticker,start="L10Y",end="today",facecolor='whitesmoke',fontcolor='black'):
2858
- """
2859
- 功能:显示股票的分拆历史
2860
- 输入:单一股票代码
2861
- 输出:分拆历史
2862
- """
2863
- start,end=start_end_preprocess(start,end)
2864
-
2865
- fromdate,todate=start,end
2866
-
2867
- print(" Searching for split info of stock",ticker,"...")
2868
- result,startdt,enddt=check_period(fromdate,todate)
2869
- if not result:
2870
- print(" #Error(stock_split): invalid period",fromdate,todate)
2871
- return None
2872
-
2873
- result,prefix,suffix=split_prefix_suffix(ticker)
2874
- if result & (suffix=='HK'):
2875
- if len(prefix)==5:
2876
- ticker=ticker[1:]
2877
-
2878
- import yfinance as yf
2879
- stock = yf.Ticker(ticker)
2880
- try:
2881
- div=stock.splits
2882
- except:
2883
- print(f" #Error(stock_split): split info inaccessible for {ticker}")
2884
- return None
2885
- if len(div)==0:
2886
- print(f" #Warning(stock_split): no split info found for {ticker}")
2887
- return None
2888
-
2889
- # 去掉时区信息,避免合并中的日期时区冲突问题
2890
- import pandas as pd
2891
- div.index = pd.to_datetime(div.index)
2892
- div.index = div.index.tz_localize(None)
2893
-
2894
- #过滤期间
2895
- div1=div[div.index >= startdt]
2896
- div2=div1[div1.index <= enddt]
2897
- if len(div2)==0:
2898
- print(" #Warning(stock_split): no split information in period",fromdate,todate)
2899
- return None
2900
-
2901
- #对齐打印
2902
- import pandas as pd
2903
- pd.set_option('display.unicode.ambiguous_as_wide', True)
2904
- pd.set_option('display.unicode.east_asian_width', True)
2905
- pd.set_option('display.width', 180) # 设置打印宽度(**重要**)
2906
- """
2907
- pd.set_option('display.max_columns', 1000)
2908
- pd.set_option('display.width', 1000)
2909
- pd.set_option('display.max_colwidth', 1000)
2910
- """
2911
- divdf=pd.DataFrame(div2)
2912
- divdf['Index Date']=divdf.index
2913
- datefmt=lambda x : x.strftime('%Y-%m-%d')
2914
- divdf['Split Date']= divdf['Index Date'].apply(datefmt)
2915
-
2916
- #增加星期
2917
- from datetime import datetime
2918
- weekdayfmt=lambda x : x.isoweekday()
2919
- divdf['Weekdayiso']= divdf['Index Date'].apply(weekdayfmt)
2920
- #wdlist=['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
2921
- wdlist=[text_lang('星期一','Mon'),text_lang('星期二','Tue'),text_lang('星期三','Wed'), \
2922
- text_lang('星期四','Thu'),text_lang('星期五','Fri'),text_lang('星期六','Sat'),text_lang('星期日','Sun')]
2923
- wdfmt=lambda x : wdlist[x-1]
2924
- divdf['Weekday']= divdf['Weekdayiso'].apply(wdfmt)
2925
-
2926
- #增加序号
2927
- divdf['Seq']=divdf['Split Date'].rank(ascending=1)
2928
- divdf['Seq']=divdf['Seq'].astype('int')
2929
-
2930
- divdf['Splitint']=divdf['Stock Splits'].astype('int')
2931
- splitfmt=lambda x: "1:"+str(x)
2932
- divdf['Splits']=divdf['Splitint'].apply(splitfmt)
2933
-
2934
- divprt=divdf[['Seq','Split Date','Weekday','Splits']]
2935
-
2936
- lang=check_language()
2937
- tname=ticker_name(ticker,'stock')
2938
- """
2939
- if lang == 'English':
2940
- print('\n======== '+texttranslate("股票分拆历史")+' ========')
2941
- print(texttranslate("股票:"),ticker,'\b,',ticker_name(ticker))
2942
- print(texttranslate("历史期间:"),fromdate,"-",todate)
2943
- divprt.columns=[texttranslate('序号'),texttranslate('日期'),texttranslate('星期'),texttranslate('分拆比例')]
2944
-
2945
- sourcetxt=texttranslate("数据来源: 雅虎财经,")
2946
- else:
2947
- print('\n======== '+"股票分拆历史"+' ========')
2948
- print("股票:",ticker,'\b,',ticker_name(ticker))
2949
- print("历史期间:",fromdate,"-",todate)
2950
- divprt.columns=['序号','日期','星期','分拆比例']
2951
-
2952
- sourcetxt="数据来源: 雅虎财经,"
2953
-
2954
- print(divprt.to_string(index=False))
2955
-
2956
- import datetime
2957
- today = datetime.date.today()
2958
- print('\n*** '+sourcetxt,today)
2959
- """
2960
- fromdatey2md=startdt.strftime('%Y/%m/%d')
2961
- todatey2md=enddt.strftime('%Y/%m/%d')
2962
-
2963
- titletxt=text_lang("证券分拆","Stock Split")+': '+tname
2964
- periodtxt=text_lang("期间:","Period:")+' '+fromdatey2md+"-"+todatey2md
2965
-
2966
- import datetime; todaydt=datetime.date.today(); todayy2md=str(todaydt.strftime('%y/%m/%d'))
2967
- #sourcetxt=text_lang("数据来源: 雅虎财经, ","Data source: Yahoo Finance, ")+todayy2md
2968
- sourcetxt=text_lang("数据来源: Yahoo/Sina","Data source: Yahoo Finance")
2969
- footnote=periodtxt+'\n'+ sourcetxt
2970
-
2971
- #修改列命为英文
2972
- divprt.columns = [text_lang('序号','No.'),text_lang('日期','Date'),text_lang('星期','Weekday'),text_lang('分拆比例','Split Ratio')]
2973
- """
2974
- print(divprt.to_string(index=False))
2975
- """
2976
- print(' ') #空一行
2977
-
2978
- df_display_CSS(divprt,titletxt=titletxt,footnote=footnote,facecolor=facecolor,decimals=2, \
2979
- first_col_align='center',second_col_align='center', \
2980
- last_col_align='right',other_col_align='center')
2981
- """
2982
- disph=divprt.style.hide() #不显示索引列
2983
- dispp=disph.format(precision=4) #设置带有小数点的列精度调整为小数点后2位
2984
- #设置标题/列名
2985
- dispt=dispp.set_caption(titletxt).set_table_styles(
2986
- [{'selector':'caption', #设置标题
2987
- 'props':[('color','black'),('font-size','16px'),('font-weight','bold')]}, \
2988
- {'selector':'th.col_heading', #设置列名
2989
- 'props':[('color','black'),('text-align','center'),('margin','auto')]}])
2990
- #设置列数值对齐
2991
- dispf=dispt.set_properties(**{'text-align':'center'})
2992
- #设置前景背景颜色
2993
- dispf2=dispf.set_properties(**{'background-color':facecolor,'color':fontcolor})
2994
-
2995
- from IPython.display import display
2996
- display(dispf2)
2997
-
2998
- print(periodtxt)
2999
- import datetime; todaydt=datetime.date.today(); todayy2md=todaydt.strftime('%y/%m/%d')
3000
- #print('\n*** '+sourcetxt,today)
3001
- print(sourcetxt,todayy2md)
3002
- """
3003
-
3004
- return divdf
3005
-
3006
-
3007
- if __name__ =="__main__":
3008
- ticker='AAPL'
3009
- fromdate='1990-1-1'
3010
- todate='2020-6-30'
3011
-
3012
- #==============================================================================
3013
- #==============================================================================
3014
- #==============================================================================
3015
- if __name__=='__main__':
3016
- symbol='AAPL'
3017
- symbol='BABA'
3018
- symbol='01398.HK'
3019
- symbol='03968.HK'
3020
- symbol='601398.SS'
3021
-
3022
- def stock_info(symbol):
3023
- """
3024
- 功能:返回静态信息, 基于yahooquery
3025
- 尚能工作,不打印
3026
- """
3027
- DEBUG=False
3028
- #print(" Searching for information of",symbol,"\b, please wait...")
3029
-
3030
- #symbol1=symbol
3031
- result,prefix,suffix=split_prefix_suffix(symbol)
3032
- if result & (suffix=='HK'):
3033
- symbol=prefix[-4:]+'.'+suffix
3034
-
3035
- from yahooquery import Ticker
3036
- #如果出现类似于{'AAPL': 'Invalid Cookie'}错误,则需要升级yahooquery
3037
- #如果出现crump相关的错误,则需要更换lxml的版本以便与当前的yahooquery版本匹配
3038
- stock = Ticker(symbol)
3039
-
3040
- """
3041
- Asset Profile:
3042
- Head office address/zip/country, Officers, Employees, industry/sector, phone/fax,
3043
- web site,
3044
- Risk ranks: auditRisk, boardRisk, compensationRisk, overallRisk, shareHolderRightRisk,
3045
- compensationRisk: 薪酬风险。Jensen 及 Meckling (1976)的研究指出薪酬與管理者的風險承擔
3046
- 具有關連性,站在管理者的立場來看,創新支出的投入使管理者承受更大的薪酬風險(compensation risk),
3047
- 管理者自然地要求更高的薪酬來補貼所面臨的風險,因此企業創新投資對管理者薪酬成正相關。
3048
- boardRisk: 董事会风险
3049
- shareHolderRightRisk:股权风险
3050
- """
3051
- try:
3052
- #如果出现类似于{'AAPL': 'Invalid Cookie'}错误,则需要升级yahooquery
3053
- adict=stock.asset_profile
3054
- except:
3055
- print(" #Error(stock_info): failed to get info of",symbol)
3056
- print(" Reasons: Wrong stock code, or poor internet connection, or need to upgrade yahooquery")
3057
- return None
3058
-
3059
- if adict[symbol] == 'Invalid Cookie':
3060
- print(" #Error(stock_info): failed in retrieving info of",symbol,"\b. Try upgrade yahooquery and run again")
3061
- return None
3062
-
3063
- keylist=list(adict[symbol].keys())
3064
- import pandas as pd
3065
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
3066
- ainfo=aframe.T
3067
- info=ainfo.copy()
3068
-
3069
-
3070
- """
3071
- ESG Scores: Risk measurements
3072
- peerGroup, ratingYear,
3073
- environmentScore, governanceScore, socialScore, totalEsg
3074
- dict: peerEnvironmentPerformance, peerGovernancePerformance, peerSocialPerformance,
3075
- peerEsgScorePerformance
3076
- """
3077
- try:
3078
- adict=stock.esg_scores
3079
- except:
3080
- print("#Error(stock_info): failed to get esg profile of",symbol)
3081
- return None
3082
-
3083
- if adict[symbol] == 'Invalid Cookie':
3084
- print(" #Error(stock_info): failed in retrieving info of",symbol)
3085
- return None
3086
-
3087
- try: #一些企业无此信息
3088
- keylist=list(adict[symbol].keys())
3089
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
3090
- ainfo=aframe.T
3091
- info=pd.concat([info,ainfo])
3092
- except:
3093
- pass
3094
-
3095
- """
3096
- Financial Data: TTM???
3097
- currentPrice, targetHighPrice, targetLowPrice, targetMeanPrice, targetMedianPrice,
3098
- currentRatio, debtToEquity, earningsGrowth, ebitda, ebitdaMargins, financialCurrency,
3099
- freeCashflow, grossMargins, grossProfits,
3100
- operatingCashflow, operatingMargins, profitMargins,
3101
- quickRatio, returnOnAssets, returnOnEquity, revenueGrowth, revenuePerShare,
3102
- totalCash, totalCashPerShare, totalDebt, totalRevenue,
3103
- """
3104
- try:
3105
- adict=stock.financial_data
3106
- except:
3107
- print(" #Error(stock_info): failed to get financial profile of",symbol)
3108
- return None
3109
-
3110
- if adict[symbol] == 'Invalid Cookie':
3111
- print(" #Error(stock_info): failed in retrieving info of",symbol)
3112
- return None
3113
-
3114
- keylist=list(adict[symbol].keys())
3115
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
3116
- ainfo=aframe.T
3117
- info=pd.concat([info,ainfo])
3118
-
3119
-
3120
- """
3121
- Key Statistics: TTM???
3122
- 52WeekChang, SandP52WeekChang, beta, floatShares, sharesOutstanding,
3123
- bookValue, earningsQuarterlyGrowth, enterpriseToEbitda, enterpriseToRevenue,
3124
- enterpriseValue, netIncomeToCommon, priceToBook, profitMargins,
3125
- forwardEps, trailingEps,
3126
- heldPercentInsiders, heldPercentInstitutions,
3127
- lastFiscalYearEnd, lastSplitDate, lastSplitFactor, mostRecentQuarter, nextFiscalYearEnd,
3128
- """
3129
- try:
3130
- adict=stock.key_stats
3131
- except:
3132
- print(" #Error(stock_info): failed to get key stats of",symbol)
3133
- return None
3134
-
3135
- if adict[symbol] == 'Invalid Cookie':
3136
- print(" #Error(stock_info): failed in retrieving info of",symbol)
3137
- return None
3138
-
3139
- keylist=list(adict[symbol].keys())
3140
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
3141
- ainfo=aframe.T
3142
- info=pd.concat([info,ainfo])
3143
-
3144
-
3145
- """
3146
- Price Information:
3147
- currency, currencySymbol, exchange, exchangeName, shortName,
3148
- longName,
3149
- marketCap, marketState, quoteType,
3150
- regularMarketChange, regularMarketChangPercent, regularMarketHigh, regularMarketLow,
3151
- regularMarketOpen, regularMarketPreviousClose, regularMarketPrice, regularMarketTime,
3152
- regularMarketVolume,
3153
- """
3154
- try:
3155
- adict=stock.price
3156
- except:
3157
- print(" #Error(stock_info): failed to get stock prices of",symbol)
3158
- return None
3159
-
3160
- if adict[symbol] == 'Invalid Cookie':
3161
- print(" #Error(stock_info): failed in retrieving info of",symbol)
3162
- return None
3163
-
3164
- keylist=list(adict[symbol].keys())
3165
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
3166
- ainfo=aframe.T
3167
- info=pd.concat([info,ainfo])
3168
-
3169
-
3170
- """
3171
- Quote Type:
3172
- exchange, firstTradeDateEpocUtc(上市日期), longName, quoteType(证券类型:股票),
3173
- shortName, symbol(当前代码), timeZoneFullName, timeZoneShortName, underlyingSymbol(原始代码),
3174
- """
3175
- try:
3176
- adict=stock.quote_type
3177
- except:
3178
- print(" #Error(stock_info): failed to get quote type of",symbol)
3179
- return None
3180
-
3181
- if adict[symbol] == 'Invalid Cookie':
3182
- print(" #Error(stock_info): failed in retrieving info of",symbol)
3183
- return None
3184
-
3185
- keylist=list(adict[symbol].keys())
3186
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
3187
- ainfo=aframe.T
3188
- info=pd.concat([info,ainfo])
3189
-
3190
-
3191
- """
3192
- Share Purchase Activity
3193
- period(6m), totalInsiderShares
3194
- """
3195
- try:
3196
- adict=stock.share_purchase_activity
3197
- except:
3198
- print(" #Error(stock_info): failed to get share purchase of",symbol)
3199
- return None
3200
-
3201
- if adict[symbol] == 'Invalid Cookie':
3202
- print(" #Error(stock_info): failed in retrieving info of",symbol)
3203
- return None
3204
-
3205
- keylist=list(adict[symbol].keys())
3206
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
3207
- ainfo=aframe.T
3208
- info=pd.concat([info,ainfo])
3209
-
3210
-
3211
- """
3212
- # Summary detail
3213
- averageDailyVolume10Day, averageVolume, averageVolume10days, beta, currency,
3214
- dayHigh, dayLow, fiftyDayAverage, fiftyTwoWeekHigh, fiftyTwoWeekLow, open, previousClose,
3215
- regularMarketDayHigh, regularMarketDayLow, regularMarketOpen, regularMarketPreviousClose,
3216
- regularMarketVolume, twoHundredDayAverage, volume,
3217
- forwardPE, marketCap, priceToSalesTrailing12Months,
3218
- dividendRate, dividendYield, exDividendDate, payoutRatio, trailingAnnualDividendRate,
3219
- trailingAnnualDividendYield, trailingPE,
3220
- """
3221
- try:
3222
- adict=stock.summary_detail
3223
- except:
3224
- print(" #Error(stock_info): failed to get summary detail of",symbol)
3225
- return None
3226
-
3227
- if adict[symbol] == 'Invalid Cookie':
3228
- print(" #Error(stock_info): failed in retrieving info of",symbol)
3229
- return None
3230
-
3231
- keylist=list(adict[symbol].keys())
3232
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
3233
- ainfo=aframe.T
3234
- info=pd.concat([info,ainfo])
3235
-
3236
-
3237
- """
3238
- summary_profile
3239
- address/city/country/zip, phone/fax, sector/industry, website/longBusinessSummary,
3240
- fullTimeEmployees,
3241
- """
3242
- try:
3243
- adict=stock.summary_profile
3244
- except:
3245
- print(" #Error(stock_info): failed to get summary profile of",symbol)
3246
- print(" Possible reasons:","\n 1.Wrong stock code","\n 2.Instable data source, try later")
3247
- return None
3248
-
3249
- if adict[symbol] == 'Invalid Cookie':
3250
- print(" #Error(stock_info): failed in retrieving info of",symbol)
3251
- return None
3252
-
3253
- keylist=list(adict[symbol].keys())
3254
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
3255
- ainfo=aframe.T
3256
- info=pd.concat([info,ainfo])
3257
-
3258
-
3259
- # 清洗数据项目
3260
- info.sort_index(inplace=True) #排序
3261
-
3262
- import numpy as np
3263
- colList=list(info)
3264
- info[colList[0]]=info[colList[0]].apply(lambda x: np.nan if x==[] else x)
3265
- info.dropna(inplace=True) #去掉空值
3266
- #去重
3267
- info['Item']=info.index
3268
- info.drop_duplicates(subset=['Item'],keep='first',inplace=True)
3269
-
3270
- #删除不需要的项目
3271
- delrows=['adult','alcoholic','animalTesting','ask','askSize','bid','bidSize', \
3272
- 'catholic','coal','controversialWeapons','furLeather','gambling', \
3273
- 'gmo','gmtOffSetMilliseconds','militaryContract','messageBoardId', \
3274
- 'nuclear','palmOil','pesticides','tobacco','uuid','maxAge']
3275
- for r in delrows:
3276
- info.drop(info[info['Item']==r].index,inplace=True)
3277
-
3278
- #修改列名
3279
- info.rename(columns={symbol:'Value'}, inplace=True)
3280
- del info['Item']
3281
-
3282
- return info
3283
-
3284
-
3285
- if __name__=='__main__':
3286
- info=stock_info('AAPL')
3287
- info=stock_info('BABA')
3288
-
3289
- #==============================================================================
3290
- if __name__=='__main__':
3291
- info=stock_info('AAPL')
3292
-
3293
- def stock_basic(info):
3294
-
3295
- wishlist=['sector','industry','quoteType', \
3296
- #公司地址,网站
3297
- 'address1','address2','city','state','country','zip','phone','fax', \
3298
- 'website', \
3299
-
3300
- #员工人数
3301
- 'fullTimeEmployees', \
3302
-
3303
- #上市与交易所
3304
- 'exchangeName', \
3305
-
3306
- #其他
3307
- 'currency']
3308
-
3309
- #按照wishlist的顺序从info中取值
3310
- rowlist=list(info.index)
3311
- import pandas as pd
3312
- info_sub=pd.DataFrame(columns=['Item','Value'])
3313
- infot=info.T
3314
- for w in wishlist:
3315
- if w in rowlist:
3316
- v=infot[w][0]
3317
- s=pd.Series({'Item':w,'Value':v})
3318
- try:
3319
- info_sub=info_sub.append(s,ignore_index=True)
3320
- except:
3321
- info_sub=info_sub._append(s,ignore_index=True)
3322
-
3323
- return info_sub
3324
-
3325
- if __name__=='__main__':
3326
- basic=stock_basic(info)
3327
-
3328
- #==============================================================================
3329
- if __name__=='__main__':
3330
- info=stock_info('AAPL')
3331
-
3332
- def stock_officers(info):
3333
-
3334
- wishlist=['sector','industry','currency', \
3335
- #公司高管
3336
- 'companyOfficers', \
3337
- ]
3338
-
3339
- #按照wishlist的顺序从info中取值
3340
- rowlist=list(info.index)
3341
- import pandas as pd
3342
- info_sub=pd.DataFrame(columns=['Item','Value'])
3343
- infot=info.T
3344
- for w in wishlist:
3345
- if w in rowlist:
3346
- v=infot[w][0]
3347
- s=pd.Series({'Item':w,'Value':v})
3348
- try:
3349
- info_sub=info_sub.append(s,ignore_index=True)
3350
- except:
3351
- info_sub=info_sub._append(s,ignore_index=True)
3352
-
3353
- return info_sub
3354
-
3355
- if __name__=='__main__':
3356
- sub_info=stock_officers(info)
3357
-
3358
- #==============================================================================
3359
- def stock_risk_general(info):
3360
-
3361
- wishlist=['sector','industry', \
3362
-
3363
- 'overallRisk','boardRisk','compensationRisk', \
3364
- 'shareHolderRightsRisk','auditRisk'
3365
- ]
3366
-
3367
- #按照wishlist的顺序从info中取值
3368
- rowlist=list(info.index)
3369
- import pandas as pd
3370
- info_sub=pd.DataFrame(columns=['Item','Value'])
3371
- infot=info.T
3372
- for w in wishlist:
3373
- if w in rowlist:
3374
- v=infot[w][0]
3375
- s=pd.Series({'Item':w,'Value':v})
3376
- try:
3377
- info_sub=info_sub.append(s,ignore_index=True)
3378
- except:
3379
- info_sub=info_sub._append(s,ignore_index=True)
3380
-
3381
- return info_sub
3382
-
3383
- if __name__=='__main__':
3384
- risk_general=stock_risk_general(info)
3385
-
3386
- #==============================================================================
3387
- def stock_risk_esg(info):
3388
- """
3389
- wishlist=[
3390
- 'peerGroup','peerCount','percentile','esgPerformance', \
3391
- 'totalEsg','peerEsgScorePerformance', \
3392
- 'environmentScore','peerEnvironmentPerformance', \
3393
- 'socialScore','peerSocialPerformance','relatedControversy', \
3394
- 'governanceScore','peerGovernancePerformance'
3395
- ]
3396
- """
3397
- wishlist=[
3398
- 'peerGroup','peerCount','percentile', \
3399
- 'totalEsg','peerEsgScorePerformance', \
3400
- 'environmentScore','peerEnvironmentPerformance', \
3401
- 'socialScore','peerSocialPerformance','relatedControversy', \
3402
- 'governanceScore','peerGovernancePerformance'
3403
- ]
3404
-
3405
- #按照wishlist的顺序从info中取值
3406
- rowlist=list(info.index)
3407
- import pandas as pd
3408
- info_sub=pd.DataFrame(columns=['Item','Value'])
3409
- infot=info.T
3410
- for w in wishlist:
3411
- if w in rowlist:
3412
- v=infot[w][0]
3413
- s=pd.Series({'Item':w,'Value':v})
3414
- try:
3415
- info_sub=info_sub.append(s,ignore_index=True)
3416
- except:
3417
- info_sub=info_sub._append(s,ignore_index=True)
3418
-
3419
- return info_sub
3420
-
3421
- if __name__=='__main__':
3422
- risk_esg=stock_risk_esg(info)
3423
-
3424
- #==============================================================================
3425
- def stock_fin_rates(info):
3426
-
3427
- wishlist=['financialCurrency', \
3428
-
3429
- #偿债能力
3430
- 'currentRatio','quickRatio','debtToEquity', \
3431
-
3432
- #盈利能力
3433
- #'ebitdaMargins','operatingMargins','grossMargins','profitMargins', \
3434
- 'operatingMargins','profitMargins', \
3435
-
3436
- #股东回报率
3437
- 'returnOnAssets','returnOnEquity', \
3438
- 'dividendRate','trailingAnnualDividendRate','trailingEps', \
3439
- 'payoutRatio','revenuePerShare','totalCashPerShare', \
3440
-
3441
- #业务发展能力
3442
- #'revenueGrowth','earningsGrowth','earningsQuarterlyGrowth'
3443
- 'revenueGrowth','earningsQuarterlyGrowth',
3444
- ]
3445
-
3446
- #按照wishlist的顺序从info中取值
3447
- rowlist=list(info.index)
3448
- import pandas as pd
3449
- info_sub=pd.DataFrame(columns=['Item','Value'])
3450
- infot=info.T
3451
- for w in wishlist:
3452
- if w in rowlist:
3453
- v=infot[w][0]
3454
- s=pd.Series({'Item':w,'Value':v})
3455
- try:
3456
- info_sub=info_sub.append(s,ignore_index=True)
3457
- except:
3458
- info_sub=info_sub._append(s,ignore_index=True)
3459
-
3460
- return info_sub
3461
-
3462
- if __name__=='__main__':
3463
- fin_rates=stock_fin_rates(info)
3464
-
3465
- #==============================================================================
3466
- def stock_fin_statements(info):
3467
-
3468
- wishlist=['financialCurrency','lastFiscalYearEnd','mostRecentQuarter','nextFiscalYearEnd', \
3469
-
3470
- #资产负债
3471
- #'marketCap','totalAssets','totalDebt', \
3472
- 'marketCap', \
3473
-
3474
- #利润表
3475
- 'totalRevenue','grossProfits','ebitda','netIncomeToCommon', \
3476
-
3477
- #现金流量
3478
- 'operatingCashflow','freeCashflow','totalCash', \
3479
-
3480
- #股票数量
3481
- 'sharesOutstanding','totalInsiderShares'
3482
- ]
3483
-
3484
- datelist=['lastFiscalYearEnd','mostRecentQuarter','nextFiscalYearEnd']
3485
-
3486
- #按照wishlist的顺序从info中取值
3487
- rowlist=list(info.index)
3488
- import pandas as pd
3489
- info_sub=pd.DataFrame(columns=['Item','Value'])
3490
- infot=info.T
3491
- for w in wishlist:
3492
- if w in rowlist:
3493
- if not (w in datelist):
3494
- v=infot[w][0]
3495
- else:
3496
- v=infot[w][0][0:10]
3497
-
3498
- s=pd.Series({'Item':w,'Value':v})
3499
- try:
3500
- info_sub=info_sub.append(s,ignore_index=True)
3501
- except:
3502
- info_sub=info_sub._append(s,ignore_index=True)
3503
-
3504
- return info_sub
3505
-
3506
- if __name__=='__main__':
3507
- fin_statements=stock_fin_statements(info)
3508
-
3509
- #==============================================================================
3510
- def stock_market_rates(info):
3511
-
3512
- wishlist=['beta','currency', \
3513
-
3514
- #市场观察
3515
- 'priceToBook','priceToSalesTrailing12Months', \
3516
-
3517
- #市场风险与收益
3518
- '52WeekChange','SandP52WeekChange', \
3519
- 'trailingEps','forwardEps','trailingPE','forwardPE','pegRatio', \
3520
-
3521
- #分红
3522
- 'dividendYield', \
3523
-
3524
- #持股
3525
- 'heldPercentInsiders','heldPercentInstitutions', \
3526
-
3527
- #股票流通
3528
- 'sharesOutstanding','currentPrice',
3529
- 'targetHighPrice','targetMeanPrice','targetMedianPrice','targetLowPrice',
3530
- 'numberOfAnalystOpinions',
3531
- #'recommendationKey',
3532
- ]
3533
-
3534
- #按照wishlist的顺序从info中取值
3535
- rowlist=list(info.index)
3536
- import pandas as pd
3537
- info_sub=pd.DataFrame(columns=['Item','Value'])
3538
- infot=info.T
3539
- for w in wishlist:
3540
- if w in rowlist:
3541
- v=infot[w][0]
3542
- s=pd.Series({'Item':w,'Value':v})
3543
- try:
3544
- info_sub=info_sub.append(s,ignore_index=True)
3545
- except:
3546
- info_sub=info_sub._append(s,ignore_index=True)
3547
-
3548
- return info_sub
3549
-
3550
- if __name__=='__main__':
3551
- market_rates=stock_market_rates(info)
3552
-
3553
- #==============================================================================
3554
- if __name__=='__main__':
3555
- ticker='AAPL'
3556
- ticker='00700.HK'
3557
- ticker='03968.HK'
3558
- ticker='01398.HK'
3559
-
3560
- info_type='fin_rates'
3561
-
3562
- ticker='FIBI.TA'
3563
- info_type='officers'
3564
-
3565
- def get_stock_profile(ticker,info_type='basic',printout=True):
3566
- """
3567
- 功能:抓取和获得股票的信息
3568
- basic: 基本信息
3569
- officers:管理层
3570
- fin_rates: 财务比率快照
3571
- fin_statements: 财务报表快照
3572
- market_rates: 市场比率快照
3573
- risk_general: 一般风险快照
3574
- risk_esg: 可持续发展风险快照(有些股票无此信息)
3575
- """
3576
- #print("\nSearching for snapshot info of",ticker,"\b, please wait...")
3577
-
3578
- typelist=['basic','officers','fin_rates','fin_statements','market_rates','risk_general','risk_esg']
3579
- if info_type not in typelist:
3580
- print(" #Sorry, info_type not supported for",info_type)
3581
- print(" Supported info_type:\n",typelist)
3582
- return None
3583
-
3584
- #应对各种出错情形:执行出错,返回NoneType,返回空值
3585
- try:
3586
- info=stock_info(ticker)
3587
- except:
3588
- print(" #Warning(get_stock_profile): recovering info for",ticker,"...")
3589
- import time; time.sleep(5)
3590
- try:
3591
- info=stock_info(ticker)
3592
- except:
3593
- print(" #Error(get_stock_profile): failed to access Yahoo for",ticker)
3594
- return None
3595
- if info is None:
3596
- print(" #Error(get_stock_profile): retrieved none info of",ticker)
3597
- print(f" Solution: if {ticker} is correct, try again later!")
3598
- return None
3599
- if len(info) == 0:
3600
- print(" #Error(get_stock_profile): retrieved empty info of",ticker)
3601
- return None
3602
- """
3603
- #处理公司短名字
3604
- name0=info.T['shortName'][0]
3605
- name1=name0.split('.',1)[0] #仅取第一个符号.以前的字符串
3606
- name2=name1.split(',',1)[0] #仅取第一个符号,以前的字符串
3607
- name3=name2.split('(',1)[0] #仅取第一个符号(以前的字符串
3608
- #name4=name3.split(' ',1)[0] #仅取第一个空格以前的字符串
3609
- #name=ticker_name(name4) #去掉空格有名字错乱风险
3610
- name9=name3.strip()
3611
- name=ticker_name(name9) #从短名字翻译
3612
- """
3613
- if not printout: return info
3614
-
3615
- footnote=''
3616
- name=ticker_name(ticker) #从股票代码直接翻译
3617
- if info_type in ['basic']:
3618
- sub_info=stock_basic(info)
3619
- info_text="公司基本信息"
3620
-
3621
- if info_type in ['officers']:
3622
- sub_info=stock_officers(info)
3623
- info_text="公司高管信息"
3624
-
3625
- if info_type in ['fin_rates']:
3626
- sub_info=stock_fin_rates(info)
3627
- info_text="基本财务比率TTM"
3628
-
3629
- if info_type in ['fin_statements']:
3630
- sub_info=stock_fin_statements(info)
3631
- info_text="财报主要项目"
3632
-
3633
- if info_type in ['market_rates']:
3634
- sub_info=stock_market_rates(info)
3635
- info_text="基本市场指标"
3636
-
3637
- if info_type in ['risk_general']:
3638
- sub_info=stock_risk_general(info)
3639
- info_text="一般风险评估"
3640
- footnote="注:数值越小风险越低,最高10分"
3641
-
3642
- if info_type in ['risk_esg']:
3643
- info_text="ESG风险评估"
3644
- footnote="注:分数越小风险越低,最高100分"
3645
- sub_info=stock_risk_esg(info)
3646
- if len(sub_info)==0:
3647
- print(" \n#Warning: ESG info not available for",ticker)
3648
- return None
3649
-
3650
- # 显示信息
3651
- lang=check_language()
3652
- if lang == 'Chinese':
3653
- titletxt="===== "+name+": "+info_text+" =====\n"
3654
- if len(footnote) > 0:
3655
- footnote1='\n'+footnote
3656
- else:
3657
- footnote1=footnote
3658
- else:
3659
- titletxt="===== "+name+": "+texttranslate(info_text)+" =====\n"
3660
-
3661
- if len(footnote) > 0:
3662
- footnote1='\n'+texttranslate(footnote)
3663
- else:
3664
- footnote1=footnote
3665
-
3666
- printdf(sub_info,titletxt,footnote1)
3667
-
3668
- return info
3669
-
3670
- if __name__=='__main__':
3671
- info=get_stock_profile(ticker,info_type='basic')
3672
- info=get_stock_profile(ticker,info_type='officers')
3673
- info=get_stock_profile(ticker,info_type='fin_rates')
3674
- info=get_stock_profile(ticker,info_type='fin_statements')
3675
- info=get_stock_profile(ticker,info_type='market_rates')
3676
- info=get_stock_profile(ticker,info_type='risk_general')
3677
- info=get_stock_profile(ticker,info_type='risk_esg')
3678
-
3679
- #==============================================================================
3680
-
3681
- def stock_snapshot(ticker='AAPL',info_type="all"):
3682
- """
3683
- 功能:打印指定选项,套壳函数get_stock_profile
3684
- """
3685
- print(" Connecting to Yahoo Finance ... ...")
3686
- typelist=['basic',
3687
- 'officers',
3688
- 'fin_rates',
3689
- 'fin_statements',
3690
- 'market_rates',
3691
- 'risk_general',
3692
- 'risk_esg']
3693
-
3694
- if info_type.lower() !="all" and info_type.lower() in typelist:
3695
- info=get_stock_profile(ticker,info_type=info_type)
3696
- return
3697
-
3698
- if info_type.lower() =="all":
3699
- for t in typelist:
3700
- info=get_stock_profile(ticker,info_type=t)
3701
-
3702
- if info is None:
3703
- break
3704
- return
3705
- else:
3706
- print(" #Error(stock_snapshot): unsupported info type",info_type)
3707
- print(" Supporting",typelist)
3708
- return
3709
-
3710
-
3711
- def security_snapshot(ticker='AAPL'):
3712
- """
3713
- 功能:一次性打印所有选项,套壳函数get_stock_profile
3714
- """
3715
- print(" Try connecting to Yahoo Finance ... ...")
3716
- typelist=['basic',
3717
- 'officers',
3718
- 'fin_rates',
3719
- 'fin_statements',
3720
- 'market_rates',
3721
- 'risk_general',
3722
- 'risk_esg']
3723
- for t in typelist:
3724
- info=get_stock_profile(ticker,info_type=t)
3725
-
3726
- if info is None:
3727
- break
3728
-
3729
- return
3730
- #==============================================================================
3731
- if __name__=='__main__':
3732
- ticker='AAPL'
3733
- info=stock_info(ticker)
3734
- sub_info=stock_basic(info)
3735
- titletxt="===== "+ticker+": Snr Management ====="
3736
-
3737
- def printdf(sub_info,titletxt,footnote):
3738
- """
3739
- 功能:整齐显示股票信息快照,翻译中文,按照中文项目长度计算空格数
3740
- """
3741
- print("\n"+titletxt)
3742
-
3743
- for index,row in sub_info.iterrows():
3744
-
3745
- #----------------------------------------------------------------------
3746
- #特殊打印:高管信息
3747
- if row['Item']=="companyOfficers":
3748
- print_companyOfficers(sub_info)
3749
- continue
3750
-
3751
- #特殊打印:ESG同行状况
3752
- peerlist=["peerEsgScorePerformance","peerEnvironmentPerformance", \
3753
- "peerSocialPerformance","peerGovernancePerformance"]
3754
- if row['Item'] in peerlist:
3755
- print_peerPerformance(sub_info,row['Item'])
3756
- continue
3757
-
3758
- #特殊打印:ESG Social风险内容
3759
- if row['Item']=="relatedControversy":
3760
- print_controversy(sub_info,row['Item'])
3761
- continue
3762
- #----------------------------------------------------------------------
3763
-
3764
- print_item(row['Item'],row['Value'],10)
3765
-
3766
- import datetime; todaydt=datetime.date.today().strftime("%y-%m-%d")
3767
- lang=check_language()
3768
- if lang == 'Chinese':
3769
- print(footnote+"\n数据来源: 雅虎/Sustainalytics,",todaydt)
3770
- else:
3771
- print(footnote+"\nSource: Yahoo/Sustainalytics,",todaydt)
3772
-
3773
- return
3774
-
3775
- if __name__=='__main__':
3776
- printdf(sub_info,titletxt)
3777
-
3778
- #==============================================================================
3779
- if __name__=='__main__':
3780
- item='currentPrice'
3781
- value='110.08'
3782
- maxlen=10
3783
-
3784
- def print_item(item,value,maxlen):
3785
- """
3786
- 功能:打印一个项目和相应的值,中间隔开一定空间对齐
3787
- 限制:只区分字符串、整数和浮点数
3788
- """
3789
- DEBUG=False
3790
-
3791
- print(ectranslate(item)+': ',end='')
3792
-
3793
- directprint=['zip','ratingYear','ratingMonth']
3794
- if item in directprint:
3795
- if DEBUG: print("...Direct print")
3796
- print(value)
3797
- return
3798
-
3799
- #是否整数
3800
- if isinstance(value,int):
3801
- if DEBUG: print("...Integer: ",end='')
3802
- if value != 0:
3803
- print(format(value,','))
3804
- else:
3805
- #print('---')
3806
- print('0')
3807
- return
3808
-
3809
- #是否浮点数
3810
- ZERO=0.00001
3811
- if isinstance(value,float):
3812
- if DEBUG: print("...Float: ",end='')
3813
- if value < 1.0:
3814
- value1=round(value,4)
3815
- else:
3816
- value1=round(value,2)
3817
- if value <= -ZERO or value >= ZERO:
3818
- print(format(value1,','))
3819
- else:
3820
- #print('---')
3821
- print('0.0')
3822
- return
3823
-
3824
- #是否字符串
3825
- if not isinstance(value,str):
3826
- print(str(value))
3827
-
3828
- #是否字符串表示的整数
3829
- if value.isdigit():
3830
- value1=int(value)
3831
- if DEBUG: print("...Integer in string: ",end='')
3832
- if value1 != 0:
3833
- print(format(value1,','))
3834
- else:
3835
- #print('---')
3836
- print('0')
3837
- return
3838
-
3839
- #是否字符串表示的浮点数
3840
- try:
3841
- value1=float(value)
3842
- if value1 < 1.0:
3843
- value2=round(value1,4)
3844
- else:
3845
- value2=round(value1,2)
3846
- if DEBUG: print("...Float in string")
3847
- if value1 <= -ZERO or value1 >= ZERO:
3848
- print(format(value2,','))
3849
- else:
3850
- #print('---')
3851
- print('0.0')
3852
- except:
3853
- #只是字符串
3854
- if DEBUG: print("...String")
3855
- print(value)
3856
-
3857
- return
3858
-
3859
- if __name__=='__main__':
3860
- print_item('currentPrice','110.08',10)
3861
-
3862
- #==============================================================================
3863
- if __name__=='__main__':
3864
- str1='哈哈哈ROA1'
3865
-
3866
- def str_len(str1):
3867
- """
3868
- 功能:计算中英文混合字符串的实际占位长度,不太准
3869
- """
3870
- len_d=len(str1)
3871
- len_u=len(str1.encode('utf_8'))
3872
-
3873
- num_ch=(len_u - len_d)/2
3874
- num_en=len_d - num_ch
3875
- totallen=int(num_ch*2 + num_en)
3876
-
3877
- return totallen
3878
-
3879
- if __name__=='__main__':
3880
- str_len('哈哈哈ROA1')
3881
-
3882
- #==============================================================================
3883
- if __name__=='__main__':
3884
- info=stock_info('AAPL')
3885
- sub_info=stock_officers(info)
3886
-
3887
- def print_companyOfficers(sub_info):
3888
- """
3889
- 功能:打印公司高管信息
3890
- """
3891
- item='companyOfficers'
3892
-
3893
- lang=check_language()
3894
- if lang == 'English':
3895
- itemtxt=texttranslate('公司高管:')
3896
- else:
3897
- itemtxt='公司高管:'
3898
-
3899
- key1='name'
3900
- key2='title'
3901
- key3='yearBorn'
3902
- key4='age'
3903
-
3904
- key6='totalPay'
3905
- key7='fiscalYear'
3906
- currency=list(sub_info[sub_info['Item'] == 'currency']['Value'])[0]
3907
- alist=list(sub_info[sub_info['Item'] == item]['Value'])[0]
3908
-
3909
- print(itemtxt)
3910
- if len(alist)==0:
3911
- print(" #Warning(print_companyOfficers): company officer info not available")
3912
-
3913
- import datetime as dt; today=dt.date.today()
3914
- thisyear=int(str(today)[:4])
3915
- for i in alist:
3916
-
3917
- #测试是否存在:姓名,职位,出生年份
3918
- try:
3919
- ikey1=i[key1]
3920
- ikey2=i[key2]
3921
- ikey3=i[key3]
3922
- except:
3923
- continue
3924
- ikey4=thisyear-ikey3
3925
- print(' '*4,ikey1)
3926
- print(' '*8,ikey2,'\b,',ikey4,texttranslate('\b岁 (生于')+str(ikey3)+')')
3927
-
3928
- #测试是否存在:薪酬信息
3929
- try:
3930
- ikey6=i[key6]
3931
- ikey7=i[key7]
3932
- if ikey6 > 0:
3933
- print(' '*8,texttranslate('总薪酬'),currency+str(format(ikey6,',')),'@'+str(ikey7))
3934
- except:
3935
- continue
3936
- return
3937
-
3938
- if __name__=='__main__':
3939
- print_companyOfficers(sub_info)
3940
-
3941
- #==============================================================================
3942
- if __name__=='__main__':
3943
- info=stock_info('AAPL')
3944
- sub_info=stock_risk_esg(info)
3945
- item="peerEsgScorePerformance"
3946
-
3947
- def print_peerPerformance(sub_info,item):
3948
- """
3949
- 功能:打印ESG信息
3950
- """
3951
-
3952
- key1='min'
3953
- key2='avg'
3954
- key3='max'
3955
- i=list(sub_info[sub_info['Item'] == item]['Value'])[0]
3956
-
3957
- """
3958
- print(ectranslate(item)+':')
3959
- print(' '*4,key1+':',i[key1],'\b,',key2+':',round(i[key2],2),'\b,',key3+':',i[key3])
3960
- """
3961
- print(ectranslate(item)+': ',end='')
3962
- print(texttranslate("均值")+str(round(i[key2],2)),end='')
3963
- print(" ("+str(i[key1])+'-'+str(i[key3])+")")
3964
-
3965
- return
3966
-
3967
- if __name__=='__main__':
3968
- print_peerPerformance(sub_info,item)
3969
-
3970
- #==============================================================================
3971
- if __name__=='__main__':
3972
- info=stock_info('AAPL')
3973
- sub_info=stock_risk_esg(info)
3974
- item='relatedControversy'
3975
-
3976
- def print_controversy(sub_info,item):
3977
- """
3978
- 功能:打印ESG Social风险内容
3979
- """
3980
- alist=list(sub_info[sub_info['Item'] == item]['Value'])[0]
3981
- if len(alist)==0:
3982
- print(" #Error(print_controversy): no relevant info found.")
3983
-
3984
- print(ectranslate(item)+':')
3985
- for i in alist:
3986
- print(' '*4,ectranslate(i))
3987
-
3988
- return
3989
-
3990
- if __name__=='__main__':
3991
- print_controversy(sub_info,item)
3992
-
3993
- #==============================================================================
3994
- if __name__ =="__main__":
3995
- stocklist=["BAC", "TD","PNC"]
3996
-
3997
- def get_esg2(stocklist):
3998
- """
3999
- 功能:根据股票代码列表,抓取企业最新的可持续性发展ESG数据
4000
- 输入参数:
4001
- stocklist:股票代码列表,例如单个股票["AAPL"], 多只股票["AAPL","MSFT","GOOG"]
4002
- 输出参数:
4003
- 企业最新的可持续性发展ESG数据,数据框
4004
- """
4005
-
4006
- import pandas as pd
4007
- collist=['symbol','totalEsg','environmentScore','socialScore','governanceScore']
4008
- sust=pd.DataFrame(columns=collist)
4009
- for t in stocklist:
4010
- try:
4011
- info=stock_info(t).T
4012
- except:
4013
- print(" #Error(get_esg2): esg info not available for",t)
4014
- continue
4015
- if (info is None) or (len(info)==0):
4016
- print(" #Error(get_esg2): failed to get esg info for",t)
4017
- continue
4018
- sub=info[collist]
4019
- sust=pd.concat([sust,sub])
4020
-
4021
- newcols=['Stock','ESGscore','EPscore','CSRscore','CGscore']
4022
- sust.columns=newcols
4023
- """
4024
- sust=sust.rename(columns={'symbol':'Stock','totalEsg':'ESGscore', \
4025
- 'environmentScore':'EPscore', \
4026
- 'socialScore':'CSRscore', \
4027
- 'governanceScore':'CGscore'})
4028
- """
4029
- sust.set_index('Stock',inplace=True)
4030
-
4031
- return sust
4032
-
4033
- if __name__ =="__main__":
4034
- sust=get_esg2(stocklist)
4035
-
4036
- #==============================================================================
4037
- #==============================================================================
4038
- def portfolio_esg2(portfolio):
4039
- """
4040
- 功能:抓取、打印和绘图投资组合portfolio的可持续性发展数据,演示用
4041
- 输入参数:
4042
- 企业最新的可持续性发展数据,数据框
4043
- """
4044
- #解构投资组合
4045
- _,_,stocklist,_,ticker_type=decompose_portfolio(portfolio)
4046
-
4047
- #抓取数据
4048
- try:
4049
- sust=get_esg2(stocklist)
4050
- except:
4051
- print(" #Error(portfolio_esg): fail to get ESG data for",stocklist)
4052
- return None
4053
- if sust is None:
4054
- #print("#Error(portfolio_esg), fail to get ESG data for",stocklist)
4055
- return None
4056
-
4057
- #处理小数点
4058
- from pandas.api.types import is_numeric_dtype
4059
- cols=list(sust)
4060
- for c in cols:
4061
- if is_numeric_dtype(sust[c]):
4062
- sust[c]=round(sust[c],2)
4063
-
4064
- #显示结果
4065
- print(texttranslate("\n===== 投资组合的ESG风险评估 ====="))
4066
- print(texttranslate("投资组合:"),stocklist)
4067
- #显示各个成分股的ESG分数
4068
- sust['Stock']=sust.index
4069
- esgdf=sust[['Stock','ESGscore','EPscore','CSRscore','CGscore']]
4070
- print(esgdf.to_string(index=False))
4071
-
4072
- print("\n"+texttranslate("ESG评估分数:"))
4073
- #木桶短板:EPScore
4074
- esg_ep=esgdf.sort_values(['EPscore'], ascending = True)
4075
- p_ep=esg_ep['EPscore'][-1]
4076
- p_ep_stock=esg_ep.index[-1]
4077
- str_ep=texttranslate(" EP分数(基于")+str(p_ep_stock)+ticker_name(str(p_ep_stock))+")"
4078
- len_ep=hzlen(str_ep)
4079
-
4080
- #木桶短板:CSRScore
4081
- esg_csr=esgdf.sort_values(['CSRscore'], ascending = True)
4082
- p_csr=esg_csr['CSRscore'][-1]
4083
- p_csr_stock=esg_csr.index[-1]
4084
- str_csr=texttranslate(" CSR分数(基于")+str(p_csr_stock)+ticker_name(str(p_csr_stock))+")"
4085
- len_csr=hzlen(str_csr)
4086
-
4087
- #木桶短板:CGScore
4088
- esg_cg=esgdf.sort_values(['CGscore'], ascending = True)
4089
- p_cg=esg_cg['CGscore'][-1]
4090
- p_cg_stock=esg_cg.index[-1]
4091
- str_cg=texttranslate(" CG分数(基于")+str(p_cg_stock)+ticker_name(str(p_cg_stock))+")"
4092
- len_cg=hzlen(str_cg)
4093
-
4094
- str_esg=texttranslate(" ESG总评分数")
4095
- len_esg=hzlen(str_esg)
4096
-
4097
- #计算对齐冒号中间需要的空格数目
4098
- len_max=max(len_ep,len_csr,len_cg,len_esg)
4099
- str_ep=str_ep+' '*(len_max-len_ep+1)+':'
4100
- str_csr=str_csr+' '*(len_max-len_csr+1)+':'
4101
- str_cg=str_cg+' '*(len_max-len_cg+1)+':'
4102
- str_esg=str_esg+' '*(len_max-len_esg+1)+':'
4103
-
4104
- #对齐打印
4105
- print(str_ep,p_ep)
4106
- print(str_csr,p_csr)
4107
- print(str_cg,p_cg)
4108
- #计算投资组合的ESG综合风险
4109
- p_esg=round(p_ep+p_csr+p_cg,2)
4110
- print(str_esg,p_esg)
4111
-
4112
- import datetime as dt; today=dt.date.today()
4113
- footnote=texttranslate("注:分数越高, 风险越高.")+"\n"+texttranslate("数据来源:雅虎,")+str(today)
4114
- print(footnote)
4115
-
4116
- return p_esg
4117
-
4118
- if __name__ =="__main__":
4119
- #market={'Market':('China','^HSI')}
4120
- market={'Market':('US','^GSPC')}
4121
- #stocks={'0939.HK':2,'1398.HK':1,'3988.HK':3}
4122
- stocks={'VIPS':3,'JD':2,'BABA':1}
4123
- portfolio=dict(market,**stocks)
4124
- esg=portfolio_esg(portfolio)
4125
- #==============================================================================
4126
-
4127
- if __name__ =="__main__":
4128
- ticker='AAPL'
4129
- measures=['High','Low',"Open",'Close']
4130
- fromdate='2022-7-1'
4131
- todate='2022-12-1'
4132
-
4133
- axhline_value=0
4134
- axhline_label=''
4135
- linewidth=1.5
4136
- graph=True
4137
-
4138
- df=compare_mmeasure(ticker,measures,fromdate,todate)
4139
-
4140
- measures=['Daily Ret%',"Monthly Ret%",'Annual Ret%']
4141
- df=compare_mmeasure(ticker,measures,fromdate,todate)
4142
-
4143
- measures=['Daily Ret%',"Exp Ret%",'Annual Ret%']
4144
- df=compare_mmeasure(ticker,measures,fromdate,todate,axhline_value=0,axhline_label='零线')
4145
-
4146
-
4147
- def compare_mmeasure(ticker,measures,fromdate,todate, \
4148
- axhline_value=0,axhline_label='',linewidth=1.5, \
4149
- graph=True,smooth=True):
4150
- """
4151
- 功能:绘制单证券多指标对比图
4152
- """
4153
- #检查期间的合理性
4154
- result,startpd,endpd=check_period(fromdate,todate)
4155
- if not result:
4156
- print(" #Error(compare_mmeasure): invalid date period from",fromdate,"to",todate)
4157
- return None
4158
-
4159
- ticker1=ticker.upper()
4160
- #fromdate1=date_adjust(fromdate,adjust=-365)
4161
- fromdate1=fromdate
4162
- #抓取行情,并计算其各种期间的收益率
4163
- df1a=stock_ret(ticker1,fromdate1,todate,graph=False)
4164
- if df1a is None:
4165
- print(" #Error(compare_mmeasure): no price info found for",ticker,"from",fromdate,"to",todate)
4166
- return None
4167
-
4168
- #加入价格波动指标
4169
- df1b=price_volatility2(df1a,ticker1,fromdate1,todate,graph=False)
4170
- #加入收益率波动指标
4171
- df1c=ret_volatility2(df1b,ticker1,fromdate1,todate,graph=False)
4172
- #加入收益率下偏标准差指标
4173
- df1d=ret_lpsd2(df1c,ticker1,fromdate1,todate,graph=False)
4174
-
4175
- #去掉开始日期以前的数据
4176
- df2=df1d[(df1d.index >= startpd) & (df1d.index <= endpd)]
4177
-
4178
- #提取绘图指标
4179
- collist=[]; collist_notfound=[]
4180
- dflist=list(df2)
4181
- for m in measures:
4182
- if m in dflist:
4183
- collist=collist+[m]
4184
- else:
4185
- collist_notfound=collist_notfound+[m]
4186
- if len(collist)==0:
4187
- print(" #Error(compare_mmeasure): no measure info found for",ticker,"from",fromdate,"to",todate)
4188
- return None
4189
-
4190
- if len(collist_notfound)>0:
4191
- print(" #Warning(compare_mmeasure): unsupported measure(s) found ",collist_notfound)
4192
-
4193
- df3=pd.DataFrame(df2[collist])
4194
- for c in collist:
4195
- df3.rename(columns={c:ectranslate(c)},inplace=True)
4196
-
4197
- # 填充非交易日的缺失值,使得绘制的曲线连续
4198
- df3.fillna(axis=0,method='ffill',inplace=True)
4199
- #df3.fillna(axis=0,method='bfill',inplace=True)
4200
-
4201
- #绘制单个证券的多指标对比图
4202
- y_label=''
4203
- import datetime; today = datetime.date.today()
4204
-
4205
- x_label=text_lang("数据来源: Sina/EM/Stooq/Yahoo/SWHY,","Data source: Sina/Yahoo/Stooq/EM, ")+str(today)
4206
- title_txt=text_lang("证券趋势分析:","Security Trend: ")+ticker_name(ticker)
4207
-
4208
- draw_lines(df3,y_label=y_label,x_label=x_label, \
4209
- axhline_value=axhline_value,axhline_label=axhline_label, \
4210
- title_txt=title_txt, \
4211
- data_label=False,resample_freq='H',smooth=smooth,linewidth=linewidth)
4212
-
4213
- return df3
4214
-
4215
- #==============================================================================
4216
- #==============================================================================
4217
- #==============================================================================
4218
- #==============================================================================
4219
- #==============================================================================
4220
- def fix_mac_hanzi_plt():
4221
- """
4222
- 功能:修复MacOSX中matplotlib绘图时汉字的乱码问题,安装SimHei.ttf字体
4223
- 注意:本函数未经测试,弃用
4224
- """
4225
- #判断当前的操作系统
4226
- import platform
4227
- pltf=platform.platform()
4228
- os=pltf[0:5]
4229
- if not (os == "macOS"):
4230
- print("#Warning(fix_mac_hanzi_plt): This command is only valid for MacOSX.")
4231
- return
4232
-
4233
- #查找模块的安装路径
4234
- import os
4235
- import imp
4236
- dir1=imp.find_module('siat')[1]
4237
- dir2=imp.find_module('matplotlib')[1]
4238
-
4239
- #查找matplotlib的字体地址
4240
- pltttf=dir2+'/mpl-data/fonts/ttf'
4241
-
4242
- #复制字体文件
4243
- cpcmd="cp -r "+dir1+"/SimHei.ttf "+pltttf
4244
- result=os.popen(cpcmd)
4245
-
4246
- #修改配置文件内容
4247
- import matplotlib
4248
- pltrc=matplotlib.matplotlib_fname()
4249
-
4250
- line1='\nfont.family : sans-serif\n'
4251
- line2='font.sans-serif : SimHei,DejaVu Sans,Bitstream Vera Sans,Lucida Grande,Verdana,Geneva,Lucid,Arial,Helvetica,Avant Garde,sans-serif\n'
4252
- line3='axes.unicode_minus : False\n'
4253
-
4254
- filehandler=open(pltrc,'a')
4255
- filehandler.write(line1)
4256
- filehandler.write(line2)
4257
- filehandler.write(line3)
4258
- filehandler.close()
4259
-
4260
- from matplotlib.font_manager import _rebuild
4261
- _rebuild()
4262
- print(" Fixed Mac Hanzi problems for matplotlib graphics!")
4263
- print(" Please RESTART Python kernel to make it effective!")
4264
-
4265
- return
4266
-
4267
-
4268
-
4269
-
4270
-
4271
-
4272
-
4273
-
4274
-
4275
-
4276
-
4277
-
4278
-
4279
-
4280
-
4281
-
4282
-
4283
-
4284
-