def update_ctp_order(cls, account_name, pOrder, session_id=None, front_id=None): complete_time = cancel_time = None if pOrder.VolumeTotal == 0: complete_time = datetime.now().strftime("%Y-%m-%dT%H:%M:%S") if pOrder.OrderStatus == ApiStruct.OST_Canceled: cancel_time = datetime.now().strftime("%Y-%m-%dT%H:%M:%S") update_time = datetime.now().strftime("%Y-%m-%dT%H:%M:%S") finished = bool(complete_time or cancel_time) session_id = session_id or pOrder.SessionID front_id = front_id or pOrder.FrontID data = { "Account": account_name, "BrokerID": pOrder.BrokerID.decode(), "InvestorID": pOrder.InvestorID.decode(), "session_id": session_id, "front_id": front_id, 'order_ref': pOrder.OrderRef.decode(), "OrderSysID": pOrder.OrderSysID.decode().strip(), "InstrumentID": pOrder.InstrumentID.decode(), "Direction": pOrder.Direction.decode(), "Offset": pOrder.CombOffsetFlag.decode(), "Price": pOrder.LimitPrice, "VolumesTotal": pOrder.VolumeTotalOriginal, 'VolumesTraded': pOrder.VolumeTraded, 'UpdateTime': update_time, 'CompleteTime': complete_time, 'CancelTime': cancel_time, 'StatusMsg': pOrder.StatusMsg.decode("gbk"), 'Finished': finished, } api.action("ctp_order", "partial_update", params=data)
def submit(self, order_id): # 把任务状态设置为“已运行” api.action("order", "partial_update", params={ "ID": order_id, "Status": 1 }) # 正式开始发单 asyncio.ensure_future(self.trade(order_id), loop=self.loop)
async def trade(self, order_id, retries=20): if retries == 0: logger.info(f"{order_id}尝试达到最大次数,停止。") api.action("order", "partial_update", params={ "ID": order_id, "Status": OrderStatus.FINISHED, "StatusMsg": "尝试达到最大次数", "CancelTime": datetime.now().strftime("%Y-%m-%dT%H:%M:%S") }) return task = self.get_task(order_id) if task['Status'] == OrderStatus.FINISHED: return trade_volume, offset = self.decide_volume_and_offset(task) if not trade_volume: return price = self.decide_price(task['InstrumentID'], task['Direction'], task['Price']) sessionid, frontid, orderref = self.trader.send_order( task['InstrumentID'], price, trade_volume, task['Direction'], offset, order_id) await asyncio.sleep(task['split_options']['sleep_after_submit'], loop=self.loop) ctp_order = TradingAPI.get_ctp_order(sessionid, frontid, orderref) if not hasattr(ctp_order, "Finished"): print(ctp_order) if not ctp_order['Finished']: self.trader.cancel_order(task['InstrumentID'], orderref, frontid, sessionid) if ctp_order.get('CancelTime'): # 如果CTP发单出错,那么直接取消整个订单 api.action("order", "partial_update", params={ "ID": order_id, "Status": OrderStatus.FINISHED, "StatusMsg": ctp_order['StatusMsg'], "CancelTime": datetime.now().strftime("%Y-%m-%dT%H:%M:%S") }) return await asyncio.sleep(task['split_options']['sleep_after_cancel'], loop=self.loop) await self.trade(order_id, retries - 1)
def insert_ctp_trade(account, pTrade): data = { "CTPOrderID": 123456, # This is dummy "OrderSysID": pTrade.OrderSysID.decode().strip(), "Account": account, "Instrument": pTrade.InstrumentID.decode(), "Direction": pTrade.Direction.decode(), "OffsetFlag": pTrade.OffsetFlag.decode(), "TradeID": pTrade.TradeID.decode(), "Price": pTrade.Price, "Volume": pTrade.Volume, "TradeTime": reformat_date(pTrade.TradeDate, pTrade.TradeTime) } api.action("ctp_trade", "create", params=data)
def send_order(self, instrument, price, volume, direction, offset, order_id): orderref = str(self.inc_orderref_id()) instrument_info = api.action("instruments", "read", params={"InstrumentID": instrument}) order = ApiStruct.InputOrderField( BrokerID=self.broker_id, InvestorID=self.investor_id, InstrumentID=instrument, OrderRef=orderref, UserID=self.investor_id, OrderPriceType=ApiStruct.OPT_LimitPrice, LimitPrice=price, VolumeTotalOriginal=volume, Direction=direction, CombOffsetFlag=offset, CombHedgeFlag=ApiStruct.HF_Speculation, ContingentCondition=ApiStruct.CC_Immediately, ForceCloseReason=ApiStruct.FCC_NotForceClose, IsAutoSuspend=0, TimeCondition=ApiStruct.TC_GFD, UserForceClose=0, VolumeCondition=ApiStruct.VC_AV, MinVolume=1, ExchangeID=instrument_info['ExchangeID'], ) # 插入API必须在CTP报单之前,否则OnRtnOrder时可能查询不到报单 TradingAPI.insert_ctp_order(self.account_name, order_id, order, self.session_id, self.front_id) self.ReqOrderInsert(order, self.inc_request_id()) return self.session_id, self.front_id, orderref
def get_order(order_id): order = api.action("order", "read", params={"ID": order_id}) order['split_options'] = { "sleep_after_submit": order['SplitSleepAfterSubmit'], "sleep_after_cancel": order['SplitSleepAfterCancel'], "split_percent": order['SplitPercent'], } return order
def get_ctp_order(sessionid, frontid, orderref): return api.action("ctp_order", "read", params={ "session_id": sessionid, "front_id": frontid, "order_ref": orderref })
def query_order(orderref): rsp = api.action("query_order_from_ctporder", "read", params={"id": int(orderref)}) if rsp: return rsp['OrderID'] else: raise ValueError(f"Can't find CTPOrder {orderref}")
def __init__(self, account_name): self.account_name = account_name self.url = self.register(account_name) atexit.register(lambda: api.action( "tradebot", "delete", params={"id": account_name})) self.loop = None self.trader = TraderBot(account_name) self.trader.start() self.task_manager = TaskManager(self.trader)
def insert_ctp_order(account, order_id, pInputOrder, session_id, front_id): data = { "SessionID": session_id, "OrderRef": pInputOrder.OrderRef.decode(), "FrontID": front_id, "Account": account, "BrokerID": pInputOrder.BrokerID.decode(), "InvestorID": pInputOrder.InvestorID.decode(), "OrderID": order_id, "InstrumentID": pInputOrder.InstrumentID.decode(), "Direction": pInputOrder.Direction.decode(), "Offset": pInputOrder.CombOffsetFlag.decode(), "Price": pInputOrder.LimitPrice, "VolumesTotal": pInputOrder.VolumeTotalOriginal, "VolumesTraded": 0, "InsertTime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "Finished": False, } api.action("ctp_order", "create", params=data)
def decide_volume_and_offset(self, task): if task['Offset'] == ApiStruct.OF_Close: # 处理平仓,优先平昨 if task['Direction'] == ApiStruct.D_Buy: cs = 'S' else: cs = 'L' position = TraderInterface.query_position(self.trader.account_name, task['InstrumentID']) # 优先使用昨仓 volumes_holding = position.get(f'Yd{cs}Position', 0) offset = ApiStruct.OF_CloseYesterday if not volumes_holding: # 如果没有昨仓,使用今仓 volumes_holding = position.get(f'Today{cs}Position', 0) offset = ApiStruct.OF_CloseToday if not volumes_holding: # 如果已经没有仓位了,取消整个订单 api.action("order", "partial_update", params={ "ID": task['ID'], "Status": OrderStatus.FINISHED, "StatusMsg": "平仓数量不够", "CancelTime": datetime.now().strftime("%Y-%m-%dT%H:%M:%S") }) return 0, None else: # 如果开仓,不限数量 volumes_holding = 99999999999 offset = task['Offset'] volumes_left = max( min(task['VolumesTotal'] - task['VolumesTraded'], volumes_holding), 0) percent = task['split_options']['split_percent'] volume = min(max(round(percent * volumes_left), 1), volumes_left) return volume, offset
def __init__(self, account_name): self.account_name = account_name account_info = api.action("ctp", "read", params={"Name": account_name}) print(account_info) self.position_detail_cache = {} super().__init__( account_info['TdHost'], account_info['UserID'], account_info['BrokerID'], account_info['Password'], account_info['AppID'], account_info['AuthCode'], )
def register(self, account): if platform.system() == "Windows": params = { "account": account, "method": "tcp", "bind": "127.0.0.1", } else: params = {"account": account} resp = api.action("tradebot", "create", params=params) if not resp['OK']: raise RuntimeError( f"Tradebot with account {account} is already running") return resp['url']
def insert_order(account, instrument, price, volume, direction, offset, split_options): data = { "Account": account, "InstrumentID": instrument, "Direction": direction, "Offset": offset, "Price": str(price), "VolumesTotal": volume, "VolumesTraded": 0, "InsertTime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "SplitSleepAfterSubmit": split_options['sleep_after_submit'], "SplitSleepAfterCancel": split_options['sleep_after_cancel'], "SplitPercent": split_options['split_percent'], "Status": OrderStatus.INACTIVE, } resp = api.action("order", "create", params=data) return resp['ID']
async def run(self): # 第一次先启动所有“已运行”的任务,然后只轮询“未启动”的任务 status_flag = OrderStatus.RUNNING while True: resp = api.action("order", "list", params={ "Status": status_flag, "Account": self.trader.account_name }) for order in resp: logger.info( f"启动任务 {order['ID']} {order['InstrumentID']} {order['Direction']} {order['VolumesTotal'] - order['VolumesTraded']} @ {order['Price']}" ) self.submit(order['ID']) await asyncio.sleep(1, loop=self.loop) status_flag = OrderStatus.INACTIVE
def cancel_order(self, instrument, order_ref, front_id, session_id): """ 撤单 """ instrument_info = api.action("instruments", "read", params={"InstrumentID": instrument}) req = ApiStruct.InputOrderActionField( InstrumentID=instrument, OrderRef=order_ref, FrontID=front_id, SessionID=session_id, ActionFlag=ApiStruct.AF_Delete, BrokerID=self.broker_id, InvestorID=self.investor_id, UserID=self.investor_id, ExchangeID=instrument_info['ExchangeID'], ) self.ReqOrderAction(req, self.inc_request_id())