マルチレベルダイナミックトレンドフォローシステム (Multi-Level Dynamic Trend Following System) は,タートル・トレードルールをベースとした改良戦略である.この戦略は,多期間のトレンド信号を活用し,ダイナミックストップ・ロスとピラミッドポジション構築を組み合わせ,中長期のトレンドを把握する.このシステムは,異なる速度でトレンドを把握するために2つのトレンドフォロー期 (L1とL2) を設定し,適応性のあるATR指標を使用してエントリー,ポジション構築,ストップ-ロスポイントを動的に調整する.このマルチレベルデザインにより,戦略はピラミッドポジション構築を通じて潜在的な利益を最大化しながら,異なる市場環境で安定性を維持することができる.
トレンド識別: 2つの移動平均期 (L1とL2) は,異なる速度でトレンドを特定するために使用されます. L1は,より速いトレンドを捉えるのに使用されます.
エントリー・シグナル:価格がL1またはL2の高値を超えるとロング・シグナルが生成される.前回のL1取引が収益性があった場合,L2信号が現れるまで次のL1シグナルをスキップする.
ダイナミックストップ・ロース: ATR の倍数 (デフォルト 3x) が初期ストップ・ロース距離として使用され,ポジションが保持されるにつれて徐々に上昇します.
ピラミッドポジション構築: トレンド継続中に,価格が0.5ATR上昇するたびに,最大5倍まで追加のポジションが追加されます.
リスク管理: ダイナミックなポジションサイズ化によって達成される各取引は,口座資本の2%を超えないリスクを負う.
エクジットメカニズム:価格が10日低値 (L1) または20日低値 (L2) 以下の値を下回り,またはストップロスが引き起こすとき,ポジションは閉鎖されます.
多レベルトレンドキャプチャ: L1とL2期間は,戦略の適応性と安定性を向上させ,急速なトレンドと長期的トレンドの両方をキャプチャすることができます.
動的リスク管理: ATR を波動性指標として使用することで,市場変化により良く適応し,エントリー,ストップ・ロース,ポジション構築のポイントを動的に調整できます.
ピラミッドポジション構築: 傾向の継続中にポジションを徐々に増やすことは,リスクをコントロールし,利益の可能性を最大化します.
柔軟なパラメータ設定: 複数の調整可能なパラメータにより,戦略は異なる市場と取引スタイルに適応できます.
自動実行: 戦略は完全に自動化され,人間の介入と感情的な影響が減少します.
トレンド逆転リスク: 強いトレンド市場では良好なパフォーマンスを発揮するが,レンジ・バインド市場では頻繁な損失につながる可能性がある.
スリップと取引コスト: 頻繁にポジションを構築し,ストップ・ロスを移動すると,高い取引コストが生じる可能性があります.
過剰最適化リスク:多くのパラメータが歴史的なデータに過剰な適合につながる可能性があります.
資本管理リスク: 初期資本が少ない場合,複数のポジション構築を効果的に実行できない可能性があります.
市場流動性リスク: 流動性が低い市場では,理想的な価格で取引を行うことは困難かもしれません.
市場環境フィルタリングを組み込む: 市場状況を評価し,範囲限定市場での取引頻度を減らすために傾向強度指標 (例えば,ADX) を追加する.
ポジション構築戦略を最適化: 固定0.5ATRと5倍ではなく,トレンド強度に基づいて位置構築の間隔と数を動的に調整することを検討します.
利益の引き上げメカニズムを導入します 長期的トレンドでは 3倍ATR利益に達するとポジションの半分を閉じるように,利益をロックするために部分的な利益の引き上げを設定します
複数のインスタントメントの相関分析: ポートフォリオに適用する場合,全体的なリスク・リターン比を最適化するために,インスタントメント間の相関分析を追加します.
波動性フィルタリングを追加する: 異常な市場状況に対処するために,極端な波動性の期間中に取引を一時停止またはリスクパラメータを調整する.
出口メカニズムの最適化:パラボリックSARやシャンデリア出口などのより柔軟な出口指標を使用することを検討します.
マルチレベルダイナミックトレンドフォローシステム (MTLTS) は,クラシックなタートルトレードルールを現代的な定量技術と組み合わせた包括的な戦略である.マルチレベルトレンド識別,ダイナミックリスク管理,ピラミッドポジション構築を通じて,この戦略は強さを維持しながらトレンドキャプチャ能力と利益の可能性を改善する.範囲限定市場では課題に直面しているが,適切なパラメータ最適化とリスク制御により,戦略はさまざまな市場環境で安定したパフォーマンスを維持する可能性がある.将来の改善は,市場環境評価を導入し,ポジション構築と退出メカニズムを最適化し,戦略の強さと収益性を高めることに焦点を当てることができる.
/*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)