def decode(self, rawmsg): #msg = rawmsg.rstrip(os.linesep).split(SOH) try: rawmsg = rawmsg.decode('utf-8') msg = rawmsg.split(self.SOH) msg = msg[:-1] if len(msg) < 3: # at a minumum we require BeginString, BodyLength & Checksum return (None, 0) tag, value = msg[0].split('=', 1) if tag != self.protocol.fixtags.BeginString: logging.error("*** BeginString missing or not 1st field *** [" + tag + "]") elif value != self.protocol.beginstring: logging.error("FIX Version unexpected (Recv: %s Expected: %s)" % (value, self.protocol.beginstring)) tag, value = msg[1].split('=', 1) msgLength = len(msg[0]) + len(msg[1]) + len('10=000') + 3 if tag != self.protocol.fixtags.BodyLength: logging.error("*** BodyLength missing or not 2nd field *** [" + tag + "]") else: msgLength += int(value) # do we have a complete message on the sockt if msgLength > len(rawmsg): return (None, 0) else: remainingMsgFragment = msgLength # resplit our message msg = rawmsg[:msgLength].split(self.SOH) msg = msg[:-1] decodedMsg = FIXMessage("UNKNOWN") # logging.debug("\t-----------------------------------------") # logging.debug("\t" + "|".join(msg)) repeatingGroups = [] repeatingGroupTags = self.protocol.fixtags.repeatingGroupIdentifiers() currentContext = decodedMsg for m in msg: tag, value = m.split('=', 1) t = None try: t = self.protocol.fixtags.tagToName(tag) except KeyError: logging.info("\t%s(Unknown): %s" % (tag, value)) t = "{unknown}" if tag == self.protocol.fixtags.CheckSum: cksum = ((sum([ord(i) for i in list(self.SOH.join(msg[:-1]))]) + 1) % 256) if cksum != int(value): logging.warning("\tCheckSum: %s (INVALID) expecting %s" % (int(value), cksum)) elif tag == self.protocol.fixtags.MsgType: try: msgType = self.protocol.msgtype.msgTypeToName(value) decodedMsg.setMsgType(value) except KeyError: logging.error('*** MsgType "%s" not supported ***') if tag in repeatingGroupTags: # found the start of a repeating group if type(currentContext) is RepeatingGroupContext: # i.e. we are already in a repeating group while repeatingGroups and tag not in currentContext.repeatingGroupTags: currentContext.parent.addRepeatingGroup(currentContext.tag, currentContext) currentContext = currentContext.parent del repeatingGroups[-1] # pop the completed group off the stack ctx = RepeatingGroupContext(tag, repeatingGroupTags[tag], currentContext) repeatingGroups.append(ctx) currentContext = ctx elif repeatingGroups: # we have 1 or more repeating groups in progress & our tag isn't the start of a group while repeatingGroups and tag not in currentContext.repeatingGroupTags: currentContext.parent.addRepeatingGroup(currentContext.tag, currentContext) currentContext = currentContext.parent del repeatingGroups[-1] # pop the completed group off the stack if tag in currentContext.tags: # if the repeating group already contains this field, start the next currentContext.parent.addRepeatingGroup(currentContext.tag, currentContext) ctx = RepeatingGroupContext(currentContext.tag, currentContext.repeatingGroupTags, currentContext.parent) del repeatingGroups[-1] # pop the completed group off the stack repeatingGroups.append(ctx) currentContext = ctx # else add it to the current one currentContext.setField(tag, value) else: # this isn't a repeating group field, so just add it normally decodedMsg.setField(tag, value) return (decodedMsg, remainingMsgFragment) except UnicodeDecodeError as why: logging.error("Failed to parse message %s" % (why, )) return (None, 0)
def sendOrder(self, symbol, side, ordType, quantity, price=None, connectionHandler=None): if not connectionHandler: connectionHandler = self.connectionHandler self.clOrdID = str(uuid.uuid4()) codec = connectionHandler.codec msg = FIXMessage(codec.protocol.msgtype.NEWORDERSINGLE) if price and ordType == "limit": msg.setField(codec.protocol.fixtags.Price, price) msg.setField(codec.protocol.fixtags.OrderQty, quantity) msg.setField(codec.protocol.fixtags.OrdType, self.orderTypeDict[ordType]) msg.setField(codec.protocol.fixtags.TimeInForce, "1") msg.setField(codec.protocol.fixtags.Symbol, symbol) msg.setField(codec.protocol.fixtags.HandlInst, "1") msg.setField(codec.protocol.fixtags.Side, self.orderSideDict[side]) msg.setField(codec.protocol.fixtags.ClOrdID, self.clOrdID) connectionHandler.sendMsg(msg) print("Send order at: " + str(self.current_datetime()))
def logon(): msg = FIXMessage(msgtype.LOGON) msg.setField(fixtags.EncryptMethod, 0) msg.setField(fixtags.HeartBtInt, 30) return msg
def resend_request(beginSeqNo, endSeqNo = '0'): msg = FIXMessage(msgtype.RESENDREQUEST) msg.setField(fixtags.BeginSeqNo, str(beginSeqNo)) msg.setField(fixtags.EndSeqNo, str(endSeqNo)) return msg
def sequence_reset(respondingTo, isGapFill): msg = FIXMessage(msgtype.SEQUENCERESET) msg.setField(fixtags.GapFillFlag, 'Y' if isGapFill else 'N') msg.setField(fixtags.MsgSeqNum, respondingTo[fixtags.BeginSeqNo]) return msg
def _handleResendRequest(self, msg): protocol = self.codec.protocol responses = [] beginSeqNo = msg[protocol.fixtags.BeginSeqNo] endSeqNo = msg[protocol.fixtags.EndSeqNo] if int(endSeqNo) == 0: endSeqNo = sys.maxsize logging.info("Received resent request from %s to %s", beginSeqNo, endSeqNo) replayMsgs = self.engine.journaller.recoverMsgs( self.session, MessageDirection.OUTBOUND, beginSeqNo, endSeqNo) gapFillBegin = int(beginSeqNo) gapFillEnd = int(beginSeqNo) for replayMsg in replayMsgs: msgSeqNum = int(replayMsg[protocol.fixtags.MsgSeqNum]) if replayMsg[protocol.fixtags. MsgType] in protocol.msgtype.sessionMessageTypes: gapFillEnd = msgSeqNum + 1 else: if self.engine.shouldResendMessage(self.session, replayMsg): if gapFillBegin < gapFillEnd: # we need to send a gap fill message gapFillMsg = FIXMessage(protocol.msgtype.SEQUENCERESET) gapFillMsg.setField(protocol.fixtags.GapFillFlag, 'Y') gapFillMsg.setField(protocol.fixtags.MsgSeqNum, gapFillBegin) gapFillMsg.setField(protocol.fixtags.NewSeqNo, str(gapFillEnd)) responses.append(gapFillMsg) # and then resent the replayMsg replayMsg.removeField(protocol.fixtags.BeginString) replayMsg.removeField(protocol.fixtags.BodyLength) replayMsg.removeField(protocol.fixtags.SendingTime) replayMsg.removeField(protocol.fixtags.SenderCompID) replayMsg.removeField(protocol.fixtags.TargetCompID) replayMsg.removeField(protocol.fixtags.CheckSum) replayMsg.setField(protocol.fixtags.PossDupFlag, "Y") responses.append(replayMsg) gapFillBegin = msgSeqNum + 1 else: gapFillEnd = msgSeqNum + 1 responses.append(replayMsg) if gapFillBegin < gapFillEnd: # we need to send a gap fill message gapFillMsg = FIXMessage(protocol.msgtype.SEQUENCERESET) gapFillMsg.setField(protocol.fixtags.GapFillFlag, 'Y') gapFillMsg.setField(protocol.fixtags.MsgSeqNum, gapFillBegin) gapFillMsg.setField(protocol.fixtags.NewSeqNo, str(gapFillEnd)) responses.append(gapFillMsg) return responses
def sendOrder(self, connectionHandler, price, quantity, side): self.clOrdID = self.clOrdID + 1 codec = connectionHandler.codec msg = FIXMessage(codec.protocol.msgtype.NEWORDERSINGLE) msg.setField(codec.protocol.fixtags.Price, float(price)) #"%0.2f" % (random.random() * 2 + 10)) msg.setField(codec.protocol.fixtags.OrderQty, int(quantity)) # int(random.random() * 100)) msg.setField(codec.protocol.fixtags.Symbol, "BTCUSD") msg.setField(codec.protocol.fixtags.SecurityID, "BTC") msg.setField(codec.protocol.fixtags.SecurityIDSource, "4") msg.setField(codec.protocol.fixtags.Account, "TEST") msg.setField(codec.protocol.fixtags.HandlInst, "1") msg.setField(codec.protocol.fixtags.ExDestination, "XLON") msg.setField(codec.protocol.fixtags.Side, int(side)) #int(random.random() * 2) + 1) msg.setField(codec.protocol.fixtags.ClOrdID, str(self.clOrdID)) msg.setField(codec.protocol.fixtags.Currency, "USD") connectionHandler.sendMsg(msg) side = Side(int(msg.getField(codec.protocol.fixtags.Side))) logging.debug("---> [%s] %s: %s %s %s@%s" % (codec.protocol.msgtype.msgTypeToName(msg.msgType), msg.getField(codec.protocol.fixtags.ClOrdID), msg.getField(codec.protocol.fixtags.Symbol), side.name, msg.getField(codec.protocol.fixtags.OrderQty), msg.getField(codec.protocol.fixtags.Price)))