Skip to content

v6.9.4

Latest

Choose a tag to compare

@wallneradam wallneradam released this 15 Sep 07:20
· 9 commits to main since this release

Features

Scripts can declare their own timeframe

indicator()'s script-level timeframe and timeframe_gaps parameters are now
implemented. A script declared with timeframe='W' executes once per completed
weekly bar, aggregated from the chart feed, on the chart bar whose close reaches
the period close resolved from the trading schedule. The other chart bars carry
na with timeframe_gaps=True, or the last value with timeframe_gaps=False.
Output rows stay keyed by chart bars, and the period close never precedes the bar
that closes it, so no higher-timeframe value becomes visible early.

The new ScriptTimeframe driver reuses HTFAggregator with a caller-supplied
period completion and the session-aware close of security.actual_bar_close. It
validates that chart bars nest inside the script period, counts last_bar_index
from the periods actually present in the feed, and raises for live mode, the bar
magnifier and a timeframe lower than the chart's.

timeframe.period, main_period, multiplier, the is* properties and every
"own bar period" site in lib (time(""), time_close, bars_back, the
trading-day and scheduled-grid trackers) now read the run timeframe;
syminfo.period keeps describing the data grid. request.security compares
seconds and modifier when detecting a same-context request, so timeframe='1W'
with a "W" request no longer spawns a child process.

Fixes

Strategy engine

  • Simultaneous triggers run in activation order. Orders resting at one price
    level trigger at the same instant, and TradingView runs them in the order they
    reached the book, not entries first. Each order now carries its activation slot:
    a re-issue that keeps its price levels and quantity keeps the resting order's
    slot, one that changes them is re-slotted last, and an exit leg issued against a
    still-pending entry is slotted when that entry fills.
  • An exit leg activated behind a reversing entry is no longer cancelled by that
    entry's fill.
    It is locked into the batch with the quantity its binding had
    when the batch started, closes what is left and opens the remainder under its own
    exit id. A leg bound to a pending entry is grown to the whole fill, including the
    part of the entry's frozen flip that found nothing to close. Only the opening part
    of a reversal entry is margined; the frozen flip component closes the opposite
    position and needs none.
  • Exit legs are priced off the fill that activated them, not off the first open
    trade under the id, so a pyramid add or a position opened earlier by a committed
    leg cannot fire a fresh bracket at a stale price.
  • An intrabar-activated exit leg gets the rest of the bar path. A leg whose
    level already stands on the wrong side of the fill price (a long's protective stop
    above it, a profit limit already in the money) is triggered the moment the entry
    opens the trade and fills at the entry's own price; a leg activated mid-bar can
    also cross the stretch between the bar open and the extreme the first leg reached
    on the way back. Previously such a leg could only fill from the next bar on.
  • Pyramid adds are covered by live strategy.exit calls. An entry that fills
    after a strategy.exit was issued gets its own leg, sized to that fill and priced
    from it, and the call stops covering further adds once one of its legs has fired.
    Trailing legs seed their water mark from the entry they are bound to instead of the
    oldest FIFO row under the from_entry_id, and the trailing pre-walk runs the whole
    book segment by segment, so several legs filling on one bar are booked in the order
    the assumed path reaches them.

Builtins

  • array.join()'s separator is now optional. TradingView defaults it to the empty
    string, but it was declared required, so a Pine script calling array.join(id)
    died with a TypeError.
  • ta.valuewhen()'s occurrence ring is no longer rolled back with the bar.
    TradingView fills the ring once per execution of the body and a discarded
    re-execution never gives its push back, so on a calc_on_order_fills bar whose
    condition is true the same value is recorded again for every order that fills
    there. var assignments and ta.cum stay un-doubled on those bars.
  • lib.time used inside a nested helper declares its history buffer in main with
    an int element type, so a conditionally called helper reads time history on the
    chart-bar grid instead of its own call grid.
  • time_close on D/W/M bars returns the end of the last scheduled session of the
    period, including effective-dated session corrections, instead of the open plus a
    nominal span.

request.security

  • A context's own read now falls back to the caller's default. A security child
    replays the whole script, so a context's own read can run before its own write;
    that read returned the raw last published value, None until the first
    publication, while every other empty answer in the same function returns the
    caller's default. An array context asking for [] received a None that no
    array.* builtin accepts, and the child process died taking the parent run
    with it.
  • Shared memory is released for contexts that allocate it without spawning a child
    process (same-context and ignored contexts).

Performance

  • Security ring lookups are binary searches. Every lookup built a Python list of
    all live closes just to bisect it, one struct unpack per entry — on the hot path,
    since has_close is the wait_for_close predicate and a consumer of a 1-minute
    lower-timeframe context waits thousands of times against a ring holding thousands
    of intrabars. The search now reads only the log2(count) entries a binary search
    needs; the column is sorted, so the result is identical. Measured on a daily plus
    1-minute context over BINANCE:BTCUSDT 30m: 110 million entry reads in 60 seconds of
    one consumer and a run past 2100 seconds, now 161 seconds with every plot matching.

Internal

  • Plot typing on fill() arguments, simplified strategy script availability checks,
    removed redundant _price_round overloads, clarified order variables and hit
    typing in the strategy engine.