I’ve been trying to make an algorithmic trading backtester and it ran with no errors. My only problem is that it doesn’t render any of the chart and widgets which I programmed into the mainwindow files. It only shows a white blank screen. Keep note, I included all the necessary libraries in mainwindow.h.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "backtester.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, m_initialCapital(0.0)
, m_chart(new QChart())
, m_chartView(new QChartView(m_chart))
, m_candlestickSeries(new QCandlestickSeries())
, m_shortTermMASeries(new QLineSeries())
, m_longTermMASeries(new QLineSeries())
, m_buySignals(new QScatterSeries())
, m_sellSignals(new QScatterSeries())
, m_holdSignals(new QScatterSeries())
{
ui->setupUi(this);
connect(ui->startButton, &QPushButton::clicked, this, &MainWindow::on_runBacktestButton_clicked);
connect(ui->initialCapitalLineEdit, &QDoubleSpinBox::valueChanged, this, &MainWindow::on_initialCapitalChanged);
connect(ui->startDateEdit, &QDateEdit::dateChanged, this, &MainWindow::on_startDateChanged);
connect(ui->endDateEdit, &QDateEdit::dateChanged, this, &MainWindow::on_endDateChanged);
setCentralWidget(m_chartView);
m_chartView->setParent(ui->widget);
m_chart->setTitle("Backtest Results");
m_chart->setAnimationOptions(QChart::SeriesAnimations);
setupChart();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setupChart()
{
m_candlestickSeries->setName("Candlesticks");
m_candlestickSeries->setIncreasingColor(QColor(Qt::green));
m_candlestickSeries->setDecreasingColor(QColor(Qt::red));
m_shortTermMASeries->setName("Short-term MA");
m_longTermMASeries->setName("Long-term MA");
m_buySignals->setName("Buy Signals");
m_buySignals->setMarkerShape(QScatterSeries::MarkerShapeCircle);
m_buySignals->setMarkerSize(10.0);
m_buySignals->setColor(Qt::green);
m_sellSignals->setName("Sell Signals");
m_sellSignals->setMarkerShape(QScatterSeries::MarkerShapeCircle);
m_sellSignals->setMarkerSize(10.0);
m_sellSignals->setColor(Qt::red);
m_holdSignals->setName("Hold Signals");
m_holdSignals->setMarkerShape(QScatterSeries::MarkerShapeCircle);
m_holdSignals->setMarkerSize(10.0);
m_holdSignals->setColor(Qt::blue);
m_chart->addSeries(m_candlestickSeries);
m_chart->addSeries(m_shortTermMASeries);
m_chart->addSeries(m_longTermMASeries);
m_chart->addSeries(m_buySignals);
m_chart->addSeries(m_sellSignals);
m_chart->addSeries(m_holdSignals);
QValueAxis* axisX = new QValueAxis;
QValueAxis* axisY = new QValueAxis;
m_chart->addAxis(axisX, Qt::AlignBottom);
m_chart->addAxis(axisY, Qt::AlignLeft);
m_candlestickSeries->attachAxis(axisX);
m_candlestickSeries->attachAxis(axisY);
m_shortTermMASeries->attachAxis(axisX);
m_shortTermMASeries->attachAxis(axisY);
m_longTermMASeries->attachAxis(axisX);
m_longTermMASeries->attachAxis(axisY);
m_buySignals->attachAxis(axisX);
m_buySignals->attachAxis(axisY);
m_sellSignals->attachAxis(axisX);
m_sellSignals->attachAxis(axisY);
m_holdSignals->attachAxis(axisX);
m_holdSignals->attachAxis(axisY);
}
void MainWindow::on_runBacktestButton_clicked()
{
// get user input from UI elements
double initialCapital = m_initialCapital;
QString startDateStr = m_startDate.toString("yyyy-MM-dd");
QString endDateStr = m_endDate.toString("yyyy-MM-dd");
std::string startDateStdStr = startDateStr.toStdString();
std::string endDateStdStr = endDateStr.toStdString();
// set the initial capital and date range in the Backtester
m_backtester->setInitialCapital(initialCapital);
m_backtester->setStartDate(startDateStdStr);
m_backtester->setEndDate(endDateStdStr);
m_backtester->loadDataFromCSV("C:\Users\maria\Downloads\historical_data.csv");
m_backtester->run();
updateUI(*m_backtester);
}
void MainWindow::on_initialCapitalChanged(double value)
{
m_initialCapital = value;
}
void MainWindow::on_startDateChanged(const QDate& date)
{
m_startDate = date;
}
void MainWindow::on_endDateChanged(const QDate& date)
{
m_endDate = date;
}
void MainWindow::updateUI(Backtester& backtester)
{
// update ui elements with the backtest results
ui->totalReturnLabel->setText(QString::number(backtester.calculateTotalReturn(), 'f', 2) + "%");
ui->annualizedReturnLabel->setText(QString::number(backtester.getAnnualizedReturn(), 'f', 2) + "%");
ui->sharpeRatioLabel->setText(QString::number(backtester.getSharpeRatio(), 'f', 2));
// load chart data
loadChartData();
plotMovingAverages();
plotSignals(m_strategy->getCandlestickData());
}
void MainWindow::loadChartData()
{
m_candlestickSeries->clear();
auto candlestickData = m_strategy->getCandlestickData();
for (const auto& data : candlestickData)
{
QCandlestickSet* set = new QCandlestickSet();
set->setOpen(data->open());
set->setHigh(data->high());
set->setLow(data->low());
set->setClose(data->close());
set->setTimestamp(data->timestamp());
m_candlestickSeries->append(set);
}
}
void MainWindow::plotMovingAverages()
{
m_shortTermMASeries->clear();
m_longTermMASeries->clear();
auto candlestickData = m_strategy->getCandlestickData();
for (size_t i = 0; i < candlestickData.size(); ++i)
{
double shortTermMA = m_strategy->calculateMovingAverage(5, i); // Example for short-term MA
double longTermMA = m_strategy->calculateMovingAverage(20, i); // Example for long-term MA
m_shortTermMASeries->append(candlestickData[i]->timestamp(), shortTermMA);
m_longTermMASeries->append(candlestickData[i]->timestamp(), longTermMA);
}
}
void MainWindow::plotSignals(const std::vector<CustomCandlestickSet*>& candlestickData)
{
m_buySignals->clear();
m_sellSignals->clear();
m_holdSignals->clear();
// loop through signals and add them to the respective series
for (const auto& sig : m_strategy->getSignals())
{
time_t timestamp = sig.timeStamp_;
bool buySignal = sig.buy_;
bool sellSignal = sig.sell_;
bool holdSignal = sig.hold_;
// find the corresponding candlestick set based on the timestamp
auto it = std::find_if(candlestickData.begin(), candlestickData.end(), [timestamp](const CustomCandlestickSet* set) {
return set->timestamp() == timestamp;
});
if (it != candlestickData.end())
{
// depending on the type of signal, add it to the appropriate series
if (buySignal)
{
m_buySignals->append(static_cast<qreal>(timestamp), (*it)->low());
}
else if (sellSignal)
{
m_sellSignals->append(static_cast<qreal>(timestamp), (*it)->high());
}
else if (holdSignal)
{
m_sellSignals->append(static_cast<qreal>(timestamp), (*it)->close());
}
}
}
}
Most of the code in the mainwindow files are that of the QChartView. I wanted to make a chart that simulates trades. For more details:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "backtester.h"
#include <QMainWindow>
#include <QDate>
#include <QString>
#include <QDebug>
#include <QtCharts/QScatterSeries>
#include <QtCharts/QCandlestickSet>
#include <QtCharts/QLineSeries>
#include <QtCharts/QValueAxis>
#include <QtCharts/QChart>
#include <QCandlestickSeries>
#include <QChartView>
#include <memory>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void updateUI(Backtester& backtester);
void setupChart();
void loadChartData();
void plotMovingAverages();
void plotSignals(const std::vector<CustomCandlestickSet*>& candlestickData);
private slots:
void on_runBacktestButton_clicked();
void on_initialCapitalChanged(double value);
void on_startDateChanged(const QDate& date);
void on_endDateChanged(const QDate& date);
private:
Ui::MainWindow *ui;
std::unique_ptr<Backtester> m_backtester;
std::unique_ptr<Strategy> m_strategy;
double m_initialCapital;
QDate m_startDate;
QDate m_endDate;
QChart* m_chart;
QChartView* m_chartView;
QCandlestickSeries* m_candlestickSeries;
QLineSeries* m_shortTermMASeries;
QLineSeries* m_longTermMASeries;
QScatterSeries* m_buySignals;
QScatterSeries* m_sellSignals;
QScatterSeries* m_holdSignals;
};
#endif // MAINWINDOW_H