Welcome to our step-by-step tutorial on accessing real-time Forex, CFD, and Crypto data using TraderMade’s WebSocket with C++. In the fast-paced financial world, staying updated with live data is essential for making informed decisions. This guide will walk you through the entire process seamlessly.
Getting Started
First, sign up for a TraderMade account and get a free API key for a 2-week trial. This key is your gateway to real-time market data. Once you have it, you’ll use it to authenticate your requests. Reviewing the Streaming Forex API documentation will also help you understand the available data and how to use it effectively.
Setting Up Your Coding Environment
C++ development is more convenient in a Linux environment. You can install the Ubuntu app from the search bar if you're using Windows.
For those new to C++, installing the GCC compiler is essential for running C++ programs. We’ll break everything down into simple steps to make the setup process smooth and efficient.
Let’s dive in and start building!
sudo apt update
If you haven’t set a password or can't remember it, you can reset it using the following command:
sudo passwd
With our system up to date, let's go ahead and install the essential tools for compilation by running the following command:
sudo apt install build-essential
To check the version of GCC you're working with, run the following command:
gcc --version
Now that the C++ compiler is set up, let's import the necessary libraries to run our program.
git clone https://github.com/zaphoyd/websocketpp.git
cd websocketpp
This will fetch the WebSocket++ library directly from its GitHub repository. Additionally, we’ll need to install two more libraries: Boost and SSL. You can do so by running the following commands:
sudo apt-get install libboost-all-dev
sudo apt-get install libssl-dev
Writing Code
Now, let's include the libraries necessary to run our program.
#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>
#include <iostream>
Next, we'll define aliases using typedef for easier reference in our code. The websocketpp is a namespace within the WebSocket++ library. The first line represents a complex type that enables WebSocket client support with Asio (for asynchronous I/O) and TLS (for secure communication).
In the second line, shared_ptr is a smart pointer from the WebSocket++ library that automatically manages memory for the object. The type of object it will manage is specified after the < symbol. context_ptr is an alias that simplifies using the longer type in the second line, making the code more readable and concise.
typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
typedef websocketpp::lib::shared_ptr<websocketpp::lib::asio::ssl::context> context_ptr;
The code below should now be clearer. In the first two lines, _1 and _2 represent the first and second arguments, which are passed to the WebSocket++ function objects and callbacks. The third line defines the bind function, which allows you to create function objects using placeholders.
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
Now that we've defined the placeholders and bound them to callback functions for handling WebSocket events, we'll explain the functions for each event that we might encounter after establishing a connection.
First, we define the on_open callback function, which is triggered when a WebSocket connection is successfully made. It takes two parameters: a handle to the connection (hdl) and a pointer to the WebSocket client (client* c).
The second line of the code is a simple print statement. Following that, we include an error code for error handling and a connection pointer (connection_ptr). The if statement checks for any errors when retrieving the connection pointer. We send a string payload as text over the WebSocket connection if no error is found.
void on_open(websocketpp::connection_hdl hdl, client* c) {
std::cout << "WebSocket connection opened!" << std::endl;
websocketpp::lib::error_code ec;
client::connection_ptr con = c->get_con_from_hdl(hdl, ec);
if (ec) {
std::cout << "Failed to get connection pointer: " << ec.message() << std::endl;
return;
}
std::string payload = "{"userKey":"API_KEY", "symbol":"EURUSD,GBPUSD"}";
c->send(con, payload, websocketpp::frame::opcode::text);
}
Now that we're familiar with the on_open callback function, the next part of the code is easy to grasp. The on_message callback function also takes two parameters; the second is message_ptr msg, which contains the Forex data received. We then print this data inside the on_message function.
The on_fail and on_close callbacks are straightforward and don't require much explanation to proceed to the next section of the code.
void on_message(websocketpp::connection_hdl, client::message_ptr msg) {
std::cout << "Received message: " << msg->get_payload() << std::endl;
}
void on_fail(websocketpp::connection_hdl hdl) {
std::cout << "WebSocket connection failed!" << std::endl;
}
void on_close(websocketpp::connection_hdl hdl) {
std::cout << "WebSocket connection closed!" << std::endl;
}
The next function configures the SSL context for secure communication in the WebSocket client. We won’t delve into the specifics of this function; instead, we’ll jump straight into the main function, where everything integrates.
context_ptr on_tls_init(const char * hostname, websocketpp::connection_hdl) {
context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
try {
ctx->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::single_dh_use);
ctx->set_verify_mode(boost::asio::ssl::verify_none);
} catch (std::exception& e) {
std::cout << "TLS Initialization Error: " << e.what() << std::endl;
}
return ctx;
}
In the main function, we define the client, then specify the URL to connect to the Forex WebSocket and retrieve sub-second data.
int main(int argc, char* argv[]) {
client c;
std::string hostname = "marketdata.tradermade.com/feedadv";
std::string uri = "wss://" + hostname;
}
We set up a try block inside the main function to handle possible exceptions.
int main(int argc, char* argv[]) {
....
try {
} catch (websocketpp::exception const & e) {
std::cout << "WebSocket Exception: " << e.what() << std::endl;
}
}
Within the try block, we begin by configuring the WebSocket++ client and initializing Asio for asynchronous operations. Next, we set up message and event handlers, including the TLS (Transport Layer Security) initialization handler.
We then declare an error object and check for issues while retrieving the connection. Lastly, we create a connection using c.connect(con) and initiate the WebSocket event loop with c.run(), which handles the asynchronous events.
try {
// Configure WebSocket++ client
c.set_access_channels(websocketpp::log::alevel::all);
c.clear_access_channels(websocketpp::log::alevel::frame_payload);
c.set_error_channels(websocketpp::log::elevel::all);
c.init_asio();
// Set message, TLS initialization, open, fail, and close handlers
c.set_message_handler(&on_message);
c.set_tls_init_handler(bind(&on_tls_init, hostname.c_str(), ::_1));
c.set_open_handler(bind(&on_open, ::_1, &c));
c.set_fail_handler(bind(&on_fail, ::_1));
c.set_close_handler(bind(&on_close, ::_1));
// Enable detailed error logging
c.set_error_channels(websocketpp::log::elevel::all);
websocketpp::lib::error_code ec;
client::connection_ptr con = c.get_connection(uri, ec);
if (ec) {
std::cout << "Could not create connection because: " << ec.message() << std::endl;
return 0;
}
// Create a connection to the specified url
c.connect(con);
c.run();
} catch (websocketpp::exception const & e) {
std::cout << "WebSocket Exception: " << e.what() << std::endl;
}
After writing the code, save it in a file named FX_WebSocket.cpp (or any name you prefer). Then, compile the program using the following command:
g++ -o ./streaming_forex FX_WebSocket.cpp -lssl -lcrypto -pthread
Your program should now be compiled into the streaming_forex file. To run the file, use the following command:
./streaming_forex
Voila! You should now see a WebSocket connection with your subscribed Forex data. Remember to replace your API key when sending the payload using the on_open function.
Output
Great! Our output is ready.
Received message: Connected
Received message: {"symbol":"GBPUSD","ts":"1708403061263","bid":1.25867,"ask":1.25871,"mid" :1.25869}
Received message: {"symbol":"GBPUSD","ts":"1708403070164","bid":1.25867,"ask":1.2587,"mid":1.258685}
Received message: {"symbol":"GBPUSD","ts":"1708403070951","bid":1.25866,"ask":1.2587,"mid":1.25868}
Received message: {"symbol":"GBPUSD","ts":"1708403071022","bid":1.25866,"ask":1.25871,"mid":1.258685}
Received message: {"symbol":"GBPUSD","ts":"1708403071213","bid":1.25866,"ask":1.2587,"mid":1.25868}
Received message: {"symbol":"GBPUSD","ts":"1708403071400","bid":1.25866,"ask":1.25869,"mid":1.258675}
Received message: {"symbol":"EURUSD","ts":"1708403071512","bid":1.07687,"ask":1.07691,"mid":1.07689}
Received message: {"symbol":"EURUSD","ts":"1708403071524","bid":1.07687,"ask":1.0769,"mid":1.076885}
Received message: {"symbol":"GBPUSD","ts":"1708403072138","bid":1.25866,"ask":1.2587,"mid":1.25868}
Received message: {"symbol":"GBPUSD","ts":"1708403074548","bid":1.25866,"ask":1.25869,"mid":1.258675}
Received message: {"symbol":"GBPUSD","ts":"1708403074618","bid":1.25866,"ask":1.2587,"mid":1.25868}
Received message: {"symbol":"GBPUSD","ts":"1708403074921","bid":1.25866,"ask":1.25869,"mid":1.258675}
Received message: {"symbol":"GBPUSD","ts":"1708403075348","bid":1.25866,"ask":1.2587,"mid":1.25868}
Received message: {"symbol":"GBPUSD","ts":"1708403077083","bid":1.25866,"ask":1.25869,"mid":1.258675}
Congratulations! You've successfully built a real-time Forex data fetcher using C++ and WebSocket++. Feel free to explore and adjust the code to suit your needs, and enjoy access to live financial data at your fingertips.
Full Code
Below is the complete code:
#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>
#include <iostream>
typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
typedef websocketpp::lib::shared_ptr<websocketpp::lib::asio::ssl::context> context_ptr;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
void on_open(websocketpp::connection_hdl hdl, client* c) {
std::cout << "WebSocket connection opened!" << std::endl;
websocketpp::lib::error_code ec;
client::connection_ptr con = c->get_con_from_hdl(hdl, ec);
if (ec) {
std::cout << "Failed to get connection pointer: " << ec.message() << std::endl;
return;
}
std::string payload = "{"userKey":"API_KEY", "symbol":"EURUSD,GBPUSD"}";
c->send(con, payload, websocketpp::frame::opcode::text);
}
void on_message(websocketpp::connection_hdl, client::message_ptr msg) {
std::cout << "Received message: " << msg->get_payload() << std::endl;
}
void on_fail(websocketpp::connection_hdl hdl) {
std::cout << "WebSocket connection failed!" << std::endl;
}
void on_close(websocketpp::connection_hdl hdl) {
std::cout << "WebSocket connection closed!" << std::endl;
}
context_ptr on_tls_init(const char * hostname, websocketpp::connection_hdl) {
context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
try {
ctx->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::single_dh_use);
} catch (std::exception& e) {
std::cout << "TLS Initialization Error: " << e.what() << std::endl;
}
return ctx;
}
int main(int argc, char* argv[]) {
client c;
std::string hostname = "marketdata.tradermade.com/feedadv";
std::string uri = "wss://" + hostname;
try {
c.set_access_channels(websocketpp::log::alevel::all);
c.clear_access_channels(websocketpp::log::alevel::frame_payload);
c.set_error_channels(websocketpp::log::elevel::all);
c.init_asio();
c.set_message_handler(&on_message);
c.set_tls_init_handler(bind(&on_tls_init, hostname.c_str(), ::_1));
c.set_open_handler(bind(&on_open, ::_1, &c));
c.set_fail_handler(bind(&on_fail, ::_1));
c.set_close_handler(bind(&on_close, ::_1));
c.set_error_channels(websocketpp::log::elevel::all); // Enable detailed error logging
websocketpp::lib::error_code ec;
client::connection_ptr con = c.get_connection(uri, ec);
if (ec) {
std::cout << "Could not create connection because: " << ec.message() << std::endl;
return 0;
}
c.connect(con);
c.run();
} catch (websocketpp::exception const & e) {
std::cout << "WebSocket Exception: " << e.what() << std::endl;
}
}
Next Steps
TraderMade’s Live Streaming API is an easy-to-use and powerful resource for building digital solutions and gaining valuable insights. You can use it in C++ to create impressive applications, and we’d love to see what you make!
Register and explore the details in the Live Streaming API documentation to get started. If you need any help, feel free to reach out via live chat or email us at support@tradermade.com. We're here to help you on your development journey.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.