The article discusses how to get offers in C++.
There are two ways to get offers in your C++ application.
The first way is to use table listener. In this case you should:
Create a session, a session status listener, subscribe the status listener to the session status
(see this article
).
Implement the IO2GTableListener
interface
in a table listener class:
class TableListener : public IO2GTableListener {...}
Allow the use of table manager (it should be done before the login):
session->useTableManager(::Yes, NULL);
Log in (see this article
).
Get table manager:
IO2GTableManager *tableManager = session->getTableManager();
Wait for TablesLoaded
status of IO2GTableManager
.
while (tableManager->getStatus() != TablesLoaded && tableManager->getStatus() != TablesLoadFailed)
uni::Sleep(50);
Get "Offers" table:
IO2GOffersTable *offersTable = (IO2GOffersTable *)tableManager->getTable(::Offers);
The table can be processed to get information about offers:
IO2GOfferTableRow *offerRow = NULL;
IO2GTableIterator tableIterator = {0, 0, NULL};
while (offersTable->getNextRow(tableIterator, offerRow))
{
printf("Instrument: %s, Bid = %f, Ask = %f\n", offerRow->getInstrument(), offerRow->getBid(), offerRow->getAsk());
offerRow->release();
}
To capture updates of "Offers" table create table listener and subscribe it to "Update" event of "Offers" table:
TableListener * tableListener = new TableListener();
offersTable->subscribeUpdate(Update, tableListener);
Process table updates in "onChanged" event of IO2GTableListener
:
void TableListener::onChanged(const char *rowID, IO2GRow *row)
{
IO2GOfferRow *offerRow = static_cast<IO2GOfferRow *>(row);
if (offerRow!=NULL)
printf("Instrument: %s, Bid = %f, Ask = %f\n", offerRow->getInstrument(), offerRow->getBid(), offerRow->getAsk());
}
Unsubscribe from table listener when you are done:
offersTable->unsubscribeUpdate(Update, tableListener);
delete tableListener;
offersTable->release();
Log out (see this article
).
Get offers example [hide]
main.cpp
#include <string>
#include <map>
#include "../../../../../../include/ForexConnect.h"
#include "sessionstatus.h"
#include "responselistener.h"
int main(int argc, char *argv[])
{
const char *user = 0;
const char *password = 0;
const char *url = 0;
const char *connection = 0;
const char *subsession = 0;
const char *pin = 0;
if (argc < 3)
{
printf("usage: GetOffers.exe user password url connection [subsession] [pin]\n");
return -1;
}
user = argv[1];
password = argv[2];
if (argc >= 4)
url = argv[3];
else
url = "http://www.fxcorporate.com/Hosts.jsp";
if (argc >= 5)
connection = argv[4];
else
connection = "Demo";
IO2GSession *session = CO2GTransport::createSession();
SessionStatusListener *status_listener = new SessionStatusListener(session, true, subsession, pin);
ResponseListener *response_listener = new ResponseListener(session);
session->subscribeSessionStatus(status_listener);
session->subscribeResponse(response_listener);
status_listener->resetError();
printf("connecting...\n");
session->login(user, password, url, connection);
bool connected = false;
while (true)
{
uni::WaitForSingleObject(status_listener->getEvent(), 250);
if (status_listener->getStatusCode() == IO2GSessionStatus::Connected)
{
connected = true;
break;
}
if (status_listener->wasError())
{
printf("Connection failed: %s", status_listener->getError());
break;
}
}
if (connected)
{
printf("connected\n");
//subscribe for offer updates if offers aren't subscribed automatically
IO2GLoginRules *rules = session->getLoginRules();
if (!rules->isTableLoadedByDefault(Offers))
{
//subscribe
IO2GRequestFactory *factory = session->getRequestFactory();
IO2GRequest *request = factory->createRefreshTableRequest(Offers);
session->sendRequest(request);
request->release();
factory->release();
}
else
{
//process response in case the offers are already subscribed
IO2GResponse *response = rules->getTableRefreshResponse(Offers);
response_listener->onRequestCompleted("", response);
response->release();
}
//do nothing 10 seconds, lets all work
Sleep(10000);
session->logout();
printf("disconnecting...\n");
while (true)
{
uni::WaitForSingleObject(status_listener->getEvent(), 250);
if (status_listener->getStatusCode() == IO2GSessionStatus::Disconnected)
break;
}
printf("disconnected\n");
}
session->unsubscribeResponse(response_listener);
response_listener->release();
session->unsubscribeSessionStatus(status_listener);
status_listener->release();
session->release();
}
Offer.h
#include "../../../../../../include/ForexConnect.h"
!
/** class to keep offers. */
class Offer
{
private:
std::string mID; //!< offer identifier
std::string mInstrument; //!< instrument
int mPrecision; //!< offer precision
DATE mTime; //!< date and time of the offer change
double mPipSize; //!< offer pipsize
double mBid; //!< offer bid
double mAsk; //!< offer ask
public:
/** Constructor. */
Offer(const char *id, const char *instrument, int precision, double pipsize, double date, double bid, double ask);
/** Update bid. */
void setBid(double bid);
/** Update ask. */
void setAsk(double ask);
/** Update date. */
void setTime(DATE date);
/** Get id. */
const char *getID() const;
/** Get instrument. */
const char *getInstrument() const;
/** Get precision. */
int getPrecision() const;
/** Get pipsize. */
double getPipSize() const;
/** Get bid. */
double getBid() const;
/** Get ask. */
double getAsk() const;
/** Get date. */
DATE getTime() const;
};
offer.cpp
#include <string>
#include <vector>
#include <map>
#include "offer.h"
/** Constructor. */
Offer::Offer(const char *id, const char *instrument, int precision, double pipsize, DATE date, double bid, double ask)
{
mID = id;
mInstrument = instrument;
mPrecision = precision;
mPipSize = pipsize;
mTime = date;
mBid = bid;
mAsk = ask;
}
/** Update bid. */
void Offer::setBid(double bid)
{
mBid = bid;
}
/** Update ask. */
void Offer::setAsk(double ask)
{
mAsk = ask;
}
/** Update date. */
void Offer::setTime(DATE date)
{
mTime = date;
}
/** Get id. */
const char *Offer::getID() const
{
return mID.c_str();
}
/** Get instrument. */
const char *Offer::getInstrument() const
{
return mInstrument.c_str();
}
/** Get precision. */
int Offer::getPrecision() const
{
return mPrecision;
}
/** Get pipsize. */
double Offer::getPipSize() const
{
return mPipSize;
}
/** Get bid. */
double Offer::getBid() const
{
return mBid;
}
/** Get ask. */
double Offer::getAsk() const
{
return mAsk;
}
/** Get date. */
DATE Offer::getTime() const
{
return mTime;
}
/** Constructor. */
OfferCollection::OfferCollection()
{
}
/** Destructor. */
OfferCollection::~OfferCollection()
{
clear();
}
/** Add offer to collection. */
void OfferCollection::addOffer(Offer *offer)
{
std::map<std::string, Offer *>::const_iterator iter = mIndex.find(offer->getID());
if (iter != mIndex.end())
{
for (int i = 0; i < (int)mOffers.size(); i++)
{
if (mOffers[i] == offer)
{
delete mOffers[i];
mOffers.erase(mOffers.begin() + i);
break;
}
}
}
mOffers.push_back(offer);
mIndex[offer->getID()] = offer;
}
/** Find offer by id. */
Offer *OfferCollection::findOfferForUpdate(const char *id) const
{
std::map<std::string, Offer *>::const_iterator iter = mIndex.find(id);
if (iter == mIndex.end())
return 0;
else
return iter->second;
}
/** Find offer by id. */
const Offer *OfferCollection::findOffer(const char *id) const
{
std::map<std::string, Offer *>::const_iterator iter = mIndex.find(id);
if (iter == mIndex.end())
return 0;
else
return iter->second;
}
/** Get number of offers. */
int OfferCollection::size() const
{
return (int)mOffers.size();
}
/** Get offer by index. */
const Offer *OfferCollection::get(int index) const
{
return mOffers[index];
}
void OfferCollection::clear()
{
int i;
for (i = 0; i < (int)mOffers.size(); i++)
delete mOffers[i];
mOffers.clear();
mIndex.clear();
}
sessionstatuslistener.h
#pragma once
#include <stdio.h>
#include <string.h>
#include "../../../../threadlib/include/threadlib.h"
#ifdef WIN32
#pragma warning (disable : 4996)
#else
#define Sleep(A) sleep((A) / 1000)
#endif
/** Status listener for the sessions. */
class SessionStatusListener : public IO2GSessionStatus
{
private:
long mRefCount;
/** Sub session identifier. */
std::string mSubSessionID;
/** Pin code. */
std::string mPin;
/** The last session status code received. */
IO2GSessionStatus::O2GSessionStatus mStatusCode;
/** Flag indicating what error happened. */
bool mHasError;
/** Error. */
std::string mError;
/** Flag indicating whether sessions must be printed. */
bool mPrintSubsessions;
/** Session object. */
IO2GSession *mSession;
/** Event handle. */
HANDLE mEvent;
protected:
/** Destructor. */
~SessionStatusListener();
public:
/** Constructor.
@param session Session to listen
@param printSubsessions Print sub sessions
@param subSessionID Identifier of the subsession or NULL in case
no subsession selector is expected
@param pin Pin code or NULL in case no pin code request is expected
*/
SessionStatusListener(IO2GSession *session, bool printSubsessions, const char *subSessionID = 0, const char *pin = 0);
/** Increase reference counter. */
virtual long addRef();
/** Decrease reference counter. */
virtual long release();
/** Callback called when login has been failed. */
virtual void onLoginFailed (const char *error);
/** Callback called when session status has been changed. */
virtual void onSessionStatusChanged(IO2GSessionStatus::O2GSessionStatus status);
/** Get the session status. */
IO2GSessionStatus::O2GSessionStatus getStatusCode() const;
/** Check whether error happened. */
bool wasError() const;
/** Reset error information (use before login). */
void resetError();
/** Get error. */
const char *getError() const;
/** Get event handle to monitor the status. */
HANDLE getEvent() const;
};
sessionstatuslistener.cpp
#include <string>
#include "../../../../../../include/ForexConnect.h"
#include "sessionstatus.h"
/** Constructor. */
SessionStatusListener::SessionStatusListener(IO2GSession *session, bool printSubsessions, const char *subSessionID, const char *pin)
{
if (subSessionID != 0)
mSubSessionID = subSessionID;
else
mSubSessionID = "";
if (pin != 0)
mPin = pin;
else
mPin = "";
mSession = session;
mSession->addRef();
mHasError = false;
mError = "";
mPrintSubsessions = printSubsessions;
mRefCount = 1;
mStatusCode = IO2GSessionStatus::Disconnected;
mEvent = uni::CreateEvent(0, FALSE, FALSE, 0);
}
/** Destructor. */
SessionStatusListener::~SessionStatusListener()
{
mSession->release();
mSubSessionID.clear();
mPin.clear();
mError.clear();
uni::CloseHandle(mEvent);
}
/** Increase reference counter. */
long SessionStatusListener::addRef()
{
return InterlockedIncrement(&mRefCount);
}
/** Decrease reference counter. */
long SessionStatusListener::release()
{
long rc = InterlockedDecrement(&mRefCount);
if (rc == 0)
delete this;
return rc;
}
/** Callback called when login has been failed. */
void SessionStatusListener::onLoginFailed(const char *error)
{
mHasError = true;
mError = error;
uni::SetEvent(mEvent);
}
/** Callback called when session status has been changed. */
void SessionStatusListener::onSessionStatusChanged(IO2GSessionStatus::O2GSessionStatus status)
{
switch (status)
{
case IO2GSessionStatus::Disconnected:
printf("status::disconnected\n");
break;
case IO2GSessionStatus::Connecting:
printf("status::connecting\n");
break;
case IO2GSessionStatus::TradingSessionRequested:
printf("status::trading session requested\n");
break;
case IO2GSessionStatus::Connected:
printf("status::connected\n");
break;
case IO2GSessionStatus::Reconnecting:
printf("status::reconnecting\n");
break;
case IO2GSessionStatus::Disconnecting:
printf("status::disconnecting\n");
break;
case IO2GSessionStatus::SessionLost:
printf("status::session lost\n");
break;
}
if (status == IO2GSessionStatus::TradingSessionRequested)
{
IO2GSessionDescriptorCollection *descriptors = mSession->getTradingSessionDescriptors();
bool found = false;
if (descriptors != 0)
{
if (mPrintSubsessions)
printf("descriptors available:\n");
int i;
for (i = 0; i < descriptors->size(); i++)
{
IO2GSessionDescriptor *descriptor = descriptors->get(i);
if (mPrintSubsessions)
printf(" id:='%s' name='%s' description='%s' %s\n", descriptor->getID(), descriptor->getName(), descriptor->getDescription(), descriptor->requiresPin() ? "requires pin" : "");
if (strcmp(mSubSessionID.c_str(), descriptor->getID()) == 0)
found = true;
descriptor->release();
}
descriptors->release();
}
if (!found)
{
onLoginFailed("The specified sub session identifier is not found");
}
else
{
mSession->setTradingSession(mSubSessionID.c_str(), mPin.c_str());
}
}
mStatusCode = status;
uni::SetEvent(mEvent);
}
/** Get the session status. */
IO2GSessionStatus::O2GSessionStatus SessionStatusListener::getStatusCode() const
{
return mStatusCode;
}
/** Check whether error happened. */
bool SessionStatusListener::wasError() const
{
return mHasError;
}
/** Reset error information (use before login). */
void SessionStatusListener::resetError()
{
mHasError = false;
mError = "";
}
/** Get error. */
const char *SessionStatusListener::getError() const
{
return mError.c_str();
}
HANDLE SessionStatusListener::getEvent() const
{
return mEvent;
}
responselistern.h
#include "../../../../../../include/ForexConnect.h"
/** Response listener class. */
class OfferCollection;
class Offer;
class ResponseListener : public IO2GResponseListener
{
private:
long mRefCount;
/** Session object. */
IO2GSession *mSession;
/** Collection of the offers. */
OfferCollection *mOffers;
protected:
/** Destructor. */
virtual ~ResponseListener();
/** Print offer to the console. */
void printOffer(Offer *offer);
/** Format date to print */
void formatDate(DATE d, char *buf);
public:
ResponseListener(IO2GSession *session);
/** Increase reference counter. */
virtual long addRef();
/** Decrease reference counter. */
virtual long release();
/** 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);
};
responselistener.cpp
#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include <time.h>
#include <math.h>
#include "../../../../../../include/ForexConnect.h"
#include "offer.h"
#include "responselistener.h"
#include "sessionstatus.h"
ResponseListener::ResponseListener(IO2GSession *session)
{
mSession = session;
mSession->addRef();
mOffers = new OfferCollection();
mRefCount = 1;
}
ResponseListener::~ResponseListener()
{
delete mOffers;
mSession->release();
}
/** 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;
}
/** Request execution completed data handler. */
void ResponseListener::onRequestCompleted(const char *requestId, IO2GResponse *response)
{
if (response != 0)
{
if (response->getType() == GetOffers)
{
//process updates
IO2GResponseReaderFactory *factory = mSession->getResponseReaderFactory();
if (factory == 0)
return;
IO2GOffersTableResponseReader *offersReader = factory->createOffersTableReader(response);
if (offersReader != 0)
{
mOffers->clear();
int size = offersReader->size();
for (int i = 0; i < size; i++)
{
IO2GOfferRow *offer_row = offersReader->getRow(i);
const char *id = offer_row->getOfferID();
if (offer_row->isBidValid() && offer_row->isAskValid())
{
Offer *offer = new Offer(offer_row->getOfferID(), offer_row->getInstrument(),
offer_row->getDigits(), offer_row->getPointSize(),
offer_row->getTime(), offer_row->getBid(), offer_row->getAsk());
mOffers->addOffer(offer);
printOffer(offer);
}
offer_row->release();
}
offersReader->release();
}
factory->release();
}
}
}
/** Request execution failed data handler. */
void ResponseListener::onRequestFailed(const char *requestId , const char *error)
{
printf("Request %s failed:\n%s\n", requestId, error);
}
/** Request update data received data handler. */
void ResponseListener::onTablesUpdates(IO2GResponse *data)
{
//process updates
IO2GResponseReaderFactory *factory = mSession->getResponseReaderFactory();
if (factory == 0)
return;
IO2GOffersTableResponseReader *offersReader = factory->createOffersTableReader(data);
if (offersReader != 0)
{
int size = offersReader->size();
for (int i = 0; i < size; i++)
{
IO2GOfferRow *offer_row = offersReader->getRow(i);
const char *id = offer_row->getOfferID();
Offer *offer = mOffers->findOfferForUpdate(id);
if (offer != 0)
{
if (offer_row->isTimeValid() && offer_row->isBidValid() && offer_row->isAskValid())
{
offer->setTime(offer_row->getTime());
offer->setBid(offer_row->getBid());
offer->setAsk(offer_row->getAsk());
printOffer(offer);
}
}
offer_row->release();
}
offersReader->release();
}
factory->release();
}
/** Print offer to the console. */
void ResponseListener::printOffer(Offer *offer)
{
char sbid[32], sask[32], stime[64];
char format[32];
sprintf(format, "%%.%if", offer->getPrecision());
sprintf(sbid, format, offer->getBid());
sprintf(sask, format, offer->getAsk());
formatDate(offer->getTime(), stime);
printf("%s %s bid:=%s ask:=%s\n", offer->getInstrument(), stime, sbid, sask);
}
/** Format date to print */
void ResponseListener::formatDate(DATE d, char *buf)
{
struct tm t1;
CO2GDateUtils::VariantTimeToUnixTime(d, &t1);
sprintf(buf, "%04i/%02i/%02i %02i:%02i:%02i", t1.tm_year + 1900, t1.tm_mon + 1, t1.tm_mday, t1.tm_hour, t1.tm_min, t1.tm_sec);
}
The second way to get offers in your C++ application is to use response listener.
In that case you should:
Create a session, a session status listener, subscribe the status listener to the session status
(see this article
).
Implement the IO2GResponseListener
interface
in a response listener class:
class ResponseListener : public IO2GResponseListener{...}
Create a response listener object:
ResponseListener * responseListener = new ResponseListener(...);
Subscribe an object of this class to the session response:
pSession->subscribeResponse(responseListener);
Log in (see this article
).
The events are coming asynchronously. They should come in another thread. When an event comes, a signal will be sent to the main thread.
Use the function onSessionStatusChanged
of the session status listener to capture the Connected
event.
Get IO2GLoginRules
:
IO2GLoginRules * loginRules = mSession->getLoginRules();
Then you can get IO2GResponse
:
IO2GResponse * response = loginRules->getTableRefreshResponse(Offers);
The response can be processed to extract necessary information.
You should also capture IO2GResponse
in the
onTablesUpdates
function of a response listener class.
To get information from the "Offers" table from IO2GResponse
:
1. Create IO2GResponseReaderFactory
:
IO2GResponseReaderFactory * factory = mSession->getResponseReaderFactory();
2. Create IO2GOffersTableResponseReader
:
IO2GOffersTableResponseReader * offersReader = factory->createOffersTableReader(response);
3. Process row by row:
for (int i = 0; i < offersReader->size(); i++)
{
IO2GOfferRow * offer = offersReader->getRow(i);
// Information like
// offer->getInstrument(),
// offer->getOfferID(),
// offer->getBid(),
// offer->getAsk(),
// offer->getVolume()
// can be extracted now.
}