{"id":17030008,"url":"https://github.com/rob-blackbourn/jetblack-fixengine","last_synced_at":"2025-07-18T08:02:54.849Z","repository":{"id":55002053,"uuid":"170181216","full_name":"rob-blackbourn/jetblack-fixengine","owner":"rob-blackbourn","description":"An asyncio fix engine","archived":false,"fork":false,"pushed_at":"2023-04-07T06:43:40.000Z","size":167,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-29T23:02:56.645Z","etag":null,"topics":["asyncio","fix","fix-engine","fixprotocol","python","python3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rob-blackbourn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-11T18:39:13.000Z","updated_at":"2024-11-07T11:33:56.000Z","dependencies_parsed_at":"2025-03-22T20:35:47.337Z","dependency_job_id":null,"html_url":"https://github.com/rob-blackbourn/jetblack-fixengine","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/rob-blackbourn/jetblack-fixengine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rob-blackbourn%2Fjetblack-fixengine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rob-blackbourn%2Fjetblack-fixengine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rob-blackbourn%2Fjetblack-fixengine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rob-blackbourn%2Fjetblack-fixengine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rob-blackbourn","download_url":"https://codeload.github.com/rob-blackbourn/jetblack-fixengine/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rob-blackbourn%2Fjetblack-fixengine/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265724161,"owners_count":23817741,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncio","fix","fix-engine","fixprotocol","python","python3"],"created_at":"2024-10-14T08:03:24.724Z","updated_at":"2025-07-18T08:02:54.798Z","avatar_url":"https://github.com/rob-blackbourn.png","language":"Python","readme":"# jetblack-fixengine\n\nA pure python asyncio FIX engine.\n\n## Status\n\nThis is work in progress.\n\n## Installation\n\nThe package can be installed from the pie store.\n\n```bash\npip install jetblack-fixengine\n```\n\n## Overview\n\nThis project provides a pure Python, asyncio implementation of\na FIX engine, supporting both initiators and acceptors.\n\nThe engines use the\n[jetblack-fixparser](https://github.com/rob-blackbourn/jetblack-fixparser)\npackage to pass the FIX messages as plain Python objects. For example, a\n`LOGON` message could be sent as follows:\n\n```python\nawait send_message(\n    'LOGON',\n    {\n        'EncryptMethod': \"NONE\",\n        'HeartBtInt': 30\n    }\n)\n```\n\nThe `send_message` function adds the header fields for the session. The\nreceived message might look as follows:\n\n```python\n{\n    'MsgType': 'LOGON',\n    'MsgSeqNum': 42,\n    'SenderCompID': 'ME',\n    'TargetCompID': 'BANK OF SOMEWHERE',\n    'SendingTime': datetime(2000, 1, 1, 12, 35, 15, 734, timezone.utc),\n    'EncryptMethod': \"NONE\",\n    'HeartBtInt': 30\n}\n```\n\n### FIX Protocols\n\nThe FIX protocol consists of *admin* and *application* messages. The\nadmin messages are used for authentication and maintaining the session,\nand are generally of a well known structure. While the application messages\nare in the standard, they are often customized to include information not\nspecified in the standard.\n\nBecause of this the protocols are provided by config files. Historically\n`XML` was used. While this is supported, `yaml` is preferred and some\nexamples are provided in the\n[etc](https://github.com/rob-blackbourn/jetblack-fixengine/tree/master/etc)\nfolder.\n\nCurrently supported versions are 4.0, 4.1, 4.2, 4.3, 4.4.\n\n### Initiators\n\nAn initiator is a class which inherits from `FIXApplication`, and implements a\nfew methods, and has access to `send_message` from the `fix_engine`. Here is an example.\n\n```python\nimport asyncio\nimport logging\nfrom pathlib import Path\nfrom typing import Mapping, Any\n\nfrom jetblack_fixparser import load_yaml_protocol\nfrom jetblack_fixengine import (\n    FileStore,\n    start_initiator,\n    InitiatorConfig,\n    FIXApplication,\n    FIXEngine\n)\n\nLOGGER = logging.getLogger(__name__)\n\n\nclass MyInitiator(FIXApplication):\n    \"\"\"An instance of the initiator\"\"\"\n\n    async def on_logon(\n            self,\n            message: Mapping[str, Any],\n            fix_engine: FIXEngine\n    ) -\u003e None:\n        LOGGER.info(\n            'on_logon[%s] %s/%s',\n            message['MsgSeqNum'],\n            message['SenderCompID'],\n            message['TargetCompID'],\n        )\n\n    async def on_logout(\n            self,\n            _message: Mapping[str, Any],\n            fix_engine: FIXEngine\n    ) -\u003e None:\n        LOGGER.info('on_logout')\n\n    async def on_application_message(\n            self,\n            _message: Mapping[str, Any],\n            fix_engine: FIXEngine\n    ) -\u003e None:\n        LOGGER.info('on_application_message')\n\n\napp = MyInitiator()\nconfig = InitiatorConfig(\n    '127.0.0.1',\n    9801,\n    load_yaml_protocol(Path('etc') / 'FIX44.yaml'),\n    'INITIATOR1',\n    'ACCEPTOR',\n    FileStore(Path('store'))\n)\n\nlogging.basicConfig(level=logging.DEBUG)\n\nasyncio.run(\n    start_initiator(app, config)\n)\n```\n\n### Acceptor\n\nThe acceptor works in the same way as the initiator. Here is an example:\n\n```python\nimport asyncio\nimport logging\nfrom pathlib import Path\nfrom typing import Mapping, Any\n\nfrom jetblack_fixparser import load_yaml_protocol\nfrom jetblack_fixengine import (\n    FileStore,\n    start_acceptor,\n    AcceptorConfig,\n    FIXApplication,\n    FIXEngine\n)\n\n\nLOGGER = logging.getLogger(__name__)\n\n\nclass MyAcceptor(FIXApplication):\n    \"\"\"An instance of the acceptor\"\"\"\n\n    async def on_logon(\n            self,\n            _message: Mapping[str, Any],\n            _fix_engine: FIXEngine\n    ) -\u003e None:\n        LOGGER.info('on_logon')\n\n    async def on_logout(\n            self,\n            _message: Mapping[str, Any],\n            _fix_engine: FIXEngine\n    ) -\u003e None:\n        LOGGER.info('on_logout')\n\n    async def on_application_message(\n            self,\n            _message: Mapping[str, Any],\n            _fix_engine: FIXEngine\n    ) -\u003e None:\n        LOGGER.info('on_application_message')\n\n\nlogging.basicConfig(level=logging.DEBUG)\n\napp = MyAcceptor()\nconfig = AcceptorConfig(\n    '0.0.0.0',\n    9801,\n    load_yaml_protocol(Path('etc') / 'FIX44.yaml'),\n    'ACCEPTOR',\n    'INITIATOR1',\n    FileStore(Path(\"store\"))\n)\n\nasyncio.run(\n    start_acceptor(\n        app,\n        config\n    )\n)\n```\n\nNote that throwing the exception `LogonError` from `on_logon` will reject\nthe logon request.\n\n### Stores\n\nThe engines need to store their state. Two stores are currently provided:\na file store (`FileStore`) and sqlite (`SqlStore`).\n\n## Implementation\n\nThe engines are implemented as state machines. This means they can be\ntested without the need for IO.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frob-blackbourn%2Fjetblack-fixengine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frob-blackbourn%2Fjetblack-fixengine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frob-blackbourn%2Fjetblack-fixengine/lists"}