PineForge v0.13.1-379-g9b50973
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
quantity_intent.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cmath>
4#include <optional>
5#include <stdexcept>
6#include <variant>
7
8namespace pineforge {
9
11
12// A requested amount, before executable quantity is rounded, reserved or
13// reduced. A fraction retains its numerator and denominator so a frontend can
14// preserve the caller's exact representation (for example 50 / 100).
15class QuantityIntent {
16 struct Units { double amount; };
17 struct Fraction { double numerator; double denominator; };
18 struct All {};
19 using Value = std::variant<Units, Fraction, All>;
20public:
22 static QuantityIntent units(double amount) { return QuantityIntent(Units{amount}); }
23 static QuantityIntent fraction(double numerator, double denominator) {
24 if (!std::isfinite(denominator) || denominator <= 0.0)
25 throw std::invalid_argument("quantity fraction requires a positive finite denominator");
26 return QuantityIntent(Fraction{numerator, denominator});
27 }
28 static QuantityIntent all() { return QuantityIntent(All{}); }
29 Kind kind() const { return static_cast<Kind>(value_.index()); }
30 double units() const { return std::get<Units>(value_).amount; }
31 double numerator() const { return std::get<Fraction>(value_).numerator; }
32 double denominator() const { return std::get<Fraction>(value_).denominator; }
33private:
34 explicit QuantityIntent(Value value) : value_(value) {}
35 Value value_;
36};
37
38// A reservation is a causal quantity snapshot. Later OCA reductions of the
39// executable order do not rewrite its original request or this basis.
41 double units;
43};
44
46public:
47 const std::optional<QuantityIntent>& intent() const { return intent_; }
48 const std::optional<QuantityReservation>& reservation() const { return reservation_; }
50 intent_ = intent;
51 reservation_.reset();
52 }
53 void reserve(double units, double basis_units) {
54 if (!intent_) throw std::logic_error("quantity reservation requires an original request");
55 reservation_ = QuantityReservation{units, basis_units};
56 }
57 bool requests_all() const {
58 return intent_ && intent_->kind() == QuantityIntent::Kind::All;
59 }
60 // Tolerances belong to the caller's quantity policy. No minimum lot,
61 // percentage rounding or strategy-specific eligibility lives here.
62 bool is_partial(double units_tolerance, double fraction_tolerance) const {
63 if (reservation_)
64 return reservation_->units < reservation_->basis_units - units_tolerance;
65 return intent_ && intent_->kind() == QuantityIntent::Kind::Fraction
66 && intent_->numerator() < intent_->denominator() - fraction_tolerance;
67 }
68private:
69 // Absent for commands that do not carry this exit-request contract.
70 std::optional<QuantityIntent> intent_;
71 std::optional<QuantityReservation> reservation_;
72};
73
74} // namespace pineforge
static QuantityIntent fraction(double numerator, double denominator)
static QuantityIntent units(double amount)
static QuantityIntent all()
bool is_partial(double units_tolerance, double fraction_tolerance) const
void request(QuantityIntent intent)
void reserve(double units, double basis_units)
const std::optional< QuantityReservation > & reservation() const
const std::optional< QuantityIntent > & intent() const