PineForge v0.13.1-379-g9b50973
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
exit_activation.cpp
Go to the documentation of this file.
2
3#include <cmath>
4#include <stdexcept>
5
7
9 : evidence_(std::move(evidence)) {
10 const auto& value = *evidence_;
11 if (value.position_cycle <= 0 || value.entry_bar < 0
12 || (value.direction != 1 && value.direction != -1)
13 || !std::isfinite(value.cursor_price)) {
14 throw std::invalid_argument("invalid Pine exit placement evidence");
15 }
16}
17
18bool ExitActivationPolicy::holds_stop() const noexcept {
19 return evidence_ && !std::isnan(evidence_->stop_level)
20 && (evidence_->direction > 0 ? evidence_->cursor_price <= evidence_->stop_level
21 : evidence_->cursor_price >= evidence_->stop_level);
22}
23
24bool ExitActivationPolicy::holds_limit() const noexcept {
25 return evidence_ && !evidence_->limit_continuation
26 && !std::isnan(evidence_->limit_level)
27 && (evidence_->direction > 0 ? evidence_->cursor_price >= evidence_->limit_level
28 : evidence_->cursor_price <= evidence_->limit_level);
29}
30
32 return evidence_ && evidence_->limit_continuation
33 && evidence_->limit_continuation->cause == LimitContinuationCause::LaterSameOpen;
34}
35
37 int owner_entry_bar) const {
38 const int first = owner_entry_bar;
39 return {owner_cycle, first + (holds_stop() ? 1 : 0), first + (holds_limit() ? 1 : 0)};
40}
41
43 double stop, double limit,
44 const ExitActivationContext& context) {
45 if (!context.fill_recalc || !context.scheduler || !std::isfinite(context.cursor_price)
46 || context.cycle <= 0 || context.position_open_bar != context.bar_index
47 || (context.direction != 1 && context.direction != -1)) {
48 return {};
49 }
50 const bool limit_marketable = !std::isnan(limit)
51 && (context.direction > 0 ? context.cursor_price >= limit
52 : context.cursor_price <= limit);
53 std::optional<LimitContinuation> continuation;
54 const bool historical_reach = historical_cascade_reach(request.birth_reach);
55 if (!context.magnifier && historical_reach
56 && context.after_first_open_fill
57 && context.recalc_leg == 0 && (!std::isnan(stop) || !std::isnan(limit))
58 && !request.requested_trailing && limit_marketable) {
60 context.current_fill};
61 } else if (!context.magnifier && !context.process_on_close && !context.warmup
62 && context.stream_idle && historical_reach
63 && request.full_quantity && !request.requested_trailing
64 && !context.historical_segment && context.at_extreme
65 && context.historical_point == 1 && context.recalc_leg == 1
66 && context.market_recalc_incarnation != 0
67 && context.market_recalc_fill == context.current_fill
68 && context.direction > 0 && context.position_entry_count == 1
69 && context.pyramiding == 0 && context.lot_count == 1
71 && request.has_from_entry
72 && request.from_entry == context.first_lot_id
73 && std::isfinite(request.quantity)
74 && std::abs(request.quantity - context.position_quantity) <= 1e-9
75 && context.pending_empty && request.oca_name.empty()
76 && context.slippage == 0 && context.pointvalue == 1.0
77 && context.account_fx == 1.0 && context.fx_series_empty
78 && limit_marketable && context.bar_path_high_first
79 && context.cursor_price == context.tick_high
80 && context.bar.low < limit && limit < context.bar.high
81 && (std::isnan(stop) || stop < context.bar.low)) {
83 context.current_fill};
84 }
85 return ExitActivationPolicy({context.cycle, context.position_open_bar,
86 context.direction, context.cursor_price,
87 stop, limit, continuation});
88}
89
90} // namespace pineforge::compat::pine
ExitLegActivationBounds resolve(std::int64_t owner_cycle, int owner_entry_bar) const
const std::optional< ExitPlacementEvidence > & evidence() const noexcept
bool historical_cascade_reach(HistoricalBirthReach reach) noexcept
ExitActivationPolicy select_exit_activation(const ExitActivationRequest &request, double stop, double limit, const ExitActivationContext &context)
double low
Definition bar.hpp:7
double high
Definition bar.hpp:7