Writing Strategies
In FLOX a strategy is any class that satisfies the
concepts::Strategy
contract – i.e. it is both a MarketDataSubscriber
and a Subsystem
.
template <typename T>
concept Strategy =
MarketDataSubscriber<T> && Subsystem<T>;
You do not inherit from a common base; you simply implement the
required methods and expose a static factory (or use make<YourStrategy>()
)
to obtain a StrategyRef
.
Minimal Contract
Category | Methods / Fields |
---|---|
Lifecycle | void start() , void stop() |
Subscriber Identity | SubscriberId id() , SubscriberMode mode() |
Market-data callbacks | void onBookUpdate(const BookUpdateEvent&) void onTrade(const TradeEvent&) void onCandle(const CandleEvent&) |
Anything beyond that – risk, execution, validation – is plugged in via constructor parameters or setter functions you define.
Dependency Injection Pattern
class MyStrategy {
public:
MyStrategy(OrderExecutorRef exec,
RiskManagerRef risk = {},
OrderValidatorRef val = {})
: _exec(exec), _risk(risk), _val(val) {}
/* required interface … */
private:
OrderExecutorRef _exec;
RiskManagerRef _risk;
OrderValidatorRef _val;
};
The builder injects the refs when the strategy instance is created.
Recommended Workflow
void onBookUpdate(const BookUpdateEvent& u) {
if (!shouldTrade(u)) return;
Order ord = buildOrder(u);
std::string reason;
if (_val && !_val.validate(ord, reason)) return;
if (_risk && !_risk.allow(ord)) return;
_exec.submitOrder(ord);
}
- Signal → decide if you want to trade.
- Build an
Order
(limit/market, side, price, qty). - Validate →
OrderValidatorRef
(optional). - Risk Check →
RiskManagerRef
(optional). - Submit via
OrderExecutorRef
.
Best Practices
- Non-blocking callbacks – your strategy runs on a dedicated queue, but long tasks still add latency.
- No heap churn – reuse objects or use the FLOX memory pools.
- Stateless first – only keep state you absolutely need; use
PositionManagerRef
when you must track positions. - Pool safety – never keep raw pointers to events beyond the callback.
Example Skeleton
class MeanRevert final {
public:
explicit MeanRevert(OrderExecutorRef exec) : _exec(exec) {}
/* Subscriber identity */
SubscriberId id() const { return 42; }
SubscriberMode mode() const { return SubscriberMode::PUSH; }
/* Lifecycle */
void start() {}
void stop() {}
/* Market-data */
void onTrade(const TradeEvent& t) {}
void onCandle(const CandleEvent& c) {}
void onBookUpdate(const BookUpdateEvent& u) {
if (!spreadOK(u)) return;
Order o = makeOrder(u);
_exec.submitOrder(o);
}
private:
bool spreadOK(const BookUpdateEvent& u) const { /* … */ }
Order makeOrder(const BookUpdateEvent& u) const { /* … */ }
OrderExecutorRef _exec;
};
Register it in your builder with:
auto strat = make<MeanRevert>(executorRef);
marketDataBus.subscribe(strat);
subsystems.push_back(strat);
The engine starts and stops the strategy automatically via the Subsystem
interface.