Skip to content

Instrument

Instrument object represent a tradable contract such as Equity, Futures, Options. In any trading framework, Instrument class is key to represent the important properties such as InstrumentID, Exchange InstrumentID, Exchange Segment, Symbol name, Lot Size, Minimum tick Size, Contract multiplier etc. Every exchange or broker provides these details in structured file format or through an API called contract specifications or contract master. QXFinLib defines these Instrument class structure to represent your contracts in object form to be used in trading models. The technical analysis functionality uses Instrument class to derive various statistics based on TickSize, multiplier and other properties of Instrument class.

namespace QX.FinLib.Instrument

InstrumentBase is a base class of all instrument types and is abstract class.

Instrument

User can create specific Instrument type object depending on needs and register it with InstrumentManager singleton object.

These instrument types holds some additional properties relevant to them i.e OptionsInstrument has addition properties like StrikePrice, OptionsType(CE, PE, CA, PA)

Following are some important instrument properties and must be assigned while define Instrument object:

Properties Data Type Descriptions
InstrumentID ulong It is unique identifier across all instrument in system and it is automatically assigned based on two subkeys ExchangeSegment and Exchange InstrumentID
i.e ExchangeSegment is NSECM(1) and exchange token id is 17903.
The system assign InstrumentID a value 100000017903.
ExchangeSegment Enumerated value NSECM = 1
NSEFO = 2
NSECD = 3
etc
ExchangeInstrumentID uint The unique identifier provided by exchange for instrument
InstrumentType Enumerated value Futures =1
Options = 2
Spread = 4
Equity = 8
etc
Symbol string Example: Reliance, SBIN, ACC, APPL, EUR/USD
InstrumentName string For Equity segment it is usually same as Symbol name and for FO segment the name is in format
BANKBARODA 25MAR21 FUT
BANKNIFTY 18FEB21 PE 27700
InstrumentDescription string User can provide any descriptive name
i.e. BANKBARODA21MARFUT
IGL21FEB760PE
RELIANCE INDUSTRIES LTD
LowLimit double In some cases, exchanges provides a Low limit price below which order cannot be submitted.
HighLimit double In some cases, exchanges provides a High limit price above which order cannot be submitted.
QtyMultiplier int The quantity multiplier is used to get a traded value. In most cases it is 1 but some contracts are quoted at low denomination but traded value is higher, i.e MCX gold quoted price is 10 gram but traded unit is 1 kg. In this case the multiplier is 100.
LotSize This is minimum shares or contract buy in one transaction.
i.e. Nifty has lot size of 75. You can buy or sell in multiple of 75
MinTickSize Every exchange defines a minimum price movement of a tradable contract. In case of NSECM and NSEFO all major contracts have a minimum price movement also called tick size value as 0.05.
For emini S&P 500 the tick size is 0.25
BigPointValue In some case quotes value is different than monetary value of a contract. In most cases the BPP is 1. For For emini S&P 500 the BPP is $12.50 per tick movement. This value is used to derive a contract value in monetary terms.
PriceFormat Enumerated value How price can be formatted and represented. Default value is DECIMAL
.i.e.
DECIMAL
THIRTYSECONDS
HALFTHIRTYSECONDS
QUARTERTHIRTYSECONDS
etc.
US treasury bond and futures are not traded in decimal price format but in fractional of par value
ISIN (EquityInstrument) string ISIN (International Securities Identification Number) is a unique identification number for a security across universe
i.e. for RELIANCE the ISIN is INE002A01018
ContractExpiration (FuturesInstrument, OptionsInstrument) Datetime The date on which contract expire. It is mainly a derivative property.
UnderlyingType (FuturesInstrument, OptionsInstrument) Enumerated Value Assign a underline type. Default is General
General = 0
Commodity = 1
Currency = 2
Equity = 3
Index = 4
OptionType (OptionsInstrument) Enumerated Value Valid for options contract
CA = 1 (Call American)
PA = 2 (Put American)
CE = 1 (Call European)
PE = 1 (Put European)
Strike Price (OptionsInstrument) double Valid for options contract
A strike price is the set price at which a derivative contract can be bought or sold when it is exercised.

Instrument Manager

This is singleton class and every instrument instance must be subscribe with Instrument manager. It is a container class for all subscribed instruments and provides access and filter criteria to identify individual or set of instruments meeting specific group creteria.

