Phân tích chiến lược giao dịch đảo ngược kênh

Tác giả:ChaoZhang, Ngày: 2023-10-17 15:48:36
Tags:

Tổng quan

Chiến lược này dựa trên giao dịch kênh giá bằng cách sử dụng Bollinger Bands và Keltner Channels. Nó xác định các cơ hội giao dịch bằng đặc điểm của giá bật trở lại sau khi phá vỡ các đường ranh giới kênh trên hoặc dưới. Chiến lược cung cấp nhiều tùy chỉnh tùy chọn để tinh chỉnh nó cho tài sản và khung thời gian của bạn.

Chiến lược logic

Các thành phần chính của chiến lược này là:

  1. Chỉ số kênh: Bollinger Bands hoặc Keltner Channels

  2. Điều kiện nhập cảnh: Giá vượt qua ranh giới kênh, với tùy chọn yêu cầu đảo ngược trở lại bên trong vào ngày đóng nến tiếp theo

  3. Dừng Loss: Trước đây nến s wick, mở rộng dải kênh, ATR dừng mất mát

  4. Lấy lợi nhuận: Phạm vi kênh đối diện, đường giữa kênh, ATR lấy lợi nhuận

  5. Các cấu hình khác: Chỉ dài, chỉ ngắn, điều chỉnh lợi nhuận năng động vv

Với các sự kết hợp trên, chiến lược xác định động các điểm vào và ra tối ưu theo điều kiện thị trường.

Phân tích lợi thế

So với các chiến lược dừng / lấy lợi nhuận cố định, chiến lược này có những lợi thế sau:

  1. Sử dụng khả năng của các kênh để chứa biến động giá, nắm bắt chính xác hơn các điểm đảo ngược xu hướng.

  2. Các tùy chọn dừng lỗ và lấy lợi nhuận đa dạng cho phép cấu hình tốt nhất cho các tài sản và khung thời gian khác nhau.

  3. Các hoạt động phá vỡ và đảo ngược dựa trên các chỉ số kênh có thể tận dụng các dao động phạm vi nhỏ để hấp thụ tiền của đối thủ.

  4. Khoảng cách dừng / lấy lợi nhuận được tính theo ATR tự động điều chỉnh theo biến động thị trường.

  5. Cho phép điều chỉnh lợi nhuận năng động khai thác đầy đủ không gian hoạt động bổ sung tiềm năng.

Phân tích rủi ro

Những rủi ro chính của chiến lược này là:

  1. Trong thị trường xu hướng mạnh, sự cố kênh có thể kích hoạt dừng lỗ. Khoảng cách dừng lỗ có thể được nới lỏng.

  2. Với sự biến động cao, khoảng cách dừng / lấy lợi nhuận được tính ATR có thể quá rộng, làm tăng tổn thất.

  3. Trong các thị trường dao động, việc chạm vào ranh giới kênh thường xuyên có thể gây ra giao dịch quá mức.

  4. Sự đảo ngược nghiêm trọng có thể gây ra lợi nhuận trước khi dừng lỗ với điều chỉnh năng động.

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

Chiến lược này có thể được tối ưu hóa thêm bằng cách:

  1. Kiểm tra các thông số thời gian ATR để xác định tác động đến mức rút tối đa.

  2. Bao gồm các chỉ số xu hướng để tạm dừng giao dịch khi xu hướng không rõ ràng.

  3. Kiểm tra các kỹ thuật đảo ngược JOIN để giảm kích thước vị trí gần các vùng S / R quan trọng.

  4. Thêm kiểm soát kích thước giao dịch để hạn chế lỗ giao dịch duy nhất.

  5. Tối ưu hóa tham số cho các tài sản cụ thể để tìm kết hợp tham số tối ưu.

Tóm lại

Tóm lại, đây là một chiến lược thoát và đảo ngược kênh. Nó cung cấp các tùy chọn cấu hình phong phú cho các môi trường thị trường khác nhau. Những lợi thế là nắm bắt các điểm đảo ngược và linh hoạt. Nhưng hãy cẩn thận với việc vô hiệu hóa dừng lỗ trong xu hướng mạnh. Tối ưu hóa trong tương lai về xu hướng, kiểm soát rủi ro vv sẽ cải thiện tính thực tế.


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


Thêm nữa