双重VWAP振動突破戦略

作者: リン・ハーンチャオチャン,日付: 2023-11-23 11:10:28
タグ:

img

概要

ダブルVWAP振動突破戦略は,ダブルVWAP帯を使用して市場動向を分析し,振動する市場における突破機会を探します.市場が振動しているかどうかを判断するためにADX指標を組み合わせ,ブレイクアウトエントリーポイントを特定するために異なる標準偏差の2つのVWAP帯を使用します.

戦略の原則

戦略は以下の主要要素で構成されています.

  1. VWAP 設定: VWAP 帯域とその幅を計算します.stDevMultiplier外側のVWAP幅は,stDevMultiplier2に設定します.

  2. ADX設定: ADX値を計算し,市場が振動しているかどうかを判断する. ADXが値を下回るとき,市場が振動していると考えられる. ADXパラメータは構成可能である.

  3. 入場設定:価格が振動中に外側のVWAP帯を突破すると市場に参入する.ストップ・ロスト価格とテイク・プロフィート価格は設定可能である.

  4. エントリー制限: EMA またはタイムフレームフィルタがオプションで,不利な期間中にエントリーを避ける.

  5. 利益取得:ストップ・ロスの追跡または利益を得る価格が破られた場合,ポジションを閉鎖する.価格が外側のVWAP帯を突破したとき,離脱するオプション.

この戦略は,ADX指標を使用して振動する市場を特定し,価格がVWAP帯を突破したときのエントリー機会を探します.ダブルVWAP帯は,強力なエントリー信号を確保するために追加のフィルターを提供します.トライリングストップは,より安定した方法で利益をロックします.

利点を分析する

  1. 双重VWAP帯は,より強い入力信号のための追加のフィルターを提供します.

  2. ADXオシレーターは振動を特定し,トレンド中に誤ったエントリを回避します.

  3. 後ろのストップは 利益を固定し 罠にはまりないようにします

  4. 高度な設定可能なパラメータは 異なる市場条件に適応します

  5. シンプルな論理は 理解し,複製し,修正しやすくします

リスク と 解決策

  1. パラメータの調節が正しくない場合,入口と出口が過剰に熱心になる可能性があります.戦略の安定性を確保するためにパラメータの組み合わせを最適化してください.

  2. トレーリングストップは攻撃的すぎたり 保守的すぎたりします 変動指標に基づいて動的に調整します

  3. 効率を把握するために時間フィルターを使用して最適化します.

  4. VWAP 帯は不規則な価格に敏感です.追加指標で価格を確認してください.

オプティマイゼーションの方向性

  1. 動的にストップ・ロスの範囲を調整し,波動性および他の指標に基づいて調整します.

  2. 逆動向のエントリを避けるために,より高い時間枠のトレンドと機関信号を追加します.

  3. 波動性と総資本に基づいてポジションのサイズを考慮する.

  4. 異なるVWAPアンカー期間をテストする.VWAP期間が全体の戦略保持期間を決定する.

概要

ダブルVWAP振動ブレイクアウト戦略は,ADXで振動を識別し,VWAP帯で追加のエントリーフィルターを提供する.論理は実装が簡単である.パラメータ調節,ストップ損失最適化,位置サイズ化は安定性を大幅に改善することができる.


