In this post, I share my vision for an Open Trading standard for communicating with online brokers using modern technologies.

While looking for a way to add support for multiple brokers and data vendors to my open-source Python trading library, I discovered that there's currently no way to communicate with various brokers without re-writing most of the code responsible for getting market data, sending orders, and do everything aside from generating trading signals.

Sure, financial institutions have had the FIX protocol since the '90s. It's a communications protocol designed to streamline communications in the financial services industry.

The problems with FIX is that, aside from being overly complicated, very few retail and online brokers support it, and the few who do are charging quite a bit for the privilege to use it — making it inaccessible (and frankly irrelevant) for most retail traders.

This led me to the idea of designing a new standard for communicating with online brokers by providing a modern trading interface using technologies like a REST API for polling data, HTTP/2 Server-Sent Events (SSE) for event notifications, and WebSockets for streaming live market data.

I've named this idea the Open Trading Initiative :)

Below is my (very rudimentary) vision for the Open Trading standard. It's far from complete, and it's basically in a “brain dump” status.


Naming Conventions

A crucial part of the Open Trading Standard is to have brokers use the same naming convention for tickers and symbols. One way of achieving this for all of them to support the Financial Instrument Global Identifier (FIGI) when referring to tradable instruments.

For example, the FIGI or the SPY is BBG000BDTG10, while Apple's is BBG000B9Y2J5.

In 2016, Bloomberg launched OpenFIGI.com to provide exchanges, data providers, custodians, and other organizations search for existing FIGIs, request identifiers for new securities and cross-reference, or map, FIGIs to other third-party identifiers.

Server Responses

Responses to API calls will be in JSON format and must use the same data structure and field names for compatibility with the Open Trading standard.

As an example, an account status response may look something like this:

{
    "account_number": "12345ABCD",
    "buying_power": 262113.32,
    "cash": -23140.20,
    "created_at": "2019-06-12T22:47:07.99658Z",
    "currency": "USD",
    "daytrade_count": 2,
    "daytrading_buying_power": 262113.32,
    "equity": 103820.56,
    "id": "e6fe16f364a44921-8928cadf02f92f98",
    "initial_margin": 63480.38,
    "last_equity": 103529.24,
    "last_maintenance_margin": 38000.832,
    "long_market_value": 126960.76,
    "maintenance_margin": 38088.228,
    "multiplier": 4,
    "pattern_day_trader": false,
    "portfolio_value": 103820.56,
    "regt_buying_power": 80680.36,
    "short_market_value": 0,
    "shorting_enabled": true,
    "sma": 0,
    "status": "ACTIVE"
}

SDKs / Libraries

SDKs and libraries will need to be available for multiple programming platforms and languages like Python, Node.js, Go, Java, .NET, etc.

These libraries will implement the standardized REST, SSE, and WS architecture, as described later in this post.

As a first step, these libraries will offer their own implementation of the Open Trading standard, served via localhost, while “translating” the trader-broker messages behind the scenes.

This obfuscation will help get people comfortable with the Open Trading standard and help gain traction.


REST API — for data polling:

The REST API will allow traders to request information from the broker, submit orders, download historical prices, and subscribe to SSE event notifications.

Connection:

  • POST /connect — Authenticate using API credentials or connect to a locally running service (like IB's TWS). Query supports mode (live or paper/demo).
  • POST /disconnect — Disconnect from a locally running service (unsubscribes from server events, and disconnects from socket if applicable — see below)

Account:

  • GET /account — Get account information (balance, margin, etc..
  • GET /positions — Get current positions
  • GET /positions/{FIGI} — Get positions for instrument

Orders:

  • GET /orders — List all orders (query supports status, date_range, etc)
  • GET /orders/{FIGI} — List all orders for instrument
  • DELETE /orders — Cancel all pending orders
  • DELETE /orders/{FIGI} — Cancel all pending orders for instrument
  • POST /orders — Submit new order(s). JSON body includes FIGI, qty, side (buy/sell), type (market/limit/stop/stop_limit), time in force (day/gtc/opg/moc/...), exchange, price (required if type is limit, stop, or stop_limit), rth (Regular Trading Hours — defaults to true)
  • GET/orders/{orderId} — Get information for specific order
  • PUT /orders/{orderId} — Modify an existing, pending order
  • DELETE /orders/{orderId} — Delete an existing, pending order

Trades:

  • GET /trades — List trades (query supports status, date_range, etc.)
  • GET /trades/{FIGI} — List trades for instrument

Pricing:

  • GET /prices/{FIGI} — Get OHLC(V) data bars for instrument (query supports resolution and lookback)
  • GET /price/{FIGI} — Get latest price (inc. bid/ask info) for instrument

SSE — for event handling:

Server-Sent Events (SSE) is a server push technology enabling a client to receive automatic updates from a server via HTTP(S) connection. The SSE EventSource API is standardized as part of HTML5 by the W3C.

To subscribe to events, the protocol will listen for events on /events.

The suggested events are:

  • account — receive account updates (balance, margin, etc.)
  • positions — receive positions updates
  • order — receive order updates (fills, rejections, cancellations, etc.)

Here's an example (using Javascript code):

const endpoint = new EventSource("/events");

endpoint.addEventListener('account', (event) => {
    const data = JSON.parse(event.data);
    console.log('Account:', data);
    // do stuff with the data
}, false);

endpoint.addEventListener('positions', (event) => {
    const data = JSON.parse(event.data);
    console.log('Positions:', data);
    // do stuff with the data
}, false);

endpoint.addEventListener('order', (event) => {
    const data = JSON.parse(event.data);
    console.log('Order:', data);
    // do stuff with the data
}, false);

WebSockets — for streaming data:

For streaming live tick, bid-ask, or order book data, the Open Trading standard will use WebSockets to subscribe to the ticks and/or the book channels.

Here's an example (using Javascript and SocketIO):

const socket = io.connect('//broker.com');

socket.on('connect', () => {
    socket.emit('subscribe', {
        "token": "AUTH_TOKEN",
        "events": ["ticks", "book"],
        "instruments": ["FIGI1", "FIGI2", ...]
    });
});

socket.on('tick', (event) => {
    const data = JSON.parse(event.data);
    console.log('Tick:', data);
    // do stuff with tick data
});

socket.on('book', (event) => {
    const data = JSON.parse(event.data);
    console.log('Book:', data);
    // do stuff with boot data
});

What now?

I'm looking for programmers and traders to establish the Open Trading initiative's consortium, bounce ideas off each other, and decide on the Open Trading standards, methods and, implementation.

If you're interested in joining me on this (unpaid and open-sourced) project, please subscribe here and join the Discord server to share your thoughts with me.

Thanks for reading!