###################################
# 1、
# 本示例主要包含两个py文件
# TqTrade.py为交易逻辑所在文件,在主线程完成交易逻辑
# 主要是建立 参数字典,行情字典,以及交易的处理逻辑
# 这样每次遍历字典就可以在主线程中完成多合约单策略的交易
# 里面的策略请勿用于实盘,亏钱,亏钱,亏钱自负。
# 本程序所用写法会影响交易速度,有速度需求,请谨慎参考
# 2、
# TradeInterval.py 文件主要定义了各个品种的交易时间
# 以在策略中,当日进行平仓
# 更新记录 2019 年 12月 10 日
# 更新 TradeInterval.py 文件中郑商所品种的夜盘收盘时间
# 如果使用TradeInterval.py,有新品种上市请自行添加
###################################
###################################
## TradeInterval.py
###################################
#!/usr/bin/python3
# Filename: TradeInterval.py
# 本文件定义了各个品种的交易区间,以及查询给定合约给定时间的交易状态
import re
# 可以使用函数的方法某种特定的字典,类似C++ 中的结构体
# 定义交易需要的参数
def CreatPara(code):
# 建立一个字典数据
# 交易参数定义
# "code" :交易合约
# "orderId":订单编号
# "posvol":持仓量
# "posSide":持仓方向
# 'posPrice':持仓价格
para = {'code':code,
'orderId': '',
'posvol': 0,
'posside': 'BUY',
'posprice': 0}
return para
# 郑商所品种夜盘收盘时间表,-1 表示没有夜盘
# 白天各开盘时间和收盘时间都一样,不再定义
CZCE_NIGHT_END = {'TA':82800,
'MA':82800,
'SR':82800,
'CF':82800,
'CY':82800,
'ZC':82800,
'FG':82800,
'OI': 82800,
'RM': 82800,
'UR':-1,
'SM': -1,
'SF': -1,
'CJ':-1,
'AP': -1,
'WH': -1,
'RI': -1,
'LR': -1,
'JR': -1,
'RS': -1,
}
# 大商所品种交易时间定义
# 主要区别在于夜盘,白天交易时间不再单独定义
DCE_NIGHT_END = {'M':82800,
'Y':82800,
'A':82800,
'B':82800,
'P':82800,
'C':82800,
'CS':82800,
'RR':82800,
'L':82800,
'V':82800,
'PP':82800,
'EG':82800,
'EB':82800,
'J':82800,
'JM':82800,
'I':82800,
'JD':-1,
'BB':-1,
'FB':-1,
}
# 上期所品种交易时间定义
SHFE_NIGHT_END = {'CU':3600,
'AL':3600,
'ZN':3600,
'PB':3600,
'NI':3600,
'SN':3600,
'AU':9000,
'AG':9000,
'RB':82800,
'HC':82800,
'SS':82800,
'FU':82800,
'BU':82800,
'RU':82800,
'SP':82800,
'WR': -1,
}
# 能源交易所时间定义
INE_NIGHT_END = {'SC':9000,
'NR':82800
}
# 中金所品种交易时间定义
CFFEX_OPEN_TIME = {'IF':34200,
'IH':34200,
'IC':34200,
'TS':34200,
'TF':34200,
'T':34200}
# 当天结束交易的时间
CFFEX_DAY_END = {'IF':54000,
'IH':54000,
'IC':54000,
'TS':54900,
'TF':54900,
'T':54900}
def time2Secs(timestr):
# 本函数摘抄自如下链接
# https: // www.cnblogs.com / gayhub / p / 6154707.html
# 转换:hh:mm:ss 格式的时间为秒时间
h,m,s = timestr.strip().split(':')
return int(h) * 3600 + int(m) * 60 + int(s)
def secs_to_trade_end(symbol,timestr):
# 计算给定时间距离收盘的时间
# 先定义各个品种的交易时段信息
# 返回值
# interval 0 表示非交易时间,1-表示晚上,2-表示早上第一小节,3-表示早上第二小节,5-表示下午
# secsEnd 距离收盘的时间值
interval = 0
secend = -1
exch,sym = symbol.strip().split('.')
commodity = (''.join(re.split(r'[^A-Za-z]', sym))).upper()
secs = time2Secs(timestr)
if secs < 0:
return 0,0
if exch == "CZCE":
if 21 * 3600 - 1 < secs <= 23*3600 + 30 * 60:
#夜盘
if commodity in CZCE_NIGHT_END.keys():
if CZCE_NIGHT_END[commodity] < 0:
interval = 0
secend = 0
else:
interval = 1
secend = CZCE_NIGHT_END[commodity] - secs
else:
interval = 0
secend = 0
elif 9 * 3600 - 1 < secs <= 10 * 3600 + 15 * 60:
#早盘第二小节
if commodity in CZCE_NIGHT_END.keys():
interval = 2
secend = 10 * 3600 + 15 * 60 - secs
else:
interval = 0
secend = -1
elif 10 * 3600 + 30 * 60 <= secs <= 11 * 3600 + 30 * 60:
#早盘第二小节
if commodity in CZCE_NIGHT_END.keys():
interval = 3
secend = 11 * 3600 + 30 * 60 - secs
else:
interval = 0
secend = -1
elif 13 * 3600 + 30 * 60 <= secs <= 15 * 3600:
#下午时段
if commodity in CZCE_NIGHT_END.keys():
interval = 5
secend = 15 * 3600 - secs
else:
interval = 0
secend = 0
else:
return 0,0
elif exch == 'DCE':
if 21 * 3600 - 1 < secs <= 23*3600:
#夜盘
if commodity in DCE_NIGHT_END.keys():
if DCE_NIGHT_END[commodity] < 0:
interval = 0
secend = 0
else:
interval = 1
secend = DCE_NIGHT_END[commodity] - secs
else:
interval = 0
secend = 0
elif 9 * 3600 - 1 < secs <= 10 * 3600 + 15 * 60:
#早盘第二小节
if commodity in DCE_NIGHT_END.keys():
interval = 2
secend = 10 * 3600 + 15 * 60 - secs
else:
interval = 0
secend = -1
elif 10 * 3600 + 30 * 60 < secs <= 11 * 3600 + 30 * 60:
#早盘第二小节
if commodity in DCE_NIGHT_END.keys():
interval = 3
secend = 11 * 3600 + 30 * 60 - secs
else:
interval = 0
secend = -1
elif 13 * 3600 + 30 * 60 < secs <= 15 * 3600:
#下午时段
if commodity in DCE_NIGHT_END.keys():
interval = 5
secend = 15 * 3600 - secs
else:
interval = 0
secend = 0
else:
return 0,0
pass
elif exch == 'SHFE':
if secs > 21 * 3600 - 1:
#夜盘
if commodity in SHFE_NIGHT_END.keys():
if SHFE_NIGHT_END[commodity] > secs:
interval = 1
secend = SHFE_NIGHT_END[commodity] - secs
elif 0 < SHFE_NIGHT_END[commodity] < 3 * 3600:
interval = 1
secend = 86400 - secs + SHFE_NIGHT_END[commodity]
elif secs <= 2 * 3600 + 30 * 60:
if commodity in SHFE_NIGHT_END.keys():
if secs <= SHFE_NIGHT_END[commodity] < 2 * 3600 + 30 * 60 + 1:
interval = 1
secend = SHFE_NIGHT_END[commodity] - secs
elif 9 * 3600 - 1 < secs <= 10 * 3600 + 15 * 60:
# 早盘第二小节
if commodity in SHFE_NIGHT_END.keys():
interval = 2
secend = 10 * 3600 + 15 * 60 - secs
else:
interval = 0
secend = -1
elif 10 * 3600 + 30 * 60 < secs <= 11 * 3600 + 30 * 60:
# 早盘第二小节
if commodity in SHFE_NIGHT_END.keys():
interval = 3
secend = 11 * 3600 + 30 * 60 - secs
else:
interval = 0
secend = -1
elif 13 * 3600 + 30 * 60 < secs <= 15 * 3600:
#下午时段
if commodity in SHFE_NIGHT_END.keys():
interval = 5
secend = 15 * 3600 - secs
else:
interval = 0
secend = 0
else:
return 0,0
pass
elif exch == 'INE':
if secs > 21 * 3600 - 1:
#夜盘
if commodity in INE_NIGHT_END.keys():
if INE_NIGHT_END[commodity] > secs:
interval = 1
secend = INE_NIGHT_END[commodity] - secs
elif 0 < INE_NIGHT_END[commodity] < 3 * 3600:
interval = 1
secend = 86400 + INE_NIGHT_END[commodity] - secs
elif secs <= 2 * 3600 + 30 * 60:
if commodity in INE_NIGHT_END.keys():
if secs <= INE_NIGHT_END[commodity] < 2 * 3600 + 30 * 60 + 1:
interval = 1
secend = INE_NIGHT_END[commodity] - secs
elif 9 * 3600 - 1 < secs <= 10 * 3600 + 15 * 60:
#早盘第二小节
if commodity in INE_NIGHT_END.keys():
interval = 2
secend = 10 * 3600 + 15 * 60 - secs
else:
interval = 0
secend = -1
elif 10 * 3600 + 30 * 60 < secs <= 11 * 3600 + 30 * 60:
#早盘第二小节
if commodity in INE_NIGHT_END.keys():
interval = 3
secend = 11 * 3600 + 30 * 60 - secs
else:
interval = 0
secend = -1
elif 13 * 3600 + 30 * 60 < secs <= 15 * 3600:
#下午时段
if commodity in INE_NIGHT_END.keys():
interval = 5
secend = 15 * 3600 - secs
else:
interval = 0
secend = 0
else:
return 0,0
elif exch == 'CFFEX':
if 9 * 3600 < secs <= 11 * 3600 + 30 * 60:
#早盘
if commodity in CFFEX_OPEN_TIME.keys():
if secs - CFFEX_OPEN_TIME[commodity] < 0:
interval = 0
secend = 0
else:
interval = 3
secend = 11 * 3600 + 30 * 60 - secs
else:
interval = 0
secend = -1
elif 13 * 3600 <= secs <= 15 * 3600 + 15 * 60:
#下午时段
if commodity in CFFEX_OPEN_TIME.keys():
interval = 5
secend = CFFEX_OPEN_TIME[commodity] - secs
else:
interval = 0
secend = 0
else:
return 0,0
else:
return 0,0
# 如果 secend < 0 ,则说明不是交易时间
if secend < 0:
interval = 0
return interval,secend
def secs_to_open(symbol,timestr):
#检查当前时间距离开盘时间的秒数
interval = 0
secbegin = -1
exch, sym = symbol.strip().split('.')
commodity = (''.join(re.split(r'[^A-Za-z]', sym))).upper()
secs = time2Secs(timestr)
if secs < 0:
return 0,0
if exch == 'CZCE':
if 21 * 3600 - 1 < secs <= 23 * 3600 + 30 * 60:
if commodity in CZCE_NIGHT_END.keys():
if CZCE_NIGHT_END[commodity] > 0:
interval = 1
secbegin = secs - 21 * 3600
elif 9 * 3600 - 1 < secs <= 10 * 3600 + 15 * 60:
interval = 2
secbegin = secs - 9 * 3600
elif 10 * 3600 + 30 * 60 <= secs <= 11 * 3600 + 30 * 60:
interval = 3
secbegin = secs - 10 * 3600 - 30 * 60
elif 13 * 3600 + 30 * 60 <= secs <= 15 * 3600:
interval = 5
secbegin = secs - 13 * 3600 - 30 * 60
elif exch == 'DCE':
if 21 * 3600 - 1 < secs <= 23 * 3600:
if commodity in DCE_NIGHT_END.keys():
if DCE_NIGHT_END[commodity] > 0:
interval = 1
secbegin = secs - 21 * 3600
elif 9 * 3600 - 1 < secs <= 10 * 3600 + 15 * 60:
interval = 2
secbegin = secs - 9 * 3600
elif 10 * 3600 + 30 * 60 <= secs <= 11 * 3600 + 30 * 60:
interval = 3
secbegin = secs - 10 * 3600 - 30 * 60
elif 13 * 3600 + 30 * 60 <= secs <= 15 * 3600:
interval = 5
secbegin = secs - 13 * 3600 - 30 * 60
elif exch == 'SHFE':
if secs > 21 * 3600 - 1:
if commodity in SHFE_NIGHT_END.keys():
if SHFE_NIGHT_END[commodity] > 0:
if secs <= SHFE_NIGHT_END[commodity] or SHFE_NIGHT_END[commodty[ < 3 * 3600:
interval = 1
secbegin = secs - 21 * 3600
elif secs <= 2 * 3600 + 30 * 60:
if commodity in SHFE_NIGHT_END.keys():
if secs < SHFE_NIGHT_END[commodity] < 2 * 3600 +30 * 60 + 1:
interval = 1
secbegin = 3600
elif 9 * 3600 - 1 < secs <= 10 * 3600 + 15 * 60:
interval = 2
secbegin = secs - 9 * 3600
elif 10 * 3600 + 30 * 60 <= secs <= 11 * 3600 + 30 * 60:
interval = 3
secbegin = secs - 10 * 3600 - 30 * 60
elif 13 * 3600 + 30 * 60 <= secs <= 15 * 3600:
interval = 5
secbegin = secs - 13 * 3600 - 30 * 60
elif exch == 'INE':
if secs > 21 * 3600 - 1:
if commodity in INE_NIGHT_END.keys():
if INE_NIGHT_END[commodity] > 0:
if secs < INE_NIGHT_END[commodity] or INE_NIGHT_END[commodity] < 3 * 3600:
interval = 1
secbegin = secs - 21 * 3600
elif secs <= 2 * 3600 + 30 * 60:
if commodity in INE_NIGHT_END.keys():
if secs < INE_NIGHT_END[commodity] <= 2 * 3600 + 30 * 60:
interval = 1
secbegin = 3600
elif 9 * 3600 - 1 < secs <= 10 * 3600 + 15 * 60:
interval = 2
secbegin = secs - 9 * 3600
elif 10 * 3600 + 30 * 60 <= secs <= 11 * 3600 + 30 * 60:
interval = 3
secbegin = secs - 10 * 3600 - 30 * 60
elif 13 * 3600 + 30 * 60 <= secs <= 15 * 3600:
interval = 5
secbegin = secs - 13 * 3600 - 30 * 60
elif exch == 'CFFEX':
if 9 * 3600 <= secs <= 11 * 3600 + 30 * 60:
# 早盘
if commodity in CFFEX_OPEN_TIME.keys():
if secs - CFFEX_OPEN_TIME[commodity] < 0:
interval = 0
secbegin = 0
else:
interval = 3
secbegin = secs - CFFEX_OPEN_TIME[commodity]
else:
interval = 0
secbegin = -1
elif 13 * 3600 <= secs <= 15 * 3600 + 15 * 60:
# 下午时段
if commodity in CFFEX_OPEN_TIME.keys() and secs <= CFFEX_DAY_END[commodity]:
interval = 5
secbegin = secs - 13 * 3600
else:
interval = 0
secbegin = 0
else:
return 0,0
return interval,secbegin
if __name__ == '__main__':
a = 10
a -= 1
print(a)
code = 'CZCE.TA001'
time_str = '21:30:00'
print('Thie is assistan file')
# 提取code中大小写字母,并组成新
res = (''.join(re.split(r'[^A-Za-z]', code))).upper()
print(res.upper())
print(secs_to_trade_end(code,time_str))
print(secs_to_open(code,time_str))
if 'TA' in CZCE_NIGHT_END.keys():
print('TA in CZCE_NIGHT_END')
######################################
## TqTrade.py
######################################
### 此程序开始尝试编写一个简单的 tqsdk交易策略。
### 为以后做完整的界面进行铺路
### 本文提供一种单线程多合约相同策略的编写方式
#先做一个简单的均线策略
#交易循环逻辑
# 开仓和平仓的时候需要根据交易时间进行处理
#
# 循环:
#【1】、等待行情更新,并计算均线
#【2】、首先判断当前合约是否有订单需要处理:
# 如果有,则先处理订单,然后转到步骤【1】
# 如果没有待处理订单,转到步骤【3】
#【3】、检查是否有持仓需要处理
# 如果有持仓,则处理持仓,处理完成后,转到步骤【1】
# 如果没有持仓,则转到步骤【4】
#【4】、判断开仓条件是否满足,进行开仓。
# 无论是否开仓,完成后,都转到【1】
# author : Jieyou
from contextlib import closing
from tqsdk import TqApi
from tqsdk import TqAccount
from tqsdk import TqApi,TqSim,tafunc
import time
import TradeInterval
import threading
# 此处填写自己的模拟账号或交易账号
tq_company = "simnow"
# 此处填写自己的模拟账号和密码
tq_account = 'xxxxxx'
tq_pwd = 'pwd'
# 设定需要交易合约
list_code = ["CZCE.TA001","SHFE.ni2002"]
para1 = TradeInterval.CreatPara('CZCE.TA001')
ParaDic = {}
paraChFlag = {}
ParaDic.update({para1['code']:para1})
# para2 = CreatPara('SHFE.ni1912')
#para2['code'] = 'SHFE.ni1912'
#ParaDic.update({para2['code']:para2})
# 生成参数组以及标记合约行情变化的信息
for code in list_code:
ParaDic.update({code:TradeInterval.CreatPara(code)})
paraChFlag.update({code:{'qtime':'','chflag':True}})
print(ParaDic)
print(paraChFlag)
#exit(0)
#para1 = ParaDic['SHFE.ni1912']
#para1['posvol'] = 1
#para1['posPrice'] = 135000
#print(ParaDic)
#此种情况不会改变已经存入字典中的值
para1 = TradeInterval.CreatPara('CZCE.MA001')
print(para1)
print(ParaDic)
#时间戳转换为 HH:MM:SS 格式
print(type(time.strftime("%H:%M:%S", time.localtime())))
#exit(0)
def TradeFunc(para,qtick,aliveorder):
# 先判断时间
pass
try:
# 如果登陆失败则抛出异常
tq_acc_info = TqAccount(tq_company,tq_account,tq_pwd)
tq_api = TqApi(tq_acc_info)
#tq_api = TqApi(TqSim())
print("登陆成功")
# 获取资金信息,没有用到
fundInfo = tq_api.get_account()
# 获取订单信息
orderInfo = tq_api.get_order()
# 获取持仓信息,没有用到
posInfo = tq_api.get_position()
# 定义合约
# symbol = 'CZCE.TA001'
# kline_length = 20
# 定义 tick 字典
qtickDic = {}
for code in list_code:
qtickDic.update({code:tq_api.get_quote(code)})
# 定义 k 线字典
kLineDic = {}
for code in list_code:
kLineDic.update({code:tq_api.get_kline_serial(code,60,data_length=20)})
"""
# 此部分用于测试,建立的tick 字典以及 kline 字典是否正常工作
while True:
tq_api.wait_update()
for sym in qtickDic.keys():
if tq_api.is_changing(kLineDic[sym]):
print(sym,"up date")
"""
# 此部分代码大部分为测试某些代码的结果
# 在单合约需要,多合约的情况就不再需要
"""
qtick = tq_api.get_quote(symbol)
print(qtick.datetime)
secs = tafunc.time_to_s_timestamp(qtick.datetime)
print(tafunc.time_to_s_timestamp(qtick.datetime))
print(time.strftime("%H:%M:%S",time.localtime(secs)))
qm60kline = tq_api.get_kline_serial(symbol,60,data_length=20)
ser_ma = list(tafunc.ma(qm60kline.close,5))
print(ser_ma)
tims_hms = time.strftime("%H:%M:%S", time.localtime(tafunc.time_to_s_timestamp(qtick.datetime)))
print(tims_hms)
interval, secsToEnd = TradeInterval.secs_to_trade_end(symbol, tims_hms)
print(interval,secsToEnd)
is_close = 0
"""
while True:
# print('主循环启动')
tq_api.wait_update()
#tq_api.is_changing(qtick)
#print('最新 :',qtick.last_price)
#print('买一:',qtick.bid_price1)
#print('卖一:',qtick.ask_price1)
# 多合约运行的话,需要循环检测哪个合约的行情产生了变化,进行处理
for symbol in list_code:
if tq_api.is_changing(kLineDic[symbol]):
# 计算均线信息
# 测试证明 k线也是实时更新的
# 计算距离开盘以及收盘的时间
tims_hms = time.strftime("%H:%M:%S", time.localtime(tafunc.time_to_s_timestamp(qtickDic[symbol].datetime)))
# 根据行情的时间戳计算交易所时间
# 计算当前时间距离开盘的时间
interval, secs2Open = TradeInterval.secs_to_open(symbol, tims_hms)
if interval == 0:
# 非交易时间,不再继续
continue
# 计算当前时间距离收盘的时间
interval,secsToEnd = TradeInterval.secs_to_trade_end(symbol,tims_hms)
if interval == 0:
# 非交易时间,不再继续
continue
tempPara = ParaDic[symbol]
ser_ma = list(tafunc.ma(kLineDic[symbol].close,8))
secs = kLineDic[symbol].iloc[-1]['datetime']/1000000000
#print(ser_ma[-1])
#print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
#print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(secs)))
#print("k 线更新")
# 如果有委托单,则处理委托单
if tempPara['orderId'] != '':
#说明有订单需要处理,检测订单状态
tempOrder = orderInfo[tempPara['orderId']]
if tempOrder.status == 'FINISHED' and tempOrder.volume_orign - tempOrder.volume_left > 0:
# 订单成交
print('报单数量', tempOrder.volume_orign)
print('未成交数量', tempOrder.volume_left)
if tempOrder.offset == 'OPEN':
tempPara['posvol'] += tempOrder.volume_orign - tempOrder.volume_left
tempPara['orderId'] = ''
if tempOrder.direction == 'BUY':
tempPara['posside'] = 'BUY'
elif tempOrder.direction == 'SELL':
tempPara['posside'] = 'SELL'
elif tempOrder.offset == 'CLOSE' or tempOrder.offset == 'CLOSETODAY':
tempPara['posvol'] -= tempOrder.volume_orign - tempOrder.volume_left
tempPara['orderId'] = ''
print('平仓,策略持仓量', tempPara['posvol'])
elif tempOrder.status == 'ALIVE':
#此处处理订单排队或部分成交的情况
#如果行情变动已经偏离报盘价格,则需要进行撤单
if tempOrder.direction == 'BUY':
if qtickDic[symbol].bid_price1 > tempOrder.limit_price + 0.0001:
#撤单
tq_api.cancel_order(tempOrder)
elif tempOrder.direction == 'SELL':
if qtickDic[symbol].ask_price1 < tempOrder.limit_price - 0.0001:
#撤单
tq_api.cancel_order(tempOrder)
elif tempOrder.status == 'FINISHED' and tempOrder.volume_orign - tempOrder.volume_left == 0:
#此种情况应该是错单或者撤销的情况
print(tempOrder)
tempPara['orderId'] = ''
print('订单撤单或订单错误')
continue
# 如果合约有持仓,则处理持仓
if tempPara['posvol'] > 0:
#持仓数据大于 0 检测是否达到平仓线
if ser_ma[-1] < ser_ma[-2] and ser_ma[-2] < ser_ma[-3]:
price = qtickDic[symbol].bid_price1
order = tq_api.insert_order(symbol, 'SELL', 'CLOSETODAY', 1, price)
tempPara['orderId'] = order.order_id
print('平仓条件满足,进行平仓')
print('平仓 orderid', tempPara['orderId'])
elif (interval == 1 or interval == 5) and secsToEnd < 30:
# 距离夜盘或当天收盘小于 30 秒,则平仓
print('临近收盘,平仓')
price = qtickDic[symbol].bid_price1
order = tq_api.insert_order(symbol, 'SELL', 'CLOSETODAY', 1, price)
tempPara['orderId'] = order.order_id
continue
else:
pass
# print('没有持仓')
#在没有持仓以及没有委托单的情况下
#判断行情进行委托
if interval == 0:
# 非交易时间,或者距离开盘小于60 秒 或者距离收盘小于 30 秒,不进行交易
print('非交易时间')
continue
elif secs2Open < 60 and (interval == 1 or interval == 5):
print('开盘不到 60 秒')
continue
elif secsToEnd < 30 and (interval == 1 or interval == 5):
print('临近收盘,不开仓')
continue
if ser_ma[-1] > ser_ma[-2] > ser_ma[-3]:
print("满足条件,执行开仓")
price = qtickDic[symbol].ask_price1
order = tq_api.insert_order(symbol,'BUY','OPEN',1,price)
tempPara['orderId'] = order.order_id
print('开仓 orderid', tempPara['orderId'])
else:
#print("不满足开仓条件")
pass
#退出 tqsdk
#if is_close > 300:
# tq_api.close()
except Exception as e:
print("登陆失败")
print(e)
if __name__ == '__main__':
print('test')
133133 已回答的问题 2021年2月24日