FastMM documentation
FastMM C++ API 0.6.0
Public headers, tier 1 and tier 2
Loading...
Searching...
No Matches
markout.hpp
Go to the documentation of this file.
1#pragma once
2// Post-fill markouts: the metric that separates spread captured from adverse selection.
3//
4// For a fill of `qty` at `price` with signed quantity s (+qty bought, -qty sold) and the venue
5// mid m(t) at the fill time t0 and at the horizon t0 + h:
6//
7// spread capture = s * (m(t0) - price) what the passive quote earned against the mid
8// markout(h) = s * (m(t0 + h) - price) what the fill was still worth h later
9// adverse selection(h) = spread capture - markout(h) how much of it the mid took back
10//
11// A passive quoter always has a positive spread capture: it quotes away from the mid by
12// construction. Only the markout says whether the fills were worth taking. Amounts are in quote
13// currency (raw 1e-8 fixed point) and, divided by the traded notional, in basis points.
14//
15// A fill whose horizon falls after the last event of the run has no mid to mark against and is
16// EXCLUDED, not marked at the last known mid: `excluded_fills` counts them, and the buckets of
17// that horizon only cover the fills that were measured. Capture is recomputed on the same
18// subset so capture and markout at a horizon are directly comparable.
19#include "fastmm/core/time.hpp"
20
21#include <cstdint>
22#include <string>
23#include <vector>
24
25namespace fastmm::bt {
26
27// Horizons measured by default, in simulated time.
28inline constexpr std::int64_t kDefaultMarkoutHorizonsNs[] = {
29 1'000'000'000LL, 10'000'000'000LL, 60'000'000'000LL};
31struct MarkoutBucket {
32 std::int64_t markout_raw = 0; // sum of s * (mid(t0 + h) - price), quote currency
33 std::int64_t capture_raw = 0; // sum of s * (mid(t0) - price) over the same fills
34 std::int64_t notional_raw = 0; // sum of |qty| * price over the same fills
35 std::uint64_t fills = 0;
37 [[nodiscard]] double markout_quote() const noexcept;
38 [[nodiscard]] double capture_quote() const noexcept;
39 // capture - markout: the part of the captured spread the mid took back.
40 [[nodiscard]] double adverse_selection_quote() const noexcept;
41 // Notional-weighted basis points; 0 when no fill was measured.
42 [[nodiscard]] double markout_bps() const noexcept;
43 [[nodiscard]] double capture_bps() const noexcept;
44 [[nodiscard]] double adverse_selection_bps() const noexcept;
45 [[nodiscard]] double notional() const noexcept;
47 void add(std::int64_t markout, std::int64_t capture, std::int64_t notional) noexcept {
48 markout_raw += markout;
49 capture_raw += capture;
51 ++fills;
52 }
53};
54
55// Buckets of one horizon, all over the same measured fills.
56struct MarkoutHorizon {
57 std::int64_t horizon_ns = 0;
63 // Indexed by instrument id, sized to the highest instrument that traded.
64 std::vector<MarkoutBucket> instrument;
65 // Fills the run could not mark, split by cause. Their sum is the number left out of the
66 // buckets above; they are never marked at a substitute price.
67 std::uint64_t excluded_fills = 0; // the sum of the two below
68 std::uint64_t excluded_past_end = 0; // fill ts + horizon is after the last event of the run
69 std::uint64_t excluded_no_mid = 0; // the venue book had no two sides there (or at the fill)
71 [[nodiscard]] std::string label() const; // "1s", "250ms", "2m"
72};
74} // namespace fastmm::bt
Definition backtest_config.hpp:39
constexpr std::int64_t kDefaultMarkoutHorizonsNs[]
Horizons measured by default, in simulated time.
Definition markout.hpp:30
Definition markout.hpp:33
double capture_quote() const noexcept
std::int64_t capture_raw
sum of s * (mid(t0) - price) over the same fills
Definition markout.hpp:35
double notional() const noexcept
double adverse_selection_quote() const noexcept
capture - markout: the part of the captured spread the mid took back.
double capture_bps() const noexcept
std::uint64_t fills
Definition markout.hpp:37
void add(std::int64_t markout, std::int64_t capture, std::int64_t notional) noexcept
Definition markout.hpp:49
double markout_quote() const noexcept
double adverse_selection_bps() const noexcept
double markout_bps() const noexcept
Notional-weighted basis points; 0 when no fill was measured.
std::int64_t markout_raw
sum of s * (mid(t0 + h) - price), quote currency
Definition markout.hpp:34
std::int64_t notional_raw
sum of |qty| * price over the same fills
Definition markout.hpp:36
MarkoutBucket maker
Definition markout.hpp:63
MarkoutBucket sell
Definition markout.hpp:62
std::uint64_t excluded_no_mid
the venue book had no two sides there (or at the fill)
Definition markout.hpp:71
MarkoutBucket total
Definition markout.hpp:60
std::uint64_t excluded_fills
Fills the run could not mark, split by cause.
Definition markout.hpp:69
std::string label() const
"1s", "250ms", "2m"
MarkoutBucket buy
Definition markout.hpp:61
std::int64_t horizon_ns
Definition markout.hpp:59
std::vector< MarkoutBucket > instrument
Indexed by instrument id, sized to the highest instrument that traded.
Definition markout.hpp:66
MarkoutBucket taker
Definition markout.hpp:64
std::uint64_t excluded_past_end
fill ts + horizon is after the last event of the run
Definition markout.hpp:70
Time primitives.