채널 회귀 거래 전략 분석


생성 날짜: 2023-10-17 15:48:36 마지막으로 수정됨: 2023-10-17 15:48:36
복사: 1 클릭수: 649
avatar of ChaoZhang ChaoZhang
1
집중하다
1617
수행원

채널 회귀 거래 전략 분석

[trans]

개요

이 전략은 브린 띠와 켄터 통로에 기반하여 가격 통로 거래를 한다. 그것은 가격이 상하 통로 경계선을 돌파한 후 통로 내부로 돌아가는 특성을 사용하여 거래 기회를 식별한다. 이 전략은 자산과 시간 주기에 따라 조정할 수 있는 다양한 사용자 정의 옵션을 제공합니다.

전략 원칙

이 전략은 다음과 같은 핵심 요소들을 포함하고 있습니다.

  1. 채널 지표 선택켄터 통로:

  2. 입학 조건: 가격이 통로 경계선을 뚫고, 하위 K 라인을 통로 안에 다시 닫을 것을 요구하는지

  3. 손해 방지 방법: 전신 K선 그림선, 확장 통로 경계, ATR 정지

  4. 정지방법: 옆 통로 경계, 통로 중간, ATR 정지

  5. 다른 구성더 많은 일을 하고, 더 많은 일을 하고, 역동적으로 정지 조정이 허용되는지 등

위와 같은 조합을 통해, 이 전략은 시장 특성의 역동성에 따라 최적의 입상 시점과 출전 목표를 판단하는 기능을 구현한다.

우위 분석

고정된 이동식 상쇄 전략에 비해 이 전략은 다음과 같은 장점을 가지고 있다:

  1. 채널의 가격 변동 범위를 포함하는 특성을 활용하여 시장 추세의 전환점을 더 정확하게 파악할 수 있다.

  2. 다채로운 손해 차단 방식은 선택적으로 조합되어 다양한 품종과 주기에 최적의 구성이 가능합니다.

  3. 통로 지표에 기반한 돌파 회귀 연산으로, 소규모의 흔들림을 이용해 상대방의 자금을 삼켜버릴 수 있다.

  4. ATR의 계산된 스톱 스톱 손실 거리는 시장의 변동성에 따라 자동으로 조정되며, 적응력이 강하다는 장점이 있다.

  5. 역동적으로 정지를 조정할 수 있도록 하고, 가능한 추가 운영 공간을 최대한 활용한다.

위험 분석

이 전략에는 다음과 같은 위험들이 있습니다.

  1. 대폭 트렌드 시장에서, 통로가 실패하여 스톱로스가 활성화 될 수 있습니다. 스톱로스 거리는 적절하게 느려질 수 있습니다.

  2. 시장이 높은 변동률을 가지고 있을 때, ATR 계산의 스톱 스톱 손실 거리가 너무 커져 손실이 확대될 수 있다. ATR 계수를 축소하는 것을 고려할 수 있다.

  3. 변동적인 상황에서는 가격이 채널 경계를 자주 유발할 수 있으며 이는 너무 자주 거래되는 것을 초래합니다. 종결점 돌파가 있을 경우에만 입시를 고려할 수 있습니다.

  4. 상황이 급격히 역전될 때, 동적조정정 스톱이 적시에 손실을 막지 못하면 손실이 발생할 수 있다. 중요한 지원/저항 지점 근처에서 탈퇴하는 것이 좋습니다.

최적화 방향

이 전략은 다음과 같은 부분에서 개선될 수 있습니다.

  1. 다른 ATR 계산 주기의 파라미터가 전략의 최대 회수 효과에 대한 테스트

  2. 트렌드를 판단하는 지표에 테스트를 추가하고, 트렌드가 보이지 않는 경우 거래를 중지한다.

  3. JOIN 거래법을 테스트하고, 중요한 지지 압력 지역 근처의 포지션을 낮추십시오.

  4. 거래량 통제를 강화하여 단일 손실이 너무 커지지 않도록하십시오.

  5. 특정 품종에 대한 변수 최적화 테스트를 수행하여 최적의 변수 조합을 찾습니다.

요약하다

이 전략은 전반적으로 통로 지표에 기반한 돌파구 회귀 거래 전략이다. 그것은 다양한 시장 환경에 맞게 조정할 수 있는 풍부한 구성 옵션을 제공한다. 장점은 시장 역전 시점을 파악할 수 있다는 점이며, 유연성이 강한 특징이다. 그러나 또한 큰 시장 상황에서 중단 손실이 파괴될 위험을 주의할 필요가 있다. 추세 판단, 위험 제어 등의 측면에서 향후 최적화하여 전략을 더 실용화 할 수 있다. ||

