Chiến lược trung bình động làm mịn Stochastic Momentum


Ngày tạo: 2023-12-19 11:41:40 sửa đổi lần cuối: 2023-12-19 11:41:40
sao chép: 0 Số nhấp chuột: 661
1
tập trung vào
1621
Người theo dõi

Chiến lược trung bình động làm mịn Stochastic Momentum

Tổng quan

Chiến lược này kết hợp các chỉ số di chuyển trung bình (EMA) với các chỉ số ngẫu nhiên (Stochastic Oscillator), theo xu hướng theo dõi và tiếp tục, và có một số tính năng tuyệt vời. Tôi đã thiết kế chiến lược này đặc biệt cho các loại tiền tệ thay thế giao dịch, nhưng nó cũng áp dụng cho Bitcoin và một số cặp giao dịch ngoại hối.

Nguyên tắc chiến lược

Chiến lược này có 4 điều kiện cần thiết để mở tín hiệu giao dịch. Dưới đây là các điều kiện để mở nhiều giao dịch (các tín hiệu yên là ngược lại):

  • EMA nhanh cao hơn EMA chậm
  • Dòng K ngẫu nhiên ở khu vực mua quá mức
  • Đường K ngẫu nhiên đi ngang qua đường D ngẫu nhiên
  • Giá đóng cửa giữa EMA chậm và EMA nhanh

Một khi tất cả các điều kiện là đúng, K-line tiếp theo sẽ được mở khi mở.

Phân tích lợi thế

Chiến lược này kết hợp lợi thế của EMA và chỉ số ngẫu nhiên, có thể nắm bắt hiệu quả sự khởi đầu và tiếp tục của xu hướng, phù hợp với hoạt động đường dài trung bình. Chiến lược cũng cung cấp nhiều tham số có thể tùy chỉnh, người dùng có thể điều chỉnh theo phong cách giao dịch và đặc điểm thị trường của mình.

Cụ thể, chiến lược này có những ưu điểm:

  1. EMA đánh giá chéo xu hướng, tăng cường tín hiệu ổn định và đáng tin cậy
  2. Chỉ số ngẫu nhiên đánh giá quá mua quá bán, tìm kiếm cơ hội đảo ngược
  3. Kết hợp hai chỉ số, theo xu hướng và ngược lại
  4. ATR tự động tính toán khoảng cách dừng lỗ, dừng lỗ điều chỉnh theo biến động thị trường
  5. Tỷ lệ lợi nhuận rủi ro tùy chỉnh, đáp ứng nhu cầu của người dùng khác nhau
  6. Cung cấp nhiều tùy chỉnh tham số, người dùng có thể điều chỉnh theo thị trường

Phân tích rủi ro

Những rủi ro chính trong chiến lược này là:

  1. Tín hiệu hình thành chéo EMA có thể bị phá vỡ giả, dẫn đến tín hiệu sai
  2. Các chỉ số ngẫu nhiên tự nó bị tụt hậu, có thể bỏ lỡ thời điểm tốt nhất để giá đảo ngược
  3. Một chiến lược duy nhất không thể thích ứng hoàn toàn với môi trường thị trường thay đổi

Các biện pháp sau đây có thể được áp dụng để giảm thiểu các rủi ro trên:

  1. Điều chỉnh đúng các tham số chu kỳ EMA để tránh quá nhiều tín hiệu giả
  2. Kết hợp nhiều chỉ số để xác định xu hướng và hỗ trợ, đảm bảo tín hiệu giao dịch đáng tin cậy
  3. Xây dựng chiến lược quản lý tài chính rõ ràng, kiểm soát các lỗ hổng rủi ro cho mỗi giao dịch
  4. Sử dụng các chiến lược tổng hợp, các chiến lược khác nhau có thể xác thực tín hiệu với nhau, tăng sự ổn định

Hướng tối ưu hóa

Chiến lược này có thể được tối ưu hóa hơn nữa ở những khía cạnh sau:

  1. Thêm mô-đun điều chỉnh vị trí nắm giữ dựa trên biến động. Khi thị trường biến động tăng lên, giảm vị trí thích hợp; Khi biến động yếu đi, có thể tăng vị trí.
  2. Tăng khả năng đánh giá xu hướng cấp độ lớn, tránh hoạt động ngược. Ví dụ: kết hợp với đường K hàng ngày hoặc hàng tuần để đánh giá xu hướng.
  3. Thêm mô hình học máy để đánh giá tín hiệu mua và bán. Mô hình phân loại có thể được đào tạo dựa trên dữ liệu lịch sử, hỗ trợ tạo tín hiệu giao dịch.
  4. Tối ưu hóa mô-đun chiến lược quản lý tài sản, làm cho Stop Loss và Position Size thông minh hơn.

Tóm tắt

Chiến lược này tích hợp các ưu điểm của việc theo dõi xu hướng và giao dịch đảo ngược, xem xét môi trường thị trường lớn và chú ý đến hành vi giá hiện tại, là một chiến lược hiệu quả đáng để theo dõi trong dài hạn. Bằng cách liên tục tối ưu hóa các tham số thiết lập, tăng các mô-đun đánh giá xu hướng, hiệu suất của chiến lược có rất nhiều không gian nâng cao, đáng để đầu tư nhiều năng lượng nghiên cứu và phát triển.

