该策略是基于Donchain价格通道指标和量化指标OBV振荡器产生的多空信号,进行双向交易的策略。它使用价格通道指标判断价格突破和回调,结合量化指标判断多空力量,产生交易信号。
使用Donchain价格通道指标判断价格上下通道。价格上通道由最高价计算,下通道由最低价计算。
使用OBV量化指标和EMA指标构建OBV振荡器判断多空力量。当振荡器大于0视为多头力量大于空头力量,小于0则反之。
当价格突破上通道,且振荡器大于0时产生做多信号;当价格突破下通道,且振荡器小于0时产生做空信号。
当价格回调至下通道时平仓做多头;当价格回调至上通道时平仓做空头。
使用价格通道判断趋势,避免被震荡行情误导。
结合量化指标判断多空力量,确保交易方向与市场力量一致。
采用双向交易,无论市场上涨还是下跌都可以获利。
设置止损止盈策略,有效控制风险。
价格通道参数设置不当可能导致通道过于宽松或过于狭窄,错过交易机会或产生错误信号。
指标参数设置不当也可能导致信号产生滞后或提前。
突发事件导致快速异常行情可能触发止损单导致损失。
双向交易需要同时管理做多和做空仓位,操作难度较大。
对价格通道参数进行优化,找到最佳参数组合。
对OBV振荡器参数也要测试优化,确保及时准确判断多空力量。
可以考虑结合其他指标如MACD、KD等判断市场趋势,提高信号准确率。
可以测试不同的止损方式,如追踪止损、百分比止损等方式的效果。
可以测试不同品种,寻找最适合该策略运行的品种。
该策略整体来说是一个双向交易策略,同时结合价格行情和量化指标判断市场趋势和多空力量,策略思路清晰、易于理解。优化空间也比较大,通过参数优化和指标组合还可以继续提高策略的稳定性和盈利能力。
/*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)