diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52deaf5..2e9dd25 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,23 +1,17 @@ # Contributing -Thanks for taking a look! This is an active solo experiment, and I'm grateful for the interest. +Thanks for taking a look! This is an active experiment, and I'm grateful for the interest. ## I'm not accepting pull requests right now -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. +This repository isn't currently accepting external contributions. -Please don't take it personally — the policy is the same for everyone, and it isn't a judgement on the change. +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. ## Please fork freely -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). +The project is [MIT-licensed](LICENSE.MD), so you're very welcome to fork it and take the code in your own direction. ## Use GitHub Issues for bugs, questions, and ideas -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. - -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. - -## A note on `@claude` mentions - -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. +Bugs, questions, and ideas are all welcome on the [Issues tab](https://github.com/mccaffers/backtesting-engine-cpp/issues). diff --git a/include/trading/tradeManager.hpp b/include/trading/tradeManager.hpp index e853c8f..e185901 100644 --- a/include/trading/tradeManager.hpp +++ b/include/trading/tradeManager.hpp @@ -25,7 +25,9 @@ class TradeManager { boost::decimal::decimal64_t stopDistancePips = boost::decimal::decimal64_t{0}, boost::decimal::decimal64_t limitDistancePips = boost::decimal::decimal64_t{0}); size_t reviewAccount() const; - bool closeTrade(const std::string& tradeId, boost::decimal::decimal64_t closePrice); + bool closeTrade(const std::string& tradeId, + boost::decimal::decimal64_t closePrice, + const PriceData& tick); const std::unordered_map& getActiveTrades() const; const std::vector& getClosedTrades() const; boost::decimal::decimal64_t calculatePnl() const; diff --git a/source/operations.cpp b/source/operations.cpp index a55c998..9c161cb 100644 --- a/source/operations.cpp +++ b/source/operations.cpp @@ -39,7 +39,7 @@ void reviewStopAndLimit(TradeManager& tradeManager, const PriceData& tick) { } } for (const auto& [id, exitPrice] : toClose) { - tradeManager.closeTrade(id, exitPrice); + tradeManager.closeTrade(id, exitPrice, tick); } } diff --git a/source/trading/tradeManager.cpp b/source/trading/tradeManager.cpp index e8c1cd7..a7705c8 100644 --- a/source/trading/tradeManager.cpp +++ b/source/trading/tradeManager.cpp @@ -6,6 +6,11 @@ #include "tradeManager.hpp" #include +#include +#include +#include +#include +#include namespace { std::string nextTradeId() { @@ -35,12 +40,14 @@ size_t TradeManager::reviewAccount() const { return activeTrades.size(); } -bool TradeManager::closeTrade(const std::string& tradeId, boost::decimal::decimal64_t closePrice) { +bool TradeManager::closeTrade(const std::string& tradeId, + boost::decimal::decimal64_t closePrice, + const PriceData& tick) { auto it = activeTrades.find(tradeId); if (it != activeTrades.end()) { Trade closed = it->second; closed.closePrice = closePrice; - closed.closeTime = std::chrono::system_clock::now(); + closed.closeTime = tick.timestamp; auto diff = closePrice - closed.entryPrice; if (closed.direction == Direction::SHORT) diff = -diff; // scalingFactor stays an int — boost::decimal has overloads for builtin @@ -48,6 +55,20 @@ bool TradeManager::closeTrade(const std::string& tradeId, boost::decimal::decima closed.pnl = diff * closed.scalingFactor * closed.size; closedTrades.push_back(closed); activeTrades.erase(it); + + auto t = std::chrono::system_clock::to_time_t(tick.timestamp); + std::tm utc{}; + gmtime_r(&t, &utc); + std::ostringstream ts; + ts << std::put_time(&utc, "%Y-%m-%dT%H:%M:%SZ"); + + const char* side = (closed.direction == Direction::LONG) ? "BUY" : "SELL"; + std::cout << ts.str() + << ", Trade Closed, " << closed.symbol + << ", " << side + << ", " << std::showpos << std::fixed << std::setprecision(2) << closed.pnl + << std::noshowpos + << std::endl; return true; } return false; diff --git a/tests/tradeManager.mm b/tests/tradeManager.mm index a7e7dd9..b4cfb05 100644 --- a/tests/tradeManager.mm +++ b/tests/tradeManager.mm @@ -39,7 +39,7 @@ - (void)testOpenTrade { - (void)testCloseTrade { PriceData tick("100.0"_dd, "99.0"_dd, std::chrono::system_clock::now(), "EURUSD"); std::string tradeId = self.manager->openTrade(tick, "1.0"_dd, Direction::LONG); - bool closed = self.manager->closeTrade(tradeId, "110.0"_dd); + bool closed = self.manager->closeTrade(tradeId, "110.0"_dd, tick); XCTAssertTrue(closed, "Trade should be closed successfully"); XCTAssertEqual(self.manager->reviewAccount(), 0, "Should have 0 active trades"); }