Mã nguồn chiến lược
/*backtest
start: 2023-11-18 00:00:00
end: 2023-12-18 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/
// © LucasVivien

// Since this Strategy may have its stop loss hit within the opening candle, consider turning on 'Recalculate : After Order is filled' in the strategy settings, in the "Properties" tabs

//@version=5
strategy("Stochastic Moving Average", shorttitle="Stoch. EMA", overlay=true, default_qty_type= strategy.cash, initial_capital=10000, default_qty_value=100)

//==============================================================================
//==============================   USER INPUT   ================================
//==============================================================================

var g_tradeSetup = "     Trade Setup"
activateLongs  = input.bool (title="Long Trades"        , defval=true                                       , inline="A1", group=g_tradeSetup, tooltip="")
activateShorts = input.bool (title="Short Trades"       , defval=true                                       , inline="A1", group=g_tradeSetup, tooltip="")
rr             = input.float(title="Risk : Reward"      , defval=1   , minval=0, maxval=100       , step=0.1, inline=""  , group=g_tradeSetup, tooltip="")
RiskEquity     = input.bool (title="Risk = % Equity    ", defval=false                                      , inline="A2", group=g_tradeSetup, tooltip="Set stop loss size as a percentage of 'Initial Capital' -> Strategy Parameter -> Properties tab (Low liquidity markets will affect will prevent to get an exact amount du to gaps)")
riskPrctEqui   = input.float(title=""                   , defval=1   , minval=0, maxval=100       , step=0.1, inline="A2", group=g_tradeSetup, tooltip="")
RiskUSD        = input.bool (title="Risk = $ Amount   " , defval=false                                      , inline="A3", group=g_tradeSetup, tooltip="Set stop loss size as a fixed Base currency amount (Low liquidity markets will affect will prevent to get an exact amount du to gaps)")
riskUSD        = input.float(title=""                   , defval=1000, minval=0, maxval=1000000000, step=100, inline="A3", group=g_tradeSetup, tooltip="")

var g_stopLoss = "     Stop Loss"
atrMult = input.float(title="ATR Multiplier", defval=1 , minval=0, maxval=100 , step=0.1, tooltip="", inline="", group=g_stopLoss)
atrLen  = input.int  (title="ATR Lookback"  , defval=14, minval=0, maxval=1000, step=1  , tooltip="", inline="", group=g_stopLoss)

var g_stochastic = "     Stochastic"
Klen            = input.int  (title="K%"                   , defval=14, minval=0, maxval=1000, step=1, inline="S2", group=g_stochastic, tooltip="")
Dlen            = input.int  (title=" D%"                  , defval=3 , minval=0, maxval=1000, step=1, inline="S2", group=g_stochastic, tooltip="")
OBstochLvl      = input.int  (title="OB"                   , defval=80, minval=0, maxval=100 , step=1, inline="S1", group=g_stochastic, tooltip="")
OSstochLvl      = input.int  (title=" OS"                  , defval=20, minval=0, maxval=100 , step=1, inline="S1", group=g_stochastic, tooltip="")
OBOSlookback    = input.int  (title="Stoch. OB/OS lookback", defval=0 , minval=0, maxval=100 , step=1, inline=""  , group=g_stochastic, tooltip="This option allow to look 'x' bars back for a value of the Stochastic K line to be overbought or oversold when detecting an entry signal (if 0, looks only at current bar. if 1, looks at current and previous and so on)")
OBOSlookbackAll = input.bool (title="All must be OB/OS"    , defval=false                            , inline=""  , group=g_stochastic, tooltip="If turned on, all bars within the Stochastic K line lookback period must be overbought or oversold to return a true signal")
entryColor      = input.color(title="   "                  , defval=#00ffff                          , inline="S3", group=g_stochastic, tooltip="")
baseColor       = input.color(title="  "                   , defval=#333333                          , inline="S3", group=g_stochastic, tooltip="Will trun to designated color when stochastic gets to opposite extrem zone of current trend / Number = transparency")
transp          = input.int  (title="   "                  , defval=50, minval=0, maxval=100, step=10, inline="S3", group=g_stochastic, tooltip="")

var g_ema = "     Exp. Moving Average"
ema1len = input.int  (title="Fast EMA     ", defval=21, minval=0, maxval=1000, step=1, inline="E1", group=g_ema, tooltip="")
ema2len = input.int  (title="Slow EMA     ", defval=50, minval=0, maxval=1000, step=1, inline="E2", group=g_ema, tooltip="")
ema1col = input.color(title="     "        , defval=#0066ff                          , inline="E1", group=g_ema, tooltip="")
ema2col = input.color(title="     "        , defval=#0000ff                          , inline="E2", group=g_ema, tooltip="")

var g_referenceMarket ="     Reference Market"
refMfilter = input.bool     (title="Reference Market Filter", defval=false            , inline="", group=g_referenceMarket)
market     = input   (title="Market"                 , defval="BTC_USDT:swap", inline="", group=g_referenceMarket)
res        = input.timeframe(title="Timeframe"              , defval="30"             , inline="", group=g_referenceMarket)
len        = input.int      (title="EMA Length"             , defval=50               , inline="", group=g_referenceMarket)


//==============================================================================
//==========================   FILTERS & SIGNALS   =============================
//==============================================================================

//------------------------------   Stochastic   --------------------------------
K = ta.stoch(close, high, low, Klen)
D = ta.sma(K, Dlen)
stochBullCross = ta.crossover(K, D)
stochBearCross = ta.crossover(D, K)
OSstoch = false
OBstoch = false
for i = 0 to OBOSlookback
    if K[i] < OSstochLvl
        OSstoch := true
    else 
        if OBOSlookbackAll
            OSstoch := false
for i = 0 to OBOSlookback
    if K[i] > OBstochLvl
        OBstoch := true
    else 
        if OBOSlookbackAll
            OBstoch := false

//----------------------------   Moving Averages   -----------------------------
ema1 = ta.ema(close, ema1len)
ema2 = ta.ema(close, ema2len)
emaBull = ema1 > ema2
emaBear = ema1 < ema2

//----------------------------   Price source   --------------------------------
bullRetraceZone = (close < ema1 and close >= ema2) 
bearRetraceZone = (close > ema1 and close <= ema2)

//---------------------------   Reference market   -----------------------------
ema      = ta.ema(close, len)
emaHTF   = request.security(market, res, ema  [barstate.isconfirmed ? 0 : 1])
closeHTF = request.security(market, res, close[barstate.isconfirmed ? 0 : 1])

bullRefMarket = (closeHTF > emaHTF or closeHTF[1] > emaHTF[1])
bearRefMarket = (closeHTF < emaHTF or closeHTF[1] < emaHTF[1])

//--------------------------   SIGNAL VALIDATION   -----------------------------
validLong  = stochBullCross and OSstoch and emaBull and bullRetraceZone 
 and activateLongs  and (refMfilter ? bullRefMarket : true) and strategy.position_size == 0
validShort = stochBearCross and OBstoch and emaBear and bearRetraceZone 
 and activateShorts and (refMfilter ? bearRefMarket : true) and strategy.position_size == 0


//==============================================================================
//===========================   STOPS & TARGETS   ==============================
//==============================================================================

SLdist      = ta.atr(atrLen) * atrMult
longSL      = close - SLdist
longSLDist  = close - longSL
longTP      = close + (longSLDist * rr)
shortSL     = close + SLdist
shortSLDist = shortSL - close
shortTP     = close - (shortSLDist * rr)
var SLsaved = 0.0
var TPsaved = 0.0
if validLong or validShort
    SLsaved := validLong ? longSL : validShort ? shortSL : na
    TPsaved := validLong ? longTP : validShort ? shortTP : na


//==============================================================================
//==========================   STRATEGY COMMANDS   =============================
//==============================================================================
 
if validLong 
    strategy.entry("Long", strategy.long, 
     qty = RiskEquity ? ((riskPrctEqui/100)*strategy.equity)/longSLDist : RiskUSD ? riskUSD/longSLDist : na)
if validShort 
    strategy.entry("Short", strategy.short, 
     qty = RiskEquity ? ((riskPrctEqui/100)*strategy.equity)/shortSLDist  : RiskUSD ? riskUSD/shortSLDist : na)

strategy.exit(id="Long Exit" , from_entry="Long" , limit=TPsaved, stop=SLsaved, when=strategy.position_size > 0)
strategy.exit(id="Short Exit", from_entry="Short", limit=TPsaved, stop=SLsaved, when=strategy.position_size < 0)


//==============================================================================
//=============================   CHART PLOTS   ================================
//==============================================================================
    
//----------------------------   Stops & Targets   -----------------------------
plot(strategy.position_size != 0 or (strategy.position_size[1] != 0 and strategy.position_size == 0) ? SLsaved : na,
 color=color.red  , style=plot.style_linebr)
plot(strategy.position_size != 0 or (strategy.position_size[1] != 0 and strategy.position_size == 0) ? TPsaved : na,
 color=color.green, style=plot.style_linebr) 

//---------------------------------   EMAs   -----------------------------------
l1 = plot(ema1, color=#0066ff, linewidth=2)
l2 = plot(ema2, color=#0000ff, linewidth=2)

//--------------------------   Stochastic gradient   ---------------------------
// fill(l1, l2, color.new(color.from_gradient(K, OSstochLvl, OBstochLvl,
//  emaBull ? entryColor : emaBear ? baseColor : na, 
//  emaBull ? baseColor  : emaBear ? entryColor : na), transp))
    
//----------------------------   Trading Signals   -----------------------------
plotshape(validLong, color=color.green, location=location.belowbar, style=shape.xcross, size=size.small)
plotshape(validShort, color=color.red , location=location.abovebar, style=shape.xcross, size=size.small)

//----------------------------   Reference Market   ----------------------------
bgcolor(bullRefMarket and refMfilter ? color.new(color.green,90) : na)
bgcolor(bearRefMarket and refMfilter ? color.new(color.red  ,90) : na)