Skip to main content

A pure Python implementation of the FIX protocol

Project description

jetblack-fixengine

A pure python asyncio FIX engine.

Status

This is work in progress.

Installation

The package can be install from the pie store.

pip install jetblack-fixengine

Overview

This project provides a pure Python, asyncio implementation of a FIX engine, supporting both initiators and acceptors.

The engine uses the jetblack-fixparser package to present the FIX messages a plain Python objects. For example, a LOGON message can be sent as follows:

await send_message({
    'MsgType': 'LOGON',
    'MsgSeqNum': 42,
    'SenderCompID': 'ME',
    'TargetCompID': 'BANK OF SOMEWHERE',
    'SendingTime': datetime.now(timezone.utc),
    'EncryptMethod': "NONE",
    'HeartBtInt': 30
})

FIX Protocols

The FIX protocol is a combination of well known messages (like LOGON) and custom messages (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. Historically XML was used. While this is supported, yaml is preferred and some example protocols are provided in the etc folder.

Currently supported versions are 4.0, 4.1, 4.2, 4.3, 4.4.

Initiators

An initiator is a class which inherits from FIXApplication, and implements a few methods, and has access to send_message from the fix_engine. Here is an example.

import asyncio
import logging
from pathlib import Path
from typing import Mapping, Any

from jetblack_fixparser import load_yaml_protocol
from jetblack_fixengine import (
    FileStore,
    start_initiator,
    InitiatorConfig,
    FIXApplication,
    FIXEngine
)

LOGGER = logging.getLogger(__name__)


class MyInitiator(FIXApplication):
    """An instance of the initiator"""

    async def on_logon(
            self,
            _message: Mapping[str, Any],
            fix_engine: FIXEngine
    ) -> None:
        LOGGER.info('on_logon')

    async def on_logout(
            self,
            _message: Mapping[str, Any],
            fix_engine: FIXEngine
    ) -> None:
        LOGGER.info('on_logout')

    async def on_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)
)

Acceptor

The acceptor works in the same way as the initiator. Here is an example:

import asyncio
import logging
from pathlib import Path
from typing import Mapping, Any

from jetblack_fixparser import load_yaml_protocol
from jetblack_fixengine import (
    FileStore,
    start_acceptor,
    AcceptorConfig,
    FIXApplication,
    FIXEngine
)


LOGGER = logging.getLogger(__name__)


class MyAcceptor(FIXApplication):
    """An instance of the acceptor"""

    async def on_logon(
            self,
            _message: Mapping[str, Any],
            _fix_engine: FIXEngine
    ) -> None:
        LOGGER.info('on_logon')

    async def on_logout(
            self,
            _message: Mapping[str, Any],
            _fix_engine: FIXEngine
    ) -> None:
        LOGGER.info('on_logout')

    async def on_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 exception LogonError from on_logon will reject the logon request.

Stores

The engines need to store their state. Two stores are currently provided: a file store (FileStore) and sqlite (SqlStore).

Implementation

The engines are implemented as state machines. This means they can be tested without the need for IO.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jetblack-fixengine-1.0.0a5.tar.gz (29.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jetblack_fixengine-1.0.0a5-py3-none-any.whl (40.2 kB view details)

Uploaded Python 3

File details

Details for the file jetblack-fixengine-1.0.0a5.tar.gz.

File metadata

  • Download URL: jetblack-fixengine-1.0.0a5.tar.gz
  • Upload date:
  • Size: 29.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.12 CPython/3.10.10 Darwin/21.6.0

File hashes

Hashes for jetblack-fixengine-1.0.0a5.tar.gz
Algorithm Hash digest
SHA256 1cfcc80be8e9866921f6d8b42f67227afac317eb95148801e91a322db810ba1a
MD5 60cc171a92767e735ec7bdc4c3e29f18
BLAKE2b-256 06455613673f3851bd74e91dd979ec08c275b86645b1b32e1518ab44ed2a2786

See more details on using hashes here.

File details

Details for the file jetblack_fixengine-1.0.0a5-py3-none-any.whl.

File metadata

File hashes

Hashes for jetblack_fixengine-1.0.0a5-py3-none-any.whl
Algorithm Hash digest
SHA256 5b5728bafcf9ec92a90ee29a9acd9f6783aa69b20a64a51de2c48b68233918f9
MD5 3b46798e3a8183cfaa60a6b87e6a437f
BLAKE2b-256 65084b7fccb7858e9c287a087b751038dc1d866bf521e2e03eb7c990189735eb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page