shepherdpp / qteasy

a python-based fast quantitative investment module
BSD 3-Clause "New" or "Revised" License
73 stars 28 forks source link

png

qteasy -- 一个本地化、灵活易用的高效量化投资工具包

PyPI PyPI - Wheel Build Status Documentation Status GitHub GitHub repo size GitHub code size in bytes GitHub top language PyPI - Implementation PyPI - Python Version GitHub branch checks state GitHub commit activity GitHub issues GitHub last commit GitHub contributors PyPI - Downloads PyPI - Downloads GitHub Repo stars GitHub forks GitHub watchers GitHub followers GitHub Sponsors

Note:

目前qteays正处于密集开发测试阶段,软件中不免存在一些漏洞和bug,如果大家使用中出现问题,欢迎Issue-报告bug或者提交新功能需求给我,也可以进入讨论区参与讨论。也欢迎各位贡献代码!

我会尽快修复问题并回复大家的问题。

关于qteasy

qteasy是为量化交易人员开发的一套量化交易工具包,特点如下:

  1. 全流程覆盖 从金融数据获取、存储,到交易策略的开发、回测、优化、实盘运行
  2. 完全本地化 所有的金融数据、策略运算和优化过程完全本地化,不依赖于任何云端服务
  3. 使用简单 提供大量内置交易策略,用户可以搭积木式地创建自己的交易策略
  4. 灵活多变 使用qteasy提供的策略类,用户可以自行创建自己的交易策略,灵活设置可调参数

qteasy能做什么?

获取并管理金融历史数据:

png

创建交易策略,模拟自动化交易

png
png
png

回测、评价、优化交易策略

png

安装

$ pip install qteasy

文档

关于QTEASY系统的更多详细解释和使用方法,请参阅QTEASY文档

python 版本

安装可选依赖包

qteasy所有必要的依赖包都可以在pip安装的同时安装好,但某些特殊情况下,您需要在安装时指定可选依赖包,以便在安装qteasy时同时安装,或者手动安装依赖包:

10分钟了解qteasy的功能

导入qteasy

基本的模块导入方法如下

import qteasy as qt
qt.__version__

配置本地数据源

为了使用qteasy,需要大量的金融历史数据,所有的历史数据都必须首先保存在本地,如果本地没有历史数据,那么qteasy的许多功能就无法执行。

