ホーム
/
戦略のサンプル
GitHub で見る
ネクストバー戦略
概要
ネクストバー戦略 は、MetaTrader 4 エキスパート アドバイザー nextbar.mq4 の直訳です。オリジナルの EA は、最後に完了したローソク足と数バー古いローソク足との間の距離を評価します。価格が一方向に十分に移動すると、構成された方向フラグに応じて、勢いに従うか、勢いに逆らって取引されます。その後、ポジションは対称的なテイクプロフィット/ストップロスレベルで保護され、一定数のバーが経過すると強制的にクローズされます。
この StockSharp バージョンは、高レベルの戦略 API を使用している間、同じ動作を維持します。完了したローソク足のみを処理し、すべての計算が MT4 スクリプトのバーオンクローズ ロジックと一致することを保証します。
元の MQL ロジック
運動量距離 – Close[1] と Close[bars2check+1] を比較します。差が少なくとも minbar * Point である場合、それを有効な信号として扱います。
Direction flag – the MQL input direction equals 1 for trend-following (buy after a rally, sell after a drop) and 2 for contrarian trading (buy after a drop, sell after a rally).
エントリーの制約 – 一度にオープンできる注文は 1 つだけです。新しい取引はシグナルに続いてバーの開始時に送信されます。
エグジットルール – 最後の終値がエントリーより上の利益距離、またはそれより下の損失距離に達した場合はロングを閉じます。ショートの場合はその逆が当てはまります。どちらのレベルにも達していない場合は、bars2hold のローソク足が完了した後に取引を終了します。
StockSharp 実装のハイライト
SubscribeCandles() と Bind を使用して、設定された時間枠で完了したローソク足を受け取ります。
MQL bars2check + 1 オフセットに一致するローソク足を参照するために、終値の短いローリング履歴を保存します。
すべてのポイントベースのパラメータを Security.PriceStep で変換し、MetaTrader Point 定数を模倣します。
戦略 Volume を使用して成行注文を出し、Direction パラメーターを介してモメンタム追従または逆張りのエントリーをサポートします。
元のワークフローとの整合性を維持するために、利益、損失、および保持期間の終了を完成したキャンドルごとに 1 回だけ実装します。
パラメーター
パラメータ
説明
デフォルト
注意事項
CandleType
信号評価に使用される時間枠。
1時間枠
このローソク タイプを提供できる証券にストラテジーをアタッチします。
BarsToCheck
基準終値と最新終値の間で完了したローソク足の数。
8
EA の bars2check と一致します。
BarsToHold
オープンポジションを維持するための完了したローソクの最大数。
10
bars2hold と一致します。カウンタがこの数値に達したバーでポジションはクローズされます。
MinMovePoints
比較された 2 つの終値間の最小距離 (MetaTrader ポイント単位)。
77
minbarに対応します。 Security.PriceStep を使用して変換されました。
TakeProfitPoints
目標距離を MetaTrader ポイント単位で獲得します。
115
profit 入力と同等。必要に応じて無効にするには、ゼロに設定します。
StopLossPoints
MetaTrader ポイント単位のストップロス距離。
115
loss 入力と同等。必要に応じて無効にするには、ゼロに設定します。
Direction
取引モード: Follow (トレンド) または Reverse (逆張り)。
Follow
direction 入力をミラーリングします (1 = フォロー、2 = リバース)。
Volume
成行注文に使用される取引量。
戦略ボリューム
標準の Strategy.Volume プロパティを通じて設定します。
取引ワークフロー
ローソクが完成するのを待って、その終値をキャッシュします。
BarsToCheck 個前のローソク足から終値を取得し、差を計算します。
絶対移動が MinMovePoints * PriceStep 未満の場合は何もしません。
それ以外の場合:
フォロー モードでは、価格が上昇した場合は買い、価格が下落した場合は売ります。
リバース モードでは、価格が下落した場合は買い、価格が上昇した場合は売ります。
ポジションがオープンしている間、後続の終了したキャンドルごとに:
終値が保存されたエントリー価格より TakeProfitPoints 高いか、StopLossPoints 低い場合、終値ロングとなります。
終値がエントリーよりTakeProfitPoints下かStopLossPoints上になったらショートを閉じます。
エントリーから BarsToHold キャンドルが経過したら強制終了します。
使用上の注意
ポイントから絶対価格への変換には、Security.PriceStep が必要です。戦略を実行する前に、正しい商品メタデータ (価格ステップ、ステップ価格、出来高ルール) を提供してください。
この戦略は複数の同時ポジションを管理しません。 Volume が 1 回の MT4 注文で予想されるサイズに対応していることを確認してください。
Because decisions are evaluated on completed candles only, the strategy should be run with historical and real-time data that deliver finished bars.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class NextbarStrategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevOpen;
private decimal _prevClose;
private bool _hasPrev;
private int _cooldownRemaining;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public NextbarStrategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 50).SetDisplay("EMA Period", "EMA filter", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 200).SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevOpen = default;
_prevClose = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevOpen = 0;
_prevClose = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (!_hasPrev) { _prevOpen = candle.OpenPrice; _prevClose = close; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevOpen = candle.OpenPrice;
_prevClose = close;
return;
}
var prevBullish = _prevClose > _prevOpen;
var prevBearish = _prevClose < _prevOpen;
if (prevBullish && close > ema && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (prevBearish && close < ema && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevOpen = candle.OpenPrice;
_prevClose = close;
}
}
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 nextbar_strategy(Strategy):
def __init__(self):
super(nextbar_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 50) \
.SetDisplay("EMA Period", "EMA filter", "Indicators")
self._cooldown_candles = self.Param("CooldownCandles", 200) \
.SetDisplay("Cooldown", "Candles between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_open = 0.0
self._prev_close = 0.0
self._has_prev = False
self._cooldown_remaining = 0
@property
def ema_period(self):
return self._ema_period.Value
@property
def cooldown_candles(self):
return self._cooldown_candles.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(nextbar_strategy, self).OnReseted()
self._prev_open = 0.0
self._prev_close = 0.0
self._has_prev = False
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(nextbar_strategy, self).OnStarted2(time)
self._prev_open = 0.0
self._prev_close = 0.0
self._has_prev = False
self._cooldown_remaining = 0
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, self.process_candle).Start()
def process_candle(self, candle, ema):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
ema_val = float(ema)
if not self._has_prev:
self._prev_open = open_price
self._prev_close = close
self._has_prev = True
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_open = open_price
self._prev_close = close
return
prev_bullish = self._prev_close > self._prev_open
prev_bearish = self._prev_close < self._prev_open
if prev_bullish and close > ema_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_candles
elif prev_bearish and close < ema_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_candles
self._prev_open = open_price
self._prev_close = close
def CreateClone(self):
return nextbar_strategy()