Вводный курс по языку PINE Inventor Quantitative
В дополнение к видео:
Трудно ли внедрять квантовую торговлю? использовать trading view язык Pine от маленького белого до большого Quant - язык Pine для начинающих
Платформа квантовой торговли Inventor поддерживает стратегию написания языка Pine, поддерживает обратную связь, реализацию стратегий языка Pine, совместимость с более низкими версиями языка Pine.Стратегический квадратВ ней собраны и перенесены многие стратегии (скрипты) Pine.
FMZ не только поддерживает язык Pine, но и поддерживает мощную графическую функцию языка Pine. Различные функции на платформе FMZ, богатые практические инструменты, эффективное и удобное управление, а также дополнительно улучшают практичность стратегии и сценария Pine. FMZ основан на совместимости с языком Pine, а также на языке Pine производится определенная степень расширения, оптимизации и резки.
Вот краткий обзор некоторых наиболее заметных различий:
-
1., Политика Pine на FMZ, кодовое начало версии
//@versionНачинается с кодаstrategy、indicatorФМЗ пока не поддерживает введение фраз в качестве обязательного требования.importИмпортlibraryфункция.В некоторых из них можно увидеть тактику, которая выглядит так:
pine//@version=5 indicator("My Script", overlay = true) src = close a = ta.sma(src, 5) b = ta.sma(src, 50) c = ta.cross(a, b) plot(a, color = color.blue) plot(b, color = color.black) plotshape(c, color = color.red)Или вот как:
pine//@version=5 strategy("My Strategy", overlay=true) longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28)) if (longCondition) strategy.entry("My Long Entry Id", strategy.long) shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28)) if (shortCondition) strategy.entry("My Short Entry Id", strategy.short)На FMZ это можно сократить до:
pinesrc = close a = ta.sma(src, 5) b = ta.sma(src, 50) c = ta.cross(a, b) plot(a, color = color.blue, overlay=true) plot(b, color = color.black, overlay=true) plotshape(c, color = color.red, overlay=true)Или:
pinelongCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28)) if (longCondition) strategy.entry("My Long Entry Id", strategy.long) shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28)) if (shortCondition) strategy.entry("My Short Entry Id", strategy.short) -
2 , Политика (сценарий) Некоторые параметры, связанные с транзакциями, устанавливаются в интерфейсе стратегии FMZ параметром "Pine Language Transaction Class Library".
-
Модели закрытия и модели реального времени
В Trading View мы можем просматриватьstrategyФункцияcalc_on_every_tickПараметры, чтобы настроить стратегический скрипт, который будет выполнять логику стратегии в реальном времени при каждом изменении цены.calc_on_every_tickПараметры должны быть установлены наtrueПо умолчаниюcalc_on_every_tickПараметрыfalseЭто означает, что логика стратегии будет выполняться только тогда, когда текущая K-линия BAR будет полностью завершена.
На FMZ параметры настраиваются с помощью шаблона "Pine Language Transaction Class Repository". -
Контроль за точностью количественных значений, таких как цена при выполнении стратегии, количество заказов, требуется на FMZ
В trading view, поскольку можно только провести аналогичные тесты, нет проблем с точностью заказа на реальную торговлю. На FMZ можно запустить стратегию Pine в реальном режиме. Тогда требуется стратегия, которая может гибко определять ценовую точность торгового типа и точность количества заказов. Эти точности настраиваются, то есть контролируют небольшие цифры соответствующих данных, чтобы избежать того, что данные не соответствуют требованиям к отчетности биржи, что может привести к невозможности заказа. -
Код фьючерсного контракта
На FMZ торговые сорта имеют два свойства, если они являются контрактами: "торговые пары" и "контрактный код". В дополнение к необходимости четко установить торговые пары на диске и в ретроспективном режиме, также необходимо установить конкретный контрактный код в параметре "код сорта" в шаблоне "Pine Language Trading Library". Например, для постоянных контрактов необходимо заполнитьswap, код контракта зависит от того, есть ли у биржи такой контракт. Например, все квартальные контракты на некоторые сделки можно заполнить здесьquarter。 Эти коды контрактов совпадают с кодами контрактов на сроки, определенными в документации API языка Javascript/python/c++ FMZ.
Другие параметры, такие как минимальная загрузка и загрузка по умолчанию, приведены в документации на языке Pine."Классическая база знаний на языке Пайн"Введение в параметры.
-
-
3、
runtime.debug、runtime.log、runtime.errorФункция расширения FMZ, используемая для дебютирования。На платформе FMZ добавлены 3 функции для дебютирования.
-
runtime.debug: для печати информации о переменных на консоли, как правило, не используется. -
runtime.logФункция FMZ PINE: выводит содержимое журнала.pineruntime.log(1, 2, 3, close, high, ...),可以传多个参数。 -
runtime.error: при вызове, вызывает ошибку во время выполнения и сопровождается сообщением об ошибке, указанной в параметре "message".pineruntime.error(message)
-
-
- Расширенная часть функций
overlayпараметр
Функция рисования в языке Pine на FMZ
plot、plotshape、plotcharДобавлено.overlayПоддержка параметров, позволяющая настраивать рисунки на матрицу или подматрицу.overlayнастраиватьtrueРисунок на главной карте, настройка наfalseРисуйте на подкартинках. Это позволяет одновременно рисовать главные и подкартинки при выполнении стратегии Pine на FMZ. - Расширенная часть функций
-
5、
syminfo.mintickВстроенные переменныеsyminfo.mintickВстроенная переменная определяется как минимальное измерение текущей разновидности.Твердое предложение/БэктестингВ интерфейсе "Pine Language Transaction Class Library" шаблонный параметр "Pricing Currency Precision" позволяет контролировать это значение. Настройка "Pricing Currency Precision 2" означает, что цена в момент сделки точна до второго знака дроби, при этом минимальная единица изменения цены составляет 0.01.syminfo.mintickЗначение 0.01 ≠ 0.01 ≠ 0.01 -
6 Средние цены в FMZ PINE Script включают комиссионные
Например: цена заказа - 8000, продажа направлена, количество - 1 рука ((один, лист), средняя цена после сделки - не 8000, меньше 8000 ((в стоимость включена комиссионная плата)).
Основы языка Pine
Когда мы начинаем изучать основы языка Pine, мы, возможно, не знакомы с инструкциями и кодовым грамматикой некоторых примеров. Неважно, что мы не понимаем, мы можем сначала ознакомиться с концепцией, понять цель теста, или мы можем обратиться к документации языка Pine в FMZ, чтобы ознакомиться с инструкциями. Затем следуйте пошаговым шагам в руководстве, чтобы постепенно ознакомиться с различными грамматиками, инструкциями, функциями и встроенными переменными.
Исполнение модели
В начале изучения языка Pine очень важно понимать, что языковые стратегии языка Pine основаны на графике, который можно понять как серию вычислений и операций, выполняемых на графике в хронологическом порядке, начиная с самых ранних данных, уже загруженных на графике. Количество данных, первоначально загруженных на график, ограничено.bar_indexСсылается на индексную величину K-линии Bar при исполнении скрипта Pine.
pine
plot(bar_index, "bar_index")
plotФункции - это одна из тех функций, которые мы будем использовать в будущем.bar_index, линия называетсяbar_index。 можно увидеть, что в первом Bar значение строки, названной bar_index, равняется 0, а с увеличением Bar вправо увеличивается в последовательности 1。
В зависимости от настроек стратегии, модель стратегии выполняется по-разному.收盘价模型и实时价模型│ │ │ │ │ │ │ │ │ │ │ │
-
Модель цены закрытия
При выполнении кода стратегии, текущий K-линейный Бар полностью выполняет цикл, а когда K-линия закрывается, то есть K-линейный цикл закончен. В этот момент выполняется логика стратегии Pine, и вызванный торговый сигнал будет выполнен в начале следующего K-линейного Бар.
-
Модель цен в реальном времени
При выполнении кода стратегии, текущая K-линия Bar, независимо от того, закрыта она или нет, выполняет логику стратегии Pine каждый раз при изменении ситуации, и вызванный торговый сигнал выполняется немедленно.
Когда стратегия языка Pine выполняется слева направо на графике, K-линия Bar на графике делится на历史Barи实时BarОтвет:
-
Исторический бар
При запуске стратегии, настроенной на "реальную модель цены", все K-строки на графике, за исключением одной K-строки на правой стороне, будут представлены как
历史Bar◦ Стратегическая логика в каждой корень历史BarВыполните это только один раз.
При запуске стратегии, настроенной на модель закрытия цены, все bars на графике будут历史Bar◦ Стратегическая логика в каждой корень历史BarВыполните это только один раз.Расчеты на основе исторической панели:
Код стратегии выполняется один раз в закрытом состоянии Исторической панели, а затем он продолжает выполняться в следующей Исторической панели, пока все Исторические панели не будут выполнены один раз. -
Реальный Бар
Когда стратегия выполняется на крайнем правом конце K-линии Bar, эта Bar является реальной Bar. После того, как реальная Bar закрывается, эта Bar превращается в прошедшую реальную Bar (в историческую Bar).
Когда стратегия настроена на "реальную ценовую модель", она начинает выполняться с логикой стратегии для каждого изменения курса в реальном времени.
При запуске стратегии, настроенной на "закрывающую модель цены", на графике не отображается реальный Bar.По расчетам Bar в реальном времени:
Если стратегия настроена на график "Модель закрытия цены" и не отображает Bar в реальном времени, код стратегии будет выполнен только один раз при закрытии текущего Bar.
Если политика была установлена как "модель реального опциона", то расчеты на реальном барсе и историческом барсе были бы совершенно разными. Каждое изменение событий на реальном барсе выполнялось бы одним кодом политики. Например, встроенные переменные.high、low、closeВ историческом Бар определены, в реальном Бар эти значения могут меняться каждый раз, когда ситуация меняется. Поэтому данные, такие как показатели, рассчитанные на основе этих значений, также изменяются в реальном времени.closeЭто означает, что они должны быть всегда актуальными, чтобы соответствовать текущим ценам.highиlowВсегда представляет собой самые высокие и самые низкие значения, достигнутые с начала текущего реального бар. Эти встроенные переменные представляют собой конечные значения, достигнутые в момент последнего обновления реального бар.Механизм обратного отката при выполнении стратегии в режиме реального времени Bar (модель цены в режиме реального времени):
При выполнении Bar в реальном времени, каждый новый выпуск стратегии выполняет перезагрузку пользовательских определенных переменных, которые называются rewinds. Чтобы понять механизм rewinds, давайте рассмотрим пример, как тестировать код.Уведомление:
/*backtest ... .. . */Пакет содержит конфигурацию отслеживания, сохраненную в коде на платформе FMZ.
pine/*backtest start: 2022-06-03 09:00:00 end: 2022-06-08 15:00:00 period: 1m basePeriod: 1m exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}] */ var n = 0 if not barstate.ishistory runtime.log("n + 1之前, n:", n, " 当前bar_index:", bar_index) n := n + 1 runtime.log("n + 1之后, n:", n, " 当前bar_index:", bar_index) plot(n, title="n")Мы рассматриваем только сцены, выполненные в режиме реального времени в Bar, поэтому используем
not barstate.ishistoryОграничение выражения применяется только в режиме реального времени при агрегации n переменных в Bar и до и после выполнения агрегации.runtime.logФункция выводит информацию в журнале стратегий.plotВычерченная кривая n может быть показана, когда стратегия находится в истории Бар, n всегда было 0. Когда она выполняется в реальном времени Бар, запускается операция n + 1, и в реальном времени Бар выполняется каждый раз, когда выполняется стратегия. Из информации о журнале можно увидеть, что каждый раз, когда выполняется стратегия, код n перенастраивается на значение, которое было в конечном итоге представлено предыдущей стратегией Bar.Подводя итог:
1 , Код стратегии будет выполняться при каждом обновлении ситуации, когда стратегия начинает выполняться в реальном времени.
2. При выполнении в реальном времени Bar, переменная будет перевернута перед каждым исполнением кода политики.
3. При выполнении в реальном времени Bar, переменная представляется один раз при обновлении закрытия.Поскольку данные переворачиваются, то такие операции, как изображение кривых на графике, также могут вызывать перерисовку, например, мы изменили только что тестируемый код, тестирование на реальном диске:
pinevar n = 0 if not barstate.ishistory runtime.log("n + 1之前, n:", n, " 当前bar_index:", bar_index) n := open > close ? n + 1 : n runtime.log("n + 1之后, n:", n, " 当前bar_index:", bar_index) plot(n, title="n")Мы изменили только одно предложение:
n := open > close ? n + 1 : n, в настоящее время в реальном времени Bar является отрицательной ценой (то есть цена открытия выше, чем цена закрытия). можно увидеть, что в первом графике (в момент A), так как цена открытия была выше, чем цена закрытия (то есть отрицательная цена), поэтому n накопилось 1, графическая кривая n показала значение 5 . затем, как показано во втором графике (в момент B), изменилась ситуация, цена была обновлена. -
Контекст переменных в функции
Давайте вместе рассмотрим переменные в языковых функциях Pine. Согласно описаниям в некоторых учебниках Pine, переменные в функциях отличаются от переменных вне функций следующим образом:
История серийных переменных, используемых в функции Pine, создается при каждом последовательном вызове функции. Если функция не будет вызвана в каждом столбце, выполняемом в сценарии, это приведет к различию между историческими значениями внутри локального блока функции и внешних серий. Таким образом, если функция не будет вызвана в каждом столбце, то серии, использующие одинаковые индексированные значения, ссылающиеся внутри и снаружи функции, не будут ссылаться на одинаковые исторические точки.
Это не имеет значения, мы решили задать этот вопрос с помощью тестового кода, запущенного на FMZ:
pine/*backtest start: 2022-06-03 09:00:00 end: 2022-06-08 15:00:00 period: 1m basePeriod: 1m exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}] */ f(a) => a[1] f2() => close[1] oneBarInTwo = bar_index % 2 == 0 plotchar(oneBarInTwo ? f(close) : na, title = "f(close)", color = color.red, location = location.absolute, style = shape.xcross, overlay = true, char = "A") plotchar(oneBarInTwo ? f2() : na, title = "f2()", color = color.green, location = location.absolute, style = shape.circle, overlay = true, char = "B") plot(close[2], title = "close[2]", color = color.red, overlay = true) plot(close[1], title = "close[1]", color = color.green, overlay = true)Скриншот отслеживания
Тест-код довольно прост, и в основном используется для изучения данных, которые ссылаются на два способа:
f(a) => a[1]иf2() => close[1]。-
f(a) => a[1]Функция возвращается в конце:a[1]。 -
f2() => close[1]Использование встроенных переменных:closeФункция возвращается в конце .close[1]。
[]Символ, используемый для операций с историческими значениями переменных серии данных, close[1] это цитирование данных о цене закрытия на предыдущем барке от текущей цены закрытия. В нашем тестовом коде на графике изображены 4 вида данных:-
plotchar(oneBarInTwo ? f(close) : na, title = "f(close)", color = color.red, location = location.absolute, style = shape.xcross, overlay = true, char = "A")
Нарисуйте один символ A<unk>, цвет красный, только когда oneBarInTwo является истинным, и вычеркните его место (на оси Y) как:f(close)Вернутое значение: -
plotchar(oneBarInTwo ? f2() : na, title = "f2()", color = color.green, location = location.absolute, style = shape.circle, overlay = true, char = "B")
Нарисуйте символы B и B, цвет зеленый, только если oneBarInTwo является истинным, и вычеркните их место (на оси Y) как:f2()Вернутое значение: -
plot(close[2], title = "close[2]", color = color.red, overlay = true)
Линия, окрашенная в красный цвет, расположена на оси Y следующим образом:close[2]То есть закрытие цены на текущем Бар (на 2й корень впереди) (на 2й корень слева). -
plot(close[1], title = "close[1]", color = color.green, overlay = true)
Линия, окрашенная в зеленый цвет, расположена на оси Y следующим образом:close[1]То есть закрытие цены на текущем Бар на 1-м номере впереди ((1-м номере слева) Бар.
Скриншоты с помощью стратегии отслеживания запуска можно увидеть, хотя рисунок A маркирует функции, используемые
f(a) => a[1]Функции, используемые для обозначенияf2() => close[1]Использование[1] для ссылки на исторические данные по серии данных, но расположение знаков "A" и "B" на графике совершенно разное.plot(close[2], title = "close[2]", color = color.red, overlay = true)Нарисуйте линию, используя данные из этой линии.close[2]。Причина в том, что индексация через K-линию Bar, то есть встроенные переменные
bar_indexВычислить, будут ли нарисованы знаки "A" и "B". Знаки "A" и "B" не будут нарисованы на каждой K-линии.f(a) => a[1]Значение, которое будет цитироваться таким образом, будет связано с функцией, если функция не будет вызвана на каждом Bar.f2() => close[1]При этом используются различные значения ссылок (((, даже если[1] такой же индекс) <unk> -
-
Некоторые встроенные функции должны быть рассчитаны на каждом Bar, чтобы правильно рассчитать их результаты
Вот простой пример:
pineres = close > close[1] ? ta.barssince(close < close[1]) : -1 plot(res, style = plot.style_histogram, color=res >= 0 ? color.red : color.blue)Мы вызываем функцию в коде.
ta.barssince(close < close[1])Напишите в треугольном оператореcondition ? value1 : value2Это привело к тому, что только вclose > close[1]Функция ta.barssince.ta.barssinceФункция рассчитывается с последнегоclose < close[1]Количество строк K, созданных при вызове функции ta.barssince close > close[1], то есть текущая цена закрытия больше, чем цена закрытия предыдущего Bar, когда функция ta.barssince была вызвана, ее условие close < close[1] не было создано, и поэтому не было создано последнее место.ta.barssince: при вызове, функция возвращает na。, если условие никогда не было выполнено до текущей K-линии.
Как показано на рисунке:
Таким образом, когда мы рисуем график, мы рисуем только те данные, которые имеют значение переменной res ((-1) ∈ R).
Чтобы избежать этой проблемы, мы просто используем
ta.barssince(close < close[1])Функциональные вызовы берутся из треугольного оператора и записываются на любой возможный внешний условный ответвление. Это позволяет выполнять вычисления на каждом K-строке Bar.a = ta.barssince(close < close[1]) res = close > close[1] ? a : -1 plot(res, style = plot.style_histogram, color=res >= 0 ? color.red : color.blue)
Временная последовательность
Концепция временной последовательности очень важна в языке Пайн, и это концепция, которую мы должны понять, когда учимся языку Пайн. Временная последовательность не является типом, а основной структурой для хранения последовательных значений переменных во времени. Мы знаем, что сценарий Пайна основан на диаграммах.openЭто встроенная переменная в языке Pine, структура которой состоит в том, чтобы хранить временные последовательности для каждой K-линейной Bar.openЭта хронологическая структура представляет собой открытую цену всех K-линейных баров, когда текущая K-линейная карта начинается с первой Bar и заканчивается с Bar, выполненной в текущем сценарии. Если текущая K-линейная карта имеет 5-минутный цикл, то мы ссылаемся в коде стратегии Pine на ((или используем)openЭто цена открытия K-линии Bar при текущем исполнении кода стратегии.[]Оператор . . Используется, когда стратегия Pine выполняется на Bar линии Kopen[1]Указать ссылкуopenНачальная цена предыдущего K-линейного бара, выполненного текущим сценарием в временной последовательности ((то есть начальная цена предыдущего K-линейного цикла)).
-
Переменные в временной последовательности очень удобны для вычисления
Мы используем встроенную функцию.ta.cumПримеры:ta.cum Cumulative (total) sum of `source`. In other words it's a sum of all elements of `source`. ta.cum(source) → series float RETURNS Total sum series. ARGUMENTS source (series int/float) SEE ALSO math.sumТестовый код:
pinev1 = 1 v2 = ta.cum(v1) plot(v1, title="v1") plot(v2, title="v2") plot(bar_index+1, title="bar_index")Есть много аналогов
ta.cumТакие встроенные функции могут непосредственно обрабатывать данные по временным рядам, напримерta.cumЭто означает, что входящие переменные на каждой K-линии Bar должны быть суммированы, а затем мы используем график, чтобы понять.Процесс выполнения стратегии встроенной переменной bar_index
| - | - | - | - |
Стратегия работает на первой K-линии
Стратегия работает на второй K-линии.
Стратегия работает на третьем корне K-линии Bar ≠ 2 ≠ 1 ≠ 3 ≠
|...|...|...|...|
Стратегия работает на N+1 корневой K-линииВидно, что v1, v2 и даже bar_index являются структурами временной последовательности, и на каждом Bar имеются соответствующие данные. Этот тест-код не отличается от "модели реального времени" или "модели закрытия цен" только тем, что на графике отображается реальный Bar. Для измерения скорости мы используем "модель закрытия цен" для обратной проверки.
Мы можем вычислить, что v1 будет равен 1, потому что v1 будет равен 1 на каждом столбце.
ta.cum(v1)Функция выполняется на первой K-линии Bar, и, поскольку есть только первая Bar, вычисляется 1, присваивая значение переменной v2 ◦.
Когдаta.cum(v1)При выполнении на второй K-линии Bar, уже имеется 2 K-линии Bar ((первая соответствующая встроенная переменная bar_index = 0, вторая соответствующая встроенная переменная bar_index = 1), поэтому вычисление получает результат 2, присваивая значение переменной v2, и так далее. Фактически можно наблюдать, что v2 - это количество K-линий Bar в графике, поскольку индекс K-линийbar_indexЭто будет расти с нуля.bar_index + 1Это фактически количество K-линий. Вы также можете увидеть линии на диаграмме наблюдения.v2иbar_indexЭто действительно совпадениеТак же я могу использовать
ta.cumВстроенная функция вычисляет сумму цен на закрытие всех бар на текущем графике и может быть записана следующим образом:ta.cum(close), когда стратегия запускается в правую панель реального времениta.cum(close)Результатом является сумма цен на закрытие всех бар на графике (без работы в правую сторону, только прибавление к текущему бар).Переменные в временной последовательности также могут быть рассчитаны с помощью оператора, например, код:
ta.sma(high - low, 14)Встроенные переменныеhigh(K Line Bar максимальная цена) минусlow(K-Line Bar минимальные цены), последнее использованиеta.smaФункция искала среднее значение. -
Результаты вызова функции также оставляют следы значения в временной последовательности
v1 = ta.highest(high, 10)[1] v2 = ta.highest(high[1], 10) plot(v1, title="v1", overlay=true) plot(v2, title="v2", overlay=true)Этот тест-код работает во время обратного измерения, и можно наблюдать
v1иv2Значения, выделенные на графике, полностью совпадают. Результаты вычислений, вызванные функцией, оставляют следы значений в временной последовательности, например, кодta.highest(high, 10)[1]В том числеta.highest(high, 10)Результаты, полученные при вызове функции, также могут быть использованы[1] ссылаясь на исторические значения.ta.highest(high, 10)И вот что получилось.ta.highest(high[1], 10)Так что...ta.highest(high[1], 10)иta.highest(high, 10)[1]Совершенно равные цены.Проверка вывода информации с помощью другой функции рисунка:
a = ta.highest(close, 10)[1] b = ta.highest(close[1], 10) plotchar(true, title="a", char=str.tostring(a), location=location.abovebar, color=color.red, overlay=true) plotchar(true, title="b", char=str.tostring(b), location=location.belowbar, color=color.green, overlay=true)Можно увидеть, что значения переменных a и b в временной последовательности отображаются в верхней и нижней части соответствующих баров. В процессе обучения можно сохранить этот графический код, поскольку во время тестирования и экспериментов часто может потребоваться выход информации на графике для наблюдения.
Структура сценария
Общая структура
В начале урока мы рассказали о некоторых отличиях между использованием языка Pine в FMZ и в Trading View.indicator()、strategy()И, временно не поддерживаю.library()Конечно, для совместимости с более ранними версиями сценария Pine, при составлении стратегии входили такие вещи, как://@version=5,indicator(),strategy()Некоторые параметры политики также доступны вstrategy()Настройка передаточных параметров в функции.
<version>
<declaration_statement>
<code>
<version>Информация о контроле версий может быть пропущена.
Примечание
Язык Пайн//Как однострочные комментарии, FMZ расширяет комментарии, поскольку в языке Pine нет многострочных комментариев/**/Для многострочных комментариев.
Код
Сценарий, не содержащий комментарии или инструкции компилятора, является предложением, реализующим алгоритм сценария. Сценарий может быть одним из этих элементов.
- Заявление переменной
- Переоценка переменной
- Заявление функции
- Встроенные функции, пользовательские функции
if,for,whileилиswitchСтруктура и т.д.
Предложения можно составить разными способами.
- Некоторые предложения могут быть выражены в одной строке, например, большинство заявлений переменных, содержащих только одну строку для вызова функции или однострочные заявления функции. Другие, как структуры, всегда нуждаются в нескольких строках, поскольку они требуют локального блока.
- Глобальные высказывания в сценарии (то есть части, которые не относятся к локальным блокам) не могут быть использованы в качестве
空格или制表符(таб-клавиши) начинаются. Их первый символ также должен быть первым символом строки. Строки, начинающиеся с первой строки строки, по определению являются частью глобального масштаба сценария. - Структурные или многострочные функции всегда требуют
local block。 Локальный блок должен быть сжат в один значок или четыре пробела (в противном случае он будет расшифрован как последовательность кода предыдущей строки, то есть будет рассматриваться как последовательность кода предыдущей строки), и каждый локальный блок определяет другой локальный диапазон。 - Несколько одиночных предложений могут быть соединены в один ряд, используя запятую ((,) в качестве разделительного знака.
- В одной строке может быть комментарий, а может быть только комментарий.
- Строки также могут быть завершены (продолжение в нескольких строках).
Например, включает в себя три локальных блока, один в заявлениях с функциями на заказ, два в заявлениях с переменными с использованием if-структуры, следующим образом:
pine
indicator("", "", true) // 声明语句(全局范围),可以省略不写
barIsUp() => // 函数声明(全局范围)
close > open // 本地块(本地范围)
plotColor = if barIsUp() // 变量声明 (全局范围)
color.green // 本地块 (本地范围)
else
color.red // 本地块 (本地范围)
runtime.log("color", color = plotColor) // 调用一个内置函数输出日志 (全局范围)
Код смены
Длинные строки могут быть разделены на несколько строк, или "упакованы". Упакованные строки должны быть сжаты в любое количество пробелов, если только они не являются кратными числами 4 (эти границы используются для сжатия локальных блоков).
pine
a = open + high + low + close
может быть упакован в (заметьте, что количество пробелов в каждой строке не является кратным количеству 4):
pine
a = open +
high +
low +
close
Длинный вызов plot ((() может быть упакован в。
pine
close1 = request.security(syminfo.tickerid, "D", close) // syminfo.tickerid 当前交易对的日线级别收盘价数据系列
close2 = request.security(syminfo.tickerid, "240", close) // syminfo.tickerid 当前交易对的240分钟级别收盘价数据系列
plot(ta.correlation(close, open, 100), // 一行长的plot()调用可以被包装
color = color.new(color.purple, 40),
style = plot.style_area,
trackprice = true)
Однако, поскольку локальный блок грамматически должен начинаться со сжатия (((4 пробела или 1 значок), при разделе его на следующую строку, продолжение части предложения должно начинаться с более чем одного сжатия (((не равняется кратному количеству 4 пробелов)). Например:
pine
test(c, o) =>
ret = c > o ?
(c > o+5000 ?
1 :
0):
(c < o-5000 ?
-1 :
0)
a = test(close, open)
plot(a, title="a")
Идентификаторы и операторы
Идентификатор
Прежде чем понять переменную, мы должны сначала понять понятие колонки идентификатора колонки.функцияиПеременныеНазвание {используется для обозначения переменных, функций) }}.функцияВ следующих уроках мы узнаем, что сначала мы должны выучить кодовый знак <unk>.
-
- Идентификатор должен быть заглавным
(A-Z)Или маленьким шрифтом.(a-z)Буквы или подчеркивание(_)Начало, как первый символ идентификатора.
- Идентификатор должен быть заглавным
- 2, следующий за первым символом идентификатора может бытьБуквы、ПодчеркнутьилиЦифры。
-
- Имена обозначений написаны в больших и малых буквах для разграничения.
Например, следующие обозначения:
pine
fmzVar
_fmzVar
fmz666Var
funcName
MAX_LEN
max_len
maxLen
3barsDown // 错误的命名!使用了数字字符作为标识符的开头字符
Как и в большинстве языков программирования, в языке Pine есть рекомендации по написанию. Обычно рекомендуется при наименовании идентификатора:
- 1, все буквы заглавными используются для обозначения констант.
-
- ИспользованиеПравило о верховьяхНаименование для других идентификаторов.
pine
// 命名变量、常量
GREEN_COLOR = #4CAF50
MAX_LOOKBACK = 100
int fastLength = 7
// 命名函数
zeroOne(boolValue) => boolValue ? 1 : 0
Оператор
Операторы - это операционные символы в языке программирования, которые используются для построения выражений, а выражения - это правила вычислений, разработанные для определенных целей при написании стратегий. Операторы в языке Pine подразделяются по функциям:
Операторы присвоения, операторы вычислений, операторы сравнения, логические операторы,? : Трехмерные операторы[]Оператор исторической ссылки <unk>
Оператор счисления*Например, в отличие от типа вопросов, вызванных возвратом результатов оператора языка Pine в Trading View, существует следующий тест-код:
pine
//@version=5
indicator("")
lenInput = input.int(14, "Length")
factor = year > 2020 ? 3 : 1
adjustedLength = lenInput * factor
ma = ta.ema(close, adjustedLength) // Compilation error!
plot(ma)
При выполнении этого сценария в Trading View будет создаваться ошибка компиляции, потому что:adjustedLength = lenInput * factorПосле умножения получаемseries intТип (серия), однакоta.emaВторой параметр функции не поддерживает этот тип. Однако на FMZ нет таких строгих ограничений, и вышеуказанный код может работать нормально.
Давайте рассмотрим, как используются различные операторы.
Оператор присвоения
Существует два типа операторов присвоения:=、:=Мы видели это в некоторых примерах в начале урока.
=Оператор для присвоения значения переменной при инициализации или декларировании.=Инициализация, заявление, присвоение значения после переменной начинается с этого значения на каждом последующем Bar. Все это являются действительными заявлениями:
a = close // 使用内置变量赋值给a
b = 10000 // 使用数值赋值
c = "test" // 使用字符串赋值
d = color.green // 使用颜色值赋值
plot(a, title="a")
plot(b, title="b")
plotchar(true, title="c", char=str.tostring(c), color=d, overlay=true)
Уведомлениеa = closeПрисвоенное выражение, где переменная a на каждом Bar является текущей ценой закрытия этого Bar ((close) ⋅ другие переменныеb、c、dНе изменяется, может быть протестировано в системе отклика на FMZ, результаты можно увидеть на рисунке.
:=Используется для переоценки существующих переменных.:=Оператор используется для изменения уже заявленных и инициализированных значений переменных.
При использовании:=Операторы, присваивающие значение неизменной, которая не инициирована или не объявлена, вызывают ошибки, например:
pine
a := 0
Так что...:=Операторы присвоения обычно используются для переоценки существующих переменных, например:
pine
a = close > open
b = 0
if a
b := b + 1
plot(b)
Если быclose > open(т.е. текущий BAR - солнечная линия), а переменная a - истинное значение ((true)) ¦ выполняет код в локальном блоке if-заявленияb := b + 1, используя оператор присвоения:=Переоценить b, добавив 1 ◦, а затем использовать функцию plot, чтобы начертить на графике значения переменной b на каждом BAR в временной последовательности, соединенной в линию ◦.
Предполагаем ли мы, что если появится солнечный луч BAR, то b будет продолжать накапливать 1? Конечно нет, здесь мы не используем никаких ключевых слов, когда объявляем переменную b и инициализируем ее как 0.b=0Это выполняется на каждом BAR, так что вы можете видеть, что результат этого кода - это перенастройка b на 0 каждый раз, если a - истинное значение, то это соответствуетclose > openТак что в этом раунде выполнения кода b будет складывать 1, в графическом рисунке функции b будет 1, но в следующем раунде выполнения кода b будет переоценен в 0. Это также место, где начинающим языку Pine легко попасть в яму.
Если говорить об ассигнованиях, то здесь необходимо расширить объяснение двух ключевых слов:var、varip
-
var
Это ключевое слово, которое мы уже видели и использовали в предыдущих уроках, но не обсуждали подробно. Давайте посмотрим на его описание:
var - ключевое слово для распределения и одноразовой инициализации переменных. Обычно, синтаксис присвоения переменных, не содержащий ключевое слово var, приводит к тому, что значения переменных покрываются при каждом обновлении данных. Напротив, когда используется ключевое слово var для распределения переменных, они могут оставаться в своем состоянии, несмотря на обновление данных.
Мы все равно используем этот пример, но мы используем его, когда мы присваиваем b.
varКлючевые слова:pinea = close > open var b = 0 if a b := b + 1 plot(b)varКлючевое слово позволяет переменной b выполнять только первоначальное первое присвоение, после чего каждый раз при выполнении логики стратегии b не будет перенастраиваться на 0, так что из рисованной во время выполнения линии можно наблюдать b, то есть количество иных BAR, появившихся при измерении текущей K-линии BAR.Изменные в var-декларации могут быть написаны не только в глобальном масштабе, но и в блоках кода, например в этом примере:
pinestrategy(overlay=true) var a = close var b = 0.0 var c = 0.0 var green_bars_count = 0 if close > open var x = close b := x green_bars_count := green_bars_count + 1 if green_bars_count >= 10 var y = close c := y plot(a, title = "a") plot(b, title = "b") plot(c, title = "c")Переменная 'a' сохраняет закрытие первого столбца серии.
Переменная 'b' сохраняет ценовую оценку на закрытие первой в серии ценовой палки на зеленый кремний.
Переменная 'c' сохраняет закрытие десятой в серии зеленой картошки. -
varip
varipЭто ключевое слово мы увидели впервые, и мы можем посмотреть на его описание:varip ((var intrabar persist) - ключевое слово, используемое для распределения и разовой инициализации переменных. Оно похоже на ключевое слово var, но переменные с использованием декларации varip сохраняют свои значения между обновлениями K-линий в реальном времени.
Это не так уж и сложно понять, но если мы приведем пример, то все будет понятно.
strategy(overlay=true) // 测试 var varip var i = 0 varip ii = 0 // 将策略逻辑每轮改变的i、ii打印在图上 plotchar(true, title="ii", char=str.tostring(ii), location=location.abovebar, color=color.red) plotchar(true, title="i", char=str.tostring(i), location=location.belowbar, color=color.green) // 每轮逻辑执行都给i、ii递增1 i := i + 1 ii := ii + 1Этот тест-код работает по-разному в модели закрытия цены и в модели реального времени:
Модели цены в реальном времени:
Помните, как мы говорили ранее о том, что время выполнения стратегии делится на историческую фазу BAR и реальную фазу BAR?var、varipОбъявленные переменныеi、iiВ каждом раунде выполнения кода стратегии выполняется увеличивающая операция. Таким образом, можно увидеть, что цифры, отображаемые на линии KBAR в результате обратной измерения, увеличиваются по 1. Когда историческая фаза K-линии заканчивается, начинается фаза K-линии в реальном времени.i := i + 1иii := ii + 1Все выполняется один раз。 отличие состоит в том, что ii изменяется каждый раз。 хотя i изменяется каждый раз, но при следующем раунде логики стратегии выполнения возвращается к предыдущему значению ((помнишь механизм прокрутки, описанный нами в предыдущей главе "Модельное выполнение"?)), до тех пор, пока текущая KBAR не будет завершена, чтобы обновить определённое значение i ((то есть при следующем раунде логики стратегии выполнения больше не будет возвращаться к предыдущему значению。). Таким образом, можно увидеть, что переменная i по-прежнему увеличивается на 1 на каждый BAR。 но переменная ii накапливается на BAR несколько раз。Модель закрытия цен:
Поскольку модель закрытия цены выполняет стратегическую логику только после того, как каждый K-линия BAR заканчивается. Таким образом, в модели закрытия цены этапы исторической K-линии и этапы реальной K-линии, переменные заявлений var, varp в приведенном выше примере показывают совершенно то же самое, увеличивая 1 на каждую K-линию BAR.
Оператор
| Оператор | проиллюстрировать |
|---|---|
| + | Добавление |
| - | Снижение |
| * | Умножение |
| / | Отмена закона |
| % | Поиск примеров |
+、-Операторы могут быть использованы как двоичные операторы, так и как единичные операторы. Другие алгоритмические операторы могут быть использованы только как двоичные операторы. Если они будут использоваться как единичные операторы, они будут ошибаться.
1 , числовой оператор обе стороны являются числовыми типами, результатом является числовой тип, целое или число плавающих точек в зависимости от результата операции.
2, если число операций - это строка, то оператор - это+, вычисляется как строка, число преобразуется в строку, затем строка склеивается вместе. Если это другой арифметический оператор, то он пытается преобразовать строку в числовое значение, а затем работает.
3, если число операций na, то вычислим нулевое значение na, и при печати на FMZ будет показано NaN.
pine
a = 1 + 1
b = 1 + 1.1
c = 1 + "1.1"
d = "1" + "1.1"
e = 1 + na
runtime.log("a:", a, ", b:", b, ", c:", c, ", d:", d, ", e:", e)
// a: 2 , b: 2.1 , c: 11.1 , d: 11.1 , e: NaN
Пинский язык на FMZ немного отличается от Пинского языка на Trading View. Пинский язык на FMZ не очень требователен к типам переменных. Например:
pine
a = 1 * "1.1"
b = "1" / "1.1"
c = 5 % "A"
plot(a)
plot(b)
plot(c)
На FMZ это возможно, но в trading view будет сообщаться о ошибке типа. Для операторов алгоритма, когда операционные числа на обеих сторонах являются строками, система будет рассчитывать строки после их преобразования в числовые значения. Если нецифровые строки не могут быть рассчитаны, система будет рассчитывать нулевые значения na.
Оператор сравнения
Операторы сравнения являются двоичными операторами.
| Оператор | проиллюстрировать |
|---|---|
| < | меньше |
| > | Больше чем |
| <= | меньше, чем равно |
| >= | Больше, чем равно |
| == | Равным |
| != | Неравенство |
Пример теста:
pine
a = 1 > 2
b = 1 < 2
c = "1" <= 2
d = "1" >= 2
e = 1 == 1
f = 2 != 1
g = open > close
h = na > 1
i = 1 > na
runtime.log("a:", a, ", b:", b, ", c:", c, ", d:", d, ", e:", e, ", f:", f, ", g:", g, ", h:", h, ", i:", i)
// a: false , b: true , c: true , d: false , e: true , f: true , g: false , h: false , i: false
Как видно, сравнительный оператор очень прост в использовании, но это также один из наиболее часто используемых операторов при написании стратегий. Можно сравнивать как числовые значения, так и встроенные переменные, напримерclose、openждать.
Как и в случае с операторами, в отличие от Pine в Trading View, в FMZ нет особо строгих типов требований, поэтому такие заявленияd = "1" >= 2 На FMZ не будет сообщений об ошибках, при выполнении сначала будет преобразована строка в числовое значение, а затем сравнивается. На Trading View будет сообщений об ошибках.
Логические операторы
| Оператор | Кодовые знаки | проиллюстрировать |
|---|---|---|
| Нет, нет | not | Одномерный оператор, не оператор |
| и | and | Бинарный оператор, с (и) |
| или | or | Бинарные операторы, или операции |
Если говорить о логических операторах, то обязательно надо говорить о таблице истинных значений. Как и в школе, только здесь мы тестируем и учимся в системе обратной связи:
pine
a = 1 == 1 // 使用比较运算符构成的表达式,结果为布尔值
b = 1 != 1
c = not b // 逻辑非操作符
d = not a // 逻辑非操作符
runtime.log("测试逻辑操作符:and", "#FF0000")
runtime.log("a:", a, ", c:", c, ", a and c:", a and c)
runtime.log("a:", a, ", b:", b, ", a and b:", a and b)
runtime.log("b:", b, ", c:", c, ", b and c:", b and c)
runtime.log("d:", d, ", b:", b, ", d and b:", d and b)
runtime.log("测试逻辑操作符:or", "#FF0000")
runtime.log("a:", a, ", c:", c, ", a or c:", a or c)
runtime.log("a:", a, ", b:", b, ", a or b:", a or b)
runtime.log("b:", b, ", c:", c, ", b or c:", b or c)
runtime.log("d:", d, ", b:", b, ", d or b:", d or b)
runtime.error("stop")
Для того, чтобы не замечать влияние непрерывного печати информации в системе отслеживания, мы используемruntime.error("stop")Сказание после выполнения одного печати, бросается аномальная ошибка, чтобы остановить отсчет, после чего можно наблюдать за выходной информацией, можно обнаружить, что содержание печати и таблицы истинных значений фактически одинаковы.
Трехмерный оператор
Использование треугольных операторов? : Трехмерные выражения с комбинацией операционных чиселcondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalseМы уже знакомы с этим в предыдущих уроках. Так называемые триединые выражения, триединые операторы означают, что их число операций составляет три.
condition ? valueWhenConditionIsTrue : valueWhenConditionIsFalseВнутренниеconditionЭто критерий, если значение истинного выражения:valueWhenConditionIsTrueЕслиconditionВыражение, используемое в качестве гипотезы, имеет значениеvalueWhenConditionIsFalse。
Пример, который, хотя и не имеет практического применения, может быть полезен для демонстрации:
pine
a = close > open
b = a ? "阳线" : "阴线"
c = not a ? "阴线" : "阳线"
plotchar(a, location=location.abovebar, color=color.red, char=b, overlay=true)
plotchar(not a, location=location.belowbar, color=color.green, char=c, overlay=true)
Если вы столкнетесь со звездочкой, это не будет иметь значения! Тривиальные выражения также могут быть встроены, мы уже делали это в предыдущих уроках.
pine
a = close > open
b = a ? math.abs(close-open) > 30 ? "阳线" : "十字星" : math.abs(close-open) > 30 ? "阴线" : "十字星"
c = not a ? math.abs(close-open) > 30 ? "阴线" : "十字星" : math.abs(close-open) > 30 ? "阳线" : "十字星"
plotchar(a, location=location.abovebar, color=color.red, char=b, overlay=true)
plotchar(not a, location=location.belowbar, color=color.green, char=c, overlay=true)
Это равносильно тому, чтоcondition ? valueWhenConditionIsTrue : valueWhenConditionIsFalseВvalueWhenConditionIsTrue、valueWhenConditionIsFalseВместо этого используются другие тривиальные выражения:
Исторический оператор
Использование оператора истории[], ссылаясь на исторические значения в временной последовательности. Эти исторические значения являются значениями переменных на K-линии BAR перед текущей K-линией BAR во время выполнения сценария.[]Оператор используется после вызова переменной, выражения, функции.[]Значение в этой квадратной скобке - это отклонение исторической информации от текущей K-линии BAR. Например, если я хочу указать закрытие цены на последнюю K-линию BAR, я напишу:close[1]。
В предыдущих уроках мы видели, как пишется:
pine
high[10]
ta.sma(close, 10)[1]
ta.highest(high, 10)[20]
close > nz(close[1], open)
[]Оператор может быть использован только один раз на одном и том же значении, так что это будет ошибочно:
pine
a = close[1][2] // 错误
Возможно, вы увидите здесь, что некоторые из ваших учеников говорят, что оператор[]Это то, что мы используем для серийных структур, которые выглядят почти так же, как и массивы!
В следующей статье мы примером покажем, что в языке Пайн есть разница между сериями и массивами.
pine
strategy("test", overlay=true)
a = close
b = close[1]
c = b[1]
plot(a, title="a")
plot(b, title="b")
plot(c, title="c")
Хотяa = close[1][2]Я не могу сказать, что это было бы неправильно, но:
pine
b = close[1]
c = b[1]
Если мы рассмотрим это как обычный массив, то мы не ошибимся.b = close[1]После присвоения значения b должно быть числовым, ноc = b[1],b может быть снова использовано с использованием исторического оператора для ссылки на историческую величину. Видно, что в языке Pine понятие серии не так просто, как массив. Можно понимать как историческую величину на верхней строке close Bar (присвоение значения b), b также является структурой временной последовательности (time series), которая может продолжать ссылку на историческую величину.
Мы можем перетащить диаграмму на левую сторону и обнаружить, что в первой K-линии значения b и c являются пустыми ((na). Это связано с тем, что когда сценарий выполняется на первой K-линии BAR, исторические значения, ссылающиеся на один или два цикла вперед, отсутствуют. Поэтому нам нужно постоянно следить при написании стратегии, будет ли ссылаться на пустые значения при ссылке на исторические данные.na、nzВстроенные функции, которые мы рассматривали в предыдущих уроках,nz、naФункции, помните, в какой главе?) конкретно рассматривают ситуации с пустыми значениями, например:
pine
close > nz(close[1], open) // 当引用close内置变量前一个BAR的历史值时,如果不存在,则使用open内置变量
Это обработка возможных цитируемых нулевых значений ((na)).
Приоритет оператора
Мы уже выучили много операторов языка Пайн, которые формируют выражения с помощью различных комбинаций операторов и чисел. Что же делать с приоритетом этих операций при вычислении в выражениях?
| Приоритеты | Оператор |
|---|---|
| 9 | [] |
| 8 | + 、- и ``` not `` |
| 7 | *、/、% |
| 6 | Двузначный оператор +、- |
| 5 | >、<、>=、<= |
| 4 | ==、!= |
| 3 | and |
| 2 | or |
| 1 | ?: |
Если вы хотите заставить произвести операцию сначала на какой-то части выражения, используйте()Замкнутое выражение, которое требует, чтобы его часть была обработана первой.
Переменные
Заявление переменной
Мы уже изучали концепцию кода идентификатора кода, кода идентификатора кода - это имя переменной, которое дается переменной. Так что переменная - это идентификатор сохраненной величины.
-
Форма заявления:
Первое, что пишется при декларировании переменной, - это "мода декларирования". Существует три вида моделей декларирования переменной:- Использование ключевых слов
var。 - Использование ключевых слов
varip。 - Ничего не пишите.
var、varipКлючевые слова мы уже изучали в предыдущем разделе "Операторы присвоения" и не будем их здесь обсуждать. Если модель объявления переменной ничего не пишет, например:i = 1, как мы уже говорили ранее, такие объявленные переменные и присвоенные значения выполняются на каждой K-линии BAR. - Использование ключевых слов
-
тип
Язык Pine на FMZ не является строгим в отношении требований к типам и, как правило, может быть отменен. Однако, для совместимости со сценарием в Trading View, можно также использовать тип при декларировании переменных. Например:int i = 0 float f = 1.1Типы в Trading View требуют более строгих требований, и если использовать следующий код в Trading View, то будет ошибка:
baseLine0 = na // compile time error! -
Идентификатор
Идентификатор - это имя переменной, название идентификатора уже упоминалось в предыдущих главах, и его можно посмотреть: https://www.fmz.com/bbs-topic/9390#标识符
В заключение, заявление о переменной может быть написано так:
// [<declaration_mode>] [<type>] <identifier> = value
声明模式 类型 标识符 = 值
Здесь используется оператор присвоения:=При объявлении переменной присваивается значение. При присваивании значение может быть строкой, числом, выражением, вызовом функции,if、 for、whileилиswitchСтруктура и т. д. (эти структурные ключевые слова и фразы будут подробно описаны в следующих уроках, но мы уже узнали об этом в предыдущих уроках.)
Здесь мы обратим внимание на функцию input, которую мы часто используем при разработке стратегий. Она очень важна для разработки стратегий.
Входные функции:
input函数,参数defval、title、tooltip、inline、group
Функция input в FMZ немного отличается от функции в Trading View, но она используется в качестве ввода значения параметров стратегии. Давайте рассмотрим пример использования функции input в FMZ:
pine
param1 = input(10, title="参数1名称", tooltip="参数1的描述信息", group="分组名称A")
param2 = input("close", title="参数2名称", tooltip="参数2的描述信息", group="分组名称A")
param3 = input(color.red, title="参数3名称", tooltip="参数3的描述信息", group="分组名称B")
param4 = input(close, title="参数4名称", tooltip="参数4的描述信息", group="分组名称B")
param5 = input(true, title="参数5名称", tooltip="参数5的描述信息", group="分组名称C")
ma = ta.ema(param4, param1)
plot(ma, title=param2, color=param3, overlay=param5)
При декларировании переменных часто используется функция input, которая автоматически выделяет в интерфейсе стратегии FMZ элементы, используемые для настройки параметров стратегии. Поддерживаемые на FMZ элементы в настоящее время включают в себя окна для ввода цифр, окна для ввода текста, выдвижные окна и выделение значений. Кроме того, можно настроить группу параметров стратегии и текстовую информацию о параметрах.
Мы расскажем о некоторых основных параметрах входных функций:
- defval: по умолчанию для параметров политики в качестве параметров вводной функции, поддерживает встроенные переменные, значения и строки языка Pine
- title: Название параметра, показываемого в интерфейсе стратегии на диске / в реверсе.
- tooltip: Пособие к параметру политики, показывающее текстовую информацию о его установке, когда мышь подвешена над параметром политики.
- group: название группы параметров стратегии, которую можно дать группе параметров。
Помимо объявления и присвоения отдельных переменных, в языке Пайн существует также написание для объявления и присвоения целого ряда переменных:
[变量A,变量B,变量C] = 函数 或者 ```if```、 ```for```、```while```或```switch```等结构
Самый распространенный из них - это то, что мы используем.ta.macdФункция вычисляет MACD-индикатор, и, поскольку MACD-индикатор - это многолинейный индикатор, вычисляет три группы данных. Поэтому можно написать:
pine
[dif,dea,column] = ta.macd(close, 12, 26, 9)
plot(dif, title="dif")
plot(dea, title="dea")
plot(column, title="column", style=plot.style_histogram)
Мы можем легко нарисовать MACD-графику с помощью вышеприведенного кода. Встроенные функции могут возвращать не только несколько переменных, но и пользовательские функции могут возвращать несколько данных.
pine
twoEMA(data, fastPeriod, slowPeriod) =>
fast = ta.ema(data, fastPeriod)
slow = ta.ema(data, slowPeriod)
[fast, slow]
[ema10, ema20] = twoEMA(close, 10, 20)
plot(ema10, title="ema10", overlay=true)
plot(ema20, title="ema20", overlay=true)
Использование структур, таких как if, в качестве присвоения значения нескольким переменным, также похоже на вышеуказанный метод пользовательских функций.
[ema10, ema20] = if true
fast = ta.ema(close, 10)
slow = ta.ema(close, 20)
[fast, slow]
plot(ema10, title="ema10", color=color.fuchsia, overlay=true)
plot(ema20, title="ema20", color=color.aqua, overlay=true)
Условная структура
Некоторые функции не могут быть записаны в блоках локального кода с условным разветвлением, в основном следующие:
barcolor(), fill(), hline(), indicator(), plot(), plotcandle(), plotchar(), plotshape()
На Trading View компилируется сообщение об ошибке. На FMZ ограничения не столь строгие, но также рекомендуется писать в соответствии с правилами на Trading View. Например, хотя в FMZ не сообщается об ошибке, но не рекомендуется писать так.
pine
strategy("test", overlay=true)
if close > open
plot(close, title="close")
else
plot(open, title="open")
if-соглашение
Пример:
pine
var lineColor = na
n = if bar_index > 10 and bar_index <= 20
lineColor := color.green
else if bar_index > 20 and bar_index <= 30
lineColor := color.blue
else if bar_index > 30 and bar_index <= 40
lineColor := color.orange
else if bar_index > 40
lineColor := color.black
else
lineColor := color.red
plot(close, title="close", color=n, linewidth=5, overlay=true)
plotchar(true, title="bar_index", char=str.tostring(bar_index), location=location.abovebar, color=color.red, overlay=true)
Примечание: выражение, используемое для определения, возвращает значение бура. Обратите внимание на сжатие.
pine
x = if close > open
close
plot(x, title="x")
Поскольку, когда K-линия BAR является отрицательной линией, то есть close < open, если выражение после фразы false, то локальный блок if не выполняется. В этом случае нет никакой ветви else, и фраза if возвращает na. x присваивается как na.
Справка switch
switch-справки также являются разветвленными структурами, которые используются для разработки различных путей выполнения в соответствии с определенными условиями.
1, как и в случае с if, ссылка switch возвращает значение.
В отличие от других языковых ссылок, ссылочная структура выполняет только один локальный блок в своем коде, поэтому объявление break не требуется (то есть не нужно писать ключевые слова break и т. д.).
3. Каждая ветвь switch может быть записана как локальный блок, и последняя строка этого локального блока является возвращаемым значением (((который может быть элементом значений)). Если ни один из ветвей не выполнен, то возвращается na。
4., расположение выражения в структуре коммутатора, можно написать строку, переменную, выражение или вызов функции.
5. switch позволяет задать возвращаемое значение, которое используется в качестве значения по умолчанию, когда в структуре нет других условий выполнения.
switch состоит из двух форм, и мы рассмотрим примеры, чтобы понять, как их использовать.
1, с выражениемswitchПример:
pine
// input.string: defval, title, options, tooltip
func = input.string("EMA", title="指标名称", tooltip="选择要使用的指标函数名称", options=["EMA", "SMA", "RMA", "WMA"])
// input.int: defval, title, options, tooltip
// param1 = input.int(10, title="周期参数")
fastPeriod = input.int(10, title="快线周期参数", options=[5, 10, 20])
slowPeriod = input.int(20, title="慢线周期参数", options=[20, 25, 30])
data = input(close, title="数据", tooltip="选择使用收盘价、开盘价、最高价...")
fastColor = color.red
slowColor = color.red
[fast, slow] = switch func
"EMA" =>
fastLine = ta.ema(data, fastPeriod)
slowLine = ta.ema(data, slowPeriod)
fastColor := color.red
slowColor := color.red
[fastLine, slowLine]
"SMA" =>
fastLine = ta.sma(data, fastPeriod)
slowLine = ta.sma(data, slowPeriod)
fastColor := color.green
slowColor := color.green
[fastLine, slowLine]
"RMA" =>
fastLine = ta.rma(data, fastPeriod)
slowLine = ta.rma(data, slowPeriod)
fastColor := color.blue
slowColor := color.blue
[fastLine, slowLine]
=>
runtime.error("error")
plot(fast, title="fast" + fastPeriod, color=fastColor, overlay=true)
plot(slow, title="slow" + slowPeriod, color=slowColor, overlay=true)
Ранее мы изучали функцию input, а здесь мы продолжаем изучать две функции, похожие на input:input.string、input.intфункция.
input.stringВместо этого используйте другие символы.input.intФункция возвращает целое число. В нашем примере мы добавили новую функцию.optionsИспользование параметровoptionsПараметры могут быть перенесены в массив, состоящий из выборных значений. Например, в примереoptions=["EMA", "SMA", "RMA", "WMA"]иoptions=[5, 10, 20](Обратите внимание, что один из них является типом строки, а другой - типом числа). Таким образом, вместо того, чтобы вводить конкретные числа, контроллер в интерфейсе политики становится выдвижной панелью, выбирая опции, предоставленные в параметре options.
Значение переменной func представляет собой строку, где переменная function является выражением switch (может быть переменной, вызовом функции, выражением), для определения того, какая часть switch выполняется. Если переменная func не может совпадать с выражением на любой части switch (то есть равнозначна), то выполняется блок кода по умолчанию.runtime.error("error")Функция приводит к тому, что политика бросает исключения и останавливается.
В нашем тестовом коде мы не включили после runtime.error после последней строки в блоке кода по умолчанию в switch[Для совместимости кода na, na] с возвращаемыми значениями в trading view необходимо учитывать эту проблему, если тип не соответствует, то он будет ошибаться. Однако на FMZ, поскольку нет строгих требований к типам, такой совместимый код может быть пропущен. Поэтому на FMZ не нужно учитывать тип совместимости if, switch branch возвращаемых значений.
pine
strategy("test", overlay=true)
x = if close > open
close
else
"open"
plotchar(true, title="x", char=str.tostring(x), location=location.abovebar, color=color.red)
В FMZ ошибок не будет, в trading view они будут, потому что if-отделения возвращают несовместимые типы.
2, без выраженияswitch
Давайте посмотрим.switchДругой вариант написания слова "и" - без выражения.
pine
up = close > open // up = close < open
down = close < open
var upOfCount = 0
var downOfCount = 0
msgColor = switch
up =>
upOfCount += 1
color.green
down =>
downOfCount += 1
color.red
plotchar(up, title="up", char=str.tostring(upOfCount), location=location.abovebar, color=msgColor, overlay=true)
plotchar(down, title="down", char=str.tostring(downOfCount), location=location.belowbar, color=msgColor, overlay=true)
В примере с испытуемым кодом видно, что switch будет соответствовать выполнению локального блока с условием разделения на истинный локальный блок. В общем случае после слова switch условия разделения должны быть взаимосвязанными. То есть в примере up и down не могут быть одновременно истинными.up = close > open // up = close < open Помимо этого, необходимо обратить внимание на то, чтобы не вводить вызов функции в ответвление switch, так как вызов функции на каждом BAR может вызвать некоторые проблемы с вычислением данных, если только:switch"В примере, исполнительная ветвь определена и не изменяется в процессе выполнения стратегии".)
Циклическая структура
Фраза for
返回值 = for 计数 = 起始计数 to 最终计数 by 步长
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
Использование фразы "for" очень просто, цикл "for" может в конечном итоге возвращать одно значение или возвращать несколько значений, чтобы[a, b, c] и т. д.). Как и в предыдущем примере, переменная, присвоенная позиции "возвращаемой стоимости" в коде. За словами "for" следует переменная "счет" для управления количеством циклов, ссылки на другие значения и т. д. Переменная "счет" присваивается в качестве "первоначального счета" до начала цикла, а затем возрастает в соответствии с настройкой "шага", и цикл останавливается, когда переменная "счет" больше "конечного счета".
используется в цикле forbreakКлючевое слово: когда исполняетсяbreakПосле слов цикл прекращается.
используется в цикле forcontinueКлючевое слово: когда исполняетсяcontinueПосле высказывания цикл проигнорируетcontinueПоследующий код выполняет следующий цикл. Заявление for возвращает значение, полученное при выполнении последнего цикла. Если код не выполнен, возвращается пустое значение.
Вот простой пример:
pine
ret = for i = 0 to 10 // 可以增加by关键字修改步长,暂时FMZ不支持 i = 10 to 0 这样的反向循环
// 可以增加条件设置,使用continue跳过,break跳出
runtime.log("i:", i)
i // 如果这行不写,就返回空值,因为没有可返回的变量
runtime.log("ret:", ret)
runtime.error("stop")
for ... in высказывания
for ... inСуществуют две формы предложения, которые обозначаются следующими кодами:
返回值 = for 数组元素 in 数组
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
返回值 = for [索引变量, 索引变量对应的数组元素] in 数组
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
Основное различие между этими двумя формами заключается в том, что они следуют за ключевым словом "for", то есть используют одну из переменных в качестве ссылки на элементы массива. Другая - использует структуру, содержащую подмножество переменных, индексирующих элементы массива.
pine
testArray = array.from(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
for ele in testArray // 修改成 [i, ele]的形式:for [i, ele] in testArray , runtime.log("ele:", ele, ", i:", i)
runtime.log("ele:", ele)
runtime.error("stop")
Используйте индексы, когда это необходимо.for [i, ele] in testArrayКак пишется
for циклическое применение
Когда можно использовать встроенные функции, предоставленные языком Pine, для выполнения некоторых циклических логических вычислений, можно использовать циклическую структуру для прямой записи, а также для обработки встроенных функций. Давайте приведем два примера.
1 . Расчет среднего значения
При использовании циклических конструкций:
pine
length = 5
var a = array.new(length)
array.push(a, close)
if array.size(a) >= length
array.remove(a, 0)
sum = 0
for ele in a
sum += ele
avg = sum / length
plot(avg, title="avg", overlay=true)
В примере используется циклическое суммирование for, а затем рассчитывается среднее значение.
Вычислить среднюю линию прямо с помощью встроенной функции:
pine
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Использование встроенных функцийta.smaДля вычисления среднелинейных показателей, очевидно, проще использовать встроенные функции. На диаграмме можно увидеть, что результаты вычислений полностью совпадают.
- Сравнение
Или используйте приведенные выше примеры.
При использовании циклических конструкций:
pine
length = 5
var a = array.new(length)
array.push(a, close)
if array.size(a) >= length
array.remove(a, 0)
sum = 0
for ele in a
sum += ele
avg = sum / length
plot(avg, title="avg", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Для вычисления суммы всех элементов массива можно использовать цикл, а также можно использовать встроенную функциюarray.sumЯ не знаю, что делать.
Вычислить суммирование с помощью встроенной функции:
pine
length = 5
var a = array.new(length)
array.push(a, close)
if array.size(a) >= length
array.remove(a, 0)
plot(array.sum(a) / length, title="avg", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Вычисленные данные полностью совпадают на графике, используемом для составления графика.
Если вы можете сделать все это с помощью встроенных функций, зачем создавать циклы?
- Для некоторых операций на массиве, вычисления.
- Возвращайтесь в прошлое, например, чтобы узнать, сколько прошлых вершин было выше, чем вершины текущего BAR. Поскольку вершины текущего BAR известны только в BAR, на котором работает сценарий, требуется цикл, чтобы вовремя вернуться и проанализировать прошлые BAR.
- Встроенная функция, использующая язык Pine, не может выполнить вычисление прошлых BAR.
Ссылка на while
whileСтрока, позволяющая выполнять код части цикла до тех пор, пока в структуре "while" не будет выполнено условие "false".
返回值 = while 判断条件
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
Другие правила while похожи на правила цикла for, где последняя строка локального блока цикла является возвращаемым значением, которое может возвращать несколько значений. Выполнение цикла происходит, когда "условие цикла" является истинным, и прекращение цикла, когда условие ложное. В цикле также можно использовать фразы break, continue.
Я покажу это на примере счисления равной линии:
pine
length = 10
sma(data, length) =>
i = 0
sum = 0
while i < 10
sum += data[i]
i += 1
sum / length
plot(sma(close, length), title="sma", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Можно увидеть, что использование цикла while также очень просто, а также можно спроектировать некоторые вычислительные логики, которые нельзя заменить встроенными функциями, например, вычислить степень умножения:
pine
counter = 5
fact = 1
ret = while counter > 0
fact := fact * counter
counter := counter - 1
fact
plot(ret, title="ret") // ret = 5 * 4 * 3 * 2 * 1
Группы
Схемы в языке Pine похожи на определения в других языках программирования. Схемы в языке Pine являются одномерными. Обычно они используются для хранения последовательной серии данных. Схемы, в которых хранятся отдельные данные, называются элементами, которые могут быть: целостными, фонарными, строками, цветными значениями, буквенными значениями.[]Они должны использоваться.array.get()иarray.set()Функция ◦ индексирует элементы в массиве в том порядке, что индекс первого элемента массива равен 0, а индекс следующего элемента увеличивается на 1。
Мы объясняем это простым кодом:
pine
var a = array.from(0)
if bar_index == 0
runtime.log("当前BAR上的a值:", a, ", 上1根BAR上的a,即a[1]值:", a[1])
else if bar_index == 1
array.push(a, bar_index)
runtime.log("当前BAR上的a值:", a, ", 上1根BAR上的a,即a[1]值:", a[1])
else if bar_index == 2
array.push(a, bar_index)
runtime.log("当前BAR上的a值:", a, ", 上1根BAR上的a,即a[1]值:", a[1], ", 向前数2根BAR上的a,即a[2]值:", a[2])
else if bar_index == 3
array.push(a, bar_index)
runtime.log("当前BAR上的a值:", a, ", 上1根BAR上的a,即a[1]值:", a[1], ", 向前数2根BAR上的a,即a[2]值:", a[2], ", 向前数3根BAR上的a,即a[3]值:", a[3])
else if bar_index == 4
// 使用array.get 按索引获取元素,使用array.set按索引修改元素
runtime.log("数组修改前:", array.get(a, 0), array.get(a, 1), array.get(a, 2), array.get(a, 3))
array.set(a, 1, 999)
runtime.log("数组修改后:", array.get(a, 0), array.get(a, 1), array.get(a, 2), array.get(a, 3))
Объявленный массив
использоватьarray<int> a、float[] bОбъявление массива или объявление только одной переменной может быть присвоено массиву, например:
pine
array<int> a = array.new(3, bar_index)
float[] b = array.new(3, close)
c = array.from("hello", "fmz", "!")
runtime.log("a:", a)
runtime.log("b:", b)
runtime.log("c:", c)
runtime.error("stop")
Общее применение для инициализации переменныхarray.newиarray.fromФункция 。 В языке Pine есть много других функций, связанных с типами, похожих на функции array.new:array.new_int()、array.new_bool()、array.new_color()、array.new_string()ждать.
Ключевое слово var также может работать с формулой объявления массива, где массив, объявленный с помощью ключевого слова var, инициируется только на первом строке BAR. Давайте рассмотрим пример:
pine
var a = array.from(0)
b = array.from(0)
if bar_index == 1
array.push(a, bar_index)
array.push(b, bar_index)
else if bar_index == 2
array.push(a, bar_index)
array.push(b, bar_index)
else if barstate.islast
runtime.log("a:", a)
runtime.log("b:", b)
runtime.error("stop")
Можно увидеть, что изменения в массиве a постоянно определяются и не перемещаются. А массив b инициализируется на каждом BAR.barstate.islastДля реального времени печати остается только один элемент, число 0.
Читать и писать элементы в массиве
Используйте array.get, чтобы получить элементы, указанные в индексируемом положении, и используйте array.set, чтобы изменить элементы, указанные в индексируемом положении.
Первый аргумент array.get - это обработанный массив, второй - указанный индекс.
Первый аргумент array.set - это массив, который нужно обработать, второй - это индекс, который нужно указать, а третий - элемент, который нужно записать.
Для иллюстрации используйте следующий простой пример:
pine
lookbackInput = input.int(100)
FILL_COLOR = color.green
var fillColors = array.new(5)
if barstate.isfirst
array.set(fillColors, 0, color.new(FILL_COLOR, 70))
array.set(fillColors, 1, color.new(FILL_COLOR, 75))
array.set(fillColors, 2, color.new(FILL_COLOR, 80))
array.set(fillColors, 3, color.new(FILL_COLOR, 85))
array.set(fillColors, 4, color.new(FILL_COLOR, 90))
lastHiBar = - ta.highestbars(high, lookbackInput)
fillNo = math.min(lastHiBar / (lookbackInput / 5), 4)
bgcolor(array.get(fillColors, int(fillNo)), overlay=true)
plot(lastHiBar, title="lastHiBar")
plot(fillNo, title="fillNo")
Этот пример инициализирует основной цвет зеленый, объявляет и инициализирует массив, используемый для сохранения цвета, а затем придает цветным значениям различную прозрачность (используя функцию color.new). Расчет цветного ранга осуществляется путем вычисления расстояния от текущего BAR до наивысшего значения в течение 100 обзорных циклов. Чем ближе к наивысшему значению в течение последних 100 обзорных циклов, тем выше ранг, и тем глубже соответствующий цвет (низкая прозрачность). Многие подобные стратегии используются таким образом, чтобы показать уровень текущей цены в течение N отдельных обзорных циклов.
Прохождение по элементам
Как пройти через массив, мы можем использовать предшествующие нам выражения for/for in/while.
pine
a = array.from(1, 2, 3, 4, 5, 6)
for i = 0 to (array.size(a) == 0 ? na : array.size(a) - 1)
array.set(a, i, i)
runtime.log(a)
runtime.error("stop")
pine
a = array.from(1, 2, 3, 4, 5, 6)
i = 0
while i < array.size(a)
array.set(a, i, i)
i += 1
runtime.log(a)
runtime.error("stop")
pine
a = array.from(1, 2, 3, 4, 5, 6)
for [i, ele] in a
array.set(a, i, i)
runtime.log(a)
runtime.error("stop")
Все три метода выполняют один и тот же результат.
Массивы могут быть объявлены в глобальном масштабе сценария или в локальном масштабе функции или if-отдела.
Исторические данные
Для использования элементов в массиве, следующий способ является эквивалентным, мы можем увидеть на следующем примере, что на рисунке начертано две группы линий, по две линии в каждой группе, и числовые значения двух линий в каждой группе полностью одинаковы.
pine
a = array.new_float(1)
array.set(a, 0, close)
closeA1 = array.get(a, 0)[1]
closeB1 = close[1]
plot(closeA1, "closeA1", color.red, 6)
plot(closeB1, "closeB1", color.black, 2)
ma1 = ta.sma(array.get(a, 0), 20)
ma2 = ta.sma(close, 20)
plot(ma1, "ma1", color.aqua, 6)
plot(ma2, "ma2", color.black, 2)
Функции добавления и удаления из массива
1, связанные с функцией прибавления операций в массиве:
array.unshift()、array.insert()、array.push()。
Функции, связанные с удалением массива:
array.remove()、array.shift()、array.pop()、array.clear()。
Мы используем следующий пример для тестирования функций добавления и удаления этих массивов.
pine
a = array.from("A", "B", "C")
ret = array.unshift(a, "X")
runtime.log("数组a:", a, ", ret:", ret)
ret := array.insert(a, 1, "Y")
runtime.log("数组a:", a, ", ret:", ret)
ret := array.push(a, "D")
runtime.log("数组a:", a, ", ret:", ret)
ret := array.remove(a, 2)
runtime.log("数组a:", a, ", ret:", ret)
ret := array.shift(a)
runtime.log("数组a:", a, ", ret:", ret)
ret := array.pop(a)
runtime.log("数组a:", a, ", ret:", ret)
ret := array.clear(a)
runtime.log("数组a:", a, ", ret:", ret)
runtime.error("stop")
Приложения для добавления и удаления: Array as Queue
Используя массив, а также некоторые функции добавления и удаления из массива, мы можем построить структуру данных "кольцо". Кольцо может быть использовано для расчета скользящих средних цен на тик, и некоторые ученики могут спросить: "Почему вы построили массивную структуру?
Коечка - это структура, часто используемая в программировании, характеризующаяся следующими свойствами:
Первые элементы в строке будут первыми выходить из строки.
Это гарантирует, что данные, содержащиеся в очереди, являются самыми свежими, и что длина очереди не будет расширяться до бесконечности (код с бесконечно расширенным объемом может быть написан только в полдень, потому что это может быть проблемой в утренние и вечерние часы).
В следующем примере мы используем строку очередей, записывающую цены на каждое тик, вычисляем скользящие средние цены на уровне тиков, а затем сравниваем их с скользящими средними на уровне K-линий в течение 1 минуты.
pine
strategy("test", overlay=true)
varip a = array.new_float(0)
var length = 10
if not barstate.ishistory
array.push(a, close)
if array.size(a) > length
array.shift(a)
sum = 0.0
for [index, ele] in a
sum += ele
avgPrice = array.size(a) == length ? sum / length : na
plot(avgPrice, title="avgPrice")
plot(ta.sma(close, length), title="ta.sma")
Обратите внимание, что для объявления а-ареста мы указали форму объявления, используя ключевые слова.varip│ таким образом, каждое изменение цены будет записываться в массиве a│
Обычно используемые функции для вычисления и обработки массивов
Вычислить соответствующие функции:
array.avg()Получите среднее значение всех элементов в массиве.array.min()Найдите самый маленький элемент в массиве.array.max()Найдите самый большой элемент в массиве.array.stdev()Найдите стандартное расстояние для всех элементов в массиве.array.sum()Найдите сумму всех элементов в массиве.
Функции, связанные с операцией:
array.concat()Объединение или соединение двух массивов.
array.copy()Копировать массив.
array.joinСоедините все элементы в массиве в одну строку.
array.sort()В порядке перехода в следующую категорию:
array.reverse()Обратная матрица.
array.slice()Вырезаем массив.
array.includes()Элементы суждения.
array.indexof()Возвращает индекс, в котором впервые появилось значение, введенное в параметре. Если значение не найдено, возвращается -1.
array.lastindexof()Найдите значение последнего появления.
Примеры тестов соответствующих функций для вычисления массивов:
pine
a = array.from(3, 2, 1, 4, 5, 6, 7, 8, 9)
runtime.log("数组a的算数平均:", array.avg(a))
runtime.log("数组a中的最小元素:", array.min(a))
runtime.log("数组a中的最大元素:", array.max(a))
runtime.log("数组a中的标准差:", array.stdev(a))
runtime.log("数组a的所有元素总和:", array.sum(a))
runtime.error("stop")
Это наиболее часто используемые функции для вычисления массивов.
Примеры операционных функций:
pine
a = array.from(1, 2, 3, 4, 5, 6)
b = array.from(11, 2, 13, 4, 15, 6)
runtime.log("数组a:", a, ", 数组b:", b)
runtime.log("数组a,数组b连接在一起:", array.concat(a, b))
c = array.copy(b)
runtime.log("复制一个数组b,赋值给变量c,变量c:", c)
runtime.log("使用array.join处理数组c,给每个元素中间增加符号+,连接所有元素结果为字符串:", array.join(c, "+"))
runtime.log("排序数组b,按从小到大顺序,使用参数order.ascending:", array.sort(b, order.ascending)) // array.sort函数修改原数组
runtime.log("排序数组b,按从大到小顺序,使用参数order.descending:", array.sort(b, order.descending)) // array.sort函数修改原数组
runtime.log("数组a:", a, ", 数组b:", b)
array.reverse(a) // 此函数修改原数组
runtime.log("反转数组a中的所有元素顺序,反转之后数组a为:", a)
runtime.log("截取数组a,索引0 ~ 索引3,遵循左闭右开区间规则:", array.slice(a, 0, 3))
runtime.log("在数组b中搜索元素11:", array.includes(b, 11))
runtime.log("在数组a中搜索元素100:", array.includes(a, 100))
runtime.log("将数组a和数组b连接,搜索其中第一次出现元素2的索引位置:", array.indexof(array.concat(a, b), 2), " , 参考观察 array.concat(a, b):", array.concat(a, b))
runtime.log("将数组a和数组b连接,搜索其中最后一次出现元素6的索引位置:", array.lastindexof(array.concat(a, b), 6), " , 参考观察 array.concat(a, b):", array.concat(a, b))
runtime.error("stop")
функция
Функция по умолчанию
В языке Pine можно проектировать пользовательские функции, которые, как правило, следуют следующим правилам:
- Все функции определены в глобальном масштабе сценария. Функция не может быть объявлена в другой функции.
- Не разрешает функциям вызывать себя в своем коде (рекурсивно) [2].
3, в принципе, все языки PINE имеют встроенную функцию рисования ((barcolor()、 fill()、 hline()、plot()、 plotbar()、 plotcandle()) не может быть вызван в рамках пользовательских функций.
Функции могут быть написаны как в одном, так и в нескольких строках. Возвращаемое значение последнего предложения является возвращаемым значением текущей функции, а возвращаемое значение может быть возвращено в виде элемента.
В предыдущих уроках мы также использовали пользовательские функции, например, функции, разработанные в виде одного строки:
pine
barIsUp() => close > open
Функция возвращает, является ли текущий BAR солнечным светом.
Дизайн многострочных функций:
pine
sma(data, length) =>
i = 0
sum = 0
while i < 10
sum += data[i]
i += 1
sum / length
plot(sma(close, length), title="sma", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)
Функция, которую мы сами вычислили в виде средней линии sma, реализованной с помощью нашей собственной функции.
Кроме того, можно вернуть примеры функций с двумя переменными:
pine
twoEMA(data, fastPeriod, slowPeriod) =>
fast = ta.ema(data, fastPeriod)
slow = ta.ema(data, slowPeriod)
[fast, slow]
[ema10, ema20] = twoEMA(close, 10, 20)
plot(ema10, title="ema10", overlay=true)
plot(ema20, title="ema20", overlay=true)
Функция может вычислить быструю линию, медленную линию, два показателя средней линии EMA.
Встроенная функция
Встроенная функция может быть легко использована вFMZ PINE Script ДокументыПоиск в Интернете
Встроенные функции языка Pine классифицируются:
1, функция обработки стринговstr.Сериал
Функция обработки цветаcolor.Сериал
3, вводная функцияinput.Сериал
4. Функция подсчета показателейta.Сериал
5 , графическая функцияplot.Сериал
6., Функция обработкиarray.Сериал
7. Функции, связанные с сделкойstrategy.Сериал
8. Функции, связанные с математической операциейmath.Сериал
9 , другие функции ((время обработки, неплот серийный рисунок функции,request.Функции серии, функции обработки типов и т. д.)
Транзакционная функция
strategy.Функции серии - это функции, которые мы часто используем при разработке стратегий, связанные с выполнением операций по сделкам при конкретном запуске стратегии.
1、strategy.entry
strategy.entryФункция является одной из наиболее важных в написании стратегии функций заказа. Некоторые важные параметры функции:id, direction, qty, whenждать.
параметр:
id: может быть понят как имя, которое используется для ссылки на определенную торговую позицию. Можно ссылаться на это id для отмены, изменения ордера, ликвидации позиции.direction: если заказ направлен на то, чтобы сделать больше ((покупать) этот параметр передаетсяstrategy.longЭта встроенная переменная передается, если мы хотим продать.strategy.shortЭта переменная .qty: укажите количество заказов, если этот параметр не передается, используется по умолчанию количество заказов.whenУсловия выполнения: можно задать этот параметр, чтобы контролировать, будет ли вызвана текущая следующая операция.limit: указать ценовую лимиту заказа.stopСтоп-Лост
strategy.entryПодробности выполнения функцииstrategyКонтроль параметров при вызове функции также может осуществляться с помощью"Параметры модуляции класса Exchange в языке Pine"Подробнее об операциях, контролируемых параметрами настройки и модуляции класса "Pine Language Transaction Library", можно прочитать в документации по ссылке.
Я хочу рассказать об этом.strategyФункцияpyramiding、default_qty_valueПараметры. Тестируйте с помощью следующего кода:
pine
/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
strategy(title = "open long example", pyramiding = 3, default_qty_value=0.1, overlay=true)
ema10 = ta.ema(close, 10)
findOrderIdx(idx) =>
if strategy.opentrades == 0
false
else
ret = false
for i = 0 to strategy.opentrades - 1
if strategy.opentrades.entry_id(i) == idx
ret := true
break
ret
if not findOrderIdx("long1")
strategy.entry("long1", strategy.long)
if not findOrderIdx("long2")
strategy.entry("long2", strategy.long, 0.2, when = close > ema10)
if not findOrderIdx("long3")
strategy.entry("long3", strategy.long, 0.2, limit = low[1])
strategy.entry("long3", strategy.long, 0.3, limit = low[1])
if not findOrderIdx("long4")
strategy.entry("long4", strategy.long, 0.2)
plot(ema10, title="ema10", color=color.red)
Начало кода/*backtest ... */Часть пакета предназначена для отслеживания настроек, чтобы записывать информацию о времени отслеживания настроек в то время, для удобства дебютирования, а не для кода стратегии.
В коде:strategy(title = "open long example", pyramiding = 3, default_qty_value=0.1, overlay=true)Когда мы назначилиpyramidingЕсли параметр равен 3, то мы установили, что мы можем совершать одну и ту же сделку не более 3 раз.strategy.entryСледующая операция не была выполнена.default_qty_valueПараметр 0.1, так что ID обозначен как <unk>long1<unk>strategy.entryСледующий шаг для выполнения операции по умолчанию 0.1.strategy.entryМы называем функцию, которую мы называемdirectionВ среднемstrategy.longТак что при обратном тестировании все заказы оплачиваются.
Внимание в кодеstrategy.entry("long3", ...Следующая операция вызвана дважды, для того же ID: <unk>long3<unk>strategy.entryСледующая операция не состоялась, второй вызовstrategy.entryФункция изменяет заказ с этим ID ((показаны данные, показанные при тестировании, также могут показать, что заказ с этим лимитным заказом был изменен на 0.3) ◦ В другом случае, например, если в первый раз ID был сделан заказ на <unk>long3<unk>, продолжайте использовать <unk>long3<unk> в соответствии с этим ID.strategy.entryФункции заказываются, тогда ордерные позиции будут накапливаться на ID<unk>long3<unk>
2、strategy.close
strategy.closeФункция используется для определения позиции входа в позицию, идентифицирующую ID. Основные параметры:id,when,qty,qty_percent。
параметр:
idМы используем ID для входа в систему, который требует уравнения.strategy.entryИдентификатор, указанный при открытии позиции при входе в функцию.whenУсловия исполнения:qtyКоличество сделанных сделокqty_percentПроцентное соотношение равновесия.
Для того, чтобы ознакомиться с деталями использования этой функции, приведем пример:
В коде/*backtest ... */Это конфигурационная информация, которую вы можете удалить, настроив рынок, сорт, временной диапазон, который вам нужно протестировать.
pine
/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
strategy("close Demo", pyramiding=3)
var enableStop = false
if enableStop
runtime.error("stop")
strategy.entry("long1", strategy.long, 0.2)
if strategy.opentrades >= 3
strategy.close("long1") // 多个入场订单,不指定qty参数,全部平仓
// strategy.close() // 不指定id参数,会平掉当前的持仓
// strategy.close("long2") // 如果指定一个不存在的id则什么都不操作
// strategy.close("long1", qty=0.15) // 指定qty参数平仓
// strategy.close("long1", qty_percent=50) // qty_percent设置50即为平掉long1标识仓位的50%持仓
// strategy.close("long1", qty_percent=80, when=close<open) // 指定when参数,修改为close>open就不触发了
enableStop := true
Испытательная стратегия показала, что начать с трех последовательных многопоступлений с идентификатором входа 1<unk>long1<unk>, а затем использоватьstrategy.closeРазличные результаты, полученные при установке равновесия на различные параметры функции.strategy.closeФункция не имеет параметров для указания цены, по которой может быть произведена ликвидация. Функция используется в первую очередь для немедленной ликвидации по текущей рыночной цене.
3、strategy.close_all
strategy.close_allФункция используется для уравнения всех текущих позиций, так как скрипт языка Pine может держать позиции только в одном направлении, то есть если есть сигнал, противоположный направлению текущего держателя, то он будет уравнять текущие позиции и открывать позиции в соответствии с сигналом.strategy.close_allПри вызове он устраняет все позиции в текущем направлении.strategy.close_allОсновные параметры функции:when。
параметр:
whenУсловия исполнения:
Мы используем пример, чтобы увидеть:
pine
/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
strategy("closeAll Demo")
var enableStop = false
if enableStop
runtime.error("stop")
strategy.entry("long", strategy.long, 0.2, when=strategy.position_size==0 and close>open)
strategy.entry("short", strategy.short, 0.3, when=strategy.position_size>0 and close<open)
if strategy.position_size < 0
strategy.close_all()
enableStop := true
В начале тестирования код был на уровне 0.strategy.position_size==0true), так что выполняется только ID, если он соответствует условиям, установленным в параметре whenstrategy.entryФункция входа: после многопозицииstrategy.position_sizeВ случае, если ID больше 0, то входная функция short может быть выполнена только в том случае, если в данный момент имеется множественная позиция, и этот обратный сигнал об обесценении приводит к обесценению множественной позиции и обратному обесценению. Затем мы записываем в условиях ifstrategy.position_size < 0В случае, когда держатель держит позицию в пустом направлении, он устраняет все позиции, которые он держит в текущем направлении.enableStop := true│ │ │ │ │ │ │ │ │
Найденоstrategy.close_allФункция не имеет параметров для указания цены, по которой может быть произведена ликвидация. Функция используется в первую очередь для немедленной ликвидации по текущей рыночной цене.
4、strategy.exit
strategy.exitФункция используется для вхождения в позицию, в отличие от функции, которая используется для вхождения в позициюstrategy.closeиstrategy.close_allФункция является мгновенным выравниванием по текущей рыночной цене.strategy.exitФункция планирует уравнение в зависимости от параметров.
параметр:
id: Идентификатор заказа для текущей позиции.from_entry: входный идентификатор, используемый для указания операций по ликвидации.qtyКоличество сделанных сделокqty_percentПроцентное соотношение, диапазон: 0 ~ 100profitЦель прибыли в баллах.lossПоказатель: Стоп-ущерб.limitЦель прибыли определяется ценой.stopЦель: остановить убытки, указать цену.whenУсловия исполнения:
Использование стратегии тестирования для понимания использования параметров.
pine
/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
args: [["RunMode",1,358374],["ZPrecision",0,358374]]
*/
strategy("strategy.exit Demo", pyramiding=3)
varip isExit = false
findOrderIdx(idx) =>
ret = -1
if strategy.opentrades == 0
ret
else
for i = 0 to strategy.opentrades - 1
if strategy.opentrades.entry_id(i) == idx
ret := i
break
ret
strategy.entry("long1", strategy.long, 0.1, limit=1, when=findOrderIdx("long1") < 0)
strategy.entry("long2", strategy.long, 0.2, when=findOrderIdx("long2") < 0)
strategy.entry("long3", strategy.long, 0.3, when=findOrderIdx("long3") < 0)
if not isExit and strategy.opentrades > 0
// strategy.exit("exitAll") // 如果仅仅指定一个id参数,则该退场订单无效,参数profit, limit, loss, stop等出场条件也至少需要设置一个,否则也无效
strategy.exit("exit1", "long1", profit=50) // 由于long1入场订单没有成交,因此ID为exit1的出场订单也处于暂待状态,直到对应的入场订单成交才会放置exit1
strategy.exit("exit2", "long2", qty=0.1, profit=100) // 指定参数qty,平掉ID为long2的持仓中0.1个持仓
strategy.exit("exit3", "long3", qty_percent=50, limit=strategy.opentrades.entry_price(findOrderIdx("long3")) + 1000) // 指定参数qty_percent,平掉ID为long3的持仓中50%的持仓
isExit := true
if bar_index == 0
runtime.log("每点价格为:", syminfo.mintick) // 每点价格和Pine语言模板参数上「定价货币精度」参数设置有关
Используя обратную связь с моделью цены в реальном времени, эта тестовая стратегия начинается с выполнения трех входных операций:strategy.entryФункция), <unk>long1 <unk> намеренно установленаlimitПараметр, цена заказа на 1 делает его невозможным. Затем тестируйте условия выходной функцииstrategy.exit。 используется стоп-стоп по пункту, стоп-стоп по цене, используется стоп-стоп по фиксированному количеству позиций, используется стоп-стоп по проценту. 。 учитывая, что в примере расширения показан только стоп-стоп.strategy.exitФункции также имеют более сложные параметры для отслеживания потерь:trail_price、trail_points、trail_offsetВ этом примере также можно попробовать научиться использовать эти слова.
5、strategy.cancel
strategy.cancelФункции, используемые для отмены/остановки всех предварительных заказов.strategy.order, strategy.entry , strategy.exitФункция может генерировать входный ID. Основные параметры функции:id、when。
параметр:
idИдентификационный номер:whenУсловия исполнения:
Эта функция хорошо понятна, она используется для отмены входных команд, которые не были сделаны.
pine
/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
strategy("strategy.cancel Demo", pyramiding=3)
var isStop = false
if isStop
runtime.error("stop")
strategy.entry("long1", strategy.long, 0.1, limit=1)
strategy.entry("long2", strategy.long, 0.2, limit=2)
strategy.entry("long3", strategy.long, 0.3, limit=3)
if not barstate.ishistory and close < open
strategy.cancel("long1")
strategy.cancel("long2")
strategy.cancel("long3")
isStop := true
6、strategy.cancel_all
strategy.cancel_allФункции иstrategy.cancelФункция подобна . Отменить / отключить все предварительные заказы . Можно указатьwhenПараметры
параметр:
whenУсловия исполнения:
pine
/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/
strategy("strategy.cancel Demo", pyramiding=3)
var isStop = false
if isStop
runtime.error("stop")
strategy.entry("long1", strategy.long, 0.1, limit=1)
strategy.entry("long2", strategy.long, 0.2, limit=2)
strategy.entry("long3", strategy.long, 0.3, limit=3)
if not barstate.ishistory and close < open
strategy.cancel_all()
isStop := true
7、strategy.order
strategy.orderФункции, параметры и т.д.strategy.entryОднообразиеstrategy.orderФункции не защищеныstrategyФункцияpyramidingВлияние параметров настройки, без ограничения на количество заказов.
параметр:
id: может быть понят как имя, которое используется для ссылки на определенную торговую позицию. Можно ссылаться на это id для отмены, изменения ордера, ликвидации позиции.direction: если заказ направлен на то, чтобы сделать больше ((покупать) этот параметр передаетсяstrategy.longЭта встроенная переменная передается, если мы хотим продать.strategy.shortЭта переменная .qty: укажите количество заказов, если этот параметр не передается, используется по умолчанию количество заказов.whenУсловия выполнения: можно задать этот параметр, чтобы контролировать, будет ли вызвана текущая следующая операция.limit: указать ценовую лимиту заказа.stopСтоп-Лост
Мы используемstrategy.orderЭто не ограничивается количеством последовательностей.strategy.exitФункция условного выхода из игры. │Сценарий построения сетевой транзакции. │Примеры очень простые и только для изучения:
pine
/*backtest
start: 2021-03-01 00:00:00
end: 2022-08-30 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"ETH_USDT"}]
args: [["ZPrecision",0,358374]]
*/
varip beginPrice = -1
if not barstate.ishistory
if beginPrice == -1 or (math.abs(close - beginPrice) > 1000 and strategy.opentrades == 0)
beginPrice := close
for i = 0 to 20
strategy.order("buy"+i, strategy.long, 0.01, limit=beginPrice-i*200, when=(beginPrice-i*200)<close)
strategy.exit("coverBuy"+i, "buy"+i, qty=0.01, profit=200)
strategy.order("sell"+i, strategy.short, 0.01, limit=beginPrice+i*200, when=(beginPrice+i*200)>close)
strategy.exit("coverSell"+i, "sell"+i, qty=0.01, profit=200)
Примеры стратегий
Примеры стратегий, приведенные в этом руководстве, используются только для обучения стратегии, ориентирования на разработку стратегии, а не для предоставления каких-либо торговых рекомендаций.
Стратегия индикации супертенденций
pine
strategy("supertrend", overlay=true)
[supertrend, direction] = ta.supertrend(input(5, "factor"), input.int(10, "atrPeriod"))
plot(direction < 0 ? supertrend : na, "Up direction", color = color.green, style=plot.style_linebr)
plot(direction > 0 ? supertrend : na, "Down direction", color = color.red, style=plot.style_linebr)
if direction < 0
if supertrend > supertrend[2]
strategy.entry("entry long", strategy.long)
else if strategy.position_size < 0
strategy.close_all()
else if direction > 0
if supertrend < supertrend[3]
strategy.entry("entry short", strategy.short)
else if strategy.position_size > 0
strategy.close_all()
Тренд-стратегию написать на языке Pine очень просто. Здесь мы создаем простую стратегию отслеживания трендов с помощью супер-тенденциального индикатора. Давайте вместе проанализируем исходный код этой стратегии.
Сначала используйте стратегический код.strategyФункция делает несколько простых настроек:strategy("supertrend", overlay=true)Вместо этого, мы просто настроим стратегию под заголовком "supertrend".overlayПараметры:trueПервое, что мы делаем, когда разрабатываем стратегию Pine или изучаем сценарий стратегии Pine, это обращаем внимание на дизайн параметров интерфейса стратегии, мы смотрим на исходный код "Стратегии индикаторов супертенденции", в котором есть то, что мы изучали в предыдущих курсах.inputфункция
[supertrend, direction] = ta.supertrend(input(5, "factor"), input.int(10, "atrPeriod"))
inputФункциональные вызовы используются непосредственно какta.supertrendПараметры функции индикатора используются для вычисления индикатора супертенденции.
- input(5, "factor")
- input.int(10, "atrPeriod")
Функция по умолчанию устанавливает два параметра управления в интерфейсе политики языка Pine, как показано на рисунке:
Вы можете видеть, что значение по умолчанию на контроле -inputФункции иinputФункция ряда ((input.intПервые параметры для () были описаны в предыдущих главах. Эти две функции позволяют нам настроить их на политическом интерфейсе.ta.supertrendФункция с параметрами: . Функция супертенденциального индикатора вычисляет данные о ценахsupertrendИ одно направление данныхdirection◯ ИспользуйтеplotФункциональная диаграмма, обратите внимание, что при рисовании диаграмма рисуется в соответствии с направлением индикатора супертенденции, рисуйте только текущее направление.directionВ случае, если текущая тенденция в сторону повышения, то она будет равна -1.directionВ течение часа текущая тенденция будет снижаться, так что мы увидим, чтоplotФункции, которые вы должны знать, когда рисоватьdirectionБольше, чем 0, меньше, чем 0.
Следующийif ... else ifЛогика - это суждение о торговых сигналах, когда выражениеdirection < 0В качестве реального времени показывает, что текущая ситуация находится на подъемной стадии, в то время как если данные о ценах в индикаторе супертенденцииsupertrendСупертенденциальная цена на 2 BAR вперед (т.е.supertrend[2],还记得历史操作符引用某个变量历史数据吧Если в данный момент имеется позиция, то обратный вызов функции заказа в данный момент будет сначала погасить предыдущую позицию, а затем открыть позицию в соответствии с текущим направлением торговли.supertrend > supertrend[2]Условия не достигнуты, если толькоstrategy.position_size < 0Иными словами, наличие свободных позиций может спровоцироватьstrategy.close_all()Функция выполняется, при полном выравнивании.
direction > 0То же самое можно сказать и о падении, если у вас есть несколько позиций, которые будут полностью ликвидированы, и вы будете соответствовать условиям.supertrend < supertrend[3]В этом случае вы можете установить настройку, которая позволит вам выключить пульс, когда вы включите пульс.[3]Возможно, это было сделано специально для стратегов, поскольку в некоторых рынках, таких как контрактный рынок, риск потери капитала немного выше, чем риск потери капитала.
дляta.supertrendИндекс, интересует ли кого-то из студентов, как он определяет текущие тенденции - вверх или вниз?
На самом деле, этот показатель может быть реализован в виде функций на языке Pine:
pine
pine_supertrend(factor, atrPeriod) =>
src = hl2
atr = ta.atr(atrPeriod)
upperBand = src + factor * atr
lowerBand = src - factor * atr
prevLowerBand = nz(lowerBand[1])
prevUpperBand = nz(upperBand[1])
lowerBand := lowerBand > prevLowerBand or close[1] < prevLowerBand ? lowerBand : prevLowerBand
upperBand := upperBand < prevUpperBand or close[1] > prevUpperBand ? upperBand : prevUpperBand
int direction = na
float superTrend = na
prevSuperTrend = superTrend[1]
if na(atr[1])
direction := 1
else if prevSuperTrend == prevUpperBand
direction := close > upperBand ? -1 : 1
else
direction := close < lowerBand ? 1 : -1
superTrend := direction == -1 ? lowerBand : upperBand
[superTrend, direction]
Эта функция является и встроенной функцииta.supertrendИными словами, если вы используете один и тот же алгоритм, то вы получаете один и тот же показатель.
Из этого алгоритма мы можем увидеть, что встроенный в Pine супертенденционный индикатор используетhl2Встроенная переменная ((высочайшая цена, наименьшая цена сложены и разделены на 2, то есть среднее значение наивысшей цены и наименьшей цены), затем ATR-показатель определенного периода рассчитан на основе параметраatrPeriod ((волновой диапазон)). Затем используйте hl2 и ATR для построения верхней и нижней полос.
Обновление в соответствии с треугольным выражением в кодеlowerBandиupperBand。
pine
lowerBand := lowerBand > prevLowerBand or close[1] < prevLowerBand ? lowerBand : prevLowerBand
upperBand := upperBand < prevUpperBand or close[1] > prevUpperBand ? upperBand : prevUpperBand
lowerBand: нижняя полоса, используемая для определения изменения в восходящей тенденции. upperBand: верхняя полоса, используемая для определения изменения в нисходящей тенденции. lowerBand и upperBand всегда рассчитываются, только в этом пользовательском функции, в конечном итоге, определяется направление текущей тенденции.
pine
else if prevSuperTrend == prevUpperBand
direction := close > upperBand ? -1 : 1
else
direction := close < lowerBand ? 1 : -1
Если мы будем считать, что цены на супер тренды на BAR, то мы получимprevUpperBand, то есть верхняя линия, показывает текущую тенденцию к снижению.closeБольшеupperBandНапример, если мы считаем, что цена перешла в верхнюю сторону, то это означает, что она перешла в другую сторону.directionВ противном случае, он будет по-прежнему установлен на 1 (находящийся в тренде). Таким образом, вы увидите это в стратегии супертенденции.if direction < 0Когда запускается сигнал, делается больше.direction > 0Когда, после запуска сигнала условия пустуют.
pine
superTrend := direction == -1 ? lowerBand : upperBand
[superTrend, direction]
Наконец, в зависимости от направления выбирается конкретный индикатор супертенденции, который возвращает данные о ценах и направлениях.
Стратегия динамического баланса
pine
/*backtest
start: 2021-03-01 00:00:00
end: 2022-09-08 00:00:00
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Binance","currency":"ETH_USDT"}]
args: [["v_input_1",4374],["v_input_2",3],["v_input_3",300],["ZPrecision",0,358374]]
*/
varip balance = input(50000, "balance")
varip stocks = input(0, "stocks")
maxDiffValue = input(1000, "maxDiffValue")
if balance - close * stocks > maxDiffValue and not barstate.ishistory
// more balance , open long
tradeAmount = (balance - close * stocks) / 2 / close
strategy.order("long", strategy.long, tradeAmount)
balance := balance - tradeAmount * close
stocks := stocks + tradeAmount
runtime.log("balance:", balance, ", stocks:", stocks, ", tradeAmount:", tradeAmount)
else if close * stocks - balance > maxDiffValue and not barstate.ishistory
// more stocks , open short
tradeAmount = (close * stocks - balance) / 2 / close
strategy.order("short", strategy.short, tradeAmount)
balance := balance + tradeAmount * close
stocks := stocks - tradeAmount
runtime.log("balance:", balance, ", stocks:", stocks, ", tradeAmount:", tradeAmount)
plot(balance, title="balance value(quoteCurrency)", color=color.red)
plot(stocks*close, title="stocks value(quoteCurrency)", color=color.blue)
Продолжая изучать примеры разработки стратегий в языке Pine, мы рассмотрим стратегию динамического балансирования.BaseCurrency(Трансферный сорт) иQuoteCurrencyЕсли относительная цена какого-либо актива повышается, а стоимость, хранящаяся в счете, увеличивается, то какой актив продается. Если относительная цена какого-либо актива снижается, а стоимость, хранящаяся в счете, уменьшается, то такой актив покупается. Это называется стратегией динамического равновесия.
Недостатком является то, что, как показано на диаграмме отсчета этой стратегии, в фазе большого роста цены (или большого падения) эта стратегия имеет большие убытки. Поэтому эта стратегия хороша для текущей стратегии, а использование на фьючерсах требует хорошего контроля риска.
Давайте посмотрим на стратегию разработки кода:
Мы использовали упрощенный дизайн, чтобы имитировать в стратегииbalance(то есть количество активов QuoteCurrency) иstocks(И.е. количество активов BaseCurrency) балансовая информация. Мы не читаем реальное количество активов в счетах, мы просто используем имитированную сумму, чтобы рассчитать подходящие покупки и продажи.maxDiffValueЭто параметр является критерием для балансировки.BaseCurrencyиQuoteCurrencyСклонность превышаетmaxDiffValueИменно тогда мы сможем сбалансировать, продать высокоценные активы, купить низкоценные, чтобы сбалансировать их.
Сигналы стратегических сделок должны быть сделаны в режиме реального времени, чтобы иметь смысл, поэтому условия стратегических сделок установлены в решении ifnot barstate.ishistory◦ По текущим ценам,balanceСтоимость превышаетstocksПокупка при стоимости. Продажа при стоимости. Обновление после исполнения сделки.balanceиstocksПеременная, а затем ожидание следующего сбалансированного срабатывания.
Информация, приведенная выше, содержит цены на сорта, которые были в начале отсчета, и их цена была 1458, поэтому я специально установил параметрыbalanceВ качестве: 43741458*3), параметры настройкиstocksДля: 3. Пусть активы находятся в начале в состоянии равновесия.
Стратегия супертенденции с отслеживанием и остановкой убытков
В предыдущих уроках мы изучалиstrategy.exitФункция выхода из позиции, в которой есть функция отслеживания и остановки убытков.strategy.exitФункция отслеживает и останавливает убытки, чтобы оптимизировать стратегию супертенденции.
Сначала давайте посмотрим.strategy.exitФункция следить за параметрами остановки ущерба:
1、trail_priceПараметры: местоположение, которое вызвало логическое действие размещения стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стоп-стопстоп-стопстопстоп-стопстопстопстопстопстопстопстопсто
2、trail_offsetПараметр: расстояние между размещенной позицией и наивысшей ценой (в случае повышения) или наименьшей ценой (в случае понижения) после выполнения действия стоп-стоп.
3、trail_pointsПараметры:trail_priceПараметры, только в том случае, если местоположение определено с помощью числа преимуществ.
Если это трудно понять, это неважно! Давайте посмотрим на это с помощью стратегии, опирающейся на сценарии, которые, на самом деле, очень просты.
pine
/*backtest
start: 2022-09-23 00:00:00
end: 2022-09-23 08:00:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Binance","currency":"ETH_USDT"}]
args: [["RunMode",1,358374],["ZPrecision",0,358374]]
*/
strategy("test", overlay = true)
varip a = na
varip highPrice = na
varip isTrade = false
varip offset = 30
if not barstate.ishistory and not isTrade
strategy.entry("test 1", strategy.long, 1)
strategy.exit("exit 1", "test 1", 1, trail_price=close+offset, trail_offset=offset)
a := close + offset
runtime.log("每点价格为:", syminfo.mintick, ",当前close:", close)
isTrade := true
if close > a and not barstate.ishistory
highPrice := na(highPrice) ? close : highPrice
highPrice := close > highPrice ? close : highPrice
plot(a, "trail_price 触发线")
plot(strategy.position_size>0 ? highPrice : na, "当前最高价")
plot(strategy.position_size>0 ? highPrice-syminfo.mintick*offset : na, "移动止损触发线")
При запуске стратегии сразу же начинается многоголовое вхождение, а затем сразу же следующееstrategy.exitВыходный заказ ((указан параметр стоп-стоп для отслеживания убытков), когда изменение цены на рынке повышается выше триггерной линии trail_price, начинается выполнение логики стоп-стоп-стоп для отслеживания убытков, стоп-стоп-стоп линия ((голубая) начинает следовать за максимальной динамикой ценовой корректировки, расположение голубой линии - это цена, на которой стоп-стоп-стоп вызывает выравнивание, и, наконец, когда изменение цены на рынке снижается ниже голубой линии, то это вызывает выравнивание.
Мы используем эту функцию, чтобы оптимизировать стратегию супер-тренда, мы просто даем ей входный заказ.strategy.exitВ программе выхода можно добавить функцию отслеживания и предотвращения повреждений.
pine
if not barstate.ishistory and findOrderIdx("open") >= 0 and state == 1
trail_price := strategy.position_size > 0 ? close + offset : close - offset
strategy.exit("exit", "open", 1, trail_price=trail_price, trail_offset=offset)
runtime.log("每点价格为:", syminfo.mintick, ",当前close:", close, ",trail_price:", trail_price)
state := 2
tradeBarIndex := bar_index
Полный код стратегии:
pine
/*backtest
start: 2022-05-01 00:00:00
end: 2022-09-27 00:00:00
period: 1d
basePeriod: 5m
exchanges: [{"eid":"Binance","currency":"ETH_USDT"}]
args: [["RunMode",1,358374],["ZPrecision",0,358374]]
*/
varip trail_price = na
varip offset = input(50, "offset")
varip tradeBarIndex = 0
// 0 : idle , 1 current_open , 2 current_close
varip state = 0
findOrderIdx(idx) =>
ret = -1
if strategy.opentrades == 0
ret
else
for i = 0 to strategy.opentrades - 1
if strategy.opentrades.entry_id(i) == idx
ret := i
break
ret
if strategy.position_size == 0
trail_price := na
state := 0
[superTrendPrice, dir] = ta.supertrend(input(2, "atr系数"), input(20, "atr周期"))
if ((dir[1] < 0 and dir[2] > 0) or (superTrendPrice[1] > superTrendPrice[2])) and state == 0 and tradeBarIndex != bar_index
strategy.entry("open", strategy.long, 1)
state := 1
else if ((dir[1] > 0 and dir[2] < 0) or (superTrendPrice[1] < superTrendPrice[2])) and state == 0 and tradeBarIndex != bar_index
strategy.entry("open", strategy.short, 1)
state := 1
// 反向信号,全平
if strategy.position_size > 0 and dir[2] < 0 and dir[1] > 0
strategy.cancel_all()
strategy.close_all()
runtime.log("趋势反转,多头全平")
else if strategy.position_size < 0 and dir[2] > 0 and dir[1] < 0
strategy.cancel_all()
strategy.close_all()
runtime.log("趋势反转,空头全平")
if not barstate.ishistory and findOrderIdx("open") >= 0 and state == 1
trail_price := strategy.position_size > 0 ? close + offset : close - offset
strategy.exit("exit", "open", 1, trail_price=trail_price, trail_offset=offset)
runtime.log("每点价格为:", syminfo.mintick, ",当前close:", close, ",trail_price:", trail_price)
state := 2
tradeBarIndex := bar_index
plot(superTrendPrice, "superTrendPrice", color=dir>0 ? color.red : color.green, overlay=true)
- 1




















