RSI Trend Following Strategy with Trailing Stop Loss (Тенденция RSI в соответствии со стратегией с последующим остановкой потери)

Автор:Чао Чжан, Дата: 2023-12-08 11:41:31
Тэги:

img

Обзор

Эта стратегия представляет собой автоматизированную торговую стратегию, которая идентифицирует тренд с помощью индикатора RSI и подтверждает тренд с помощью скользящих средних значений, с установкой стоп-лосса и прибыли. Она длится, когда RSI превышает 68 и текущая скользящая средняя пересекает предыдущую скользящую среднюю, и становится короткой, когда RSI падает ниже 28 и текущая скользящая средняя пересекает предыдущую скользящую среднюю.

Логика стратегии

Стратегия в основном использует индикатор RSI для выявления условий перекупа и перепродажи для определения тренда. Значения выше 70 для RSI указывают на перекупленное состояние, а значения ниже 30 указывают на перепроданное состояние.

Длинный сигнал: RSI выходит выше 68 и текущая скользящая средняя пересекает предыдущую скользящую среднюю, идите длинный.
Короткий сигнал: RSI опускается ниже 28 и текущая скользящая средняя пересекает предыдущую скользящую среднюю, переходит в короткий.

Настройки стоп-лосса и прибыли распределены, от более свободных до более строгих:

Долгое получение прибыли: получение прибыли 50% позиции на 1,4% выше максимума, получение прибыли 100% на 0,8% выше максимума.
Длинный стоп-лосс: установить стоп-лосс на 2% ниже входной цены.

Короткий прибыль: прибыль 50% позиции на 0,4% ниже минимума, прибыль 100% на 0,8% ниже минимума. Короткий стоп-лосс: установить стоп-лосс на 2% выше входной цены.

Кроме того, когда тренд переходит в обратную сторону, например, когда RSI падает ниже 30, когда он длинный, закрывайте всю длинную позицию на рынке; когда RSI падает выше 60, когда он короткий, закрывайте всю короткую позицию на рынке.

Преимущества

  1. Используйте RSI для определения перекупленности/перепроданности, чтобы избежать покупки высоко и продажи низко.
  2. Фильтры с скользящими средними для сокращения торгов против основного тренда.
  3. Стремиться к максимизации прибыли.
  4. Более широкая стоп-лосс позволяет некоторое отступление.
  5. Закрытие позиции на основе обратного тренда быстро реагирует на внезапные события.

Риски

  1. Плохая настройка параметров RSI, что приводит к неточным сигналам.
  2. Плохая настройка параметров скользящей средней, что приводит к слабой фильтрации.
  3. Стоп-потеря слишком широкая, что приводит к большим потерям.
  4. Принимать прибыль слишком жестко, оставляя прибыль на столе.
  5. Неточный сигнал обратного движения закрывает позиции излишне.

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

Возможности для расширения

Стратегия может быть еще улучшена:

  1. Добавьте больше фильтров, таких как громкость, чтобы улучшить точность сигнала.
  2. Используйте стоп-лосс для получения прибыли.
  3. Используйте отслеживание для получения прибыли для некоторых выходов, чтобы максимизировать прибыль.
  4. Добавить переключение приборов для использования оптимальных параметров.
  5. Включить стоимость переноса фьючерсов для динамической корректировки остановок.

Заключение

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


// © CRabbit
//@version=5

// Starting with $100 and using 10% of the account per trade
strategy("RSI Template", shorttitle="RSI", overlay=false, initial_capital=100, default_qty_value=10, default_qty_type=strategy.percent_of_equity)

// RSI Indicator
ma(source, length, type) =>
    switch type
        "SMA" => ta.sma(source, length)
        "Bollinger Bands" => ta.sma(source, length)
        "EMA" => ta.ema(source, length)
        "SMMA (RMA)" => ta.rma(source, length)
        "WMA" => ta.wma(source, length)
        "VWMA" => ta.vwma(source, length)

