이 독특한 체계적인 규칙 기반 거래 전략은 다음 트렌드 범주에 속합니다. 원시 틱어 가격에서 생성 트레이딩 신호로 변환 된 표준화 된 가격 시리즈를 사용합니다. 기관 포트폴리오 관리에 일반적으로 예약 된 고급 위치 사이징 및 리스크 관리 기술이이 전략에서 사용됩니다. 재화 거래 자문자 및 관리 선물 펀드와 같은 금융 자문자가 사용하는 검증 된 위치 및 리스크 제어 기술.
핵심 거래는 간단합니다. 정상화 된 가격 크로스오버 HMA에서 긴, HMA 아래에서 크로스오버 때 짧은. 새로운 신호는 기존의 반대 입장을 닫습니다.
포지션 크기는 최근 가격 변동성과 사용자가 정의한 연간 위험 목표에 따라 동적으로 조정됩니다. 포지션은 위험 가중화, 낮은 변동성과 함께 더 큰 크기와 더 높은 변동성과 함께 작습니다. 최근 변동성은 지난 14 기간 동안의 수익의 표준 편차이며, 예상 수익으로 연간 변동성으로 추출됩니다. 연간 위험 목표는 변동성 조정 된 포지션 크기의 참조로 사용됩니다. 기본 목표는 총 자본의 10%입니다. 초기 자본은 거래당 최대 손실로 설정해야합니다. 최대 레버리지는 기본 자연 변동성이 충분하지 않으면 위험 목표를 달성 할 수 있으며 과도하게 낮은 변동성을 완화합니다.
하드 스톱은 최근 가격 평균 실제 범위 곱자에 기반합니다. 사용자 설정이 가능합니다.
리스크 통제 조치에는 대체 이동 평균 선택, 리스크 목표의 조정 등이 포함됩니다.
이 전략은 정상화, 동적 위치 조정, 위험을 제어하기 위한 하드 스톱과 같은 다양한 기술을 통합한다. 거래는 간단한 트렌드 다음 규칙을 기반으로 한다. 개인 선호도와 시장 체제에 따라 매개 변수를 조정할 수 있다. 실현 가능한 실제 세계 응용을 위해 추가 테스트와 검증을 할 가치가 있다.
/*backtest start: 2023-01-17 00:00:00 end: 2024-01-23 00:00:00 period: 1d basePeriod: 1h 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/ // © Crunchster1 //@version=5 strategy(title="Crunchster's Normalised Trend Strategy", shorttitle="Normalised Trend Strategy", overlay=false ) // Inputs and Parameters src = input(close, 'Source', group='Strategy Settings') length = input.int(title="Lookback period for price normalisation filter", defval=14, minval=2, group='Strategy Settings', tooltip='This sets the lookback period for the volatility adjustment of returns, which is used to transform the price series into the "real price"') hlength = input.int(title="Lookback period for Hull Moving Average", defval=100, minval=2, group='Strategy Settings') offset = input.int(title="HMA Offset", defval=0, minval=0, group='Strategy Settings') long = input(true, 'Long', inline='08', group='Strategy Settings') short = input(true, 'Short', inline='08', group='Strategy Settings', tooltip='Toggle long/short strategy on/off') stopMultiple = input.float(1, 'Stop multiple', step=0.25, group='Risk Management Settings', tooltip='Multiple for ATR, setting hard stop loss from entry price') lev = input.float(1, 'Max Leverage', step=0.5, group='Risk Management Settings', tooltip='Max leverage sets maximum allowable leverage of total capital (initial capital + any net profit), capping maximum volatility adjusted position size') riskT = input.float(10, maxval=75, title='Annualised Volatility Target %', group='Risk Management Settings', tooltip='Specify annual risk target, used to determine volatility adjusted position size. Annualised daily volatility is referenced to this value and position size adjusted accordingly') comp = input(false, 'Compounding', inline='09', group='Risk Management Settings') Comppct = input.float(50, '%', step=5, inline='09', group='Risk Management Settings', tooltip='Toggle compounding of profit, and set % of profit to compound') // Backtesting period FromDay = input.int(defval=1, title='From Day', minval=1, maxval=31, inline='04', group='Backtest range') FromMonth = input.int(defval=1, title='From Mon', minval=1, maxval=12, inline='04', group='Backtest range') FromYear = input.int(defval=2018, title='From Yr', minval=1900, inline='04', group='Backtest range', tooltip='Set start of backtesting period') ToDay = input.int(defval=1, title='To Day', minval=1, maxval=31, inline='05', group='Backtest range') ToMonth = input.int(defval=1, title='To Mon', minval=1, maxval=12, inline='05', group='Backtest range') ToYear = input.int(defval=9999, title='To Yr', minval=1900, inline='05', group='Backtest range', tooltip='Set end of backtesting period') start = timestamp(FromYear, FromMonth, FromDay, 00, 00) finish = timestamp(ToYear, ToMonth, ToDay, 23, 59) window = true // Normalised returns calculation nRet = (src - src[1]) / ta.stdev((src - src[1]), length) nPrice = ta.cum(nRet) //Hull Moving Average - using normalised price series fHMA = ta.wma(2 * ta.wma(nPrice[offset], hlength / 2) - ta.wma(nPrice[offset], hlength), math.round(math.sqrt(hlength))) //Risk Management formulae strategy.initial_capital = 50000 tr = math.max(high - low, math.abs(high - close), math.abs(low - close)) //True range stopL = ta.sma(tr, 14) //Average true range stdev = ta.stdev(close-close[1], 14) //volatility of recent returns maxcapital = strategy.initial_capital+strategy.netprofit //Maximum capital available to invest - initial capital net of profit annvol = 100*math.sqrt(365)*stdev/close //converts recent volatility of returns into annualised volatility of returns - assumes daily timeframe risk = 1.1 if comp risk := (strategy.initial_capital+(Comppct*strategy.netprofit/100))//adjust investment capital to include compounding else risk := strategy.initial_capital shares = (risk * (riskT/annvol)) / close //calculates volatility adjusted position size, dependent on user specified annualised risk target if ((shares*close) > lev*maxcapital) //ensures position size does not exceed available capital multiplied by user specified maximum leverage shares := lev*maxcapital/close //To set the price at the entry point of trade Posopen() => math.abs(strategy.position_size[1]) <= 0 and math.abs(strategy.position_size) > 0 var float openN = na if Posopen() openN := stopL // Strategy Rules if long longCondition = ta.crossover(nPrice, fHMA) and window exitlong = ta.crossunder(nPrice, fHMA) if (longCondition) strategy.entry('Go Long!', strategy.long, qty=shares) if strategy.position_size > 0 strategy.exit('Stop Long', from_entry = 'Go Long!', stop=(strategy.opentrades.entry_price(0) - (openN * stopMultiple))) if (exitlong) strategy.close('Go Long!', immediately = true) if short shortCondition = ta.crossunder(nPrice, fHMA) and window exitshort = ta.crossover(nPrice, fHMA) if (shortCondition) strategy.entry('Go Short!', strategy.short, qty=shares) if strategy.position_size < 0 strategy.exit('Stop Short', from_entry = 'Go Short!', stop=(strategy.opentrades.entry_price(0) + (openN * stopMultiple))) if (exitshort) strategy.close('Go Short!', immediately = true) // Visuals of trend and direction plot(nPrice, title='Real Price', color=color.black) MAColor = fHMA > fHMA[3] ? #00ff00 : #ff0000 MA1 = plot(fHMA, title='Hull MA', color=MAColor) MA2 = plot(fHMA[3], title='Hull MA Offset', color=MAColor) fill(MA1, MA2, title='Band Filler', color=MAColor)