Strategi Trading Reversal Berdasarkan Dukungan/Resistansi Umum

Penulis:ChaoZhang, Tanggal: 2023-10-30 11:23:25
Tag:

img

Gambaran umum

Strategi ini mengadopsi reversal trading berdasarkan faktor bullish/bearish, dengan tingkat profit-taking yang telah ditetapkan sebelumnya. Inti dari faktor-faktor ini adalah pola diperpanjang Generalized Support/Resistance berdasarkan volume trading, cocok untuk saham dengan volume dan volatilitas tinggi. Keuntungannya terletak pada menangkap peluang reversal yang lebih besar dalam jangka menengah-pendek dan mendapatkan keuntungan dengan cepat, sementara berisiko terjebak.

Logika Strategi

  1. Mengidentifikasi faktor bullish/bearish berdasarkan Generalized Support/Resistance dengan volume

    • Menggunakan pola candlestick untuk mengidentifikasi tingkat S/R klasik, disaring berdasarkan volume yang signifikan

    • S/R umum memiliki cakupan yang lebih baik daripada pola klasik

    • Pemecahan sinyal dukungan umum faktor panjang, pemecahan sinyal resistensi umum faktor pendek

  2. Perdagangan reversal

    • Mengambil posisi terbalik ketika sinyal faktor memicu

    • Jika sudah berada di posisi, mengurangi atau menambahkan posisi mundur

  3. Menetapkan target tingkat keuntungan

    • Set stop loss berdasarkan ATR

    • Atur beberapa tingkat keuntungan seperti 1R, 2R, 3R

    • Mengambil keuntungan parsial ketika mencapai target yang berbeda

Keuntungan

  • Menangkap pembalikan jangka menengah yang layak

    S/R breakouts mewakili sinyal pembalikan yang kuat dengan beberapa keandalan, mampu menangkap pembalikan jangka menengah

  • Keuntungan cepat, pengurangan kecil

    Dengan menetapkan stop loss dan target keuntungan ganda, dapat mencapai keuntungan cepat dan membatasi drawdowns

  • Cocok untuk saham dengan uang institusional yang signifikan dan volatilitas

    Strategi ini bergantung pada volume, yang membutuhkan partisipasi institusi yang cukup besar; juga membutuhkan volatilitas untuk menghasilkan keuntungan

Risiko

  • Terjebak di pasar yang terbatas

    Stop loss yang sering keluar dan masuk kembali ke arah yang berlawanan dapat mengakibatkan whipsaws

  • Kegagalan dukungan/resistensi

    S/R umum tidak benar-benar dapat diandalkan, beberapa kegagalan ada

  • Risiko kepemilikan satu sisi

    Logika pembalikan murni mungkin kehilangan peluang tren besar

  • Manajemen risiko:

    • Kondisi faktor longgar, tidak terbalik pada setiap keluar

    • Tambahkan filter lain misalnya perbedaan harga/volume

    • Mengoptimalkan strategi stop loss untuk mengurangi perangkap

Arah Peningkatan

  • Mengoptimalkan parameter S/R

    Temukan faktor yang lebih dapat diandalkan dengan mengubah pengaturan S/R umum

  • Mengoptimalkan pengambilan keuntungan

    Tambahkan lebih banyak tingkat keuntungan, atau gunakan target yang tidak tetap

  • Optimalkan stop loss

    Sesuaikan parameter ATR atau gunakan istics stop loss untuk mengurangi stop yang tidak perlu

  • Menggabungkan tren dan faktor lain

    Tambahkan filter tren seperti rata-rata bergerak untuk menghindari konflik tren besar; juga tambahkan faktor pendukung lainnya

Ringkasan

Inti dari strategi ini adalah untuk menangkap pergeseran jangka menengah yang layak melalui perdagangan pembalikan. Logika sederhana dan langsung, dan dapat praktis dengan penyesuaian parameter. Tetapi sifat agresif pembalikan menyebabkan beberapa penurunan dan risiko perangkap. Peningkatan lebih lanjut dalam stop loss, profit-taking dan keselarasan tren akan membantu mengurangi kerugian yang tidak perlu.


