Skip to content

Commit d759344

Browse files
committed
Refactoring the QuestDB/Postgres flow
1 parent a903259 commit d759344

File tree

6 files changed

+105
-37
lines changed

6 files changed

+105
-37
lines changed

backtesting-engine-cpp.xcodeproj/project.pbxproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
941B549C2D3BBFB900E3BF64 /* trading_definitions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = trading_definitions.hpp; sourceTree = "<group>"; };
5454
94280BA12D2FC00200F1CF56 /* base64.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = base64.hpp; sourceTree = "<group>"; };
5555
94280BA22D2FC00200F1CF56 /* base64.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = base64.cpp; sourceTree = "<group>"; };
56+
942966D82D48E84A00532862 /* priceData.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = priceData.hpp; sourceTree = "<group>"; };
5657
94364CB52D416D8000F35B55 /* db.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = db.mm; sourceTree = "<group>"; };
5758
944D0DC82C8C3704004DD0FC /* LICENSE.MD */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.MD; sourceTree = "<group>"; };
5859
944D0DC92C8C3704004DD0FC /* build.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = build.sh; sourceTree = "<group>"; };
@@ -1285,6 +1286,14 @@
12851286
path = utilities;
12861287
sourceTree = "<group>";
12871288
};
1289+
942966D72D48E84100532862 /* models */ = {
1290+
isa = PBXGroup;
1291+
children = (
1292+
942966D82D48E84A00532862 /* priceData.hpp */,
1293+
);
1294+
path = models;
1295+
sourceTree = "<group>";
1296+
};
12881297
944D0DB52C8C36C0004DD0FC = {
12891298
isa = PBXGroup;
12901299
children = (
@@ -3455,6 +3464,7 @@
34553464
94DE4F772C8C3E7C00FE48FF /* include */ = {
34563465
isa = PBXGroup;
34573466
children = (
3467+
942966D72D48E84100532862 /* models */,
34583468
94B8C7932D3D770800E17EB6 /* utilities */,
34593469
941B548F2D3BBA3B00E3BF64 /* trading_definitions */,
34603470
941B549C2D3BBFB900E3BF64 /* trading_definitions.hpp */,

source/databaseConnection.cpp

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// ---------------------------------------
66

77
#include "databaseConnection.hpp"
8+
#include "base64.hpp"
89
#include <pqxx/pqxx>
910

1011
DatabaseConnection::DatabaseConnection(const std::string& endpoint, int port,
@@ -20,41 +21,53 @@ DatabaseConnection::DatabaseConnection(const std::string& endpoint, int port,
2021

2122
}
2223

23-
void DatabaseConnection::executeQuery(const std::string& query) const {
24-
try {
25-
// Establish connection
26-
pqxx::connection conn(this->connection_string);
27-
28-
// Rest of your code remains the same
29-
if (!conn.is_open()) {
30-
throw std::invalid_argument("Failed to open database connection");
31-
}
32-
33-
std::cout << "Connected to database successfully!" << std::endl;
34-
35-
// Create a transaction
36-
pqxx::work txn(conn);
37-
38-
// Execute query
39-
pqxx::result result = txn.exec(query);
40-
41-
// Print results
42-
for (const auto& row : result) {
43-
for (const auto& field : row) {
44-
std::cout << field.c_str() << "\t";
45-
}
46-
std::cout << std::endl;
47-
}
48-
49-
// Commit transaction
50-
txn.commit();
51-
52-
} catch (const pqxx::broken_connection& e) {
53-
std::cerr << "Connection error: " << e.what() << std::endl;
54-
} catch (const pqxx::sql_error& e) {
55-
std::cerr << "SQL error: " << e.what() << std::endl;
56-
std::cerr << "Query was: " << e.query() << std::endl;
57-
} catch (const pqxx::usage_error& e) {
58-
std::cerr << "Usage error: " << e.what() << std::endl;
24+
std::vector<PriceData> DatabaseConnection::executeQuery(const std::string& query) const {
25+
std::vector<PriceData> results;
26+
27+
try {
28+
pqxx::connection conn(this->connection_string);
29+
30+
if (!conn.is_open()) {
31+
throw std::invalid_argument("Failed to open database connection");
32+
}
33+
34+
std::cout << "Connected to database successfully!" << std::endl;
35+
36+
pqxx::work txn(conn);
37+
pqxx::result result = txn.exec(query);
38+
39+
// Convert results to PriceData objects
40+
for (const auto& row : result) {
41+
double value1 = row[0].as<double>();
42+
double value2 = row[1].as<double>();
43+
std::string timestamp_str = row[2].as<std::string>();
44+
45+
auto timestamp = Utilities::parseTimestamp(timestamp_str);
46+
47+
results.emplace_back(value1, value2, timestamp);
48+
}
49+
50+
txn.commit();
51+
52+
} catch (const std::exception& e) {
53+
std::cerr << "Error: " << e.what() << std::endl;
54+
}
55+
56+
return results;
57+
}
58+
59+
// Example usage function to demonstrate how to work with the results
60+
void DatabaseConnection::printResults(const std::vector<PriceData>& results) const {
61+
for (const auto& data : results) {
62+
// Convert timestamp back to string for display
63+
auto time_t = std::chrono::system_clock::to_time_t(data.timestamp);
64+
auto tm = *std::localtime(&time_t);
65+
std::stringstream ss;
66+
ss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
67+
68+
std::cout << std::fixed << std::setprecision(4)
69+
<< data.value1 << "\t"
70+
<< data.value2 << "\t"
71+
<< ss.str() << std::endl;
5972
}
6073
}

source/include/databaseConnection.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#pragma once
77
#include <iostream>
88
#include <pqxx/pqxx>
9+
#include "models/priceData.hpp"
910

1011
class DatabaseConnection {
1112
private:
@@ -18,7 +19,8 @@ class DatabaseConnection {
1819
const std::string& user = "admin",
1920
const std::string& password = "");
2021

21-
void executeQuery(const std::string& query) const;
22+
void printResults(const std::vector<PriceData>& results) const;
23+
std::vector<PriceData> executeQuery(const std::string& query) const;
2224

2325
const std::string& getConnectionString() const {
2426
return connection_string;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Backtesting Engine in C++
2+
//
3+
// (c) 2025 Ryan McCaffery | https://mccaffers.com
4+
// This code is licensed under MIT license (see LICENSE.txt for details)
5+
// ---------------------------------------
6+
#pragma once
7+
8+
struct PriceData {
9+
double value1;
10+
double value2;
11+
std::chrono::system_clock::time_point timestamp;
12+
13+
// Constructor for easy creation
14+
PriceData(double v1, double v2, const std::chrono::system_clock::time_point& ts)
15+
: value1(v1), value2(v2), timestamp(ts) {}
16+
};

source/include/utilities/base64.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,9 @@ class Base64 {
2020
static bool isValidBase64(const std::string& input);
2121
static std::string checkInput(const std::string& base64_input);
2222
};
23+
24+
class Utilities {
25+
public:
26+
static std::chrono::system_clock::time_point parseTimestamp(const std::string& ts);
27+
};
28+

source/utilities/base64.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
// This code is licensed under MIT license (see LICENSE.txt for details)
55
// ---------------------------------------
66

7+
#include <iomanip> // Add this header for std::get_time
8+
#include <sstream>
9+
#include <chrono>
710
#include "base64.hpp"
811

912
static const char* const B64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -111,3 +114,21 @@ bool Base64::isValidBase64(const std::string& input) {
111114
return strchr(valid, c) != nullptr;
112115
});
113116
}
117+
118+
std::chrono::system_clock::time_point Utilities::parseTimestamp(const std::string& ts) {
119+
std::tm tm = {};
120+
std::istringstream ss(ts);
121+
ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
122+
123+
auto timePoint = std::chrono::system_clock::from_time_t(std::mktime(&tm));
124+
125+
// Parse milliseconds if present
126+
if (ss.peek() == '.') {
127+
ss.ignore(); // Skip the dot
128+
int milliseconds;
129+
ss >> milliseconds;
130+
timePoint += std::chrono::milliseconds(milliseconds / 1000); // Convert microseconds to milliseconds
131+
}
132+
133+
return timePoint;
134+
}

0 commit comments

Comments
 (0)