Skip to content

Commit b70e5dc

Browse files
authored
added redis headers and scafolding (#36)
* added redis headers and scafolding * fixed xcode project references * Updated payloads and scripts to support busybox approach * Updated readme * fix build workflow, sonar scanning needed boost and ssl dependencies * Silenced dependency warnings and updated boost version on ubuntu for sonar cloud scanning
1 parent e5a82f6 commit b70e5dc

19 files changed

Lines changed: 657 additions & 55 deletions

File tree

.github/workflows/build.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,21 @@ jobs:
7878
uses: actions/checkout@v5
7979
with:
8080
fetch-depth: 0
81+
- name: Install dependencies
82+
run: sudo apt install -y libssl-dev libpq-dev
83+
# Ubuntu's apt Boost (1.83 on 24.04) predates Boost.Redis, which was added
84+
# in Boost 1.84, so <boost/redis.hpp> is absent. Install a newer Boost.
85+
# Boost.Redis/Asio are header-only, so we only need the headers plus the
86+
# CMake package config — building just Boost.System generates both quickly.
87+
- name: Install Boost >= 1.84 (for Boost.Redis)
88+
run: |
89+
BOOST_VERSION=1.86.0
90+
BOOST_DIR="boost_${BOOST_VERSION//./_}"
91+
wget -q "https://archives.boost.io/release/${BOOST_VERSION}/source/${BOOST_DIR}.tar.gz"
92+
tar xzf "${BOOST_DIR}.tar.gz"
93+
cd "${BOOST_DIR}"
94+
./bootstrap.sh
95+
sudo ./b2 install --prefix=/usr/local --with-system -j"$(nproc)"
8196
- name: Check compiler version, for debugging
8297
run: |
8398
g++ --version

.github/workflows/scripts/brew.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ check_and_install() {
1212

1313
# Install packages if they don't exist
1414
check_and_install postgresql@18 # Check and install PostgreSQL (which includes libpq)
15-
check_and_install pkg-config # Check and install pkg-config
15+
check_and_install pkg-config # Check and install pkg-config
16+
check_and_install boost # Check and install pkg-config

CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,19 @@ if(APPLE)
6262
target_include_directories(BacktestingEngineLib PRIVATE /opt/homebrew/opt/libomp/include)
6363
endif()
6464

65+
# Boost (Homebrew) — Boost.Redis is header-only but its implementation is
66+
# compiled into one TU via <boost/redis/src.hpp> (included in
67+
# source/redisRunner.cpp). It pulls in Boost.Asio's SSL layer, which needs
68+
# OpenSSL.
69+
find_package(Boost REQUIRED CONFIG)
70+
find_package(OpenSSL REQUIRED)
71+
find_package(Threads REQUIRED)
72+
target_link_libraries(BacktestingEngineLib PUBLIC
73+
Boost::headers
74+
OpenSSL::SSL
75+
OpenSSL::Crypto
76+
Threads::Threads)
77+
6578
add_subdirectory(external/boost-decimal)
6679
target_link_libraries(BacktestingEngineLib PUBLIC Boost::decimal)
6780

README.md

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ I'm extracting results and creating various graphs for trend analyses using SciP
1414

1515
![alt text](documents/images/random-indices-sp500-variable.svg)
1616

17-
*Read more results on https://mccaffers.com/randomly_trading/*
17+
*Read more results on https://mccaffers.com/quantitative_analysis/randomly_trading/*
1818

1919
## Setup
2020

21-
This backtesting engine can pull tick data from local files or from a Postgres database. I'm using QuestDB.
21+
This backtesting engine can pull tick data from local files or from a Postgres database (I'm using QuestDB). Strategy execution is dispatched via a Redis list called `strategy_queue`, with each entry a Base64-encoded JSON payload, the `load` subcommand enqueues strategies (LPUSH) and the `run` subcommand dequeues and executes them (RPOP). The default workflow expects a local `redis-server` listening on `127.0.0.1:6379`.
2222

2323
### Clone with submodules
2424

@@ -40,9 +40,22 @@ For OpenSuse: zypper in postgresql-devel
4040
For ArchLinux: pacman -S postgresql-libs
4141
```
4242

43+
### Install Boost, OpenSSL, and Redis
44+
45+
Boost.Redis is header-only but its single translation unit (compiled via `<boost/redis/src.hpp>` from `source/redisRunner.cpp`) pulls in Boost.Asio's SSL layer, so OpenSSL is a transitive requirement. A local `redis-server` on `127.0.0.1:6379` is also needed for the default `load`/`run` workflow.
46+
47+
```
48+
For Mac Homebrew: brew install boost openssl redis
49+
For Ubuntu/Debian systems: sudo apt-get install libboost-all-dev libssl-dev redis-server
50+
```
51+
52+
The canonical CI prerequisite list lives in `.github/workflows/scripts/brew.sh` (`postgresql`, `pkg-config`, `boost`).
53+
54+
![alt text](documents/flow.png)
55+
4356
### Build dependencies
4457

45-
`libpqxx` is built once via CMake. `boost-decimal` is header-only and pulled in via `add_subdirectory` from the top-level `CMakeLists.txt` nothing to build. The script below handles the libpqxx build:
58+
`libpqxx` is built once via CMake. `boost-decimal` is header-only and pulled in via `add_subdirectory` from the top-level `CMakeLists.txt`, nothing to build. The script below handles the libpqxx build:
4659

4760
```
4861
bash ./scripts/build_dep.sh
@@ -76,15 +89,36 @@ Xcode - Library Path
7689

7790
### Run via terminal
7891

79-
`bash ./scripts/run.sh`
92+
`bash ./scripts/run.sh` builds the project, then, if `redis-cli ping` reaches a local Redis, enqueues an inline JSON strategy via `load` and executes it via `run localhost`. If Redis is unreachable the script prints a message and exits cleanly (see `scripts/run.sh:22-25`), so first-time users without Redis still get a clear signal.
93+
94+
The `BacktestingEngine` binary exposes a subcommand CLI:
95+
96+
```
97+
BacktestingEngine load <path> [path...]
98+
Read each file as raw JSON, Base64-encode it, and LPUSH onto the Redis
99+
`strategy_queue` list.
100+
101+
BacktestingEngine run <questdb-host>
102+
RPOP one Base64-encoded strategy from `strategy_queue` and execute it
103+
against the supplied QuestDB host.
104+
105+
BacktestingEngine run <questdb-host> <base64-config>
106+
Decode the supplied Base64 strategy and execute it directly, bypassing
107+
Redis.
108+
109+
BacktestingEngine -h | --help
110+
Show usage.
111+
```
112+
113+
Defaults are `127.0.0.1:6379` for the Redis endpoint and `strategy_queue` for the list key (see `include/redisRunner.hpp` and `include/redisLoader.hpp`).
80114

81115
### Run tests via terminal
82116

83117
`bash ./scripts/test.sh`
84118

85119
### Contributing
86120

87-
This is an active solo experiment, so I'm not accepting pull requests right now but please fork freely and use [GitHub Issues](https://github.com/mccaffers/backtesting-engine-cpp/issues) for bugs, questions, and ideas. See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
121+
This is an active solo experiment, so I'm not accepting pull requests right now, but please fork freely and use [GitHub Issues](https://github.com/mccaffers/backtesting-engine-cpp/issues) for bugs, questions, and ideas. See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
88122

89123
### License
90124
[MIT](https://choosealicense.com/licenses/mit/)

backtesting-engine-cpp.xcodeproj/project.pbxproj

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@
1717
941B549B2D3BBADE00E3BF64 /* trading_definitions_json.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 941B54992D3BBADD00E3BF64 /* trading_definitions_json.cpp */; };
1818
94280BA32D2FC00200F1CF56 /* base64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94280BA22D2FC00200F1CF56 /* base64.cpp */; };
1919
94280BA42D2FC00200F1CF56 /* base64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94280BA22D2FC00200F1CF56 /* base64.cpp */; };
20+
942EC5622FBEF94700CCBB5D /* redisConnection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 942EC5612FBEF94700CCBB5D /* redisConnection.cpp */; };
21+
942EC5632FBEF94700CCBB5D /* redisConnection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 942EC5612FBEF94700CCBB5D /* redisConnection.cpp */; };
22+
942EC5672FBEF95000CCBB5D /* backtestRunner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 942EC5642FBEF95000CCBB5D /* backtestRunner.cpp */; };
23+
942EC5682FBEF95000CCBB5D /* redisLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 942EC5652FBEF95000CCBB5D /* redisLoader.cpp */; };
24+
942EC5692FBEF95000CCBB5D /* redisRunner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 942EC5662FBEF95000CCBB5D /* redisRunner.cpp */; };
25+
942EC56A2FBEF95000CCBB5D /* backtestRunner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 942EC5642FBEF95000CCBB5D /* backtestRunner.cpp */; };
26+
942EC56B2FBEF95000CCBB5D /* redisLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 942EC5652FBEF95000CCBB5D /* redisLoader.cpp */; };
27+
942EC56C2FBEF95000CCBB5D /* redisRunner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 942EC5662FBEF95000CCBB5D /* redisRunner.cpp */; };
2028
943398242D57E53400287A2D /* jsonParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 943398232D57E53400287A2D /* jsonParser.cpp */; };
2129
943398252D57E53400287A2D /* jsonParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 943398232D57E53400287A2D /* jsonParser.cpp */; };
2230
943398272D57E54000287A2D /* jsonParser.mm in Sources */ = {isa = PBXBuildFile; fileRef = 943398262D57E54000287A2D /* jsonParser.mm */; };
@@ -70,6 +78,14 @@
7078
94280BA12D2FC00200F1CF56 /* base64.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = base64.hpp; sourceTree = "<group>"; };
7179
94280BA22D2FC00200F1CF56 /* base64.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = base64.cpp; sourceTree = "<group>"; };
7280
942966D82D48E84A00532862 /* priceData.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = priceData.hpp; sourceTree = "<group>"; };
81+
942EC55D2FBEF92F00CCBB5D /* redisConnection.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = redisConnection.hpp; sourceTree = "<group>"; };
82+
942EC55E2FBEF93A00CCBB5D /* backtestRunner.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = backtestRunner.hpp; sourceTree = "<group>"; };
83+
942EC55F2FBEF93A00CCBB5D /* redisLoader.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = redisLoader.hpp; sourceTree = "<group>"; };
84+
942EC5602FBEF93A00CCBB5D /* redisRunner.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = redisRunner.hpp; sourceTree = "<group>"; };
85+
942EC5612FBEF94700CCBB5D /* redisConnection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = redisConnection.cpp; sourceTree = "<group>"; };
86+
942EC5642FBEF95000CCBB5D /* backtestRunner.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = backtestRunner.cpp; sourceTree = "<group>"; };
87+
942EC5652FBEF95000CCBB5D /* redisLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = redisLoader.cpp; sourceTree = "<group>"; };
88+
942EC5662FBEF95000CCBB5D /* redisRunner.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = redisRunner.cpp; sourceTree = "<group>"; };
7389
943398222D57E52900287A2D /* jsonParser.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = jsonParser.hpp; sourceTree = "<group>"; };
7490
943398232D57E53400287A2D /* jsonParser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = jsonParser.cpp; sourceTree = "<group>"; };
7591
943398262D57E54000287A2D /* jsonParser.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = jsonParser.mm; sourceTree = "<group>"; };
@@ -1309,6 +1325,7 @@
13091325
94280BA72D2FC29F00F1CF56 /* utilities */ = {
13101326
isa = PBXGroup;
13111327
children = (
1328+
942EC5612FBEF94700CCBB5D /* redisConnection.cpp */,
13121329
94280BA22D2FC00200F1CF56 /* base64.cpp */,
13131330
943398232D57E53400287A2D /* jsonParser.cpp */,
13141331
);
@@ -1403,6 +1420,9 @@
14031420
9470B5A22C8C5AD0007D9CC6 /* source */ = {
14041421
isa = PBXGroup;
14051422
children = (
1423+
942EC5642FBEF95000CCBB5D /* backtestRunner.cpp */,
1424+
942EC5652FBEF95000CCBB5D /* redisLoader.cpp */,
1425+
942EC5662FBEF95000CCBB5D /* redisRunner.cpp */,
14061426
94D6010F2FA9CD700066F51A /* strategies */,
14071427
94674B8C2D533E7800973137 /* models */,
14081428
94674B862D533B4000973137 /* trading */,
@@ -1432,6 +1452,7 @@
14321452
94B8C7932D3D770800E17EB6 /* utilities */ = {
14331453
isa = PBXGroup;
14341454
children = (
1455+
942EC55D2FBEF92F00CCBB5D /* redisConnection.hpp */,
14351456
94C331A02FA899A8006BD690 /* decimal_json.hpp */,
14361457
94280BA12D2FC00200F1CF56 /* base64.hpp */,
14371458
);
@@ -3530,6 +3551,9 @@
35303551
94DE4F772C8C3E7C00FE48FF /* include */ = {
35313552
isa = PBXGroup;
35323553
children = (
3554+
942EC55E2FBEF93A00CCBB5D /* backtestRunner.hpp */,
3555+
942EC55F2FBEF93A00CCBB5D /* redisLoader.hpp */,
3556+
942EC5602FBEF93A00CCBB5D /* redisRunner.hpp */,
35333557
94D601132FA9CD890066F51A /* strategies */,
35343558
94674B842D533B2F00973137 /* trading */,
35353559
942966D72D48E84100532862 /* models */,
@@ -3642,12 +3666,16 @@
36423666
941408AE2D59F93F000ED1F9 /* sqlManager.cpp in Sources */,
36433667
9470B5A42C8C5AD0007D9CC6 /* main.cpp in Sources */,
36443668
943398252D57E53400287A2D /* jsonParser.cpp in Sources */,
3669+
942EC56A2FBEF95000CCBB5D /* backtestRunner.cpp in Sources */,
3670+
942EC56B2FBEF95000CCBB5D /* redisLoader.cpp in Sources */,
3671+
942EC56C2FBEF95000CCBB5D /* redisRunner.cpp in Sources */,
36453672
94280BA32D2FC00200F1CF56 /* base64.cpp in Sources */,
36463673
94674B8E2D533E7800973137 /* trade.cpp in Sources */,
36473674
941B549B2D3BBADE00E3BF64 /* trading_definitions_json.cpp in Sources */,
36483675
946EFF7E2FB9F44E008D9647 /* reporting.cpp in Sources */,
36493676
94674B872D533B4000973137 /* tradeManager.cpp in Sources */,
36503677
94CD8BA02D2E8CE500041BBA /* databaseConnection.cpp in Sources */,
3678+
942EC5622FBEF94700CCBB5D /* redisConnection.cpp in Sources */,
36513679
940A61132C92CE210083FEB8 /* configManager.cpp in Sources */,
36523680
94724A842F8B92C10029B940 /* operations.cpp in Sources */,
36533681
940A61172C92CE960083FEB8 /* serviceA.cpp in Sources */,
@@ -3662,7 +3690,11 @@
36623690
94CD8BA12D2E8CE500041BBA /* databaseConnection.cpp in Sources */,
36633691
941408AF2D59F93F000ED1F9 /* sqlManager.cpp in Sources */,
36643692
9464E5F12FA7467200D82BAD /* symbolScale.mm in Sources */,
3693+
942EC5632FBEF94700CCBB5D /* redisConnection.cpp in Sources */,
36653694
943398242D57E53400287A2D /* jsonParser.cpp in Sources */,
3695+
942EC5672FBEF95000CCBB5D /* backtestRunner.cpp in Sources */,
3696+
942EC5682FBEF95000CCBB5D /* redisLoader.cpp in Sources */,
3697+
942EC5692FBEF95000CCBB5D /* redisRunner.cpp in Sources */,
36663698
94280BA42D2FC00200F1CF56 /* base64.cpp in Sources */,
36673699
94674B8D2D533E7800973137 /* trade.cpp in Sources */,
36683700
941B549A2D3BBADE00E3BF64 /* trading_definitions_json.cpp in Sources */,
@@ -3809,16 +3841,22 @@
38093841
"\"$(SRCROOT)/external/libpqxx/build/include\"",
38103842
"\"$(SRCROOT)/external/\"",
38113843
"\"$(SRCROOT)/external/boost-decimal/include\"",
3844+
/opt/homebrew/include,
3845+
/opt/homebrew/opt/openssl/include,
38123846
);
38133847
INCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES = "";
38143848
LIBRARY_SEARCH_PATHS = (
38153849
"\"$(SRCROOT)/external/libpqxx/build/src\"",
38163850
"/opt/homebrew/opt/postgresql@18/lib/postgresql",
3851+
/opt/homebrew/opt/openssl/lib,
38173852
);
38183853
MACOSX_DEPLOYMENT_TARGET = 26.0;
38193854
OTHER_LDFLAGS = (
38203855
"-lpq",
38213856
"-lpqxx",
3857+
"-lssl",
3858+
"-lcrypto",
3859+
"-pthread",
38223860
);
38233861
OTHER_LIBTOOLFLAGS = "";
38243862
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -3838,16 +3876,22 @@
38383876
"\"$(SRCROOT)/external/libpqxx/build/include\"",
38393877
"\"$(SRCROOT)/external/\"",
38403878
"\"$(SRCROOT)/external/boost-decimal/include\"",
3879+
/opt/homebrew/include,
3880+
/opt/homebrew/opt/openssl/include,
38413881
);
38423882
INCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES = "";
38433883
LIBRARY_SEARCH_PATHS = (
38443884
"\"$(SRCROOT)/external/libpqxx/build/src\"",
38453885
"/opt/homebrew/opt/postgresql@18/lib/postgresql",
3886+
/opt/homebrew/opt/openssl/lib,
38463887
);
38473888
MACOSX_DEPLOYMENT_TARGET = 26.0;
38483889
OTHER_LDFLAGS = (
38493890
"-lpq",
38503891
"-lpqxx",
3892+
"-lssl",
3893+
"-lcrypto",
3894+
"-pthread",
38513895
);
38523896
OTHER_LIBTOOLFLAGS = "";
38533897
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -3868,16 +3912,22 @@
38683912
"\"$(SRCROOT)/external/libpqxx/include/pqxx/internal\"",
38693913
"\"$(SRCROOT)/external/libpqxx/build/include\"",
38703914
"\"$(SRCROOT)/external/boost-decimal/include\"",
3915+
/opt/homebrew/include,
3916+
/opt/homebrew/opt/openssl/include,
38713917
);
38723918
LIBRARY_SEARCH_PATHS = (
38733919
"\"$(SRCROOT)/external/libpqxx/build/src\"",
38743920
"/opt/homebrew/opt/postgresql@18/lib/postgresql",
3921+
/opt/homebrew/opt/openssl/lib,
38753922
);
38763923
MACOSX_DEPLOYMENT_TARGET = 26.0;
38773924
MARKETING_VERSION = 1.0;
38783925
OTHER_LDFLAGS = (
38793926
"-lpq",
38803927
"-lpqxx",
3928+
"-lssl",
3929+
"-lcrypto",
3930+
"-pthread",
38813931
);
38823932
PRODUCT_BUNDLE_IDENTIFIER = com.mccaffers.tests;
38833933
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -3898,16 +3948,22 @@
38983948
"\"$(SRCROOT)/external/libpqxx/include/pqxx/internal\"",
38993949
"\"$(SRCROOT)/external/libpqxx/build/include\"",
39003950
"\"$(SRCROOT)/external/boost-decimal/include\"",
3951+
/opt/homebrew/include,
3952+
/opt/homebrew/opt/openssl/include,
39013953
);
39023954
LIBRARY_SEARCH_PATHS = (
39033955
"\"$(SRCROOT)/external/libpqxx/build/src\"",
39043956
"/opt/homebrew/opt/postgresql@18/lib/postgresql",
3957+
/opt/homebrew/opt/openssl/lib,
39053958
);
39063959
MACOSX_DEPLOYMENT_TARGET = 26.0;
39073960
MARKETING_VERSION = 1.0;
39083961
OTHER_LDFLAGS = (
39093962
"-lpq",
39103963
"-lpqxx",
3964+
"-lssl",
3965+
"-lcrypto",
3966+
"-pthread",
39113967
);
39123968
PRODUCT_BUNDLE_IDENTIFIER = com.mccaffers.tests;
39133969
PRODUCT_NAME = "$(TARGET_NAME)";

documents/flow.png

601 KB
Loading

include/backtestRunner.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Backtesting Engine in C++
2+
//
3+
// (c) 2026 Ryan McCaffery | https://mccaffers.com
4+
// This code is licensed under MIT license (see LICENSE.txt for details)
5+
// ---------------------------------------
6+
7+
#pragma once
8+
#include <string>
9+
#include "trading_definitions/configuration.hpp"
10+
11+
int runBacktest(const std::string& questdbHost,
12+
const trading_definitions::Configuration& config);

include/redisLoader.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Backtesting Engine in C++
2+
//
3+
// (c) 2026 Ryan McCaffery | https://mccaffers.com
4+
// This code is licensed under MIT license (see LICENSE.txt for details)
5+
// ---------------------------------------
6+
7+
#pragma once
8+
9+
#include <string>
10+
11+
// LPUSH pairs with RedisRunner's RPOP so consumers observe FIFO ordering.
12+
class RedisLoader {
13+
public:
14+
static int load(const std::string& rawJson,
15+
const std::string& redisHost = "127.0.0.1",
16+
int redisPort = 6379,
17+
const std::string& queueKey = "strategy_queue");
18+
19+
static int loadPayload(const std::string& redisHost,
20+
int redisPort,
21+
const std::string& queueKey,
22+
const std::string& rawJson);
23+
};

include/redisRunner.hpp

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) 2026 Ryan McCaffery | https://mccaffers.com
4+
// This code is licensed under MIT license (see LICENSE.txt for details)
5+
// ---------------------------------------
6+
7+
#pragma once
8+
#include <string>
9+
10+
class RedisRunner {
11+
public:
12+
static int run(const std::string& questdbHost,
13+
const std::string& redisHost = "127.0.0.1",
14+
int redisPort = 6379,
15+
const std::string& queueKey = "strategy_queue");
16+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Backtesting Engine in C++
2+
//
3+
// (c) 2026 Ryan McCaffery | https://mccaffers.com
4+
// This code is licensed under MIT license (see LICENSE.txt for details)
5+
// ---------------------------------------
6+
7+
#pragma once
8+
9+
#include <stdexcept>
10+
#include <string>
11+
#include <utility>
12+
13+
// Thrown by the strategy factory when the configured strategy name does not
14+
// match any known strategy. Derives from std::runtime_error so existing
15+
// catch(const std::runtime_error&) / catch(const std::exception&) sites still
16+
// match, while giving new callers a dedicated type to discriminate a
17+
// configuration / domain error from any other runtime failure.
18+
class UnknownStrategyError : public std::runtime_error {
19+
public:
20+
explicit UnknownStrategyError(std::string name)
21+
: std::runtime_error("Unknown strategy: '" + name + "'"),
22+
name_(std::move(name)) {}
23+
24+
const std::string& name() const noexcept { return name_; }
25+
26+
private:
27+
std::string name_;
28+
};

0 commit comments

Comments
 (0)