PineForge unreleased
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
selected_window_plan.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <pineforge/bar.hpp>
4
5#include <cstddef>
6#include <cstdint>
7#include <optional>
8#include <string>
9
10// The selected primary planner: from the supplied primary rows and one
11// selected-window request, which rows a selected run keeps and what the native
12// consumer will execute over them. Pure and read-only: it constructs no
13// strategy or engine, runs no host callback, hashes nothing, opens no feed or
14// artifact, and reads only the rows' timestamps. The caller owns the row array;
15// the result owns its values. An allocation failure (std::bad_alloc)
16// propagates; any other exception of the native calendar becomes a status,
17// never a guessed value.
18//
19// Grouping is the consumer's own (NativeExecutionConsumer for a batch run): the
20// input interval at the row's timestamp, then the script interval at that input
21// interval's open, both from native_calendar and its session-day memo. A
22// group's key and its published label are both the script interval's open_ms
23// and are held separately. A FeedTolerant request on a Passthrough pairing
24// groups on each row's own timestamp; otherwise a failed interval lookup falls
25// back to that raw partition under FeedTolerant and is a refusal without it. The
26// groups a run executes follow the consumer's three seal rules: an input that
27// reaches the script interval's next_period_open, the first input of a later
28// group, and, at the end of the batch, a final input that reaches the script
29// interval's last_traded_close. A final window group none of them seals is
30// never executed and is not counted.
31//
32// Admission order: the script token (one of the first build's eight intraday
33// primary tokens) and an explicit input timeframe; T/E/F as signed 53-bit
34// integers with T < E and F <= T; preroll_bars <= 5000; the row array; the
35// conservative clock identity (after the empty default only the exact spellings
36// UTC, GMT, Etc/UTC and Etc/GMT fold together, every other zone string is
37// compared exactly, and the one session string serves both clocks); the native
38// session, timezone and timeframe grammar and the pairing;
39// T, E and F each equal to the nominal open of the native script interval that
40// holds them, independent of the rows; then the rows (strictly increasing, each
41// F <= timestamp < E). Nothing snaps a boundary.
42//
43// On a refusal only status, option, bound, value_ms, previous_boundary_ms and
44// next_boundary_ms are set; every count is zero. `option` names the faulty
45// request member:
46// RequestInvalid script_tf, input_tf, start_ms, end_ms, fed_start_ms,
47// preroll_bars (value_ms = the count), rows. A bound
48// carries bound 0/1/2 and value_ms; end_ms <= start_ms
49// carries previous_boundary_ms = T, fed_start_ms > T
50// carries next_boundary_ms = T.
51// CalendarUnsupported timezone (the clock identities differ), engine_timezone
52// (grammar), session (grammar), calendar (a native
53// calendar exception), timeframes (a pairing the
54// consumer does not group), start_ms/end_ms/fed_start_ms
55// (no native interval holds the boundary), rows (no input
56// or script interval holds a row, value_ms = its
57// timestamp), and start_ms with bound 0 when one group
58// would hold rows on both sides of T (previous_boundary_ms
59// and next_boundary_ms = that group's open and next open).
60// BoundaryUnaligned start_ms, end_ms or fed_start_ms with bound 0, 1 or 2,
61// value_ms = the boundary, previous_boundary_ms and
62// next_boundary_ms = the open and next_period_open of the
63// native script interval that holds it.
64// FeedRangeInvalid rows; bound 2 below F, bound 1 at or after E, value_ms =
65// the row's timestamp, previous_boundary_ms = F,
66// next_boundary_ms = E.
67// RowsUnordered rows; value_ms = the row's timestamp,
68// previous_boundary_ms = the row before it.
69// InternalError a native exception outside the admission step, or a
70// state the plan's own two passes disagree on.
71//
72// The plan is a prediction, not a count: the actual executed counts are the
73// consumer's observed counters, which must later equal it. A pending PRE-T
74// group that nothing seals is completed once at the accepted T from its own
75// retained aggregate (the consumer integration, a separate change, must do that
76// without synthetic prices, orders or fills and before capture);
77// complete_pending_preroll_at_horizon says it is needed. An OFF run never
78// uses this planner.
79
80namespace pineforge {
81inline namespace selected_window_plan_v1 {
82
93 std::string option;
94 int bound = -1; // 0=T, 1=E, 2=F, -1=no boundary detail
98 std::uint64_t trimmed_script_bars = 0, trim_index = 0;
99 std::uint64_t fed_input_bars = 0, fed_script_bars = 0;
101 std::int64_t trim_start_ms = 0;
102 std::optional<std::int64_t> preroll_first_bar_ms, preroll_last_bar_ms;
103 std::optional<std::int64_t> supplied_first_data_ms, supplied_last_data_ms;
104 std::optional<std::int64_t> fed_first_data_ms, fed_last_data_ms;
105 std::optional<std::int64_t> window_first_data_ms, window_last_data_ms;
106 bool shortfall = false;
108};
109SelectedPrimaryPlan plan_selected_primary(const Bar* rows, std::size_t count,
110 const SelectedPlanRequest& request);
111
112// The retained primary count, for the source layer's tail expectations: over
113// rows the caller has ALREADY retained (any pre-roll trimming happened before
114// them), the number of script bars a selected batch run executes. It is
115// plan_selected_primary's fed_script_bars for a feed that plan would not trim
116// further, taken from the same clock admission, boundary check and consumer
117// bucket walk (no second calendar), with no F boundary, no pre-roll request and
118// no 5000 cap: a native caller's retained prehistory is its own. Every group
119// that opens before T is counted (each is executed, a last pending one by the
120// completion at the accepted T) together with every window group the consumer's
121// seal rules execute; an unsealed window tail adds none. Pure and read-only like
122// the planner: it constructs no strategy or consumer and reads only timestamps.
123//
124// Admission order: the script token (one of the eight intraday primary tokens)
125// and an explicit input timeframe; T and E as signed 53-bit integers with
126// T < E; the row array; the conservative clock identity, the native session,
127// timezone and timeframe grammar and the pairing, exactly as the planner
128// admits them; T and E each equal to the nominal open of the native script
129// interval that holds them; then the rows (strictly increasing, each < E).
130// Nothing snaps a boundary. A refusal sets `status` and `option` with the
131// planner's names for the same fault (script_tf, input_tf, start_ms, end_ms,
132// rows, timezone, engine_timezone, session, calendar, timeframes) and leaves
133// script_bars zero; a group that would hold rows on both sides of T is
134// CalendarUnsupported on start_ms. Allocation failure behaves as in the
135// planner: std::bad_alloc propagates and any other native calendar exception
136// becomes a status.
148 const SelectedRetainedRequest& request);
149
150// The script bars an admitted selected batch run executes over its retained rows:
151// count_selected_retained_primary with E unchecked and unbounded. The selected
152// window setter admits any T < E, the consumer executes the same groups whatever E
153// is, and the count above refuses only on E's own alignment or a row at or after
154// it, so a run reads the one answer every such E gives. T, the clock and the rows
155// are admitted exactly as above.
157 const SelectedRetainedRequest& request);
158
159} // inline namespace selected_window_plan_v1
160} // namespace pineforge
SelectedPrimaryPlan plan_selected_primary(const Bar *rows, std::size_t count, const SelectedPlanRequest &request)
SelectedRetainedCount count_selected_executed_primary(const Bar *rows, std::size_t count, const SelectedRetainedRequest &request)
SelectedRetainedCount count_selected_retained_primary(const Bar *rows, std::size_t count, const SelectedRetainedRequest &request)