################################### # 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日