88
99#include < array>
1010#include < charconv>
11- #include < iostream>
11+ #include < print>
12+ #include < ranges>
1213#include < stdexcept>
1314#include < string>
1415#include < system_error>
2627#include " parameterSweep.hpp"
2728#include " queueKeys.hpp"
2829#include " redisLoader.hpp"
29- #include " trading_definitions.hpp"
30+ #include " run_configuration.hpp"
31+ #include " strategy.hpp"
3032
3133namespace {
3234
@@ -60,8 +62,8 @@ sweep::ParameterGenerator buildRandomStrategySweep() {
6062 sweep::ParameterGenerator generator;
6163 // generator.addRange("OHLC_COUNT", 80, 20, 140); // 80, 100, 120, 140
6264 // generator.addList("OHLC_MINUTES", {1, 3, 5, 8});
63- generator.addList (" STOP_DISTANCE_IN_PIPS" , {1.0 , 1.5 , 2 .0 });
64- generator.addList (" LIMIT_DISTANCE_IN_PIPS" , {1.0 , 1.5 , 2 .0 });
65+ generator.addList (" STOP_DISTANCE_IN_PIPS" , {1.0 , 1.5 , 10 .0 });
66+ generator.addList (" LIMIT_DISTANCE_IN_PIPS" , {1.0 , 1.5 , 10 .0 });
6567 return generator;
6668}
6769
@@ -70,8 +72,8 @@ sweep::ParameterGenerator buildRandomStrategySweep() {
7072RunConfiguration makeRunConfiguration (const std::string& runId) {
7173 return RunConfiguration{
7274 .RUN_ID = runId,
73- .SYMBOLS = " EURUSD,AUDUSD " ,
74- .LAST_MONTHS = 2 ,
75+ .SYMBOLS = " EURUSD" ,
76+ .LAST_MONTHS = 6 ,
7577 };
7678}
7779
@@ -82,7 +84,9 @@ Strategy makeStrategy(const sweep::Combination& combo) {
8284 using namespace trading_definitions ;
8385
8486 return Strategy{
85- .UUID = " " ,
87+ // Each parameter combination gets its own UUID so a single backtest
88+ // result is uniquely identifiable and traceable back to its inputs.
89+ .UUID = boost::uuids::to_string (boost::uuids::random_generator ()()),
8690 .TRADING_VARIABLES = TradingVariables{
8791 .STRATEGY = " RandomStrategy" ,
8892 .STOP_DISTANCE_IN_PIPS = toDecimal (combo.get (" STOP_DISTANCE_IN_PIPS" )),
@@ -108,36 +112,40 @@ Strategy makeStrategy(const sweep::Combination& combo) {
108112int LoadCommand::run () {
109113 // One RUN_ID identifies the whole sweep; each combination becomes its own
110114 // queue entry, distinguished by its parameter values.
111- const std::string runId = boost::uuids::to_string (boost::uuids::random_generator ()());
112- const std::string redisHost = env::getOr (" REDIS_HOST" , " 127.0.0.1" );
115+ const auto runId = boost::uuids::to_string (boost::uuids::random_generator ()());
116+ const auto redisHost = env::getOr (" REDIS_HOST" , " 127.0.0.1" );
113117
114118 // Build random here
115- const sweep::ParameterGenerator generator = buildRandomStrategySweep ();
119+ const auto generator = buildRandomStrategySweep ();
116120
117- const std::vector<sweep::Combination> combinations = generator.generateAllCombinations ();
121+ const auto combinations = generator.generateAllCombinations ();
118122
119- std::cout << " LoadCommand: sweeping " << combinations. size ()
120- << " parameter combination(s) for RUN_ID= " << runId << std::endl ;
123+ std::println ( " LoadCommand: sweeping {} parameter combination(s) for RUN_ID={} " ,
124+ combinations. size (), runId) ;
121125
122- // Serialise every swept strategy first.
123- std::vector<std::string> strategyPayloads;
124- strategyPayloads.reserve (combinations.size ());
125- for (const sweep::Combination& combo : combinations) {
126- const nlohmann::json j = makeStrategy (combo);
127- strategyPayloads.push_back (j.dump ());
128- }
126+ // Serialise every swept strategy first. combinations is a sized range, so
127+ // std::ranges::to reserves up front (no manual reserve needed). The json type
128+ // is pinned explicitly because makeStrategy returns a Strategy and relies on
129+ // the implicit conversion for .dump().
130+ const auto strategyPayloads =
131+ combinations | std::views::transform ([](const sweep::Combination& combo) {
132+ const nlohmann::json j = makeStrategy (combo);
133+ return j.dump ();
134+ }) | std::ranges::to<std::vector<std::string>>();
129135
130136 // Push all strategies BEFORE the run descriptor. A worker that sees the run
131137 // immediately drains the strategy list and retires the run when empty, so the
132138 // full set must already be present the moment the run becomes visible.
133- const std::string strategyKey = queue_keys::strategyKey (runId);
134- const int strategyStatus = RedisLoader::loadPayloadBatch (
139+ const auto strategyKey = queue_keys::strategyKey (runId);
140+ const auto strategyStatus = RedisLoader::loadPayloadBatch (
135141 redisHost, 6379 , strategyKey, strategyPayloads);
136142 if (strategyStatus != 0 ) {
137143 return strategyStatus;
138144 }
139145
140- // Now advertise the run so workers can pick it up.
146+ // Now advertise the run so workers can pick it up. runJson is pinned to
147+ // nlohmann::json (not auto) because makeRunConfiguration returns a
148+ // RunConfiguration and relies on the implicit conversion for .dump().
141149 const nlohmann::json runJson = makeRunConfiguration (runId);
142150 return RedisLoader::loadPayload (redisHost, 6379 , queue_keys::RUN ,
143151 runJson.dump ());
0 commit comments