当前位置: 首页 > news >正文

python量化交易——金融数据管理最佳实践——qteasy创建本地数据源

文章目录

  • qteasy金融历史数据管理
    • 总体介绍
    • 本地数据源——DataSource对象
      • 默认数据源
      • 查看数据表
      • 查看数据源的整体信息
      • 最重要的数据表
        • 其他的数据表
      • 从数据表中获取数据
      • 向数据表中添加数据
      • 删除数据表 —— 请尽量小心,删除后无法恢复!!
      • 总结

qteasy金融历史数据管理

qteasy 是一套功能全面的量化交易工具包,金融数据的获取和使用是qteasy提供的核心功能之一。

总体介绍

目前,网上有很多不同的金融数据获取渠道,可供量化交易者下载金融数据,但是直接从网上下载数据,有许多缺点:

  • 数据格式不统一:同样的数据,例如交易量数据,有些渠道提供的数据单位为“手”,而另一些提供的数据为“股”
  • 可提取的数据量有限:尤其是通过爬虫获取的数据,高频K线数据往往只有过去几天的数据,更久以前的数据无法提供
  • 数据提取不稳定:数据提取速度和成功率不能保证,受网络连接影响很大
  • 下载成本较高:收费数据渠道往往能提供更全面的数据,但是一般都有流量限制,而免费渠道提供的数据不全,也提高成本
  • 信息提取不易:获得原始数据以后,还需要进一步将数据转化为需要的信息,这个过程费力且不直观

qteasy就是为了解决上面提到的这些痛点而设计的。

qteasy的金融数据管理模块提供了三个主要的功能,这三个功能的设计,着眼点都是为了

  • 数据拉取:从多个不同的网络数据提供商拉取多种金融数据,满足不同用户的使用习惯:

    qteasy提供的数据拉取API具备强大的多线程并行下载、数据分块下载、下载流量控制和错误延时重试功能,以适应不同数据供应商各种变态的流量限制,同时数据拉取API可以方便地定期自动运行完成数据批量下载任务,不用担心错过高频数据。

  • 数据清洗和存储:标准化定义本地数据存储,将从网络拉取的数据清洗、整理后保存到本地数据库中:

    qteasy定义了一个专门用于存储金融历史数据的DataSource类,并以标准化的形式预定义了大量金融历史数据存储表,不管数据的来源如何,最终存储的数据始终会被清洗后以统一的格式存储在DataSource中,避免不同时期不同来源的数据产生偏差,确保数据高质量存储。同时提供多种存储引擎,满足不同用户的使用习惯。

  • 信息提取和使用:区分“数据“和”信息,“提供接口将集中在数据表中的真正有意义的信息提取出来,从而直接用于交易策略或数据分析:

    我们知道”数据“并不等于”信息“,光是将数据表保存在本地不代表立即就能使用其中的信息。而qteasy特意将数据表中的可用“信息”以标准化的方式定义为DataType对象,简化数据访问过程和策略的定义过程,统一的API使得获取信息的过程变得更加直接和友好

总体来说,qteasy的数据获取模块的结构可以用下面的示意图来表示:

在这里插入图片描述

如图所示,qteasy的数据功能分为三层,第一层包括多种数据下载接口,用于从网络数据提供商获取数据,这个过程称为DataFetching。第二层是qteasy的核心功能之一,定义了一个本地数据库用于存储大量的数据表,并且支持多种数据引擎,这一层的核心是DataSource类,第三层是数据应用层,将数据表中有意义的信息提取出来定义为DataType对象,提取数据的过程被称为Information Extraction。而这个DataType对象在qteasy内部被广泛使用,创建交易策略,进行数据分析、可视化等后续的一切工作,都是以DataType对象为基础进行的。

正因为金融数据在量化交易过程中的重要性,从下一章节开始,我们将详细介绍qteasy数据功能的所有功能模块:

  • 本地数据源——DataSource对象
  • 本地数据源——内置数据表
  • 拉取网络数据——从不同的渠道
  • 使用本地数据——DataType对象

本地数据源——DataSource对象

本地数据源是qteasy数据管理功能的核心,所有的数据都必须首先下载并保存在本地数据源中,才能为qteasy所用。qteasy使用DataSource对象管理本地数据源,本地数据源类似于一个数据库,包含一系列预先定义的数据表,DataSource类提供了一系列API用于数据表中数据的管理,包括读取、更新、删除和查询其中的数据。

要创建一个新的DataSource对象,可以使用下面的命令:

>>> import qteasy as qt
>>> ds = qt.DataSource()

通过打印datasource对象,可以查看其最基本的属性:

>>> print(ds)
file://csv@qt_root/data/

从datasource的打印字符串file://csv@qt_root/data/中,可以看出它的基本属性

