Sie sind auf Seite 1von 21

Takion API and Developer

Documentation
Current Version: 1.1.138

Scope
The scope of this document is to provide developers for the Takion API an overview
and some modest level of detail in order to write fully functional Takion extensions.
We will discuss the details of placing orders and receiving order notifications,
subscribing to stocks and receiving data from those stocks, as well as buying power,
risk constraints, and other account-based API capabilities.

Lastly we will discuss the Takion GUI and show a demonstration of several popular
GUI features.

Introduction
The Takion API is entirely based on the Observer pattern. A full treatment of the
Observer pattern can be found on the following pages:
 http://en.wikipedia.org/wiki/Observer_pattern
 http://www.oodesign.com/observer-pattern.html

You will be working extensively with this design pattern, and should understand the
details of it before proceeding. This document assumes a good knowledge of C++
and the Observer design pattern.

An example is a useful learning experience. Let’s say we want to monitor all NYSE
symbols and be notified when any trade events occur for any of those stocks.
Further, if any trade event occurs where the total order size is greater than 10,000
shares, we would like to place an order. For the purposes of our initial example use
case, we will create this functionality for a single symbol, and later in the
documentation we will discuss how to subscribe our single observer to all NYSE
symbols.

The following diagram depicts the software components that are used in this
example.
Observer
Observable
observes
MyNyseObserver Security (“XOM”)

Message

Fig 1. In the above diagram, objects in Blue are part of the Takion API, while objects in Red are
components that we will write. The Observer (MyNyseObserver) tells the Observable
(Security) that it wants to be notified of any messages that it sends. Subsequently, the Security
will invoke the Notify method on the Observer for every message that is generated.

The components that we will write to solve this example problem are quite simple.
First, we will create a observer, which will be notified when any message is
generated by Takion (in our case, the Trade messages). Second, we will subscribe
this Observer to the Observable (the Security object that represents the “XOM”
symbol, which is provided by Takion). And lastly, we will process some messages
that we receive from this Security.

Implementation Detail: Any message that is generated by the Observable


object is passed to the Observer object via the Notify method. The Notify
method takes parameters that are typed according to the highest class in the class
hierarchies possible to keep the method signature as general as possible. Therefore,
we must perform a switch on a field of the message object in order to perform the
appropriate casting operation for the message. Your Notify method must allow
for the possibility that unrecognized message types may be passed into it and ignore
such messages.

Hello World for Takion


We will walk through the simplest possible example for building a Takion extension
DLL – a “Hello World” for Takion. As indicated in the Introduction, our example use
case is simple:
1. Subscribe to the “XOM” Stock
2. Receive notifications of any Trade events that occur
3. Generate an order in response to any trade that occurs, whose share size is
larger than 10,000 shares
4. Receive notification of any status updates for this order (including when the
order is acknowledged and received by the market, and when the order has
been traded).
5. Cancel all open orders for a given Stock
We will start by creating the MyNyseObserver component. Since Takion is a C++
application, the following code is written in C++ (using Visual Studio 2010). To
jumpstart this process, you may use the project settings that can be found with the
accompanying sample code.

Step 1: Creating the Observer and Subscribing to “XOM”

We begin by creating the header file for our observer.

MyNyseObserver.h

#include “ObserverApi.h”
#include “TakionDataApi.h”

class MyNyseObserver : public Observer


{

public:
MyNyseObserver(const std::string& symbol);

virtual ~MyNyseObserver();

// this is inherited from Observer


void Notify(const Message* msg,
const Observable* from,
const Message* info);

private:
Security* takSecurity;

};

Later, we will add the necessary methods to process a Trade message and respond
by placing an order.
Next, we will create the MyNyseObserver cpp file.

MyNyseObserver.cpp

// required because Takion is an VC++ application


#include “stdafx.h”

#include “TakionLogApi.h”
#include “TakionUtilsApi.h”
#include “MyNyseObserver.h”

