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

Давайте погрузимся в процесс, для начала у вас должна быть учетная запись в TradingView. Затем создайте новый макет диаграммы. В этом проекте я буду использовать таймфрейм 2H и криптовалютную пару BITMEX: XBTUSD.

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

Если вы пытались кодировать стратегию, которую читали в Интернете, вы бы знали, что большую часть времени (если не все) тестирование на истории выглядит разочаровывающим. Однако все, что вы читаете, хранится в нашем мозгу, и однажды одна из этих вещей станет полезной. Затем добавьте код к тому, что вы читаете, и это укрепит полученные знания. Чем больше вы исследуете, тем больше ваш разум начинает связывать точки всего, что вы обработали, и тогда начинают течь оригинальные идеи. Это награда за долгие часы попыток создать окончательную стратегию.

Когда у нас появляется идея, мы открываем «Pine Editor». В моем случае я вспомнил, что это был термин с буквой «w», состоящий из 4 букв, и все, это была очень расплывчатая идея, и поиск решения стал очень интересным.

Одной из лучших функций TradingView является его «Справочное руководство по языку сценариев Pine», если вы наводите курсор на любой из его операторов или встроенных переменных / функций; в этом случае слово «закрыть», которое содержит текущую цену закрытия ценной бумаги для указанной свечи или бара, тогда вы можете увидеть, какие клавиши нужно нажать, чтобы открыть его, в зависимости от вашей операционной системы.

Там вы можете найти конкретный термин или прочитать все и поэкспериментировать. В этом случае я искал «w», а по нему нашел «SWMA». Прочитав, что это было, я понял, что это не тот, который я искал, но поскольку он использует короткий взгляд назад, длину или период (количество столбцов, которые вы хотите, чтобы индикатор заглядывал в прошлое, чем выше, тем меньше шум, но и еще больше лагов) Я подумал, что попробую. После кодирования он должен выглядеть, как показано ниже.

//@version=4
study("My Script")
swmaClose = swma(close)
plot(close)

Обратите внимание, что я создал только переменную с именем «swmaClose» и присвоил ей значение «swma (close)». Для тех, кто новичок в программировании, я думаю, что одна из самых страшных вещей - это то, насколько подавляющим является кодирование в более широкой картине, когда весь код готов и остается много-много строк. Я усвоил одну вещь: какой бы сложной ни была программа, все начинается с одной строчки кода. Итак, когда дело доходит до программирования, все, на чем вы должны сосредоточиться, - это линия, на которую вы смотрите.

Чтобы увидеть, что код делает на диаграмме, нажмите «Добавить в диаграмму».

Там вы увидите, что делает приведенный выше код.

Не совсем то, что мы имели в виду, мы хотим, чтобы код в это время распечатал «swmaClose» рядом с ценой. Для этого мы должны внести несколько изменений. Помните «Справочное руководство по языку сценариев Pine»?

Чтобы скрипт отображался рядом с ценой, мы должны изменить значение «overlay» на значение «true».

study(“My Script”, overlay = true)

Чтобы скрипт выводил значение «swmaClose», мы должны заменить на него «close» в функции «plot ()».

plot(swmaClose)

Теперь наш код выглядит так.

//@version=4
study(“My Script”, overlay = true)
swmaClose = swma(close)
plot(swmaClose)

Итак, нам удалось достичь нашей первоначальной цели, однако мы замечаем, что едва ли можем увидеть значение «swmaClose». Если мы посмотрим на «plot ()», мы сможем понять, почему.

Таким образом, мы можем изменить «цвет», «ширину линии» и «прозрачность» в «Pine Editor», и мы получим лучшее представление о графике.

plot(swmaClose, color = color.red, linewidth = 4, transp = 0)

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

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

Прежде чем я вам это покажу, давайте добавим фактическую переменную, которую я хотел в начале этой идеи. Куда нам его найти?

Давайте объявим «vwapClose» и присвоим значение «vwap (close)».

vwapClose = vwap(close)

Обратите внимание, что основной «VWAP» использует «HLC3» (максимум, минимум и закрытие, разделенные на три). Я выбрал серию источников «close», потому что она меньше лагает.

Давайте теперь погрузимся в подход к цветам. Я создал две новые переменные: «swmaLong» и «vwapLong». Оба сравнивают цену («закрытие») со своим значением, идея в том, что когда цена выше каждого из них, она будет иметь тенденцию к росту.

swmaLong = close > swmaClose
vwapLong = close > vwapClose

Чтобы доказать теорию, давайте воспользуемся функцией «bgcolor ()», чтобы запомнить, что она означает, попробуйте думать о ней как о цвете фона.

Мы хотим, чтобы если условие истинно, то отображать цвет X, иначе цвет Y.

bgcolor(swmaLong ? color.blue : na)
bgcolor(vwapLong ? color.orange : na)

