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_) {
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);
38 state.aggregator.set_early_close_completes(session_template_knows_early_close());
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();
46 const int script_seconds = script_tf_seconds_;
48 || effective_input_tf != script_tf_ || input_bars ==
nullptr || n_input <= 0
49 || input_seconds <= 0 || script_seconds <= 0) {
54 const std::int64_t input_ms =
static_cast<std::int64_t
>(input_seconds) * 1000;
55 for (
auto& state : security_eval_states_) {
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
63 && (calendar_month || requested_seconds > script_seconds);
64 if (!eligible)
continue;
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);
76 return input_bars[child].timestamp;
78 int projection_begin = 0;
79 while (projection_begin < n_input
80 && security_input_precedes_range_start(
81 state, child_instant_ms(projection_begin))) {
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;
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);
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;
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;
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});
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);
121 aggregate = input_bars[i];
123 merge(aggregate, input_bars[i]);
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);
134void PineStrategyHost::clear_historical_security_lookahead_projections() {
137 entry.second.historical_projections.clear();
138 entry.second.historical_projection_cursor = 0;
139 entry.second.historical_projection_dispatched =
false;
std::vector< Bar > aux_security_bars_
bool historical_security_lookahead_projection_active_
int64_t security_calling_close_ms_
std::vector< std::size_t > aux_security_chart_begin_
std::map< int, PineSecurityEvalState > pine_security_states_
bool historical_security_lookahead_projection_
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.