Breakout Band Fixed Stop Loss chiến lược

Tác giả:ChaoZhang, Ngày: 2023-11-03 14:31:21
Tags:

img

Tổng quan

Ý tưởng chính của chiến lược này là sử dụng băng thông đột phá để xác định hướng xu hướng và kết hợp dừng lỗ cố định để quản lý rủi ro. Chiến lược đầu tiên tính toán giá cao nhất và thấp nhất trong một khoảng thời gian nhất định để tạo thành băng thông đột phá. Khi giá vượt qua băng thông đột phá, một tín hiệu giao dịch được tạo ra. Ngoài ra, chiến lược cho phép các nhà giao dịch đặt số tiền dừng lỗ cố định. Mỗi khi giao dịch được đặt, hệ thống sẽ tính toán kích thước vị trí dựa trên số tiền dừng lỗ cố định, để mỗi lỗ được cố định.

Nguyên tắc chiến lược

Chiến lược bao gồm bốn phần chính: quản lý vị trí, xác định dải đột phá, thiết lập dừng lỗ và kích thước vị trí.

Đầu tiên, chiến lược kiểm tra xem có bất kỳ vị trí mở nào không.

Thứ hai, chiến lược tính toán giá cao nhất và thấp nhất trong một khoảng thời gian để tạo thành một dải đột phá. Khi giá vượt qua dải, một tín hiệu giao dịch được tạo ra. Cụ thể, nếu giá vượt qua dải trên, một tín hiệu dài được tạo ra. Nếu giá vượt qua dải dưới, một tín hiệu ngắn được tạo ra.

Ngoài ra, khi một tín hiệu dài được tạo ra, chiến lược thiết lập điểm giữa của băng tần đột phá như là lỗ dừng. Điều tương tự cũng xảy ra với các tín hiệu ngắn. Để theo dõi lỗ dừng, chiến lược cũng điều chỉnh lỗ dừng trong thời gian thực khi ở vị trí.

Cuối cùng, chiến lược cho phép thiết lập một số tiền dừng lỗ cố định. Khi một tín hiệu được tạo ra, chiến lược tính toán số lượng pips từ stop loss đến giá hiện tại, và kết hợp các yếu tố như kích thước dấu chấm và tỷ giá hối đoái, để xác định sự thay đổi giá giữa stop loss và giá hiện tại theo nghĩa tiền tệ.

Trên đây là các nguyên tắc chính của chiến lược. Xác định hướng xu hướng với các băng tần đột phá và kiểm soát rủi ro với lỗ dừng cố định là các khái niệm cốt lõi.

Ưu điểm

Chiến lược dừng lỗ cố định băng tần này có những lợi thế sau:

  1. Khái niệm dừng lỗ tiên tiến. Chiến lược sử dụng số tiền dừng lỗ cố định thay vì khoảng cách dừng lỗ cố định. Điều này tránh được vấn đề không thể cố định rủi ro trên các sản phẩm có giá trị tick khác nhau. Từ góc độ quản lý rủi ro, dừng lỗ tiền tệ cố định là tiên tiến hơn.

  2. Kích thước vị trí hợp lý: Chiến lược có thể tính toán kích thước vị trí một cách thông minh dựa trên số tiền dừng lỗ cố định, để kiểm soát lỗ cho mỗi giao dịch, do đó quản lý rủi ro một cách hợp lý.

  3. Nhận dạng đột phá đơn giản và hiệu quả. Xác định đột phá bằng các dải là đơn giản và trực tiếp, và có thể xác định hiệu quả hướng xu hướng. So với đột phá của một mức giá duy nhất, nhận dạng dải đột phá này có thể tránh nhiều tín hiệu sai xa khỏi xu hướng.

  4. Trailing stop loss làm tăng lợi nhuận. Khả năng điều chỉnh stop loss trong thời gian thực cho trailing stop loss giúp khóa thêm lợi nhuận.

  5. Khả năng áp dụng rộng rãi. Chiến lược có thể áp dụng cho bất kỳ sản phẩm nào. Miễn là các tham số được thiết lập đúng cách, kiểm soát rủi ro dừng lỗ với số tiền cố định có thể đạt được, làm cho chiến lược rất linh hoạt.

  6. Cấu trúc mã sạch. Cấu trúc mã là rõ ràng và mô-đun, làm cho nó dễ hiểu và tối ưu hóa.

Rủi ro