MyNyseObserver::MyNyseObserver(const std::string& symbol)


: takSecurity(NULL)
{
takSecurity = TD_ObtainStock(symbol.c_str(), true);
if (takSecurity != NULL)
{
takSecurity->AddInThreadObserver(this);
}

MyNyseObserver::~MyNyseObserver()
{
if (takSecurity != NULL)
{
takSecurity->RemoveInThreadObserver(this);
TD_ReleaseStock(takSecurity);
}
}

void MyNyseObserver::Notify(const Message* msg,


const Observable* from, const Message* info)
{
// to be added in the next step
}

Step 2: Processing Trade Messages


At this point we have a working Observer that is subscribed to the “XOM” stock, but
we are not yet responding to any trade messages. In this step we will add the
necessary code to perform this feature.

We will add the following code to our MyNyseObserver header file. We begin by
adding a new method to the MyNyseObserver class. This method is also called
Notify, but its parameter list accepts a message of a more specific type :
TMsgTrade.

We also add a third method to our observer, PlaceSomeOrder, which responds to


qualifying trade events. Note that this type of method redirection is not necessary
for actual implementations. You may choose to collapse these methods directly into
the stock Notify. The below structure is designed to provide the user with a clean
image of how the responsibilities are delineated.

class MyNyseObserver : public Observer


{

// previously added code here


// excluded for brevity

private:
// we re-direct the above Notify to this
// method when we receive a message of this type
void Notify(const TMsgTrade* msg,
const Observable* from,
const Message* info);

// invoked when we get a trade message that


// meets our criteria
void LogTradeMsg(const TMsgTrade* msg);

};

Next, we will add the following implementation code to our MyNyseObserver cpp
file.

First, we will provide a detailed implementation inside of our Notify method. This
implementation will perform a switch-case operation on the Message::m_type
property to determine the message type. If the message is of a type that is relevant
to our feature set, we will process this message by dispatching it to a method to
handle that specific message type.
In our case, we are concerned with the M_TRADE_REPORT message enumerated
type, which corresponds to the TMsgTrade Message subclass type. A list of the most
commonly used enumerated types and corresponding subclassed Message types can
be found later in the documentation.

Secondly, we will add some implementation to our specialized Notify method to log
a friendly message if the trade execution was within our parameters.

void MyNyseObserver::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;
}

// we must gracefully ignore any messages that


// are irrelevant to our feature set
default : { }
}

