siat 2.14.2__py3-none-any.whl → 3.0.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.
siat/security_prices.py CHANGED
@@ -19,200 +19,238 @@ import pandas as pd
19
19
 
20
20
  #==============================================================================
21
21
  #==============================================================================
22
- def get_price(ticker,fromdate,todate,adj=False,source='auto'):
23
- """
24
- 套壳函数get_prices,为保持兼容
25
- """
26
- df=get_prices(ticker,fromdate,todate,adj=adj,source=source)
27
-
28
- df2=remove_timezone(df)
29
- return df2
30
- #==============================================================================
31
22
  if __name__=='__main__':
32
- ticker='AAPL'
33
- fromdate='2011-1-1'
34
- todate='2020-12-31'
35
- retry_count=3
36
- pause=1
23
+ ticker="430047.BJ"
24
+ ticker="430047.BJ"
25
+ ticker="600519.SS"
26
+ ticker="000858.SZ"
27
+ ticker_type='auto'
37
28
 
38
- ticker='ABCD'
29
+ ticker="sz169107" #LOF基金
30
+ ticker="sh510050" #ETF基金
39
31
 
40
- ticker=['AAPL','MSFT']
41
- ticker=['AAPL','MSFT','ABCD']
42
32
 
43
- ticker=['600011.SS']
44
- fromdate='2020-1-1'
45
- todate='2020-6-30'
33
+ ticker="sh010504" #国债
34
+ ticker_type='bond'
35
+
36
+ ticker='801002.SW'
37
+ ticker_type='auto'
38
+
39
+ ticker={'Market':('China','000001.SS','白酒组合'),'600519':0.4,'000858':0.6}
40
+
41
+ fromdate="2024-1-1"
42
+ todate="2024-4-1"
43
+ adj=False
44
+ retry_count=3
45
+ pause=1
46
+ source='auto'
47
+
48
+ prices=get_prices_all(ticker,fromdate,todate,ticker_type=ticker_type)
46
49
 
47
- def upper_ticker(ticker):
50
+ def get_prices_all(ticker,fromdate,todate,adj=False,source='auto',ticker_type='auto'):
48
51
  """
49
- 功能:改成大写,字符串或列表
52
+ 功能:多个证券(股票,指数,基金,债券),或投资组合(可含股票和/或债券)
53
+ ticker_type:若为'auto'则基金优先于债券(代码重合时),亦可为列表分别指定优先抓取类型。
54
+ 'stock', 'fund', 'bond','swindex','portfolio',不足部分自动补充为'auto'
55
+ 其中,'auto'/'stock'/'fund'优先抓取指数、股票和基金;'bond'优先抓取债券;
56
+ 'swindex'优先抓取申万行业指数
57
+
58
+ 注意:未经充分测试!!!
50
59
  """
51
- if isinstance(ticker,str):
52
- return ticker.upper()
53
- elif isinstance(ticker,list):
54
- tlist=[]
55
- for t in ticker:
56
- try:
57
- tupper=t.upper()
58
- except:
59
- tupper=t
60
- tlist=tlist+[tupper]
61
- return tlist
62
60
 
63
- if __name__=='__main__':
64
- upper_ticker('000001.ss')
65
- upper_ticker(['000001.ss','aapl'])
61
+ #补足ticker_type
62
+ if isinstance(ticker_type,str):
63
+ ticker_type_list=[ticker_type]
64
+
65
+ if isinstance(ticker,str) or isinstance(ticker,dict):
66
+ ticker_list=[ticker]
67
+
68
+ ticker_num=len(ticker_list)
69
+ ticker_type_len=len(ticker_type_list)
70
+ if ticker_num > ticker_type_len:
71
+ ticker_type_list=ticker_type_list + ['auto'*(ticker_type_len - ticker_num)]
72
+
73
+ #单个证券的特殊处理
74
+ if ticker_num == 1:
75
+ #普通证券
76
+ if isinstance(ticker_list[0],str):
77
+ df=get_prices(ticker_list[0],fromdate,todate,adj=adj,source=source,ticker_type=ticker_type_list[0])
78
+
79
+ #投资组合
80
+ if isinstance(ticker_list[0],dict):
81
+ _,_,tickerlist,sharelist=decompose_portfolio(ticker_list[0])
82
+ df=get_price_portfolio(tickerlist,sharelist,fromdate,todate,adj=adj, \
83
+ source=source,ticker_type='bond')
84
+ return df
66
85
 
67
- ticker=['000001.ss','aapl']
68
- ticker=upper_ticker(ticker)
86
+ #多个证券
87
+ df=pd.DataFrame()
88
+ for t in ticker_list:
89
+ pos=ticker_list.index(t)
90
+ tt=ticker_type_list[pos]
91
+
92
+ #普通证券
93
+ if isinstance(t,str):
94
+ dft=get_prices(t,fromdate,todate,adj=adj,source=source,ticker_type=tt)
95
+
96
+ #投资组合
97
+ if isinstance(t,dict):
98
+ _,_,tickerlist,sharelist=decompose_portfolio(t)
99
+ dft=get_price_portfolio(tickerlist,sharelist,fromdate,todate,adj=adj, \
100
+ source=source,ticker_type='bond')
101
+ t=portfolio_name(t)
102
+
103
+ columns=create_tuple_for_columns(dft,t)
104
+ dft.columns=pd.MultiIndex.from_tuples(columns)
105
+
106
+ if len(df)==0:
107
+ df=dft
108
+ else:
109
+ #合并
110
+ df=pd.merge(df,dft,how='outer',left_index=True,right_index=True)
69
111
 
112
+ return df
113
+
114
+ #==============================================================================
115
+ if __name__=='__main__':
116
+ ticker="430047.BJ"
70
117
  ticker="430047.BJ"
71
- fromdate="2022-11-1"
72
- todate="2022-12-15"
118
+ ticker="600519.SS"
119
+ ticker="000858.SZ"
120
+ ticker_type='auto'
121
+
122
+ ticker="sz169107" #LOF基金
123
+ ticker="sh510050" #ETF基金
124
+
125
+ ticker="sh010504" #国债
126
+ ticker_type='bond'
127
+
128
+ ticker='801002.SW'
129
+ ticker_type='auto'
130
+
131
+ ticker=['600519','000858']
132
+ ticker_type='bond'
133
+
134
+ fromdate="2024-1-1"
135
+ todate="2024-4-1"
73
136
  adj=False
74
137
  retry_count=3
75
138
  pause=1
76
-
77
- prices=get_prices(ticker,fromdate,todate)
139
+ source='auto'
78
140
 
79
- """
80
- 北交所股票以43开头或83、87、88开头,因为新三板(基础层、创新层)股票代码一般为43、83、87开头。
81
- 沪市普通A股股票代码是以60开头,沪市科创板股票代码是以688开头。
82
- 深市普通A股票代码是以00开头,深市创业板股票代码以300开头。
83
- """
141
+ prices=get_prices(ticker,fromdate,todate,ticker_type=ticker_type)
84
142
 
85
143
  def get_prices(ticker,fromdate,todate,adj=False,source='auto', \
86
- retry_count=3,pause=1):
144
+ retry_count=3,pause=1,ticker_type='auto'):
87
145
  """
88
146
  功能:抓取证券价格,pandas_datareader + yfinance + akshare
89
147
  输出:指定收盘价格序列,日期升序排列
90
- ticker: 股票代码或其列表。大陆股票代码加上后缀.SZ或.SS,港股代码去掉前导0加后缀.HK
148
+ ticker: 证券代码或其列表。大陆证券代码加上后缀.SZ或.SS或.BJ,港股代码去掉前导0加后缀.HK
91
149
  start: 样本开始日期,yyyy-mm-dd
92
150
  end: 样本结束日期,既可以是今天日期,也可以是一个历史日期
93
- retry_count:网络失败时的重试次数
94
- pause:每次重试前的间隔秒数
151
+ retry_count:网络失败时的重试次数,仅用于雅虎
152
+ pause:每次重试前的间隔秒数,仅用于雅虎
95
153
  """
96
- print(" Searching prices for corresponding securities, please wait ...")
97
- ticker=upper_ticker(ticker)
98
154
 
99
155
  #检查日期期间的合理性
100
156
  result,start,end=check_period(fromdate,todate)
101
157
  if not result:
102
158
  print(" #Error(get_prices): invalid date period from",fromdate,'to',todate)
103
159
  return None
160
+
161
+ print(" Searching prices of security, please wait ...")
162
+ ticker=tickers_cvt2yahoo(ticker)
104
163
 
105
- """
106
- #尝试pandas_datareader+FRED(仅对部分国外市场指数有效)
107
- if ticker[0]=='^':
108
- print(" Trying to capture info from fred for",ticker)
109
- prices=get_index_fred(ticker,start,end)
110
- if prices is None:
111
- print(" #Warning(get_prices): info retrieving failed from fred for",ticker)
112
- else:
113
- if len(prices)==0:
114
- print(" #Warning(get_prices): zero record found in fred for",ticker)
115
- else:
116
- return prices
117
- """
118
164
  if source in ['auto']:
119
165
  #尝试AkShare+Sina+EM(新浪,对中国内地股票、港股和美股有效,但不包括国外市场指数)
120
- #printmsg=str(ticker)+" from "+fromdate+' to '+todate
121
- print(" Trying to capture prices from sina/EM for",ticker)
166
+ print(" Trying to capture prices from sina/EM ... ...")
122
167
  try:
