
Bài viết này giới thiệu về một chiến lược giao dịch thuật toán sử dụng mô hình ăn trộm để xác định cơ hội lợi nhuận và giá giao dịch với đường trung bình di chuyển làm tín hiệu đầu vào. Chiến lược này kết hợp phân tích kỹ thuật giá và phương pháp theo dõi xu hướng để thu thập và lợi nhuận từ các điểm đảo ngược xu hướng.
Lập luận cốt lõi của chiến lược này dựa trên sự kết hợp của hai chỉ số không liên quan:
Hình thức nuốt: một mô hình đảo ngược của hai dòng K, trong đó thực thể của dòng K thứ hai hoàn toàn nuốt thực thể của dòng K đầu tiên, được sử dụng để xác định cơ hội đảo ngược.
Giá vượt qua đường trung bình di chuyển: Khi giá vượt qua đường trung bình di chuyển từ bên dưới đường trung bình di chuyển, tạo ra tín hiệu mua; Khi giá vượt qua đường trung bình di chuyển từ phía trên đường trung bình di chuyển xuống, tạo ra tín hiệu bán.
Xác định thời gian thị trường có thể đảo ngược bằng cách ăn hình dạng, và kết hợp với giá và đường trung bình di chuyển như một tín hiệu lọc để xác định đảo ngược, có thể làm tăng khả năng kiếm lợi nhuận.
Cụ thể, chiến lược này đánh giá khả năng cân bằng và đảo ngược bằng cách theo dõi ba hình thức ăn uống: ăn nhiều đầu, ăn trần và ăn không có bóng. Sau đó, kết hợp với giá và các tín hiệu lọc vàng và chết của giá với đường trung bình di chuyển, cuối cùng quyết định hướng mở vị trí.
Lợi thế lớn nhất của chiến lược này là sử dụng sự kết hợp của các chỉ số không liên quan để nâng cao hiệu quả ra quyết định. Chế độ ăn uống đánh giá thời gian và xác suất của thị trường đảo ngược; và giá và trung bình di chuyển chéo xác minh hướng và cường độ đảo ngược. Cả hai đều được xác minh lẫn nhau, có thể làm giảm hiệu quả tổn thất giao dịch do tín hiệu sai.
Một lợi thế khác là tính linh hoạt trong thiết lập các tham số. Người dùng có thể tự thiết lập các tham số như chu kỳ trung bình di chuyển, mức dừng lỗ, để tối ưu hóa chiến lược.
Mặc dù sử dụng nhiều chỉ số để nâng cao hiệu quả phán đoán, chiến lược này vẫn có một số rủi ro tín hiệu sai. Hình thức ăn không phải là tín hiệu đảo ngược đáng tin cậy 100%, và giao thoa giữa giá và đường trung bình di chuyển cũng có thể không hiệu quả.
Ngoài ra, giống như hầu hết các chiến lược phân tích kỹ thuật, chiến lược này cũng kém hiệu quả đối với thị trường trong các tình huống xung đột như biến động giá.
Để kiểm soát rủi ro, bạn có thể điều chỉnh các tham số trung bình di chuyển để tối ưu hóa mức dừng lỗ. Bạn cũng có thể xem xét mức độ tham gia của chiến lược điều chỉnh động lực kết hợp với các chỉ số khác để xác định xu hướng và tình trạng chấn động.
Chiến lược này có thể được tối ưu hóa bằng cách:
Kiểm tra nhiều loại trung bình di chuyển để tìm kiếm sự kết hợp tham số tốt nhất. Ví dụ: trung bình di chuyển nặng, trơn trơn theo thứ tự của trung bình di chuyển.
Tăng các chỉ số định giá xu hướng để tránh các biến động trong thị trường. Ví dụ: ADX, Binance, v.v.
Tối ưu hóa phương pháp dừng lỗ để cải thiện hiệu quả của việc dừng lỗ. Có thể xem xét các chiến lược dừng lỗ như theo dõi dừng lỗ, Chandelier Exit.
Tăng phương pháp học máy để đánh giá hình dạng đường K, nâng cao độ chính xác nhận dạng ngâm.
Thêm chức năng tối ưu hóa tham số tự động, cho phép tham số tự điều chỉnh.
Chiến lược này sử dụng thời gian đảo ngược để đánh giá hình dạng, xác minh hướng đảo ngược bằng giá và đường trung bình di chuyển. Tăng hiệu quả quyết định bằng cách kết hợp các chỉ số, là một chiến lược phân tích kỹ thuật. Ưu điểm là các chỉ số bổ sung, các tham số linh hoạt; Nhược điểm là vẫn có nguy cơ tín hiệu giả, yếu đối với tình hình xung đột.
/*backtest
start: 2023-12-30 00:00:00
end: 2024-01-29 00:00:00
period: 3h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
//@version=4
//@author=Daveatt
StrategyName = "BEST Engulfing + MA"
ShortStrategyName = "BEST Engulfing + MA"
strategy(title=StrategyName, shorttitle=ShortStrategyName, overlay=true)
includeEngulfing = true
includeMA = true
source_ma = input(title="Source Price vs MA", type=input.source, defval=close)
typeofMA = input(title="Type of MA", defval="SMA", options=["RMA", "SMA", "EMA", "WMA", "VWMA", "SMMA", "KMA", "TMA", "HullMA", "DEMA", "TEMA"])
length_ma = input(32, title = "MA Length", type=input.integer)
// ---------- Candle components and states
GreenCandle = close > open
RedCandle = close < open
NoBody = close==open
Body = abs(close-open)
// bullish conditions
isBullishEngulfing1 = max(close[1],open[1]) < max(close,open) and min(close[1],open[1]) > min(close,open) and Body > Body[1] and GreenCandle and RedCandle[1]
isBullishEngulfing2 = max(close[1],open[1]) < max(close,open) and min(close[1],open[1]) <= min(close,open) and Body > Body[1] and GreenCandle and RedCandle[1]
// bearish conditions
isBearishEngulfing1 = max(close[1],open[1]) < max(close,open) and min(close[1],open[1]) > min(close,open) and Body > Body[1] and RedCandle and GreenCandle[1]
isBearishEngulfing2 = max(close[1],open[1]) >= max(close,open) and min(close[1],open[1]) > min(close,open) and Body > Body[1] and RedCandle and GreenCandle[1]
// consolidation of conditions
isBullishEngulfing = isBullishEngulfing1 or isBullishEngulfing2
isBearishEngulfing = isBearishEngulfing1 or isBearishEngulfing2
//isBullishEngulfing = max(close[1],open[1]) < max(close,open) and min(close[1],open[1]) > min(close,open) and Body > Body[1] and GreenCandle and RedCandle[1]
//isBearishEngulfing = max(close[1],open[1]) < max(close,open) and min(close[1],open[1]) > min(close,open) and Body > Body[1] and RedCandle and GreenCandle[1]
Engulf_curr = 0 - barssince(isBearishEngulfing) + barssince(isBullishEngulfing)
Engulf_Buy = Engulf_curr < 0 ? 1 : 0
Engulf_Sell = Engulf_curr > 0 ? 1 : 0
// Price vs MM
smma(src, len) =>
smma = 0.0
smma := na(smma[1]) ? sma(src, len) : (smma[1] * (len - 1) + src) / len
smma
ma(smoothing, src, length) =>
if smoothing == "RMA"
rma(src, length)
else
if smoothing == "SMA"
sma(src, length)
else
if smoothing == "EMA"
ema(src, length)
else
if smoothing == "WMA"
wma(src, length)
else
if smoothing == "VWMA"
vwma(src, length)
else
if smoothing == "SMMA"
smma(src, length)
else
if smoothing == "HullMA"
wma(2 * wma(src, length / 2) - wma(src, length), round(sqrt(length)))
else
if smoothing == "LSMA"
src
else
if smoothing == "KMA"
xPrice = src
xvnoise = abs(xPrice - xPrice[1])
nfastend = 0.666
nslowend = 0.0645
nsignal = abs(xPrice - xPrice[length])
nnoise = sum(xvnoise, length)
nefratio = iff(nnoise != 0, nsignal / nnoise, 0)
nsmooth = pow(nefratio * (nfastend - nslowend) + nslowend, 2)
nAMA = 0.0
nAMA := nz(nAMA[1]) + nsmooth * (xPrice - nz(nAMA[1]))
nAMA
else
if smoothing == "TMA"
sma(sma(close, length), length)
else
if smoothing == "DEMA"
2 * src - ema(src, length)
else
if smoothing == "TEMA"
3 * (src - ema(src, length)) + ema(ema(src, length), length)
else
src
MA = ma(typeofMA, source_ma, length_ma)
plot(MA, color=#006400FF, title="MA breakout", linewidth=3)
macrossover = crossover (source_ma, MA)
macrossunder = crossunder(source_ma, MA)
since_ma_buy = barssince(macrossover)
since_ma_sell = barssince(macrossunder)
macross_curr = 0 - since_ma_sell + since_ma_buy
bullish_MA_cond = macross_curr < 0 ? 1 : 0
bearish_MA_cond = macross_curr > 0 ? 1 : 0
posUp = (Engulf_Buy ? 1 : 0) + (bullish_MA_cond ? 1 : 0)
posDn = (Engulf_Sell ? 1 : 0) + (bearish_MA_cond ? 1 : 0)
conditionUP = posUp == 2 and posUp[1] < 2
conditionDN = posDn == 2 and posDn[1] < 2
sinceUP = barssince(conditionUP)
sinceDN = barssince(conditionDN)
// primary-first signal of the trend
nUP = crossunder(sinceUP,sinceDN)
nDN = crossover(sinceUP,sinceDN)
// and the following secondary signals
// save of the primary signal
sinceNUP = barssince(nUP)
sinceNDN = barssince(nDN)
buy_trend = sinceNDN > sinceNUP
sell_trend = sinceNDN < sinceNUP
// engulfing by
barcolor(nUP ? color.orange : na, title="Bullish condition")
barcolor(nDN ? color.yellow : na, title="Bearish condition")
isLong = nUP
isShort = nDN
long_entry_price = valuewhen(nUP, close, 0)
short_entry_price = valuewhen(nDN, close, 0)
longClose = close[1] < MA
shortClose = close[1] > MA
///////////////////////////////////////////////
//* Backtesting Period Selector | Component *//
///////////////////////////////////////////////
StartYear = input(2017, "Backtest Start Year",minval=1980)
StartMonth = input(1, "Backtest Start Month",minval=1,maxval=12)
StartDay = input(1, "Backtest Start Day",minval=1,maxval=31)
testPeriodStart = timestamp(StartYear,StartMonth,StartDay,0,0)
StopYear = input(2020, "Backtest Stop Year",minval=1980)
StopMonth = input(12, "Backtest Stop Month",minval=1,maxval=12)
StopDay = input(31, "Backtest Stop Day",minval=1,maxval=31)
testPeriodStop = timestamp(StopYear,StopMonth,StopDay,0,0)
testPeriod() => true
//////////////////////////
//* Profit Component *//
//////////////////////////
input_tp_pips = input(600, "Backtest Profit Goal (in USD)",minval=0)
input_sl_pips = input(300, "Backtest STOP Goal (in USD)",minval=0)
tp = buy_trend? long_entry_price + input_tp_pips : short_entry_price - input_tp_pips
sl = buy_trend? long_entry_price - input_sl_pips : short_entry_price + input_sl_pips
long_TP_exit = buy_trend and high >= tp
short_TP_exit = sell_trend and low <= tp
plot(tp, title="TP", style=plot.style_circles, linewidth=3, color=color.blue)
plot(sl, title="SL", style=plot.style_circles, linewidth=3, color=color.red)
if testPeriod()
strategy.entry("Long", 1, when=isLong)
strategy.close("Long", when=longClose )
strategy.exit("XL","Long", limit=tp, when=buy_trend, stop=sl)
if testPeriod()
strategy.entry("Short", 0, when=isShort)
strategy.close("Short", when=shortClose )
strategy.exit("XS","Short", when=sell_trend, limit=tp, stop=sl)