本文记录使用easytrader+easyquotation实现策略的程序化交易的流程。笔记(50)已经记录了使用easytrader进行程序化交易的过程,本文主要对easyquotation获取实时数据实现策略进行介绍。
- easyquotation安装
pip install easyquotation
- 选择行情数据源
import easyquotation as eq
# 选择数据源
q = eq.use('qq') # 新浪 ['sina'] 腾讯 ['tencent', 'qq']
- 获取行情数据
quotation.stocks(['sz000001', 'sh600000'], prefix=True) # prefix默认为False
返回字典类型数据,类似于:
{
'sh000159': {
'name': '国际实业', # 股票名
'buy': 8.87, # 竞买价
'sell': 8.88, # 竞卖价
'now': 8.88, # 现价
'open': 8.99, # 开盘价
'close': 8.96, # 昨日收盘价
'high': 9.15, # 今日最高价
'low': 8.83, # 今日最低价
'turnover': 22545048, # 交易股数
'volume': 202704887.74, # 交易金额
'ask1': 8.88, # 卖一价
'ask1_volume': 111900, # 卖一量
'ask2': 8.89,
'ask2_volume': 54700,
'bid1': 8.87, # 买一价
'bid1_volume': 21800, # 买一量
...
'bid2': 8.86,
'bid2_volume': 78400,
'date': '2016-02-19',
'time': '14:30:00',
...},
......
}
以上就是easyquotation的基本用法,下面逐步记录使用easytrader+easyquotation逐步实现策略程序化交易的过程,所使用的策略为:放量突破20日均线就买入。
- 登录交易软件
if g_trade:
# 登陆交易软件
user = easytrader.use('htzq_client')
user.prepare(user='498XXXXXXX', password='XXXXXX', comm_password='XXXXXX',
exe_path='C:\\e海通财独立交易\\AlternateTradeSys5.18.73\\xiadan.exe')
详细的配置可以参见笔记(50)。
这里引入了一个全局变量g_trade,用于控制是否实盘交易,还是只是做数据跟踪。
- 获取待交易股票池
# 读取待跟踪股票代码
file = proj_path + 'data/temp/2021-03-29-20-27-59.csv'
stocks = pd.read_csv(file, converters={
'code': str})['code'].tolist()
读取的csv文件中包含了前一日筛选出的收盘在20日均线以下的股票代码(不包含前缀),将所有股票代码保存在列表stocks中。
- 读取股票历史数据
# 读取历史数据
history_data = {
}
for stock in stocks:
if '6' == stock[0:1]:
prefix_stock = 'sh.' + stock
else:
prefix_stock = 'sz.' + stock
history_file = proj_path + 'data/extend/d/qfq/lite/' + prefix_stock + '.csv'
history_data[stock] = pd.read_csv(history_file)[['close', 'ma_19', 'volume']].iloc[-1]
其中的条件分支主要用于在股票代码上添加前缀,来正确读取因子文件数据。baostock默认下载股票数据的代码格式"sh.XXXXXX"或"sz.XXXXXX"。因子计算可以参见笔记(47)。这里读取了股票池中股票的前一日收盘价、19日均线、前一日成交量数据。如果要使用复杂的策略,则需要提前进行对应的因子计算,并读入更多的因子。
- 循环遍历股票最新数据
# 循环遍历股票最新数据,判断是否买入
while True:
time.sleep(5 * 60)
每5分钟刷新一次数据。
- 判断是否进入交易时间
# 判断是否进入交易时间
time_now = datetime.datetime.now()
if time_now.time() < datetime.time(9, 30, 0) \
or datetime.time(11, 30, 0) <= time_now.time() <= datetime.time(13, 0, 0):
continue
if time_now.time() >= datetime.time(15, 0, 0):
break
如果是未开盘或者是午盘休息,则继续循环等待;如果收盘,则跳出循环。
- 更新成交量的权重
# 根据时间更新成交量权重
volume_weight = 1
if time_now.time() > datetime.time(13, 0, 0):
delta_seconds = (time_now - datetime.datetime(time_now.year, time_now.month, time_now.day, 13, 0, 0)).total_seconds()
volume_weight = 1 + delta_seconds / 7200
这里主要是对策略成交量的约束。如果上午突破20日均线,则要求当前成交量大于前一日成交量。如果下午突破20日均线,则按照收盘成交量是前一日两倍的标准,计算分时成交量权重。
- 判断是否买入
buy_stocks = {
}
data = q.stocks(stocks)
if g_trade:
balance = user.balance['可用金额']
for key in data:
# 价格过20日均线
ma_20 = (history_data[key]['ma_19'] * 19 + data[key]['now']) / 20
if not data[key]['now'] >= ma_20:
continue
# 涨幅不能过大
if not (data[key]['now'] - data[key]['close']) / data[key]['close'] < 0.0618:
continue
# 成交量
if not data[key]['volume'] > history_data[key]['volume'] * volume_weight:
continue
使用easyquotation获取股票实时数据,当同时满足价格突破20日均线,涨幅不能过大,且成交量满足放大条件时,进行买入。
8、买入
buy_price = 0.02 + data[key]['now']
if g_trade:
buy_limit = min(balance, 3000)
if 100 * buy_price < balance:
ret = user.buy(key, buy_price, buy_limit // (buy_price * 100) * 100)
print(ret)
buy_stocks[key] = buy_price
stocks.remove(key)
print(key)
在股票当前价格的基础上加2分作为买入价格,买入总额不超过3000元,记录价格,并在候选股票池中移除已挂买单的股票。
9、 保存符合买入条件的股票信息
if len(buy_stocks):
pd.DataFrame.from_dict(buy_stocks, orient='index').to_csv(proj_path + 'data/temp/' + time_str + '.csv')
保存的文件名为当前时间,文件内容有两列,第一列为当前时间买入的股票代码,第二列为买入价格。以2021年3月30日下午为例,共有3只股票在3个时间点符合了买入条件,因此保存为3个文件:
3只股票的代码和买入价格分别为"600133:5.99"、“600338:10.62”、“000911:9.21”。到本文发布时间(2021年4月10日),2只盈利,1只亏损。
策略程序化交易代码:
import easytrader
import easyquotation as eq
import os
import sys
import pandas as pd
import time
import datetime
# 获取当前目录
proj_path = os.path.dirname(os.path.abspath(sys.argv[0])) + '/../'
g_trade = False
if __name__ == '__main__':
if g_trade:
# 登陆交易软件
user = easytrader.use('htzq_client')
user.prepare(user='498XXXXXXX', password='XXXXXX', comm_password='XXXXXX',
exe_path='C:\\e海通财独立交易\\AlternateTradeSys5.18.73\\xiadan.exe')
# 读取待跟踪股票代码
file = proj_path + 'data/temp/2021-03-29-20-27-59.csv'
stocks = pd.read_csv(file, converters={
'code': str})['code'].tolist()
stocks.reverse()
# 读取历史数据
history_data = {
}
for stock in stocks:
if '6' == stock[0:1]:
prefix_stock = 'sh.' + stock
else:
prefix_stock = 'sz.' + stock
history_file = proj_path + 'data/extend/d/qfq/lite/' + prefix_stock + '.csv'
history_data[stock] = pd.read_csv(history_file)[['close', 'ma_19', 'volume']].iloc[-1]
# 选择数据源
q = eq.use('qq')
# 循环遍历股票最新数据,判断是否买入
while True:
time.sleep(5 * 60)
# 判断是否进入交易时间
time_now = datetime.datetime.now()
if time_now.time() < datetime.time(9, 30, 0) \
or datetime.time(11, 30, 0) <= time_now.time() <= datetime.time(13, 0, 0):
continue
if time_now.time() >= datetime.time(15, 0, 0):
break
# 根据时间更新成交量权重
volume_weight = 1
if time_now.time() > datetime.time(13, 0, 0):
delta_seconds = (time_now - datetime.datetime(time_now.year, time_now.month, time_now.day, 13, 0, 0)).total_seconds()
volume_weight = 1 + delta_seconds / 7200
print('\n', time_now)
time_str = time_now.strftime('%Y-%m-%d-%H-%M-%S')
buy_stocks = {
}
data = q.stocks(stocks)
if g_trade:
balance = user.balance['可用金额']
for key in data:
# 价格过20日均线
ma_20 = (history_data[key]['ma_19'] * 19 + data[key]['now']) / 20
if not data[key]['now'] >= ma_20:
continue
# 涨幅不能过大
if not (data[key]['now'] - data[key]['close']) / data[key]['close'] < 0.0618:
continue
# 成交量
if not data[key]['volume'] > history_data[key]['volume'] * volume_weight:
continue
buy_price = 0.02 + data[key]['now']
if g_trade:
buy_limit = min(balance, 3000)
if 100 * buy_price < balance:
ret = user.buy(key, buy_price, buy_limit // (buy_price * 100) * 100)
print(ret)
buy_stocks[key] = buy_price
stocks.remove(key)
print(key)
if len(buy_stocks):
pd.DataFrame.from_dict(buy_stocks, orient='index').to_csv(proj_path + 'data/temp/' + time_str + '.csv')
欢迎大家关注、点赞、转发、留言,感谢支持!
微信群用于学习交流,感兴趣的读者请扫码加微信!
QQ群(676186743)用于资料共享,欢迎加入!