PineForge v0.13.1-379-g9b50973
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
order_cancellation.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <cmath>
5#include <limits>
6
7namespace pineforge {
8
9// A cancellation is a broker-book result with a causal source. The engine
10// owns this state; compatibility layers choose when a source instruction is
11// cancelled and bind the resulting receipt to the affected order.
12inline namespace order_cancellation_v1 {
13
14enum class CancellationCause : int32_t {
15 None = 0,
18};
19
20enum class CancellationState : int32_t {
21 Live = 0,
23};
24
25enum class CloseClaimRelease : int32_t {
30};
31
32enum class CancellationResult : int32_t {
34 Replay = 1,
37};
38
40 uint64_t incarnation = 0;
41 int64_t owner = 0;
42 uint64_t revision = 0;
43};
44
45// One order-owned receipt covers both cancellation sites currently modelled
46// by the broker. The cause and source identity make the result auditable;
47// CloseClaimRelease is a state transition, so a close reservation can be
48// returned at most once even if the fill loop revisits the order.
50public:
51 CancellationCause cause() const { return cause_; }
52 CancellationState state() const { return state_; }
53 CloseClaimRelease close_claim_release() const { return close_claim_release_; }
54 uint64_t source_incarnation() const { return source_incarnation_; }
55 int64_t source_sequence() const { return source_sequence_; }
56 uint64_t target_incarnation() const { return target_incarnation_; }
57 int64_t target_owner() const { return target_owner_; }
58 uint64_t target_revision() const { return target_revision_; }
59 double close_claim_consumed() const { return close_claim_consumed_; }
60 double close_claim_retired() const { return close_claim_retired_; }
61
62 bool cancelled() const { return state_ == CancellationState::Cancelled; }
63 bool has_close_claim() const {
64 return close_claim_release_ != CloseClaimRelease::Unbound
65 && close_claim_release_ != CloseClaimRelease::NotApplicable;
66 }
67
68 // Validate the causal request against the lifecycle identity supplied by
69 // the caller before mutating the receipt. The target comparison prevents
70 // a stale order reference from cancelling a later incarnation.
72 int64_t source_sequence, CancellationTarget target,
73 CancellationTarget current_target) {
74 const bool valid = cause != CancellationCause::None
76 && target.incarnation != 0 && target.owner >= 0
77 && target.revision != std::numeric_limits<uint64_t>::max()
78 && current_target.incarnation == target.incarnation
79 && current_target.owner == target.owner
80 && current_target.revision == target.revision;
81 if (!valid) return CancellationResult::Invalid;
82 if (state_ == CancellationState::Cancelled) {
83 return cause_ == cause && source_incarnation_ == source_incarnation
84 && source_sequence_ == source_sequence
85 && target_incarnation_ == target.incarnation
86 && target_owner_ == target.owner
87 && target_revision_ == target.revision
90 }
91 cause_ = cause;
93 source_incarnation_ = source_incarnation;
94 source_sequence_ = source_sequence;
95 target_incarnation_ = target.incarnation;
96 target_owner_ = target.owner;
97 target_revision_ = target.revision;
99 }
100
101 // Atomically commit a cancellation and its already-prepared claim credit.
102 // The caller reserves the ledger slot before calling this method; all
103 // validation and finite arithmetic happen on a copy, so an invalid claim
104 // cannot leave a cancelled instruction behind.
106 uint64_t source_incarnation, int64_t source_sequence,
107 CancellationTarget target, CancellationTarget current_target,
108 double* ledger) {
109 OrderCancellationReceipt next = *this;
110 const auto result = next.cancel(cause, source_incarnation,
111 source_sequence, target, current_target);
112 if (result != CancellationResult::Applied) return result;
113 if (next.close_claim_release_ == CloseClaimRelease::Pending) {
114 if (!ledger) return CancellationResult::Invalid;
115 double value = *ledger;
117 *this = next;
118 *ledger = value;
120 }
121 *this = next;
123 }
124
125 // Capture the placement-time close claim. NaN is the existing sentinel
126 // for a close that did not debit the id ledger, so it remains a no-op.
127 bool bind_close_claim(double consumed, double retired) {
128 if (state_ != CancellationState::Live
129 || close_claim_release_ != CloseClaimRelease::Unbound) return false;
130 const bool no_claim = std::isnan(consumed) && retired == 0.0;
131 const bool valid_claim = std::isfinite(consumed) && consumed > 0.0
132 && std::isfinite(retired) && retired >= 0.0;
133 if (!no_claim && !valid_claim) return false;
134 close_claim_consumed_ = consumed;
135 close_claim_retired_ = retired;
136 close_claim_release_ = valid_claim
138 return true;
139 }
140
141 // Return the captured claim exactly once. The caller supplies the
142 // order-id ledger so the generic receipt has no knowledge of Pine ids.
143 bool release_close_claim_once(double& ledger) {
144 if (state_ != CancellationState::Cancelled
145 || close_claim_release_ != CloseClaimRelease::Pending
146 || !std::isfinite(ledger)) {
147 return false;
148 }
149 const double credit = close_claim_consumed_ + close_claim_retired_;
150 if (!std::isfinite(credit) || !std::isfinite(ledger + credit)) return false;
151 ledger += credit;
152 close_claim_release_ = CloseClaimRelease::Released;
153 return true;
154 }
155
156private:
159 CloseClaimRelease close_claim_release_ = CloseClaimRelease::Unbound;
160 uint64_t source_incarnation_ = 0;
161 int64_t source_sequence_ = 0;
162 uint64_t target_incarnation_ = 0;
163 int64_t target_owner_ = 0;
164 uint64_t target_revision_ = 0;
165 double close_claim_consumed_ = std::numeric_limits<double>::quiet_NaN();
166 double close_claim_retired_ = 0.0;
167};
168
169} // inline namespace order_cancellation_v1
170} // namespace pineforge
CancellationResult cancel(CancellationCause cause, uint64_t source_incarnation, int64_t source_sequence, CancellationTarget target, CancellationTarget current_target)
CancellationResult cancel_and_release(CancellationCause cause, uint64_t source_incarnation, int64_t source_sequence, CancellationTarget target, CancellationTarget current_target, double *ledger)