资源加载中... loading...

VWAP交易策略与成交量异常监测

Author: ChaoZhang, Date: 2024-06-07 15:44:04
Tags: VWAPRSIYTDSMA

VWAP交易策略与成交量异常监测

概述

该策略基于多个VWAP(成交量加权平均价)水平,包括开盘价、最高价、最低价和成交量异常高的蜡烛图的VWAP。策略利用VWAP作为支撑位和阻力位,同时考虑了成交量的异常情况。当价格突破VWAP水平并满足一定条件时,策略会产生交易信号。此外,该策略还使用RSI指标来检测动量变化,作为平仓条件。

策略原理

  1. 计算多个VWAP水平,包括开盘价VWAP、最高价VWAP、最低价VWAP和异常高成交量蜡烛图的VWAP。
  2. 检测成交量异常高的蜡烛图,并在该蜡烛图上重置异常高成交量VWAP的累积变量。
  3. 在VWAP水平上下设置偏离值,作为交易信号的触发条件。
  4. 检查价格是否在VWAP的另一侧存在跳空,以避免错误信号。
  5. 根据价格相对于VWAP的位置以及收盘价与开盘价的关系,产生多个交易信号,包括Wick(影线)和Crossover(交叉)两种类型。
  6. 使用RSI指标检测动量变化,当RSI超过70或低于30时,平仓相应的交易。

优势分析

  1. 该策略利用了多个VWAP水平,提供了更全面的支撑位和阻力位信息。
  2. 通过检测成交量异常高的蜡烛图,策略可以捕捉到市场的重要变化。
  3. 设置偏离值可以过滤掉一些噪音信号,提高交易信号的质量。
  4. 考虑了价格在VWAP另一侧的跳空情况,避免了一些错误信号。
  5. 根据价格与VWAP的相对位置以及收盘价与开盘价的关系,产生多个交易信号,增加了策略的灵活性。
  6. 使用RSI指标作为平仓条件,可以帮助策略在动量发生变化时及时退出交易。

风险分析

  1. 该策略依赖于VWAP水平,如果市场出现极端行情,VWAP可能失去效力。
  2. 异常高成交量的判断基于固定的阈值,可能无法适应不同的市场情况。
  3. 偏离值的设置可能需要根据不同的市场和交易品种进行调整。
  4. 该策略产生了多个交易信号,可能导致过度交易和高昂的交易成本。
  5. RSI指标可能产生滞后的平仓信号,导致策略承受更大的风险。

优化方向

  1. 对VWAP水平的计算方法进行优化,如考虑更长的时间周期或使用加权方法。
  2. 优化异常高成交量的判断标准,如采用自适应的阈值或结合其他成交量指标。
  3. 对偏离值进行参数优化,找到最佳的偏离幅度。
  4. 引入风险管理措施,如设置止损和止盈,控制单笔交易的风险敞口。
  5. 尝试其他的动量指标或组合多个指标,以获得更准确的平仓信号。
  6. 对交易信号进行过滤,减少过度交易和降低交易成本。

总结

该策略利用多个VWAP水平和成交量异常检测,生成多样化的交易信号。通过考虑价格与VWAP的相对位置、收盘价与开盘价的关系以及RSI指标,策略试图捕捉市场的重要变化并及时退出交易。然而,该策略也存在一些风险,如对极端行情的适应性、过度交易和滞后的平仓信号等。为了进一步改进,可以考虑优化VWAP的计算方法、异常成交量的判断标准、偏离值的设置,并引入风险管理措施和更多的指标组合。总的来说,该策略为基于VWAP的交易提供了一个很好的起点,但仍需要根据实际市场情况进行优化和调整。


