Basic: | Intro/Trade | Quote | Category | Status | Symbol | Options |
Detailed: | Trade | Quote |
Introduction to Options
This example should use the demo.DO.nx2 tape instead of demo.XU.nx2. 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
using System; using System.Threading; using NxCoreAPI; class NxCoreThread { private String filename; private int threadPermission; private bool successfulExclude = false; public NxCoreThread(String tapePath, int perm) { this.filename = tapePath; this.threadPermission = perm; } unsafe int OnNxCoreCallback(NxCoreSystem* pNxCoreSys, NxCoreMessage* pNxCoreMsg) { if (pNxCoreMsg->MessageType == NxCore.NxMSG_STATUS && !successfulExclude) { int[] optionPermissions = { 2, 20, 21, 22 }; for (int i = 0; i < 4; i++) { int permission = optionPermissions[i]; if (threadPermission != permission && NxCore.ExcludeOpraExch(NxCore.NxPERMID_REMOVE | permission) != 0) return NxCore.NxCALLBACKRETURN_CONTINUE; } successfulExclude = true; } if (pNxCoreMsg->MessageType == NxCore.NxMSG_TRADE) { NxCoreHeader* pHeader = &pNxCoreMsg->coreHeader; NxOptionHdr* pnxOptionHdr = pHeader->pnxOptionHdr; if (pnxOptionHdr != null) { String symbol = new String(&pHeader->pnxStringSymbol->String); NxTime* pTimestamp = &pHeader->nxExgTimestamp; NxDate* pExpireDate = &pnxOptionHdr->nxExpirationDate; double strikePrice = NxCore.PriceToDouble(pnxOptionHdr->strikePrice, 7); String contractType; if (pnxOptionHdr->PutCall == 1) contractType = "Put"; else contractType = "Call"; NxCoreTrade* pTrade = &pNxCoreMsg->coreData.Trade; double price = NxCore.PriceToDouble(pTrade->Price, pTrade->PriceType); uint size = pTrade->Size; Console.WriteLine("Trade for {0:s} {1:s} expiring {2:d}/{3:d2}/{4:d2} with strike ${5:f2} at {6:d2}:{7:d2}:{8:d2} for {9:d} shares at ${10:f2}", symbol, contractType, pExpireDate->Year, pExpireDate->Month, pExpireDate->Day, strikePrice, pTimestamp->Hour, pTimestamp->Minute, pTimestamp->Second, size, price); } } return NxCore.NxCALLBACKRETURN_CONTINUE; } public unsafe void run() { int returnValue = NxCore.ProcessTape(filename, null,(uint) NxCore.NxCF_EXCLUDE_CRC_CHECK, 0, this.OnNxCoreCallback); NxCore.processReturnValue(returnValue); } } class optionSample { static void Main(string[] args) { if (args.Length < 1) return; Thread[] threads = { new Thread((new NxCoreThread(args[0],2)).run), new Thread((new NxCoreThread(args[0], 20)).run), new Thread((new NxCoreThread(args[0], 21)).run), new Thread((new NxCoreThread(args[0], 22)).run) }; foreach (var thread in threads) thread.Start(); foreach (var thread in threads) thread.Join(); } }
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 threadPermission, each thread will only process a quarter of the data. |
if (pNxCoreMsg->MessageType == NxCore.NxMSG_STATUS && !successfulExclude) { int[] optionPermissions = { 2, 20, 21, 22 }; for (int i = 0; i < 4; i++) { int permission = optionPermissions[i]; if (threadPermission != permission && NxCore.ExcludeOpraExch(NxCore.NxPERMID_REMOVE | permission) != 0) return NxCore.NxCALLBACKRETURN_CONTINUE; } successfulExclude = true; } |
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. |
NxCoreHeader* pHeader = &pNxCoreMsg->coreHeader; NxOptionHdr* pnxOptionHdr = pHeader->pnxOptionHdr; if (pnxOptionHdr != null) { String symbol = new String(&pHeader->pnxStringSymbol->String); NxTime* pTimestamp = &pHeader->nxExgTimestamp; NxDate* pExpireDate = &pnxOptionHdr->nxExpirationDate; double strikePrice = NxCore.PriceToDouble(pnxOptionHdr->strikePrice, 7); String contractType; if (pnxOptionHdr->PutCall == 1) contractType = "Put"; else contractType = "Call"; ... } |
Process Tape Flags
To improve performance we are going to use a control flag in the 3rd argument of ProcessTape. NxCF_EXCLUDE_CRC_CHECK disables frequent CRC calculations. CRC checks will still be performed, but not as frequently. |
NxCore.ProcessTape( filename, null, uint) NxCore.NxCF_EXCLUDE_CRC_CHECK, 0, this.OnNxCoreCallback); |
Launching Threads
On the main thread we create an array of thread objects with the 4 different option permission value. Then, we wait for every thread to finish. |
Thread[] threads = { new Thread((new NxCoreThread(args[0],2)).run), new Thread((new NxCoreThread(args[0], 20)).run), new Thread((new NxCoreThread(args[0], 21)).run), new Thread((new NxCoreThread(args[0], 22)).run) }; foreach (var thread in threads) thread.Start(); foreach (var thread in threads) thread.Join(); |