PineForge v0.13.1-379-g9b50973
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
pineforge::TimeframeAggregator Class Reference

#include <timeframe.hpp>

Public Member Functions

 TimeframeAggregator ()
 Default: passthrough mode (no aggregation).
 
 TimeframeAggregator (int ratio)
 Ratio-based: every ratio input bars produce one output bar.
 
 TimeframeAggregator (const std::string &target_tf, const std::string &input_tf)
 Calendar-based: aggregate until day/week/month boundary.
 
 TimeframeAggregator (const std::string &target_tf, const std::string &input_tf, const std::string &tz, const std::string &session="")
 Calendar/ratio aggregation anchored on a symbol clock.
 
AggregatedBar feed (const Bar &input_bar)
 Feed one input bar. Returns aggregation state.
 
AggregatedBar feed (const Bar &input_bar, int64_t next_input_ms)
 feed() with the NEXT input bar's timestamp known (0 = unknown, the form above).
 
AggregatedBar feed (const Bar &input_bar, int64_t next_input_ms, int64_t calling_close_ms)
 feed(bar, next_input_ms) with the CALLING chart bar's nominal close known (0 = unknown, the forms above): TradingView's time_close of the chart bar this input bar belongs to – the input bar's own end on a single-feed run, the native D/W/M chart bar's session close on the split-feed path, where a finer auxiliary slice advances request.security.
 
Bar current () const
 Current in-progress bar.
 
bool has_pending_partial () const
 RATIO (fixed intraday target) only: whether the bucket in progress holds sub-bars no completion has emitted yet – the tail of a chart bar whose last sub-bars never reached the bucket's count, real end or session close (the 21:57Z 3m bucket of OANDA:XAUUSD's Thanksgiving 2025-11-26 session holds only the 21:59Z minute).
 
AggregatedBar complete_pending_partial ()
 Finalize the pending partial bucket exactly as feed() finalizes a bucket – the sub-bars it holds ARE the bucket – and return it complete.
 
Bar last_completed () const
 Last completed aggregated bar.
 
bool is_active () const
 Whether aggregation is active (non-passthrough).
 
CalendarPeriod calendar_period () const
 The D/W/M period a CALENDAR aggregator buckets on; NONE for RATIO and PASSTHROUGH.
 
void set_native_periods (std::vector< int64_t > stamps, std::vector< int64_t > trade_instants, CalendarPeriod feed_period)
 TradingView's own period partition for a CALENDAR aggregator, from the native request.security feed of the aggregated timeframe: the stamps (Unix ms, strictly increasing) are the exchange's native bars' opens, and trade_instants[k] is an instant inside the session-day the k-th native bar COMPLETES on – its last input bar (the stamp itself when no input bar falls in the period), the trade date TradingView files the bar under.
 
bool has_native_periods () const
 