/*backtest
start: 2023-10-23 00:00:00
end: 2023-11-22 00:00:00
period: 1h
basePeriod: 15m
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/
// © jordanfray

//@version=5
strategy(title="Double VWAP Strategy", overlay=true, scale=scale.none, max_bars_back=500, default_qty_type=strategy.percent_of_equity, default_qty_value=100,initial_capital=100000, commission_type=strategy.commission.percent, commission_value=0.05, backtest_fill_limits_assumption=2)

// Indenting Classs
indent_1 = " "
indent_2 = "  "
indent_3 = "   "
indent_4 = "    "

// Group Titles
group_one_title = "VWAP Settings"
group_two_title = "ADX Settings"
group_three_title = "Entry Settings"
group_four_title = "Limit Entries"

// Input Tips
adx_thresholdToolTip = "The minumn ADX value to allow opening a postion"
adxCancelToolTip= "You can optionally set a different lower value for ADX that will allow entries even if below the trigger threshold."

ocean_blue = color.new(#0C6090,0)
sky_blue = color.new(#00A5FF,0)
green = color.new(#2DBD85,0)
red = color.new(#E02A4A,0)
light_blue = color.new(#00A5FF,90)
light_green = color.new(#2DBD85,90)
light_red = color.new(#E02A4A,90)
light_yellow = color.new(#FFF900,90)
white = color.new(#ffffff,0)
transparent = color.new(#000000,100)

// Strategy Settings - VWAP
var cumVol = 0.
cumVol += nz(volume)
if barstate.islast and cumVol == 0
    runtime.error("No volume is provided by the data vendor.")
    
computeVWAP(src, isNewPeriod, stDevMultiplier) =>
    var float sum_src_vol = na
    var float sum_vol = na
    var float sum_src_src_vol = na

    sum_src_vol := isNewPeriod ? src * volume : src * volume + sum_src_vol[1]
    sum_vol := isNewPeriod ? volume : volume + sum_vol[1]
    sum_src_src_vol := isNewPeriod ? volume * math.pow(src, 2) : volume * math.pow(src, 2) + sum_src_src_vol[1]

    _vwap = sum_src_vol / sum_vol
    variance = sum_src_src_vol / sum_vol - math.pow(_vwap, 2)
    variance := variance < 0 ? 0 : variance
    standard_deviation = math.sqrt(variance)

    lower_band_value = _vwap - standard_deviation * stDevMultiplier
    upper_band_value = _vwap + standard_deviation * stDevMultiplier

    [_vwap, lower_band_value, upper_band_value]

var anchor = input.string(defval="Session", title="Anchor Period", options=["Session", "Week", "Month", "Quarter", "Year"], group=group_one_title)
src = input(defval = close, title = "Inner VWAP Source", group=group_one_title)
multiplier_inner = input(defval=1.0, title="Inner Bands Multiplier", group=group_one_title)
multiplier_outer = input(defval=2.0, title="Outer Bands Multiplier", group=group_one_title)
show_bands = true

timeChange(period) =>
   ta.change(time(period))

isNewPeriod = switch anchor
    "Session" => timeChange("D")
    "Week" => timeChange("W")
    "Month" => timeChange("M")
    "Quarter" => timeChange("3M")
    "Year" => timeChange("12M")
    => false

float vwap_val = na
float upper_inner_band_value = na
float lower_inner_band_value = na
float upper_outer_band_value = na
float lower_outer_band_value = na

[inner_vwap, inner_bottom, inner_top] = computeVWAP(src, isNewPeriod, multiplier_inner)
[outer_vwap, outer_bottom, outer_top] = computeVWAP(src, isNewPeriod, multiplier_outer)
vwap_val := inner_vwap
upper_inner_band_value := show_bands ? inner_top : na
lower_inner_band_value := show_bands ? inner_bottom : na
upper_outer_band_value := show_bands ? outer_top : na
lower_outer_band_value := show_bands ? outer_bottom : na

plot(vwap_val, title="VWAP", color=green)

upper_inner_band = plot(upper_inner_band_value, title="Upper Inner Band", color=sky_blue)
lower_inner_band = plot(lower_inner_band_value, title="Lower Inner Band", color=sky_blue)
upper_outer_band = plot(upper_outer_band_value, title="Upper Outer Band", linewidth=2, color=ocean_blue)
lower_outer_band = plot(lower_outer_band_value, title="Lower Outer Band", linewidth=2, color=ocean_blue)

fill(upper_outer_band, lower_outer_band, title="VWAP Bands Fill", color= show_bands ? light_blue : na)

// ADX Settings
adx_len = input.int(defval=14, title="ADX Smoothing", group=group_two_title)
di_len = input.int(defval=14, title="DI Length", group=group_two_title)
adx_threshold = input.int(defval=40, title="ADX Threshold", group=group_two_title, tooltip=adx_thresholdToolTip)
dirmov(len) =>
    up = ta.change(high)
    down = -ta.change(low)
    plus_dm = na(up) ? na : (up > down and up > 0 ? up : 0)
    minus_dm = na(down) ? na : (down > up and down > 0 ? down : 0)
    true_range = ta.rma(ta.tr, len)
    plus = fixnan(100 * ta.rma(plus_dm, len) / true_range)
    minus = fixnan(100 * ta.rma(minus_dm, len) / true_range)
    [plus, minus]

adx(di_len, adx_len) =>
    [plus, minus] = dirmov(di_len)
    sum = plus + minus
    adx = 100 * ta.rma(math.abs(plus - minus) / (sum == 0 ? 1 : sum), adx_len)

adx_val = adx(di_len, adx_len)
plot(adx_val, title="ADX")

// Entry Settings
stop_loss_val = input.float(defval=2.0, title="Stop Loss (%)", step=0.1, group=group_three_title)/100
take_profit_val = input.float(defval=6.0, title="Take Profit (%)", step=0.1, group=group_three_title)/100
long_entry_limit_lookback = input.int(defval=1, title="Long Entry Limit Lookback", minval=1, step=1, group=group_three_title)
short_entry_limit_lookback = input.int(defval=1, title="Short Entry Limit Lookback", minval=1, step=1, group=group_three_title)
limit_order_long_price = ta.lowest(close, long_entry_limit_lookback)
limit_order_short_price = ta.highest(close, short_entry_limit_lookback)
start_trailing_after = input.float(defval=3, title="Start Trailing After (%)", step=0.1, group=group_three_title)/100
trail_behind = input.float(defval=2, title="Trail Behind (%)", step=0.1, group=group_three_title)/100
close_early_if_crosses_outter_band = input.bool(defval=false, title="Close early if price crosses outer VWAP band")

// Limit Entries
enableEmaFilter = input.bool(defval=true, title="Use EMA Filter", group=group_four_title)
emaFilterTimeframe = input.timeframe(defval="", title=indent_4+"Timeframe", group=group_four_title)
emaFilterLength = input.int(defval=300, minval=1, step=10, title=indent_4+"Length", group=group_four_title)
emaFilterSource = input.source(defval=hl2, title=indent_4+"Source", group=group_four_title)
ema_filter = ta.ema(emaFilterSource, emaFilterLength)
ema_filter_smoothed = request.security(syminfo.tickerid, emaFilterTimeframe, ema_filter[barstate.isrealtime ? 1 : 0], gaps=barmerge.gaps_on)
plot(enableEmaFilter ? ema_filter_smoothed: na, title="EMA Macro Filter", linewidth=2, color=sky_blue, editable=true)

useTimeFilter = input.bool(defval=false, title="Use Time Session Filter", group=group_four_title)

withinTime = true


long_start_trailing_val = strategy.position_avg_price + (strategy.position_avg_price * start_trailing_after)
short_start_trailing_val = strategy.position_avg_price - (strategy.position_avg_price * start_trailing_after)
long_trail_behind_val = close - (strategy.position_avg_price * (trail_behind/100))
short_trail_behind_val = close + (strategy.position_avg_price * (trail_behind/100))
currently_in_a_long_postion = strategy.position_size > 0
currently_in_a_short_postion = strategy.position_size < 0
long_profit_target = strategy.position_avg_price * (1 + take_profit_val)
long_stop_loss = strategy.position_avg_price * (1.0 - stop_loss_val)
short_profit_target = strategy.position_avg_price * (1 - take_profit_val)
short_stop_loss = strategy.position_avg_price * (1 + stop_loss_val)
bars_since_entry = currently_in_a_long_postion or currently_in_a_short_postion ? bar_index - strategy.opentrades.entry_bar_index(strategy.opentrades - 1) + 1 : 5
plot(bars_since_entry, editable=false, title="Bars Since Entry", color=green)
long_run_up = ta.highest(high, bars_since_entry)
long_trailing_stop = currently_in_a_long_postion and bars_since_entry > 0 and long_run_up > long_start_trailing_val ? long_run_up - (long_run_up * trail_behind) : long_stop_loss
//long_run_up_line = plot(long_run_up, style=plot.style_stepline, editable=false, color=currently_in_a_long_postion ? green : transparent)
long_trailing_stop_line = plot(long_trailing_stop, style=plot.style_stepline, editable=false, color=currently_in_a_long_postion ? long_trailing_stop > strategy.position_avg_price ? green : red : transparent)
short_run_up = ta.lowest(low, bars_since_entry)
short_trailing_stop = currently_in_a_short_postion and bars_since_entry > 0 and short_run_up < short_start_trailing_val ? short_run_up + (short_run_up * trail_behind) : short_stop_loss
//short_run_up_line = plot(short_run_up, style=plot.style_stepline, editable=false, color=currently_in_a_short_postion ? green : transparent)
short_trailing_stop_line = plot(short_trailing_stop, style=plot.style_stepline, editable=false, color=currently_in_a_short_postion ? short_trailing_stop < strategy.position_avg_price ? green : red : transparent)


// Conditions
adx_is_below_threshold = adx_val < adx_threshold
price_crossed_down_VWAP_lower_outer_band = ta.crossunder(low, lower_outer_band_value)
price_closed_above_VWAP_lower_outer_band = close > lower_outer_band_value
price_crossed_up_VWAP_upper_outer_band =  ta.crossover(high,upper_outer_band_value)
price_closed_below_VWAP_upper_outer_band = close < upper_outer_band_value
price_above_ema_filter = close > ema_filter_smoothed
price_below_ema_filter = close < ema_filter_smoothed

//Trade Restirctions
no_trades_allowed = not withinTime or not adx_is_below_threshold

// Enter trades when...
long_conditions_met = enableEmaFilter ? price_above_ema_filter and not currently_in_a_long_postion and withinTime and adx_is_below_threshold and price_crossed_down_VWAP_lower_outer_band and price_closed_above_VWAP_lower_outer_band : not currently_in_a_long_postion and withinTime and adx_is_below_threshold and price_crossed_down_VWAP_lower_outer_band and price_closed_above_VWAP_lower_outer_band
short_conditions_met = enableEmaFilter ? price_below_ema_filter and not currently_in_a_short_postion and withinTime and adx_is_below_threshold and price_crossed_up_VWAP_upper_outer_band and price_closed_below_VWAP_upper_outer_band : not currently_in_a_short_postion and withinTime and adx_is_below_threshold and price_crossed_up_VWAP_upper_outer_band and price_closed_below_VWAP_upper_outer_band
plotshape(long_conditions_met ? close  : na, title="Long Entry Symbol", color=green, style=shape.triangleup, location=location.abovebar)
plotshape(short_conditions_met ? close  : na, title="Short Entry Symbol", color=red, style=shape.triangledown, location=location.belowbar)

// Take Profit When...
price_closed_below_short_trailing_stop = ta.cross(close, short_trailing_stop)
price_hit_short_entry_profit_target = low > short_profit_target
price_closed_above_long_entry_trailing_stop = ta.cross(close, long_trailing_stop)
price_hit_long_entry_profit_target = high > long_profit_target

long_position_take_profit = close_early_if_crosses_outter_band ? price_crossed_up_VWAP_upper_outer_band or price_closed_above_long_entry_trailing_stop or price_hit_long_entry_profit_target : price_closed_above_long_entry_trailing_stop or price_hit_long_entry_profit_target
short_position_take_profit = close_early_if_crosses_outter_band ? price_crossed_down_VWAP_lower_outer_band or price_closed_below_short_trailing_stop or price_hit_short_entry_profit_target : price_closed_below_short_trailing_stop or price_hit_short_entry_profit_target

// Cancel limir order if...
cancel_long_condition = false
cancel_short_condition = false


// Long Entry
strategy.entry(id="Long", direction=strategy.long, limit=limit_order_long_price, when=long_conditions_met)
strategy.cancel(id="Cancel Long", when=cancel_long_condition)
strategy.exit(id="Close Long", from_entry="Long", stop=long_trailing_stop, limit=long_profit_target, when=long_position_take_profit)

// Short Entry 
strategy.entry(id="Short", direction=strategy.short, limit=limit_order_short_price, when=short_conditions_met)
strategy.cancel(id="Cancel Short", when=cancel_short_condition)
strategy.exit(id="Close Short", from_entry="Short", stop=short_trailing_stop, limit=short_profit_target, when=short_position_take_profit)

entry = plot(strategy.position_avg_price, editable=false, title="Entry", style=plot.style_stepline, color=currently_in_a_long_postion or currently_in_a_short_postion ? color.blue : transparent, linewidth=1)
fill(entry,long_trailing_stop_line, editable=false, color=currently_in_a_long_postion ? long_trailing_stop > strategy.position_avg_price ? light_green : light_red : transparent)
fill(entry,short_trailing_stop_line, editable=false, color=currently_in_a_short_postion ? short_trailing_stop < strategy.position_avg_price ? light_green : light_red : transparent)
bgcolor(title="No Trades Allowed", color=no_trades_allowed ? light_red : light_green)


もっと