다단계 동적 트렌드 추적 시스템 (Multi-Level Dynamic Trend Following System) 은 거북이 거래 규칙에 기반한 향상된 전략이다. 이 전략은 동적 스톱 로스 및 피라미드 포지션 구축과 결합하여 중장기 트렌드를 캡처하기 위해 여러 기간의 트렌드 신호를 활용한다. 이 시스템은 서로 다른 속도로 트렌드를 캡처하기 위해 두 개의 트렌드 추적 기간 (L1 및 L2) 을 설정하고 적응 가능한 ATR 지표를 사용하여 엔트리, 포지션 구축 및 스톱 로스 포인트를 동적으로 조정한다. 이 다단계 설계는 전략이 피라미드 포지션 구축을 통해 잠재적 이익을 극대화하면서 다른 시장 환경에서 안정성을 유지할 수 있게 한다.
트렌드 식별: 두 개의 이동 평균 기간 (L1 및 L2) 은 서로 다른 속도로 트렌드를 식별하는 데 사용됩니다. L1은 더 빠른 트렌드를 캡처하는 데 사용되며, L2는 느리지만 더 신뢰할 수있는 트렌드를 캡처합니다.
엔트리 신호: 가격이 L1 또는 L2 최고치를 넘을 때 긴 신호가 생성됩니다. 이전 L1 거래가 수익성이 있었다면 L2 신호가 나타날 때까지 다음 L1 신호가 건너뛰됩니다.
동적 스톱 로스 (Dynamic Stop Loss): ATR의 배수 (디폴트 3x) 를 초기 스톱 로스 거리로 사용하며, 포지션이 유지됨에 따라 점차 상승합니다.
피라미드 포지션 구축: 트렌드 지속 기간 동안 가격은 최대 5 배까지 0.5 ATR 상승 할 때마다 추가 포지션이 추가됩니다.
리스크 제어: 각각의 거래는 역동적인 포지션 사이즈링을 통해 달성되는 계정 자본의 2% 이상을 리스크하지 않습니다.
출구 메커니즘: 가격이 10일 최저치 (L1) 또는 20일 최저치 (L2) 이하로 떨어지거나 후속 스톱 로스가 발생하면 포지션이 폐쇄됩니다.
다단계 트렌드 포착: L1 및 L2 기간은 전략의 적응력과 안정성을 향상시키는 신속하고 장기적인 트렌드를 포착 할 수 있습니다.
동적 리스크 관리: 변동성 지표로 ATR을 사용하면 시장 변화에 더 잘 적응하여 엔트리, 스톱 로스 및 포지션 구축 포인트를 동적으로 조정할 수 있습니다.
피라미드 포지션 구축: 트렌드 지속 기간 동안 점진적으로 포지션을 늘리는 것은 위험을 통제하고 수익 잠재력을 극대화합니다.
유연한 매개 변수 설정: 여러 가지 조정 가능한 매개 변수로 전략이 다른 시장과 거래 스타일에 적응 할 수 있습니다.
자동 실행: 전략은 완전히 자동화되어 인간의 개입과 감정적 영향을 줄일 수 있습니다.
트렌드 역전 위험: 강한 트렌드 시장에서 좋은 성과를 거두지만 범위 제한 시장에서 빈번한 손실로 이어질 수 있습니다.
슬리핑 및 거래 비용: 빈번한 포지션 구축 및 이동 스톱 손실은 높은 거래 비용을 초래할 수 있습니다.
과도한 최적화 위험: 많은 매개 변수가 역사적 데이터의 과도한 적합성으로 이어질 수 있습니다.
자본 관리 위험: 작은 초기 자본은 여러 포지션 구축을 효과적으로 실행하지 못할 수 있습니다.
시장 유동성 위험: 유동성이 낮은 시장에서는 이상적인 가격으로 거래를 수행하는 것이 어려울 수 있습니다.
시장 환경 필터링을 포함: 시장 조건을 평가하고 범위 시장에서 거래 빈도를 줄이기 위해 트렌드 강도 지표 (예: ADX) 를 추가하십시오.
포지션 구축 전략을 최적화하십시오: 고정 0.5 ATR 및 5 번보다는 트렌드 강도에 따라 포지션 구축의 간격과 수를 동적으로 조정하는 것을 고려하십시오.
이윤 취득 메커니즘을 도입하십시오: 장기적인 추세에서 3 배의 ATR 이윤에 도달 할 때 포지션의 절반을 닫는 것과 같은 이윤을 잠금하기 위해 부분 이윤 취득을 설정하십시오.
다중 도구 상관 분석: 포트폴리오에 적용할 때 전체 위험/이익 비율을 최적화하기 위해 도구 간 상관 분석을 추가하십시오.
변동성 필터링을 추가합니다. 비정상적인 시장 상황을 처리하기 위해 극심한 변동성 기간 동안 거래를 중단하거나 위험 매개 변수를 조정합니다.
출구 메커니즘을 최적화하십시오. Parabolic SAR 또는 Chandelier Exit와 같은 더 유연한 출구 지표를 사용하는 것을 고려하십시오.
다단계 동적 트렌드 추적 시스템 (Multi-Level Dynamic Trend Following System) 은 고전적인 거북이 거래 규칙과 현대적인 양적 기법을 결합한 포괄적인 전략이다. 다단계 트렌드 식별, 동적 위험 관리, 피라미드 위치 구축을 통해 이 전략은 견고함을 유지하면서 트렌드 캡처 능력과 수익 잠재력을 향상시킨다. 적절한 매개 변수 최적화와 위험 통제로 범위 제한 시장에서 도전에 직면하지만, 전략은 다양한 시장 환경에서 안정적인 성능을 유지할 잠재력을 가지고 있다. 향후 개선은 전략의 견고성과 수익성을 향상시키기 위해 시장 환경 평가, 위치 구축 및 출구 메커니즘을 최적화하는 데 초점을 맞출 수 있다.
/*backtest start: 2024-06-28 00:00:00 end: 2024-07-28 00:00:00 period: 1h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ //@version=5 // This is a strategy based on the famous turtle system. // https://www.tradingblox.com/originalturtles/originalturtlerules.htm // // In a nutshell, it a trend trading system where you are buying on strength, selling on weakness. // positions should be entered when the price crosses over the 20-day high (L1 high) or 55-day high (L2 high). // positions should be exited when the prices crosses below the 10-day low (L1 low) or 20-day low (L2 low) // you can add positions at every unit (measured by multiple of n, where n=1 ATR) // stops should be placed at 2*n below every position entered, when the stop is hit exit your entire position. // positions should be entered everytime price crosses over L1 or L2, with one exception: // if the last trade was an L1 trade and it was a winning trade, skip the next trade unless the price crosses // over L2, if that is the case, you should take it. // L1 and L2 levels are also configurable for high and lows. // N multiple for stops and pyramid are also configurable // To change this from a strategy to a study: // 1) uncomment the next line and comment out the strategy line. // 2) at the end of the file comment out the last 2 lines // study(title="Turtle Study", overlay=true) strategy(title='kTF-VNI', overlay=true, initial_capital=100000000, commission_type=strategy.commission.percent, commission_value=0.0, pyramiding=100, process_orders_on_close=true, calc_on_every_tick=true) stopInput = input.float(3, 'Stop N', step=.05) riskPercent = input.float(.01, 'Risk % of capital', step=.005) pyramidInput = input.float(0.5, 'Pyramid N', step=.05) maxUnits = input.int(5, 'Max Pyramid Units', step=1) atrPeriod = input(20, 'ATR period') l1LongInput = 10 l2LongInput = 20 l1LongExitInput = 20 l2LongExitInput = 40 l1LongInput := input.int(20, 'L1 Long', minval=2) l2LongInput := input.int(60, 'L2 Long', minval=2) l1LongExitInput := input.int(10, 'L1 Long Exit', minval=2) l2LongExitInput := input.int(20, 'L2 Long Exit', minval=2) FromYear = input.int(1970, 'From Year', minval=1900) FromMonth = input.int(1, 'From Month', minval=1, maxval=12) FromDay = input.int(1, 'From Day', minval=1, maxval=31) ToYear = input.int(9999, 'To Year', minval=1900) ToMonth = input.int(1, 'To Month', minval=1, maxval=12) ToDay = input.int(1, 'To Day', minval=1, maxval=31) FromDate = timestamp(FromYear, FromMonth, FromDay, 00, 00) ToDate = timestamp(ToYear, ToMonth, ToDay, 23, 59) TradeDateIsAllowed() => time >= FromDate and time <= ToDate l1Long = ta.highest(l1LongInput) l1LongExit = ta.lowest(l1LongExitInput) l2Long = ta.highest(l2LongInput) l2LongExit = ta.lowest(l2LongExitInput) bool win = false // tracks if last trade was winning trade of losing trade. float buyPrice = 0.0 // tracks the buy price of the last long position. float nextBuyPrice = 0.0 // tracks the next buy price float stopPrice = na // tracks the stop price int totalBuys = 0 // tracks the total # of pyramid buys bool inBuy = false // tracks if we are in a long position or not. float l1LongPlot = ta.highest(l1LongInput) // tracks the L1 price to display float l2LongPlot = ta.highest(l2LongInput) // tracks the L2 price to display float n = ta.atr(atrPeriod) // tracks the n used to calculate stops and pyramid buys string mode = 'L1' // tracks whether we are in a L1 position or L2 position. bool fake = na // tracks if this is a fake trade, see comments below. string longLevel = na // tracks where long positions, stops, pyramid buys occur. float capitalLeft = strategy.initial_capital var shares = 0 float fakeBuyPrice = 0.0 // by default use the last value from the previous bar. buyPrice := buyPrice[1] totalBuys := totalBuys[1] nextBuyPrice := nextBuyPrice[1] stopPrice := stopPrice[1] win := win[1] capitalLeft := capitalLeft[1] inBuy := inBuy[1] n := ta.atr(atrPeriod) fakeBuyPrice := fakeBuyPrice[1] // State to track if we are in a long positon or not. if not inBuy[1] and (high > l1Long[1] or high > l2Long[1]) inBuy := true inBuy else inBuy := inBuy[1] and low < stopPrice[1] ? false : inBuy inBuy := inBuy[1] and mode[1] == 'L1' and low < l1LongExit[1] ? false : inBuy inBuy := inBuy[1] and mode[1] == 'L2' and low < l2LongExit[1] ? false : inBuy inBuy // State to track if we are ia a fake trade. If the last trade was a winning, we need to skip the next trade. // We still track it though as a fake trade (not counted against us). as the outcome determines if we can // can take the next trade. if not inBuy[1] and high > l1Long[1] and win[1] fake := true fakeBuyPrice := close fakeBuyPrice else fake := fake[1] fake if fake[1] and inBuy[1] and not inBuy fake := false win := close >= fakeBuyPrice win fake := high > l2Long[1] ? false : fake // Series representing the l1 and l2 levels. If we break out above the l1 or l2 level, we want the // line to stay at the breakout level, not follow it up. l1LongPlot := not inBuy[1] or inBuy[1] and mode == 'L1' and fake[1] ? l1Long[1] : l1LongPlot[1] l2LongPlot := not inBuy[1] or inBuy[1] and mode == 'L1' and fake[1] ? l2Long[1] : l2LongPlot[1] // Variable in the series is only set when it happens. Possible values is L1, L2, SR // (stopped out with a loss), SG (exited with a gain), and 'P' for pyramid buy. longLevel := not inBuy[1] and high > l1Long[1] ? 'L1' : na longLevel := (not inBuy[1] or inBuy[1] and fake[1]) and high > l2Long[1] ? 'L2' : longLevel // Either 'L1' or 'L2' depending on what breakout level we are in. mode := longLevel == na ? mode[1] : longLevel // Variables to track calculating nextBuyPrice for pyramiding. if longLevel == 'L1' or longLevel == 'L2' buyPrice := close totalBuys := 1 stopPrice := close - stopInput * n nextBuyPrice := close + pyramidInput * n nextBuyPrice // Marks if we hit our next buy price, if so mark it with a 'P' longLevel := longLevel == na and inBuy[1] and high > nextBuyPrice and TradeDateIsAllowed() and totalBuys < maxUnits ? 'P' : longLevel if longLevel == 'P' buyPrice := close totalBuys := totalBuys[1] + 1 stopPrice := close - stopInput * n nextBuyPrice := close + pyramidInput * n nextBuyPrice // Tracks stops and exits, marking them with SG or SR longLevel := longLevel == na and inBuy[1] and low < stopPrice and close >= strategy.position_avg_price ? 'SG' : longLevel longLevel := longLevel == na and inBuy[1] and low < stopPrice and close < strategy.position_avg_price ? 'SR' : longLevel longLevel := longLevel == na and mode[1] == 'L1' and inBuy[1] and low < l1LongExit[1] and close >= strategy.position_avg_price ? 'SG' : longLevel longLevel := longLevel == na and mode[1] == 'L2' and inBuy[1] and low < l2LongExit[1] and close >= strategy.position_avg_price ? 'SG' : longLevel longLevel := longLevel == na and mode[1] == 'L1' and inBuy[1] and low < l1LongExit[1] and close < strategy.position_avg_price ? 'SR' : longLevel longLevel := longLevel == na and mode[1] == 'L2' and inBuy[1] and low < l2LongExit[1] and close < strategy.position_avg_price ? 'SR' : longLevel // Tracks if the trade was a win or loss. win := longLevel == 'SG' ? true : win win := longLevel == 'SR' ? false : win // Variables used to tell strategy when to enter/exit trade. //plotarrow(fake ? 1 : 0, colordown=color.red, colorup=color.purple, transp=40) // down arrow for winning trade enterLong = (longLevel == 'L1' or longLevel == 'L2' or longLevel == 'P') and not fake and TradeDateIsAllowed() exitLong = (longLevel == 'SG' or longLevel == 'SR') and not fake and TradeDateIsAllowed() p1 = plot(l1LongPlot, title='l1 long', linewidth=3, style=plot.style_stepline, color=color.new(color.green, 0)) p2 = plot(l1LongExit[1], title='l1 exit', linewidth=3, style=plot.style_stepline, color=color.new(color.red, 0)) p3 = plot(l2LongPlot, title='l2 long', linewidth=2, style=plot.style_stepline, color=color.new(color.green, 0)) p4 = plot(l2LongExit[1], title='l2 exit', linewidth=2, style=plot.style_stepline, color=color.new(color.red, 0)) color1 = color.new(color.black, 0) color2 = color.new(color.black, 100) col = inBuy ? color1 : color2 p5 = plot(stopPrice, title='stop', linewidth=2, style=plot.style_circles, join=true, color=color.new(color.black, 0)) p6 = plot(nextBuyPrice, title='next buy', linewidth=2, style=plot.style_circles, join=true, color=color.new(color.blue, 0)) fill(p1, p3, color=color.new(color.green, 90)) fill(p2, p4, color=color.new(color.red, 90)) risk = (strategy.initial_capital + strategy.netprofit) * riskPercent shares := math.floor(risk / (stopInput * n)) capitalLeft := strategy.initial_capital + strategy.netprofit - strategy.position_size * strategy.position_avg_price if shares * close > capitalLeft shares := math.max(0, math.floor(capitalLeft / close)) shares shares := math.max(0, shares) plotshape(longLevel == 'L1' and not fake and strategy.position_size == 0 ? true : false, color=color.new(color.green, 40), style=shape.triangleup, text='L1 ') // up arrow for entering L1 trade plotshape(not fake[1] and fake and longLevel == 'L1' and strategy.position_size == 0 ? true : false, color=color.new(color.gray, 40), style=shape.triangleup, text='L1') // up arrow for entering L1 trade plotshape(longLevel == 'L2' and strategy.position_size == 0 ? true : false, color=color.new(color.green, 40), style=shape.triangleup, text='L2') // up arrow for entering L2 trade plotshape((mode == 'L1' or mode == 'L2') and shares > 0 and enterLong and strategy.position_size > 0 ? true : false, color=color.new(color.green, 40), style=shape.triangleup, text='P') plotarrow(strategy.position_size == 0 and longLevel == 'L1' and enterLong ? 1 : 0, colordown=color.new(color.black, 40), colorup=color.new(color.green, 40)) // up arrow for entering L1 trade plotarrow(strategy.position_size == 0 and longLevel == 'L2' and enterLong ? 1 : 0, colordown=color.new(color.black, 40), colorup=color.new(color.green, 40)) // up arrow for entering L2 trade plotarrow(strategy.position_size > 0 and longLevel == 'SR' and exitLong ? -1 : 0, colordown=color.new(color.red, 40), colorup=color.new(color.purple, 40)) // down arrow for losing trade plotarrow(strategy.position_size > 0 and longLevel == 'SG' and exitLong ? -1 : 0, colordown=color.new(color.green, 40), colorup=color.new(color.purple, 40)) // down arrow for winning trade plotshape(longLevel == na and inBuy[1] and not inBuy, color=color.new(color.gray, 40), style=shape.triangleup, text='Exit') // up arrow for entering L1 trade plot(ta.atr(atrPeriod), title='ATR', color=color.new(#991515, 0)) plot(strategy.position_avg_price, title='Average Price', color=color.new(#991515, 0)) alertcondition(low < stopPrice, title='crosses under stop price', message='price crossed under stop price') alertcondition(high > l1Long, title='crosses over L1 price', message='price crossed over L1 price') alertcondition(high > l2Long, title='crosses over L2 price', message='price crossed over L2 price') alertcondition(low < l1LongExit, title='crosses under L1 exit price', message='price crossed under L1 exit price') alertcondition(low < l2LongExit, title='crosses under L2 exit price', message='price crossed under L2 exit price') strategy.entry('long', strategy.long, qty=shares, comment='long', when=enterLong) strategy.close('long', when=exitLong) // simulate_amount = 100000 // simulate_risk = simulate_amount*0.005 // simulate_shares = floor(simulate_risk/(n*stopInput)) // plot(simulate_shares, "Shares", color=#991515, transp=0) // if (enterLong) // label.new(bar_index, high, text=tostring(simulate), style=label.style_none)