GitHub で見る
保留中のリミットグリッド戦略(MQL/8147 コンバージョン)
概要
保留制限グリッド戦略は、MetaTrader エキスパートの動作を再現します。
MQL/8147 に保存されています。この戦略は、保留中の指値注文の対称グリッドを構築します。
現在の買値/買値付近。利益を浮かせながらグリッドをアクティブに保ちます
設定された利益目標とドローダウンしきい値の範囲内に留まります。そのうちの 1 つが、
しきい値に違反すると、すべての注文がキャンセルされ、オープンポジションがフラット化され、
新しいアカウント資本をベースラインとして使用してグリッドが再構築されます。
取引ロジック
- レベル 1 データを購読して、最良の買値と売値を追跡します。
- 初めてライブデータを受信したときにアカウントの資産を取得し、次のように保存します。
セッションのベースライン。
LevelsPerSide の売り制限を市場より上に設定し、同じ数の買いを追加します
市場を下回る限界。グリッド レベル間の距離は次によって制御されます。
GridStepPoints が商品価格ステップに変換されました。
- 未決注文が約定されたときに新しい注文を再発行することなく、保留中の注文を保持します。の
グリッドは完全にリセットされた後にのみ再作成されます。
- 変動損益を継続的に監視します。
- 利益が
ProfitTargetCurrency に達したら、すべてのエクスポージャを閉じてリセットします。
- ドローダウンが
MaxDrawdownCurrency を超えた場合は、ブックを平らにしてリセットしてください。
- リセットされるたびに、ベースライン エクイティが再度取得され、グリッドが再構築されます。
最新の買値/売値スナップショットを使用します。
パラメーター
| パラメータ |
説明 |
ProfitTargetCurrency |
グリッドの完全なリセットをトリガーする純利益 (アカウント通貨)。 |
MaxDrawdownCurrency |
すべての露光が終了する前の最大許容浮遊損失。 |
GridStepPoints |
ブローカー ポイントで表される連続するグリッド レベル間の距離。 |
LevelsPerSide |
市場の上下で作成された未決注文の数。 |
OrderVolume |
未決の各指値注文に割り当てられたボリューム。 |
リスク管理
この戦略では、オーダーごとのストップやターゲットは付加されません。代わりに、それを監督します。
合計された損益。 RequestFlatten ヘルパーは保留中の注文をキャンセルし、
成行注文 (ClosePosition 経由) を使用して、オープンなエクスポージャーを削除します。その後
平坦化が完了すると、グリッド状態とベースライン エクイティが配置前にリセットされます。
新しい注文。
注意事項
- 価格は為替を考慮して
Security.ShrinkPrice を通じて正規化されます
価格ステップ。
- MetaTrader の「ポイント」値は、機器
PriceStep を分析することによってエミュレートされます。
4 桁と 5 桁の引用符と一致します。
- この戦略では、グリッド注文の再送信を回避し、
元の専門家は、フラグ変数に依存して、すべてのレベルを一意に保つようにしました。
手動または自動リセットが発生します。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class PendingLimitGridStrategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _prevClose;
private decimal _prevMid;
private bool _hasPrev;
private int _barsSinceLastTrade;
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public PendingLimitGridStrategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 24).SetDisplay("Channel Period", "Grid channel lookback", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
_cooldownBars = Param(nameof(CooldownBars), 200).SetDisplay("Cooldown Bars", "Minimum bars between trades", "Risk");
}
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0;
_prevMid = 0;
_hasPrev = false;
_barsSinceLastTrade = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
_barsSinceLastTrade = 0;
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
var mid = (highest + lowest) / 2;
if (!_hasPrev) { _prevClose = close; _prevMid = mid; _hasPrev = true; return; }
_barsSinceLastTrade++;
if (_barsSinceLastTrade >= CooldownBars)
{
if (_prevClose <= _prevMid && close > mid && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_barsSinceLastTrade = 0;
}
else if (_prevClose >= _prevMid && close < mid && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_barsSinceLastTrade = 0;
}
}
_prevClose = close;
_prevMid = mid;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class pending_limit_grid_strategy(Strategy):
def __init__(self):
super(pending_limit_grid_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 24).SetDisplay("Channel Period", "Grid channel lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(pending_limit_grid_strategy, self).OnReseted()
self._has_prev = False
self._prev_close = 0
self._prev_mid = 0
def OnStarted2(self, time):
super(pending_limit_grid_strategy, self).OnStarted2(time)
self._has_prev = False
self._prev_close = 0
self._prev_mid = 0
highest = Highest()
highest.Length = self._channel_period.Value
lowest = Lowest()
lowest.Length = self._channel_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(highest, lowest, self.OnProcess).Start()
def OnProcess(self, candle, highest, lowest):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
mid = (highest + lowest) / 2.0
if not self._has_prev:
self._prev_close = close
self._prev_mid = mid
self._has_prev = True
return
if self._prev_close <= self._prev_mid and close > mid and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_close >= self._prev_mid and close < mid and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_mid = mid
def CreateClone(self):
return pending_limit_grid_strategy()