GitHub で見る
3100 すべてのポジションを決済する
概要
- MQL5ユーティリティClose all positionsをStockSharpの高レベル戦略に変換します。
- 設定された時間軸の完了ローソク足を監視し、割り当てられたポートフォリオ内のすべてのオープンポジションの浮動利益を累積します。
- 浮動利益が閾値以上になると、ブックが完全に閉じるまで戦略(子戦略を含む)が管理するすべての証券をフラットにするために成行注文が送られます。
_closeAllRequestedフラグはMQL変数m_close_allを反映し、ポジションが残らなくなるまでエグジット注文が継続して発行されます。
パラメーター
| 名前 |
型 |
デフォルト |
説明 |
ProfitThreshold |
decimal |
10 |
戦略がすべてのオープンポジションをフラットにする前に必要な浮動利益(口座通貨)。EAのInpProfitを反映します。 |
CandleType |
DataType |
1m時間軸 |
"新しいバー"の瞬間を定義するローソク足シリーズ。利益チェックはローソク足が完了したときにのみ実行され、元のPrevBarsロジックをエミュレートします。 |
トレードロジック
- 戦略は
CandleTypeのローソク足をサブスクライブし、EAが新しいバーでのみ利益を評価したのと同様に、完了したバーのみを処理します。
- 各完了バーで、ヘルパー
CalculateTotalProfitはPortfolio.CurrentProfit(コミッションとスワップを含む浮動PnL)を取得します。アダプターがこの値を提供できない場合、個々のポジションPnL値の合計にフォールバックします。
- 計算された浮動利益が
ProfitThresholdを下回る場合、何も起こりません。
- 利益が閾値に達するとすぐに、
_closeAllRequestedがtrueに設定され、CloseAllPositions()がすぐに実行されます。
CloseAllPositions()はポートフォリオまたはネストされた戦略でエクスポージャーを持つすべての証券を収集し、現在のボリュームの反対方向に成行注文を送ります(ロング→売り、ショート→買い)。
_closeAllRequestedフラグはHasAnyOpenPosition()がポートフォリオがフラットであることを検出するまで設定されたままになり、m_close_allがすべてのチケットが閉じられるまで真のままだったMQLの動作に一致します。
追加の注意事項
- C#実装のみが提供されます;Pythonフォルダーはタスク要件に従って意図的に空のままにされています。
- 元のスクリプトが成行ポジションのみを閉じたため、戦略は保留注文をキャンセルしません。
- 必要に応じてDesignerオプティマイザーを通じて代替の利益目標を探るために、
ProfitThresholdにSetOptimizeを使用します。
ファイル
CS/CloseAllPositionsStrategy.cs
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Opens positions based on SMA trend and closes when floating PnL reaches a profit threshold.
/// Simplified from the "Close all positions" utility expert.
/// </summary>
public class CloseAllPositionsStrategy : Strategy
{
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private SimpleMovingAverage _sma;
private decimal _entryPrice;
private decimal _prevSma;
private int _cooldown;
/// <summary>
/// SMA period for entry signals.
/// </summary>
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.Value = value;
}
/// <summary>
/// Stop-loss distance in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take-profit distance in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public CloseAllPositionsStrategy()
{
_smaPeriod = Param(nameof(SmaPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "Moving average period for entry signals", "Indicators");
_stopLossPoints = Param(nameof(StopLossPoints), 200)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 300)
.SetNotNegative()
.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_sma = null;
_entryPrice = 0;
_prevSma = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_sma = new SimpleMovingAverage { Length = SmaPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_sma, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_sma.IsFormed)
{
_prevSma = smaValue;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevSma = smaValue;
return;
}
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
// Check SL/TP
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 60;
_prevSma = smaValue;
return;
}
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 60;
_prevSma = smaValue;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 60;
_prevSma = smaValue;
return;
}
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 60;
_prevSma = smaValue;
return;
}
}
// Crossover entry: price crosses above SMA -> buy
if (close > smaValue && candle.OpenPrice <= _prevSma && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = close;
_cooldown = 60;
}
// Price crosses below SMA -> sell
else if (close < smaValue && candle.OpenPrice >= _prevSma && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = close;
_cooldown = 60;
}
_prevSma = smaValue;
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class close_all_positions_strategy(Strategy):
"""
Opens positions based on SMA trend and closes when SL/TP reached.
"""
def __init__(self):
super(close_all_positions_strategy, self).__init__()
self._sma_period = self.Param("SmaPeriod", 100) \
.SetDisplay("SMA Period", "Moving average period for entry signals", "Indicators")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 300) \
.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk")
self._entry_price = 0.0
self._prev_sma = 0.0
self._cooldown = 0
@property
def candle_type(self):
return DataType.TimeFrame(TimeSpan.FromMinutes(5))
def OnReseted(self):
super(close_all_positions_strategy, self).OnReseted()
self._entry_price = 0.0
self._prev_sma = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(close_all_positions_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = self._sma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def on_process(self, candle, sma_val):
if candle.State != CandleStates.Finished:
return
if self._prev_sma == 0.0:
self._prev_sma = sma_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_sma = sma_val
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
step = 1.0
if self.Security is not None and self.Security.PriceStep is not None and float(self.Security.PriceStep) > 0:
step = float(self.Security.PriceStep)
if self.Position > 0 and self._entry_price > 0:
if self._stop_loss_points.Value > 0 and close <= self._entry_price - self._stop_loss_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_sma = sma_val
return
if self._take_profit_points.Value > 0 and close >= self._entry_price + self._take_profit_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_sma = sma_val
return
elif self.Position < 0 and self._entry_price > 0:
if self._stop_loss_points.Value > 0 and close >= self._entry_price + self._stop_loss_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_sma = sma_val
return
if self._take_profit_points.Value > 0 and close <= self._entry_price - self._take_profit_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_sma = sma_val
return
if close > sma_val and open_price <= self._prev_sma and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 60
elif close < sma_val and open_price >= self._prev_sma and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 60
self._prev_sma = sma_val
def CreateClone(self):
return close_all_positions_strategy()