ホーム
/
戦略のサンプル
GitHub で見る
N Candles シーケンス・エントリー戦略
コンセプト
N Candles戦略は、すべて同じ方向に閉じる連続したローソク足をマーケットでスキャンします。設定可能な数の強気または弱気のローソク足が現れると、戦略はシーケンスの方向にエントリーします。この実装はMetaTrader「N Candles v4」エキスパートアドバイザーの直接変換であり、StockSharpの高レベルAPIの中でリスクコントロール、pipsベースの設定、オプションのトレーリングストップ動作を維持します。
エントリー条件
完成した各ローソク足を一度評価する。
上方に閉じるローソク足は強気としてカウント、下方に閉じるローソク足は弱気としてカウント、十字足はシーケンスをリセットする。
ConsecutiveCandles本の強気(または弱気)ローソク足が連続して現れた場合、戦略は動きの方向に成行注文を送信する。
選択されたAccountingModeに応じてヘッジスタイルのスタッキングまたはネッティングスタイルのエクスポージャー上限が適用される。
エグジット管理
StopLossPipsとTakeProfitPipsはアクティブポジションの平均エントリー価格からpipsで測定した静的な出口レベルを定義する。
TrailingStopPipsがゼロより大きい場合、ストップレベルは最も有利な価格に追随する:
固定ストップが存在しない場合(例えばStopLossPipsがゼロの場合)、戦略はブレイクイーブンストップを設定する前に価格がトレードに有利な方向にTrailingStopPips動くまで待つ。
ストップが設定されると、価格とストップ間の距離がTrailingStopPips + TrailingStepPipsを超えるとき市場に向かって移動する。
保護レベルはポジションサイズが変化するたびに再計算され、各完成ローソク足に対してチェックされ、ストップロスまたはテイクプロフィットイベントが即座にトレードを閉じることを保証する。
パラメーター
名前
説明
デフォルト値
ConsecutiveCandles
エントリーを発動するために必要な同一ローソク足の数。
3
TakeProfitPips
pipsでのテイクプロフィット距離。ターゲットを無効にするにはゼロを使用。
50
StopLossPips
pipsでのストップロス距離。ストップを無効にするにはゼロを使用。
50
TrailingStopPips
pipsでのトレーリングストップ距離。ゼロはトレーリングを無効にする。
10
TrailingStepPips
トレーリングストップが前進する前に必要な追加の動き。
4
MaxPositionsPerDirection
ヘッジングでの方向ごとのスタックされたエントリーの最大数。
2
MaxNetVolume
ネッティングモードで動作するときの最大絶対ネットポジションサイズ。
2
AccountingMode
Netting(ボリューム上限)とHedging(エントリー数上限)を切り替え。
Netting
CandleType
パターン検出に使用するローソク足集計。
1分足
すべてのpipsベースのパラメーターは銘柄のティックサイズを使用して価格オフセットに変換されます。銘柄に3または5の小数点桁数がある場合、MetaTraderの定義を反映するためにpipサイズは10倍に拡張されます。
実装上の注意
戦略はStockSharpの高レベルローソク足サブスクリプション(SubscribeCandles)に依存し、手動の履歴バッファを避けます。
保護ロジックはオリジナルのトレーリング動作をエミュレートするためにエントリー後に見られた最高値(ロング用)または最安値(ショート用)を追跡します。
ポジション制限は戦略のベースVolumeに自動的に適応します。Volumeを増加させるとストップとテイクプロフィット注文サイズが比例して拡大します。
保護出口(ストップまたはテイクプロフィット)がポジションを閉じるたびにログメッセージが発せられ、バックテスト中の明確さを提供します。
使用上のヒント
方向ごとに複数のチケットを許可するプラットフォームをシミュレートするときはHedgingモードを選択し、単一ポジション口座を反映するにはNettingにとどまる。
市場がTrailingStopPips前進するたびに移動するクラシックなトレーリングストップにはTrailingStepPipsをゼロに設定する。
出口は完成したローソク足で評価されるため、バー内精度が重要な場合はより短いローソク足間隔を検討する。
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that opens positions after detecting N identical candles in a row.
/// Enters in the direction of the candle streak.
/// </summary>
public class NCandlesSequenceStrategy : Strategy
{
private readonly StrategyParam<int> _consecutiveCandles;
private readonly StrategyParam<DataType> _candleType;
private int _consecutiveDirection;
private int _consecutiveCount;
/// <summary>
/// Number of identical candles required before entering a trade.
/// </summary>
public int ConsecutiveCandles
{
get => _consecutiveCandles.Value;
set => _consecutiveCandles.Value = value;
}
/// <summary>
/// Candle type used for pattern detection.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the strategy.
/// </summary>
public NCandlesSequenceStrategy()
{
_consecutiveCandles = Param(nameof(ConsecutiveCandles), 3)
.SetGreaterThanZero()
.SetDisplay("Consecutive Candles", "Number of identical candles in a row", "Entry")
.SetOptimize(2, 6, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to analyze", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_consecutiveDirection = 0;
_consecutiveCount = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_consecutiveDirection = 0;
_consecutiveCount = 0;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var direction = GetCandleDirection(candle);
if (direction == 0)
{
_consecutiveDirection = 0;
_consecutiveCount = 0;
return;
}
if (direction == _consecutiveDirection)
{
_consecutiveCount++;
}
else
{
_consecutiveDirection = direction;
_consecutiveCount = 1;
}
if (_consecutiveCount < ConsecutiveCandles)
return;
if (direction > 0 && Position <= 0)
{
BuyMarket();
}
else if (direction < 0 && Position >= 0)
{
SellMarket();
}
}
private static int GetCandleDirection(ICandleMessage candle)
{
if (candle.ClosePrice > candle.OpenPrice)
return 1;
if (candle.ClosePrice < candle.OpenPrice)
return -1;
return 0;
}
}
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.Strategies import Strategy
class n_candles_sequence_strategy(Strategy):
"""Opens positions after detecting N identical-direction candles in a row."""
def __init__(self):
super(n_candles_sequence_strategy, self).__init__()
self._consecutive = self.Param("ConsecutiveCandles", 3) \
.SetGreaterThanZero() \
.SetDisplay("Consecutive Candles", "Number of identical candles in a row", "Entry")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Type of candles to analyze", "General")
self._direction = 0
self._count = 0
@property
def ConsecutiveCandles(self):
return self._consecutive.Value
@property
def CandleType(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(n_candles_sequence_strategy, self).OnStarted2(time)
self._direction = 0
self._count = 0
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
d = 0
if float(candle.ClosePrice) > float(candle.OpenPrice):
d = 1
elif float(candle.ClosePrice) < float(candle.OpenPrice):
d = -1
if d == 0:
self._direction = 0
self._count = 0
return
if d == self._direction:
self._count += 1
else:
self._direction = d
self._count = 1
if self._count < self.ConsecutiveCandles:
return
if d > 0 and self.Position <= 0:
self.BuyMarket()
elif d < 0 and self.Position >= 0:
self.SellMarket()
def OnReseted(self):
super(n_candles_sequence_strategy, self).OnReseted()
self._direction = 0
self._count = 0
def CreateClone(self):
return n_candles_sequence_strategy()