PineForge v0.13.1-379-g9b50973
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
pine_scheduler.cpp
Go to the documentation of this file.
3
4#include <algorithm>
5#include <limits>
6
7namespace pineforge::source {
8
9void PineStrategyHost::init_security_eval_states_for_run(
10 const std::string& effective_input_tf) {
11 security_next_input_ms_ = 0;
13 for (auto& state : security_eval_states_) {
14 state.feed_count = 0;
15 state.eval_complete_count = 0;
16 state.eval_partial_count = 0;
17 state.current_bar = Bar{};
18 state.current_sub_bar_count = 0;
19 PineSecurityEvalState& pine = pine_security_state(state.sec_id);
20 pine.lower_tf_sub_bar_index = 0;
21 pine.lower_tf_input_buffer.clear();
22 pine.first_bucket_published = false;
23 pine.deferred_aux.clear();
24 pine.slice_open_label = 0;
25 pine.last_published_label = 0;
26 pine.historical_projections.clear();
27 pine.historical_projection_cursor = 0;
28 pine.historical_projection_dispatched = false;
29 state.native_feed_index = -1;
30 state.native_bars_by_label.clear();
31 state.aggregator = TimeframeAggregator();
32 if (pine.lower_tf_emulation || pine.lower_tf_use_input) continue;
33 const int ratio = tf_ratio(effective_input_tf, state.tf);
34 if (ratio > 1 || ratio == -1) {
35 state.aggregator = TimeframeAggregator(
36 state.tf, effective_input_tf, syminfo_.timezone, syminfo_.session);
37 }
38 state.aggregator.set_early_close_completes(session_template_knows_early_close());
39 }
40}
41
42void PineStrategyHost::prepare_historical_security_lookahead_projections(
43 const Bar* input_bars, int n_input, const std::string& effective_input_tf) {
44 clear_historical_security_lookahead_projections();
45 const int input_seconds = tf_to_seconds(effective_input_tf);
46 const int script_seconds = script_tf_seconds_;
47 if (!historical_security_lookahead_projection_ || stream_warmup_mode_
48 || effective_input_tf != script_tf_ || input_bars == nullptr || n_input <= 0
49 || input_seconds <= 0 || script_seconds <= 0) {
50 return;
51 }
52
54 const std::int64_t input_ms = static_cast<std::int64_t>(input_seconds) * 1000;
55 for (auto& state : security_eval_states_) {
56 const int requested_seconds = tf_to_seconds(state.tf);
57 const bool calendar_month = requested_seconds == -1
59 PineSecurityEvalState& pine = pine_security_state(state.sec_id);
60 const bool eligible = !pine.lower_tf_requested && !pine.lower_tf_emulation
61 && !pine.lower_tf_use_input && pine.lookahead_on && !pine.gaps_on
62 && !pine.heikinashi
63 && (calendar_month || requested_seconds > script_seconds);
64 if (!eligible) continue;
65
66 auto child_instant_ms = [&](int child) -> std::int64_t {
67#ifdef PINEFORGE_HAS_AUX_SECURITY_FEED_V1
68 if (aux_security_feed_enabled()) {
69 const std::size_t index = static_cast<std::size_t>(child);
70 if (index < aux_security_chart_begin_.size()
72 return aux_security_bars_[aux_security_chart_begin_[index]].timestamp;
73 }
74 }
75#endif
76 return input_bars[child].timestamp;
77 };
78 int projection_begin = 0;
79 while (projection_begin < n_input
80 && security_input_precedes_range_start(
81 state, child_instant_ms(projection_begin))) {
82 ++projection_begin;
83 }
84 if (projection_begin >= n_input) continue;
85 const int projection_count = n_input - projection_begin;
86 const int expected_children = std::max(
87 1, (calendar_month ? 31 * 86400 : requested_seconds) / input_seconds);
88 pine.historical_projections.reserve(
89 static_cast<std::size_t>(projection_count / expected_children + 1));
90 pine.historical_projection_cursor = 0;
91 pine.historical_projection_dispatched = false;
92
93 auto crosses_requested_boundary = [&](std::int64_t from_ms, std::int64_t to_ms) {
94 if (from_ms != 0 && to_ms != 0) {
95 if (state.aggregator.has_native_periods())
96 return state.aggregator.period_changes(from_ms, to_ms);
97 return tf_change(from_ms, to_ms, state.tf,
98 syminfo_.timezone, syminfo_.session);
99 }
100 const std::int64_t requested_ms =
101 static_cast<std::int64_t>(requested_seconds) * 1000;
102 return requested_ms > 0 && from_ms / requested_ms != to_ms / requested_ms;
103 };
104 auto merge = [](Bar& aggregate, const Bar& child) {
105 aggregate.high = std::max(aggregate.high, child.high);
106 aggregate.low = std::min(aggregate.low, child.low);
107 aggregate.close = child.close;
108 aggregate.volume += child.volume;
109 };
110 auto publish_group = [&](int begin, const Bar& aggregate, bool complete) {
111 pine.historical_projections.push_back(
112 HistoricalSecurityProjection{aggregate, child_instant_ms(begin), complete});
113 };
114
115 int group_begin = projection_begin;
116 Bar aggregate = input_bars[projection_begin];
117 for (int i = projection_begin + 1; i < n_input; ++i) {
118 if (crosses_requested_boundary(aggregate.timestamp, input_bars[i].timestamp)) {
119 publish_group(group_begin, aggregate, true);
120 group_begin = i;
121 aggregate = input_bars[i];
122 } else {
123 merge(aggregate, input_bars[i]);
124 }
125 }
126 bool final_complete = false;
127 const std::int64_t last_timestamp = input_bars[n_input - 1].timestamp;
128 if (last_timestamp <= std::numeric_limits<std::int64_t>::max() - input_ms)
129 final_complete = crosses_requested_boundary(last_timestamp, last_timestamp + input_ms);
130 publish_group(group_begin, aggregate, final_complete);
131 }
132}
133
134void PineStrategyHost::clear_historical_security_lookahead_projections() {
136 for (auto& entry : pine_security_states_) {
137 entry.second.historical_projections.clear();
138 entry.second.historical_projection_cursor = 0;
139 entry.second.historical_projection_dispatched = false;
140 }
141}
142
143} // namespace pineforge::source
std::vector< std::size_t > aux_security_chart_begin_
std::map< int, PineSecurityEvalState > pine_security_states_
int tf_to_seconds(const std::string &tf)
Convert a TradingView timeframe string to seconds.
int tf_ratio(const std::string &input_tf, const std::string &target_tf)
Compute how many input bars fit into one target bar.
CalendarPeriod calendar_period_for(const std::string &tf)
Determine the calendar period for a target TF string.
bool tf_change(int64_t prev_ms, int64_t curr_ms, const std::string &tf)
Check if prev/curr timestamps cross a timeframe boundary.