RSI와 가중 이동 평균을 기반으로 한 추세 추종 전략


생성 날짜: 2023-12-25 13:28:24 마지막으로 수정됨: 2023-12-25 13:28:24
복사: 0 클릭수: 712
avatar of ChaoZhang ChaoZhang
1
집중하다
1621
수행원

RSI와 가중 이동 평균을 기반으로 한 추세 추종 전략

개요

이 전략은 두 개의 유명한 지표에 기반합니다: 상대적으로 약한 지표 ((RSI) 와 중화 이동 평균 ((Weighted Moving Average, WMA), 시장 추세를 식별하고 그 방향을 추적합니다. RSI는 과매매를 판단하기 위해 사용되며, WMA는 가격 추세를 판단하기 위해 사용되며, 두 가지의 조합은 관련없는 신호를 효과적으로 필터링하여 수익을 올릴 수 있습니다.

전략 원칙

RSI 지표

RSI는 가장 널리 알려진 과매매 과매매 지표 중 하나입니다.

\[RSI = 100 - \frac{100}{1+\frac{AvgGain}{AvgLoss}}\]

여기서 AvgGain은 일정 기간 동안 개시 가격보다 클로즈 가격이 높은 날의 클로즈 가격의 합으로 나누는 날 수, AvgLoss은 개시 가격보다 클로즈 가격이 낮은 날의 클로즈 가격의 절대값의 합으로 나누는 날 수이다.

이 전략은 RSI 주기를 20로 설정하여 트렌드를 판단하는 지표로 사용한다. RSI가 60보다 크면 멀티 헤드 신호가 발생하고, 40보다 작으면 공백 신호가 발생한다.

무게 이동 평균 (WMA)

WMA는 SMA에 비해 근래 가격 조정에 더 강하다. 계산 공식은 다음과 같다:

\[WMA = \frac{\sum_{i=1}^n w_i x_i}{\sum_{i=1}^n w_i}\]

w는 가중치이며, i가 증가함에 따라 w는 지수적으로 증가한다. 이 전략에서 사용하는 가중치 공식은 다음과 같다.

\[w = \begin{cases} 100/(4+(n-4)*1.3), & i <= 3 \ 1.3*w, & i > 3 \end{cases}\]

즉, 최근 3일의 무게는 동일하고, 그 후 1일 전의 무게는 1.3배 증가한다. 이것은 최근 가격의 영향을 강조할 수 있다.

이 전략에서는 WMA의 기간은 20일이다.

전략적 신호

멀티 헤드 신호: RSI > 60 그리고 WMA 20일 ROC <-1
공백 신호: RSI < 40 그리고 WMA 20 일 ROC > 1

WMA의 20일 ROC의 계산 공식은 다음과 같다.

\[ROC = (WMA_{오늘}/WMA_{20일 전} - 1) \times 100\]

전략적 이점

  • RSI를 통해 트렌드 방향을 파악하고, 흔들리는 시장에서 자금을 소모하지 마십시오.
  • WMA는 최근 소음 감축에 대한 주요 추세를 평가합니다.
  • RSI와 WMA ROC 결합으로 사용되어 무관한 신호를 효과적으로 필터링할 수 있다.
  • 다수의 ATR 무작위 정지, 추적 정지로 수익을 유연하게 고정할 수 있습니다.
  • 자금 관리 방법은 이익과 손실에 따라 포지션 규모를 조정하고 위험을 제어 할 수 있습니다.

전략적 위험

  • 잘못된 전략 매개 변수는 거래 빈도를 높일 수 있으며 최적화 매개 변수는 권장됩니다.
  • 부적절한 스톱포인트 설정으로 손실이 커질 수 있습니다.
  • 트렌드 추적 전략으로 쓰이는 것은 좋지 않습니다.
  • 대폭적인 환경변화에 주의를 기울이고 필요한 경우 수동으로 평정해야 한다.

전략 최적화 방향

  • RSI 길이, WMA 길이, ROC 절댓값을 테스트하여 최적의 변수 조합을 찾습니다.
  • 다양한 재원 관리 방법을 테스트하여 최적의 포지션 조정 방법을 찾습니다.
  • 다른 지표들을 추가하여 더 많은 신호를 필터링합니다.
  • 단독 손실의 위험을 줄이기 위한 손해 방지 전략과 결합
  • 트렌드에서 최대한의 수익을 올리기 위한 최적화 전략

요약하다

이 전략은 RSI와 WMA 두 지표를 종합적으로 사용하여 트렌드 방향을 판단하여 중장선으로 주요 트렌드의 이익을 취한다. 동시에 자본 관리 및 중지 전략의 위험을 제어하는 것은 실제 전쟁에 약간의 가치가 있다. 그러나 매개 변수 설정 및 중단 메커니즘은 더 나은 효과를 얻기 위해 지속적으로 테스트 및 최적화가 필요합니다. 투자자는 실제 시장에서 시기를 검토하고 필요한 경우 수동으로 개입하여 항상 위험을 제어 할 수 있도록 권장한다.

전략 소스 코드
/*backtest
start: 2022-12-24 00:00:00
end: 2023-12-06 05:20:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © gsanson66


//This code is based on RSI and a backed weighted MA
//@version=5
strategy("RSI + MA BACKTESTING", overlay=true, initial_capital=1000, default_qty_type=strategy.fixed, commission_type=strategy.commission.percent, commission_value=0.18, slippage=3)


//------------------------TOOL TIPS---------------------------//

t1 = "Choice between a Standard MA (SMA) or a backed-weighted MA (RWMA) which permits to minimize the impact of short term reversal. Default is RWMA."
t2 = "Value of RSI to send a LONG or a SHORT signal. RSI above 60 is a LONG signal and RSI below 40 is a SHORT signal."
t3 = "Rate of Change Value of selected MA to send a LONG or a SHORT signal. By default : ROC MA below -1 is a LONG signal and ROC MA above 1 is a SHORT signal"
t4 = "Threshold value to trigger trailing Take Profit. This threshold is calculated as a multiple of the ATR (Average True Range)."
t5 = "Percentage value of trailing Take Profit. This Trailing TP follows the profit if it increases, remaining selected percentage below it, but stops if the profit decreases."
t6 = "Each gain or losse (relative to the previous reference) in an amount equal to this fixed ratio will change quantity of orders."
t7 = "The amount of money to be added to or subtracted from orders once the fixed ratio has been reached."


//------------------------FUNCTIONS---------------------------//

//@function which calculate a retro weighted moving average to minimize the impact of short term reversal
rwma(source, length) =>
    sum = 0.0
    denominator = 0.0
    weight = 0.0
    weight_x = 100/(4+(length-4)*1.30)
    weight_y = 1.30*weight_x
    for i=0 to length - 1
        if i <= 3
            weight := weight_x
        else
            weight := weight_y
        sum := sum + source[i] * weight
        denominator := denominator + weight
    rwma = sum/denominator

//@function which permits the user to choose a moving average type
ma(source, length, type) =>
    switch type
        "SMA" => ta.sma(source, length)
        "RWMA" => rwma(source, length)

//@function Displays text passed to `txt` when called.
debugLabel(txt, color) =>
    label.new(bar_index, high, text = txt, color=color, style = label.style_label_lower_right, textcolor = color.black, size = size.small)

//@function which looks if the close date of the current bar falls inside the date range
inBacktestPeriod(start, end) => (time >= start) and (time <= end)


//--------------------------------USER INPUTS-------------------------------//

//Technical parameters
rsiLengthInput = input.int(20, minval=1, title="RSI Length", group="RSI Settings")
maTypeInput = input.string("RWMA", title="MA Type", options=["SMA", "RWMA"], group="MA Settings", inline="1", tooltip=t1)
maLenghtInput = input.int(20, minval=1, title="MA Length", group="MA Settings", inline="1")
rsiLongSignalValue = input.int(60, minval=1, maxval=99, title="RSI Long Signal", group="Strategy parameters", inline="3")
rsiShortSignalValue = input.int(40, minval=1, maxval=99, title="RSI Short Signal", group="Strategy parameters", inline="3", tooltip=t2)
rocMovAverLongSignalValue = input.float(-1, maxval=0, title="ROC MA Long Signal", group="Strategy parameters", inline="4")
rocMovAverShortSignalValue = input.float(1, minval=0, title="ROC MA Short Signal", group="Strategy parameters", inline="4", tooltip=t3)
//TP Activation and Trailing TP
takeProfitActivationInput = input.float(5, minval=1.0, title="TP activation in multiple of ATR", group="Strategy parameters", tooltip=t4)
trailingStopInput = input.float(3, minval=0, title="Trailing TP in percentage", group="Strategy parameters", tooltip=t5)
//Money Management
fixedRatio = input.int(defval=400, minval=1, title="Fixed Ratio Value ($)", group="Money Management", tooltip=t6)
increasingOrderAmount = input.int(defval=200, minval=1, title="Increasing Order Amount ($)", group="Money Management", tooltip=t7)
//Backtesting period
startDate = input(title="Start Date", defval=timestamp("1 Jan 2018 00:00:00"), group="Backtesting Period")
endDate = input(title="End Date", defval=timestamp("1 July 2024 00:00:00"), group="Backtesting Period")


//------------------------------VARIABLES INITIALISATION-----------------------------//

float rsi = ta.rsi(close, rsiLengthInput)
float ma = ma(close, maLenghtInput, maTypeInput)
float roc_ma = ((ma/ma[maLenghtInput]) - 1)*100
float atr = ta.atr(20)
var float trailingStopOffset = na
var float trailingStopActivation = na
var float trailingStop = na
var float stopLoss = na
var bool long = na
var bool short = na
var bool bufferTrailingStopDrawing = na
float theoreticalStopPrice = na
bool inRange = na
equity = math.abs(strategy.equity - strategy.openprofit)
strategy.initial_capital = 50000
var float capital_ref = strategy.initial_capital
var float cashOrder = strategy.initial_capital * 0.95


//------------------------------CHECKING SOME CONDITIONS ON EACH SCRIPT EXECUTION-------------------------------//

//Checking if the date belong to the range
inRange := true

//Checking performances of the strategy
if equity > capital_ref + fixedRatio
    spread = (equity - capital_ref)/fixedRatio
    nb_level = int(spread)
    increasingOrder = nb_level * increasingOrderAmount
    cashOrder := cashOrder + increasingOrder
    capital_ref := capital_ref + nb_level*fixedRatio
if equity < capital_ref - fixedRatio
    spread = (capital_ref - equity)/fixedRatio
    nb_level = int(spread)
    decreasingOrder = nb_level * increasingOrderAmount
    cashOrder := cashOrder - decreasingOrder
    capital_ref := capital_ref - nb_level*fixedRatio

//Checking if we close all trades in case where we exit the backtesting period
if strategy.position_size!=0 and not inRange
    debugLabel("END OF BACKTESTING PERIOD : we close the trade", color=color.rgb(116, 116, 116))
    strategy.close_all()
    bufferTrailingStopDrawing := false
    stopLoss := na
    trailingStopActivation := na
    trailingStop := na
    short := false
    long := false


//------------------------------STOP LOSS AND TRAILING STOP ACTIVATION----------------------------//

// We handle the stop loss and trailing stop activation 
if (low <= stopLoss or high >= trailingStopActivation) and long
    if high >= trailingStopActivation
        bufferTrailingStopDrawing := true
    else if low <= stopLoss
        long := false
    stopLoss := na
    trailingStopActivation := na
if (low <= trailingStopActivation or high >= stopLoss) and short
    if low <= trailingStopActivation
        bufferTrailingStopDrawing := true
    else if high >= stopLoss
        short := false
    stopLoss := na
    trailingStopActivation := na


//-------------------------------------TRAILING STOP--------------------------------------//

// If the traling stop is activated, we manage its plotting with the bufferTrailingStopDrawing
if bufferTrailingStopDrawing and long
    theoreticalStopPrice := high - trailingStopOffset * syminfo.mintick
    if na(trailingStop)
        trailingStop := theoreticalStopPrice
    else if theoreticalStopPrice > trailingStop
        trailingStop := theoreticalStopPrice
    else if low <= trailingStop
        trailingStop := na
        bufferTrailingStopDrawing := false
        long := false
if bufferTrailingStopDrawing and short
    theoreticalStopPrice := low + trailingStopOffset * syminfo.mintick
    if na(trailingStop)
        trailingStop := theoreticalStopPrice
    else if theoreticalStopPrice < trailingStop
        trailingStop := theoreticalStopPrice
    else if high >= trailingStop
        trailingStop := na
        bufferTrailingStopDrawing := false
        short := false


//---------------------------------LONG CONDITION--------------------------//

if rsi >= 60 and roc_ma <= rocMovAverLongSignalValue and inRange and not long
    if short
        bufferTrailingStopDrawing := false
        stopLoss := na
        trailingStopActivation := na
        trailingStop := na
        short := false
    trailingStopActivation := close + takeProfitActivationInput*atr
    trailingStopOffset := (trailingStopActivation * trailingStopInput/100) / syminfo.mintick
    stopLoss := close - 3*atr
    long := true
    qty = cashOrder/close
    strategy.entry("Long", strategy.long, qty)
    strategy.exit("Exit Long", "Long", stop = stopLoss, trail_price = trailingStopActivation,
                 trail_offset = trailingStopOffset)


//--------------------------------SHORT CONDITION-------------------------------//

if rsi <= 40 and roc_ma >= rocMovAverShortSignalValue and inRange and not short
    if long
        bufferTrailingStopDrawing := false
        stopLoss := na
        trailingStopActivation := na
        trailingStop := na
        long := false
    trailingStopActivation := close - takeProfitActivationInput*atr
    trailingStopOffset := (trailingStopActivation * trailingStopInput/100) / syminfo.mintick
    stopLoss := close + 3*atr
    short := true
    qty = cashOrder/close
    strategy.entry("Short", strategy.short, qty)
    strategy.exit("Exit Short", "Short", stop = stopLoss, trail_price = trailingStopActivation,
                 trail_offset = trailingStopOffset)


//--------------------------------PLOTTING ELEMENT---------------------------------//

// Plotting of element in the graph
plotchar(rsi, "RSI", "", location.top, color.rgb(0, 214, 243))
plot(ma, "MA", color.rgb(219, 219, 18))
plotchar(roc_ma, "ROC MA", "", location.top, color=color.orange)
// Visualizer trailing stop and stop loss movement
plot(stopLoss, "SL", color.red, 3, plot.style_linebr)
plot(trailingStopActivation, "Trigger Trail", color.green, 3, plot.style_linebr)
plot(trailingStop, "Trailing Stop",  color.blue, 3, plot.style_linebr)