/*backtest
start: 2023-09-29 00:00:00
end: 2023-10-29 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/
// © DojiEmoji

//@version=5
strategy("Fractal Strat [KL] ", overlay=true, pyramiding=1, initial_capital=1000000000)
var string ENUM_LONG = "Long"
var string GROUP_ENTRY = "Entry"
var string GROUP_TSL = "Stop loss"
var string GROUP_TREND = "Trend prediction"
var string GROUP_ORDER = "Order size and Profit taking"

// backtest_timeframe_start = input.time(defval=timestamp("01 Apr 2000 13:30 +0000"), title="Backtest Start Time")
within_timeframe = true

// TSL: calculate the stop loss price. {
_multiple       = input(2.0, title="ATR Multiplier for trailing stop loss", group=GROUP_TSL)
ATR_TSL         = ta.atr(input(14, title="Length of ATR for trailing stop loss", group=GROUP_TSL, tooltip="Initial risk amount = atr(this length) x multiplier")) * _multiple
TSL_source      = low
TSL_line_color  = color.green
TSL_transp      = 100
var stop_loss_price = float(0)

var float initial_entry_p    = float(0)
var float risk_amt           = float(0)
var float initial_order_size = float(0)

if strategy.position_size == 0 or not within_timeframe
    TSL_line_color := color.black
    stop_loss_price := TSL_source - ATR_TSL
else if strategy.position_size > 0
    stop_loss_price := math.max(stop_loss_price, TSL_source - ATR_TSL)
    TSL_transp := 0

plot(stop_loss_price, color=color.new(TSL_line_color, TSL_transp))
// } end of "TSL" block


// Order size and profit taking {
pcnt_alloc = input.int(5, title="Allocation (%) of portfolio into this security", tooltip="Size of positions is based on this % of undrawn capital. This is fixed throughout the backtest period.", minval=0, maxval=100, group=GROUP_ORDER) / 100

// Taking profits at user defined target levels relative to risked amount (i.e 1R, 2R, 3R)
var bool  tp_mode = input(true, title="Take profit and different levels", group=GROUP_ORDER)
var float FIRST_LVL_PROFIT = input.float(1, title="First level profit", tooltip="Relative to risk. Example: entry at $10 and inital stop loss at $9. Taking first level profit at 1R means taking profits at $11", group=GROUP_ORDER)
var float SECOND_LVL_PROFIT = input.float(2, title="Second level profit", tooltip="Relative to risk. Example: entry at $10 and inital stop loss at $9. Taking second level profit at 2R means taking profits at $12", group=GROUP_ORDER)
var float THIRD_LVL_PROFIT = input.float(3, title="Third level profit", tooltip="Relative to risk. Example: entry at $10 and inital stop loss at $9. Taking third level profit at 3R means taking profits at $13", group=GROUP_ORDER)

// }

// Fractals {
// Modified from synapticEx's implementation: https://www.tradingview.com/script/cDCNneRP-Fractal-Support-Resistance-Fixed-Volume-2/

rel_vol_len = 6 // Relative volume is used; the middle candle has to have volume above the average (say sma over prior 6 bars)
rel_vol = ta.sma(volume, rel_vol_len)
_up = high[3]>high[4] and high[4]>high[5] and high[2]<high[3] and high[1]<high[2] and volume[3]>rel_vol[3]
_down = low[3]<low[4] and low[4]<low[5] and low[2]>low[3] and low[1]>low[2] and volume[3]>rel_vol[3]

fractal_resistance = high[3], fractal_support = low[3]   // initialize

fractal_resistance :=  _up ? high[3] : fractal_resistance[1]
fractal_support := _down ? low[3] : fractal_support[1]

plot(fractal_resistance, "fractal_resistance", color=color.new(color.red,50), linewidth=2, style=plot.style_cross, offset =-3, join=false)
plot(fractal_support, "fractal_support", color=color.new(color.lime,50), linewidth=2, style=plot.style_cross, offset=-3, join=false)
// }

// ATR diversion test {
// Hypothesis testing (2-tailed):
//
// Null hypothesis (H0) and Alternative hypothesis (Ha):
//     H0 : atr_fast equals atr_slow
//     Ha : atr_fast not equals to atr_slow; implies atr_fast is either too low or too high
len_fast    = input(5,title="Length of ATR (fast) for diversion test", group=GROUP_ENTRY)
atr_fast    = ta.atr(len_fast)
atr_slow    = ta.atr(input(50,title="Length of ATR (slow) for diversion test", group=GROUP_ENTRY, tooltip="This needs to be larger than Fast"))

// Calculate test statistic (test_stat)
std_error   = ta.stdev(ta.tr, len_fast) / math.pow(len_fast, 0.5)
test_stat = (atr_fast - atr_slow) / std_error

// Compare test_stat against critical value defined by user in settings
//critical_value = input.float(1.645,title="Critical value", tooltip="Strategy uses 2-tailed test to compare atr_fast vs atr_slow. Null hypothesis (H0) is that both should equal. Based on the computed test statistic value, if absolute value of it is +/- this critical value, then H0 will be rejected.", group=GROUP_ENTRY)
conf_interval = input.string(title="Confidence Interval", defval="95%", options=["90%","95%","99%"], tooltip="Critical values of 1.645, 1.96, 2.58, for CI=90%/95%/99%, respectively; Under 2-tailed test to compare atr_fast vs atr_slow. Null hypothesis (H0) is that both should equal. Based on the computed test statistic value, if absolute value of it is +/- critical value, then H0 will be rejected.")
critical_value = conf_interval == "90%" ? 1.645 : conf_interval == "95%" ? 1.96 : 2.58
reject_H0_lefttail = test_stat < -critical_value
reject_H0_righttail = test_stat > critical_value

// } end of "ATR diversion test" block

// Entry Signals
entry_signal_long = close >= fractal_support and reject_H0_lefttail

// MAIN {
// Update the stop limit if strategy holds a position.
if strategy.position_size > 0
    strategy.exit(ENUM_LONG, comment="SL", stop=stop_loss_price)

// Entry
if within_timeframe and entry_signal_long and strategy.position_size == 0
    initial_entry_p := close
    risk_amt := ATR_TSL
    initial_order_size := math.floor(pcnt_alloc * strategy.equity / close)
    strategy.entry(ENUM_LONG, strategy.long, qty=initial_order_size)

var int TP_taken_count = 0
if tp_mode and close > strategy.position_avg_price
    if close >= initial_entry_p + THIRD_LVL_PROFIT * risk_amt and TP_taken_count == 2
        strategy.close(ENUM_LONG, comment="TP Lvl3", qty=math.floor(initial_order_size / 3))
        TP_taken_count := TP_taken_count + 1
    else if close >= initial_entry_p + SECOND_LVL_PROFIT * risk_amt and TP_taken_count == 1
        strategy.close(ENUM_LONG, comment="TP Lvl2", qty=math.floor(initial_order_size / 3))
        TP_taken_count := TP_taken_count + 1
    else if close >= initial_entry_p + FIRST_LVL_PROFIT * risk_amt and TP_taken_count == 0
        strategy.close(ENUM_LONG, comment="TP Lvl1", qty=math.floor(initial_order_size / 3))
        TP_taken_count := TP_taken_count + 1
    
// Alerts
_atr = ta.atr(14)
alert_helper(msg) =>
    prefix = "[" + syminfo.root + "] "
    suffix = "(P=" + str.tostring(close, "#.##") + "; atr=" + str.tostring(_atr, "#.##") + ")"
    alert(str.tostring(prefix) + str.tostring(msg) + str.tostring(suffix), alert.freq_once_per_bar)

if strategy.position_size > 0 and ta.change(strategy.position_size)
    if strategy.position_size > strategy.position_size[1]
        alert_helper("BUY")
    else if strategy.position_size < strategy.position_size[1]
        alert_helper("SELL")

// Clean up - set the variables back to default values once no longer in use
if ta.change(strategy.position_size) and strategy.position_size == 0
    TP_taken_count := 0
    initial_entry_p := float(0)
    risk_amt := float(0)
    initial_order_size := float(0)
    stop_loss_price := float(0)
// } end of MAIN block


Lebih banyak