123
- #prices=get_prices_ak(ticker,fromdate,todate,adjust=adj)
124
- prices=get_prices_ak(ticker,fromdate,todate)
168
+ prices=get_prices_ak(ticker,fromdate,todate,ticker_type=ticker_type) #支持多个证券
125
169
  except:
126
- print(" #Warning(get_prices): info retrieving failed from sina/EM for",ticker)
127
- #return None
170
+ print(" #Warning(get_prices): info retrieving failed from sina/EM")
128
171
  else:
129
172
  if prices is None:
130
- print(" #Warning(get_prices): info not found from sina/EM for",ticker)
173
+ print(" #Warning(get_prices): info not found from sina/EM")
131
174
  else:
132
175
  num=len(prices)
133
176
  if num==0:
134
- print(" #Warning(get_prices): zero record found in sina/EM for",ticker)
177
+ print(" #Warning(get_prices): security may suspend trading or already expired")
178
+ return prices
135
179
  else:
136
- #print(" Successfully retrieved",num,"records for",ticker)
137
180
  prices2=remove_timezone(prices)
138
- return prices2
181
+ return prices2 #找到有效数据就返回,否则继续
139
182
 
140
183
  if source in ['auto','stooq']:
141
184
  #尝试pandas_datareader+stooq(对美股、港股、欧股、国外市场指数有效,但对深交所股票无效)
142
185
  #注意stooq代码与新浪/stooq的不同
143
186
  print(" Trying to capture info from stooq for",ticker)
144
187
  try:
145
- prices=get_price_stooq(ticker,fromdate,todate)
188
+ prices=get_price_stooq(ticker,fromdate,todate) #仅支持单只证券
189
+ #prices=get_prices_stooq(ticker,fromdate,todate)?
146
190
  except:
147
- print(" #Warning(get_prices): info retrieving failed from stooq for",ticker)
148
- #return None
191
+ print(" #Warning(get_prices): info retrieving failed from stooq")
149
192
  else:
150
193
  if prices is None:
151
- print(" #Warning(get_prices): info not found from stooq for",ticker)
194
+ print(" #Warning(get_prices): info not found from stooq")
152
195
  else:
153
196
  num=len(prices)
154
197
  if num==0:
155
- print(" #Warning(get_prices): zero record found for",ticker)
198
+ print(" #Warning(get_prices): zero record found")
156
199
  else:
157
- #print(" Successfully retrieved",num,"records for",ticker)
158
200
  prices2=remove_timezone(prices)
159
- return prices2
201
+ return prices2 #找到有效数据就返回,否则继续
160
202
 
161
203
  if source in ['auto','yahoo']:
162
204
  #使用yahoo+yfinance抓取数据
163
205
  #由于雅虎无法访问,建议暂时关闭,2021-10-24
164
206
  #抓取证券(列表)价格,需要调整收盘价:yfinance优先,线程极易出错,先尝试关闭线程
165
207
  try:
166
- print(" Trying to capture info from Yahoo Finance using non-threads for",ticker)
167
- prices=get_prices_yf(ticker,start,end,threads=False)
208
+ print(" Trying to capture info from Yahoo Finance using non-threads")
209
+ prices=get_prices_yf(ticker,start,end,threads=False) #支持多个证券
168
210
  except:
169
- print(" #Warning(get_prices): retrieving using non-threads failed from yahoo for",ticker)
211
+ print(" #Warning(get_prices): retrieving using non-threads failed from yahoo")
170
212
  else:
171
213
  if prices is None:
172
- print(" #Warning(get_prices): info not found using non-threads failed from yahoo for",ticker)
214
+ print(" #Warning(get_prices): info not found using non-threads failed from yahoo")
173
215
  else:
174
216
  num=len(prices)
175
217
  if num==0:
176
- print(" #Warning(get_prices): zero record found for",ticker)
218
+ print(" #Warning(get_prices): zero record found")
177
219
  else:
178
- #print(" Successfully retrieved",num,"records for",ticker)
179
220
  prices2=remove_timezone(prices)
180
- return prices2
221
+ return prices2 #找到有效数据就返回,否则继续
181
222
 
182
223
  #抓取证券(列表)价格,需要调整收盘价:yfinance优先,尝试打开线程
183
224
  try:
184
- print(" Trying to capture info from Yahoo Finance using threads for",ticker)
185
- prices=get_prices_yf(ticker,start,end,threads=True)
225
+ print(" Trying to capture info from Yahoo Finance using threads")
226
+ prices=get_prices_yf(ticker,start,end,threads=True) #支持多个证券
186
227
  except:
187
- print(" #Warning(get_prices): retrieving using threads failed from yahoo for",ticker)
228
+ print(" #Warning(get_prices): retrieving using threads failed from yahoo")
188
229
  else:
189
230
  if prices is None:
190
- print(" #Warning(get_prices): info not found using non-threads failed from yahoo for",ticker)
231
+ print(" #Warning(get_prices): info not found using non-threads failed from yahoo")
191
232
  else:
192
233
  num=len(prices)
193
234
  if num==0:
194
- print(" #Warning(get_prices): zero record found for",ticker)
235
+ print(" #Warning(get_prices): zero record found")
195
236
  else:
196
- #print(" Successfully retrieved",num,"records for",ticker)
197
237
  prices2=remove_timezone(prices)
198
- return prices2
238
+ return prices2 #找到有效数据就返回,否则继续
199
239
 
200
- #抓取证券(列表)价格,不考虑是否需要调整收盘价:pandas_datareader
201
- #由于雅虎财经当前无法访问,建议本段停用
202
- #由于雅虎无法访问,暂时关闭,2021-10-24
240
+ #抓取证券(列表)价格,不考虑是否需要调整收盘价:pandas_datareader,使用雅虎
203
241
  try:
204
- print(" Trying to capture info from Yahoo Finance in traditional process for",ticker)
242
+ print(" Trying to capture info from Yahoo Finance traditionally")
205
243
  prices=get_prices_yahoo(ticker,start,end,retry_count=retry_count,pause=pause)
206
244
  except:
207
- print(" #Warning(get_prices): info retrieving failed from Yahoo Finance in traditional process for",ticker)
245
+ print(" #Warning(get_prices): info retrieving failed from Yahoo traditionally")
208
246
  return None
209
247
  else:
210
248
  if prices is None:
211
- print(" #Warning(get_prices): info not found from Yahoo Finance in traditional process for",ticker)
249
+ print(" #Warning(get_prices): info not found from Yahoo traditionally")
212
250
  else:
213
251
  num=len(prices)
214
252
  if num==0:
215
- print(" #Warning(get_prices): zero record found for",ticker)
253
+ print(" #Warning(get_prices): zero record found from Yahoo traditionally")
216
254
  else:
217
255
  #print(" Successfully retrieved",num,"records for",ticker)
218
256
  prices2=remove_timezone(prices)
