siat 3.10.125__py3-none-any.whl → 3.10.126__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- siat/common.py +106 -2
- siat/exchange_bond_china.pickle +0 -0
- siat/fund_china.pickle +0 -0
- siat/stock.py +10 -2
- siat/stock_info.pickle +0 -0
- {siat-3.10.125.dist-info → siat-3.10.126.dist-info}/METADATA +234 -226
- siat-3.10.126.dist-info/RECORD +76 -0
- {siat-3.10.125.dist-info → siat-3.10.126.dist-info}/WHEEL +1 -1
- {siat-3.10.125.dist-info → siat-3.10.126.dist-info/licenses}/LICENSE +0 -0
- {siat-3.10.125.dist-info → siat-3.10.126.dist-info}/top_level.txt +0 -0
- siat/__init__ -20240701.py +0 -65
- siat/__init__.py.backup_20250214.py +0 -73
- siat/alpha_vantage_test.py +0 -24
- siat/assets_liquidity_test.py +0 -44
- siat/barrons_scraping_test.py +0 -276
- siat/beta_adjustment_test.py +0 -77
- siat/bond_test.py +0 -142
- siat/capm_beta_test.py +0 -49
- siat/cmat_commons.py +0 -961
- siat/compare_cross_test.py +0 -117
- siat/concepts_iwencai.py +0 -86
- siat/concepts_kpl.py +0 -93
- siat/cryptocurrency_test.py +0 -71
- siat/derivative.py +0 -1111
- siat/economy-20230125.py +0 -1206
- siat/economy_test.py +0 -360
- siat/esg_test.py +0 -63
- siat/fama_french_test.py +0 -115
- siat/financial_statements_test.py +0 -31
- siat/financials2 - /321/205/320/231/320/277/321/206/320/254/320/274.py" +0 -341
- siat/financials_china2_test.py +0 -67
- siat/financials_china2_test2.py +0 -88
- siat/financials_china2_test3.py +0 -87
- siat/financials_china_test.py +0 -475
- siat/financials_china_test2.py +0 -197
- siat/financials_china_test2_fin_indicator.py +0 -197
- siat/financials_test.py +0 -713
- siat/fred_test.py +0 -40
- siat/fund_china_test.py +0 -175
- siat/fund_test.py +0 -40
- siat/future_china_test.py +0 -37
- siat/global_index_test.py +0 -66
- siat/grafix_test.py +0 -112
- siat/holding_risk_test.py +0 -13
- siat/local_debug_test.py +0 -100
- siat/markowitz2-20240620.py +0 -2614
- siat/markowitz_ccb_test.py +0 -37
- siat/markowitz_ef_test.py +0 -136
- siat/markowitz_old.py +0 -871
- siat/markowitz_simple-20230709.py +0 -370
- siat/markowitz_test.py +0 -164
- siat/markowitz_test2.py +0 -69
- siat/ml_cases_example1.py +0 -60
- siat/option_china_test.py +0 -447
- siat/option_pricing_test.py +0 -81
- siat/option_sina_api_test.py +0 -112
- siat/proxy_test.py +0 -84
- siat/quandl_test.py +0 -39
- siat/risk_adjusted_return_test.py +0 -81
- siat/risk_evaluation_test.py +0 -96
- siat/risk_free_rate_test.py +0 -127
- siat/sector_china_test.py +0 -203
- siat/security_price.py +0 -831
- siat/security_prices_test.py +0 -310
- siat/security_trend2-20240620.py +0 -493
- siat/setup.py +0 -41
- siat/shenwan index history test.py +0 -41
- siat/stock_china_test.py +0 -38
- siat/stock_info_test.py +0 -189
- siat/stock_list_china_test.py +0 -33
- siat/stock_technical-20240620.py +0 -2736
- siat/stock_test.py +0 -487
- siat/temp.py +0 -36
- siat/test2_graphviz.py +0 -484
- siat/test_graphviz.py +0 -411
- siat/test_markowitz_simple.py +0 -198
- siat/test_markowitz_simple_revised.py +0 -215
- siat/test_markowitz_simple_revised2.py +0 -218
- siat/transaction_test.py +0 -436
- siat/translate-20230125.py +0 -2107
- siat/translate-20230206.py +0 -2109
- siat/translate-20230215.py +0 -2158
- siat/translate_20240606.py +0 -4206
- siat/translate_241003_keep.py +0 -4300
- siat/universal_test.py +0 -100
- siat/valuation_market_china_test.py +0 -36
- siat-3.10.125.dist-info/RECORD +0 -152
siat/security_price.py
DELETED
@@ -1,831 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
"""
|
3
|
-
本模块功能:提供全球证券市场行情
|
4
|
-
所属工具包:证券投资分析工具SIAT
|
5
|
-
SIAT:Security Investment Analysis Tool
|
6
|
-
创建日期:2020年1月5日
|
7
|
-
最新修订日期:2020年2月2日
|
8
|
-
作者:王德宏 (WANG Dehong, Peter)
|
9
|
-
作者单位:北京外国语大学国际商学院
|
10
|
-
作者邮件:wdehong2000@163.com
|
11
|
-
版权所有:王德宏
|
12
|
-
用途限制:仅限研究与教学使用,不可商用!商用需要额外授权。
|
13
|
-
特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
|
14
|
-
|
15
|
-
注意:本文件弃用!!!
|
16
|
-
"""
|
17
|
-
|
18
|
-
#==============================================================================
|
19
|
-
#屏蔽所有警告性信息
|
20
|
-
import warnings; warnings.filterwarnings('ignore')
|
21
|
-
#==============================================================================
|
22
|
-
#以下使用雅虎财经数据源
|
23
|
-
#==============================================================================
|
24
|
-
def check_period(fromdate,todate):
|
25
|
-
"""
|
26
|
-
功能:根据开始/结束日期检查期间日期的合理性
|
27
|
-
输入参数:
|
28
|
-
fromdate:开始日期。格式:YYYY-MM-DD
|
29
|
-
enddate:开始日期。格式:YYYY-MM-DD
|
30
|
-
输出参数:
|
31
|
-
validity:期间合理性。True-合理,False-不合理
|
32
|
-
start:开始日期。格式:datetime类型
|
33
|
-
end:结束日期。格式:datetime类型
|
34
|
-
"""
|
35
|
-
import pandas as pd
|
36
|
-
try:
|
37
|
-
start=pd.to_datetime(fromdate)
|
38
|
-
except:
|
39
|
-
print("Error #1(check_period): invalid date:",fromdate)
|
40
|
-
return None,None,None
|
41
|
-
try:
|
42
|
-
end=pd.to_datetime(todate)
|
43
|
-
except:
|
44
|
-
print("Error #2(check_period): invalid date:",todate)
|
45
|
-
return None,None,None
|
46
|
-
if start > end:
|
47
|
-
print("Error #3(check_period): invalid period: from",fromdate,"to",todate)
|
48
|
-
return None,None,None
|
49
|
-
|
50
|
-
return True,start,end
|
51
|
-
|
52
|
-
if __name__ =="__main__":
|
53
|
-
check_period('2020-1-1','2020-2-4')
|
54
|
-
check_period('2020-1-1','2010-2-4')
|
55
|
-
|
56
|
-
#==============================================================================
|
57
|
-
def get_price(ticker,fromdate,todate):
|
58
|
-
"""
|
59
|
-
功能:从雅虎财经抓取股票股价或指数价格或投资组合价值,使用pandas_datareader
|
60
|
-
输入:股票代码或股票代码列表,开始日期,结束日期
|
61
|
-
ticker: 股票代码或者股票代码列表。
|
62
|
-
大陆股票代码加上后缀.SZ或.SS,港股代码去掉前导0加后缀.HK
|
63
|
-
fromdate: 样本开始日期。
|
64
|
-
todate: 样本结束日期。既可以是今天日期,也可以是一个历史日期
|
65
|
-
|
66
|
-
输出:股票价格序列,按照日期升序排列。原汁原味的抓取数据
|
67
|
-
*Close price adjusted for splits.
|
68
|
-
**Adjusted close price adjusted for both dividends and splits.
|
69
|
-
"""
|
70
|
-
#检查期间合理性
|
71
|
-
result,start,end=check_period(fromdate,todate)
|
72
|
-
if result is None:
|
73
|
-
print("Error #1(get_price): incorrect date or invalid period!")
|
74
|
-
return None
|
75
|
-
|
76
|
-
#抓取雅虎股票价格
|
77
|
-
from pandas_datareader import data
|
78
|
-
try:
|
79
|
-
price=data.DataReader(ticker,'yahoo',start,end)
|
80
|
-
except:
|
81
|
-
print("Error #2(get_price): failed to get stock prices!")
|
82
|
-
print("Information:",ticker,fromdate,todate)
|
83
|
-
print("Possible reasons:")
|
84
|
-
print(" 1)internet connection problems.")
|
85
|
-
print(" 2)incorrect stock code.")
|
86
|
-
print(" 3)stock delisted or suspended during the period.")
|
87
|
-
return None
|
88
|
-
if len(price)==0:
|
89
|
-
print("Error #3(get_price): fetched empty stock data!")
|
90
|
-
print("Possible reasons:")
|
91
|
-
print(" 1)internet connection problems.")
|
92
|
-
print(" 2)incorrect stock code.")
|
93
|
-
print(" 3)stock delisted or suspended during the period.")
|
94
|
-
return None
|
95
|
-
"""
|
96
|
-
#去掉比起始日期更早的样本
|
97
|
-
price2=price[price.index >= fromdate]
|
98
|
-
#去掉比结束日期更晚的样本
|
99
|
-
price2=price2[price2.index <= todate]
|
100
|
-
|
101
|
-
#按日期升序排序,近期的价格排在后面
|
102
|
-
sortedprice=price2.sort_index(axis=0,ascending=True)
|
103
|
-
"""
|
104
|
-
return price
|
105
|
-
|
106
|
-
if __name__ =="__main__":
|
107
|
-
price=get_price('^GSPC','2020-1-1','2020-2-4')
|
108
|
-
print(price['Close'].tail(10))
|
109
|
-
price=get_price(['000001.SS','^HSI'],'2020-1-1','2020-2-4')
|
110
|
-
apclose=price['Close']['^HSI']
|
111
|
-
print(price['Close']['^HSI'].tail(10))
|
112
|
-
|
113
|
-
#==============================================================================
|
114
|
-
def compare_price(price,ticker1,ticker2,fromdate,todate):
|
115
|
-
"""
|
116
|
-
功能:比较两支股票的收盘价价格趋势,采用双坐标轴
|
117
|
-
输入:
|
118
|
-
price:抓取到的多只股票价格序列
|
119
|
-
ticker1/ticker2:股票或指数或ETF代码
|
120
|
-
fromdate/todate:开始/结束日期
|
121
|
-
输出:折线图,双坐标轴,避免数量级差异过大的问题
|
122
|
-
"""
|
123
|
-
#检查期间合理性
|
124
|
-
result,start,end=check_period(fromdate,todate)
|
125
|
-
if result is None:
|
126
|
-
print("Error #1(compare_price): incorrect date or invalid period!")
|
127
|
-
return
|
128
|
-
|
129
|
-
#检查ticker1/ticker2是否已经抓取在price中
|
130
|
-
try:
|
131
|
-
p1=price['Close'][ticker1]
|
132
|
-
except:
|
133
|
-
print("Error #2(compare_price): price data not found for",ticker1)
|
134
|
-
return
|
135
|
-
try:
|
136
|
-
p2=price['Close'][ticker2]
|
137
|
-
except:
|
138
|
-
print("Error #3(compare_price): price data not found for",ticker2)
|
139
|
-
return
|
140
|
-
|
141
|
-
#去掉比起始日期更早的样本
|
142
|
-
p1b=p1[p1.index >= start]
|
143
|
-
p2b=p2[p2.index >= start]
|
144
|
-
#去掉比结束日期更晚的样本
|
145
|
-
p1c=p1b[p1b.index <= end]
|
146
|
-
p2c=p2b[p2b.index <= end]
|
147
|
-
|
148
|
-
#绘制折线图,双坐标轴
|
149
|
-
import matplotlib.pyplot as plt
|
150
|
-
import matplotlib.dates as mdates
|
151
|
-
fig = plt.figure()
|
152
|
-
ax = fig.add_subplot(111)
|
153
|
-
ax.plot(p1c, '-', label = ticker1, lw=3)
|
154
|
-
|
155
|
-
#自动优化x轴标签
|
156
|
-
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m-%d')) # 格式化时间轴标注
|
157
|
-
plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
|
158
|
-
|
159
|
-
#建立第二y轴
|
160
|
-
ax2 = ax.twinx()
|
161
|
-
ax2.plot(p2c, 'r:.', label = ticker2, lw=3)
|
162
|
-
#fig.legend(loc='best', bbox_to_anchor=(1,1), bbox_transform=ax.transAxes)
|
163
|
-
#fig.legend(loc='best', bbox_transform=ax.transAxes)
|
164
|
-
#fig.legend(loc='best')
|
165
|
-
|
166
|
-
plt.title("Compare Securities Price", fontsize=18)
|
167
|
-
ax.set_xlabel("\nSource: Yahoo Finance", fontsize=13)
|
168
|
-
ax.set_ylabel(ticker1)
|
169
|
-
ax.legend(loc='lower left')
|
170
|
-
ax2.legend(loc='upper right')
|
171
|
-
ax2.set_ylabel(ticker2)
|
172
|
-
fig.show()
|
173
|
-
|
174
|
-
if __name__ =="__main__":
|
175
|
-
tickerlist=['000001.SS','601939.SS','^HSI','0939.HK']
|
176
|
-
price=get_price(tickerlist,'2019-1-1','2019-12-31')
|
177
|
-
ticker1='000001.SS'
|
178
|
-
ticker2='^HSI'
|
179
|
-
fromdate='2019-11-1'
|
180
|
-
todate='2019-12-31'
|
181
|
-
compare_price(price,'601939.SS','000001.SS','2019-1-1','2019-12-31')
|
182
|
-
compare_price(price,'601939.SS','000001.SS','2019-8-1','2019-9-1')
|
183
|
-
compare_price(price,'0939.HK','^HSI','2019-8-1','2019-9-1')
|
184
|
-
compare_price(price,'000001.SS','^HSI','2019-7-1','2019-10-1')
|
185
|
-
compare_price(price,'601939.SS','000001.SS','2019-11-15','2019-12-1')
|
186
|
-
#==============================================================================
|
187
|
-
def compare_return(price,ticker1,ticker2,fromdate,todate):
|
188
|
-
"""
|
189
|
-
功能:比较两支股票的收盘价价格趋势,采用双坐标轴
|
190
|
-
输入:
|
191
|
-
price:抓取到的多只股票价格序列
|
192
|
-
ticker1/ticker2:股票或指数或ETF代码
|
193
|
-
fromdate/todate:开始/结束日期
|
194
|
-
输出:折线图,双坐标轴,避免数量级差异过大的问题
|
195
|
-
"""
|
196
|
-
#检查期间合理性
|
197
|
-
result,start,end=check_period(fromdate,todate)
|
198
|
-
if result is None:
|
199
|
-
print("Error #1(compare_price): incorrect date or invalid period!")
|
200
|
-
return
|
201
|
-
|
202
|
-
#检查ticker1/ticker2是否已经抓取在price中
|
203
|
-
try:
|
204
|
-
p1=price['Close'][ticker1]
|
205
|
-
except:
|
206
|
-
print("Error #2(compare_price): price data not found for",ticker1)
|
207
|
-
return
|
208
|
-
try:
|
209
|
-
p2=price['Close'][ticker2]
|
210
|
-
except:
|
211
|
-
print("Error #3(compare_price): price data not found for",ticker2)
|
212
|
-
return
|
213
|
-
|
214
|
-
import matplotlib.pyplot as plt
|
215
|
-
import matplotlib.dates as mdates
|
216
|
-
import pandas as pd
|
217
|
-
|
218
|
-
#绘制折线图
|
219
|
-
r1=p1.pct_change()
|
220
|
-
r1df=pd.DataFrame(r1)
|
221
|
-
r1df.columns=['ret']
|
222
|
-
r1df['ret%']=round(r1df['ret']*100.0,2)
|
223
|
-
|
224
|
-
r1dfs1=r1df[r1df.index >= start]
|
225
|
-
r1dfs2=r1dfs1[r1dfs1.index <= end]
|
226
|
-
|
227
|
-
plt.plot(r1dfs2['ret%'],label=ticker1,lw=3)
|
228
|
-
|
229
|
-
r2=p2.pct_change()
|
230
|
-
r2df=pd.DataFrame(r2)
|
231
|
-
r2df.columns=['ret']
|
232
|
-
r2df['ret%']=round(r2df['ret']*100.0,2)
|
233
|
-
|
234
|
-
r2dfs1=r2df[r2df.index >= start]
|
235
|
-
r2dfs2=r2dfs1[r2dfs1.index <= end]
|
236
|
-
|
237
|
-
plt.plot(r2dfs2['ret%'],label=ticker2,lw=3,ls=':')
|
238
|
-
|
239
|
-
#纵轴零线
|
240
|
-
plt.axhline(y=0.0,color='green',linestyle='--')
|
241
|
-
|
242
|
-
#图示标题
|
243
|
-
titletxt="Compare Security Returns"
|
244
|
-
plt.title(titletxt,fontweight='bold', fontsize=18)
|
245
|
-
plt.ylabel("Capital gain %")
|
246
|
-
plt.xlabel("Data source: Yahoo Finance")
|
247
|
-
#plt.xticks(rotation=45)
|
248
|
-
#自动优化x轴标签
|
249
|
-
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
|
250
|
-
plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
|
251
|
-
plt.legend(loc='best')
|
252
|
-
plt.show()
|
253
|
-
|
254
|
-
|
255
|
-
if __name__ =="__main__":
|
256
|
-
tickerlist=['000001.SS','601939.SS','^HSI','0939.HK']
|
257
|
-
price=get_price(tickerlist,'2019-1-1','2019-12-31')
|
258
|
-
compare_return(price,'601939.SS','000001.SS','2019-8-1','2019-9-1')
|
259
|
-
compare_return(price,'0939.HK','^HSI','2019-8-1','2019-9-1')
|
260
|
-
compare_return(price,'000001.SS','^HSI','2019-7-1','2019-10-1')
|
261
|
-
|
262
|
-
|
263
|
-
#==============================================================================
|
264
|
-
#以下使用雅虎+tushare混合数据源
|
265
|
-
#==============================================================================
|
266
|
-
def ts_token():
|
267
|
-
"""
|
268
|
-
功能:获得tushare的token
|
269
|
-
输入:无
|
270
|
-
输出:tushare的token
|
271
|
-
"""
|
272
|
-
import tushare as ts
|
273
|
-
token='49f134b05e668d288be43264639ac77821ab9938ff40d6013c0ed24f'
|
274
|
-
pro=ts.pro_api(token)
|
275
|
-
|
276
|
-
return pro
|
277
|
-
|
278
|
-
if __name__ =="__main__":
|
279
|
-
pro=ts_token()
|
280
|
-
#==============================================================================
|
281
|
-
def cvtdate_yahootots(yahoodate):
|
282
|
-
"""
|
283
|
-
功能:日期格式转换, YYYY-MM-DD转换为YYYYMMDD
|
284
|
-
输入:日期,YYYY-MM-DD
|
285
|
-
输出:日期,YYYYMMDD
|
286
|
-
"""
|
287
|
-
import pandas as pd
|
288
|
-
try:
|
289
|
-
dateu=pd.to_datetime(yahoodate)
|
290
|
-
except:
|
291
|
-
print("Error #1(datecvt_yahootots): invalid date:",yahoodate)
|
292
|
-
return None
|
293
|
-
|
294
|
-
yyyy=str(dateu.year)
|
295
|
-
mm=dateu.month
|
296
|
-
if mm <= 9: mm='0'+str(mm)
|
297
|
-
else: mm=str(mm)
|
298
|
-
dd=dateu.day
|
299
|
-
if dd <= 9: dd='0'+str(dd)
|
300
|
-
else: dd=str(dd)
|
301
|
-
tsdate=yyyy+mm+dd
|
302
|
-
|
303
|
-
return tsdate
|
304
|
-
|
305
|
-
if __name__ =="__main__":
|
306
|
-
yahoodate='2019-12-5'
|
307
|
-
tsdate=cvtdate_yahootots(yahoodate)
|
308
|
-
print(tsdate)
|
309
|
-
#==============================================================================
|
310
|
-
def cvtticker_yahootots(yahooticker):
|
311
|
-
"""
|
312
|
-
功能:股票代码格式转换, xxxxxx.SS转换为xxxxxx.SH
|
313
|
-
输入:股票代码,xxxxxx.SS
|
314
|
-
输出:股票代码,xxxxxx.SH
|
315
|
-
"""
|
316
|
-
|
317
|
-
tsticker=yahooticker
|
318
|
-
suffix=yahooticker[-3:]
|
319
|
-
if suffix == '.SS':
|
320
|
-
tsticker=yahooticker.replace(suffix,'.SH')
|
321
|
-
|
322
|
-
return tsticker
|
323
|
-
|
324
|
-
if __name__ =="__main__":
|
325
|
-
yahooticker='601939.SS'
|
326
|
-
tsticker=cvtticker_yahootots(yahooticker)
|
327
|
-
#==============================================================================
|
328
|
-
def ts_price_stock(ticker,fromdate,todate):
|
329
|
-
"""
|
330
|
-
功能:从tushare数据源获得股票行情数据
|
331
|
-
输入:
|
332
|
-
ticker: 大陆股票代码,上交所后缀为.SS,深交所后缀为.SZ
|
333
|
-
fromdate:开始日期,格式YYYY-MM-DD
|
334
|
-
todate:结束日期
|
335
|
-
输出:
|
336
|
-
行情数据,df,雅虎格式
|
337
|
-
"""
|
338
|
-
#设置tushare的token
|
339
|
-
pro=ts_token()
|
340
|
-
|
341
|
-
#检查期间合理性
|
342
|
-
result,start,end=check_period(fromdate,todate)
|
343
|
-
if result is None:
|
344
|
-
print("Error #1(ts_price_stock): incorrect date or invalid period!")
|
345
|
-
return None
|
346
|
-
|
347
|
-
#转换输入日期
|
348
|
-
tsstart=cvtdate_yahootots(fromdate)
|
349
|
-
tsend=cvtdate_yahootots(todate)
|
350
|
-
#转换股票代码
|
351
|
-
tsticker=cvtticker_yahootots(ticker)
|
352
|
-
|
353
|
-
#抓取股票日行情
|
354
|
-
price=pro.daily(ts_code=tsticker,start_date=tsstart,end_date=tsend)
|
355
|
-
|
356
|
-
#升序排列
|
357
|
-
price.sort_values('trade_date',ascending=True,inplace=True)
|
358
|
-
|
359
|
-
#转换日期格式,设置日期索引
|
360
|
-
import pandas as pd
|
361
|
-
price['date']=pd.to_datetime(price['trade_date'])
|
362
|
-
price.set_index('date',inplace=True)
|
363
|
-
|
364
|
-
#修改列名
|
365
|
-
price.rename(columns= \
|
366
|
-
{'ts_code':'Ticker','open':'Open','high':'High','low':'Low', \
|
367
|
-
'close':'Close','vol':'Volume'},inplace=True)
|
368
|
-
|
369
|
-
#删除不需要的列
|
370
|
-
price.drop(['trade_date','pre_close','change','pct_chg','amount'], \
|
371
|
-
axis=1,inplace=True)
|
372
|
-
|
373
|
-
return price
|
374
|
-
|
375
|
-
if __name__ =="__main__":
|
376
|
-
ticker='601939.SS'
|
377
|
-
fromdate='2019-12-11'
|
378
|
-
todate='2020-02-05'
|
379
|
-
price=ts_price_stock(ticker,fromdate,todate)
|
380
|
-
|
381
|
-
#==============================================================================
|
382
|
-
def ts_price_index(ticker,fromdate,todate):
|
383
|
-
"""
|
384
|
-
功能:从tushare数据源获得指数行情数据
|
385
|
-
输入:
|
386
|
-
ticker: 大陆指数代码,上交所后缀为.SS,深交所后缀为.SZ
|
387
|
-
fromdate:开始日期,格式YYYY-MM-DD
|
388
|
-
todate:结束日期
|
389
|
-
输出:
|
390
|
-
行情数据,df,雅虎格式
|
391
|
-
"""
|
392
|
-
#设置tushare的token
|
393
|
-
pro=ts_token()
|
394
|
-
|
395
|
-
#检查期间合理性
|
396
|
-
result,start,end=check_period(fromdate,todate)
|
397
|
-
if result is None:
|
398
|
-
print("Error #1(ts_price_stock): incorrect date or invalid period!")
|
399
|
-
return None
|
400
|
-
|
401
|
-
#转换输入日期
|
402
|
-
tsstart=cvtdate_yahootots(fromdate)
|
403
|
-
tsend=cvtdate_yahootots(todate)
|
404
|
-
#转换指数代码
|
405
|
-
tsticker=cvtticker_yahootots(ticker)
|
406
|
-
|
407
|
-
#抓取指数日行情
|
408
|
-
price=pro.index_daily(ts_code=tsticker,start_date=tsstart,end_date=tsend)
|
409
|
-
|
410
|
-
#升序排列
|
411
|
-
price.sort_values('trade_date',ascending=True,inplace=True)
|
412
|
-
|
413
|
-
#转换日期格式,设置日期索引
|
414
|
-
import pandas as pd
|
415
|
-
price['date']=pd.to_datetime(price['trade_date'])
|
416
|
-
price.set_index('date',inplace=True)
|
417
|
-
|
418
|
-
#修改列名
|
419
|
-
price.rename(columns= \
|
420
|
-
{'ts_code':'Ticker','open':'Open','high':'High','low':'Low', \
|
421
|
-
'close':'Close','vol':'Volume'},inplace=True)
|
422
|
-
price['Ticker']=ticker
|
423
|
-
|
424
|
-
#删除不需要的列
|
425
|
-
price.drop(['trade_date','pre_close','change','pct_chg','amount'], \
|
426
|
-
axis=1,inplace=True)
|
427
|
-
|
428
|
-
return price
|
429
|
-
|
430
|
-
if __name__ =="__main__":
|
431
|
-
ticker='000300.SS'
|
432
|
-
fromdate='2019-12-11'
|
433
|
-
todate='2020-02-05'
|
434
|
-
price=ts_price_index(ticker,fromdate,todate)
|
435
|
-
|
436
|
-
#==============================================================================
|
437
|
-
def ts_nav_etf(etf_code,fromdate,todate):
|
438
|
-
"""
|
439
|
-
功能:从tushare获得etf每日净值数据,便于与二级市场行情比较套利空间
|
440
|
-
输入:
|
441
|
-
etf_code: 大陆etf代码,雅虎格式,上交所后缀为.SS,深交所后缀为.SZ
|
442
|
-
fromdate:开始日期,格式YYYY-MM-DD
|
443
|
-
todate:结束日期
|
444
|
-
输出:
|
445
|
-
行情数据,df,升序排列
|
446
|
-
"""
|
447
|
-
#设置tushare的token
|
448
|
-
pro=ts_token()
|
449
|
-
|
450
|
-
#检查期间合理性
|
451
|
-
result,start,end=check_period(fromdate,todate)
|
452
|
-
if result is None:
|
453
|
-
print("Error #1(ts_price_stock): incorrect date or invalid period!")
|
454
|
-
return None
|
455
|
-
|
456
|
-
#转换输入日期格式
|
457
|
-
tsstart=cvtdate_yahootots(fromdate)
|
458
|
-
tsend=cvtdate_yahootots(todate)
|
459
|
-
#转换etf代码
|
460
|
-
tsticker=cvtticker_yahootots(etf_code)
|
461
|
-
|
462
|
-
#抓取每日etf净值行情
|
463
|
-
price=pro.fund_nav(ts_code=tsticker)
|
464
|
-
|
465
|
-
#升序排列
|
466
|
-
price.sort_values('end_date',ascending=True,inplace=True)
|
467
|
-
|
468
|
-
#转换日期格式,设置日期索引
|
469
|
-
import pandas as pd
|
470
|
-
price['date']=pd.to_datetime(price['end_date'])
|
471
|
-
price.set_index('date',inplace=True)
|
472
|
-
|
473
|
-
#修改列名
|
474
|
-
price.rename(columns={'ts_code':'Ticker','unit_nav':'Unit-nav', \
|
475
|
-
'adj_nav':'Adj-nav'},inplace=True)
|
476
|
-
price['Ticker']=etf_code
|
477
|
-
|
478
|
-
#提取需要的列
|
479
|
-
nav=price[['Ticker','Unit-nav']].copy()
|
480
|
-
|
481
|
-
#去掉日期范围以外的数据
|
482
|
-
nav1=nav[nav.index >= start]
|
483
|
-
nav2=nav1[nav1.index <= end]
|
484
|
-
|
485
|
-
return nav2
|
486
|
-
|
487
|
-
if __name__ =="__main__":
|
488
|
-
etf_code='510050.SS'
|
489
|
-
fromdate='2019-12-11'
|
490
|
-
todate='2020-02-01'
|
491
|
-
etf_nav=ts_nav_etf(etf_code,fromdate,todate)
|
492
|
-
|
493
|
-
#==============================================================================
|
494
|
-
def get_price_etf(etf_code,index_code,fromdate,todate):
|
495
|
-
"""
|
496
|
-
功能:获得etf及其对应指数日行情,便于对比业绩
|
497
|
-
Parameters
|
498
|
-
----------
|
499
|
-
etf_code : ETF代码,雅虎格式
|
500
|
-
index_code : 指数代码,雅虎格式
|
501
|
-
fromdate : 开始日期,雅虎格式
|
502
|
-
todate : 截止日期,雅虎格式
|
503
|
-
Returns
|
504
|
-
-------
|
505
|
-
日行情价格,etf与指数数据,升序排列
|
506
|
-
"""
|
507
|
-
|
508
|
-
#检查期间合理性
|
509
|
-
result,start,end=check_period(fromdate,todate)
|
510
|
-
if result is None:
|
511
|
-
print("Error #1(get_price_etf): incorrect date or invalid period!")
|
512
|
-
return None
|
513
|
-
|
514
|
-
#从雅虎财经获得etf日行情
|
515
|
-
etf=get_price(etf_code,fromdate,todate)
|
516
|
-
try: etf['Ticker']=etf_code
|
517
|
-
except:
|
518
|
-
print("Error #2(get_price_etf): data not found for",etf_code)
|
519
|
-
return None,None
|
520
|
-
|
521
|
-
#去掉日期范围以外的数据
|
522
|
-
etf1=etf[etf.index >= start]
|
523
|
-
etf2=etf1[etf1.index <= end]
|
524
|
-
|
525
|
-
#获得指数日行情
|
526
|
-
flag1=index_code[0]
|
527
|
-
flag2=index_code[-3:]
|
528
|
-
if (flag1 != '^') and ((flag2 == '.SS') or (flag2 == '.SZ')):
|
529
|
-
#从tushare获得中国大陆指数行情
|
530
|
-
index=ts_price_index(index_code,fromdate,todate)
|
531
|
-
else:
|
532
|
-
#从雅虎财经获得非中国大陆指数行情
|
533
|
-
index=get_price(index_code,fromdate,todate)
|
534
|
-
|
535
|
-
try: index['Ticker']=index_code
|
536
|
-
except:
|
537
|
-
print("Error #3(get_price_etf): data not found for",index_code)
|
538
|
-
return None,None
|
539
|
-
|
540
|
-
#去掉日期范围以外的数据
|
541
|
-
index1=index[index.index >= start]
|
542
|
-
index2=index1[index1.index <= end]
|
543
|
-
|
544
|
-
return etf2,index2
|
545
|
-
|
546
|
-
if __name__ =="__main__":
|
547
|
-
etf_code='510050.SS'
|
548
|
-
index_code='000016.SS'
|
549
|
-
fromdate='2019-12-11'
|
550
|
-
todate='2020-02-05'
|
551
|
-
etf_price,index_price=get_price_etf(etf_code,index_code,fromdate,todate)
|
552
|
-
|
553
|
-
#==============================================================================
|
554
|
-
def compare_price_etf(etf_price,index_price,fromdate,todate):
|
555
|
-
"""
|
556
|
-
功能:比较etf与对应指数的收盘价趋势,采用双坐标轴
|
557
|
-
输入:
|
558
|
-
etf_price:抓取到的etf价格序列
|
559
|
-
index_price:抓取到的指数价格序列
|
560
|
-
fromdate/todate:开始/结束日期
|
561
|
-
输出:折线图,双坐标轴,避免数量级差异过大的问题
|
562
|
-
"""
|
563
|
-
#检查期间合理性
|
564
|
-
result,start,end=check_period(fromdate,todate)
|
565
|
-
if result is None:
|
566
|
-
print("Error #1(compare_price_etf): incorrect date or invalid period!")
|
567
|
-
return
|
568
|
-
|
569
|
-
#检查价格序列
|
570
|
-
if (etf_price is None) or (index_price is None):
|
571
|
-
print("Error #2(compare_price_etf): incorrect input for either etf or index")
|
572
|
-
return
|
573
|
-
|
574
|
-
#提取收盘价
|
575
|
-
p1=etf_price['Close']
|
576
|
-
try: ticker1=etf_price['Ticker'][0]
|
577
|
-
except:
|
578
|
-
print("Error #2(compare_price_etf): no data available for the etf!")
|
579
|
-
return
|
580
|
-
p2=index_price['Close']
|
581
|
-
try: ticker2=index_price['Ticker'][0]
|
582
|
-
except:
|
583
|
-
print("Error #3(compare_price_etf): no data available for the index!")
|
584
|
-
return
|
585
|
-
|
586
|
-
#去掉比起始日期更早的样本
|
587
|
-
p1b=p1[p1.index >= start]
|
588
|
-
p2b=p2[p2.index >= start]
|
589
|
-
#去掉比结束日期更晚的样本
|
590
|
-
p1c=p1b[p1b.index <= end]
|
591
|
-
p2c=p2b[p2b.index <= end]
|
592
|
-
|
593
|
-
#绘制折线图,双坐标轴
|
594
|
-
import matplotlib.pyplot as plt
|
595
|
-
import matplotlib.dates as mdates
|
596
|
-
fig = plt.figure()
|
597
|
-
ax = fig.add_subplot(111)
|
598
|
-
ax.plot(p1c, '-', label = ticker1, lw=3)
|
599
|
-
|
600
|
-
#自动优化x轴标签,格式化时间轴标注
|
601
|
-
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
|
602
|
-
plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
|
603
|
-
|
604
|
-
#建立第二y轴
|
605
|
-
ax2 = ax.twinx()
|
606
|
-
ax2.plot(p2c, 'r:.', label = ticker2, lw=3)
|
607
|
-
#fig.legend(loc='best', bbox_to_anchor=(1,1), bbox_transform=ax.transAxes)
|
608
|
-
#fig.legend(loc='best', bbox_transform=ax.transAxes)
|
609
|
-
#fig.legend(loc='best')
|
610
|
-
|
611
|
-
plt.title("Sync of ETF Price and Index Based", fontsize=15)
|
612
|
-
ax.set_xlabel("\nSource: Yahoo Finance", fontsize=13)
|
613
|
-
ax.set_ylabel(ticker1)
|
614
|
-
ax.legend(loc='upper center')
|
615
|
-
ax2.legend(loc='lower center')
|
616
|
-
ax2.set_ylabel(ticker2)
|
617
|
-
fig.show()
|
618
|
-
|
619
|
-
return
|
620
|
-
|
621
|
-
if __name__ =="__main__":
|
622
|
-
etf_code='510050.SS'
|
623
|
-
index_code='000016.SS'
|
624
|
-
fromdate='2019-7-1'
|
625
|
-
todate='2020-02-05'
|
626
|
-
etf_price,index_price=get_price_etf(etf_code,index_code,fromdate,todate)
|
627
|
-
compare_price_etf(etf_price,index_price,'2019-7-1','2019-12-1')
|
628
|
-
compare_price_etf(etf_price,index_price,'2019-7-1','2019-8-1')
|
629
|
-
|
630
|
-
#==============================================================================
|
631
|
-
def get_price_nav_etf(etf_code,fromdate,todate):
|
632
|
-
"""
|
633
|
-
功能:获得etf每日二级市场行情以及净值,便于寻找套利机会,限大陆etf
|
634
|
-
Parameters
|
635
|
-
----------
|
636
|
-
etf_code : ETF代码,雅虎格式
|
637
|
-
fromdate : 开始日期,雅虎格式
|
638
|
-
todate : 截止日期,雅虎格式
|
639
|
-
Returns
|
640
|
-
-------
|
641
|
-
etf日二级市场行情价格,etf每日净值,升序排列
|
642
|
-
"""
|
643
|
-
|
644
|
-
#检查期间合理性
|
645
|
-
result,start,end=check_period(fromdate,todate)
|
646
|
-
if result is None:
|
647
|
-
print("Error #1(get_price_nav_etf): incorrect date or invalid period!")
|
648
|
-
return None
|
649
|
-
|
650
|
-
#从雅虎财经获得etf日行情
|
651
|
-
etf=get_price(etf_code,fromdate,todate)
|
652
|
-
etf['Ticker']=etf_code
|
653
|
-
|
654
|
-
#去掉日期范围以外的数据
|
655
|
-
etf1=etf[etf.index >= start]
|
656
|
-
etf2=etf1[etf1.index <= end]
|
657
|
-
|
658
|
-
#获得大陆etf每日净值
|
659
|
-
nav2=ts_nav_etf(etf_code,fromdate,todate)
|
660
|
-
|
661
|
-
return etf2,nav2
|
662
|
-
|
663
|
-
if __name__ =="__main__":
|
664
|
-
etf_code='510050.SS'
|
665
|
-
fromdate='2019-1-1'
|
666
|
-
todate='2020-02-05'
|
667
|
-
etf_price,etf_nav=get_price_nav_etf(etf_code,fromdate,todate)
|
668
|
-
|
669
|
-
#==============================================================================
|
670
|
-
def compare_price_nav_etf(etf_price,etf_nav,fromdate,todate):
|
671
|
-
"""
|
672
|
-
功能:比较etf二级市场行情与其净值趋势
|
673
|
-
输入:
|
674
|
-
etf_price:抓取到的etf二级市场价格序列
|
675
|
-
etf_nav:抓取到的etf净值序列
|
676
|
-
fromdate/todate:开始/结束日期
|
677
|
-
输出:折线图
|
678
|
-
"""
|
679
|
-
#检查期间合理性
|
680
|
-
result,start,end=check_period(fromdate,todate)
|
681
|
-
if result is None:
|
682
|
-
print("Error #1(compare_price_nav_etf): incorrect date or invalid period!")
|
683
|
-
return
|
684
|
-
|
685
|
-
#提取收盘价
|
686
|
-
p1=etf_price['Close']
|
687
|
-
try: ticker1=etf_price['Ticker'][0]+" price"
|
688
|
-
except:
|
689
|
-
print("Error #2(compare_price_nav_etf): no data available for the etf price!")
|
690
|
-
return
|
691
|
-
p2=etf_nav['Unit-nav']
|
692
|
-
try: ticker2=etf_nav['Ticker'][0]+" nav"
|
693
|
-
except:
|
694
|
-
print("Error #3(compare_price_nav_etf): no data available for the etf nav!")
|
695
|
-
return
|
696
|
-
|
697
|
-
#去掉比起始日期更早的样本
|
698
|
-
p1b=p1[p1.index >= start]
|
699
|
-
p2b=p2[p2.index >= start]
|
700
|
-
#去掉比结束日期更晚的样本
|
701
|
-
p1c=p1b[p1b.index <= end]
|
702
|
-
p2c=p2b[p2b.index <= end]
|
703
|
-
|
704
|
-
#绘制折线图
|
705
|
-
import matplotlib.pyplot as plt
|
706
|
-
import matplotlib.dates as mdates
|
707
|
-
|
708
|
-
plt.plot(p1c, '-', label = ticker1, lw=3)
|
709
|
-
plt.plot(p2c, 'r:.', label = ticker2, lw=3)
|
710
|
-
|
711
|
-
#自动优化x轴标签,格式化时间轴标注
|
712
|
-
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
|
713
|
-
plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
|
714
|
-
|
715
|
-
plt.title("ETF Arbitrage: Market Price vs. Net Asset Value", fontsize=13)
|
716
|
-
plt.xlabel("\nSource: Yahoo Finance, Sina Finance", fontsize=11)
|
717
|
-
plt.ylabel('Unit price/net asset value')
|
718
|
-
plt.legend(loc='best')
|
719
|
-
plt.show()
|
720
|
-
|
721
|
-
return
|
722
|
-
|
723
|
-
if __name__ =="__main__":
|
724
|
-
etf_code='510050.SS'
|
725
|
-
fromdate='2019-8-1'
|
726
|
-
todate='2019-9-1'
|
727
|
-
etf_price,etf_nav=get_price_nav_etf(etf_code,fromdate,todate)
|
728
|
-
compare_price_nav_etf(etf_price,etf_nav,fromdate,todate)
|
729
|
-
|
730
|
-
#==============================================================================
|
731
|
-
def compare_return_nav_etf(etf_price,etf_nav,fromdate,todate):
|
732
|
-
"""
|
733
|
-
功能:比较etf二级市场行情与其净值的收益率
|
734
|
-
输入:
|
735
|
-
etf_price:抓取到的etf二级市场价格序列
|
736
|
-
etf_nav:抓取到的etf净值序列
|
737
|
-
fromdate/todate:开始/结束日期
|
738
|
-
输出:收益率折线图
|
739
|
-
"""
|
740
|
-
#检查期间合理性
|
741
|
-
result,start,end=check_period(fromdate,todate)
|
742
|
-
if result is None:
|
743
|
-
print("Error #1(compare_return_nav_etf): incorrect date or invalid period!")
|
744
|
-
return
|
745
|
-
|
746
|
-
#提取收盘价的收益率
|
747
|
-
import pandas as pd
|
748
|
-
cp=etf_price['Close']
|
749
|
-
r1=cp.pct_change()
|
750
|
-
r1df=pd.DataFrame(r1)
|
751
|
-
r1df.columns=['ret']
|
752
|
-
r1df['ret%']=round(r1df['ret']*100.0,2)
|
753
|
-
p1=r1df['ret%']
|
754
|
-
try: ticker1=etf_price['Ticker'][0]+" market return"
|
755
|
-
except:
|
756
|
-
print("Error #2(compare_return_nav_etf): no data available for the etf price!")
|
757
|
-
return
|
758
|
-
|
759
|
-
nv=etf_nav['Unit-nav']
|
760
|
-
r2=nv.pct_change()
|
761
|
-
r2df=pd.DataFrame(r2)
|
762
|
-
r2df.columns=['ret']
|
763
|
-
r2df['ret%']=round(r2df['ret']*100.0,2)
|
764
|
-
p2=r2df['ret%']
|
765
|
-
try: ticker2=etf_nav['Ticker'][0]+" nav gain"
|
766
|
-
except:
|
767
|
-
print("Error #3(compare_return_nav_etf): no data available for the etf nav!")
|
768
|
-
return
|
769
|
-
|
770
|
-
#去掉比起始日期更早的样本
|
771
|
-
p1b=p1[p1.index >= start]
|
772
|
-
p2b=p2[p2.index >= start]
|
773
|
-
#去掉比结束日期更晚的样本
|
774
|
-
p1c=p1b[p1b.index <= end]
|
775
|
-
p2c=p2b[p2b.index <= end]
|
776
|
-
|
777
|
-
#绘制折线图
|
778
|
-
import matplotlib.pyplot as plt
|
779
|
-
import matplotlib.dates as mdates
|
780
|
-
|
781
|
-
plt.plot(p1c, '-', label = ticker1, lw=3)
|
782
|
-
plt.plot(p2c, 'r:.', label = ticker2, lw=3)
|
783
|
-
|
784
|
-
#纵轴零线
|
785
|
-
plt.axhline(y=0.0,color='green',linestyle='--')
|
786
|
-
|
787
|
-
#自动优化x轴标签,格式化时间轴标注
|
788
|
-
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
|
789
|
-
plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
|
790
|
-
|
791
|
-
plt.title("ETF Arbitrage: Market Return vs. Nav Gain", fontsize=13)
|
792
|
-
plt.xlabel("\nSource: Yahoo Finance, Sina Finance", fontsize=11)
|
793
|
-
plt.ylabel('Market return/nav gain(%)')
|
794
|
-
plt.legend(loc='best')
|
795
|
-
plt.show()
|
796
|
-
|
797
|
-
return
|
798
|
-
|
799
|
-
if __name__ =="__main__":
|
800
|
-
etf_code='510050.SS'
|
801
|
-
fromdate='2019-8-1'
|
802
|
-
todate='2019-9-1'
|
803
|
-
etf_price,etf_nav=get_price_nav_etf(etf_code,fromdate,todate)
|
804
|
-
compare_return_nav_etf(etf_price,etf_nav,fromdate,todate)
|
805
|
-
#==============================================================================
|
806
|
-
|
807
|
-
#==============================================================================
|
808
|
-
|
809
|
-
#==============================================================================
|
810
|
-
def get_price_ts(ticker,fromdate,todate,asset='E',freq='D'):
|
811
|
-
"""
|
812
|
-
功能:从tushare数据源获得交易数据
|
813
|
-
|
814
|
-
Parameters
|
815
|
-
----------
|
816
|
-
ticker : 资产代码
|
817
|
-
包括股票、指数、数字货币、期货、基金、期货、可转债.
|
818
|
-
fromdate : 开始日期
|
819
|
-
格式:YYYY-MM-DD. 注意tushare的格式为YYYYMMDD
|
820
|
-
todate : 截止日期
|
821
|
-
格式:YYYY-MM-DD.
|
822
|
-
asset : 资产类别, optional
|
823
|
-
包括股票(E)、沪深指数(I)、数字货币(C)、期货(FT)、基金(FD)、期权(O)、
|
824
|
-
可转债(CB). The default is 'E'.
|
825
|
-
freq : 频率, optional
|
826
|
-
数据频度:支持分钟(min)/日(D)/周(W)/月(M)K线,
|
827
|
-
其中1min表示1分钟(类推1/5/15/30/60分钟),默认D.
|
828
|
-
Returns
|
829
|
-
-------
|
830
|
-
价格行情,数据框,升序排列.
|
831
|
-
"""
|