fix_session.py (294 lines of code) (raw):
#####################################################################################
# Here we illustrate how to use Python QuickFIX library to talk to Deltix FIX Gateway
# fix_sample_order_entry and fix_sample_market_data samples rely on this class
#####################################################################################
import time
import quickfix as fix
import configparser
import quickfix44 as fixnn
class Application(fix.Application):
debug = False
session_id = None
session_pwd = None
logged_out = False
def setSessionPassword(self, password):
self.session_pwd = password
def onCreate(self, session_id):
return
def onLogon(self, session_id):
print("Session %s successfully logged in" % session_id)
self.session_id = session_id
self.logged_out = False
return
def onLogout(self, session_id):
print("Session %s logged out" % session_id)
self.session_id = None
self.logged_out = True
return
def toAdmin(self, message, session_id):
if self.debug:
print("To Admin message: %s" % message)
msgType = fix.MsgType()
message.getHeader().getField(msgType)
if msgType.getValue() == fix.MsgType_Logon :
message.getHeader().setField(fix.Password(self.session_pwd))
return
def fromAdmin(self, message, session_id):
if self.debug:
print("From Admin message: %s" % message)
return
def toApp(self, message, session_id):
if self.debug:
print("To App message: ", end='')
print_message(message)
return
def fromApp(self, message, session_id):
print("Received message: ", end='')
print_message(message)
return
class FixSession(object) :
initiator = None
exec_id = 0
def __init__(self, config_file):
self.settings = fix.SessionSettings(config_file)
self.config = configparser.ConfigParser()
self.config.read(config_file)
sender_pwd = None
if "SESSION" in self.config and "SenderPassword" in self.config["SESSION"]:
sender_pwd = self.config["SESSION"]["SenderPassword"]
self.application = Application()
if sender_pwd:
self.application.setSessionPassword(sender_pwd)
else:
print("Warning: SESSION SenderPassword is not specified in config file: " + config_file)
store_factory = fix.FileStoreFactory(self.settings)
log_factory = fix.FileLogFactory(self.settings)
self.initiator = fix.SocketInitiator(self.application, store_factory, self.settings, log_factory)
def start(self):
if not self.initiator.isStopped():
raise Exception("Session is already started")
self.application.session_id = None
self.application.logged_out = False
self.initiator.start()
# wait for the client to login
while not self.application.session_id and not self.application.logged_out:
time.sleep(0.1)
if not self.application.session_id:
raise Exception("Login failed")
def stop(self):
self.initiator.stop()
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 submit(self, request):
request.set_id(self.gen_exec_id())
print("Sending %s" % request)
fix.Session.sendToTarget(request.get_fix_message(), self.application.session_id)
def submit_buy_order(self, destination, symbol, quantity, price=None, account=None, custom_fields=None):
self.submit_order(destination, fix.Side_BUY, symbol, quantity, price, account, custom_fields)
def submit_sell_order(self, destination, symbol, quantity, price=None, account=None, custom_fields=None):
self.submit_order(destination, fix.Side_SELL, symbol, quantity, price, account, custom_fields)
def submit_order(self, destination, side, symbol, quantity, price=None, account=None, custom_fields=None):
request = OrderRequest()
request.set_symbol(symbol)
request.set_destination(destination)
request.set_side(side)
request.set_quantity(quantity)
if price is not None:
request.set_price(price)
request.set_order_type(fix.OrdType_LIMIT)
else:
request.set_order_type(fix.OrdType_MARKET)
if account:
request.set_account(account)
if custom_fields:
request.set_custom_fields(custom_fields)
self.submit(request)
# End of FixSession
class OrderRequest(object) :
id = None
symbol = None
side = fix.Side_BUY
quantity = None
price = None
order_type = fix.OrdType_MARKET
time_in_force = fix.TimeInForce_DAY
account = None
destination = None
exchange = None
custom_fields = {}
def set_id(self, id):
self.id = id
def set_symbol(self, symbol):
self.symbol = symbol
def set_side(self, side):
self.side = fix.Side_BUY if side.upper() == "BUY" else fix.Side_SELL
def set_quantity(self, quantity):
self.quantity = quantity
def set_price(self, price):
self.price = price
def set_order_type(self, order_type):
self.order_type = order_type
def set_time_in_force(self, time_in_force):
self.time_in_force = time_in_force
def set_account(self, account):
self.account = account
def set_destination(self, destination):
self.destination = destination
def set_exchange(self, exchange):
self.exchange = exchange
def set_custom_fields(self, custom_fields):
self.custom_fields = custom_fields
def get_fix_message(self):
request = fix.Message()
request.getHeader().setField(fix.BeginString(fix.BeginString_FIX44))
request.getHeader().setField(fix.MsgType(fix.MsgType_NewOrderSingle))
assert self.id
request.setField(fix.ClOrdID(self.id))
assert self.symbol
request.setField(fix.Symbol(self.symbol))
assert self.side
request.setField(fix.Side(self.side))
assert self.quantity
request.setField(fix.OrderQty(self.quantity))
if self.price is not None:
request.setField(fix.Price(self.price))
elif self.order_type == fix.OrdType_LIMIT:
raise Exception("Must specify price for LIMIT order")
assert self.order_type
request.setField(fix.OrdType(self.order_type))
assert self.time_in_force
request.setField(fix.TimeInForce(self.time_in_force))
if self.account:
request.setField(fix.Account(self.account))
if self.destination is not None:
request.setField(fix.ExecBroker(self.destination))
if self.exchange is not None:
request.setField(fix.ExDestination(self.exchange))
request.setField(fix.TransactTime())
for key in self.custom_fields:
request.setField(key, self.custom_fields[key])
request.setField(fix.SenderCompID("TRADER"))
return request
def __str__(self):
side = "BUY" if self.side == fix.Side_BUY else "SELL"
order_type = "LIMIT" if self.order_type == fix.OrdType_LIMIT else "MARKET"
return "OrderRequest: ID=%s, OrderType=%s, Symbol=%s, Side=%s, Quantity=%s, Price=%s, Account=%s, Destination=%s, Exchange=%s" % \
(self.id, order_type, self.symbol, side, self.quantity, self.price, self.account, self.destination, self.exchange)
# End of ObjectRequest
class MarketDataRequest(object):
id = None
symbols = []
def set_id(self, id):
self.id = id
def set_symbols(self, symbols):
self.symbols = symbols
def get_fix_message(self):
request = fix.Message()
request.getHeader().setField(fix.BeginString(fix.BeginString_FIX44))
request.getHeader().setField(fix.MsgType(fix.MsgType_MarketDataRequest))
request.setField(fix.MDReqID(self.id))
request.setField(fix.SubscriptionRequestType(fix.SubscriptionRequestType_SNAPSHOT_PLUS_UPDATES))
request.setField(fix.SecurityType(fix.SecurityType_FOREIGN_EXCHANGE_CONTRACT))
request.setField(fix.MarketDepth(0)) # full book
request.setField(fix.MDUpdateType(fix.MDUpdateType_FULL_REFRESH)) # fix.MDUpdateType_INCREMENTAL_REFRESH
group = fixnn.MarketDataRequest().NoMDEntryTypes()
group.setField(fix.MDEntryType(fix.MDEntryType_BID))
group.setField(fix.MDEntryType(fix.MDEntryType_OFFER))
group.setField(fix.MDEntryType(fix.MDEntryType_TRADE))
request.addGroup(group)
request.setField(fix.NoRelatedSym(len(self.symbols)))
group = fixnn.MarketDataRequest().NoRelatedSym()
for symbol in self.symbols:
group.setField(fix.Symbol(symbol))
request.addGroup(group)
return request
def __str__(self):
return "MarketDataRequest: ID=%s, Symbols=%s" % (self.id, self.symbols)
# End of MarketDataRequest
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)
elif msg_type == fix.MsgType_MarketDataRequestReject:
print("REJECTED")
elif msg_type == fix.MsgType_MarketDataSnapshotFullRefresh:
print("SNAPSHOT")
print(get_field_value(fix.Symbol(), msg))
print(msg)
else:
msg_str = "OrderID="
msg_str += get_field_value(fix.ClOrdID(), msg)
msg_str += ", MessageType="
msg_str += get_message_type(msg)
msg_str += ", OrderStatus=" #39
msg_str += get_order_status(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))
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