成交量加速定向能量比(VADER)利用价格变动(位移)和相关成交量(力度)来估计幕后的正(买入)和负(卖出)“能量”,使交易者能够更详细地“解读市场行为”,并相应地调整其交易决策。
VADER是怎么工作的? 我一直是技术分析概念的粉丝,这些概念很简单,并且将价格行为和交易量结合在一起——维德背后的概念其实很简单。
让我们来看看它,避免太过技术化: 与大宗交易相关的大宗价格变动意味着买家(如果涨价)或卖家(如果涨价)都是认真的,并且“控制”了交易 另一方面,当价格波动很小但成交量很大时,这意味着在买入和卖出之间存在一场斗争,或更多的能量平衡。 此外,当大宗价格变动与相对有限的成交量相关联时,买家或卖家都缺乏“能量”——像这样的变动通常是短暂的。
与VADER的类比是,我们将价格波动(2 bar之间的收盘变化)视为位移(或动作结果),将相关的交易量视为该动作背后的“作用力”——将位移和作用力这两个值结合在一起,为我们提供了潜在能量(在特定方向)的表示或代理。 当两个值(位移和作用力)都较高时,则产生的能量较高-如果其中一个值较低,则产生的能量较低。
然后,我们取每个方向上的相对能量的平均值(正=买入,负=卖出),并计算净能量。
请注意,我们是从交易的角度来进行类比,而不是从物理学的角度:)–我们需要明白,物理学中的能量计算是不同的。
/*backtest start: 2022-04-19 09:00:00 end: 2022-05-18 15:00:00 period: 1h basePeriod: 15m exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}] args: [["ContractType","rb888",360008]] */ // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © RedKTrader //@version=5 indicator('RedK Volume-Accelerated Directional Energy Ratio', 'RedK VADER v3.0', precision=0, timeframe='', timeframe_gaps=false) // *********************************************************************************************************** // Choose volume calculation method.. Relative vs full. // Relative magnifies effect of recent volume spikes (up or down) f_RelVol(_value, _length) => min_value = ta.lowest(_value, _length) max_value = ta.highest(_value, _length) ta.stoch(_value, max_value, min_value, _length) / 100 // *********************************************************************************************************** // *********************************************************************************************************** // Choose MA type for the base DER calculation .. // WMA is my preference and is default .. SMA is really slow and lags a lot - but added for comparison f_derma(_data, _len, MAOption) => value = MAOption == 'SMA' ? ta.sma(_data, _len) : MAOption == 'EMA' ? ta.ema(_data, _len) : ta.wma(_data, _len) // *********************************************************************************************************** // =========================================================================================================== // Inputs // =========================================================================================================== price = close length = input.int(6, '周期', minval=1) DER_avg = input.int(5, '均值', minval=1, inline='DER', group='方向能量比') MA_Type = input.string('WMA', 'DER MA 类型', options=['WMA', 'EMA', 'SMA'], inline='DER', group='方向能量比') smooth = input.int(3, '平滑', minval=1, inline='DER_1', group='方向能量比') show_senti = input.bool(false, '显示观点', inline='DER_s', group='方向能量比') senti = input.int(20, '观点周期', minval=1, inline='DER_s', group='方向能量比') v_calc = input.string('Relative', '计算选项', options=['Relative', 'Full', 'None'], group='成交量参数') vlookbk = input.int(10, '回看周期 (相对的)', minval=1, group='成交量参数') // =========================================================================================================== // Calculations // =========================================================================================================== // Volume Calculation Option -- will revert to no volume acceleration for instruments with no volume data vola = v_calc == 'None' or na(volume) ? 1 : v_calc == 'Relative' ? f_RelVol(volume, vlookbk) : volume R = (ta.highest(2) - ta.lowest(2)) / 2 // R is the 2-bar average bar range - this method accomodates bar gaps sr = ta.change(price) / R // calc ratio of change to R rsr = math.max(math.min(sr, 1), -1) // ensure ratio is restricted to +1/-1 in case of big moves c = fixnan(rsr * vola) // add volume accel -- fixnan adresses cases where no price change between bars c_plus = math.max(c, 0) // calc directional vol-accel energy c_minus = -math.min(c, 0) // plot(c_plus) // plot(c_minus) avg_vola = f_derma(vola, length, MA_Type) dem = f_derma(c_plus, length, MA_Type) / avg_vola // directional energy ratio sup = f_derma(c_minus, length, MA_Type) / avg_vola adp = 100 * ta.wma(dem, DER_avg) // average DER asp = 100 * ta.wma(sup, DER_avg) anp = adp - asp // net DER.. anp_s = ta.wma(anp, smooth) // Calculate Sentiment - a VADER for a longer period and can act as a baseline (compared to a static 0 value) // note we're not re-calculating vol_avg, demand or supply energy for sentiment. this would've been a different approach s_adp = 100 * ta.wma(dem, senti) // average DER for sentiment length s_asp = 100 * ta.wma(sup, senti) V_senti = ta.wma(s_adp - s_asp, smooth) // =========================================================================================================== // Colors & plots // =========================================================================================================== c_adp = color.new(color.aqua, 30) c_asp = color.new(color.orange, 30) c_fd = color.new(color.green, 80) c_fs = color.new(color.red, 80) c_zero = color.new(#ffee00, 70) c_up = color.new(#359bfc, 0) c_dn = color.new(#f57f17, 0) c_sup = color.new(#33ff00, 80) c_sdn = color.new(#ff1111, 80) up = anp_s >= 0 s_up = V_senti >=0 hline(0, 'Zero Line', c_zero, hline.style_solid) // ============================================================================= // v3.0 --- Sentiment will be represented as a 4-color histogram c_grow_above = #1b5e2080 c_grow_below = #dc4c4a80 c_fall_above = #66bb6a80 c_fall_below = #ef8e9880 sflag_up = math.abs(V_senti) >= math.abs(V_senti[1]) plot(show_senti ? V_senti : na, "Sentiment", style=plot.style_columns, color = s_up ? (sflag_up ? c_grow_above : c_fall_above) : sflag_up ? c_grow_below : c_fall_below) // ============================================================================= s = plot(asp, 'Supply Energy', c_asp, 2, style=plot.style_circles, join=true) d = plot(adp, 'Demand Energy', c_adp, 2, style=plot.style_cross, join=true) fill(d, s, adp > asp ? c_fd : c_fs) plot(anp, 'VADER', color.new(color.gray, 30), display=display.none) plot(anp_s, 'Signal', up ? c_up : c_dn, 3) // =========================================================================================================== // v2.0 adding alerts // =========================================================================================================== Alert_up = ta.crossover(anp_s,0) Alert_dn = ta.crossunder(anp_s,0) Alert_swing = ta.cross(anp_s,0) // "." in alert title for the alerts to show in the right order up/down/swing alertcondition(Alert_up, ". VADER Crossing 0 Up", "VADER Up - Buying Energy Detected!") alertcondition(Alert_dn, ".. VADER Crossing 0 Down", "VADER Down - Selling Energy Detected!") alertcondition(Alert_swing, "... VADER Crossing 0", "VADER Swing - Possible Reversal") // =========================================================================================================== // v3.0 more alerts for VADER crossing Sentiment // =========================================================================================================== v_speedup = ta.crossover(anp_s, V_senti) v_slowdn = ta.crossunder(anp_s, V_senti) alertcondition(v_speedup, "* VADER Speeding Up", "VADER Speeding Up!") alertcondition(v_slowdn, "** VADER Slowing Down", "VADER Slowing Down!") if Alert_up strategy.entry("Enter Long", strategy.long) else if Alert_dn strategy.entry("Enter Short", strategy.short)