void MyNyseObserver::Notify(const TMsgTrade* msg,


const Observable* from, const Message* info)
{

if (msg->m_size > 10000)


{
LogTradeMsg(msg);
}

void MyNyseObserver:: LogTradeMsg(const TMsgTrade* msg)


{
std::ostringstream logMsg;
logMsg << “received qualifying trade ”;
logMsg << takSecurity->GetName();
logMsg << “ “;
logMsg << msg->m_size();
logMsg << “ “;
logMsg << msg->m_priceDollars;
logMsg << “.“;
logMsg << msg->m_priceFraction;
TL_LOG(TL_GetLogFile(), logMsg.str().c_str(), “”);
}

Step 3: Placing an Order in Response to the Trade Message

In the previous step, we simply logged a friendly message when a trade met our
criteria. In this step, we place an order when we receive a trade that meets our
criteria.

We begin by adding the following method to our MyNyseObserver header file.


Note that we have also added the Account member variable, which stores a pointer
to the current account. In the next section, we will assign a value to this variable
using traditional Takion API calls.

class MyNyseObserver : public Observer


{

// previously added code here


// excluded for brevity

void PlaceSomeOrder(const TMsgTrade* msg);

private:
Account* currentAccount;

};

Next, we add the following implementation to our MyNyseObserver cpp file.

Note that it is likely that you will send a wide variety of orders and order types.
However, the majority of these will have almost identical method parameters with
slight variations. We recommend creating a few wrapper methods, for example, one
could write the following methods that take only the parameters that differ from the
defaults:

1. SendArcaLimit
2. SendNsdqLimit
3. SendNyseMarketOpen
4. SendNyseMarketClose
5. SendArcaStop
6. SendNsdqStop

void MyNyseObserver::PlaceSomeOrder(const TMsgTrade* msg)


{
unsigned int orderClientId = 0;
Order* nullOrder = NULL;
int replaceSizeOffset = 0;
int theDestination = ARCA_ROUTE;
char orderSide = ‘B’;
int orderType = ORDER_LIMIT_TYPE;
int clientOrderType = 0;
int clientOrderData = 0;
Price orderPrice(1, 0); // $1.00
Price discretionaryPrice(0, 0); // $0.00
Price stopPrice(0, 0); // $0.00
int stopOrderType = OST_NONE;
int stopOrderBase = OSB_MIDPOINT;
Price level1Bid(takSecurity->GetL1Bid());
Price level1Ask(takSecurity->GetL1Ask());
int displayQty = 100;

int orderTif = TIF_DAY;

int reservedQty = 0;
int routingId = RI_PROACTIVE;
int routeSubType = 0;

const DestinationRouting* routeStrategy =


theDestination->FindRouting(routingId);

int routeName = 0;
if (routeStrategy != NULL)
{
routeName = routeStrategy->GetNumericName();
}

bool isIso = false;


int pegType = PEG_NONE;
Price pegPrice(0, 0); // $0.00

bool cancelWash = true;


int resizePolicy = OOP_RESIZE;
bool resizeToBorrowed = true;
bool preBorrow = false;
Price borrowPrice(0, 0); // $0.00
bool noRedirect = false;
bool closeOnly = false;
bool resizeToClose = false;
bool proAts = false;
bool blockAggressive = true;
unsigned char roundLotPolicy = 0;
std::string* isoAttachment = NULL;
int userId = 0;
int parentId = 0;
int mnemonic = 0;

currentAcct->SendOrder(&orderClientId,
nullOrder,
replaceSizeOffset,
takSecurity,
theDestination,
orderSide,
orderType,
clientOrderType,
clientOrderData,
orderPrice,
discretionaryPrice,
stopPrice,
stopOrderType,
stopOrderBase,
level1Bid,
level1Ask,
displayQty,
reserveQty,
routingId, routeSubType, routingName,
mnemonic, iso, pegType, pegOffset,
orderTif, orderTifMillis,
cancelWashOrders,
orderResizePolicy,
resizeShortBorrow,
preBorrowShares,
preBorrowPrice,
orderNoRedirect,
closeOnly,
resizeToClose,
proAts,
blockAggressive,
roundLotPolicy);
if (orderClientId != 0)
{
// order was successfully placed
}
else
{
// order was not successfully placed
}
}

Step 4: Receive Order Status Notifications

To receive notification of order status messages, we must observe some


Observable that publishes notifications about the Order to us. There are three
components that (all) do this: the Account, the Position, and the Order itself.
They differ in the scope of orders for which your observer will receive notifications.
For example, the Account receives notifications for any Order placed by that
Account, whereas the Position only receives notifications for Orders placed
corresponding to that position (or symbol). Unsurprisingly, the Order receives only
notifications for events that occur to the single Order.

For the sake of simplicity in our Hello World extension, we will observe the
Account. For a more detailed description of observing order messages from the
other objects, see the Accounts and Positions section below.

In the previous section, we added a member variable to our MyNyseObserver


class to store the Account object pointer. We will now assign this member
variable to the account (which we find using the name “TEST”). If you have not
setup this account, change this account name to the name of your simulation
account. We will add the MyNyseObserver object as an observer of the Account,
and update the destructor to remove the observer from the Account.

MyNyseObserver::MyNyseObserver(const std::string& symbol)


: takSecurity(NULL), currentAcct(NULL)
{
currentAcct = TD_FindAccount(“TEST”);
if (currentAcct != NULL)
{
currentAcct->AddInThreadObserver(this);
}

takSecurity = TD_ObtainStock(symbol.c_str(), true);


if (takSecurity != NULL)
{
takSecurity->AddInThreadObserver(this);
}
}

MyNyseObserver::~MyNyseObserver()
{
if (takSecurity != NULL)
{
takSecurity->RemoveInThreadObserver(this);
TD_ReleaseStock(takSecurity);
}

if (currentAcct != NULL)
{
currentAcct->RemoveInThreadObserver(this);
}
}

We now must modify our Notify method to acknowledge Order events. Note
that I have excluded the previous cases here for the sake of brevity.

void MyNyseObserver::Notify(const Message* msg,


const Observable* from, const Message* info)
{
switch (msg->m_type)
{
case TS_ORDER :
{
Notify((const TMsgReqOrder*)msg, from, info);
break;
}
case TS_ORDER_ACK :
{
Notify((const TMsgOrderAck*)msg, from, info);
break;
}
case TS_ORDER_UPDATE :
{
Notify((const TMsgOrderUpdate*)msg, from, info);
break;
}
case TS_ORDER_ERROR :
{
Notify((const TMsgOrderError*)msg, from, info);
break;
}
case TS_ORDER_DELETE :
{
Notify((const TMsgOrderDelete*)msg, from, info);
break;
}
case TS_EXECUTION_NEW :
{
Notify((const TMsgExecutionNew*)msg, from, info);
break;
}
case TS_NEW_EXECUTION :
{
Notify((const TMsgNewExecution*)msg, from, info);
break;
}
case TS_ORDER_REPORT :
{
Notify((const TMsgOrderReport*)msg, from, info);
break;
}
case TS_ORDER_KILL :
{
Notify((const TMsgOrderKill*)msg, from, info);
break;
}

// we must gracefully ignore any messages that


// are irrelevant to our feature set
default : { }
}

void MyNyseObserver::Notify(const TMsgReqOrder * msg,


const Observable* from, const Message* info)
{
// invoked when the client requests a new order
// via the Account::SendOrder method
}
void MyNyseObserver::Notify(const TMsgOrderAck * msg,
const Observable* from, const Message* info)
{
// invoked when the client receives a response from
// the order executor.
// Note: This is not a market acknowledgement.
}

void MyNyseObserver::Notify(const TMsgOrderNew * msg,


const Observable* from, const Message* info)
{
// invoked when the market has acknowledged the order
}

void MyNyseObserver::Notify(const TMsgOrderUpdate* msg,


const Observable* from, const Message* info)
{
// Eugene??
}

void MyNyseObserver::Notify(const TMsgOrderError* msg,


const Observable* from, const Message* info)
{
// Invoked when some error has occurred in sending
// the order (i.e., the order is invalid)
}

void MyNyseObserver::Notify(const TMsgOrderDelete* msg,


const Observable* from, const Message* info)
{
// Invoked when the order is going away forever
}

void MyNyseObserver::Notify(const TMsgOrderKill* msg,


const Observable* from, const Message* info)
{
// Eugene??
}

void MyNyseObserver::Notify(const TMsgOrderReport* msg,


const Observable* from, const Message* info)
{
// Invoked when the order has been filled
// message contains members that indicate number of
// shares filled, cancelled, and remaining, among
// other things
}

Step 5: Canceling all Open Orders

In order to cancel all open orders, we will obtain an OrderMap from the Position,
through which we can iterate and issue cancels.

We will add the following method declarations to our MyNyseObserver header.

class MyNyseObserver : public Observer


{

// previously added code here


// excluded for brevity

void CancelAllOrders(Position* position);


};

And we will add the following method definition to our MyNyseObserver source
file. Note that the Notify method is the same one that we have previously added,
and we are inserting the method invocation for Canceling all orders and Placing the
new order.

void MyNyseObserver::CancelAllOrders(Position* position)


{

if (position != NULL)
{
const OrderMap& allOrders = pos->GetAllOrders();

POSITION iter = allOrders.GetStartPosition();


while (iter != NULL)
{
unsigned int orderId = 0;
Order* theOrder = NULL;
allOrders.GetNextAssoc(pos, orderId, theOrder);

theOrder->Cancel();
}
}
}

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);
}

