В
прошлый раз вы создавали простую торговую систему для TradingView и самое время улучшить её и внести небольшие изменения, которые позволят вам обгонять рынок там, где остальные трейдеры теряют деньги. Также эта система использует обновлённую версию PineScript v5 — она предполагает незначительные различия в коде.
Идея выглядит так:
1. По-прежнему в основе лежит использование «золотого креста» на дневном таймфрейме для открытия позиций
2. В систему добавляется открытие коротких позиций (шортов)
3. Добавляются стоп-лосс и тейк-профит, но
только для шортов
Сначала инициализируем торговую систему и добавляем две скользящих средних SMA50 и SMA200:
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// This strategy has been created for illustration purposes only and should not be relied upon as a basis for buying, selling, or holding any asset or security.
// © Diamond
//@version=5
strategy('SMA Golden Short Strategy', overlay=true, calc_on_every_tick=false, default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_value=0.04, commission_type=strategy.commission.percent)
//Inputs
smaFast = input.int(title='Fast SMA', defval=50, minval=1)
smaSlow = input.int(title='Slow SMA', defval=200, minval=1)
Добавляем переменные, доступные для настройки пользователем:
//Options to configure backtest trade range
startDate = input.time(title='Start Date', defval=timestamp('01 Jan 1998 00:00'))
endDate = input.time(title='End Date', defval=timestamp('31 Dec 2070 23:59'))
//Calculations
fastSMA = ta.sma(close, smaFast)
slowSMA = ta.sma(close, smaSlow)
Рендерим скользящие поверх графика:
//Plot
plot(series=fastSMA, color=color.new(color.orange, 0), linewidth=2)
plot(series=slowSMA, color=color.new(color.blue, 0), linewidth=3)
Условия трейдинга немного меняются — мы по-прежнему торгуем по пересечениям скользящих средних, но теперь быстрая средняя, пересекающая медленную снизу вверх, называется
longCondition, а обратное условие это
shortCondition:
//Conditions
inDateRange = time >= startDate and time < endDate
longOpenCondition = ta.crossover(fastSMA, slowSMA)
shortOpenCondition = ta.crossunder(fastSMA, slowSMA)
Соответственно, теперь открываются не только длинные, но и короткие позиции. Для более наглядного отображения я добавил на график
label:
//Trading
if longOpenCondition and inDateRange
strategy.entry(id='long', direction=strategy.long, comment=' ')
label.new(bar_index, na, text='Long', size=size.normal, style=label.style_label_up, color=color.blue, textcolor=color.white, yloc=yloc.belowbar)
if shortOpenCondition and inDateRange
strategy.entry(id='short', direction=strategy.short, comment=' ')
label.new(bar_index, na, text='Short', size=size.normal, style=label.style_label_down, color=color.red, textcolor=color.white, yloc=yloc.abovebar)
Добавляем возможность ввода стоп-лосса и тейк-профита для пользователя, которые будут рассчитаны в процентах от средней цены открытой позиции
strategy.position_avg_price. Мы используем эти значения только для шортов, но для ознакомительных целей укажем их ещё и для лонгов.
//Stop Loss / Take Profit
useStopLoss = input(false, title='Use Stop Loss & Take Profit')
sl_inp = input(defval = 1.0, title='Stop Loss %')/100.0
tp_inp = input(defval = 1.5, title='Take Profit %')/100.0
stop_level = strategy.position_avg_price * (1 - sl_inp)
take_level = strategy.position_avg_price * (1 + tp_inp)
stop_level_short = strategy.position_avg_price * (1 + sl_inp)
take_level_short = strategy.position_avg_price * (1 - tp_inp)
И теперь торговая система будет закрывать шорты, если достигнут стоп-лосс или тейк-профит. Код закрытия позиций будет вызываться только в том случае, если выполняется условие
useStopLoss — пользователь должен нажать на чекбокс «Use Stop Loss & Take Profit» в настройках торговой системы. Для корректной работы
strategy.exit() должны совпадать id ранее открытых позиций (в данном случае, id=«long» и id=«short»):
//if useStopLoss and strategy.position_size > 0 and strategy.openprofit > 0
// strategy.exit(id="long", comment = "Take Profit Long +" + str.tostring(math.round(strategy.openprofit)), limit = take_level)
//if useStopLoss and strategy.position_size > 0 and strategy.openprofit < 0
// strategy.exit(id="long", comment = "Stop Loss Long -" + str.tostring(math.round(strategy.openprofit)), stop = stop_level)
if useStopLoss and strategy.position_size < 0 and strategy.openprofit > 0
strategy.exit(id="short", comment = "Take Profit Short +" + str.tostring(math.round(strategy.openprofit)), limit = take_level_short)
if useStopLoss and strategy.position_size < 0 and strategy.openprofit < 0
strategy.exit(id="short", comment = "Stop Loss Short -" + str.tostring(math.round(strategy.openprofit)), stop = stop_level_short)
Окно настроек выглядит так:
Комиссия по умолчанию составляет 0.04% и она учитывается в результатах тестирования, проскальзывание (Slippage) я поставил 0%, но сделок будет немного и оба параметра слабо повлияют на доходность.
Стоп-лосса менее 5% на дневном таймфрейме будет явно недостаточно — он будет часто срабатывать. Слишком большие стоп-лоссы снизят доходность. Тейк-профит лучше ставить более 30%, потому что движения вниз более сильные, чем вверх.
Поскольку в системе есть шорты, нужны такие биржевые инструменты, у которых Buy & Hold с большой вероятностью даёт отрицательную доходность. Например, VTBR (акции банка ВТБ обыкновенные):
Либо AFLT (акции Аэрофлот):
И ещё подойдут акции Русгидро с тикером HYDR:
Более волатильные инструменты вроде IRAO (акции Интер РАО) могут потребовать повышения стоп-лосса и тейк-профита:
Бэктесты на всех этих тикерах дают положительную доходность.
Результат VTBR
+106.88% за 20 трейдов:
Результат AFLT
+2103.92% за 27 трейдов:
Самый скромный результат у HYDR
+23.47% за 18 трейдов:
Результат IRAO
+518.62% за 24 трейда:
Но есть 2 существенных недостатка:
1. Торговая система всегда в рынке, не учтена плата за шорты
2. Большие просадки по 50%, нельзя торговать с плечом
Тем не менее, с помощью простой системы вы получаете дополнительное преимущество перед долгосрочными инвесторами.
Полный исходный код:
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// This strategy has been created for illustration purposes only and should not be relied upon as a basis for buying, selling, or holding any asset or security.
// © Diamond
//@version=5
strategy('SMA Golden Short Strategy', overlay=true, calc_on_every_tick=false, default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_value=0.04, commission_type=strategy.commission.percent)
//Inputs
smaFast = input.int(title='Fast SMA', defval=50, minval=1)
smaSlow = input.int(title='Slow SMA', defval=200, minval=1)
//Options to configure backtest trade range
startDate = input.time(title='Start Date', defval=timestamp('01 Jan 1998 00:00'))
endDate = input.time(title='End Date', defval=timestamp('31 Dec 2070 23:59'))
//Calculations
fastSMA = ta.sma(close, smaFast)
slowSMA = ta.sma(close, smaSlow)
//Plot
plot(series=fastSMA, color=color.new(color.orange, 0), linewidth=2)
plot(series=slowSMA, color=color.new(color.blue, 0), linewidth=3)
//Conditions
inDateRange = time >= startDate and time < endDate
longOpenCondition = ta.crossover(fastSMA, slowSMA)
shortOpenCondition = ta.crossunder(fastSMA, slowSMA)
//Trading
if longOpenCondition and inDateRange
strategy.entry(id='long', direction=strategy.long, comment=' ')
label.new(bar_index, na, text='Long', size=size.normal, style=label.style_label_up, color=color.blue, textcolor=color.white, yloc=yloc.belowbar)
if shortOpenCondition and inDateRange
strategy.entry(id='short', direction=strategy.short, comment=' ')
label.new(bar_index, na, text='Short', size=size.normal, style=label.style_label_down, color=color.red, textcolor=color.white, yloc=yloc.abovebar)
//Stop Loss / Take Profit
useStopLoss = input(false, title='Use Stop Loss & Take Profit')
sl_inp = input(defval = 1.0, title='Stop Loss %')/100.0
tp_inp = input(defval = 1.5, title='Take Profit %')/100.0
stop_level = strategy.position_avg_price * (1 - sl_inp)
take_level = strategy.position_avg_price * (1 + tp_inp)
stop_level_short = strategy.position_avg_price * (1 + sl_inp)
take_level_short = strategy.position_avg_price * (1 - tp_inp)
//if useStopLoss and strategy.position_size > 0 and strategy.openprofit > 0
// strategy.exit(id="long", comment = "Take Profit Long +" + str.tostring(math.round(strategy.openprofit)), limit = take_level)
//if useStopLoss and strategy.position_size > 0 and strategy.openprofit < 0
// strategy.exit(id="long", comment = "Stop Loss Long -" + str.tostring(math.round(strategy.openprofit)), stop = stop_level)
if useStopLoss and strategy.position_size < 0 and strategy.openprofit > 0
strategy.exit(id="short", comment = "Take Profit Short +" + str.tostring(math.round(strategy.openprofit)), limit = take_level_short)
if useStopLoss and strategy.position_size < 0 and strategy.openprofit < 0
strategy.exit(id="short", comment = "Stop Loss Short -" + str.tostring(math.round(strategy.openprofit)), stop = stop_level_short)