Every instrument instance must subscribe to InstrumrntManager as follows:

InstrumentManager.Instance.SubscribeInstrument(equityInstrument);

How to create instrument class and subscribe it with instrument manager?

Here we are taking an example of NSE exchange which provides to brokers an instrument definition files for each segments. Following is example to decode relevant information from exchange provided contract master files and create a Instrument class and register it with InstrumentManager.

For equity segment NSE provides security.txt file holding contract master definition and following is code snippet on how to parse the file and identify important attributes to create EquityInstrument object instances and subscribe it with Instrument Manager.

InstrumentManager.Instance.SubscribeInstrument(equityInstrument);

string securityFileName = "security.txt";

if (!File.Exists(securityFileName))
    throw new Exception(securityFileName + " file does not exists.");

List<string> fileLines = new List<string>(File.ReadAllLines(securityFileName));
if (fileLines.Count <= 1)
    throw new Exception(securityFileName + " file has no record.");

fileLines.RemoveAt(0);

foreach (string fileLine in fileLines)
{
    string[] splittedString = fileLine.Split(Constant.PIPESEPERATOR);
    if (splittedString.Count() < 54)
    continue;

    uint exchangeInstrumentID = Convert.ToUInt32(splittedString[0]);

    char deleteFlag = Convert.ToChar(splittedString[51]);
    if (deleteFlag == 'Y')
        {
           continue;
        }

    string symbol = splittedString[1];
    string series = splittedString[2];
    // EQ
    if (series != "EQ")
       continue;

    ulong instrumentID = ExchangeCommon.GenerateUniqueTokenID(ExchangeSegment.NSECM, exchangeInstrumentID);

    string highLowRange = splittedString[6];
    string[] highLowPriceTokens = highLowRange.Split(new char[] { '-' });

    int lowerPriceLimit = (int)(Convert.ToDouble(highLowPriceTokens[0]) * 100);
    int higherPriceLimit = (int)(Convert.ToDouble(highLowPriceTokens[1]) * 100);

    // The BoardLot qty is 1 for NSECM instruments
    int boardLotQty = Convert.ToInt32(splittedString[19]);

    // The TickSize is read as 5(Paisa) and interpreted as .05(INR)
    int tickSize = Convert.ToInt32(splittedString[20]);

    // The Tick Per point is evaluated as 20 if tickSize is .05
    int tpp = (int)(1.0 / tickSize);
    string instrumenDescription = splittedString[21];
    string isin = splittedString[53];

    EquityInstrument equityInstrument = new EquityInstrument(ExchangeSegment.NSECM, exchangeInstrumentID, symbol, symbol, instrumenDescription, boardLotQty, tpp);

    equityInstrument.ISIN = isin;
    equityInstrument.LowLimit = lowerPriceLimit * .01;
    equityInstrument.HighLimit = higherPriceLimit * .01;

    InstrumentManager.Instance.SubscribeInstrument(equityInstrument);

}

For Futures and Options segment NSE provides contract.txt file holding contract master definition and following is code snippet on how to parse the file and identify important attributes to create FuturesInstrument and optionsInstrument object instances and subscribe it with Instrument Manager.

string contractFileName = "contract.txt";

if (!File.Exists(contractFileName))
    throw new Exception(contractFileName + " file does not exists.");

List<string> fileLines = new List<string>(File.ReadAllLines(contractFileName));
if(fileLines.Count <= 1)
    throw new Exception(contractFileName + " file has no record.");

fileLines.RemoveAt(0);

