Esta estrategia se basa en las señales alcistas y bajistas generadas por el indicador de canal de precios Donchain y el indicador cuantitativo del oscilador OBV para el comercio bidireccional.
Utilice el indicador de canal de precios Donchain para determinar los canales de precios superior e inferior. El canal superior se calcula a partir del precio más alto y el canal inferior a partir del precio más bajo.
Construir un oscilador OBV utilizando el indicador cuantitativo OBV y el indicador EMA para determinar la fuerza alcista y bajista.
Una señal larga se genera cuando el precio rompe el canal superior y el oscilador es mayor que 0; Una señal corta se genera cuando el precio rompe el canal inferior y el oscilador es menor que 0.
Cierre posiciones largas cuando los precios retroceden hacia el canal inferior; Cierre posiciones cortas cuando los precios retroceden hacia el canal superior.
El uso de canales de precios para determinar las tendencias evita ser engañado por los mercados fluctuantes.
La incorporación de indicadores cuantitativos para juzgar la fuerza alcista y bajista garantiza que la dirección del comercio sea coherente con la fuerza del mercado.
Adoptar el comercio bidireccional permite obtener ganancias tanto si el mercado sube como si cae.
El establecimiento de estrategias de stop loss gestiona los riesgos de manera efectiva.
La configuración incorrecta de los parámetros de los canales de precios puede dar lugar a canales demasiado sueltos o estrechos, perdiendo oportunidades comerciales o generando señales incorrectas.
La configuración incorrecta de los parámetros del indicador también puede dar lugar a una generación tardía o prematura de la señal.
Los movimientos volátiles anormales repentinos de eventos pueden desencadenar pérdidas de parada que conducen a pérdidas.
La negociación bidireccional requiere la gestión simultánea de posiciones largas y cortas, lo que dificulta su operación.
Optimizar los parámetros del canal de precios para encontrar combinaciones óptimas.
Prueba y optimiza los parámetros del oscilador OBV para garantizar juicios oportunos y precisos de la fuerza alcista / bajista.
Considere incorporar otros indicadores como MACD, KD, etc. para mejorar la precisión de la señal.
Los métodos de prueba de pérdidas de parada diferentes, por ejemplo, paradas de seguimiento, paradas porcentuales, etc.
Pruebe diferentes productos para encontrar el que mejor se adapte a la estrategia.
En general, se trata de una estrategia de negociación bidireccional clara y fácil de entender que incorpora la acción de los precios y los indicadores cuantitativos para determinar las tendencias y la fortaleza del mercado.
/*backtest start: 2022-12-06 00:00:00 end: 2023-12-12 00:00:00 period: 1d basePeriod: 1h 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/ // © ahancock //@version=4 strategy( title = "Hancock - Filtered Volume OBV OSC [Strategy]", initial_capital = 1000, overlay = false, commission_type = strategy.commission.percent, commission_value= 0.075) // Inputs source = input(close, title = "Source", type = input.source) use_volume_filter = input(true, title = "Use Volume Filter", type = input.bool) vol_filter_length = input(20, title = "Volume Filter - Length", type = input.integer, minval = 1) vol_filter_multiplier = input(1.2, title = "Volume Filter - Multiplier", type = input.float, minval = 0.1, step = 0.1) use_osc = input(true, title = "Use Oscillator", type = input.bool) osc_length = input(40, title = "Oscillator - Signal Length", type = input.integer, minval = 1) channel_length = input(65, title = "Channel - Slow Length", minval = 5, maxval = 200, step = 5) channel_percent = input(70, title = "Channel - Fast Length Percent", minval = 5, maxval = 100, step = 5) trade_both = "Both", trade_long = "Long", trade_short = "Short" trade_direction = input("Both", title = "Trade - Direction", options = [trade_both, trade_long, trade_short]) trade_leverage = input(2, title = "Trade - Leverage", type = input.integer, minval = 1, maxval = 100) trade_stop = input(7.5, title = "Trade - Stop Loss %", type = input.float, minval = 0.5, step = 0.5, maxval = 100) trade_trail_threshold = input(5, title = "Trade - Trail Stop Threshold %", type = input.float, minval = 0.5, step = 0.5, maxval = 100) trade_trail = input(5, title = "Trade - Trail Stop Minimum %", type = input.float, minval = 0.5, step = 0.5, maxval = 100) trade_risk = input(100, title = "Trade - Risk %", type = input.integer, step = 1, minval = 1, maxval = 100) test_year = input(2019, "Test - Year", type = input.integer, minval = 1970, maxval = 2222) test_month = input(01, "Test - Month", type = input.integer, minval = 1, maxval = 12) test_day = input(01, "Test - Day", type = input.integer, minval = 1, maxval = 31) // Functions get_round(value, precision) => round(value * (pow(10, precision))) / pow(10, precision) get_obv(values, filter_length, filter_multiplier, use_filter, osc_length, use_osc) => threshold = abs(avg(volume, filter_length) - (stdev(volume, filter_length) * filter_multiplier)) obv = 0.0 if (use_filter and volume < threshold) obv := nz(obv[1]) else obv := nz(obv[1]) + sign(change(values)) * volume use_osc ? (obv - ema(obv, osc_length)) : obv get_dc(high_values, low_values, length) => top = highest(high_values, length) bot = lowest(low_values, length) mid = bot + ((top - bot) / 2) [top, mid, bot] get_dcs(high_values, low_values, length, length_percent) => slow_length = length fast_length = slow_length * length_percent / 100 [slow_top, slow_mid, slow_bot] = get_dc(high_values, low_values, slow_length) [fast_top, fast_mid, fast_bot] = get_dc(high_values, low_values, fast_length) [slow_top, slow_mid, slow_bot, fast_top, fast_mid, fast_bot] // Strategy obv = get_obv( source, vol_filter_length, vol_filter_multiplier, use_volume_filter, osc_length, use_osc) [slow_top_price, _, slow_bot_price, fast_top_price, _, fast_bot_price] = get_dcs(high, low, channel_length, channel_percent) [slow_top_obv, _, slow_bot_obv, fast_top_obv, _, fast_bot_obv] = get_dcs(obv, obv, channel_length, channel_percent) enter_long_price = high > slow_top_price[1] exit_long_price = low < fast_bot_price[1] enter_short_price = low < slow_bot_price[1] exit_short_price = high > fast_top_price[1] enter_long_obv = obv > slow_top_obv[1] and (use_osc ? obv > 0 : true) enter_short_obv = obv < fast_bot_obv[1] and (use_osc ? obv < 0 : true) exit_long_obv = obv < slow_bot_obv[1] exit_short_obv = obv > fast_top_obv[1] // Trade Conditions can_trade = true enter_long_condition = enter_long_obv and enter_long_price exit_long_condition = exit_long_obv and exit_long_price enter_short_condition = enter_short_obv and enter_short_price exit_short_condition = exit_short_obv and exit_short_price position_signal = 0 position_signal := enter_long_condition ? 1 : enter_short_condition ? -1 : exit_long_condition or exit_short_condition ? 0 : position_signal[1] // Positions test_time = timestamp(test_year, test_month, test_day, 0, 0) if (time >= test_time and strategy.opentrades == 0) contracts = get_round((strategy.equity * trade_leverage / close) * (trade_risk / 100), 4) if (trade_direction == trade_both or trade_direction == trade_long) strategy.entry( "LONG", strategy.long, qty = contracts, when = enter_long_condition) if (trade_direction == trade_both or trade_direction == trade_short) strategy.entry( "SHORT", strategy.short, qty = contracts, when = enter_short_condition) in_long = strategy.position_size > 0 in_short = strategy.position_size < 0 float long_high = na float short_low = na long_high := in_long ? high >= nz(long_high[1], low) ? high : long_high[1] : na short_low := in_short ? low <= nz(short_low[1], high) ? low : short_low[1] : na long_change = abs(((long_high - strategy.position_avg_price) / strategy.position_avg_price) * 100) short_change = abs(((short_low - strategy.position_avg_price) / strategy.position_avg_price) * 100) threshold_difference = (strategy.position_avg_price / trade_leverage) * (trade_trail_threshold / 100) long_trail_threshold = in_long ? strategy.position_avg_price + threshold_difference : na short_trail_threshold = in_short ? strategy.position_avg_price - threshold_difference : na long_trail = in_long and long_high > long_trail_threshold ? long_high - (long_high / trade_leverage) * (trade_trail / 100) : na short_trail = in_short and short_low < short_trail_threshold ? short_low + (short_low / trade_leverage) * (trade_trail / 100) : na stop_difference = (strategy.position_avg_price / trade_leverage) * (trade_stop / 100) long_stop = in_long ? long_high > long_trail_threshold ? long_trail : strategy.position_avg_price - stop_difference : na short_stop = in_short ? short_low < short_trail_threshold ? short_trail : strategy.position_avg_price + stop_difference : na strategy.exit("S/L", "LONG", stop = long_stop, qty = abs(get_round(strategy.position_size, 4))) strategy.exit("S/L", "SHORT", stop = short_stop, qty = abs(get_round(strategy.position_size, 4))) strategy.close_all(when = abs(change(position_signal)) > 0) // Plots plotshape(enter_long_condition, "Enter Long", shape.diamond, location.top, color.green) plotshape(exit_long_condition, "Exit Long", shape.diamond, location.top, color.red) plotshape(enter_short_condition, "Enter Short", shape.diamond, location.bottom, color.green) plotshape(exit_short_condition, "Exit Short", shape.diamond, location.bottom, color.red) color_green = #63b987 color_red = #eb3d5c hline(use_osc ? 0 : na) plot(use_osc ? obv : na, color = color.silver, style = plot.style_area, transp = 90) plot(obv, color = color.white, style = plot.style_line, linewidth = 2, transp = 0) plot_slow_top = plot(slow_top_obv, color = color_green, linewidth = 2, transp = 60) plot_slow_bot = plot(slow_bot_obv, color = color_green, linewidth = 2, transp = 60) fill(plot_slow_top, plot_slow_bot, color = color_green, transp = 90) plot_fast_top = plot(fast_top_obv, color = color_red, linewidth = 2, transp = 60) plot_fast_bot = plot(fast_bot_obv, color = color_red, linewidth = 2, transp = 60) fill(plot_fast_top, plot_fast_bot, color = color_red, transp = 90)