WARNING: Because we have subscribed our observers via the


AddInThreadObserver methods, the Trade Messages arrive from a different
thread than the Order Update messages. Because of the multi-threaded nature of
Takion, we must occasionally lock objects. Some cases where this is necessary are:

1. When we want to access Security data during an Order or Position message


update event (we must lock the Security object)
2. When we want to obtain Account, Position, or Order information during the
processing of a Security message (we must lock the appropriate Account,
Position, or Order object).

Stocks and Data


A table of useful message type enum values, as well as their corresponding class
type is listed below.

Enumeration Value Message Type Description


Used to notify the
M_TRADE_REPORT TMsgTrade observers of trade
messages.
Used to notify the
M_STOCK_IMBALANCE_INDICATOR TMsgImbalance observers of imbalance
messages.

Putting it Together (DLL Entry Points)


Now that we have a few basic components written, we need to create an operational
DLL – something that can be loaded by Takion and successfully executed. Takion is
an MFC based application, and as such there are standard DLL entry points that we
must implement in order to let Takion know how to load our extension.

The following components are required by the Takion DLL system in order to
function properly:

1. TakionMain (header and source)


2. TakionApp (header and source)
3. TakionProject.def
4. TakionProject.rc
5. Resource.h
6. stdafx.h and stdafx.cpp
7. targetver.h

