ホーム
/
戦略のサンプル
GitHub で見る
戦略 Basket Close Utility
概要
Basket Close Utility 戦略は、MetaTrader のエキスパート「Basket Close 2」の動作を反映しています。接続されたポートフォリオ内のすべてのオープンポジションの変動損益を継続的に監視します。 When either a configurable profit objective or a loss limit is reached, the strategy sends market orders to flatten all exposures in every instrument involved. Optionally, it can automatically open a small test position whenever the book is flat, which is useful inside backtests for validating that the protection logic works as expected.
パラメーター
名前
説明
LossMode
Chooses whether the loss guard compares percentages or currency values.
LossPercentage
LossMode が Percentage のときに損失出口をトリガーする負の割合のドローダウン (絶対値で表される)。
LossCurrency
LossMode が Currency の場合に決済をトリガーする口座通貨の変動損失。
ProfitMode
利益目標がパーセンテージと通貨値のどちらを比較するかを選択します。
ProfitPercentage
ProfitMode が Percentage のときにすべてのポジションを決済する割合のゲイン。
ProfitCurrency
Floating profit in account currency that closes all positions when ProfitMode is Currency.
CandleType
変動損益の定期的なチェックをトリガーするために使用される時間枠。
EnableTestOrders
有効にすると、オープンなポジションがない場合は常に、戦略は単一の成行買い注文を送信します。
TestOrderVolume
オプションのテスト注文がアクティブな場合に使用される取引サイズ。
取引ロジック
Subscribe to the configured candle series and run the evaluation only when a candle is fully finished, matching the behaviour of the original EA that works on closed bars.
すべてのオープンポジションの変動損益を集計します。ポートフォリオ オブジェクトが合計変動利益を公開する場合、それが使用されます。それ以外の場合、戦略は各ポジションの損益を合計します。
Compute the percentage change relative to the current account balance captured at start-up.
変動損益が設定された制限に違反したときに損失ルーチンをトリガーします。変動損益または利益率が利益目標に達したときに、利益ルーチンをトリガーします。
一度トリガーされると、ポートフォリオ全体のすべてのオープンポジションがクローズされるまで成行注文を送信し続けます。 This includes the main security as well as positions opened by child strategies.
オプションで、ブックがフラットになった後に成行注文を送信して (テスト用に) エクスポージャーを再開します。
注意事項
MetaTrader の専門家は、グラフ上にテキスト情報を表示しました。 In StockSharp the important figures are logged through LogInfo instead.
Swap and commission adjustments from the original script are implicitly included inside the floating PnL reported by the portfolio or individual positions.
割合のしきい値には、戦略の開始時に取得されたアカウント残高が使用されます。資本ベースが大幅に変化する場合は、長時間セッションを実行するときに制限を調整します。
When the optional test order is enabled, the helper order is reissued whenever the previous exposure has been closed by the profit or loss guard.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Basket Close strategy: EMA trend following with profit/loss close thresholds.
/// Enters on EMA direction, closes when accumulated P&L hits target or stop.
/// </summary>
public class BasketCloseStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private decimal _entryPrice;
private bool _wasBullish;
private bool _hasPrevSignal;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public BasketCloseStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0m;
_wasBullish = false;
_hasPrevSignal = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0;
_hasPrevSignal = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
var isBullish = close > emaValue;
if (_hasPrevSignal && isBullish != _wasBullish)
{
if (isBullish && Position <= 0)
{
BuyMarket();
_entryPrice = close;
}
else if (!isBullish && Position >= 0)
{
SellMarket();
_entryPrice = close;
}
}
_wasBullish = isBullish;
_hasPrevSignal = true;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class basket_close_strategy(Strategy):
def __init__(self):
super(basket_close_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._ema_period = self.Param("EmaPeriod", 50) \
.SetDisplay("EMA Period", "EMA period", "Indicators")
self._entry_price = 0.0
self._was_bullish = False
self._has_prev_signal = False
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
@property
def ema_period(self):
return self._ema_period.Value
@ema_period.setter
def ema_period(self, value):
self._ema_period.Value = value
def OnReseted(self):
super(basket_close_strategy, self).OnReseted()
self._entry_price = 0.0
self._was_bullish = False
self._has_prev_signal = False
def OnStarted2(self, time):
super(basket_close_strategy, self).OnStarted2(time)
self._entry_price = 0.0
self._has_prev_signal = False
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
is_bullish = close > ema_value
if self._has_prev_signal and is_bullish != self._was_bullish:
if is_bullish and self.Position <= 0:
self.BuyMarket()
self._entry_price = float(close)
elif not is_bullish and self.Position >= 0:
self.SellMarket()
self._entry_price = float(close)
self._was_bullish = is_bullish
self._has_prev_signal = True
def CreateClone(self):
return basket_close_strategy()