GitHub で見る
Et4 MTC v1 戦略 (StockSharp 変換)
概要
- 出身: GlobeInvestFund コレクションの MetaTrader 4 専門アドバイザー
et4_MTC_v1.mq4。
- 目的: 元のアドバイザーの資金管理ヘルパーとタイミング保護機能を反映する StockSharp ネイティブのテンプレートを提供し、トレード エントリー/エグジット ロジックはさらなる開発のためにオープンなままにしておきます。
- 取引スタイル: スケルトン戦略 – デフォルトでは自動エントリーは生成されません。このクラスは、タイミング制限の適用と、カスタム ルールの基盤として機能できるように、MQL4 スクリプトのパラメータ インターフェースを複製することに重点を置いています。
コア機能
- パラメータパリティ
- エキスパートの外部変数と 1 対 1 でマッピングされる
TakeProfit、StopLoss、Slippage、Lots、および EnableLogging プロパティを公開します。
TradeCooldown を追加して、ソース コード内の操作間のハードコーディングされた 30 秒の遅延を記述します。
CandleType を通じてチャート データ コンテキストを公開し、MetaTrader チャートの「現在のタイムフレーム」動作をエミュレートします。
- バランスベースのポジションサイジング
- 負のロット入力 (元のスクリプトのデフォルト) をサポートし、口座残高から注文量を導き出します:
floor((balance / 1000 * |Lots|) / 10) / 10 (最小ロットは 0.1)。
- 取引クールダウンの強制
- 最新の注文アクティビティ (登録、変更、キャンセル、または約定取引) から
TradeCooldown が経過するまで、それ以降の取引の試みをブロックします。これは、start() の CurTime() - LastTradeTime < 30 ガードを反映しています。
- 新しいキャンドルの検出
- 後続の終了したローソク足間の時間比較を通じて
IsNewCandle をマークすることで、CheckLevels セマンティクスを維持します。このフラグは内部的なものですが、カスタム ロジックが追加されると、OpenPosition、ManagePosition、および ClosePosition のフックでフラグを使用できます。
- 高レベルの StockSharp API の使用法
- データ配信には
SubscribeCandles().Bind(...) を使用します。
- フレームワークのベスト プラクティスに従って、起動時に
StartProtection() を 1 回適用します。
- プロジェクト全体のガイドラインに沿って、カスタム コレクションを割り当てたり、インジケーター履歴を明示的に要求したりしません。
パラメータリファレンス
| プロパティ |
デフォルト |
最適化可能 |
説明 |
TakeProfit |
150 |
✔️ |
ポイント単位のターゲット距離 (カスタム終了ルールのプレースホルダー)。 |
Lots |
-10 |
✔️ |
≥ 0 の場合はロットを固定します。負の場合のバランス比例サイジング。 |
StopLoss |
50 |
✔️ |
ポイント単位の停止距離。延長ロジックの準備が整いました。 |
Slippage |
3 |
✖️ |
ポイント単位の実行許容範囲。互換性のために保存されています。 |
EnableLogging |
false |
✖️ |
クールダウンが取引をブロックする場合に情報メッセージを出力します。 |
TradeCooldown |
30秒 |
✖️ |
連続した取引間の遅延は最小限に抑えられます。 |
CandleType |
1分足のローソク足 |
✖️ |
ローソク足のタイミングに使用される市場データのサブスクリプション。 |
実行フロー
- スタートアップ
- バランスを考慮したサイジング ヘルパーを使用して、初期の
Volume を計算します。
- 構成されたキャンドルストリームをサブスクライブし、保護メカニズムを開始します。
- キャンドルクローズ時
- 続行する前にローソク足が終了したことを確認します (MT4 の
Time[0] の終了に相当)。
- 新しいキャンドル トラッカー (
_isNewCandle) を更新します。
- エンジンの状態を考慮して
IsFormedAndOnlineAndAllowTrading() をチェックします。
- 取引クールダウンがアクティブな場合は中止され、有効になっている場合は次に利用可能な時間を記録します。
- プレースホルダー フック (
OpenPosition、ManagePosition、ClosePosition) を実行し、いずれかのステップがアクションを実行すると早期に戻ります。
- 注文と取引のコールバック
OnOrderRegistered、OnOrderChanged、OnOrderCanceled、および OnNewMyTrade は _lastTradeTime を更新し、元のコードのラッパー関数 (MOrderSend、MOrderModify など) と同じように、あらゆる種類の操作でクールダウンをリセットします。
テンプレートの拡張
OpenPosition 内にエントリー ロジックを実装します (同じローソク足でのさらなる処理を停止するには、注文を送信した後に true を返します)。
- 保存されたパラメータを使用して、停止管理動作を
ManagePosition 内に挿入します。
ClosePosition に終了ルールを設定します。このメソッドは現在、ソース スクリプトの休止動作に一致するように false を返します。
- ルールを小節ごとに 1 回トリガーする必要がある場合は、
_isNewCandle を使用します。
移植メモ
- MQL4 エキスパートは取引ルールなしで出荷されました。インフラストラクチャ ルーチンのみが存在していました。したがって、StockSharp 変換では、投機的なインジケーターを追加するのではなく、サポート機能の同等性が優先されます。
- すべてのコメントはリポジトリの標準に従って英語で書かれています。
- タブは、
AGENTS.md で定義されているスタイル ガイドラインに一致するインデントに使用されます。
- Python の翻訳は、変換リクエストに従って意図的に省略されています。
使用手順
- 開始する前に、StockSharp プロジェクトで
Et4MtcV1Strategy を参照し、Security と Portfolio を割り当てます。
- 提供されたプロパティまたは UI バインディングを使用して、
Lots またはその他のパラメーターを調整します。
- プレースホルダー メソッドをオーバーライドするか、クラスから継承して具体的な取引ロジックを挿入します。
- 戦略を実行します。クールダウン ガードにより、指定された間隔内で連続操作が行われないことが保証されます。
テスト
- 上流のソースにも実行可能なルールが欠如しているため、このテンプレートには自動テストは付属しません。手動戦略拡張では、具体的な取引動作が実装されるときに関連するテストを導入する必要があります。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Et4MtcV1Strategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _momentumPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevMom;
private bool _hasPrev;
private int _cooldown;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int MomentumPeriod { get => _momentumPeriod.Value; set => _momentumPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Et4MtcV1Strategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 20).SetDisplay("EMA Period", "EMA trend filter", "Indicators");
_momentumPeriod = Param(nameof(MomentumPeriod), 14).SetDisplay("Momentum", "Momentum period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMom = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var mom = new Momentum { Length = MomentumPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, mom, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema, decimal mom)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
var close = candle.ClosePrice;
if (!_hasPrev) { _prevMom = mom; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevMom = mom;
return;
}
if (close > ema && _prevMom <= 0 && mom > 0 && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 2;
}
else if (close < ema && _prevMom >= 0 && mom < 0 && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 2;
}
_prevMom = mom;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, Momentum
from StockSharp.Algo.Strategies import Strategy
class et4_mtc_v1_strategy(Strategy):
"""
EMA + Momentum crossover strategy.
Buys when price > EMA and momentum crosses above 0.
Sells when price < EMA and momentum crosses below 0.
"""
def __init__(self):
super(et4_mtc_v1_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 20) \
.SetDisplay("EMA Period", "EMA trend filter", "Indicators")
self._momentum_period = self.Param("MomentumPeriod", 14) \
.SetDisplay("Momentum", "Momentum period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_mom = 0.0
self._has_prev = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(et4_mtc_v1_strategy, self).OnReseted()
self._prev_mom = 0.0
self._has_prev = False
self._cooldown = 0
def OnStarted2(self, time):
super(et4_mtc_v1_strategy, self).OnStarted2(time)
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self._ema_period.Value
mom = Momentum()
mom.Length = self._momentum_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, mom, self._process_candle).Start()
def _process_candle(self, candle, ema_val, mom_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
close = float(candle.ClosePrice)
ema_val = float(ema_val)
mom_val = float(mom_val)
if not self._has_prev:
self._prev_mom = mom_val
self._has_prev = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_mom = mom_val
return
if close > ema_val and self._prev_mom <= 0 and mom_val > 0 and self.Position <= 0:
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume)
self._cooldown = 2
elif close < ema_val and self._prev_mom >= 0 and mom_val < 0 and self.Position >= 0:
volume = self.Volume + abs(self.Position)
self.SellMarket(volume)
self._cooldown = 2
self._prev_mom = mom_val
def CreateClone(self):
return et4_mtc_v1_strategy()