Overview

This strategy is based on price channel trading using Bollinger Bands and Keltner Channels. It identifies trading opportunities by the characteristic of price bouncing back after breaking through the upper or lower channel boundary lines. The strategy provides multiple customizable options to refine it for your asset and timeframe.

Strategy Logic

The key components of this strategy are:

  1. Channel Indicator: Bollinger Bands or Keltner Channels

  2. Entry Conditions: Price breakout of channel boundary, with option to require reversion back inside on next candle close

  3. Stop Loss: Previous candle’s wick, extended channel bands, ATR stop loss

  4. Take Profit: Opposite channel bands, channel midline, ATR take profit

  5. Other Configurations: Long only, short only, dynamic take profit adjustment etc.

With the above combinations, the strategy dynamically determines optimal entry and exit points according to market conditions.

Advantage Analysis

Compared to fixed moving stop/take profit strategies, this strategy has the following advantages:

  1. Utilizes the capability of channels to contain price fluctuations, more accurately capturing trend reversal points.

  2. Diverse stop loss and take profit options allow best configuration for different assets and timeframes.

  3. Breakout and reversion operations based on channel indicators can leverage small range oscillations to absorb opponent’s funds.

  4. ATR-calculated stop/take profit distances automatically adjust to market volatility.

  5. Allowing dynamic take profit adjustment fully exploits potential additional running space.

Risk Analysis

The main risks of this strategy are:

  1. In strong trending markets, channel failure may trigger stop loss. Stop loss distance can be loosened.

  2. With high volatility, ATR calculated stop/take profit distances may be too wide, enlarging losses. Consider reducing ATR coefficient.

  3. In ranging markets, frequent channel boundary touches may cause over-trading. Consider entry on close breakouts only.

  4. Severe reversals may hit take profit before stop loss with dynamic adjustment. Exits near key S/R levels recommended.

Optimization Directions

This strategy can be further optimized by:

  1. Testing ATR period parameters for impact on max drawdown.

  2. Incorporating trend indicators to pause trading when trend is unclear.

  3. Testing JOIN reversion techniques to reduce position size near key S/R zones.

  4. Adding trading size controls to limit single trade loss.

  5. Parameter optimization for specific assets to find optimal parameter combinations.

Summary

In summary, this is a channel breakout and reversion strategy. It provides rich configuration options for various market environments. The advantages are capturing reversal points and flexibility. But beware of stop loss invalidation in strong trends. Future optimizations on trend, risk control etc. will improve practicality.

