siat 3.10.131__py3-none-any.whl → 3.10.132__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 (220) hide show
  1. build/lib/build/lib/siat/__init__.py +75 -0
  2. build/lib/build/lib/siat/allin.py +137 -0
  3. build/lib/build/lib/siat/assets_liquidity.py +915 -0
  4. build/lib/build/lib/siat/beta_adjustment.py +1058 -0
  5. build/lib/build/lib/siat/beta_adjustment_china.py +548 -0
  6. build/lib/build/lib/siat/blockchain.py +143 -0
  7. build/lib/build/lib/siat/bond.py +2900 -0
  8. build/lib/build/lib/siat/bond_base.py +992 -0
  9. build/lib/build/lib/siat/bond_china.py +100 -0
  10. build/lib/build/lib/siat/bond_zh_sina.py +143 -0
  11. build/lib/build/lib/siat/capm_beta.py +783 -0
  12. build/lib/build/lib/siat/capm_beta2.py +887 -0
  13. build/lib/build/lib/siat/common.py +5360 -0
  14. build/lib/build/lib/siat/compare_cross.py +642 -0
  15. build/lib/build/lib/siat/copyrights.py +18 -0
  16. build/lib/build/lib/siat/cryptocurrency.py +667 -0
  17. build/lib/build/lib/siat/economy.py +1471 -0
  18. build/lib/build/lib/siat/economy2.py +1853 -0
  19. build/lib/build/lib/siat/esg.py +536 -0
  20. build/lib/build/lib/siat/event_study.py +815 -0
  21. build/lib/build/lib/siat/fama_french.py +1521 -0
  22. build/lib/build/lib/siat/fin_stmt2_yahoo.py +982 -0
  23. build/lib/build/lib/siat/financial_base.py +1160 -0
  24. build/lib/build/lib/siat/financial_statements.py +598 -0
  25. build/lib/build/lib/siat/financials.py +2339 -0
  26. build/lib/build/lib/siat/financials2.py +1278 -0
  27. build/lib/build/lib/siat/financials_china.py +4433 -0
  28. build/lib/build/lib/siat/financials_china2.py +2212 -0
  29. build/lib/build/lib/siat/fund.py +629 -0
  30. build/lib/build/lib/siat/fund_china.py +3307 -0
  31. build/lib/build/lib/siat/future_china.py +551 -0
  32. build/lib/build/lib/siat/google_authenticator.py +47 -0
  33. build/lib/build/lib/siat/grafix.py +3636 -0
  34. build/lib/build/lib/siat/holding_risk.py +867 -0
  35. build/lib/build/lib/siat/luchy_draw.py +638 -0
  36. build/lib/build/lib/siat/market_china.py +1168 -0
  37. build/lib/build/lib/siat/markowitz.py +2363 -0
  38. build/lib/build/lib/siat/markowitz2.py +3150 -0
  39. build/lib/build/lib/siat/markowitz2_20250704.py +2969 -0
  40. build/lib/build/lib/siat/markowitz2_20250705.py +3158 -0
  41. build/lib/build/lib/siat/markowitz_simple.py +373 -0
  42. build/lib/build/lib/siat/ml_cases.py +2291 -0
  43. build/lib/build/lib/siat/ml_cases_example.py +60 -0
  44. build/lib/build/lib/siat/option_china.py +3069 -0
  45. build/lib/build/lib/siat/option_pricing.py +1925 -0
  46. build/lib/build/lib/siat/other_indexes.py +409 -0
  47. build/lib/build/lib/siat/risk_adjusted_return.py +1576 -0
  48. build/lib/build/lib/siat/risk_adjusted_return2.py +1900 -0
  49. build/lib/build/lib/siat/risk_evaluation.py +2218 -0
  50. build/lib/build/lib/siat/risk_free_rate.py +351 -0
  51. build/lib/build/lib/siat/sector_china.py +4140 -0
  52. build/lib/build/lib/siat/security_price2.py +727 -0
  53. build/lib/build/lib/siat/security_prices.py +3408 -0
  54. build/lib/build/lib/siat/security_trend.py +402 -0
  55. build/lib/build/lib/siat/security_trend2.py +646 -0
  56. build/lib/build/lib/siat/stock.py +4284 -0
  57. build/lib/build/lib/siat/stock_advice_linear.py +934 -0
  58. build/lib/build/lib/siat/stock_base.py +26 -0
  59. build/lib/build/lib/siat/stock_china.py +2095 -0
  60. build/lib/build/lib/siat/stock_prices_kneighbors.py +910 -0
  61. build/lib/build/lib/siat/stock_prices_linear.py +386 -0
  62. build/lib/build/lib/siat/stock_profile.py +707 -0
  63. build/lib/build/lib/siat/stock_technical.py +3305 -0
  64. build/lib/build/lib/siat/stooq.py +74 -0
  65. build/lib/build/lib/siat/transaction.py +347 -0
  66. build/lib/build/lib/siat/translate.py +5183 -0
  67. build/lib/build/lib/siat/valuation.py +1378 -0
  68. build/lib/build/lib/siat/valuation_china.py +2076 -0
  69. build/lib/build/lib/siat/var_model_validation.py +444 -0
  70. build/lib/build/lib/siat/yf_name.py +811 -0
  71. build/lib/siat/__init__.py +75 -0
  72. build/lib/siat/allin.py +137 -0
  73. build/lib/siat/assets_liquidity.py +915 -0
  74. build/lib/siat/beta_adjustment.py +1058 -0
  75. build/lib/siat/beta_adjustment_china.py +548 -0
  76. build/lib/siat/blockchain.py +143 -0
  77. build/lib/siat/bond.py +2900 -0
  78. build/lib/siat/bond_base.py +992 -0
  79. build/lib/siat/bond_china.py +100 -0
  80. build/lib/siat/bond_zh_sina.py +143 -0
  81. build/lib/siat/capm_beta.py +783 -0
  82. build/lib/siat/capm_beta2.py +887 -0
  83. build/lib/siat/common.py +5360 -0
  84. build/lib/siat/compare_cross.py +642 -0
  85. build/lib/siat/copyrights.py +18 -0
  86. build/lib/siat/cryptocurrency.py +667 -0
  87. build/lib/siat/economy.py +1471 -0
  88. build/lib/siat/economy2.py +1853 -0
  89. build/lib/siat/esg.py +536 -0
  90. build/lib/siat/event_study.py +815 -0
  91. build/lib/siat/fama_french.py +1521 -0
  92. build/lib/siat/fin_stmt2_yahoo.py +982 -0
  93. build/lib/siat/financial_base.py +1160 -0
  94. build/lib/siat/financial_statements.py +598 -0
  95. build/lib/siat/financials.py +2339 -0
  96. build/lib/siat/financials2.py +1278 -0
  97. build/lib/siat/financials_china.py +4433 -0
  98. build/lib/siat/financials_china2.py +2212 -0
  99. build/lib/siat/fund.py +629 -0
  100. build/lib/siat/fund_china.py +3307 -0
  101. build/lib/siat/future_china.py +551 -0
  102. build/lib/siat/google_authenticator.py +47 -0
  103. build/lib/siat/grafix.py +3636 -0
  104. build/lib/siat/holding_risk.py +867 -0
  105. build/lib/siat/luchy_draw.py +638 -0
  106. build/lib/siat/market_china.py +1168 -0
  107. build/lib/siat/markowitz.py +2363 -0
  108. build/lib/siat/markowitz2.py +3150 -0
  109. build/lib/siat/markowitz2_20250704.py +2969 -0
  110. build/lib/siat/markowitz2_20250705.py +3158 -0
  111. build/lib/siat/markowitz_simple.py +373 -0
  112. build/lib/siat/ml_cases.py +2291 -0
  113. build/lib/siat/ml_cases_example.py +60 -0
  114. build/lib/siat/option_china.py +3069 -0
  115. build/lib/siat/option_pricing.py +1925 -0
  116. build/lib/siat/other_indexes.py +409 -0
  117. build/lib/siat/risk_adjusted_return.py +1576 -0
  118. build/lib/siat/risk_adjusted_return2.py +1900 -0
  119. build/lib/siat/risk_evaluation.py +2218 -0
  120. build/lib/siat/risk_free_rate.py +351 -0
  121. build/lib/siat/sector_china.py +4140 -0
  122. build/lib/siat/security_price2.py +727 -0
  123. build/lib/siat/security_prices.py +3408 -0
  124. build/lib/siat/security_trend.py +402 -0
  125. build/lib/siat/security_trend2.py +646 -0
  126. build/lib/siat/stock.py +4284 -0
  127. build/lib/siat/stock_advice_linear.py +934 -0
  128. build/lib/siat/stock_base.py +26 -0
  129. build/lib/siat/stock_china.py +2095 -0
  130. build/lib/siat/stock_prices_kneighbors.py +910 -0
  131. build/lib/siat/stock_prices_linear.py +386 -0
  132. build/lib/siat/stock_profile.py +707 -0
  133. build/lib/siat/stock_technical.py +3305 -0
  134. build/lib/siat/stooq.py +74 -0
  135. build/lib/siat/transaction.py +347 -0
  136. build/lib/siat/translate.py +5183 -0
  137. build/lib/siat/valuation.py +1378 -0
  138. build/lib/siat/valuation_china.py +2076 -0
  139. build/lib/siat/var_model_validation.py +444 -0
  140. build/lib/siat/yf_name.py +811 -0
  141. siat/__init__.py +0 -0
  142. siat/allin.py +0 -0
  143. siat/assets_liquidity.py +0 -0
  144. siat/beta_adjustment.py +0 -0
  145. siat/beta_adjustment_china.py +0 -0
  146. siat/blockchain.py +0 -0
  147. siat/bond.py +0 -0
  148. siat/bond_base.py +0 -0
  149. siat/bond_china.py +0 -0
  150. siat/bond_zh_sina.py +0 -0
  151. siat/capm_beta.py +0 -0
  152. siat/capm_beta2.py +0 -0
  153. siat/common.py +136 -3
  154. siat/compare_cross.py +0 -0
  155. siat/copyrights.py +0 -0
  156. siat/cryptocurrency.py +0 -0
  157. siat/economy.py +0 -0
  158. siat/economy2.py +0 -0
  159. siat/esg.py +0 -0
  160. siat/event_study.py +0 -0
  161. siat/exchange_bond_china.pickle +0 -0
  162. siat/fama_french.py +0 -0
  163. siat/fin_stmt2_yahoo.py +0 -0
  164. siat/financial_base.py +0 -0
  165. siat/financial_statements.py +0 -0
  166. siat/financials.py +0 -0
  167. siat/financials2.py +0 -0
  168. siat/financials_china.py +0 -0
  169. siat/financials_china2.py +0 -0
  170. siat/fund.py +0 -0
  171. siat/fund_china.pickle +0 -0
  172. siat/fund_china.py +0 -0
  173. siat/future_china.py +0 -0
  174. siat/google_authenticator.py +0 -0
  175. siat/grafix.py +1 -1
  176. siat/holding_risk.py +0 -0
  177. siat/luchy_draw.py +0 -0
  178. siat/market_china.py +1 -1
  179. siat/markowitz.py +0 -0
  180. siat/markowitz2.py +240 -39
  181. siat/markowitz2_20250704.py +2969 -0
  182. siat/markowitz2_20250705.py +3158 -0
  183. siat/markowitz_simple.py +0 -0
  184. siat/ml_cases.py +0 -0
  185. siat/ml_cases_example.py +0 -0
  186. siat/option_china.py +0 -0
  187. siat/option_pricing.py +0 -0
  188. siat/other_indexes.py +0 -0
  189. siat/risk_adjusted_return.py +0 -0
  190. siat/risk_adjusted_return2.py +0 -0
  191. siat/risk_evaluation.py +0 -0
  192. siat/risk_free_rate.py +0 -0
  193. siat/sector_china.py +0 -0
  194. siat/security_price2.py +0 -0
  195. siat/security_prices.py +3 -1
  196. siat/security_trend.py +0 -0
  197. siat/security_trend2.py +1 -1
  198. siat/stock.py +4 -2
  199. siat/stock_advice_linear.py +0 -0
  200. siat/stock_base.py +0 -0
  201. siat/stock_china.py +0 -0
  202. siat/stock_info.pickle +0 -0
  203. siat/stock_prices_kneighbors.py +0 -0
  204. siat/stock_prices_linear.py +0 -0
  205. siat/stock_profile.py +0 -0
  206. siat/stock_technical.py +0 -0
  207. siat/stooq.py +0 -0
  208. siat/transaction.py +0 -0
  209. siat/translate.py +11 -11
  210. siat/valuation.py +0 -0
  211. siat/valuation_china.py +0 -0
  212. siat/var_model_validation.py +0 -0
  213. siat/yf_name.py +0 -0
  214. {siat-3.10.131.dist-info → siat-3.10.132.dist-info}/METADATA +235 -227
  215. siat-3.10.132.dist-info/RECORD +218 -0
  216. {siat-3.10.131.dist-info → siat-3.10.132.dist-info}/WHEEL +1 -1
  217. {siat-3.10.131.dist-info → siat-3.10.132.dist-info/licenses}/LICENSE +0 -0
  218. siat-3.10.132.dist-info/top_level.txt +4 -0
  219. siat-3.10.131.dist-info/RECORD +0 -76
  220. siat-3.10.131.dist-info/top_level.txt +0 -1