打印结果包含数据源对象的基本信息:

  • file: – 数据源的类型。qteasy支持两种类型的数据源:文件型和数据库型,file代表数据源中的所有数据表都是以文件的形式保存在磁盘上的,同样,数据也可以保存在mysql数据库中,此时数据源的类型代码为db
  • csv: – 数据文件保存格式。qteasy可以将数据文件以不同的格式保存在磁盘上,最基本的格式为csv文件,但是用户同样可以将数据保存为hdf文件和fth文件(feather文件),以满足不同的性能偏好。
  • qt_root/data/: – 数据文件的保存路径。其中qt_root表示qteasy的安装根路径,默认情况下所有数据文件都保存在根目录下的/data/子路径下

同样,可以创建一个数据保存类型为数据库的数据源对象,并查看其基本属性:
不过,创建类型为数据库的数据源时,需要指定需要连接的Mysql数据库的主机名、用户名、密码、(或者)数据库名称等信息:

>>> ds_db = qt.DataSource(source_type='database', host='localhost', user='您的用户名', password='您的密码', db_name='test_db')
>>> print(ds_db)
db:mysql://localhost@3306/test_db

同样,打印结果中包含数据源的基本信息:

  • db:mysql – 数据源的类型为mysql数据库,所有的数据表都保存在数据库中
  • localhost – 数据库的主机名
  • 3306 – 数据库连接端口
  • test_db – 数据库名称,如果不指定名称,默认数据库qt_db,不过这个数据库必须事先创建好

不同的数据源对象,如果它们的存储方式不同,存储路径不同,那么它们所保存的数据没有关系,互不干扰,但如果两个数据源指向同一个路径,且文件类型相同时,那么它们所保存的数据就会重复。

要查看数据源的更多基本属性,可以调用数据源对象的几个属性查看:

>>> print(ds.source_type)  # 数据源的类型
file
>>> print(ds_db.source_type)
db
>>> print(ds.file_type, ds.file_path)  # 数据源的文件类型和存储路径
csv /Users/jackie/Projects/qteasy/qteasy/data/
>>> print(ds.connection_type, ds_db.connection_type)  # 数据源的连接类型
file://csv@qt_root/data/ db:mysql://localhost@3306/test_db

默认数据源

qteasy有一个内置默认的数据源,不需要用户手动创建,默认情况下,所有的数据都会保存到这个默认数据源,并从这个数据源读取。用户可以通过qteasy的配置文件配置该数据源的参数,确保该数据源指向正确的路径或使用正确的用户名登陆正确的数据库。通过下面的方法查看内置默认数据源的属性:

>>> print(qt.QT_DATA_SOURCE)
db:mysql://www.qteasy.online@3306/ts_db

查看数据表

了解数据源对象的基本属性后,下一步可以进一步了解数据源中保存的数据。

数据源中的数据表都是事先定义好的,每一张数据表都保存一类不同的数据,这些数据涵盖沪深股市、期货市场的股票、指数、基金、期货、期权等各种不同投资产品的基本信息、K线行情、上市公司业绩报表、宏观经济数据等等大量的数据,完整的数据表清单介绍,请参见下一章节,这里主要介绍如何查看各种数据表的基本情况和数据。

数据源中的数据表清单可以通过数据源的all_tables属性获取,它会返回一个列表对象,包含数据源中已经预定义的所有数据表。不过,这里必须厘清一个概念,数据源中虽然已经定义好了很多数据表,但这些数据表仅仅是有了基本的定义,即表头信息,数据表的字段名称、每个字段的含义以及数据类型都定义好了,但是刚刚建立的新数据源,其数据表往往都是空的,还没有任何数据。如果要查看数据源中有哪些数据表已经有了数据,需要用get_table_info()函数来获取:

>>> print('All tables in datasource:', len(ds.all_tables))
All tables in datasource: 108
>>> print('Some tables:', ds.all_tables[5:15])
Some tables: ['hk_trade_calendar', 'us_trade_calendar', 'stock_basic', 'hk_stock_basic', 'us_stock_basic', 'stock_names', 'stock_company', 'stk_managers', 'new_share', 'money_flow']

可见,目前版本的qteasy预定义了108张数据表,其中部分数据表的名称包括stock_basic等。

如果要查看当前数据源中某张数据表的详情,例如该数据表的定义,是否包含数据等信息,使用get_table_info()方法获取:

