Skip to content

Commit 012108a

Browse files
authored
Added scaffolding for a random trading strategy (#26)
* Added scaffolding for a random trading strategy * update github workflow to include sonar checks * creating a strategy interface * Refactoring random strategy * Updating contributing guidance and readme
1 parent 4ed667e commit 012108a

14 files changed

Lines changed: 404 additions & 145 deletions

File tree

.github/workflows/auto-close-external-prs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
owner: context.repo.owner,
2121
repo: context.repo.repo,
2222
issue_number: pr,
23-
body: "Thanks for the interest! This repository isn't currently accepting external contributions as I am actively experimenting with different approaches and want to avoid merge conflicts. Therefore, this PR is being closed automatically by Github Bot."
23+
body: "Thanks for the interest! This repository isn't currently accepting external contributions as I am actively experimenting with different approaches and want to avoid merge conflicts. Therefore, this PR is being closed automatically by Github Bot. See [CONTRIBUTING.md](https://github.com/mccaffers/backtesting-engine-cpp/blob/main/CONTRIBUTING.md) for how to fork or file an issue instead."
2424
});
2525
await github.rest.pulls.update({
2626
owner: context.repo.owner,

.github/workflows/build.yml

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@ on:
33
branches:
44
- main
55
pull_request:
6-
types: [opened, synchronize, reopened]
6+
types: [opened, synchronize, reopened]
77

88
name: Build
99

10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
1014
env:
1115
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
16+
BUILD_TYPE: Release
17+
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
1218

1319
jobs:
1420
build:
@@ -59,4 +65,57 @@ jobs:
5965
with:
6066
name: sonarqube-coverage
6167
path: sonarqube-generic-coverage.xml
62-
retention-days: 1
68+
retention-days: 1
69+
70+
sonar-scan:
71+
name: SonarCloud Scan
72+
needs: build
73+
runs-on: ubuntu-latest
74+
75+
steps:
76+
# fetch-depth: 0 gives Sonar full git history for blame-based new-code analysis.
77+
- name: Checkout repository
78+
uses: actions/checkout@v5
79+
with:
80+
fetch-depth: 0
81+
- name: Check compiler version, for debugging
82+
run: |
83+
g++ --version
84+
cmake --version
85+
- name: Build C++ Libraries
86+
run: bash ./scripts/build_dep.sh
87+
# SonarQube Server and Cloud (formerly SonarQube and SonarCloud) is a widely used static
88+
# analysis solution for continuous code quality and security inspection.
89+
# This action now supports and is the official entrypoint for scanning C++ projects via GitHub actions.
90+
# https://github.com/SonarSource/sonarqube-scan-action
91+
- name: Install Build Wrapper
92+
uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v4.2.1
93+
# This step installs the SonarQube build wrapper, which is necessary for analyzing C/C++ projects.
94+
95+
# Lands at ./artifact/sonarqube-generic-coverage.xml so the existing
96+
# sonar.coverageReportPaths argument keeps working unchanged.
97+
- name: Download coverage artifact from build job
98+
uses: actions/download-artifact@v5
99+
with:
100+
name: sonarqube-coverage
101+
path: artifact
102+
103+
# Configures the CMake build system, specifying the source directory and build directory, and setting the build type
104+
- name: Configure CMake
105+
run: cmake -S ${{github.workspace}} -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
106+
107+
# Runs the build wrapper to capture build commands and outputs them to the specified directory. Then builds the project using CMake
108+
- name: Run build-wrapper
109+
run: |
110+
build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --clean-first
111+
112+
# Performs the SonarQube scan using the scan action. Uses captured build commands for analysis and requires GitHub and SonarQube tokens for authentication
113+
- name: SonarQube Scan
114+
uses: SonarSource/sonarqube-scan-action@v4.2.1
115+
env:
116+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
117+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
118+
with:
119+
args: >
120+
--define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json"
121+
--define sonar.coverageReportPaths=artifact/sonarqube-generic-coverage.xml

.github/workflows/sonar.yml

Lines changed: 0 additions & 89 deletions
This file was deleted.

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ include_directories(
4141
${CMAKE_SOURCE_DIR}/include/models
4242
${CMAKE_SOURCE_DIR}/include/trading
4343
${CMAKE_SOURCE_DIR}/include/trading_definitions
44+
${CMAKE_SOURCE_DIR}/include/strategies
4445
${CMAKE_SOURCE_DIR}/external
4546
)
4647

CONTRIBUTING.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Contributing
2+
3+
Thanks for taking a look! This is an active solo experiment, and I'm grateful for the interest.
4+
5+
## I'm not accepting pull requests right now
6+
7+
This repository isn't currently accepting external contributions. I am actively experimenting with different approaches and want to avoid merge conflicts, so any PR opened from a non-owner account will be commented on and closed automatically by a GitHub bot.
8+
9+
Please don't take it personally — the policy is the same for everyone, and it isn't a judgement on the change.
10+
11+
## Please fork freely
12+
13+
The project is [MIT-licensed](LICENSE.MD), so you're very welcome to fork it and take the code in your own direction. If your fork sparks a discussion or you want to share what you've built on top of it, feel free to open an issue (see below).
14+
15+
## Use GitHub Issues for bugs, questions, and ideas
16+
17+
Bugs, questions, and ideas are all welcome on the [Issues tab](https://github.com/mccaffers/backtesting-engine-cpp/issues). That's the supported way to flag something — much more useful to me than a PR I'd have to close.
18+
19+
When filing an issue, a short description of what you saw, what you expected, and (for bugs) how to reproduce it goes a long way.
20+
21+
## A note on `@claude` mentions
22+
23+
This repo uses the [Claude Code GitHub Action](https://github.com/anthropics/claude-code-action) on `@claude` mentions, but it's restricted to the repository owner — `@claude` comments from other accounts won't trigger a run. This keeps paid API usage under control.

README.md

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Feel free to explore, but this code base is usuable at the moment.
88

99
I'm developing a high-performance C++ backtesting engine designed to analyze financial data and evaluate multiple trading strategies at scale.
1010

11-
[![SonarCloud Scan](https://github.com/mccaffers/backtesting-engine-cpp/actions/workflows/sonar.yml/badge.svg)](https://github.com/mccaffers/backtesting-engine-cpp/actions/workflows/sonar.yml) [![Build](https://github.com/mccaffers/backtesting-engine-cpp/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/mccaffers/backtesting-engine-cpp/actions/workflows/build.yml) [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=mccaffers_backtesting-engine-cpp&metric=bugs)](https://sonarcloud.io/summary/new_code?id=mccaffers_backtesting-engine-cpp) [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=mccaffers_backtesting-engine-cpp&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=mccaffers_backtesting-engine-cpp) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mccaffers_backtesting-engine-cpp&metric=coverage)](https://sonarcloud.io/summary/new_code?id=mccaffers_backtesting-engine-cpp)
11+
[![Build](https://github.com/mccaffers/backtesting-engine-cpp/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/mccaffers/backtesting-engine-cpp/actions/workflows/build.yml) [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=mccaffers_backtesting-engine-cpp&metric=bugs)](https://sonarcloud.io/summary/new_code?id=mccaffers_backtesting-engine-cpp) [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=mccaffers_backtesting-engine-cpp&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=mccaffers_backtesting-engine-cpp) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mccaffers_backtesting-engine-cpp&metric=coverage)](https://sonarcloud.io/summary/new_code?id=mccaffers_backtesting-engine-cpp)
1212

1313
I'm extracting results and creating various graphs for trend analyses using SciPy for calculations and Plotly for visualization.
1414

@@ -20,7 +20,17 @@ I'm extracting results and creating various graphs for trend analyses using SciP
2020

2121
This backtesting engine can pull tick data from local files or from a Postgres database. I'm using QuestDB.
2222

23-
### Postgres Setup - Requires libpq-dev or its equivalent for your OS:
23+
### Clone with submodules
24+
25+
The project depends on two vendored libraries (`libpqxx` and `boost-decimal`) tracked as git submodules under `external/`. If you didn't clone with `--recurse-submodules`, run:
26+
27+
```
28+
git submodule update --init --recursive
29+
```
30+
31+
`scripts/build_dep.sh` does this for you on first run.
32+
33+
### Install libpq (required by libpqxx)
2434

2535
```
2636
For Ubuntu/Debian systems: sudo apt-get install libpq-dev
@@ -30,15 +40,12 @@ For OpenSuse: zypper in postgresql-devel
3040
For ArchLinux: pacman -S postgresql-libs
3141
```
3242

33-
### Postgres Setup (using C++20)
43+
### Build dependencies
44+
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:
3446

3547
```
36-
cd ./external/libpqxx
37-
mkdir -p build
38-
cd ./build
39-
cmake ..
40-
./configure CXXFLAGS="-std=c++20 -O3"
41-
make
48+
bash ./scripts/build_dep.sh
4249
```
4350

4451
Xcode - Link Binary with Libraries (Source & Test)
@@ -63,17 +70,21 @@ Xcode - Library Path
6370
"/opt/homebrew/Cellar/postgresql@14/14.15/lib/postgresql@14"
6471
```
6572

66-
### Test the build
73+
### Build the project
6774

68-
`sh ./scripts/build.sh`
75+
`bash ./scripts/build.sh`
6976

7077
### Run via terminal
7178

72-
`sh ./scripts/run.sh`
79+
`bash ./scripts/run.sh`
80+
81+
### Run tests via terminal
82+
83+
`bash ./scripts/test.sh`
7384

74-
### Run via test via terminal
85+
### Contributing
7586

76-
`sh ./scripts/test.sh`
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.
7788

7889
### License
7990
[MIT](https://choosealicense.com/licenses/mit/)

backtesting-engine-cpp.xcodeproj/project.pbxproj

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
94724A842F8B92C10029B940 /* operations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94724A822F8B92C10029B940 /* operations.cpp */; };
3434
94CD8BA02D2E8CE500041BBA /* databaseConnection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CD8B9F2D2E8CE500041BBA /* databaseConnection.cpp */; };
3535
94CD8BA12D2E8CE500041BBA /* databaseConnection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CD8B9F2D2E8CE500041BBA /* databaseConnection.cpp */; };
36+
94D601102FA9CD700066F51A /* randomStrategy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D6010E2FA9CD700066F51A /* randomStrategy.cpp */; };
37+
94D601112FA9CD700066F51A /* randomStrategy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D6010E2FA9CD700066F51A /* randomStrategy.cpp */; };
3638
/* End PBXBuildFile section */
3739

3840
/* Begin PBXCopyFilesBuildPhase section */
@@ -48,6 +50,7 @@
4850
/* End PBXCopyFilesBuildPhase section */
4951

5052
/* Begin PBXFileReference section */
53+
9409A61B2FAA6411002C30FF /* strategy.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = strategy.hpp; sourceTree = "<group>"; };
5154
940A61112C92CE210083FEB8 /* configManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = configManager.cpp; sourceTree = "<group>"; };
5255
940A61122C92CE210083FEB8 /* configManager.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = configManager.hpp; sourceTree = "<group>"; };
5356
940A61152C92CE960083FEB8 /* serviceA.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = serviceA.cpp; sourceTree = "<group>"; };
@@ -1254,6 +1257,8 @@
12541257
94CD8B9A2D2DCF6E00041BBA /* libpqxx-7.10.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libpqxx-7.10.a"; path = "build/external/libpqxx/src/libpqxx-7.10.a"; sourceTree = "<group>"; };
12551258
94CD8B9E2D2E8CE500041BBA /* databaseConnection.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = databaseConnection.hpp; sourceTree = "<group>"; };
12561259
94CD8B9F2D2E8CE500041BBA /* databaseConnection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = databaseConnection.cpp; sourceTree = "<group>"; };
1260+
94D6010E2FA9CD700066F51A /* randomStrategy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = randomStrategy.cpp; sourceTree = "<group>"; };
1261+
94D601122FA9CD890066F51A /* randomStrategy.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = randomStrategy.hpp; sourceTree = "<group>"; };
12571262
/* End PBXFileReference section */
12581263

12591264
/* Begin PBXFrameworksBuildPhase section */
@@ -1388,6 +1393,7 @@
13881393
9470B5A22C8C5AD0007D9CC6 /* source */ = {
13891394
isa = PBXGroup;
13901395
children = (
1396+
94D6010F2FA9CD700066F51A /* strategies */,
13911397
94674B8C2D533E7800973137 /* models */,
13921398
94674B862D533B4000973137 /* trading */,
13931399
941B54982D3BBAD800E3BF64 /* trading_definitions */,
@@ -3494,9 +3500,27 @@
34943500
path = "../../../../../opt/homebrew/Cellar/postgresql@14/14.15/lib/postgresql@14/pgxs";
34953501
sourceTree = "<group>";
34963502
};
3503+
94D6010F2FA9CD700066F51A /* strategies */ = {
3504+
isa = PBXGroup;
3505+
children = (
3506+
94D6010E2FA9CD700066F51A /* randomStrategy.cpp */,
3507+
);
3508+
path = strategies;
3509+
sourceTree = "<group>";
3510+
};
3511+
94D601132FA9CD890066F51A /* strategies */ = {
3512+
isa = PBXGroup;
3513+
children = (
3514+
9409A61B2FAA6411002C30FF /* strategy.hpp */,
3515+
94D601122FA9CD890066F51A /* randomStrategy.hpp */,
3516+
);
3517+
path = strategies;
3518+
sourceTree = "<group>";
3519+
};
34973520
94DE4F772C8C3E7C00FE48FF /* include */ = {
34983521
isa = PBXGroup;
34993522
children = (
3523+
94D601132FA9CD890066F51A /* strategies */,
35003524
94674B842D533B2F00973137 /* trading */,
35013525
942966D72D48E84100532862 /* models */,
35023526
94B8C7932D3D770800E17EB6 /* utilities */,
@@ -3616,6 +3640,7 @@
36163640
940A61132C92CE210083FEB8 /* configManager.cpp in Sources */,
36173641
94724A842F8B92C10029B940 /* operations.cpp in Sources */,
36183642
940A61172C92CE960083FEB8 /* serviceA.cpp in Sources */,
3643+
94D601112FA9CD700066F51A /* randomStrategy.cpp in Sources */,
36193644
);
36203645
runOnlyForDeploymentPostprocessing = 0;
36213646
};
@@ -3630,6 +3655,7 @@
36303655
94280BA42D2FC00200F1CF56 /* base64.cpp in Sources */,
36313656
94674B8D2D533E7800973137 /* trade.cpp in Sources */,
36323657
941B549A2D3BBADE00E3BF64 /* trading_definitions_json.cpp in Sources */,
3658+
94D601102FA9CD700066F51A /* randomStrategy.cpp in Sources */,
36333659
94674B8A2D533BDA00973137 /* tradeManager.mm in Sources */,
36343660
94724A832F8B92C10029B940 /* operations.cpp in Sources */,
36353661
940A61182C92CE960083FEB8 /* serviceA.cpp in Sources */,

include/models/trade.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ struct Trade {
2626
std::string dealReference;
2727
std::string symbol;
2828
int scalingFactor;
29-
double stopDistancePips;
30-
double limitDistancePips;
29+
boost::decimal::decimal64_t stopDistancePips;
30+
boost::decimal::decimal64_t limitDistancePips;
3131
std::string strategyId;
3232
std::string strategyName;
3333

0 commit comments

Comments
 (0)