@@ -0,0 +1,642 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 本模块功能:跨类别对比证券投资产品的业绩指标走势
4
+ 所属工具包:证券投资分析工具SIAT
5
+ SIAT:Security Investment Analysis Tool
6
+ 创建日期:2023年4月4日
7
+ 最新修订日期:2023年4月5日
8
+ 作者:王德宏 (WANG Dehong, Peter)
9
+ 作者单位:北京外国语大学国际商学院
10
+ 作者邮件:wdehong2000@163.com
11
+ 版权所有:王德宏
12
+ 用途限制:仅限研究与教学使用,不可商用!商用需要额外授权。
13
+ 特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
14
+ """
15
+
16
+ #==============================================================================
17
+ #关闭所有警告
18
+ import warnings; warnings.filterwarnings('ignore')
19
+ #==============================================================================
20
+ from siat.common import *
21
+ from siat.translate import *
22
+ from siat.security_prices import *
23
+ from siat.security_price2 import *
24
+ from siat.transaction import *
25
+ from siat.risk_adjusted_return import *
26
+ from siat.sector_china import *
27
+ from siat.grafix import *
28
+
29
+ import pandas as pd
30
+ #==============================================================================
31
+
32
+ #==============================================================================
33
+ if __name__=='__main__':
34
+ ticker='600519.SS'
35
+ start='2023-1-1'
36
+ end='2023-4-4'
37
+ info_types=['Close','Volume']
38
+
39
+ df1=fetch_price_stock(ticker,start,end)
40
+
41
+ def fetch_price_stock(ticker,start,end,info_types=['Close','Volume'], \
42
+ adjust=-2*365,ticker_type='auto'):
43
+ """
44
+ 功能:获取股票、大盘指数、ETF和REITS的价格
45
+ ticker:股票代码
46
+ start,end:日期期间
47
+ info_types:信息测度,默认['Close'],还可以为['Close','Open','High','Low',
48
+ 'Volume','Adj Close']
49
+ 特点:为compare_indicator使用,包括股票名称
50
+ """
51
+ start1=date_adjust(start,adjust=adjust)
52
+ try:
53
+ prices=get_prices(ticker,start1,end)
54
+ except:
55
+ print(" #Error(fetch_price_stock): failed to fetch stock prices for",ticker)
56
+ return None
57
+
58
+ if prices is None:
59
+ print(" #Warning(fetch_price_stock): no info found for",ticker,"during",start,"and",end)
60
+ return None
61
+
62
+ if len(prices)==0:
63
+ print(" #Warning(fetch_price_stock): zero record found for",ticker,"during",start,"and",end)
64
+ return None
65
+
66
+ if isinstance(info_types,str):
67
+ typelist=[info_types]
68
+ else:
69
+ typelist=info_types
70
+
71
+ import pandas as pd
72
+ df=pd.DataFrame()
73
+
74
+ for t in typelist:
75
+ try:
76
+ df[t]=prices[t]
77
+ except:
78
+ continue
79
+
80
+ df['Adj Close']=df['Close']
81
+ df['Code']=ticker
82
+ df['Type']='stock'
83
+
84
+ #预处理ticker_type
85
+ ticker_type=ticker_type_preprocess_mticker_mixed(ticker,ticker_type)
86
+ df['Name']=ticker_name(ticker,ticker_type)
87
+
88
+ return df
89
+
90
+
91
+ #==============================================================================
92
+ if __name__=='__main__':
93
+ Market={'Market':('China','000300.SS','白酒组合1号')}
94
+ Stocks1={'600519.SS':.5,'000858.SZ':.3}
95
+ Stocks2={'000596.SZ':.1,'000568.SZ':.1}
96
+ portfolio=dict(Market,**Stocks1,**Stocks2)
97
+
98
+ start='2023-1-1'
99
+ end='2023-4-4'
100
+ info_types=['Close','Volume']
101
+
102
+ df2=fetch_price_stock_portfolio(portfolio,start,end)
103
+
104
+ def fetch_price_stock_portfolio(portfolio,start,end,info_types=['Close','Volume'],adjust=-2*365):
105
+ """
106
+ 功能:获取股票投资组合的信息
107
+ portfolio:股票投资组合
108
+ start,end:日期期间
109
+ info_types:信息测度,默认['Close'],还可以为['Close','Open','High','Low',
110
+ 'Volume','Adj Close']
111
+ 特点:为compare_indicator使用,包括投资组合名称
112
+ """
113
+ start1=date_adjust(start,adjust=adjust)
114
+ try:
115
+ prices=get_portfolio_prices(portfolio,start1,end)
116
+ except:
117
+ print(" #Error(fetch_price_stock_portfolio): failed to fetch stock prices for the portfolio")
118
+ return None
119
+
120
+ if prices is None:
121
+ print(" #Warning(fetch_price_stock_portfolio): no info found for the portfolio during",start,"and",end)
122
+ return None
123
+
124
+ if len(prices)==0:
125
+ print(" #Warning(fetch_price_stock_portfolio): zero record found for the portfolio during",start,"and",end)
126
+ return None
127
+
128
+ if isinstance(info_types,str):
129
+ typelist=[info_types]
130
+ else:
131
+ typelist=info_types
132
+
133
+ import pandas as pd
134
+ df=pd.DataFrame()
135
+
136
+ for t in typelist:
137
+ try:
138
+ df[t]=prices[t]
139
+ except:
140
+ continue
141
+
142
+ df['Adj Close']=df['Close']
143
+
144
+ df['Code']='stock_portfolio'
145
+ df['Type']='stock_portfolio'
146
+ df['Name']=portfolio_name(portfolio)
147
+
148
+ return df
149
+
150
+
151
+ #==============================================================================
152
+ if __name__=='__main__':
153
+ dflist=[df1,df2,df3]
154
+
155
+ measure='Weekly Ret%'
156
+ start='2023-1-1'
157
+ end='2023-4-4'
158
+ graph=True
159
+
160
+ def compare_msecurity_cross(dflist,measure,start,end,graph=True, \
161
+ loc='best',annotate=False):
162
+ """
163
+ 功能:基于多个数据表df中的列Close计算指标measure,绘图比较
164
+ 输入要求:各个数据表df需要,索引为datetime,Close,Code,Type和Name
165
+ """
166
+ #检查日期期间
167
+ result,startpd,endpd=check_period(start,end)
168
+ if not result:
169
+ print(" #Error(compare_msecurity_cross): invalid date period from",start,'to',end)
170
+ if graph: return
171
+ else: return None
172
+
173
+ #检查是否支持该measure
174
+ measurelist=['Close','Adj Close','Daily Ret','Daily Ret%','Daily Adj Ret','Daily Adj Ret%',
175
+ 'log(Daily Ret)','log(Daily Adj Ret)','Weekly Ret','Weekly Ret%',
176
+ 'Weekly Adj Ret','Weekly Adj Ret%','Monthly Ret','Monthly Ret%',
177
+ 'Monthly Adj Ret','Monthly Adj Ret%','Quarterly Ret','Quarterly Ret%',
178
+ 'Quarterly Adj Ret','Quarterly Adj Ret%','Annual Ret','Annual Ret%',
179
+ 'Annual Adj Ret','Annual Adj Ret%','Exp Ret','Exp Ret%','Exp Adj Ret',
180
+ 'Exp Adj Ret%','Weekly Price Volatility','Weekly Adj Price Volatility',
181
+ 'Monthly Price Volatility','Monthly Adj Price Volatility',
182
+ 'Quarterly Price Volatility','Quarterly Adj Price Volatility',
183
+ 'Annual Price Volatility','Annual Adj Price Volatility',
184
+ 'Exp Price Volatility','Exp Adj Price Volatility',
185
+ 'Weekly Ret Volatility','Weekly Ret Volatility%',
186
+ 'Weekly Adj Ret Volatility','Weekly Adj Ret Volatility%',
187
+ 'Monthly Ret Volatility', 'Monthly Ret Volatility%',
188
+ 'Monthly Adj Ret Volatility', 'Monthly Adj Ret Volatility%',
189
+ 'Quarterly Ret Volatility', 'Quarterly Ret Volatility%',
190
+ 'Quarterly Adj Ret Volatility', 'Quarterly Adj Ret Volatility%',
191
+ 'Annual Ret Volatility', 'Annual Ret Volatility%',
192
+ 'Annual Adj Ret Volatility', 'Annual Adj Ret Volatility%',
193
+ 'Exp Ret Volatility', 'Exp Ret Volatility%', 'Exp Adj Ret Volatility',
194
+ 'Exp Adj Ret Volatility%', 'Weekly Ret LPSD', 'Weekly Ret LPSD%',
195
+ 'Weekly Adj Ret LPSD', 'Weekly Adj Ret LPSD%', 'Monthly Ret LPSD',
196
+ 'Monthly Ret LPSD%', 'Monthly Adj Ret LPSD', 'Monthly Adj Ret LPSD%',
197
+ 'Quarterly Ret LPSD', 'Quarterly Ret LPSD%', 'Quarterly Adj Ret LPSD',
198
+ 'Quarterly Adj Ret LPSD%', 'Annual Ret LPSD', 'Annual Ret LPSD%',
199
+ 'Annual Adj Ret LPSD', 'Annual Adj Ret LPSD%', 'Exp Ret LPSD',
200
+ 'Exp Ret LPSD%', 'Exp Adj Ret LPSD', 'Exp Adj Ret LPSD%']
201
+ if measure not in measurelist:
202
+ print(" #Error(compare_msecurity_cross): unsupported measurement",measure)
203
+ print(" Supported measurements:",measurelist)
204
+ if graph: return
205
+ else: return None
206
+
207
+ print(" Calculating measurement, please wait ......")
208
+
209
+ import pandas as pd
210
+ dfg=pd.DataFrame()
211
+
212
+ for dfi in dflist:
213
+
214
+ if 'Exp' in measure:
215
+ dfi=dfi[(dfi.index >= startpd) & (dfi.index <= endpd)]
216
+
217
+ dfic=calc_indicators(dfi,measure)
218
+ dfic2=dfic[(dfic.index >= startpd) & (dfic.index <= endpd)]
219
+ dfic3=pd.DataFrame(dfic2[measure])
220
+
221
+ dfic3.columns=[dfi['Name'].values[0]]
222
+
223
+ if len(dfg)==0:
224
+ dfg=dfic3
225
+ else:
226
+ dfg=pd.merge(dfg,dfic3,how='outer',left_index=True,right_index=True)
227
+
228
+ dfg2=dfg[(dfg.index >= startpd) & (dfg.index <= endpd)]
229
+
230
+ if graph:
231
+ # 绘制多条线
232
+ title_txt="比较跨品种证券的指标走势"
233
+ y_label=ectranslate(measure)
234
+
235
+ import datetime
236
+ today = datetime.date.today().strftime("%Y-%m-%d")
237
+ x_label="数据来源:综合新浪/雅虎/stooq/FRED/申万宏源,"+today
238
+
239
+ if 'Ret%' in measure:
240
+ axhline_value=0
241
+ axhline_label='收益零线'
242
+ else:
243
+ axhline_value=0
244
+ axhline_label=''
245
+
246
+ dfg2.dropna(inplace=True)
247
+ draw_lines(dfg2,y_label,x_label,axhline_value,axhline_label,title_txt, \
248
+ data_label=False,resample_freq='H',smooth=True,linewidth=1.5, \
249
+ loc=loc,annotate=annotate)
250
+
251
+
252
+ if graph: return
253
+ else: return dfg2
254
+
255
+ #==============================================================================
256
+ #==============================================================================
257
+
258
+ if __name__=='__main__':
259
+ start='2022-1-1'
260
+ end='2022-10-31'
261
+
262
+ rar_name="sharpe"
263
+ rar_name="alpha"
264
+ RF=False
265
+ window=30
266
+
267
+ axhline_value=0
268
+ axhline_label=''
269
+ graph=True
270
+ printout=True
271
+ sortby='tpw_mean'
272
+ scope='China'
273
+
274
+ graph=False
275
+
276
+ def compare_mrar_cross(dflist,rar_name,start,end, \
277
+ RF=False,window=252, \
278
+ axhline_value=0,axhline_label='零线',graph=True,printout=False, \
279
+ sortby='tpw_mean',scope='China', \
280
+ loc='best',annotate=False,ticker_type='auto'):
281
+ """
282
+ 功能:计算多种证券的rar比率,并绘图对比
283
+ 比率:支持夏普比率、特雷诺比率、索替诺比率、阿尔法比率等
284
+ 特点:支持跨种类比较,如股票/投资组合/申万行业指数/债券指数等
285
+
286
+ 注意1:当RF=False时可能有bug
287
+ 注意2:当股票为非国内A股时,需要定义scope指定区域。这个很不灵活,需要修改:手工指定市场指数和RF
288
+ """
289
+ #检查日期期间
290
+ result,startpd,endpd=check_period(start,end)
291
+ if not result:
292
+ print(" #Error(compare_mrar_cross): invalid date period from",fromdate,'to',todate)
293
+ if graph: return
294
+ else: return None
295
+
296
+
297
+ #检查rar指标的种类
298
+ rarlist=['treynor','sharpe','sortino','alpha']
299
+ if not (rar_name.lower() in rarlist):
300
+ print(" #Error(compare_mrar_cross): unsupported rar name",rar_name)
301
+ return None
302
+
303
+ import pandas as pd
304
+ df=pd.DataFrame()
305
+ print(" *** Starting to calculate rar ratios, please wait ......")
306
+ for dfi in dflist:
307
+ name=dfi['Name'].values[0]
308
+ df_tmp=rar_ratio_rolling_df(dfi,ratio_name=rar_name,RF=RF,window=window,scope=scope)
309
+ if df_tmp is None:
310
+ print(" #Warning(compare_mrar_cross): data not available for",t)
311
+ continue
312
+ else:
313
+ dft=df_tmp[['RAR']]
314
+ dft.rename(columns={'RAR':name},inplace=True)
315
+
316
+ if len(df)==0:#第一个
317
+ df=dft
318
+ else:
319
+ df=pd.merge(df,dft,how='outer',left_index=True,right_index=True)
320
+
321
+ if len(df)==0:
322
+ print(" #Warning(compare_mrar_cross): no data available for the above securities between",start,end)
323
+ return None
324
+
325
+ df.fillna(method='ffill')
326
+ df.fillna(method='bfill')
327
+
328
+ df2=df[(df.index >= startpd) & (df.index <= endpd)]
329
+
330
+ #绘制多条曲线
331
+ rar_list=['treynor','sortino','sharpe','alpha']
332
+ rar_list_e=['Treynor Ratio','Sortino Ratio','Sharpe Ratio','Jensen alpha']
333
+ rar_list_c=['特雷诺比率','索替诺比率','夏普比率','阿尔法指标']
334
+
335
+ pos=rar_list.index(rar_name)
336
+
337
+ import datetime; today = datetime.date.today()
338
+
339
+ lang=check_language()
340
+ if lang == 'English':
341
+
342
+ y_label=rar_list_e[pos]
343
+ x_label="Source: sina/stooq, "+str(today)
344
+ title_txt="Compare Multiple Risk-adjusted Return Performance"
345
+ else:
346
+ y_label=rar_list_c[pos]
347
+ x_label="数据来源: 综合新浪/雅虎/stooq/FRED/申万宏源,"+str(today)
348
+ title_txt="比较跨品种证券的风险调整收益指标走势"
349
+
350
+ # 是否绘图
351
+ if graph:
352
+ draw_lines(df2,y_label,x_label, \
353
+ axhline_value=axhline_value,axhline_label=axhline_label, \
354
+ title_txt=title_txt,data_label=False, \
355
+ loc=loc,annotate=annotate)
356
+ ds=None
357
+ if printout:
358
+ dfcols=list(df2)
359
+
360
+ #预处理ticker_type
361
+ ticker_type_list=ticker_type_preprocess_mticker_mixed(dfcols,ticker_type)
362
+
363
+ for c in dfcols:
364
+ #ccn=ticker_name(c)+'('+c+')'
365
+ pos=dfcols.index(c)
366
+ tt=ticker_type_list[pos]
367
+ ccn=ticker_name(c,tt)
368
+ df2.rename(columns={c:ccn},inplace=True)
369
+
370
+ if sortby=='tpw_mean':
371
+ sortby_txt='按推荐标记+近期优先加权平均值降序排列'
372
+ elif sortby=='min':
373
+ sortby_txt='按推荐标记+最小值降序排列'
374
+ elif sortby=='mean':
375
+ sortby_txt='按推荐标记+平均值降序排列'
376
+ elif sortby=='median':
377
+ sortby_txt='按推荐标记+中位数值降序排列'
378
+ else:
379
+ pass
380
+
381
+ title_txt='*** '+title_txt+':'+y_label+','+sortby_txt
382
+ additional_note="*** 注:列表仅显示有星号标记或特定数量的证券。"
383
+ footnote='比较期间:'+start+'至'+end
384
+ ds=descriptive_statistics(df2,title_txt,additional_note+footnote,decimals=4, \
385
+ sortby=sortby,recommend_only=False)
386
+
387
+ return df2,ds
388
+
389
+ if __name__=='__main__':
390
+ tickers = ['000858.SZ','600779.SS','000596.SZ','603589.SS','000001.SS']
391
+ df=compare_mrar(tickers,'sharpe','2022-1-1','2022-10-31')
392
+ df=compare_mrar(tickers,'alpha','2022-10-1','2022-10-31')
393
+
394
+ #==============================================================================
395
+ if __name__=='__main__':
396
+ df=df1
397
+ ratio_name='sharpe'
398
+ ratio_name='alpha'
399
+ RF=True
400
+ window=240
401
+ scope='China'
402
+
403
+ def rar_ratio_rolling_df(df,ratio_name='sharpe',RF=True,window=252,scope='China'):
404
+ """
405
+ 功能:滚动计算一个证券投资产品经风险调整后的收益率指数
406
+ 输入:证券产品价格时间序列,rar名称,滚动窗口宽度(天数)
407
+ 输出:风险调整后的收益率指数序列
408
+
409
+ 注意:当RF=False时有bug
410
+ """
411
+
412
+ #提取开始结束日期
413
+ t0=df.head(1).index.values[0]
414
+ t1=pd.to_datetime(str(t0))
415
+ start=t1.strftime("%Y-%m-%d")
416
+
417
+ t0=df.tail(1).index.values[0]
418
+ t1=pd.to_datetime(str(t0))
419
+ end=t1.strftime("%Y-%m-%d")
420
+
421
+ #第1步:各种准备和检查工作
422
+ #设定错误信息的函数名
423
+ func_name='rar_ratio_rolling_df'
424
+
425
+ ratio_list=['treynor','sharpe','sortino','alpha']
426
+ if ratio_name not in ratio_list:
427
+ message=" #Error("+func_name+"): "+"unsupported rar ratio type"
428
+ print(message,ratio_name)
429
+ return None
430
+
431
+ #第2步:计算投资组合的日收益率序列
432
+ #计算日收益率,表示为百分比
433
+ ret_pf=pd.DataFrame(df['Close'].pct_change())*100.0
434
+ ret_pf=ret_pf.dropna()
435
+
436
+ #第3步:获得无风险收益率/市场收益率序列
437
+ #屏蔽函数内print信息输出的类
438
+ import os, sys
439
+ class HiddenPrints:
440
+ def __enter__(self):
441
+ self._original_stdout = sys.stdout
442
+ sys.stdout = open(os.devnull, 'w')
443
+
444
+ def __exit__(self, exc_type, exc_val, exc_tb):
445
+ sys.stdout.close()
446
+ sys.stdout = self._original_stdout
447
+
448
+ rf_df=None
449
+ if RF or ratio_name=='alpha':
450
+ #获得期间的日无风险收益率(抓取的RF为百分比)
451
+ #print(" Searching for risk-free interest rate ...")
452
+ if scope=='China':
453
+ mktidx='000300.SS'
454
+ with HiddenPrints():
455
+ rf_df=get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=RF)
456
+ else:
457
+ rf_df=get_rf(start,end,scope=scope,freq='daily')
458
+ if rf_df is None:
459
+ message=" #Error("+func_name+"): "+"no data available for rf in"
460
+ print(message,scope,start,end)
461
+ return None,None
462
+ #rf_df=get_rf(start,end,scope=scope,freq='daily')
463
+
464
+ #第4步:合并投资组合日收益率与无风险利率/市场收益率序列
465
+ #合并rf_df与ret_pf
466
+ reg=ret_pf
467
+ if rf_df is None:
468
+ reg['RF']=0
469
+ else:
470
+ reg=pd.merge(reg,rf_df,how='left',left_index=True,right_index=True)
471
+ if len(reg) == 0:
472
+ message=" #Error("+func_name+"): "+"empty data for ratio calculation"
473
+ print(message)
474
+ return None
475
+
476
+ #填补缺失的RF
477
+ reg.fillna(axis=0,method='ffill',inplace=True)
478
+
479
+ reg['Ret-RF']=reg['Close']-reg['RF']
480
+ reg=reg.dropna()
481
+ try:
482
+ reg.drop(columns=['SMB','HML'],inplace=True)
483
+ except: pass
484
+
485
+ #第5步:滚动计算风险调整后的收益率
486
+ ##########风险调整后的收益率,计算开始##########
487
+ #用于保存rar和ret_rf_mean
488
+ import numpy as np
489
+ datelist=reg.index.to_list()
490
+ calc_func='calc_'+ratio_name+'_ratio'
491
+
492
+ rars=pd.DataFrame(columns=('Date','RAR','Mean(Ret)'))
493
+ for i in np.arange(0,len(reg)):
494
+ i1=i+window-1
495
+ if i1 >= len(reg): break
496
+
497
+ #构造滚动窗口
498
+ windf=reg[reg.index >= datelist[i]]
499
+ windf=windf[windf.index <= datelist[i1]]
500
+ #print(i,datelist[i],i1,datelist[i1],len(windf))
501
+
502
+ #使用滚动窗口计算
503
+ try:
504
+ rar,ret_mean=eval(calc_func)(windf)
505
+ except:
506
+ print(" #Error(rar_ratio_rolling_df): failed in linear regression by",calc_func,'\b, in',df['Code'].values[0])
507
+ #print(" windf:\n",windf)
508
+ continue
509
+
510
+ #记录计算结果
511
+ row=pd.Series({'Date':datelist[i1],'RAR':rar,'Mean(Ret)':ret_mean})
512
+ try:
513
+ rars=rars.append(row,ignore_index=True)
514
+ except:
515
+ rars=rars._append(row,ignore_index=True)
516
+
517
+ rars.set_index(['Date'],inplace=True)
518
+ ##########风险调整后的收益率,计算结束##########
519
+
520
+ return rars
521
+
522
+ #==============================================================================
523
+ if __name__=='__main__':
524
+ # 混合对比
525
+ start='2023-1-1'; end='2023-11-18'
526
+
527
+ # 股票
528
+ ticker1='600519.SS'
529
+ df1=fetch_price_stock(ticker1,start,end)
530
+
531
+ # 指数
532
+ ticker2='000300.SS'
533
+ df2=fetch_price_stock(ticker2,start,end)
534
+
535
+ # 投资组合
536
+ Market={'Market':('China','000300.SS','白酒组合1号')}
537
+ Stocks1={'600519.SS':.5,'000858.SZ':.3}
538
+ Stocks2={'000596.SZ':.1,'000568.SZ':.1}
539
+ portfolio=dict(Market,**Stocks1,**Stocks2)
540
+ df3=fetch_price_stock_portfolio(portfolio,start,end)
541
+
542
+ # 申万行业指数
543
+ swindex='850831'
544
+ df4=fetch_price_swindex(swindex,start,end)
545
+
546
+ # 合并
547
+ dflist=[df1,df2,df3,df4]
548
+ measure='Exp Ret%'
549
+ dfa=compare_msecurity_cross(dflist,measure,start,end)
550
+
551
+ dfb=compare_mrar_cross(dflist,rar_name='sharpe',start=start,end=end)
552
+
553
+ # 测试
554
+ tickers=['600519.SS','000300.SS','850831.SW']
555
+ df=compare_cross(tickers)
556
+
557
+ def compare_cross(tickers,indicator='Close',start='default',end='default', \
558
+ scope='China',loc='best',annotate=False):
559
+ """
560
+ 功能:跨越证券产品品种比较趋势
561
+ 品种:股票,指数,ETF和REIT基金(仅限中国),交易所债券(仅限中国),
562
+ 股票投资组合,行业指数(仅限申万行业指数)
563
+ 指标:基于股价的相关指标,风险调整收益(rar)
564
+ 期间:默认近一个月MRM,后续考虑MRQ/MRY/YTD
565
+ """
566
+
567
+ # 检查日期:截至日期
568
+ import datetime as dt; today=dt.date.today()
569
+ end=end.lower()
570
+ if end in ['default','today']:
571
+ todate=today
572
+ else:
573
+ validdate,todate=check_date2(end)
574
+ if not validdate:
575
+ print(" #Warning(compare_cross): invalid date for",end)
576
+ todate=today
577
+
578
+ # 检查日期:开始日期
579
+ start=start.lower()
580
+ if start in ['default','mrm']: # 默认近一个月
581
+ fromdate=date_adjust(todate,adjust=-31)
582
+ elif start in ['mrq']: # 近三个月
583
+ fromdate=date_adjust(todate,adjust=-63)
584
+ elif start in ['mry']: # 近一年
585
+ fromdate=date_adjust(todate,adjust=-366)
586
+ elif start in ['lty']: # 近三年以来
587
+ fromdate=date_adjust(todate,adjust=-366*3)
588
+ elif start in ['lfy']: # 近五年以来
589
+ fromdate=date_adjust(todate,adjust=-366*5)
590
+ elif start in ['ytd']: # 今年以来
591
+ fromdate=str(today.year)+'-1-1'
592
+ else:
593
+ validdate,fromdate=check_date2(start)
594
+ if not validdate:
595
+ print(" #Warning(compare_cross): invalid date for",start,"/b, set to MRM")
596
+ fromdate=date_adjust(todate,adjust=-31)
597
+
598
+ # 检查tickers
599
+ if isinstance(tickers,str) or isinstance(tickers,dict):
600
+ tickers=[tickers]
601
+
602
+ if isinstance(tickers,list) and (len(tickers)==0):
603
+ tickers=['000001.SS','399001.SZ','899050.BJ']
604
+
605
+ # 基于类型,循环抓取数据
606
+ dflist=[]
607
+ names=locals()
608
+ for t in tickers:
609
+ pos=tickers.index(t)
610
+ if isinstance(t,str): # 字符串
611
+ t1=t.upper()
612
+ if '.' not in t1: # 不带后缀,美股
613
+ #exec("dft{}=fetch_price_stock(t1,fromdate,todate)".format(pos))
614
+ names['dft%s'%pos]=fetch_price_stock(t1,fromdate,todate)
615
+ else:
616
+ tlist=t1.split('.')
617
+ if tlist[1] not in ['SW']:
618
+ names['dft%s'%pos]=fetch_price_stock(t1,fromdate,todate)
619
+ else: #申万行业指数
620
+ names['dft%s'%pos]=fetch_price_swindex(tlist[0],fromdate,todate)
621
+ elif isinstance(t,dict): # 投资组合
622
+ names['dft%s'%pos]=fetch_price_stock_portfolio(t,fromdate,todate)
623
+ else:
624
+ continue
625
+
626
+ dflist=dflist+[names['dft%s'%pos]]
627
+
628
+ rarlist=['treynor','sharpe','sortino','alpha']
629
+ if indicator in rarlist:
630
+ indicator=indicator.lower()
631
+ df=compare_mrar_cross(dflist,rar_name=indicator,start=fromdate,end=todate, \
632
+ scope=scope,loc=loc,annotate=annotate)
633
+ else:
634
+ indicator=indicator.title() # 字符串每个单词首字母大写
635
+ df=compare_msecurity_cross(dflist,measure=indicator,start=fromdate,end=todate, \
636
+ loc=loc,annotate=annotate)
637
+
638
+ return df
639
+
640
+ #==============================================================================
641
+
642
+ #==============================================================================
@@ -0,0 +1,18 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ def version():
4
+ print("Version: 1.0.84")
5
+ print("Security Investment Analysis Tool (SIAT)")
6
+ print("Find a bug? Write to wdehong2000@163.com")
7
+ print("Copyrighs (C) WANG Dehong, 2021")
8
+ print("Not for commercial use unless authorised")
9
+
10
+
11
+ def author():
12
+ print("Author: Dr. WANG Dehong, 王德宏")
13
+ print("Professor, International Business School")
14
+ print("Beijing Foreign Studies University")
15
+ print("Email: wdehong2000@163.com")
16
+ print("Room 618 International Business School Building, West Campus")
17
+ print("No.19 West 3rd Ring North Road, Haidian District")
18
+ print("Beijing, P. R. China. Zip code: 100089")