이 문서에서는 여러 가지 기술 지표의 조합을 기반으로 거래량을 측정하는 전략에 대해 자세히 설명합니다. 이 전략은 여러 가지 지표를 통합하여 거래 신호를 형성하여 효과적인 위험 관리를 수행합니다.
1 전략
이 전략은 다음과 같은 부분들로 구성되어 있습니다.
(1) PSAR 지표는 트렌드 방향을 판단하여 기본적 인 구매/판매 신호를 생성합니다.
(2) ZigZag 선의 형태를 판단하여 신호 방향을 확인한다.
(3) 브린 라인 지표가 돌파구를 판단하고, 보조 확인 신호;
(4) MACD 지표는 신호를 다시 확인하여 정확도를 높인다.
(5) ATR 지표는 동적 스톱로스를 계산하여 단위 위험을 제어합니다.
(6) 위와 같은 신호와 조건이 합쳐진 입원
모든 지표 신호가 일치하면 최종 거래 지시가 형성되며, 이는 가짜 신호를 효과적으로 필터링하여 정확성을 향상시킵니다. ATR 계산의 중지 손실은 또한 거래마다 위험을 제어합니다.
2 전략적 장점
이 전략의 가장 큰 장점은 여러 지표의 조합으로 신호를 검증하는 것이다. 이것은 단일 지표의 한계를 피하고, 신호의 신뢰성을 높인다.
또한, 동적 스톱 방식도 큰 장점이다. 시장의 변동 정도에 따라 합리적인 스톱 지점을 설정하여 위험을 능동적으로 제어하는 데 도움이 된다.
마지막으로, 다중 지표 포트폴리오는 전략의 효율성을 높이기 위해 최적화할 수 있는 풍부한 매개 변수 공간을 제공합니다.
그러나 우리는 다음과 같은 위험도 주의해야 합니다.
첫째, 다중 지표 조합은 파라미터 최적화를 어렵게 하고, 부당한 설정은 오버 최적화를 초래할 수 있다.
두 번째, 상쇄 손실이 너무 가까이 접근하면 손실이 커집니다.
마지막으로, 지표 신호들 사이에 오차가 발생할 수 있으므로 명확한 우선 순위 규칙을 설정해야 합니다.
네 가지 내용
이 글은 다중 지표 검증을 기반으로 한 양적 거래 전략에 대해 자세히 소개한다. 이 전략은 여러 지표를 합리적으로 사용하여 신호 검증과 위험 관리를 한다. 그러나 매개 변수를 최적화하는 어려움을 충분히 인식하고 너무 가까운 손실의 위험을 사전에 예방하는 것이 필요합니다.
/*backtest
start: 2023-09-06 00:00:00
end: 2023-09-08 09:00:00
period: 1m
basePeriod: 1m
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/
// © Rolan_Kruger
//@version=5
strategy("PSAR BBPT ZLSMA","PBZ", overlay=true,default_qty_type = strategy.percent_of_equity, default_qty_value = 100)
///////////////////////////////////////////////////////////////////////////////////////////////////////
// PSAR BUY/SELL
start = input.float(title='Start', step=0.00005, defval=0.05, group = "PSAR")
increment = input.float(title='Increment', step=0.00005, defval=0.05, group = "PSAR")
maximum = input.float(title='Maximum', step=0.01, defval=0.13, group = "PSAR")
width = input.int(title='Point Width', minval=1, defval=20, group = "PSAR")
highlightStartPoints = input(title='Highlight Start Points ?', defval=false, group = "PSAR")
psar = ta.sar(start, increment, maximum)
dir = psar < close ? 1 : -1
psarColor = psar < close ? #3388bb : #fdcc02
plotshape(dir == 1 and dir[1] == -1 and highlightStartPoints ? psar : na, title='Buy', style=shape.labelup, location=location.absolute, size=size.normal, text='Buy', textcolor=color.new(color.white, 0), color=color.new(color.green, 0))
plotshape(dir == -1 and dir[1] == 1 and highlightStartPoints ? psar : na, title='Sell', style=shape.labeldown, location=location.absolute, size=size.normal, text='Sell', textcolor=color.new(color.white, 0), color=color.new(color.red, 0))
barcolor(dir == 1 ? color.green : color.red, display = display.none)
PSAR_Buy = dir == 1 and dir[1] == -1
PSAR_Sell = dir == -1 and dir[1] == 1
////////////////////////////////////////////////////////////////////////////////////////////////////////
// ZLSMA
length = input(title='Length', defval=50,group = "ZLSMA")
offset = input(title='Offset', defval=0,group = "ZLSMA")
src = input(close, title='Source',group = "ZLSMA")
lsma = ta.linreg(src, length, offset)
lsma2 = ta.linreg(lsma, length, offset)
eq = lsma - lsma2
zlsma = lsma + eq
plot(zlsma, color=color.new(color.yellow, 0), linewidth=3)
ZLSMA_Buy = close > zlsma and open > zlsma and low > zlsma and high > zlsma
ZLSMA_Sell = close < zlsma and open < zlsma and low < zlsma and high < zlsma
////////////////////////////////////////////////////////////////////////////////////////////////////////
// BBPT
//
switch_bbpt = input.bool(false, "Switch BBPT conditionals",group ="Bull Bear Power Trend")
length1 = 8
//
BullTrend_hist = 0.0
BearTrend_hist = 0.0
BullTrend = (close - ta.lowest(low, 50)) / ta.atr(5)
BearTrend = (ta.highest(high, 50) - close) / ta.atr(5)
BearTrend2 = -1 * BearTrend
Trend = BullTrend - BearTrend
if BullTrend < 2
BullTrend_hist := BullTrend - 2
BullTrend_hist
if BearTrend2 > -2
BearTrend_hist := BearTrend2 + 2
BearTrend_hist
//alexgrover-Regression Line Formula
x = bar_index
y = Trend
x_ = ta.sma(x, length1)
y_ = ta.sma(y, length1)
mx = ta.stdev(x, length1)
my = ta.stdev(y, length1)
c = ta.correlation(x, y, length1)
slope = c * (my / mx)
inter = y_ - slope * x_
reg_trend = x * slope + inter
//
BBPT_Buy = BearTrend_hist
BBPT_Sell = BullTrend_hist
if switch_bbpt
BBPT_Buy := BullTrend_hist
BBPT_Sell := BearTrend_hist
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Sessions
enable_sessions = input.bool(false, "Enable Sessions for strategy", group = "Sessions")
bgColor = input.bool(false, "Activate High/Low View", group = "Sessions")
LondonColor = color.new(color.green, 90)
NYColor = color.new(color.red, 90)
AsiaColor = color.new(color.yellow, 90)
SydneyColor = color.new(color.blue, 90)
///Sessions
res = input.timeframe("D", "Resolution", ["D","W","M"], group = "Sessions")
london = input("0300-1200:1234567", "London Session", group = "Sessions")
ny = input("0800-1700:1234567", "New York Session", group = "Sessions")
tokyo = input("2000-0400:1234567", "Tokyo Session", group = "Sessions")
sydney = input("1700-0200:1234567", "Sydney Session", group = "Sessions")
//Bars
is_newbar(sess) =>
t = time(res, sess, "America/New_York")
na(t[1]) and not na(t) or t[1] < t
is_session(sess) =>
not na(time(timeframe.period, sess, "America/New_York"))
//London
London = input.bool(false, "London Session")
londonNewbar = is_newbar(london)
londonSession = is_session(london)
float londonLow = na
londonLow := if londonSession
if londonNewbar
low
else
math.min(londonLow[1],low)
else
londonLow
float londonHigh = na
londonHigh := if londonSession
if londonNewbar
high
else
math.max(londonHigh[1],high)
else
londonHigh
plotLL = plot(londonLow, color=color.new(#000000, 100))
plotLH = plot(londonHigh, color=color.new(#000000, 100))
fill(plotLL, plotLH, color = londonSession and London and bgColor ? LondonColor : na)
bgcolor(londonSession and London and not bgColor ? LondonColor : na)
//New York
NY = input.bool(false, "New York Session")
nyNewbar = is_newbar(ny)
nySession = is_session(ny)
float nyLow = na
nyLow := if nySession
if nyNewbar
low
else
math.min(nyLow[1],low)
else
nyLow
float nyHigh = na
nyHigh := if nySession
if nyNewbar
high
else
math.max(nyHigh[1],high)
else
nyHigh
plotNYL = plot(nyLow, color=color.new(#000000, 100))
plotNYH = plot(nyHigh, color=color.new(#000000, 100))
fill(plotNYL, plotNYH, color = nySession and NY and bgColor ? NYColor : na)
bgcolor(nySession and NY and not bgColor ? NYColor : na)
//Tokyo
Tokyo = input.bool(false, "Tokyo Session")
tokyoNewbar = is_newbar(tokyo)
tokyoSession = is_session(tokyo)
float tokyoLow = na
tokyoLow := if tokyoSession
if tokyoNewbar
low
else
math.min(tokyoLow[1],low)
else
tokyoLow
float tokyoHigh = na
tokyoHigh := if tokyoSession
if tokyoNewbar
high
else
math.max(tokyoHigh[1],high)
else
tokyoHigh
plotTL = plot(tokyoLow, color=color.new(#000000, 100))
plotTH = plot(tokyoHigh, color=color.new(#000000, 100))
fill(plotTL, plotTH, color = tokyoSession and Tokyo and bgColor ? AsiaColor : na)
bgcolor(tokyoSession and Tokyo and not bgColor ? AsiaColor : na)
//Sydney
Sydney = input.bool(false, "Sydney Session")
sydneyNewbar = is_newbar(sydney)
sydneySession = is_session(sydney)
float sydneyLow = na
sydneyLow := if sydneySession
if sydneyNewbar
low
else
math.min(sydneyLow[1],low)
else
sydneyLow
float sydneyHigh = na
sydneyHigh := if sydneySession
if sydneyNewbar
high
else
math.max(sydneyHigh[1],high)
else
sydneyHigh
plotSL = plot(sydneyLow, color=color.new(#000000, 100))
plotSH = plot(sydneyHigh, color=color.new(#000000, 100))
fill(plotSL, plotSH, color = sydneySession and Sydney and bgColor ? SydneyColor : na)
bgcolor(sydneySession and Sydney and not bgColor ? SydneyColor : na)
London_ok = London and londonSession
NY_ok = NY and nySession
Tokyo_ok = Tokyo and tokyoSession
Sydney_ok = Sydney and sydneySession
in_session = true
if London_ok or NY_ok or Tokyo_ok or Sydney_ok and enable_sessions
in_session := true
else if enable_sessions == true
in_session := false
///////////////////////////////////////////////////////////////////////////////////////////////////////
// EMA Filter
ema_filter = input.bool(false, "Enable EMA filter", group = "EMA")
ema_lenght = input.int(50, "EMA lenght", group = "EMA")
ema1 = ta.ema(close, ema_lenght)
plot(ema1, "EMA", color.white, 3)
EMA_Buy = true
EMA_Sell = true
if ema_filter == true
EMA_Buy := close > ema1
EMA_Sell := ema1 > close
///////////////////////////////////////////////////////////////////////////////////////////////////////
// ZLSMA angle calc
zlsma_angle_filter = input.bool(true, "ZLSMA angle filter", group = "ZLSMA")
ZLSMA_Up = true
ZLSMA_Down = true
if zlsma_angle_filter == true
ZLSMA_Up := 1 < (zlsma - zlsma[1])
ZLSMA_Down := -1 > (zlsma - zlsma[1])
///////////////////////////////////////////////////////////////////////////////////////////////////////
// SL/TP
// Assumes quote currency is FIAT as with BTC/USDT pair
max_sl = input.float(0.2, "Max SL size in %", group = "SL/TP", minval = 0.1, tooltip = "Cancels trade if SL is too big" )
zlsma_offset = input.float(0.02, title="ZLSMA SL offset in %", group = "SL/TP",maxval = 1)
tp1_multi = input.float(1, title="TP 1 multiplier", group = "SL/TP")
tp2_multi = input.float(2, title="TP 2 multiplier", group = "SL/TP")
tp1_persentage = input.float(0.001, "Persentage of trade close on TP1", group ="SL/TP", maxval = 100, minval = 0.001)
// SL too big check
sl_check = ((math.abs(close - zlsma))/close * 100) + zlsma_offset
sl_ok = true
if sl_check > max_sl
sl_ok := false
// ZLSMA SL and TP
not_in_trade = strategy.position_size == 0
check_if_long = PSAR_Buy and ZLSMA_Buy and BBPT_Buy and EMA_Buy and ZLSMA_Up and sl_ok and in_session
check_if_short = PSAR_Sell and ZLSMA_Sell and BBPT_Sell and EMA_Sell and ZLSMA_Down and sl_ok and in_session
var float sl = 0.0
var float tp1 = 0.0
var float tp2 = 0.0
if check_if_long and not_in_trade
sl := ((close - zlsma)/close * 100) + zlsma_offset
tp1 := (((close - zlsma)/close * 100) + zlsma_offset)*tp1_multi
tp2 := (((close - zlsma)/close * 100) + zlsma_offset)*tp2_multi
if check_if_short and not_in_trade
sl := ((zlsma - close)/close * 100) + zlsma_offset
tp1 := (((zlsma - close)/close * 100) + zlsma_offset)*tp1_multi
tp2 := (((zlsma - close)/close * 100) + zlsma_offset)*tp2_multi
// FUNCTIONS
// Stochastic
f_stochastic() =>
stoch = ta.stoch(close, high, low, 14)
stoch_K = ta.sma(stoch, 3)
stoch_D = ta.sma(stoch_K, 3)
stRD = ta.crossunder(stoch_K, stoch_D)
stGD = ta.crossover(stoch_K, stoch_D)
[stoch_K, stoch_D, stRD, stGD]
// VARIABLES
[bbMiddle, bbUpper, bbLower] = ta.bb(close, 20, 2)
[stoch_K, stoch_D, stRD, stGD] = f_stochastic()
// ORDERS
// Active Orders
// Check if strategy has open positions
inLong = strategy.position_size > 0
inShort = strategy.position_size < 0
// Check if strategy reduced position size in last bar
longClose = strategy.position_size < strategy.position_size[1]
shortClose = strategy.position_size > strategy.position_size[1]
// Entry Conditions
// Enter long when during last candle these conditions are true:
// Candle high is greater than upper Bollinger Band
// Stochastic K line crosses under D line and is oversold
longCondition = PSAR_Buy and ZLSMA_Buy and BBPT_Buy and EMA_Buy and ZLSMA_Up and sl_ok and in_session
// Enter short when during last candle these conditions are true:
// Candle low is lower than lower Bollinger Band
// Stochastic K line crosses over D line and is overbought
shortCondition = PSAR_Sell and ZLSMA_Sell and BBPT_Sell and EMA_Sell and ZLSMA_Down and sl_ok and in_session
// Exit Conditions
// Calculate Take Profit
longTP1 = strategy.position_avg_price * ((100 + tp1)/100)
longTP2 = strategy.position_avg_price * ((100 + tp2)/100)
shortTP1 = strategy.position_avg_price * ((100 - tp1)/100)
shortTP2 = strategy.position_avg_price * ((100 - tp2)/100)
// Calculate Stop Loss
// Initialise variables
var float longSL = 0.0
var float shortSL = 0.0
// When not in position, set stop loss using close price which is the price used during backtesting
// When in a position, check to see if the position was reduced on the last bar
// If it was, set stop loss to position entry price. Otherwise, maintain last stop loss value
longSL := if inLong and ta.barssince(longClose) < ta.barssince(longCondition)
strategy.position_avg_price
else if inLong
longSL[1]
else
close * ((100 - sl)/100)
shortSL := if inShort and ta.barssince(shortClose) < ta.barssince(shortCondition)
strategy.position_avg_price
else if inShort
shortSL[1]
else
close * ((100 + sl)/100)
////////////////////////////////////////////////////////////////////////////////////////////////////////
// STRATEGY EXECUTION
// Manage positions
if not_in_trade and longCondition
strategy.entry("Long", strategy.long)
strategy.exit("TP1/SL", from_entry="Long", qty_percent=tp1_persentage, limit=longTP1, stop=longSL)
strategy.exit("TP2/SL", from_entry="Long", limit=longTP2, stop=longSL)
if not_in_trade and shortCondition
strategy.entry("Short", strategy.short)
strategy.exit("TP1/SL", from_entry="Short", qty_percent=tp1_persentage, limit=shortTP1, stop=shortSL)
strategy.exit("TP2/SL", from_entry="Short", limit=shortTP2, stop=shortSL)