GitHub で見る
FiftyFiveMaBarComparisonStrategy 戦略
概要
この戦略はMetaTrader 5の「55 MA」エキスパートアドバイザーを再現したもので、55期間の移動平均線の2点を比較し、その差が設定可能な閾値を超えた場合に取引を行います。すべての計算はユーザー定義のイントラデイセッション内の完成したローソク足で実行され、取引方向はオプションで反転できます。アルゴリズムは、強気条件が満たされない場合は常にショートポジションが開かれるという元の動作を保持します。
取引ロジック
- 選択したローソク足シリーズにサブスクライブし、選択した長さ、手法、適用価格で移動平均線を計算します。
- 水平MAシフトが使用されている場合でも、バーインデックス
BarA と BarB の値にアクセスできるよう、最新の移動平均値をバッファに保持します。
[StartHour, EndHour) ウィンドウ内に完成したローソク足が到着した場合:
BarA + MaShift と BarB + MaShift でのMA値を取得します。
BarA の値が BarB の値を DifferenceThreshold 以上上回る場合、ReverseSignals が有効でない限りロングポジションを開きます。
BarA の値が BarB の値を DifferenceThreshold 以上下回る場合、ショートポジションを開きます(ReverseSignals が有効な場合はロングポジション)。
- それ以外の場合、戦略は元のEAの動作を維持し、ショートエントリーをトリガーします。
- 注文は常に戦略の
Volume を使用して成行で送信されます。CloseOppositePositions が有効な場合、新しいポジションを確立する前に反対のエクスポージャーを解消するためにリクエストサイズが増加されます。
- オプションのストップロスとテイクプロフィットの保護は
StartProtection を通じて付加されます。距離はpipsで表され、1pipは3桁または5桁の小数点を持つ銘柄では PriceStep を10倍したものに相当します。
入力
| 名前 |
型 |
デフォルト |
説明 |
CandleType |
DataType |
1分足 |
計算とシグナルに使用するローソク足シリーズ。 |
StopLossPips |
int |
30 |
ストップロスの距離(pips)。無効にするには0に設定。 |
TakeProfitPips |
int |
50 |
テイクプロフィットの距離(pips)。無効にするには0に設定。 |
StartHour |
int |
8 |
取引セッション開始を示す時間(含む、0-23)。 |
EndHour |
int |
21 |
取引セッション終了を示す時間(含まない、0-23)。StartHour より大きくなければなりません。 |
DifferenceThreshold |
decimal |
0.0001 |
方向性シグナルをトリガーする比較されたMA値間の最小絶対差。 |
BarA |
int |
0 |
MAの比較に使用する最初のバーのインデックス(0 = 現在のローソク足)。 |
BarB |
int |
1 |
MAの比較に使用する2番目のバーのインデックス。 |
ReverseSignals |
bool |
false |
強気と弱気の条件を反転します。 |
CloseOppositePositions |
bool |
false |
有効にすると、新しいトレードを開く前に反対方向のポジションを閉じるために注文サイズを増加させます。 |
MaShift |
int |
0 |
移動平均線に適用する水平シフト。正の値は古いMAポイントにアクセスします。 |
MaLength |
int |
55 |
移動平均線の期間。 |
MaMethod |
MovingAverageMethods |
Exponential |
平滑化手法(Simple、Exponential、Smoothed、Weighted)。 |
AppliedPrice |
AppliedPriceTypes |
Median |
MAの入力として使用する価格(Close、Open、High、Low、Median、Typical、Weighted)。 |
ポジション管理
- 基本取引サイズを制御するために戦略の
Volume を設定します。CloseOppositePositions がアクティブな場合、現在のポジションと組み合わされます。
- ストップロスとテイクプロフィットの保護はオプションです。それぞれのpips距離がゼロより大きい場合にのみ付加されます。
注意事項
- 取引ウィンドウは銘柄の時間で動作します。
[StartHour, EndHour) 外のシグナルはスキップされます。
MaShift が負のインデックスを生成する場合、戦略は十分な履歴が蓄積されるまで待機します。これはシフトされたバッファが EMPTY_VALUE を返す可能性がある元のEAの動作を反映しています。
- 元のエキスパートは差の閾値が満たされない場合は常に売り注文をデフォルトとするため、変換された戦略は完全な忠実性のために同じロジックを維持します。この動作が望ましくない場合は
DifferenceThreshold を調整してください。
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>
/// 55 MA bar comparison strategy. Compares candle body with MA direction.
/// </summary>
public class FiftyFiveMaBarComparisonStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private decimal? _prevMa;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public FiftyFiveMaBarComparisonStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_maPeriod = Param(nameof(MaPeriod), 55)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Moving average period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMa = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMa = null;
var sma = new SimpleMovingAverage { Length = MaPeriod };
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 maVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevMa = maVal;
return;
}
if (_prevMa == null)
{
_prevMa = maVal;
return;
}
var close = candle.ClosePrice;
var bullishBar = candle.ClosePrice > candle.OpenPrice;
var bearishBar = candle.ClosePrice < candle.OpenPrice;
var maRising = maVal > _prevMa.Value;
var maFalling = maVal < _prevMa.Value;
_prevMa = maVal;
// Bullish bar + rising MA + close above MA → buy
if (bullishBar && maRising && close > maVal && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Bearish bar + falling MA + close below MA → sell
else if (bearishBar && maFalling && close < maVal && 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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class fifty_five_ma_bar_comparison_strategy(Strategy):
def __init__(self):
super(fifty_five_ma_bar_comparison_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._ma_period = self.Param("MaPeriod", 55) \
.SetDisplay("MA Period", "Moving average period", "Indicators")
self._prev_ma = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def MaPeriod(self):
return self._ma_period.Value
def OnReseted(self):
super(fifty_five_ma_bar_comparison_strategy, self).OnReseted()
self._prev_ma = None
def OnStarted2(self, time):
super(fifty_five_ma_bar_comparison_strategy, self).OnStarted2(time)
self._prev_ma = None
sma = SimpleMovingAverage()
sma.Length = self.MaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _on_process(self, candle, ma_value):
if candle.State != CandleStates.Finished:
return
mv = float(ma_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_ma = mv
return
if self._prev_ma is None:
self._prev_ma = mv
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
bullish_bar = close > open_price
bearish_bar = close < open_price
ma_rising = mv > self._prev_ma
ma_falling = mv < self._prev_ma
self._prev_ma = mv
# Bullish bar + rising MA + close above MA
if bullish_bar and ma_rising and close > mv and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Bearish bar + falling MA + close below MA
elif bearish_bar and ma_falling and close < mv and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return fifty_five_ma_bar_comparison_strategy()