PineForge v0.13.1-379-g9b50973
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
pine_path_resolve.cpp
Go to the documentation of this file.
1/*
2 * pine_path_resolve.cpp — the TradingView half of the modeled OHLC path.
3 *
4 * Moved verbatim out of src/engine_path_resolve.cpp (R5 lane L12, 2.ii g).
5 * R5 lane N10 then deleted every symbol of that move whose only remaining
6 * references were its own declaration and the tests: the priced-entry
7 * activation, the cross-event list, the tick-quantized trail machinery and
8 * the whole exit-path resolver were a second fill simulation beside the
9 * kernel matcher (src/native_matching.hpp + NativeExecutionConsumer), which
10 * is what the adapter has resolved exits on since the R5 re-lowerings. What
11 * is left is the one function a live caller still reaches:
12 * `entry_stop_first_touch`, the direction-aware first-touch position a
13 * TradingView stop ENTRY fires at (pine_adapter.cpp). The generic helpers it
14 * calls (`bar_path_uses_high_first`, `fill_bar_path_points_ordered`) stay in
15 * the kernel TU and are reached through the same engine_internal.hpp
16 * declarations as before.
17 */
18
19#include "../engine_internal.hpp"
21
22#include <algorithm>
23#include <cmath>
24
25namespace pineforge {
26namespace internal {
27
28// TradingView's trail tick arithmetic lives with the source layer (R5 lane N14).
32
33// First path position where a stop ENTRY can fire, accounting for direction:
34// long stops only fire on up-segments (price rising through the stop), short
35// stops only fire on down-segments. The gap-fill shortcut uses non-strict
36// comparisons: when bar.open already sits at or beyond the stop level in the
37// firing direction the order fills at open (path position 0). For the
38// open-equals-stop case both legs return 0 simultaneously and the dual-stop
39// arbitration breaks the tie in favour of the long leg — this matches TV's
40// broker emulator on probe 83.
41bool entry_stop_first_touch(const Bar& bar, double stop_level,
42 bool is_long, double* out_pos) {
43 return entry_stop_first_touch(bar, bar_path_uses_high_first(bar),
44 stop_level, is_long, out_pos);
45}
46
47bool entry_stop_first_touch(const Bar& bar, bool high_first, double stop_level,
48 bool is_long, double* out_pos) {
49 if (std::isnan(stop_level) || out_pos == nullptr) return false;
50
51 if (is_long) {
52 if (!(bar.high >= stop_level)) return false;
53 if (bar.open >= stop_level) {
54 *out_pos = 0.0;
55 return true;
56 }
57 } else {
58 if (!(bar.low <= stop_level)) return false;
59 if (bar.open <= stop_level) {
60 *out_pos = 0.0;
61 return true;
62 }
63 }
64
65 double path[4];
66 fill_bar_path_points_ordered(bar, high_first, path);
67
68 for (int i = 1; i < 4; ++i) {
69 double prev = path[i - 1];
70 double curr = path[i];
71 if (is_long) {
72 if (curr <= prev) continue;
73 } else {
74 if (curr >= prev) continue;
75 }
76 double lo = std::min(prev, curr);
77 double hi = std::max(prev, curr);
78 if (stop_level < lo || stop_level > hi) continue;
79
80 double pos = static_cast<double>(i - 1);
81 double denom = curr - prev;
82 if (std::abs(denom) > kSegmentDenomEps) {
83 pos += (stop_level - prev) / denom;
84 }
85 *out_pos = pos;
86 return true;
87 }
88
89 *out_pos = 0.0;
90 return true;
91}
92
93} // namespace internal
94} // namespace pineforge
double trail_offset_to_ticks(double trail_offset)
double trail_points_to_ticks(double trail_points)
double snap_trail_level_to_tick_grid(double price, double mintick)
bool entry_stop_first_touch(const Bar &bar, double stop_level, bool is_long, double *out_pos)
double open
Definition bar.hpp:7
double low
Definition bar.hpp:7
double high
Definition bar.hpp:7