전략 소스 코드
/*backtest
start: 2022-10-10 00:00:00
end: 2023-10-16 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// Copyright © 2022, José Manuel Gassin Pérez-Traverso, All rights reserved.
// © JoseMetal
//@version=5

// Ésta estrategia se basa en los rebotes de canales (ya sea Bandas de Bollinger o Keltner Channel) para entrar y salir de posiciones, tiene multitud de opciones para
// elegir el tipo de stop loss o take profit, ya sea utilizando mínimos/máximos anteriores, ATR o las propias bandas.
// La entrada de posiciones también tiene variedad de opciones, por ejemplo, se puede entrar cuando el precio salga de la banda y vuelva a entrar, o simplemente en cuanto una vela cierre fuera.
// De éste modo y con todas éstas opciones se puede realizar un backtest exhaustivo para buscar la mejor combinación según activo y temporalidad.

//== Constantes
c_verde_radiactivo = color.rgb(0, 255, 0, 0)
c_verde            = color.rgb(0, 128, 0, 0)
c_verde_oscuro     = color.rgb(0, 80, 0, 0)
c_rojo_radiactivo  = color.rgb(255, 0, 0, 0)
c_rojo             = color.rgb(128, 0, 0, 0)
c_rojo_oscuro      = color.rgb(80, 0, 0, 0)
noneColor          = color.new(color.white, 100)



//== Declarar estrategia y período de testeo
strategy("Estrategia de Canales [JoseMetal]", shorttitle="Estrategia de Canales [JoseMetal]", overlay=true, initial_capital=10000, pyramiding=0, default_qty_value=10, default_qty_type=strategy.percent_of_equity, commission_type=strategy.commission.percent, commission_value=0.0, max_labels_count=500, max_bars_back=1000)
fecha_inicio     = input(timestamp("1 Jan 2000"), title="• Fecha de inicio", group="Período de pruebas", inline="periodo_de_pruebas")
vela_en_fecha    = true
posicion_abierta = strategy.position_size != 0
LONG_abierto     = strategy.position_size > 0
SHORT_abierto    = strategy.position_size < 0

//== Condiciones de entrada y salida de estrategia
GRUPO_P           = "Posiciones"
P_indicador       = input.string("Canales de Keltner", "Indicador", ["Bandas de Bollinger", "Canales de Keltner"], "Se puede escoger entre los indicadores de Bandas de Bollinger y Canales de Keltner para las condiciones, éstos se usarán también para el Stop Loss y Take Profit y se escogen para dicha función.", group=GRUPO_P)
P_permitir_LONGS  = input.bool(title="¿LONGS?", group=GRUPO_P, defval=true)
P_permitir_SHORTS = input.bool(title="¿SHORTS?", group=GRUPO_P, defval=true)
P_cond_entrada    = input.string("Cierre fuera de la banda y luego cierre dentro", "Condición de entrada", ["Mecha fuera de la banda", "Mecha fuera de la banda y luego cierre dentro", "Cierre fuera de la banda", "Cierre fuera de la banda y luego cierre dentro"], "Se puede escoger (en orden) que el precio haya salido de la banda, que además la siguiente vela cierre de nuevo dentro de la misma, que el precio tenga que cerrar fuera, y que además la siguiente vela tenga que cerrar dentro de nuevo.", group=GRUPO_P)

GRUPO_TPSL       = "Stop Loss y Take Profit"
TP_SL_tipo_SL    = input.string("Banda extendida", "Tipo de Stop Loss", options=["Mecha anterior", "Banda extendida", "ATR"], group=GRUPO_TPSL)
TP_SL_tipo_TP    = input.string("Banda contraria",  "Tipo de Take Profit", options=["Banda contraria", "Media móvil", "ATR"], group=GRUPO_TPSL)
TPSL_SL_ATR_mult = input.float(title="• (Solo ATR) Multiplicador Stop Loss / Take Profit", group=GRUPO_TPSL, defval=1, minval=0.1, step=0.1, inline="tp_sl", tooltip="Éstos son los multiplicadores al ATR para calcular STOP LOSS y TAKE PROFIT en caso de seleccionarse como tales.")
TPSL_TP_ATR_mult = input.float(title="", group=GRUPO_TPSL, defval=1.8, minval=0.1, step=0.1, inline="tp_sl")
TPSL_SL_BB_dev   = input.float(title="• (Solo STOP LOSS con BB) Desviación estándar", group=GRUPO_TPSL, defval=4.0, minval=0.01, step=0.5, tooltip="En caso de usar las Bandas de Bollinger como STOP LOSS, éste será el valor de su desviación estándar.")
TPSL_SL_KC_mult  = input.float(title="• (Solo STOP LOSS con KC) Multiplicador", group=GRUPO_TPSL, defval=3, minval=0.01, step=0.5, tooltip="En caso de usar los canales de Keltner como STOP LOSS, éste será el valor de su multiplicador de ATR.")
TP_SL_TP_dinamico = input.bool(title="Take Profit dinámico", group=GRUPO_TPSL, defval=false, tooltip="Ésto hará que el Take Profit se ajuste vela a vela en lugar de quedarse fijo en su valor inicial.")



//== Inputs de indicadores
// ATR
GRUPO_ATR      = "ATR"
ATR_referencia = input.source(title="• Referencia / Longitud", group=GRUPO_ATR, defval=close, inline="atr_calc") // La fuente no se aplica al cálculo del ATR, es para el posicionamiento respecto al precio en el gráfico
ATR_length     = input.int(title="", group=GRUPO_ATR, defval=7, minval=1, inline="atr_calc")
ATR            = ta.atr(ATR_length)
ATR_sl         = ATR * TPSL_SL_ATR_mult
ATR_tp         = ATR * TPSL_TP_ATR_mult
ATR_LONG_sl    = ATR_referencia - ATR_sl // De forma contraria el inferior se puede usar como STOP LOSS o TRAILING STOP
ATR_LONG_tp    = ATR_referencia + ATR_tp // El ATR sobre las velas se puede usar como TAKE PROFIT
ATR_SHORT_sl   = ATR_referencia + ATR_sl // ""
ATR_SHORT_tp   = ATR_referencia - ATR_tp // Para Shorts es al revés

GRUPO_BB  = "Bollinger Bands"
BB_length = input.int(title="• Long. / Desv. ", group=GRUPO_BB, defval=20, minval=1, inline="bb")
BB_dev   = input.float(title="", group=GRUPO_BB, defval=2.0, minval=0.01, step=0.5, inline="bb")
[BB_mid, BB_upper, BB_lower]  = ta.bb(close, BB_length, BB_dev)
[_, BB_upper_SL, BB_lower_SL] = ta.bb(close, BB_length, TPSL_SL_BB_dev)

GRUPO_KC  = "Keltner Channel"
KC_length = input.int(title="• Long. / Mult. ", group=GRUPO_KC, defval=35, minval=1, inline="kc")
KC_mult   = input.float(title="", group=GRUPO_KC, defval=1.5, minval=0.01, step=0.5, inline="kc")
[KC_mid, KC_upper, KC_lower]  = ta.kc(close, KC_length, KC_mult, true)
[_, KC_upper_SL, KC_lower_SL] = ta.kc(close, KC_length, TPSL_SL_KC_mult, true)



//== Cálculo de condiciones
// Asignar variables comunes en función del indicador seleccionado
banda_superior = BB_upper
media_movil    = BB_mid
banda_inferior = BB_lower
banda_extendida_sup_SL = BB_upper_SL
banda_extendida_inf_SL = BB_lower_SL

if (P_indicador == "Canales de Keltner")
    banda_superior := KC_upper
    media_movil    := KC_mid
    banda_inferior := KC_lower
    banda_extendida_sup_SL := KC_upper_SL
    banda_extendida_inf_SL := KC_lower_SL

// Calcular condiciones de entrada
longCondition1  = false
shortCondition1 = false

if (P_cond_entrada == "Mecha fuera de la banda")
    longCondition1  := low < banda_inferior
    shortCondition1 := high > banda_superior
else if (P_cond_entrada == "Mecha fuera de la banda y luego cierre dentro")
    longCondition1  := low[1] < banda_inferior and close > banda_inferior
    shortCondition1 := high[1] > banda_superior and close < banda_superior
else if (P_cond_entrada == "Cierre fuera de la banda")
    longCondition1  := close < banda_inferior
    shortCondition1 := close > banda_superior
else // Cierre fuera de la banda y luego cierre dentro
    longCondition1  := close[1] < banda_inferior and close > banda_inferior
    shortCondition1 := close[1] > banda_superior and close < banda_superior



//== Entrada (deben cumplirse todas para entrar)
longCondition2  = true
longCondition3  = true
long_conditions = longCondition1 and longCondition2 and longCondition3
entrar_en_LONG  = P_permitir_LONGS and long_conditions and vela_en_fecha and not posicion_abierta and ATR > 0.0 // Lo del ATR > 0.0 es por seguridad ya que puede darse una entrada donde aún no es calculable el ATR porque no existan velas y nunca cerrar posición pues no se creó correctamente // Solo permitir 1 posición al mismo tiempo

shortCondition2  = true
shortCondition3  = true
short_conditions = shortCondition1 and shortCondition2 and shortCondition3
entrar_en_SHORT  = P_permitir_SHORTS and short_conditions and vela_en_fecha and not posicion_abierta and ATR > 0.0 // Lo del ATR > 0.0 es por seguridad ya que puede darse una entrada donde aún no es calculable el ATR porque no existan velas y nunca cerrar posición pues no se creó correctamente // Solo permitir 1 posición al mismo tiempo

var LONG_take_profit  = 0.0
var LONG_stop_loss    = 0.0
var SHORT_take_profit = 0.0
var SHORT_stop_loss   = 0.0

if (entrar_en_LONG)
    LONG_stop_loss   := TP_SL_tipo_SL == "Mecha anterior" ? (P_cond_entrada == "Mecha fuera de la banda" or P_cond_entrada == "Cierre fuera de la banda" ? low[1] : low) : TP_SL_tipo_SL == "Banda extendida" ? banda_extendida_inf_SL : ATR_LONG_sl
    LONG_take_profit := TP_SL_tipo_TP == "Banda contraria" ? banda_superior : TP_SL_tipo_TP == "Media móvil" ? media_movil : ATR_LONG_tp
    strategy.entry("Abrir Long", strategy.long)
    strategy.exit("Cerrar Long", "Abrir Long", limit=LONG_take_profit, stop=LONG_stop_loss)
else if (entrar_en_SHORT)
    SHORT_stop_loss   := TP_SL_tipo_SL == "Mecha anterior" ? (P_cond_entrada == "Mecha fuera de la banda" or P_cond_entrada == "Cierre fuera de la banda" ? high[1] : high) : TP_SL_tipo_SL == "Banda extendida" ? banda_extendida_sup_SL : ATR_SHORT_sl
    SHORT_take_profit := TP_SL_tipo_TP == "Banda contraria" ? banda_inferior : TP_SL_tipo_TP == "Media móvil" ? media_movil : ATR_SHORT_tp
    strategy.entry("Abrir Short", strategy.short)
    strategy.exit("Cerrar Short", "Abrir Short", limit=SHORT_take_profit, stop=SHORT_stop_loss)

if (posicion_abierta and TP_SL_TP_dinamico)
    if (LONG_abierto)
        LONG_take_profit := TP_SL_tipo_TP == "Banda contraria" ? banda_superior : TP_SL_tipo_TP == "Media móvil" ? media_movil : ATR_LONG_tp
        strategy.exit("Cerrar Long", "Abrir Long", limit=LONG_take_profit, stop=LONG_stop_loss)
    else
        SHORT_take_profit := TP_SL_tipo_TP == "Banda contraria" ? banda_inferior : TP_SL_tipo_TP == "Media móvil" ? media_movil : ATR_SHORT_tp
        strategy.exit("Cerrar Short", "Abrir Short", limit=SHORT_take_profit, stop=SHORT_stop_loss)



//== Ploteo en pantalla
bgcolor(entrar_en_LONG ? color.new(color.green, 90) : entrar_en_SHORT ? color.new(color.red, 90) : noneColor)

// ATR
plot(TP_SL_tipo_TP == "ATR" ? ATR_LONG_tp : na, style=plot.style_stepline, color=color.new(color.green, 80), linewidth=1)
plot(TP_SL_tipo_SL == "ATR" ? ATR_LONG_sl : na, style=plot.style_stepline, color=color.new(color.red, 80), linewidth=1)
plot(TP_SL_tipo_TP == "ATR" ? ATR_SHORT_tp : na, style=plot.style_stepline, color=color.new(color.green, 80), linewidth=1)
plot(TP_SL_tipo_SL == "ATR" ? ATR_SHORT_sl : na, style=plot.style_stepline, color=color.new(color.red, 80), linewidth=1)

// Canal y media
plot(banda_superior, "Banda superior", color.aqua)
plot(media_movil, "Media móvil", color.orange)
plot(banda_inferior, "Banda inferior", color.aqua)

// Bandas extendidas
plot(TP_SL_tipo_SL == "Banda extendida" ? banda_extendida_sup_SL : na, "Banda superior extendida (Stop Loss)", color.red, style=plot.style_circles)
plot(TP_SL_tipo_SL == "Banda extendida" ? banda_extendida_inf_SL : na, "Banda inferior extendida (Stop Loss)", color.red, style=plot.style_circles)

// Precio de compra, Take Profit, Stop Loss y relleno
avg_position_price_plot = plot(series=posicion_abierta ? strategy.position_avg_price : na, color=color.new(color.white, 25), style=plot.style_linebr, linewidth=2, title="Precio Entrada")

LONG_tp_plot            = plot(LONG_abierto and LONG_take_profit > 0.0 ? LONG_take_profit : na, color=color.new(color.lime, 25), style=plot.style_linebr, linewidth=3, title="LONG Take Profit")
LONG_sl_plot            = plot(LONG_abierto and LONG_stop_loss > 0.0? LONG_stop_loss : na, color=color.new(color.red, 25), style=plot.style_linebr, linewidth=3, title="Long Stop Loss")
fill(avg_position_price_plot, LONG_tp_plot, color=color.new(color.olive, 85))
fill(avg_position_price_plot, LONG_sl_plot, color=color.new(color.maroon, 85))

SHORT_tp_plot            = plot(SHORT_abierto and SHORT_take_profit > 0.0 ? SHORT_take_profit : na, color=color.new(color.lime, 25), style=plot.style_linebr, linewidth=3, title="SHORT Take Profit")
SHORT_sl_plot            = plot(SHORT_abierto and SHORT_stop_loss > 0.0 ? SHORT_stop_loss : na, color=color.new(color.red, 25), style=plot.style_linebr, linewidth=3, title="Short Stop Loss")
fill(avg_position_price_plot, SHORT_tp_plot, color=color.new(color.olive, 85))
fill(avg_position_price_plot, SHORT_sl_plot, color=color.new(color.maroon, 85))