Чтобы узнать больше о тернарном условном операторе (? :)

Итак, после удаления функции «plot ()» добавляем новые переменные «… Long» и добавляем «bgcolor ()». Наш скрипт пока должен выглядеть так.

//@version=4
study(“My Script”, overlay = true)
swmaClose = swma(close)
vwapClose = vwap(close)
swmaLong = close > swmaClose
vwapLong = close > vwapClose
bgcolor(swmaLong ? color.blue : na)
bgcolor(vwapLong ? color.orange : na)

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

Один будет показывать синий, когда «swmaLong» истинно, а другой оранжевый, когда «vwapLong» истинно. Поэтому нам не нужно удалять какой-либо код, мы можем просто закомментировать строку, как показано ниже. Это заставит скрипт пропустить эту строку и не запустить ее.

Несмотря на то, что оба сценария разбиты на два, у нас все еще есть та же проблема, потому что они перекрывают друг друга.

Решение состоит в том, чтобы изменить «оверлей» на «ложь» в обоих из них.

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

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

A: Синий / оранжевый появляются одновременно.
B: Только оранжевый.
C: Сначала появляется оранжевый, затем синий.

Я решил пойти по сценарию «С». Условия на данный момент:
1- Оранжевый должен появиться в полосе, но не синий.
2- Когда имеет место (1), ни Оранжевый, ни Синий не должны встречаться на панели раньше.

Затем я объявляю переменную с именем «triggerLong» и назначаю условия (1) и (2).

triggerLong = vwapLong and not vwapLong[1] and not swmaLong and not swmaLong[1]

Затем мы проверяем, что он работает правильно, и получаем более четкое представление о правильности наших шаблонов, передавая это значение в новую функцию «bgcolor ()».

bgcolor(triggerLong ? color.purple : na)

Прежде чем мы продолжим, я хочу коснуться темы того, сколько индикаторов нам следует использовать. Чтобы упростить задачу, назовем это «Правило никогда». Никогда не используйте только один, никогда не используйте слишком много. Одно плохо, потому что нам всегда нужно подтверждение, и слишком много, потому что чем больше индикаторов или логики вы используете, тем более строгой / жесткой становится ваша система, результатом этого является более короткий срок службы. Универсальная система является гибкой, что позволяет ей быть устойчивой к рыночным изменениям. Лично я использую два-три индикатора.

Поскольку мы хотим, чтобы наш алгоритм зависел от двух сигналов, нам нужна переменная, которая может сохранять свое состояние, пока она ожидает выполнения другого и последнего условия.

Итак, нам нужно создать новую переменную, которая может сохранять состояние в true, когда происходит «triggerLong» или Purple. Назовем его saveLong.

saveLong = false, saveLong := triggerLong ? true : not vwapLong ? false : saveLong[1]

Что делает «saveLong» - это когда появляется Purple, он становится «true», в то время как Orange все еще происходит, но в тот момент, когда Orange не отображается, он меняется на «false».

Теперь посмотрим, что делает saveLong на графике. Вот как должен выглядеть наш код на данный момент.

//@version=4
study(“My Script”, overlay = false)
swmaClose = swma(close)
vwapClose = vwap(close)
swmaLong = close > swmaClose
vwapLong = close > vwapClose
triggerLong = vwapLong and not vwapLong[1] and not swmaLong and not swmaLong[1]
saveLong = false, saveLong := triggerLong ? true : not vwapLong ? false : saveLong[1]
// bgcolor(swmaLong ? color.blue : na)
// bgcolor(vwapLong ? color.orange : na)
// bgcolor(triggerLong ? color.purple : na)
bgcolor(saveLong ? color.yellow : na)

Обратите внимание, что мы добавили новый «bgcolor ()» и передали значение «saveLong», поэтому, когда оно истинно, желтый цвет будет отображаться на диаграмме.

Наш длинный сигнал на вход почти готов, до сих пор мы работали с Orange, и особые условия, связанные с ним, закодированы в Purple. Оставшаяся часть головоломки добавляет к ней синий цвет. Итак, мы создаем еще одну переменную и называем ее startLong.

startLong = saveLong and swmaLong

Что делает startLong, пока состояние Purple, сохраненное желтым, является истинным, а состояние Blue происходит; затем он, наконец, посылает сигнал на открытие длинной позиции.

Давайте сделаем наш последний «bgcolor ()» и присвоим значение «startLong».

//@version=4
study(“My Script”, overlay = false)
swmaClose = swma(close)
vwapClose = vwap(close)
swmaLong = close > swmaClose
vwapLong = close > vwapClose
triggerLong = vwapLong and not vwapLong[1] and not swmaLong and not swmaLong[1]
saveLong = false, saveLong := triggerLong ? true : not vwapLong ? false : saveLong[1]
startLong = saveLong and swmaLong
// bgcolor(swmaLong ? color.blue : na)
// bgcolor(vwapLong ? color.orange : na)
// bgcolor(triggerLong ? color.purple : na)
// bgcolor(saveLong ? color.yellow : na)
bgcolor(startLong ? color.green : na)

