ホーム
/
戦略のサンプル
GitHub で見る
Max V2の場合
概要
For Max V2 is a port of the MetaTrader 4 expert advisor for_max_v2.mq4.この戦略は、特定の 2 本のローソク足の巻き込みパターンを待ってから、最新のローソク足の周囲に対称的な買いストップ注文と売りストップ注文のペアを配置します。ブレイクアウト注文が約定すると、反対側の未決注文が削除され、ポジションは固定ストップ、オプションのテイクプロフィットレベル、損益分岐点で最初に少額の利益を確定させてから価格に従うトレーリングルーチンで管理されます。
戦略ロジック
巻き込みパターンの検出
The original expert advisor exposes two entry blocks and both are preserved:
タイプ 1 セットアップ – 以前の Max Search ローソク足をスキャンし (現在のバーをスキップ)、その範囲内の最低安値が 2 バー前に発生するのを待ちます。または 最高高値が 2 バー前に発生するのを待ちます。 When that happens the candle two bars back must engulf the previous candle (higher high and lower low).セットアップは、最後に完成したキャンドルの周りにまたがってアームします。
Type 2 setup – also scans the previous Max Search candles, but looks for the extreme to appear one bar ago. In addition, the candle one bar ago must engulf the candle two bars back. A straddle is then placed around the most recent candle.両方のセットアップは共存できます。 each manages its own pending orders and expiration clock.
保留中の注文
エントリー価格 – 買いストップ注文は前のローソク足の高値プラス Gap Points で発注され、売りストップ注文は前のローソク足の安値から Gap Points を引いた位置で発注されます。
ストップロス – タイプ 1 の場合、ロングストップは 2 バー前のローソク足の安値 (マイナスギャップ) に固定され、ショートストップはそのローソク足の高値 (プラスギャップ) に固定されます。タイプ 2 は、両側に前のキャンドルを使用します。
利益確定 – オプション。ロングターゲットは前の高値から Gap Points + Buy Take Profit Points を加算し、ショートターゲットは前の安値から Gap Points + Sell Take Profit Points を減算します。 Setting the take-profit inputs to 0 disables the respective targets.
Expiration – each straddle carries a validity timestamp computed as Order Expiry (bars) multiplied by the configured candle timeframe. If the pending orders are still working when the timestamp is reached, both sides are cancelled.
ポジション管理
Once a buy-stop fills, any remaining sell-stop orders from either setup are cancelled;対称ルールは短いエントリの後に適用されます。
ストップとターゲットは完成したキャンドルで監視されます。 If a candle’s low reaches the long stop (or the high reaches the short stop) the position is closed with a market order. The same approach is used for the take-profit levels.
損益分岐点ルーチン (Break-even Trigger および Break-even Offset) は、ポジションがトリガー量だけ進むと、エントリー価格に構成されたオフセットをプラス/マイナスした値にストップを移動します。
後続ブロックは、ストップを最良のエクスカーションから Long/Short Trailing Buffer ポイント遠ざけますが、それは価格が十分に上昇した後のみです (オプションで取引がすでに利益を上げている後のみ)。 Trailing Step は、ストップを再度締める前に最小限の改善を要求することで、過度の調整を防ぎます。
パラメーター
出来高 – 未決の各ストップ注文の注文量。
バイプロフィット (ポイント) – ロングテイクプロフィットの計算に使用されるポイント単位の距離 (無効にする場合は 0 に設定します)。
売りテイクプロフィット (ポイント) – ショートテイクプロフィットの計算に使用されるポイント単位の距離 (無効にするには 0 に設定します)。
ギャップ (ポイント) – ストップエントリーを配置する前に高値/安値にバッファーが追加され、テイクプロフィットディスタンスに組み込まれます。
Search Depth – number of finished candles scanned when checking for Type 1 and Type 2 engulfing setups.
注文有効期限 (バー) – 両側がキャンセルされるまで保留中のストラドルがアクティブのままになるローソク足の長さの数。
損益分岐点トリガー (ポイント) – 損益分岐点調整を開始する利益のしきい値。
損益分岐点オフセット (ポイント) – 損益分岐点ストップが設定されたときにエントリー価格に追加される追加のバッファー。
ロングトレーリングバッファー (ポイント) – 損益分岐点に達した後のロングポジションのトレーリング距離。
ショート トレーリング バッファー (ポイント) – 損益分岐点に達した後のショート ポジションのトレーリング距離。
トレーリング ステップ (ポイント) – トレーリング ストップを再度更新する前に必要なストップ位置の最小限の改善。
利益後のトレーリングのみ – 有効にすると、トレーリングはポジションがバッファーを越えるまで待機してからアクティブになります。
ローソク足タイプ – パターン検出、注文の有効期限、および終了処理に使用されるローソク足の時間枠。
追加の注意事項
「ポイント」で表される価格オフセットは、証券の PriceStep に依存します。小数点以下 5 桁(または 3 桁)のシンボルは、MetaTrader と同様に、小数点以下のピップ サイズに自動的に変換されます。
ストップロスとテイクプロフィットは、閉じたローソク足のレベルを管理する EA の動作を反映するために、戦略内の成行注文を通じて実行されます。
この戦略では、元のソースの未使用の vhod_3 関数は実装されていません。 2 つのアクティブなエントリ ブロックのみが移植されました。
このパッケージには C# 実装のみが含まれています。 Python のバージョンは提供されていません。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// For Max V2: N-bar engulfing breakout with EMA filter and ATR stops.
/// </summary>
public class ForMaxV2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<int> _lookback;
private decimal _entryPrice;
private decimal _prevHigh;
private decimal _prevLow;
private readonly decimal[] _highs = new decimal[10];
private readonly decimal[] _lows = new decimal[10];
private int _barCount;
public ForMaxV2Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_emaLength = Param(nameof(EmaLength), 30)
.SetDisplay("EMA Length", "Trend filter.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
_lookback = Param(nameof(Lookback), 10)
.SetDisplay("Lookback", "N-bar channel lookback.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
public int Lookback
{
get => _lookback.Value;
set => _lookback.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0;
_barCount = 0;
_prevHigh = 0;
_prevLow = 0;
Array.Clear(_highs, 0, _highs.Length);
Array.Clear(_lows, 0, _lows.Length);
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0;
_barCount = 0;
_prevHigh = 0;
_prevLow = 0;
var ema = new ExponentialMovingAverage { Length = EmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
var len = Math.Min(Lookback, _highs.Length);
var idx = _barCount % len;
_highs[idx] = candle.HighPrice;
_lows[idx] = candle.LowPrice;
_barCount++;
if (_barCount < len || atrVal <= 0)
return;
var high = decimal.MinValue;
var low = decimal.MaxValue;
for (var i = 0; i < len; i++)
{
if (_highs[i] > high) high = _highs[i];
if (_lows[i] < low) low = _lows[i];
}
var close = candle.ClosePrice;
if (_prevHigh == 0 || _prevLow == 0)
{
_prevHigh = high;
_prevLow = low;
return;
}
if (Position > 0)
{
if (close >= _entryPrice + atrVal * 3m || close <= _entryPrice - atrVal * 1.5m)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
if (close <= _entryPrice - atrVal * 3m || close >= _entryPrice + atrVal * 1.5m)
{
BuyMarket();
_entryPrice = 0;
}
}
if (Position == 0)
{
if (close > _prevHigh && close > emaVal)
{
_entryPrice = close;
BuyMarket();
}
else if (close < _prevLow && close < emaVal)
{
_entryPrice = close;
SellMarket();
}
}
_prevHigh = high;
_prevLow = low;
}
}
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
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AverageTrueRange
class for_max_v2_strategy(Strategy):
def __init__(self):
super(for_max_v2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(8))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._ema_length = self.Param("EmaLength", 30) \
.SetDisplay("EMA Length", "Trend filter.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._lookback = self.Param("Lookback", 10) \
.SetDisplay("Lookback", "N-bar channel lookback.", "Indicators")
self._entry_price = 0.0
self._prev_high = 0.0
self._prev_low = 0.0
self._bar_count = 0
self._highs = []
self._lows = []
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
@property
def Lookback(self):
return self._lookback.Value
def OnStarted2(self, time):
super(for_max_v2_strategy, self).OnStarted2(time)
self._entry_price = 0.0
self._bar_count = 0
self._prev_high = 0.0
self._prev_low = 0.0
self._highs = [0.0] * 10
self._lows = [0.0] * 10
self._ema = ExponentialMovingAverage()
self._ema.Length = self.EmaLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._ema, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
ev = float(ema_val)
av = float(atr_val)
length = min(self.Lookback, 10)
idx = self._bar_count % length
self._highs[idx] = float(candle.HighPrice)
self._lows[idx] = float(candle.LowPrice)
self._bar_count += 1
if self._bar_count < length or av <= 0:
return
high = max(self._highs[i] for i in range(length))
low = min(self._lows[i] for i in range(length))
close = float(candle.ClosePrice)
if self._prev_high == 0 or self._prev_low == 0:
self._prev_high = high
self._prev_low = low
return
if self.Position > 0:
if close >= self._entry_price + av * 3.0 or close <= self._entry_price - av * 1.5:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close <= self._entry_price - av * 3.0 or close >= self._entry_price + av * 1.5:
self.BuyMarket()
self._entry_price = 0.0
if self.Position == 0:
if close > self._prev_high and close > ev:
self._entry_price = close
self.BuyMarket()
elif close < self._prev_low and close < ev:
self._entry_price = close
self.SellMarket()
self._prev_high = high
self._prev_low = low
def OnReseted(self):
super(for_max_v2_strategy, self).OnReseted()
self._entry_price = 0.0
self._bar_count = 0
self._prev_high = 0.0
self._prev_low = 0.0
self._highs = []
self._lows = []
def CreateClone(self):
return for_max_v2_strategy()