모멘텀 오실레이터 스토캐스틱 RSI 거래 전략


생성 날짜: 2023-12-26 12:11:21 마지막으로 수정됨: 2023-12-26 12:11:21
복사: 0 클릭수: 612
avatar of ChaoZhang ChaoZhang
1
집중하다
1621
수행원

모멘텀 오실레이터 스토캐스틱 RSI 거래 전략

개요

이 글은 주로 스토카스틱 RSI 지표에 기반한 동적 흔들림 거래 전략을 설명한다. 이 전략은 더 짧은 주기 (예: 30 분) 의 기술 지표를 채택하고, 스토카스틱 RSI가 초과 구매 초과 판매 영역에 진입했는지에 따라 거래 결정을 한다. 다른 동적 전략에 비해 이 전략은 RSI와 스토카스틱 두 지표의 장점을 동시에 결합하여 시장의 단기 흔들림을 더 정확하게 포착한다.

전략 원칙

이 전략의 핵심 지표는 스토카스틱 RSI이다. 스토카스틱 RSI 지표의 계산 공식은 다음과 같습니다.

RSI는 RSI의 하위 지점과 RSI의 하위 지점 사이의 차이입니다

RSI는 lengthRSI변수 (기본 12) 를 사용하며, Stochastic RSI는 lengthStoch변수 (기본 12) 를 사용한다.

스토카스틱 RSI가 보라색 채우기 영역보다 높을 때 오버 바이 지역으로, 이 때 공백을; 스토카스틱 RSI가 보라색 채우기 영역보다 낮을 때 오버 세 지역으로, 이 때 더 니다.

또한, 전략은 평선 필터링 조건을 설정한다. 빠른 EMA가 느린 EMA보다 높을 때만 포지션을 열 수 있고, 빠른 EMA가 느린 EMA보다 낮을 때만 포지션을 열 수 있다. 이렇게 역동적인 거래를 피할 수 있다.

전략적 이점

단일 RSI 전략에 비해 이 전략은 스토카스틱 지표와 결합하여 오버 바이 오버 소지 지역을 더 명확하게 식별하여 신호의 신뢰성을 향상시킵니다.

단일 스토카스틱 전략에 비해, 이 전략은 RSI를 스토카스틱의 입력 데이터 소스로 사용하고, 일부 잡음을 필터링하여 신호를 더 신뢰할 수 있게 한다.

일률적인 필터링 조건을 설정하여 역전기 포장을 효과적으로 방지하여 불필요한 손실을 줄일 수 있습니다.

포지션 보유 시간 지연을 설정하면 가짜 돌파구가 중단되는 것을 피할 수 있다.

전략적 위험

이 전략은 주로 단기 주기 지표를 사용하므로 단선 동작에만 적합하며, 장선 동작에는 좋지 않을 수 있다.

스토카스틱 RSI 지표 자체는 약간의 지연을 일으키고 단기 가격 급격한 변화 후 신호를 놓칠 수 있습니다.

위기 상황에서, 스토카스틱 RSI 지표는 여러 번 오버 바이 오버 셀 영역을 통과하여 거래 비용을 증가시키는 과잉 거래가 발생할 수 있습니다.

전략 최적화 방향

  1. 다양한 변수 조합을 테스트하여 스토카스틱 RSI의 길이를, K값과 D값을 더욱 최적화할 수 있다.

  2. 다른 RSI 길이 변수를 테스트하여 더 적합한 RSI 주기의 길이를 찾을 수 있습니다.

  3. MACD, Bollinger Bands 등과 같은 신호의 정확도를 더욱 높이기 위해 다른 지표와 결합하여 시도 할 수 있습니다.

  4. 다양한 포지션 시간 지연 변수를 테스트하여 더 적합한 출전 시간을 찾을 수 있다.

요약하다

이 문서에서는 스토카스틱 RSI 지표에 기반한 동적 전략의 구성 원리, 장점, 위험 및 최적화 아이디어에 대해 자세히 설명합니다. 단일 지표 전략에 비해 RSI와 스토카스틱의 장점을 동시에 활용하는 전략은 시장의 단기 오버 바이 오버 셀 현상을 더 명확하고 신뢰할 수있게 식별하여 반전 거래를 할 수 있습니다. 매개 변수 최적화 및 지표 조합을 통해 전략의 효과를 더욱 향상시킬 수 있습니다.

