Функции и аннотации – Robo.trading

Функции и аннотации

Pine Script различает функции и функции аннотаций (или просто аннотации ). Синтаксически они похожи, но служат разным целям.

В то время как функции обычно используются для вычисления значений и результата, который они возвращают, аннотации в основном используются для их побочных эффектов и лишь изредка для результата, который некоторые из них возвращают.

Функции могут быть встроенными, такими как sma(), ema(), rsi() или определяемые пользователем. Все аннотации встроены.

Побочные эффекты аннотаций используются для:

  • присвоение имени или других глобальных свойств скрипту с использованием индикатора или стратегии
  • определение входных данных скрипта с использованием ввода
  • определение выходных данных скрипта с использованием графика

Помимо побочных эффектов, несколько аннотаций, таких как plot и hline, также возвращают результат, который может быть использован или нет. Этот результат, однако, может быть использован только в других аннотациях и не может участвовать в вычислениях скрипта.

Синтаксически пользовательские функции, встроенные функции и функции аннотации похожи, т.е. мы называем их по имени со списком аргументов в круглых скобках. Различия между ними в основном семантические, за исключением того, что аннотации и встроенные функции принимают аргументы по ключевым словам, а пользовательские — нет.

Пример вызова аннотации с позиционными аргументами:
study('Example', 'Ex', true)

Тот же вызов с ключевыми словами:

study(title='Example', shorttitle='Ex', overlay=true)

Можно смешивать позиционные и именные аргументы. Позиционные аргументы должны идти первыми, а именные аргументы должны следовать за ними. Поэтому следующий вызов недействителен:

study(precision=3, 'Example') // Compilation error!

Выполнение функций Pine и исторический контекст внутри функциональных блоков

История переменных серии, используемых внутри функций Pine, создается при каждом последующем вызове функции. Если функция не вызывается на каждом баре, на котором работает скрипт, это приводит к расхождениям между историческими значениями серии внутри и вне локального блока функции. Следовательно, серии, на которые ссылаются внутри и снаружи функции, используя одно и то же значение индекса, не будут ссылаться на одну и ту же точку в истории, если функция не вызывается на каждом баре.

Рассмотрим пример, в котором функции f и f2 вызываются на каждом втором баре:
//@version=4
study("My Script", overlay=true)
// Returns the value of "a" the last time the function was called 2 bars ago.
f(a) => a[1]
// Returns the value of last bar's "close", as expected.
f2() => close[1]
oneBarInTwo = bar_index % 2 == 0
plot(oneBarInTwo ? f(close) : na, color=color.red, linewidth=6, style=plot.style_cross)
plot(oneBarInTwo ? f2() : na, color=color.lime, linewidth=6, style=plot.style_circles)
plot(close[2], color=color.red)
plot(close[1], color=color.lime)

 

Как видно из результатов на графике, a[1] возвращает предыдущее значение в контексте функции, поэтому последний раз f вызывался два бара назад — а не на закрытие предыдущего бара, как это делает close[1] в f2. В результате a[1] в блоке функции ссылается на другое прошлое значение, нежели close[1], несмотря на то, что в них используется один и тот же индекс 1.

Почему так происходит? Такое поведение необходимо, потому что принудительное выполнение функций на каждом баре приведет к неожиданным результатам, как это было бы в случае вызова функции label.new внутри ветки if, которая не должна выполняться, если только условие if не требует этого.

С другой стороны, такое поведение приводит к неожиданным результатам при наличии определенных встроенных функций, требующих выполнения каждого бара для правильного вычисления их результатов. Такие функции не будут возвращать ожидаемые результаты, если их поместить в контекст, где они выполняются не на каждом баре, а, например, в if-ветвях.

Решение в подобных случаях заключается в том, чтобы вывести эти вызовы функций за пределы их контекста, чтобы они могли быть выполнены на каждом баре.

В данном скрипте barssince не вызывается на каждом баре, так как он находится внутри условной ветви тернарного оператора:

//@version=4
study("Barssince",overlay=false)
res = close>close[1] ? barssince(close<close[1]) : -1
plot(res, style=plot.style_histogram, color=res >= 0 ? color.red : color.blue)

Это приводит к неверным результатам, потому что barssince не выполняется на каждом баре:

 

Решение состоит в том, чтобы перевести вызов barssince за пределы условной ветви, чтобы принудительно выполнить его на каждом баре:

//@version=4
study("Barssince",overlay=false)
b = barssince(close<close[1])
res = close>close[1] ? b : -1
plot(res, style=plot.style_histogram, color=res >= 0 ? color.red : color.blue)

Используя такую технику, мы получаем ожидаемый результат:

Исключения:

Не все встроенные функции должны выполняться на каждом баре. Это такие функции, которые не требуют этого, и поэтому не нуждаются в специальной обработке:

  • abs, acos, asin, atan, ceil, cos, dayofmonth, dayofweek, exp, floor, heikinashi, hour, kagi,
  • linebreak, log, log10, max, min, minute, month, na, nz, pow, renko, round, second, sign, sin,
  • sqrt, tan, tickerid, time, timestamp, tostring, weekofyear, year

Примечание

Функции, вызываемые из for цикла, используют один и тот же контекст в каждой итерации цикла. В приведенном ниже примере каждый lowest вызов на одном и том же баре использует переданное ему значение (т.е. bar_index), поэтому вызовы функций, используемых в циклах, не требуют специальной обработки.

//@version=4
study("My Script")
va = 0.0
for i = 1 to 2 by 1
if (i + bar_index) % 2 == 0
va := lowest(bar_index, 10) // same context on each call
plot(va)
/

Robo.Trading

eVe Developer
Мы используем cookie-файлы для наилучшего представления нашего сайта. Продолжая использовать этот сайт, вы соглашаетесь с использованием cookie-файлов.
Принять