fix-client.py (219 lines of code) (raw):

############################################################################### # This is all-in-one sample tht demonstates how to submit orders ############################################################################### import sys import time import argparse import quickfix as fix import configparser class Application(fix.Application): exec_id = 0 sessionID = None sessionPwd = None logged_out = False def setSessionPassword(self, password): self.sessionPwd = password def gen_exec_id(self): new_id = time.time_ns() self.exec_id = new_id if self.exec_id < new_id else self.exec_id + 1 return repr(self.exec_id) def onCreate(self, sessionID): return def onLogon(self, sessionID): print("Session %s successfully logged in" % sessionID) self.sessionID = sessionID self.logged_out = False return def onLogout(self, sessionID): print("Session %s logged out" % sessionID) self.sessionID = None self.logged_out = True return def toAdmin(self, message, sessionID): msgType = fix.MsgType(); message.getHeader().getField(msgType) if msgType.getValue() == fix.MsgType_Logon : message.getHeader().setField(fix.Password(self.sessionPwd)) return def fromAdmin(self, message, sessionID): return def toApp(self, message, sessionID): return def fromApp(self, message, sessionID): print("Received message: ", end='') print_message(message) return def submit_order(self, symbol, side, order_type, quantity, price, destination, exchange): trade = fix.Message() trade.getHeader().setField(fix.BeginString(fix.BeginString_FIX44)) trade.getHeader().setField(fix.MsgType(fix.MsgType_NewOrderSingle)) order_id = self.gen_exec_id() trade.setField(fix.ClOrdID(order_id)) trade.setField(fix.TimeInForce(fix.TimeInForce_DAY)) trade.setField(fix.Symbol(symbol)) trade.setField(fix.Side(side)) trade.setField(fix.OrdType(order_type)) trade.setField(fix.OrderQty(quantity)) if price is not None: trade.setField(fix.Price(price)) elif order_type != fix.OrdType_MARKET: raise Exception("Must specify price for LIMIT order") if destination is not None: trade.setField(fix.ExecBroker(destination)) if exchange is not None: trade.setField(fix.ExDestination(exchange)) trade.setField(fix.TransactTime()) side = "BUY" if side == fix.Side_BUY else "SELL" order_type = "LIMIT" if order_type == fix.OrdType_LIMIT else "MARKET" print("Sending order: OrderID=%s, SessionID=%s, OrderType=%s, Symbol=%s, Side=%s, Quantity=%s, Price=%s, Destination=%s, Exchange=%s" % (order_id, self.sessionID, order_type, symbol, side, quantity, price, destination, exchange)) fix.Session.sendToTarget(trade, self.sessionID) # End of Application def print_message(msg): msg_str = '' msg_type = get_field_value(fix.MsgType(), msg.getHeader()) if msg_type == fix.MsgType_News: msg_str = "MessageType=News, Sender=" msg_str += get_field_value(fix.SenderCompID(), msg.getHeader()) msg_str += ", HeadLine=" msg_str += get_field_value(fix.Headline(), msg) msg_str += ", Text=" msg_str += get_field_value(fix.Text(), msg) else: msg_str = "OrderID=" msg_str += get_field_value(fix.ClOrdID(), msg) msg_str += ", MessageType=" msg_str += get_message_type(msg) msg_str += ", Sender=" msg_str += get_field_value(fix.SenderCompID(), msg.getHeader()) msg_str += ", Target=" msg_str += get_field_value(fix.TargetCompID(), msg.getHeader()) msg_str += ", OrderType=" #40 1-Market, 2-Limit msg_str += get_order_type(msg) msg_str += ", Side=" #54 1-Buy,2-Sell msg_str += 'BUY' if get_field_value(fix.Side(), msg) == fix.Side_BUY else 'SELL' msg_str += ", Quantity=" #38 msg_str += str(get_field_value(fix.OrderQty(), msg)) msg_str += ", Price=" msg_str += str(get_field_value(fix.Price(), msg)) msg_str += ", Symbol=" msg_str += get_field_value(fix.Symbol(), msg) msg_str += ", ExecutionType=" #150 msg_str += get_exec_type(msg) if msg.isSetField(fix.Text().getField()): msg_str += ", Text=" msg_str += get_field_value(fix.Text(), msg) msg_str += ", ExecutedQuantity=" #14 msg_str += str(get_field_value(fix.CumQty(), msg)) msg_str += ", OrderStatus=" #39 msg_str += get_order_status(msg) print(msg_str) def get_field_value(fobj, msg): if msg.isSetField(fobj.getField()): msg.getField(fobj) return fobj.getValue() else: return "None" def get_message_type(msg) : msg_type = get_field_value(fix.MsgType(), msg.getHeader()) if msg_type == fix.MsgType_ExecutionReport: return "ExecutionReport" elif msg_type == fix.MsgType_News: return "News" elif msg_type == fix.MsgType_NewOrderSingle: return "NewOrderSingle" else: return msg_type def get_order_type(msg): ord_type = get_field_value(fix.OrdType(), msg) if ord_type == fix.OrdType_LIMIT: return "LIMIT" elif ord_type == fix.OrdType_MARKET: return "MARKET" else: return ord_type def get_exec_type(msg): rpt = get_field_value(fix.ExecType(), msg) if rpt == fix.ExecType_NEW: return "NEW" elif rpt == fix.ExecType_REJECTED: return "REJECTED" elif rpt == fix.ExecType_TRADE: return "FILLED" elif rpt == fix.ExecType_CANCELED: return "CANCELED" else: return rpt def get_order_status(msg): status = get_field_value(fix.OrdStatus(), msg) if status == fix.OrdStatus_NEW: return "NEW" elif status == fix.OrdStatus_FILLED: return "FILLED" elif status == fix.OrdStatus_REJECTED: return "REJECTED" elif status == fix.OrdStatus_CANCELED: return "CANCELED" else: return status def main(config_file): try: config = configparser.ConfigParser() config.read(config_file) sender_pwd = config["SESSION"]["SenderPassword"] if "SESSION" in config and "SenderPassword" in config["SESSION"] else None if not sender_pwd: print("Warning: SESSION SenderPassword is not specified in config file: " + config_file) settings = fix.SessionSettings(config_file) application = Application() application.setSessionPassword(sender_pwd) store_factory = fix.FileStoreFactory(settings) log_factory = fix.FileLogFactory(settings) initiator = fix.SocketInitiator(application, store_factory, settings, log_factory) initiator.start() parser = argparse.ArgumentParser(description='CLI Command', prog="command", usage="help | exit | {buy,sell} -s SYMBOL -q QUANTITY [-t {LIMIT,MARKET}] [-p PRICE] [-d DESTINATION] [-e EXCHANGE] [-n ORDER_COUNT] [-i INTERVAL]") parser.add_argument("command", type=str, choices=["buy", "sell"], help="Command") parser.add_argument("-s", "--symbol", type=str, required=True, help="Order instrument symbol") parser.add_argument("-q", "--quantity", type=float, required=True, help="Order quantity") parser.add_argument("-t", "--order_type", type=str, choices=["LIMIT", "MARKET"], default="MARKET", help="Order type") parser.add_argument("-p", "--price", type=float, default=None, help="Order limit price") parser.add_argument("-d", "--destination", type=str, default="SIM", help="Destination ID") parser.add_argument("-e", "--exchange", type=str, default=None, help="Exchange ID") parser.add_argument("-n", "--order_count", type=int, default=1, help="Number of orders to submit") parser.add_argument("-i", "--interval", type=int, default=5, help="Number of seconds between orders") # wait for the client to login while not application.sessionID and not application.logged_out: time.sleep(0.5) if not application.sessionID: print("Login failed") exit(1) while 1: print("--> ", end='') command = input().strip() if not command: continue command_args = command.split(' ') if ' ' in command else [ command ] command = command_args[0] if command == "buy" or command == "sell": try : args = parser.parse_args(command_args) side = fix.Side_BUY if command == "buy" else fix.Side_SELL order_type = fix.OrdType_LIMIT if args.order_type == "LIMIT" else fix.OrdType_MARKET if order_type == fix.OrdType_LIMIT and args.price is None: print("Please specify LIMIT order price") continue for x in range(args.order_count): if x > 0: time.sleep(args.interval) application.submit_order(args.symbol, side, order_type, args.quantity, args.price, args.destination, args.exchange) time.sleep(0.5) # wait a bit for response except: print(sys.exc_info()[1]) elif command == "quit" or command == "exit": sys.exit(0) elif command == "help": parser.print_usage() else: print("Unknown command: %s" % command) parser.print_usage() except (fix.ConfigError, fix.RuntimeError) as e: print(e) if __name__=='__main__': parser = argparse.ArgumentParser(description='FIX Client') parser.add_argument('config_file', type=str, help='Name of configuration file') args = parser.parse_args() main(args.config_file)