
VS, ATR, MA200, HTF
市場がVolume Spike ((VS) 信号を発したときに,多重MAフィルターで,勝利率は従来の突破戦略より明らかに優れている. 核心論理はシンプルで粗暴な大資金の入場は必ず痕跡を残す,私たちがすべきことは,これらの”クジラ”の足跡をたどることである.
伝統的な戦略は価格を見ており,このシステムは取引量異動を見ており。21周期で2つの極値を除き計算された平均波動,現在のK線波動が平均の2.3倍以上で,收盘価格の0.7%以上を占める時にシグナルをトリガーする。さらに重要なことに,收盘価格は当根K線の上65%の位置に位置しなければならないので,これが多頭主導の放量であることを確認する。
数字が語っていますこのVS検知システムは,偽の突破の90%以上をフィルターし,本当に大きな資金が関与しているケースのみを捕まえる.
市場動向がすべてを決定する.戦略は4つのMA200防衛線を設定している.
これはどういう意味ですか?システムから信号が来ないので, 明らかに下落するトレンドに引っかかることは決してありません.
各取引のリスクは100ドルで固定され,ATRで動的にポジションサイズが計算されます.14サイクルATRを初期ストップとして2.7倍に掛け,このパラメータは大量にリテックされ,通常の波動ストップを回避するとともに,実際の反転時にタイムリーにオフになるように最適化されています.
重要なイノベーション: 新しいVS信号が出るたびに,ストップ・プライスは自動で最新の低点に移動し,すでに有利なをロックしながらトレンドにスペースを残します.
最初のVS信号でポジションを開け,第二のVS信号でポジションを上げ,第三のVS信号の後にストロップがコスト価格に移動する.これは盲目なポジションアップではなく,市場の継続的な異動の論理に基づく判断であり,連続した大資金の流入は通常,より大きな市場状況を意味している.
データを裏付ける: 過去の回顧では,連続VS信号が3回以上発生したケースで,平均上昇は単一のVS信号の2.8倍であった.
第4回VS信号が触発されると,自動で33%のポジションを停止し,第5回VS信号が触発されると,残りの50%のポジションを停止する.このような設計の論理は,前期VS信号がトレンドを確認し,後期VS信号はトップ領域に近づく傾向にある.
戦闘効果“エレベーターに乗る”という厄介な状況から逃れ,その場を一部確保し,スーパーマーケットの可能性を捉えることができる.
これはリスク管理の精髓である.浮動が2%に達すると,ストップ・プローズは自動的にコスト価格より0.15%上昇する. 保守的なように見えるが,実際には,戦略の長期的安定性を保証する前提で,大トレンドに十分な余地がある.
なぜ2%がきっかけになったのか?この取引は2パーセントの浮動率で,78パーセント以上の最終利益率を示している.
策略はBTC 1時間図の最適化に専用され,トレンド的な状況で顕著に表れている.注意すべきは,揺れ動いている市場ではVS信号が頻繁だが幅は限られており,連続した小幅のストロップが発生する可能性があることである.
危険性についてのヒント: 過去の反転は,将来の利益を意味するものではなく,戦略には,連続した損失のリスクがある. 単一リスクを厳密に制御し,口座の1-2%を超えてはならないことを推奨する. 市場環境が変化する時には,戦略のパフォーマンスは大きく異なる可能性があります.
毎日シグナルを期待しているなら,この戦略はあなたには向かないだろう.あなたが本当のトレンドを捉えたいなら,そして質の高い入場機会を待たしたいなら,このサメ追跡器は深く研究する価値がある.
/*backtest
start: 2025-01-13 00:00:00
end: 2026-01-11 00:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_OKX","currency":"ETH_USDT","balance":500000}]
*/
//@version=5
strategy("BULL Whale Finder + BTC 1h",
overlay=true,
pyramiding=4,
calc_on_every_tick=true,
process_orders_on_close=false)
// =====================================================
// INPUTS (SOLO 1)
// =====================================================
float MLPT_USD = input.float(100, "MLPT USD (riesgo por trade)", minval=1, step=1)
// =====================================================
// HARD CODED (NO TOCAR)
// =====================================================
// Execution
string POINTER = ""
bool allowBacktestNoPointer = true
// SL (ATR)
int atrLen = 14
float atrMult = 2.7
// Pay-Self
bool usePaySelf = true
float payTriggerPct = 2.0 / 100.0
float payLockPct = 0.15 / 100.0
// MA200 Filter
bool useMA200Filter = true
bool useMA200Slope = true
int ma200Len = 200
int ma200SlopeLen = 20
// MA200 HTF
bool useMA200HTF = true
string ma200HTF_tf = "240" // 4H
// VS Params
int vsLen = 21
int vsOut = 2
float vsMult = 2.3
float vsMinPct = 0.7 / 100.0
float vsClosePct = 35.0 / 100.0
// Exchange / rounding
float SL_BUFFER = 0.01
float qtyFixed = 0.001
float stepQty = 0.001
float MIN_NOTIONAL_USD = 20.0
// TP
bool tpFromVS3 = false
float tp1Pct = 33.0
float tp2Pct = 50.0
// Visual
bool showSL = true
bool showShade = true
bool showEntryDot = true
color cSL = color.new(color.green, 0)
color cShade = color.new(color.green, 85)
color cVSentry = color.lime
color cVStp = color.orange
// Proximidad MA1/MA2 (tal cual tus valores)
bool useMA1Filter = true // exigir close > MA20
bool useEntryNearMA2 = true // VS#1 cerca MA200 desde LOW
float entryNearMA2Pct = 6.0 / 100.0 // 6%
bool useEntryNearMA1 = false // desactivado (tu screenshot)
float entryNearMA1Pct = 6.0 / 100.0 // queda fijo aunque no se use
bool useMA1MA2Near = true // MA20 y MA200 cerca
float ma1ma2NearPct = 6.0 / 100.0 // 6%
// =====================================================
// JSON (ALERTS) — hardcode pointer vacío
// =====================================================
f_json(_event, _reduce) =>
"{" + "\"ticker\":\"{{ticker}}\"," + "\"action\":\"{{strategy.order.action}}\"," + "\"quantity\":\"{{strategy.order.contracts}}\"," + "\"pointer\":\"" + POINTER + "\"," + "\"reduce_only\":" + (_reduce ? "true" : "false") + "," + "\"event\":\"" + _event + "\"}"
// =====================================================
// HELPERS
// =====================================================
f_round_step_floor(_x, _step) => _step > 0 ? math.floor(_x / _step) * _step : _x
f_round_step_ceil(_x, _step) => _step > 0 ? math.ceil(_x / _step) * _step : _x
f_qty_min_notional(_qty, _px) =>
need = (MIN_NOTIONAL_USD > 0) ? (MIN_NOTIONAL_USD / _px) : 0.0
qRaw = math.max(_qty, need)
f_round_step_ceil(qRaw, stepQty)
f_qty_mlpt_long(_entry, _sl) =>
risk = _entry - _sl
qRaw = (risk > 0) ? (MLPT_USD / risk) : 0.0
f_round_step_floor(qRaw, stepQty)
// =====================================================
// MA200 / MA20
// =====================================================
ma200 = ta.sma(close, ma200Len)
plot(ma200, "MA200", color=color.red, linewidth=2)
ma1 = ta.sma(close, 20)
plot(ma1, "MA20", color=color.blue, linewidth=2)
ma200Slope = ma200 - ma200[ma200SlopeLen]
ma200SlopeOK = (not useMA200Slope) or (not na(ma200Slope) and ma200Slope > 0)
ma200FilterOK = (not useMA200Filter) or (close > ma200 and ma200SlopeOK)
// HTF MA200
ma200HTF = request.security(syminfo.tickerid, ma200HTF_tf, ta.sma(close, ma200Len))
ma200HTFFilterOK = (not useMA200HTF) or (not na(ma200HTF) and close > ma200HTF)
// Proximidad (medido desde LOW)
ma1FilterOK = (not useMA1Filter) or (close > ma1)
distLowMA2 = (not na(ma200) and low > 0) ? math.abs(low - ma200) / low : na
entryNearMA2OK = (not useEntryNearMA2) or (not na(distLowMA2) and distLowMA2 <= entryNearMA2Pct)
distLowMA1 = (not na(ma1) and low > 0) ? math.abs(low - ma1) / low : na
entryNearMA1OK = (not useEntryNearMA1) or (not na(distLowMA1) and distLowMA1 <= entryNearMA1Pct)
distMA1MA2 = (not na(ma1) and not na(ma200) and ma1 != 0) ? math.abs(ma1 - ma200) / ma1 : na
ma1ma2NearOK = (not useMA1MA2Near) or (not na(distMA1MA2) and distMA1MA2 <= ma1ma2NearPct)
// =====================================================
// VS DETECTION — LONG
// =====================================================
rng = high - low
f_avg_no_out(_len, _k) =>
float result = na
if bar_index >= _len
arr = array.new_float(0)
for i = 0 to _len - 1
array.push(arr, high[i] - low[i])
array.sort(arr, order.ascending)
n = array.size(arr)
kk = math.min(_k, math.floor((n - 1) / 2))
start = kk
stop = n - kk - 1
sum = 0.0
count = 0
if stop >= start
for j = start to stop
sum += array.get(arr, j)
count += 1
result := count > 0 ? sum / count : na
result
avgRng = f_avg_no_out(vsLen, vsOut)
okRange = not na(avgRng) and rng >= avgRng * vsMult
okMinPct = rng >= close * vsMinPct
strongBull = rng > 0 and (high - close) / rng <= vsClosePct
isVS = okRange and okMinPct and strongBull
// =====================================================
// EXEC FLAGS (hardcoded)
// =====================================================
hasPointer = str.length(POINTER) > 0
canTrade = allowBacktestNoPointer or hasPointer
// =====================================================
// VARS
// =====================================================
var float slPrice = na
var float entryPx = na
var float initQty = na
var float mfePct = 0.0
var bool payArmed = false
var int vsCount = 0
var float vs2Low = na
var bool tp1 = false
var bool tp2 = false
// RESET
if strategy.position_size == 0
slPrice := na
entryPx := na
initQty := na
mfePct := 0.0
payArmed := false
vsCount := 0
vs2Low := na
tp1 := false
tp2 := false
// =====================================================
// ENTRY (VS #1) + SL inicial ATR
// =====================================================
enterCond = barstate.isconfirmed and isVS and ma200FilterOK and ma200HTFFilterOK and ma1FilterOK and entryNearMA2OK and entryNearMA1OK and ma1ma2NearOK and strategy.position_size == 0 and canTrade
if enterCond
atr = ta.atr(atrLen)
slInit = close - atr * atrMult
qtyRisk = f_qty_mlpt_long(close, slInit)
qtyFinal = f_qty_min_notional(qtyRisk, close)
qtyFinal := f_round_step_floor(qtyFinal, stepQty)
if qtyFinal > 0
strategy.entry("L", strategy.long, qty=qtyFinal, alert_message=(hasPointer ? f_json("ENTRY_INIT", false) : ""))
entryPx := close
initQty := qtyFinal
slPrice := slInit
vsCount := 1
plotshape(showEntryDot and enterCond, title="Entry Dot", style=shape.circle, size=size.tiny, location=location.belowbar, color=color.new(color.green, 0))
// =====================================================
// PAY-SELF (MFE % -> SL piso a profit fijo, sin cerrar size)
// =====================================================
if usePaySelf and strategy.position_size > 0 and not na(entryPx) and entryPx > 0
curMfePct = math.max(0.0, (high - entryPx) / entryPx)
mfePct := math.max(mfePct, curMfePct)
if not payArmed and mfePct >= payTriggerPct
payArmed := true
if payArmed and payLockPct > 0 and not na(initQty) and initQty > 0
paySL = entryPx * (1.0 + payLockPct)
slPrice := na(slPrice) ? paySL : math.max(slPrice, paySL)
// =====================================================
// VS SEQUENCE
// =====================================================
if barstate.isconfirmed and strategy.position_size > 0 and isVS
vsCount += 1
slTrail = low - SL_BUFFER
slPrice := na(slPrice) ? slTrail : math.max(slPrice, slTrail)
if vsCount == 2
vs2Low := low - SL_BUFFER
addQty = f_qty_mlpt_long(close, slPrice)
addQty := f_qty_min_notional(addQty, close)
addQty := f_round_step_floor(addQty, stepQty)
if addQty > 0
strategy.entry("L", strategy.long, qty=addQty, alert_message=(hasPointer ? f_json("ADD_VS2", false) : ""))
if vsCount == 3
slPrice := math.max(slPrice, entryPx)
if not na(vs2Low)
slPrice := math.max(slPrice, vs2Low)
int tp1VS = tpFromVS3 ? 3 : 4
int tp2VS = tpFromVS3 ? 4 : 5
if vsCount == tp1VS and not tp1
strategy.close("L", qty_percent=tp1Pct, alert_message=(hasPointer ? f_json("TP1_VS" + str.tostring(tp1VS), true) : ""))
tp1 := true
if vsCount == tp2VS and not tp2
strategy.close("L", qty_percent=tp2Pct, alert_message=(hasPointer ? f_json("TP2_VS" + str.tostring(tp2VS), true) : ""))
tp2 := true
// =====================================================
// EXIT (SL EVENT)
// =====================================================
if strategy.position_size > 0 and not na(slPrice)
strategy.exit("XL", from_entry="L", stop=slPrice, alert_message=(hasPointer ? f_json("SL_EVENT", true) : ""))
// =====================================================
// BAR COLORS (VS entrada vs VS de TP)
// =====================================================
int tp1VS_now = tpFromVS3 ? 3 : 4
int tp2VS_now = tpFromVS3 ? 4 : 5
isTPvs = strategy.position_size > 0 and isVS and (vsCount == tp1VS_now or vsCount == tp2VS_now)
barcolor(isTPvs ? cVStp : (isVS ? cVSentry : na))
// =====================================================
// SL PLOT + SHADE
// =====================================================
pSL = plot(showSL ? slPrice : na, "SL", color=cSL, linewidth=2, style=plot.style_linebr)
pPx = plot(showShade and strategy.position_size > 0 ? close : na, "PX (fill)", color=color.new(color.white, 100), display=display.none)
fill(pSL, pPx, color=(showShade and strategy.position_size > 0 ? cShade : na))