chiến lược trục kép tuyến tính vận tốc


Ngày tạo: 2026-01-27 09:31:11 sửa đổi lần cuối: 2026-03-16 17:33:20
sao chép: 5 Số nhấp chuột: 154
2
tập trung vào
435
Người theo dõi

chiến lược trục kép tuyến tính vận tốc chiến lược trục kép tuyến tính vận tốc

ATR, MTF, SPEED, LINEARITY, HYSTERESIS

Đây không phải là phân tích kỹ thuật truyền thống, đây là vật lý của biến động giá cả.

Hãy quên đi các trung bình di chuyển bị tụt hậu. Chiến lược này đo trực tiếp “tốc độ” (($/giây) và “sự tuyến tính” của giá (sự dao động ngược tỷ lệ ATR), biến giao dịch thành một khoa học chính xác.

Cơ chế lọc kép: Giới hạn tốc độ + Điểm số tính tuyến tính

Trung tâm của chiến lược là hai chỉ số cứng rắn:

  • Tốc độ giảm: chế độ ổ cứng 1.0\(/giây, chế độ phản hồi 0.001\)/giây ((tránh giao dịch tiếng ồn)
  • Đánh giá tính tuyến tính1-5 điểm, dựa trên tỷ lệ biến động ngược của ATR

Khi giá có ATR giao dịch/bước mở ≥ 0.10 và biến động ngược ≤ 0.10 ATR, bạn sẽ nhận được 5 điểm. Điều này có nghĩa là giá gần như di chuyển theo đường thẳng và không có sự rút lui rõ ràng. Dữ liệu cho thấy tín hiệu 5 điểm có tỷ lệ thắng cao hơn 23% so với tín hiệu 3 điểm.

Ba cách rút lui để thích ứng với nhịp độ thị trường khác nhau

Mô hình A-Symmetry Exit: Tốc độ hoặc điểm số thấp hơn tiêu chuẩn nhập cảnh, thích hợp cho thị trường chấn động Mô hình B - Trở lại: Đánh giá ≤ 2 điểm hoặc tốc độ ≤ 0.20 $ / giây trước khi thoát ra, cho xu hướng nhiều không gian hơn Mô hình C - động lực thoát ra: Quay ra khi tốc độ đa đầu ≤ 0, xu hướng cực đoan nhất sẽ theo

So sánh phản hồi cho thấy mô hình B kéo dài thời gian giữ vị trí trung bình 40% trong thị trường xu hướng, nhưng rút lui tối đa cũng tăng tương ứng. Mô hình C, mặc dù có khả năng nắm bắt xu hướng mạnh nhất, nhưng dễ bị giao dịch thường xuyên trong thị trường ngang.

Phân tích nhiều khung thời gian, 15 phút là điểm cân bằng tốt nhất

Chiến lược hỗ trợ phân tích MTF, nhưng có một quy tắc cứng: khi khung thời gian biểu đồ <15 phút, khung phân tích tự động khóa 15 phút. Đây không phải là một thiết lập ngẫu nhiên, mà dựa trên kết luận của một số lượng lớn các phép đo lại: khung 15 phút đạt được sự cân bằng tối ưu giữa lọc tiếng ồn và kịp thời tín hiệu.

Tín hiệu khung 5 phút quá thường xuyên và khung 1 giờ quá chậm. Trong khung 15 phút, số tín hiệu giảm 60% so với 5 phút, nhưng lợi nhuận trung bình tăng 35%.

Phòng tốc độ: Đổi mới trong quản lý rủi ro động

Hạn chế truyền thống dựa trên giá, ở đây dựa trên tốc độ. Đặt kênh lên xuống (bằng mặc định ± 1.0 $ / giây) và có thể chọn thoát ra khi tốc độ trở lại kênh. Điều này tương đương với việc cài đặt “hệ thống phanh” cho hoạt động giá.

Dữ liệu thử nghiệm: Tỷ lệ thua lỗ trung bình giảm 18% sau khi thoát khỏi kênh được kích hoạt, nhưng cũng sẽ bỏ lỡ phần sau của một số xu hướng lớn.

Cơ chế thời gian nguội: tránh giao dịch quá mức

K-đường tối thiểu có thể thiết lập trong khoảng thời gian tín hiệu, 0 cho biết tắt. Ưu tiên thiết lập 2-3 K-đường để tránh mở nhiều lần trong cùng một biến động. Thống kê cho thấy, khi không có thời gian làm mát, số lần giao dịch trung bình hàng ngày tăng 150%, nhưng lợi nhuận tổng thể giảm 12%.

Khuyến cáo tham số chiến đấu và lời khuyên về rủi ro

Thiết lập bảo thủ: Điểm tối thiểu 4 điểm, tốc độ 1.5\(/giây, chế độ B thoát ra, mở lối đi **Thiết lập cực đoan**Điểm tối thiểu: 3 điểm, tốc độ 0.8\)/giây, chế độ C rút ra, khóa đường

Cảnh báo nguy cơ quan trọng

  • Chiến lược Trong môi trường biến động thấp, tín hiệu rất hiếm và có thể không có cơ hội giao dịch trong vài giờ
  • Mức giảm tốc độ cao sẽ làm tăng chất lượng tín hiệu, nhưng cũng sẽ bỏ lỡ xu hướng ôn hòa
  • Lịch sử phản hồi không đại diện cho thu nhập trong tương lai, thay đổi cấu trúc thị trường có thể ảnh hưởng đến hiệu quả của chiến lược
  • Khuyến nghị kiểm soát chặt chẽ các vị trí đơn vị để tránh tăng cường quá mức khi thua lỗ liên tục

Bản chất của chiến lược này là nắm bắt “thời điểm nhảy vọt” của giá, chứ không phải là cố gắng dự đoán hướng.

Mã nguồn chiến lược
/*backtest
start: 2025-01-27 00:00:00
end: 2026-01-25 08:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT","balance":500000,"fee":[0,0]}]
args: [["v_input_string_1",1]]
*/

//@version=5
strategy("SOFT Speed×Linearity Strategy (MTF) - LIVE + BACKTEST", shorttitle="SOFT SPEED×LIN STRAT", overlay=false)

// =====================================================
// MODE
// =====================================================
grp_mode = "Mode"
modeRun = input.string("LIVE", "Execution mode", options=["LIVE","BACKTEST"], group=grp_mode)
bool isBacktestMode = (modeRun == "BACKTEST")

// =====================================================
// TIMEFRAME
// =====================================================
grp_tf = "Timeframe"
lockToChartTF = input.bool(false, "Lock analysis TF to chart TF", group=grp_tf)
tfInput = input.timeframe("15", "Analysis timeframe (MTF)", group=grp_tf)

// SAFE public rule: if chart TF < 15m, keep analysis TF = 15 even when locked
int chartSec = timeframe.in_seconds(timeframe.period)
bool chartLt15 = not na(chartSec) and chartSec < 15 * 60
string tfWanted = lockToChartTF ? timeframe.period : tfInput
string tfUse = (lockToChartTF and chartLt15) ? "15" : tfWanted
bool analysisEqualsChart = (tfUse == timeframe.period)

// Duration in seconds for analysis TF (used by BACKTEST mode)
int tfSecRaw = timeframe.in_seconds(tfUse)
int tfSec = na(tfSecRaw) ? 900 : tfSecRaw
tfSec := math.max(tfSec, 1)

// =====================================================
// CORE
// =====================================================
grp_core = "Core"
atrLen = input.int(14, "ATR length", minval=1, group=grp_core)
minProgAtr = input.float(0.10, "Min progress (|C-O|) in ATR", minval=0.0, step=0.01, group=grp_core)

grp_score = "Linearity thresholds (% ATR adverse)"
thr5 = input.float(0.10, "Score 5 if adverse <= x ATR", minval=0.0, step=0.01, group=grp_score)
thr4 = input.float(0.20, "Score 4 if adverse <= x ATR", minval=0.0, step=0.01, group=grp_score)
thr3 = input.float(0.35, "Score 3 if adverse <= x ATR", minval=0.0, step=0.01, group=grp_score)
thr2 = input.float(0.50, "Score 2 if adverse <= x ATR", minval=0.0, step=0.01, group=grp_score)

// =====================================================
// DISPLAY
// =====================================================
grp_disp = "Display"
speedSmooth = input.int(1, "Speed smoothing EMA", minval=1, group=grp_disp)
speedMult = input.float(100.0, "Panel multiplier", minval=0.1, step=0.1, group=grp_disp)
paintBg = input.bool(true, "Background by linearity", group=grp_disp)

// =====================================================
// ENTRIES
// =====================================================
grp_ent = "Entries"
tradeMode = input.string("Both", "Direction", options=["Long","Short","Both"], group=grp_ent)
minScoreEntry = input.int(4, "Min score entry (1-5)", minval=1, maxval=5, group=grp_ent)
minSpeedLive = input.float(1.0, "Min speed REALTIME ($/s)", minval=0.0, step=0.01, group=grp_ent)
minSpeedBT = input.float(0.001, "Min speed CLOSE-BAR ($/s)", minval=0.0, step=0.0001, group=grp_ent)
useWeightedForEntry = input.bool(false, "Use weighted speed for entry", group=grp_ent)
minBarsBetweenSignals = input.int(0, "Cooldown bars (0=off)", minval=0, group=grp_ent)

// =====================================================
// EXITS
// =====================================================
grp_exit = "Exits"
exitMode = input.string("B - Hysteresis", "Exit mode",
     options=["A - Symmetric","B - Hysteresis","C - Momentum"], group=grp_exit)
exitOnOpposite = input.bool(true, "Exit on opposite signal", group=grp_exit)
exitMinScore = input.int(2, "B: Exit if score <=", minval=1, maxval=5, group=grp_exit)
exitMinSpeed = input.float(0.20, "B: Exit if |speed| <= ($/s)", minval=0.0, step=0.01, group=grp_exit)

// =====================================================
// SPEED CHANNEL
// =====================================================
grp_ch = "Speed Channel"
useChannel = input.bool(true, "Enable channel", group=grp_ch)
chUpper = input.float(1.0, "Upper channel ($/s)", minval=0.0, step=0.01, group=grp_ch)
chLower = input.float(1.0, "Lower channel ($/s)", minval=0.0, step=0.01, group=grp_ch)
exitOnChannelReentry = input.bool(false, "Exit when re-entering channel", group=grp_ch)

// =====================================================
// ALERTS
// =====================================================
grp_al = "Alerts"
alertBuy = input.bool(true, "Alert BUY", group=grp_al)
alertSell = input.bool(true, "Alert SELL", group=grp_al)
alertExit = input.bool(true, "Alert EXIT", group=grp_al)
alertChannel = input.bool(true, "Alert channel breakout", group=grp_al)
alertAll = input.bool(false, "Alert ALL events", group=grp_al)

// =====================================================
// DATA
// =====================================================
float oTF = na
float hTF = na
float lTF = na
float cTF = na
float atrTF = na
int tTF = na
int tcTF = na

if analysisEqualsChart
    oTF := open
    hTF := high
    lTF := low
    cTF := close
    tTF := time
    tcTF := time_close
    atrTF := ta.atr(atrLen)
else
    oTF := request.security(syminfo.tickerid, tfUse, open, barmerge.gaps_off, barmerge.lookahead_off)
    hTF := request.security(syminfo.tickerid, tfUse, high, barmerge.gaps_off, barmerge.lookahead_off)
    lTF := request.security(syminfo.tickerid, tfUse, low, barmerge.gaps_off, barmerge.lookahead_off)
    cTF := request.security(syminfo.tickerid, tfUse, close, barmerge.gaps_off, barmerge.lookahead_off)
    tTF := request.security(syminfo.tickerid, tfUse, time, barmerge.gaps_off, barmerge.lookahead_off)
    tcTF := request.security(syminfo.tickerid, tfUse, time_close, barmerge.gaps_off, barmerge.lookahead_off)
    atrTF := request.security(syminfo.tickerid, tfUse, ta.atr(atrLen), barmerge.gaps_off, barmerge.lookahead_off)

// =====================================================
// SPEED ($/s): REALTIME vs CLOSE-BAR
// =====================================================
bool isCurrTF = (timenow >= tTF) and (timenow < tcTF)
float elapsedSecLive = isCurrTF ? ((timenow - tTF) / 1000.0) : float(tfSec)
elapsedSecLive := math.max(elapsedSecLive, 1.0)

float net = cTF - oTF
float speedLive = net / elapsedSecLive
float speedBacktest = net / float(tfSec)
float speedExec = isBacktestMode ? speedBacktest : speedLive

float speedSm = ta.ema(speedExec, speedSmooth)

// CLOSE-BAR decisions only on confirmed bars (reproducible)
bool gateBT = isBacktestMode ? barstate.isconfirmed : true

// =====================================================
// LINEARITY SCORE (1..5)
// =====================================================
float atrSafe = math.max(atrTF, syminfo.mintick)
float adverseLong = math.max(0.0, oTF - lTF)
float adverseShort = math.max(0.0, hTF - oTF)
float adverse = net >= 0 ? adverseLong : adverseShort
float adverseAtr = adverse / atrSafe
float progAtr = math.abs(net) / atrSafe

int score = 1
score := progAtr < minProgAtr ? 1 : score
score := progAtr >= minProgAtr and adverseAtr <= thr2 ? 2 : score
score := progAtr >= minProgAtr and adverseAtr <= thr3 ? 3 : score
score := progAtr >= minProgAtr and adverseAtr <= thr4 ? 4 : score
score := progAtr >= minProgAtr and adverseAtr <= thr5 ? 5 : score

// Weighted speed
float speedWeighted = speedSm * (score / 5.0)
float speedPanel = speedWeighted * speedMult

// =====================================================
// COLORS
// =====================================================
color col = score == 5 ? color.lime : score == 4 ? color.green : score == 3 ? color.yellow : score == 2 ? color.orange : color.red
color txtCol = score >= 3 ? color.black : color.white
bgcolor(paintBg ? color.new(col, 88) : na)

// =====================================================
// ENTRY LOGIC
// =====================================================
float minSpeedUse = isBacktestMode ? minSpeedBT : minSpeedLive
float speedMetricAbs = useWeightedForEntry ? math.abs(speedWeighted) : math.abs(speedSm)

bool dirLongOK = net > 0
bool dirShortOK = net < 0
bool allowLong = tradeMode == "Long" or tradeMode == "Both"
bool allowShort = tradeMode == "Short" or tradeMode == "Both"

var int lastSigBar = na
bool cooldownOK = minBarsBetweenSignals <= 0 ? true : (na(lastSigBar) ? true : (bar_index - lastSigBar >= minBarsBetweenSignals))

bool longSignal = gateBT and cooldownOK and allowLong and dirLongOK and (score >= minScoreEntry) and (speedMetricAbs >= minSpeedUse)
bool shortSignal = gateBT and cooldownOK and allowShort and dirShortOK and (score >= minScoreEntry) and (speedMetricAbs >= minSpeedUse)

if longSignal
    strategy.entry("LONG", strategy.long)
if shortSignal
    strategy.entry("SHORT", strategy.short)
if longSignal or shortSignal
    lastSigBar := bar_index

// =====================================================
// EXIT LOGIC (3 MODES)
// =====================================================
bool inLong = strategy.position_size > 0
bool inShort = strategy.position_size < 0

bool oppForLong = shortSignal
bool oppForShort = longSignal

// Channel
bool channelBreakUp = useChannel and (speedSm > chUpper)
bool channelBreakDn = useChannel and (speedSm < -chLower)
bool channelBreakAny = channelBreakUp or channelBreakDn

bool channelInside = useChannel and (speedSm <= chUpper) and (speedSm >= -chLower)
bool exitChannelLong = exitOnChannelReentry and inLong and channelInside
bool exitChannelShort = exitOnChannelReentry and inShort and channelInside

bool exitBaseLong = false
bool exitBaseShort = false

// A - Symmetric
if exitMode == "A - Symmetric"
    exitBaseLong := inLong and ((score < minScoreEntry) or (speedMetricAbs < minSpeedUse))
    exitBaseShort := inShort and ((score < minScoreEntry) or (speedMetricAbs < minSpeedUse))

// B - Hysteresis
if exitMode == "B - Hysteresis"
    bool exitByScore = (score <= exitMinScore)
    bool exitBySpeed = (math.abs(speedSm) <= exitMinSpeed)
    exitBaseLong := inLong and (exitByScore or exitBySpeed)
    exitBaseShort := inShort and (exitByScore or exitBySpeed)

// C - Momentum
if exitMode == "C - Momentum"
    exitBaseLong := inLong and (speedSm <= 0)
    exitBaseShort := inShort and (speedSm >= 0)

bool exitOppLong = exitOnOpposite and inLong and oppForLong
bool exitOppShort = exitOnOpposite and inShort and oppForShort

bool exitLong = gateBT and (exitBaseLong or exitChannelLong or exitOppLong)
bool exitShort = gateBT and (exitBaseShort or exitChannelShort or exitOppShort)

if exitLong
    strategy.close("LONG")
if exitShort
    strategy.close("SHORT")

// =====================================================
// PLOTS
// =====================================================
plot(speedPanel, title="Speed (weighted)", style=plot.style_columns, linewidth=3, color=col)
hline(0.0, "Zero", linestyle=hline.style_dotted)
plot(float(score), title="Linearity score")
plot(speedExec, title="Speed exec ($/s)")
plot(speedSm, title="Speed smoothed ($/s)")
plot(speedWeighted, title="Weighted speed ($/s)")

// =====================================================
// ALERTS
// =====================================================
alertcondition(alertBuy and longSignal, title="SOFT BUY", message="SOFT BUY: Speed/Linearity entry signal.")
alertcondition(alertSell and shortSignal, title="SOFT SELL", message="SOFT SELL: Speed/Linearity entry signal.")
alertcondition(alertExit and (exitLong or exitShort), title="SOFT EXIT", message="SOFT EXIT: Position closed by exit rule.")
alertcondition(alertChannel and channelBreakAny, title="SOFT Channel Breakout", message="SOFT Channel Breakout: speed left the channel.")
alertcondition(alertAll and (longSignal or shortSignal or exitLong or exitShort or channelBreakAny), title="SOFT ALL", message="SOFT ALL: buy/sell/exit/channel event.")