PineForge unreleased
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
pine_strategy_commands.cpp
Go to the documentation of this file.
2
5
6#include <limits>
7
8namespace pineforge::source {
9
10namespace {
11
12// The validator deliberately warms Pine state before the first reportable
13// trade. The legacy source command path ignored commands during that span,
14// while still evaluating the script, and retained one script interval for a
15// stop/limit placed on the preceding source bar. Keeping this at the source
16// command boundary preserves both the warmup semantics and the legacy
17// PendingOrder-incarnation provenance exported with closed trades.
18bool trading_window_active(std::int64_t current_ms, std::int64_t start_ms,
19 int script_tf_seconds) noexcept {
20 if (start_ms == std::numeric_limits<std::int64_t>::min()) return true;
21 const std::int64_t buffer_ms = script_tf_seconds > 0
22 ? static_cast<std::int64_t>(script_tf_seconds) * 1000 : 0;
23 return current_ms >= start_ms - buffer_ms;
24}
25
26} // namespace
27
28void PineStrategyHost::strategy_entry(const std::string& id, bool is_long,
29 double limit_price, double stop_price, double qty,
30 const std::string& comment,
31 const std::string& oca_name, int oca_type,
32 int qty_type) {
33 // A selected window's pre-roll call is kept for the replay, ahead of the
34 // trading-window gate and the adapter (pine_intent_state.hpp); every door
35 // opens this way, the unguarded ones included.
36 if (detail::capture_pre_roll_command(*this, current_bar_.timestamp, config_, [&] {
37 return detail::IntentEntry{id, is_long, limit_price, stop_price, qty, comment,
38 oca_name, oca_type, qty_type};
39 })) {
40 return;
41 }
42 if (!trading_window_active(current_bar_.timestamp, trade_start_time_, script_tf_seconds_))
43 return;
44 adapter_.set_configuration(config_);
45 admit_strategy_entry(id, is_long, limit_price, stop_price, qty, comment, oca_name,
46 oca_type, qty_type);
47 adapter_.entry(id, is_long, limit_price, stop_price, qty, comment, oca_name,
48 oca_type, qty_type);
49}
50
51void PineStrategyHost::strategy_close(const std::string& id, const std::string& comment,
52 double qty, double qty_percent, bool immediately) {
53 if (detail::capture_pre_roll_command(*this, current_bar_.timestamp, config_, [&] {
54 return detail::IntentClose{id, comment, qty, qty_percent, immediately};
55 })) {
56 return;
57 }
58 adapter_.set_configuration(config_);
59 admit_strategy_close(id, comment, qty, qty_percent, immediately);
60 adapter_.close(id, comment, qty, qty_percent, immediately);
61}
62
63void PineStrategyHost::strategy_close(const std::string& id, const std::string& comment,
64 double qty, double qty_percent, bool immediately,
65 std::uint64_t callsite_token) {
66 if (detail::capture_pre_roll_command(*this, current_bar_.timestamp, config_, [&] {
67 return detail::IntentCloseToken{id, comment, qty, qty_percent, immediately,
68 callsite_token};
69 })) {
70 return;
71 }
72 if (!trading_window_active(current_bar_.timestamp, trade_start_time_, script_tf_seconds_))
73 return;
74 adapter_.set_configuration(config_);
75 admit_strategy_close_token(id, comment, qty, qty_percent, immediately, callsite_token);
76 adapter_.close(id, comment, qty, qty_percent, immediately, callsite_token);
77}
78
80 if (detail::capture_pre_roll_command(*this, current_bar_.timestamp, config_, [] {
81 return detail::IntentCloseAll{};
82 })) {
83 return;
84 }
85 if (!trading_window_active(current_bar_.timestamp, trade_start_time_, script_tf_seconds_))
86 return;
87 adapter_.set_configuration(config_);
89 adapter_.close_all();
90}
91
92void PineStrategyHost::strategy_exit(const std::string& id, const std::string& from_entry,
93 double limit_price, double stop_price,
94 double trail_points, double trail_offset,
95 double trail_price, double qty_percent,
96 const std::string& comment, double qty,
97 const std::string& oca_name,
98 double profit_ticks, double loss_ticks) {
99 if (detail::capture_pre_roll_command(*this, current_bar_.timestamp, config_, [&] {
100 return detail::IntentExit{id, from_entry, limit_price, stop_price, trail_points,
101 trail_offset, trail_price, qty_percent, comment, qty,
102 oca_name, profit_ticks, loss_ticks};
103 })) {
104 return;
105 }
106 if (!trading_window_active(current_bar_.timestamp, trade_start_time_, script_tf_seconds_))
107 return;
108 adapter_.set_configuration(config_);
109 admit_strategy_exit(id, from_entry, limit_price, stop_price, trail_points, trail_offset,
110 trail_price, qty_percent, comment, qty, oca_name, profit_ticks,
111 loss_ticks);
112 adapter_.exit(id, from_entry, limit_price, stop_price, trail_points, trail_offset,
113 trail_price, qty_percent, comment, qty, oca_name, profit_ticks,
114 loss_ticks);
115}
116
118 const std::string& from_entry,
119 const std::string& comment) {
120 if (detail::capture_pre_roll_command(*this, current_bar_.timestamp, config_, [&] {
121 return detail::IntentExitCancelBracket{exit_id, from_entry, comment};
122 })) {
123 return;
124 }
125 if (!trading_window_active(current_bar_.timestamp, trade_start_time_, script_tf_seconds_))
126 return;
127 adapter_.set_configuration(config_);
128 admit_strategy_exit_cancel_bracket(exit_id, from_entry, comment);
129 adapter_.exit_cancel_bracket(exit_id, from_entry, comment);
130}
131
132void PineStrategyHost::strategy_cancel(const std::string& id) {
133 if (detail::capture_pre_roll_command(*this, current_bar_.timestamp, config_, [&] {
134 return detail::IntentCancel{id};
135 })) {
136 return;
137 }
138 adapter_.set_configuration(config_);
140 adapter_.cancel(id);
141}
142
144 if (detail::capture_pre_roll_command(*this, current_bar_.timestamp, config_, [] {
145 return detail::IntentCancelAll{};
146 })) {
147 return;
148 }
149 adapter_.set_configuration(config_);
151 adapter_.cancel_all();
152}
153
154void PineStrategyHost::strategy_order(const std::string& id, bool is_long, double qty,
155 double limit_price, double stop_price,
156 const std::string& oca_name, int oca_type) {
157 if (detail::capture_pre_roll_command(*this, current_bar_.timestamp, config_, [&] {
158 return detail::IntentOrder{id, is_long, qty, limit_price, stop_price, oca_name,
159 oca_type};
160 })) {
161 return;
162 }
163 if (!trading_window_active(current_bar_.timestamp, trade_start_time_, script_tf_seconds_))
164 return;
165 adapter_.set_configuration(config_);
166 admit_strategy_order(id, is_long, qty, limit_price, stop_price, oca_name, oca_type);
167 adapter_.order(id, is_long, qty, limit_price, stop_price, oca_name, oca_type);
168}
169
170} // namespace pineforge::source
void strategy_entry(const std::string &id, bool is_long, double limit_price=std::numeric_limits< double >::quiet_NaN(), double stop_price=std::numeric_limits< double >::quiet_NaN(), double qty=std::numeric_limits< double >::quiet_NaN(), const std::string &comment={}, const std::string &oca_name={}, int oca_type=0, int qty_type=-1)
void strategy_order(const std::string &id, bool is_long, double qty, double limit_price=std::numeric_limits< double >::quiet_NaN(), double stop_price=std::numeric_limits< double >::quiet_NaN(), const std::string &oca_name={}, int oca_type=0)
void strategy_exit_cancel_bracket(const std::string &exit_id, const std::string &from_entry, const std::string &comment={})
void strategy_exit(const std::string &id, const std::string &from_entry, double limit_price, double stop_price, double trail_points=std::numeric_limits< double >::quiet_NaN(), double trail_offset=std::numeric_limits< double >::quiet_NaN(), double trail_price=std::numeric_limits< double >::quiet_NaN(), double qty_percent=100.0, const std::string &comment={}, double qty=std::numeric_limits< double >::quiet_NaN(), const std::string &oca_name={}, double profit_ticks=std::numeric_limits< double >::quiet_NaN(), double loss_ticks=std::numeric_limits< double >::quiet_NaN())
void strategy_close(const std::string &id, const std::string &comment={}, double qty=std::numeric_limits< double >::quiet_NaN(), double qty_percent=std::numeric_limits< double >::quiet_NaN(), bool immediately=false)
bool capture_pre_roll_command(const NativeStrategyHost &host, std::int64_t label_ms, const PineStrategyConfig &config, MakePayload &&make_payload)
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 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)