Actually, you were right. It's much better to use your method, because that way we don't need to recompile the code every time a variable changes, and therefore we can automate the whole testing process by combining all the inputs with a PowerShell or a Batch script. I take this note for further readers who need the detailed solution.

First make a struct to store the settings:
Code
struct settings_data {
	int startDate;
	int endDate;
	std::string asset;
	int barPeriod;
	...
};
settings_data settings;


Then, in the main() function, you can load all the data into that struct.
For example if you are using file input like that:

Code
2018
2020
EURUSD
5
...


You can read it line by line like this:

Code
#include <string>
#include <fstream>
...
DLLFUNC void main() {
	std::string line;
	ifstream file("C:/zinput/input.txt");

	getline(file, line);
	settings.startDate = atoi(line.c_str()) * 10000 + 101;		//2018 => 20180101
	getline(file, line);
	settings.endDate = atoi(line.c_str()) * 10000 + 1231;		//2020 => 20201231
	getline(file, line);
	settings.asset = line;
	...
}


Or if you have Zorro S you can also use the command line arguments.
Now you can easily reach the settings it the run() function.
Code
DLLFUNC void run() {
	StartDate = settings.startDate;
	EndDate = settings.endDate;
	asset(settings.asset.c_str());
	BarPeriod = settings.barPeriod;
	...
}