Athanor Quickstart¶
TL;DR
Define factors in a .at file, compile them to C++ with the Athanor CLI,
wire them into a strategy, and read computed values through ref().
Athanor is a build-time compiler — no Athanor service runs in production.
Why a DSL for factors?¶
You could compute a spread factor in C++:
on(TOPIC<"bar://okx/BTCUSDT@1m">, [](const Tick<schema::BarRow>& tick) {
double spread = tick.payload.close - tick.payload.open;
// Store it somewhere, manage the window yourself...
});
This works for one factor. For ten factors with rolling windows, lagged inputs, and shared subexpressions, the manual C++ becomes verbose, error-prone, and hard to optimize.
Athanor lets you declare factors in a domain-specific language, then compiles
them into optimized C++ that shares subexpressions, manages windows, and
publishes typed factor:// resources automatically.
Note
Athanor is optional. If you prefer handwritten C++ for all your factor logic, Aurum works fine without it. Athanor exists for strategies where the number and complexity of factors makes manual implementation unwieldy.
Define two factors¶
Create factors.at:
factor spread :=
Bar.close - Bar.open
factor spread_mean := ~window:20
MEAN spread
Compile the definitions with the Athanor CLI included in the release:
mkdir -p generated
athanor compile --output generated/factors.hpp factors.at
The output is a C++ header under namespace aurum::alpha. Regenerate it
after changing any input definition.
Tip
Treat the generated header as an artifact: review compiler diagnostics, but
do not edit it by hand. Your next athanor compile will overwrite any
manual changes.
Attach the factors¶
#include "generated/factors.hpp"
#include <aurum/sdk.hpp>
#include <aurum/venue/okx.hpp>
using namespace aurum;
using aurum::alpha::spread;
using aurum::alpha::spread_mean;
class FactorWatch final : public sdk::Application {
public:
FactorWatch() : sdk::Application({.mode = sdk::RuntimeMode::LIVE}) {
bind<Datafeed>(venue::okx::Bar("BTCUSDT", "1m"));
(void)wire<"bar://okx/BTCUSDT@1m", spread, spread_mean>();
on(TOPIC<"bar://okx/BTCUSDT@1m">, [](const auto&) {
auto value =
ref(TOPIC<"factor://spread_mean/btcusdt.okx@bar:1m">);
if (value) log::info("spread mean={}", *value);
});
}
};
AURUM_EXPORT(FactorWatch)
Run the project with aurum run .. The factor resource becomes visible in
the runtime catalog after the source is bound.
Warning
Windowed factors are unavailable until they have enough input. A 20-bar mean
factor will return empty from ref() for the first 19 bars. Always check
the optional before using the value — an empty optional is normal during
warmup, not an error.
Continue with Factors in Strategies for window and lifecycle behavior.