14 if (args.
bars && args.
n > 0) next.bars.assign(args.
bars, args.
bars + args.
n);
23 retained_ = std::move(next);
26void PineScheduler::reset_language() {
39 current_script_open_ms_ = 0; saw_open_fill_ =
false; open_point_fills_ = 0;
40 current_script_bar_ = {}; current_script_bar_valid_ =
false;
41 source_bar_count_ = 0; expected_source_bars_ = 0; applied_cursor_ = 0;
42 coof_callback_script_open_ = std::numeric_limits<std::int64_t>::min();
43 last_published_script_open_ms_ = std::numeric_limits<std::int64_t>::min();
44 prior_input_script_open_ms_ = std::numeric_limits<std::int64_t>::min();
45 awaiting_legacy_script_open_ms_ = std::numeric_limits<std::int64_t>::min();
46 last_stream_input_open_ms_ = std::numeric_limits<std::int64_t>::min();
47 input_script_completes_.clear();
48 input_script_boundary_completes_.clear();
49 uses_aux_security_feed_ =
false;
50 deferred_boundary_input_ = {};
54 if (language_._src_series_active_) {
55 language_.coof_checkpoint_src_open_ = language_._src_open_;
56 language_.coof_checkpoint_src_high_ = language_._src_high_;
57 language_.coof_checkpoint_src_low_ = language_._src_low_;
58 language_.coof_checkpoint_src_close_ = language_._src_close_;
59 language_.coof_checkpoint_src_volume_ = language_._src_volume_;
60 language_.coof_checkpoint_src_hl2_ = language_._src_hl2_;
61 language_.coof_checkpoint_src_hlc3_ = language_._src_hlc3_;
62 language_.coof_checkpoint_src_ohlc4_ = language_._src_ohlc4_;
63 language_.coof_checkpoint_src_hlcc4_ = language_._src_hlcc4_;
65 language_.coof_checkpoint_prev_chart_close_ = language_.prev_chart_close_;
66 language_.coof_checkpoint_last_chart_close_ = language_.last_chart_close_;
67 language_.coof_checkpoint_contains_current_bar_ =
false;
68 host.snapshot_script_state();
72 if (language_._src_series_active_) {
73 language_._src_open_ = language_.coof_checkpoint_src_open_;
74 language_._src_high_ = language_.coof_checkpoint_src_high_;
75 language_._src_low_ = language_.coof_checkpoint_src_low_;
76 language_._src_close_ = language_.coof_checkpoint_src_close_;
77 language_._src_volume_ = language_.coof_checkpoint_src_volume_;
78 language_._src_hl2_ = language_.coof_checkpoint_src_hl2_;
79 language_._src_hlc3_ = language_.coof_checkpoint_src_hlc3_;
80 language_._src_ohlc4_ = language_.coof_checkpoint_src_ohlc4_;
81 language_._src_hlcc4_ = language_.coof_checkpoint_src_hlcc4_;
83 language_.prev_chart_close_ = language_.coof_checkpoint_prev_chart_close_;
84 language_.last_chart_close_ = language_.coof_checkpoint_last_chart_close_;
85 host.restore_script_state();
89 if (language_._src_series_active_) {
90 language_.coof_checkpoint_src_open_ = language_._src_open_;
91 language_.coof_checkpoint_src_high_ = language_._src_high_;
92 language_.coof_checkpoint_src_low_ = language_._src_low_;
93 language_.coof_checkpoint_src_close_ = language_._src_close_;
94 language_.coof_checkpoint_src_volume_ = language_._src_volume_;
95 language_.coof_checkpoint_src_hl2_ = language_._src_hl2_;
96 language_.coof_checkpoint_src_hlc3_ = language_._src_hlc3_;
97 language_.coof_checkpoint_src_ohlc4_ = language_._src_ohlc4_;
98 language_.coof_checkpoint_src_hlcc4_ = language_._src_hlcc4_;
100 language_.coof_checkpoint_prev_chart_close_ = language_.prev_chart_close_;
101 language_.coof_checkpoint_last_chart_close_ = language_.last_chart_close_;
102 language_.coof_checkpoint_contains_current_bar_ =
true;
103 host.commit_script_state();
108 const bool static_eligible = !retained_.is_stream && !retained_.bar_magnifier
109 && retained_.input_tf.empty() && retained_.script_tf.empty();
110 const auto state = host.native_state();
111 const bool undetected = state.spec && state.spec->timeframe_undetected;
112 const int ratio = undetected || !state.spec ? 1
113 :
tf_ratio(state.spec->input_tf, state.spec->script_tf);
114 const bool needs_aggregation = ratio > 1 || ratio == -1;
115 input_script_completes_.assign(retained_.bars.size(), 1U);
116 input_script_boundary_completes_.assign(retained_.bars.size(), 0U);
117 if (needs_aggregation && state.spec) {
119 state.spec->timezone, state.spec->session);
120 for (std::size_t i = 0; i < retained_.bars.size(); ++i) {
122 input_script_completes_[i] = aggregate.
is_complete ? 1U : 0U;
123 input_script_boundary_completes_[i] = aggregate.
is_complete
125 state.spec->script_tf, state.spec->timezone,
126 state.spec->session) ? 1U : 0U;
129 expected_source_bars_ = 0;
130 for (
const auto complete : input_script_completes_) {
131 expected_source_bars_ += complete != 0U ? 1 : 0;
133 host.stream_warmup_mode_ = retained_.is_stream;
134 host.scheduler_prepare_script_run(retained_.bars, static_eligible,
135 expected_source_bars_, !needs_aggregation);
146 if (!retained_.simple_run) host.scheduler_configure_security_evaluators();
147 uses_aux_security_feed_ = host.scheduler_uses_aux_security_feed();
148 host.scheduler_prepare_security_sequence(retained_.bars);
156 const bool published = last_published_script_open_ms_
157 == context.script_bar_open_ms;
158 const bool coof_published = coof_callback_script_open_ == context.script_bar_open_ms;
159 if (published || coof_published)
160 return std::max(0, source_bar_count_ - 1);
161 return source_bar_count_;
167 const auto found = std::find_if(retained_.bars.begin(), retained_.bars.end(),
168 [&](
const Bar&
bar) { return bar.timestamp == context.sub_bar_open_ms; });
169 if (found == retained_.bars.end())
return std::nullopt;
170 bool high_first = std::abs(found->high - found->open)
171 < std::abs(found->open - found->low);
172 if (order == NativePathOrder::HighFirst) high_first =
true;
173 else if (order == NativePathOrder::LowFirst) high_first =
false;
175 NativePathPhase::Open,
176 high_first ? NativePathPhase::High : NativePathPhase::Low,
177 high_first ? NativePathPhase::Low : NativePathPhase::High,
178 NativePathPhase::Close,
180 const double price[] = {
182 high_first ? found->high : found->low,
183 high_first ? found->low : found->high,
186 for (
int index = 0; index < 4; ++index) {
187 if (phase[index] != context.coordinate.path_phase)
continue;
188 if (index > 0 && current_price !=
price[index])
return price[index];
189 if (index < 3)
return price[index + 1];
197 update_source_series(
bar);
200void PineScheduler::update_source_series(
const Bar& bar) {
205 const double hl2 = (
bar.high +
bar.low) / 2.0;
206 const double hlc3 = (
bar.high +
bar.low +
bar.close) / 3.0;
207 const double ohlc4 = (
bar.open +
bar.high +
bar.low +
bar.close) / 4.0;
208 const double hlcc4 = (
bar.high +
bar.low +
bar.close +
bar.close) / 4.0;
234 if (language_.pos_view_freeze_bar_ ==
bar_index) {
236 return language_.pos_view_frozen_qty_;
238 return -language_.pos_view_frozen_qty_;
248 const std::vector<PyramidEntry>& lots) {
249 if (language_.pos_view_freeze_bar_ ==
bar_index)
return;
250 language_.pos_view_freeze_bar_ =
bar_index;
251 language_.pos_view_frozen_side_ = side;
252 language_.pos_view_frozen_qty_ = quantity;
253 language_.pos_view_frozen_entry_qty_.clear();
254 for (
const auto& lot : lots)
255 language_.pos_view_frozen_entry_qty_[lot.entry_id] += lot.qty;
259 language_.pos_view_freeze_bar_ = -1;
263 if (key ==
"open")
return language_._src_open_;
264 if (key ==
"high")
return language_._src_high_;
265 if (key ==
"low")
return language_._src_low_;
266 if (key ==
"close")
return language_._src_close_;
267 if (key ==
"volume")
return language_._src_volume_;
268 if (key ==
"hl2")
return language_._src_hl2_;
269 if (key ==
"hlc3")
return language_._src_hlc3_;
270 if (key ==
"ohlc4")
return language_._src_ohlc4_;
271 if (key ==
"hlcc4")
return language_._src_hlcc4_;
272 throw std::invalid_argument(
"unknown source series");
276 language_.history_slot_is_new_ = new_history_slot;
277 language_.is_first_tick_ = new_history_slot;
278 update_source_series(
bar);
283 struct InputBarIndexScope {
287 : host(value), previous(value.bar_index_) { host.bar_index_ = index; }
288 ~InputBarIndexScope() { host.bar_index_ = previous; }
293 if (uses_aux_security_feed_ || host.security_sites_kernel_routed()) {
297 std::int64_t next_input_ms = 0;
299 && context.
input_index + 1 <
static_cast<int>(retained_.bars.size())) {
300 next_input_ms = retained_.bars[
static_cast<std::size_t
>(context.
input_index + 1)].timestamp;
302 if (retained_.bar_magnifier && deferred_boundary_input_.active
307 const std::int64_t completed_script_open =
308 deferred_boundary_input_.prior_script_open_ms;
309 (void)host.scheduler_feed_security_input(
310 deferred_boundary_input_.bar, deferred_boundary_input_.next_input_ms,
314 deferred_boundary_input_.bar =
bar;
315 deferred_boundary_input_.next_input_ms = next_input_ms;
316 deferred_boundary_input_.prior_script_open_ms = completed_script_open;
317 deferred_boundary_input_.calling_bar_complete =
false;
318 deferred_boundary_input_.all_security_states =
true;
319 deferred_boundary_input_.active =
true;
328 if (!retained_.bar_magnifier && awaiting_legacy_script_open_ms_
329 != std::numeric_limits<std::int64_t>::min()) {
330 deferred_boundary_input_.bar =
bar;
331 deferred_boundary_input_.next_input_ms = next_input_ms;
332 deferred_boundary_input_.prior_script_open_ms = awaiting_legacy_script_open_ms_;
333 deferred_boundary_input_.calling_bar_complete =
false;
334 deferred_boundary_input_.all_security_states =
true;
335 deferred_boundary_input_.active =
true;
341 bool boundary = prior_input_script_open_ms_
342 != std::numeric_limits<std::int64_t>::min()
345 && context.
input_index <
static_cast<int>(input_script_completes_.size())) {
346 calling_bar_complete = input_script_completes_[
347 static_cast<std::size_t
>(context.
input_index)] != 0U;
348 boundary = input_script_boundary_completes_[
349 static_cast<std::size_t
>(context.
input_index)] != 0U;
354 if (retained_.bar_magnifier && next_input_ms == 0)
355 calling_bar_complete =
false;
356 bool security_boundary_ahead =
false;
357 if (retained_.bar_magnifier && next_input_ms != 0) {
359 bar.timestamp, next_input_ms, retained_.script_tf,
360 host.syminfo_.timezone, host.syminfo_.session);
361 if (caller_boundary) {
362 for (
const auto& state : host.security_eval_states_) {
364 security_boundary_ahead =
true;
370 if (security_boundary_ahead) {
371 deferred_boundary_input_.bar =
bar;
372 deferred_boundary_input_.next_input_ms = next_input_ms;
374 deferred_boundary_input_.calling_bar_complete =
true;
375 deferred_boundary_input_.all_security_states =
false;
376 deferred_boundary_input_.active =
true;
380 const bool deferred_gate = host.scheduler_feed_security_input(
381 bar, next_input_ms, calling_bar_complete,
382 boundary && !retained_.bar_magnifier);
384 deferred_boundary_input_.bar =
bar;
385 deferred_boundary_input_.next_input_ms = next_input_ms;
386 deferred_boundary_input_.prior_script_open_ms = prior_input_script_open_ms_;
387 deferred_boundary_input_.calling_bar_complete =
false;
388 deferred_boundary_input_.all_security_states =
false;
389 deferred_boundary_input_.active =
true;
391 if (calling_bar_complete && !retained_.bar_magnifier) {
392 awaiting_legacy_script_open_ms_ = boundary
400 if (!retained_.is_stream)
return;
402 if (last_stream_input_open_ms_ == interval.open_ms)
return;
403 if (prior_input_script_open_ms_ != std::numeric_limits<std::int64_t>::min()
408 host.scheduler_publish_security_boundary();
410 last_stream_input_open_ms_ = interval.
open_ms;
413 (void)host.scheduler_feed_security_input(
414 bar, interval.next_input_open_ms, complete,
false);
415 prior_input_script_open_ms_ = script.open_ms;
422 saw_open_fill_ =
false;
423 open_point_fills_ = 0;
424 coof_callback_script_open_ = std::numeric_limits<std::int64_t>::min();
425 if (host.scheduler_coof_enabled()) snapshot_coof_script_state(host);
427 if (!retained_.is_stream) {
428 current_script_bar_ = value;
430 current_script_bar_valid_ =
true;
446 if (retained_.is_stream && current_script_bar_valid_
451 host.scheduler_record_broker_hash();
454 const bool coof = host.scheduler_coof_enabled();
455 const bool had_coof_recalc = coof_callback_script_open_
457 Bar script_bar = value;
459 if (retained_.is_stream && !retained_.bars.empty()
460 && source_bar_count_ >=
static_cast<int>(retained_.bars.size())) {
462 const std::int64_t expected_open = retained_.bars.back().timestamp
463 +
static_cast<std::int64_t
>(std::max(input_seconds, 0)) * 1000;
464 if (input_seconds > 0 && script_bar.
timestamp < expected_open) {
472 current_script_bar_ = script_bar;
473 current_script_bar_valid_ =
true;
474 const bool completes_awaiting_legacy_script = awaiting_legacy_script_open_ms_
476 if (deferred_boundary_input_.active
477 && !deferred_boundary_input_.all_security_states
482 if (!retained_.bar_magnifier)
483 host.scheduler_publish_security_boundary();
486 if (uses_aux_security_feed_) host.scheduler_feed_aux_security(chart_index);
488 restore_coof_script_state(host);
489 language_.is_first_tick_ =
true;
490 language_.is_last_tick_ =
true;
491 language_.history_slot_is_new_ =
492 !language_.coof_checkpoint_contains_current_bar_;
494 publish_series(script_bar, host);
495 std::optional<std::int64_t> next_script_open_ms;
496 if (
const auto state = host.native_state(); state.spec
497 && !state.spec->timeframe_undetected) {
498 if (
tf_ratio(state.spec->input_tf, state.spec->script_tf) == 1
499 && source_bar_count_ + 1 <
static_cast<int>(retained_.bars.size())) {
500 next_script_open_ms = retained_.bars[
501 static_cast<std::size_t
>(source_bar_count_ + 1)].timestamp;
503 host.scheduler_update_session_state(script_bar, next_script_open_ms);
506 && expected_source_bars_ > 0
507 && source_bar_count_ + 1 >= expected_source_bars_;
508 if (suppress_probe_tail) host.scheduler_publish_suppressed_tail(script_bar);
510 host.scheduler_publish_source_bar(script_bar,
true, !had_coof_recalc);
513 if (coof) commit_coof_script_state(host);
514 if (uses_aux_security_feed_) host.scheduler_feed_deferred_aux_security(chart_index);
515 if (deferred_boundary_input_.active
517 if (deferred_boundary_input_.all_security_states) {
518 (void)host.scheduler_feed_security_input(
519 deferred_boundary_input_.bar, deferred_boundary_input_.next_input_ms,
520 deferred_boundary_input_.calling_bar_complete,
false);
522 host.scheduler_feed_deferred_security_input(
523 deferred_boundary_input_.bar, deferred_boundary_input_.next_input_ms);
525 deferred_boundary_input_ = {};
527 if (completes_awaiting_legacy_script) {
528 awaiting_legacy_script_open_ms_ = std::numeric_limits<std::int64_t>::min();
530 if (!had_coof_recalc) ++source_bar_count_;
532 if (!suppress_probe_tail) host.scheduler_record_range_end(current_script_bar_);
533 if (!retained_.is_stream) host.scheduler_finish_security_sequence();
535 host.scheduler_record_broker_hash();
539 if (event.
ordinal <= applied_cursor_)
return;
540 applied_cursor_ =
event.ordinal;
548 if (event.
ordinal != applied_cursor_)
return false;
549 if (!host.scheduler_coof_enabled())
return false;
577 const bool bar_known = current_script_bar_valid_
580 && host.
adapter_.source_path_uses_high_first(current_script_bar_)
581 ? NativePathPhase::High : NativePathPhase::Low;
584 &&
event.cursor.t == 0.0);
585 const bool at_open = open_point && open_point_fills_ < 2;
586 open_point_fills_ = at_open ? open_point_fills_ + 1 : 2;
587 const bool first_open = at_open && !saw_open_fill_;
588 if (at_open) saw_open_fill_ =
true;
589 const bool first_callback = coof_callback_script_open_
591 const bool callback_advances_source_bar = first_callback
592 && !language_.coof_checkpoint_contains_current_bar_;
597 Bar callback_bar = current_script_bar_valid_
599 ? current_script_bar_ : host.current_bar_;
601 restore_coof_script_state(host);
602 language_.is_first_tick_ =
true;
603 language_.is_last_tick_ =
true;
604 language_.history_slot_is_new_ =
605 !language_.coof_checkpoint_contains_current_bar_;
606 publish_series(callback_bar, host);
611 event, coof_context, first_open, host.broker_fill_event_seq_);
616 Bar extremes_bar = callback_bar;
618 extremes_bar.
high = extremes_bar.
low = extremes_bar.
close = extremes_bar.
open;
621 host.pyramid_entries_, host.position_side_, host.bar_index_, extremes_bar);
623 host.scheduler_publish_source_bar(
624 callback_bar,
true, callback_advances_source_bar);
630 host.
adapter_.flush_coof_tail(
true);
637 restore_coof_script_state(host);
640 if (callback_advances_source_bar) ++source_bar_count_;
643 for (
const auto& handle : newborns) {
644 (void)host.execute_current({handle, NativeCurrentPriceRule::NearestTick});
648 constexpr std::uint64_t kNoFillEventBudget = std::numeric_limits<std::uint64_t>::max();
653 std::uint64_t budget = kNoFillEventBudget;
654 std::size_t executed = 0;
657 if (newborns.empty())
break;
658 for (
const auto& handle : newborns) {
659 if (budget == 0 || executed == kFirstOpenLoopGuard)
660 throw std::overflow_error(
"Pine COOF first-open loop guard exhausted");
663 (void)host.execute_current({handle, NativeCurrentPriceRule::NearestTick});
AggregatedBar feed(const Bar &input_bar)
Feed one input bar. Returns aggregation state.
void begin_coof_recalc(const native_order::ExecutionAppliedEvent &, const NativeDecisionContext &, bool first_open, std::uint64_t source_fill_sequence)
void end_coof_recalc() noexcept
std::vector< native_order::RequestHandle > take_first_open_newborns()
bool suppress_grouped_stop_recalc(const native_order::ExecutionAppliedEvent &, const NativeDecisionContext &) const noexcept
std::optional< double > next_input_waypoint(const NativeDecisionContext &, double current_price, NativePathOrder) const noexcept
void tick(const Bar &, const NativeTickContext &, PineStrategyHost &)
void run_begin(PineStrategyHost &)
void input(const Bar &, const NativeInputContext &, PineStrategyHost &)
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
void fixture_publish_source_series(const Bar &, bool new_history_slot)
void recalculate(const native_order::ExecutionAppliedEvent &, const NativeDecisionContext &, PineStrategyHost &)
void clear_script_position_view() 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 &)
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 &)
PineExecutionAdapter adapter_
bool probe_suppress_tail_logic() const
PineStrategyConfig config_
NativePathPhase
Which leg of a modeled OHLC walk a point sits on.
NativePathOrder
Generic ordering for a modeled OHLC path.
constexpr std::uint32_t kCoofLoopGuard
void sample_open_trade_extremes(std::vector< PyramidEntry > &lots, PositionSide side, int bar_index, const Bar &bar)
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.
bool tf_change(int64_t prev_ms, int64_t curr_ms, const std::string &tf)
Check if prev/curr timestamps cross a timeframe boundary.
Borrowed begin-call facts.
MagnifierDistribution magnifier_distribution
bool simple_run
Which public overload began the run: the bare run(bars, n) lifecycle (true) or a timeframe-aware / ma...
int magnifier_volume_weighted_min_samples
bool magnifier_volume_weighted
int magnifier_volume_weighted_max_samples
Accepted input facts presented before the generic consumer aggregates the bar into its script interva...
bool completes_script_interval
native_calendar::NativeInterval script_interval
One accepted realtime print before native matching at its current decision point.
NativeDecisionContext decision
int64_t next_period_open_ms
NativePathPhase path_phase
NativePriceProvenance provenance
native_calendar::NativeInterval input_interval
native_calendar::NativeInterval script_interval
int64_t script_bar_open_ms
NativeCoordinate coordinate
One committed execution: the definition, the cursor, the resolved price and units,...
Series< double > coof_checkpoint_src_high_
Series< double > _src_low_
Series< double > _src_high_
Series< double > coof_checkpoint_src_open_
bool history_slot_is_new_
Series< double > _src_hlc3_
PositionSide pos_view_frozen_side_
Series< double > _src_volume_
Series< double > _src_open_
Series< double > coof_checkpoint_src_hl2_
Series< double > coof_checkpoint_src_hlcc4_
std::unordered_map< std::string, double > pos_view_frozen_entry_qty_
Series< double > coof_checkpoint_src_close_
Series< double > _src_hl2_
Series< double > coof_checkpoint_src_volume_
Series< double > coof_checkpoint_src_low_
Series< double > _src_close_
bool coof_checkpoint_contains_current_bar_
Series< double > _src_ohlc4_
Series< double > _src_hlcc4_
double pos_view_frozen_qty_
Series< double > coof_checkpoint_src_hlc3_
Series< double > coof_checkpoint_src_ohlc4_
int publish_gate_tf_seconds
bool process_orders_on_close