/*backtest
start: 2024-05-30 00:00:00
end: 2024-06-06 00:00:00
period: 4h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=5
strategy("5 Anchored VWAP Strategy with Abnormally High Volume Candle", overlay=true)

// Initialize VWAP variables
var float vwap_open = na
var float vwap_high = na
var float vwap_low = na
var float vwap_high_volume = na

var float cum_v_open = 0
var float cum_v_high = 0
var float cum_v_low = 0
var float cum_v_high_volume = 0

var float cum_pv_open = 0
var float cum_pv_high = 0
var float cum_pv_low = 0
var float cum_pv_high_volume = 0

var float highest_volume = 0

// Initialize YTD high and low variables
var float ytd_high = na
var float ytd_low = na

// Parameters for abnormal volume detection
length = 20
volume_threshold = 2.0

// Displacement parameters
displacement_percentage = 0.01 // 1% displacement

// Calculate average volume
avg_volume = ta.sma(volume, length)

// Check if it's the first day of the year
is_first_day_of_year = year(time) != year(time[1])

// Reset YTD high and low on the first day of the year
if is_first_day_of_year
    ytd_high := high
    ytd_low := low

// Update YTD high and low
ytd_high := na(ytd_high) ? high : math.max(ytd_high, high)
ytd_low := na(ytd_low) ? low : math.min(ytd_low, low)

// Update cumulative variables for open VWAP
cum_v_open += volume
cum_pv_open += close * volume
if cum_v_open != 0
    vwap_open := cum_pv_open / cum_v_open

// Update cumulative variables for high VWAP
if high == ytd_high
    cum_v_high := 0
    cum_pv_high := 0

cum_v_high += volume
cum_pv_high += close * volume
if cum_v_high != 0
    vwap_high := cum_pv_high / cum_v_high

// Update cumulative variables for low VWAP
if low == ytd_low
    cum_v_low := 0
    cum_pv_low := 0

cum_v_low += volume
cum_pv_low += close * volume
if cum_v_low != 0
    vwap_low := cum_pv_low / cum_v_low

// Check for new high-volume candle that is also abnormally high and reset cumulative variables for high-volume VWAP
new_high_volume = false
if volume > highest_volume and volume > volume_threshold * avg_volume
    highest_volume := volume
    cum_v_high_volume := 0
    cum_pv_high_volume := 0
    new_high_volume := true

cum_v_high_volume += volume
cum_pv_high_volume += close * volume
if cum_v_high_volume != 0
    vwap_high_volume := cum_pv_high_volume / cum_v_high_volume

// Plot VWAPs
plot(vwap_open, color=color.red, linewidth=2, title="VWAP Open")
plot(vwap_high, color=color.green, linewidth=2, title="VWAP High")
plot(vwap_low, color=color.blue, linewidth=2, title="VWAP Low")
plot(vwap_high_volume, color=color.purple, linewidth=2, title="VWAP High Volume")

// Plot a vertical line on the chart only when a new high-volume VWAP anchor occurs
bgcolor(new_high_volume ? color.new(color.purple, 90) : na, offset=-1)

// Calculate displacement amounts
displacement_amount_open = vwap_open * displacement_percentage
displacement_amount_high = vwap_high * displacement_percentage
displacement_amount_low = vwap_low * displacement_percentage
displacement_amount_high_volume = vwap_high_volume * displacement_percentage

// Check for gaps on the opposite side of a VWAP
gap_up_opposite_open = na(close[1]) ? false : (open > close[1] and open < vwap_open and close[1] > vwap_open)
gap_down_opposite_open = na(close[1]) ? false : (open < close[1] and open > vwap_open and close[1] < vwap_open)

gap_up_opposite_high = na(close[1]) ? false : (open > close[1] and open < vwap_high and close[1] > vwap_high)
gap_down_opposite_high = na(close[1]) ? false : (open < close[1] and open > vwap_high and close[1] < vwap_high)

gap_up_opposite_low = na(close[1]) ? false : (open > close[1] and open < vwap_low and close[1] > vwap_low)
gap_down_opposite_low = na(close[1]) ? false : (open < close[1] and open > vwap_low and close[1] < vwap_low)

gap_up_opposite_high_volume = na(close[1]) ? false : (open > close[1] and open < vwap_high_volume and close[1] > vwap_high_volume)
gap_down_opposite_high_volume = na(close[1]) ? false : (open < close[1] and open > vwap_high_volume and close[1] < vwap_high_volume)

// RSI calculation for momentum change detection
rsi = ta.rsi(close, 14)
long_exit_condition = rsi > 70
short_exit_condition = rsi < 30

// Debugging Plots
plotshape(not gap_up_opposite_open and not gap_down_opposite_open and close > vwap_open and low < vwap_open - displacement_amount_open and close[1] < vwap_open, style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small, title="Open Long Signal")
plotshape(not gap_up_opposite_open and not gap_down_opposite_open and close < vwap_open and high > vwap_open + displacement_amount_open and close[1] > vwap_open, style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small, title="Open Short Signal")

plotshape(not gap_up_opposite_high and not gap_down_opposite_high and close > vwap_high and low < vwap_high - displacement_amount_high and close[1] < vwap_high, style=shape.triangledown, location=location.abovebar, color=color.blue, size=size.small, title="High Long Signal")
plotshape(not gap_up_opposite_high and not gap_down_opposite_high and close < vwap_high and high > vwap_high + displacement_amount_high and close[1] > vwap_high, style=shape.triangleup, location=location.belowbar, color=color.orange, size=size.small, title="High Short Signal")

plotshape(not gap_up_opposite_low and not gap_down_opposite_low and close > vwap_low and low < vwap_low - displacement_amount_low and close[1] < vwap_low, style=shape.triangledown, location=location.abovebar, color=color.purple, size=size.small, title="Low Long Signal")
plotshape(not gap_up_opposite_low and not gap_down_opposite_low and close < vwap_low and high > vwap_low + displacement_amount_low and close[1] > vwap_low, style=shape.triangleup, location=location.belowbar, color=color.yellow, size=size.small, title="Low Short Signal")

plotshape(not gap_up_opposite_high_volume and not gap_down_opposite_high_volume and close > vwap_high_volume and low < vwap_high_volume - displacement_amount_high_volume and close[1] < vwap_high_volume, style=shape.triangledown, location=location.abovebar, color=color.teal, size=size.small, title="High Volume Long Signal")
plotshape(not gap_up_opposite_high_volume and not gap_down_opposite_high_volume and close < vwap_high_volume and high > vwap_high_volume + displacement_amount_high_volume and close[1] > vwap_high_volume, style=shape.triangleup, location=location.belowbar, color=color.fuchsia, size=size.small, title="High Volume Short Signal")

// Trading signals based on VWAP support/resistance with displacement, no gaps on the opposite side, and bounce conditions
if not gap_up_opposite_open and not gap_down_opposite_open
    if (close > vwap_open and low < vwap_open)
        if close > open
            strategy.entry("Long_Open_Wick", strategy.long, comment="Wick")
        else
            strategy.entry("Long_Open_Crossover", strategy.long, comment="Crossover")
    
    if (close < vwap_open and high > vwap_open)
        if close < open
            strategy.entry("Short_Open_Wick", strategy.short, comment="Wick")
        else
            strategy.entry("Short_Open_Crossover", strategy.short, comment="Crossover")

if not gap_up_opposite_high and not gap_down_opposite_high
    if (close > vwap_high and low < vwap_high)
        if close > open
            strategy.entry("Long_High_Wick", strategy.long, comment="Wick")
        else
            strategy.entry("Long_High_Crossover", strategy.long, comment="Crossover")
    
    if (close < vwap_high and high > vwap_high)
        if close < open
            strategy.entry("Short_High_Wick", strategy.short, comment="Wick")
        else
            strategy.entry("Short_High_Crossover", strategy.short, comment="Crossover")

if not gap_up_opposite_low and not gap_down_opposite_low
    if (close > vwap_low and low < vwap_low)
        if close > open
            strategy.entry("Long_Low_Wick", strategy.long, comment="Wick")
        else
            strategy.entry("Long_Low_Crossover", strategy.long, comment="Crossover")
    
    if (close < vwap_low and high > vwap_low)
        if close < open
            strategy.entry("Short_Low_Wick", strategy.short, comment="Wick")
        else
            strategy.entry("Short_Low_Crossover", strategy.short, comment="Crossover")

if not gap_up_opposite_high_volume and not gap_down_opposite_high_volume
    if (close > vwap_high_volume and low < vwap_high_volume)
        if close > open
            strategy.entry("Long_High_Volume_Wick", strategy.long, comment="Wick")
        else
            strategy.entry("Long_High_Volume_Crossover", strategy.long, comment="Crossover")
    
    if (close < vwap_high_volume and high > vwap_high_volume)
        if close < open
            strategy.entry("Short_High_Volume_Wick", strategy.short, comment="Wick")
        else
            strategy.entry("Short_High_Volume_Crossover", strategy.short, comment="Crossover")

// Exit trades based on RSI momentum change
if strategy.position_size > 0 and long_exit_condition
    strategy.close("Long_Open_Wick")
    strategy.close("Long_Open_Crossover")
    strategy.close("Long_High_Wick")
    strategy.close("Long_High_Crossover")
    strategy.close("Long_Low_Wick")
    strategy.close("Long_Low_Crossover")
    strategy.close("Long_High_Volume_Wick")
    strategy.close("Long_High_Volume_Crossover")

if strategy.position_size < 0 and short_exit_condition
    strategy.close("Short_Open_Wick")
    strategy.close("Short_Open_Crossover")
    strategy.close("Short_High_Wick")
    strategy.close("Short_High_Crossover")
    strategy.close("Short_Low_Wick")
    strategy.close("Short_Low_Crossover")
    strategy.close("Short_High_Volume_Wick")
    strategy.close("Short_High_Volume_Crossover")

相关内容

更多内容