리소스 로딩... 로딩...

브레이크오웃 밴드 고정 스톱 손실 전략

저자:차오장, 날짜: 2023-11-03 14:31:21
태그:

img

전반적인 설명

이 전략의 주요 아이디어는 트렌드 방향을 파악하고 위험 관리를 위해 고정 스톱 손실을 결합하기 위해 브레이크아웃 밴드를 사용하는 것입니다. 전략은 먼저 브레이크아웃 밴드를 형성하기 위해 특정 기간 동안 가장 높고 가장 낮은 가격을 계산합니다. 가격이 브레이크아웃 밴드를 통과하면 거래 신호가 생성됩니다. 또한 전략은 거래자가 고정 스톱 손실 금액을 설정 할 수 있습니다. 거래가 할 때마다 시스템은 고정 스톱 손실 금액을 기반으로 포지션 크기를 계산하여 각 손실이 고정됩니다.

전략 원칙

이 전략은 네 가지 주요 부분으로 구성됩니다. 포지션 관리, 브레이크 오브 밴드 식별, 스톱 로스 설정 및 포지션 사이즈링.

첫째, 전략은 오픈 포지션이 있는지 확인합니다. 만약 그렇게 된다면 새로운 신호가 생성되지 않습니다.

두 번째로, 전략은 브레이크아웃 밴드를 형성하기 위해 한 기간 동안 가장 높고 가장 낮은 가격을 계산합니다. 가격이 밴드를 벗어날 때 거래 신호가 생성됩니다. 구체적으로 가격이 상위 밴드를 넘으면 긴 신호가 생성됩니다. 가격이 하위 밴드를 넘으면 짧은 신호가 생성됩니다.

또한, 긴 신호가 생성되면 전략은 브레이크아웃 밴드의 중점을 스톱 로스로 설정합니다. 짧은 신호에도 마찬가지입니다. 스톱 로스를 추적하기 위해 전략은 위치에서 실시간으로 스톱 로스를 조정합니다.

마지막으로, 전략은 고정 스톱 로스 금액을 설정할 수 있습니다. 신호가 생성되면 전략은 현재 가격에 스톱 로스로부터 피프 수를 계산하고, 틱 크기 및 환율과 같은 요인을 결합하여 금전적 측면에서 스톱 로스와 현재 가격 사이의 가격 변화를 결정합니다. 그 다음 포지션 크기는 고정 스톱 로스 금액을 기반으로 계산됩니다.

위는 전략의 주요 원칙입니다. 브레이크오웃 밴드를 통해 트렌드 방향을 파악하고 고정 스톱 로스로 위험을 제어하는 것이 핵심 개념입니다.

장점

이 브레이크밴드 고정 스톱 손실 전략은 다음과 같은 장점을 가지고 있습니다:

  1. 고급 스톱 로스 개념. 전략은 고정 스톱 로스 거리의 대신 고정 스톱 로스 금액을 사용합니다. 이것은 다른 틱 값의 제품에서 위험을 고정할 수 없는 문제를 피합니다. 위험 관리 관점에서, 고정 통화 스톱 로스는 더 진보되어 있습니다.

  2. 합리적인 포지션 사이즈: 전략은 고정된 스톱 로스 금액에 기초한 포지션 크기를 지능적으로 계산하여 거래당 손실을 제어하여 합리적으로 위험 노출을 관리 할 수 있습니다.

  3. 단순하고 효과적인 브레이크오웃 식별. 밴드를 사용하여 브레이크오웃을 식별하는 것은 간단하고 직접적이며 트렌드 방향을 효과적으로 식별 할 수 있습니다. 단일 가격 수준의 브레이크오웃과 비교하면 이러한 브레이크오웃 밴드 식별은 트렌드에서 더 많은 잘못된 신호를 피할 수 있습니다.

  4. 트래일링 스톱 로스는 이윤을 증가시킵니다. 트래일링 스톱 로스를 위해 실시간으로 스톱 로스를 조정하는 전략의 능력은 더 많은 이윤을 확보하는 데 도움이됩니다.

  5. 폭넓은 적용 가능성. 전략은 모든 제품에 적용됩니다. 매개 변수가 올바르게 설정되는 한, 고정 금액의 스톱 로스 리스크 통제가 달성 될 수 있으므로 전략은 매우 다재다능합니다.

  6. 깨끗한 코드 구조. 코드 구조는 명확하고 모듈화되어 이해하기 쉽고 최적화됩니다.

위험성

