
이 전략은 3가지 지표인 붐 헌터 (Boom Hunter), 헐 스위트 (Hull Suite) 및 변동성 오스실레이터 (Volatility Oscillator) 를 결합하여, 여러 시간 프레임에 걸쳐 트렌드를 추적하고 거래의 돌파를 수행하는 정량화 전략을 구현한다. 이 전략은 비트코인과 같은 높은 변동성 및 급격한 가격 상황의 디지털 자산에 적용된다.
이 전략의 핵심 논리는 다음과 같은 세 가지 지표에 기초하고 있습니다.
붐 헌터 (Boom Hunter): 지표 압축 기술을 이용한 진동기, 두 지표 (Quotient1과 Quotient2) 의 교차로 구매 및 판매 신호를 판단한다.
헐 스위트 (Hull Suite): 평평한 이동평준 지표의 집합으로, 중간 궤도와 상하 궤도의 관계를 통해 트렌드 방향을 판단한다.
변동율 진동기 (Volatility Oscillator): 가격 변동에 대한 정보의 양적 진동 지표.
이 전략의 진입 논리는, 양반 사냥꾼의 두 개의 Quotient 지표가 위 또는 아래로 교차하는 동시에, 가격이 헐 중간 궤도를 뚫고 상반도 또는 하반도와 이탈하는 것입니다. meanwhile 변동률 지표는 과매도 과매도 영역에 있습니다. 이렇게하면 일부 가짜 돌파 신호를 필터링하여 진입의 정확성을 향상시킬 수 있습니다.
정지 손실은 일정 기간 동안의 최저 계곡이나 최고 절벽을 찾아서 설정되며, 수익은 정지 손실 비율을配置의 정지 비율로 곱하여 얻습니다. 포지션은 계정 총 자산의 비율 (설정 3%) 과 특정 지표의 정지 손실 정도에 따라 계산됩니다.
해결책:
이 전략은 다음과 같은 부분에서 최적화될 수 있습니다.
변수 최적화: 주기 길이, 압축 계수 등과 같은 지표 변수를 변경하여 최적의 변수 조합을 얻습니다.
시간 프레임 최적화다른 시간 주기를 테스트하고, 1분, 5분, 30분 등으로, 가장 적합한 거래 주기를 찾습니다.
포지션 최적화: 거래마다 포지션의 크기와 비율을 변경하여 최적의 자금 활용 방법을 찾습니다.
손해 방지 최적화: 서로 다른 거래에 따라 스톱 포지션을 조정하여 최적의 리스크/이익 비율을 달성합니다.
조건 최적화: 더 정확한 입시 시점을 얻기 위해 지표 필터링 조건을 늘리거나 줄여라
이 전략은 헝 사냥꾼, 헐 킷 및 변동률 진동기의 세 가지 지표의 조합을 사용하여, 다중 시간 프레임에 대한 트렌드 추적 거래를 구현하고, 가격의 갑작스러운 행동을 효과적으로 식별할 수 있습니다. 이 전략은 위험이 제어 가능하며, 매개 변수, 파동 조건 및 상쇄 등 여러 가지 측면에서 최적화되며, 강력한 실전성과 확장성이 있습니다.
/*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))