These components are detailed below.

TakionMain

The TakionMain source and header files are the primary entry points from the
Takion application into the Takion extension DLL.

The following table lists the required DLL entry point methods and a description for
each. A sample of them can be found below.

Entry Method Description


Required. Must be overridden to create
ExtensionInitialize any objects that the extension wishes
to create.
Required. The extension should clean
ExtensionTerminate up any resources that were allocated
during Initialize.
Required, but does not require an
implementation (a no-op is sufficient).

KeyStrokeAndCommand Takion invokes this method when the


user performs a key-stroke combination
that corresponds to a Takion mapped
command.
Required, but does not require an
implementation (a no-op is sufficient).

Takion invokes this method when the


SymbolEnteredInMMBox
user has successfully entered a valid
symbol into the Market Maker. For
example, when the user types “XOM”,
this method is invoked.
Required, but does not require an
implementation (a no-op is sufficient).

Takion invokes this command when the


SecurityRefreshed
security has been refreshed (i.e., if
the data was not previously being
subscribed to, and now is being
subscribed to).
Required, but does not require an
implementation (a no-op is sufficient).
ActiveMMBoxChanged
Think: when the user tabs between
market maker boxes. This indicates
which market maker is currently active.
Required, but does not require an
implementation (a no-op is sufficient).

TakionMoveWindows Gives the DLL an opportunity to move


any windows that it has created at the
same time as the primary Takion window
is being moved.
Required, but does not require an
implementation (a no-op is sufficient).
ExecuteTakionCommand
The command corresponds to the command
that was created in the
GetTakionExtensionMenu method.
Required, but does not require an
GetTakionExtensionMenu
implementation (a no-op is sufficient).
Allows the user to create custom menu
items for the Takion menu (right-
click).

A sample of the above TakionMain methods is listed below. They are exceedingly
simple in that we simply redirect them to the TakionApp to perform any necessary
work.

void WINAPI ExtensionInitialize() {


theApp.ExtensionInitialize();
}

void WINAPI ExtensionTerminate() {


theApp.ExtensionTerminate();
}

