130 : params_(¶ms), bars_(bars), n_(bars == nullptr ? 0 : n), own_open_(own_open) {}
133 while (index_ < n_) {
134 const std::int64_t ts = bars_[index_++].timestamp;
135 if (!own_open_ && cycle_ && origin_ <= ts && ts < next_origin_)
continue;
139 cycle_ = day.has_value();
141 origin_ = day->origin_ms;
142 next_origin_ = day->next_origin_ms;
144 out.
value = own_open_
157 std::size_t index_ = 0;
159 std::int64_t origin_ = 0;
160 std::int64_t next_origin_ = 0;
167 :
walk(params, bars, n, own_open) {}
173 while (
walk.next(day)) {
198 : chart_(params, params.chart, params.n_chart, params.daily_chart),
199 aux_(params, params.aux, params.n_aux, false) {
200 chart_.refill(ordered_);
201 aux_.refill(ordered_);
205 if (!chart_.live && !aux_.live)
return false;
206 if (chart_.live && (!aux_.live || chart_.head.ordinal <= aux_.head.ordinal)) {
208 if (aux_.live && aux_.head.ordinal == out.
ordinal) aux_.refill(ordered_);
209 chart_.refill(ordered_);
212 aux_.refill(ordered_);
223 bool ordered_ =
true;
232 year_(params.first_year),
234 year_end_(
native_calendar::native_civil_days(params.first_year + 1, 1, 1)) {
235 have_head_ = held_.next(head_);
240 bool next(std::int64_t& stamp) {
241 if (failed_ || done_)
return false;
250 while (next_open(open)) {
251 if (open.date > params_->first) {
264 }
else if (has_ahead_) {
267 }
else if (!next_open(open)) {
271 std::int64_t at = open.value;
277 params_->tz.empty() ?
"UTC" : params_->tz,
static_cast<int>(date.
year),
286 if (has_previous_ && at <= previous_) {
290 has_previous_ =
true;
303 std::int64_t date = 0;
305 std::int64_t value = 0;
311 bool next_open(Open& open) {
312 const Params& p = *params_;
314 if (day_ >= year_end_) {
315 if (year_ >= p.last_year)
return false;
322 const std::int64_t d = day_++;
323 while (have_head_ && head_.
ordinal < d) have_head_ = held_.
next(head_);
324 const bool is_held = have_head_ && head_.
ordinal == d;
325 bool trading =
false;
326 if (p.exchange_calendar && d >= p.first && d <= p.last) {
329 const std::int64_t weekday = ((d % 7) + 7 + 4) % 7;
330 trading = p.every_day || (weekday >= 1 && weekday <= 5);
332 if (!trading)
continue;
333 if (count_++ % p.days == 0) {
336 open.value = is_held ? head_.value : 0;
342 const Params* params_;
345 bool have_head_ =
false;
348 std::int64_t year_end_;
349 std::int64_t count_ = 0;
351 bool has_ahead_ =
false;
352 bool started_ =
false;
354 bool failed_ =
false;
355 bool has_previous_ =
false;
356 std::int64_t previous_ = 0;
363 Source(std::shared_ptr<const Params> params, std::int64_t first_stamp,
365 : params_(
std::move(params)), first_stamp_(first_stamp), last_stamp_(
last_stamp) {
366 recent_.reserve(kBuffered + 1);
369 bool stamp_at(std::int64_t ms, std::int64_t& stamp,
bool& last)
override {
370 if (ms < first_stamp_)
return false;
371 if (recent_.empty() || ms < recent_.front()) restart();
372 if (recent_.empty())
return false;
373 while (has_next_ && next_ <= ms) advance();
374 const auto after = std::upper_bound(recent_.begin(), recent_.end(), ms);
375 if (after == recent_.begin())
return false;
376 stamp = *(after - 1);
377 last = !has_next_ && after == recent_.end();
381 std::int64_t
last_stamp()
const override {
return last_stamp_; }
383 std::size_t
stamps_held()
const override {
return recent_.size() + (has_next_ ? 1u : 0u); }
394 recent_.push_back(next_);
395 if (recent_.size() > kBuffered) recent_.erase(recent_.begin());
396 has_next_ = stamps_->next(next_);
403 stamps_ = std::make_unique<Stamps>(*params_);
406 std::int64_t first = 0;
407 if (!stamps_->next(first))
return;
408 recent_.push_back(first);
409 has_next_ = stamps_->next(next_);
412 std::shared_ptr<const Params> params_;
413 std::int64_t first_stamp_;
414 std::int64_t last_stamp_;
415 std::unique_ptr<Stamps> stamps_;
416 std::vector<std::int64_t> recent_;
417 std::int64_t next_ = 0;
418 bool has_next_ =
false;
428 bool find(std::int64_t ordinal, std::int64_t& value) {
429 if (failed_ || ordinal < params_->first || ordinal > params_->last)
return false;
430 if (!loaded_ || ordinal < begin_ || ordinal >= end_) {
439 present_.fill(
false);
440 scan(params_->chart, params_->n_chart, params_->daily_chart);
441 if (!failed_) scan(params_->aux, params_->n_aux,
false);
444 if (failed_)
return false;
445 if (ordinal < begin_ || ordinal >= end_) {
449 const std::size_t at =
static_cast<std::size_t
>(ordinal - begin_);
450 if (at >= values_.size()) {
454 if (!present_[at])
return false;
462 void scan(
const Bar* bars, std::size_t n,
bool own_open) {
463 FeedWalk walk(*params_, bars, n, own_open);
465 while (walk.next(day)) {
469 const std::size_t at =
static_cast<std::size_t
>(day.
ordinal - begin_);
470 if (at >= values_.size()) {
476 values_[at] = day.
value;
481 const Params* params_;
482 std::array<std::int64_t, kUnorderedRescanDays> values_{};
483 std::array<bool, kUnorderedRescanDays> present_{};
484 std::int64_t begin_ = 0;
485 std::int64_t end_ = 0;
486 bool loaded_ =
false;
487 bool failed_ =
false;
497 year_(params.first_year),
499 year_end_(
native_calendar::native_civil_days(params.first_year + 1, 1, 1)) {}
501 bool next(std::int64_t& stamp) {
502 if (failed_ || done_)
return false;
508 while (next_open(open)) {
509 if (open.date > params_->first) {
522 }
else if (has_ahead_) {
525 }
else if (!next_open(open)) {
529 std::int64_t at = open.value;
533 params_->tz.empty() ?
"UTC" : params_->tz,
static_cast<int>(date.
year),
542 if (has_previous_ && at <= previous_) {
546 has_previous_ =
true;
556 std::int64_t date = 0;
558 std::int64_t value = 0;
561 bool next_open(Open& open) {
562 const Params& p = *params_;
564 if (day_ >= year_end_) {
565 if (year_ >= p.last_year)
return false;
572 const std::int64_t d = day_++;
573 std::int64_t value = 0;
574 const bool is_held = held_.
find(d, value);
579 bool trading =
false;
580 if (p.exchange_calendar && d >= p.first && d <= p.last) {
583 const std::int64_t weekday = ((d % 7) + 7 + 4) % 7;
584 trading = p.every_day || (weekday >= 1 && weekday <= 5);
586 if (!trading)
continue;
587 if (count_++ % p.days == 0) {
596 const Params* params_;
597 RescannedHeldDays held_;
600 std::int64_t year_end_;
601 std::int64_t count_ = 0;
603 bool has_ahead_ =
false;
604 bool started_ =
false;
606 bool failed_ =
false;
607 bool has_previous_ =
false;
608 std::int64_t previous_ = 0;
617 : params_(
std::move(params)), first_stamp_(first_stamp), last_stamp_(
last_stamp) {
618 recent_.reserve(kBuffered + 1);
621 bool stamp_at(std::int64_t ms, std::int64_t& stamp,
bool& last)
override {
622 if (ms < first_stamp_)
return false;
623 if (recent_.empty() || ms < recent_.front()) restart();
624 if (recent_.empty())
return false;
625 while (has_next_ && next_ <= ms) advance();
626 const auto after = std::upper_bound(recent_.begin(), recent_.end(), ms);
627 if (after == recent_.begin())
return false;
628 stamp = *(after - 1);
629 last = !has_next_ && after == recent_.end();
633 std::int64_t
last_stamp()
const override {
return last_stamp_; }
635 std::size_t
stamps_held()
const override {
return recent_.size() + (has_next_ ? 1u : 0u); }
642 recent_.push_back(next_);
643 if (recent_.size() > kBuffered) recent_.erase(recent_.begin());
644 has_next_ = stamps_->next(next_);
651 stamps_ = std::make_unique<RescannedStamps>(*params_);
654 std::int64_t first = 0;
655 if (!stamps_->next(first))
return;
656 recent_.push_back(first);
657 has_next_ = stamps_->next(next_);
660 std::shared_ptr<const Params> params_;
661 std::int64_t first_stamp_;
662 std::int64_t last_stamp_;
663 std::unique_ptr<RescannedStamps> stamps_;
664 std::vector<std::int64_t> recent_;
665 std::int64_t next_ = 0;
666 bool has_next_ =
false;
670 std::shared_ptr<Params> params) {
672 const auto scan_bounds = [&](
const Bar* bars, std::size_t n,
bool own_open) {
673 FeedWalk walk(*params, bars, n, own_open);
675 while (walk.
next(day)) {
680 params->first = std::min(params->first, day.
ordinal);
681 params->last = std::max(params->last, day.
ordinal);
686 scan_bounds(params->chart, params->n_chart, params->daily_chart);
687 scan_bounds(params->aux, params->n_aux,
false);
688 if (!any)
return nullptr;
691 std::int64_t first_stamp = 0;
692 std::int64_t last_stamp = 0;
696 auto stamps = std::make_unique<RescannedStamps>(*params);
697 std::int64_t stamp = 0;
698 bool have_stamp =
false;
699 while (stamps->next(stamp)) {
700 if (!have_stamp) first_stamp = stamp;
704 if (!have_stamp || stamps->failed())
return nullptr;
706 return std::make_shared<RescannedSource>(std::move(params), first_stamp, last_stamp);
722 if (feeds.
days < 2)
return nullptr;
725 if (!calendar)
return nullptr;
726 auto params = std::make_shared<detail::Params>();
727 params->days = feeds.
days;
729 params->every_day = feeds.
session.empty() || feeds.
session ==
"24x7";
731 params->chart = feeds.
chart;
732 params->n_chart = feeds.
n_chart > 0 ?
static_cast<std::size_t
>(feeds.
n_chart) : 0;
733 params->aux = feeds.
aux;
734 params->n_aux = feeds.
n_aux;
735 params->tz = feeds.
tz;
736 params->session = feeds.
session;
737 params->calendar = std::move(*calendar);
739 detail::HeldDays held(*params);
742 while (held.next(day)) {
743 if (!any) params->first = day.ordinal;
744 params->last = day.ordinal;
747 if (!any || !held.ordered()) {
748 if (!any)
return nullptr;
749 return detail::make_rescanned_source(std::move(params));
754 std::int64_t first_stamp = 0;
755 std::int64_t last_stamp = 0;
757 detail::Stamps stamps(*params);
758 std::int64_t stamp = 0;
760 while (stamps.next(stamp)) {
761 if (!any) first_stamp = stamp;
765 if (!any || stamps.failed())
return nullptr;
767 return std::make_shared<detail::Source>(std::move(params), first_stamp, last_stamp);
A period partition generated on demand rather than stored: what set_native_period_source installs whe...
FeedWalk(const Params ¶ms, const Bar *bars, std::size_t n, bool own_open)
HeldDays(const Params ¶ms)
RescannedHeldDays(const Params ¶ms)
bool find(std::int64_t ordinal, std::int64_t &value)
RescannedSource(std::shared_ptr< const Params > params, std::int64_t first_stamp, std::int64_t last_stamp)
bool stamp_at(std::int64_t ms, std::int64_t &stamp, bool &last) override
std::size_t stamps_held() const override
How many period opens the source holds in memory right now.
std::int64_t last_stamp() const override
The final period's open.
bool next(std::int64_t &stamp)
RescannedStamps(const Params ¶ms)
Source(std::shared_ptr< const Params > params, std::int64_t first_stamp, std::int64_t last_stamp)
std::int64_t last_stamp() const override
The final period's open.
bool stamp_at(std::int64_t ms, std::int64_t &stamp, bool &last) override
std::size_t stamps_held() const override
How many period opens the source holds in memory right now.
bool next(std::int64_t &stamp)
Stamps(const Params ¶ms)
constexpr int64_t native_civil_days(int64_t year, int month, int day) noexcept
std::optional< CivilResolution > resolve_civil(std::string_view timezone, int year, int month, int day, int hour, int minute, int second=0)
constexpr NativeCivilDate native_civil_date(int64_t days) noexcept
std::optional< NativeSessionDay > session_day_at(const SessionCalendar &calendar, int64_t ms)
std::optional< SessionCalendar > parse_session(std::string_view session, std::string_view timezone)
std::shared_ptr< TimeframeAggregator::PeriodSource > make_rescanned_source(std::shared_ptr< Params > params)
constexpr std::size_t kUnorderedRescanDays
Bounds the fallback's retained trading-date slots to one calendar year, including a leap year; N-day ...
constexpr std::size_t kMultiDayWindow
The most period opens a multi-day period source holds at once: the recent ones it answers short quest...
std::shared_ptr< TimeframeAggregator::PeriodSource > make_multi_day_period_source(const MultiDayFeeds &feeds)
The N-day partition of feeds, or null where TradingView's rule yields none: fewer than two days,...
int64_t session_covered_instant_ms(int64_t ms, const std::string &tz, const std::string &session)
The session instant a native CALENDAR chart stamp covers.
int64_t session_period_open_ms(int64_t ms, const std::string &tz, const std::string &session, CalendarPeriod period)
Open (Unix ms) of the symbol's D/W/M bar that contains ms: the day stamp of the period's first sessio...
What a run holds of the symbol the N-day request reads.
const Bar * chart
the chart's bars, strictly increasing
int days
N of the request, at least 2.
std::string session
the symbol's session
bool exchange_calendar
the held sessions are the trading dates
const Bar * aux
the auxiliary feed's bars, strictly increasing
std::string tz
the symbol's timezone
bool daily_chart
a chart bar's own open dates its session day
Lane(const Params ¶ms, const Bar *bars, std::size_t n, bool own_open)
void refill(bool &ordered)
native_calendar::SessionCalendar calendar