Package: jetblack-fixengine
jetblack-fixengineA pure python asyncio FIX engine.StatusThis is work in progress.InstallationThe package can be install from the pie store.pipinstalljetblack-fixengineOverviewThis project provides a pure Python, asyncio implementation of
a FIX engine, supporting both initiators and acceptors.The engine uses thejetblack-fixparserpackage to present the FIX messages a plain Python objects. For example, aLOGONmessage
can be sent as follows:awaitsend_message({'MsgType':'LOGON','MsgSeqNum':42,'SenderCompID':'ME','TargetCompID':'BANK OF SOMEWHERE','SendingTime':datetime.now(timezone.utc),'EncryptMethod':"NONE",'HeartBtInt':30})FIX ProtocolsThe FIX protocol is a combination ofwell knownmessages (likeLOGON)
andcustommessages (like an order to buy or sell). The protocol
has evolved through a number of different versions providing new features.Because of this the protocols are provided by config files. HistoricallyXMLwas used. While this is supported,yamlis preferred and some
example protocols are provided in theetcfolder.Currently supported versions are 4.0, 4.1, 4.2, 4.3, 4.4.InitiatorsAn initiator is a class which inherits fromFIXApplication, and implements a
few methods, and has access tosend_messagefrom thefix_engine. Here is an example.importasyncioimportloggingfrompathlibimportPathfromtypingimportMapping,Anyfromjetblack_fixparserimportload_yaml_protocolfromjetblack_fixengineimport(FileStore,start_initiator,InitiatorConfig,FIXApplication,FIXEngine)LOGGER=logging.getLogger(__name__)classMyInitiator(FIXApplication):"""An instance of the initiator"""asyncdefon_logon(self,_message:Mapping[str,Any],fix_engine:FIXEngine)->None:LOGGER.info('on_logon')asyncdefon_logout(self,_message:Mapping[str,Any],fix_engine:FIXEngine)->None:LOGGER.info('on_logout')asyncdefon_application_message(self,_message:Mapping[str,Any],fix_engine:FIXEngine)->None:LOGGER.info('on_application_message')app=MyInitiator()config=InitiatorConfig('127.0.0.1',9801,load_yaml_protocol(Path('etc')/'FIX44.yaml'),'INITIATOR1','ACCEPTOR',FileStore(Path('store')))logging.basicConfig(level=logging.DEBUG)asyncio.run(start_initiator(app,config))AcceptorThe acceptor works in the same way as the initiator. Here is an example:importasyncioimportloggingfrompathlibimportPathfromtypingimportMapping,Anyfromjetblack_fixparserimportload_yaml_protocolfromjetblack_fixengineimport(FileStore,start_acceptor,AcceptorConfig,FIXApplication,FIXEngine)LOGGER=logging.getLogger(__name__)classMyAcceptor(FIXApplication):"""An instance of the acceptor"""asyncdefon_logon(self,_message:Mapping[str,Any],_fix_engine:FIXEngine)->None:LOGGER.info('on_logon')asyncdefon_logout(self,_message:Mapping[str,Any],_fix_engine:FIXEngine)->None:LOGGER.info('on_logout')asyncdefon_application_message(self,_message:Mapping[str,Any],_fix_engine:FIXEngine)->None:LOGGER.info('on_application_message')logging.basicConfig(level=logging.DEBUG)app=MyAcceptor()config=AcceptorConfig('0.0.0.0',9801,load_yaml_protocol(Path('etc')/'FIX44.yaml'),'ACCEPTOR','INITIATOR1',FileStore(Path("store")))asyncio.run(start_acceptor(app,config))Note that throwing the exceptionLogonErrorfromon_logonwill reject
the logon request.StoresThe engines need to store their state. Two stores are currently provided:
a file store (FileStore) and sqlite (SqlStore).ImplementationThe engines are implemented as state machines. This means they can be
tested without the need for IO.