foreach (string fileLine in fileLines)
{
    string[] splittedString = fileLine.Split(Constant.PIPESEPERATOR);
    if (splittedString.Count() < COLUMNCOUNT)
    continue;

    uint exchangeInstrumentID = Convert.ToUInt32(splittedString[TOKEN_INDEX]);
    uint assetToken = Convert.ToUInt32(splittedString[ASSETTOKEN_INDEX]);
    string instrumenType = splittedString[INSTRUMENTTYPE_INDEX];  //  OPTIDX, FUTIDX, FUTSTK

    string symbol = splittedString[SYMBOL_INDEX]; // BANKNIFTY
    string series = splittedString[SERIES_INDEX]; // XX

    string optionType = splittedString[OPTIONTYPE_INDEX];

    DateTime contractExpiration = ExchangeCommon.GetDateTimeFromBaseDateElapsedSeconds( ExchangeSegment.NSEFO, (long)Convert.ToInt32(splittedString[EXPIRYDATE_INDEX]));

    double strikePrice = Convert.ToInt32(splittedString[STRIKEPRICE_INDEX]) / ExchangeCommon.GetPriceDivisor(ExchangeSegment.NSEFO);
    bool isFutures = true;
    if (optionType == "XX" && strikePrice > 0)
      continue;
    if (instrumenType.StartsWith("OPT") && strikePrice <= 0)
      continue;              
    OptionType optionTypeEnum = OptionType.NONE;
    if (optionType == "CE")
        {
            optionTypeEnum = OptionType.CE;
            isFutures = false;
        }
    else if (optionType == "PE")
        {
            optionTypeEnum = OptionType.PE;
            isFutures = false;
        }
    else if (optionType == "XX")
            isFutures = true;
         else
            continue;

    string category = splittedString[CATEGORY_INDEX];
    short caLevel = Convert.ToInt16(splittedString[CALEVEL_INDEX]);

    ulong instrumentID = ExchangeCommon.GenerateUniqueTokenID(ExchangeSegment.NSEFO, exchangeInstrumentID);

    short permittedToTrade = Convert.ToInt16(splittedString[PERMITTEDTOTRADE_INDEX]);
    short issueRate = Convert.ToInt16(splittedString[ISSUERATE_INDEX]);

    int minimumLotQuantity = Convert.ToInt32(splittedString[MINIMUMLOTQUANTITY_INDEX]);
    int boardLotQty = Convert.ToInt32(splittedString[BOARDLOTQUANTITY_INDEX]);
    double tickSize = (double)Convert.ToInt32(splittedString[TICKSIZE_INDEX]) / ExchangeCommon.GetPriceDivisor(ExchangeSegment.NSEFO);
        if (tickSize <= 0)
            {
               continue;
            }

        // The Tick Per point is evaluated as 20 if tickSize is .05
        int tpp = (int)(1.0/tickSize);
        int lowPriceRange = Convert.ToInt32(splittedString[LOWPRICERANGE_INDEX]);
        int highPriceRange = Convert.ToInt32(splittedString[HIGHPRICERANGE_INDEX]);
        string instrumentDisplayName = splittedString[NAME_INDEX];

        if (isFutures)
            {
                string instrumentName = InstrumentBase.GetInstrumnetName(symbol, contractExpiration);
                FuturesInstrument futuresInstrument = new FuturesInstrument(ExchangeSegment.NSEFO,
                exchangeInstrumentID,
                symbol,
                instrumentName,
                instrumentDisplayName,
                contractExpiration,
                boardLotQty,
                tpp);

        futuresInstrument.LowLimit = lowPriceRange * .01;
        futuresInstrument.HighLimit = highPriceRange * .01;

        instrumentDict[instrumentID] = futuresInstrument;

        InstrumentBase underlineInstrument = InstrumentManager.Instance.GetInstrument(ExchangeSegment.NSECM, assetToken);
            if (underlineInstrument != null)
              futuresInstrument.UnderlyingInstrument = underlineInstrument;
              futuresInstrument.ExtendedPropertyList["UnderlyingExchangeInstrumentID"] = assetToken.ToString();                    InstrumentManager.Instance.SubscribeInstrument(futuresInstrument);
                }
            else
                {
                    string instrumentName = InstrumentBase.GetInstrumnetName(symbol, contractExpiration, optionTypeEnum, strikePrice);

            OptionsInstrument optionInstrument = new OptionsInstrument(ExchangeSegment.NSEFO,
            exchangeInstrumentID,
            symbol,
            instrumentName,
            instrumentDisplayName,
            contractExpiration,
            optionTypeEnum,
            strikePrice,
            boardLotQty,
            tpp);

            optionInstrument.LowLimit = lowPriceRange * .01;
            optionInstrument.HighLimit = highPriceRange * .01;

            instrumentDict[instrumentID] = optionInstrument;

            InstrumentBase underlineInstrument = InstrumentManager.Instance.GetInstrument(ExchangeSegment.NSECM, assetToken);
            if (underlineInstrument != null)
                optionInstrument.UnderlyingInstrument = underlineInstrument;
                optionInstrument.ExtendedPropertyList["UnderlyingExchangeInstrumentID"] = assetToken.ToString();
                InstrumentManager.Instance.SubscribeInstrument(futuresInstrument);
     }
}

