Last active
October 25, 2019 16:20
-
-
Save vitawasalreadytaken/7c71a3d1c341501c388f to your computer and use it in GitHub Desktop.
Skeleton of a real Quickfix application
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import logging | |
import quickfix as fix | |
def _str(msg): | |
''' Convert a FIX message to a readable string. ''' | |
return msg.toString().replace('\x01', '@') | |
class MyApplication(fix.Application): | |
def __init__(self, session): | |
''' | |
:param session: An object (like `fix.Session`) with a `sendToTarget` method that we can use to dispatch messages. | |
''' | |
super(MyApplication, self).__init__() | |
self.logger = logging.getLogger(self.__class__.__name__) | |
self.session = session | |
self.connected = False | |
def onCreate(self, sessionID): | |
''' | |
Called when the application is initialized. | |
''' | |
self.sessionID = sessionID | |
# Use our session ID as the name of the logger. | |
self.logger = logging.getLogger('{}({})'.format(self.__class__.__name__, sessionID.toString())) | |
self.logger.info('Application created with sessionID = %s.', sessionID.toString()) | |
def onLogon(self, sessionID): | |
''' | |
Called by Quickfix on session login. | |
''' | |
self.logger.info('Logon.') | |
self.connected = True | |
def onLogout(self, sessionID): | |
''' | |
Called by Quickfix on session logout. | |
''' | |
self.logger.info('Logout.') | |
self.connected = False | |
def onMessage(self, message, sessionID): | |
# Still not sure when (if?) this callback is called by Quickfix. | |
self.logger.info('Message = %s.', _str(message)) | |
def toAdmin(self, message, sessionID): | |
''' | |
Process outgoing session-level messages (logon, logout, heartbeat) before they are sent. | |
''' | |
self.logger.info('Sending admin message = %s.', _str(message)) | |
def fromAdmin(self, message, sessionID): | |
''' | |
Process incoming session-level messages (logon, logout, heartbeat). | |
Quickfix handles them automatically and sends appropriate responses. | |
''' | |
self.logger.info('Received admin message = %s.', _str(message)) | |
def toApp(self, message, sessionID): | |
''' | |
Process outgoing application-level messages before they are sent. | |
''' | |
self.logger.info('Sending app message = %s.', _str(message)) | |
def fromApp(self, message, sessionID): | |
''' | |
Handle incoming application-level messages. | |
''' | |
self.logger.info('Received app message = %s.', _str(message)) | |
msgType = fix.MsgType() | |
message.getHeader().getField(msgType) | |
msgType = msgType.getValue() | |
if msgType == fix.MsgType_ExecutionReport: | |
# Extract fields from the message here and pass to an upper layer | |
pass | |
elif msgType == fix.MsgType_OrderCancelReject: | |
# Extract fields from the message here and pass to an upper layer | |
pass | |
def createOrder(self, order): | |
''' | |
:param order: Dictionary describing the order to be created. Mandatory fields: | |
id: order ID unique for the session and the day (FIX# 11) | |
exchange: target exchange identifier (FIX# 100) | |
symbol: the traded security symbol (FIX# 55) | |
currency: currency code of the order (FIX# 15) | |
side: side of the order (1 == buy, 2 == sell) (FIX# 54) | |
price: price (required for limit orders) (FIX# 44) | |
quantity: transaction quantity (FIX# 38) | |
type: order type (1 == market, 2 == limit) (FIX# 40) | |
''' | |
if not self.connected: | |
raise RuntimeError('Application not connected') | |
message = fix.Message() | |
header = message.getHeader() | |
header.setField(fix.BeginString('FIX.4.2')) | |
header.setField(fix.MsgType('D')) | |
# 11 | |
message.setField(fix.ClOrdID(str(order['id']))) | |
# 21 | |
message.setField(fix.HandlInst('1')) | |
# 100 | |
message.setField(fix.ExDestination(str(order['exchange']))) | |
# 55 | |
message.setField(fix.Symbol(str(order['symbol']))) | |
# 60 (current time in UTC) | |
message.setField(fix.TransactTime(1)) | |
# 15 | |
message.setField(fix.Currency(str(order['currency']))) | |
# 54 (1 == buy, 2 == sell) | |
message.setField(fix.Side(str(order['side']))) | |
# 44 | |
message.setField(fix.Price(float(order['price']))) | |
# 38 | |
message.setField(fix.OrderQty(int(order['quantity']))) | |
# 40 (1 == market, 2 == limit) | |
message.setField(fix.OrdType(str(order['type']))) | |
self.session.sendToTarget(message, self.sessionID) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[DEFAULT] | |
ConnectionType=initiator | |
ReconnectInterval=2 | |
FileStorePath=store | |
FileLogPath=log | |
StartTime=00:00:00 | |
EndTime=00:00:00 | |
UseDataDictionary=Y | |
DataDictionary=quickfix/FIX42.xml | |
SocketConnectHost=192.168.1.50 | |
SocketConnectPort=44000 | |
LogoutTimeout=5 | |
ResetOnLogon=N | |
ResetOnDisconnect=N | |
[SESSION] | |
BeginString=FIX.4.2 | |
SenderCompID=CLIENTID | |
TargetCompID=FIXENGINEID | |
HeartBtInt=30 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
sys.path.insert(0, 'path/to/your/new/quickfix/directory') | |
import quickfix as fix | |
import application | |
app = application.MyApplication(fix.Session) | |
fixSettings = fix.SessionSettings('path/to/quickfix/configuration.conf') | |
storeFactory = fix.FileStoreFactory(fixSettings) | |
initiator = fix.SocketInitiator(app, storeFactory, fixSettings) | |
initiator.start() | |
# Run your application logic here | |
initiator.stop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment