이 문서에서는 주로 스토카스틱 RSI 지표에 기반한 모멘텀 오스실레이션 거래 전략을 설명합니다. 이 전략은 스토카스틱 RSI가 과잉 구매/ 과잉 판매 지역에 진입하는지 여부에 따라 거래 결정을 내리기 위해 짧은 주기 기술 지표를 채택합니다. 다른 모멘텀 전략과 비교하면이 전략은 RSI와 스토카스틱 지표의 장점을 결합하여 단기 시장 오스실레이션을 더 정확하게 포착합니다.
전략의 핵심 지표는 스토카스틱 RSI입니다. 스토카스틱 RSI의 계산 공식은:
스토카스틱 RSI = (RSI - RSI 낮은) / (RSI 높은 - RSI 낮은) * 100
RSI가 lengthRSI 매개 변수를 사용하여 계산되는 경우 (디폴트 12), 스토카스틱 RSI는 lengthStoch 매개 변수를 사용하여 계산되는 경우 (디폴트 12).
스토카스틱 RSI가 보라색 채운 영역보다 높을 때, 그것은 과잉 매입 영역이고, 그 다음에는 단위로 이동합니다. 스토카스틱 RSI가 보라색 채운 영역보다 낮을 때, 그것은 과잉 판매 영역이고, 그 다음에는 길게 이동합니다.
또한, 전략은 또한 이동 평균 필터 조건을 설정합니다. 빠른 EMA가 느린 EMA보다 높을 때만 긴 포지션을 열 수 있습니다. 빠른 EMA가 느린 EMA보다 낮을 때만 짧은 포지션을 열 수 있습니다. 이것은 역 트렌드 거래를 피합니다.
단일 RSI 전략과 비교하면 이 전략은 스토카스틱 지표를 결합하여 과잉 구매/ 과잉 판매 영역을 보다 명확하게 식별하여 신호의 신뢰성을 향상시킵니다.
단일 스토카스틱 전략과 비교하면 이 전략은 소음을 필터링하여 신호를 더 신뢰할 수 있도록 하는 스토카스틱의 입력 데이터 소스로 RSI를 사용합니다.
이동 평균 필터 조건은 역동 트렌드 포지션 구축을 효과적으로 방지하여 불필요한 손실을 줄이기 위해 설정됩니다.
포지션 유지 시간 지연은 가짜 파업으로 중단되는 것을 피하기 위해 설정됩니다.
이 전략은 주로 단기 주기의 지표를 사용하므로 단기 운영에만 적합하며 장기적으로 좋은 성과를 거두지 않을 수 있습니다.
스토카스틱 RSI 지표 자체는 특정 지연을 가지고 있으며 단기간에 급격한 가격 변화 후 신호를 놓칠 수 있습니다.
변동 시장에서 스토카스틱 RSI는 과잉 매수/ 과잉 판매 영역에 여러 번 침투하여 과잉 거래와 거래 비용을 증가시킬 수 있습니다.
다른 매개 변수 조합을 테스트하여 스토카스틱 RSI의 길이, K 및 D 값을 더 최적화 할 수 있습니다.
더 적절한 RSI 사이클을 찾기 위해 다른 RSI 길이 매개 변수를 테스트 할 수 있습니다.
MACD, 볼링거 밴드 등과 같은 신호 정확성을 더욱 향상시키기 위해 다른 지표와 결합을 시도하십시오.
더 적절한 출구 시기를 찾기 위해 다른 위치 유지 지연 매개 변수를 테스트합니다.
이 문서에서는 스토카스틱 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)")