def new_order(sender_comp_id, target_comp_id, symbol, quantity, price, side, order_type): if side.lower() == "buy": side = fix.Side_BUY else: side = fix.Side_SELL message = Message() header = message.getHeader() header.setField(fix.BeginString("FIX.4.2")) header.setField(fix.SenderCompID(sender_comp_id)) header.setField(fix.TargetCompID(target_comp_id)) header.setField(fix.MsgType("D")) ord_id = get_order_id(sender_comp_id, symbol) message.setField(fix.ClOrdID(ord_id)) message.setField(fix.Symbol(symbol)) message.setField(fix.Side(side)) message.setField(fix.Price(float(price))) if order_type.lower() == "market": message.setField(fix.OrdType(fix.OrdType_MARKET)) else: message.setField(fix.OrdType(fix.OrdType_LIMIT)) message.setField(fix.HandlInst(fix.HandlInst_MANUAL_ORDER_BEST_EXECUTION)) message.setField(fix.TransactTime()) message.setField(fix.OrderQty(float(quantity))) message.setField(fix.Text(f"{side} {symbol} {quantity}@{price}")) return message
def process_security_list(self, security_list): no_related_sym = quickfix.NoRelatedSym() symbol_field = quickfix.Symbol() security_list.getField(no_related_sym) number_of_instruments = int(no_related_sym.getValue()) for i in range(number_of_instruments): group = quickfix.Group(no_related_sym.getField(), symbol_field.getField()) security_list.getGroup(i + 1, group) group.getField(symbol_field) security_exchange = quickfix.SecurityExchange() group.getField(security_exchange) exchange = security_exchange.getValue() symbol = symbol_field.getValue() instrument = self.reference_data.ins_instrument(exchange, symbol) print("New Instrument : " + str(instrument)) text_field = quickfix.Text() if group.isSetField(text_field): group.getField(text_field) text = str(text_field.getValue()) ref_data = json.loads(text) self.reference_data.ins_reference_data(instrument, ref_data)
def fromApp(self, message, sessionID): if self.verbose: print(f'[fromApp] {sessionID} | {read_FIX_message(message)}') log(self.logger, f'[fromApp] {sessionID} | {read_FIX_message(message)}') # Get incoming message Type msgType = fix.MsgType() message.getHeader().getField(msgType) msgType = msgType.getValue() # Get timestamp (tag 52) sending_time = extract_message_field_value(fix.SendingTime(), message, 'datetime') # print('sending_time:', sending_time) ########## Quote messages ########## if msgType == fix.MsgType_MassQuote: self.parse_MassQuote(message, sending_time) elif msgType == fix.MsgType_MarketDataSnapshotFullRefresh: self.parse_MarketDataSnapshotFullRefresh(message, sending_time) # 3) Process MarketDataSnapshot_IncrementalRefresh message elif msgType == fix.MsgType_MarketDataIncrementalRefresh: print(self._server_str + ' {MD} INCREMENTAL REFRESH!') ########## Trade messages ########## elif msgType == fix.MsgType_ExecutionReport: self.parse_ExecutionReport(message, sending_time) elif msgType == fix.MsgType_OrderCancelReject: # An OrderCancelReject will be sent as an answer to an OrderCancelRequest, which cannot be executed. # Not much to do here as our order dict would stay the same. # If it was canceled successfully, we should get an execution report. ClOrdID = extract_message_field_value(fix.ClOrdID(), message, 'int') print( f'[fromApp] Order Cancel Request Rejected for order: {ClOrdID}' ) elif msgType == fix.MsgType_MarketDataRequestReject: text = extract_message_field_value(fix.Text(), message, 'str') print(f'[fromApp] Market Data Request Reject with message: {text}') elif self.verbose: print(f'[fromApp] {sessionID} | {read_FIX_message(message)}') print('unknown message type: ', msgType)
def cancel(self, message, sessionID): symbol = fix.Symbol() side = fix.Side() orderQty = fix.OrderQty() clOrdID = fix.ClOrdID() org = fix.OrigClOrdID() message.getField(symbol) message.getField(side) message.getField(orderQty) message.getField(clOrdID) message.getField(org) log.info("cancel:\nsymbol:{},side:{},orderQty:{},clOrdID:{},org:{} -----"\ .format(symbol, side, orderQty, clOrdID, org)) cancel = fix44.OrderCancelReject() cancel.setField(clOrdID) cancel.setField(fix.OrderID(self.genOrderID())) cancel.setField(fix.OrdStatus(fix.OrdStatus_NEW)) cancel.setField(fix.OrigClOrdID(org.getValue())) cancel.setField(fix.Text('order completed')) cancel.setField(fix.TransactTime()) cancel.setField(fix.CxlRejReason(fix.CxlRejReason_BROKER)) cancel.setField( fix.CxlRejResponseTo(fix.CxlRejResponseTo_ORDER_CANCEL_REQUEST)) fix.Session.sendToTarget(cancel, sessionID)
def toAdmin(self, m: fix.Message, session_id: fix.SessionID): if self.username and self.password: if m.getHeader().getField( fix.MsgType().getTag()) == fix.MsgType_Logon: m.setField(fix.Username(self.username)) m.setField(fix.Password(self.password)) if self.autofix_sequence_numbers: text_tag = fix.Text().getTag() is_seqnum_too_low = ( m.getHeader().getField(fix.MsgType().getTag()) == fix.MsgType_Logout and m.isSetField(text_tag) and m.getField(text_tag).startswith("MsgSeqNum too low")) if is_seqnum_too_low: needed_seqnum = int( re.match( "MsgSeqNum too low, expecting (\d+) but received (\d+)", m.getField(text_tag))[2]) self.log_message("toAdmin", m, session_id, levelize=False) logger.warning( f"Resetting MsgSeqNum to {needed_seqnum} as needed. Wait for reconnect..." ) self.session.setNextTargetMsgSeqNum(needed_seqnum) return self.log_message("toAdmin", m, session_id) self.outgoing_messages.put(fix.Message(m))
def put_new_order(self, instrument, side, price, size): """Request sample new order single""" message = quickfix44.NewOrderSingle() header = message.getHeader() print("Executing : " + str(instrument) + ":" + str(side) + ":" + str(price) + ":" + str(size)) message.setField(quickfix.ClOrdID(self.genExecID())) message.setField(quickfix.Side(side)) message.setField(quickfix.Symbol(instrument.symbol)) message.setField(quickfix.SecurityExchange(instrument.exchange)) message.setField(quickfix.OrderQty(size)) message.setField(quickfix.Price(int(price))) message.setField(quickfix.OrdType(quickfix.OrdType_LIMIT)) message.setField(quickfix.TimeInForce('0')) message.setField(quickfix.Text("NewOrderSingle")) trstime = quickfix.TransactTime() trstime.setString( datetime.utcnow().strftime("%Y%m%d-%H:%M:%S.%f")[:-3]) message.setField(trstime) msg = message.toString().replace(__SOH__, "|") print("New Order Single: " + msg) quickfix.Session.sendToTarget(message, self.sessionID)
def new_order(self): print("Creating the following order: ") trade = fix.Message() trade.getHeader().setField(fix.BeginString(fix.BeginString_FIX42)) # trade.getHeader().setField(fix.MsgType( fix.MsgType_NewOrderSingle)) #35=D trade.setField(fix.ClOrdID(self.genOrderID())) #11=Unique order id trade.setField(fix.HandlInst(fix.HandlInst_MANUAL_ORDER_BEST_EXECUTION) ) #21=3 (Manual order, best executiona) trade.setField(fix.Symbol("ethbtc")) #55=ethbtc trade.setField(fix.Side(fix.Side_BUY)) #54=1 Buy trade.setField(fix.OrdType(fix.OrdType_LIMIT)) #40=2 Limit order trade.setField(fix.OrderQty(9)) #38=9 trade.setField(fix.Price(1.5)) #44=1.5 trade.setField( fix.StringField( 60, (datetime.utcnow().strftime("%Y%m%d-%H:%M:%S.%f"))[:-3]) ) #60 TransactTime, not supported in python, so use tag number trade.setField(fix.Text("New Order")) #58 text print(trade.toString()) try: fix.Session.sendToTarget(trade, self.sessionID) except (fix.ConfigError, fix.RuntimeError) as e: print(e)
def getExecutionReportForNewOrder(self, message): beginString = fix.BeginString() message.getHeader().getField(beginString) symbol = fix.Symbol() side = fix.Side() ordType = fix.OrdType() orderQty = fix.OrderQty() price = fix.Price() clOrdID = fix.ClOrdID() message.getField(ordType) if ordType.getValue() != fix.OrdType_LIMIT: raise fix.IncorrectTagValue(ordType.getField()) message.getField(symbol) message.getField(side) message.getField(orderQty) message.getField(price) message.getField(clOrdID) executionReport = fix.Message() executionReport.getHeader().setField(beginString) executionReport.getHeader().setField( fix.MsgType(fix.MsgType_ExecutionReport)) executionReport.setField(fix.OrderID(self.genOrderID())) executionReport.setField(fix.ExecID(self.genExecID())) executionReport.setField(fix.OrdStatus(fix.OrdStatus_FILLED)) executionReport.setField(symbol) executionReport.setField(side) executionReport.setField(fix.CumQty(orderQty.getValue())) executionReport.setField(fix.AvgPx(price.getValue())) executionReport.setField(fix.LastShares(orderQty.getValue())) executionReport.setField(fix.LastPx(price.getValue())) executionReport.setField(clOrdID) executionReport.setField(orderQty) executionReport.setField(fix.Text("New order accepted!")) # Since FIX 4.3, ExecTransType is killed and the values are moved to ExecType if beginString.getValue( ) == fix.BeginString_FIX40 or beginString.getValue( ) == fix.BeginString_FIX41 or beginString.getValue( ) == fix.BeginString_FIX42: executionReport.setField(fix.ExecTransType(fix.ExecTransType_NEW)) # ExecType and LeavesQty fields only existsince FIX 4.1 if beginString.getValue() >= fix.BeginString_FIX41: if beginString.getValue() <= fix.BeginString_FIX42: executionReport.setField(fix.ExecType( fix.ExecType_FILL)) #150=2 FILL (or 1 PARTIAL_FILL) else: # FILL and PARTIAL_FILL are removed and replaced by TRADE (F) since FIX 4.3 as these info can be retrieved from OrdStatus field executionReport.setField(fix.ExecType( fix.ExecType_TRADE)) #150=F TRADE executionReport.setField(fix.LeavesQty(0)) return executionReport
def sendMarketDataReject(self, requestID, reason, sessionID): self.logger.error("FixServer:SEND REJECT %s", reason) reject = self.fixVersion.MarketDataRequestReject() reject.setField(requestID) text = quickfix.Text(reason) reject.setField(quickfix.MDReqRejReason("0")) reject.setField(text) self.sendToTarget(reject, sessionID)
def fromApp(self, message, sessionID): print("Received the following message: %s" % message.toString()) beginString = fix.BeginString() msgType = fix.MsgType() msgSeqNum = fix.MsgSeqNum() message.getHeader().getField(beginString) message.getHeader().getField(msgType) message.getHeader().getField(msgSeqNum) print("Message type = %s" % msgType.getString()) if msgType.getString() == fix.MsgType_NewOrderSingle: print("New Order received") if SKIP_AUTHENTICATION: executionReport = self.getExecutionReportForNewOrder(message) else: executionReport = self.getExecutionReportForNewOrder2(message) print("Execution report to send: %s" % executionReport.toString()) self.sendReport(executionReport, sessionID) elif msgType.getString() == fix.MsgType_OrderCancelRequest: print("Cancel Order received") if SKIP_AUTHENTICATION: executionReport = self.getExecutionReportForCancelOrder( message) # use below 3 lines and comment out above 3 if you want to send order cancel reject message # orderCancelReject = self.getOrderCancelReject(message) # print("Order cancel reject to send: %s" % orderCancelReject.toString()) # self.sendReport(orderCancelReject, sessionID) else: executionReport = self.getExecutionReportForCancelOrder2( message) print("Execution report to send: %s" % executionReport.toString()) self.sendReport(executionReport, sessionID) elif msgType.getString() == fix.MsgType_OrderStatusRequest: print("Order status request received") if SKIP_AUTHENTICATION: executionReport = self.getExecutionReportForStatusRequest( message) else: executionReport = self.getExecutionReportForStatusRequest2( message) print("Execution report to send: %s" % executionReport.toString()) self.sendReport(executionReport, sessionID) else: print("Unsupported MsgType") reject = fix.Message() reject.getHeader().setField(beginString) reject.getHeader().setField(fix.MsgType(fix.MsgType_Reject)) reject.setField(fix.RefMsgType(msgType.getString())) reject.setField(fix.RefSeqNum( msgSeqNum.getValue())) #45 = RefSeqNum reject.setField( fix.SessionRejectReason(fix.SessionRejectReason_INVALID_MSGTYPE )) #373 = 11 INVALID_MSGTYPE reject.setField( fix.Text("iSTOX FIX API does not support this message type")) self.sendReport(reject, sessionID)
def _create_execution_report( self, symbol, side, client_order_id, price=None, quantity=None, order_status=fix.OrdStatus_NEW, exec_trans_type=fix.ExecTransType_NEW, exec_type=fix.ExecType_NEW, text=None, reject_reason=None, orig_client_order_id=None, ): # defaults execution_report = Message() execution_report.getHeader().setField( fix.MsgType(fix.MsgType_ExecutionReport)) execution_report.setField( fix.OrderID(self.generate_order_id(symbol.getValue()))) execution_report.setField( fix.ExecID(self.generate_execution_id(symbol.getValue()))) execution_report.setField(fix.OrdStatus(order_status)) execution_report.setField(symbol) execution_report.setField(side) execution_report.setField(client_order_id) execution_report.setField(fix.ExecTransType(exec_trans_type)) execution_report.setField(fix.ExecType(exec_type)) execution_report.setField(fix.LeavesQty(0)) if price: execution_report.setField(fix.AvgPx(price.getValue())) execution_report.setField(fix.LastPx(price.getValue())) if quantity: execution_report.setField(fix.CumQty(quantity.getValue())) execution_report.setField(fix.LastShares(quantity.getValue())) execution_report.setField(quantity) if orig_client_order_id: execution_report.setField( fix.OrigClOrdID(orig_client_order_id.getValue())) if text: execution_report.setField(fix.Text(text)) if exec_type == fix.ExecType_REJECTED: execution_report.setField(fix.OrdRejReason(reject_reason)) self.logger.debug( f"Created execution report {execution_report.__str__()}") return execution_report
def sendOrderCancelRequest(self): message = fix.Message() header = message.getHeader() header.setField(fix.BeginString("FIX.4.2")) header.setField(fix.SenderCompID("CLIENT1")) header.setField(fix.TargetCompID("EXECUTOR")) header.setField(fix.MsgType("D")) message.setField(fix.OrigClOrdID("123")) message.setField(fix.ClOrdID("321")) message.setField(fix.Symbol("LNUX")) message.setField(fix.Side(fix.Side_BUY)) message.setField(fix.Text("Cancel My Order!")) fix.Session.sendToTarget(message, self.sessionID)
def sendHelloWorldMessage(sessionID): message = fix.Message() header = message.getHeader() header.setField(fix.BeginString("FIX.4.1")) header.setField(fix.SenderCompID("HELLOWORLD_TRADER")) header.setField(fix.TargetCompID("HELLOWORLD_EXCHANGE")) header.setField(fix.MsgType(fix.MsgType_NewOrderSingle)) message.setField(fix.ClOrdID('1')) message.setField(fix.HandlInst('1')) message.setField(fix.Symbol('BMLL')) message.setField(fix.Side(fix.Side_BUY)) message.setField(fix.OrdType(fix.OrdType_MARKET)) message.setField(fix.Text("Hello Exchange! How are you?")) fix.Session.sendToTarget(message, sessionID)
def getExecutionReportForStatusRequest(self, message): beginString = fix.BeginString() message.getHeader().getField(beginString) clOrdID = fix.ClOrdID() message.getField(clOrdID) executionReport = fix.Message() executionReport.getHeader().setField(beginString) executionReport.getHeader().setField( fix.MsgType(fix.MsgType_ExecutionReport)) executionReport.setField(fix.Symbol("ABCD")) executionReport.setField(fix.Side(fix.Side_BUY)) #43=1 Buy executionReport.setField(fix.OrderID(self.genOrderID())) executionReport.setField(fix.ExecID(self.genExecID())) executionReport.setField(fix.OrdType( fix.OrdType_LIMIT)) #40=2 Limit order executionReport.setField(fix.OrderQty(100)) #38=100 executionReport.setField(fix.Price(10)) #44=10 executionReport.setField(fix.OrdStatus(fix.OrdStatus_FILLED)) executionReport.setField(fix.AvgPx(10)) #6=10 executionReport.setField(fix.CumQty(100)) #14=100 executionReport.setField(clOrdID) executionReport.setField(fix.Text("Order status retrieved!")) # Since FIX 4.3, ExecTransType values are moved to ExecType if beginString.getValue( ) == fix.BeginString_FIX40 or beginString.getValue( ) == fix.BeginString_FIX41 or beginString.getValue( ) == fix.BeginString_FIX42: executionReport.setField( fix.ExecTransType(fix.ExecTransType_STATUS)) # ExecType and LeavesQty fields only existsince FIX 4.1 if beginString.getValue() >= fix.BeginString_FIX41: if beginString.getValue() <= fix.BeginString_FIX42: executionReport.setField(fix.ExecType( fix.ExecType_FILL)) #150=2 FILL (or 1 PARTIAL_FILL) else: # FILL and PARTIAL_FILL are removed and replaced by TRADE (F) since FIX 4.3 as these info can be retrieved from OrdStatus field executionReport.setField(fix.ExecType( fix.ExecType_TRADE)) #150=F TRADE executionReport.setField(fix.LeavesQty(0)) return executionReport
def getExecutionReportForCancelOrder(self, message): beginString = fix.BeginString() message.getHeader().getField(beginString) symbol = fix.Symbol() side = fix.Side() clOrdID = fix.ClOrdID() message.getField(symbol) message.getField(side) message.getField(clOrdID) executionReport = fix.Message() executionReport.getHeader().setField(beginString) executionReport.getHeader().setField( fix.MsgType(fix.MsgType_ExecutionReport)) executionReport.setField(fix.OrderID(self.genOrderID())) executionReport.setField(fix.ExecID(self.genExecID())) executionReport.setField(fix.OrdType( fix.OrdType_LIMIT)) #40=2 Limit order executionReport.setField(fix.OrderQty(100)) #38=100 executionReport.setField(fix.Price(10)) #44=10 executionReport.setField(fix.OrdStatus(fix.OrdStatus_FILLED)) executionReport.setField(symbol) executionReport.setField(side) executionReport.setField(fix.AvgPx(10)) #6=10 executionReport.setField(fix.CumQty(100)) #14=100 executionReport.setField(clOrdID) executionReport.setField(fix.Text("Order cancelled!")) # Since FIX 4.3, ExecTransType values are moved to ExecType if beginString.getValue( ) == fix.BeginString_FIX40 or beginString.getValue( ) == fix.BeginString_FIX41 or beginString.getValue( ) == fix.BeginString_FIX42: executionReport.setField( fix.ExecTransType(fix.ExecTransType_CANCEL)) # ExecType and LeavesQty fields only existsince FIX 4.1 if beginString.getValue() >= fix.BeginString_FIX41: executionReport.setField(fix.ExecType( fix.ExecType_CANCELED)) #150=4 CANCELED executionReport.setField(fix.LeavesQty(0)) #151=0 return executionReport
def delete_order(sender_comp_id, target_comp_id, orig_client_order_id): symbol = ORDERS[orig_client_order_id][0].getValue() side = ORDERS[orig_client_order_id][3].getValue() message = fix44.OrderCancelRequest() header = message.getHeader() header.setField(fix.SenderCompID(sender_comp_id)) header.setField(fix.TargetCompID(target_comp_id)) ord_id = get_order_id(sender_comp_id, symbol) message.setField(fix.OrigClOrdID(orig_client_order_id)) message.setField(fix.ClOrdID(ord_id)) message.setField(fix.Symbol(symbol)) message.setField(fix.Side(side)) message.setField(fix.TransactTime()) message.setField(fix.Text(f"Delete {orig_client_order_id}")) return message
def cancel_parent_order(self, parent_orderid: str): """""" algo_setting = self.algo_settings.get(parent_orderid, None) if not algo_setting: print(f"{parent_orderid} algo setting not found.") return message = new_message(fix.MsgType_OrderCancelRequest) self.parent_orderid += 1 cancel_orderid = f"Cancel_{self.parent_orderid}" message.setField(fix.ClOrdID(cancel_orderid)) message.setField(fix.OrigClOrdID(parent_orderid)) message.setField(fix.Symbol(algo_setting["symbol"])) message.setField(fix.Side(algo_setting["side"])) message.setField(847, algo_setting["algo_type"]) message.setField(fix.Text("vnpy")) fix.Session.sendToTarget(message, self.session_id)
def msgtofix_reject(reject_msg): """ Converte Reject (message) para Reject (fix). """ reject_text = reject_msg.Text contact = get_contact_info() if contact: reject_text += f' ({contact})' response = fix44.Message() quoterequest_msg, quoterequest_fix = get_quoterequest(reject_msg.QuoteReqID) response.reverseRoute(quoterequest_fix.getHeader()) response.getHeader().setField(fix.MsgType(fix.MsgType_QuoteAcknowledgement)) response.setField(fix.QuoteReqID(quoterequest_msg.QuoteReqID)) response.setField(fix.QuoteAckStatus(5)) response.setField(fix.QuoteRejectReason(99)) response.setField(fix.Text(reject_text)) return response
def fromApp(self, message, sessionID): msgtype = fix.MsgType() symbol = fix.Symbol() side = fix.Side() ordtype = fix.OrdType() text = fix.Text() message.getHeader().getField(msgtype) message.getField(symbol) message.getField(side) message.getField(ordtype) message.getField(text) print print 'Message received! It reads:' print ' = '.join(self.parse(msgtype)) print self.getFieldName(symbol), '=', symbol.getString() print ' = '.join(self.parse(side)) print ' = '.join(self.parse(ordtype)) print self.getFieldName(text), '=', text.getString()
def on_parent_order(self, message: fix.Message): """""" parent_orderid = get_field_value(message, fix.ClOrdID()) # Get parent orderid of cancel request if parent_orderid.startswith("Cancel"): parent_orderid = get_field_value(message, fix.OrigClOrdID()) # If this parent order is from previous session if parent_orderid not in self.algo_settings: # Cancel it to avoid future update self.cancel_parent_order(parent_orderid) return tradeid = get_field_value(message, fix.ExecID()) status = get_field_value(message, fix.OrdStatus()) side = get_field_value(message, fix.Side()) genus_symbol = get_field_value(message, fix.Symbol()) order_traded = get_field_value(message, fix.CumQty()) text = get_field_value(message, fix.Text()) algo_type = get_field_value(message, fix.StringField(847)) variables = {"推送编号": tradeid, "已成交": order_traded, "算法信息": text} self.algo_settings[parent_orderid] = { "symbol": genus_symbol, "side": side, "algo_type": algo_type } # Add algo active status if status in {"0", "1", "5", "6", "A", "D", "E"}: variables["active"] = True else: variables["active"] = False if status == "C": self.client.write_log("执行时间已结束,停止算法", parent_orderid) self.client.put_variables_event(parent_orderid, variables)
def cancel_order(self): message = fix.Message() header = message.getHeader() header.setField(fix.BeginString(fix.BeginString_FIX42)) header.setField(fix.MsgType(fix.MsgType_OrderCancelRequest)) #35=F originalOrderId = str(int(self.genOrderID()) - 1) message.setField(fix.OrigClOrdID(originalOrderId)) message.setField(fix.ClOrdID(str(int(originalOrderId) + 1))) #11=Unique order id message.setField(fix.OrderID("375")) message.setField(fix.Symbol("ABCD")) #55=ABCD message.setField(fix.Side(fix.Side_BUY)) #54=1 Buy message.setField( fix.StringField( 60, (datetime.utcnow().strftime("%Y%m%d-%H:%M:%S.%f"))[:-3]) ) #60 TransactTime, not supported in python, so use tag number message.setField(fix.Text("Cancel my Order")) #58 text print(message.toString()) try: fix.Session.sendToTarget(message, self.sessionID) except (fix.ConfigError, fix.RuntimeError) as e: print(e)
def replace_order(sender_comp_id, target_comp_id, quantity, price, orig_client_order_id): symbol = ORDERS[orig_client_order_id][0].getValue() side = ORDERS[orig_client_order_id][3].getValue() message = fix42.OrderCancelReplaceRequest() header = message.getHeader() header.setField(fix.SenderCompID(sender_comp_id)) header.setField(fix.TargetCompID(target_comp_id)) ord_id = get_order_id(sender_comp_id, symbol) message.setField(fix.OrigClOrdID(orig_client_order_id)) message.setField(fix.ClOrdID(ord_id)) message.setField(fix.Symbol(symbol)) message.setField(fix.Side(side)) message.setField(fix.Price(float(price))) message.setField(fix.OrdType(fix.OrdType_LIMIT)) message.setField(fix.HandlInst(fix.HandlInst_MANUAL_ORDER_BEST_EXECUTION)) message.setField(fix.TransactTime()) message.setField(fix.TransactTime()) message.setField(fix.OrderQty(float(quantity))) message.setField(fix.Text(f"{side} {symbol} {quantity}@{price}")) return message
def fromAdmin(self, m: fix.Message, session_id: fix.SessionID): if self.autofix_sequence_numbers: text_tag = fix.Text().getTag() is_seqnum_too_low = ( m.getHeader().getField(fix.MsgType().getTag()) == fix.MsgType_Logout and m.isSetField(text_tag) and m.getField(text_tag).startswith("MsgSeqNum too low")) if is_seqnum_too_low: needed_seqnum = int( re.match("MsgSeqNum too low, expecting (\d+)", m.getField(text_tag))[1]) self.log_message("fromAdmin", m, session_id, levelize=False) logger.warning( f"Resetting MsgSeqNum to {needed_seqnum} as needed. Wait for reconnect..." ) self.session.setNextSenderMsgSeqNum(needed_seqnum) return self.log_message("fromAdmin", m, session_id) self.incoming_messages.put(fix.Message(m))
def log_message(self, from_func: str, m: fix.Message, session_id: fix.SessionID, levelize=True): logger.debug("{}: {} {}", from_func, m.toString().replace("\x01", "|"), session_id) m1 = self.fix_to_dict(m, True) msg_type = m.getHeader().getField(fix.MsgType().getTag()) if not levelize: logger.info(f"{from_func}: {m1} {session_id}") return if msg_type == fix.MsgType_Reject: logger.error(f"{from_func}: {m1} {session_id}") elif msg_type == fix.MsgType_Heartbeat: logger.debug(f"{from_func}: {m1} {session_id}") elif msg_type == fix.MsgType_Logout and m.isSetField( fix.Text().getTag()): logger.error(f"{from_func}: {m1} {session_id}") else: logger.info(f"{from_func}: {m1} {session_id}")
def put_new_order(self): """Request sample new order single""" message = fix.Message() header = message.getHeader() header.setField(fix.MsgType(fix.MsgType_NewOrderSingle)) #39 = D message.setField(fix.ClOrdID( self.genExecID())) #11 = Unique Sequence Number message.setField(fix.Side(fix.Side_BUY)) #43 = 1 BUY message.setField(fix.Symbol("MSFT")) #55 = MSFT message.setField(fix.OrderQty(10000)) #38 = 1000 message.setField(fix.Price(100)) message.setField(fix.OrdType(fix.OrdType_LIMIT)) #40=2 Limit Order message.setField( fix.HandlInst(fix.HandlInst_MANUAL_ORDER_BEST_EXECUTION)) #21 = 3 message.setField(fix.TimeInForce('0')) message.setField(fix.Text("NewOrderSingle")) trstime = fix.TransactTime() trstime.setString( datetime.utcnow().strftime("%Y%m%d-%H:%M:%S.%f")[:-3]) message.setField(trstime) fix.Session.sendToTarget(message, self.sessionID)
def getExecutionReportForNewOrder2(self, message): beginString = fix.BeginString() message.getHeader().getField(beginString) msgSeqNum = fix.MsgSeqNum() message.getHeader().getField(msgSeqNum) symbol = fix.Symbol() side = fix.Side() ordType = fix.OrdType() orderQty = fix.OrderQty() price = fix.Price() clOrdID = fix.ClOrdID() message.getField(ordType) # todo handle market order if ordType.getValue() != fix.OrdType_LIMIT: raise fix.IncorrectTagValue(ordType.getField()) message.getField(symbol) message.getField(side) message.getField(orderQty) message.getField(price) message.getField(clOrdID) data = {} data['market'] = symbol.getValue() data['price'] = price.getValue() data['side'] = 'buy' if side.getValue() == fix.Side_BUY else 'sell' data['volume'] = orderQty.getValue() response = createOrder(self.accessKey, self.secretKey, data) jResponse = json.loads(response) executionReport = fix.Message() executionReport.getHeader().setField(beginString) executionReport.getHeader().setField( fix.MsgType(fix.MsgType_ExecutionReport)) # todo exec id? executionReport.setField(fix.ExecID(self.genExecID())) executionReport.setField(symbol) executionReport.setField(side) executionReport.setField(fix.CumQty(orderQty.getValue())) executionReport.setField(fix.AvgPx(price.getValue())) executionReport.setField(fix.LastShares(orderQty.getValue())) executionReport.setField(fix.LastPx(price.getValue())) # todo save Client order id to DB? executionReport.setField(clOrdID) executionReport.setField(orderQty) if 'error' in jResponse and jResponse['error']: executionReport.setField(fix.OrderID("nil")) executionReport.setField(fix.OrdStatus(fix.OrdStatus_REJECTED)) executionReport.setField(fix.Text(jResponse['error']['message'])) # todo Reject reason for each case executionReport.setField( fix.OrdRejReason(fix.OrdRejReason_UNKNOWN_SYMBOL)) else: executionReport.setField(fix.OrderID(str(jResponse['id']))) # todo check trades_count from json response and set FILL status? executionReport.setField(fix.OrdStatus(fix.OrdStatus_NEW)) executionReport.setField(fix.Text('New order accpeted!')) # Since FIX 4.3, ExecTransType is killed and the values are moved to ExecType if beginString.getValue( ) == fix.BeginString_FIX40 or beginString.getValue( ) == fix.BeginString_FIX41 or beginString.getValue( ) == fix.BeginString_FIX42: executionReport.setField(fix.ExecTransType(fix.ExecTransType_NEW)) # todo check trades_count from json response and set FILL status? # ExecType and LeavesQty fields only existsince FIX 4.1 if beginString.getValue() >= fix.BeginString_FIX41: if beginString.getValue() <= fix.BeginString_FIX42: executionReport.setField(fix.ExecType( fix.ExecType_FILL)) #150=2 FILL (or 1 PARTIAL_FILL) else: # FILL and PARTIAL_FILL are removed and replaced by TRADE (F) since FIX 4.3 as these info can be retrieved from OrdStatus field executionReport.setField(fix.ExecType( fix.ExecType_TRADE)) #150=F TRADE executionReport.setField(fix.LeavesQty(0)) """if 'error' in jResponse and jResponse['error']: reject = fix.Message() reject.getHeader().setField(beginString) reject.getHeader().setField(fix.MsgType(fix.MsgType_Reject)) reject.setField(fix.RefMsgType(fix.MsgType_NewOrderSingle)) reject.setField(fix.RefSeqNum(msgSeqNum.getValue())) #45 = RefSeqNum reject.setField(fix.SessionRejectReason(fix.SessionRejectReason_OTHER)) #373 = 99 OTHER reject.setField(fix.Text(jResponse['message'])) return reject """ return executionReport
def getExecutionReportForCancelOrder2(self, message): beginString = fix.BeginString() message.getHeader().getField(beginString) symbol = fix.Symbol() side = fix.Side() clOrdID = fix.ClOrdID() orderID = fix.OrderID() origClOrdID = fix.OrigClOrdID() message.getField(symbol) message.getField(side) message.getField(clOrdID) message.getField(orderID) message.getField(origClOrdID) executionReport = fix.Message() executionReport.getHeader().setField(beginString) executionReport.getHeader().setField( fix.MsgType(fix.MsgType_ExecutionReport)) data = {} data['id'] = orderID.getValue() response = cancelOrder(self.accessKey, self.secretKey, orderID.getValue()) jResponse = json.loads(response) executionReport.setField(fix.OrderID(orderID.getValue())) # todo get client order id executionReport.setField(clOrdID) executionReport.setField(fix.ExecID(self.genExecID())) if 'error' in jResponse and jResponse['error']: orderCancelReject = fix.Message() orderCancelReject.getHeader().setField(beginString) orderCancelReject.getHeader().setField( fix.MsgType(fix.MsgType_OrderCancelReject)) orderCancelReject.setField(clOrdID) orderCancelReject.setField(orderID) orderCancelReject.setField(origClOrdID) # todo reject reason orderCancelReject.setField(fix.OrdStatus( fix.OrdStatus_FILLED)) #39 = 2 FILLED orderCancelReject.setField( fix.CxlRejReason(0)) #102=0 TOO_LATE_TO_CANCEL orderCancelReject.setField( fix.CxlRejResponseTo(1)) #434=1 ORDER_CANCEL_REQUEST orderCancelReject.setField(fix.Text(jResponse['error']['message'])) return orderCancelReject else: executionReport.setField(fix.OrderID(str(jResponse['id']))) # todo check trades_count from json response and set FILL status? executionReport.setField(fix.OrdStatus(fix.OrdStatus_CANCELED)) executionReport.setField( fix.Side(fix.Side_BUY if jResponse['side'] == 'buy' else fix.Side_SELL)) executionReport.setField( fix.OrdType( fix.OrdType_LIMIT if jResponse['ord_type'] == 'limit' else fix.OrdType_MARKET)) #40=2 Limit order executionReport.setField(fix.Symbol(jResponse['market'])) executionReport.setField(fix.Price(float(jResponse['price']))) #44 executionReport.setField(fix.OrderQty(float( jResponse['volume']))) #38 executionReport.setField( fix.CumQty(float(jResponse['executed_volume']))) #14=100 executionReport.setField(fix.AvgPx(float( jResponse['avg_price']))) #6 executionReport.setField(fix.Text("Order cancelled!")) # Since FIX 4.3, ExecTransType values are moved to ExecType if beginString.getValue( ) == fix.BeginString_FIX40 or beginString.getValue( ) == fix.BeginString_FIX41 or beginString.getValue( ) == fix.BeginString_FIX42: executionReport.setField( fix.ExecTransType(fix.ExecTransType_CANCEL)) # ExecType and LeavesQty fields only existsince FIX 4.1 if beginString.getValue() >= fix.BeginString_FIX41: executionReport.setField(fix.ExecType( fix.ExecType_CANCELED)) #150=4 CANCELED executionReport.setField(fix.LeavesQty(0)) #151=0 return executionReport
def getExecutionReportForStatusRequest2(self, message): beginString = fix.BeginString() message.getHeader().getField(beginString) clOrdID = fix.ClOrdID() orderID = fix.OrderID() message.getField(clOrdID) message.getField(orderID) response = getOrder(self.accessKey, self.secretKey, orderID.getValue()) jResponse = json.loads(response) executionReport = fix.Message() executionReport.getHeader().setField(beginString) executionReport.getHeader().setField( fix.MsgType(fix.MsgType_ExecutionReport)) executionReport.setField(fix.ExecID(self.genExecID())) # todo get client order id executionReport.setField(clOrdID) if 'error' in jResponse and jResponse['error']: executionReport.setField(fix.OrderID(orderID.getValue())) executionReport.setField(fix.OrdStatus(fix.OrdStatus_REJECTED)) executionReport.setField(fix.Text(jResponse['error']['message'])) # todo Reject reason for each case executionReport.setField( fix.OrdRejReason(fix.OrdRejReason_UNKNOWN_ORDER)) else: executionReport.setField(fix.OrderID(str(jResponse['id']))) # todo check trades_count from json response and set FILL status? executionReport.setField(fix.OrdStatus(fix.OrdStatus_NEW)) executionReport.setField( fix.Side(fix.Side_BUY if jResponse['side'] == 'buy' else fix.Side_SELL)) executionReport.setField( fix.OrdType( fix.OrdType_LIMIT if jResponse['ord_type'] == 'limit' else fix.OrdType_MARKET)) #40=2 Limit order executionReport.setField(fix.Symbol(jResponse['market'])) executionReport.setField(fix.Price(float(jResponse['price']))) #44 executionReport.setField(fix.OrderQty(float( jResponse['volume']))) #38 executionReport.setField( fix.CumQty(float(jResponse['executed_volume']))) #14=100 executionReport.setField(fix.AvgPx(float( jResponse['avg_price']))) #6 executionReport.setField(fix.Text('Order status retrieved!')) # Since FIX 4.3, ExecTransType values are moved to ExecType if beginString.getValue( ) == fix.BeginString_FIX40 or beginString.getValue( ) == fix.BeginString_FIX41 or beginString.getValue( ) == fix.BeginString_FIX42: executionReport.setField( fix.ExecTransType(fix.ExecTransType_STATUS)) # ExecType and LeavesQty fields only existsince FIX 4.1 if beginString.getValue() >= fix.BeginString_FIX41: if beginString.getValue() <= fix.BeginString_FIX42: executionReport.setField(fix.ExecType( fix.ExecType_FILL)) #150=2 FILL (or 1 PARTIAL_FILL) else: # FILL and PARTIAL_FILL are removed and replaced by TRADE (F) since FIX 4.3 as these info can be retrieved from OrdStatus field executionReport.setField(fix.ExecType( fix.ExecType_TRADE)) #150=F TRADE executionReport.setField(fix.LeavesQty(0)) return executionReport
def send_parent_order(self, setting: dict): """""" vt_symbol = setting["vt_symbol"] volume = setting["volume"] price = setting["price"] order_type = OrderType(setting["order_type"]) direction = Direction(setting["direction"]) offset = Offset(setting["offset"]) template_name = setting["template_name"] algo_type = template_name.replace("Genus", "") message = new_message(fix.MsgType_NewOrderSingle) symbol, exchange = extract_vt_symbol(vt_symbol) genus_exchange = EXCHANGE_VT2GNS[exchange] genus_symbol = f"{symbol}.{genus_exchange}" side = DIRECTION_VT2GNS[direction] genus_type = ORDERTYPE_VT2GNS[order_type] self.parent_orderid += 1 parent_orderid = f"{template_name}_{self.parent_orderid}" message.setField(fix.ClOrdID(parent_orderid)) message.setField(fix.HandlInst("2")) message.setField(fix.Currency("CNY")) message.setField(fix.ExDestination(genus_exchange)) message.setField(fix.Symbol(genus_symbol)) message.setField(fix.Side(side)) message.setField(fix.OrdType(genus_type)) message.setField(fix.OrderQty(volume)) message.setField(526, parent_orderid) message.setField(fix.Text("vnpy")) if order_type == OrderType.LIMIT: message.setField(fix.Price(price)) seconds = setting["time"] dt = datetime.now() + timedelta(seconds=seconds) local_dt = CHINA_TZ.localize(dt) utc_dt = local_dt.astimezone(pytz.utc) utc_end = utc_dt.strftime("%Y%m%d-%H:%M:%S") parameters = f"EndTime;{utc_end}" message.setField(847, algo_type) message.setField(848, parameters) fix.Session.sendToTarget(message, self.session_id) self.algo_settings[parent_orderid] = { "symbol": genus_symbol, "side": side, "algo_type": algo_type } self.client.set_parent_offset(parent_orderid, offset) self.client.put_parameters_event(parent_orderid, setting) return parent_orderid