이 전략은 붐 헌터 (Boom Hunter), 헐 스위트 (Hull Suite), 그리고 변동성 오시일레이터 (Volatility Oscillator) 인디케이터들을 결합하여 트렌드 추적 및 브레이크아웃 트레이딩을 위한 양적 전략을 여러 시간 프레임에 걸쳐 구현한다. 이는 비트코인과 같은 높은 변동성과 급격한 가격 움직임이 있는 디지털 자산에 적합하다.
이 전략의 핵심 논리는 다음 세 가지 지표에 기초합니다.
붐 헌터: 지표 압축 기법을 사용하여 두 분수 (Quotient1와 Quotient2) 사이의 교차에서 거래 신호를 생성하는 오시레이터입니다.
헬스 스위트: 중간선과 상부/하부 간 사이의 관계를 기반으로 트렌드 방향을 결정하는 평형 이동 평균선의 집합.
변동성 오시레이터: 가격 변동성을 정량화하는 오시레이터 지표입니다.
이 전략의 진입 논리는 붐 헌터의 두 쿼이언트 지표가 상향 또는 하향을 넘어서면, 가격이 헬스 미드라인을 뚫고 상위 또는 하위 밴드에서 벗어나면서 변동성 오시레이터가 과잉 구매 / 과잉 판매 영역에있을 때입니다. 이것은 일부 잘못된 브레이크 아웃 신호를 필터링하고 진입 정확도를 향상시킵니다.
스톱 손실은 특정 기간 동안 가장 낮은 계곡 또는 가장 높은 정점을 찾는 것으로 설정됩니다 (디폴트 20 바), 그리고 스톱 손실 비율을 구성 된 이익 인수로 곱하여 수익을 얻습니다 (디폴트 3x). 포지션 사이징은 전체 계좌 자금의 비율 (디폴트 3%) 및 도구의 특정 스톱 손실 범위에 따라 계산됩니다.
해결책:
이 전략은 다음과 같은 측면에서 최적화 될 수 있습니다.
매개 변수 최적화: 기간과 압축 계수와 같은 지표 설정을 조정하여 최고의 매개 변수 조합을 얻으십시오.
시간 프레임 최적화: 최적의 거래 기간을 찾기 위해 다양한 기간 (1분, 5분, 30분 등) 을 테스트합니다.
위치 크기 최적화: 이상적인 자본 활용 계획을 찾기 위해 거래 위치 크기와 비율에 따른 변화
손실 최적화 중지: 최적의 위험/이익 비율을 달성하기 위해 다른 거래 도구에 기초한 스톱 로스 배치를 조정합니다.
조건 최적화: 더 정확한 입력 신호를 얻기 위해 표시 필터를 추가/감소
이 전략은 붐 헌터 (Boom Hunter), 헐 스위트 (Hull Suite) 및 변동성 오시일레이터를 결합하여 다중 타임프레임 트렌드 추적 거래를 구현하여 매우 변동성 있는 디지털 자산에 적합한 급격한 가격 행동을 효과적으로 식별합니다. 제어 가능한 위험, 강력한 실용성 및 매개 변수 조정, 필터 조건 및 스톱 로스 최적화를 통해 확장성으로, 그것은 모범적인 양적 모델입니다.
/*backtest start: 2024-01-27 00:00:00 end: 2024-02-26 00:00:00 period: 1h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ // Strategy based on the 3 indicators: // - Boom Hunter Pro // - Hull Suite // - Volatility Oscillator // // Strategy was designed for the purpose of back testing. // See strategy documentation for info on trade entry logic. // // Credits: // - Boom Hunter Pro: veryfid (https://www.tradingview.com/u/veryfid/) // - Hull Suite: InSilico (https://www.tradingview.com/u/InSilico/) // - Volatility Oscillator: veryfid (https://www.tradingview.com/u/veryfid/) //@version=5 strategy("Boom Hunter + Hull Suite + Volatility Oscillator Strategy", overlay=false, initial_capital=1000, currency=currency.NONE, max_labels_count=500, default_qty_type=strategy.cash, commission_type=strategy.commission.percent, commission_value=0.01) // ============================================================================= // STRATEGY INPUT SETTINGS // ============================================================================= // --------------- // Risk Management // --------------- swingLength = input.int(20, "Swing High/Low Lookback Length", group='Strategy: Risk Management', tooltip='Stop Loss is calculated by the swing high or low over the previous X candles') accountRiskPercent = input.float(3, "Account percent loss per trade", step=0.1, group='Strategy: Risk Management', tooltip='Each trade will risk X% of the account balance') profitFactor = input.float(3, "Profit Factor (R:R Ratio)", step = 0.1, group='Strategy: Risk Management') // ---------- // Date Range // ---------- start_year = input.int(title='Start Date', defval=2022, minval=2010, maxval=3000, group='Strategy: Date Range', inline='1') start_month = input.int(title='', defval=1, group='Strategy: Date Range', inline='1', options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) start_date = input.int(title='', defval=1, group='Strategy: Date Range', inline='1', options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]) end_year = input.int(title='End Date', defval=2023, minval=1800, maxval=3000, group='Strategy: Date Range', inline='2') end_month = input.int(title='', defval=1, group='Strategy: Date Range', inline='2', options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) end_date = input.int(title='', defval=1, group='Strategy: Date Range', inline='2', options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]) in_date_range = true // ============================================================================= // INDICATORS // ============================================================================= // --------------- // Boom Hunter Pro // --------------- square = input.bool(true, title='Square Line?', group='Main Settings') //Quotient LPPeriod = input.int(6, title='Quotient | LPPeriod', inline='quotient', group='EOT 1 (Main Oscillator)') K1 = input.int(0, title='K1', inline='quotient', group='EOT 1 (Main Oscillator)') esize = 60 //, title = "Size", inline = "quotient2", group = "EOT 1 (Main Oscillator)") ey = 50 //, title = "Y axis", inline = "quotient2", group = "EOT 1 (Main Oscillator)") trigno = input.int(1, 'Trigger Length', group='EOT 1 (Main Oscillator)', inline='quotient2') trigcol = input.color(color.white, title='Trigger Color:', group='EOT 1 (Main Oscillator)', inline='q2') // EOT 2 //Inputs LPPeriod2 = input.int(28, title='LPPeriod2', group='EOT 2 (Red Wave)', inline='q2') K22 = input.float(0.3, title='K2', group='EOT 2 (Red Wave)', inline='q2') //EOT 1 //Vars alpha1 = 0.00 HP = 0.00 a1 = 0.00 b1 = 0.00 c1 = 0.00 c2 = 0.00 c3 = 0.00 Filt = 0.00 Peak = 0.00 X = 0.00 Quotient1 = 0.00 pi = 2 * math.asin(1) //Highpass filter cyclic components //whose periods are shorter than 100 bars alpha1 := (math.cos(.707 * 2 * pi / 100) + math.sin(.707 * 2 * pi / 100) - 1) / math.cos(.707 * 2 * pi / 100) HP := (1 - alpha1 / 2) * (1 - alpha1 / 2) * (close - 2 * nz(close[1]) + nz(close[2])) + 2 * (1 - alpha1) * nz(HP[1]) - (1 - alpha1) * (1 - alpha1) * nz(HP[2]) //SuperSmoother Filter a1 := math.exp(-1.414 * pi / LPPeriod) b1 := 2 * a1 * math.cos(1.414 * pi / LPPeriod) c2 := b1 c3 := -a1 * a1 c1 := 1 - c2 - c3 Filt := c1 * (HP + nz(HP[1])) / 2 + c2 * nz(Filt[1]) + c3 * nz(Filt[2]) //Fast Attack - Slow Decay Algorithm Peak := .991 * nz(Peak[1]) if math.abs(Filt) > Peak Peak := math.abs(Filt) Peak //Normalized Roofing Filter if Peak != 0 X := Filt / Peak X Quotient1 := (X + K1) / (K1 * X + 1) // EOT 2 //Vars alpha1222 = 0.00 HP2 = 0.00 a12 = 0.00 b12 = 0.00 c12 = 0.00 c22 = 0.00 c32 = 0.00 Filt2 = 0.00 Peak2 = 0.00 X2 = 0.00 Quotient4 = 0.00 alpha1222 := (math.cos(.707 * 2 * pi / 100) + math.sin(.707 * 2 * pi / 100) - 1) / math.cos(.707 * 2 * pi / 100) HP2 := (1 - alpha1222 / 2) * (1 - alpha1222 / 2) * (close - 2 * nz(close[1]) + nz(close[2])) + 2 * (1 - alpha1222) * nz(HP2[1]) - (1 - alpha1222) * (1 - alpha1222) * nz(HP2[2]) //SuperSmoother Filter a12 := math.exp(-1.414 * pi / LPPeriod2) b12 := 2 * a12 * math.cos(1.414 * pi / LPPeriod2) c22 := b12 c32 := -a12 * a12 c12 := 1 - c22 - c32 Filt2 := c12 * (HP2 + nz(HP2[1])) / 2 + c22 * nz(Filt2[1]) + c32 * nz(Filt2[2]) //Fast Attack - Slow Decay Algorithm Peak2 := .991 * nz(Peak2[1]) if math.abs(Filt2) > Peak2 Peak2 := math.abs(Filt2) Peak2 //Normalized Roofing Filter if Peak2 != 0 X2 := Filt2 / Peak2 X2 Quotient4 := (X2 + K22) / (K22 * X2 + 1) q4 = Quotient4 * esize + ey //Plot EOT q1 = Quotient1 * esize + ey trigger = ta.sma(q1, trigno) Plot3 = plot(trigger, color=trigcol, linewidth=2, title='Quotient 1') Plot44 = plot(q4, color=color.new(color.red, 0), linewidth=2, title='Quotient 2') // ---------- // HULL SUITE // ---------- //INPUT src = input(close, title='Source') modeSwitch = input.string('Hma', title='Hull Variation', options=['Hma', 'Thma', 'Ehma']) length = input(200, title='Length(180-200 for floating S/R , 55 for swing entry)') lengthMult = input(2.4, title='Length multiplier (Used to view higher timeframes with straight band)') useHtf = input(false, title='Show Hull MA from X timeframe? (good for scalping)') htf = input.timeframe('240', title='Higher timeframe') //FUNCTIONS //HMA HMA(_src, _length) => ta.wma(2 * ta.wma(_src, _length / 2) - ta.wma(_src, _length), math.round(math.sqrt(_length))) //EHMA EHMA(_src, _length) => ta.ema(2 * ta.ema(_src, _length / 2) - ta.ema(_src, _length), math.round(math.sqrt(_length))) //THMA THMA(_src, _length) => ta.wma(ta.wma(_src, _length / 3) * 3 - ta.wma(_src, _length / 2) - ta.wma(_src, _length), _length) //SWITCH Mode(modeSwitch, src, len) => modeSwitch == 'Hma' ? HMA(src, len) : modeSwitch == 'Ehma' ? EHMA(src, len) : modeSwitch == 'Thma' ? THMA(src, len / 2) : na //OUT _hull = Mode(modeSwitch, src, int(length * lengthMult)) HULL = useHtf ? request.security(syminfo.ticker, htf, _hull) : _hull MHULL = HULL[0] SHULL = HULL[2] //COLOR hullColor = MHULL > SHULL ? color.green : color.red //PLOT ///< Frame Fi1 = plot(-10, title='MHULL', color=hullColor, linewidth=2) // ----------------- // VOLUME OSCILLATOR // ----------------- volLength = input(80) spike = close - open x = ta.stdev(spike, volLength) y = ta.stdev(spike, volLength) * -1 volOscCol = spike > x ? color.green : spike < y ? color.red : color.gray plot(-30, color=color.new(volOscCol, transp=0), linewidth=2) // ============================================================================= // STRATEGY LOGIC // ============================================================================= // Boom Hunter Pro entry conditions boomLong = ta.crossover(trigger, q4) boomShort = ta.crossunder(trigger, q4) // Hull Suite entry conditions hullLong = MHULL > SHULL and close > MHULL hullShort = MHULL < SHULL and close < SHULL // Volatility Oscillator entry conditions volLong = spike > x volShort = spike < y inLong = strategy.position_size > 0 inShort = strategy.position_size < 0 longCondition = boomLong and hullLong and volLong and in_date_range shortCondition = boomShort and hullShort and volShort and in_date_range swingLow = ta.lowest(source=low, length=swingLength) swingHigh = ta.highest(source=high, length=swingLength) atr = ta.atr(14) longSl = math.min(close - atr, swingLow) shortSl = math.max(close + atr, swingHigh) longStopPercent = math.abs((1 - (longSl / close)) * 100) shortStopPercent = math.abs((1 - (shortSl / close)) * 100) longTpPercent = longStopPercent * profitFactor shortTpPercent = shortStopPercent * profitFactor longTp = close + (close * (longTpPercent / 100)) shortTp = close - (close * (shortTpPercent / 100)) // Position sizing (default risk 3% per trade) riskAmt = strategy.equity * accountRiskPercent / 100 longQty = math.abs(riskAmt / longStopPercent * 100) / close shortQty = math.abs(riskAmt / shortStopPercent * 100) / close if (longCondition and not inLong) strategy.entry("Long", strategy.long, qty=longQty) strategy.exit("Long SL/TP", from_entry="Long", stop=longSl, limit=longTp, alert_message='Long SL Hit') buyLabel = label.new(x=bar_index, y=high[1], color=color.green, style=label.style_label_up) label.set_y(id=buyLabel, y=-40) label.set_tooltip(id=buyLabel, tooltip="Risk Amt: " + str.tostring(riskAmt) + " Qty: " + str.tostring(longQty) + " Swing low: " + str.tostring(swingLow) + " Stop Percent: " + str.tostring(longStopPercent) + " TP Percent: " + str.tostring(longTpPercent)) if (shortCondition and not inShort) strategy.entry("Short", strategy.short, qty=shortQty) strategy.exit("Short SL/TP", from_entry="Short", stop=shortSl, limit=shortTp, alert_message='Short SL Hit') sellLabel = label.new(x=bar_index, y=high[1], color=color.red, style=label.style_label_up) label.set_y(id=sellLabel, y=-40) label.set_tooltip(id=sellLabel, tooltip="Risk Amt: " + str.tostring(riskAmt) + " Qty: " + str.tostring(shortQty) + " Swing high: " + str.tostring(swingHigh) + " Stop Percent: " + str.tostring(shortStopPercent) + " TP Percent: " + str.tostring(shortTpPercent))