GitHub で見る
MA価格クロス戦略
MA 価格クロス戦略は、MetaTrader 4 エキスパート アドバイザー「MA 価格クロス」を StockSharp の高レベル API に直接変換したものです。設定可能な時間枠内で取引が許可されている間、選択した移動平均が現在の価格を超えるまで待機します。下からクロスが発生すると、アルゴリズムはロングポジションをオープンします。クロスが上から発生すると、ショートポジションがオープンします。保護的なストップロスとテイクプロフィットの距離は MetaTrader ポイントで定義され、商品の PriceStep を使用して絶対価格オフセットに自動的に変換されます。
すべてのティックに反応する元の MQL 実装とは異なり、StockSharp バージョンは完成したキャンドルで動作し、SubscribeCandles の高レベルのサブスクリプションを使用します。これにより、取引の決定がバーごとに 1 回実行され、インジケーター バインディング パイプラインとの互換性が維持されることが保証されます。移動平均は 4 つの MetaTrader モードすべてに一致するように構成でき、さまざまな価格ソース (終値、始値、高値、安値、中央値、標準、加重値) を受け入れます。
取引ロジック
- 現在時刻が
[StartTime, StopTime) 取引ウィンドウ内に収まるまで待ちます。夜間ウィンドウは、午前 0 時をラップすることでサポートされます。
- 完成したキャンドルのみを処理します。設定された移動平均に、選択した適用価格を入力します。
- 以前の移動平均値を保存して、MetaTrader で使用される
iMA シフト ロジックをエミュレートします。
- 以前の平均が最新の価格を下回っており、新しい平均が価格を上回っている場合、ロングポジションをオープン(またはリバース)します。
- 以前の平均が最新の価格を上回っており、新しい平均が価格を下回っている場合、ショートポジションをオープン(またはリバース)します。
- 反対側で新しいポジションを開く前に、元のコードの
OrdersTotal() == 0 制約を反映するために既存のエクスポージャをフラット化します。
- MetaTrader ポイントと現在の商品
PriceStep を乗算して表される距離で仮想ストップロスとテイクプロフィットを開始します。
デフォルトパラメータ
| パラメータ |
デフォルト |
説明 |
CandleType |
TimeFrame(1m) |
あらゆる計算を駆動するキャンドルシリーズ。 |
MaPeriod |
160 |
移動平均で使用されるバーの数。 |
MaMethod |
Simple |
移動平均タイプ: 単純、指数、平滑化、または線形加重。 |
PriceType |
Close |
価格ソースは移動平均 (終値/始値/高値/安値/中央値/典型/加重) に転送されます。 |
StartTime |
01:00 |
取引が活発になる時間帯。 |
StopTime |
22:00 |
新しいエントリが停止する時刻。 |
StopLossPoints |
200 |
MetaTrader ポイントが絶対保護停止距離に変換されます。 |
TakeProfitPoints |
600 |
MetaTrader ポイントが絶対利益目標距離に変換されます。 |
OrderVolume |
0.1 |
デフォルトのボリュームは成行注文で送信されます。 |
注意事項
StartTime が StopTime に等しい場合、時間フィルターは無効になり、取引は終日許可されます。
StopLossPoints または TakeProfitPoints が 0 の場合、対応する保護レベルは登録されません。
- 時間フィルターはローソク足の終了時間 (
candle.CloseTime.TimeOfDay) を使用するため、MarketDataConnector によって提供される為替タイムゾーンに適応します。
- セキュリティが
PriceStep を公開しない場合、ポイントベースの距離がスケーリングなしで直接使用されます。
オリジナル攻略参考資料
- 出典:
MQL/44133/MA Price Cross.mq4
- 著者: JBlanked (2023)
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "MA Price Cross" MetaTrader expert.
/// Enters when SMA crosses above/below the current close price.
/// </summary>
public class MaPriceCrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private ExponentialMovingAverage _sma;
private decimal? _prevAverage;
private decimal? _prevClose;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public MaPriceCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for MA cross detection", "General");
_maPeriod = Param(nameof(MaPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("MA Period", "SMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_sma = new ExponentialMovingAverage { Length = MaPeriod };
_prevAverage = null;
_prevClose = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_sma.IsFormed)
{
_prevAverage = smaValue;
_prevClose = candle.ClosePrice;
return;
}
if (_prevAverage is null || _prevClose is null)
{
_prevAverage = smaValue;
_prevClose = candle.ClosePrice;
return;
}
var close = candle.ClosePrice;
var volume = Volume;
if (volume <= 0)
volume = 1;
// MA was below price, now crosses above -> sell signal (price goes under MA)
var sellSignal = _prevClose.Value >= _prevAverage.Value && close < smaValue;
// MA was above price, now crosses below -> buy signal (price goes above MA)
var buySignal = _prevClose.Value <= _prevAverage.Value && close > smaValue;
if (buySignal)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (sellSignal)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevAverage = smaValue;
_prevClose = close;
}
/// <inheritdoc />
protected override void OnReseted()
{
_sma = null;
_prevAverage = null;
_prevClose = null;
base.OnReseted();
}
}
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 ma_price_cross_strategy(Strategy):
def __init__(self):
super(ma_price_cross_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._ma_period = self.Param("MaPeriod", 100)
self._prev_average = None
self._prev_close = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
def OnReseted(self):
super(ma_price_cross_strategy, self).OnReseted()
self._prev_average = None
self._prev_close = None
def OnStarted2(self, time):
super(ma_price_cross_strategy, self).OnStarted2(time)
self._prev_average = None
self._prev_close = None
sma = ExponentialMovingAverage()
sma.Length = self.MaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma, self._process_candle).Start()
def _process_candle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
sma_val = float(sma_value)
close = float(candle.ClosePrice)
if self._prev_average is None or self._prev_close is None:
self._prev_average = sma_val
self._prev_close = close
return
# Price crosses above MA -> buy
buy_signal = self._prev_close <= self._prev_average and close > sma_val
# Price crosses below MA -> sell
sell_signal = self._prev_close >= self._prev_average and close < sma_val
if buy_signal:
if self.Position <= 0:
self.BuyMarket()
elif sell_signal:
if self.Position >= 0:
self.SellMarket()
self._prev_average = sma_val
self._prev_close = close
def CreateClone(self):
return ma_price_cross_strategy()