Можете ли вы угадать, какого цвета он будет, если «startLong» верно?

Теперь наша диаграмма будет выглядеть так.

Обратите внимание, сколько шума снижается с добавлением каждой новой строки кода.

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

Следующая часть - как протестировать то, что мы построили. Помните, что наш сценарий во второй строке начинался с учебы (…). Что ж, TradingView предлагает два типа скриптов, изучение и стратегию. У них много различий, но главное из них заключается в том, что вы можете создавать предупреждения в рамках одного исследования, а вы можете тестировать на исторических данных в рамках другого исследования. Есть определенные параметры, которые работают только в рамках стратегии, но все функции исследования работают с первой. Итак, чтобы превратить исследование в стратегию, вы можете просто заменить слово «изучение» словом «стратегия» во второй строке.

Затем давайте добавим новую строку и воспользуемся функцией strategy.entry ().

Закончив с цветами, нам удалось добавить два новых изменения, преобразовав исследование в стратегию и добавив функцию «strategy.entry ()», чтобы TradingView мог принять наш входной сигнал и смоделировать, как он работал бы в прошлом. Ниже наш новый код.

//@version=4
strategy(“My Script”, overlay = true)
swmaClose = swma(close)
vwapClose = vwap(close)
swmaLong = close > swmaClose
vwapLong = close > vwapClose
triggerLong = vwapLong and not vwapLong[1] and not swmaLong and not swmaLong[1]
saveLong = false, saveLong := triggerLong ? true : not vwapLong ? false : saveLong[1]
startLong = saveLong and swmaLong
strategy.entry(“Open Long”, strategy.long, when = startLong)
// bgcolor(swmaLong ? color.blue : na)
// bgcolor(vwapLong ? color.orange : na)
// bgcolor(triggerLong ? color.purple : na)
// bgcolor(saveLong ? color.yellow : na)
bgcolor(startLong ? color.green : na)

Как только мы добавляем его в диаграммы, мы видим, что на самом деле ничего не происходит.

Если мы посмотрим на «Список сделок», мы увидим, что есть только одна сделка, и она все еще открыта.

Как вы, наверное, догадались, условия выхода пока нет, вот почему. Хотя есть много способов создать его, на этот раз я выбрал простой тейк-профит / стоп-лосс.

Обратите внимание, что TradingView предлагает два варианта выхода по риску: указанную вами точную цену и количество тиков от цены входа, зарегистрированной в системе тестирования на исторических данных. Для кодирования рискованных выходов нам понадобится функция «strategy.exit ()».

Поскольку цель этой статьи - выразить простой способ, я выбрал галочки. Мы должны разместить функцию «strategy.exit ()» ниже функции «strategy.entry ()», в то время как нет правила, по которому функция стратегии должна идти первой, поскольку она будет вести себя так же, как я лично выбрал ниже.

strategy.exit(“Exit Long”, “Open Long”, profit = stopLoss, loss = takeProfit)

Как только мы попытаемся добавить его в диаграммы, мы получим следующую ошибку.

К сожалению, мы забыли добавить эти переменные, поэтому давайте сделаем это ниже.

stopLoss = input(250, “Stop Loss”, step = 50)
takeProfit = input(10, “Reward/Risk”) * stopLoss

Там вы видите новую функцию «input ()».

Теперь вы знаете, что делает «input ()», обратите внимание на строку, в которой мы упоминаем «takeProfit»; как мы запрашиваем другой ввод и умножаем на значение «stopLoss». Мы делаем это, чтобы быть в курсе соотношения вознаграждения и риска, что является наиболее эффективным способом добиться успеха в торговле. Теперь наш скрипт должен работать. Если вы немного заблудились, наш код должен выглядеть так, как показано ниже.

//@version=4
strategy("My Script", overlay = true)
swmaClose = swma(close)
vwapClose = vwap(close)
swmaLong = close > swmaClose
vwapLong = close > vwapClose
triggerLong = vwapLong and not vwapLong[1] and not swmaLong and not swmaLong[1]
saveLong = false, saveLong := triggerLong ? true : not vwapLong ? false : saveLong[1]
startLong = saveLong and swmaLong
stopLoss = input(250, "Stop Loss", step = 50)
takeProfit = input(10, "Reward/Risk") * stopLoss
strategy.entry("Open Long", strategy.long, when = startLong)
strategy.exit("Exit Long", "Open Long", profit = stopLoss, loss = takeProfit)
// bgcolor(swmaLong ? color.blue : na)
// bgcolor(vwapLong ? color.orange : na)
// bgcolor(triggerLong ? color.purple : na)
// bgcolor(saveLong ? color.yellow : na)
bgcolor(startLong ? color.green : na)

