Personalized. Customized. Trading
Choose Security
Calculate Lot Size
Determine strategy
Set Max or Min Price
Control and Cover Position
The API is designed to function in the Observer pattern. There are three main parts to this pattern – the observer, the observable item (object) and the communication through messages.
To handle messages, the observer must implement the notify() method which has a signature definition for receiving messages and which observer originated these messages.
void MyObserver::Notify(const Message* msg, const Observable* from, const Message* info)
{
switch (msg->m_type) {
case < Some Message > : {
//Handle the message as desired
break;
}
//Gracefully ignore any irrelevant / unrecognized messages
default : { }
}
}
Thank you for your interest in our company.
We make the Complex Simple to Achieve Better Results
For various reasons, the API is designed to function in the Observer pattern. There are three main parts to this pattern the observer, the observable item (object) and the communication through messages.
The observable object can be a security, such as Apple, Inc. (AAPL), or an account, an order, or a position object. These objects have properties, methods and will communicate through messages generated from market activity, status, or state changes.
The observer is a class in the main API program that provides the ability to receive messages from observable objects (see above). Using the provided pre-built start application and the example algorithm in the ExtensionSample program, an observer object is created then told about a security to ‘follow’. Inside the observer, an observable with the desired symbol (eg. AAPL) is instantiated, then followed by calling the method AddInThreadObserver(
To handle messages, the observer must implement the notify() method which has a signature definition for receiving messages and from which observable it originated. Bear in mind that there are MANY possible message and message types. It is a best practice to add a default clause to the switch statement (see example below) to manage unhandled message types. Below is a stubbed-out general example of what this might look like:
void MyObserver::Notify(const Message* msg, const Observable* from, const Message* info)
{
switch (msg->m_type)
{
case < Some Message > :
{
//Handle the message as desired
break;
}
// Gracefully ignore any irrelevant / unrecognized messages
default : { }
}
}
For the sake of clarity, it is possible to overload the notify() method and dedicate certain notify() methods to specific message types – especially if they are commonly received. See the example below:
void MyObserver::Notify(const Message* msg, const Observable* from, const Message* info){
switch (msg->m_type) {
case M_TRADE_REPORT : {
Notify((const TMsgTrade*)msg, from, info);
break;
}
default : { }
}
}
void MyObserver::Notify(const TMsgTrade* msg, const Observable* from, const Message* info){
//only handle Trade Messages
}
Since most algorithms want to react to market activity, a common practice is to place trading logic in the notify() method (that handles trade messages) in the observer objects. A general example follows:
void MyObserver::Notify(const TMsgTrade* msg, const Observable* from, const Message* info){
bool haveAPosition = false;
//write code to determine if we have a position ...
if(haveAPosition == false) {
//Get prices for comparison:
Price curPrice = Price(msg->m_priceDollars, msg->m_priceFraction);
Price yesHighPrice = takSecurity->GetYesterdaysHighPrice();
Price yesLowPrice = takSecurity->GetYesterdaysLowPrice();
Price todaysHighPrice = takSecurity->GetHighPrice();
Price todaysLowPrice = takSecurity->GetLowPrice();
//< Code to Trade >
}
}
Another best practice in this pattern is to dedicate one observer per security. Thus, when looping through a list of securities to follow, be sure to instantiate one observer per security. Dedicating an observer this way provides the functional clarity and separation.
When specific events or actions occur in the observable object, a message is generated and made available to the observer. The observer must be aware of the potential messages and look for each one individually, as stubbed out above. Unknown messages or, more specifically, messages that are not specifically handled by the observer are discarded. There are several types of messages, each of which contain information specific to its source. For example, the messages from a Position will be different than the messages generated by the market trade of a security. In the above examples, the focus was on trade messages. The example referenced the message object (msg) and used a property to get access to the last execution price. Taken from the example above:
//Get prices for comparison:
Price curPrice = Price(msg->m_priceDollars, msg->m_priceFraction);
In the event a security has a large enough price fluctuation, it may be subject to a circuit breaker restriction. For example if a security’s price drops more than 10 percent from the previous day’s closing price, it will incur a short sale restriction. In order to obtain circuit breaker information, you need to initiate a request through the security object.
Below is an example of how to accomplish this:
Security* security = (initialize code goes here);
char circuitBreaker = security->GetRegSHOTestIndicator();
Character | Source | Indicates |
---|---|---|
Blank | CTS | Short sale restriction not in effect |
A | CTS | Short sale restriction activated |
C | CTS | Short sale restriction continued |
D | CTS | Short sale restriction deactivated |
E | CTS | Listed Stocks only |
0 | UTDF | No Reg SHO Short Sale Price test Restriction |
1 | UTDF | Reg SHO Short Sale Price test Restriction in effect due to a price drop |
2 | UTDF | Reg SHO Short Sale Price test Restriction remains in effect |
Next, by ‘listening for’ certain messages it is possible to determine if there are updated circuit breaker states. However, one still needs to make a function call to get that state value. Below is a list of messages that could indicate a change of Circuit Breaker state:
Message | Type | Where to Listen |
---|---|---|
TM_EQUITY_UPDATE | MarketSorter securities | Main Thread |
TM_STOCK_UPDATE_LEVEL1 | MarketData Securities | Main Thread |
M_MS_SHORT_SALE_INDICATORS | Ms Securities | Stock Thread |
SM_MS_SHORT_SALE_INDICATORS | Ms Securities | Stock Thread |
M_SHORT_SALE_INDICATORS | Md Securities | Stock Thread |
SM_M_SHORT_SALE_INDICATORS | Md Securities | Stock Thread |
1 | UTDF | Reg SHO Short Sale Price test Restriction in effect due to a price drop |
2 | UTDF | Reg SHO Short Sale Price test Restriction remains in effect |
What follows is a code sample (continued from the previous example’s security instantiation code) to call for getting the current Circuit Breaker state once the above message have been received:
security->GetRegSHOTestIndicator();
To obtain borrowing information about a security, the account’s clearing firm needs to be referenced in a call asking for the state of a security’s borrowing details. The value of ‘Hard To Borrow’ (HTB) depends on the Account in which you are trading.
Here’s a small code illustration:
Account* account = (initialize process);
//Note: use TD_GetCurrentAccount() or TD_FindAccount(accountId) or iterating through accounts or //other
unsigned int ordinal = account->GetClearingFirmOrdinal();
unsigned char htb = isHTB(ordinal);
Usually, the function isHTB() returns:
Further, updates to the value should be checked when you get the following messages:
Message | Type | Where to Listen |
---|---|---|
TM_EQUITY_UPDATE | MarketSorter securities | Main Thread |
TM_STOCK_UPDATE_LEVEL1 | MarketData Securities | Main Thread |
When the Takion application starts, it creates a number of "worker" threads. The number of worker threads is equal to the number of CPUs that your computer has. When subscribing to a security either through the Takion application or the API, the security is assigned to a worker thread that processes the security's data. Internally, there is a mechanism that keeps all the worker threads balanced with approximately the same number of securities.
When a message about the security arrives, it is posted to the same worker thread assigned to the security. This means that several securities can be processed simultaneously in different threads.
When changing the security's state, the Takion application locks the security for modification, which is a ‘write’ process that is only performed in the Takion application to maintain a current understanding of the state of a security based on market messages. This modification type of locking and changing a security's state is not available through the API, since it is a consumer of a security’s state and has no reason to modify a security.
When a custom built API DLL wants to perform an inquiry into the security's state for observation, it calls the’ inquiry functions like GetLastPrice(), ResetIterator(), GetNextQuote() . But before doing this it must Lock the security for inquiry to avoid a state change during the inquiry.
Some data is never modified, like stock symbol name. Consequently, this data can be accessed without locking. Also, if you are accessing a single data item, which is no longer than 4 bytes (e.g. "imbalance size"), the API DLL does not need to lock the item because those values are modified "atomically" and it is not possible to access a partially changed values. However, given time constraints when accessing several values and they all need to be based on the last message, the security must be to be locked.
If a lock for inquiry is obtained, it must be unlocked when the data retrieval is complete. Further, it is a good practice not to keep the security locked for an extended period because it holds the worker thread and prevents the ongoing market modification of the security. Ideally, API code should lock for inquiry, quickly collect the necessary info, unlock, and leave the time consuming algorithm calculation and processing for buying or selling security outside the inquiry locks.
Caution! Of special note is the process of accessing security data through iteration, such as like getting several top quotes of the Level2. Not only is this dangerous because of the increased risk of incorrect (out of date) data due to the modification in progress, but there is a risk of crashing the Takion Application too!
Below is an example of using locks (for inquiry) in the API:
void MyNyseObserver::Notify(const TMsgTrade* msg, const Observable* from, const Message* info){
if (msg->m_size > 10000){
LogTradeMsg(msg):
Position* position = currentAcct->FindPosition(takSecurity);
if (position != NULL){
position->LockInquiryWait();
CancelAllOrders(position);
position->Unlock();
}
PlaceSomeOrder(msg);
}
}
The same locking details apply to Account objects. The accounts are assigned a worker thread (in a balanced manner) for processing. The entire account object, with all its Positions, Orders, and Executions belongs to a worker thread.
There may be multiple accounts, sometimes hundreds, loaded into Takion. Thus, it helps to have and use as many CPUs as possible to process them in parallel.
Modification and inquiry locking of Accounts, Executions, Orders, and Positions is syntactically the same as for securities. Although, one difference being that you Lock in a single manner, the Account object for all kinds of modifications and inquiries. In contrast, securities can be locked in a separate manner for Level1 data, Level2 data, trade prints, and Charts. The worker threads, discussed at the start of the threading section, manage these types of objects in the same set of threads as the securities and therefore can have a mix of Security and Account objects in the same thread. As mentioned above, the API code doesn’t have access to the worker threads; instead, these are managed by the Takion application. As a result, API code simply needs to lock and unlock properly.
Method Name | Objects with Method | Description |
---|---|---|
LockInquiryWait() |
|
Often calls LockInquiry(wait) iteratively until it returns ‘true’. |
LockInquiry(Wait) |
|
Boolean response for whether a lock can be obtained [generally used by internal object coding, less so by direct calls in the API] |
Unlock() |
|
Removes the inquiry lock |
Q: Must I use the sample extension application?
A: No. One could download the API from the Takion FTP Site and refer to the above Example Extension API walkthrough for required files, folder structures, etc. to get started.
Q: Once I download the ExtensionSample application and add the necessary files and write my logic, I can just tell the Takion application where it is and so long as it works as expected, I won’t need to download anything else, correct?
A: From time to time, you may benefit from updates to the Takion API base code files. They can just be copied over the existing files in your project, be recompiled and ‘re-associated’ with the Takion application.