Implementing MACD strategy using Qt/C++ using Zerodha API and deploying in AWS for High Frequency Trading.
Manish Chakravarty
Senior Project Manager @ Blue Yonder | Retail Replenishment, Data Engineering, Project Management, Hands-on development
Overview
In this article we will:
Why Qt and C++ are Ideal for High-Frequency Trading Over Python
High-frequency trading (HFT) is a demanding segment of the financial market where transactions are executed within microseconds. The choice of programming language and framework is critical for achieving optimal performance. In this post, we'll explore why Qt and C++ are preferred over Python for HFT, explain the Moving Average Convergence Divergence (MACD) indicator, and provide an example of implementing a MACD trading strategy using C++. We'll also discuss the benefits of deploying this setup on AWS to minimize latency.
Why Choose Qt and C++ for High-Frequency Trading?
Understanding MACD
The Moving Average Convergence Divergence (MACD) is a widely used technical analysis tool for identifying trends in stock prices. It consists of three main components:
A basic MACD trading strategy involves:
Implementing MACD Strategy in Qt/C++
Below is an example of a MACD strategy for trading NIFTY futures using Zerodha's REST API in Qt/C++.
Understanding the Methods in Our High-Frequency Trading (HFT) Application
In our HFT application using Qt and C++, we've implemented a MACD (Moving Average Convergence Divergence) trading strategy for NIFTY futures using Zerodha's REST API. Let's dive into each method used in our?ZerodhaTraderclass to understand their roles and functionality.
1.?Constructor:?ZerodhaTrader
The constructor initializes the?ZerodhaTrader?object with the API key and access token required for authentication with Zerodha's REST API.
Functionality:
领英推荐
ZerodhaTrader(const QString &apiKey, const QString &accessToken, QObject *parent = nullptr)
: QObject(parent), apiKey(apiKey), accessToken(accessToken) {
manager = new QNetworkAccessManager(this);
}
2.?Method:?fetchHistoricalData
This method fetches historical price data for a specified instrument and date range from Zerodha's API.
Functionality:
void fetchHistoricalData(const QString &instrumentToken, const QString &fromDate, const QString &toDate) {
QUrl url("https://api.kite.trade/instruments/historical/" + instrumentToken + "/minute");
QUrlQuery query;
query.addQueryItem("from", fromDate);
query.addQueryItem("to", toDate);
url.setQuery(query);
QNetworkRequest request(url);
request.setRawHeader("X-Kite-Version", "3");
request.setRawHeader("Authorization", "token " + apiKey + ":" + accessToken);
QNetworkReply *reply = manager->get(request);
connect(reply, &QNetworkReply::finished, this, &ZerodhaTrader::onHistoricalDataFetched);
}
3. Slot:?onHistoricalDataFetched()
This slot is called when the historical data fetch request is completed.
void onHistoricalDataFetched() {
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (reply->error() == QNetworkReply::NoError) {
QByteArray response = reply->readAll();
QJsonDocument jsonDoc = QJsonDocument::fromJson(response);
QJsonObject jsonObj = jsonDoc.object();
QJsonArray data = jsonObj["data"].toArray();
QVector<double> closePrices;
for (const QJsonValue &value : data) {
closePrices.append(value.toObject()["close"].toDouble());
}
calculateMACD(closePrices);
} else {
qWarning() << "Error fetching historical data:" << reply->errorString();
}
reply->deleteLater();
}
4.?Method:?calculateMACD
Functionality:
void calculateMACD(const QVector<double> &prices) {
int shortWindow = 12;
int longWindow = 26;
int signalWindow = 9;
QVector<double> macdLine;
QVector<double> signalLine;
QVector<double> macdHistogram;
for (int i = 0; i < prices.size(); ++i) {
if (i >= longWindow - 1) {
double shortEma = calculateEMA(prices, i - shortWindow + 1, i, shortWindow);
double longEma = calculateEMA(prices, i - longWindow + 1, i, longWindow);
macdLine.append(shortEma - longEma);
if (i >= longWindow + signalWindow - 2) {
double signalEma = calculateEMA(macdLine, i - signalWindow + 1, i, signalWindow);
signalLine.append(signalEma);
macdHistogram.append(macdLine[i] - signalLine.last());
if (macdHistogram.last() > 0 && macdHistogram[macdHistogram.size() - 2] <= 0) {
qDebug() << "Buy signal at index" << i;
} else if (macdHistogram.last() < 0 && macdHistogram[macdHistogram.size() - 2] >= 0) {
qDebug() << "Sell signal at index" << i;
}
}
}
}
}
5. Helper Method:?calculateEMA
Functionality:
double calculateEMA(const QVector<double> &data, int start, int end, int window) {
double multiplier = 2.0 / (window + 1);
double ema = data[start];
for (int i = start + 1; i <= end; ++i) {
ema = ((data[i] - ema) * multiplier) + ema;
}
return ema;
}
Deploying on AWS to Minimize Latency
Deploying your HFT system on AWS can significantly reduce latency, enhancing the performance of your trading algorithms. Here's a step-by-step guide to deploying your Qt/C++ application on AWS:
By leveraging Qt and C++ for your HFT system, you gain the performance and control necessary for executing trades swiftly and efficiently. Deploying this setup on AWS further enhances your system’s performance by reducing latency and providing a robust, scalable infrastructure.
Computing Engineering and Mathematics Undergrad | Ex- Chegg Expert | Problem Solver | Django Developer | DU'25
3 个月This article is very interesting bcz in this article Manish Chakravarty discuss how to build a High Frequency Trading application written using the Qt/C++ cross-platform framework and with using Zerodha's Kite API and discuss why it is a better choice over a python based stack to use case and implementation of the MACD strategy in Qt/C++ and discuss how to deployment on AWS. Keep posting Manish Chakravarty ????????
Qt | QML | C++ | Scripting | Unity | Software Engineer
6 个月That's amazing ??
Engineering Consultant || Full Stack Lead Developer || ex-DXC || ex-CGI Inc || Certified SAFe 5 Practitioner Engineering
7 个月Interesting!
Embedded C | C++ STL | Qt/QML | Bash | Device Drivers | e-linux |
9 个月Very Interesting!Manish Chakravarty