qteasy默认通过tushare金融数据包来获取大量的金融数据,用户需要自行申请API Token,获取相应的权限和积分(详情参考:https://tushare.pro/document/2

因此,在使用qteasy之前需要对本地数据源和tushare进行必要的配置。在QT_ROOT_PATH/qteasy/路径下打开配置文件qteasy.cfg,可以看到下面内容:

# qteasy configuration file
# following configurations will be loaded when initialize qteasy

# example:
# local_data_source = database

配置tushare token

将你获得的tushare API token添加到配置文件中,如下所示:

tushare_token = <你的tushare API Token> 

配置本地数据源 —— 用MySQL数据库作为本地数据源

默认情况下qteasy使用存储在data/路径下的.csv文件作为数据源,不需要特殊设置。 如果设置使用mysql数据库作为本地数据源,在配置文件中添加以下配置:

local_data_source = database  

local_db_host = <host name>
local_db_port = <port number>
local_db_user = <user name>
local_db_password = <password>
local_db_name = <database name>

关闭并保存好配置文件后,重新导入qteasy,就完成了数据源的配置,可以开始下载数据到本地了。

下载金融历史数据

要下载金融价格数据,使用qt.refill_data_source()函数。下面的代码下载2021及2022两年内所有股票、所有指数的日K线数据,同时下载所有的股票和基金的基本信息数据。 (根据网络速度,下载数据可能需要十分钟左右的时间,如果存储为csv文件,将占用大约200MB的磁盘空间):

qt.refill_data_source(
        tables=['stock_daily',   # 股票的日线价格
                'index_daily',   # 指数的日线价格
                'basics'],       # 股票和基金的基本信息
        start_date='20210101',  # 下载数据的起止时间
        end_date='20221231',  
)

数据下载到本地后,可以使用qt.get_history_data()来获取数据,如果同时获取多个股票的历史数据,每个股票的历史数据会被分别保存到一个dict中。

qt.get_history_data(htypes='open, high, low, close', 
                    shares='000001.SZ, 000300.SH',
                    start='20210101',
                    end='20210115')

运行上述代码会得到一个Dict对象,包含两个股票"000001.SZ"以及"000005.SZ"的K线数据(数据存储为DataFrame):

{'000001.SZ':
              open   high    low  close
 2021-01-04  19.10  19.10  18.44  18.60
 2021-01-05  18.40  18.48  17.80  18.17
 2021-01-06  18.08  19.56  18.00  19.56
 ... 
 2021-01-13  21.00  21.01  20.40  20.70
 2021-01-14  20.68  20.89  19.95  20.17
 2021-01-15  21.00  21.95  20.82  21.00,

 '000300.SH':
                  open       high        low      close
 2021-01-04  5212.9313  5284.4343  5190.9372  5267.7181
 2021-01-05  5245.8355  5368.5049  5234.3775  5368.5049
 2021-01-06  5386.5144  5433.4694  5341.4304  5417.6677
 ...
 2021-01-13  5609.2637  5644.7195  5535.1435  5577.9711
 2021-01-14  5556.2125  5568.0179  5458.6818  5470.4563
 2021-01-15  5471.3910  5500.6348  5390.2737  5458.0812}

除了价格数据以外,qteasy还可以下载并管理包括财务报表、技术指标、基本面数据等在内的大量金融数据,详情请参见qteasy文档

股票的数据下载后,使用qt.candle()可以显示股票数据K线图。

import qteasy as qt
data = qt.candle('000300.SH', start='2021-06-01', end='2021-8-01', asset_type='IDX')

png

qteasy的K线图函数candle支持通过六位数股票/指数代码查询准确的证券代码,也支持通过股票、指数名称显示K线图 qt.candle()支持功能如下:

详细的用法请参考文档,示例如下(请先使用qt.refill_data_source()下载相应的历史数据):

import qteasy as qt
# 场内基金的小时K线图
qt.candle('159601', start = '20220121', freq='h')
# 沪深300指数的日K线图
qt.candle('000300', start = '20200121')
# 股票的30分钟K线,复权价格
qt.candle('中国电信', start = '20211021', freq='30min', adj='b')
# 期货K线,三条移动均线分别为9天、12天、26天
qt.candle('沪铜主力', start = '20211021', mav=[9, 12, 26])
# 场外基金净值曲线图,复权净值,不显示移动均线
qt.candle('000001.OF', start='20200101', asset_type='FD', adj='b', mav=[])

png

png

png

png

png

生成的K线图可以是一个交互式动态K线图(请注意,K线图基于matplotlib绘制,在使用不同的终端时,显示功能有所区别,某些终端并不支持 动态图表,详情请参阅 matplotlib文档

在使用动态K线图时,用户可以用鼠标和键盘控制K线图的显示范围:

gif

关于DataSource对象的更多详细介绍,请参见qteasy文档

创建一个投资策略并启动实盘自动化运行(模拟)

png

qteasy中的所有交易策略都是由qteast.Operator(交易员)对象来实现回测和运行的,Operator对象是一个策略容器,一个交易员可以同时 管理多个不同的交易策略。

qteasy提供了两种方式创建交易策略,详细的说明请参见使用教程:

创建一个DMA均线择时交易策略

在这里,我们将使用一个内置的DMA均线择时策略来生成一个最简单的大盘择时交易系统。所有内置交易策略的清单和详细说明请参见文档。

创建Operator对象时传入参数:strategies='DMA',可以新建一个DMA双均线择时交易策略。 创建好Operator对象后,可以用op.info()来查看它的信息。

import qteasy as qt

op = qt.Operator(strategies='dma')
op.info()

现在可以看到op中有一个交易策略,ID是dma,我们在Operator层面设置或修改策略的参数 时,都需要引用这个ID

DMA是一个内置的均线择时策略,它通过计算股票每日收盘价的快、慢两根移动均线的差值DMA与其移动平均值AMA之间的交叉情况来确定多空或买卖点。:

使用qt.built_ins()函数可以查看DMA策略的详细解,使用qt.built_ins()函数可以获取或者筛选需要的内置交易策略,例如:

import qteasy as qt
qt.built_in_doc('dma')
qt.built

得到:

 DMA择时策略

    策略参数:
        s, int, 短均线周期
        l, int, 长均线周期
        d, int, DMA周期
    信号类型:
        PS型:百分比买卖交易信号
    信号规则:
        在下面情况下产生买入信号:
        1, DMA在AMA上方时,多头区间,即DMA线自下而上穿越AMA线后,输出为1
        2, DMA在AMA下方时,空头区间,即DMA线自上而下穿越AMA线后,输出为0
        3, DMA与股价发生背离时的交叉信号,可信度较高

    策略属性缺省值:
    默认参数:(12, 26, 9)
    数据类型:close 收盘价,单数据输入
    采样频率:天
    窗口长度:270
    参数范围:[(10, 250), (10, 250), (8, 250)]
    策略不支持参考数据,不支持交易数据

在默认情况下,策略有三个可调参数(12,26,9), 但我们可以给出任意大于2小于250的三个整数作为策略的参数,以适应不同交易活跃度的股票、或者适应 不同的策略运行周期。

您可以使用qt.built_in_list()函数查看所有内置策略的清单,并使用qt.built_ins()qt.built_in_strategies()函数查看特定策略的详细说明。

启动交易策略的实盘自动化模拟运行

在配置好Operator对象并设置好策略后,qteasy可以自动定期运行、自动盯盘、自动下载实时数据并根据策略结果生成交易指令,模拟交易过程并记录交易结果。

Qteasy的实盘一旦启动,就会在terminal中启动一个单独的线程在后台运行,运行的时机也是跟真实的股票市场一致的,股票市场收市的时候不运行,交易日早上9点15分唤醒系统开始拉取实时股价,9点半开始运行交易策略,交易策略的运行时机和运行频率在策略的属性中设置。如果策略运行的结果产生交易信号,则根据交易信号模拟挂单,挂单成交后修改响应账户资金和股票持仓,交易费用按照设置中的费率扣除。如果资金不足或持仓不足会导致交易失败,当天买入的股票同真实市场一样T+1交割,第二个交易日开始前交割完毕。

import qteasy as qt

# 创建一个交易策略alpha
alpha = qt.get_built_in_strategy('ndayrate')  # 创建一个N日股价涨幅交易策略

# 设置策略的运行参数
alpha.strategy_run_freq = 'd'  # 每日运行
alpha.data_freq = 'd' # 策略使用日频数据
alpha.window_length = 20  # 数据窗口长度
alpha.sort_ascending = False  # 优先选择涨幅最大的股票
alpha.condition = 'greater'  # 筛选出涨幅大于某一个值的股票
alpha.ubound = 0.005  # 筛选出涨幅大于0.5%的股票
alpha.sel_count = 7  # 每次选出7支股票

# 创建一个交易员对象,运行alpha策略
op = qt.Operator(alpha, signal_type='PT', op_type='step')

# 设置策略运行参数
# 交易股票池包括所有的银行股和家用电器股
asset_pool = qt.filter_stock_codes(industry='银行, 家用电器', exchange='SSE, SZSE')

qt.configure(
        asset_type='E',  # 交易的标的类型为股票
        asset_pool=asset_pool,  # 交易股票池为所有银行股和家用电器股
        trade_batch_size=100,  # 交易批量为100股的整数倍
        sell_batch_size=1,  # 卖出数量为1股的整数倍
        live_trade_account_id=None,  # 不指定实盘交易账户,给出账户名称并创建一个新的账户
        live_trade_account_name='new_account'
        # 如果想要使用已有的账户,应该指定账户ID同时不给出account_name:
        # live_trade_account_id=1
        # live_trade_account_name=None
        live_trade_ui_type='tui',  # 使用TUI界面监控实盘交易,默认使用CLI界面
)

完成上述设置后,使用下面的代码运行交易策略,运行交易策略时指定模式0,代表实盘交易:

qt.run(op, mode=0,  # 交易模式为实盘运行)

Qteasy的实盘运行有一个“账户”的概念,就跟您在股票交易市场开户一样,一个账户可以有自己的持有资金,股票持仓,单独计算盈亏。运行过程中您可以随时终止程序,这时所有的交易记录都会保存下来,下次重新启动时,只要引用上一次运行使用的账户ID(account ID)就可以从上次中断的地方继续运行了,因此启动时需要指定账户,如果不想继续上次的账户,可以新开一个账户运行。

在启动实盘时可以通过qteasy的系统配置变量live_trade_account_name来指定使用的账户名,系统会自动创建一个新的账户并赋予账户ID;如果想要使用已有的账户,可以在启动时通过live_trade_account_id指定账户ID。

实盘自动化交易的控制界面

为了对策略运行过程进行监控,同时与qteasy进行互动,qteasy提供了两种不同的交互界面:

命令行用户界面 CLI

Terminal图形用户界面 TUI

上面两种方式都可以在实盘运行时使用,根据qteasy的配置参数进入不同的交互界,关于更多实盘运行的介绍,请参见QTEASY文档

回测、评价并优化交易策略的性能表现

交易策略的表现与策略的参数息息相关,针对不同类型的股票,不同的交易风格、不同的交易周期,策略的参数可能需要不同的设置,qteasy提供了策略回测功能,并多种优化算法,帮助搜索最优的策略参数,提高策略表现。

交易策略的回测

qteasy可以使用历史数据回测策略表现并输出图表如下: png

使用默认参数回测刚才建立的DMA策略在历史数据上的表现,可以使用op.run()

import qteasy as qt

op = qt.Operator(strategies='dma')
res = op.run(
        mode=1,                         # 历史回测模式
        asset_pool='000300.SH',         # 投资资产池,即允许投资的股票或指数,此处为沪深300指数
        asset_type='IDX',               # 投资资产类型,IDX表示指数,E表示股票
        invest_cash_amounts=[100000],   # 初始投资资金,此处为10万元
        invest_start='20220501',        # 投资回测开始日期
        invest_end='20221231',          # 投资回测结束日期
        cost_rate_buy=0.0003,           # 买入费率,此处为0.03%
        cost_rate_sell=0.0001,          # 卖出费率,此处为0.01%
        visual=True,                    # 打印可视化回测图表
        trade_log=True                  # 打印交易日志
)

输出结果如下:

     ====================================
     |                                  |
     |       BACK TESTING RESULT        |
     |                                  |
     ====================================

qteasy running mode: 1 - History back testing
time consumption for operate signal creation: 4.4 ms
time consumption for operation back looping:  82.5 ms

investment starts on      2022-05-05 00:00:00
ends on                   2022-12-30 00:00:00
Total looped periods:     0.7 years.

-------------operation summary:------------
Only non-empty shares are displayed, call 
"loop_result["oper_count"]" for complete operation summary

          Sell Cnt Buy Cnt Total Long pct Short pct Empty pct
000300.SH    6        6      12   56.4%      0.0%     43.6%   

Total operation fee:     ¥      257.15
total investment amount: ¥  100,000.00
final value:              ¥  105,773.09
Total return:                     5.77% 
Avg Yearly return:                8.95%
Skewness:                          0.58
Kurtosis:                          3.54
Benchmark return:                -3.46% 
Benchmark Yearly return:         -5.23%

------strategy loop_results indicators------ 
alpha:                            0.142
Beta:                             1.003
Sharp ratio:                      0.637
Info ratio:                       0.132
250 day volatility:               0.138
Max drawdown:                    11.92% 
    peak / valley:        2022-08-17 / 2022-10-31
    recovered on:         Not recovered!

===========END OF REPORT=============

png

交易策略的参数调优

交易策略的表现与参数有关,如果输入不同的参数,策略回报相差会非常大。qteasy可以用多种不同的优化算法,帮助搜索最优的策略参数,

要使用策略优化功能,需要设置交易策略的优化标记opt_tag=1,并配置环境变量mode=2即可:

import qteasy as qt

op = qt.Operator(strategies='dma')
op.set_parameter('dma', opt_tag=1)
res = op.run(mode=2,                    # 优化模式
             opti_start='20220501',     # 优化区间开始日期
             opti_end='20221231',       # 优化区间结束日期
             test_start='20220501',     # 测试区间开始日期
             test_end='20221231',       # 测试区间结束日期
             opti_sample_count=1000,    # 优化样本数量
             visual=True,               # 打印优化结果图表
             parallel=False)            # 不使用并行计算

qteasy将在同一段历史数据(优化区间)上反复回测,找到结果最好的30组参数,并把这30组参数在另一段历史数据(测试区间)上进行独立测试,并显 示独立测试的结果:

==================================== 
|                                  |
|       OPTIMIZATION RESULT        |
|                                  |
====================================

qteasy running mode: 2 - Strategy Parameter Optimization

... # 省略部分输出

# 以下是30组优化的策略参数及其结果(部分结果省略)
    Strategy items Sell-outs Buy-ins ttl-fee     FV      ROI  Benchmark rtn MDD 
0     (35, 69, 60)     1.0      2.0    71.45 106,828.20  6.8%     -3.5%     9.5%
1   (124, 104, 18)     3.0      2.0   124.86 106,900.59  6.9%     -3.5%     7.4%
2   (126, 120, 56)     1.0      1.0    72.38 107,465.86  7.5%     -3.5%     7.5%
...
27   (103, 84, 70)     1.0      1.0    74.84 114,731.44 14.7%     -3.5%     8.8%
28  (143, 103, 49)     1.0      1.0    74.33 116,453.26 16.5%     -3.5%     4.3%
29   (129, 92, 56)     1.0      1.0    74.55 118,811.58 18.8%     -3.5%     4.3%

===========END OF REPORT=============

png
将优化后的参数应用到策略中,并再次回测,可以看到结果明显提升:

op.set_parameter('dma', pars=(143, 99, 32))
res = op.run(
        mode=1,                         # 历史回测模式
        asset_pool='000300.SH',         # 投资资产池
        asset_type='IDX',               # 投资资产类型
        invest_cash_amounts=[100000],   # 投资资金
        invest_start='20220501',        # 投资回测开始日期
        invest_end='20221231',          # 投资回测结束日期
        cost_rate_buy=0.0003,           # 买入费率
        cost_rate_sell=0.0001,          # 卖出费率
        visual=True,                    # 打印可视化回测图表
        trade_log=True,                 # 打印交易日志
)

结果如下:

png

关于策略优化结果的更多解读、以及更多优化参数的介绍,请参见详细文档