@@ -220,9 +258,8 @@ def get_prices(ticker,fromdate,todate,adj=False,source='auto', \
220
258
 
221
259
  #若能够抓取到数据均已提前返回,到达此处时表面未能抓取到任何数据
222
260
  print(" #Warning(get_prices): tried everything but nothing found for",ticker)
223
- return None
224
-
225
261
 
262
+ return None
226
263
 
227
264
  if __name__=='__main__':
228
265
  get_prices('INTC','2021-11-1','2021-11-5')
@@ -234,6 +271,18 @@ if __name__=='__main__':
234
271
  df6=get_prices(['00988.HK','000858.SZ'],'2021-11-1','2021-11-5')
235
272
  df7=get_prices(['INTL','MSFT','00988.HK','000858.SZ'],'2021-11-1','2021-11-5')
236
273
 
274
+ #==============================================================================
275
+
276
+ def get_price(ticker,fromdate,todate,adj=False,source='auto',ticker_type='auto'):
277
+ """
278
+ 套壳函数get_prices,为保持兼容
279
+ """
280
+ df=get_prices(ticker,fromdate,todate,adj=adj,source=source,ticker_type=ticker_type)
281
+
282
+ df2=remove_timezone(df)
283
+
284
+ return df2
285
+
237
286
  #==============================================================================
238
287
  if __name__ =="__main__":
239
288
  ticker="BMW.DE"
@@ -293,8 +342,7 @@ if __name__=='__main__':
293
342
  todate='2022-12-15'
294
343
  adjust=''
295
344
 
296
- #在common中定义
297
- #SUFFIX_LIST_CN=['SS','SZ','BJ','NQ']
345
+ #在common中定义SUFFIX_LIST_CN
298
346
 
299
347
  def get_price_ak_em(ticker,fromdate,todate,adjust=''):
300
348
  """
@@ -368,9 +416,9 @@ def get_price_ak_em(ticker,fromdate,todate,adjust=''):
368
416
 
369
417
  num=len(df1)
370
418
  if num > 0:
371
- print(" Successfully retrieved",num,"records for",ticker)
419
+ print(" Successfully retrieved",num,"records for",ticker,ticker_name(ticker,ticker_type))
372
420
  else:
373
- print(" Sorry, no records retrieved for",ticker)
421
+ print(" Sorry, no records retrieved for",ticker,ticker_name(ticker,ticker_type))
374
422
 
375
423
  return df1
376
424
 
@@ -393,7 +441,7 @@ def cvt_stooq_suffix(symbol):
393
441
  """
394
442
  import pandas as pd
395
443
  suffix=pd.DataFrame([
396
- ['SS','CN'], ['SZ','CN'], ['T','JP'],
444
+ ['SS','CN'], ['SH','CN'], ['SZ','CN'], ['BJ','CN'], ['T','JP'],
397
445
 
398
446
  ], columns=['yahoo','stooq'])
399
447
 
@@ -414,10 +462,11 @@ def cvt_stooq_symbol(symbol):
414
462
  """
415
463
  映射雅虎指数符号至stooq指数符号
416
464
  输入:雅虎指数符号。输出:stooq指数符号
465
+ 注意:^IXIC/^NDQ是纳斯达克综合指数,^NDX是纳斯达克100指数
417
466
  """
418
467
  import pandas as pd
419
468
  suffix=pd.DataFrame([
420
- ['^GSPC','^SPX'], ['^IXIC','^NDQ'], ['^IXIC','^NDX'],
469
+ ['^GSPC','^SPX'], ['^IXIC','^NDQ'],
421
470
  ['^RUT','QR.F'],
422
471
  ['000001.SS','^SHC'],
423
472
  ['^N225','^NKX'], ['^TWII','^TWSE'], ['^KS11','^KOSPI'],
@@ -448,7 +497,7 @@ def cvt_stooq_ticker(ticker):
448
497
  """
449
498
  映射雅虎证券符号至stooq证券符号
450
499
  输入:雅虎证券符号。输出:stooq证券符号
451
- 局限:无法处理深交所股票代码!!!!!
500
+ 局限:无法处理深交所股票代码!stooq里没有深交所股票
452
501
  """
453
502
  #直接转换
454
503
  result,ticker_stooq=cvt_stooq_symbol(ticker)
@@ -496,6 +545,8 @@ if __name__=='__main__':
496
545
  ticker='TRBNCN.M'
497
546
  ticker='RSAYCN.M'
498
547
 
548
+ ticker=['AAPL','MSFT']
549
+
499
550
  start='2023-1-1'
500
551
  end='2024-2-19'
501
552
 
@@ -503,7 +554,7 @@ if __name__=='__main__':
503
554
 
504
555
  def get_price_stooq(ticker,start,end):
505
556
  """
506
- 抓取股价
557
+ 从stooq抓取单个股价
507
558
  """
508
559
  #转换证券代码
509
560
  ticker2=cvt_stooq_ticker(ticker)
@@ -535,7 +586,7 @@ def get_price_stooq(ticker,start,end):
535
586
  ticker2 = ".".join([ticker2, 'US']) #若为空尝试当作美股代码处理,挽救第二次
536
587
  prices=web.DataReader(ticker2,start=start,end=end,data_source='stooq')
537
588
  else:
538
- print(" Sorry, zero records found from stooq for",ticker,"from",start,'to',end)
589
+ #print(" Sorry, zero records found from stooq for",ticker,"from",start,'to',end)
539
590
  return None
540
591
 
541
592
  prices.sort_index(axis=0, ascending=True, inplace=True)
@@ -546,14 +597,17 @@ def get_price_stooq(ticker,start,end):
546
597
  prices['ticker']=str(ticker)
547
598
  prices['footnote']=''
548
599
 
600
+ if 'Volume' not in list(prices):
601
+ prices['Volume']=0
602
+
549
603
  _,start1,end1=check_period(start,end)
550
604
  prices2=prices[(prices.index >= start1) & (prices.index <= end1)]
551
605
  num=len(prices2)
552
606
  if num > 0:
553
- print(" Successfully retrieved",num,"records for",ticker)
607
+ print(" Successfully retrieved",num,"records for",ticker,ticker_name(ticker,'stock'))
554
608
  return prices2
555
609
  else:
556
- print(" Sorry, no records found from stooq for",ticker,"from",start,'to',end)
610
+ print(" Sorry, no records found from stooq for",ticker,ticker_name(ticker,'stock'),"from",start,'to',end)
557
611
  return None
558
612
  else:
559
613
  return None
@@ -569,17 +623,22 @@ if __name__=='__main__':
569
623
  #==============================================================================
570
624
  if __name__=='__main__':
571
625
  ticker='600340.SS'
572
- fromdate='2020-12-1'
573
- todate='2021-1-31'
626
+ ticker='000338.SZ'
627
+ ticker='600519.SS'
628
+ ticker_type='auto'
629
+
630
+ ticker='859811.SW'
631
+ ticker_type='auto'
632
+
633
+ fromdate='2024-1-1'
634
+ todate='2024-4-1'
574
635
  adjust='none'
575
636
 
576
- ticker='000338.SZ'
577
-
578
- #在common中定义
579
- #SUFFIX_LIST_CN=['SS','SZ','BJ','NQ']
637
+ df=get_price_ak(ticker,fromdate,todate,ticker_type=ticker_type)
580
638
 
639
+ #在common中定义SUFFIX_LIST_CN
581
640
 
582
- def get_price_ak(ticker,fromdate,todate,adjust='none'):
641
+ def get_price_ak(ticker,fromdate,todate,adjust='none',ticker_type='auto'):
583
642
  """
584
643
  功能:基于akshare抓取A股、港股和美股单只股价
585
644
  若抓取A股,调用get_price_ak_cn
@@ -592,60 +651,85 @@ def get_price_ak(ticker,fromdate,todate,adjust='none'):
592
651
  ticker1=ticker.upper()
593
652
  result,prefix,suffix=split_prefix_suffix(ticker1)
594
653
 
595
- # A股
654
+ df=pd.DataFrame()
655
+ # A股股票、指数、基金、债券,申万行业指数
596
656
  if suffix in SUFFIX_LIST_CN:
597
657
  try:
598
- #df=get_price_ak_em(ticker,fromdate,todate,adjust=adjust)
599
- df=get_price_ak_cn(ticker,fromdate,todate)
658
+ #抓取单个中国的证券
659
+ df=get_price_ak_cn(ticker1,fromdate,todate,ticker_type=ticker_type)
600
660
  except:
601
- df=None
602
- #df=get_price_ak_cn(ticker,fromdate,todate,adjust=adjust)
603
- if df is None:
604
- #df=get_price_ak_cn(ticker,fromdate,todate)
605
661
  #抓取东方财富,处理股指有时出错,所以要放在后面做planB
606
- df=get_price_ak_em(ticker,fromdate,todate)
607
- #if not (df is None): return df
662
+ df=get_price_ak_em(ticker1,fromdate,todate)
608
663
 
609
- #抓取新浪A股,能处理股指
610
- #df=get_price_ak_cn(ticker,fromdate,todate,adjust=adjust)
664
+ if df is None:
665
+ print(" #Error(get_price_ak): no info found for",ticker1)
666
+ return df
667
+
668
+ if len(df) ==0:
669
+ print(" #Warning(get_price_ak): no record found for",ticker1,'between',fromdate,todate)
670
+ return df
671
+
611
672
  return df
612
673
 
613
674
  if adjust=='none':
614
675
  adjust=''
676
+
615
677
  #抓取新浪港股,不能处理股指
616
678
  if suffix in ['HK']:
617
679
  #df=get_price_ak_hk(ticker,fromdate,todate,adjust=adjust)
618
- df=get_price_ak_hk(ticker,fromdate,todate)
619
- return df
680
+ df=get_price_ak_hk(ticker1,fromdate,todate)
681
+ return df
682
+
620
683
  # 美股,不能处理股指
621
684
  #df=get_price_ak_us(ticker,fromdate,todate,adjust=adjust)
622
- df=get_price_ak_us(ticker,fromdate,todate)
685
+ df=get_price_ak_us(ticker1,fromdate,todate)
623
686
 
624
687
  return df
625
688
 
626
- def get_price_ak_cn(ticker,fromdate,todate,adjust='none'):
689
+ #==============================================================================
690
+ if __name__=='__main__':
691
+ ticker='600340.SS' #股票
692
+ ticker='159990.SZ' #ETF基金
693
+ ticker='169201.SZ' #LOF基金
694
+ ticker='180801.SZ' #封闭式基金
695
+ ticker_type='auto'
696
+
697
+ ticker='sh019319' #国债
698
+ ticker='sh018084' #政策性金融债
699
+ ticker='sz149996' #公司债
700
+ ticker='sh018003' #政策性金融债
701
+ ticker_type='bond'
702
+
703
+ ticker='801002.SW'
704
+ ticker='sz100303'
705
+ ticker='100303.SZ'
706
+ ticker_type='auto'
707
+
708
+ fromdate='2024-1-1'; todate='2024-3-31'
709
+ adjust=''
710
+
711
+ prices=get_price_ak_cn(ticker,fromdate,todate)
712
+
713
+ #def get_price_ak_cn(ticker,fromdate,todate,adjust='none',ticker_type='auto'):
714
+ def get_price_ak_cn(ticker,fromdate,todate,adjust='',ticker_type='auto'):
627
715
  """
628
- 功能:从akshare获得中国国内的股票和指数历史行情,只能处理单个股票或指数
629
- ticker:雅虎格式,沪市股票为.SS,深市为.SZ,其他的不处理,直接返回None
716
+ 功能:从akshare获得中国国内的股票、交易所基金、指数和债券历史行情,只能处理单个证券
717
+ ticker:雅虎格式,其他的不处理,直接返回None
630
718
  fromdate:格式为YYYY-m-d,需要改造为YYYYMMDD
631
719
  todate:格式为YYYY-m-d,需要改造为YYYYMMDD
632
- adjust:不考虑复权为'none',后复权为'hfq',前复权为'qfq'
720
+ adjust:不复权为'',后复权为'hfq',前复权为'qfq'
721
+ ticker_type:抓取数据的优先顺序,'auto'/'stock'/'fund'为指数、股票和基金优先,'bond'为债券优先
722
+ 其目的是解决基金和债券代码部分重合的问题
633
723
  返回结果:雅虎格式,日期升序,列明首字母大写等
634
724
  """
725
+ import akshare as ak
726
+ import pandas as pd
727
+ import datetime as dt
728
+
729
+ df=None; found='None'
730
+
635
731
  #变换代码格式
636
- ticker1=ticker.upper()
637
- last3=ticker1[-3:]
638
- headcode=ticker1[:-3]
639
- if last3 == '.SS':
640
- ticker2='sh'+headcode
641
- if last3 == '.SZ':
642
- ticker2='sz'+headcode
643
- if last3 == '.BJ':
644
- ticker2='bj'+headcode
645
-
646
- if last3 not in ['.SS','.SZ','.BJ']:
647
- print(" #Warning(get_price_ak_cn): not eligible for security",ticker)
648
- return None
732
+ ticker2=tickers_cvt2ak(ticker)
649
733
 
650
734
  #变换日期格式
651
735
  result,start,end=check_period(fromdate,todate)
@@ -655,66 +739,160 @@ def get_price_ak_cn(ticker,fromdate,todate,adjust='none'):
655
739
  start1=start.strftime('%Y%m%d')
656
740
  end1=end.strftime('%Y%m%d')
657
741
 
658
- adjustlist=['none','hfq','qfq']
742
+ #adjustlist=['none','hfq','qfq']
743
+ adjustlist=['','qfq','hfq','qfq-factor','hfq-factor']
659
744
  if adjust not in adjustlist:
660
745
  print(" #Warning(get_price_ak_cn): adjust only supports",adjustlist)
661
746
  return None
662
747
 
663
- import akshare as ak
664
- import pandas as pd
665
- import datetime as dt
666
- df=None
667
- #printmsg=str(ticker)+" from "+fromdate+" to "+todate
668
- #不考虑复权情形
669
- if adjust == 'none':
670
- try:
671
- #抓取指数行情,实际上亦可抓取股票行情
672
- df = ak.stock_zh_index_daily(symbol=ticker2)
673
- df['Date']=df.index
674
- df['Date']=df['Date'].dt.tz_localize(None)
675
- except:
748
+ _,prefix,suffix=split_prefix_suffix(ticker2)
749
+ #考虑股票复权情形:指数/基金/债券无复权
750
+ if adjust != '':
751
+ if ticker_type in ['auto','stock'] and suffix not in ['SW']:
676
752
  try:
677
- #股票的历史行情数据(不考虑复权,特殊函数)
678
- df=ak.stock_zh_a_cdr_daily(ticker2,start1,end1)
679
- df['Date']=pd.to_datetime(df['date'])
753
+ #仅用于股票的历史行情数据(考虑复权)
754
+ df=ak.stock_zh_a_daily(ticker2,start1,end1,adjust=adjust)
755
+ df['Date']=df['date']
680
756
  except:
681
- print(" #Error(get_price_ak_cn): failed to find prices for",ticker)
682
- return None
757
+ df=None
758
+ found=df_have_data(df)
759
+
760
+ #不是股票:指数/基金/债券
761
+ if found != 'Found':
762
+ if ticker_type in ['auto','stock'] and suffix not in ['SW']:
763
+ try:
764
+ #指数/股票/基金
765
+ df = ak.stock_zh_index_daily(symbol=ticker2)
766
+ df['Date']=df['date'].apply(lambda x: pd.to_datetime(x))
767
+ except: pass
768
+ found=df_have_data(df)
769
+
770
+ if found != 'Found':
771
+ try:
772
+ #特殊函数(不考虑复权)
773
+ df=ak.stock_zh_a_cdr_daily(ticker2,start1,end1)
774
+ df['Date']=pd.to_datetime(df['date'])
775
+ except: pass
776
+ found=df_have_data(df)
777
+
778
+ if found != 'Found':
779
+ try:
780
+ #最后抓取交易所债券行情
781
+ df = exchange_bond_price(ticker2,fromdate,todate,graph=False,data_crop=False)
782
+ df['Date']=df.index
783
+ except:
784
+ #print(" #Error(get_price_ak_cn): failed to find prices for",ticker)
785
+ return None
786
+ found=df_have_data(df)
787
+
788
+ #已找到证券信息,但在规定时段无数据
789
+ if found=='Empty': return df
683
790
 
684
- #考虑复权情形
685
- if adjust != 'none':
686
- try:
687
- #股票的历史行情数据(考虑复权)
688
- df=ak.stock_zh_a_daily(ticker2,start1,end1,adjust=adjust)
689
- df['Date']=df['date']
690
- except:
691
- print(" #Error(get_price_ak_cn): failed to find prices for",ticker)
692
- return None
791
+ #债券优先,然后查找指数、股票和基金。因部分债券代码(特别是国债)与基金代码重合,需要甄别!
792
+ #例如;sh010504既是"05国债⑷"也是"招商稳兴混合C"基金的代码:-(
793
+ if ticker_type in ['bond'] and suffix not in ['SW']:
794
+ try:
795
+ #优先抓取交易所债券行情
796
+ df = exchange_bond_price(ticker2,fromdate,todate,graph=False,data_crop=False)
797
+ df['Date']=df.index
798
+ except: pass
799
+ found=df_have_data(df)
800
+
801
+ #已找到证券信息,但在规定时段无数据
802
+ if found=='Empty': return df
803
+
804
+ if found != 'Found':
805
+ try:
806
+ #其次仅抓取股票行情
807
+ df=ak.stock_zh_a_daily(ticker2,start1,end1,adjust=adjust)
808
+ df['Date']=df['date']
809
+ df['Date']=df['Date'].dt.tz_localize(None)
810
+ except: pass
811
+ found=df_have_data(df)
812
+
813
+ if found != 'Found':
814
+ try:
815
+ #接着查找指数
816
+ df = ak.stock_zh_index_daily(symbol=ticker2)
817
+ df['Date']=df['date'].apply(lambda x: pd.to_datetime(x))
818
+ except: pass
819
+ found=df_have_data(df)
820
+
821
+ if found != 'Found':
822
+ try:
823
+ #最后查找开放式基金
824
+ df =get_price_oef_china(ticker2,fromdate,todate)
825
+ df['Date']=df.index
826
+ except: pass
827
+ found=df_have_data(df)
828
+
829
+ #基金。因部分债券代码(特别是国债)与基金代码重合,需要甄别!
830
+ if ticker_type in ['fund'] and suffix not in ['SW']:
831
+ try:
832
+ #优先抓取开放式基金单位净值
833
+ df =get_price_oef_china(ticker2,fromdate,todate)
834
+ df['Date']=df.index
835
+ except: pass
836
+ found=df_have_data(df)
837
+
838
+ #已找到证券信息,但在规定时段无数据
839
+ if found=='Empty': return df
840
+
841
+ if found != 'Found': #未找到,其次抓取股票行情
842
+ try:
843
+ df=ak.stock_zh_a_daily(ticker2,start1,end1,adjust=adjust)
844
+ df['Date']=df['date']
845
+ df['Date']=df['Date'].dt.tz_localize(None)
846
+ except: pass
847
+ found=df_have_data(df)
848
+
849
+ if found != 'Found':
850
+ try:
851
+ #再次查找股票指数
852
+ df = ak.stock_zh_index_daily(symbol=ticker2)
853
+ df['Date']=df['date'].apply(lambda x: pd.to_datetime(x))
854
+ except: pass
855
+ found=df_have_data(df)
856
+
857
+ if found != 'Found':
858
+ try:
859
+ #最后查找债券
860
+ df = exchange_bond_price(ticker2,fromdate,todate,graph=False,data_crop=False)
861
+ df['Date']=df.index
862
+ except: pass
863
+ found=df_have_data(df)
864
+
865
+
866
+ if suffix in ['SW']:
867
+ try:
868
+ df = fetch_price_swindex(prefix,fromdate,todate)
869
+ df['Date']=df.index
870
+ except: pass
871
+ #print(" #Error(get_price_ak_cn): failed to retrieve prices for",ticker)
872
+ found=df_have_data(df)
693
873
 
694
- if df is None:
695
- return None
696
- else:
874
+ if found in ['Found','Empty']:
697
875
  #设置新的索引
698
876
  df.set_index(['Date'],inplace=True)
699
877
  df.rename(columns={'open':'Open','high':'High','low':'Low','close':'Close','volume':'Volume'},inplace=True)
700
878
  df['Adj Close']=df['Close']
701
879
 
702
- df1=df[df.index >= start]
703
- df2=df1[df1.index <= end]
704
-
705
- if df2 is None:
706
- print(" #Error(get_price_ak_cn): failed to find prices for",ticker)
707
- return None
708
- num=len(df2)
709
- if num==0:
710
- print(" #Error(get_price_ak_cn): found zero record for",ticker)
711
- return None
712
-
713
- df2['source']='新浪'
714
- df2['ticker']=str(ticker)
715
- df2['Adj Close']=df2['Close']
716
- df2['footnote']=adjust
717
- print(" Successfully retrieved",num,"records for",ticker)
880
+ try:
881
+ df1=df[df.index >= start]
882
+ df2=df1[df1.index <= end]
883
+ except:
884
+ df2=df
885
+ found=df_have_data(df2)
886
+
887
+ if found in ['Found','Empty']:
888
+ df2['source']=text_lang('新浪','sina')
889
+ df2['ticker']=str(ticker)
890
+ if 'Adj Close' not in list(df2):
891
+ df2['Adj Close']=df2['Close']
892
+ df2['footnote']=adjust
893
+
894
+ if len(df2) > 0:
895
+ print(" Successfully retrieved",len(df2),"records for",ticker,ticker_name(ticker,ticker_type))
718
896
 
719
897
  return df2
720
898
 
@@ -747,11 +925,11 @@ def get_price_ak_us(symbol, fromdate, todate, adjust=""):
747
925
  #printmsg=str(symbol)+" from "+fromdate+" to "+todate
748
926
 
749
927
  import akshare as ak
750
- print(" Searching info in Sina for",symbol,"... ...")
928
+ #print(" Searching info in Sina for",symbol,"... ...")
751
929
  try:
752
930
  df=ak.stock_us_daily(symbol=symbol, adjust=adjust)
753
931
  except:
754
- print(" #Error(get_price_ak_us): no info found for",symbol)
932
+ #print(" #Error(get_price_ak_us): no info found for",symbol)
755
933
  return None
756
934
 
757
935
  #去掉可能出现的时区信息,必须使用datetime中的tz_localize
@@ -778,7 +956,7 @@ def get_price_ak_us(symbol, fromdate, todate, adjust=""):
778
956
  df2['Adj Close']=df2['Close']
779
957
  df2['source']='新浪'
780
958
  df2['footnote']=adjust
781
- print(" Successfully retrieved",num,"records for",symbol)
959
+ print(" Successfully retrieved",num,"records for",symbol,ticker_name(symbol,ticker_type))
782
960
 
783
961
  return df2
784
962
 
@@ -795,7 +973,7 @@ if __name__=='__main__':
795
973
 
796
974
  def get_price_ak_hk(symbol, fromdate, todate, adjust=""):
797
975
  """
798
- 抓取单个港股股价,不能处理股指
976
+ 抓取单个港股股价,不能处理股指,股指无.HK后缀
799
977
  """
800
978
 
801
979
  #检查日期期间
@@ -807,7 +985,7 @@ def get_price_ak_hk(symbol, fromdate, todate, adjust=""):
807
985
  #printmsg=str(symbol)+" from "+fromdate+" to "+todate
808
986
 
809
987
  import akshare as ak
810
- print(" Searching info in Sina for",symbol,"... ...")
988
+ #print(" Searching info in Sina for",symbol,"... ...")
811
989
  symbol1=symbol.upper()
812
990
  symbol2 = symbol1.strip('.HK')
813
991
  if len(symbol2)==4:
@@ -840,14 +1018,14 @@ def get_price_ak_hk(symbol, fromdate, todate, adjust=""):
840
1018
  return None
841
1019
  num=len(df2)
842
1020
  if num==0:
843
- print(" #Error(get_price_ak_hk): found zero record for",ticker)
1021
+ print(" #Error(get_price_ak_hk): found zero record for",symbol)
844
1022
  return None
845
1023
 
846
1024
  df2.rename(columns={'open':'Open','high':'High','low':'Low','close':'Close','volume':'Volume'},inplace=True)
847
1025
  df2['ticker']=symbol
848
1026
  df2['Adj Close']=df2['Close']
849
1027
  df2['source']='新浪'
850
- print(" Successfully retrieved",num,"records for",symbol)
1028
+ print(" Successfully retrieved",num,"records for",symbol,ticker_name(symbol,ticker_type))
851
1029
 
852
1030
  return df2
853
1031
 
@@ -860,56 +1038,52 @@ if __name__=='__main__':
860
1038
  ticker=['600519.SS','000858.SZ']
861
1039
  fromdate='2020-12-1'
862
1040
  todate='2021-1-31'
863
- adjust='none'
1041
+ adjust='none'
1042
+
1043
+ prices=get_prices_ak(ticker,fromdate,todate,adjust,ticker_type)
864
1044
 
865
- def get_prices_ak(ticker,fromdate,todate,adjust='none'):
1045
+ def get_prices_ak(ticker,fromdate,todate,adjust='none',ticker_type='auto'):
866
1046
  """
867
1047
  功能:获取中国国内股票或指数的历史行情,多个股票
868
1048
  """
869
- #检查是否为多个股票:单个股票代码
1049
+ #检查是否为多个证券:单个证券代码
870
1050
  if isinstance(ticker,str):
871
- df=get_price_ak(ticker,fromdate,todate,adjust=adjust)
1051
+ df=get_price_ak(ticker,fromdate,todate,adjust=adjust,ticker_type=ticker_type)
872
1052
  return df
873
1053
 
874
- #检查是否为多个股票:空的列表
1054
+ #检查是否为多个证券:空的列表
875
1055
  if isinstance(ticker,list) and len(ticker) == 0:
876
1056
  pass
877
1057
  return None
878
1058
 
879
- #检查是否为多个股票:列表中只有一个代码
1059
+ #检查是否为多个证券:列表中只有一个代码
880
1060
  if isinstance(ticker,list) and len(ticker) == 1:
881
1061
  ticker1=ticker[0]
882
- df=get_price_ak(ticker1,fromdate,todate,adjust=adjust)
1062
+ #抓取单个证券
1063
+ df=get_price_ak(ticker1,fromdate,todate,adjust=adjust,ticker_type=ticker_type)
883
1064
  return df
884
1065
 
885
- """
886
- #检查是否均为中国国内的股票或指数
887
- cncode=True
888
- for t in ticker:
889
- last3=t[-3:]
890
- if last3 not in ['.SS','.SZ']:
891
- cncode=False
892
- return None
893
- """
894
1066
  import pandas as pd
895
- #处理列表中的第一个股票
1067
+ #处理列表中的第一个证券
896
1068
  i=0
897
1069
  df=None
898
1070
  while df is None:
899
1071
  t=ticker[i]
900
- df=get_price_ak(t,fromdate,todate,adjust=adjust)
1072
+ #抓取单个证券
1073
+ df=get_price_ak(t,fromdate,todate,adjust=adjust,ticker_type=ticker_type)
901
1074
  if not (df is None):
902
1075
  columns=create_tuple_for_columns(df,t)
903
1076
  df.columns=pd.MultiIndex.from_tuples(columns)
904
1077
  else:
905
1078
  i=i+1
906
1079
  if (i+1) == len(ticker):
907
- #已经到达股票代码列表末尾
1080
+ #已经到达代码列表末尾
908
1081
  return df
909
1082
 
910
- #处理列表中的其余股票
1083
+ #处理列表中的其余证券
911
1084
  for t in ticker[(i+1):]:
912
- dft=get_price_ak(t,fromdate,todate,adjust=adjust)
1085
+ #抓取单个证券
1086
+ dft=get_price_ak(t,fromdate,todate,adjust=adjust,ticker_type=ticker_type)
913
1087
  if not (dft is None):
914
1088
  columns=create_tuple_for_columns(dft,t)
915
1089
  dft.columns=pd.MultiIndex.from_tuples(columns)
@@ -994,7 +1168,7 @@ if __name__=='__main__':
994
1168
  ticker='AAPL'
995
1169
  ticker='^JN0U.JO'
996
1170
 
997
- start='2023-12-1'
1171
+ start='2024-3-1'
998
1172
  end='2024-3-31'
999
1173
  retry_count=3
1000
1174
  pause=1
@@ -1003,12 +1177,14 @@ if __name__=='__main__':
1003
1177
 
1004
1178
  ticker=['AAPL','MSFT']
1005
1179
  ticker=['AAPL','MSFT','ABCD']
1180
+
1181
+ df=get_prices_yahoo(ticker,start,end)
1006
1182
 
1007
1183
  def get_prices_yahoo(ticker,start,end,retry_count=3,pause=1):
1008
1184
  """
1009
1185
  功能:抓取股价,使用pandas_datareader
1010
1186
  输出:指定收盘价格序列,最新日期的股价排列在前
1011
- ticker: 股票代码。大陆股票代码加上后缀.SZ或.SS,港股代码去掉前导0加后缀.HK
1187
+ ticker: 股票代码。大陆股票代码加上后缀.SZ或.SS或.BJ,港股代码去掉前导0加后缀.HK
1012
1188
  start: 样本开始日期,尽量远的日期,以便取得足够多的原始样本,yyyy-mm-dd
1013
1189
  end: 样本结束日期,既可以是今天日期,也可以是一个历史日期
1014
1190
  retry_count:网络失败时的重试次数
@@ -1024,26 +1200,24 @@ def get_prices_yahoo(ticker,start,end,retry_count=3,pause=1):
1024
1200
  import yfinance as yfin
1025
1201
  yfin.pdr_override()
1026
1202
  """
1203
+ p=None
1204
+
1027
1205
  try:
1028
1206
  #p=data.DataReader(ticker,'yahoo',start,end,retry_count=retry_count,pause=pause)
1029
1207
  p=pdr.get_data_yahoo(ticker,start=start,end=end)
1030
- except:
1031
- print(" #Error(get_prices_yahoo): data source unreachable, try later")
1032
- return None
1208
+ except: pass
1209
+ found=df_have_data(p)
1033
1210
 
1034
- cols=list(p)
1035
- if 'Adj Close' not in cols:
1036
- p['Adj Close']=p['Close']
1037
-
1038
- p['ticker']=ticker
1039
- #p['Adj Close']=p['Close']
1040
- p['source']='雅虎'
1211
+ if found in ['Found']:
1212
+ cols=list(p)
1213
+ if 'Adj Close' not in cols:
1214
+ p['Adj Close']=p['Close']
1041
1215
 
1042
- num=len(p)
1043
- if num > 0:
1044
- print(" Successfully retrieved",num,"records for",ticker)
1045
- else:
1046
- print(" Sorry, no records retrieved for",ticker)
1216
+ p['ticker']=ticker
1217
+ #p['Adj Close']=p['Close']
1218
+ p['source']='雅虎'
1219
+
1220
+ print(" Successfully retrieved",len(p),"records for",ticker,ticker_name(ticker,ticker_type))
1047
1221
 
1048
1222
  return p
1049
1223
 
@@ -1062,16 +1236,6 @@ def get_price_yf(ticker,start,end,threads=False):
1062
1236
  """
1063
1237
  df=get_prices_yf(ticker,start,end,threads=threads)
1064
1238
 
1065
- df['ticker']=ticker
1066
- df['Adj Close']=df['Close']
1067
- df['source']='雅虎'
1068
-
1069
- num=len(df)
1070
- if num > 0:
1071
- print(" Successfully retrieved",num,"records for",ticker)
1072
- else:
1073
- print(" Sorry, no records retrieved for",ticker)
1074
-
1075
1239
  return df
1076
1240
 
1077
1241
 
@@ -1085,21 +1249,25 @@ if __name__=='__main__':
1085
1249
  ticker=['AAPL','MSFT','0700.HK','600519.SS']
1086
1250
 
1087
1251
  threads=False
1252
+ threads=True
1253
+
1254
+ df=get_price_yf(ticker,start,end,threads)
1088
1255
 
1089
1256
 
1090
1257
  def get_prices_yf(ticker,start,end,threads=False):
1091
1258
  """
1092
1259
  功能:从新浪/stooq抓取股价,使用yfinance(对非美股抓取速度快,但有时不太稳定)
1093
1260
  输入:股票代码或股票代码列表,开始日期,结束日期
1094
- ticker: 股票代码或股票代码列表。大陆股票代码加上后缀.SZ或.SS,港股代码去掉前导0加后缀.HK
1261
+ ticker: 股票代码或股票代码列表。大陆股票代码加上后缀.SZ或.SS或.BJ,港股代码去掉前导0加后缀.HK
1095
1262
  start: 样本开始日期,尽量远的日期,以便取得足够多的原始样本,yyyy-mm-dd
1096
1263
  end: 样本结束日期,既可以是今天日期,也可以是一个历史日期
1097
1264
 
1098
1265
  输出:指定收盘价格序列,最新日期的股价排列在前
1099
1266
  特别注意:yfinance中的收盘价Close其实是Yahoo Finance中的调整收盘价Adj Close。
1100
1267
  """
1101
-
1102
- #抓取新浪/stooq股票价格
1268
+ p=None
1269
+
1270
+ #支持多个证券
1103
1271
  import yfinance as yf
1104
1272
  ticker1,islist=cvt_yftickerlist(ticker)
1105
1273
  if not islist:
@@ -1108,46 +1276,33 @@ def get_prices_yf(ticker,start,end,threads=False):
1108
1276
  try:
1109
1277
  #p=stock.history(start=start,end=end,threads=threads)
1110
1278
  p=stock.history(start=start,end=end)
1111
- except Exception as e:
1112
- emsg=str(e)
1113
- #print(emsg)
1114
-
1115
- #检查是否网络超时出错
1116
- key1='WSAETIMEDOUT'
1117
- if emsg.find(key1) != -1:
1118
- print(" #Error(get_prices_yf): data source unreachable, try later")
1119
- return None
1120
-
1121
- #单个代码:是否未找到
1122
- key2='Date'
1123
- if emsg.find(key2):
1124
- #单个ticker,未找到代码
1125
- print(" #Error(get_prices_yf): ticker info inaccessible now for",ticker)
1126
- return None
1279
+ #仅针对雅虎情况
1280
+ if p is not None:
1281
+ if len(p)==0: p=None
1282
+ except:
1283
+ p=None
1127
1284
  else:
1128
1285
  #下载股票列表的股价
1129
1286
  try:
1130
1287
  p=yf.download(ticker1,start=start,end=end,progress=False,threads=threads)
1131
- except Exception as e:
1132
- #检查是否网络超时出错
1133
- key1='WSAETIMEDOUT'
1134
- if emsg.find(key1) != -1:
1135
- print(" #Error(get_prices_yf): data source unreachable, try later")
1136
- return None
1137
-
1138
- cols=list(p)
1139
- if 'Adj Close' not in cols:
1140
- p['Adj Close']=p['Close']
1141
-
1142
- p['ticker']=ticker
1143
- p['Adj Close']=p['Close']
1144
- p['source']='雅虎'
1145
-
1146
- num=len(p)
1147
- if num > 0:
1148
- print(" Successfully retrieved",num,"records for",ticker)
1288
+ #仅针对雅虎情况
1289
+ if p is not None:
1290
+ if len(p)==0: p=None
1291
+ except:
1292
+ p=None
1293
+
1294
+ found=df_have_data(p)
1295
+ if found in ['Found','Empty']:
1296
+ if 'Adj Close' not in list(p):
1297
+ p['Adj Close']=p['Close']
1298
+ p['ticker']=ticker
1299
+ p['source']='雅虎'
1300
+
1301
+ if len(p) > 0:
1302
+ print(" Successfully retrieved",len(p),"records for",ticker1,ticker_name(ticker1,ticker_type))
1149
1303
  else:
1150
- print(" Sorry, no records retrieved for",ticker)
1304
+ pass
1305
+ #print(" #Error(get_prices_yf):",ticker1,"not found or no prices in the period or inaccessible to yahoo")
1151
1306
 
1152
1307
  return p
1153
1308
 
@@ -1207,7 +1362,7 @@ def get_index_fred(ticker,start,end):
1207
1362
 
1208
1363
  num=len(df)
1209
1364
  if num > 0:
1210
- print(" Successfully retrieved",num,"records for",ticker)
1365
+ print(" Successfully retrieved",num,"records for",ticker,ticker_name(ticker,ticker_type))
1211
1366
  else:
1212
1367
  print(" Sorry, no records retrieved for",ticker)
1213
1368
 
@@ -1241,12 +1396,15 @@ def create_tuple_for_columns(df_a, multi_level_col):
1241
1396
  #==============================================================================
1242
1397
  #==============================================================================
1243
1398
  #==============================================================================
1244
- def get_price_portfolio(tickerlist,sharelist,fromdate,todate,adj=False,source='auto'):
1399
+ def get_price_portfolio(tickerlist,sharelist,fromdate,todate,adj=False, \
1400
+ source='auto',ticker_type='bond'):
1245
1401
  """
1246
1402
  套壳函数get_prices_portfolio
1247
1403
  经测试,已经能够支持capm_beta2
1404
+ ticker_type='bond':抓取债券优先,因投资组合中配置债券的可能性远高于基金和指数
1248
1405
  """
1249
- df=get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=adj,source=source)
1406
+ df=get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=adj, \
1407
+ source=source,ticker_type=ticker_type)
1250
1408
  return df
1251
1409
 
1252
1410
  if __name__=='__main__':
@@ -1263,20 +1421,22 @@ if __name__=='__main__':
1263
1421
  sharelist=[1000]
1264
1422
 
1265
1423
  fromdate='2024-1-1'
1266
- todate='2024-3-23'
1424
+ todate='2024-4-1'
1267
1425
  adj=False
1268
1426
  source='auto'
1427
+ ticker_type='auto'
1269
1428
 
1270
- security={'Market':('US','^SPX','中概教培组合'),'EDU':0.4,'TAL':0.3,'TCTM':0.2}
1271
- _,_,tickerlist,sharelist=decompose_portfolio(security)
1429
+ ticker={'Market':('China','000001.SS','白酒组合'),'600519.SS':0.4,'000858.SZ':0.6}
1430
+ _,_,tickerlist,sharelist=decompose_portfolio(ticker)
1272
1431
 
1273
1432
  p=get_prices_portfolio(tickerlist,sharelist,fromdate,todate,source='auto')
1274
1433
 
1275
- def get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=False,source='auto'):
1434
+ def get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=False, \
1435
+ source='auto',ticker_type='bond'):
1276
1436
  """
1277
1437
  功能:抓取投资组合的每日价值
1278
- 输入:股票代码列表,份额列表,开始日期,结束日期
1279
- tickerlist: 股票代码列表
1438
+ 输入:证券代码列表,份额列表,开始日期,结束日期
1439
+ tickerlist: 证券代码列表
1280
1440
  sharelist:持有份额列表,与股票代码列表一一对应
1281
1441
  fromdate: 样本开始日期。格式:'YYYY-MM-DD'
1282
1442
  todate: 样本结束日期。既可以是今天日期,也可以是一个历史日期
@@ -1285,13 +1445,13 @@ def get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=False,source='
1285
1445
  """
