この記事では,複数の技術指標を組み合わせた定量的な取引戦略を詳細に説明します.様々な指標からのシグナルを合成することで,効果的なリスク管理を達成します.
I. 戦略の論理
戦略は主に以下の要素を含みます.
(1) 傾向の方向性を決定し,基本的買い/売シグナルを生成するPSAR.
(2) シグザグ 振動を特定して信号の方向性を確認する
(3) ブレイクアウトを検知して信号を検証するボリンジャー・バンド
(4) MACD は信号の検証をさらに進めて,精度を向上させる.
(5) ATRは,取引ごとにリスクを制御するためのダイナミックストップロスの計算です.
(6) 合成された信号と基準に基づいて取引を行う.
取引はすべての指標が一致するときにのみ行われ,誤ったシグナルをフィルタリングし,正確性を向上させます. ATRベースのストップロスは,すべての取引のリスク制御も保証します.
戦略の利点
最大の利点は,複数の指標で信号を検証し,単一の指標の制限を回避し,信頼性を向上させることにある.
さらに,ダイナミックストップロスのアプローチも大きな利点です. リスク制御のために,市場の変動に基づいて合理的なストップロスのレベルを設定します.
最後に,複数の指標の組み合わせは,戦略の効率性をさらに高めるために,豊富なパラメータ調整スペースを提供します.
III.潜在的なリスク
ただし,次のリスクも注意する必要があります.
まず,複数の指標の複雑さは最適化の難易性を高めます.不適切な設定は過度に適合につながる可能性があります.
2つ目に ストップ・ロスはあまりにも近すぎると 早期にストップ・ロスは起き 損失が増大する危険性があります
最後に,指標信号の間の差異が起こり,明確な優先規則が必要になります.
IV.要約
この記事では,マルチインジケータ確認とリスク管理を利用した定量的な取引戦略について説明しています. 検証とリスク管理のための指標を巧みに組み合わせています. しかし,パラメータ最適化の難しさは完全に認識され,ストップがあまりにも緊密なリスクは防止されるべきです. 全体的に,比較的堅牢な定量的な取引方法論を提供します.
/*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)