void set_early_close_completes (bool on)
 Whether a session ending BEFORE its nominal close completes the running D/W/M bucket on that session's actual last input bar (feed(bar, next_input_ms) seeing the next input bar open a new period) – true, the default – or the bucket waits for the period's nominal close (the 16:45 bar reaching 17:00, the last traded session-day's close) and, when no input bar reaches it, completes lazily on the next period's first bar (false) – unless the CALLING chart bar's nominal close reaches the period's (feed(bar, next_input_ms, calling_close_ms): the 1D chart's early-close daily bar, whose time_close stays 17:00 ET).
 
bool early_close_completes () const
 
bool period_changes (int64_t prev_ms, int64_t curr_ms) const
 CALENDAR: whether prev_ms and curr_ms lie in different periods of this aggregator – different native periods / W-M groups when native periods are installed, crosses_boundary on the nominal session calendar otherwise.
 
int64_t bucket_open_ms (int64_t ms) const
 Open (Unix ms) of the target-TF bucket an input bar stamped ms belongs to, on the aggregator's anchor clock (syminfo tz + session): CALENDAR -> session_period_open_ms of the bar's D/W/M period (the forex week opens Sunday 17:00 ET, its month on the session whose close date is the 1st); RATIO -> session_intraday_bucket_open_ms, the day-stamp-anchored grid bucket (the same key feed() splits on and time("<intraday tf>") reads); PASSTHROUGH, or a count-only ratio with no wall-clock width, -> ms itself.
 
int64_t bar_label_ms (int64_t ms) const
 Timestamp of the target-TF bar OPENED by an input bar stamped ms — what TradingView dates the aggregated bar, and what feed() stamps on every bucket it starts (finding 473).
 

Detailed Description

Definition at line 288 of file timeframe.hpp.

Constructor & Destructor Documentation

◆ TimeframeAggregator() [1/4]

pineforge::TimeframeAggregator::TimeframeAggregator ( )

Default: passthrough mode (no aggregation).

◆ TimeframeAggregator() [2/4]

pineforge::TimeframeAggregator::TimeframeAggregator ( int ratio)
explicit

Ratio-based: every ratio input bars produce one output bar.

◆ TimeframeAggregator() [3/4]

pineforge::TimeframeAggregator::TimeframeAggregator ( const std::string & target_tf,
const std::string & input_tf )

Calendar-based: aggregate until day/week/month boundary.

◆ TimeframeAggregator() [4/4]

pineforge::TimeframeAggregator::TimeframeAggregator ( const std::string & target_tf,
const std::string & input_tf,
const std::string & tz,
const std::string & session = "" )

Calendar/ratio aggregation anchored on a symbol clock.

tz is the Pine syminfo.timezone (exchange tz); session the Pine session string ("0930-1600", "24x7", ...). Defaults reproduce the UTC/24x7 forms bit-for-bit, so every existing construction site compiles unchanged.

Member Function Documentation

◆ feed() [1/3]

AggregatedBar pineforge::TimeframeAggregator::feed ( const Bar & input_bar)

Feed one input bar. Returns aggregation state.

Referenced by pineforge::source::PineScheduler::run_begin().

◆ feed() [2/3]

AggregatedBar pineforge::TimeframeAggregator::feed ( const Bar & input_bar,
int64_t next_input_ms )

feed() with the NEXT input bar's timestamp known (0 = unknown, the form above).

A historical run holds its whole feed, and on a declared exchange session TradingView finalizes a D/W/M bar on the period's actual last chart bar whatever the nominal calendar says that bar is: the 12:45 ET bar of a 13:00 half-day (NYSE:F Fri 2025-11-28), the Thursday 15:45 bar before a holiday Friday, the 15:45 CT bar closing an overnight CME session-day (lab tv wm-security-buckets tapes, 2026-09-05). CALENDAR mode therefore also completes the running bucket when the next input bar opens a new period. RATIO and PASSTHROUGH ignore the hint, and so do ""/"24x7" sessions (a data hole before a 24x7 midnight is not an early close), so every caller passing 0 and every session-less feed stay bit-identical. The rule applies where TradingView's session template knows the early close – exchange calendars; set_early_close_completes(false) switches a symbol whose template does not (OANDA's cfd / forex streams) back to the nominal close and the lazy completion on the next period's first bar.

◆ feed() [3/3]

AggregatedBar pineforge::TimeframeAggregator::feed ( const Bar & input_bar,
int64_t next_input_ms,
int64_t calling_close_ms )

feed(bar, next_input_ms) with the CALLING chart bar's nominal close known (0 = unknown, the forms above): TradingView's time_close of the chart bar this input bar belongs to – the input bar's own end on a single-feed run, the native D/W/M chart bar's session close on the split-feed path, where a finer auxiliary slice advances request.security.

Read only by the OTC rule (set_early_close_completes(false)): TradingView surfaces a D/W/M value on the chart bar whose time_close reaches the period's nominal close, and the daily bar of an early-close day keeps its nominal time_close – on the OANDA:XAUUSD 1D chart the Fri 2025-07-04 bar (data to 12:45 ET) still closes at 17:00 ET, so request.security(tickerid, "W", x) advances on it (cW 3336.61, the early close) exactly as on every regular Friday, and "D" is the chart bar itself there and on Mon 2026-02-16 (14:15 early close); on the 15m chart the 12:45 / 14:15 bar's own time_close falls short and the value waits for the next session's first bar (lab tv oanda1d-{jul,feb,novm,decm} beside the oanda 15m pin, 2026-09-05). So on an OTC stream a bucket the next input bar leaves completes on this input bar iff calling_close_ms reaches the period's nominal close (session_period_last_traded_close_ms); with 0 it waits, as before. Exchange kinds (early_close_completes) ignore the hint: the actual last bar completes the period either way.

◆ current()

Bar pineforge::TimeframeAggregator::current ( ) const

Current in-progress bar.

◆ has_pending_partial()

bool pineforge::TimeframeAggregator::has_pending_partial ( ) const

RATIO (fixed intraday target) only: whether the bucket in progress holds sub-bars no completion has emitted yet – the tail of a chart bar whose last sub-bars never reached the bucket's count, real end or session close (the 21:57Z 3m bucket of OANDA:XAUUSD's Thanksgiving 2025-11-26 session holds only the 21:59Z minute).

CALENDAR and PASSTHROUGH answer false; so does a count-only ratio with no wall-clock width.

◆ complete_pending_partial()

AggregatedBar pineforge::TimeframeAggregator::complete_pending_partial ( )

Finalize the pending partial bucket exactly as feed() finalizes a bucket – the sub-bars it holds ARE the bucket – and return it complete.

TradingView surfaces the LAST intrabar of a chart bar at that bar's close whatever its minute count (lab tv dca-ltf-last-intrabar, 2026-09-05), so a request.security evaluator served by a finer feed calls this when its calling chart bar completes. The bucket is emitted once: the next boundary resets it without re-emitting (current_emitted_complete), and a later sub-bar of the same bucket merges without completing it again, as after any early completion. Without a pending partial nothing changes and the current bar is returned incomplete.

◆ last_completed()

Bar pineforge::TimeframeAggregator::last_completed ( ) const

Last completed aggregated bar.

◆ is_active()

bool pineforge::TimeframeAggregator::is_active ( ) const

Whether aggregation is active (non-passthrough).

◆ calendar_period()

CalendarPeriod pineforge::TimeframeAggregator::calendar_period ( ) const

The D/W/M period a CALENDAR aggregator buckets on; NONE for RATIO and PASSTHROUGH.

◆ set_native_periods()

void pineforge::TimeframeAggregator::set_native_periods ( std::vector< int64_t > stamps,
std::vector< int64_t > trade_instants,
CalendarPeriod feed_period )

TradingView's own period partition for a CALENDAR aggregator, from the native request.security feed of the aggregated timeframe: the stamps (Unix ms, strictly increasing) are the exchange's native bars' opens, and trade_instants[k] is an instant inside the session-day the k-th native bar COMPLETES on – its last input bar (the stamp itself when no input bar falls in the period), the trade date TradingView files the bar under.

Installed, they replace the nominal session calendar as the period key: an input bar belongs to the native bar whose stamp is the latest at or before it, so a D period is exactly that native bar's span. On CME_MINI:ES1! a holiday session that pauses at 12:00 CT and reopens at 17:00 the same day (Labor Day, Thanksgiving, Independence Day) is folded by TradingView into the NEXT trade date's daily bar with no stamp of its own (lab tv esd pin, 2026-09-05: the Sun 08-31 17:00 stamp runs to Tue 09-02 15:45 and is Tuesday's bar), so no D period closes at the pause, none opens at the reopen, and a data hole inside a native day is not a close. A W / M period groups the native days by the nominal week / month of their trade date (the holiday session belongs to the next trade date, so to its week). bar_label_ms is the stamp of the bar's native period, bucket_open_ms the group's first stamp, period_changes compares those, and feed(bar, next_input_ms) completes the running bucket on the last input bar before the next native stamp. The partition covers the feed: an input bar before the first stamp keeps the nominal key, and so does one at or after the LAST stamp's nominal period close (session_period_close_ms of feed_period, the feed's own timeframe – DAY for a daily feed), since without a next stamp nothing proves the last native bar reaches further; a chart day the feed does not hold stays a nominal session-day bucket with no native bar to substitute. Empty vectors (the default) leave every nominal rule bit-identical; RATIO / PASSTHROUGH ignore the call. Mismatched sizes or non-increasing stamps install nothing.

◆ has_native_periods()

bool pineforge::TimeframeAggregator::has_native_periods ( ) const
inline

Definition at line 425 of file timeframe.hpp.

◆ set_early_close_completes()

void pineforge::TimeframeAggregator::set_early_close_completes ( bool on)
inline

Whether a session ending BEFORE its nominal close completes the running D/W/M bucket on that session's actual last input bar (feed(bar, next_input_ms) seeing the next input bar open a new period) – true, the default – or the bucket waits for the period's nominal close (the 16:45 bar reaching 17:00, the last traded session-day's close) and, when no input bar reaches it, completes lazily on the next period's first bar (false) – unless the CALLING chart bar's nominal close reaches the period's (feed(bar, next_input_ms, calling_close_ms): the 1D chart's early-close daily bar, whose time_close stays 17:00 ET).

TradingView finalizes on the actual last bar only where its session template carries the early close: exchange calendars (stock / futures / index – NYSE:F's 13:00 half-days, CME's 12:00 CT early closes). OTC quote streams have no holiday template: on OANDA:XAUUSD 15m (cfd, 1800-1700 ET) the Fri 2025-07-04 session ends at the 12:45 ET bar, yet request.security(tickerid, "D", x) lookahead_off surfaces that day on Sun 07-06 18:00 – the next session's first bar – never on the 12:45 bar; so does the Mon 2026-02-16 day ending 14:15 (on Mon 18:00) and the week holding the 07-04 close (lab tv oanda-{jul,julw,feb,febw} pin, ledger log-20260905t034240z-30be11fe, 2026-09-05). The engine sets it from syminfo.type (BacktestEngine:: session_template_knows_early_close: false for forex / cfd / crypto). Read only by the CALENDAR next-input-bar rule without a native partition: ""/"24x7" sessions never reach that rule, the nominal rules are untouched, and an installed native period partition (set_native_periods) stays authoritative either way.

Definition at line 453 of file timeframe.hpp.

◆ early_close_completes()

bool pineforge::TimeframeAggregator::early_close_completes ( ) const
inline

Definition at line 454 of file timeframe.hpp.

◆ period_changes()

bool pineforge::TimeframeAggregator::period_changes ( int64_t prev_ms,
int64_t curr_ms ) const

CALENDAR: whether prev_ms and curr_ms lie in different periods of this aggregator – different native periods / W-M groups when native periods are installed, crosses_boundary on the nominal session calendar otherwise.

RATIO / PASSTHROUGH: false.

◆ bucket_open_ms()

int64_t pineforge::TimeframeAggregator::bucket_open_ms ( int64_t ms) const

Open (Unix ms) of the target-TF bucket an input bar stamped ms belongs to, on the aggregator's anchor clock (syminfo tz + session): CALENDAR -> session_period_open_ms of the bar's D/W/M period (the forex week opens Sunday 17:00 ET, its month on the session whose close date is the 1st); RATIO -> session_intraday_bucket_open_ms, the day-stamp-anchored grid bucket (the same key feed() splits on and time("<intraday tf>") reads); PASSTHROUGH, or a count-only ratio with no wall-clock width, -> ms itself.

Pure function of the configuration: it neither reads nor advances the aggregation state, so callers may query it before feeding the bar.

◆ bar_label_ms()

int64_t pineforge::TimeframeAggregator::bar_label_ms ( int64_t ms) const

Timestamp of the target-TF bar OPENED by an input bar stamped ms — what TradingView dates the aggregated bar, and what feed() stamps on every bucket it starts (finding 473).

RATIO -> bucket_open_ms (the session-anchored grid open, whether or not the grid-opening sub-bar traded: a forex 1m tape that starts at 17:04 ET still yields the 17:00 chart bar); CALENDAR -> the day stamp of the session-day holding ms (the D/W/M bar is dated by its first TRADED session-day, so a holiday-Monday week stays Tuesday's bar, but never by a thin-open sub-bar inside that day; on OANDA 1800-1700 the stamp is 17:00 ET, an hour before the day trades); PASSTHROUGH -> ms. Gap-free feeds whose open is the stamp are bit-identical: there the first sub-bar IS the bucket open.


The documentation for this class was generated from the following file: