12. 使用數據獲取渠道自動填充數據

前面介紹過DataSource對象的基本操作方法,但是在實際使用中,我們需要往DataSource對象中填充大量數據,如果使用前面章節介紹的DataSource.update_table_data()方法手動填充數據,這樣的工作量是非常大的。

這裏我們介紹如何使用數據獲取渠道自動填充數據。

12.1. QTEASY數據拉取功能

QTEASY數據管理模塊: 數據獲取模塊結構

如上圖所示,qteasy的數據功能分爲三層,第一層包括多種數據下載接口,用於從網絡數據提供商獲取數據,這個過程稱爲DataFetching

12.2. 數據拉取接口refill_data_source()

qteasy提供了一個自動化數據下載接口qteasy.refill_data_source(),可以從多個不同的網絡數據提供商拉取多種金融數據,滿足不同用戶的使用習慣。qteasy提供的數據拉取API具備強大的多線程並行下載、數據分塊下載、下載流量控制和錯誤延時重試功能,以適應不同數據供應商各種變態的流量限制,同時數據拉取API可以方便地定期自動運行完成數據批量下載任務,不用擔心錯過高頻數據。

下面先用一個例子解釋如何使用qteasy.refill_data_source()接口自動填充數據。我們先創建一個不含數據的DataSource對象,並向其中填充最基本的數據。