1286
1446
  import pandas as pd
1287
1447
 
1288
- #检查股票列表个数与份额列表个数是否一致
1448
+ #检查证券列表个数与份额列表个数是否一致
1289
1449
  if len(tickerlist) != len(sharelist):
1290
1450
  print(" #Error(get_prices_portfolio): numbers of stocks and shares mismatch.")
1291
1451
  return None
1292
1452
 
1293
- #抓取股票价格
1294
- p=get_prices(tickerlist,fromdate,todate,adj=adj,source=source)
1453
+ #抓取证券价格:如何只抓取股票和债券???
1454
+ p=get_prices(tickerlist,fromdate,todate,adj=adj,source=source,ticker_type=ticker_type)
1295
1455
  if p is None: return None
1296
1456
 
1297
1457
  #删除无用的空列preclose,避免引起后续程序误判
@@ -1537,7 +1697,7 @@ def calc_rolling_return(drdf, period="Weekly"):
1537
1697
  #检查period类型
1538
1698
  periodlist = ["Weekly","Monthly","Quarterly","Annual"]
1539
1699
  if not (period in periodlist):
1540
- print("*** 错误#1(calc_rolling_return),仅支持期间类型:",periodlist)
1700
+ print(" #Error(calc_rolling_return), periodic type only support:",periodlist)
1541
1701
  return None
