この戦略は,ケルトナーチャネルとダイナミックなサポート/レジスタンスレベルに基づいた包括的な取引システムである.複数のタイムフレームを分析し,移動平均値と変動指標を組み合わせて完全な取引決定枠組みを形成する.コアアプローチは,市場動向と変動を考慮しながら価格ブレイク機会を特定し,高い確率の取引機会を把握することです.
この戦略は,複数の層の技術指標システムを採用しています. 1.21期ケルトナーチャネルを主要なトレンド識別ツールとして使用し,チャネル幅はATRによって決定される. 2. 21 左側と 8 右側バーを使用して主要なサポート/抵抗レベルを計算します. 3. トレンドフィルターとしてより高いタイムフレーム移動平均を組み込む 4. 短期 (5 期) と長期 (30 期) の移動平均を組み合わせ,エントリータイミングを計算する 5. 動的ストップ損失調整のためにATRを使用する
この戦略は,結構的で論理的に厳格な定量的な取引戦略である.複数の技術指標の調整された使用を通じて,信頼性の高い取引信号と効果的なリスク管理の両方を保証する.この戦略の強力な拡張性は,さまざまな市場環境で安定したパフォーマンスを維持する潜在的な継続的な最適化と改善を可能にします.
/*backtest start: 2024-12-17 00:00:00 end: 2024-12-21 00:00:00 period: 1h basePeriod: 1h exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT","balance":49999}] */ // This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © sathcm //@version=5 strategy("KMS", overlay=true, initial_capital=100000, default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.05, slippage=3) // Inputs for Keltner Channels kcLength = input.int(21, title="Keltner Channel Length", minval=1) // Length for Keltner Channel calculation kcMultiplier = input.float(2.0, title="Keltner Channel Multiplier", minval=0.1) // Multiplier for Keltner Channel width // Calculate Keltner Channels using best practices kcBasis = ta.ema(close, kcLength) // Use EMA for a smoother basis line atrValue = ta.atr(kcLength) // Use ATR for channel width calculation kcUpper = kcBasis + kcMultiplier * atrValue // Upper Keltner Channel kcLower = kcBasis - kcMultiplier * atrValue // Lower Keltner Channel // Inputs for Pivot Point Calculation leftBars = input.int(21, title="Left Bars", minval=1) // Number of bars to the left for pivot calculation rightBars = input.int(8, title="Right Bars", minval=1, tooltip="Number of bars to the right for pivot calculation") // Number of bars to the right for pivot calculation // Calculate Smoothed Pivot Highs and Lows using Weighted Moving Average pivotHigh = ta.pivothigh(high, leftBars, rightBars) // Apply WMA for smoothing pivotLow = ta.pivotlow(low, leftBars, rightBars) // Apply WMA for smoothing // Convert Pivot Highs and Lows to Boolean Conditions isPivotHigh = not na(pivotHigh) // True when a pivot high exists isPivotLow = not na(pivotLow) // True when a pivot low exists // Get Recent Support and Resistance Levels recentResistance = ta.valuewhen(isPivotHigh, high, 0) // Most recent resistance level recentSupport = ta.valuewhen(isPivotLow, low, 0) // Most recent support level // Plot Smoothed Support and Resistance Levels //plot(recentResistance, color=color.red, title="Recent Resistance", linewidth=2, style=plot.style_line) //plot(recentSupport, color=color.green, title="Recent Support", linewidth=2, style=plot.style_line) // Store Entry Price into a Variable var float entryPrice = na // Declare a variable to store the entry price // Input for Higher Timeframe higherTimeframeInput = input.timeframe('W', title="Higher Timeframe for MA Calculation") if (timeframe.period == "240") or (timeframe.period == "120") higherTimeframeInput := "D" if (timeframe.period == "60") or (timeframe.period == "30") or (timeframe.period == "15") higherTimeframeInput := "120" if (timeframe.period == "10") or (timeframe.period == "5") higherTimeframeInput := "30" if (timeframe.period == "1") higherTimeframeInput := "10" prd = input.int(defval=10, title='Pivot Period', minval=4, maxval=30, group='Settings 🔨', tooltip='Used while calculating Pivot Points, checks left&right bars') ppsrc = input.string(defval='High/Low', title='Source', options=['High/Low', 'Close/Open'], group='Settings 🔨', tooltip='Source for Pivot Points') ChannelW = input.int(defval=5, title='Maximum Channel Width %', minval=1, maxval=8, group='Settings 🔨', tooltip='Calculated using Highest/Lowest levels in 300 bars') minstrength = input.int(defval=1, title='Minimum Strength', minval=1, group='Settings 🔨', tooltip='Channel must contain at least 2 Pivot Points') maxnumsr = input.int(defval=4, title='Maximum Number of S/R', minval=1, maxval=10, group='Settings 🔨', tooltip='Maximum number of Support/Resistance Channels to Show') - 1 loopback = input.int(defval=150, title='Loopback Period', minval=100, maxval=400, group='Settings 🔨', tooltip='While calculating S/R levels it checks Pivots in Loopback Period') res_col = input.color(defval=color.new(color.red, 75), title='Resistance Color', group='Colors 🟡🟢🟣') sup_col = input.color(defval=color.new(color.lime, 75), title='Support Color', group='Colors 🟡🟢🟣') inch_col = input.color(defval=color.new(color.gray, 75), title='Color When Price in Channel', group='Colors 🟡🟢🟣') // Get Pivot High/Low src1 = ppsrc == 'High/Low' ? high : math.max(close, open) src2 = ppsrc == 'High/Low' ? low : math.min(close, open) ph = ta.pivothigh(src1, prd, prd) pl = ta.pivotlow(src2, prd, prd) // Calculate maximum S/R channel width prdhighest = ta.highest(300) prdlowest = ta.lowest(300) cwidth = (prdhighest - prdlowest) * ChannelW / 100 // Get/keep Pivot levels var pivotvals = array.new_float(0) var pivotlocs = array.new_float(0) if ph or pl array.unshift(pivotvals, ph ? ph : pl) array.unshift(pivotlocs, bar_index) for x = array.size(pivotvals) - 1 to 0 by 1 if bar_index - array.get(pivotlocs, x) > loopback // remove old pivot points array.pop(pivotvals) array.pop(pivotlocs) continue break // Find/create SR channel of a pivot point get_sr_vals(ind) => float lo = array.get(pivotvals, ind) float hi = lo int numpp = 0 for y = 0 to array.size(pivotvals) - 1 by 1 float cpp = array.get(pivotvals, y) float wdth = cpp <= hi ? hi - cpp : cpp - lo if wdth <= cwidth // fits the max channel width? if cpp <= hi lo := math.min(lo, cpp) else hi := math.max(hi, cpp) numpp += 20 // each pivot point added as 20 [hi, lo, numpp] // Keep old SR channels and calculate/sort new channels if we met new pivot point var suportresistance = array.new_float(20, 0) // min/max levels changeit(x, y) => tmp = array.get(suportresistance, y * 2) array.set(suportresistance, y * 2, array.get(suportresistance, x * 2)) array.set(suportresistance, x * 2, tmp) tmp := array.get(suportresistance, y * 2 + 1) array.set(suportresistance, y * 2 + 1, array.get(suportresistance, x * 2 + 1)) array.set(suportresistance, x * 2 + 1, tmp) if ph or pl supres = array.new_float(0) // number of pivot, strength, min/max levels stren = array.new_float(10, 0) // Get levels and strengths for x = 0 to array.size(pivotvals) - 1 by 1 [hi, lo, strength] = get_sr_vals(x) array.push(supres, strength) array.push(supres, hi) array.push(supres, lo) // Add each HL to strength for x = 0 to array.size(pivotvals) - 1 by 1 h = array.get(supres, x * 3 + 1) l = array.get(supres, x * 3 + 2) s = 0 for y = 0 to loopback by 1 if high[y] <= h and high[y] >= l or low[y] <= h and low[y] >= l s += 1 array.set(supres, x * 3, array.get(supres, x * 3) + s) // Reset SR levels array.fill(suportresistance, 0) // Get strongest SRs src = 0 for x = 0 to array.size(pivotvals) - 1 by 1 stv = -1. // value stl = -1 // location for y = 0 to array.size(pivotvals) - 1 by 1 if array.get(supres, y * 3) > stv and array.get(supres, y * 3) >= minstrength * 20 stv := array.get(supres, y * 3) stl := y if stl >= 0 // Get SR level hh = array.get(supres, stl * 3 + 1) ll = array.get(supres, stl * 3 + 2) array.set(suportresistance, src * 2, hh) array.set(suportresistance, src * 2 + 1, ll) array.set(stren, src, array.get(supres, stl * 3)) // Make included pivot points' strength zero for y = 0 to array.size(pivotvals) - 1 by 1 if array.get(supres, y * 3 + 1) <= hh and array.get(supres, y * 3 + 1) >= ll or array.get(supres, y * 3 + 2) <= hh and array.get(supres, y * 3 + 2) >= ll array.set(supres, y * 3, -1) src += 1 if src >= 10 break for x = 0 to 8 by 1 for y = x + 1 to 9 by 1 if array.get(stren, y) > array.get(stren, x) tmp = array.get(stren, y) array.set(stren, y, array.get(stren, x)) changeit(x, y) get_level(ind) => float ret = na if ind < array.size(suportresistance) if array.get(suportresistance, ind) != 0 ret := array.get(suportresistance, ind) ret get_color(ind) => color ret = na if ind < array.size(suportresistance) if array.get(suportresistance, ind) != 0 ret := array.get(suportresistance, ind) > close and array.get(suportresistance, ind + 1) > close ? res_col : array.get(suportresistance, ind) < close and array.get(suportresistance, ind + 1) < close ? sup_col : inch_col ret // var srchannels = array.new_box(10) // for x = 0 to math.min(9, maxnumsr) by 1 // box.delete(array.get(srchannels, x)) // srcol = get_color(x * 2) // if not na(srcol) // array.set(srchannels, x, box.new(left=bar_index, top=get_level(x * 2), right=bar_index + 1, bottom=get_level(x * 2 + 1), border_color=srcol, border_width=1, extend=extend.both, bgcolor=srcol)) // Improved dynamic support detection float recentSupport1 = na float previousSupport = na float currentsupport = na if na(previousSupport) or currentsupport != previousSupport if array.size(suportresistance) > 1 for i = 0 to math.floor(array.size(suportresistance) / 2) - 1 // Iterate through support levels currentsupport := array.get(suportresistance, i * 2 + 1) // Support is stored at odd indices if currentsupport < close and (na(recentSupport1) or math.abs(close - currentsupport) < math.abs(close - recentSupport1)) previousSupport := currentsupport // Store the newly detected support // Set the most recent support to the new support recentSupport1 := na(recentSupport1) ? ta.lowest(low, 10) : currentsupport // Moving averages for entry and exit maShort = ta.sma(close, 5) maLong = ta.sma(close, 30) + ta.atr(14) // Track entry price entryPrice1 = strategy.position_avg_price // Get the price of the currently open position currentTimeFrame = timeframe.period exitPrice = entryPrice1 * 0.99 if currentTimeFrame == "1H" or currentTimeFrame == "30" or currentTimeFrame == "15" or currentTimeFrame == "5" exitPrice := entryPrice1 * 0.99 // Set the exit price at 99% of the entry price if currentTimeFrame == "120" or currentTimeFrame == "180" or currentTimeFrame == "240" or currentTimeFrame == "D" exitPrice := entryPrice1 * 0.98 // Set the exit price at 95% of the entry price // Calculate Moving Average based on higher timeframe for length of 20 bars higherTimeframeMA = request.security(syminfo.tickerid, higherTimeframeInput, ta.sma(close, 20), barmerge.gaps_off, barmerge.lookahead_on) // Calculate MA with adjusted timeframe // Entry and Exit Conditions for Long entryLong = (close > kcUpper) and (close > recentResistance) and (close > higherTimeframeMA) // Long entry when price breaks above KC upper, recent resistance, and higher timeframe MA exitLong = (close < recentResistance - 1.5*atrValue) // Long exit when price falls below recent resistance with cushion of one ATR // Entry and Exit Conditions for Short entryShort = (close < kcLower) and (close < recentSupport) and (close < higherTimeframeMA+atrValue) // Add RSI filter to reduce false signals by confirming momentum // Short entry when price breaks below KC lower, recent support, and higher timeframe MA exitShort = (close > recentSupport + atrValue) // Short exit when price rises above recent support with cushion of one ATR(close > recentSupport + atrValue) // Short exit when price rises above recent support with cushion of one ATR(close > recentSupport + atrValue) // Short exit when price rises above recent support with cushion of one ATR // Strategy Execution for Long if not na(recentSupport1) and (close <= recentSupport1 +(close*0.01) or close >= recentSupport1 - (close*0.0075)) and (maShort > maLong) and entryLong strategy.entry("Long Entry", strategy.long) //entryPrice := strategy.position_avg_price // Store the entry price when a position is opened if ((maShort < maLong + 3*ta.atr(14)) or close < exitPrice) and exitLong strategy.close("Long Entry") // Strategy Execution for Short if entryShort strategy.entry("Short Entry", strategy.short) entryPrice := strategy.position_avg_price // Store the entry price when a position is opened if exitShort strategy.close("Short Entry") // Plot Keltner Channels plot(kcUpper, color=color.orange, title="Keltner Channel Upper", linewidth=1) plot(kcLower, color=color.orange, title="Keltner Channel Lower", linewidth=1) // Plot Moving Averages plot(higherTimeframeMA, color=color.blue, title="Higher Timeframe MA", linewidth=2) //plot(recentSupport1, color=#04313f, title="Recent Support1") //plot(recentResistance, color=color.purple, title="Recent Resistance") //plot(entryPrice1, color=color.lime, title="Entry Price 1") //plot(exitPrice, color=color.maroon, title="Exit Price") //plot(maShort, color=color.green, title="MA Short") //plot(maLong, color=color.blue, title="MA Long Plus ATR") // Highlight Entry Zones bgcolor(entryLong ? color.new(color.green, 85) : na, title="Long Entry Zone") bgcolor(entryShort ? color.new(color.red, 85) : na, title="Short Entry Zone") // Alerts alertcondition(entryLong, title="Long Entry", message="Price broke above the Keltner Channel and recent resistance for Long Entry") alertcondition(exitLong, title="Long Exit", message="Price fell below recent resistance with cushion of one ATR - Long Exit") alertcondition(entryShort, title="Short Entry", message="Price broke below the Keltner Channel and recent support for Short Entry") alertcondition(exitShort, title="Short Exit", message="Price rose above recent support with cushion of one ATR - Short Exit")