FastMM documentation
FastMM C++ API 0.6.0
Public headers, tier 1 and tier 2
Loading...
Searching...
No Matches
signal_eval.hpp
Go to the documentation of this file.
1#pragma once
2// evaluate_signal(): what a candidate predictor is worth, per horizon, before anyone writes a
3// strategy around it.
4//
5// Three things come out of one pass over a FeatureTable:
6//
7// * the information coefficient, Spearman rank correlation between the signal and the forward
8// mid move, and the same coefficient over equal-sized contiguous blocks of the sample, which
9// is what says whether one hour carried it;
10// * a decile table of the forward mid move by signal value, in basis points of the mid;
11// * the conditional touch markout: for each bucket, what a quote resting at the touch would
12// have made or lost by the horizon, one number per side, in basis points of the mid.
13//
14// The touch markout is the one that decides whether a passive quote is viable. For a row with mid
15// m, best bid b, best ask a and forward mid f:
16//
17// buy_bps = (f - b) / m * 1e4 a resting bid that filled at b, marked at f
18// sell_bps = (a - f) / m * 1e4 a resting ask that filled at a, marked at f
19//
20// which split into (m - b) / m, the half spread the quote earned, plus or minus (f - m) / m, the
21// move the mid made afterwards. Both sides of one quote average to the half spread, because the
22// move cancels; the point of conditioning on a signal is that in a given bucket only one of them
23// is the side that fills. The numbers are gross: subtract the venue's maker fee to compare.
24//
25// Rows without a forward mid at a horizon are left out of every statistic of that horizon, and
26// counted; they are never marked at a substitute price.
28
29#include <cstdint>
30#include <span>
31#include <string>
32#include <string_view>
33#include <vector>
34
35namespace fastmm::research {
36
37// A built-in column, so the common signals need no array from the caller.
38enum class Feature : std::uint8_t {
39 Imbalance = 0, // (bid qty - ask qty) / (bid qty + ask qty) at the touch, in [-1, 1]
40 MicropriceEdge = 1, // (microprice - mid) / mid, in basis points
41 Spread = 2, // (best ask - best bid) / mid, in basis points
42};
43
44[[nodiscard]] std::string_view to_string(Feature f) noexcept;
45// The feature of every row, in row order, in the units above.
46[[nodiscard]] std::vector<double> feature_values(const FeatureTable& t, Feature f);
47
49 double lo = 0.0; // signal range of the bucket, inclusive
50 double hi = 0.0;
51 std::uint64_t n = 0;
52 double mean_signal = 0.0;
53 double forward_bps = 0.0; // mean (forward mid - mid) / mid, basis points
54 double buy_bps = 0.0; // resting bid filled at the touch, marked at the horizon
55 double sell_bps = 0.0; // resting ask filled at the touch, marked at the horizon
56 double half_spread_bps = 0.0; // (mid - best bid) / mid; (buy_bps + sell_bps) / 2
57};
59struct HorizonEval {
60 std::int64_t horizon_ns = 0;
61 std::uint64_t n = 0; // rows that had a forward mid at this horizon
62 std::uint64_t excluded_past_end = 0;
63 std::uint64_t excluded_no_mid = 0;
64 double ic = 0.0; // Spearman, signal against forward mid move; NaN when n < 2
65 // The same coefficient per contiguous equal-sized block of the measured rows.
66 std::vector<double> block_ic;
67 double block_ic_mean = 0.0;
68 double block_ic_stdev = 0.0; // population standard deviation over the blocks
69 double block_ic_min = 0.0;
70 double block_ic_max = 0.0;
71 double block_sign_agreement = 0.0; // share of blocks whose IC has the sign of `ic`
72 std::vector<SignalBucket> buckets; // in ascending signal order
74 [[nodiscard]] std::string label() const { return horizon_label(horizon_ns); }
75};
77struct SignalEval {
78 std::string signal;
79 std::uint64_t rows = 0; // rows of the table the signal was measured on
80 std::uint32_t blocks = 0; // blocks the sample was split into
81 std::vector<HorizonEval> horizons;
83 // Per horizon: the coverage and IC line, then the bucket table.
84 [[nodiscard]] std::string table() const;
85};
87struct EvalConfig {
88 std::uint32_t buckets = 10; // equal-count buckets of the signal; 10 is a decile table
89 std::uint32_t blocks = 10; // contiguous equal-sized blocks the IC is recomputed over
90};
92// `values` must hold one signal value per row of `t`, in row order. Throws
93// std::invalid_argument on a length mismatch or a bucket/block count of 0.
94[[nodiscard]] SignalEval evaluate_signal(const FeatureTable& t,
95 std::span<const double> values,
96 std::string_view name,
97 const EvalConfig& cfg = {});
98// evaluate_signal() over feature_values(t, f).
99[[nodiscard]] SignalEval evaluate_feature(const FeatureTable& t,
100 Feature f,
101 const EvalConfig& cfg = {});
102
103} // namespace fastmm::research
FeatureTable: book features and forward mid moves, one row per qualifying market-data event,...
Definition feature_table.hpp:22
SignalEval evaluate_feature(const FeatureTable &t, Feature f, const EvalConfig &cfg={})
evaluate_signal() over feature_values(t, f).
Feature
A built-in column, so the common signals need no array from the caller.
Definition signal_eval.hpp:40
@ Spread
(best ask - best bid) / mid, in basis points
@ Imbalance
(bid qty - ask qty) / (bid qty + ask qty) at the touch, in [-1, 1]
@ MicropriceEdge
(microprice - mid) / mid, in basis points
SignalEval evaluate_signal(const FeatureTable &t, std::span< const double > values, std::string_view name, const EvalConfig &cfg={})
values must hold one signal value per row of t, in row order.
std::string_view to_string(Feature f) noexcept
std::vector< double > feature_values(const FeatureTable &t, Feature f)
The feature of every row, in row order, in the units above.
std::string horizon_label(std::int64_t ns)
"100ms", "1s", "1m": the shortest exact unit, the spelling MarkoutHorizon::label() uses.
Definition signal_eval.hpp:89
std::uint32_t buckets
equal-count buckets of the signal; 10 is a decile table
Definition signal_eval.hpp:90
std::uint32_t blocks
contiguous equal-sized blocks the IC is recomputed over
Definition signal_eval.hpp:91
Definition feature_table.hpp:63
Definition signal_eval.hpp:61
std::vector< double > block_ic
The same coefficient per contiguous equal-sized block of the measured rows.
Definition signal_eval.hpp:68
double block_ic_stdev
population standard deviation over the blocks
Definition signal_eval.hpp:70
std::uint64_t excluded_no_mid
Definition signal_eval.hpp:65
std::uint64_t n
rows that had a forward mid at this horizon
Definition signal_eval.hpp:63
std::uint64_t excluded_past_end
Definition signal_eval.hpp:64
std::string label() const
Definition signal_eval.hpp:76
double block_sign_agreement
share of blocks whose IC has the sign of ic
Definition signal_eval.hpp:73
double block_ic_max
Definition signal_eval.hpp:72
std::vector< SignalBucket > buckets
in ascending signal order
Definition signal_eval.hpp:74
std::int64_t horizon_ns
Definition signal_eval.hpp:62
double ic
Spearman, signal against forward mid move; NaN when n < 2.
Definition signal_eval.hpp:66
double block_ic_min
Definition signal_eval.hpp:71
double block_ic_mean
Definition signal_eval.hpp:69
Definition signal_eval.hpp:50
double half_spread_bps
(mid - best bid) / mid; (buy_bps + sell_bps) / 2
Definition signal_eval.hpp:58
double forward_bps
mean (forward mid - mid) / mid, basis points
Definition signal_eval.hpp:55
std::uint64_t n
Definition signal_eval.hpp:53
double sell_bps
resting ask filled at the touch, marked at the horizon
Definition signal_eval.hpp:57
double mean_signal
Definition signal_eval.hpp:54
double hi
Definition signal_eval.hpp:52
double buy_bps
resting bid filled at the touch, marked at the horizon
Definition signal_eval.hpp:56
double lo
signal range of the bucket, inclusive
Definition signal_eval.hpp:51
Definition signal_eval.hpp:79
std::vector< HorizonEval > horizons
Definition signal_eval.hpp:83
std::uint64_t rows
rows of the table the signal was measured on
Definition signal_eval.hpp:81
std::uint32_t blocks
blocks the sample was split into
Definition signal_eval.hpp:82
std::string table() const
Per horizon: the coverage and IC line, then the bucket table.
std::string signal
Definition signal_eval.hpp:80