Utilities
Development utilities to support building backtesting programs with tzutrader.
Overview
The utils/ directory contains helper tools that simplify common development tasks. These utilities follow the same Unix philosophy as the main library—small, focused tools that do one thing well.
Currently available utilities focus on program configuration and setup. As the project evolves, more utilities may be added to support testing, data preparation, and other development needs.
genopts - Command-Line Option Parser Generator
What It Does
genopts is an AWK script that generates C++ command-line parsing code from a simple specification file. Instead of manually writing argument parsing logic, you describe your options in a text file and generate a complete parser.
This is useful when writing backtesting programs that need configurable parameters (strategy periods, portfolio settings, data files, etc.).
Why It Exists
Command-line parsing in C++ is tedious. Libraries like getopt are C-style and verbose. Modern C++ options exist but add dependencies. genopts generates simple, readable C++ code with no runtime dependencies—you own the generated code.
Philosophy:
- Generate code, don't depend on a library
- Simple specification format anyone can understand
- Generated code is readable C++ you can modify if needed
- No magic, no hidden behavior
How It Works
1. Write a specification file (opts.txt):
bool verbose false "Enable verbose output"
int period 20 "Indicator period"
double threshold 0.02 "Signal threshold"
std::string datafile POSITIONAL "CSV data file"
2. Generate the header:
cd utils/genopts
./genopts.awk opts.txt > generated_config.h
3. Use in your C++ program:
#include "generated_config.h"
int main(int argc, char* argv[]) {
Config config;
parse_args(config, argc, argv);
// Use parsed options
if (config.verbose) {
std::cout << "Period: " << config.period << std::endl;
}
// config.datafile contains the positional argument
return 0;
}
4. Compile and run:
g++ -std=c++17 my_backtest.cpp -o my_backtest
./my_backtest --verbose --period 50 data.csv
./my_backtest --help # Auto-generated help
Specification Format
Each line describes one option:
TYPE NAME DEFAULT "Description"
Fields:
- TYPE: C++ type (bool, int, size_t, double, std::string)
- NAME: Option name (becomes --NAME flag and struct member)
- DEFAULT: Default value (or POSITIONAL for required argument)
- Description: Help text in quotes
Example:
bool verbose false "Enable verbose logging"
int threads 4 "Number of worker threads"
size_t limit 1024 "Size limit in bytes"
std::string output output.txt "Output filename"
std::string input POSITIONAL "Input file"
Generated Code
The script generates:
1. Config struct:
struct Config {
bool verbose = false;
int threads = 4;
size_t limit = 1024;
std::string output = "output.txt";
std::string input; // positional
};
2. parse_args() function:
Parses command-line arguments and fills the Config struct. Handles:
- Long flags:
--verbose,--threads 8 - Short flags:
-v,-t 8(auto-assigned) - Help flag:
-h,--help - Positional arguments
- Type conversions (string to int, double, etc.)
3. print_help() function:
Auto-generated help message showing all options and defaults.
Usage Examples
Basic backtest with options:
# backtest_opts.txt
bool verbose false "Print portfolio after each update"
int fast_period 10 "Fast SMA period"
int slow_period 30 "Slow SMA period"
double threshold 0.01 "Crossover threshold percentage"
std::string datafile POSITIONAL "CSV data file"
Generate and use:
./genopts.awk backtest_opts.txt > generated_config.h
#include "tzu.h"
#include "generated_config.h"
int main(int argc, char* argv[]) {
Config cfg;
parse_args(cfg, argc, argv);
tzu::SMACrossover strategy(cfg.fast_period, cfg.slow_period, cfg.threshold);
tzu::BasicPortfolio portfolio(100000, 0.001, 0.1, 0.2);
std::ifstream file(cfg.datafile);
tzu::Csv<tzu::Ohlcv> csv(file);
tzu::BasicRunner<tzu::BasicPortfolio, tzu::SMACrossover, tzu::Csv<tzu::Ohlcv>>
runner(portfolio, strategy, csv);
runner.run(cfg.verbose);
return 0;
}
Run with different parameters:
# Default parameters
./backtest data.csv
# Custom parameters
./backtest --fast-period 5 --slow-period 20 --verbose data.csv
# Show help
./backtest --help
Supported Types
Boolean (bool):
- Flags that set to
truewhen present - Example:
--verbosesetsconfig.verbose = true
Integers (int, size_t):
- Converted using
std::stoiorstd::stoul - Example:
--period 50setsconfig.period = 50
Floating-point (double):
- Converted using
std::stod - Example:
--threshold 0.05setsconfig.threshold = 0.05
Strings (std::string):
- Assigned directly
- Example:
--output result.txtsetsconfig.output = "result.txt"
Positional arguments:
- Use
POSITIONALas default value - Must appear after all flags
- Example:
input_filein./program [options] input_file
Short Flags
Short flags are auto-assigned using the first available letter of the option name:
verbose→-vthreads→-toutput→-o
If the first letter is taken, the next available letter is used. The -h flag is reserved for --help.
Limitations
Simple by design:
- No combined short flags (
-vtfor-v -t) - No advanced getopt-style features
- No option validation (you handle that in your program)
- No complex default values (must be C++ literals)
These limitations keep the generator simple and the generated code readable.
When to Use
Use genopts when:
- Building backtesting programs with configurable parameters
- You want simple command-line parsing without dependencies
- You prefer generated code over library dependencies
- Your option parsing needs are straightforward
Don't use genopts when:
- You need complex option parsing (subcommands, validation, etc.)
- You're already using a parsing library you like
- Your program has no command-line options
Files
utils/genopts/
├── genopts.awk # The generator script
├── README.md # Detailed documentation
├── specs.txt # Example specification
├── main.cc # Example usage
└── generated_config.h # Example generated output
Try it:
cd utils/genopts
./genopts.awk specs.txt > test_config.h
g++ -std=c++17 main.cc -o test
./test --help
./test --verbose --threads 8 input.txt
Future Utilities
The utils/ directory may expand with additional development tools:
Potential additions:
- Data format converters (JSON to CSV, etc.)
- Test data generators (synthetic OHLCV)
- Parameter grid search helpers
- Performance profiling wrappers
- Result visualization scripts
- Build configuration helpers
Data acquisition: For downloading historical price data, see yfnim, a separate Yahoo Finance data puller that outputs CSV in the format tzutrader expects:
yf history -s:btc-usd --lookback:10y --format:csv --date_format:unix > data.csv
If you create utilities that would be useful to others, consider contributing them. See Contributing for details.
Philosophy
Utilities follow the same principles as the main library:
1. Small and focused: Each utility does one thing well.
2. No dependencies: Generate code or use standard tools (AWK, shell scripts).
3. Composable: Work with Unix pipes and shell scripting.
4. Optional: Use them if helpful, ignore them if not.
5. Readable: Simple enough to understand and modify.
The goal is providing helpful tools without imposing a workflow. If a utility doesn't fit your needs, don't use it or modify it for your situation.
Contributing Utilities
If you've created a useful development tool for tzutrader:
- Ensure it's small and focused
- Document clearly what it does and why
- Provide examples of usage
- Keep dependencies minimal
- Submit a pull request with the utility in
utils/your_tool/
See Contributing for the full process.
Getting Help
For utility-specific questions:
- Check the README.md in each utility's directory
- Look at example files provided
- File an issue on Codeberg
For general questions about tzutrader, see the FAQ.