ホーム
/
戦略のサンプル
GitHub で見る
3103 — ADX EA (C#) 戦略
概要
オリジナルのMetaTrader「ADX EA」は、Average Directional Indexのブレイクアウトと+DI/−DIのクロスオーバー、上位タイムフレームの
モメンタム確認、月次MACDフィルターを組み合わせています。C#ポートはStockSharpの高レベルAPIの上でそのマルチフィルターワーク
フローを複製します。戦略は3つの足ストリームを購読します:
主要タイムフレーム (デフォルト5分) — ADX、線形加重移動平均、価格構造チェック、ボリュームフィルターを駆動します。
モメンタムタイムフレーム (デフォルト15分) — エントリーを制御する100ベースライン周辺のモメンタム偏差を生成します。
MACDタイムフレーム (デフォルト30日) — ポジション決済を制御する月次MACDを反映します。
取引ロジック
ブレイクアウトモジュール – 有効時、ロング取引には以下が必要です:
ADXまたは+DIがEntryLevelを上回り、+DIと−DIの差がMinDirectionalDifferenceより大きい。
高速LWMAが低速LWMAを上回り、強気足構造(Low[2] < High[1])、モメンタム上昇(Momentum[1] > Momentum[2])。
上位タイムフレームの直近3回のモメンタム読み取りのうち少なくとも1回が100からMomentumBuyThreshold以上乖離している。
主要タイムフレームで出来高増加(Volume[1] > Volume[2]またはVolume[1] > Volume[3])。
月次タイムフレームのMACDが強気(MacdMain[1] > MacdSignal[1])。
全体的なトレンド強度を確認するためADXがExitLevelを上回る。
ショートブレイクアウトは、−DI優位、弱気構造(Low[1] < High[2])、MomentumSellThreshold分の100以下のモメンタム、
弱気MACDの比較で対称的なロジックを適用します。
クロスオーバーモジュール – 有効時、+DIが−DIを上回るクロス(ロング)または−DIが+DIを上回るクロス(ショート)を探します。
オプションのフィルターはオリジナルのEAを反映します:
RequireAdxSlopeはADXが前回読み取りより高いことを要求します。
ConfirmCrossOnBreakoutはクロスバーに同じブレイクアウト閾値チェックを追加します。
MinAdxMainLineはクロス中の最小ADX強度を強制します。
LWMAの整列、モメンタムの傾き、出来高の拡大、MACDの極性が意図した方向に一致している必要があります。
ピラミッディング – 各新規注文はLotExponentに従ってボリュームを追加します。戦略はTradeVolumeをベースロットサイズ
として扱い、LotExponent^n(nはすでに開いているステップ数)で増やします。MaxTradesは蓄積できるネットボリュームを制限します。
リスク管理
保護注文 – TakeProfitStepsとStopLossStepsはStartProtectionに渡され、銘柄の価格ステップで表現されます。
トレーリングストップ – TrailingStopStepsは最高の終値を超えた手動トレーリングバリアを維持します。
ブレイクイーブン – UseBreakEvenが有効の場合、価格がBreakEvenTriggerステップ前進した後にストップが締め付けられ、
BreakEvenOffsetステップだけストップをオフセットできます。
MACD決済 – EnableMacdExitが真の場合、月次MACD関係はMACDがシグナルを下回ったときにロングを閉じます(ショートはその逆)、
EAのClose_BUY/Close_SELLルーティンに対応します。
資本ストップ – UseEquityStopは浮動利益曲線を追跡し、ドローダウンがTotalEquityRiskパーセントに達するとポジションを
清算します。
口座通貨ターゲットに依存する機能(「Take Profit in Money」、「Trailing Profit in Money」など)はポートされていません。
StockSharp戦略は通常、ストップ距離と組み込み保護サービスを通じて保護ロジックを管理するためです。EAの他のすべての決定ポイントは
インジケーター等価物で保持されます。
パラメーター
パラメーター
デフォルト
説明
TradeVolume
0.01
最初のエントリーのベースロットサイズ。
CandleType
5mタイムフレーム
ADX/LWMAロジックの主要足シリーズ。
MomentumCandleType
15mタイムフレーム
モメンタム偏差フィルターの上位タイムフレーム。
MacdCandleType
30日タイムフレーム
MACD決済フィルターを供給するタイムフレーム。
FastMaPeriod
6
高速線形加重移動平均の長さ。
SlowMaPeriod
85
低速線形加重移動平均の長さ。
AdxPeriod
14
Average Directional Indexの期間。
MomentumPeriod
14
上位タイムフレームのモメンタムインジケーター期間。
MacdFastPeriod
12
MACD決済フィルター内の高速EMA期間。
MacdSlowPeriod
26
MACD決済フィルター内の低速EMA期間。
MacdSignalPeriod
9
MACD決済フィルター内のシグナルSMA期間。
EnableBreakoutStrategy
true
ADXブレイクアウトブランチのトグル。
EnableCrossStrategy
true
DIクロスオーバーブランチのトグル。
UseTrendFilter
true
ブレイクアウト中にロングで+DI優位、ショートで−DI優位を強制。
RequireAdxSlope
true
DIクロスを評価する際にADXが上昇することを要求。
ConfirmCrossOnBreakout
true
クロスオーバーモジュールにブレイクアウト閾値を追加。
EnableMacdExit
true
MACDベースの決済ルーティンを有効化。
EntryLevel
10
ブレイクアウトで使用される最小ADX/+DI/−DIレベル。
ExitLevel
10
新規エントリーを許可する最小ADX強度。
MinDirectionalDifference
10
+DIと−DIの必要差。
MinAdxMainLine
10
DIクロス中の最小ADXレベル。
MomentumBuyThreshold
0.3
強気モメンタム確認に必要な100からの偏差。
MomentumSellThreshold
0.3
弱気モメンタム確認に必要な100からの偏差。
MaxTrades
10
最大ピラミッディングステップ数。
LotExponent
1.44
各追加ステップのボリューム乗数。
TakeProfitSteps
50
テイクプロフィット注文の価格ステップ単位の距離。
StopLossSteps
20
ストップロス注文の価格ステップ単位の距離。
TrailingStopSteps
40
価格ステップ単位の手動トレーリングストップ距離。
UseBreakEven
true
ブレイクイーブン再配置ロジックを有効化。
BreakEvenTrigger
30
ブレイクイーブンを有効にする前に必要な有利な動きのステップ数。
BreakEvenOffset
30
ストップ移動時にエントリー価格に追加されるステップ数。
UseEquityStop
true
ドローダウンベースの緊急決済を有効化。
TotalEquityRisk
1
すべてのポジションをフラットにする前の許容ドローダウンパーセンテージ。
使用のヒント
元のタイムフレームマッピングを模倣するためにMomentumCandleTypeとMacdCandleTypeを主要タイムフレームに合わせてください
(例:5分チャート → 15分モメンタム → 月次MACD)。
EntryLevel、MinDirectionalDifference、MinAdxMainLineを一緒に調整してください;三つ全てを下げるとブレイクアウト
フィルターがかなり緩くなります。
LotExponentを1.0より大きくするとEAのマーチンゲール式スケーリングが再現されます。ポジションサイズを一定に保つには1.0に設定。
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// ADX EA strategy using EMA crossover with ADX trend strength filter.
/// Buys when fast EMA crosses above slow EMA with strong trend.
/// Sells on reverse crossover.
/// </summary>
public class AdxEaStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
/// <summary>
/// Fast EMA period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow EMA period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Stop-loss distance in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take-profit distance in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public AdxEaStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 200)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400)
.SetNotNegative()
.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fast = null;
_slow = null;
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_fast.IsFormed || !_slow.IsFormed)
{
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
// Check SL/TP
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 60;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
// EMA crossover
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = close;
_cooldown = 60;
}
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = close;
_cooldown = 60;
}
_prevFast = fastValue;
_prevSlow = slowValue;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class adx_ea_strategy(Strategy):
def __init__(self):
super(adx_ea_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 50) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 200) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(adx_ea_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(adx_ea_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
# Check SL/TP
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
return
# EMA crossover
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 60
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 60
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return adx_ea_strategy()