Наконец-то у нас есть кое-что.

Нам еще предстоит кое-что сделать. Давайте начнем с изменения параметров, которые используются в системе тестирования на исторических данных, чтобы она могла вести себя как торговля в реальном времени.

Ключ к нему находится во второй строке «strategy ()».

После того, как вы прочтете и усвоите основы, я хочу дать вам параметры, которые я лично использую каждый раз. Вы можете заменять значения внутри «title» и «shorttitle» своими новыми каждый раз, когда вы строите новую стратегию.

//@version=4
strategy(title = "Simple Price Momentum", shorttitle = "SPM", overlay = true, initial_capital = 20000, default_qty_value = 100, default_qty_type = strategy.percent_of_equity, commission_value = 0.025)

Если вы сравните показатели между предыдущими и нынешними, вы увидите, что теперь они отражают более реалистичные результаты.

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

В основном, хотя зеленый цвет появляется раньше, сигнал на самом деле имеет место в конце бара. Помните, что «закрытый» источник - это текущая цена, пока свеча все еще формируется, потому что она может изменить свое состояние и может создать ситуацию, когда «A› B », а затем изменится на« A ‹B», поэтому мы не знаем, какой единица - это окончательное значение до тех пор, пока полоса не закончится официально. Вот почему система тестирования на истории открывает позицию в баре после.

Чтобы зеленый совпадал с тестированием на истории, мы можем добавить «[1]» к «startLong» внутри «bgcolor ()».

bgcolor(startLong[1] ? color.green : na)

Тогда это будет выглядеть так, как показано ниже.

Чтобы узнать больше о том, как работают стратегии, прочтите это.

У нас еще осталось одно дело. Вы заметили, что происходит что-то странное?

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

Ниже приведен пример того, как это может быть плохо.

Я решаю эту проблему, вводя логику управления позицией или ордером. Самый простой способ представить это - создать условие, которое гласит: «Разрешить это, когда это верно сейчас, а не в полосе раньше». Мы можем закодировать это следующим образом.

startLong = saveLong and swmaLong
startLong := startLong and not startLong[1]

Чтобы понять, что произошло, см. Ниже.

Теперь, прежде чем тестировать наш новый код, я хочу взять предыдущее правило управления порядком и превратить его во что-то необязательное, используя «input ()».

startLong := input(false, "Consecutive Orders") ? startLong : startLong and not startLong[1]

Теперь у нас больше гибкости в работе нашей торговой системы.

Посмотрите ниже, как, когда параметр «Последовательные заказы» отключен, что означает, что наша логика управления заказами работает, посмотрите, как улучшаются наши результаты, это связано с тем, что нам удалось удалить с помощью этого еще больше шума.

Ну вот и все. Мы успешно создали стратегию с использованием логического подхода, добавили параметры риска и улучшили результаты тестирования на истории.

Наш окончательный сценарий должен быть похож на приведенный ниже.

//@version=4
strategy(title = "Simple Price Momentum", shorttitle = "SPM", overlay = true, initial_capital = 20000, default_qty_value = 100, default_qty_type = strategy.percent_of_equity, commission_value = 0.025)
swmaClose = swma(close)
vwapClose = vwap(close)
swmaLong = close > swmaClose
vwapLong = close > vwapClose
triggerLong = vwapLong and not vwapLong[1] and not swmaLong and not swmaLong[1]
saveLong = false, saveLong := triggerLong ? true : not vwapLong ? false : saveLong[1]
startLong = saveLong and swmaLong
startLong := input(false, "Consecutive Orders") ? startLong : startLong and not startLong[1]
stopLoss = input(250, "Stop Loss", step = 50)
takeProfit = input(10, "Reward/Risk") * stopLoss
strategy.entry("Open Long", strategy.long, when = startLong)
strategy.exit("Exit Long", "Open Long", profit = stopLoss, loss = takeProfit)
// bgcolor(swmaLong ? color.blue : na)
// bgcolor(vwapLong ? color.orange : na)
// bgcolor(triggerLong ? color.purple : na)
// bgcolor(saveLong ? color.yellow : na)
bgcolor(startLong[1] ? color.green : na)

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

Я рекомендую прочитать эти Соглашения о кодировании сосны. Я должен признать, что их не было в наличии, когда я начинал много лет назад, поэтому, хотя я осознаю, что рекомендую их, я должен сам последовать совету; как говорится: Не научишь старую собаку новым трюкам. В любом случае, чем раньше вы начнете правильно учиться, тем лучше. Вы можете посетить PineCoders, чтобы узнать больше и стать разработчиком 10x Pine Script.

Спасибо за чтение, надеюсь, вы не только преуспеете в своей торговой карьере, но и получите от нее удовольствие.