26std::string bar_prefix() {
28 if (!ctx.installed)
return std::string();
29 return "Error on bar " + std::to_string(ctx.bar_index) +
": ";
32[[noreturn]]
void length_not_positive(
long long value,
const char* function,
33 const char* argument) {
34 throw coded<std::runtime_error>(
36 {{
"function", function}, {
"argument", argument}, {
"rule",
"must_be_positive"}},
37 bar_prefix() +
"Invalid value of the '" + argument +
38 "' argument (" + std::to_string(value) +
") in the '" +
39 function +
"' function. It must be > 0.");
42[[noreturn]]
void length_na(
const char* function,
const char* argument) {
43 throw coded<std::runtime_error>(
45 {{
"function", function}, {
"argument", argument}, {
"rule",
"must_not_be_na"}},
46 bar_prefix() +
"Invalid value of the '" + argument +
47 "' argument in the '" + function +
48 "' function. It must not be na");
53bool length_value(
double value,
long long& out) {
54 if (
is_na(value))
return false;
55 const double t = std::trunc(value);
56 if (t > 1e15) out =
static_cast<long long>(1e15);
57 else if (t < -1e15) out =
static_cast<long long>(-1e15);
58 else out =
static_cast<long long>(
t);
62[[noreturn]]
void factor_not_positive(
double factor) {
64 if (factor == std::trunc(factor) && std::fabs(factor) < 1e15) {
65 std::snprintf(text,
sizeof text,
"%lld",
static_cast<long long>(factor));
67 std::snprintf(text,
sizeof text,
"%.15g", factor);
69 throw coded<std::runtime_error>(
71 {{
"function",
"supertrend"}, {
"argument",
"factor"}, {
"rule",
"must_be_positive"}},
72 bar_prefix() +
"Invalid value of the 'factor' argument (" +
text +
73 ") in the 'supertrend' function. It must be > 0.");
82 if (!length_value(value, length)) length_na(function, argument);
83 if (length <= 0) length_not_positive(length, function, argument);
84 return length > INT_MAX ? INT_MAX :
static_cast<int>(length);
88 if (
is_na(value)) length_na(function, argument);
89 if (value <= 0) length_not_positive(value, function, argument);
94 if (
is_na(value)) length_na(function, argument);
95 if (value <= 0) length_not_positive(value, function, argument);
96 return value > INT_MAX ? INT_MAX :
static_cast<int>(value);
101void HeldHistory::push(
double value) {
102 if (tail_.size() ==
kChunk) {
103 frozen_.push_back(std::make_shared<
const std::vector<double>>(std::move(tail_)));
104 tail_ = std::vector<double>();
106 if (tail_.capacity() == 0) tail_.reserve(
kChunk);
107 tail_.push_back(value);
111void HeldHistory::drop_front_chunks(std::size_t keep) {
112 std::size_t drop = 0;
113 while (drop < frozen_.size() &&
114 count_ -
static_cast<long long>(
kChunk) >=
static_cast<long long>(keep)) {
115 count_ -=
static_cast<long long>(
kChunk);
116 first_bar_ +=
static_cast<long long>(
kChunk);
119 if (drop) frozen_.erase(frozen_.begin(), frozen_.begin() +
static_cast<long>(drop));
129 if (bar < last)
return;
131 tail_.back() = value;
136 const double held = tail_.back();
137 long long gap = bar - last - 1;
138 if (gap >=
static_cast<long long>(keep)) {
140 tail_ = std::vector<double>();
142 first_bar_ = bar -
static_cast<long long>(keep);
143 gap =
static_cast<long long>(keep);
145 for (
long long i = 0; i < gap; ++i) push(held);
147 drop_front_chunks(keep);
151 const long long i = bar - first_bar_;
152 const std::size_t chunk =
static_cast<std::size_t
>(i) /
kChunk;
153 const std::size_t offset =
static_cast<std::size_t
>(i) %
kChunk;
154 if (chunk < frozen_.size())
return (*frozen_[chunk])[offset];
155 return tail_[offset];
161 bool advance,
bool want_max,
162 const char* function) {
172 if (advance || !has_bar_) ++own_bar_;
177 if (length <= 0) length_not_positive(length, function,
"length");
183 "The script attempts to reference historical data that is too far from "
184 "the current bar (" + std::to_string(length - 1) +
185 " bars back). The historical buffer's limit is " +
190 if (!has_bar_ || bar != current_bar_) {
191 saved_state_ = state_;
195 state_ = saved_state_;
197 BarState& s = state_;
198 if (!s.started) first_exec_bar_ = bar;
199 history_.write(bar, src,
static_cast<std::size_t
>(
kMaxBarsBack) + 1);
201 const auto better = [want_max](
double a,
double b) {
return want_max ? a > b : a < b; };
204 const auto member = [&](
long long at,
double& value) ->
int {
205 if (at < origin)
return -1;
206 if (at < first_exec_bar_ || at < history_.first_bar())
return 0;
207 value = history_.at(at);
208 return is_na(value) ? 0 : 1;
211 const auto walk = [&](
long long from_k,
long long to_k, Cache& running) {
212 for (
long long k = from_k; k >= to_k; --k) {
214 const int kind = member(bar - k, v);
215 if (kind < 0)
continue;
217 running.valid =
false;
220 if (!running.valid || better(v, running.value)) {
221 running.valid =
true;
223 running.bar = bar - k;
227 const auto rescan = [&]() {
229 walk(length - 1, 0, fresh);
234 bool na_source =
false;
236 s.cache.valid =
false;
239 }
else if (!s.started) {
242 }
else if (length > s.prev_length) {
243 if (first_exec_bar_ > origin && length > s.max_length) s.cache.valid =
false;
244 if (!s.cache.valid || bar - s.cache.bar < length) {
245 walk(length - 1, s.prev_length, s.cache);
247 if (!s.cache.valid) {
251 }
else if (better(src, s.cache.value)) {
254 }
else if (bar - s.cache.bar >= length) {
258 if (!s.cache.valid) {
260 }
else if (better(src, s.cache.value)) {
263 }
else if (bar - s.cache.bar >= length) {
267 s.prev_length = length;
268 s.max_length = std::max(s.max_length, length);
271 const Cache& result = answer.valid ? answer : s.cache;
273 return Result{result.value, -
static_cast<double>(bar - result.bar)};
278long long series_length(
double length,
const char* function) {
281 if (!length_value(length, value)) length_not_positive(0, function,
"length");
288 return core_.update(src, series_length(length,
"highest"),
true,
true,
"highest").value;
291 return core_.update(src, series_length(length,
"highest"),
false,
true,
"highest").value;
294 return core_.update(src, series_length(length,
"lowest"),
true,
false,
"lowest").value;
297 return core_.update(src, series_length(length,
"lowest"),
false,
false,
"lowest").value;
300 return core_.update(src, series_length(length,
"highestbars"),
true,
true,
"highestbars")
304 return core_.update(src, series_length(length,
"highestbars"),
false,
true,
"highestbars")
308 return core_.update(src, series_length(length,
"lowestbars"),
true,
false,
"lowestbars")
312 return core_.update(src, series_length(length,
"lowestbars"),
false,
false,
"lowestbars")
320 if (again) atr_->recompute(high, low, close);
321 else atr_->compute(high, low, close);
324 const double atr = again ? atr_->recompute(high, low, close) : atr_->compute(high, low, close);
325 const double src = (high + low) / 2.0;
326 double upper = src + factor_ * atr;
327 double lower = src - factor_ * atr;
328 const double prev_lower =
is_na(state_.prev_lower) ? 0.0 : state_.prev_lower;
329 const double prev_upper =
is_na(state_.prev_upper) ? 0.0 : state_.prev_upper;
330 const double close1 = state_.prev_close;
332 lower = (lower > prev_lower || close1 < prev_lower) ? lower : prev_lower;
333 upper = (upper < prev_upper || close1 > prev_upper) ? upper : prev_upper;
335 if (
is_na(state_.prev_atr)) {
337 }
else if (state_.prev_st == prev_upper) {
338 direction = close > upper ? -1.0 : 1.0;
340 direction = close < lower ? 1.0 : -1.0;
342 const double line = direction == -1.0 ? lower : upper;
343 state_.prev_upper = upper;
344 state_.prev_lower = lower;
345 state_.prev_st = line;
346 state_.prev_atr = atr;
347 state_.prev_close = close;
348 return ta::SupertrendResult{line, direction};
352 double low,
double close) {
359 if (!
is_na(factor) && factor <= 0.0) factor_not_positive(factor);
363 saved_state_ = state_;
364 return step(high, low, close,
false);
368 double low,
double close) {
369 if (!latched_)
return compute(factor, atr_period, high, low, close);
370 state_ = saved_state_;
371 return step(high, low, close,
true);
Base with a code: throw coded<std::invalid_argument>(code, {args}, text).
long long last_bar() const
double at(long long bar) const
void write(long long bar, double value, std::size_t keep)
static constexpr std::size_t kChunk
ta::SupertrendResult recompute(double factor, double atr_period, double high, double low, double close)
ta::SupertrendResult compute(double factor, double atr_period, double high, double low, double close)
double recompute(double src, double length)
double compute(double src, double length)
double compute(double src, double length)
double recompute(double src, double length)
double recompute(double src, double length)
double compute(double src, double length)
double compute(double src, double length)
double recompute(double src, double length)
Result update(double src, long long length, bool advance, bool want_max, const char *function)
static constexpr long long kMaxBarsBack
int simple_ta_length(double value, const char *function, const char *argument)
BarContext & bar_context()
bool is_na(const Line &h)