PineForge unreleased
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
market_driver.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <pineforge/bar.hpp>
5
6#include <cstdint>
7#include <optional>
8#include <string>
9
10namespace pineforge {
11inline namespace native_run_spec_v3 { struct NativeRunSpec; }
12inline namespace native_driver_v5 {
13
14// Semantic versions hashed into native continuation identity.
15inline constexpr const char* kNativeDriverSemanticVersion = "native-driver/v5";
16inline constexpr const char* kNativeConsumerSemanticVersion = "native-consumer/v9";
17inline constexpr const char* kNativeCalendarSemanticVersion = "native-calendar/v1";
18
19/// Where a driver point's price came from. Confirmed is a confirmed input bar's
20/// own label; ObservedPrint a realtime tick; the two ModeledOHLC values and
21/// AfterCalculationClose are the modeled waypoints of a confirmed bar's path;
22/// CarriedOpen is a quiet tradable interval's carried last price; PartialFinalized
23/// a partially finalized observed slot; Calculation the script calculation point
24/// itself; CurrentExecution a synchronous execute_current. A host reads it off
25/// NativeDecisionContext::coordinate and never has to infer it.
37
38/// Which leg of a modeled OHLC walk a point sits on. None is a discrete point (a
39/// calculation, an observed print); Open, High, Low and Close are the waypoints,
40/// in the order NativeRunSpec::path_order resolves. A margin check point's
41/// cursor.point.path_phase is the waypoint the check was taken at.
42enum class NativePathPhase : std::uint8_t {
43 None = 0,
44 Open = 1,
45 High = 2,
46 Low = 3,
47 Close = 4,
48};
49
50/// How a script interval or a higher-timeframe bucket was closed. Confirmed means
51/// its own last contributing bar closed it; LazyComplete that the NEXT interval's
52/// first input did — a hole over the last slot, or a script interval a session
53/// close clips (a subscription bucket it clips is Confirmed on its own last bar);
54/// PartialFinalized that a stream end finalized a forming observed slot; no path
55/// produces SessionShortened. Delivered on NativeTimeframeBarContext::completion
56/// for a bucket and on the coordinate for a calculation.
63
64/// Everything the kernel knows about WHERE a point is, as one owning value: its
65/// event ordinal, the script interval index, the named input interval index,
66/// the nominal and scheduled-eligible opens,
67/// the last traded close, the next period and next input opens, the effective time
68/// the account converts and hashes at, the source price time, and the three
69/// classifications above. A host reads it through NativeDecisionContext; mutating
70/// a copy cannot move the consumer's floor, matching time or after-calculation
71/// coordinate.
73 uint64_t ordinal = 0;
75 // The script-bar coordinate is the public index above. Aggregated runs
76 // retain the input slot that supplied this point here for hosts that need
77 // to inspect input cadence; it occupies the former alignment padding and
78 // does not change the v19 C++ layout.
80 int64_t open_ms = 0;
81 int64_t eligible_open_ms = 0;
84 int64_t next_input_open_ms = 0;
85 int64_t effective_time_ms = 0;
90};
91
92/// One point the driver produced: its coordinate, the raw price before slippage or
93/// any grid, the provider's sequence for an observed print (nullopt otherwise),
94/// and whether the point is a matching point, an excursion sample, or both.
95/// Recorded in the event history as the NativeEventKind::Driver rows
96/// native_events() returns.
99 double raw_price = 0.0;
100 std::optional<uint64_t> sequence;
101 bool matching = false;
102 bool excursion = false;
103};
104
105// Generic facts about the retained intrabar driver. They let a host project
106// run diagnostics without consulting a source scheduler or borrowing driver
107// state. Counts are cumulative for the run except the two current-script-bar
108// shape fields.
116
117// Presentation snapshot copied onto the callback stack. Mutating these
118// fields cannot change the consumer's decision floor, matching time, or
119// after-calculation coordinate.
122 int64_t decision_floor_ms = 0;
125 // A non-magnified run is the one-element intrabar path. The sub-bar
126 // timestamp is deliberately separate from the script label: execution
127 // ledgers use the former while script-time policy uses the latter.
128 int sub_index = 0;
129 int sub_count = 1;
131 // Session-day facts of the script bar under delivery, read off the run's
132 // own calendar (NativeRunSpec::session / ::timezone) and session day
133 // (native_calendar::session_day_ordinal: the cycle that rolls at the first
134 // window's start, keyed to its trading date — an overnight session is one
135 // day across local midnight). Every callback of the bar carries the same
136 // four: its open, its sub-bars and ticks, its calculation, and every fill
137 // and recalculation on it.
138 // in_session in session at the bar's label, or at its interval's
139 // first eligible instant when later (a break's reopen).
140 // opens_session_day in session, and the bar before it is not, or is on
141 // another session day.
142 // closes_session_day in session, and the bar after it is not, or is on
143 // another session day.
144 // "The bar before / after" is the one the run holds — the batch input or
145 // stream warmup being consumed — and otherwise the calendar's previous
146 // or next eligible input slot, across declared breaks. At the run's own
147 // edges nothing is held: its first bar opens its session day, and a
148 // batch's final bar closes it (complete input); a stream reads on.
149 // closes_session_day_open_ended
150 // closes_session_day for a run whose input goes on
151 // past it: a batch's final bar, which nothing held
152 // follows, is judged by the calendar's next eligible
153 // input slot, exactly as a stream's bar is, instead of by the
154 // run's end. Every other bar reads closes_session_day.
155 // It is what a host that recomputes a batch whose
156 // last input is still forming reads for that bar.
157 // A bar at or above the session-day grain (D, W, M) holds whole session
158 // days: all four are true. Derived per point from the calendar, the label
159 // and the run's input, they are presentation, not state, and fold into no
160 // digest. They sit in what was this struct's padding, so no member moved.
161 bool in_session = false;
162 bool opens_session_day = false;
163 bool closes_session_day = false;
165 int64_t sub_bar_open_ms = 0;
168};
169
170// Pump-produced events obtain ordinals from the consumer allocator.
172public:
173 virtual ~INativeDriverSink() = default;
174 /// The consumer's ordinal allocator, called by the pump for every event it
175 /// produces. Implemented by the kernel's own consumer; a host never implements
176 /// this interface.
177 virtual uint64_t allocate_native_ordinal() = 0;
178 /// A point at which live requests may match. The consumer runs the matching pass
179 /// here; excursion-only points do not reach it.
180 virtual void on_native_matching_point(const NativeDriverPoint& point) = 0;
181 /// A point that updates open lots' favorable and adverse excursions without
182 /// offering a match.
183 virtual void on_native_excursion(const NativeDriverPoint& point) = 0;
184 /// The script bar's calculation point, with the complete script bar and its
185 /// coordinate. The consumer turns it into the host's on_native_bar /
186 /// on_native_recalculate call.
187 virtual void on_native_calculation(const Bar& script_bar, const NativeCoordinate& coordinate) = 0;
188};
189
190/// Whether a bar can be admitted at all: finite positive OHLC with
191/// high >= max(open, close) and low <= min(open, close), and a finite nonnegative
192/// volume. A run's NativeFeedTolerance may relax the positivity and the volume
193/// half; this is the strict predicate those bits are measured against. It is also
194/// what refuses a bar of an auxiliary feed (InvalidAuxiliaryFeedBar).
195bool native_bar_structurally_valid(const Bar& bar) noexcept;
196
197// Confirmed-bar labels admitted by v9: the immutable nominal slot origin
198// and the scheduled clipped eligible opening. Both identify one slot key
199// `interval.open_ms`. Mid-slot and other off-grid timestamps are refused.
201 const native_calendar::NativeInterval& interval, int64_t timestamp) noexcept {
202 return timestamp == interval.open_ms || timestamp == interval.eligible_open_ms;
203}
204
205// Canonical exclusive completion of a confirmed input slot. Source-price
206// time remains a separate fact (bar.timestamp / last print).
208 const native_calendar::NativeInterval& interval) noexcept {
209 return interval.next_period_open_ms;
210}
211
212// ---------------------------------------------------------------------------
213// Shared pure input preflight (host + runner)
214//
215// Exact signature the runner worker should bind:
216// NativeInputPreflightResult
217// preflight_native_inputs(const NativeRunSpec& spec,
218// const Bar* bars,
219// int n,
220// NativeInputPolicy policy);
221//
222// Calendar-aware, allocation of diagnostic text is the caller's job.
223// No host reset, callback, identity mutation, high-water change, or
224// decision-floor change. Parses the spec's session/timezone/input_tf
225// on each call. Batch may be sparse; StreamWarmup refuses missing
226// in-session bars after a closed gap by walking next_input_open_ms
227// through interval_containing (Fri 16 -> Mon 11 cannot skip Mon 09:30).
228// Warmup complete-script policy is NOT decided here.
229// ---------------------------------------------------------------------------
230enum class NativeInputPolicy : std::uint8_t {
231 Batch = 0,
233};
234
235/// Why a bar array was refused before the run touched anything. NullArray and
236/// InvalidCount are the argument shape; StructuralInvalid is
237/// native_bar_structurally_valid; Unaligned and OffGridLabel are the slot label;
238/// NotStrictlyIncreasing and OverlappingSlot the ordering; InSessionGap a missing
239/// in-session slot, which only a stream warmup refuses; CalendarFailure a calendar
240/// the spec's own timezone and session could not resolve. A preflight refusal
241/// leaves the host Ready or Running and does NOT raise the decision floor.
255
256/// What preflight_native_inputs answers: the error and the first offending bar's
257/// index, or -1 when the refusal is not about one bar. ok() and the explicit
258/// operator bool are the success reads.
261 int index = -1; // first offending bar, or -1 when not index-specific
262
263 constexpr bool ok() const noexcept {
265 }
266 constexpr explicit operator bool() const noexcept { return ok(); }
267};
268
269/// Judge a whole bar array against a run spec before any of it is consumed, under
270/// NativeInputPolicy::Batch (sparse input is admitted; missing in-session slots
271/// are legal) or ::StreamWarmup (every provided slot must be a complete confirmed
272/// interval and an in-session gap is refused). Every public begin runs it first,
273/// which is why an invalid array leaves the lifecycle where it was instead of
274/// failing the host.
276 const NativeRunSpec& spec,
277 const Bar* bars,
278 int n,
279 NativeInputPolicy policy);
280
281} // inline namespace native_driver_v5
282} // namespace pineforge
virtual void on_native_excursion(const NativeDriverPoint &point)=0
A point that updates open lots' favorable and adverse excursions without offering a match.
virtual uint64_t allocate_native_ordinal()=0
The consumer's ordinal allocator, called by the pump for every event it produces.
virtual void on_native_calculation(const Bar &script_bar, const NativeCoordinate &coordinate)=0
The script bar's calculation point, with the complete script bar and its coordinate.
virtual void on_native_matching_point(const NativeDriverPoint &point)=0
A point at which live requests may match.
NativeInputPreflightResult preflight_native_inputs(const NativeRunSpec &spec, const Bar *bars, int n, NativeInputPolicy policy)
Judge a whole bar array against a run spec before any of it is consumed, under NativeInputPolicy::Bat...
bool native_confirmed_bar_label_admitted(const native_calendar::NativeInterval &interval, int64_t timestamp) noexcept
constexpr const char * kNativeConsumerSemanticVersion
constexpr const char * kNativeDriverSemanticVersion
int64_t native_canonical_input_completion(const native_calendar::NativeInterval &interval) noexcept
NativeCompletionKind
How a script interval or a higher-timeframe bucket was closed.
constexpr const char * kNativeCalendarSemanticVersion
NativeInputPreflightError
Why a bar array was refused before the run touched anything.
bool native_bar_structurally_valid(const Bar &bar) noexcept
Whether a bar can be admitted at all: finite positive OHLC with high >= max(open, close) and low <= m...
NativePathPhase
Which leg of a modeled OHLC walk a point sits on.
NativePriceProvenance
Where a driver point's price came from.
Everything the kernel knows about WHERE a point is, as one owning value: its event ordinal,...
One point the driver produced: its coordinate, the raw price before slippage or any grid,...
What preflight_native_inputs answers: the error and the first offending bar's index,...
One complete setup value, staged/copied by NativeStrategyHost before it is applied at begin.