This release completes the strategy statistics surface and rebuilds the equity excursion tracking on TradingView's measured behaviour.
Features
Strategy statistics
The last missing strategy statistics variables are now implemented:
strategy.avg_trade_percent,strategy.avg_winning_trade_percent,strategy.avg_losing_trade_percentstrategy.grossprofit_percent,strategy.grossloss_percentstrategy.max_contracts_held_all,strategy.max_contracts_held_long,strategy.max_contracts_held_shortstrategy.max_runup_percentstrategy.closedtrades.first_index
The percent averages are the mean of the closed trades' own profit ratios, each divided by that trade's entry cost including the entry fee.
strategy.default_entry_qty()
strategy.default_entry_qty(fill_price) returns the quantity a default-sized entry would buy at the given fill price. The price is snapped onto the tick grid, the size is floored onto the lot grid, and an unsizable price returns 0.
Fixes
Equity excursions
strategy.max_drawdown and strategy.max_runup are rebuilt on the measured TradingView law: the sums carry the gross mark, the drop is measured from the realized-equity high-water mark and the rise from the anchor each entry fill leaves behind, and a leg closed mid-bar no longer books the whole bar's range. Each percent divides by its excursion's higher endpoint and is tracked separately from the currency maximum.
A closed trade's profit_percent, max_drawdown_percent and max_runup_percent now divide by the total entry cost, and the per-trade excursion is measured from the trade's own entry price. strategy.avg_losing_trade divides the published gross loss.
Builtin state on discarded re-executions
An anchored binding whose bound object is an overload dispatcher was opaque to the calc_on_order_fills / calc_on_every_history_tick snapshot, so the restore dropped it and the anchor re-bound with an empty state vector. Every multi-signature builtin machine — ta.highest, ta.lowest and the dispatched percentile machines — therefore restarted its window from scratch after each discarded pass, which under calc_on_order_fills is every fill bar. The snapshot now walks the dispatcher's per-implementation vectors and restores them in place.
math.round at precision 0
The 1e-10 tie tolerance belongs to the decimal scaling of a non-zero precision. Precision 0 scales nothing, so applying the slack there rounded values up that TradingView rounds down. Measured on BINANCE:BTCUSDT 30m: every value below the tie rounds down however close it sits (452523.49999999994 -> 452523), while an exact tie still goes away from zero (2.5 -> 3, -2.5 -> -3). Precision >= 1 is unchanged.
ta.pivothigh() / ta.pivotlow() zero strength
Both now accept a zero leftbars or rightbars, matching TradingView, which rejects only negative strengths.
OHLC relation check on spread symbols
The OHLC relation check got a magnitude-scaled ULP slack: a TradingView spread symbol multiplies each leg by its rate separately, so at 1e13 magnitudes high can land one ULP below open. That is rounding noise in the source feed, and the stored bar must stay the one the venue computes on.
Broker: OCA sibling-fill cancels delivered ahead of the fill
Bybit's private stream can push the venue's OCA auto-cancel of a bracket's reduce-only take-profit leg before the sibling stop-loss leg's fill. Processed in isolation the cancel looked like an external cancel of a bot-owned order and quarantined the engine. The sync engine now snapshots the queued event batch and treats a reduce-only exit-leg cancel with a queued sibling-leg fill of the same intent as expected OCA fallout — only the dead leg is trimmed and the fill settles normally. A lone leg cancel with no queued sibling fill still quarantines.