ColorX2MA Digit戦略
この戦略はMQL5エキスパート Exp_ColorX2MA_Digit のポートです。 元のアルゴリズムは、二重平滑化移動平均線をその傾きに応じて異なる色で描画し、その色を取引シグナルの生成に使用します。 このC#バージョンでは、2本の単純移動平均線でその動作を近似し、それらのクロスオーバーで取引を行います。
取引ロジック
- 速い移動平均線が価格系列を平滑化します。
- 遅い移動平均線が速い移動平均の結果を平滑化します。
- 速い平均線が遅い平均線を上抜けると、戦略はロングポジションを開き、既存のショートポジションを決済します。
- 速い平均線が遅い平均線を下抜けると、戦略はショートポジションを開き、既存のロングポジションを決済します。
- シグナルは足が確定した後にのみ処理されます。
パラメーター
FastLength– 最初の平滑化の長さ(デフォルト12)。SlowLength– 2番目の平滑化の長さ(デフォルト5)。CandleType– 計算に使用する足の時間軸。
この戦略は高水準APIのみを使用します:インジケーターにデータを供給するために SubscribeCandles と Bind を使用し、ポジション管理には BuyMarket/SellMarket を使用します。コード内のコメントはメンテナンスを容易にするために英語で記述されています。
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Trend following strategy based on two sequential moving averages.
/// Trades on crossovers of fast and slow SMAs.
/// </summary>
public class ColorX2MaDigitStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevFast;
private decimal? _prevSlow;
public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ColorX2MaDigitStrategy()
{
_fastLength = Param(nameof(FastLength), 8)
.SetGreaterThanZero()
.SetDisplay("Fast MA Length", "Length of the first smoothing", "Parameters");
_slowLength = Param(nameof(SlowLength), 21)
.SetGreaterThanZero()
.SetDisplay("Slow MA Length", "Length of the second smoothing", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fastMa = new ExponentialMovingAverage { Length = FastLength };
var slowMa = new ExponentialMovingAverage { Length = SlowLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastMa, slowMa, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastMa);
DrawIndicator(area, slowMa);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastMa, decimal slowMa)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_prevFast is null || _prevSlow is null)
{
_prevFast = fastMa;
_prevSlow = slowMa;
return;
}
var wasAbove = _prevFast > _prevSlow;
var isAbove = fastMa > slowMa;
// Fast MA crossed above slow MA -> buy
if (!wasAbove && isAbove && Position <= 0)
BuyMarket();
// Fast MA crossed below slow MA -> sell
else if (wasAbove && !isAbove && Position >= 0)
SellMarket();
_prevFast = fastMa;
_prevSlow = slowMa;
}
}
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 color_x2_ma_digit_strategy(Strategy):
def __init__(self):
super(color_x2_ma_digit_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 8) \
.SetDisplay("Fast MA Length", "Length of the first smoothing", "Parameters")
self._slow_length = self.Param("SlowLength", 21) \
.SetDisplay("Slow MA Length", "Length of the second smoothing", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for strategy", "General")
self._prev_fast = None
self._prev_slow = None
@property
def fast_length(self):
return self._fast_length.Value
@property
def slow_length(self):
return self._slow_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_x2_ma_digit_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(color_x2_ma_digit_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast_ma = ExponentialMovingAverage()
fast_ma.Length = self.fast_length
slow_ma = ExponentialMovingAverage()
slow_ma.Length = self.slow_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_ma, slow_ma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ma)
self.DrawIndicator(area, slow_ma)
self.DrawOwnTrades(area)
def process_candle(self, candle, fast_ma, slow_ma):
if candle.State != CandleStates.Finished:
return
fast_ma = float(fast_ma)
slow_ma = float(slow_ma)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fast_ma
self._prev_slow = slow_ma
return
was_above = self._prev_fast > self._prev_slow
is_above = fast_ma > slow_ma
if not was_above and is_above and self.Position <= 0:
self.BuyMarket()
elif was_above and not is_above and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_ma
self._prev_slow = slow_ma
def CreateClone(self):
return color_x2_ma_digit_strategy()