PineForge v0.13.1-379-g9b50973
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
broker_events.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <limits>
5#include <optional>
6#include <utility>
7#include <variant>
8
10
11// Stable causal identity, independent of a reusable Pine entry ID, FIFO trade
12// rows and observer delivery. Zero IDs are reserved for native test fixtures;
13// the production fill dispatcher supplies the committed cycle/fill/order IDs.
16 uint64_t producerFill;
19 int64_t timestamp;
20
21};
22
23inline bool operator==(const OpeningOwner& owner, const OpeningOwner& other) {
24 return owner.positionCycle == other.positionCycle
25 && owner.producerFill == other.producerFill
26 && owner.orderIncarnation == other.orderIncarnation
27 && owner.barIndex == other.barIndex && owner.timestamp == other.timestamp;
28}
29
32
33// The decision is made when a real opening fill commits. An exempt event is
34// still present until its checkpoint; it cannot carry an adverse continuation.
35// Taking a receipt never promotes an exemption into a check.
36class OpeningReceipt {
37 struct Check { OpeningContinuation continuation; };
38 struct Exempt {};
39 using Decision = std::variant<Check, Exempt>;
40
41public:
42 static OpeningReceipt check(
45 return OpeningReceipt(owner, raw_fill_base, Check{continuation});
46 }
47 static OpeningReceipt exempt(OpeningOwner owner, double raw_fill_base) {
48 return OpeningReceipt(owner, raw_fill_base, Exempt{});
49 }
50
51 const OpeningOwner& owner() const { return owner_; }
52 double raw_fill_base() const { return raw_fill_base_; }
54 return std::holds_alternative<Check>(decision_)
56 }
57 bool requires_adverse_pass() const {
58 const auto* check = std::get_if<Check>(&decision_);
59 return check
61 }
62
63private:
65 : owner_(owner), raw_fill_base_(raw_fill_base), decision_(decision) {}
66
67 OpeningOwner owner_;
68 double raw_fill_base_;
69 Decision decision_;
70};
71
72// One coalescing checkpoint for the live position. Successful qualifying fills
73// replace it; rejected/no-op attempts have no transition. Full close, reversal
74// and accepted incompatible fills invalidate it. This is not a queue of all
75// past fills: the checkpoint evaluates the current aggregate position using
76// the latest eligible producer's raw match price.
78public:
79 bool pending() const { return pending_.has_value(); }
80 bool actionable() const {
81 return pending_ && pending_->decision() == OpeningDecision::Check;
82 }
83 bool requires_adverse_pass() const {
84 return pending_ && pending_->requires_adverse_pass();
85 }
86 double raw_fill_base() const {
87 return pending_ ? pending_->raw_fill_base()
88 : std::numeric_limits<double>::quiet_NaN();
89 }
90 const std::optional<OpeningReceipt>& peek() const { return pending_; }
91
92 void replace(OpeningReceipt receipt) { pending_ = std::move(receipt); }
93 void invalidate() { pending_.reset(); }
94
95 // Consume before the financial consumer can return, recurse or book a
96 // close. A receipt from a different position cycle cannot reach it.
97 std::optional<OpeningReceipt> take(int64_t live_position_cycle) {
98 auto receipt = std::exchange(pending_, std::nullopt);
99 if (receipt && receipt->owner().positionCycle != live_position_cycle)
100 return std::nullopt;
101 return receipt;
102 }
103
104 // The pre-priced-exit checkpoint commits consumption only after it books
105 // a slice. It cannot erase an event that a later producer has replaced.
106 bool consume(const OpeningOwner& owner) {
107 if (!pending_ || !(pending_->owner() == owner)) return false;
108 pending_.reset();
109 return true;
110 }
111
112private:
113 std::optional<OpeningReceipt> pending_;
114};
115
116} // namespace pineforge::broker
const std::optional< OpeningReceipt > & peek() const
void replace(OpeningReceipt receipt)
bool consume(const OpeningOwner &owner)
std::optional< OpeningReceipt > take(int64_t live_position_cycle)
static OpeningReceipt exempt(OpeningOwner owner, double raw_fill_base)
const OpeningOwner & owner() const
static OpeningReceipt check(OpeningOwner owner, double raw_fill_base, OpeningContinuation continuation=OpeningContinuation::None)
OpeningDecision decision() const
bool operator==(const OpeningOwner &owner, const OpeningOwner &other)