rsiLengthInput = input.int(4, minval=1, title="RSI Length", group="RSI Settings")
rsiSourceInput = input.source(close, "Source", group="RSI Settings")
maTypeInput = input.string("SMA", title="MA Type", options=["SMA", "Bollinger Bands", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group="MA Settings")
maLengthInput = input.int(23, title="MA Length", group="MA Settings")
bbMultInput = input.float(2.0, minval=0.001, maxval=50, title="BB StdDev", group="MA Settings")

up = ta.rma(math.max(ta.change(rsiSourceInput), 0), rsiLengthInput)
down = ta.rma(-math.min(ta.change(rsiSourceInput), 0), rsiLengthInput)
rsi = down == 0 ? 100 : up == 0 ? 0 : 100 - (100 / (1 + up / down))
rsiMA = ma(rsi, maLengthInput, maTypeInput)
isBB = maTypeInput == "Bollinger Bands"

plot(rsi, "RSI", color=#7E57C2)
plot(rsiMA, "RSI-based MA", color=color.green)
rsiUpperBand = hline(70, "RSI Upper Band", color=#787B86)
hline(50, "RSI Middle Band", color=color.new(#787B86, 50))
rsiLowerBand = hline(30, "RSI Lower Band", color=#787B86)
fill(rsiUpperBand, rsiLowerBand, color=color.rgb(126, 87, 194, 90), title="RSI Background Fill")


// Configure backtest start date with inputs
startDate = input.int(title="Start Date", defval=1, minval=1, maxval=31)
startMonth = input.int(title="Start Month", defval=6, minval=1, maxval=12)
startYear = input.int(title="Start Year", defval=2022, minval=1800, maxval=2100)

// See if this bar's time happened on/after start date
afterStartDate = (time >= timestamp(syminfo.timezone,
     startYear, startMonth, startDate, 0, 0))


// Long and Short buy strategy
// Submit a market open/ close Long order, but only on/after start date
if (afterStartDate)
    if rsi > 68 and (rsiMA > rsiMA[1])
        strategy.entry("Long Order", strategy.long, comment="ENTER-LONG")
    if rsi < 30
        strategy.close("Long Order", alert_message="L-CL")

strategy.exit("L-TP1", from_entry="Long Order", limit=high * 1.004, qty_percent=50, alert_message="L-TP1" + str.tostring(high * 1.004))
strategy.exit("L-TP2", from_entry="Long Order", limit=high * 1.008, qty_percent=100, alert_message="L-TP2" + str.tostring(high * 1.008))
strategy.exit("Exit Long", from_entry="Long Order", stop=low * 0.98, alert_message="L-SL" + str.tostring(low * 0.98))        


// Submit a market Open/ Close Short order, but only on/after start date
if (afterStartDate)
    if rsi < 28 and (rsiMA < rsiMA[1])
        strategy.entry("Short Order", strategy.short, comment="ENTER-SHORT")
    if rsi > 60
        strategy.close("Short Order", alert_message="S-CL")    

strategy.exit("S-TP1", from_entry="Short Order", limit=low * 0.996, qty_percent=50, alert_message="S-TP1" + str.tostring(low * 0.996))
strategy.exit("S-TP2", from_entry="Short Order", limit=low * 0.992, qty_percent=100, alert_message="S-TP2" + str.tostring(low * 0.992))
strategy.exit("Exit Short", from_entry="Short Order", stop=high * 1.02, alert_message="S-SL" + str.tostring(high * 1.02))

// MONTHLY TABLE //

prec      = input(2, title = "Return Precision")

new_month = month(time) != month(time[1])
new_year  = year(time)  != year(time[1])

eq = strategy.equity

bar_pnl = eq / eq[1] - 1

cur_month_pnl = 0.0
cur_year_pnl  = 0.0

// Current Monthly P&L
cur_month_pnl := new_month ? 0.0 : 
                 (1 + cur_month_pnl[1]) * (1 + bar_pnl) - 1 

// Current Yearly P&L
cur_year_pnl := new_year ? 0.0 : 
                 (1 + cur_year_pnl[1]) * (1 + bar_pnl) - 1  

// Arrays to store Yearly and Monthly P&Ls
var month_pnl  = array.new_float(0)
var month_time = array.new_int(0)

var year_pnl  = array.new_float(0)
var year_time = array.new_int(0)

if (not na(cur_month_pnl[1]) and (new_month or barstate.islast))
    array.push(month_pnl , cur_month_pnl[1])
    array.push(month_time, time[1])

if (not na(cur_year_pnl[1]) and (new_year or barstate.islast))
    array.push(year_pnl , cur_year_pnl[1])
    array.push(year_time, time[1])

// Monthly P&L Table    
var monthly_table = table(na)

if (barstate.islast)
    monthly_table := table.new(position.bottom_right, columns = 14, rows = array.size(year_pnl) + 1, border_width = 1)

    table.cell(monthly_table, 0,  0, "",     bgcolor = #cccccc)
    table.cell(monthly_table, 1,  0, "Jan",  bgcolor = #cccccc)
    table.cell(monthly_table, 2,  0, "Feb",  bgcolor = #cccccc)
    table.cell(monthly_table, 3,  0, "Mar",  bgcolor = #cccccc)
    table.cell(monthly_table, 4,  0, "Apr",  bgcolor = #cccccc)
    table.cell(monthly_table, 5,  0, "May",  bgcolor = #cccccc)
    table.cell(monthly_table, 6,  0, "Jun",  bgcolor = #cccccc)
    table.cell(monthly_table, 7,  0, "Jul",  bgcolor = #cccccc)
    table.cell(monthly_table, 8,  0, "Aug",  bgcolor = #cccccc)
    table.cell(monthly_table, 9,  0, "Sep",  bgcolor = #cccccc)
    table.cell(monthly_table, 10, 0, "Oct",  bgcolor = #cccccc)
    table.cell(monthly_table, 11, 0, "Nov",  bgcolor = #cccccc)
    table.cell(monthly_table, 12, 0, "Dec",  bgcolor = #cccccc)
    table.cell(monthly_table, 13, 0, "Year", bgcolor = #999999)


    for yi = 0 to array.size(year_pnl) - 1
        table.cell(monthly_table, 0,  yi + 1, str.tostring(year(array.get(year_time, yi))), bgcolor = #cccccc)
        
        y_color = array.get(year_pnl, yi) > 0 ? color.new(color.green, transp = 50) : color.new(color.red, transp = 50)
        table.cell(monthly_table, 13, yi + 1, str.tostring(math.round(array.get(year_pnl, yi) * 100, prec)), bgcolor = y_color)
        
    for mi = 0 to array.size(month_time) - 1
        m_row   = year(array.get(month_time, mi))  - year(array.get(year_time, 0)) + 1
        m_col   = month(array.get(month_time, mi)) 
        m_color = array.get(month_pnl, mi) > 0 ? color.new(color.green, transp = 70) : color.new(color.red, transp = 70)
        
        table.cell(monthly_table, m_col, m_row, str.tostring(math.round(array.get(month_pnl, mi) * 100, prec)), bgcolor = m_color)      


Больше