>>> info = ds.get_table_info('stock_basic')
<stock_basic>--<股票基本信息>
852KB/5K records on disc
primary keys: 
----------------------------------------
1:   ts_code:  <5396> entriesstarts: 000001.SZ, end: 920128.BJcolumns of table:
------------------------------------columns        dtypes remarks
0       ts_code    varchar(9)    证券代码
1        symbol    varchar(6)    股票代码
2          name   varchar(20)    股票名称
3          area   varchar(10)      地域
4      industry   varchar(10)    所属行业
5      fullname   varchar(50)    股票全称
6        enname  varchar(120)    英文全称
7       cnspell   varchar(40)    拼音缩写
8        market    varchar(6)    市场类型
9      exchange    varchar(6)   交易所代码
10    curr_type    varchar(6)    交易货币
11  list_status    varchar(4)    上市状态
12    list_date          date    上市日期
13  delist_date          date    退市日期
14        is_hs    varchar(2)  是否沪深港通

打印的信息包括数据表的名称、说明、数据表的字段定义以及数据类型。

值得说明的是,如果数据表中已经填充了数据,那么就会显示出数据表目前的大小,在上面的例子中,一些关键信息的解释如下:

  • 852KB/5K records on disc – 表示数据表占用磁盘空间大约852K字节,且数据量大约为5000行
  • primary keys – 显示数据的主键列,这里表示ts_code列为数据表的主键,且该列大约有5396条不同的记录。如果数据表有多个主键,那么每个主键列都分别列出,同时会列出该字段数据的范围,例如上例中ts_code列数据范围就是从000001.SZ开始一直到920128.BJ为止,让我们知道股票基本信息表里包含了代码从000001一直到920128为止的共五千多只股票的信息
  • columns of table – 这里显示数据表的字段定义,也就是数据表的schema。列出每一列的名称columns、数据类型dtypes以及说明信息remarks

另外,get_table_info()方法返回一个dict,同样包含该数据表的信息,可以将这些信息打印出来,与上述格式化信息对照了解:

>>> print(info)
{'table': 'stock_basic', 'table_exists': True, 'table_size': '852KB', 'table_rows': '5K', 'primary_key1': 'ts_code', 'pk_records1': 5396, 'pk_min1': '000001.SZ', 'pk_max1': '920128.BJ', 'primary_key2': None, 'pk_records2': None, 'pk_min2': None, 'pk_max2': None}

查看数据源的整体信息

通过上面的方法,我们可以查看每一张数据表的具体定义和已经填充的数据信息。同样,通过overview()方法,我们可以检查所有的数据表,并汇总出整个数据源的整体信息:

>>> 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/
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

查看整个数据源的总体信息,可能需要花费数分钟的时间,因为需要统计每张数据表的所有信息。

在统计过程中,qteasy会显示一根进度条显示统计的进度,最终统计分析完成后,qteasy会将数据源中所有数据表的信息以DataFrame的形式返回,并打印出关键的信息。

上面的信息显示了数据源中有3张数据表已经有了数据,包括trade_calendarstock_basicstock_daily,并显示了这些数据表的数据量、占用磁盘空间、数据的起始日期��结束日期等信息。如果想查看所有数据表的信息,可以将返回的DataFrame打印出来:

>>> print(overview)has_data   size records       pk1 records1       min1  \
table                                                                      
trade_calendar         True  1.8MB     70K  cal_date    12865   19901012   
hk_trade_calendar     False      0       0  cal_date  unknown        N/A   
us_trade_calendar     False      0       0  cal_date  unknown        N/A   
stock_basic            True  852KB      5K   ts_code     5396  000001.SZ   
hk_stock_basic        False      0       0   ts_code  unknown        N/A   
...                     ...    ...     ...       ...      ...        ...   
cn_cpi                False      0       0     month  unknown        N/A   
cn_ppi                False      0       0     month  unknown        N/A   
cn_money              False      0       0     month  unknown        N/A   
cn_sf                 False      0       0     month  unknown        N/A   
cn_pmi                False      0       0     month  unknown        N/A   max1       pk2 records2   min2  max2  
table                                                         
trade_calendar      20251231  exchange        7  CFFEX  SZSE  
hk_trade_calendar        N/A      None     None   None  None  
us_trade_calendar        N/A      None     None   None  None  
stock_basic        920128.BJ      None     None   None  None  
hk_stock_basic           N/A      None     None   None  None  
...                      ...       ...      ...    ...   ...  
cn_cpi                   N/A      None     None   None  None  
cn_ppi                   N/A      None     None   None  None  
cn_money                 N/A      None     None   None  None  
cn_sf                    N/A      None     None   None  None  
cn_pmi                   N/A      None     None   None  None  [104 rows x 11 columns]

最重要的数据表

如果您是第一次使用qteasy,很可能数据源中的数据表都是空的,没有任何数据。通常这没有任何问题,因为qteasy的设计初衷就是极大地简化金融数据的获取和使用过程。

