Ide utama dari strategi ini adalah untuk menggunakan band breakout untuk mengidentifikasi arah tren dan menggabungkan stop loss tetap untuk manajemen risiko. Strategi pertama menghitung harga tertinggi dan terendah selama periode tertentu untuk membentuk band breakout. Ketika harga menembus band breakout, sinyal perdagangan dihasilkan. Selain itu, strategi ini memungkinkan pedagang untuk menetapkan jumlah stop loss tetap. Setiap kali perdagangan dilakukan, sistem akan menghitung ukuran posisi berdasarkan jumlah stop loss tetap, sehingga setiap kerugian tetap.
Strategi ini terdiri dari empat bagian utama: manajemen posisi, identifikasi band breakout, pengaturan stop loss dan ukuran posisi.
Pertama, strategi memeriksa apakah ada posisi terbuka.
Kedua, strategi menghitung harga tertinggi dan terendah selama periode untuk membentuk band breakout. Ketika harga keluar dari band, sinyal perdagangan dihasilkan. Secara khusus, jika harga pecah di atas band atas, sinyal panjang dihasilkan. Jika harga pecah di bawah band bawah, sinyal pendek dihasilkan.
Selain itu, ketika sinyal panjang dihasilkan, strategi menetapkan titik tengah dari band breakout sebagai stop loss. Hal yang sama berlaku untuk sinyal pendek. Untuk melacak stop loss, strategi juga menyesuaikan stop loss secara real-time saat berada di posisi.
Akhirnya, strategi memungkinkan untuk menetapkan jumlah stop loss tetap. Ketika sinyal dihasilkan, strategi menghitung jumlah pips dari stop loss ke harga saat ini, dan menggabungkan faktor seperti ukuran tik dan nilai tukar, untuk menentukan perubahan harga antara stop loss dan harga saat ini dalam hal moneter. Ukuran posisi kemudian dihitung berdasarkan jumlah stop loss tetap.
Di atas adalah prinsip-prinsip utama dari strategi. mengidentifikasi arah tren dengan break-out band dan mengendalikan risiko dengan stop loss tetap adalah konsep inti.
Strategi stop loss yang tetap ini memiliki keuntungan berikut:
Konsep stop loss lanjutan. Strategi ini menggunakan jumlah stop loss tetap bukan jarak stop loss tetap. Hal ini menghindari masalah tidak dapat memperbaiki risiko di seluruh produk dengan nilai tick yang berbeda. Dari perspektif manajemen risiko, stop loss moneter tetap lebih maju.
Ukuran posisi yang wajar. Strategi dapat secara cerdas menghitung ukuran posisi berdasarkan jumlah stop loss tetap, sehingga kerugian per perdagangan dikendalikan, sehingga mengelola eksposur risiko secara wajar.
Identifikasi breakout yang sederhana dan efektif. Mengidentifikasi breakout dengan band adalah sederhana dan langsung, dan dapat secara efektif mengidentifikasi arah tren. Dibandingkan dengan breakout dari satu tingkat harga, identifikasi band breakout ini dapat menghindari lebih banyak sinyal palsu dari tren.
Kemampuan strategi untuk menyesuaikan stop loss secara real-time untuk trailing stop loss membantu mengunci lebih banyak keuntungan.
Aplikasi yang luas. Strategi ini dapat diterapkan pada produk apa pun. Selama parameter ditetapkan dengan benar, pengendalian risiko stop loss dengan jumlah tetap dapat dicapai, membuat strategi ini sangat serbaguna.
Struktur kode yang jelas dan modular, membuatnya mudah dipahami dan dioptimalkan.
Meskipun ada keuntungan, ada beberapa risiko yang harus diperhatikan untuk strategi:
Kualitas pola pecah tidak diuji. Strategi ini tidak menilai kualitas pola pecah dan dapat menghasilkan beberapa sinyal berkualitas rendah. Indikator lain diperlukan untuk menyaring sinyal.
Stop loss tetap mungkin terlalu mekanis. harga pasar sering selisih. stop loss tetap mungkin terlalu bergantung pada aturan dan kurang fleksibel dalam penyesuaian.
Tidak ada batasan pada frekuensi perdagangan. Strategi tidak membatasi frekuensi perdagangan dan mungkin perdagangan terlalu sering. Aturan lain diperlukan untuk membatasi frekuensi.
Stop loss tetap tergantung pada pengaturan parameter. Menetapkan jumlah stop loss tetap sangat penting untuk pengendalian risiko secara keseluruhan dan perlu mempertimbangkan ukuran modal, nafsu risiko dll.
Arah breakout dapat memberikan sinyal yang salah. Sinyal breakout yang salah dapat terjadi selama osilasi harga atau pullback. Lebih banyak kondisi diperlukan untuk mengoptimalkan strategi.
Tidak ada mekanisme pengambilan keuntungan. Strategi saat ini tidak memiliki kemampuan pengambilan keuntungan untuk secara aktif mengunci keuntungan. Ini dapat menyebabkan keuntungan yang tidak memuaskan.
Untuk mengatasi risiko ini, beberapa cara untuk mengoptimalkan strategi meliputi:
Menambahkan indikator untuk menyaring kualitas sinyal, misalnya MACD, KD dll.
Mengintegrasikan indikator kekuatan pecah untuk mengevaluasi kualitas.
Menambahkan batas frekuensi perdagangan terbuka, misalnya satu perdagangan per hari.
Mengoptimalkan logika stop loss tetap, misalnya stop loss berbasis persentase di atas ambang batas.
Menambahkan filter lain, misalnya volatilitas, meningkatkan stop loss, dll.
Menggabungkan strategi mengambil keuntungan, misalnya mengambil keuntungan di dekat resistensi.
Berdasarkan analisis, strategi dapat dioptimalkan dalam aspek berikut:
Menambahkan filter untuk meningkatkan kualitas sinyal menggunakan beberapa indikator teknis dan menilai kualitas tren.
Mengoptimalkan stop loss untuk fleksibilitas yang lebih besar. Dapat beralih ke stop trailing berdasarkan persentase setelah retracement tertentu. Juga dapat mengoptimalkan secara dinamis berdasarkan volatilitas.
Mengontrol frekuensi perdagangan untuk menghindari perdagangan berlebihan dengan menambahkan filter pada periode waktu atau frekuensi.
Memasukkan indikator tren untuk meningkatkan waktu, misalnya menunggu konfirmasi tren.
Mengoptimalkan strategi pengambilan keuntungan untuk meningkatkan profitabilitas melalui target keuntungan, penundaan keuntungan, penundaan volatilitas, dll.
Mengoptimalkan parameter risiko berdasarkan backtest, seperti jumlah stop tetap, periode breakout dll.
Refactoring kode untuk ekstensibilitas yang lebih baik dengan lebih memisahkan sinyal, filter, risiko, modul keuntungan.
Uji lebih banyak produk untuk peluang arbitrase. Evaluasi keuntungan di berbagai kombinasi produk.
Melalui dimensi optimasi ini, strategi stop loss breakout dapat menjadi lebih kuat dan menguntungkan.
Secara keseluruhan, strategi ini masuk akal dalam menggunakan band istirahat untuk mengidentifikasi tren dan berhenti jumlah tetap untuk pengendalian risiko. Konsepnya progresif untuk manajemen risiko. Logika ukuran posisi juga bagus untuk mengendalikan kerugian per perdagangan. Tetapi strategi dapat ditingkatkan melalui berbagai optimasi untuk meningkatkan kualitas sinyal, fleksibilitas dalam stop loss, profitabilitas, dll. Dengan menggabungkan filter tren, meningkatkan pengambilan keuntungan, dan mengontrol frekuensi perdagangan secara ketat, perbaikan yang signifikan dapat dicapai.
/*backtest start: 2023-10-26 00:00:00 end: 2023-10-28 03:00:00 period: 10m basePeriod: 1m 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/ //@version=4 //@author=Takazudo strategy("Fixed price SL", overlay=true, default_qty_type=strategy.fixed, initial_capital=0, currency=currency.USD) var COLOR_TRANSPARENT = color.new(#000000, 100) var COLOR_ENTRY_BAND = color.new(#43A6F5, 30) //============================================================================ // config //============================================================================ // Money management _g1 = 'Money management' var config_riskPrice = input(100, minval=1, title="Risk price for each entry", group=_g1) var config_depositCurrency = input(title="Deposit currency", type=input.string, defval="USD", options=["USD"], group=_g1) // Entry strategy _g2 = 'Entry strategy' var config_entryBandBars = input(defval = 100, title = "Entry band bar count", minval=1, group=_g2) // Backtesting range _g3 = 'Backtesting range' fromYear = input(defval = 2018, title = "From Year", minval = 1970, group=_g3) fromMonth = input(defval = 1, title = "From Month", minval = 1, maxval = 12, group=_g3) fromDay = input(defval = 1, title = "From Day", minval = 1, maxval = 31, group=_g3) toYear = input(defval = 2020, title = "To Year", minval = 1970, group=_g3) toMonth = input(defval = 12, title = "To Month", minval = 1, maxval = 12, group=_g3) toDay = input(defval = 31, title = "To Day", minval = 1, maxval = 31, group=_g3) //============================================================================ // exchange caliculations //============================================================================ // mico pip size caliculation // ex1: AUDCAD -> 0.0001 // ex2: USDJPY -> 0.01 f_calcMicroPipSize() => _base = syminfo.basecurrency _quote = syminfo.currency _result = 0.0001 if _quote == 'JPY' _result := _result * 100 if _base == 'BTC' _result := _result * 100 _result // convert price to pips f_convertPriceToPips(_price) => _microPipSize = f_calcMicroPipSize() _price / _microPipSize // caliculate exchange rate between deposit and quote currency f_calcDepositExchangeSymbolId() => _result = '' _deposit = config_depositCurrency _quote = syminfo.currency if (_deposit == 'USD') and (_quote == 'USD') _result := na if (_deposit == 'USD') and (_quote == 'AUD') _result := 'OANDA:AUDUSD' if (_deposit == 'EUR') and (_quote == 'USD') _result := 'OANDA:EURUSD' if (_deposit == 'USD') and (_quote == 'GBP') _result := 'OANDA:GBPUSD' if (_deposit == 'USD') and (_quote == 'NZD') _result := 'OANDA:NZDUSD' if (_deposit == 'USD') and (_quote == 'CAD') _result := 'OANDA:USDCAD' if (_deposit == 'USD') and (_quote == 'CHF') _result := 'OANDA:USDCHF' if (_deposit == 'USD') and (_quote == 'JPY') _result := 'OANDA:USDJPY' _result // Let's say we need CAD to USD exchange // However there's only "OANDA:USDCAD" symbol. // Then we need to invert the exhchange rate. // this function tells us whether we should invert the rate or not f_calcShouldInvert() => _result = false _deposit = config_depositCurrency _quote = syminfo.currency if (_deposit == 'USD') and (_quote == 'CAD') _result := true if (_deposit == 'USD') and (_quote == 'CHF') _result := true if (_deposit == 'USD') and (_quote == 'JPY') _result := true _result // caliculate how much quantity should I buy or sell f_calcQuantitiesForEntry(_depositExchangeRate, _slPips) => _microPipSize = f_calcMicroPipSize() _priceForEachPipAsDeposit = _microPipSize * _depositExchangeRate _losePriceOnSl = _priceForEachPipAsDeposit * _slPips floor(config_riskPrice / _losePriceOnSl) //============================================================================ // Quantity caliculation //============================================================================ depositExchangeSymbolId = f_calcDepositExchangeSymbolId() // caliculate deposit exchange rate rate = security(depositExchangeSymbolId, timeframe.period, hl2) shouldInvert = f_calcShouldInvert() depositExchangeRate = if config_depositCurrency == syminfo.currency // if USDUSD, no exchange of course 1 else // else, USDCAD to CADUSD invert if we need shouldInvert ? (1 / rate) : rate //============================================================================ // Range Edge caliculation //============================================================================ f_calcEntryBand_high() => _highest = max(open[3], close[3]) for i = 4 to (config_entryBandBars - 1) _highest := max(_highest, open[i], close[i]) _highest f_calcEntryBand_low() => _lowest = min(open[3], close[3]) for i = 4 to (config_entryBandBars - 1) _lowest := min(_lowest, open[i], close[i]) _lowest entryBand_high = f_calcEntryBand_high() entryBand_low = f_calcEntryBand_low() entryBand_height = entryBand_high - entryBand_low plot(entryBand_high, color=COLOR_ENTRY_BAND, linewidth=1) plot(entryBand_low, color=COLOR_ENTRY_BAND, linewidth=1) rangeBreakDetected_long = entryBand_high < close rangeBreakDetected_short = entryBand_low > close shouldMakeEntryLong = (strategy.position_size == 0) and rangeBreakDetected_long shouldMakeEntryShort = (strategy.position_size == 0) and rangeBreakDetected_short //============================================================================ // SL & Quantity //============================================================================ var sl_long = hl2 var sl_short = hl2 entryQty = 0 slPips = 0.0 // just show info bubble f_showEntryInfo(_isLong) => _str = 'SL pips: ' + tostring(slPips) + '\n' + 'Qty: ' + tostring(entryQty) _bandHeight = entryBand_high - entryBand_low _y = _isLong ? (entryBand_low + _bandHeight * 1/4) : (entryBand_high - _bandHeight * 1/4) _style = _isLong ? label.style_label_up : label.style_label_down label.new(bar_index, _y, _str, size=size.large, style=_style) if shouldMakeEntryLong sl_long := (entryBand_high + entryBand_low) / 2 slPips := f_convertPriceToPips(close - sl_long) entryQty := f_calcQuantitiesForEntry(depositExchangeRate, slPips) if shouldMakeEntryShort sl_short := (entryBand_high + entryBand_low) / 2 slPips := f_convertPriceToPips(sl_short - close) entryQty := f_calcQuantitiesForEntry(depositExchangeRate, slPips) // trailing SL if strategy.position_size > 0 sl_long := max(sl_long, entryBand_low) if strategy.position_size < 0 sl_short := min(sl_short, entryBand_high) //============================================================================ // backtest duration //============================================================================ // Calculate start/end date and time condition startDate = timestamp(fromYear, fromMonth, fromDay, 00, 00) finishDate = timestamp(toYear, toMonth, toDay, 00, 00) //============================================================================ // make entries //============================================================================ if (true) if shouldMakeEntryLong strategy.entry(id="Long", long=true, stop=close, qty=entryQty) f_showEntryInfo(true) if shouldMakeEntryShort strategy.entry(id="Short", long=false, stop=close, qty=entryQty) f_showEntryInfo(false) strategy.exit('Long-SL/TP', 'Long', stop=sl_long) strategy.exit('Short-SL/TP', 'Short', stop=sl_short) //============================================================================ // plot misc //============================================================================ sl = strategy.position_size > 0 ? sl_long : strategy.position_size < 0 ? sl_short : na plot(sl, color=color.red, style=plot.style_cross, linewidth=2, title="SL") value_bgcolor = rangeBreakDetected_long ? color.green : rangeBreakDetected_short ? color.red : COLOR_TRANSPARENT bgcolor(value_bgcolor, transp=95)