전략 소스 코드
/*backtest
start: 2023-11-25 00:00:00
end: 2023-12-25 00:00:00
period: 1h
basePeriod: 15m
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/
// © Drun30 (Federico Magnani)

//@version=4
//STRATEGIA PRINCIPALE
capitaleIniziale=10000

var sizeordineInit= 50 // → % di capitale investita per ogni trade
var deltaSize = 25 // → delta% di capitale investito se trade precedente è stato in perdita
var sizeLimite = 100 //il trade non userà mai questa percentuale di capitale investito
var sizeordine = sizeordineInit

//Parametri ottimali 30 min
usiShort=false
usiLong=true
ipercomprato=85.29
ipervenduto=30.6
//

strategy("Momentum Strategy (V7.B.4)", initial_capital=capitaleIniziale, currency="USD", default_qty_type=strategy.percent_of_equity, commission_type=strategy.commission.percent, commission_value=0.1, slippage = 5, default_qty_value=sizeordineInit, overlay=false, pyramiding=0)

backtest = input(title="------------------------Backtest Period------------------------", defval = false)
start = timestamp(input(2020, "start year"), input(1, "start month"), input(1, "start day"), 00, 00)
end = timestamp(input(0, "end year"), input(0, "end month"), input(0, "end day"), 00, 00) 

siamoindata=time > start?true:false
if end > 0
    siamoindata:=time > start and time <= end?true:false

basicParameters = input(title="------------------------Basic Parameters------------------------", defval = false)
smoothK = input(3, minval=1)
smoothD = input(6, minval=1)
lengthRSI = input(12, minval=1) 
src = input(close, title="RSI Source")
rsi1 = rsi(src, lengthRSI)
lengthStoch = input(12, minval=1)
k = ema(stoch(rsi1, rsi1, rsi1, lengthStoch), smoothK)
d = ema(k, smoothD)
altezzaipercomprato= input(ipercomprato, title="Overbought Height", minval=1, type=input.float)
altezzaipervenduto= input(ipervenduto, title="Oversold Height", minval=1,type=input.float) 

BarsDelay = input(6,title="Bars delay",minval=0) 

GambleSizing = input(true, title = "Gamble Sizing?",type=input.bool)
gambleAdd = input(deltaSize,title="Gamble Add (%)",minval=0,type=input.integer)
gambleLimit = input(sizeLimite,title="Gamble MAX (%)",minval=0,type=input.integer)
if GambleSizing and strategy.closedtrades[0]>strategy.closedtrades[1]
    if strategy.losstrades[0]>strategy.losstrades[1] and sizeordine<gambleLimit
        sizeordine:=sizeordine+gambleAdd
    if strategy.wintrades[0]>strategy.wintrades[1]
        sizeordine:=sizeordineInit

periodomediamobile_fast = input(1, title="Fast EMA length",minval=1)
periodomediamobile_slow = input(60, title="Slow EMA length",minval=1)

plot(k, color=color.blue)
plot(d, color=color.orange)
h0 = hline(altezzaipercomprato)
h1 = hline(altezzaipervenduto)
fill(h0, h1, color=color.purple, transp=80)
// n=input(Vicinanzadalcentro,title="Vicinanza dal centro",minval=0) 
//sarebbe il livello di D in cui si acquista o si vende, maggiore è la vicinanza maggiore sarà la frequenza dei trades, SE 0 è DISABILITATO

//     siamoinipervenduto= d<=altezzaipervenduto and d<=d[n] and d>d[1]?true:false //and d<d[3] and d>d[1]
//     siamoinipercomprato= d>=altezzaipercomprato and d>=d[n] and d<d[1]?true:false //and d>d[3] and d<d[1]
goldencross = crossover(k,d)
deathcross = crossunder(k,d)
// METTI VARIABILE IN CUI AVVIENE CROSSOVER O CROSSUNDER
valoreoro = valuewhen(goldencross,d,0)
valoremorte = valuewhen(deathcross,d,0)

siamoinipervenduto = goldencross and valoreoro<=altezzaipervenduto?true:false//d<=altezzaipervenduto?true:false
siamoinipercomprato = deathcross and valoremorte>=altezzaipercomprato?true:false//d>=altezzaipercomprato?true:false

long_separator = input(title="------------------------LONG------------------------", defval = usiLong)

sl_long_inp = input(10, title="Stop Loss LONG %", type=input.float) 
tp_long_inp = input(8, title="Take Profit LONG %",type=input.float)
stop_level_long = strategy.position_avg_price * (1 - (sl_long_inp/100)) //strategy.position_avg_price corrisponde al prezzo con cui si è aperta la posizione
take_level_long = strategy.position_avg_price * (1 + (tp_long_inp/100))

//BINANCE
JSON_long = 'OPEN LONG: PUT THE JSON HERE FOR THE API CALL'
JSON_chiusura = 'CLOSE POSITION: PUT THE JSON HERE FOR THE API CALL' 

webhookLong = JSON_long
webhookClose= JSON_chiusura

trendFilterL = input(title="TREND FILTER LONG?", defval = true)

EMAfast=ema(close,periodomediamobile_fast)
EMAslow=ema(close,periodomediamobile_slow)

siamoinuptrend_ema=EMAfast>EMAslow?true:false //close>=EMAfast and EMAfast>EMAslow
siamoinuptrend = siamoinuptrend_ema

// CondizioneAperturaLong = siamoinipervenduto and siamoindata // and siamoinuptrend
CondizioneAperturaLong = siamoinipervenduto and siamoindata and long_separator
if trendFilterL
    CondizioneAperturaLong := siamoinipervenduto and siamoindata and long_separator and siamoinuptrend

CondizioneChiusuraLong = siamoinipercomprato and siamoindata 

possiamoAprireLong=0
if trendFilterL and siamoinuptrend
    possiamoAprireLong:=5
plot(possiamoAprireLong,color=color.green)

sonPassateLeBarreG = barssince(CondizioneAperturaLong) == BarsDelay?true:false
sonPassateLeBarreD = barssince(CondizioneChiusuraLong) == BarsDelay?true:false

haiUnLongAncoraAperto = false
haiUnLongAncoraAperto := strategy.position_size>0?true:false

// Se l'ultimo valore della serie "CondizioneAperturaLong" è TRUE, allora hai un long ancora aperto
// Se l'ultimo valore della serie "CondizioneAperturaLong" è FALSE, allora:
//       Se l'ultimo valore della serie "CondizioneChiusuraLong" è TRUE, allora NON hai un long ancora aperto 
//       Se l'ultimo valore della serie "CondizioneChiusuraLong" è FALSE, allora restituisce l'ultimo valore della serie "haiUnLongAncoraAperto"

haiUnLongAncoraAperto_float = if(haiUnLongAncoraAperto==true)
    10
else
    0

plot(haiUnLongAncoraAperto_float,color=color.red) //FInché la linea rossa si trova a livello "1" allora c'è un ordine long in corso

quantita = (sizeordine/100*(capitaleIniziale+strategy.netprofit))/valuewhen(haiUnLongAncoraAperto==false and CondizioneAperturaLong,close,0)

plot(sizeordine,color=color.purple, linewidth=3)

if  strategy.position_size<=0 and CondizioneAperturaLong //and sonPassateLeBarreG and haiUnLongAncoraAperto==false strategy.opentrades==0
    strategy.entry("Vamonos",strategy.long, alert_message=webhookLong, comment="OPEN LONG", qty=quantita)

if  strategy.position_size>0 //and sonPassateLeBarreD // and CondizioneChiusuraLong 
    if siamoinuptrend == true and sonPassateLeBarreD
        strategy.close("Vamonos", alert_message=webhookClose, comment="CLOSE LONG")
    else if siamoinuptrend == false and CondizioneChiusuraLong
        strategy.close("Vamonos", alert_message=webhookClose, comment="CLOSE LONG")

    
if strategy.position_size>0 and siamoindata
    strategy.exit("Vamonos", stop=stop_level_long, limit=take_level_long, comment="CLOSE LONG (LIMIT/STOP)")


short_separator = input(title="------------------------SHORT------------------------", defval = usiShort)    

sl_short_inp = input(20, title="Stop Loss SHORT %")
tp_short_inp = input(35, title="Take Profit SHORT %")
stop_level_short = strategy.position_avg_price * (1 + (sl_short_inp/100))
take_level_short= strategy.position_avg_price * (1 - (tp_short_inp/100))

// BINANCE 
JSON_short = 'OPEN SHORT: PUT THE JSON HERE FOR THE API CALL'

webhookShort = JSON_short

trendFilterS = input(title="TREND FILTER SHORT?", defval = true)

siamoindowntrend_ema=EMAfast<EMAslow?true:false //close<=EMAfast and EMAfast<EMAslow
siamoindowntrend=siamoindowntrend_ema

CondizioneAperturaShort = short_separator and siamoinipercomprato and siamoindata 
if trendFilterS
    CondizioneAperturaShort:=short_separator and siamoinipercomprato and siamoindata and siamoindowntrend

CondizioneChiusuraShort = siamoinipervenduto and siamoindata

sonPassateLeBarreGs = barssince(CondizioneAperturaShort) == BarsDelay?true:false
sonPassateLeBarreDs = barssince(CondizioneChiusuraShort) == BarsDelay?true:false

haiUnoShortAncoraAperto = false
haiUnoShortAncoraAperto := strategy.position_size<0?true:false

haiUnoShortAncoraAperto_float = if(haiUnoShortAncoraAperto==true)
    15
else
    0

plot(haiUnoShortAncoraAperto_float,color=color.purple) //FInché la linea viola si trova a livello "2" allora c'è un ordine short in corso

if CondizioneAperturaShort and strategy.position_size>=0 //and haiUnoShortAncoraAperto==false
    strategy.entry("Andale",strategy.short,alert_message=webhookShort, comment="OPEN SHORT")

if  strategy.position_size<0 //and sonPassateLeBarreD // and CondizioneChiusuraLong 
    if siamoindowntrend == true and sonPassateLeBarreDs
        strategy.close("Andale",alert_message=webhookClose, comment="CLOSE SHORT")
    else if siamoindowntrend == false and CondizioneChiusuraShort
        strategy.close("Andale",alert_message=webhookClose, comment="CLOSE SHORT")

if strategy.position_size<0 and siamoindata
    strategy.exit("Andale", stop=stop_level_short, limit=take_level_short, comment="CLOSE SHORT (LIMIT/STOP)")