您可以非常容易地从网络数据提供商处获取最基本的数据。不过,虽然数据表中的数据可以是空的,但是有几张数据表却比其他的数据表更加重要,您应该优先将这几张数据表的数据填充完整,因为这几张数据表中的数据是很多其他数据表的基础,甚至是qteasy的运行基础:

  • trade_calendar – 交易日历表,包含了所有交易所的交易日历信息,包括交易日、交易所代码、交易所名称等信息。可以说这是qteasy运行的基础,如果缺了这张表,qteasy的很多功能都将无法运行或者将降低效率。 qteasy使用这张表中的数据来判断交易日,如果要下载其他的数据表,通常也必须通过交易日数据表来确定下载的起止日期,因此,这是您应该绝对优先填充的数据表。
  • stock_basic – 股票基本信息表,包含了所有上市股票的基本信息,包括股票代码、股票名称、上市日期、退市日期、所属行业、地域等信息。这张表是很多其他数据表的基础,例如股票日K线数据表、股票财务数据表等,因此,这也是您应该优先填充的数据表。
  • index_basic – 指数基本信息表,包含了所有指数的基本信息,包括指数代码、指数名称、发布日期、退市日期等信息。这张表是很多其他数据表的基础,例如指数日K线数据表、指数成分股表等,因此,这也是您应该优先填充的数据表。
  • fund_basic – 基金基本信息表,包含了所有基金的基本信息,包括基金代码、基金名称、基金类型、基金规模等信息。这张表是很多其他数据表的基础,例如基金日K线数据表、基金净值数据表等,因此,这也是您应该优先填充的数据表。

基本上,如果您能够填充了上面这几张数据表的数据,那么您就可以开始比较顺畅使用qteasy的大部分数据相关的功能了。

另外,qteasy还在数据源中定义了几张系统数据表,这些表一共四张,用于存储跟实盘交易相关的信息:

  • sys_op_live_accounts – 实盘交易账户信息表,包含了所有实盘交易账户的基本信息,包括账户ID、账户名称、账户类型、账户状态等信息。
  • sys_op_positions – 实盘持仓信息表,包括所有实盘交易账户的持仓信息,包括账户ID、证券代码、证券名称、持仓数量、持仓成本等信息。
  • sys_op_trade_orders – 实盘交易委托表,包括所有实盘交易账户的交易委托信息,包括账户ID、委托时间、委托类型、证券代码、委托数量、委托价格等信息。
  • sys_op_trade_results – 实盘交易成交表,包括所有实盘交易账户的交易成交信息,包括账户ID、成交时间、证券代码、成交数量、成交价格等信息。

上面四张表是qteasy实盘交易功能的基础,这几张表中的数据不需要人为填充,而是系统自动生成,您不需要查看、填充或删除这些表

其他的数据表

除了上面提到的几张重要的数据表之外,数据源中还定义了大量的数据表,这些数据表包含了各种各样的金融数据,包括股票、指数、基金、期货、期权等各种金融产品的基本信息、日K线数据、财务数据、分红数据、业绩报表、宏观经济数据等等,主要分类如下:

  • 行情数据表 – 这类数据表包含了股票、基金、指数各个不同频率的K线行情数据
  • 基本信息表 – 这类数据表包含了股票、基金、指数、期货、期权等各种金融产品的基本信息
  • 指标信息表 – 这类数据表包含了各种指标的信息,例如技术指标、基本面指标、宏观经济指标等
  • 财务数据表 – 这类数据表包含了上市公司的财务报表数据,包括资产负债表、利润表、现金流量表等
  • 业绩报表表 – 这类数据表包含了上市公司的业绩报表数据,包括业绩快报、业绩预告、业绩预测等
  • 分红交易数据表 – 这类数据表包含了上市公司的分红数据,以及股票大宗交易、股东交易等信息表
  • 参考数据表 – 这类数据表包含了各种参考数据,例如宏观经济数据、行业数据、交易所数据等

这些数据表的具体定义和数据类型,可以通过get_table_info()方法查看,或者通过本文档的下一章节查询。

从数据表中获取数据

如果数据表中已经填充了数据,那么现在就可以从中读取数据了。DataSource提供了read_table_data()方法,从数据源中直接读取某个数据表中的数据,同时,用户可以筛选数据的起止日期以及证券代码,同时不用考虑数据表的具体结构、存储方式、存储位置等具体的实现方式。

为了避免读取的数据量过大,建议在读取数据时一定要同时给出某些筛选条件。对于read_table_data()方法来说,用户总是可以通过证券代码和起止日期来筛选数据:

  • shares: 给出一个证券代码或者逗号分隔的多个证券代码,如果数据表的主键中含有证券代码,那么根据该证券代码筛选输出的数据
  • start: 给出一个日期,格式为“YYYYMMDD”,如果数据表的主键包含时间或日期,那么根据筛选startend之间的数据,start/end必须成对给出
  • end: 给出一个日期,格式为“YYYYMMDD”,如果数据表的主键包含时间或日期,那么根据筛选startend之间的数据,start/end必须成对给出

