Bài viết này chủ yếu giải thích một chiến lược giao dịch dao động động dựa trên chỉ số Stochastic RSI. Chiến lược này áp dụng các chỉ số kỹ thuật chu kỳ ngắn hơn (như 30 phút) để đưa ra quyết định giao dịch dựa trên việc liệu Stochastic RSI có đi vào khu vực mua quá mức / bán quá mức hay không. So với các chiến lược động lực khác, chiến lược này kết hợp các lợi thế của cả chỉ số RSI và Stochastic để nắm bắt chính xác hơn các dao động thị trường ngắn hạn.
Chỉ số cốt lõi của chiến lược là Stochastic RSI. Công thức tính toán của Stochastic RSI là:
Chỉ số RSI ngẫu nhiên = (RSI - RSI thấp) / (RSI cao - RSI thấp) * 100
Trong đó RSI được tính bằng cách sử dụng tham số lengthRSI (bên mặc định 12), và Stochastic RSI được tính bằng cách sử dụng tham số lengthStoch (bên mặc định 12).
Khi Stochastic RSI cao hơn khu vực màu tím, đó là khu vực mua quá mức, sau đó mua ngắn; khi Stochastic RSI thấp hơn khu vực màu tím, đó là khu vực bán quá mức, sau đó mua dài.
Ngoài ra, chiến lược cũng thiết lập điều kiện lọc trung bình động. Chỉ khi EMA nhanh cao hơn EMA chậm bạn có thể mở một vị trí dài; chỉ khi EMA nhanh thấp hơn EMA chậm bạn có thể mở một vị trí ngắn. Điều này tránh giao dịch ngược xu hướng.
So với một chiến lược RSI duy nhất, chiến lược này kết hợp chỉ số Stochastic để xác định rõ hơn các khu vực mua quá mức / bán quá mức, do đó cải thiện độ tin cậy của tín hiệu.
So với một chiến lược Stochastic duy nhất, chiến lược này sử dụng RSI làm nguồn dữ liệu đầu vào của Stochastic, có thể lọc ra một số tiếng ồn và làm cho tín hiệu đáng tin cậy hơn.
Điều kiện lọc trung bình động được thiết lập để tránh hiệu quả việc xây dựng các vị trí ngược xu hướng, do đó giảm thiểu tổn thất không cần thiết.
Thời gian trì hoãn vị trí được thiết lập để tránh bị dừng lại bởi các vụ phá vỡ sai.
Chiến lược chủ yếu sử dụng các chỉ số chu kỳ ngắn, vì vậy nó chỉ phù hợp với các hoạt động ngắn hạn và có thể không hoạt động tốt trong dài hạn.
Chỉ số Stochastic RSI có một sự chậm trễ nhất định và có thể bỏ lỡ tín hiệu sau những thay đổi giá mạnh mẽ trong ngắn hạn.
Trong các thị trường dao động, Stochastic RSI có thể tạo ra nhiều lần thâm nhập vào các khu vực mua quá mức / bán quá mức, có thể dẫn đến giao dịch quá mức và tăng chi phí giao dịch.
Các kết hợp tham số khác nhau có thể được thử nghiệm để tối ưu hóa thêm giá trị chiều dài, K và D của Stochastic RSI.
Các thông số độ dài RSI khác nhau có thể được thử nghiệm để tìm một chu kỳ RSI phù hợp hơn.
Hãy thử kết hợp với các chỉ số khác để cải thiện thêm độ chính xác tín hiệu, chẳng hạn như MACD, Bollinger Bands, v.v.
Kiểm tra các thông số trì hoãn giữ vị trí khác nhau để tìm thời gian thoát phù hợp hơn.
Bài viết này chi tiết các nguyên tắc xây dựng, lợi thế, rủi ro và ý tưởng tối ưu hóa của một chiến lược đà dựa trên chỉ số Stochastic RSI. So với các chiến lược chỉ số duy nhất, chiến lược này sử dụng điểm mạnh của cả RSI và Stochastic để xác định rõ ràng và đáng tin cậy hơn các hiện tượng mua/bán quá mức ngắn hạn trên thị trường cho giao dịch đảo ngược.
/*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)")