GitHub で見る
ExpICustomV1 戦略
概要
ExpICustomV1 戦略は、MetaTrader エキスパート exp_iCustom_v1 の StockSharp 移植です。この戦略は、設定可能なインジケーター インスタンスから取引シグナルを読み取り、選択されたバッファー内のゼロ以外の値に反応します。買いバッファーがゼロ以外の場合、戦略はロングポジションをオープンし、売りバッファーはショートエントリーをトリガーします。保護的なストップロス、テイクプロフィット、トレーリングおよび損益分岐点ロジックは、元の専門家の資金管理オプションを再現します。
注: C# 実装のみが提供されます。 Python バージョンはまだ利用できません。
取引ロジック
- キャンドル タイプ で指定されたプライマリ タイムフレームをサブスクライブし、クローズされたキャンドルのみを処理します。
- インジケーター名で定義されたインジケーターをインスタンス化し、スラッシュで区切られたインジケーター パラメーターを適用します (
Name=Value ペアと順序付き数値の両方をサポートします)。
- 後のローソク足でシフトにアクセスできるように、最終的なインジケーター出力を履歴バッファーに保存します。
- インジケーター シフトの買いバッファ値がゼロでない場合、ストラテジーはロング ポジションをオープン/維持します。売りバッファーがゼロ以外の場合、戦略はショートポジションをオープン/維持します。
- 両方のバッファーがゼロ以外の値を同時に返す場合、曖昧なエントリを避けるために信号が互いにキャンセルされます。
- オプションの Close On Reverse は、反対の信号に反応する前に現在の位置を終了します。
- スリープ ロジックは、同じ方向の連続するエントリ間の最小数のバーを強制します。 スリープのキャンセル が有効になっている場合、逆の信号が発生したときにタイマーをキャンセルできます。
- ポジションはストップロス、テイクプロフィット、オプションのトレーリングストップ、損益分岐点ロックによって保護されます。すべての距離は価格ポイントで表されます。
インジケーターの構成
- インジケーター名 – 完全なタイプ名または短い StockSharp インジケーター名 (例:
SMA、MACD、BollingerBands)。
- インジケーター パラメーター – インジケーターに適用されるスラッシュ区切りのリスト。
Length=14/Width=2 と 14/2/0.7 のような順序付けされた値の両方がサポートされています。
- オーバーライド ブロック – 最大 5 つの置換により、元のエキスパートの
Opt_X 入力と同様に、最適化中にインデックスによってパラメーター値を調整できます。インデックスはゼロベースです。
リスクと資金の管理
- 基本ボリューム – 各成行注文で送られる金額。
- ストップロス/テイクプロフィット – エントリー価格からのポイント単位の絶対距離。
- トレーリングストップ – 指定された利益の後にアクティブになり、極値から設定された距離を維持します。
- 損益分岐点 – 指定された利益の後にストップをエントリー価格に向けて移動し、オプションで追加のポイントをロックします。
パラメータリファレンス
| パラメータ |
説明 |
| キャンドルの種類 |
インジケーターとシグナルの評価に使用されるタイムフレーム。 |
| インジケーター名 |
インジケーター インスタンスの型名。 |
| インジケーターパラメータ |
スラッシュで区切られたインジケーターパラメーターのリスト。 |
| バッファを買う/バッファを売る |
買い/売りマーカーを含むバッファーインデックス。 |
| インジケーターシフト |
インジケーターバッファーを読み取るときに適用される履歴シフト。 |
| ブロックをオーバーライドする |
実行時に特定のパラメータの位置を置き換えます。 |
| スリープバー |
同じ方向のエントリ間の最小バー数。 |
| スリープをキャンセル |
逆信号の後にスリープ タイマーをリセットします。 |
| リバース時にクローズ |
逆のシグナルが現れたら、既存のポジションを閉じます。 |
| 最大注文数 / 最大購入数 / 最大販売数 |
同時ポジション数を制限するソフトキャップ。 |
| ストップロス/テイクプロフィット |
保護命令のポイント単位の距離。 |
| トレーリングストップの設定 |
トレーリングストップの有効化と距離を制御するパラメーター。 |
| 損益分岐点の設定 |
損益分岐点のアクティブ化とロック距離を制御するパラメーター。 |
| ベースボリューム |
各市場参入のボリューム。 |
使用法
- 戦略を戦略コンテナに追加し、セキュリティとポートフォリオを設定します。
- ターゲットのカスタム インジケーターと一致するように インジケーター名 と インジケーター パラメーター を構成します。
- リスク設定 (ストップ、テイク、トレーリング、損益分岐点) と基本注文量を調整します。
- 戦略を実行します。選択した時間枠をサブスクライブし、指標バッファーを評価し、条件が満たされた場合に成行注文を送信します。
制限事項
- インジケーターは、StockSharp インジケーター タイプとして使用できる必要があります。バイナリ MetaTrader インジケーターを直接ロードすることはできません。
- ブローカー側のフリーマージンに依存する資金管理モードは、固定ベースボリュームに簡素化されます。
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// ExpICustomV1 - custom indicator signal strategy.
/// Uses fast/slow EMA crossover to generate entry/exit signals.
/// Reverses position on opposite crossover.
/// </summary>
public class ExpICustomV1Strategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ExpICustomV1Strategy()
{
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 21)
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev)
{
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
return;
}
var bullCross = _prevFast <= _prevSlow && fast > slow;
var bearCross = _prevFast >= _prevSlow && fast < slow;
if (bullCross && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (bearCross && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevFast = fast;
_prevSlow = slow;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class exp_i_custom_v1_strategy(Strategy):
"""Fast/slow EMA crossover strategy. Reverses position on opposite crossover."""
def __init__(self):
super(exp_i_custom_v1_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 21) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(exp_i_custom_v1_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(exp_i_custom_v1_strategy, self).OnStarted2(time)
self._has_prev = False
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._process_candle).Start()
def _process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast)
slow_val = float(slow)
if not self._has_prev:
self._prev_fast = fast_val
self._prev_slow = slow_val
self._has_prev = True
return
bull_cross = self._prev_fast <= self._prev_slow and fast_val > slow_val
bear_cross = self._prev_fast >= self._prev_slow and fast_val < slow_val
if bull_cross and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif bear_cross and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return exp_i_custom_v1_strategy()