DataSource对象会根据输入的筛选条件自动筛选数据,例如:

stock_daily表中读取一只股票(000651.SZ)从2024年1月1日到2024年1月15日之间的股票日K线数据:

>>> ds.read_table_data(table='stock_daily', shares='000651.SZ', start='20240101', end='20240115')open   high    low  ...  pct_chg        vol       amount
ts_code   trade_date                       ...                                 
000651.SZ 2024-01-03  32.00  32.08  31.70  ...  -0.7181  254468.92   810315.0132024-01-04  31.90  32.01  31.45  ...   0.4717  333398.05  1057458.4112024-01-08  33.12  33.21  32.85  ...  -0.2426  415911.34  1372722.0502024-01-02  32.17  32.20  31.96  ...  -0.4352  253797.30   814257.1752024-01-15  33.45  33.95  33.42  ...   0.6544  295681.34   996815.7252024-01-11  33.66  33.82  33.42  ...  -0.2376  284088.74   955075.1002024-01-09  32.81  33.55  32.65  ...   1.7933  438207.66  1454959.6372024-01-10  33.35  33.84  33.28  ...   0.5375  366485.52  1233441.5722024-01-12  33.50  33.83  33.42  ...   0.0893  224012.73   753931.8212024-01-05  32.05  33.29  31.62  ...   3.2238  832156.75  2738167.636[10 rows x 9 columns]

DataSource对象会自动根据数据表的定义来进行正确的筛选,并忽略掉不必要的参数。例如,我们可以筛选出某两支股票的基本信息。对于股票基本信息来说,交易日期是个不必要的参数,此时qteasy会自动忽略掉start/end参数并给出提示信息。同样,shares参数也不一定只能匹配股票代码,对于基金、指数、甚至期货、期权,都可以同样匹配:

>>> ds.read_table_data(table='stock_basic', shares='000651.SZ,000700.SZ', start='20240101', end='20240131')
/Users/jackie/Projects/qteasy/qteasy/database.py:1314: RuntimeWarning: list index out of range
can not find date-like primary key in the table stock_basic!
passed start(2024-01-01) and end(2024-01-31) arguments will be ignored!warnings.warn(msg, RuntimeWarning)symbol  name area industry  ... list_status list_date delist_date is_hs
ts_code                                ...                                        
000651.SZ     651  格力电器   广东     家用电器  ...           L  19961118         NaN     S
000700.SZ     700  模塑科技   江苏     汽车配件  ...           L  19970228         NaN     S[2 rows x 14 columns]

关于read_table_data()方法的更多信息,请参阅DataSource对象的参考信息。

向数据表中添加数据

如果数据表中尚未填充数据,或者数据表中填充的数据不足以满足我们的需求,那么读取数据就会不成功。为了避免这种情况,我们需要向数据表中填充数据。

向数据表中填充数据可以使用数据源的update_table_data()方法。使用这个API,用户可以将保存在一个DataFrame中的数据写入到相应的数据表中。这个API只需要给出三个参数:

  • table: 一个数据表的名称,需要写入数据的数据表
  • df: 一个DataFrame,保存了需要写入数据表中的数据
  • merge_type: 如果是update则更新数据表中已经存在的数据,如果是ignore则忽略重复的数据.

使用update_table_data()方法,用户不需要保证写入的数据格式与数据表完全一致,只要数据格式与数据表大致一致,qteasy就会自动整理数据格式、删除重复数据,确保写入数据表中的数据符合要求。

下面将一些示例数据写入数据源(写入的数据仅为演示效果)

>>> import pandas as pd
>>> df = pd.DataFrame({
...         'ts_code':    ['000001.SZ', '000002.SZ', '000003.SZ', '000004.SZ', '000005.SZ',
...                        '000001.SZ', '000002.SZ', '000003.SZ', '000004.SZ', '000005.SZ'],
...         'trade_date': ['20211112', '20211112', '20211112', '20211112', '20211112',
...                        '20211113', '20211113', '20211113', '20211113', '20211113'],
...         'open':       [1., 2., 3., 4., 5., 6., 7., 8., 9., 10.],
...         'high':       [2., 3., 4., 5., 6., 7., 8., 9., 10., 1.],
...         'low':        [3., 4., 5., 6., 7., 8., 9., 10., 1., 2.],
...         'close':      [4., 5., 6., 7., 8., 9., 10., 1., 2., 3.]
...     })
>>> print(df)ts_code trade_date  open  high   low  close
0  000001.SZ   20211112   1.0   2.0   3.0    4.0
1  000002.SZ   20211112   2.0   3.0   4.0    5.0
2  000003.SZ   20211112   3.0   4.0   5.0    6.0
3  000004.SZ   20211112   4.0   5.0   6.0    7.0
4  000005.SZ   20211112   5.0   6.0   7.0    8.0
5  000001.SZ   20211113   6.0   7.0   8.0    9.0
6  000002.SZ   20211113   7.0   8.0   9.0   10.0
7  000003.SZ   20211113   8.0   9.0  10.0    1.0
8  000004.SZ   20211113   9.0  10.0   1.0    2.0
9  000005.SZ   20211113  10.0   1.0   2.0    3.0