void WINAPI KeyStrokeAndCommand(unsigned char ascii,


unsigned char modifier, const char* commandName) {
theApp.KeyStrokeAndCommand(ascii, modifier,
commandName);
}

void WINAPI SymbolEnteredInMmBox(const char* symbol, bool


valid, bool fromKeyboard, unsigned int ordinal) {
theApp.SymbolEnteredInMmBox(symbol, valid,
fromKeyboard, ordinal);
}

void WINAPI SecurityRefreshed(const char* symbol, const


Security* security, bool wasLoaded, unsigned int ordinal)
{
theApp.SecurityRefreshed(symbol, security,
wasLoaded, ordinal);
}

void WINAPI ActiveMmBoxChanged(const char* symbol, const


Security* security, bool wasLoaded, unsigned int ordinal)
{
theApp.ActiveMmBoxChanged(symbol, security,
wasLoaded, ordinal);
}

void WINAPI TakionMoveWindows(int dx, int dy) {


theApp.TakionMoveWindows(dx, dy);
}

TakionApp

Because Takion is an MFC application, we must provide a default implementation of


a CWinApp derived object. The implementation is not verbose or detailed, but is
required. Note, these files are included in the accompanying source set, and contain
additional required syntax (as required by C++ and MFC, but excluded here for
brevity).

Note that for our purposes, we recommend redirecting the TakionMain entry
methods (described below) to the TakionApp object. As such, these methods and
their accompanying parameters must be added to the TakionApp. While this seems
like a bit of a complication at first, it pays dividends in the future.

class TakionApp : public CWinApp


{
public:
TakionApp();
Virtual BOOL InitInstance();
Virtual int ExitInstance();
const std::string& GetFilePathAndName() const
{return m_filePathAndName;}
const std::string& GetFileDescription() const
{return m_fileDescription;}
const std::string& GetPlatform() const
{return m_platform;}
const std::string& GetVersionStr() const
{return m_versionStr;}
const unsigned __int64& GetVersionNum() const
{return m_versionNum;}

// these methods are invoked from DLL entry points


void ExtensionInitialize() { }
void ExtensionTerminate() { }
void KeyStrokeAndCommand(unsigned char ascii,
unsigned char modifier,
const char* commandName) { }

void SymbolEnteredInMmBox(const char* symbol,


bool valid, bool fromKeyboard,
unsigned int ordinal) { }

void SecurityRefreshed(const char* symbol,


const Security* security, bool wasLoaded,
unsigned int ordinal) { }

void ActiveMmBoxChanged(const char* symbol,


const Security* security, bool wasLoaded,
unsigned int ordinal) { }

void TakionMoveWindows(int dx, int dy) { }

protected:
DECLARE_MESSAGE_MAP()
std::string m_filePathAndName;
std::string m_fileDescription;
std::string m_platform;
std::string m_versionStr;
unsigned __int64 m_versionNum;
};

The source file is quite simple as well. Note, the user’s own objects should be owned
by TakionApp. This provides a singular spot where all resources are created and
destroyed and owned. However, one must avoid the temptation to place the
initialization code in the TakionApp::InitInstance method. This method is
provided for compatibility with MFC only.

Instead, the user should provide their own initialization in the


ExtensionInitialize method.

TakionApp theApp;

unsigned int WINAPI GetExtensionCode()


{
return ClientExtensionDll::validExtensionCode;
}

BEGIN_MESSAGE_MAP(TakionApp, CWinApp)
END_MESSAGE_MAP()

TakionApp::TakionApp() {

BOOL TakionApp::InitInstance() {
CWinApp::InitInstance();

U_InitializeInstanceInfo(m_hInstance,
m_filePathAndName, m_fileDescription,
m_platform, m_versionNum, m_versionStr);
return TRUE;
}

int TakionApp::ExitInstance() {
return CWinApp::ExitInstance();
}

Multi-Threading Takion Objects

GUI Concerns

Appendix A : Visual C++ Project Settings

Das könnte Ihnen auch gefallen