이 전략의 장점에도 불구하고 몇 가지 위험 요소가 있습니다.

  1. 브레이크아웃 패턴 품질은 테스트되지 않았습니다. 전략은 브레이크아웃 패턴 품질을 판단하지 않으며 낮은 품질의 신호를 생성 할 수 있습니다. 신호를 필터하기 위해 다른 지표가 필요합니다.

  2. 고정 스톱 손실은 너무 기계적 일 수 있습니다. 시장 가격은 종종 격차가 있습니다. 고정 스톱 손실은 규칙에 너무 의존하고 조정에 유연성이 부족 할 수 있습니다.

  3. 거래 빈도에 제한이 없습니다. 전략은 거래 빈도를 제한하지 않으며 너무 자주 거래 할 수 있습니다. 빈도를 제한하기 위해 다른 규칙이 필요합니다.

  4. 고정 스톱 손실은 매개 변수 설정에 달려 있습니다. 고정 스톱 손실 금액을 설정하는 것은 전반적인 위험 통제에 매우 중요하며 자본 규모, 위험 욕구 등을 고려해야합니다.

  5. 브레이크오웃 방향은 잘못된 신호를 줄 수 있다. 잘못된 브레이크오웃 신호는 가격 변동이나 인하 과정에서 발생할 수 있다. 전략을 최적화하기 위해 더 많은 조건이 필요하다.

  6. 수익 취득 메커니즘이 없습니다. 전략은 현재 수익을 적극적으로 차단 할 수있는 수익 취득 능력이 없습니다. 이것은 만족스럽지 않은 수익으로 이어질 수 있습니다.

이러한 위험을 해결하기 위해 전략을 최적화하는 몇 가지 방법은 다음과 같습니다.

  1. 신호 품질을 필터링하는 지표, 예를 들어 MACD, KD 등을 추가합니다.

  2. 품질을 평가하기 위해 파업 강도 지표를 포함합니다. 예를 들어 부피 변화를 통해 강도를 판단합니다.

  3. 오픈 트레이드 빈도 제한을 추가합니다. 예를 들어 하루에 하나의 트레이드.

  4. 고정 스톱 로스 로직을 최적화합니다. 예를 들어, 한 임계 이상의 비율에 기반한 스톱 로스

  5. 다른 필터를 추가합니다. 예를 들어 변동성, 스톱 로스 강화 등.

  6. 수익을 취하는 전략을 포함합니다. 예를 들어 저항에 가까운 수익을 취하는 것입니다.

최적화 방향

분석을 바탕으로 전략은 다음 측면으로 최적화 될 수 있습니다.

  1. 여러 가지 기술적 지표를 사용하여 신호 품질을 향상시키기 위해 필터를 추가하고 트렌드 품질을 평가합니다. 또한 브레이크 강도를 판단합니다.

  2. 더 많은 유연성을 위해 스톱 손실을 최적화합니다. 특정 리트레이싱 후에 비율 기반 트레일링 스톱으로 전환 할 수 있습니다. 또한 변동성에 따라 동적으로 최적화 할 수 있습니다.

  3. 거래 빈도를 조절하여 시간 또는 빈도에 필터를 추가하여 과도한 거래를 피합니다.

  4. 트렌드 인디케이터를 포함하여 시기를 개선합니다. 예를 들어 트렌드 확인을 기다립니다.

  5. 이윤 목표, 후속 이윤 중지, 변동성 중지 등을 통해 수익성을 향상시키기 위해 수익을 취하는 전략을 최적화합니다.

  6. 고정 스톱 금액, 브레이크 아웃 기간 등과 같은 백테스트에 기반한 위험 매개 변수 최적화

  7. 신호, 필터, 위험, 이익 모듈을 더 분리하여 더 나은 확장성을 위해 코드를 재배포합니다.

  8. 다른 제품 조합에서 장점을 평가합니다.

이러한 최적화 차원을 통해, 브레이크아웃 스톱 로스 전략은 더 견고하고 수익성이 될 수 있습니다. 그것은 또한 더 많은 전략 조합으로 확장 할 수있는 기초를 마련합니다.

결론

전체적으로 전략은 트렌드를 식별하고 위험 통제를 위해 일정한 금액의 정지를 사용하는 데 합리적입니다. 개념은 위험 관리에 진보적입니다. 포지션 사이징 논리 또한 거래 당 손실을 제어하는 데 적합합니다. 그러나 전략은 신호 품질, 스톱 손실의 유연성, 수익성 등을 향상시키기 위해 다양한 최적화를 통해 향상시킬 수 있습니다. 트렌드 필터를 통합하여 수익을 개선하고 거래 빈도를 엄격히 제어함으로써 상당한 개선이 가능합니다. 결론적으로 전략은 위험 관리 및 포지션 사이징 기술을 배우는 틀을 제공하여 더 복잡한 중재 및 멀티 전략 시스템에 대한 추가 연구에 기반을 마련합니다.


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


더 많은