上面的DataFrame中保存了一些示例数据,我们下面将把这个DataFrame的数据写入数据源中的‘index_daily’数据表。
目前我们可以看到,index_daily数据表是空的,而且这个数据表的schema与上面的DataFrame并不完全相同:

  • index_daily数据表的数据定义中包含11列,而上面的数据只有6列,不过DataFrame中的所有列都包含在index_daily数据表的schema中
  • index_daily数据表目前是空的,没有填充任何数据
>>> info = ds.get_table_info('index_daily')
<index_daily>--<指数日线行情>
0 MB/0 records on disc
primary keys: 
----------------------------------------
1:   ts_code:  <unknown> entriesstarts: N/A, end: N/A
2:   trade_date:  <unknown> entriesstarts: N/A, end: N/Acolumns of table:
------------------------------------columns       dtypes  remarks
0      ts_code  varchar(20)     证券代码
1   trade_date         date     交易日期
2         open        float      开盘价
3         high        float      最高价
4          low        float      最低价
5        close        float      收盘价
6    pre_close        float      昨收价
7       change        float      涨跌额
8      pct_chg        float      涨跌幅
9          vol       double   成交量()
10      amount       double  成交额(千元)

接下来我们可以将数据写入数据表,如果方法执行正确,它将返回写入数据表中的数据的行数,如下所示:

>>> ds.update_table_data(table='index_daily', df=df)
10

将数据写入数据表之后,我们可以尝试一下从数据表中读取数据,现在我们已经可以读出刚才写入的数据了。

请注意,读出来的数据有许多列都是NaN值,这表明这些列没有写入数据,原因就是我们写入的df并不包含这些数据,因此读出的数据为NaN值。

>>> df = ds.read_table_data('index_daily', shares='000001.SZ, 000002.SZ')
>>> print(df)open  high  low  close  pre_close  change  pct_chg  vol  \
ts_code   trade_date                                                            
000001.SZ 2021-11-12   1.0   2.0  3.0    4.0        NaN     NaN      NaN  NaN   
000002.SZ 2021-11-12   2.0   3.0  4.0    5.0        NaN     NaN      NaN  NaN   
000001.SZ 2021-11-13   6.0   7.0  8.0    9.0        NaN     NaN      NaN  NaN   
000002.SZ 2021-11-13   7.0   8.0  9.0   10.0        NaN     NaN      NaN  NaN   amount  
ts_code   trade_date          
000001.SZ 2021-11-12     NaN  
000002.SZ 2021-11-12     NaN  
000001.SZ 2021-11-13     NaN  
000002.SZ 2021-11-13     NaN  

删除数据表 —— 请尽量小心,删除后无法恢复!!

我们除了可以向数据表中写入数据,从数据表中读取数据之外,当然也可以删除数据,不过请注意,在qteasy中操作DataSource删除数据时,您务必非常小心:因为qteasy不支持从数据表中删除部分数据,您只能删除整张数据表。

这是因为qteasy的数据源被设计为高效地存储和读取数据,但它并不是一个通常的数据库,我们并不需要经常操作其中的数据,这个数据仓库的作用是为了存储巨量的数据,因此,它的重点在于保存和提取数据,而不是删除操作。

qteasyDataSource对象提供了一个删除数据表的方法: drop_table_data(),这个方法将删除整个数据表,而且删除后无法恢复

为了避免在代码中误删除数据表,默认情况下drop_table_data()会导致错误,例如我们想删除之前写入临时数据的index_daily表:

>>> ds.drop_table_data('index_daily')
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In[19], line 1
----> 1 ds.drop_table_data('index_daily')File ~/Projects/qteasy/qteasy/database.py:1587, in DataSource.drop_table_data(self, table)1584 if not self.allow_drop_table:1585     err = RuntimeError('Can\'t drop table from current datasource according to setting, please check: '1586                        'datasource.allow_drop_table')
-> 1587     raise err1589 if self.source_type == 'db':1590     self._drop_db_table(db_table=table)RuntimeError: Can't drop table from current datasource according to setting, please check: datasource.allow_drop_table