Mặc dù có những lợi thế, có một số rủi ro cần lưu ý cho chiến lược:

  1. Chất lượng mô hình đột phá chưa được kiểm tra. Chiến lược này không đánh giá chất lượng mô hình đột phá và có thể tạo ra một số tín hiệu chất lượng thấp. Các chỉ số khác là cần thiết để lọc tín hiệu.

  2. Giá cả thị trường thường chênh lệch. Giá dừng lỗ cố định có thể phụ thuộc quá nhiều vào các quy tắc và thiếu sự linh hoạt trong điều chỉnh.

  3. Không giới hạn tần suất giao dịch. Chiến lược không giới hạn tần suất giao dịch và có thể giao dịch quá thường xuyên. Các quy tắc khác là cần thiết để hạn chế tần suất.

  4. Đặt số tiền dừng lỗ cố định là rất quan trọng để kiểm soát rủi ro tổng thể và cần phải xem xét quy mô vốn, ham muốn rủi ro v.v.

  5. Hướng đột phá có thể cung cấp tín hiệu sai. Các tín hiệu đột phá sai có thể xảy ra trong các dao động giá hoặc giảm giá. Cần nhiều điều kiện hơn để tối ưu hóa chiến lược.

  6. Không có cơ chế lấy lợi nhuận. Chiến lược hiện không có khả năng lấy lợi nhuận để khóa lợi nhuận một cách tích cực. Điều này có thể dẫn đến lợi nhuận không thỏa mãn.

Để giải quyết những rủi ro này, một số cách tối ưu hóa chiến lược bao gồm:

  1. Thêm các chỉ số để lọc chất lượng tín hiệu, ví dụ: MACD, KD vv.

  2. Tích hợp các chỉ số sức mạnh để đánh giá chất lượng. Ví dụ, đánh giá sức mạnh thông qua thay đổi khối lượng.

  3. Thêm giới hạn tần suất giao dịch mở, ví dụ: một giao dịch mỗi ngày.

  4. Tối ưu hóa logic dừng lỗ cố định, ví dụ như dừng lỗ dựa trên tỷ lệ phần trăm trên ngưỡng.

  5. Thêm các bộ lọc khác, ví dụ như biến động, tăng mức dừng lỗ v.v.

  6. Bao gồm các chiến lược lấy lợi nhuận, ví dụ như lấy lợi nhuận gần ngưỡng kháng cự.

Hướng dẫn tối ưu hóa

Dựa trên phân tích, chiến lược có thể được tối ưu hóa trong các khía cạnh sau:

  1. Thêm bộ lọc để cải thiện chất lượng tín hiệu bằng cách sử dụng nhiều chỉ số kỹ thuật và đánh giá chất lượng xu hướng.

  2. Tối ưu hóa stop loss để linh hoạt hơn. Có thể chuyển sang stop trailing dựa trên tỷ lệ phần trăm sau một sự khôi phục nhất định. Cũng có thể tối ưu hóa năng động dựa trên biến động.

  3. Kiểm soát tần suất giao dịch để tránh giao dịch quá mức bằng cách thêm các bộ lọc về thời gian hoặc tần suất.

  4. Bao gồm các chỉ số xu hướng để cải thiện thời gian, ví dụ như chờ xác nhận xu hướng.

  5. Tối ưu hóa chiến lược thu lợi nhuận để cải thiện lợi nhuận thông qua mục tiêu lợi nhuận, dừng lợi nhuận, dừng biến động v.v.

  6. Tối ưu hóa các tham số rủi ro dựa trên các thử nghiệm sau, chẳng hạn như số tiền dừng cố định, thời gian thoát vv.

  7. Refactoring mã để mở rộng tốt hơn bằng cách tách thêm tín hiệu, bộ lọc, rủi ro, module lợi nhuận.

  8. Kiểm tra nhiều sản phẩm hơn cho các cơ hội điều chỉnh. Đánh giá lợi thế trên các kết hợp sản phẩm khác nhau.

Thông qua các khía cạnh tối ưu hóa này, chiến lược dừng lỗ đột phá có thể trở nên mạnh mẽ và có lợi hơn. Nó cũng đặt nền tảng để mở rộng thành nhiều sự kết hợp chiến lược hơn.

Kết luận

Nhìn chung, chiến lược là hợp lý trong việc sử dụng các băng tần đột phá để xác định xu hướng và dừng số tiền cố định để kiểm soát rủi ro. Các khái niệm là tiến bộ cho quản lý rủi ro. Lý thuyết kích thước vị trí cũng hợp lý để kiểm soát lỗ trên mỗi giao dịch. Nhưng chiến lược có thể được nâng cao thông qua các tối ưu hóa khác nhau để cải thiện chất lượng tín hiệu, tính linh hoạt trong dừng lỗ, lợi nhuận vv.v. Bằng cách kết hợp các bộ lọc xu hướng, cải thiện việc lấy lợi nhuận và kiểm soát tần suất giao dịch nghiêm ngặt, có thể đạt được sự cải thiện đáng kể.


/*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)


Thêm nữa