GitHub で見る
ダフ屋 EMA のシンプルな戦略
概要
ダフ屋 EMA シンプル戦略 は、MetaTrader エキスパート アドバイザー ScalperEMAEASimple を変換したものです。高速/低速の指数移動平均、確率的オシレーター、平均方向性インデックス (ADX) フィルターの組み合わせを使用して、既存のトレンド内の短期間のプルバック エントリーを特定します。この戦略は、流動的なFXペアの日中スキャルピング向けに設計されていますが、ピップベースのリスク管理が理にかなっているあらゆる商品に適用できます。
この実装は、StockSharp の高レベルの API に従い、終了したキャンドルのみを評価します。すべての計算は履歴データを再処理することなく段階的に実行されるため、ロジックはライブ取引に適しています。
インジケータースタック
- 高速 EMA (
FastEmaPeriod) – 短期的な勢いを検出します。
- スロー EMA (
SlowEmaPeriod) – 一般的なトレンドの方向を定義します。
- Stochastic オシレーター (
StochasticLength、StochasticKPeriod、StochasticDPeriod) – 売られすぎ/買われすぎの境界付近での勢いの反転を追跡します。
- 平均方向性インデックス – トレンドが過度に強くなった場合(
AdxThresholdを上回るADX)、取引を拒否します。
確率オシレーターは、%K ラインが売られ過ぎレベルを上回ったとき (長いセットアップ)、または買われすぎレベルを下回ったとき (短いセットアップ) に必ず確認シグナルを発します。 EMA ペアは方向性フィルターを提供し、ADX コンポーネントはエントリーが暴走トレンドではなく穏やかなリトレースメントに制限されるようにします。
エントリーロジック
- ローソク足は遅い EMA のトレンド側で閉じる必要があり、速い EMA はその方向と一致する必要があります (ロングの場合は
fast > slow、ショートの場合は fast < slow)。
- ローソク足とスロー EMA の間の距離は、ローソク足の範囲よりも小さく、前の 3 つの距離よりも狭い必要があります。この動作により、元の MQL コードからプルバック検出ループが再作成されます。
- ローソク本体が速い EMA を通過するか、速い EMA 自体が遅い EMA を通過します。この状態はブレイクアウトのトリガーとして機能します。
- 確率的オシレーターは、最後の
ConditionWindowBars ローソク足内の極端なゾーンからクロスバックして勢いを確認する必要があります。
- ADX は
AdxThreshold 未満に維持する必要があり、ボラティリティが急激に加速した場合の取引を妨げます。
- 少なくとも
SignalCooldownBars 個のローソク足が、同じ方向の 2 つの連続するシグナル間を通過する必要があります。
すべてのチェックに合格すると、戦略は反対のエクスポージャーを閉じ、検出された方向に新しい成行注文を開きます。
出口ロジックとリスク管理
- 最初のストップロスは、エントリー価格から
StopLossPips (商品のピップサイズを使用して価格に変換) に設定されます。
- 未実現利益が
TrailingActivationPips に達すると、トレーリング ストップは自動的に TrailingDistancePips の距離を維持します。
- 反対のシグナルは、新たな取引を確立する前にフラットポジションを強制します。
すべての保護注文は、リスク管理を現在のポジション量と同期させるために、StockSharp の SetStopLoss ヘルパーを通じて管理されます。
パラメーター
| パラメータ |
説明 |
Volume |
各シグナルの基本取引量。この戦略は、方向を変えるときに完全な反転を確実にするために、既存のエクスポージャーを自動的に追加します。 |
FastEmaPeriod / SlowEmaPeriod |
指数移動平均の期間の長さ。 |
StochasticLength, StochasticKPeriod, StochasticDPeriod |
オリジナルの EA のデフォルトをミラーリングした Stochastic オシレーター構成。 |
StochasticOversold / StochasticOverbought |
リトレースメントゾーンを定義する極端なレベル。 |
AdxThreshold |
取引を拒否する前に許可される最大値は ADX です。 |
SignalCooldownBars |
同じ方向の連続する信号間の最小バー。 |
ConditionWindowBars |
リトレースメント、EMA ブレイクアウト、確率的確認が一致する必要があるバーの数。 |
StopLossPips |
ピップ単位で表される初期のストップロス距離。 |
TrailingDistancePips |
トレーリングストップが作動すると維持される距離。 |
TrailingActivationPips |
トレーリングストップを発動する利益の閾値。 |
CandleType |
すべてのインジケーターに使用されているキャンドルシリーズ。デフォルトは 5 分の時間枠です。 |
実装メモ
- Pip 変換は手段
PriceStep に依存します。小数点以下 3 桁または 5 桁の商品の場合、ピップ係数は MetaTrader の規則に合わせて 10 倍されます。
- この戦略は完了したローソク足のみを処理するため、実行は各バーの終了後に行われます。
- 内部状態変数には、履歴全体をスキャンせずに元のエキスパート アドバイザーが使用したルックバック ウィンドウを再現するために、リトレースメント、EMA ブレイクアウト、および確率的確認の最後のインデックスが保存されます。
使用法
- 構成されたセキュリティとポートフォリオを使用して、戦略を
Connector または Trader インスタンスにアタッチします。
- 証券に pip から価格への変換に有効な
PriceStep があることを確認してください。
- 金融商品のボラティリティに応じてパラメーターを調整します。遅い EMA は、ソース EA と一致するようにデフォルトで 740 に設定されていますが、より速い市場では設定を短くするとメリットが得られる場合があります。
- 戦略を開始します。上記の条件が満たされると、成行注文と保護注文が自動的に生成されます。
免責事項: この戦略は教育目的で移植されたものです。ライブキャピタルを取引する前に、徹底的なフォワードテストとリスク分析を行うことをお勧めします。
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// EMA scalper strategy combining fast/slow EMA trend with stochastic momentum.
/// Buys when fast EMA > slow EMA and stochastic is oversold.
/// Sells when fast EMA below slow EMA and stochastic is overbought.
/// </summary>
public class ScalperEmaSimpleStrategy : Strategy
{
private readonly StrategyParam<int> _fastEmaPeriod;
private readonly StrategyParam<int> _slowEmaPeriod;
private readonly StrategyParam<decimal> _stochOversold;
private readonly StrategyParam<decimal> _stochOverbought;
private readonly StrategyParam<DataType> _candleType;
public int FastEmaPeriod
{
get => _fastEmaPeriod.Value;
set => _fastEmaPeriod.Value = value;
}
public int SlowEmaPeriod
{
get => _slowEmaPeriod.Value;
set => _slowEmaPeriod.Value = value;
}
public decimal StochOversold
{
get => _stochOversold.Value;
set => _stochOversold.Value = value;
}
public decimal StochOverbought
{
get => _stochOverbought.Value;
set => _stochOverbought.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public ScalperEmaSimpleStrategy()
{
_fastEmaPeriod = Param(nameof(FastEmaPeriod), 20)
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 50)
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_stochOversold = Param(nameof(StochOversold), 10m)
.SetDisplay("Stochastic Oversold", "Oversold level", "Indicators");
_stochOverbought = Param(nameof(StochOverbought), 90m)
.SetDisplay("Stochastic Overbought", "Overbought level", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Primary candle series", "General");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastEmaPeriod };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaPeriod };
var stochK = new StochasticK { Length = 14 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, stochK, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue, decimal stochK)
{
if (candle.State != CandleStates.Finished)
return;
// Buy: uptrend (fast > slow) + stochastic oversold
if (fastValue > slowValue && stochK < StochOversold && Position <= 0)
{
BuyMarket(Position < 0 ? Math.Abs(Position) + 1 : 1);
}
// Sell: downtrend (fast < slow) + stochastic overbought
else if (fastValue < slowValue && stochK > StochOverbought && Position >= 0)
{
SellMarket(Position > 0 ? Math.Abs(Position) + 1 : 1);
}
}
}
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, StochasticK
from StockSharp.Algo.Strategies import Strategy
class scalper_ema_simple_strategy(Strategy):
def __init__(self):
super(scalper_ema_simple_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._fast_ema_period = self.Param("FastEmaPeriod", 20)
self._slow_ema_period = self.Param("SlowEmaPeriod", 50)
self._stoch_oversold = self.Param("StochOversold", 10.0)
self._stoch_overbought = self.Param("StochOverbought", 90.0)
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastEmaPeriod(self):
return self._fast_ema_period.Value
@FastEmaPeriod.setter
def FastEmaPeriod(self, value):
self._fast_ema_period.Value = value
@property
def SlowEmaPeriod(self):
return self._slow_ema_period.Value
@SlowEmaPeriod.setter
def SlowEmaPeriod(self, value):
self._slow_ema_period.Value = value
@property
def StochOversold(self):
return self._stoch_oversold.Value
@StochOversold.setter
def StochOversold(self, value):
self._stoch_oversold.Value = value
@property
def StochOverbought(self):
return self._stoch_overbought.Value
@StochOverbought.setter
def StochOverbought(self, value):
self._stoch_overbought.Value = value
def OnReseted(self):
super(scalper_ema_simple_strategy, self).OnReseted()
def OnStarted2(self, time):
super(scalper_ema_simple_strategy, self).OnStarted2(time)
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastEmaPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowEmaPeriod
stoch_k = StochasticK()
stoch_k.Length = 14
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, stoch_k, self._process_candle).Start()
def _process_candle(self, candle, fast_value, slow_value, stoch_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
stoch_val = float(stoch_value)
# Buy: uptrend (fast > slow) + stochastic oversold
if fast_val > slow_val and stoch_val < float(self.StochOversold) and self.Position <= 0:
self.BuyMarket()
# Sell: downtrend (fast < slow) + stochastic overbought
elif fast_val < slow_val and stoch_val > float(self.StochOverbought) and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return scalper_ema_simple_strategy()