在 GitHub 上查看

重新开仓策略

该策略是 MQL5 示例 Exp_ReOpenPositions 的 StockSharp 版本,用于在当前持仓盈利时再次加仓。

逻辑

  1. 策略启动后先建立初始多头仓位。
  2. 当价格相对上一笔开仓价格上移 ProfitThreshold 点时,再开一笔同方向仓位。
  3. 每次新的开仓都会根据其价格重新计算止损和止盈。
  4. 当价格触及止损或止盈时,全部仓位平仓并重新开始循环。

若第一笔为空头仓位,同样的规则适用。

参数

  • ProfitThreshold – 加仓所需的价格变动点数。
  • MaxPositions – 允许开仓的最大数量。
  • StopLossPoints – 距离开仓价的止损点数。
  • TakeProfitPoints – 距离开仓价的止盈点数。
  • CandleType – 用于处理的K线类型。

说明

该示例为演示目的进行简化,没有实现原始脚本中的资金管理功能。

using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;



/// <summary>
/// Strategy that reopens positions once profit reaches a target in points.
/// </summary>
public class ReOpenPositionsStrategy : Strategy
{
	private readonly StrategyParam<decimal> _profitThreshold;
	private readonly StrategyParam<int> _maxPositions;
	private readonly StrategyParam<decimal> _stopLossPoints;
	private readonly StrategyParam<decimal> _takeProfitPoints;
	private readonly StrategyParam<DataType> _candleType;

	private int _openedCount;
	private decimal _lastEntryPrice;
	private decimal _currentStop;
	private decimal _currentTake;

	public decimal ProfitThreshold
	{
		get => _profitThreshold.Value;
		set => _profitThreshold.Value = value;
	}

	public int MaxPositions
	{
		get => _maxPositions.Value;
		set => _maxPositions.Value = value;
	}

	public decimal StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	public decimal TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public ReOpenPositionsStrategy()
	{
		_profitThreshold = Param(nameof(ProfitThreshold), 300m)
			.SetDisplay("Profit Threshold", "Points to reopen a position", "Parameters");

		_maxPositions = Param(nameof(MaxPositions), 1)
			.SetDisplay("Max Positions", "Maximum number of positions", "Parameters");

		_stopLossPoints = Param(nameof(StopLossPoints), 1000m)
			.SetDisplay("Stop Loss (pts)", "Stop loss distance in points", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 2000m)
			.SetDisplay("Take Profit (pts)", "Take profit distance in points", "Risk");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_openedCount = 0;
		_lastEntryPrice = default;
		_currentStop = default;
		_currentTake = default;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		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;

		var close = candle.ClosePrice;

		if (Position > 0)
		{
			// Check for stop loss or take profit.
			if (close <= _currentStop || close >= _currentTake)
			{
				SellMarket();
				_openedCount = 0;
			}
			else if (_openedCount < MaxPositions && close - _lastEntryPrice >= ProfitThreshold)
			{
				BuyMarket();
				_lastEntryPrice = close;
				_openedCount++;
				_currentStop = _lastEntryPrice - StopLossPoints;
				_currentTake = _lastEntryPrice + TakeProfitPoints;
			}
		}
		else if (Position < 0)
		{
			// Check for stop loss or take profit for short position.
			if (close >= _currentStop || close <= _currentTake)
			{
				BuyMarket();
				_openedCount = 0;
			}
			else if (_openedCount < MaxPositions && _lastEntryPrice - close >= ProfitThreshold)
			{
				SellMarket();
				_lastEntryPrice = close;
				_openedCount++;
				_currentStop = _lastEntryPrice + StopLossPoints;
				_currentTake = _lastEntryPrice - TakeProfitPoints;
			}
		}
		else
		{
			// Open the first position.
			BuyMarket();
			_lastEntryPrice = close;
			_openedCount = 1;
			_currentStop = _lastEntryPrice - StopLossPoints;
			_currentTake = _lastEntryPrice + TakeProfitPoints;
		}
	}
}