マックバリューのクラウド戦略
このフォルダには、MetaTrader エキスパート アドバイザー「Mc_valute」の StockSharp ポートが含まれています。ショート丈を組み合わせたオリジナルロボット 3 つの平滑化移動平均、Ichimoku クラウド フィルター、および複数の MACD インスタンスを含む指数移動平均 (EMA) トレンドにスケーリングします。 StockSharp の実装は、コアのトレンド確認スタックを維持しながら、ポジション管理を簡素化します ロジックが高レベルの API に自然に適合するように、各方向で単一の露出に対応します。
取引ロジック
- 価格フィルター EMA –
FilterMaLengthEMA は、2 つの滑らかな動きの上(ロングの場合)または下(ショートの場合)に配置する必要があります 平均 (BlueMaLengthとLimeMaLength)。平滑化された平均は、MT4 テンプレートの「青」と「ライム」の線をエミュレートします。 - Ichimoku クラウドの確認 – EMA もクラウドの外にある必要があります。ロングトレードには両方の上にフィルター EMA が必要です センコウはスパンですが、ショートトレードでは雲底を下回ることが要求されます。
- MACD の勢いチェック – メインの MACD ラインは、ロングエントリーの場合はシグナルラインより上にあり、ショートエントリーの場合はシグナルラインより下にある必要があります。 残りのコピーは最終的な MQL バージョンで無効になっているため、元の EA の最初の MACD セットのみが保持されます。
- 単一ポジション管理 – 新しいシグナルが現れるたびに、戦略は既存の反対ポジションを相殺し、ポジションをオープンします。
設定された
Volumeとの新たな取引。保護注文は成行注文が送信された直後に更新されます。 - ローソクごとの評価 – すべてのインジケーターは、
CandleTypeで定義された時間枠で動作します。取引に関する決定が下される 閉じたバーを処理した MT4start()ハンドラーをミラーリングするために、終了したローソク足でのみ使用します。
リスク管理
TakeProfitとStopLossは価格ポイントで測定されます。各エントリの後に、ヘルパーSetTakeProfitとSetStopLoss関数は、予想される結果のポジションサイズを使用して呼び出されます。これは、ストップが適用されたMT4の動作を反映しています。 チケット。- 元のエキスパートアドバイザーは、
Stepの距離を使用して、最大 3 つの追加注文をピラミッド化しました。 StockSharp ポートは 上位レベルのオーダーヘルパー内に留まる単一のポジション。スケーリングが必要なユーザーは、Volumeを増やすか、クローンを作成できます。 複数のポートフォリオにわたる戦略。
パラメーター
| パラメータ | 説明 |
|---|---|
Volume |
高レベルの BuyMarket/SellMarket 呼び出しで使用される基本取引サイズ。 |
CandleType |
インジケーターとトレードロジックを動かす主要なローソク足シリーズ。 |
FilterMaLength |
EMA トレンド フィルターの長さ。 |
BlueMaLength, LimeMaLength |
方向性バンドとして機能する 2 つの平滑化移動平均の長さ。 |
MacdFastLength, MacdSlowLength, MacdSignalLength |
MACD 確認の EMA の長さ。 |
TenkanLength, KijunLength, SenkouLength |
Ichimoku クラウドフィルターのKinko Hyo設定。 |
TakeProfit, StopLoss |
保護距離は価格で表されます。 |
使用上の注意
- インジケーター シフト – MetaTrader では、平滑化移動平均を作成するときにゼロ以外の「シフト」パラメーターが許可されました。 StockSharpさん インジケーターは現在のバーで動作するため、ポートは元の期間を維持しながらこれらのシフトを無視します。
- MACD のバリアント – ソース コードでは 3 つの MACD ブロックが宣言されていますが、ライブ信号に参加するのは最初のブロックのみです。港 その行動に従います。追加の MACD フィルターは、インジケーター バインディングを複製することで再度有効にすることができます。
- 取引のスケーリング – MT4 ロボットは、
Stepポイントで区切られた最大 3 つの平均注文を送信しました。この動作は文書化されています ただし、高レベルの戦略は単一の集約されたポジションで機能するため、意図的に省略されています。 - 保護ブロック –
StartProtection()は起動時に 1 回呼び出され、組み込みインフラストラクチャが停止を監視します。 再接続後も注文をターゲットにします。
ファイル
CS/McValuteCloudStrategy.cs– インジケーター バインディングと詳細を備えた高レベルの戦略 API を使用した C# 実装 コメント。README.md– 英語のドキュメント (このファイル)。README_zh.md– 簡体字中国語翻訳。README_ru.md– ロシア語の翻訳。
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Trend-following strategy inspired by the "Mc_valute" MetaTrader expert advisor.
/// Combines smoothed moving averages, an Ichimoku cloud filter and a MACD confirmation.
/// </summary>
public class McValuteCloudStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _filterMaLength;
private readonly StrategyParam<int> _blueMaLength;
private readonly StrategyParam<int> _limeMaLength;
private readonly StrategyParam<int> _macdFastLength;
private readonly StrategyParam<int> _macdSlowLength;
private readonly StrategyParam<int> _macdSignalLength;
private readonly StrategyParam<int> _tenkanLength;
private readonly StrategyParam<int> _kijunLength;
private readonly StrategyParam<int> _senkouLength;
private readonly StrategyParam<int> _takeProfit;
private readonly StrategyParam<int> _stopLoss;
private ExponentialMovingAverage _filterMa;
private SmoothedMovingAverage _blueMa;
private SmoothedMovingAverage _limeMa;
private MovingAverageConvergenceDivergenceSignal _macd;
private Ichimoku _ichimoku;
private decimal? _filterValue;
private decimal? _blueValue;
private decimal? _limeValue;
private decimal? _senkouAValue;
private decimal? _senkouBValue;
private decimal? _macdMainValue;
private decimal? _macdSignalValue;
private DateTimeOffset _lastProcessedTime;
/// <summary>
/// Initializes a new instance of the <see cref="McValuteCloudStrategy"/> class.
/// </summary>
public McValuteCloudStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Primary timeframe used for signals", "General");
_filterMaLength = Param(nameof(FilterMaLength), 3)
.SetDisplay("Filter EMA", "Length of the trend filter EMA", "Trend")
.SetOptimize(2, 20, 1);
_blueMaLength = Param(nameof(BlueMaLength), 13)
.SetDisplay("Blue SMMA", "Length of the slower smoothed MA", "Trend")
.SetOptimize(5, 60, 1);
_limeMaLength = Param(nameof(LimeMaLength), 5)
.SetDisplay("Lime SMMA", "Length of the faster smoothed MA", "Trend")
.SetOptimize(3, 40, 1);
_macdFastLength = Param(nameof(MacdFastLength), 12)
.SetDisplay("MACD Fast", "Short EMA length for the MACD", "Momentum")
.SetOptimize(5, 30, 1);
_macdSlowLength = Param(nameof(MacdSlowLength), 26)
.SetDisplay("MACD Slow", "Long EMA length for the MACD", "Momentum")
.SetOptimize(10, 80, 1);
_macdSignalLength = Param(nameof(MacdSignalLength), 9)
.SetDisplay("MACD Signal", "Signal EMA length for the MACD", "Momentum")
.SetOptimize(3, 30, 1);
_tenkanLength = Param(nameof(TenkanLength), 12)
.SetDisplay("Tenkan", "Tenkan-sen length for the Ichimoku cloud", "Ichimoku")
.SetOptimize(5, 30, 1);
_kijunLength = Param(nameof(KijunLength), 20)
.SetDisplay("Kijun", "Kijun-sen length for the Ichimoku cloud", "Ichimoku")
.SetOptimize(10, 60, 1);
_senkouLength = Param(nameof(SenkouLength), 40)
.SetDisplay("Senkou Span B", "Span B length for the Ichimoku cloud", "Ichimoku")
.SetOptimize(20, 120, 1);
_takeProfit = Param(nameof(TakeProfit), 30)
.SetDisplay("Take Profit", "Take profit distance in points", "Risk")
.SetOptimize(10, 200, 5);
_stopLoss = Param(nameof(StopLoss), 350)
.SetDisplay("Stop Loss", "Stop loss distance in points", "Risk")
.SetOptimize(50, 600, 10);
_lastProcessedTime = DateTimeOffset.MinValue;
}
/// <summary>
/// Timeframe used for the working candles.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Length of the EMA filter.
/// </summary>
public int FilterMaLength
{
get => _filterMaLength.Value;
set => _filterMaLength.Value = value;
}
/// <summary>
/// Length of the slower smoothed moving average.
/// </summary>
public int BlueMaLength
{
get => _blueMaLength.Value;
set => _blueMaLength.Value = value;
}
/// <summary>
/// Length of the faster smoothed moving average.
/// </summary>
public int LimeMaLength
{
get => _limeMaLength.Value;
set => _limeMaLength.Value = value;
}
/// <summary>
/// Fast EMA length used by the MACD.
/// </summary>
public int MacdFastLength
{
get => _macdFastLength.Value;
set => _macdFastLength.Value = value;
}
/// <summary>
/// Slow EMA length used by the MACD.
/// </summary>
public int MacdSlowLength
{
get => _macdSlowLength.Value;
set => _macdSlowLength.Value = value;
}
/// <summary>
/// Signal EMA length used by the MACD.
/// </summary>
public int MacdSignalLength
{
get => _macdSignalLength.Value;
set => _macdSignalLength.Value = value;
}
/// <summary>
/// Tenkan-sen length for the Ichimoku indicator.
/// </summary>
public int TenkanLength
{
get => _tenkanLength.Value;
set => _tenkanLength.Value = value;
}
/// <summary>
/// Kijun-sen length for the Ichimoku indicator.
/// </summary>
public int KijunLength
{
get => _kijunLength.Value;
set => _kijunLength.Value = value;
}
/// <summary>
/// Senkou Span B length for the Ichimoku indicator.
/// </summary>
public int SenkouLength
{
get => _senkouLength.Value;
set => _senkouLength.Value = value;
}
/// <summary>
/// Take profit distance in points.
/// </summary>
public int TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Stop loss distance in points.
/// </summary>
public int StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_filterMa = null;
_blueMa = null;
_limeMa = null;
_macd = null;
_ichimoku = null;
_filterValue = null;
_blueValue = null;
_limeValue = null;
_senkouAValue = null;
_senkouBValue = null;
_macdMainValue = null;
_macdSignalValue = null;
_lastProcessedTime = DateTimeOffset.MinValue;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_filterMa = new ExponentialMovingAverage { Length = FilterMaLength };
_blueMa = new SmoothedMovingAverage { Length = BlueMaLength };
_limeMa = new SmoothedMovingAverage { Length = LimeMaLength };
_macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = MacdFastLength },
LongMa = { Length = MacdSlowLength },
},
SignalMa = { Length = MacdSignalLength }
};
_ichimoku = new Ichimoku
{
Tenkan = { Length = TenkanLength },
Kijun = { Length = KijunLength },
SenkouB = { Length = SenkouLength }
};
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_filterMa, _blueMa, _limeMa, ProcessMovingAverages)
.BindEx(_macd, ProcessMacd)
.BindEx(_ichimoku, ProcessIchimoku)
.Start();
StartProtection(null, null);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _filterMa);
DrawIndicator(area, _blueMa);
DrawIndicator(area, _limeMa);
DrawIndicator(area, _macd);
DrawOwnTrades(area);
}
}
private void ProcessMovingAverages(ICandleMessage candle, decimal filter, decimal blue, decimal lime)
{
if (candle.State != CandleStates.Finished)
return;
_filterValue = filter;
_blueValue = blue;
_limeValue = lime;
TryTrade(candle);
}
private void ProcessMacd(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
var typed = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
if (typed.Macd is not decimal macd || typed.Signal is not decimal signal)
return;
_macdMainValue = macd;
_macdSignalValue = signal;
TryTrade(candle);
}
private void ProcessIchimoku(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
var ichimokuValue = (IchimokuValue)value;
if (ichimokuValue.SenkouA is not decimal spanA || ichimokuValue.SenkouB is not decimal spanB)
return;
_senkouAValue = spanA;
_senkouBValue = spanB;
TryTrade(candle);
}
private void TryTrade(ICandleMessage candle)
{
// indicators formed check removed
if (candle.State != CandleStates.Finished)
return;
if (_lastProcessedTime == candle.OpenTime)
return;
if (_filterValue is not decimal filter ||
_blueValue is not decimal blue ||
_limeValue is not decimal lime ||
_senkouAValue is not decimal spanA ||
_senkouBValue is not decimal spanB ||
_macdMainValue is not decimal macd ||
_macdSignalValue is not decimal signal)
{
return;
}
_lastProcessedTime = candle.OpenTime;
var cloudTop = Math.Max(spanA, spanB);
var cloudBottom = Math.Min(spanA, spanB);
var maUpper = Math.Max(blue, lime);
var maLower = Math.Min(blue, lime);
var allowLong = filter > maUpper && filter > cloudTop && macd > signal;
var allowShort = filter < maLower && filter < cloudBottom && macd < signal;
var closePrice = candle.ClosePrice;
if (allowLong && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (allowShort && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
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, SmoothedMovingAverage,
MovingAverageConvergenceDivergenceSignal, Ichimoku
)
from StockSharp.Algo.Strategies import Strategy
class mc_valute_cloud_strategy(Strategy):
"""Trend-following strategy combining smoothed MAs, Ichimoku cloud filter and MACD confirmation."""
def __init__(self):
super(mc_valute_cloud_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Primary timeframe used for signals", "General")
self._filter_ma_length = self.Param("FilterMaLength", 3) \
.SetDisplay("Filter EMA", "Length of the trend filter EMA", "Trend")
self._blue_ma_length = self.Param("BlueMaLength", 13) \
.SetDisplay("Blue SMMA", "Length of the slower smoothed MA", "Trend")
self._lime_ma_length = self.Param("LimeMaLength", 5) \
.SetDisplay("Lime SMMA", "Length of the faster smoothed MA", "Trend")
self._macd_fast_length = self.Param("MacdFastLength", 12) \
.SetDisplay("MACD Fast", "Short EMA length for the MACD", "Momentum")
self._macd_slow_length = self.Param("MacdSlowLength", 26) \
.SetDisplay("MACD Slow", "Long EMA length for the MACD", "Momentum")
self._macd_signal_length = self.Param("MacdSignalLength", 9) \
.SetDisplay("MACD Signal", "Signal EMA length for the MACD", "Momentum")
self._tenkan_length = self.Param("TenkanLength", 12) \
.SetDisplay("Tenkan", "Tenkan-sen length for the Ichimoku cloud", "Ichimoku")
self._kijun_length = self.Param("KijunLength", 20) \
.SetDisplay("Kijun", "Kijun-sen length for the Ichimoku cloud", "Ichimoku")
self._senkou_length = self.Param("SenkouLength", 40) \
.SetDisplay("Senkou Span B", "Span B length for the Ichimoku cloud", "Ichimoku")
self._take_profit = self.Param("TakeProfit", 30) \
.SetDisplay("Take Profit", "Take profit distance in points", "Risk")
self._stop_loss = self.Param("StopLoss", 350) \
.SetDisplay("Stop Loss", "Stop loss distance in points", "Risk")
self._filter_value = None
self._blue_value = None
self._lime_value = None
self._senkou_a_value = None
self._senkou_b_value = None
self._macd_main_value = None
self._macd_signal_value = None
self._last_processed_time = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FilterMaLength(self):
return self._filter_ma_length.Value
@property
def BlueMaLength(self):
return self._blue_ma_length.Value
@property
def LimeMaLength(self):
return self._lime_ma_length.Value
@property
def MacdFastLength(self):
return self._macd_fast_length.Value
@property
def MacdSlowLength(self):
return self._macd_slow_length.Value
@property
def MacdSignalLength(self):
return self._macd_signal_length.Value
@property
def TenkanLength(self):
return self._tenkan_length.Value
@property
def KijunLength(self):
return self._kijun_length.Value
@property
def SenkouLength(self):
return self._senkou_length.Value
@property
def TakeProfit(self):
return self._take_profit.Value
@property
def StopLoss(self):
return self._stop_loss.Value
def OnReseted(self):
super(mc_valute_cloud_strategy, self).OnReseted()
self._filter_value = None
self._blue_value = None
self._lime_value = None
self._senkou_a_value = None
self._senkou_b_value = None
self._macd_main_value = None
self._macd_signal_value = None
self._last_processed_time = None
def OnStarted2(self, time):
super(mc_valute_cloud_strategy, self).OnStarted2(time)
filter_ma = ExponentialMovingAverage()
filter_ma.Length = self.FilterMaLength
blue_ma = SmoothedMovingAverage()
blue_ma.Length = self.BlueMaLength
lime_ma = SmoothedMovingAverage()
lime_ma.Length = self.LimeMaLength
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self.MacdFastLength
macd.Macd.LongMa.Length = self.MacdSlowLength
macd.SignalMa.Length = self.MacdSignalLength
ichimoku = Ichimoku()
ichimoku.Tenkan.Length = self.TenkanLength
ichimoku.Kijun.Length = self.KijunLength
ichimoku.SenkouB.Length = self.SenkouLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(filter_ma, blue_ma, lime_ma, self._process_moving_averages)
subscription.BindEx(macd, self._process_macd)
subscription.BindEx(ichimoku, self._process_ichimoku)
subscription.Start()
def _process_moving_averages(self, candle, filter_val, blue_val, lime_val):
if candle.State != CandleStates.Finished:
return
self._filter_value = float(filter_val)
self._blue_value = float(blue_val)
self._lime_value = float(lime_val)
self._try_trade(candle)
def _process_macd(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
macd_raw = macd_value.Macd
signal_raw = macd_value.Signal
if macd_raw is None or signal_raw is None:
return
self._macd_main_value = float(macd_raw)
self._macd_signal_value = float(signal_raw)
self._try_trade(candle)
def _process_ichimoku(self, candle, ichimoku_value):
if candle.State != CandleStates.Finished:
return
senkou_a = ichimoku_value.SenkouA
senkou_b = ichimoku_value.SenkouB
if senkou_a is None or senkou_b is None:
return
self._senkou_a_value = float(senkou_a)
self._senkou_b_value = float(senkou_b)
self._try_trade(candle)
def _try_trade(self, candle):
if candle.State != CandleStates.Finished:
return
if self._last_processed_time == candle.OpenTime:
return
if self._filter_value is None or self._blue_value is None or self._lime_value is None:
return
if self._senkou_a_value is None or self._senkou_b_value is None:
return
if self._macd_main_value is None or self._macd_signal_value is None:
return
self._last_processed_time = candle.OpenTime
filter_val = self._filter_value
blue = self._blue_value
lime = self._lime_value
span_a = self._senkou_a_value
span_b = self._senkou_b_value
macd = self._macd_main_value
signal = self._macd_signal_value
cloud_top = max(span_a, span_b)
cloud_bottom = min(span_a, span_b)
ma_upper = max(blue, lime)
ma_lower = min(blue, lime)
allow_long = filter_val > ma_upper and filter_val > cloud_top and macd > signal
allow_short = filter_val < ma_lower and filter_val < cloud_bottom and macd < signal
if allow_long and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif allow_short and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return mc_valute_cloud_strategy()