この戦略は,ボリンジャー帯とケルトナーチャネルを使用して価格チャネル取引に基づいています.この戦略は,上または下チャネル境界線を突破した後,価格が反発する特徴によって取引機会を特定します.この戦略は,資産と時間枠に合わせてそれを精製するための複数のカスタマイズ可能なオプションを提供します.
この戦略の主な要素は次のとおりです.
チャンネル表示: ボリンガー帯またはケルトナーチャネル
入国条件: 次のキャンドルの閉じる時に内側に戻るオプションでチャネル境界の価格ブレイク
損失を止める前のキャンドル
利益 を 得る: 反対チャンネル帯,チャンネルミッドライン,ATRの利益
その他の配置: ロングのみ,ショートのみ,ダイナミック・テイク・プロフィート調整など
上記の組み合わせにより 戦略は 市場状況に応じて 動的に最適なエントリー・アウトリーチポイントを決定します
固定型移動型ストップ・テイク・プロフィート戦略と比較して,この戦略には以下の利点があります.
価格変動を抑制するチャネルの能力を利用し,傾向逆転点をより正確に把握します.
ストップ・ロストとテイク・プロフィートの選択肢は,さまざまな資産と時間枠に最適設定を可能にします.
チャネル指標に基づくブレイクアウトとリバースオペレーションは,小範囲の振動を利用して相手の資金を吸収することができます.
ATRで計算されたストップ/テイク・プロフィート距離は,市場の変動に自動的に調整されます.
ダイナミック・テイク・プロフィートの調整を許可することで,潜在的な追加的な走行スペースを完全に利用できます.
この戦略の主なリスクは,
強いトレンド市場では,チャネル障害がストップ・ロスを引き起こす可能性があります.ストップ・ロスの距離が緩められます.
高波動性がある場合,ATRで計算されたストップ/テイク・プロフィートの距離は幅が大きくなり,損失が増大する可能性があります.ATR係数を減らすことを検討してください.
レンジング市場では,頻度の高いチャネル境界が過剰な取引を引き起こす可能性があります. 接近したブレイクでの入場のみを検討してください.
ダイナミックな調整によるストップロスの前に重度の逆転が起こり得る.S/R基値に近い出口が推奨される.
この戦略は,次の方法でさらに最適化できます.
ATR 期間パラメータを最大引出量への影響のテスト
トレンドが不透明なときに取引を一時停止するための傾向指標を組み込む
主要なS/Rゾーンの近くでの位置サイズを減らすためのJOINリバース技術試験.
単一の取引損失を制限するために取引サイズ制御を追加します.
特定の資産のパラメータ最適化により,最適なパラメータ組み合わせを見つけることができます.
概要すると,これはチャネルブレイクアウトとリバース戦略である.さまざまな市場環境のための豊富な構成オプションを提供します.利点はリバースポイントと柔軟性を把握しています.しかし,強いトレンドでストップロスの無効化に注意してください.トレンド,リスク制御などの将来の最適化は実用性を向上させます.
/*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))