Skip to content

About

Small C++20 library for Wilder's Average True Range (ATR) and ATR-based stop-loss levels, with GoogleTest tests, a benchmark, Conan 2 and CMake.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

atr-sl-cpp

A small C++20 library that computes Wilder's Average True Range (ATR) and an ATR-based stop-loss level.

ATR stop-losses in brief

The true range of a candle is the largest of high − low, |high − previous close| and |low − previous close|. ATR averages true range over a period (commonly 14) to measure how far price typically moves per candle. An ATR stop sits a multiple k of ATR away from price, so it widens in volatile markets and tightens in quiet ones.

Features

  • atr::calc_atr: Wilder's ATR. Candle 0 only supplies the first previous close, so true ranges start at candle 1. The first ATR value, at index period, is the simple average of the true ranges of candles 1 … period; every later value uses Wilder's smoothing, ATR[i] = (ATR[i-1] × (period − 1) + TR[i]) / period.
  • atr::trailing_sl: long-side stop level, close − k × ATR, with k defaulting to 3.0.
  • One header and one source file, built as the CMake library target atr_sl.
  • GoogleTest unit tests, a Google Benchmark micro-benchmark, Conan 2 dependency management and a GitHub Actions workflow.

API

namespace atr {
std::vector<double> calc_atr(std::span<const double> highs,
                             std::span<const double> lows,
                             std::span<const double> closes,
                             int period);

inline double trailing_sl(double close, double atr, double k = 3.0);
}
  • Inputs hold one element per candle, oldest first. std::vector<double> and plain arrays convert to std::span automatically.
  • The result has the same length as the inputs. Elements 0 … period-1 are 0.0; the first ATR value is at index period.
  • ATR is in the same price units as the inputs.
  • Preconditions: all three inputs have the same length, period > 0, and there are at least period + 1 candles. They are checked with assert inside src/atr_sl.cpp, so the checks run only when the library itself is compiled without NDEBUG (for example with -DCMAKE_BUILD_TYPE=Debug). The Release build below compiles them out, and breaking a precondition is then undefined behaviour (out-of-bounds access), not a reported error.
  • trailing_sl is stateless and returns the level for a single candle. To trail a long position, keep the highest level returned so far. For a short position the mirror level is close + k × ATR; trail it by keeping the lowest level so far. The library has no separate helper for it.

Usage

#include "atr_sl.hpp"
#include <cstdio>
#include <vector>

int main() {
    std::vector<double> highs  {100, 102, 101, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115};
    std::vector<double> lows   { 99, 100,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112};
    std::vector<double> closes {100, 101, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114};

    const int period = 14;  // needs at least period + 1 candles
    std::vector<double> atr_series = atr::calc_atr(highs, lows, closes, period);

    double stop = atr::trailing_sl(closes.back(), atr_series.back(), 2.5);
    std::printf("ATR(%d) = %.4f, long stop = %.4f\n", period, atr_series.back(), stop);
    // Prints: ATR(14) = 2.8673, long stop = 106.8316
}

To try it, save it as example.cpp in the repository root and run c++ -std=c++20 -Iinclude example.cpp src/atr_sl.cpp -o example && ./example.

Build and test

Requirements: CMake 3.20 or newer, a C++20 compiler, Conan 2 and Ninja (or drop -G Ninja to use CMake's default generator). These mirror the CI workflow's steps; on its fresh runner CI uses conan profile detect --force. The toolchain path below assumes your default Conan profile has build_type=Release, which conan profile detect sets.

conan profile detect                      # once per machine, if you have no default profile
conan install . -of build --build=missing
cmake -B build -G Ninja \
      -DCMAKE_TOOLCHAIN_FILE=build/build/Release/generators/conan_toolchain.cmake \
      -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build --output-on-failure

With CMake 3.23 or newer you can use the presets that conan install generates instead (they use Conan's default generator, Unix Makefiles, so Ninja is not needed for this path):

cmake --preset conan-release
cmake --build --preset conan-release
ctest --preset conan-release

Run the benchmark with ./build/bench_atr (or ./build/build/Release/bench_atr after a preset build).

CMakeLists.txt calls find_package(GTest REQUIRED CONFIG) and find_package(benchmark REQUIRED CONFIG) unconditionally, so any build without Conan, even of the library alone, needs both installed as CMake config packages where find_package can find them.

Tests

tests/test_atr.cpp contains two GoogleTest cases, registered with CTest as the single test RunAll:

  • ATR.Wilder14_KnownExample: 15 candles with period = 14; checks atr.back(), the first ATR value (index 14), against 2.85714285714 to within 1e-9. That is 40 / 14: the true ranges of candles 1 to 14 sum to 40.
  • TrailingSL.Basic: trailing_sl(100.0, 2.0, 3.0) returns 94.0.

Main files

include/atr_sl.hpp         public API (namespace atr)
src/atr_sl.cpp             calc_atr implementation
tests/test_atr.cpp         GoogleTest unit tests
bench/bench_atr.cpp        Google Benchmark: calc_atr on 10,000 candles
CMakeLists.txt             library, test and benchmark targets
conanfile.py               Conan 2 conanfile used by `conan install` (gtest 1.14.0, benchmark 1.8.4)
.github/workflows/ci.yml   GitHub Actions workflow

Continuous integration

.github/workflows/ci.yml is triggered by pushes to main and by pull requests. On ubuntu-latest it installs Conan 2 and Ninja with pip, detects a Conan profile, installs dependencies, builds in Release mode with Ninja and runs ctest. The benchmark is built but not run in CI.

About

Small C++20 library for Wilder's Average True Range (ATR) and ATR-based stop-loss levels, with GoogleTest tests, a benchmark, Conan 2 and CMake.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages