This strategy integrates the exponential moving average crossover system and turtle trading system, two popular systematic trading strategies. It is specially designed for the daily timeframe to track market trends in real-time by dynamically managing positions.
The strategy contains two sub-strategies: trend strategy and breakout strategy.
The trend strategy uses fast EMA and slow EMA crossovers as trading signals. The fast EMA period is user-defined and the slow EMA period is 5 times of the fast EMA. The signal is generated by dividing the EMA difference by the 252-period return standard deviation, which is volatility-adjusted to produce more reliable signals. It goes long or short when detecting new trend formations.
The breakout strategy uses the average of highest high and lowest low prices over a fixed lookback period as the baseline. Long/short signals are generated when the price breaks out above/below the baseline by a certain percentage.
Position sizing is based on recent price volatility and user-defined annual risk target. Larger size is taken when volatility is low while smaller size is taken when volatility is high. This realizes dynamic position management with risk adjustment.
Hard stops are set as multiples of the average true range. Trailing stops trail recent highest high or lowest low prices.
The main advantages of this strategy include:
Combining trend tracking and breakout sub-strategies adapts to different market environments with strong robustness.
Applying advanced position sizing and risk management techniques dynamically manages position and effectively controls risk.
Volatility-adjusting positions based on recent volatility and annual risk target maintains relatively stable portfolio risk across high/low volatility regimes.
Setting stop loss based on actual price fluctuation avoids unnecessary small losses from stop runs.
Adjusting trailing stop in real-time flexibly follows trends to book profits and stops out timely.
The main risks of this strategy are:
Reliance on parameter optimization. Different parameters considerably impact strategy performance so comprehensive testing is needed to find optimum parameters.
Frequent stop outs in choppy trends. Stop loss width could be relaxed and stop mechanisms optimized.
Sensitivity to initial capital and trading costs. Insufficient initial capital and high trading costs negatively impact profitability.
Reliance on accurate volatility estimates for position sizing and risk controls. Inaccurate volatility estimates lead to oversized or undersized positions.
The main optimization directions include:
Search for optimal parameter sets via more backtesting with larger historical dataset.
Improve stop mechanisms by testing various stops like moving stops, time stops, volatility stops etc.
Optimize position sizing and risk management by testing different risk targets to find best risk-return profile. Also test impacts of different leverage levels.
Try more auxiliary indicators to improve signal accuracy and strategy robustness.
Test different holding periods by assisting decisions with higher timeframe signals to improve position allocation accuracy.
This strategy integrates two major categories of trading strategies: trend following and breakouts. By applying advanced dynamic position adjustment techniques, it effectively controls risk while tracking market moves to profit. It demonstrates strong profit potential and is worth further testing and optimization.
/*backtest start: 2023-12-01 00:00:00 end: 2023-12-31 23:59:59 period: 1h basePeriod: 15m 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 Turtle and Trend System", shorttitle="Turtle Trend", overlay=true, slippage=10, pyramiding=1, precision = 4, calc_on_order_fills = false, calc_on_every_tick = false, default_qty_value = 0.1, initial_capital = 1000, commission_value = 0.06, process_orders_on_close = true) // Inputs and Parameters src = input(close, 'Source', group='Strategy Settings') length = input.int(title="Lookback period for fast EMA", defval=10, minval=2, group='Strategy Settings', tooltip='This sets the lookback period for the fast exponential moving average. The slow EMA is 5x the fast EMA length') blength = input.int(title="Lookback period for Breakout", defval=20, minval=5, step=5, group='Strategy Settings') long = input(true, 'Long', inline='08', group='Strategy toggle') short = input(true, 'Short', inline='08', group='Strategy toggle', tooltip='Toggle long/short strategy on/off') EMAwt = input(false, 'Trend', inline='01', group='Strategy toggle') breakwt = input(true, 'Breakout', inline='01', group='Strategy toggle', tooltip='Toggle trend/breakout strategy on/off') stopMultiple = input.float(2, 'Stop multiple', step=0.5, group='Risk Management Settings', tooltip='Multiple for ATR, setting hard stop loss from entry price') trail = input.int(10, 'Trail lookback', step=5, group='Risk Management Settings', tooltip='Lookback period for the trailing stop') 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(15, 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(true, '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 = time >= start and time <= finish // Breakout strategy lower = ta.lowest(low[1], blength) upper = ta.highest(high[1], blength) basis = math.avg(upper, lower) signal = 20*(close - basis) / (upper - lower) // Trend strategy fEMA = ta.ema(close[1], length) sEMA = ta.ema(close[1], length*5) emadiff = fEMA - sEMA nemadiff = 5*emadiff/(ta.stdev(close - close[1], 252)) //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 // Trailing stop tlower = ta.lowest(low[1], trail) tupper = ta.highest(high[1], trail) tbasis = math.avg(tupper, tlower) tsignal = 20*(close - tbasis) / (tupper - tlower) // Strategy Rules if EMAwt if long longCondition2 = (nemadiff >2 and nemadiff[1] <2) and window exitlong = tsignal <= -10 if (longCondition2) strategy.entry('Trend Long!', strategy.long, qty=shares) if strategy.position_size > 0 strategy.exit('Stop Long', from_entry = 'Trend Long!', stop=(strategy.opentrades.entry_price(0) - (openN * stopMultiple))) if (exitlong) strategy.close('Trend Long!', immediately = true) if short shortCondition2 = (nemadiff <-1 and nemadiff[1] >-1) and window exitshort = tsignal >= 10 if (shortCondition2) strategy.entry('Trend Short!', strategy.short, qty=shares) if strategy.position_size < 0 strategy.exit('Stop Short', from_entry = 'Trend Short!', stop=(strategy.opentrades.entry_price(0) + (openN * stopMultiple))) if (exitshort) strategy.close('Trend Short!', immediately = true) if breakwt if long longCondition1 = (signal >= 10) and window exitlong = tsignal <= -10 if (longCondition1) strategy.entry('Break Long!', strategy.long, qty=shares) if strategy.position_size > 0 strategy.exit('Stop Long', from_entry = 'Break Long!', stop=(strategy.opentrades.entry_price(0) - (openN * stopMultiple))) if (exitlong) strategy.close('Break Long!', immediately = true) if short shortCondition1 = (signal <= -10) and window exitshort = tsignal >= 10 if (shortCondition1) strategy.entry('Break Short!', strategy.short, qty=shares) if strategy.position_size < 0 strategy.exit('Stop Short', from_entry = 'Break Short!', stop=(strategy.opentrades.entry_price(0) + (openN * stopMultiple))) if (exitshort) strategy.close('Break Short!', immediately = true) // Visuals of trend and direction plot(nemadiff, title='EMA Forecast', color=color.black, display=display.none) plot(ta.sma(ta.median(math.sqrt(math.pow(nemadiff,2)), 700), 350), 'Forecast mean', color=color.rgb(245, 0, 0), display=display.none) MAColor = fEMA > sEMA ? #00ff00 : #ff0000 MA1 = plot(fEMA, title='Fast EMA', color=MAColor) MA2 = plot(sEMA, title='Slow EMA', color=MAColor) fill(MA1, MA2, title='Band Filler', color=MAColor)