|
PineForge unreleased
Deterministic PineScript v6 backtest runtime — C ABI reference
|
Default-off flags and read-only accessors used by pineforge-live. More...
Data Structures | |
| struct | pf_scratch_tables_v1 |
| Version 1 scratch-table admission maxima, in keys/rows and key bytes. More... | |
Macros | |
| #define | PINEFORGE_HAS_SCRATCH_TABLES_V1 1 |
| #define | PF_STATE_QUERY_ALLOWED_V1 0 |
| Both queries may answer, and the quote writers store. | |
| #define | PF_STATE_QUERY_SELECTED_WINDOW_AFTER_SEAL_V1 1 |
| Both are refused, and so are the quote writers: a selected window's run has sealed. | |
| #define | PF_STATE_QUERY_INVALID_HANDLE_V1 2 |
| The handle is NULL. | |
Typedefs | |
| typedef int32_t | pf_state_query_status_v1_t |
| What strategy_state_query_status_v1 answers: whether the two state queries, strategy_broker_state_hash and strategy_stream_state_hash, may answer a handle now, and whether the report-only terminal-quote writers may still store. | |
Enumerations | |
| enum | pf_scratch_table_backend_t { PF_SCRATCH_TABLE_DISK_SCRATCH = 0 , PF_SCRATCH_TABLE_BOUNDED_MEMORY = 1 } |
| Storage policy for the nine historical scratch-table regions. More... | |
| enum | pf_fill_qty_partition_t { PF_FILL_QTY_PARTITION_EXIT = -1 , PF_FILL_QTY_PARTITION_EXPLICIT = 0 , PF_FILL_QTY_PARTITION_FROZEN_PLACEMENT = 1 , PF_FILL_QTY_PARTITION_DEFAULT_STOP_PLACEMENT = 2 , PF_FILL_QTY_PARTITION_AT_FILL = 3 } |
Which sizing rule strategy_pending_order_fill_qty's quantity came from, written to its partition out-parameter; each value is documented there. More... | |
| enum | pf_close_cause_t { PF_CLOSE_CAUSE_UNSPECIFIED = 0 , PF_CLOSE_CAUSE_SCRIPT = 1 , PF_CLOSE_CAUSE_BRACKET = 2 , PF_CLOSE_CAUSE_LIQUIDATION = 3 , PF_CLOSE_CAUSE_RISK_LIMIT = 4 , PF_CLOSE_CAUSE_FILL_CAP = 5 , PF_CLOSE_CAUSE_RANGE_END = 6 } |
Why a closed report row exited — execution::CloseCause, the value strategy_closed_trade_close_cause answers for a valid row. More... | |
Functions | |
| int | strategy_set_scratch_tables_v1 (pf_strategy_t s, const pf_scratch_tables_v1 *config) |
| Copy scratch-table configuration while idle; NULL restores disk defaults. | |
| void | strategy_request_abort (pf_strategy_t s) |
| Request cooperative abort of the run in progress (see c_abi.cpp). | |
| int | strategy_last_run_status (pf_strategy_t s) |
0 = completed, 1 = NOT_COMPLETED (aborted), -1 = s is NULL. | |
| void | strategy_set_realtime_tail (pf_strategy_t s, int on, int horizon_bars) |
| Live-runtime tail semantics (spec §3.1): the LAST bar of the array fed to every subsequent run() is a still-forming bar, not the chart's rightmost historical bar. | |
| void | strategy_set_probe_suppress_tail_logic (pf_strategy_t s, int on) |
| Live probe tail suppression (spec §3.2): the LAST script bar of the array fed to every subsequent run() is matched but not calculated. | |
| void | strategy_set_path_order (pf_strategy_t s, int mode) |
| Force this run's intrabar path order (ABI v4 live-runtime surface): the leg order every modeled OHLC path the engine walks uses – stop/limit fill priority, exit trail walking, dual-entry-stop arbitration, bar-magnifier sub-bar sampling, and the excursion columns a source host reports on a closed row. | |
| int | strategy_last_bar_dual_entry_path (pf_strategy_t s) |
| The dual-entry-stop arbitration decided on the LAST bar the most recent run() dispatched: a flat position resting exactly one long stop-only ENTRY and one short stop-only ENTRY, both touched on that bar. | |
| void | strategy_set_broker_state_hash_recording (pf_strategy_t s, int on) |
| Toggle per-report-point broker-state hash recording (spec §3.4, ABI v4). | |
| uint64_t | strategy_broker_state_hash (pf_strategy_t s) |
| Return the broker-state hash of the FINAL state after the most recent run() (see strategy_set_broker_state_hash_recording's doc and pf_report_t::broker_state_hash for the per-bar recording; this accessor works whether or not recording was enabled). | |
| pf_state_query_status_v1_t | strategy_state_query_status_v1 (pf_strategy_t s) |
The current eligibility of BOTH strategy_broker_state_hash and strategy_stream_state_hash on s, as a pf_state_query_status_v1_t: PF_STATE_QUERY_ALLOWED_V1 when either may answer, PF_STATE_QUERY_SELECTED_WINDOW_AFTER_SEAL_V1 when the handle carries selected-window provenance and its run has sealed (a refused query returns 0, which is also a legal hash value: this tells the two apart), and PF_STATE_QUERY_INVALID_HANDLE_V1 for a NULL s. | |
| int | strategy_pending_orders_len (pf_strategy_t s) |
| Number of orders resting in the engine's pending-order book after the most recent run() (ABI v4 live-runtime surface, task 7, spec 3.6): the book in force for the NEXT bar. | |
| int | strategy_pending_order_get (pf_strategy_t s, int index, void *out, size_t size_in) |
Copy the index-th resting order (0-based, the engine's own book order – insertion order; broker fill priority is decided at fill time from created_seq, not from this index) into out as a pf_pending_order_v1_t value snapshot. | |
| const pf_field_desc_t * | strategy_pending_order_layout (int *count) |
The field table of pf_pending_order_v1_t as THIS runtime compiled it – one pf_field_desc_t {name, type, offset, size} per field, in struct order, starting with struct_version and size. | |
| int | strategy_pending_order_fill_qty (pf_strategy_t s, int index, double fill_price, double *qty, int *close_only, int *partition) |
Engine-computed fill quantity of the index-th resting order (ABI v4 live-runtime surface, task 8, spec 3.6): the contracts the entry kernel would OPEN if that order filled at fill_price, sized by the engine's own rules so a live runtime never re-implements them. | |
| int | strategy_pending_order_level_resolved (pf_strategy_t s, int index) |
1 when the index-th resting order's entry-relative offsets (profit_ticks / loss_ticks / trail_points) resolve now (ABI v4, task 8): entries, plain orders and exits with an empty from_entry always; an exit bound to a from_entry only once that id has filled in the CURRENT position cycle – the same condition the level-resolution and eligibility passes use. | |
| int | strategy_pending_order_effective_levels (pf_strategy_t s, int index, double *stop, double *limit, double *trail_activation) |
The price levels the index-th resting order would fire at, as the engine's fill path resolves them (ABI v4, task 8). | |
| double | strategy_trail_best_price (pf_strategy_t s) |
The trail extreme the exit trail legs ride (trail_best_price_: the running high of a long / low of a short since the position filled, bar extremes folded in as the fill path folds them). | |
| double | strategy_position_avg_price (pf_strategy_t s) |
The live position's volume-weighted average entry price (position_entry_price_). | |
| int64_t | strategy_position_cycle_seq (pf_strategy_t s) |
The live position's cycle id (position_cycle_seq_): 0 when flat, a fresh nonzero id per open or reversal, unchanged across same-direction adds – the id created_position_cycle_seq on a mirrored order refers to. | |
| const char * | strategy_closed_trade_entry_id (pf_strategy_t s, int trade_index) |
Task 9: closed-trade id / exit-comment string accessors, indexing the same REPORT row space as strategy_closed_trade_entry_incarnation (trades_ then the range-end rows, open_at_end). | |
| const char * | strategy_closed_trade_exit_id (pf_strategy_t s, int trade_index) |
| See strategy_closed_trade_entry_id for the row-space/lifetime/NULL contract. | |
| const char * | strategy_closed_trade_exit_comment (pf_strategy_t s, int trade_index) |
| See strategy_closed_trade_entry_id. | |
| int | strategy_closed_trade_close_cause (pf_strategy_t s, int trade_index) |
Task 9: why the trade_index-th REPORT-row closed trade exited, a pf_close_cause_t. | |
| double | strategy_position_size (pf_strategy_t s) |
Task 9: the script-facing signed position size (strategy.position_size; KI-64 freeze-aware – while a same-bar process_orders_on_close close is frozen for the current bar, this reads the PRE-close position, matching what the script itself observes). | |
| double | strategy_current_equity (pf_strategy_t s) |
Task 9: initial capital plus realized net profit (strategy.initial_capital + strategy.netprofit). | |
| double | strategy_initial_capital (pf_strategy_t s) |
| ABI v4 live-runtime surface (1.8.0): the configured run's initial capital, before realized or open profit. | |
| int64_t | strategy_script_bars_processed (pf_strategy_t s) |
Task 9: total SCRIPT bars dispatched by the most recent run() (mirrors pf_report_t::script_bars_processed, engine_report.cpp) – includes a stream's warmup leg and every realtime tick-driven bar dispatched afterward by strategy_stream_push_tick / strategy_stream_push_ticks. | |
Default-off flags and read-only accessors used by pineforge-live.
None of them changes a historical run unless enabled.
| #define PINEFORGE_HAS_SCRATCH_TABLES_V1 1 |
Definition at line 896 of file pineforge.h.
| #define PF_STATE_QUERY_ALLOWED_V1 0 |
Both queries may answer, and the quote writers store.
Definition at line 1156 of file pineforge.h.
| #define PF_STATE_QUERY_SELECTED_WINDOW_AFTER_SEAL_V1 1 |
Both are refused, and so are the quote writers: a selected window's run has sealed.
Definition at line 1157 of file pineforge.h.
| #define PF_STATE_QUERY_INVALID_HANDLE_V1 2 |
The handle is NULL.
Definition at line 1158 of file pineforge.h.
| typedef int32_t pf_state_query_status_v1_t |
What strategy_state_query_status_v1 answers: whether the two state queries, strategy_broker_state_hash and strategy_stream_state_hash, may answer a handle now, and whether the report-only terminal-quote writers may still store.
A fixed-width word rather than an enum, so its width does not depend on the consumer's compiler flags.
Definition at line 1155 of file pineforge.h.
Storage policy for the nine historical scratch-table regions.
| Enumerator | |
|---|---|
| PF_SCRATCH_TABLE_DISK_SCRATCH | |
| PF_SCRATCH_TABLE_BOUNDED_MEMORY | |
Definition at line 899 of file pineforge.h.
Which sizing rule strategy_pending_order_fill_qty's quantity came from, written to its partition out-parameter; each value is documented there.
The value set is the Pine source host's pending-order sizing, the only host that answers a probe.
Definition at line 1227 of file pineforge.h.
| enum pf_close_cause_t |
Why a closed report row exited — execution::CloseCause, the value strategy_closed_trade_close_cause answers for a valid row.
The names are the kernel's; the descriptive labels in that function's documentation are the same numbers.
Definition at line 1366 of file pineforge.h.
| int strategy_set_scratch_tables_v1 | ( | pf_strategy_t | s, |
| const pf_scratch_tables_v1 * | config ) |
Copy scratch-table configuration while idle; NULL restores disk defaults.
Never retains a pointer into the caller's descriptor. Returns 0 on success, -1 for a null handle or invalid size/version/backend/reserved/V, -2 during a stream, and -3 during a batch run (including begin callbacks). A refusal preserves the installed configuration and active run ownership. Finite streams must supply maxima for their complete admitted lifetime. The embedding host sets RLIMIT_FSIZE and owns disk-scratch SIGXFSZ policy. This setter does not attach an arena; see strategy_require_report_scratch_arena_v1 for the SIGXFSZ side effect of arena attachment.
References PF_API.
| void strategy_request_abort | ( | pf_strategy_t | s | ) |
Request cooperative abort of the run in progress (see c_abi.cpp).
References PF_API.
| int strategy_last_run_status | ( | pf_strategy_t | s | ) |
0 = completed, 1 = NOT_COMPLETED (aborted), -1 = s is NULL.
References PF_API.
| void strategy_set_realtime_tail | ( | pf_strategy_t | s, |
| int | on, | ||
| int | horizon_bars ) |
Live-runtime tail semantics (spec §3.1): the LAST bar of the array fed to every subsequent run() is a still-forming bar, not the chart's rightmost historical bar.
This is persistent configuration, not a one-shot flag – it stays in effect until a caller passes on == 0, so a handle reused for a later plain historical replay must be explicitly turned back off. Effects when on is non-zero:
barstate.islast is false for that bar.session.islastbar is computed from the bucket calendar (no next bar to peek at, so it evaluates whether the next bucket – this bar's timestamp plus one script-TF step – falls out of session).bar_index stays put; last_bar_index is frozen at the horizon bar (horizon_bars - 1), when horizon_bars > 0. last_bar_time is exact when the horizon bar is in the script-bar array, one script-TF step per missing bar past the array's last bar otherwise; under aggregation (input_tf < script_tf) it is extrapolated from the first bar instead, and the aggregation-path caveat below applies.open_at_end row); the final equity point keeps open_profit.run(bars, n) with at least two bars, whose timeframe it detects from them; with fewer, session.ismarket/session.islastbar keep their reset-state false whatever this flag says. The bucket-calendar lookahead stands in for the next bar wherever the scheduler holds none: with input_tf == script_tf that is the array's last bar alone, but under aggregation (input_tf < script_tf) the scheduler holds no next script bar at all, so the lookahead decides session.islastbar on every bar of the run. Callers must feed an input_tf == script_tf array, matching strategy_set_probe_suppress_tail_logic's scope note. strategy_stream_begin refuses a handle with this flag set. Default off (on == 0): every historical run stays byte-identical to before this flag existed. The mode belongs to the Pine source host; on a host that models no still-forming tail bar (a bare kernel host) the call is accepted and inert, as it always was there. References PF_API.
| void strategy_set_probe_suppress_tail_logic | ( | pf_strategy_t | s, |
| int | on ) |
Live probe tail suppression (spec §3.2): the LAST script bar of the array fed to every subsequent run() is matched but not calculated.
The kernel matches that bar like any other, so resting stop/limit orders settle against it; the Pine source host's scheduler then publishes it through its suppressed-tail step instead of the generated script – source history and bar_index advance, the fills already matched on the bar are settled, the report point is marked, on_bar is not invoked and no range-end row is written. The host's own bar-close policy is not the script and still runs on that bar – its risk-state update and its TradingView margin-call checkpoint – so a margin call due against the forming bar is booked against it. Apart from what that policy books, the run's last-bar fills are exactly the settled book's fills against the forming bar, and the post-run pending-order book is the book in force during that bar. This is persistent configuration, like strategy_set_realtime_tail, and independent of it – do not assume the two flags are coupled; set each explicitly. Scope (ABI v4 / live v1): honoured on every batch path – the single-timeframe and the timeframe-aware overloads, with or without the bar magnifier. Under aggregation (input_tf < script_tf) the suppressed bar is the run's last COMPLETED script bar, and a trailing partial bucket is never calculated at all. Under calc_on_order_fills only the bar's close calculation is suppressed: a fill on the forming bar still triggers the fill recalculation, which runs the script on it. calc_on_order_fills and the bar magnifier stay gated in live v1 and a probe must not enable them; callers must feed an input_tf == script_tf array. strategy_stream_begin refuses a handle with this flag set: clear it (on = 0) first. Default off (on == 0): every historical run stays byte-identical to before this flag existed. Like strategy_set_realtime_tail the mode belongs to the Pine source host; on a host that models no still-forming tail bar the call is accepted and inert, as it always was there.
References PF_API.
| void strategy_set_path_order | ( | pf_strategy_t | s, |
| int | mode ) |
Force this run's intrabar path order (ABI v4 live-runtime surface): the leg order every modeled OHLC path the engine walks uses – stop/limit fill priority, exit trail walking, dual-entry-stop arbitration, bar-magnifier sub-bar sampling, and the excursion columns a source host reports on a closed row.
Values:
0 AUTO (default): the unchanged TV-emulator rule – the leg nearer open (by |high-open| vs |open-low|) goes first.1 HIGH_FIRST: force O -> H -> L -> C regardless of the bar's own shape.2 LOW_FIRST: force O -> L -> H -> C regardless of the bar's own shape. The values are pf_native_path_order_t's (<pineforge/native_c_api.h>): PF_NATIVE_PATH_ORDER_AUTO, PF_NATIVE_PATH_ORDER_HIGH_FIRST and PF_NATIVE_PATH_ORDER_LOW_FIRST. Any other mode is clamped to AUTO: this setter answers nothing, so it cannot refuse one. A live probe runs the SAME forming bar under BOTH forced orders and emits only the fills that agree between the two – a fill that depends on which leg TradingView's own (unobservable, still-forming) bar will resolve to is path-dependent and must be suppressed rather than guessed. This is persistent configuration, like strategy_set_realtime_tail – it stays in effect until a caller passes mode == 0, so a handle reused for a later plain historical replay must be explicitly set back to AUTO. Scope: the mode is carried by the RUN, in NativeRunSpec::path_order. A native-bound source host projects this setting into that field at begin – at run() and at strategy_stream_begin alike – and a bare native host declares the field itself; every modeled path the native driver walks then resolves its leg order from that field. So the setting takes effect at the next begin rather than mid-run, and a stream is NOT exempt: a confirmed bar pushed with strategy_stream_push_bar is sealed on the same forced waypoint sequence a run() walks (measured on a 99/101 bracket and an AUTO-low-first touch bar: both routes exit at 99.00 under AUTO and at 101.00 under HIGH_FIRST). What a forced order cannot reach is an OBSERVED TICK (strategy_stream_push_tick): one price is not a modeled path and has no legs to order, so the same tape fills identically under all three modes; the forming bar those ticks build is ordered only when it seals, on the waypoint sequence above. Default AUTO (mode == 0): every historical run stays byte-identical to before this flag existed. References PF_API.
| int strategy_last_bar_dual_entry_path | ( | pf_strategy_t | s | ) |
The dual-entry-stop arbitration decided on the LAST bar the most recent run() dispatched: a flat position resting exactly one long stop-only ENTRY and one short stop-only ENTRY, both touched on that bar.
Values mirror internal::DualEntryStopPathWinner's enumerator order:
0 None – no such pair was arbitrated on that bar (not flat, no matching pair, or neither/only one side touched).1 LongFirst – the long stop's first-touch position on the intrabar path came first (or the two tied, which the engine always resolves in the long leg's favour).2 ShortFirst – the short stop's first-touch position came first.-1 – s is NULL. This is a per-BAR snapshot, not a live read of the engine's per-pass working state: it is written once, at the arbitration itself, and then holds for the rest of that bar even though the working state goes back to None the moment the winning side fills (position no longer flat) or its stop-entry admission is declined – neither of which undoes the fact that TradingView's broker emulator arbitrated a real pair that bar. A caller therefore gets the right answer whether it reads this after a strategy_set_probe_suppress_tail_logic forming-bar probe (a single native request-matching pass) or after an ordinary process_orders_on_close run with no tail suppression (two passes, the winner already filled by the second). A live probe reads this after a forming-bar run to see which side the engine's own broker-emulator tie-break picked, without having to re-run and infer it from which of the two possible fills came back. Only the standard (non-calc_on_order_fills) dispatch path updates this value; it is a silent no-op under the COOF scheduler, mirroring strategy_set_probe_suppress_tail_logic's dispatch-path-scope caveat. References PF_API.
| void strategy_set_broker_state_hash_recording | ( | pf_strategy_t | s, |
| int | on ) |
Toggle per-report-point broker-state hash recording (spec §3.4, ABI v4).
When on is non-zero, every subsequent run() appends strategy_broker_state_hash's value to pf_report_t::broker_state_hash after each report point (KernelRecorded for bare hosts); completed runs match pf_report_t::script_bars_processed, failed ones may not. Cleared (recorded array emptied, not the flag itself) at the start of every run(); the flag is persistent configuration, like strategy_set_realtime_tail, and stays set until a caller passes on == 0. Also covers strategy_stream_begin's warmup run() and every script bar dispatched afterward by the realtime tick stream, so strategy_stream_fill_report's cumulative report satisfies the same len == script_bars_processed invariant. Set this BEFORE strategy_stream_begin to also record the warmup leg – reset_run_state() (which stream_begin's internal run() invokes) empties the recorded array, not the flag, but a flag flipped on only after stream_begin returns misses the warmup bars already dispatched. Default off (on == 0): pf_report_t::broker_state_hash is NULL / 0-length and every historical run stays byte-identical to before this flag existed.
What a row is, and what it is for. A row is the run's CONTINUATION IDENTITY at that bar, not its trade outcome: it folds the broker state and, ahead of it, the state a resume would continue from – the driving mode (batch run, stream warmup, stream realtime) included, on purpose. So the array is a replay check WITHIN one driving mode and deliberately not across modes: two runs driven the same way over the same bars record the same rows, and a run driven the same way that ended at bar k recorded, as its last row, the row the longer run recorded after bar k; but a run(), a strategy_stream_begin with one warmup bar and one with every bar as warmup record DIFFERENT rows from index 0 over the same bars booking the same trades. Only the len == script_bars_processed identity above holds across drivings. What pins that a stream books what a batch books is the outcome itself – the trades, the position and the equity – and not this array.
References PF_API.
| uint64_t strategy_broker_state_hash | ( | pf_strategy_t | s | ) |
Return the broker-state hash of the FINAL state after the most recent run() (see strategy_set_broker_state_hash_recording's doc and pf_report_t::broker_state_hash for the per-bar recording; this accessor works whether or not recording was enabled).
Compare runs of one configuration: the recipe belongs to the script ABI epoch, fixed from 1.0.0 for every 1.x engine (engine_script_run_v19), so two values differ only when the states they fold differ. This is not a serialized checkpoint. Returns 0 when s is NULL.
A refused read also returns 0, so a 0 alone does not tell it from an answer: once a handle that carries selected-window provenance has sealed its run, this query is refused and strategy_state_query_status_v1 names it (PF_STATE_QUERY_SELECTED_WINDOW_AFTER_SEAL_V1). A caller that needs that run's terminal witness enables strategy_set_broker_state_hash_recording BEFORE the run and reads the last pf_report_t::broker_state_hash row; no row means no witness.
References PF_API.
| pf_state_query_status_v1_t strategy_state_query_status_v1 | ( | pf_strategy_t | s | ) |
The current eligibility of BOTH strategy_broker_state_hash and strategy_stream_state_hash on s, as a pf_state_query_status_v1_t: PF_STATE_QUERY_ALLOWED_V1 when either may answer, PF_STATE_QUERY_SELECTED_WINDOW_AFTER_SEAL_V1 when the handle carries selected-window provenance and its run has sealed (a refused query returns 0, which is also a legal hash value: this tells the two apart), and PF_STATE_QUERY_INVALID_HANDLE_V1 for a NULL s.
A handle answers PF_STATE_QUERY_ALLOWED_V1 unless it was admitted as a selected-window run, which only a separately documented export can do. This is the state of the handle at the call, not a last-error slot: it allocates nothing, changes nothing, runs no host code and never records, replaces or clears strategy_get_last_error or its code, so a run's first cause stays what the run made it. To keep a selected run's terminal witness, enable strategy_set_broker_state_hash_recording BEFORE the run and read the last pf_report_t::broker_state_hash row. A broker-state row is not a value of the strategy_stream_state_hash token, and no row means no witness.
The same status is the observable refusal of the report-only terminal-quote writers (docs/report-terminal-quote.md), under the same condition: once a selected-window run has sealed (completed, failed or aborted), the Pine host stores neither reserved syminfo metadata key, report_terminal_quote_time_ms and report_terminal_quote_close, whatever the value, nor a clear of the quote. In C++ the host throws pineforge::SelectedWindowQueryAfterSeal before any store; the C export strategy_set_syminfo_metadata keeps its void signature and swallows every exception, so a caller learns of the refusal from this status: PF_STATE_QUERY_SELECTED_WINDOW_AFTER_SEAL_V1 means a quote-key write stored nothing. Like the state queries, the refusal records, replaces and clears no strategy_get_last_error or its code, latches no run failure and leaves the captured report as it was. A handle without selected-window provenance, and a selected handle before its first admitted begin, accept the writes as before. Proof: tests/test_selected_quote_seal.cpp.
References PF_API.
| int strategy_pending_orders_len | ( | pf_strategy_t | s | ) |
Number of orders resting in the engine's pending-order book after the most recent run() (ABI v4 live-runtime surface, task 7, spec 3.6): the book in force for the NEXT bar.
0 when s is NULL. Read-only; a historical run is byte-identical whether or not a caller reads it.
References PF_API.
| int strategy_pending_order_get | ( | pf_strategy_t | s, |
| int | index, | ||
| void * | out, | ||
| size_t | size_in ) |
Copy the index-th resting order (0-based, the engine's own book order – insertion order; broker fill priority is decided at fill time from created_seq, not from this index) into out as a pf_pending_order_v1_t value snapshot.
Copies min(size_in, sizeof(pf_pending_order_v1_t)) bytes: an older reader with a smaller struct receives a prefix (struct_version and size first), a newer reader with a larger one receives the whole v1 and must not read past pf_pending_order_v1_t::size. Strings are NUL-terminated char[64] copies with a _truncated flag and a _hash64 (FNV-1a 64 of the full string); enums are int32 values; NaN sentinels are copied verbatim. Returns 0 on success, -1 – with nothing written – when s or out is NULL, index is out of range, or size_in < 8 (too small to hold even the struct_version + size header; every larger size_in is honoured as a prefix copy). The layout is self-described by strategy_pending_order_layout.
References PF_API.
| const pf_field_desc_t * strategy_pending_order_layout | ( | int * | count | ) |
The field table of pf_pending_order_v1_t as THIS runtime compiled it – one pf_field_desc_t {name, type, offset, size} per field, in struct order, starting with struct_version and size.
Static storage: the pointer stays valid for the life of the process and needs no handle. count (may be NULL) receives the row count. An FFI consumer builds its struct from this table rather than from a hand-typed copy, so the mirror can grow (append-only) without breaking it.
References PF_API.
| int strategy_pending_order_fill_qty | ( | pf_strategy_t | s, |
| int | index, | ||
| double | fill_price, | ||
| double * | qty, | ||
| int * | close_only, | ||
| int * | partition ) |
Engine-computed fill quantity of the index-th resting order (ABI v4 live-runtime surface, task 8, spec 3.6): the contracts the entry kernel would OPEN if that order filled at fill_price, sized by the engine's own rules so a live runtime never re-implements them.
fill_price is slipped the way the kernel slips it (native_matching::apply_slippage then the directional grid snap; an entry with a limit leg takes the unslipped limit-or-better route). partition receives which sizing rule produced the value, a pf_fill_qty_partition_t:
0 EXPLICIT – a script-supplied qty: for strategy.entry the lot-floored contracts (apply_qty_step) of a fixed qty, or the explicit percent/cash budget sized at the fill for a per-call qty_type override; a strategy.order explicit qty is dispatched verbatim (no lot step).1 FROZEN_PLACEMENT – a quantity fixed before the fill, never re-derived from the fill price: the default percent_of_equity / cash MARKET (or strategy.order) size frozen at the signal close (frozen_default_qty); a MARKET's frozen broker transaction (a finalized flat pair's paired_flat_market_transaction_qty; a same-bar-market member's sbmt_tx_qty from flat or as a kept over-cap add); or what one of the two MARKET reversal kernels opens – a same-bar-market member against an opposite live position opens the remainder sbmt_tx_qty - min(sbmt_tx_qty, live qty) (the same-bar market reversal path), and the exact SHORT-seed collision's final short re-opens the residual pyramid_entries[0].qty - pyramid_entries[1].qty after closing both lots (the short-seed collision path). Both kernels are modelled; each reports close_only 1 when it opens nothing.2 DEFAULT_STOP_PLACEMENT – the DEFAULT percent_of_equity pure STOP entry's placement size, at any percentage (default_stop_placement_qty, round-7 family K), when the placement-size rule says the fill consumes it: created flat, filling from flat, positive fill.3 AT_FILL – default sizing at the slipped fill. close_only receives 1 when the kernel's close-only predicate fires – the fill closes against the live opposite position and that predicate opens no leg of its own: the order's affordability_close_only (entry leg declined at placement), the priced-entry prior_cycle_close_only rule (opposite live position whose cycle the order was not placed in – created_position_side != the live side – and not a KI-65 reverses_same_bar_market_from_flat), the same-cycle frozen explicit-FIXED transaction the close consumes exactly, a finalized flat MARKET pair against an opposite position, or one of the two reversal kernels above opening nothing. Where the order was created FLAT the engine's close-only branch can open a remainder: a transaction larger than the live position still opens the remainder, so a consumer compares qty with the live position. A replaced default-percent short is dispatched with its frozen_default_qty: qty is that transaction, close_only 0. The probe answers for the order filling against the CURRENT book and position; fills that an earlier order in the same pass would make first are not simulated. NOT folded into qty: the deferred-flip carry (tv_carry_qty, added on a priced entry from FLAT whose placement side is the opposite of the requested side) – read tv_carry_qty / created_position_side from the mirror. Returns 0 on success; 1 – with qty NaN, close_only 0, partition -1 (PF_FILL_QTY_PARTITION_EXIT) – when the order is an EXIT (its fill quantity is decided against the live position at the fill, not by a partition); -1 with nothing written when s is NULL, index is out of range, or any out-pointer is NULL. Read-only: no historical run changes because a caller probed it. References PF_API.
| int strategy_pending_order_level_resolved | ( | pf_strategy_t | s, |
| int | index ) |
1 when the index-th resting order's entry-relative offsets (profit_ticks / loss_ticks / trail_points) resolve now (ABI v4, task 8): entries, plain orders and exits with an empty from_entry always; an exit bound to a from_entry only once that id has filled in the CURRENT position cycle – the same condition the level-resolution and eligibility passes use.
0 otherwise; -1 when s is NULL or index is out of range.
References PF_API.
| int strategy_pending_order_effective_levels | ( | pf_strategy_t | s, |
| int | index, | ||
| double * | stop, | ||
| double * | limit, | ||
| double * | trail_activation ) |
The price levels the index-th resting order would fire at, as the engine's fill path resolves them (ABI v4, task 8).
A leg the order carries as a price (stop_price, limit_price, trail_price) is reported verbatim – it is already on the price grid. A leg carried as a tick offset is resolved against the live position's average entry price only when strategy_pending_order_level_resolved is 1 AND a position is live, with the POSITION side's sign exactly as the fill path: limit = entry + dir * profit_ticks * mintick, stop = entry - dir * loss_ticks * mintick (dir = +1 long, -1 short; both level_on_price_grid), and trail_activation = entry +/- ceil( trail_points - 8e-3 * mintick) * mintick snapped to the tick grid (trail_points wins over trail_price when both are set, as in the trail activation rule). NaN for a leg that is unset or not yet resolvable. Returns 0; -1 with nothing written when s is NULL, index is out of range, or any out-pointer is NULL.
References PF_API.
| double strategy_trail_best_price | ( | pf_strategy_t | s | ) |
The trail extreme the exit trail legs ride (trail_best_price_: the running high of a long / low of a short since the position filled, bar extremes folded in as the fill path folds them).
NaN when s is NULL and NaN until a position has filled.
References PF_API.
| double strategy_position_avg_price | ( | pf_strategy_t | s | ) |
The live position's volume-weighted average entry price (position_entry_price_).
NaN when s is NULL and NaN when the position is flat (the engine keeps 0 there; a live reader must not mistake it for a price).
References PF_API.
| int64_t strategy_position_cycle_seq | ( | pf_strategy_t | s | ) |
The live position's cycle id (position_cycle_seq_): 0 when flat, a fresh nonzero id per open or reversal, unchanged across same-direction adds – the id created_position_cycle_seq on a mirrored order refers to.
-1 when s is NULL.
References PF_API.
| const char * strategy_closed_trade_entry_id | ( | pf_strategy_t | s, |
| int | trade_index ) |
Task 9: closed-trade id / exit-comment string accessors, indexing the same REPORT row space as strategy_closed_trade_entry_incarnation (trades_ then the range-end rows, open_at_end).
The returned pointer is valid until the next run() (or stream call) on this handle, like strategy_get_last_error. NULL on a NULL s or an out-of-range trade_index. This legacy borrowed-pointer API materializes each requested row until the next run; full-history requests use growing RAM.
References PF_API.
| const char * strategy_closed_trade_exit_id | ( | pf_strategy_t | s, |
| int | trade_index ) |
See strategy_closed_trade_entry_id for the row-space/lifetime/NULL contract.
The returned string is the engine's own INTERNAL exit id, not always the script's strategy.exit/strategy.close id verbatim:
strategy.exit bracket leg – the user's own id, unchanged.strategy.close(id, ...) close – "__close__" + id.strategy.close_all() / a bare-id strategy.close() – the literal "__close__" (empty target id appended)."__margin_call__".risk.max_intraday_loss, or the max-filled-orders cap) – empty (""). A caller matching exit ids back to its own strategy.close calls should strip the "__close__" prefix rather than compare verbatim. References PF_API.
| const char * strategy_closed_trade_exit_comment | ( | pf_strategy_t | s, |
| int | trade_index ) |
See strategy_closed_trade_entry_id.
References PF_API.
| int strategy_closed_trade_close_cause | ( | pf_strategy_t | s, |
| int | trade_index ) |
Task 9: why the trade_index-th REPORT-row closed trade exited, a pf_close_cause_t.
Values:
0 UNKNOWN – reserved for the documented "no cause" value on a VALID trade. Every in-range row currently falls through the derivation below to at worst 1 SCRIPT, so no live derivation today actually returns 0; it is not used for a bad index (see -1 below, final review F7).1 SCRIPT – a strategy.close / strategy.close_all market close, or a reversal-driven close.2 BRACKET – a strategy.exit stop/limit/trail/profit/loss leg, or a native host's close its owner's fill armed.3 MARGIN_CALL – a forced liquidation slice.4 INTRADAY_LOSS_CAP – risk.max_intraday_loss.5 INTRADAY_FILL_CAP – the max-filled-orders intraday cap.6 RANGE_END – the still-open position closed at the end of a flag-off run (open_at_end, ABI v3) – this always wins over every other cause below it. Derivation order (see BacktestEngine::closed_trade_close_cause, engine_trade_accessors.cpp): open_at_end -> 6; then the cause the CLOSER recorded on the row (execution::CloseCause, whose numbers are exactly these values) – a kernel-originated liquidation or risk flatten states it through the settling fill, and so does a host request its owner's fill armed (a WaitForApplied owner relation, as native_toolkit::submit_bracket builds, with an intent that only closes: Reduce, Flatten or a host-sized close), which records 2 BRACKET; a host running its own forced-close policy states it on the row it produced, which is where the Pine adapter's margin-call (3), max-intraday-loss (4) and filled-order-cap (5) rows get their value (the adapter classifies its own bracket rows by order family, so it clears the kernel's 2 on them first); then the row's exit_from_bracket flag – true only for a REAL strategy.exit leg, either an exit-order fill whose id does NOT carry the internal "__close__" prefix that a deferred strategy.close/close_all order is also given (that path reuses the same exit fill machinery), or a whole-position bracket revived and fired at the margin-call event price (through the margin-call bracket revival) – -> 2; otherwise 1. A Pine/source run's values are unchanged. A bare native host that declares a kernel margin model now reads 3 for its own liquidation rows (and 4 for a kernel risk flatten) where the retired string derivation, which only recognised the adapter's sentinels, answered 1, and it reads 2 for a bracket leg its owner armed, where it read 1 before R5 lane F3. -1 when s is NULL, or when trade_index is out of range (final review F7: matches every sibling indexed live accessor's -1-on-bad-index convention – strategy_pending_order_fill_qty, strategy_pending_order_level_resolved, strategy_pending_order_effective_levels). 0 therefore never ambiguously means "bad index"; a caller can tell "row exists but reads
UNKNOWN" apart from "bad index" without a separate strategy_closed_trade_entry_incarnation report_trade_count bounds check first, though doing that check is still good practice. References PF_API.
| double strategy_position_size | ( | pf_strategy_t | s | ) |
Task 9: the script-facing signed position size (strategy.position_size; KI-64 freeze-aware – while a same-bar process_orders_on_close close is frozen for the current bar, this reads the PRE-close position, matching what the script itself observes).
NaN when s is NULL.
References PF_API.
| double strategy_current_equity | ( | pf_strategy_t | s | ) |
Task 9: initial capital plus realized net profit (strategy.initial_capital + strategy.netprofit).
NOT Pine's strategy.equity, which adds open profit on top of this (unlike the last point of pf_report_t::equity_curve, which does). NaN when s is NULL.
References PF_API.
| double strategy_initial_capital | ( | pf_strategy_t | s | ) |
ABI v4 live-runtime surface (1.8.0): the configured run's initial capital, before realized or open profit.
Includes staged native specs before begin, and generated defaults or overrides once the source host configures the run. NaN when s is NULL or the read raises, matching strategy_current_equity's invalid-handle sentinel so a failed query is not mistaken for a capital value.
References PF_API.
| int64_t strategy_script_bars_processed | ( | pf_strategy_t | s | ) |
Task 9: total SCRIPT bars dispatched by the most recent run() (mirrors pf_report_t::script_bars_processed, engine_report.cpp) – includes a stream's warmup leg and every realtime tick-driven bar dispatched afterward by strategy_stream_push_tick / strategy_stream_push_ticks.
-1 when s is NULL.
References PF_API.