Chiến lược giao thoa đa xu hướng

Tác giả:ChaoZhang, Ngày: 2023-09-21 16:50:23
Tags:

Tổng quan

Chiến lược này tạo ra tín hiệu giao dịch bằng cách chọn các chỉ số xu hướng nhanh và chậm và đi dài khi xu hướng nhanh vượt qua xu hướng chậm và đi ngắn khi xu hướng nhanh vượt qua xu hướng chậm.

Chiến lược logic

Cốt lõi của chiến lược là lựa chọn và kết hợp các chỉ số xu hướng nhanh và chậm:

FastTrend = User selected fast trend indicator
SlowTrend = User selected slow trend indicator

Xu hướng nhanh bao gồm thuật toán xu hướng SMA, EMA, KAMA và 20+. Xu hướng chậm cũng có thể được chọn tự do.

Các tín hiệu giao dịch được tạo ra bằng cách đánh giá mối quan hệ giữa xu hướng nhanh và chậm:

if FastTrend > SlowTrend:
    Go long
if FastTrend < SlowTrend:
    Close position

Tín hiệu dài được kích hoạt khi xu hướng nhanh vượt qua xu hướng chậm. Tín hiệu ngắn được kích hoạt khi xu hướng nhanh vượt qua xu hướng chậm.

Phân tích lợi thế

  • Bao gồm hơn 20 chỉ số cho sự kết hợp linh hoạt
  • Có thể xác định xu hướng trong các khung thời gian khác nhau
  • Các thông số có thể được tối ưu hóa để tìm kết hợp tốt nhất
  • Có thể đi cả dài và ngắn để nắm bắt xu hướng trong cả hai hướng
  • Stop loss có thể được sử dụng để kiểm soát rủi ro

Phân tích rủi ro

  • Lựa chọn xu hướng nhanh / chậm sai có thể gây thất bại cho chiến lược
  • Các chỉ số xu hướng có sự chậm trễ, có thể bỏ lỡ các điểm đầu vào tốt nhất
  • Có xu hướng tạo ra tín hiệu sai trên các thị trường khác nhau
  • Cần tối ưu hóa tham số để tìm kết hợp chỉ số tốt nhất
  • Không thể cắt giảm tổn thất nhanh chóng, nguy cơ để cho tổn thất chạy

Hướng dẫn tối ưu hóa

Chiến lược có thể được cải thiện trong các khía cạnh sau:

  1. Điều chỉnh xu hướng và tham số nhanh / chậm để tìm kết hợp tối ưu.

  2. Thêm các bộ lọc như âm lượng để tránh tín hiệu sai trong thời gian thị trường hỗn loạn.

  3. Kết hợp các chiến lược dừng lỗ như dừng lỗ để kiểm soát lỗ giao dịch duy nhất.

  4. Kết hợp với các chỉ số khác như MACD, KDJ để cải thiện sự ổn định.

  5. Tối ưu hóa thời gian nhập cảnh, đừng chỉ dựa vào xu hướng chéo.

Tóm lại

Chiến lược chéo đa xu hướng xác định những thay đổi xu hướng trên các khung thời gian bằng cách kết hợp các xu hướng nhanh và chậm. Nhưng nó nhạy cảm với biến động thị trường và chỉ hoạt động tốt trong các thị trường xu hướng rõ ràng. Chúng ta cần các phương pháp như tối ưu hóa tham số và quản lý rủi ro để cải thiện sự ổn định và lợi nhuận của chiến lược.

[/trans]


