PineForge unreleased
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
pine_value_admission.cpp
Go to the documentation of this file.
3
4#include <cmath>
5#include <cstddef>
6#include <string_view>
7
8namespace pineforge::source {
9namespace {
10
11// Unicode scalar UTF-8, using the string's length rather than a C terminator.
12// NUL is ASCII; the first continuation bounds exclude overlong encodings,
13// surrogate code points and values beyond U+10FFFF.
14bool valid_utf8(std::string_view text) noexcept {
15 std::size_t index = 0;
16 while (index < text.size()) {
17 const auto lead = static_cast<unsigned char>(text[index++]);
18 if (lead < 0x80) continue;
19 std::size_t tails = 0;
20 if (lead >= 0xc2 && lead <= 0xdf) tails = 1;
21 else if (lead >= 0xe0 && lead <= 0xef) tails = 2;
22 else if (lead >= 0xf0 && lead <= 0xf4) tails = 3;
23 else return false;
24 if (tails > text.size() - index) return false;
25 for (std::size_t tail = 0; tail < tails; ++tail) {
26 const auto byte = static_cast<unsigned char>(text[index + tail]);
27 if (byte < 0x80 || byte > 0xbf) return false;
28 if (tail == 0) {
29 if (lead == 0xe0 && byte < 0xa0) return false;
30 if (lead == 0xed && byte > 0x9f) return false;
31 if (lead == 0xf0 && byte < 0x90) return false;
32 if (lead == 0xf4 && byte > 0x8f) return false;
33 }
34 }
35 index += tails;
36 }
37 return true;
38}
39
40void admit_comment(const std::string& text, const char* field) {
41 if (!valid_utf8(text))
43}
44
45void admit_text(const std::string& text, const char* field) {
46 admit_comment(text, field);
47 // IDs, entry selectors and OCA names feed separator-delimited adapter
48 // keys. Inspect the entire string, including bytes after an embedded NUL.
49 if (text.find('\x1f') != std::string::npos || text.find('\0') != std::string::npos) {
50 const std::string_view name(field);
51 const auto dot = name.find('.');
52 throw coded<std::invalid_argument>(
54 RunFailureArgs{{"function", std::string("strategy.") + std::string(name.substr(0, dot))},
55 {"argument", std::string(name.substr(dot + 1))},
56 {"rule", "unsupported_combination"}},
57 "strategy identifiers cannot contain NUL or unit separator");
58 }
59}
60
61void admit_level(double value, const char* field) {
62 // D1: a raw NaN is the absent level. Finite arithmetic is lane S3's.
63 if (std::isinf(value))
65}
66
67} // namespace
68
69void admit_strategy_entry(const std::string& id, bool,
70 double limit_price, double stop_price, double,
71 const std::string& comment, const std::string& oca_name,
72 int, int) {
73 admit_text(id, value_field::entry_id);
74 admit_level(limit_price, value_field::entry_limit_price);
75 admit_level(stop_price, value_field::entry_stop_price);
76 admit_comment(comment, value_field::entry_comment);
77 admit_text(oca_name, value_field::entry_oca_name);
78 // Entry qty NaN and both infinities keep the documented default.
79}
80
81void admit_strategy_close(const std::string& id, const std::string& comment,
82 double, double, bool) {
83 admit_text(id, value_field::close_id);
84 admit_comment(comment, value_field::close_comment);
85}
86
87void admit_strategy_close_token(const std::string& id, const std::string& comment,
88 double qty, double qty_percent, bool immediately,
89 std::uint64_t) {
90 admit_strategy_close(id, comment, qty, qty_percent, immediately);
91}
92
93void admit_strategy_close_all() noexcept {}
94
95void admit_strategy_exit(const std::string& id, const std::string& from_entry,
96 double limit_price, double,
97 double, double trail_offset, double trail_price,
98 double, const std::string& comment, double,
99 const std::string& oca_name, double profit_ticks, double loss_ticks) {
100 admit_text(id, value_field::exit_id);
101 admit_text(from_entry, value_field::exit_from_entry);
102 admit_level(limit_price, value_field::exit_limit_price);
103 // Rule 4: test_fills_edge and its l4d twin pin infinity as actionable for
104 // stop_price and trail_points. Those arguments remain unadmitted.
105 admit_level(trail_offset, value_field::exit_trail_offset);
106 admit_level(trail_price, value_field::exit_trail_price);
107 admit_comment(comment, value_field::exit_comment);
108 admit_text(oca_name, value_field::exit_oca_name);
109 admit_level(profit_ticks, value_field::exit_profit_ticks);
110 admit_level(loss_ticks, value_field::exit_loss_ticks);
111 // Exit qty/qty_percent retain their non-explicit/default semantics.
112}
113
114void admit_strategy_exit_cancel_bracket(const std::string& exit_id,
115 const std::string& from_entry,
116 const std::string& comment) {
117 admit_text(exit_id, value_field::exit_cancel_bracket_exit_id);
118 admit_text(from_entry, value_field::exit_cancel_bracket_from_entry);
119 admit_comment(comment, value_field::exit_cancel_bracket_comment);
120}
121
122void admit_strategy_cancel(const std::string& id) {
123 admit_text(id, value_field::cancel_id);
124}
125
127
128void admit_strategy_order(const std::string& id, bool, double,
129 double limit_price, double stop_price,
130 const std::string& oca_name, int) {
131 admit_text(id, value_field::order_id);
132 admit_level(limit_price, value_field::order_limit_price);
133 admit_level(stop_price, value_field::order_stop_price);
134 admit_text(oca_name, value_field::order_oca_name);
135 // The CANCEL path retains non-finite qty for default host sizing and its
136 // full-fill sibling cancellation predicate. Ordinary qty NaN is default.
137}
138
139} // namespace pineforge::source
constexpr const char * exit_limit_price
constexpr const char * order_limit_price
constexpr const char * exit_cancel_bracket_exit_id
constexpr const char * order_stop_price
constexpr const char * exit_cancel_bracket_comment
constexpr const char * entry_stop_price
constexpr const char * exit_trail_price
constexpr const char * exit_trail_offset
constexpr const char * exit_profit_ticks
constexpr const char * entry_limit_price
constexpr const char * exit_cancel_bracket_from_entry
void admit_strategy_exit(const std::string &id, const std::string &from_entry, double limit_price, double, double, double trail_offset, double trail_price, double, const std::string &comment, double, const std::string &oca_name, double profit_ticks, double loss_ticks)
void admit_strategy_close_token(const std::string &id, const std::string &comment, double qty, double qty_percent, bool immediately, std::uint64_t)
void throw_strategy_value_invalid(const char *field, StrategyValueReason reason)
The coded failure of a source-owned invalid actionable value.
void admit_strategy_cancel(const std::string &id)
void admit_strategy_close_all() noexcept
void admit_strategy_entry(const std::string &id, bool, double limit_price, double stop_price, double, const std::string &comment, const std::string &oca_name, int, int)
void admit_strategy_exit_cancel_bracket(const std::string &exit_id, const std::string &from_entry, const std::string &comment)
void admit_strategy_close(const std::string &id, const std::string &comment, double, double, bool)
void admit_strategy_cancel_all() noexcept
void admit_strategy_order(const std::string &id, bool, double, double limit_price, double stop_price, const std::string &oca_name, int)
std::vector< RunFailureArg > RunFailureArgs