这时候我们需要修改数据源的allow_drop_table属性,将其修改为True,这样就可以删除数据表了,请记住删除后将allow_drop_table改为False。

下面代码删除了index_daily表,然后就会发现,无法从该表读取数据了:

>>> ds.allow_drop_table = True
>>> ds.drop_table_data('index_daily')
>>> ds.allow_drop_table = False
>>> df = ds.read_table_data(table='index_daily')
>>> print(df)Empty DataFrame
Columns: []
Index: []

总结

至此,我们已经了解了DataSource对象,qteasy中金融历史数据管理的最重要的核心类的基本工作方式,了解了下面内容:

  • 什么是DataSource,如何创建一个数据源
  • 如何从数据源中提取数据
  • 如何操作数据源

在后面的章节中,您将会了解更多的内容:

  • 数据源中有哪些有用的金融数据?
  • 如何批量下载数据并填充到数据源中?
  • 如何从数据源中更有效地提取信息?

相关文章:

python量化交易——金融数据管理最佳实践——qteasy创建本地数据源

文章目录 qteasy金融历史数据管理总体介绍本地数据源——DataSource对象默认数据源查看数据表查看数据源的整体信息最重要的数据表其他的数据表 从数据表中获取数据向数据表中添加数据删除数据表 —— 请尽量小心&#xff0c;删除后无法恢复&#xff01;&#xff01;总结 qteas…...

手机放兜里,支付宝“碰一下”被盗刷?

大家好&#xff0c;我是小悟。 近期&#xff0c;网络上关于“支付宝‘碰一下’支付易被盗刷”的传言甚嚣尘上&#xff0c;不少用户对此心生疑虑。 首先&#xff0c;要明确一点&#xff1a;“碰一下”支付并不会像某些传言中所描述的那样容易被隔空盗刷。这一观点已经得到了支付…...

C/C++语言知识点一

目录 1. 请对这段代码进行解释&#xff1a;char *const *(*next)( ); 2. 函数指针数组&#xff1a;解释这个表达式char *(*c[10])(int **p); 3. 字符串常量&#xff1a;分析下面这段代码。 4. 访问指定内存地址 5. typedef 和 define 的区别 6. 函数返回局部变量地址问…...

前端面试题---在vue中为什么要用路由

在vue中为什么要用路由, 毕竟a标签可以直接跳转页面 在 Vue 中使用 Vue Router 的主要原因是提高 单页面应用&#xff08;SPA&#xff09; 的用户体验和性能。 相比传统的 <a> 标签跳转&#xff0c;Vue Router 提供了以下优势&#xff1a; 避免页面刷新&#xff1a; V…...

Three.js 快速入门教程【十】常见的纹理类型

系列文章目录 Three.js 快速入门教程【一】开启你的 3D Web 开发之旅 Three.js 快速入门教程【二】透视投影相机 Three.js 快速入门教程【三】渲染器 Three.js 快速入门教程【四】三维坐标系 Three.js 快速入门教程【五】动画渲染循环 Three.js 快速入门教程【六】相机控件 Or…...

文档识别-C#中英文文档识别接口-PDF文件内容识别API

文档识别接口可满足用户在数字化转型过程中对文档处理的高效、准确需求。翔云文档识别接口以成熟的文字识别技术、自然语言处理技术、图像识别技术为核心&#xff0c;能够将文档上的非可编辑文本转化为可编辑的数据&#xff0c;从而提升信息处理的速度与实现文档数字化管理的准…...

gRPG协议

gRPG协议是一种用于游戏开发的网络通信协议&#xff0c;全称为Game Real-time Protocol。它主要用于实现实时多人游戏中的数据传输和同步。gRPG协议的设计目标是提供低延迟、高可靠性的数据传输&#xff0c;以支持游戏中的实时互动和状态同步。 gRPG协议的特点 低延迟&#x…...

【maven打包错误】 无效的目标发行版:16

maven打包错误 错误截图 About 故事在一个风和日丽的下午&#xff0c;我一如往常的摸鱼&#xff0c;突如其来的事情打乱我的摸鱼节奏&#xff0c;“为什么测试不能用了” &#xff0c;随着前端帅哥一声轻咦&#xff0c;故事便开始了&#xff0c;我检查发现是是磁盘满了&#x…...

Oracle 查询表空间使用情况及收缩数据文件

本文介绍Oracle收缩数据文件的相关操作&#xff0c;运维工作中有时会需要通过收缩数据文件来释放磁盘空间。 数据文件初始化方式&#xff1a; 1.我们创建表空间一般有两种方式初始化其数据文件&#xff0c;即指定初始大小为32G&#xff08;很大的值&#xff09;或指定初始大小为…...