How to add custom properties in instrument object?

Instrument object provides an extended property container to add your custom properties that can be retrieved as when needed

FuturesInstrument futuresInstrument = InstrumentManager.Instance.Getinstrument(Exchangesegment.NSECM, 10222);

futuresInstrument.ExtendedPropertyList["UnderlyingExchangeInstrumentID"] =  "23332";
futuresInstrument.ExtendedPropertyList["AssetClass"] =  "Comodities";

string assetClass = futuresInstrument.ExtendedPropertyList["AssetClass"]

Accessing Instrument or set of Instruments from Instrument Manager

InstrumentManager is singleton container of all subscribed instruments and allow a single point access of Instrument instance

// Accessing instrument using Exchange Segment and Exchange Instrument ID
FuturesInstrument futuresinstrument1 = (FuturesInstrument)InstrumentManager.Instance.GetInstrument(ExchangeSegment.NSEFO, 48548);

// Accessing instrument using Exchange Segment and Instrument Name
FuturesInstrument futuresinstrument2 = (FuturesInstrument)InstrumentManager.Instance.GetInstrument(ExchangeSegment.NSEFO, "BANKNIFTY 25MAR21 FUT");

// Accessing instrument using InstrumentID
FuturesInstrument futuresinstrument3 = (FuturesInstrument)InstrumentManager.Instance.GetInstrument(200000048548);

// Accessing all call and put options list of BankNifty with specific expiry month

string symbolName = "BANKNIFTY";
DateTime contractExpiry = new DateTime(2021, 03, 25);
List<OptionsInstrument> callOptionsList = InstrumentManager.Instance.GetAllCallOptionsInstrumentForSymbolAndExpiry(symbolName, contractExpiry);
List<OptionsInstrument> putOptionsList = InstrumentManager.Instance.GetAllPutOptionsInstrumentForSymbolAndExpiry(symbolName, contractExpiry);

// Accessing all call and put options list of BankNifty

List<OptionsInstrument> bankNiftyOptionsList = InstrumentManager.Instance.GetAllOptionsInstrumenttForSymbol(symbolName);

// Apply linq query to filter call options with given expiry month
List<OptionsInstrument> callOptionsListX = bankNiftyOptionsList.Where(iterator => iterator.Symbol.ToUpper() == symbolName.ToUpper() &&
(iterator.OptionType == OptionType.CE || iterator.OptionType == OptionType.CA) && 
iterator.StrikePrice > 0 &&
iterator.ContractExpiration.Date == contractExpiry.Date). OrderBy(iterator => iterator.ContractExpiration).ThenBy(iterator => iterator.StrikePrice).ToList();

Instrument object is serializable and deserializable using a Protobuf?

All instrument types object are seriazable to byte array and subsequently deserialize byte array to object using a protobuf serialization deserialization mechanism. This is helpful in case you want to preserve the state of Instrument in some binary file or database.

Using ProtoBuf;
using Newtonsoft.Json;
using QX.FinLib.Common;
using QX.FinLib.Instrument;

FuturesInstrument futuresinstrument = (FuturesInstrument)InstrumentManager.Instance.GetInstrument(ExchangeSegment.NSEFO, 48548);

// Serialize to byte stream
byte[] bData = ProtoSerialize<FuturesInstrument>(futuresinstrument);

// Deserialzie from byte stream to object
FuturesInstrument futuresinstrumentX = ProtoDeserialize<FuturesInstrument>(bData);

public byte[] ProtoSerialize<T>(T record) where T : class
{
    if (null == record) return null;
        try
        {
            using (var stream = new MemoryStream())
            {
                Serializer.Serialize(stream, record);
                return stream.ToArray();
            }
        }
        catch (Exception exp)
            {
                // Log error
                throw exp;
            }
}

public T ProtoDeserialize<T>(byte[] data) where T : class
{
    if (null == data) return null;
        try
        {
            using (var stream = new MemoryStream(data))
            {
                return Serializer.Deserialize<T>(stream);
            }
        }
        catch (Exception exp)
        {
            // Log error
            throw exp;
        }
}