How to open position on hedging and non-hedging accounts
Brief
The article describes how to open a position on hedging and non-hedging accounts.
Details
How to Open Position
Positions are opened by orders. So, to open a position, create a request to make an order.
When the order is created, it appears in the Orders
table. It stays in the table until it is executed.
Depending on market liquidity and position maintenance (that is, the way trade operations are performed on an account), there are a few possible results of the order execution. To process the results, it is necessary to monitor table events.
Section 1 of the article discusses how to process the basic case when the result of the order execution is a newly opened position. The section also discusses how to the process the case when the order is rejected.
Sections 2 and 3 discuss other cases that may happen on the Real market when the order is sent on external execution, namely, partial execution.
Section 4 discusses how to process all the possible results of the order execution.
1. Most Usual Case
1.1. Create and Send Order Request
To request an order creation, you should fill an instance of IO2GValueMap
with corresponding parameters.
The set of parameters depends on a particular order type. Please refer to the list of order types for the detailed description on how to fill the value map for each particular order type.
Below is an example of creating and sending a request for an Open Market order.
std::string sBuySell = O2G2::Buy;
std::string sLastRequestID;
IO2GRequestFactory *requestFactory = session->getRequestFactory();
IO2GValueMap *valuemap = requestFactory->createValueMap();
valuemap->setString(Command, O2G2::Commands::CreateOrder);
valuemap->setString(OrderType, O2G2::Orders::OpenLimit);
valuemap->setString(AccountID, sAccountID.c_str());
valuemap->setString(OfferID, sOfferID.c_str());
valuemap->setString(BuySell, sBuySell.c_str());
valuemap->setDouble(Rate, dAskRate);
valuemap->setInt(Amount, iAmount);
IO2GRequest *request = requestFactory->createOrderRequest(valuemap);
valuemap->release();
ResponseListener *responseListener = new ResponseListener(session);
sLastRequestID = request->getRequestID();
responseListener->setRequest(sLastRequestID.c_str());
session->subscribeResponse(responseListener);
session->sendRequest(request);
RequestID
should be saved. It is necessary to monitor the order creation.
1.2. Process Request Response
After sending a request for an order creation to the server, process results of request execution. Possible results are as follows:
Request completed
It means that the order has been validated and accepted.
Actually, the onRequestCompleted
event does not mean that the order has been successfully executed.
So you should monitor the execution of your order to know the results of the execution.
Important: The onRequestCompleted
event should not be used as the confirmation of an order creation.
Instead, you should monitor appearance of the order in the Orders
table (see the "Monitor Appearing Order in Orders Table" section below).
Request failed
It means that the order has not passed the initial verification. For example, an incorrect account was specified, there is insufficient margin, etc.
To process notifications about the request response, an instance of the class implementing the IO2GResponseListener
interface should be subscribed to a session object by using the subscribeResponse
method. To process notifications about request failures, you should use the IO2GResponseListener.onRequestFailed
method.
Below is an example of the IO2GResponseListener
interface implementation.
void ResponseListener::onRequestCompleted(const char *requestId, IO2GResponse *response)
{
//the method should not be used as the confirmation of an order creation
}
/** Request execution failed data handler. */
void ResponseListener::onRequestFailed(const char *requestId , const char *error)
{
std::cout << "Request failed. ID: " << requestId << " : " << error << std::endl;
if (requestId != 0 && mRequestID.length() > 0 && strcmp(requestId, mRequestID.c_str()) == 0)
{
mSuccess = false;
uni::SetEvent(mResponseEvent);
}
}
/** Request update data received data handler. */
void ResponseListener::onTablesUpdates(IO2GResponse *data)
{
//the method should be implemented when table manager is not used!
}
1.3. Result of Request Execution: Order and Trade
When the order is created, it appears in the Orders
table. It stays in the table until it is executed. When the order is executed, a position is opened and appears in the Trades
table. To monitor the appearance the order and the trade in the tables, it is necessary to subscribe to table events.
1.3.1. How to Subscribe to Table Events
There are two ways to subscribe for table events:
OnTableUpdates
You should handle table updates in the onTablesUpdates()
method by implementing the IO2GResponseListener
interface.
You should create an instance of the IO2GTablesUpdatesReader
class by using IO2GResponseReaderFactory
.
TableListener
Create a table listener class that implements the IO2GTableListener
interface. Then create an object of that class and subscribe the table listener object to a table event. For details, please read “How to use table manager in ForexConnect API.”
You should subscribe to the following events: onAdded
(onOrderAdded) for the orders
table, onAdded
(onTradeAdded) for the trades
table.
1.3.2. How to Monitor Appearance of Order in Orders Table
As it has been said above, the onRequestCompleted
event cannot be used as the confirmation of the order creation. You should check if the order is actually added to the Orders table. To do so, check OnOrderAdded
events for the Orders
table. You should make sure that the event satisfies the following criteria:
The RequestID
order field must be the same as the RequestID
of the order request you have sent;
The Type
order field must be the same as the type of your order. It is important because the table can contain several orders with the same RequestID. For example, if a market order with stop and limit orders attached is created, the table contains several orders with the same RequestID
. So you should use the Type
field to uniquely identify the order.
Once you get such an event, you should retrieve OrderID
. OrderID
is necessary to monitor further order execution.
1.3.3. How to Monitor Appearance of Position in Trades Table
To monitor appearance of a position in the Trades
table, check onTradeAdded
events for the Trades
table.
When the event occurs, it is necessary to check that the added trade is opened by your order. To do so, make sure that the OpenOrderID
field of the added trade is the same as the OrderID
of your order.
1.4. Order Rejection
Sometimes there is no liquidity on the market. It may lead to failure to fill an order and consequently to the order rejection. There is also possible a case when the market price significantly moves away from the order price. For the Open Range and the Open Limit orders, it may also lead to the order rejection.
In case of rejection, a rejection message will appear in the Messages table.
To process this case, it is necessary to monitor onAdded
(onMessageAdded) events. To make sure that an onMessageAdded
event occurs for your order, it is necessary to check that the Feature
field of the message is the same as "Market conditions" and the message text
contains your OrderID
.
1.5. Diagram and Sample for Processing Happy Day Case
Below is the state machine diagram that demonstrates what events should be processed to monitor the creation and the execution of an order and what actions should be performed depending on the order status.
Below is an example of the diagram implementation.
[hide]
OpenOrderMonitor.h
#pragma once
bool isOpeningOrder(IO2GOrderRow *order);
bool isClosingOrder(IO2GOrderRow *order);
/** Helper class for monitoring creation open positions using a open order.
On no dealing desk more than one position can be create. It is depends on
liquidity on forex market, The class stores all open positions
*/
class OrderMonitor
{
public:
enum ExecutionResult
{
Executing,
Executed,
PartialRejected,
FullyRejected,
Canceled
};
OrderMonitor(IO2GOrderRow *order);
~OrderMonitor();
void onTradeAdded(IO2GTradeRow* traderRow);
void onOrderDeleted(IO2GOrderRow *order);
void onMessageAdded(IO2GMessageRow *message);
ExecutionResult getResult();
bool isOrderCompleted();
IO2GOrderRow *getOrder();
int getRejectAmount();
void getTrade(IO2GTradeRow* &trade);
std::string getRejectMessage();
private:
enum OrderState
{
OrderExecuting,
OrderExecuted,
OrderCanceled,
OrderRejected
};
/** Set result.*/
void setResult(bool success);
bool isAllTradeReceived();
bool checkAndStoreMessage(IO2GMessageRow *message);
OrderState mState;
std::string mRejectMessage;
IO2GTradeRow* mTrade;
int mTotal;
IO2GOrderRow* mOrder;
ExecutionResult mResult;
int mRejectAmount;
};
OpenOrderMonitor.cpp
#include "stdafx.h"
#include "OrderMonitor.h"
#define MarketCondition "5"
bool isOpeningOrder(IO2GOrderRow *order)
{
const char* type = order->getType();
return type[0] == 'O';
}
bool isClosingOrder(IO2GOrderRow *order)
{
const char* type = order->getType();
return type[0] == 'C';
}
OrderMonitor::OrderMonitor(IO2GOrderRow *order)
{
mOrder = order;
mOrder->addRef();
mRejectAmount = 0;
mState = OrderExecuting;
mResult = Executing;
mTrade = NULL;
mRejectAmount = 0;
}
OrderMonitor::~OrderMonitor()
{
mTrade->release();
mOrder->release();
}
OrderMonitor::ExecutionResult OrderMonitor::getResult()
{
return mResult;
}
void OrderMonitor::onTradeAdded(IO2GTradeRow* tradeRow)
{
std::string tradeOrderID = tradeRow->getOpenOrderID();
std::string orderID = mOrder->getOrderID();
if (tradeOrderID == orderID)
{
mTrade = tradeRow;
mTrade->addRef();
if (mState == OrderExecuted ||
mState == OrderRejected ||
mState == OrderCanceled)
{
setResult(true);
}
}
}
void OrderMonitor::onOrderDeleted(IO2GOrderRow *order)
{
std::string deletedOrderID = order->getOrderID();
std::string orderID = mOrder->getOrderID();
if (deletedOrderID == orderID)
{
if (*(order->getStatus()) == 'R')
{
mState = OrderRejected;
mRejectAmount = order->getAmount();
if (!mRejectMessage.empty())
setResult(true);
}
else if (*(order->getStatus()) == 'C')
{
mState = OrderCanceled;
mRejectAmount = order->getAmount();
setResult(false);
}
else
{
mRejectAmount = 0;
mState = OrderExecuted;
setResult(true);
}
}
}
void OrderMonitor::onMessageAdded(IO2GMessageRow *message)
{
if (mState == OrderRejected ||
mState == OrderExecuting)
{
bool isRejectMessage = checkAndStoreMessage(message);
if (mState == OrderRejected && isRejectMessage)
setResult(true);
}
}
bool OrderMonitor::checkAndStoreMessage(IO2GMessageRow *message)
{
std::string feature;
feature = message->getFeature();
if (feature == MarketCondition)
{
std::string text = message->getText();
size_t findPos = text.find(mOrder->getOrderID());
if (findPos != std::string::npos)
{
mRejectMessage = message->getText();
return true;
}
}
return false;
}
IO2GOrderRow *OrderMonitor::getOrder()
{
if (mOrder)
mOrder->addRef();
return mOrder;
}
/** */
void OrderMonitor::getTrade(IO2GTradeRow* &trade)
{
if (mTrade)
mTrade->addRef();
trade = mTrade;
}
std::string OrderMonitor::getRejectMessage()
{
return mRejectMessage;
}
void OrderMonitor::setResult(bool success)
{
if (success)
{
if (mRejectAmount == 0)
mResult = Executed;
else
{
if (mTrade && mTrade->getAmount() != 0)
mResult = PartialRejected;
else
mResult = FullyRejected;
}
}
else
mResult = Canceled;
}
bool OrderMonitor::isOrderCompleted()
{
return mResult != Executing;
}
int OrderMonitor::getRejectAmount()
{
return mRejectAmount;
}
An example on how to subscribe the order monitor by using onTableUpdates
is given below.
[hide]
ResponseListener.h
#pragma once
/** Response listener class. */
class OfferCollection;
class Offer;
class OrderMonitor;
class ResponseListener : public IO2GResponseListener
{
protected:
/** Destructor. */
virtual ~ResponseListener();
/** Print offer to the console. */
void printOffer(Offer *offer);
/** Format date to print */
void formatDate(DATE d, std::string &buf);
public:
ResponseListener(IO2GSession *session);
/** Increase reference counter. */
virtual long addRef();
/** Decrease reference counter. */
virtual long release();
/** Set request. */
void setRequest(const char *requestId);
/** Request execution completed data handler. */
virtual void onRequestCompleted(const char * requestId, IO2GResponse *response = 0);
/** Request execution failed data handler. */
virtual void onRequestFailed(const char *requestId , const char *error);
/** Request update data received data handler. */
virtual void onTablesUpdates(IO2GResponse *data);
bool getRequestSuccess()
{
return mSuccess;
}
HANDLE getResponseEvent()
{
return mResponseEvent;
};
HANDLE getUpdateEvent()
{
return mUpdateEvent;
}
private:
void printResult();
void printTrade(IO2GTradeRow *trade, std::string &orderID);
void checkResultAndNotify();
OrderMonitor *mOrderMonitor;
long mRefCount;
/** Session object. */
IO2GSession *mSession;
/** Request we are waiting for. */
std::string mRequestID;
/** Response Event handle. */
HANDLE mResponseEvent;
/** Update Event handle. */
HANDLE mUpdateEvent;
/** State of last request. */
bool mSuccess;
};
ResponseListener.cpp
#include "stdafx.h"
#include <string>
#include "responselistener.h"
#include "OrderMonitor.h"
ResponseListener::ResponseListener(IO2GSession *session)
{
mSession = session;
mSession->addRef();
mSuccess = false;
mRefCount = 1;
mResponseEvent = uni::CreateEvent(0, FALSE, FALSE, 0);
mUpdateEvent = uni::CreateEvent(0, FALSE, FALSE, 0);
mOrderMonitor = NULL;
}
ResponseListener::~ResponseListener()
{
if (mOrderMonitor)
delete mOrderMonitor;
mSession->release();
uni::CloseHandle(mResponseEvent);
uni::CloseHandle(mUpdateEvent);
}
/** Increase reference counter. */
long ResponseListener::addRef()
{
return InterlockedIncrement(&mRefCount);
}
/** Decrease reference counter. */
long ResponseListener::release()
{
long rc = InterlockedDecrement(&mRefCount);
if (rc == 0)
delete this;
return rc;
}
/** Set request. */
void ResponseListener::setRequest(const char *requestId)
{
mRequestID = requestId;
uni::ResetEvent(mResponseEvent);
uni::ResetEvent(mUpdateEvent);
mSuccess = false;
}
/** Request execution completed data handler. */
void ResponseListener::onRequestCompleted(const char *requestId, IO2GResponse *response)
{
if (response != 0)
{
if (response->getType() == CreateOrderResponse && mRequestID == requestId)
{
std::cout << "Request complete. ID: " << requestId << std::endl;
mSuccess = true;
uni::SetEvent(mResponseEvent);
}
}
}
/** Request execution failed data handler. */
void ResponseListener::onRequestFailed(const char *requestId , const char *error)
{
std::cout << "Request failed. ID: " << requestId << " : " << error << std::endl;
if (requestId != 0 && mRequestID.length() > 0 && strcmp(requestId, mRequestID.c_str()) == 0)
{
mSuccess = false;
uni::SetEvent(mResponseEvent);
uni::SetEvent(mUpdateEvent);
}
}
void ResponseListener::checkResultAndNotify()
{
if (mOrderMonitor->isOrderCompleted())
{
printResult();
uni::SetEvent(mUpdateEvent);
}
}
/** Request update data received data handler. */
void ResponseListener::onTablesUpdates(IO2GResponse *data)
{
if (data)
{
IO2GResponseReaderFactory *factory = mSession->getResponseReaderFactory();
IO2GTablesUpdatesReader *reader = factory->createTablesUpdatesReader(data);
if (reader)
{
for (int i = 0; i < reader->size(); ++i)
{
switch (reader->getUpdateTable(i))
{
case Orders:
{
O2G2Ptr<IO2GOrderRow> orderRow = reader->getOrderRow(i);
if (mRequestID != orderRow->getRequestID())
break;
if (reader->getUpdateType(i) == Insert)
{
if ((isClosingOrder(orderRow) || isOpeningOrder(orderRow)) &&
mOrderMonitor == NULL)
{
std::cout << "The order has been added. Order ID: " << orderRow->getOrderID()
<< " Rate: " << orderRow->getRate()
<< " Time In Force:" << orderRow->getTimeInForce() << std::endl;
mOrderMonitor = new OrderMonitor(orderRow);
}
}
else if (reader->getUpdateType(i) == Delete)
{
std::cout << "The order has been deleted. Order ID: " << orderRow->getOrderID() << std::endl;
if (mOrderMonitor)
{
mOrderMonitor->onOrderDeleted(orderRow);
checkResultAndNotify();
}
}
}
break;
case Trades:
{
if (reader->getUpdateType(i) == Insert)
{
IO2GTradeRow *tradeRow = reader->getTradeRow(i);
if (mOrderMonitor)
{
mOrderMonitor->onTradeAdded(tradeRow);
checkResultAndNotify();
}
}
}
break;
case Messages:
{
if (reader->getUpdateType(i) == Insert)
{
IO2GMessageRow *messageRow = reader->getMessageRow(i);
if (mOrderMonitor)
{
mOrderMonitor->onMessageAdded(messageRow);
checkResultAndNotify();
}
}
}
break;
}
}
reader->release();
}
factory->release();
}
}
void ResponseListener::printResult()
{
if (mOrderMonitor)
{
OrderMonitor::ExecutionResult result = mOrderMonitor->getResult();
IO2GTradeRow *trade;
O2G2Ptr<IO2GOrderRow> order = mOrderMonitor->getOrder();
std::string orderID = order->getOrderID();
mOrderMonitor->getTrade(trade);
switch (result)
{
case OrderMonitor::Canceled:
{
if (trade != NULL)
{
printTrade(trade, orderID);
std::cout << "A part of the order has been canceled." << "Amount = " << mOrderMonitor->getRejectAmount() << std::endl;
}
else
{
std::cout << "The order: OrderID = " << orderID << " has been canceled." << std::endl;
std::cout << "The cancel amount = " << mOrderMonitor->getRejectAmount() << "." << std::endl;
}
}
break;
case OrderMonitor::FullyRejected:
{
std::cout << "The order has been rejected. OrderID = " << orderID << std::endl;
std::cout << "The rejected amount = " << mOrderMonitor->getRejectAmount() << std::endl;;
std::cout << "Rejection cause: " << mOrderMonitor->getRejectMessage() << std::endl;
}
break;
case OrderMonitor::Executed:
printTrade(trade, orderID);
break;
}
}
}
void ResponseListener::printTrade(IO2GTradeRow* trade, std::string &orderID)
{
if (trade == NULL)
return;
std::cout << "For the order: OrderID = " << orderID << " the following position has been opened: " << std::endl;
std::string tradeID = trade->getTradeID();
int amount = trade->getAmount();
double rate = trade->getOpenRate();
std::cout << "Trade ID: " << tradeID << "; Amount: " << amount << "; Rate: " << rate << std::flush << std::endl;
}
An example on how to subscribe the order monitor by using TableListener
can be found below.
[hide]
TableListener.h
#pragma once
class OrderMonitor;
class TableListener :
public IO2GTableListener
{
public:
long addRef(void);
long release();
void onStatusChanged(O2GTableStatus);
void onAdded(const char *,IO2GRow *);
void onChanged(const char *,IO2GRow *);
void onDeleted(const char *,IO2GRow *);
void setRequest(const char *requestID )
{
mRequestID = requestID;
};
TableListener(void);
HANDLE getEvent();
~TableListener(void);
private:
void printResult();
void printTrade(IO2GTradeRow *trades, std::string &orderID);
HANDLE mEvent;
long mRef;
std::string mRequestID;
OrderMonitor *mOrderMonitor;
};
void subscribeTableListener(IO2GTableManager *manager, IO2GTableListener *listener);
void unsubscribeTableListener(IO2GTableManager *manager, IO2GTableListener *listener);
TableListener.cpp
#include "stdafx.h"
#include "OrderMonitor.h"
#include "tablelistener.h"
TableListener::TableListener(void)
{
mEvent = uni::CreateEvent(0, FALSE, FALSE, 0);
mRef = 1;
mOrderMonitor = NULL;
}
TableListener::~TableListener(void)
{
uni::CloseHandle(mEvent);
}
long TableListener::addRef()
{
return InterlockedIncrement(&mRef);
}
long TableListener::release()
{
InterlockedDecrement(&mRef);
if(mRef == 0)
delete this;
return mRef;
}
HANDLE TableListener::getEvent()
{
return mEvent;
}
void TableListener::onStatusChanged(O2GTableStatus status)
{
}
void TableListener::onAdded(const char *rowID, IO2GRow *row)
{
O2GTable type = row->getTableType();
switch(type)
{
case Orders:
{
IO2GOrderRow *orderRow = static_cast<IO2GOrderRow *>(row);
if( mRequestID == orderRow->getRequestID() &&
(isClosingOrder(orderRow) || isOpeningOrder(orderRow)))
{
std::cout << "The order has been added. Order ID: " << orderRow->getOrderID()
<< " Rate: " << orderRow->getRate()
<< " Time In Force:" << orderRow->getTimeInForce() << std::endl;
mOrderMonitor = new OrderMonitor(orderRow);
}
}
break;
case Trades:
{
IO2GTradeRow *tradeRow = static_cast<IO2GTradeRow *>(row);
if (mOrderMonitor)
{
mOrderMonitor->onTradeAdded(tradeRow);
if (mOrderMonitor->isOrderCompleted())
{
printResult();
uni::SetEvent(mEvent);
}
}
}
break;
case Messages:
{
IO2GMessageRow *messageRow = static_cast<IO2GMessageRow *>(row);
if (mOrderMonitor)
{
mOrderMonitor->onMessageAdded(messageRow);
if (mOrderMonitor->isOrderCompleted())
{
printResult();
uni::SetEvent(mEvent);
}
}
}
break;
}
}
void TableListener::onChanged(const char *rowID, IO2GRow *row)
{
O2GTable type = row->getTableType();
if (type == Accounts)
{
IO2GAccountTableRow *account = (IO2GAccountTableRow*)row;
std::cout.precision(2);
std::cout << "The balance has been changed AccountID=" << account->getAccountID() <<
" Balance=" << std::fixed << account->getBalance() <<
" Equity=" << std::fixed << account->getEquity() << std::endl;
std::cout.precision(5);
}
}
void TableListener::onDeleted(const char *rowID, IO2GRow *row)
{
IO2GOrderRow *orderRow = static_cast<IO2GOrderRow *>(row);
if( mRequestID == orderRow->getRequestID() )
{
std::cout << "The order has been deleted. Order ID: " << orderRow->getOrderID() << std::endl;
mOrderMonitor->onOrderDeleted(orderRow);
if (mOrderMonitor)
{
if (mOrderMonitor->isOrderCompleted())
{
printResult();
uni::SetEvent(mEvent);
}
}
}
}
void TableListener::printResult()
{
if (mOrderMonitor)
{
OrderMonitor::ExecutionResult result = mOrderMonitor->getResult();
IO2GTradeRow *trade;
O2G2Ptr<IO2GOrderRow> order = mOrderMonitor->getOrder();
std::string orderID = order->getOrderID();
mOrderMonitor->getTrade(trade);
switch (result)
{
case OrderMonitor::Canceled:
{
if (trade != NULL)
{
printTrade(trade, orderID);
std::cout << "A part of the order has been canceled." << "Amount = " << mOrderMonitor->getRejectAmount() << std::endl;
}
else
{
std::cout << "The order: OrderID = " << orderID << " has been canceled." << std::endl;
std::cout << "The cancel amount = " << mOrderMonitor->getRejectAmount() << "." << std::endl;
}
}
break;
case OrderMonitor::FullyRejected:
{
std::cout << "The order has been rejected. OrderID = " << orderID << std::endl;
std::cout << "The rejected amount = " << mOrderMonitor->getRejectAmount() << std::endl;;
std::cout << "Rejection cause: " << mOrderMonitor->getRejectMessage() << std::endl;
}
break;
case OrderMonitor::Executed:
printTrade(trade, orderID);
break;
}
}
}
void TableListener::printTrade(IO2GTradeRow* trade, std::string &orderID)
{
if (trade == NULL)
return;
std::cout << "For the order: OrderID = " << orderID << " the following position has been opened: " << std::endl;
std::string tradeID = trade->getTradeID();
int amount = trade->getAmount();
double rate = trade->getOpenRate();
std::cout << "Trade ID: " << tradeID << "; Amount: " << amount << "; Rate: " << rate << std::flush << std::endl;
}
void subscribeTableListener(IO2GTableManager *manager, IO2GTableListener *listener)
{
O2G2Ptr<IO2GAccountsTable> accountsTable = (IO2GMessagesTable*)manager->getTable(Messages);
O2G2Ptr<IO2GTradesTable> tradesTable = (IO2GTradesTable*)manager->getTable(Trades);
O2G2Ptr<IO2GOrdersTable> ordersTable = (IO2GOrdersTable *)manager->getTable(Orders);
O2G2Ptr<IO2GMessagesTable> messageTable = (IO2GMessagesTable*)manager->getTable(Messages);
accountsTable->subscirbeUpdate(Update, listener);
ordersTable->subscribeUpdate(Insert, listener);
ordersTable->subscribeUpdate(Delete, listener);
tradesTable->subscribeUpdate(Insert, listener);
messageTable->subscribeUpdate(Insert, listener);
}
void unsubscribeTableListener(IO2GTableManager *manager, IO2GTableListener *listener)
{
O2G2Ptr<IO2GAccountsTable> accountsTable = (IO2GMessagesTable*)manager->getTable(Messages);
O2G2Ptr<IO2GTradesTable> tradesTable = (IO2GTradesTable*)manager->getTable(Trades);
O2G2Ptr<IO2GOrdersTable> ordersTable = (IO2GOrdersTable *)manager->getTable(Orders);
O2G2Ptr<IO2GMessagesTable> messageTable = (IO2GMessagesTable*)manager->getTable(Messages);
accountsTable->unsubscirbeUpdate(Update, listener);
ordersTable->unsubscribeUpdate(Insert, listener);
ordersTable->unsubscribeUpdate(Delete, listener);
tradesTable->unsubscribeUpdate(Insert, listener);
messageTable->unsubscribeUpdate(Insert, listener);
}
ResponseListener.h
#include "stdafx.h"
/** Response listener class. */
class ResponseListener : public IO2GResponseListener
{
private:
long mRefCount;
/** Session object. */
IO2GSession *mSession;
/** Response Event handle. */
HANDLE mEvent;
/** Request ID to wait. */
std::string mRequestID;
bool mCompleted;
protected:
/** Destructor. */
virtual ~ResponseListener();
public:
/** Constructor */
ResponseListener();
/** Increase reference counter. */
virtual long addRef();
/** Decrease reference counter. */
virtual long release();
/** Set request. */
void setRequest(const char *requestId);
/** Request execution completed data handler. */
virtual void onRequestCompleted(const char * requestId, IO2GResponse *response = 0);
/** Request execution failed data handler. */
virtual void onRequestFailed(const char *requestId , const char *error);
/** Request update data received data handler. */
virtual void onTablesUpdates(IO2GResponse *data);
bool isRequestCompleted();
HANDLE getEvent()
{
return mEvent;
}
};
ResponseListener.cpp
#include "stdafx.h"
#include "responselistener.h"
ResponseListener::ResponseListener()
{
mRefCount = 1;
mEvent = uni::CreateEvent(0, FALSE, FALSE, 0);
mCompleted = true;
}
ResponseListener::~ResponseListener()
{
uni::CloseHandle(mEvent);
}
/** Increase reference counter. */
long ResponseListener::addRef()
{
return InterlockedIncrement(&mRefCount);
}
/** Decrease reference counter. */
long ResponseListener::release()
{
long rc = InterlockedDecrement(&mRefCount);
if (rc == 0)
delete this;
return rc;
}
/** Set request. */
void ResponseListener::setRequest(const char *requestId)
{
mRequestID = requestId;
}
/** Request execution completed data handler. */
void ResponseListener::onRequestCompleted(const char *requestId, IO2GResponse *response)
{
if (requestId && mRequestID == requestId)
{
std::cout << "The request has been completed ID " << requestId << std::endl;
mCompleted = true;
uni::SetEvent(mEvent);
}
}
/** Request execution failed data handler. */
void ResponseListener::onRequestFailed(const char *requestId , const char *error)
{
if (requestId && mRequestID == requestId)
{
std::cout << "The request has been failed ID: " << requestId << " :" << error << std::endl;
mCompleted = false;
uni::SetEvent(mEvent);
}
}
/** Request update data received data handler. */
void ResponseListener::onTablesUpdates(IO2GResponse *data)
{
}
bool ResponseListener::isRequestCompleted()
{
return mCompleted;
}
2. What is Partial Execution
2.1. No Dealing Desk
In the no dealing desk execution model, a broker passes on to his clients the best prices provided by one of the liquidity providers with a fixed mark-up for each currency pair. A broker relies on these external providers with regard to currency pricing. Although this model promotes efficiency and competition for market pricing, there are certain limitations on liquidity that can affect the final execution of an order.
A partial fill occurs when only a part of the order can be executed at the price requested due to the limited liquidity. The rest of the order will be filled at the next best available price or cancelled entirely depending on the order type (see the “Order Time in Force” section for details).
A partial fill is possible on Real accounts only.
Partial orders give a trader the opportunity to enter a part of the position instead of rejecting the entire order.
2.2. Order Time in Force
With different order types a trader has different time-in-force options that provide additional instructions on how long an order should remain active until it is executed or expires:
Fill Or Kill (FOK);
Immediate Or Cancel (IOC);
Good Till Cancelled (GTC);
Day (DAY).
Please see Orders State Machines for the description of time-in-force options for different order types.
An order with the GTC
and the IOC
time-in-force options can be executed partially. It means that one order may result in a number of positions opened/closed at different prices. A GTC
order is filled in portions until it is completely executed. An IOC
order is filled in portions to the maximum extent possible (until the liquidity pool dries up), the rest of the order is rejected. In case of partial closing, the system closes a position in the filled amount and opens a new position in the remaining amount. The system does so until the order is entirely filled (GTC
orders) or the liquidity dries up (IOC
orders).
3. Process Partial Execution
In case of partial filling, one order results in a number of positions opened at different prices. Depending on the order time in force, some part(s) of the order may also be rejected.
To monitor the partial execution, it is necessary to process the following events:
OnTradeAdded
The OpenOrderID
field of the added trade must be the same as the OrderID of your order.
OnMessageAdded
The Feature
field of the message must be the same as "Market conditions" and the message text must contain your OrderID.
To define whether or not the order execution is completed, you need to:
Process the onDeleted
event of Orders table (further it will be referred as onOrderDeleted
event). When the order execution is completed, the order is deleted. In case of deletion, the order status is 'F' if the order is filled completely and ‘R’ if the order is rejected completely or partially. If the order is filled completely, a new trade(s) is inserted in the Trades table. If the order is rejected completely or partially, a rejection message is inserted in the Messages table. The rejected amount is contained in the order amount field.
Note that the order deletion, the trade addition, and the message rejection notification can be received randomly.
Check if the total amount of resulting opened positions (including the amount of rejected order parts, if any) matches the amount of the order specified in the order request.
4. All Variants of Order Execution
In addition to the described execution results (an opened position, a completely or partially rejected order), there is also possible a case when the order execution results in closure of the existing position(s).
This case is possible on accounts where hedging is not allowed. Note that hedging is not allowed on all the U.S. accounts. On such accounts, opening of a position for the symbol that already has an open position(s) of the opposite trade operation always causes closure of the open position(s). Note that if the amount of an open order exceeds the total amount of the currently opened positions on that symbol, the result of the order execution will be closure of the existing positions and opening of a new position in the rest of the amount.
For example, there are three long (buy) positions for EUR/USD totaling 50k. You create an open sell order in the amount of 70k for EUR/USD. The result of the order execution will be closure of the existing positions and opening of a new position in the amount of 20k.
To monitor the position(s) closure, it is necessary to check onClosedTradeAdded
events. The CloseOrderID
field of the closed trade must be the same as the OrderID
of your order.
Please see below the summary table of all possible variants of the order execution and execution results.
Variant of Order Execution |
Execution Result |
An opened position |
A new position will appear in the Trades table. The position amount must be equal to the amount specified in the order request. |
A closed position |
A closed position will appear in the Closed Trades table. The position amount must not be less than the amount specified in the order request. |
A partially opened/closed position |
Either a new position will appear in the Trades table or a closed position will appear in the Closed Trades table. The position amount must be less than the amount specified in the order request. |
A completely rejected order |
A rejection message will appear in the Messages table. An order with the "R " status will appear in the Orders table. |
A partially rejected order |
Either a new position will appear in the Trades table or a closed position will appear in the Closed Trades table (depending on the account type).
A rejection message will appear in the Messages table. |
The state machine diagram below shows all possible execution variants and all events that must be processed to monitor the order execution. The diagram also shows what actions should be performed depending on the order status.
Below is an example of the diagram implementation.
[hide]
OrderMonitor.h
#pragma once
bool isOpeningOrder(IO2GOrderRow *order);
bool isClosingOrder(IO2GOrderRow *order);
/** Helper class for monitoring creation open positions using a open order.
On no dealing desk more than one position can be create. It is depends on
liquidity on forex market, The class stores all opened and closed positions
*/
class OrderMonitor
{
public:
enum ExecutionResult
{
Executing,
Executed,
PartialRejected,
FullyRejected,
Canceled
};
OrderMonitor(IO2GOrderRow *order);
~OrderMonitor();
void onTradeAdded(IO2GTradeRow* traderRow);
void onOrderDeleted(IO2GOrderRow *order);
void onMessageAdded(IO2GMessageRow *message);
void onClosedTradeAdded(IO2GClosedTradeRow* closeTradeRow);
ExecutionResult getResult();
bool isOrderCompleted();
IO2GOrderRow *getOrder();
void getTrades(std::vector<IO2GTradeRow*> &trades);
void getClosedTrades(std::vector<IO2GClosedTradeRow*> &closedTrades);
int getRejectAmount();
std::string getRejectMessage();
private:
enum OrderState
{
OrderExecuting,
OrderExecuted,
OrderCanceled,
OrderRejected
};
/** Set result.*/
void setResult(bool success);
bool isAllTradeReceived();
bool checkAndStoreMessage(IO2GMessageRow *message);
OrderState mState;
std::string mRejectMessage;
std::vector<IO2GTradeRow*> mTrades;
std::vector<IO2GClosedTradeRow*> mClosedTrades;
int mTotalAmount;
int mRejectAmount;
IO2GOrderRow* mOrder;
ExecutionResult mResult;
};
OrderMonitor.cpp
#include "stdafx.h"
#include "OrderMonitor.h"
#define MarketCondition "5"
bool isOpeningOrder(IO2GOrderRow *order)
{
const char* type = order->getType();
return type[0] == 'O';
}
bool isClosingOrder(IO2GOrderRow *order)
{
const char* type = order->getType();
return type[0] == 'C';
}
OrderMonitor::OrderMonitor(IO2GOrderRow *order)
{
mOrder = order;
mOrder->addRef();
mRejectAmount = 0;
mState = OrderExecuting;
mResult = Executing;
}
OrderMonitor::~OrderMonitor()
{
for (size_t i = 0; i < mTrades.size(); ++i)
mTrades[i]->release();
for (size_t i = 0; i < mClosedTrades.size(); ++i)
mClosedTrades[i]->release();
mOrder->release();
}
OrderMonitor::ExecutionResult OrderMonitor::getResult()
{
return mResult;
}
void OrderMonitor::onTradeAdded(IO2GTradeRow* tradeRow)
{
std::string tradeOrderID= tradeRow->getOpenOrderID();
std::string orderID = mOrder->getOrderID();
if (tradeOrderID == orderID)
{
mTrades.push_back(tradeRow);
if (mState == OrderExecuted ||
mState == OrderRejected ||
mState == OrderCanceled)
{
if (isAllTradeReceived())
setResult(true);
}
}
}
void OrderMonitor::onClosedTradeAdded(IO2GClosedTradeRow* closedTradeRow)
{
std::string orderID = mOrder->getOrderID();
std::string closedTradeOrderID = closedTradeRow->getCloseOrderID();
if (orderID == closedTradeOrderID)
{
mClosedTrades.push_back(closedTradeRow);
if (mState == OrderExecuted ||
mState == OrderRejected ||
mState == OrderCanceled)
{
if (isAllTradeReceived())
setResult(true);
}
}
}
void OrderMonitor::onOrderDeleted(IO2GOrderRow *order)
{
std::string deletedOrderID = order->getOrderID();
std::string orderID = mOrder->getOrderID();
if (deletedOrderID == orderID)
{
// Store Reject amount
if (*(order->getStatus()) == 'R')
{
mState = OrderRejected;
mRejectAmount = order->getAmount();
mTotalAmount = order->getOriginAmount() - mRejectAmount;
if (!mRejectMessage.empty() && isAllTradeReceived())
setResult(true);
}
else if (*(order->getStatus()) == 'C')
{
mState = OrderCanceled;
mRejectAmount = order->getAmount();
mTotalAmount = order->getOriginAmount() - mRejectAmount;
if (isAllTradeReceived())
setResult(false);
}
else
{
mRejectAmount = 0;
mTotalAmount = order->getOriginAmount();
mState = OrderExecuted;
if (isAllTradeReceived())
setResult(true);
}
}
}
void OrderMonitor::onMessageAdded(IO2GMessageRow *message)
{
if (mState == OrderRejected ||
mState == OrderExecuting)
{
bool isRejectMessage = checkAndStoreMessage(message);
if (mState == OrderRejected && isRejectMessage)
setResult(true);
}
}
bool OrderMonitor::checkAndStoreMessage(IO2GMessageRow *message)
{
std::string feature;
feature = message->getFeature();
if (feature == MarketCondition)
{
std::string text = message->getText();
size_t findPos = text.find(mOrder->getOrderID());
if (findPos != std::string::npos)
{
mRejectMessage = message->getText();
return true;
}
}
return false;
}
IO2GOrderRow *OrderMonitor::getOrder()
{
mOrder->addRef();
return mOrder;
}
/** */
void OrderMonitor::getTrades(std::vector<IO2GTradeRow*> &trades)
{
trades.clear();
trades.resize(mTrades.size());
std::copy(mTrades.begin(), mTrades.end(), trades.begin());
for (size_t i = 0; i < mTrades.size(); ++i)
mTrades[i]->addRef();
}
void OrderMonitor::getClosedTrades(std::vector<IO2GClosedTradeRow*> &closedTrades)
{
closedTrades.clear();
closedTrades.resize(mClosedTrades.size());
std::copy(mClosedTrades.begin(), mClosedTrades.end(), closedTrades.begin());
for (size_t i = 0; i < mClosedTrades.size(); ++i)
mClosedTrades[i]->addRef();
}
int OrderMonitor::getRejectAmount()
{
return mRejectAmount;
}
std::string OrderMonitor::getRejectMessage()
{
return mRejectMessage;
}
bool OrderMonitor::isAllTradeReceived()
{
if (mState == Executing)
return false;
int currenTotalAmaount = 0;
for (size_t i = 0; i < mTrades.size(); ++i)
currenTotalAmaount += mTrades[i]->getAmount();
for (size_t i = 0; i < mClosedTrades.size(); ++i)
currenTotalAmaount += mClosedTrades[i]->getAmount();
return currenTotalAmaount == mTotalAmount;
}
void OrderMonitor::setResult(bool success)
{
if (success)
{
if (mRejectAmount == 0)
mResult = Executed;
else
mResult = (mTrades.size() == 0 && mClosedTrades.size()==0) ? FullyRejected : PartialRejected;
}
else
mResult = Canceled;
}
bool OrderMonitor::isOrderCompleted()
{
return mResult != Executing;
}
An example on how to subscribe the order monitor by using onTableUpdates
is provided below.
[hide]
ResponseListener.h
/** Response listener class. */
class OfferCollection;
class Offer;
class OrderMonitor;
class ResponseListener : public IO2GResponseListener
{
protected:
/** Destructor. */
virtual ~ResponseListener();
/** Print offer to the console. */
void printOffer(Offer *offer);
/** Format date to print */
void formatDate(DATE d, std::string &buf);
public:
ResponseListener(IO2GSession *session);
/** Increase reference counter. */
virtual long addRef();
/** Decrease reference counter. */
virtual long release();
/** Set request. */
void setRequest(const char *requestId);
/** Request execution completed data handler. */
virtual void onRequestCompleted(const char * requestId, IO2GResponse *response = 0);
/** Request execution failed data handler. */
virtual void onRequestFailed(const char *requestId , const char *error);
/** Request update data received data handler. */
virtual void onTablesUpdates(IO2GResponse *data);
bool getRequestSuccess()
{
return mSuccess;
}
HANDLE getResponseEvent()
{
return mResponseEvent;
};
HANDLE getUpdateEvent()
{
return mUpdateEvent;
}
private:
void printResult();
void printTrades(std::vector<IO2GTradeRow*> &trades, std::string &orderID);
void printClosedTrades(std::vector<IO2GClosedTradeRow*> &trades, std::string &orderID);
void checkResultAndNotify();
OrderMonitor *mOrderMonitor;
long mRefCount;
/** Session object. */
IO2GSession *mSession;
/** Request we are waiting for. */
std::string mRequestID;
/** Response Event handle. */
HANDLE mResponseEvent;
/** Update Event handle. */
HANDLE mUpdateEvent;
/** State of last request. */
bool mSuccess;
};
ResponseListener.cpp
#include "stdafx.h"
#include <math.h>
#include <time.h>
#include <string>
#include <vector>
#include <map>
#include "responselistener.h"
#include <sstream>
#include <iomanip>
#include "OrderMonitor.h"
ResponseListener::ResponseListener(IO2GSession *session)
{
mSession = session;
mSession->addRef();
mSuccess = false;
mRefCount = 1;
mResponseEvent = uni::CreateEvent(0, FALSE, FALSE, 0);
mUpdateEvent = uni::CreateEvent(0, FALSE, FALSE, 0);
mOrderMonitor = NULL;
}
ResponseListener::~ResponseListener()
{
if (mOrderMonitor)
delete mOrderMonitor;
mSession->release();
uni::CloseHandle(mResponseEvent);
uni::CloseHandle(mUpdateEvent);
}
/** Increase reference counter. */
long ResponseListener::addRef()
{
return InterlockedIncrement(&mRefCount);
}
/** Decrease reference counter. */
long ResponseListener::release()
{
long rc = InterlockedDecrement(&mRefCount);
if (rc == 0)
delete this;
return rc;
}
/** Set request. */
void ResponseListener::setRequest(const char *requestId)
{
mRequestID = requestId;
uni::ResetEvent(mResponseEvent);
uni::ResetEvent(mUpdateEvent);
mSuccess = false;
}
/** Request execution completed data handler. */
void ResponseListener::onRequestCompleted(const char *requestId, IO2GResponse *response)
{
if (response != 0)
{
if (response->getType() == CreateOrderResponse && mRequestID == requestId)
{
std::cout << "Request complete. ID: " << requestId << std::endl;
mSuccess = true;
uni::SetEvent(mResponseEvent);
}
}
}
/** Request execution failed data handler. */
void ResponseListener::onRequestFailed(const char *requestId , const char *error)
{
std::cout << "Request failed. ID: " << requestId << " : " << error << std::endl;
if (requestId != 0 && mRequestID.length() > 0 && strcmp(requestId, mRequestID.c_str()) == 0)
{
mSuccess = false;
uni::SetEvent(mResponseEvent);
}
}
void ResponseListener::checkResultAndNotify()
{
if (mOrderMonitor->isOrderCompleted())
{
printResult();
uni::SetEvent(mUpdateEvent);
}
}
/** Request update data received data handler. */
void ResponseListener::onTablesUpdates(IO2GResponse *data)
{
if (data)
{
IO2GResponseReaderFactory *factory = mSession->getResponseReaderFactory();
IO2GTablesUpdatesReader *reader = factory->createTablesUpdatesReader(data);
if ( reader )
{
for ( int i = 0; i < reader->size(); ++i )
{
switch (reader->getUpdateTable(i))
{
case Orders:
{
O2G2Ptr<IO2GOrderRow> orderRow = reader->getOrderRow(i);
if (mRequestID != orderRow->getRequestID())
break;
if (reader->getUpdateType(i) == Insert)
{
if ((isClosingOrder(orderRow) || isOpeningOrder(orderRow)) &&
mOrderMonitor == NULL)
{
std::cout << "The order has been added. Order ID: " << orderRow->getOrderID()
<< " Rate: " << orderRow->getRate()
<< " Time In Force:" << orderRow->getTimeInForce() << std::endl;
mOrderMonitor = new OrderMonitor(orderRow);
}
}
else if (reader->getUpdateType(i) == Delete)
{
std::cout << "The order has been deleted. Order ID: " << orderRow->getOrderID() << std::endl;
if (mOrderMonitor)
{
mOrderMonitor->onOrderDeleted(orderRow);
checkResultAndNotify();
}
}
}
break;
case Trades:
{
if (reader->getUpdateType(i) == Insert)
{
IO2GTradeRow *tradeRow = reader->getTradeRow(i);
if (mOrderMonitor)
{
mOrderMonitor->onTradeAdded(tradeRow);
checkResultAndNotify();
}
}
}
break;
case ClosedTrades:
if (reader->getUpdateType(i) == Insert)
{
IO2GClosedTradeRow *closedTradeRow = reader->getClosedTradeRow(i);
if (mOrderMonitor)
{
mOrderMonitor->onClosedTradeAdded(closedTradeRow);
checkResultAndNotify();
}
}
break;
case Messages:
{
if (reader->getUpdateType(i) == Insert)
{
IO2GMessageRow *messageRow = reader->getMessageRow(i);
if (mOrderMonitor)
{
mOrderMonitor->onMessageAdded(messageRow);
checkResultAndNotify();
}
}
}
break;
}
}
reader->release();
}
factory->release();
}
}
void ResponseListener::printResult()
{
if (mOrderMonitor)
{
OrderMonitor::ExecutionResult result = mOrderMonitor->getResult();
std::vector<IO2GTradeRow*> trades;
std::vector<IO2GClosedTradeRow*> closedTrades;
O2G2Ptr<IO2GOrderRow> order = mOrderMonitor->getOrder();
std::string orderID = order->getOrderID();
mOrderMonitor->getTrades(trades);
mOrderMonitor->getClosedTrades(closedTrades);
switch (result)
{
case OrderMonitor::Canceled:
{
if (trades.size() > 0)
{
printTrades(trades, orderID);
printClosedTrades(closedTrades, orderID);
std::cout << "A part of the order has been canceled." << "Amount = " << mOrderMonitor->getRejectAmount() << std::endl;
}
else
{
std::cout << "The order: OrderID = " << orderID << " has been canceled." << std::endl;
std::cout << "The cancel amount = " << mOrderMonitor->getRejectAmount() << "." << std::endl;
}
}
break;
case OrderMonitor::FullyRejected:
{
std::cout << "The order has been rejected. OrderID = " << orderID << std::endl;
std::cout << "The rejected amount = " << mOrderMonitor->getRejectAmount() << std::endl;;
std::cout << "Rejection cause: " << mOrderMonitor->getRejectMessage() << std::endl;
}
break;
case OrderMonitor::PartialRejected:
{
printTrades(trades, orderID);
printClosedTrades(closedTrades, orderID);
std::cout << "A part of the order has been rejected. " << "Amount = " << mOrderMonitor->getRejectAmount() << std::endl;
std::cout << "Rejection cause: " << mOrderMonitor->getRejectMessage() << std::endl;
}
break;
case OrderMonitor::Executed:
printTrades(trades, orderID);
printClosedTrades(closedTrades, orderID);
break;
}
}
}
void ResponseListener::printTrades(std::vector<IO2GTradeRow*> &trades, std::string &orderID)
{
if (trades.size() == 0)
return;
std::cout << "For the order: OrderID = " << orderID << " the following positions have been opened: " << std::endl;
for (size_t i = 0; i < trades.size(); ++i)
{
IO2GTradeRow *trade = trades[i];
std::string tradeID = trade->getTradeID();
int amount = trade->getAmount();
double rate = trade->getOpenRate();
std::cout << "Trade ID: " << tradeID << "; Amount: " << amount << "; Rate: " << rate << std::endl;
trade->release();
}
}
void ResponseListener::printClosedTrades(std::vector<IO2GClosedTradeRow*> &closedTrades, std::string &orderID)
{
if (closedTrades.size() == 0)
return;
std::cout << "For the order: OrderID = " << orderID << " the following positions have been closed: " << std::endl;
for (size_t i = 0; i < closedTrades.size(); ++i)
{
IO2GClosedTradeRow *closedTrade = closedTrades[i];
std::string tradeID = closedTrade->getTradeID();
int amount = closedTrade->getAmount();
double rate = closedTrade->getCloseRate();
std::cout << "Closed Trade ID: " << tradeID << "; Amount: " << amount << "; Closed Rate: " << rate << std::endl;
closedTrade->release();
}
}
An example on how to subscribe the order monitor by using TableListener
can be studied below.
[hide]
TableListener.h
#pragma once
class OrderMonitor;
class TableListener :
public IO2GTableListener
{
public:
long addRef(void);
long release();
void onStatusChanged(O2GTableStatus);
void onAdded(const char *,IO2GRow *);
void onChanged(const char *,IO2GRow *);
void onDeleted(const char *,IO2GRow *);
void setRequest(const char *requestID )
{
mRequestID = requestID;
};
TableListener(void);
HANDLE getEvent();
~TableListener(void);
private:
void printResult();
void printTrades(std::vector<IO2GTradeRow*> &trades, std::string &orderID);
void printClosedTrades(std::vector<IO2GClosedTradeRow*> &trades, std::string &orderID);
HANDLE mEvent;
long mRef;
std::string mRequestID;
OrderMonitor *mOrderMonitor;
};
void subscribeTableListener(IO2GTableManager *manager, IO2GTableListener *listener);
void unsubscribeTableListener(IO2GTableManager *manager, IO2GTableListener *listener);
TableListener.cpp
#include "stdafx.h"
#include "OrderMonitor.h"
#include "tablelistener.h"
TableListener::TableListener(void)
{
mEvent = uni::CreateEvent(0, FALSE, FALSE, 0);
mRef = 1;
mOrderMonitor = NULL;
}
TableListener::~TableListener(void)
{
uni::CloseHandle(mEvent);
}
long TableListener::addRef()
{
return InterlockedIncrement(&mRef);
}
long TableListener::release()
{
InterlockedDecrement(&mRef);
if(mRef == 0)
delete this;
return mRef;
}
HANDLE TableListener::getEvent()
{
return mEvent;
}
void TableListener::onStatusChanged(O2GTableStatus status)
{
}
void TableListener::onAdded(const char *rowID, IO2GRow *row)
{
O2GTable type = row->getTableType();
switch(type)
{
case Orders:
{
IO2GOrderRow *orderRow = static_cast<IO2GOrderRow *>(row);
if( mRequestID == orderRow->getRequestID() &&
(isClosingOrder(orderRow) || isOpeningOrder(orderRow)))
{
std::cout << "The order has been added. Order ID: " << orderRow->getOrderID()
<< " Rate: " << orderRow->getRate()
<< " Time In Force:" << orderRow->getTimeInForce() << std::endl;
mOrderMonitor = new OrderMonitor(orderRow);
}
}
break;
case Trades:
{
IO2GTradeRow *tradeRow = static_cast<IO2GTradeRow *>(row);
if (mOrderMonitor)
{
mOrderMonitor->onTradeAdded(tradeRow);
if (mOrderMonitor->isOrderCompleted())
{
printResult();
uni::SetEvent(mEvent);
}
}
}
break;
case ClosedTrades:
{
IO2GClosedTradeRow *closedTradeRow = static_cast<IO2GClosedTradeRow *>(row);
if (mOrderMonitor)
{
mOrderMonitor->onClosedTradeAdded(closedTradeRow);
if (mOrderMonitor->isOrderCompleted())
{
printResult();
uni::SetEvent(mEvent);
}
}
}
break;
case Messages:
{
IO2GMessageRow *messageRow = static_cast<IO2GMessageRow *>(row);
if (mOrderMonitor)
{
mOrderMonitor->onMessageAdded(messageRow);
if (mOrderMonitor->isOrderCompleted())
{
printResult();
uni::SetEvent(mEvent);
}
}
}
break;
}
}
void TableListener::onChanged(const char *rowID, IO2GRow *row)
{
O2GTable type = row->getTableType();
if (type == Accounts)
{
IO2GAccountTableRow *account = (IO2GAccountTableRow*)row;
std::cout.precision(2);
std::cout << "The balance has been changed AccountID=" << account->getAccountID() <<
" Balance=" << std::fixed << account->getBalance() <<
" Equity=" << std::fixed << account->getEquity() << std::endl;
std::cout.precision(5);
}
}
void TableListener::onDeleted(const char *rowID, IO2GRow *row)
{
IO2GOrderRow *orderRow = static_cast<IO2GOrderRow *>(row);
if( mRequestID == orderRow->getRequestID() )
{
std::cout << "The order has been deleted. Order ID: " << orderRow->getOrderID() << std::endl;
mOrderMonitor->onOrderDeleted(orderRow);
if (mOrderMonitor)
{
if (mOrderMonitor->isOrderCompleted())
{
printResult();
uni::SetEvent(mEvent);
}
}
}
}
void TableListener::printResult()
{
if (mOrderMonitor)
{
OrderMonitor::ExecutionResult result = mOrderMonitor->getResult();
std::vector<IO2GTradeRow*> trades;
std::vector<IO2GClosedTradeRow*> closedTrades;
O2G2Ptr<IO2GOrderRow> order = mOrderMonitor->getOrder();
std::string orderID = order->getOrderID();
mOrderMonitor->getTrades(trades);
mOrderMonitor->getClosedTrades(closedTrades);
switch (result)
{
case OrderMonitor::Canceled:
{
if (trades.size() > 0)
{
printTrades(trades, orderID);
printClosedTrades(closedTrades, orderID);
std::cout << "A part of the order has been canceled." << "Amount = " << mOrderMonitor->getRejectAmount() << std::endl;
}
else
{
std::cout << "The order: OrderID = " << orderID << " has been canceled." << std::endl;
std::cout << "The cancel amount = " << mOrderMonitor->getRejectAmount() << "." << std::endl;
}
}
break;
case OrderMonitor::FullyRejected:
{
std::cout << "The order has been rejected. OrderID = " << orderID << std::endl;
std::cout << "The rejected amount = " << mOrderMonitor->getRejectAmount() << std::endl;;
std::cout << "Rejection cause: " << mOrderMonitor->getRejectMessage() << std::endl;
}
break;
case OrderMonitor::PartialRejected:
{
printTrades(trades, orderID);
printClosedTrades(closedTrades, orderID);
std::cout << "A part of the order has been rejected. " << "Amount = " << mOrderMonitor->getRejectAmount() << std::endl;
std::cout << "Rejection cause: " << mOrderMonitor->getRejectMessage() << std::endl;
}
break;
case OrderMonitor::Executed:
printTrades(trades, orderID);
printClosedTrades(closedTrades, orderID);
break;
}
}
}
void TableListener::printTrades(std::vector<IO2GTradeRow*> &trades, std::string &orderID)
{
if (trades.size() == 0)
return;
std::cout << "For the order: OrderID = " << orderID << " the following positions have been opened: " << std::endl;
for (size_t i = 0; i < trades.size(); ++i)
{
IO2GTradeRow *trade = trades[i];
std::string tradeID = trade->getTradeID();
int amount = trade->getAmount();
double rate = trade->getOpenRate();
std::cout << "Trade ID: " << tradeID << "; Amount: " << amount << "; Rate: " << rate << std::endl;
trade->release();
}
}
void TableListener::printClosedTrades(std::vector<IO2GClosedTradeRow*> &closedTrades, std::string &orderID)
{
if (closedTrades.size() == 0)
return;
std::cout << "For the order: OrderID = " << orderID << " the following positions have been closed: " << std::endl;
for (size_t i = 0; i < closedTrades.size(); ++i)
{
IO2GClosedTradeRow *closedTrade = closedTrades[i];
std::string tradeID = closedTrade->getTradeID();
int amount = closedTrade->getAmount();
double rate = closedTrade->getCloseRate();
std::cout << "Closed Trade ID: " << tradeID << "; Amount: " << amount << "; Closed Rate: " << rate << std::endl;
closedTrade->release();
}
}
void subscribeTableListener(IO2GTableManager *manager, IO2GTableListener *listener)
{
O2G2Ptr<IO2GAccountsTable> accountsTable = (IO2GMessagesTable*)manager->getTable(Messages);
O2G2Ptr<IO2GOrdersTable> ordersTable = (IO2GOrdersTable *)manager->getTable(Orders);
O2G2Ptr<IO2GTradesTable> tradesTable = (IO2GTradesTable*)manager->getTable(Trades);
O2G2Ptr<IO2GMessagesTable> messageTable = (IO2GMessagesTable*)manager->getTable(Messages);
O2G2Ptr<IO2GClosedTradesTable> closeTradesTable = (IO2GClosedTradesTable*)manager->getTable(ClosedTrades);
accountsTable->subscirbeUpdate(Update, listener);
ordersTable->subscribeUpdate(Insert, listener);
ordersTable->subscribeUpdate(Delete, listener);
tradesTable->subscribeUpdate(Insert, listener);
closeTradesTable->subscribeUpdate(Insert, listener);
messageTable->subscribeUpdate(Insert, listener);
}
void unsubscribeTableListener(IO2GTableManager *manager, IO2GTableListener *listener)
{
O2G2Ptr<IO2GAccountsTable> accountsTable = (IO2GMessagesTable*)manager->getTable(Messages);
O2G2Ptr<IO2GTradesTable> tradesTable = (IO2GTradesTable*)manager->getTable(Trades);
O2G2Ptr<IO2GOrdersTable> ordersTable = (IO2GOrdersTable *)manager->getTable(Orders);
O2G2Ptr<IO2GMessagesTable> messageTable = (IO2GMessagesTable*)manager->getTable(Messages);
O2G2Ptr<IO2GClosedTradesTable> closeTradesTable = (IO2GClosedTradesTable*)manager->getTable(ClosedTrades);
accountsTable->unsubscirbeUpdate(Update, listener);
ordersTable->unsubscribeUpdate(Insert, listener);
ordersTable->unsubscribeUpdate(Delete, listener);
tradesTable->unsubscribeUpdate(Insert, listener);
closeTradesTable->unsubscribeUpdate(Insert, listener);
messageTable->unsubscribeUpdate(Insert, listener);
}
ResponseListener.h
#include "stdafx.h"
/** Response listener class. */
class ResponseListener : public IO2GResponseListener
{
private:
long mRefCount;
/** Session object. */
IO2GSession *mSession;
/** Response Event handle. */
HANDLE mEvent;
/** Request ID to wait. */
std::string mRequestID;
bool mCompleted;
protected:
/** Destructor. */
virtual ~ResponseListener();
public:
/** Constructor */
ResponseListener();
/** Increase reference counter. */
virtual long addRef();
/** Decrease reference counter. */
virtual long release();
/** Set request. */
void setRequest(const char *requestId);
/** Request execution completed data handler. */
virtual void onRequestCompleted(const char * requestId, IO2GResponse *response = 0);
/** Request execution failed data handler. */
virtual void onRequestFailed(const char *requestId , const char *error);
/** Request update data received data handler. */
virtual void onTablesUpdates(IO2GResponse *data);
bool isRequestCompleted();
HANDLE getEvent()
{
return mEvent;
}
};
ResponseListener.cpp
#include "stdafx.h"
#include "responselistener.h"
ResponseListener::ResponseListener()
{
mRefCount = 1;
mEvent = uni::CreateEvent(0, FALSE, FALSE, 0);
mCompleted = true;
}
ResponseListener::~ResponseListener()
{
uni::CloseHandle(mEvent);
}
/** Increase reference counter. */
long ResponseListener::addRef()
{
return InterlockedIncrement(&mRefCount);
}
/** Decrease reference counter. */
long ResponseListener::release()
{
long rc = InterlockedDecrement(&mRefCount);
if (rc == 0)
delete this;
return rc;
}
/** Set request. */
void ResponseListener::setRequest(const char *requestId)
{
mRequestID = requestId;
}
/** Request execution completed data handler. */
void ResponseListener::onRequestCompleted(const char *requestId, IO2GResponse *response)
{
if (requestId && mRequestID == requestId)
{
std::cout << "The request has been completed ID " << requestId << std::endl;
mCompleted = true;
uni::SetEvent(mEvent);
}
}
/** Request execution failed data handler. */
void ResponseListener::onRequestFailed(const char *requestId , const char *error)
{
if (requestId && mRequestID == requestId)
{
std::cout << "The request has been failed ID: " << requestId << " :" << error << std::endl;
mCompleted = false;
uni::SetEvent(mEvent);
}
}
/** Request update data received data handler. */
void ResponseListener::onTablesUpdates(IO2GResponse *data)
{
}
bool ResponseListener::isRequestCompleted()
{
return mCompleted;
}
back