Transformer 代码剖析1 - 数据处理 (pytorch实现)

引言 Transformer 架构自《Attention Is All You Need》论文发表以来&#xff0c;在自然语言处理领域引起了巨大的变革。它摒弃了传统的循环结构&#xff0c;完全基于注意力机制&#xff0c;显著提高了处理序列数据的效率和性能。本文将通过对一个具体的项目代码结构进行详细分…...

Python异常处理面试题及参考答案

目录 什么是 Python 中的异常?程序为什么需要异常处理机制? 解释 BaseException 和 Exception 的区别 Python 的异常处理与传统的错误代码返回机制相比有哪些优势? 列出至少 5 个 Python 内置异常类型并说明触发场景 语法错误 (SyntaxError) 与运行时异常 (Runtime Erro…...

Python多线程知多少

目录 目标 Python版本 官方文档 概述 线程 守护线程 线程同步 事件对象&#xff08;Event Object&#xff09; 实战 创建线程的基本语法 阻塞线程 守护线程 线程同步的方法 互斥锁&#xff08;排他锁&#xff09; 信号量&#xff08;Semaphore&#xff09; 事件…...

C++ Qt常见面试题(8):C++ Qt中的线程同步与互斥

在C++ Qt中,线程同步和互斥通常通过 QMutex 和 QMutexLocker 来实现。线程同步确保多个线程不会同时访问共享资源,而互斥机制通过锁定一个资源,确保在任何给定时刻只有一个线程能够访问它。 以下是一个使用 QMutex 来同步和互斥访问共享资源的详细示例代码: 1. 使用 QMut…...

数字内容个性化推荐的关键是什么?

智能算法交互体系构建 构建数字内容体验的智能推荐系统&#xff0c;本质上是实现数据驱动与算法响应的动态协同。其核心在于建立多维度用户数据与机器学习模型的深度交互链路——通过实时采集用户点击、停留时长、交互路径等行为特征&#xff0c;结合设备属性、场景状态等上下…...

DeepSeek-OpenSourceWeek-第三天-Release of DeepGEMM

DeepGEMM:这是一款专为高效的 FP8(8 位浮点)通用矩阵乘法(GEMMs)而开发的尖端库。GEMMs 是许多 AI 工作负载(尤其是深度学习)中的基本操作。 特点: 支持稠密和 MoE GEMMs:它可以处理标准的稠密矩阵乘法以及混合专家(MoE)模型中使用的矩阵乘法。MoE 是一种神经网络架…...

LeetCode 1472.设计浏览器历史记录:一个数组完成模拟,单次操作均O(1)

【LetMeFly】1472.设计浏览器历史记录&#xff1a;一个数组完成模拟&#xff0c;单次操作均O(1) 力扣题目链接&#xff1a;https://leetcode.cn/problems/design-browser-history/ 你有一个只支持单个标签页的 浏览器 &#xff0c;最开始你浏览的网页是 homepage &#xff0c…...

AI+游戏,正在进行时!

2月&#xff0c;DeepSeek引领的AI浪潮对游戏行业造成了巨大冲击。 2月17日马斯克在社交平台宣布&#xff0c;xAI将成立一家AI游戏工作室&#xff0c;高调宣布两大核心理念&#xff0c;打破大公司的垄断&#xff0c;利用AI重构游戏体验。随后的新闻中还表示&#xff0c;团队计划…...

贪心算法精品题

1.找钱问题 本题的贪心策略在于我们希望就可能的保留作用大的5元 class Solution { public:bool lemonadeChange(vector<int>& bills) {std::map<int ,int> _map;for(auto ch:bills){if(ch 5) _map[ch];else if(ch 10){if(_map[5] 0) return false;else{_m…...

sql server 复制从备份初始化数据

参考 &#xff1a; 从备份初始化订阅&#xff08;事务&#xff09; - SQL Server | Microsoft Learn sql server 复制默认是用快照初始化数据的&#xff0c;也支持从备份初始化数据&#xff0c;参考如上...

【蓝桥杯】1.k倍区间

前缀和 #include <iostream> using namespace std; const int N100010; long long a[N]; int cnt[N]; int main(){int n, m;cnt[0] 1;cin >> n >> m;long long res 0;for(int i 1; i < n; i){scanf("%d", &a[i]);a[i] a[i-1];res cnt…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

对象回调初步研究

_OBJECT_TYPE结构分析 在介绍什么是对象回调前&#xff0c;首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例&#xff0c;用_OBJECT_TYPE这个结构来解析它&#xff0c;0x80处就是今天要介绍的回调链表&#xff0c;但是先不着急&#xff0c;先把目光…...