v6.4.10 — bid/ask & time_tradingday built-ins, strategy simulator fidelity
What's new
A feature-and-correctness release. Two Pine v6 built-ins land (bid/ask source series and time_tradingday), a per-bar time-isolation regression that silently froze time_close and timenow is fixed, and the strategy backtest simulator gets a large fidelity pass — rewritten trailing stops, full strategy.risk.* enforcement, an intraday filled-order cap, corrected gap-open and same-bar fill ordering, sticky-bracket / partial-exit correctness, and a lot-size rounding fix — bringing strategy results closer to TradingView.
Built-ins
bid and ask source series
Pine v6's bid and ask built-in float sources are now available, so Pyne code referencing them (including history access like bid[1]) compiles and runs. As on TradingView, they only carry real values on the unsupported 1-tick (1T) feed and resolve to na on every bar timeframe — PyneCore has no tick data, so they are always na. Any bid/ask columns present in the input data's extra fields are intentionally ignored for the same reason.
time_tradingday
New Pine v6 built-in returning 00:00 UTC of the bar's trading-day date in the exchange timezone. For symbols whose session crosses midnight (forex/futures overnight sessions), a bar whose window contains the session open is assigned to the new trading day — matching TradingView and session.isfirstbar_regular — even when the open does not land on a bar boundary (e.g. a 17:00–18:00 bar with a 17:05 open). Intraday-only and 24/7 symbols, and sessions opening exactly at midnight, use the bar's own date.
Time & sessions
time_close and timenow no longer frozen at the first bar
The function-isolation transform substitutes a snapshot of the module globals captured at a function's first call. time_close and timenow were being wrapped by that pass, so the per-bar updates to the underlying time state never reached them and both returned the bar-0 value on every subsequent bar. They are now marked non-transformable and read live per-bar state. (time was already exempt, so only time_close and timenow were affected.)
Strategy / backtest simulator
A large set of simulator fixes that change trade lists, exit prices/bars, trade counts, and halt behavior for affected strategies, bringing them in line with TradingView.
Trailing stops rewritten
The trailing-stop engine now re-evaluates once per bar from the prior high/low-water mark instead of riding the stop to the current bar's extreme, with a trail level persisted per order. An offset-0 trailing stop fills on its activation bar at the activation level; a carried stop fills at the open when a no-wick bar gaps past the water mark; it defers to a hard stop= reached earlier in intra-bar time; and the trail is seeded on the entry-fill bar so the water mark is not one bar behind TradingView. A re-issued live trailing leg inherits its ratcheted level instead of re-arming at the bare activation level each bar.
strategy.risk.* rules enforced
max_drawdown, max_intraday_loss, and max_cons_loss_days are now actually enforced via a post-bar risk pass. Max-drawdown is anchored to running peak equity (for percent_of_equity), max-intraday-loss to start-of-day equity, and the consecutive-loss-day counter rolls over on a session-aware trading day (driven by time_tradingday, not the calendar day) so overnight forex/futures sessions count correctly. A breach fires a synthetic Risk management close trade with a rule-identifying comment and latches a trading halt.
Intraday filled-order cap
max_intraday_filled_orders now counts a position reversal as a single filled order (not two), flattens the position on the reversal/flip path as well as the plain-fill path (tagged Close Position (Max number of filled orders in one day)), and blocks new strategy.entry placement — not just the fill — until the next trading day, preventing a phantom entry at the new day's open.
Sticky-bracket / partial-exit correctness
Re-issuing strategy.exit() on every open bar (TradingView's sticky-bracket pattern) no longer re-arms already-filled partial-exit legs at a shrinking size. Each exit leg reserves a fixed slice of the entry's original filled size — a qty_percent leg off the original size, a no-qty "rest" leg off the remainder after its siblings — and fires at most once; a re-issue only refreshes its limit/stop prices. While the bound entry is still pending, the exit tracks the entry's current pending size. This restores exact partial-exit trade counts and sizes against TradingView (e.g. 132 vs a prior 444 on a 50% partial-take-profit strategy).
Fill ordering
When two brackets sharing one entry gap through the open together, both now fill on the gap bar instead of one evicting the other. Same-bar exits walk the open→low / open→high price path so the fill nearest the open executes first, matching TradingView's intrabar order.
Other strategy fixes
strategy.exit()withlimit,stop,profit,loss, andtrailallnais now a no-op instead of becoming a level-less same-bar market close.- Lot-size rounding snaps a value within a few ULPs of a lot boundary up before flooring, so an exact lot multiple is no longer truncated a whole lot down while a genuine sub-lot fraction still floors.
strategy.order(limit=…, stop=…)documentation corrected: supplying both creates two OCA legs (a separate limit and a separate stop order), not a single stop-limit order.