API Documentation

Language: C++ Java Python
Basic: Intro/Trade Quote Category Status Symbol Options
Detailed: Trade Quote

Introduction to Options

Messages for option contracts are very similar to messages for equities. The primary difference is the addition of pnxOptionHdr to the coreHeader object. The major challenge for options processing is the number of messages. In addition to parsing options messages, this guide will also cover some recommended performance improvements.

Code

import NxCore
from multiprocessing import Process

def OnNxCoreCallback(NxCoreSys, NxCoreMsg):
    if NxCoreMsg.MessageType == NxCore.NxMSG_STATUS and NxCoreSys.UserData:
        for permission in [2,20,21,22].remove(NxCoreSys.UserData):
            if NxCore.ExcludeOpraExch(NxCore.NxPERMID_REMOVE | permission):
                return NxCore.NxCALLBACKRETURN_CONTINUE
        NxCoreSys.UserData = 0

    if NxCoreMsg.MessageType == NxCore.NxMSG_TRADE:

        header = NxCoreMsg.coreHeader
        option_header = header.pnxOptionHdr
        if option_header:

            symbol = header.pnxStringSymbol.String
            timestamp = header.nxExgTimestamp
            expire_date = option_header.nxExpirationDate
            strike_price = NxCore.PriceToFloat(option_header.strikePrice, 7)
            if option_header.PutCall == 1:
                contract_type = "Put"
            else:
                contract_type = "Call"

            trade = NxCoreMsg.coreData.Trade
            price = NxCore.PriceToFloat(trade.Price,trade.PriceType)
            size = trade.Size

            print("Trade for {} {} expiring {:02d}{:02d}{:02d} with strike ${:.3f} at {:02d}:{:02d}:{:02d} for {} shares at ${:.2f}"
                .format(symbol, contract_type, expire_date.Year, expire_date.Month, expire_date.Day, strike_price,
                        timestamp.Hour, timestamp.Minute, timestamp.Second, size, price))
    return NxCore.NxCALLBACKRETURN_CONTINUE

def NxCoreThread(permission):
    if NxCore.LoadNxCore("NxCoreAPI64.dll"):
        returnValue = NxCore.ProcessTape("demo.DO.nx2", 0, NxCore.NxCF_EXCLUDE_CRC_CHECK | NxCore.NxCF_EXCLUDE_QUOTES, permission, OnNxCoreCallback)
        NxCore.ProcessReturnValue(returnValue)
    else:
        print("loading library failed")
        if NxCore.LoadNxCore("NxCoreAPI64.dll"):

if __name__ == "__main__":
    threads = []
    threads.append(Process(target=NxCoreThread, args=(2, )))
    threads.append(Process(target=NxCoreThread, args=(20, )))
    threads.append(Process(target=NxCoreThread, args=(21, )))
    threads.append(Process(target=NxCoreThread, args=(22, )))

    for thread in threads:
        thread.start()

    for thread in threads:
        thread.join()

Import

In addition to the NxCore module used in all examples, the Process class from multiprocessing is included to allow processing data on multiple threads.

import NxCore
from multiprocessing import Process

Splitting data

One way of improving performance is limiting what part of the options feed is processed on a thread. Nanex splits the option feed into 4 permissions 2, 20, 21, and 22 each corresponding to different ranges of option roots. The function ExcludeOpraExch is used to remove a permission from processing. By removing all option permissions except for the one assigned to UserData, each thread will only process a quarter of the data.

if NxCoreMsg.MessageType == NxCore.NxMSG_STATUS and NxCoreSys.UserData:
    for permission in [2,20,21,22].remove(NxCoreSys.UserData):
        if NxCore.ExcludeOpraExch(NxCore.NxPERMID_REMOVE | permission):
            return NxCore.NxCALLBACKRETURN_CONTINUE
    NxCoreSys.UserData = 0

Option Header

Option contract information is contained within pnxOptionHdr in the coreHeader object. For this example we will get the expiration date, strike price, and put/call. The strike price always has a price type of 7.

header = NxCoreMsg.coreHeader
option_header = header.pnxOptionHdr
if option_header:

    symbol = header.pnxStringSymbol.String
    timestamp = header.nxExgTimestamp
    expire_date = option_header.nxExpirationDate
    strike_price = NxCore.PriceToFloat(
        option_header.strikePrice, 7)
    if option_header.PutCall == 1:
        contract_type = "Put"
    else:
        contract_type = "Call"

Thread Function

This is the function that will be called by each thread. For the purposes of this example we will pass it a permission id as the first parameter. To improve performance we are going to use two control flags, joined by a bitwise or, as the 3rd argument of ProcessTape. NxCF_EXCLUDE_CRC_CHECK disables frequent CRC calculations. CRC checks will still be performed, but not as frequently. Since we are only processing trades in this example we will also set NxCF_EXCLUDE_QUOTES which prevents all quote messages from being sent to the Python callback.
Additionally we will pass the permission id as the 4th argument of ProcessTape which assigns it to UserData in NxCoreSys during the callback.

def NxCoreThread(permission):
    if NxCore.LoadNxCore("NxCoreAPI64.dll"):
        returnValue = NxCore.ProcessTape(
            "demo.DO.nx2",
            0,
            NxCore.NxCF_EXCLUDE_CRC_CHECK | NxCore.NxCF_EXCLUDE_QUOTES,
            permission,
            OnNxCoreCallback)

Launching Threads

On the main thread we first create a list of Process objects with the 4 different option permission value. Next, we start each process. Then, we wait for every process to finish.

if __name__ == "__main__":
    threads = []
    threads.append(Process(target=NxCoreThread, args=(2, )))
    threads.append(Process(target=NxCoreThread, args=(20, )))
    threads.append(Process(target=NxCoreThread, args=(21, )))
    threads.append(Process(target=NxCoreThread, args=(22, )))

    for thread in threads:
        thread.start()

    for thread in threads:
        thread.join()