PineForge unreleased
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
metrics_stream.hpp
Go to the documentation of this file.
1#pragma once
2
3// CR-150 P00 declarations only. DESIGN.md revision 6, section 3.3:513-567,
4// with scratch storage in 3.8:902-909 and selected observations in 3.6:745-773.
5// Existing array entry points in metrics.hpp remain unchanged.
8
9#include <cstdint>
10#include <memory>
11
12namespace pineforge {
13namespace detail { class ScratchFile; }
14namespace metrics {
15
17PF_STATIC_ASSERT(offsetof(pf_equity_point_t, time_ms) == 0);
18PF_STATIC_ASSERT(offsetof(pf_equity_point_t, equity) == 8);
19PF_STATIC_ASSERT(offsetof(pf_equity_point_t, open_profit) == 16);
20
21/// Report-only O(1) trade fold (DESIGN 3.3:515-533,547-553).
22/// One accumulator per existing TradeFilter ALL/LONG/SHORT. Initialization
23/// and filtering match compute_trade_stats; fold is exactly its loop body,
24/// finish exactly its tail. Sums are plain left folds from 0.0 in row order,
25/// with the existing NaN, positive-loss and even-trade conventions; no sort,
26/// compensation or reuse of the engine's differently seeded running counters.
27///
28/// Fold sealed rows first, then finish a COPY with the unsealed tail and the
29/// final, re-marked range-end rows (3.3:547-551). Copies preserve the prefix;
30/// finish() never consumes or mutates it, so repeated report reads agree.
31/// The implementations replace the old loop only in L7a; none are supplied
32/// here. Report state is added to the broker hash waiver list by that lane,
33/// not silently treated as new decision state (3.3:552-553).
35public:
36 TradeStatsAccumulator(TradeFilter filter, double initial_capital);
40
41 void fold(const TradeC& trade);
43
44private:
45 struct State;
46 std::unique_ptr<State> state_;
47};
48
49/// Array point source, the first source of 3.3:535-543. data stays caller-
50/// owned and alive throughout the metric walk. Indexing returns a point
51/// value, so callers do not keep references to a source's refillable window.
52/// Required structural interface for BOTH sources: size() -> int64_t and
53/// source[int64_t] -> pf_equity_point_t, with 0 <= index < size().
55public:
56 ArrayCurve(const pf_equity_point_t* data, std::int64_t point_count);
57 std::int64_t size() const;
58 pf_equity_point_t operator[](std::int64_t index) const;
59
60private:
61 const pf_equity_point_t* data_;
62 std::int64_t point_count_;
63};
64
65/// A region of the engine-private scratch file (3.8:902-909). A point is
66/// exactly the 24-byte binary pf_equity_point_t: time_ms, equity, open_profit.
67/// This describes either a region or a separate file without choosing the
68/// curve/position-tail placement that DESIGN leaves open (3.8:908).
69/// Production regions borrow scratch and its lifetime, with descriptor=-1.
70/// The descriptor form remains available for existing external file readers;
71/// it is used only when scratch is null. Neither form owns its backing.
74 std::int64_t byte_offset;
75 std::int64_t point_count;
76 const detail::ScratchFile* scratch = nullptr;
77};
78
79struct ScratchCurveReader; // positional reader contract: spill_curve_reader.hpp
80
81/// Scratch point source (3.3:535-546; 3.8:904-909). Read exact binary doubles
82/// through positional scratch I/O into ONE 64 KiB window; never map a curve
83/// in the reader or parse sink text. Index i refers to byte_offset + 24*i.
84/// The borrowed backing remains valid during the walk. State/cache is
85/// opaque and O(1) in bars.
86///
87/// Required access pattern is first point, last point, then forward passes;
88/// each pass may restart at index 0. This is not a destructive input stream.
89/// Return by value keeps a previously read point independent of refills.
90/// OPEN M1: DESIGN does not set malformed-region/bounds/short-read error
91/// transport or concurrent-reader rules. No recovery policy is implied.
93public:
94 explicit SpillCurve(const ScratchCurveRegion& region);
95 /// Alternate read boundary for scratch adapters and file-like test readers.
96 /// Copies the reader descriptor; its context must outlive this source.
97 explicit SpillCurve(const ScratchCurveReader& reader);
99 std::int64_t size() const;
100 pf_equity_point_t operator[](std::int64_t index) const;
101
102private:
103 struct State;
104 std::unique_ptr<State> state_;
105};
106
107/// Equity computation over the structural point-source interface above
108/// (3.3:531-546). Same parameters, guards and formulas as the array overload
109/// in metrics.hpp; only curve[i] goes through PointSource. n is the number
110/// of points to walk (within source.size()), not an observation denominator.
111/// Ordinary calls use observation_count=n; the second overload states it.
112///
113/// Five sequential walks, no growing vectors: drawdown/runup walk, generated
114/// month-end returns twice, generated per-bar returns twice. Pass 1 sums and
115/// counts; pass 2 accumulates variance/downside in today's exact order, with
116/// today's final-n/span risk-free rate. Do not change grouping/rounding or
117/// -ffp-contract=off (3.3:518-543). A non-UTC chart holds ONE ScopedTimezone
118/// for the whole fill-time walk, never a nested lock (3.3:545-546).
119/// These are template declarations, with no metric bodies/instantiations.
120template <class PointSource>
122 const PointSource& curve, std::int64_t n, double initial_capital,
123 const std::string& chart_tz, double first_open, double last_close,
124 std::int64_t bars_in_market, double net_profit);
125
126/// Selected source has the final presented anchor and M window points:
127/// n=M+1, observation_count=M (including M=0). The anchor is the first
128/// return's base, not a bar. Only time_in_market_pct uses the observation
129/// denominator, as the existing metrics.hpp overload documents
130/// (3.6:745-749,769-773). Metrics read the scratch curve at each report read;
131/// they do not consume it or change the engine's held point (3.2:499-509).
132template <class PointSource>
134 const PointSource& curve, std::int64_t n, double initial_capital,
135 const std::string& chart_tz, double first_open, double last_close,
136 std::int64_t bars_in_market, double net_profit,
137 std::int64_t observation_count);
138
139// O1 report-point provider overloads: declarations only, metrics-lane bodies.
140// FULL/STREAMED can reread captured final points in the same five ordered
141// walks through visit()/bounded pages. n counts points, observation_count
142// counts observations (selected M+1 points, M observations). Preserve every
143// formula, float operation grouping, calendar/NaN guard and presented value.
144// Source/read failures propagate; never adapt by materializing an array.
145//
146// F3: SUMMARY_ONLY does not create a captured provider or a private curve tape.
147// These overloads only read captured points; they never dispatch a replay.
148// When a second pass is needed:
149// The host runs EquityMetricsSecondPass and calls install_equity_ratio_result().
150// Until then, reports carry NaN Sharpe/Sortino ratios, monthly and per-bar.
151// BacktestEngine::equity_summary_ratios_ready() is false until installation.
152// A host that never runs that pass must not present those four ratio fields.
153// Release the non-recursive timezone guard before execution dispatch.
155 const report::EquityPointSourceV1& curve, std::int64_t n,
156 double initial_capital, const std::string& chart_tz,
157 double first_open, double last_close, std::int64_t bars_in_market,
158 double net_profit);
159
161 const report::EquityPointSourceV1& curve, std::int64_t n,
162 double initial_capital, const std::string& chart_tz,
163 double first_open, double last_close, std::int64_t bars_in_market,
164 double net_profit, std::int64_t observation_count);
165
166} // namespace metrics
167} // namespace pineforge
pf_equity_point_t operator[](std::int64_t index) const
std::int64_t size() const
ArrayCurve(const pf_equity_point_t *data, std::int64_t point_count)
pf_equity_point_t operator[](std::int64_t index) const
SpillCurve(const ScratchCurveRegion &region)
std::int64_t size() const
SpillCurve(const ScratchCurveReader &reader)
Alternate read boundary for scratch adapters and file-like test readers.
TradeStatsAccumulator(TradeFilter filter, double initial_capital)
TradeStatsAccumulator(const TradeStatsAccumulator &)
TradeStatsAccumulator & operator=(const TradeStatsAccumulator &)
pf_equity_stats_t compute_equity_stats(const pf_equity_point_t *curve, int64_t n, double initial_capital, const std::string &chart_tz, double first_open, double last_close, int64_t bars_in_market, double net_profit)
#define PF_STATIC_ASSERT(condition)
Definition pineforge.h:52
Single per-script-bar equity point.
Definition pineforge.h:326
Equity-curve-derived statistics (all-trades only, like TV).
Definition pineforge.h:272
Trade-level statistics block — computed once each for all / long / short.
Definition pineforge.h:209
Minimal read boundary for the private binary curve (DESIGN 3.8).
A region of the engine-private scratch file (3.8:902-909).
const detail::ScratchFile * scratch