GitHub で見る
2 つの未決注文 2
概要
この戦略は、MetaTrader エキスパート アドバイザー 「2 つの保留中の注文 2」 の StockSharp 移植です。市場価格を中心に 2 つの対称的な未決注文を保持し、最初にトリガーされた側が設定可能なストップロス、テイクプロフィット、およびトレーリングルールを使用して取引を管理できるようにします。変換では高レベルの StockSharp API が使用され、元のアルゴリズムの核となるアイデアを維持しながら、戦略パラメータを通じてすべての調整ノブが公開されます。
取引ロジック
- この戦略は、選択したローソク足シリーズ (デフォルトでは毎日のローソク足) をサブスクライブします。ローソク足が終了すると、それが次の取引サイクルの決定点になります。
- 有効な保留中の注文は、期限切れになるか、新しい注文が発注される前にキャンセルされます。これにより、市場には最も新鮮なレベルのみが存在することが保証されます。
- 現在のスプレッドが許容しきい値内にあり、アクティブなポジション/注文数が設定された制限を下回っている場合、ストラテジーは 2 つの対称未決注文を配置します。
- ストップ モード (デフォルト) は、市場の上に買いストップを配置し、市場の下に売りストップを配置します。
- 指値モードは、市場よりも低い買い指値とそれより高い売り指値を設定します。
- Reverse Levels フラグは注文タイプを交換して、元の EA のリバース スイッチを複製します。
- エントリー価格は、Pending Indent パラメーターによって現在のビッド/アスクからオフセットされます。注文が既存のポジションから Min Step 距離よりも近い場合、注文はスキップされます。
- 保留中の注文は、指定された分数後に期限切れになる場合があります。有効期限が切れると、残りの注文はすべてキャンセルされます。
ポジション管理
- 注文が約定されると、戦略は対応するサイドの平均エントリー価格と出来高を追跡します。反対の約定は、新しいポジションをオープンする前に、既存のポジションを減らすかクローズします。
- この戦略は、価格が次のいずれかの条件に達したときにロング ポジションを終了します。
- 価格は平均エントリー価格を下回るストップロス距離に達します。
- 価格は平均エントリー価格を上回る利益確定距離に達します。
- トレーリングストップは、利益が有効化しきい値を超えた後に有効化され、その後価格がトレーリングレベルに戻ります(段階的に移動します)。
- ショートトレードでは、価格を反転したミラールールを使用します。
- Only One Position が有効になっている場合、エンジンは現在のエクスポージャーがクローズされるまで待機してから、新しい未決注文が発注されます。
パラメーター
| 名前 |
説明 |
StopLossPoints |
保護ストップロスまでの距離 (ポイント単位) (0 は無効にします)。 |
TakeProfitPoints |
テイクプロフィットターゲットまでの距離 (ポイント単位) (0 は無効にします)。 |
MaxPositions |
同時にアクティブなポジションと未決注文の最大数。 |
MinStepPoints |
既存の取引のエントリー価格と新しい未決注文の間の最小距離。 |
TrailingActivatePoints |
トレーリングストップを有効にする利益のしきい値 (0 はトレーリングを無効にします)。 |
TrailingStopPoints |
有効化された後の市場価格とトレーリングストップの間の距離。 |
TrailingStepPoints |
トレーリングストップを再度移動させるために必要な最低価格改善。 |
TradeMode |
新しい未決注文に許可される方向: Buy、Sell、または BuySell。 |
PendingType |
発注する未決注文のタイプ: Stop または Limit。 |
PendingExpirationMinutes |
保留中の注文の存続期間 (分単位) (0 は手動で約定またはキャンセルされるまで保持されます)。 |
PendingIndentPoints |
未決注文価格の計算に使用される現在のビッド/アスクからのオフセット。 |
PendingMaxSpreadPoints |
未決注文を出すための買値と売値の間の最大許容スプレッド (0 はフィルタを無効にします)。 |
OnlyOnePosition |
true の場合、現在のポジションがクローズされるまで新しい取引を開始できなくなります。 |
ReverseLevels |
買い注文と売り注文の配置を交換して、元の EA のリバース モードを反映します。 |
CandleType |
信号評価をトリガーするために使用される時間枠 (デフォルトでは毎日)。 |
注意事項
- 価格距離はポイントで表され、自動的に商品ティックサイズに変換されます。
- この戦略は、注文の登録に StockSharp ヘルパー メソッド (
BuyStop、SellStop、BuyLimit、SellLimit) を使用し、新しい決定が行われるたびに書籍をリセットするために CancelActiveOrders を使用します。
- トレーリングストップロジックは、終了したローソク足で評価されます。バー内のトレーリング動作には、より短い
CandleType を使用します。
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "Two pending orders 2" MetaTrader expert.
/// Places symmetric breakout levels around recent range and enters on breakout.
/// Uses high/low of N bars as breakout boundaries.
/// </summary>
public class TwoPendingOrders2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _lookback;
private readonly Queue<decimal> _highs = new();
private readonly Queue<decimal> _lows = new();
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int Lookback
{
get => _lookback.Value;
set => _lookback.Value = value;
}
public TwoPendingOrders2Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for breakout detection", "General");
_lookback = Param(nameof(Lookback), 10)
.SetGreaterThanZero()
.SetDisplay("Lookback", "Number of bars for high/low range", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highs.Clear();
_lows.Clear();
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;
if (_highs.Count < Lookback)
{
EnqueueCandle(candle);
return;
}
decimal highest = decimal.MinValue;
decimal lowest = decimal.MaxValue;
var highs = _highs.ToArray();
var lows = _lows.ToArray();
foreach (var h in highs)
if (h > highest) highest = h;
foreach (var l in lows)
if (l < lowest) lowest = l;
var close = candle.ClosePrice;
var volume = Volume;
if (volume <= 0)
volume = 1;
var range = highest - lowest;
var breakoutPadding = range * 0.05m;
// Breakout above range
if (close > highest + breakoutPadding)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
// Breakout below range
else if (close < lowest - breakoutPadding)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
EnqueueCandle(candle);
}
private void EnqueueCandle(ICandleMessage candle)
{
_highs.Enqueue(candle.HighPrice);
_lows.Enqueue(candle.LowPrice);
if (_highs.Count > Lookback)
{
_highs.Dequeue();
_lows.Dequeue();
}
}
/// <inheritdoc />
protected override void OnReseted()
{
_highs.Clear();
_lows.Clear();
base.OnReseted();
}
}
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 two_pending_orders2_strategy(Strategy):
def __init__(self):
super(two_pending_orders2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._lookback = self.Param("Lookback", 10)
self._highs = []
self._lows = []
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def Lookback(self):
return self._lookback.Value
@Lookback.setter
def Lookback(self, value):
self._lookback.Value = value
def OnReseted(self):
super(two_pending_orders2_strategy, self).OnReseted()
self._highs = []
self._lows = []
def OnStarted2(self, time):
super(two_pending_orders2_strategy, self).OnStarted2(time)
self._highs = []
self._lows = []
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
lookback = self.Lookback
if len(self._highs) < lookback:
self._enqueue_candle(candle)
return
highest = max(self._highs)
lowest = min(self._lows)
close = float(candle.ClosePrice)
range_val = highest - lowest
breakout_padding = range_val * 0.05
if close > highest + breakout_padding:
if self.Position <= 0:
self.BuyMarket()
elif close < lowest - breakout_padding:
if self.Position >= 0:
self.SellMarket()
self._enqueue_candle(candle)
def _enqueue_candle(self, candle):
self._highs.append(float(candle.HighPrice))
self._lows.append(float(candle.LowPrice))
lookback = self.Lookback
while len(self._highs) > lookback:
self._highs.pop(0)
self._lows.pop(0)
def CreateClone(self):
return two_pending_orders2_strategy()