/*backtest
start: 2023-08-21 00:00:00
end: 2023-09-20 00:00:00
period: 3h
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/
// @version=5
// Author = TradeAutomation


strategy(title="Multi Trend Cross Strategy Template", shorttitle="Multi Trend Cross Strategy", process_orders_on_close=true, overlay=true, commission_type=strategy.commission.cash_per_contract, commission_value=0.0035, initial_capital = 1000000, default_qty_type=strategy.percent_of_equity, default_qty_value=100)


// Backtest Date Range Inputs // 
StartTime = input(defval=timestamp('01 Jan 2000 05:00 +0000'), group="Date Range", title='Start Time')
EndTime = input(defval=timestamp('01 Jan 2099 00:00 +0000'), group="Date Range", title='End Time')
InDateRange = true

// Trend Selector //
TrendSelectorInput = input.string(title="Fast Trend Selector", defval="EMA", group="Core Settings", options=["ALMA", "DEMA", "DSMA", "EMA", "HMA", "JMA", "KAMA", "Linear Regression (LSMA)", "RMA", "SMA", "SMMA", "Price Source", "TEMA", "TMA", "VAMA", "VIDYA", "VMA", "VWMA", "WMA", "WWMA", "ZLEMA"], tooltip="Select your fast trend")
TrendSelectorInput2 = input.string(title="Slow Trend Selector", defval="EMA", group="Core Settings", options=["ALMA", "DEMA", "DSMA", "EMA", "HMA", "JMA", "KAMA", "Linear Regression (LSMA)", "RMA", "SMA", "SMMA", "Price Source", "TEMA", "TMA", "VAMA", "VIDYA", "VMA", "VWMA", "WMA", "WWMA", "ZLEMA"], tooltip="Select your slow trend")
src = input.source(close, "Price Source", group="Core Settings", tooltip="This is the price source being used for the trends to calculate based on")
length = input.int(10, "Fast Trend Length", group="Core Settings", step=5, tooltip="A long is entered when the selected fast trend crosses over the selected slow trend")
length2 = input.int(200, "Slow Trend Length", group="Core Settings", step=5, tooltip="A long is entered when the selected fast trend crosses over the selected slow trend")
LineWidth = input.int(1, "Line Width", group="Core Settings", tooltip="This is the width of the line plotted that represents the selected trend")

// Individual Moving Average / Regression Setting //
AlmaOffset = input.float(0.85, "ALMA Offset", group="Individual Trend Settings", tooltip="This only applies when ALMA is selected")
AlmaSigma = input.float(6, "ALMA Sigma", group="Individual Trend Settings", tooltip="This only applies when ALMA is selected")
ATRFactor = input.float(3, "ATR Multiplier For SuperTrend", group="Individual Trend Settings", tooltip="This only applies when SuperTrend is selected")
ATRLength = input.int(12, "ATR Length For SuperTrend", group="Individual Trend Settings", tooltip="This only applies when SuperTrend is selected")
ssfLength = input.int(20, "DSMA Super Smoother Filter Length", minval=1, tooltip="This only applies when EDSMA is selected", group="Individual Trend Settings")
ssfPoles = input.int(2, "DSMA Super Smoother Filter Poles", options=[2, 3], tooltip="This only applies when EDSMA is selected", group="Individual Trend Settings")
JMApower = input.int(2, "JMA Power Parameter", group="Individual Trend Settings", tooltip="This only applies when JMA is selected")
phase = input.int(-45, title="JMA Phase Parameter", step=10, minval=-110, maxval=110, group="Individual Trend Settings", tooltip="This only applies when JMA is selected")
KamaAlpha = input.float(3, "KAMA's Alpha", minval=1,step=0.5, group="Individual Trend Settings", tooltip="This only applies when KAMA is selected")
LinRegOffset = input.int(0, "Linear Regression Offset", group="Individual Trend Settings", tooltip="This only applies when Linear Regression is selected")
VAMALookback =input.int(12, "VAMA Volatility lookback", group="Individual Trend Settings", tooltip="This only applies when VAMA is selected")


// Trend Indicators With Library Functions //
ALMA = ta.alma(src, length, AlmaOffset, AlmaSigma) 
EMA = ta.ema(src, length)
HMA = ta.hma(src, length)
LinReg = ta.linreg(src, length, LinRegOffset)
RMA = ta.rma(src, length)
SMA = ta.sma(src, length)
VWMA = ta.vwma(src, length)
WMA = ta.wma(src, length)

ALMA2 = ta.alma(src, length2, AlmaOffset, AlmaSigma) 
EMA2 = ta.ema(src, length2)
HMA2 = ta.hma(src, length2)
LinReg2 = ta.linreg(src, length2, LinRegOffset)
RMA2 = ta.rma(src, length2)
SMA2 = ta.sma(src, length2)
VWMA2 = ta.vwma(src, length2)
WMA2 = ta.wma(src, length2)

// Additional Trend Indicators Built In And/Or Open Sourced //
//DEMA
de1 = ta.ema(src, length)
de2 = ta.ema(de1, length)
DEMA = 2 * de1 - de2

de3 = ta.ema(src, length2)
de4 = ta.ema(de3, length2)
DEMA2 = 2 * de3 - de4

// Ehlers Deviation-Scaled Moving Average - DSMA [Everget]
PI = 2 * math.asin(1)
get2PoleSSF(src, length) =>
    arg = math.sqrt(2) * PI / length
    a1 = math.exp(-arg)
    b1 = 2 * a1 * math.cos(arg)
    c2 = b1
    c3 = -math.pow(a1, 2)
    c1 = 1 - c2 - c3
    var ssf = 0.0
    ssf := c1 * src + c2 * nz(ssf[1]) + c3 * nz(ssf[2])
get3PoleSSF(src, length) =>
    arg = PI / length
    a1 = math.exp(-arg)
    b1 = 2 * a1 * math.cos(1.738 * arg)
    c1 = math.pow(a1, 2)
    coef2 = b1 + c1
    coef3 = -(c1 + b1 * c1)
    coef4 = math.pow(c1, 2)
    coef1 = 1 - coef2 - coef3 - coef4
    var ssf = 0.0
    ssf := coef1 * src + coef2 * nz(ssf[1]) + coef3 * nz(ssf[2]) + coef4 * nz(ssf[3])
zeros = src - nz(src[2])
avgZeros = (zeros + zeros[1]) / 2
// Ehlers Super Smoother Filter 
ssf = ssfPoles == 2
     ? get2PoleSSF(avgZeros, ssfLength)
     : get3PoleSSF(avgZeros, ssfLength)
// Rescale filter in terms of Standard Deviations
stdev = ta.stdev(ssf, length)
scaledFilter = stdev != 0
     ? ssf / stdev
     : 0
alpha1 = 5 * math.abs(scaledFilter) / length
EDSMA = 0.0
EDSMA := alpha1 * src + (1 - alpha1) * nz(EDSMA[1])

get2PoleSSF2(src, length2) =>
    arg = math.sqrt(2) * PI / length2
    a1 = math.exp(-arg)
    b1 = 2 * a1 * math.cos(arg)
    c2 = b1
    c3 = -math.pow(a1, 2)
    c1 = 1 - c2 - c3
    var ssf2 = 0.0
    ssf2 := c1 * src + c2 * nz(ssf2[1]) + c3 * nz(ssf2[2])
get3PoleSSF2(src, length2) =>
    arg = PI / length2
    a1 = math.exp(-arg)
    b1 = 2 * a1 * math.cos(1.738 * arg)
    c1 = math.pow(a1, 2)
    coef2 = b1 + c1
    coef3 = -(c1 + b1 * c1)
    coef4 = math.pow(c1, 2)
    coef1 = 1 - coef2 - coef3 - coef4
    var ssf2 = 0.0
    ssf2 := coef1 * src + coef2 * nz(ssf2[1]) + coef3 * nz(ssf2[2]) + coef4 * nz(ssf2[3])
// Ehlers Super Smoother Filter 
ssf2 = ssfPoles == 2
     ? get2PoleSSF2(avgZeros, ssfLength)
     : get3PoleSSF2(avgZeros, ssfLength)
// Rescale filter in terms of Standard Deviations
stdev2 = ta.stdev(ssf2, length2)
scaledFilter2 = stdev2 != 0
     ? ssf2 / stdev2
     : 0
alpha12 = 5 * math.abs(scaledFilter2) / length2
EDSMA2 = 0.0
EDSMA2 := alpha12 * src + (1 - alpha12) * nz(EDSMA2[1])

//JMA [Everget]
phaseRatio = phase < -100 ? 0.5 : phase > 100 ? 2.5 : phase / 100 + 1.5
beta = 0.45 * (length - 1) / (0.45 * (length - 1) + 2)
alpha = math.pow(beta, JMApower)
var JMA = 0.0
var e0 = 0.0
e0 := (1 - alpha) * src + alpha * nz(e0[1])
var e1 = 0.0
e1 := (src - e0) * (1 - beta) + beta * nz(e1[1])
var e2 = 0.0
e2 := (e0 + phaseRatio * e1 - nz(JMA[1])) * math.pow(1 - alpha, 2) + math.pow(alpha, 2) * nz(e2[1])
JMA := e2 + nz(JMA[1])

beta2 = 0.45 * (length2 - 1) / (0.45 * (length2 - 1) + 2)
alpha2 = math.pow(beta2, JMApower)
var JMA2 = 0.0
var e02 = 0.0
e02 := (1 - alpha2) * src + alpha2 * nz(e02[1])
var e12 = 0.0
e12 := (src - e02) * (1 - beta2) + beta2 * nz(e12[1])
var e22 = 0.0
e22 := (e02 + phaseRatio * e12 - nz(JMA2[1])) * math.pow(1 - alpha2, 2) + math.pow(alpha2, 2) * nz(e22[1])
JMA2 := e22 + nz(JMA2[1])

//KAMA [Everget]
var KAMA = 0.0
fastAlpha = 2.0 / (KamaAlpha + 1)
slowAlpha = 2.0 / 31
momentum = math.abs(ta.change(src, length))
volatility = math.sum(math.abs(ta.change(src)), length)
efficiencyRatio = volatility != 0 ? momentum / volatility : 0
smoothingConstant = math.pow((efficiencyRatio * (fastAlpha - slowAlpha)) + slowAlpha, 2)
KAMA := nz(KAMA[1], src) + smoothingConstant * (src - nz(KAMA[1], src))

var KAMA2 = 0.0
momentum2 = math.abs(ta.change(src, length2))
volatility2 = math.sum(math.abs(ta.change(src)), length2)
efficiencyRatio2 = volatility2 != 0 ? momentum2 / volatility2 : 0
smoothingConstant2 = math.pow((efficiencyRatio2 * (fastAlpha - slowAlpha)) + slowAlpha, 2)
KAMA2 := nz(KAMA2[1], src) + smoothingConstant2 * (src - nz(KAMA2[1], src))

//SMMA
var SMMA = 0.0
SMMA := na(SMMA[1]) ? ta.sma(src, length) : (SMMA[1] * (length - 1) + src) / length

var SMMA2 = 0.0
SMMA2 := na(SMMA2[1]) ? ta.sma(src, length2) : (SMMA2[1] * (length2 - 1) + src) / length2

//TEMA
t1 = ta.ema(src, length)
t2 = ta.ema(t1, length)
t3 = ta.ema(t2, length)
TEMA = 3 * (t1 - t2) + t3

t12 = ta.ema(src, length2)
t22 = ta.ema(t12, length2)
t32 = ta.ema(t22, length2)
TEMA2 = 3 * (t12 - t22) + t32

//TMA
TMA = ta.sma(ta.sma(src, math.ceil(length / 2)), math.floor(length / 2) + 1)

TMA2 = ta.sma(ta.sma(src, math.ceil(length2 / 2)), math.floor(length2 / 2) + 1)

//VAMA [Duyck]
mid=ta.ema(src,length)
dev=src-mid
vol_up=ta.highest(dev,VAMALookback)
vol_down=ta.lowest(dev,VAMALookback)
VAMA = mid+math.avg(vol_up,vol_down)

mid2=ta.ema(src,length2)
dev2=src-mid2
vol_up2=ta.highest(dev2,VAMALookback)
vol_down2=ta.lowest(dev2,VAMALookback)
VAMA2 = mid2+math.avg(vol_up2,vol_down2)

//VIDYA [KivancOzbilgic]
var VIDYA=0.0
VMAalpha=2/(length+1)
ud1=src>src[1] ? src-src[1] : 0
dd1=src<src[1] ? src[1]-src : 0
UD=math.sum(ud1,9)
DD=math.sum(dd1,9)
CMO=nz((UD-DD)/(UD+DD))
VIDYA := na(VIDYA[1]) ? ta.sma(src, length) : nz(VMAalpha*math.abs(CMO)*src)+(1-VMAalpha*math.abs(CMO))*nz(VIDYA[1])

var VIDYA2=0.0
VMAalpha2=2/(length2+1)
ud12=src>src[1] ? src-src[1] : 0
dd12=src<src[1] ? src[1]-src : 0
UD2=math.sum(ud12,9)
DD2=math.sum(dd12,9)
CMO2=nz((UD2-DD2)/(UD2+DD2))
VIDYA2 := na(VIDYA2[1]) ? ta.sma(src, length2) : nz(VMAalpha2*math.abs(CMO2)*src)+(1-VMAalpha2*math.abs(CMO2))*nz(VIDYA2[1])

//VMA [LazyBear]
sc = 1/length
pdm = math.max((src - src[1]), 0)
mdm = math.max((src[1] - src), 0)
var pdmS = 0.0
var mdmS = 0.0
pdmS := ((1 - sc)*nz(pdmS[1]) + sc*pdm)
mdmS := ((1 - sc)*nz(mdmS[1]) + sc*mdm)
s = pdmS + mdmS
pdi = pdmS/s
mdi = mdmS/s
var pdiS = 0.0
var mdiS = 0.0
pdiS := ((1 - sc)*nz(pdiS[1]) + sc*pdi)
mdiS := ((1 - sc)*nz(mdiS[1]) + sc*mdi)
d = math.abs(pdiS - mdiS)
s1 = pdiS + mdiS
var iS = 0.0
iS := ((1 - sc)*nz(iS[1]) + sc*d/s1)
hhv = ta.highest(iS, length) 
llv = ta.lowest(iS, length) 
d1 = hhv - llv
vi = (iS - llv)/d1
var VMA=0.0
VMA := na(VMA[1]) ? ta.sma(src, length) : sc*vi*src + (1 - sc*vi)*nz(VMA[1])

sc2 = 1/length2
pdm2 = math.max((src - src[1]), 0)
mdm2 = math.max((src[1] - src), 0)
var pdmS2 = 0.0
var mdmS2 = 0.0
pdmS2 := ((1 - sc2)*nz(pdmS2[1]) + sc2*pdm2)
mdmS2 := ((1 - sc2)*nz(mdmS2[1]) + sc2*mdm2)
s2 = pdmS2 + mdmS2
pdi2 = pdmS2/s2
mdi2 = mdmS2/s2
var pdiS2 = 0.0
var mdiS2 = 0.0
pdiS2 := ((1 - sc2)*nz(pdiS2[1]) + sc2*pdi2)
mdiS2 := ((1 - sc2)*nz(mdiS2[1]) + sc2*mdi2)
d2 = math.abs(pdiS2 - mdiS2)
s12 = pdiS2 + mdiS2
var iS2 = 0.0
iS2 := ((1 - sc2)*nz(iS2[1]) + sc2*d2/s12)
hhv2 = ta.highest(iS2, length) 
llv2 = ta.lowest(iS2, length) 
d12 = hhv2 - llv2
vi2 = (iS2 - llv2)/d12
var VMA2=0.0
VMA2 := na(VMA2[1]) ? ta.sma(src, length2) : sc2*vi2*src + (1 - sc2*vi2)*nz(VMA2[1])

//WWMA
var WWMA=0.0
WWMA := (1/length)*src + (1-(1/length))*nz(WWMA[1])

var WWMA2=0.0
WWMA2 := (1/length2)*src + (1-(1/length2))*nz(WWMA2[1])

//Zero Lag EMA [KivancOzbilgic]
EMA1a = ta.ema(src,length)
EMA2a = ta.ema(EMA1a,length)
Diff = EMA1a - EMA2a
ZLEMA = EMA1a + Diff

EMA12 = ta.ema(src,length2)
EMA22 = ta.ema(EMA12,length2)
Diff2 = EMA12 - EMA22
ZLEMA2 = EMA12 + Diff2

// Trend Mapping and Plotting //
FastTrend = TrendSelectorInput == "ALMA" ? ALMA : TrendSelectorInput == "DEMA" ? DEMA : TrendSelectorInput == "DSMA" ? EDSMA : TrendSelectorInput == "EMA" ? EMA : TrendSelectorInput == "HMA" ? HMA : TrendSelectorInput == "JMA" ? JMA : TrendSelectorInput == "KAMA" ? KAMA : TrendSelectorInput == "Linear Regression (LSMA)" ? LinReg : TrendSelectorInput == "RMA" ? RMA : TrendSelectorInput == "SMA" ? SMA : TrendSelectorInput == "SMMA" ? SMMA : TrendSelectorInput == "Price Source" ? src : TrendSelectorInput == "TEMA" ? TEMA : TrendSelectorInput == "TMA" ? TMA : TrendSelectorInput == "VAMA" ? VAMA : TrendSelectorInput == "VIDYA" ? VIDYA : TrendSelectorInput == "VMA" ? VMA : TrendSelectorInput == "VWMA" ? VWMA : TrendSelectorInput == "WMA" ? WMA : TrendSelectorInput == "WWMA" ? WWMA : TrendSelectorInput == "ZLEMA" ? ZLEMA : SMA
SlowTrend = TrendSelectorInput2 == "ALMA" ? ALMA2 : TrendSelectorInput2 == "DEMA" ? DEMA2 : TrendSelectorInput2 == "DSMA" ? EDSMA2 : TrendSelectorInput2 == "EMA" ? EMA2 : TrendSelectorInput2 == "HMA" ? HMA2 : TrendSelectorInput2 == "JMA" ? JMA2 : TrendSelectorInput2 == "KAMA" ? KAMA2 : TrendSelectorInput2 == "Linear Regression (LSMA)" ? LinReg2 : TrendSelectorInput2 == "RMA" ? RMA2 : TrendSelectorInput2 == "SMA" ? SMA2 : TrendSelectorInput2 == "SMMA" ? SMMA2 : TrendSelectorInput2 == "Price Source" ? src : TrendSelectorInput2 == "TEMA" ? TEMA2 : TrendSelectorInput2 == "TMA" ? TMA2 : TrendSelectorInput2 == "VAMA" ? VAMA2 : TrendSelectorInput2 == "VIDYA" ? VIDYA2 : TrendSelectorInput2 == "VMA" ? VMA2 : TrendSelectorInput2 == "VWMA" ? VWMA2 : TrendSelectorInput2 == "WMA" ? WMA2 : TrendSelectorInput2 == "WWMA" ? WWMA2 : TrendSelectorInput2 == "ZLEMA" ? ZLEMA2 : SMA2
plot(FastTrend, color=color.green, linewidth=LineWidth)
plot(SlowTrend, color=color.red, linewidth=LineWidth)

//Short & Long Options
Long = input.bool(true, "Model Long Trades", group="Core Settings")
Short = input.bool(false, "Model Short Trades", group="Core Settings")

// Entry & Exit Functions //
if (InDateRange and Long==true and FastTrend>SlowTrend)
    strategy.entry("Long", strategy.long, alert_message="Long")

if (InDateRange and Long==true and FastTrend<SlowTrend)
    strategy.close("Long", alert_message="Close Long")

if (InDateRange and Short==true and FastTrend<SlowTrend)
    strategy.entry("Short", strategy.short, alert_message="Short")

if (InDateRange and Short==true and FastTrend>SlowTrend)
    strategy.close("Short", alert_message="Cover Short")  

if (not InDateRange)
    strategy.close_all(alert_message="End of Date Range")
    

Thêm nữa