1542
1702
 
1543
1703
  #换算期间对应的实际交易天数
@@ -2173,6 +2333,473 @@ def get_price_security(security,start,end,source='auto'):
2173
2333
 
2174
2334
  return prices
2175
2335
 
2336
+ #==============================================================================
2337
+ if __name__=='__main__':
2338
+ ticker='600519.SS'
2339
+ ticker='000858.SZ'
2340
+
2341
+ ticker='SH600519'
2342
+ ticker='sh600519'
2343
+ ticker='sz000858'
2344
+
2345
+ ticker='sz600519'
2346
+ ticker='sh000858'
2347
+
2348
+ ticker='600519.SH'
2349
+ ticker='600519.sh'
2350
+ ticker='000858.sz'
2351
+
2352
+ ticker='000858.sh'
2353
+ ticker='600519.sz'
2354
+
2355
+ ticker='600519'
2356
+ ticker='000858'
2357
+ ticker='600519.CN'
2358
+ ticker='000858.CN'
2359
+ ticker='801010.SW'
2360
+ ticker='880410.ZZ'
2361
+
2362
+ ticker='01210.HK'
2363
+ ticker='AAPL'
2364
+ ticker='6758.T'
2365
+ ticker='SONA.F'
2366
+
2367
+ ticker1_cvt2yahoo(ticker)
2368
+
2369
+ def ticker1_cvt2yahoo(ticker):
2370
+ """
2371
+ 功能:将一只股票、基金、债券代码转换为siat内部默认的yahoo格式
2372
+ 情形:后缀,前缀,无后缀和前缀
2373
+ 注意:中证行业代码若为沪深交易所收藏的,仍以SS/SZ为后缀,不可用ZZ后缀
2374
+ """
2375
+ ticker1=ticker.upper() #转为大写
2376
+
2377
+ #后缀
2378
+ result,prefix,suffix=split_prefix_suffix(ticker1)
2379
+ if suffix in ['SS','SH','SZ','BJ','CN','SW','ZZ'] and len(prefix)==6:
2380
+ if suffix in ['SH']:
2381
+ suffix1='SS'
2382
+ elif suffix in ['CN']:
2383
+ suffix1,_=china_security_identify(prefix)
2384
+ else:
2385
+ suffix1=suffix
2386
+
2387
+ """
2388
+ #检查是否搞错SS/SZ/BJ
2389
+ if suffix1 in ['SS','SZ','BJ']:
2390
+ suffix1,_=china_security_identify(prefix)
2391
+ """
2392
+ ticker2=prefix+'.'+suffix1
2393
+ return ticker2
2394
+
2395
+ #前缀
2396
+ head2=ticker1[:2]
2397
+ rest2=ticker1[2:]
2398
+ if head2 in ['SH','SZ','BJ','SW','ZZ'] and len(rest2)==6:
2399
+ #suffix1,_=china_security_identify(rest2)
2400
+ if head2 in ['SH']:
2401
+ suffix1='SS'
2402
+ else:
2403
+ suffix1=head2
2404
+ """
2405
+ #检查是否搞错SS/SZ/BJ
2406
+ if suffix1 in ['SS','SZ','BJ']:
2407
+ suffix1,_=china_security_identify(rest2)
2408
+ """
2409
+ ticker2=rest2+'.'+suffix1
2410
+ return ticker2
2411
+
2412
+ #无前后缀,6位数字,默认为A股
2413
+ if is_all_digits(ticker1) and len(ticker1) == 6:
2414
+ suffix1,_=china_security_identify(ticker1)
2415
+ ticker2=ticker1+'.'+suffix1
2416
+ return ticker2
2417
+
2418
+ #其他:直接返回
2419
+ return ticker1
2420
+
2421
+ #==============================================================================
2422
+ if __name__=='__main__':
2423
+ ticker=['600519.SS','sz000858','002594.sz','aapl']
2424
+
2425
+ tickers_cvt2yahoo(ticker)
2426
+
2427
+ def tickers_cvt2yahoo(ticker):
2428
+ """
2429
+ 功能:将多只股票、基金、债券代码转换为siat内部默认的yahoo格式
2430
+ """
2431
+ #单个字符串:返回字符串
2432
+ if isinstance(ticker,str):
2433
+ result=ticker1_cvt2yahoo(ticker)
2434
+ return result
2435
+
2436
+ #列表:返回列表
2437
+ if isinstance(ticker,list): #避免下面的循环出错
2438
+ tickerlist=[]
2439
+ for t in ticker:
2440
+ t2=ticker1_cvt2yahoo(t)
2441
+ tickerlist=tickerlist+[t2]
2442
+
2443
+ result=tickerlist
2444
+ return result
2445
+
2446
+ #其他:直接返回
2447
+ return ticker
2448
+
2449
+ #==============================================================================
2450
+ if __name__=='__main__':
2451
+ ticker='SH600519'
2452
+ ticker='sh600519'
2453
+ ticker='sz000858'
2454
+
2455
+ ticker='sz600519'
2456
+ ticker='sh000858'
2457
+
2458
+ ticker='600519.SH'
2459
+ ticker='600519.sh'
2460
+ ticker='000858.sz'
2461
+
2462
+ ticker='000858.sh'
2463
+ ticker='600519.sz'
2464
+
2465
+ ticker='600519'
2466
+ ticker='000858'
2467
+ ticker='600519.CN'
2468
+ ticker='000858.CN'
2469
+ ticker='801010.SW'
2470
+ ticker='880410.ZZ'
2471
+
2472
+ ticker='sh149996'
2473
+
2474
+ ticker='01210.HK'
2475
+ ticker='AAPL'
2476
+ ticker='6758.T'
2477
+ ticker='SONA.F'
2478
+
2479
+ ticker1_cvt2ak(ticker)
2480
+
2481
+ def ticker1_cvt2ak(ticker):
2482
+ """
2483
+ 功能:将一只股票、基金、债券代码转换为akshare格式
2484
+ 情形:后缀,前缀,无后缀和前缀
2485
+ 注意:中证行业代码若为沪深交易所收藏的,仍以SS/SZ为后缀,不可用ZZ后缀
2486
+ """
2487
+ ticker1=ticker.upper() #转为大写
2488
+
2489
+ #后缀
2490
+ result,prefix,suffix=split_prefix_suffix(ticker1)
2491
+ if suffix in ['SS','SH','SZ','BJ','CN'] and len(prefix)==6:
2492
+ if suffix in ['SH','SS']: prefix1='sh'
2493
+ if suffix in ['SZ']: prefix1='sz'
2494
+ if suffix in ['BJ']: prefix1='bj'
2495
+ if suffix in ['CN']:
2496
+ suffix1,_=china_security_identify(prefix)
2497
+ prefix1='sh'
2498
+ if suffix1 in ['SS']: prefix1='sh'
2499
+ if suffix1 in ['SZ']: prefix1='sz'
2500
+ if suffix1 in ['BJ']: prefix1='bj'
2501
+ """
2502
+ #检查是否搞错SS/SZ/BJ
2503
+ if suffix in ['SS','SH','SZ','BJ']:
2504
+ suffix1,_=china_security_identify(prefix)
2505
+ if suffix1 in ['SS','SH']: prefix1='sh'
2506
+ if suffix1 == 'SZ': prefix1='sz'
2507
+ if suffix1 == 'BJ': prefix1='bj'
2508
+ """
2509
+ ticker2=prefix1+prefix
2510
+ return ticker2
2511
+
2512
+ #前缀
2513
+ head2=ticker1[:2]
2514
+ rest2=ticker1[2:]
2515
+ if head2 in ['SH','SS','SZ','BJ'] and len(rest2)==6:
2516
+ if head2 in ['SH','SS']: prefix1='sh'
2517
+ if head2 in ['SZ']: prefix1='sz'
2518
+ if head2 in ['BJ']: prefix1='bj'
2519
+
2520
+ """
2521
+ #检查是否搞错SS/SZ/BJ
2522
+ if head2 in ['SH','SS','SZ','BJ']:
2523
+ suffix1,_=china_security_identify(rest2)
2524
+ if suffix1 == 'SS': prefix1='sh'
2525
+ if suffix1 == 'SZ': prefix1='sz'
2526
+ if suffix1 == 'BJ': prefix1='bj'
2527
+ """
2528
+ ticker2=prefix1+rest2
2529
+ return ticker2
2530
+
2531
+ #无前后缀,6位数字,默认为A股
2532
+ if is_all_digits(ticker1) and len(ticker1) == 6:
2533
+ suffix1,_=china_security_identify(ticker1)
2534
+ prefix1='sh'
2535
+ if head2 in ['SH','SS']: prefix1='sh'
2536
+ if head2 in ['SZ']: prefix1='sz'
2537
+ if head2 in ['BJ']: prefix1='bj'
2538
+
2539
+ ticker2=prefix1+ticker1
2540
+ return ticker2
2541
+
2542
+ #其他:直接返回
2543
+ return ticker1
2544
+
2545
+ #==============================================================================
2546
+ if __name__=='__main__':
2547
+ ticker=['600519.SS','sz000858','002594.sz','aapl']
2548
+
2549
+ tickers_cvt2ak(ticker)
2550
+
2551
+ def tickers_cvt2ak(ticker):
2552
+ """
2553
+ 功能:将多只股票、基金、债券代码转换为akshare格式
2554
+ """
2555
+ #单个字符串:返回字符串
2556
+ if isinstance(ticker,str):
2557
+ result=ticker1_cvt2ak(ticker)
2558
+ return result
2559
+
2560
+ #列表:返回列表
2561
+ if isinstance(ticker,list): #避免下面的循环出错
2562
+ tickerlist=[]
2563
+ for t in ticker:
2564
+ t2=ticker1_cvt2ak(t)
2565
+ tickerlist=tickerlist+[t2]
2566
+
2567
+ result=tickerlist
2568
+ return result
2569
+
2570
+ #其他:直接返回
2571
+ return ticker
2572
+
2573
+
2574
+ #==============================================================================
2575
+ if __name__=='__main__':
2576
+ s='123456'
2577
+ s='123456.'
2578
+ s='123456a'
2579
+
2580
+ is_all_digits(s)
2581
+
2582
+ def is_all_digits(s):
2583
+ """
2584
+ 功能:检查字符串s是否为全数字构成
2585
+ """
2586
+ import re
2587
+ return bool(re.match(r'^\d+$', s))
2588
+
2589
+ #==============================================================================
2590
+ if __name__=='__main__':
2591
+ ticker6='AAPL'
2592
+ ticker6='01211'
2593
+ ticker6='600519'
2594
+ ticker6='149996'
2595
+
2596
+ def china_security_identify(ticker6):
2597
+ """
2598
+ 功能:区分中国内地证券代码前缀,返回后缀SS/SZ/BJ
2599
+ 情形:股票,基金,债券,指数
2600
+ 注意:ticker6需为6位数字字符,目前仅限沪深京交易所,未包括期货期权交易所
2601
+ """
2602
+ suffix='SS'
2603
+ stype='stock'
2604
+
2605
+ #检查是否为6位数字字符
2606
+ if not is_all_digits(ticker6) or len(ticker6) != 6:
2607
+ suffix=''
2608
+ stype=''
2609
+ return suffix,stype
2610
+
2611
+ head1=ticker6[:1]
2612
+ head2=ticker6[:2]
2613
+ head3=ticker6[:3]
2614
+
2615
+ #股票代码
2616
+ if head2 in ['60','68']: #上交所:60-主板,68-科创板
2617
+ suffix='SS'
2618
+ stype='stock'
2619
+ return suffix,stype
2620
+ if head2 in ['00','30']: #深交所:00-主板,30-创业板
2621
+ suffix='SZ'
2622
+ stype='stock'
2623
+ return suffix,stype
2624
+ if head1 in ['8']: #北交所
2625
+ suffix='BJ'
2626
+ stype='stock'
2627
+ return suffix,stype
2628
+
2629
+ #沪深基金
2630
+ if head2 in ['50','51']: #上交所:50-封闭式,51-ETF
2631
+ suffix='SS'
2632
+ stype='fund'
2633
+ return suffix,stype
2634
+ if head2 in ['15','16','18']: #深交所:15-ETF,16-LOF,18-封闭式
2635
+ suffix='SZ'
2636
+ stype='fund'
2637
+ return suffix,stype
2638
+
2639
+ #沪深债券
2640
+ if head3 in ['271','270','240','188','185','184','175','163','155','152', \
2641
+ '143','138','137','136','127','124','122','118','115','113', \
2642
+ '100','020','019','018','010']:
2643
+ suffix='SS'
2644
+ stype='bond'
2645
+ return suffix,stype
2646
+
2647
+ #有重复
2648
+ if head3 in ['149','148','133','128','127','123','114','112','111','110', \
2649
+ '108','102','101','100']:
2650
+ suffix='SZ'
2651
+ stype='bond'
2652
+ return suffix,stype
2653
+
2654
+ #沪深B股
2655
+ if head3 in ['900']:
2656
+ suffix='SS'
2657
+ stype='stockb'
2658
+ return suffix,stype
2659
+ if head3 in ['200']:
2660
+ suffix='SZ'
2661
+ stype='stockb'
2662
+ return suffix,stype
2663
+
2664
+ #其他
2665
+ return '',''
2666
+
2667
+ #==============================================================================
2668
+ if __name__=='__main__':
2669
+ ticker='850831'
2670
+
2671
+ start='2023-1-1'
2672
+ end='2023-4-4'
2673
+ info_types=['Close','Volume']
2674
+
2675
+ df3=fetch_price_swindex(ticker,start,end)
2676
+
2677
+ def fetch_price_swindex(ticker,start,end,info_types=['Close','Volume'],adjust=-2*365):
2678
+ """
2679
+ 功能:获取申万行业指数的信息
2680
+ ticker:申万行业指数
2681
+ start,end:日期期间
2682
+ info_types:信息测度,默认['Close'],还可以为['Close','Open','High','Low',
2683
+ 'Volume','Adj Close']
2684
+ 特点:为compare_indicator使用,包括指数名称
2685
+ """
2686
+ df=None
2687
+
2688
+ # 检查日期期间的合理性
2689
+ result,startpd,endpd=check_period(start,end)
2690
+ if not result:
2691
+ #print(" #Error(fetch_price_swindex): invalid date period between",start,"and",end)
2692
+ return None
2693
+
2694
+ start1=date_adjust(start,adjust=adjust)
2695
+ _,start1pd,_=check_period(start1,end)
2696
+
2697
+ import akshare as ak
2698
+ try:
2699
+ prices= ak.index_hist_sw(symbol=ticker,period="day")
2700
+ except: pass
2701
+
2702
+ found=df_have_data(prices)
2703
+ if found not in ['Found','Empty']: return df
2704
+
2705
+ prices.columns=['Code','Date','Close','Open','High','Low','Volume','Amount']
2706
+ million=1000000
2707
+ prices['Volume']=prices['Volume']*million
2708
+ prices['Amount']=prices['Amount']*million
2709
+
2710
+ import pandas as pd
2711
+ prices['date']=pd.to_datetime(prices['Date'])
2712
+ prices.set_index('date',inplace=True)
2713
+
2714
+ prices2=prices[(prices.index >= start1pd) & (prices.index <= endpd)]
2715
+
2716
+
2717
+ if isinstance(info_types,str):
2718
+ typelist=[info_types]
2719
+ else:
2720
+ typelist=info_types
2721
+
2722
+ import pandas as pd
2723
+ df=pd.DataFrame()
2724
+
2725
+ for t in typelist:
2726
+ try:
2727
+ df[t]=prices2[t]
2728
+ except:
2729
+ continue
2730
+
2731
+ collist=list(df)
2732
+ pcollist=['Open','High','Low','Adj Close']
2733
+ for p in pcollist:
2734
+ if p not in collist:
2735
+ df[p]=df['Close']
2736
+
2737
+ df['Code']=ticker
2738
+ df['Type']='swindex'
2739
+ df['Name']=ticker_name(ticker)
2740
+
2741
+ #print(" Successfully retrieved",len(df),"records for sw index",ticker)
2742
+
2743
+ return df
2744
+
2745
+ #==============================================================================
2746
+ if __name__=='__main__':
2747
+ ticker='sh018003'
2748
+ fromdate='2024-1-1'
2749
+ todate='2024-4-17'
2750
+ trend_type='净值'
2751
+
2752
+ f=get_price_oef_china(ticker,fromdate,todate)
2753
+
2754
+ def get_price_oef_china(ticker,fromdate,todate):
2755
+ """
2756
+ 功能:单纯获取中国开放式基金的单位净值趋势
2757
+ """
2758
+ #检查日期
2759
+ result,start,end=check_period(fromdate,todate)
2760
+ if not result:
2761
+ print(" #Error(get_price_oef_china): invalid date period:",fromdate,todate)
2762
+ return None
2763
+
2764
+ #print("Searching for open-ended fund (OEF) trend info in China ...")
2765
+ import akshare as ak
2766
+
2767
+ fund1=ticker[:6]; fund2=ticker[-6:]
2768
+ if fund1.isdigit():
2769
+ fund=fund1
2770
+ elif fund2.isdigit():
2771
+ fund=fund2
2772
+ else:
2773
+ fund=ticker
2774
+
2775
+ fund_name=ticker_name(fund,'fund')
2776
+
2777
+ #单位净值
2778
+ found='None'; df2=None
2779
+ try:
2780
+ df1 = ak.fund_open_fund_info_em(fund, indicator="单位净值走势")
2781
+ df1.rename(columns={'净值日期':'date','单位净值':'Close'}, inplace=True)
2782
+ df1['Open']=df1['High']=df1['Low']=df1['Close']
2783
+ df1['Volume']=0
2784
+ df1['name']=ticker_name(fund,'fund')
2785
+
2786
+ df1['date']=df1['date'].apply(lambda x: pd.to_datetime(x))
2787
+ df1.set_index(['date'],inplace=True)
2788
+
2789
+ df2=df1[['Open','Close','High','Low','Volume','name']]
2790
+ df2=df2[(df2.index >= start) & (df2.index <= end)]
2791
+
2792
+ if len(df2)==0:
2793
+ found='Empty'
2794
+ else:
2795
+ found='Found'
2796
+ except:
2797
+ pass
2798
+
2799
+ return df2
2800
+
2801
+ #==============================================================================
2802
+
2176
2803
  #==============================================================================
2177
2804
  #==============================================================================
2178
2805
  #==============================================================================