
この戦略は,平均トレンド指数DI+とDI-をベースに,2つの異なる時間枠のDI指数を使用してトレンドの方向を判断し,その後空白を多めにします.より大きな時間枠とより小さな時間枠のDI+がDI-よりも高い場合,看板の傾向として判断し,多めにします.
この戦略は以下の原則に基づいています.
DI+とDI−を計算する. 高値,閉店値,低値を取得し,DI+とDI−を計算する.
2つの時間枠のDI+とDI−を比較する.主図の時間枠 (例えば1時間) とより大きな時間枠 (例えば日線) でそれぞれDI+とDI−を計算し,大きさと小さい関係を比較する.
トレンドの方向を判断する.より大きな時間枠とより小さな時間枠のDI+がDI−より大きいときは,多頭傾向として判断する.両方の時間枠のDI−がDI+より大きいときは,空頭傾向として判断する.
取引信号を発する。多頭信号は2つの時間枠DI+>DI-,多行;空頭信号は2つの時間枠DI->DI+,空行。
設定ストップ.ATRベースのストップを計算し,トレンド追跡ストップを実現する.
退出条件 ストーダストトリガーまたは価格逆転時に平仓する
この戦略の利点は以下の通りです.
双時間枠DIを使ってトレンドを判断し,偽突破をフィルターすることができます.
ATRは動的ストップトラッキングにより,利益の最大化と小規模なストップの回避を可能にします.
タイムストップは,単発ストップを制御できます.
トレンドで取引することで,トレンドの機会を捉えることができます.
ルールが明確で分かりやすいので 操作が簡単です.
この戦略には以下のリスクもあります.
DI指標が遅れているため,入場時間を逃す可能性がある。パラメータを適切に最適化するか,他の指標と組み合わせて判断することができる。
双時間枠判断には上下流の分歧があるかもしれない。時間枠検証信号を追加できる。
ストップ・ロスが過度に激進化されすぎると,取引頻度が過度になる可能性がある.ATR倍数を適切に緩和することができる.
変動の状況では頻繁に取引が起こりうる. フィルタリング条件を追加することで取引頻度を減らすことができる.
パラメータの最適化は,過去データに依存し,实体には過度な最適化がある可能性がある.パラメータの粗性を慎重に評価すべきである.
この戦略は以下の点で最適化できます.
DI計算パラメータを最適化し,最適なパラメータ組み合わせを探します.
MACD,KDJなどの他の指標のフィルタを追加し,信号の精度を向上させる.
市場条件に適したストップ戦略を最適化. 移動ストップまたは固定ストップに変更できます.
重要なニュースイベントを回避するために,取引時間フィルターを追加します.
様々な品種のパラメータの健壮性をテストし,適応性を向上させる.
機械学習の要素を加え,歴史データから判断モデルを訓練する.
この戦略は全体的に典型的なトレンド追跡戦略であり,DI指標を使用してトレンドの方向性を判断し,ストップロスを設定して収益をロックし,トレンドで収益を継続する.この戦略の優点は,戦略の考え方が明確で,实体操作が容易であることである.同時に,最適化パラメータ,フィルター条件の追加など,いくつかの改善の余地がある.この戦略は,テストを最適化し続ければ,非常に実用的なトレンド追跡戦略になることができる.
/*backtest
start: 2022-10-31 00:00:00
end: 2023-11-06 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/
// © DojiEmoji
//@version=5
strategy("DI+/- multi TF Strat [KL]", overlay=true, pyramiding=1, initial_capital=1000000000, default_qty_type=strategy.percent_of_equity, default_qty_value=5)
var string GROUP_ALERT = "Alerts"
var string GROUP_SL = "Stop loss"
var string GROUP_ORDER = "Order size"
var string GROUP_TP = "Profit taking"
var string GROUP_HORIZON = "Time horizon of backtests"
var string GROUP_IND = "Directional IndicatorDI+ DI-"
// ADX Indicator {
adx_len = input(14, group=GROUP_IND, tooltip="Typically 14")
tf1 = input.timeframe("", title="DI +/- in Timeframe 1", group=GROUP_IND, tooltip="Main: DI+ > DI-")
tf2 = input.timeframe("1D", title="DI +/- in Timeframe 2", group=GROUP_IND, tooltip="Confirmation: DI+ > DI-")
// adx_thres = input(20, group=GROUP_IND) //threshold not used in this strategy
get_ADX(_high, _close, _low) =>
// (high, close, mid) -> [plus_DM, minus_DM]
// Based on TradingView user BeikabuOyaji's implementation
_tr = math.max(math.max(_high - _low, math.abs(_high - nz(_close[1]))), math.abs(_low - nz(_close[1])))
smooth_tr = 0.0
smooth_tr := nz(smooth_tr[1]) - nz(smooth_tr[1]) / adx_len + _tr
smooth_directional_mov_plus = 0.0
smooth_directional_mov_plus := nz(smooth_directional_mov_plus[1]) - nz(smooth_directional_mov_plus[1]) / adx_len + (_high - nz(_high[1]) > nz(_low[1]) - _low ? math.max(_high - nz(_high[1]), 0) : 0)
smooth_directional_mov_minus = 0.0
smooth_directional_mov_minus := nz(smooth_directional_mov_minus[1]) - nz(smooth_directional_mov_minus[1]) / adx_len + (nz(_low[1]) - _low > _high - nz(_high[1]) ? math.max(nz(_low[1]) - _low, 0) : 0)
plus_DM = smooth_directional_mov_plus / smooth_tr * 100
minus_DM = smooth_directional_mov_minus / smooth_tr * 100
// DX = math.abs(plus_DM - minus_DM) / (plus_DM + minus_DM) * 100 // DX not used in this strategy
[plus_DM, minus_DM]
// DI +/- from timeframes 1 and 2
[plus_DM_tf1, minus_DM_tf1] = get_ADX(request.security(syminfo.tickerid, tf1, high), request.security(syminfo.tickerid, tf1, close),request.security(syminfo.tickerid, tf1, low))
[plus_DM_tf2, minus_DM_tf2] = get_ADX(request.security(syminfo.tickerid, tf2, high),request.security(syminfo.tickerid, tf2, close),request.security(syminfo.tickerid, tf2, low))
// } end of block: ADX Indicator
var string ENUM_LONG = "LONG"
var string LONG_MSG_ENTER = input.string("Long entered", title="Alert MSG for buying (Long position)", group=GROUP_ALERT)
var string LONG_MSG_EXIT = input.string("Long closed", title="Alert MSG for closing (Long position)", group=GROUP_ALERT)
backtest_timeframe_start = input(defval=timestamp("01 Apr 2020 13:30 +0000"), title="Backtest Start Time", group=GROUP_HORIZON)
within_timeframe = true
// Signals for entry
_uptrend_confirmed = plus_DM_tf1 > minus_DM_tf1 and plus_DM_tf2 > minus_DM_tf2
entry_signal_long = _uptrend_confirmed
plotshape(_uptrend_confirmed, style=shape.triangleup, location=location.bottom, color=color.green)
plotshape(not _uptrend_confirmed, style=shape.triangledown, location=location.bottom, color=color.red)
// Trailing stop loss ("TSL") {
tsl_multi = input.float(2.0, title="ATR Multiplier for trailing stoploss", group=GROUP_SL)
SL_buffer = ta.atr(input.int(14, title="Length of ATR for trailing stoploss", group=GROUP_SL)) * tsl_multi
TSL_source_long = low
var stop_loss_price_long = float(0)
var pos_opened_long = false
stop_loss_price_long := pos_opened_long ? math.max(stop_loss_price_long, TSL_source_long - SL_buffer) : TSL_source_long - SL_buffer
// MAIN: {
if pos_opened_long and TSL_source_long <= stop_loss_price_long
pos_opened_long := false
alert(LONG_MSG_EXIT, alert.freq_once_per_bar)
strategy.close(ENUM_LONG, comment=close < strategy.position_avg_price ? "stop loss" : "take profit")
// (2) Update the stoploss to latest trailing amt.
if pos_opened_long
strategy.exit(ENUM_LONG, stop=stop_loss_price_long, comment="SL")
// (3) INITIAL ENTRY:
if within_timeframe and entry_signal_long
pos_opened_long := true
alert(LONG_MSG_ENTER, alert.freq_once_per_bar)
strategy.entry(ENUM_LONG, strategy.long, comment="long")
// Plotting:
TSL_transp_long = pos_opened_long and within_timeframe ? 0 : 100
plot(stop_loss_price_long, color=color.new(color.green, TSL_transp_long))
// CLEAN UP: Setting variables back to default values once no longer in use
if ta.change(strategy.position_size) and strategy.position_size == 0
pos_opened_long := false
if not pos_opened_long
stop_loss_price_long := float(0)
// } end of MAIN block