>>> import qteasy as qt
>>> ds = qt.DataSource()
# 检查数据源中是否有数据
>>> ds.overview()
Analyzing local data source tables... depending on size of tables, it may take a few minutes
[########################################]104/104-100.0%  A...zing completed!
Finished analyzing datasource: 
file://csv@qt_root/data/
3 table(s) out of 104 contain local data as summary below, to view complete list, print returned DataFrame
===============================tables with local data===============================
               Has_data Size_on_disk Record_count Record_start Record_end
table                                                                    
trade_calendar   True       1.8MB         70K          CFFEX        SZSE 
stock_basic      True       852KB          5K           None        None 
stock_daily      True      98.8MB        1.3M       20211112    20241231 

我們可以看到,DataSource對象中已經有了一些數據表,爲了進行下面的測試,我們將首先刪除trade_calendar以及stock_daily兩張數據表中的數據,然後再使用數據拉取接口自動填充它們。

首先刪除兩張數據表,爲了刪除數據表,首先將數據源的allow_drop_table屬性設置爲True,然後再刪除數據表。

>>> ds.allow_drop_table = True
>>> ds.drop_table_data('trade_calendar')
>>> ds.drop_table_data('stock_daily')
>>> ds.allow_drop_table = False
>>> overview = ds.overview()
Analyzing local data source tables... depending on size of tables, it may take a few minutes
[########################################]104/104-100.0%  A...zing completed!
Finished analyzing datasource: 
file://csv@qt_root/data/
1 table(s) out of 104 contain local data as summary below, to view complete list, print returned DataFrame
===============================tables with local data===============================
            Has_data Size_on_disk Record_count Record_start Record_end
table                                                                 
stock_basic   True       852KB         5K          None        None   

可以看到,trade_calendarstock_daily兩張數據表中的數據已經被刪除。

接下來,我們使用qteasy.refill_data_source()接口自動填充數據,代碼很簡單,只有一行,剩下的工作qteasy會自動完成。

>>> qt.refill_data_source(
        tables='stock_daily',  # 指定要填充的数据表:股票日K线数据
        channel='tushare',  # 指定数据下载渠道
        data_source=ds,  # 指定需要填充的数据源对象
        start_date='20210101',  # 指定数据下载的起始日期
        end_date='20211231',  # 指定数据下载的结束日期
)

Filling data source file://csv@qt_root/data/ ...
into 2 table(s) (parallely): {'stock_daily', 'trade_calendar'}
[########################################]243/243-100.0%  <stock_daily> 2398764 wrtn in about 16 sec                 
[########################################]7/7-100.0%  <trade_calendar> 70054 wrtn in about 1 sec                     
                    
Data refill completed! 2468818 rows written into 2/2 table(s)!

拉取並填充數據後,可以檢查數據已經下載成功了:

>>> ds.read_table_data('stock_daily', shares='000001.SZ, 000002.SZ', start='20211111', end='20211131')

                       open   high    low  close  pre_close  change  pct_chg  \
ts_code   trade_date                                                           
000001.SZ 2021-11-11  17.35  18.43  17.32  18.35      17.40    0.95   5.4598   
          2021-11-12  18.31  18.63  18.11  18.27      18.35   -0.08  -0.4360   
          2021-11-15  18.35  18.63  18.20  18.43      18.27    0.16   0.8758   
          2021-11-16  18.36  18.54  18.17  18.22      18.43   -0.21  -1.1394   
          2021-11-17  18.15  18.30  17.98  18.11      18.22   -0.11  -0.6037   
          2021-11-18  18.09  18.12  17.73  17.80      18.11   -0.31  -1.7118   
          2021-11-19  17.80  18.24  17.70  18.15      17.80    0.35   1.9663   
          2021-11-22  18.03  18.25  17.90  18.12      18.15   -0.03  -0.1653   
          2021-11-23  18.11  18.35  17.68  17.88      18.12   -0.24  -1.3245   
          2021-11-24  17.77  17.95  17.66  17.87      17.88   -0.01  -0.0559   
          2021-11-25  17.74  17.79  17.63  17.68      17.87   -0.19  -1.0632   
          2021-11-26  17.62  17.67  17.52  17.58      17.68   -0.10  -0.5656   
          2021-11-29  17.41  17.57  17.36  17.51      17.58   -0.07  -0.3982   
          2021-11-30  17.54  17.68  17.35  17.44      17.51   -0.07  -0.3998   
000002.SZ 2021-11-11  18.95  20.84  18.89  20.79      18.98    1.81   9.5364   
          2021-11-12  20.50  20.50  19.41  19.76      20.79   -1.03  -4.9543   
          2021-11-15  19.56  19.59  19.12  19.40      19.76   -0.36  -1.8219   
          2021-11-16  19.29  19.57  19.21  19.24      19.40   -0.16  -0.8247   
          2021-11-17  19.23  19.53  19.09  19.46      19.24    0.22   1.1435   
          2021-11-18  19.35  19.40  18.98  19.09      19.46   -0.37  -1.9013   
          2021-11-19  19.01  20.28  18.92  19.90      19.09    0.81   4.2431   
          2021-11-22  19.90  19.95  19.19  19.22      19.90   -0.68  -3.4171   
          2021-11-23  19.19  19.44  19.10  19.24      19.22    0.02   0.1041   
          2021-11-24  19.12  19.38  19.00  19.30      19.24    0.06   0.3119   
          2021-11-25  19.22  19.35  19.07  19.22      19.30   -0.08  -0.4145   
          2021-11-26  19.15  19.15  18.95  18.99      19.22   -0.23  -1.1967   
          2021-11-29  18.75  18.87  18.35  18.46      18.99   -0.53  -2.7909   
          2021-11-30  18.44  18.66  18.16  18.26      18.46   -0.20  -1.0834   

                             vol       amount  
ts_code   trade_date                           
000001.SZ 2021-11-11  2084729.00  3752413.858  
          2021-11-12   957546.46  1753072.716  
          2021-11-15   655089.99  1203764.095  
          2021-11-16   601110.48  1099113.409  
          2021-11-17   664640.38  1203859.180  
          2021-11-18   799843.77  1430058.311  
          2021-11-19   786371.56  1414506.380  
          2021-11-22   738617.80  1337768.172  
          2021-11-23  1235977.96  2213817.590  
          2021-11-24   741310.84  1316774.397  
          2021-11-25   603532.70  1068221.304  
          2021-11-26   694499.88  1219937.312  
          2021-11-29   512594.71   895105.981  
          2021-11-30   733616.06  1280384.552  
000002.SZ 2021-11-11  3151015.76  6352746.112  
          2021-11-12  2065924.12  4100076.111  
          2021-11-15   959331.52  1852352.374  
          2021-11-16   593989.40  1149085.955  
          2021-11-17   623749.71  1205064.294  
          2021-11-18   609995.75  1168010.581  
          2021-11-19  1308293.09  2570652.947  
          2021-11-22   877584.30  1697701.639  
          2021-11-23   563435.65  1083646.252  
          2021-11-24   827366.98  1587246.249  
          2021-11-25   518123.06   995473.890  
          2021-11-26   504023.33   959331.064  
          2021-11-29   718595.81  1334479.867  
          2021-11-30   713092.22  1305310.857

12.3. 數據拉取API的功能特性

分析數據拉取的過程,我們可以看到,qteasy自動完成了下面的工作:

  • 自動查找依賴表 —— 雖然我們只指定了stock_daily數據表,但是qteasy自動檢測到trade_calendar數據表也是空的,且stock_daily表依賴交易日曆表,所以也自動填充了trade_calendar數據表。

  • 下載進度可視化 —— qteasy提供了下載進度可視化,可以看到每個數據分塊的下載進度,以及總體下載進度,過程中可以顯示剩餘時間,方便用戶查看數據下載的情況。

  • 大數據量自動分塊 —— 上面的代碼下載了2021年全年所有股票的日K線數據,這些數據量共有239萬行,不管從任何數據渠道,這麼大量的數據都不可能一次性下載下來,因此,qteasy自動將數據分塊,每一塊只有一天的數據,可以看到整年的數據被分成了243塊,數據分塊下載顯著降低了每次網絡申請的數據量,提高成功率且降低了被阻斷的風險。

  • 多線程並行下載 —— 實行數據分塊下載後,qteasy自動使用多線程並行下載,加快數據下載速度,243個數據分塊並行下載總共耗時僅16秒。

有了上面這些特性,qteasy的數據拉取功能可以滿足幾乎所有用戶的數據獲取需求,不管是下載大量數據,還是下載高頻數據,qteasy都能提供高效的數據下載服務。

當然,除了上面提到的這些特性之外,qteasy還提供了更多的功能特性,以針對下載過程中出現的各種狀況,這些功能特性我們在後面會逐步介紹:

  • 多渠道下載 —— qteasy提供了多種數據下載渠道,很多數據表可以從多個不同的渠道下載,而且隨着版本更新,數據拉取渠道也在不斷增加。

  • 流量控制 —— 有些數據渠道對數據下載有流量限制,qteasy提供了流量控制功能,可以限制數據下載的速度,即下載一定分塊數量的數據後,可以暫停一段時間,例如每下載300個分塊的數據,就暫停一分鐘,避免被數據渠道封禁。

  • 錯誤重試 —— 有些數據渠道下載數據時,可能會出現網絡錯誤,qteasy提供了錯誤重試功能,可以在下載失敗後,自動重試下載,如果重試不成功,會延長重試等待時間再試,直到下載成功或超過重試次數並報錯。

  • 日誌記錄 —— qteasy提供了數據下載日誌記錄功能,可以記錄每次數據下載的詳細資訊,包括下載的數據量、下載的時間、下載的速度等,方便用戶查看數據下載的情況。

多渠道拉取數據

qteasy提供了多種數據下載渠道,很多數據表可以從多個不同的渠道下載,而且隨着版本更新,數據拉取渠道也在不斷增加。

refill_data_source()接口的channel参数可以指定数据下载渠道,如果不指定,qteasy会使用默认渠道tushare(见qteasy/core.pyrefill_data_source的默认逻辑)。用户也可以手动指定数据下载渠道。

当前内置四通道为:tushareakshareeastmoney(别名 emoney)、sina

四通道能力对照(常用表)

下表概括常用数据表在各通道下的支持情况(「支持」表示当前版本已实现映射并可走 refill 链路;「不支持」表示该通道无映射,refill 会跳过并提示)。AKShare 完整 108 表状态见仓库内维护清单 tests/akshare_data_test_checklist.md

数据表

tushare

akshare

eastmoney

sina

trade_calendar

支持(需 token/积分)

支持

暂不支持

暂不支持

stock_basic

支持(行业/上市日等完整)

支持(代码+简称索引;行业/地域等常为空)

部分场景不支持

暂不支持

index_basic / fund_basic

支持

支持(字段少于 Tushare 的项可能为空)

部分

暂不支持

stock_daily / weekly / monthly

支持

支持

支持(日/部分分)

支持(日/分)

stock_5/15/30min、hourly

支持

支持

支持

支持

stock_adj_factor

支持

支持(新浪因子源)

暂不支持

暂不支持

index_daily / weekly / monthly

支持

支持

支持(日)

暂不支持

fund_daily / weekly / monthly / 1min

支持

支持

部分

暂不支持

stock_suspend / money_flow / dividend

支持

支持

暂不支持

暂不支持

new_share / stock_company

支持

支持(字段可能少于 Tushare)

暂不支持

暂不支持

realtime_bars / realtime_quotes

支持

支持

支持

支持

index_1min 等指数分钟

支持

暂不支持(待 spike)

支持

暂不支持

说明:

  • basics 表与 merge_type='update':对 table_usage=='basics' 的表(如 stock_basicindex_basicfund_basic 等),主键冲突时仅用下载侧非空字段覆盖对应列,下载值为空字符串或 NULL 时保留本地已有值。因此可用 AKShare 补全代码列表拉分钟线依赖表,而不会冲掉此前用 Tushare 写入的 industrylist_date 等。按行业/地域筛选股票(filter_stocks / filter_stock_codes)仍建议以 Tushare 的 stock_basic 为准或先确认本地行业列非空。

  • tushare:覆盖最全,多数表需配置 tushare_token 及相应积分/权限。

  • akshare:无需 token;当前 25 张历史/基础/事件表已实现(见 tests/akshare_data_test_checklist.md),其余表仍为 blockednot_supportedstock_basic 等 basics 表仅保证 代码与名称索引,不替代 Tushare 完整基本面。

  • eastmoney:无需 token;分钟线覆盖较全,部分基础表(如 stock_basic)可能无法从此通道拉取。

  • sina:无需 token;以股票日线与分钟线为主,无周/月线等。

下面的代碼嘗試從eastmoney數據渠道下載stock_daily數據表從2025年最初兩個月的日K線數據:

>>> qt.refill_data_source(
        tables='stock_daily', 
        channel='eastmoney',   # 指定数据下载渠道为东方财经
        data_source=ds, 
        start_date='20250101', 
        end_date='20250301',
)

Filling data source file://csv@qt_root/data/ ...
into 2 table(s) (parallely): {'stock_daily', 'stock_basic'}
[########################################]11078/11078-100.0%  <stock_daily> 131264304 wrtn in about 17 min           
[----------------------------------------]0/1-0.0%  <stock_basic> can't be fetched from channel:eastmoney!
          
Data refill completed! 131264304 rows written into 1/2 table(s)!

驗證一下數據是否下載成功:

>>> ds.read_table_data('stock_daily', shares='000001.SZ, 000002.SZ', start='20250101', end='20250103')

                       open   high    low  close  pre_close  change  pct_chg  \
ts_code   trade_date                                                           
000001.SZ 2025-01-13  11.25  11.26  11.08  11.20      11.30   -0.10  -0.8850   
          2025-01-14  11.20  11.40  11.19  11.38      11.20    0.18   1.6071   
          2025-01-15  11.38  11.58  11.36  11.48      11.38    0.10   0.8787   
          2025-01-16  11.55  11.59  11.47  11.57      11.48    0.09   0.7840   
          2025-01-17  11.53  11.55  11.42  11.45      11.57   -0.12  -1.0372   
          2025-01-20  11.50  11.52  11.40  11.42      11.45   -0.03  -0.2620   
          2025-01-21  11.45  11.45  11.32  11.33      11.42   -0.09  -0.7881   
          2025-01-22  11.32  11.33  11.08  11.09      11.33   -0.24  -2.1183   
          2025-01-23  11.17  11.40  11.17  11.32      11.09    0.23   2.0739   
          2025-01-24  11.32  11.39  11.22  11.34      11.32    0.02   0.1767   
          2025-01-27  11.38  11.55  11.38  11.47      11.34    0.13   1.1464   
000002.SZ 2025-01-13   6.60   6.77   6.55   6.76       6.69    0.07   1.0463   
          2025-01-14   6.76   6.93   6.75   6.91       6.76    0.15   2.2189   
          2025-01-15   6.88   6.96   6.79   6.86       6.91   -0.05  -0.7236   
          2025-01-16   6.90   7.07   6.84   6.88       6.86    0.02   0.2915   
          2025-01-17   6.58   6.65   6.45   6.63       6.88   -0.25  -3.6337   
          2025-01-20   6.60   6.94   6.48   6.85       6.63    0.22   3.3183   
          2025-01-21   6.84   7.54   6.82   7.36       6.85    0.51   7.4453   
          2025-01-22   7.27   7.36   6.98   7.02       7.36   -0.34  -4.6196   
          2025-01-23   7.15   7.70   7.08   7.36       7.02    0.34   4.8433   
          2025-01-24   7.33   7.54   7.21   7.39       7.36    0.03   0.4076   
          2025-01-27   7.38   7.56   7.22   7.27       7.39   -0.12  -1.6238   

                            vol       amount  
ts_code   trade_date                          
000001.SZ 2025-01-13   934966.0  1044904.416  
          2025-01-14   824629.0   934467.766  
          2025-01-15  1031631.0  1185403.653  
          2025-01-16   872964.0  1007689.274  
          2025-01-17   689765.0   791230.419  
          2025-01-20   832029.0   953092.179  
          2025-01-21   902069.0  1024879.174  
          2025-01-22  1347129.0  1504818.607  
          2025-01-23  1514920.0  1715172.472  
          2025-01-24   944944.0  1069899.088  
          2025-01-27  1151935.0  1324270.607  
000002.SZ 2025-01-13   911147.0   611005.036  
          2025-01-14  1116454.0   765177.082  
          2025-01-15   887294.0   608363.557  
          2025-01-16  1110545.0   771648.218  
          2025-01-17  3620283.0  2369977.993  
          2025-01-20  2988167.0  2009728.944  
          2025-01-21  5849397.0  4290640.172  
          2025-01-22  3448728.0  2457396.391  
          2025-01-23  4416581.0  3245710.622  
          2025-01-24  2555024.0  1885566.128  
          2025-01-27  2151753.0  1580357.769  

數據下載顯然也是成功的。分析上面的下載過程,可以發現幾個特點:

  • 不同渠道下載的數據格式是相同的,這是qteasy的設計原則,不同的數據下載渠道下載的數據會經歷相同的清洗過程,這樣用戶可以方便地切換不同的數據下載渠道,而不用擔心數據格式不同導致的數據處理問題。

  • 不同的渠道下載分塊方式不同,導致下載速度不同,eastmoney數據渠道下載速度較慢,需要約17分鐘才能下載完成。這是由於不同下載渠道的特殊限制決定的。

  • 不同渠道的下載可以下載的數據表也不同,有些數據表無法通過某些渠道下載,可能是因爲權限限制或者其他因素導致的,如果某個數據表無法下載,qteasy會自動跳過這個數據表,不會影響其他數據表的下載。

因此,用戶需要根據自身的情況選擇不同的渠道拉取數據。

使用 AKShare 通道

AKShare 适合无 Tushare token、仅需 P0 行情表的场景。使用前请安装依赖:

pip install akshare

最小 refill 示例(短日期窗、指定 channel='akshare'):

>>> qt.refill_data_source(
        tables='stock_daily',
        channel='akshare',
        data_source=ds,
        shares='000001.SZ,600000.SH',
        start_date='20240101',
        end_date='20240110',
)

完整可运行脚本见仓库 examples/akshare_refill_minimal.py(需联网)。

限制与注意

  • AKShare 接口由第三方维护,稳定性与速率不可控;失败时会按 hist_dnld_retry_* 配置重试。

  • 当前版本承诺 108 张内置表均可从 AKShare 下载;扩表属于 S3.2 后续批次,详见 tests/akshare_data_test_checklist.md

  • 拉取分钟线时若自动补 stock_basic,AKShare 会更新代码/名称,但不会用空值覆盖已有 industry 等列;若库中从未写入过 Tushare 基本面,按行业选股前仍需 refill_data_source(tables='stock_basic', channel='tushare')

通道切换与配置

一次性下载(脚本 / 交互):在 refill_data_source(..., channel='...') 中显式传入通道名即可,例如 Tushare 与 AKShare 对比如下:

>>> qt.refill_data_source(tables='stock_daily', channel='tushare', start_date='20240101', end_date='20240131')
>>> qt.refill_data_source(tables='stock_daily', channel='akshare', start_date='20240101', end_date='20240131')

实盘默认渠道(写入 qteasy.cfg 或通过 qt.configure() 修改):

配置键

含义

默认值

live_trade_data_refill_channel

Trader 日更自动 refill 使用的通道

eastmoney

live_price_acquire_channel

实盘获取实时价格的通道

eastmoney

示例:

>>> qt.configure(live_trade_data_refill_channel='akshare')
>>> qt.configure(live_price_acquire_channel='akshare')

修改后,实盘任务会使用新通道执行 refill / 取价;历史脚本仍可在每次 refill_data_source 调用中单独指定 channel,与全局配置无关。

實現下載流量控制

qteasyrefill_data_source提供了流量控制功能,可以限制數據下載的速度,即下載一定分塊數量的數據後,可以暫停一段時間,例如每下載300個分塊的數據,就暫停一分鐘,避免被數據渠道封禁。

這個功能通過refill_data_source()接口的download_batch_sizedownload_batch_interval兩個參數實現:

  • download_batch_size參數指定每次下載的數據分塊數量,如果設置爲300,則在下載300個數據分塊後,會暫停一段時間。

  • download_batch_interval參數指定每次下載數據分塊後的暫停時間,默認爲0,即不暫停。

下面的代碼演示瞭如何使用download_batch_sizedownload_batch_interval參數實現下載流量控制:

>>> qt.refill_data_source(
        tables='stock_daily',
        channel='tushare',
        data_source=ds, 
        start_date='20250101', 
        end_date='20250301', 
        download_batch_size=300,  # 每次下载300个数据分块
        download_batch_interval=60,  # 每次下载300个数据分块后暂停60秒
)

如果是用流量控制,當然下載時間會變長,但是對於某些數據渠道,這是必須的,否則可能會被封禁或報錯導致下載失敗。

實現錯誤重試

需要注意的是,數據下載過程中出錯,qteasy會自動重試下載,重試機制如下:

  • 第一次下載失敗後重試之前會等待一段時間,默認等待時間爲1.0秒

  • 每次重試失敗後,等待時間都會增加,默認等待時間增加爲2倍,即第一次等待1.0秒,第二次等待2.0秒,第三次等待4.0秒,以此類推。

  • 重試超過最大限額後停止重試並報錯,默認情況下最多重複7次。

以上三個錯誤重試參數都是通過qteasy的配置文件在設定的,用戶可以通過qt.config()接口查看或修改這些參數,也可以在qteasy的初始配置文件中修改這些參數。

  • hist_dnld_retry_cnt - 最大重試次數,默認爲7次

  • hist_dnld_retry_wait - 第一次重試等待時間,默認爲1.0秒

  • hist_dnld_backoff - 重試等待時間增加倍數,默認爲2.0

關於如何修改配置文件,或者使用qteasy的初始配置文件,請參考qteasy的配置文件章節

日誌記錄

qteasy提供了數據下載日誌記錄功能,可以記錄每次數據下載的詳細資訊,包括下載的數據量、下載的時間、下載的速度等,方便用戶查看數據下載的情況。

其他功能

qteasyrefill_data_source()接口還提供了其他一些功能,例如:

  • 限制下載數據的範圍,可以通過start_dateend_date參數限制下載數據的時間範圍,通過shares參數限制下載數據的股票範圍。

  • 未传 start_date / end_date 时的默认行为:内部将 start_date 视为该表映射中的最早可用日(如 new_share19700101),end_date 视为当天。因此 tables='basics' 会包含需按日期分块下载的 new_share(IPO 新股);若不传日期,会从 1970-01-01 分块拉至今日,耗时较长。若只需代码/行业类 basics、不要 IPO 表,请显式指定表名或传入较窄的日期窗。

  • 設置是否並行下載,可以通過parallel參數設置是否並行下載,如果設置爲False,則會串行下載,否則會並行下載。

  • 設置是否下載依賴表,可以通過download_dependent參數設置是否下載依賴表,如果設置爲False,則不會下載依賴表,否則會下載依賴表。

  • 設置是否強制更新交易日曆表。

其他更多關於該接口的解釋,請參見qteasyAPI文檔