siat 2.14.1__py3-none-any.whl → 3.0.0__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.
@@ -0,0 +1,616 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 版权:王德宏,北京外国语大学国际商学院
4
+ 功能:
5
+ 1、获取证券价格,多种方法
6
+ 2、首先获取单一证券的价格,其后证券列表的价格
7
+ 3、支持股票、基金、债券、申万行业指数
8
+ 版本:0.1,2024-4-3,经过多方测试
9
+ """
10
+
11
+ #==============================================================================
12
+ #关闭所有警告
13
+ import warnings; warnings.filterwarnings('ignore')
14
+ from siat.common import *
15
+ from siat.translate import *
16
+ from siat.security_prices import *
17
+ #==============================================================================
18
+ import pandas as pd
19
+ #==============================================================================
20
+ SUFFIX_LIST_CN=['SS','SZ','BJ','SW','SH']
21
+ SUFFIX_LIST_HK=['HK']
22
+ #==============================================================================
23
+
24
+ #==============================================================================
25
+ #==============================================================================
26
+ if __name__=='__main__':
27
+ ticker='AAPL' #股票
28
+ ticker='600519.SS'
29
+ ticker='00700.HK'
30
+ ticker='OPN.PL'
31
+
32
+ ticker='000001.SS' #指数
33
+ ticker='000300.SS'
34
+
35
+ ticker='sh018003' #债券
36
+ ticker='sz149808'
37
+ ticker='sz159998' #基金
38
+
39
+ ticker='801010.SW' #申万
40
+
41
+ fromdate='2024-1-1'; todate='2024-4-6'
42
+
43
+ ticker_type='auto'
44
+ ticker_type='bond'
45
+
46
+ source='auto'
47
+ source='yahoo'
48
+
49
+ adjust=''
50
+ fill=True
51
+
52
+ price,found=get_price_1ticker(ticker=ticker,fromdate=fromdate,todate=todate, \
53
+ ticker_type=ticker_type,source=source, \
54
+ adjust=adjust,fill=fill)
55
+
56
+ def get_price_1ticker(ticker,fromdate,todate, \
57
+ ticker_type='auto',source='auto', \
58
+ adjust='',fill=False):
59
+ """
60
+ 功能:抓取一只证券的价格序列,不处理列表,不处理投资组合
61
+ 数据源优先度:1-source,2-ticker属地,3-ticker_type
62
+ adjust:""-未复权,qfq-前复权,hfq-后复权,qfq-factor:前复权因子和调整,hfq-factor: 后复权因子和调整
63
+ 返回值:
64
+ df: None-未找到ticker,空df-找到ticker但规定时间段内无数据
65
+ found: 字符串,Found-找到且有数据,Empty-找到但规定时间段内无数据,None-未找到ticker。
66
+ 简化使用者判断
67
+ fill:为现有数据开始结束日期之间的工作日填充=True
68
+ """
69
+
70
+ #返回值初始状态,确保各种情况下都有返回值
71
+ df=None
72
+ found='None'
73
+
74
+ #只处理字符串
75
+ if not isinstance(ticker,str):
76
+ print(" #Warning(get_price_1ticker):",ticker,"is not a single security code")
77
+ return df,found
78
+
79
+ #检查日期期间合理性
80
+ valid_period,fromdatepd,todatepd=check_period(fromdate,todate)
81
+ if not valid_period:
82
+ #print(" #Warning(get_price_1ticker): invalid date period from",fromdate,"to",todate)
83
+ return df,found
84
+
85
+ #检查复权选项合理性
86
+ ak_fq_list=['','qfq','hfq','qfq-factor','hfq-factor']
87
+ if adjust not in ak_fq_list:
88
+ adjust=''
89
+
90
+ #变换ticker为内部格式(yahoo格式)
91
+ ticker1=ticker1_cvt2yahoo(ticker)
92
+ _,prefix,suffix=split_prefix_suffix(ticker1)
93
+
94
+ #预处理ticker_type
95
+ ticker_type=ticker_type_preprocess_1str(ticker,ticker_type)
96
+
97
+ #数据源情形1:akshare
98
+ if source in ['auto','sina']:
99
+ #中国的证券
100
+ if suffix in SUFFIX_LIST_CN:
101
+ #含处理证券类型优先级
102
+ dft=get_price_ak_cn(ticker1,fromdate,todate,adjust=adjust,ticker_type=ticker_type)
103
+ found=df_have_data(dft)
104
+
105
+ #香港的证券
106
+ if suffix in SUFFIX_LIST_HK and found not in ['Found','Empty']:
107
+ dft=get_price_ak_hk(ticker1,fromdate,todate,adjust=adjust)
108
+ found=df_have_data(dft)
109
+
110
+ #是否美股
111
+ if found not in ['Found','Empty']:
112
+ adjust='qfq' if adjust != '' else ''
113
+ dft=get_price_ak_us(ticker1,fromdate,todate,adjust=adjust)
114
+ found=df_have_data(dft)
115
+
116
+ #数据源情形2:stooq
117
+ if source in ['auto','stooq'] and found not in ['Found','Empty']:
118
+ dft=get_price_stooq(ticker1,fromdate,todate)
119
+ found=df_have_data(dft)
120
+
121
+ #访问雅虎财经
122
+ if source in ['auto','yahoo'] and found not in ['Found','Empty']:
123
+ dft=None
124
+ if test_yahoo_finance():
125
+ #数据源情形3:yahoo, yfinance, 需要访问yahoo
126
+ dft=get_price_yf(ticker1,fromdate,todate)
127
+ found=df_have_data(dft)
128
+
129
+ #数据源情形4:yahoo, pandas_datareader,需要访问yahoo,近期似乎不工作!
130
+ if found not in ['Found','Empty']:
131
+ dft=get_prices_yahoo(ticker1,fromdate,todate)
132
+ found=df_have_data(dft)
133
+ else:
134
+ if source in ['yahoo']:
135
+ print(" #Warning(get_price_1ticker): sorry, yahoo is currently inaccessible")
136
+
137
+ #数据源情形5:FRED, 仅用于几个常用指数,备用
138
+ if source in ['auto'] and found not in ['Found','Empty']:
139
+ dft=get_index_fred(ticker1,fromdate,todate)
140
+ found=df_have_data(dft)
141
+
142
+ #数据源情形6:pandas_datareader,其他数据源,暂不支持
143
+ """
144
+ Tiingo:获取股票,共同基金和信息和交易所交易基金的信息,可以免费注册获得API_KEY
145
+ IEX:获得投资交易信息,需要API_KEY
146
+ Alpha Vantage:美股信息,需要API_KEY
147
+ Econdb:提供超过90家官方统计机构提供的经济数据,免费
148
+ Enigma:交易数据,需要API
149
+ Quandl:股价和基金交易数据,需要API_KEY
150
+ FRED:来自FRED的金融研究数据,编码特殊,需要转换
151
+ Fama/French:来自Fama/French数据实验室的数据
152
+ World Bank:世行数据
153
+ OECD:经合组织数据
154
+ Eurostat:欧洲统计局数据
155
+ TSP Fund Data:TSP(Thrift Savings Plan) 基金数据
156
+ Nasdaq Trader Symbol Definitions:Nasdaq 股票代码定义文档 (包含公司名,上市状态等一些数据)
157
+ MOEX Data:莫斯科交易所数据
158
+ Bank of Canada:加拿大银行数据
159
+ """
160
+
161
+ #整理字段
162
+ if found in ['Found','Empty']:
163
+ dft1_cols=['Open','High','Low','Close','Volume','Adj Close','source','ticker']
164
+ dft1=dft[dft1_cols]
165
+
166
+ dft1['name']=ticker_name(ticker1,ticker_type=ticker_type)
167
+ dft1['Amount']=dft1.apply(lambda x: x['Close'] * x['Volume'],axis=1)
168
+ else:
169
+ dft1=dft
170
+
171
+ if found == 'None':
172
+ print(" Sorry, tried all means,",ticker,'info not found or inaccessible')
173
+ if found == 'Empty':
174
+ print(" Pity, zero record available for",ticker,'from',fromdate,'to',todate)
175
+
176
+ if found in ['Found'] and fill:
177
+ #需要产生连续工作日日期,以便对缺失值填充
178
+ dft1=df_fill_extend(dft1,colname='Close',extend_business_date=True)
179
+ dft1['Volume']=dft1.apply(lambda x: 0 if x['filled']==True else x['Volume'],axis=1)
180
+ dft1['Amount']=dft1.apply(lambda x: 0 if x['filled']==True else x['Amount'],axis=1)
181
+
182
+ return dft1,found
183
+
184
+ #==============================================================================
185
+ if __name__=='__main__':
186
+ ticker=["430047.BJ","600519.SS","000858.SZ"] #全股票
187
+ ticker_type='auto'
188
+ ticker_type=['auto','stock']
189
+
190
+ ticker=["sz169107","sh510050","sh010504","000858.SZ"] #LOF基金,ETF基金,国债,股票
191
+ ticker_type='bond'
192
+
193
+ ticker=['801002.SW',"600519.SS","sh510050","sh010504"] #申万指数,股票,ETF基金,国债
194
+ ticker_type='bond'
195
+
196
+ fromdate="2024-3-1"
197
+ todate="2024-4-1"
198
+
199
+ adjust=''
200
+ adjust=['','qfq']
201
+
202
+ source='auto'
203
+ fill=True
204
+
205
+ prices,found=get_price_mticker(ticker,fromdate,todate,adjust,source,ticker_type,fill)
206
+
207
+ def get_price_mticker(ticker,fromdate,todate, \
208
+ adjust='',source='auto',ticker_type='auto',fill=False):
209
+ """
210
+ 功能:多个证券(股票,指数,基金,债券),不含投资组合(否则容易引起递归调用)
211
+ ticker_type:若为'auto'则基金优先于债券(代码重合时),亦可为列表分别指定优先抓取类型。
212
+ 'stock', 'fund', 'bond',不足部分自动补充为最后项
213
+ 其中,'auto'/'stock'/'fund'优先抓取指数、股票和基金;'bond'优先抓取债券;
214
+
215
+ 注意:adjust,source,ticker_type既可以指定单个值,也可以使用列表分别指定各个证券
216
+ 不足部分由最后1个值补全
217
+ """
218
+ DEBUG=False
219
+
220
+ df=None; found='None'
221
+
222
+ #将证券代码列表化
223
+ if isinstance(ticker,list): ticker_list=ticker
224
+ else: ticker_list=[ticker]
225
+ ticker_num=len(ticker_list)
226
+
227
+ #将adjust列表化:不足部分由列表中最后1个值补全
228
+ if isinstance(adjust,list): adjust_list=adjust
229
+ else: adjust_list=[adjust]
230
+ adjust_len=len(adjust_list)
231
+
232
+ if ticker_num > adjust_len:
233
+ adjust1=adjust_list[-1] #延续最后项
234
+ adjust_list=adjust_list + [adjust1]*(ticker_num - adjust_len)
235
+
236
+ #将source列表化
237
+ if isinstance(source,list): source_list=source
238
+ else: source_list=[source]
239
+ source_len=len(source_list)
240
+
241
+ if ticker_num > source_len:
242
+ source1=source_list[-1] #延续最后项
243
+ source_list=source_list + [source1]*(ticker_num - source_len)
244
+
245
+ #预处理ticker_type
246
+ ticker_type_list=ticker_type_preprocess_mstr(ticker,ticker_type)
247
+
248
+ #单个普通证券的特殊处理,不产生MultiIndex,避免后续程序识别出错
249
+ if ticker_num == 1:
250
+ df,found=get_price_1ticker(ticker=ticker_list[0],fromdate=fromdate,todate=todate, \
251
+ adjust=adjust_list[0],source=source_list[0], \
252
+ ticker_type=ticker_type_list[0])
253
+
254
+ #多个普通证券
255
+ if ticker_num > 1:
256
+ for t in ticker_list:
257
+ pos=ticker_list.index(t)
258
+ at=adjust_list[pos]
259
+ st=source_list[pos]
260
+ tt=ticker_type_list[pos]
261
+
262
+ #普通单个证券
263
+ dft,found=get_price_1ticker(t,fromdate,todate,adjust=at,source=st,ticker_type=tt)
264
+ if found=='Found':
265
+ columns=create_tuple_for_columns(dft,t)
266
+ dft.columns=pd.MultiIndex.from_tuples(columns)
267
+ else: continue
268
+
269
+ if df is None: df=dft
270
+ else: #合并
271
+ df=pd.merge(df,dft,how='outer',left_index=True,right_index=True)
272
+
273
+ found=df_have_data(df)
274
+
275
+ return df,found
276
+
277
+ #==============================================================================
278
+ if __name__=='__main__':
279
+ #股票组合
280
+ ticker={'Market':('China','000001.SS','白酒组合'),'600519.SS':0.4,'000858.SZ':0.6}
281
+ ticker_type='auto'
282
+
283
+ #股债/股基组合
284
+ ticker={'Market':('China','000001.SS','股债组合'),'600519.SS':0.4,'sh010504':0.6}
285
+ ticker_type='bond' #股债组合
286
+ ticker_type='auto' #股基组合
287
+
288
+ #股债基组合:分别指定每个成份股的品种(股票,债券,基金),份额自动换算
289
+ ticker={'Market':('China','000001.SS','股债基组合'),'600519.SS':50,'sh018003':150,'sh010504':300}
290
+ ticker_type=['stock','bond','fund']
291
+
292
+ fromdate='2024-1-1'
293
+ todate='2024-4-1'
294
+ adjust=''
295
+ source='auto'
296
+ fill=True
297
+
298
+ pf,found=get_price_1portfolio(ticker=ticker,fromdate=fromdate,todate=todate, \
299
+ adjust=adjust,source=source,ticker_type=ticker_type, \
300
+ fill=fill)
301
+
302
+ def get_price_1portfolio(ticker,fromdate,todate, \
303
+ adjust='',source='auto',ticker_type='bond',fill=True):
304
+ """
305
+ 功能:抓取1个投资组合的信息,不能处理单个证券或证券列表
306
+ 注意:
307
+ 投资组合采用字典格式,但各个成份股份额之和不一定为1
308
+ fill默认为True,否则由于成份股股价为nan时投资组合价格会受影响
309
+ """
310
+
311
+ #返回值初始状态,确保各种情况下都有返回值
312
+ df=None
313
+ found='None'
314
+
315
+ #只处理投资组合
316
+ if not isinstance(ticker,dict):
317
+ print(" #Warning(get_price_1portfolio): not in dict format for",ticker)
318
+ return df,found
319
+
320
+ #检查日期期间合理性
321
+ valid_period,fromdatepd,todatepd=check_period(fromdate,todate)
322
+ if not valid_period:
323
+ print(" #Warning(v): invalid date period from",fromdate,"to",todate)
324
+ return df,found
325
+
326
+ #拆分投资组合为成份股列表和份额列表
327
+ _,_,tickerlist,sharelist=decompose_portfolio(ticker)
328
+
329
+ #处理份额列表,确保其和为1
330
+ share_sum=sum(sharelist)
331
+ sharelist1=[x / share_sum for x in sharelist]
332
+
333
+ #预处理ticker_type
334
+ ticker_type=ticker_type_preprocess_1portfolio(ticker,ticker_type)
335
+
336
+ #抓取各个成份股的价格信息
337
+ prices,found=get_price_mticker(ticker=tickerlist, \
338
+ fromdate=fromdate,todate=todate, \
339
+ adjust=adjust,source=source, \
340
+ ticker_type=ticker_type,fill=fill)
341
+
342
+ if found not in ['Found','Empty']:
343
+ return df,found
344
+
345
+ #加权平均,矩阵乘法
346
+ df=pd.DataFrame() #为None时无法对其赋值
347
+ collist=['Open','High','Low','Close','Adj Close','Amount']
348
+ for c in collist:
349
+ dfc=prices[c]
350
+ df[c]=dfc.dot(sharelist1)
351
+
352
+ df['Volume']=df.apply(lambda x: (x['Amount'] / x['Close']),axis=1)
353
+ df['ticker']=portfolio_name(ticker)
354
+ df['name']=df['ticker']
355
+ df['source']=source
356
+ df['component']=str(list(prices['name'].tail(1).values[0]))
357
+ df['portion']=str(sharelist1)
358
+
359
+ return df,found
360
+
361
+ #==============================================================================
362
+ if __name__=='__main__':
363
+ #股票组合
364
+ pf1={'Market':('China','000001.SS','白酒组合'),'600519.SS':0.4,'000858.SZ':0.6}
365
+ pf2={'Market':('China','000001.SS','股债组合'),'600519.SS':0.4,'sh010504':0.6}
366
+ pf3={'Market':('China','000001.SS','股债基组合'),'600519.SS':50,'sh018003':150,'sh010504':300}
367
+
368
+ pflist=[pf1,pf2]
369
+ pflist=[pf1,pf2,pf3]
370
+
371
+ ticker_type='bond'
372
+ ticker_type=['stock','bond','bond']
373
+
374
+ fromdate='2024-1-1'
375
+ todate='2024-4-1'
376
+ adjust=''
377
+ source='auto'
378
+ fill=True
379
+
380
+ pfs,found=get_price_mportfolio(ticker=pflist,fromdate=fromdate,todate=todate, \
381
+ adjust=adjust,source=source, \
382
+ ticker_type=ticker_type,fill=fill)
383
+
384
+
385
+ def get_price_mportfolio(ticker,fromdate,todate, \
386
+ adjust='',source='auto',ticker_type='bond',fill=True):
387
+ """
388
+ 功能:多个投资组合(股票,指数,基金,债券),不含非投资组合(否则容易引起递归调用)
389
+ ticker_type:可为单个、列表或列表中含有列表
390
+
391
+ 注意:adjust,source,ticker_type既可以指定单个值,也可以使用列表分别指定各个投资组合
392
+ 不足部分由最后1个值补全
393
+ """
394
+ DEBUG=False
395
+
396
+ df=None; found='None'
397
+
398
+ #将投资组合列表化
399
+ if isinstance(ticker,list): ticker_list=ticker
400
+ elif isinstance(ticker,dict): ticker_list=[ticker]
401
+ else: return df,found
402
+ ticker_num=len(ticker_list)
403
+
404
+ #将adjust列表化:不足部分由列表中最后1个值补全
405
+ if isinstance(adjust,list): adjust_list=adjust
406
+ else: adjust_list=[adjust]
407
+ adjust_len=len(adjust_list)
408
+
409
+ if ticker_num > adjust_len:
410
+ adjust1=adjust_list[-1] #延续最后项
411
+ adjust_list=adjust_list + [adjust1]*(ticker_num - adjust_len)
412
+
413
+ #将source列表化和补全
414
+ if isinstance(source,list): source_list=source
415
+ else: source_list=[source]
416
+ source_len=len(source_list)
417
+
418
+ if ticker_num > source_len:
419
+ source1=source_list[-1] #延续最后项
420
+ source_list=source_list + [source1]*(ticker_num - source_len)
421
+
422
+ #预处理ticker_type
423
+ ticker_type_list=ticker_type_preprocess_mticker_mixed(ticker,ticker_type)
424
+
425
+ #单个投资组合的特殊处理,不产生MultiIndex,避免后续程序识别出错
426
+ if ticker_num == 1:
427
+ df,found=get_price_1portfolio(ticker=ticker_list[0],fromdate=fromdate,todate=todate, \
428
+ adjust=adjust_list[0],source=source_list[0], \
429
+ ticker_type=ticker_type_list[0],fill=fill)
430
+
431
+ #多个投资组合
432
+ if ticker_num > 1:
433
+ for t in ticker_list:
434
+ pos=ticker_list.index(t)
435
+ at=adjust_list[pos]
436
+ st=source_list[pos]
437
+ tt=ticker_type_list[pos]
438
+
439
+ #单个投资组合
440
+ dft,found=get_price_1portfolio(ticker=t,fromdate=fromdate,todate=todate, \
441
+ adjust=at,source=st,ticker_type=tt,fill=fill)
442
+ if found=='Found':
443
+ tn=ticker_name(t)
444
+ columns=create_tuple_for_columns(dft,tn)
445
+ dft.columns=pd.MultiIndex.from_tuples(columns)
446
+ else: continue
447
+
448
+ if df is None: df=dft
449
+ else: #合并
450
+ df=pd.merge(df,dft,how='outer',left_index=True,right_index=True)
451
+
452
+ found=df_have_data(df)
453
+
454
+ return df,found
455
+
456
+ #==============================================================================
457
+ if __name__=='__main__':
458
+ #股票/债券/基金+投资组合
459
+ pf={'Market':('China','000001.SS','白酒组合'),'600519.SS':0.4,'000858.SZ':0.6}
460
+ ticker=[pf,'000002.SZ','002594.SZ','sh018003','sh010504']
461
+ ticker_type=[['auto','stock'],'auto','auto','bond'] #不足部分自动延续最后一个类型
462
+
463
+ fromdate='2024-1-1'
464
+ todate='2024-4-1'
465
+ adjust=''
466
+ source='auto'
467
+ fill=True
468
+
469
+ mix,found=get_price_mticker_mixed(ticker=ticker,fromdate=fromdate,todate=todate, \
470
+ adjust=adjust,source=source,ticker_type=ticker_type,fill=fill)
471
+
472
+ def get_price_mticker_mixed(ticker,fromdate,todate, \
473
+ adjust='',source='auto',ticker_type='auto',fill=False):
474
+ """
475
+ 功能:混合抓取证券列表的价格信息,列表中的元素可为多个股票、基金、债券或投资组合
476
+ 注意:
477
+ 可为列表中的各个元素分别指定证券类型ticker_type
478
+ 若元素为投资组合可为其指定类型列表(即列表中的列表)
479
+ 某个元素为债券时证券类型需要选择'bond'(即优先寻找债券),余者指定为'auto'即可
480
+
481
+ """
482
+
483
+ #返回值初始状态,确保各种情况下都有返回值
484
+ df=None; found='None'
485
+
486
+ #将ticker列表化
487
+ if isinstance(ticker,list): ticker_list=ticker
488
+ else: ticker_list=[ticker]
489
+ ticker_num=len(ticker_list)
490
+
491
+ #将adjust列表化和补全:不足部分由列表中最后1个值补全
492
+ if isinstance(adjust,list): adjust_list=adjust
493
+ else: adjust_list=[adjust]
494
+ adjust_len=len(adjust_list)
495
+
496
+ if ticker_num > adjust_len:
497
+ adjust1=adjust_list[-1] #延续最后项
498
+ adjust_list=adjust_list + [adjust1]*(ticker_num - adjust_len)
499
+
500
+ #将source列表化和补全
501
+ if isinstance(source,list): source_list=source
502
+ else: source_list=[source]
503
+ source_len=len(source_list)
504
+
505
+ if ticker_num > source_len:
506
+ source1=source_list[-1] #延续最后项
507
+ source_list=source_list + [source1]*(ticker_num - source_len)
508
+
509
+ #预处理ticker_type
510
+ ticker_type_list=ticker_type_preprocess_mticker_mixed(ticker,ticker_type)
511
+
512
+ #若列表中仅有1个元素,不需要产生MultiIndex
513
+ if ticker_num == 1:
514
+ #单个证券
515
+ if isinstance(ticker_list[0],str):
516
+ df,found=get_price_1ticker(ticker=ticker_list[0],fromdate=fromdate,todate=todate, \
517
+ ticker_type=ticker_type_list[0],source=source_list[0], \
518
+ adjust=adjust_list[0],fill=fill)
519
+
520
+ #单个投资组合
521
+ if isinstance(ticker_list[0],dict):
522
+ df,found=get_price_1portfolio(ticker=ticker_list[0],fromdate=fromdate,todate=todate, \
523
+ ticker_type=ticker_type_list[0],source=source_list[0], \
524
+ adjust=adjust_list[0],fill=fill)
525
+
526
+ return df,found
527
+
528
+ #若ticker是列表************************************************************
529
+ if ticker_num > 1:
530
+ for t in ticker_list:
531
+ pos=ticker_list.index(t)
532
+ at=adjust_list[pos]
533
+ st=source_list[pos]
534
+ tt=ticker_type_list[pos]
535
+
536
+ #单个普通证券
537
+ if isinstance(t,str):
538
+ dft,found=get_price_1ticker(ticker=t,fromdate=fromdate,todate=todate, \
539
+ adjust=at,source=st,ticker_type=tt,fill=fill)
540
+ tn=t
541
+
542
+ #单个投资组合
543
+ if isinstance(t,dict):
544
+ dft,found=get_price_1portfolio(ticker=t,fromdate=fromdate,todate=todate, \
545
+ adjust=at,source=st,ticker_type=tt,fill=fill)
546
+ tn=ticker_name(t)
547
+
548
+ if found=='Found':
549
+ columns=create_tuple_for_columns(dft,tn)
550
+ dft.columns=pd.MultiIndex.from_tuples(columns)
551
+ else: continue
552
+
553
+ if df is None: df=dft
554
+ else: #合并
555
+ df=pd.merge(df,dft,how='outer',left_index=True,right_index=True)
556
+
557
+ found=df_have_data(df)
558
+
559
+ return df,found
560
+
561
+ #==============================================================================
562
+ if __name__=='__main__':
563
+ #股票/债券/基金+投资组合
564
+ ticker={'Market':('China','000001.SS','白酒组合'),'600519.SS':0.4,'000858.SZ':0.6}
565
+ ticker='sh018003'
566
+ ticker_type='bond'
567
+
568
+ fromdate='2024-1-1'
569
+ todate='2024-4-1'
570
+ adjust=''
571
+ source='auto'
572
+ fill=True
573
+
574
+ mixed,found=get_price_1ticker_mixed(ticker=ticker,fromdate=fromdate,todate=todate, \
575
+ adjust=adjust,source=source,ticker_type=ticker_type,fill=fill)
576
+
577
+ def get_price_1ticker_mixed(ticker,fromdate,todate, \
578
+ adjust='',source='auto',ticker_type='auto',fill=False):
579
+ """
580
+ 功能:混合抓取证券列表的价格信息,列表中的元素需为单个股票、基金、债券或投资组合
581
+ 方便仅需一只证券的调用
582
+ """
583
+
584
+ #返回值初始状态,确保各种情况下都有返回值
585
+ df=None; found='None'
586
+
587
+ #若ticker为列表则取其第1个元素
588
+ if isinstance(ticker,list): ticker=ticker[0]
589
+
590
+ #若adjust为列表则取其第1个元素
591
+ if isinstance(adjust,list): adjust=adjust[0]
592
+
593
+ #若source为列表则取其第1个元素
594
+ if isinstance(source,list): source=source[0]
595
+
596
+ #若ticker_type为列表则取其第1个元素
597
+ if isinstance(ticker_type,list): ticker_type=ticker_type[0]
598
+
599
+ #单个证券
600
+ if isinstance(ticker,str):
601
+ df,found=get_price_1ticker(ticker=ticker,fromdate=fromdate,todate=todate, \
602
+ ticker_type=ticker_type,source=source, \
603
+ adjust=adjust,fill=fill)
604
+
605
+ #单个投资组合
606
+ if isinstance(ticker,dict):
607
+ df,found=get_price_1portfolio(ticker=ticker,fromdate=fromdate,todate=todate, \
608
+ ticker_type=ticker_type,source=source, \
609
+ adjust=adjust,fill=fill)
610
+
611
+ return df,found
612
+
613
+
614
+ #==============================================================================
615
+ #==============================================================================
616
+ #==============================================================================