고정 손절매 전략으로 돌파


생성 날짜: 2023-11-03 14:31:21 마지막으로 수정됨: 2023-11-03 14:31:21
복사: 0 클릭수: 635
avatar of ChaoZhang ChaoZhang
1
집중하다
1617
수행원

고정 손절매 전략으로 돌파

개요

이 전략의 주요 아이디어는 브레이크 밴드 식별 트렌드 방향을 사용하여 고정 스톱로즈와 결합하여 리스크 관리를 수행하는 것입니다. 전략은 먼저 일정 주기 동안의 최고 가격과 최저 가격을 계산하여 브레이크 밴드를 형성합니다. 가격이 브레이크 밴드를 뚫을 때 거래 신호를 생성합니다. 또한, 전략은 거래자가 고정 스톱 손실 금액을 설정할 수 있습니다.

전략 원칙

이 전략은 크게 네 부분으로 구성된다: 포지션 관리, 브레이크 밴드 식별, 스톱 손실 설정 및 수량 계산.

우선, 전략은 현재 포지션이 있는지 여부를 판단합니다. 포지션이 있다면 새로운 신호는 생성되지 않습니다.

둘째, 전략은 일정 주기 동안의 최고 가격과 최저 가격을 계산하여 브레이크대를 형성한다. 가격이 브레이크대의 내부에서 외부로 돌파 할 때 거래 신호를 생성한다. 구체적으로, 가격이 브레이크 밴드를 돌파하면 경로에 오르면 다중 신호를 생성하고, 가격이 브레이크 밴드를 돌파하면 경로에 오르면 공백 신호를 생성한다.

또한, 다중 신호가 발생했을 때, 전략은 돌파구 중간 지점을 중지 지점으로 설정한다. 하위 신호가 발생했을 때, 중지 지점도 설정된다. 중지 손실을 추적하기 위해, 전략은 포지션 기간 동안 실시간으로 중지 지점을 조정한다.

마지막으로, 전략은 고정된 스톱로스 금액을 설정할 수 있다. 신호가 발생했을 때, 전략은 스톱로스 포인트와 현재 가격의 점수 거리를 계산하고, 시판 단위, 환율 등과 결합하여 스톱로스 포인트 사이의 가격 변화로 나타난 금액을 계산한다. 그리고 고정된 스톱로스 기준으로 거래 수를 역으로 계산한다.

이 전략의 주요 원칙은 다음과 같습니다. 이 전략의 핵심 아이디어는 트렌드 방향을 파악하고 고정된 손실을 사용하여 위험을 통제하는 것입니다.

우위 분석

이 브레이크밴드 고정 손실 전략은 다음과 같은 장점이 있습니다.

  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)