PineForge v0.13.1-379-g9b50973
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
pine_scheduler.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <algorithm>
7#include <cstdint>
8#include <limits>
9#include <optional>
10#include <string>
11#include <vector>
12
13namespace pineforge::source {
14
16
17// Source cadence over generic native callbacks. The driver remains the sole
18// owner of matching; this class owns only language publication, retained begin
19// data and the Pine calc-on-order-fills callback cadence.
21public:
22 void capture_begin(const NativeBeginArgs&);
24 void input(const Bar&, const NativeInputContext&, PineStrategyHost&);
25 void tick(const Bar&, const NativeTickContext&, PineStrategyHost&);
27 void bar(const Bar&, const NativeDecisionContext&, PineStrategyHost&);
28 // Applied-notification bookkeeping only. The calc_on_order_fills
29 // recalculation itself is the kernel's cadence now
30 // (NativeCalculationTrigger::BarCloseAndFills): the consumer drives it
31 // from the same drain iteration, right after this callback returns, and
32 // delivers it as recalculate() below.
34 // Pine's own admission of a fill recalculation, re-checked at the
35 // kernel's OrderFill cursor. Pure: it reads the freshly advanced applied
36 // cursor, the source config and adapter facts, and mutates nothing.
41
42 PineLanguageState& language() noexcept { return language_; }
43 bool is_first_tick() const noexcept { return language_.is_first_tick_; }
44 bool is_last_tick() const noexcept { return language_.is_last_tick_; }
45 bool bar_magnifier_enabled() const noexcept { return retained_.bar_magnifier; }
46 bool history_advances_new_bar() const noexcept {
47 return language_.is_first_tick_ && language_.history_slot_is_new_;
48 }
49 bool security_series_slot_is_new(int) const noexcept {
50 return language_.history_slot_is_new_;
51 }
52 double previous_chart_close() const noexcept { return language_.prev_chart_close_; }
53 int bar_index_offset() const noexcept { return language_.bar_index_offset_; }
54 void set_bar_index_offset(int value) noexcept { language_.bar_index_offset_ = value; }
55 void set_source_series_active(bool value) noexcept { language_._src_series_active_ = value; }
56 double script_position_view(int bar_index, PositionSide side, double quantity) const noexcept;
57 void freeze_script_position_view(int bar_index, PositionSide side, double quantity,
58 const std::vector<PyramidEntry>& lots);
59 void clear_script_position_view() noexcept;
60 const Series<double>& source_series(const std::string&) const;
61 void fixture_publish_source_series(const Bar&, bool new_history_slot);
62 int source_bar_count() const noexcept { return source_bar_count_; }
63 std::optional<Bar> next_source_bar(int interval_index) const {
64 if (retained_.is_stream || retained_.bar_magnifier
65 || (!retained_.input_tf.empty() && !retained_.script_tf.empty()
66 && retained_.input_tf != retained_.script_tf)
67 || interval_index < 0
68 || interval_index + 1 >= static_cast<int>(retained_.bars.size())) {
69 return std::nullopt;
70 }
71 return retained_.bars[static_cast<std::size_t>(interval_index + 1)];
72 }
73 bool terminal_source_bar() const noexcept {
74 return expected_source_bars_ > 0 && source_bar_count_ >= expected_source_bars_;
75 }
76 int source_bar_index_for(const NativeDecisionContext& context) const noexcept;
77 std::optional<double> next_input_waypoint(
78 const NativeDecisionContext&, double current_price,
79 NativePathOrder) const noexcept;
80 const Bar* current_script_bar() const noexcept {
81 return current_script_bar_valid_ ? &current_script_bar_ : nullptr;
82 }
83 std::optional<Bar> broker_bar(const NativeDecisionContext& context) const {
84 const auto& bars = retained_.bars;
85 const std::size_t n = bars.size();
86 if (n > 0) {
87 if (broker_bar_cursor < n && bars[broker_bar_cursor].timestamp == context.sub_bar_open_ms) {
88 return bars[broker_bar_cursor];
89 }
90 if (broker_bar_cursor >= n || bars[broker_bar_cursor].timestamp > context.sub_bar_open_ms) {
91 broker_bar_cursor = 0;
92 }
93 while (broker_bar_cursor < n && bars[broker_bar_cursor].timestamp < context.sub_bar_open_ms) {
94 ++broker_bar_cursor;
95 }
96 if (broker_bar_cursor < n && bars[broker_bar_cursor].timestamp == context.sub_bar_open_ms) {
97 return bars[broker_bar_cursor];
98 }
99 const auto found = std::find_if(bars.begin(), bars.end(),
100 [&](const Bar& bar) { return bar.timestamp == context.sub_bar_open_ms; });
101 if (found != bars.end()) {
102 broker_bar_cursor = static_cast<std::size_t>(std::distance(bars.begin(), found));
103 return *found;
104 }
105 }
106 return current_script_bar_valid_ ? std::optional<Bar>{current_script_bar_}
107 : std::nullopt;
108 }
109
110 void hash_state(BrokerStateHashSink&) const;
111
112private:
113 struct RetainedBegin {
114 std::vector<Bar> bars;
115 std::string input_tf;
116 std::string script_tf;
117 bool bar_magnifier = false;
118 int magnifier_samples = 4;
120 bool volume_weighted = false;
121 int volume_weighted_min_samples = 2;
122 int volume_weighted_max_samples = 64;
123 bool is_stream = false;
124 int warmup_n = 0;
125 bool simple_run = false;
126 };
127
128 void publish_series(const Bar&, PineStrategyHost&);
129 void update_source_series(const Bar&);
130 void reset_language();
131 void snapshot_coof_script_state(PineStrategyHost&);
132 void restore_coof_script_state(PineStrategyHost&);
133 void commit_coof_script_state(PineStrategyHost&);
134
135 struct DeferredBoundaryInput {
136 Bar bar{};
137 std::int64_t next_input_ms = 0;
138 std::int64_t prior_script_open_ms = 0;
139 bool calling_bar_complete = false;
140 bool all_security_states = false;
141 bool active = false;
142 };
143
144 // Derived lookup cursor over retained_.bars (reset-and-rescan in
145 // broker_bar()); waived from the state hash by
146 // scripts/check_broker_state_hash_coverage.py::SCHEDULER_CACHE_WAIVERS.
147 mutable std::size_t broker_bar_cursor = 0;
148
149 // @source-state begin
150 PineLanguageState language_;
151 RetainedBegin retained_;
152 std::int64_t current_script_open_ms_ = 0;
153 Bar current_script_bar_{};
154 bool current_script_bar_valid_ = false;
155 bool saw_open_fill_ = false;
156 int open_point_fills_ = 0;
157 int source_bar_count_ = 0;
158 int expected_source_bars_ = 0;
159 std::uint64_t applied_cursor_ = 0;
160 std::int64_t coof_callback_script_open_ = std::numeric_limits<std::int64_t>::min();
161 std::int64_t last_published_script_open_ms_ =
162 std::numeric_limits<std::int64_t>::min();
163 std::int64_t prior_input_script_open_ms_ = std::numeric_limits<std::int64_t>::min();
164 std::int64_t awaiting_legacy_script_open_ms_ = std::numeric_limits<std::int64_t>::min();
165 std::int64_t last_stream_input_open_ms_ = std::numeric_limits<std::int64_t>::min();
166 std::vector<unsigned char> input_script_completes_;
167 std::vector<unsigned char> input_script_boundary_completes_;
168 bool uses_aux_security_feed_ = false;
169 DeferredBoundaryInput deferred_boundary_input_{};
170 // @source-state end
171};
172
173} // namespace pineforge::source
std::optional< double > next_input_waypoint(const NativeDecisionContext &, double current_price, NativePathOrder) const noexcept
void tick(const Bar &, const NativeTickContext &, PineStrategyHost &)
void input(const Bar &, const NativeInputContext &, PineStrategyHost &)
int source_bar_count() const noexcept
double script_position_view(int bar_index, PositionSide side, double quantity) const noexcept
bool coof_recalculation_due(const native_order::ExecutionAppliedEvent &, const NativeDecisionContext &, PineStrategyHost &) const
bool is_first_tick() const noexcept
std::optional< Bar > broker_bar(const NativeDecisionContext &context) const
bool bar_magnifier_enabled() const noexcept
void fixture_publish_source_series(const Bar &, bool new_history_slot)
const Bar * current_script_bar() const noexcept
void recalculate(const native_order::ExecutionAppliedEvent &, const NativeDecisionContext &, PineStrategyHost &)
std::optional< Bar > next_source_bar(int interval_index) const
int bar_index_offset() const noexcept
const Series< double > & source_series(const std::string &) const
bool terminal_source_bar() const noexcept
int source_bar_index_for(const NativeDecisionContext &context) const noexcept
void bar_open(const Bar &, const NativeDecisionContext &, PineStrategyHost &)
PineLanguageState & language() noexcept
void set_source_series_active(bool value) noexcept
void hash_state(BrokerStateHashSink &) const
void capture_begin(const NativeBeginArgs &)
void freeze_script_position_view(int bar_index, PositionSide side, double quantity, const std::vector< PyramidEntry > &lots)
void applied(const native_order::ExecutionAppliedEvent &)
void bar(const Bar &, const NativeDecisionContext &, PineStrategyHost &)
void set_bar_index_offset(int value) noexcept
bool is_last_tick() const noexcept
bool security_series_slot_is_new(int) const noexcept
double previous_chart_close() const noexcept
bool history_advances_new_bar() const noexcept
NativePathOrder
Generic ordering for a modeled OHLC path.
MagnifierDistribution
Definition magnifier.hpp:7
Borrowed begin-call facts.
Accepted input facts presented before the generic consumer aggregates the bar into its script interva...
One accepted realtime print before native matching at its current decision point.
One committed execution: the definition, the cursor, the resolved price and units,...