Auf GitHub ansehen

Exp Fishing-Strategie

Diese Strategie eröffnet eine Position, wenn das Schlusskurs der abgeschlossenen Kerze vom Eröffnungskurs um mindestens Price Step abweicht. Ist die Differenz positiv, wird gekauft; ist sie negativ, wird verkauft.

Nach dem Eröffnen einer Position löst jede zusätzliche Bewegung von Price Step zugunsten des Trades eine weitere Marktorder in dieselbe Richtung aus, bis Max Orders erreicht ist. Für jede Position werden Stop-Loss und Take-Profit mit absoluten Preisabständen angewendet.

Parameter

  • Price Step – minimale Preisbewegung (in absoluten Einheiten) zum Öffnen oder Hinzufügen einer Position.
  • Max Orders – maximale Anzahl erlaubter Marktorders in eine Richtung.
  • Stop Loss – Abstand vom Einstiegspreis, bei dem ein Schutz-Stop gesetzt wird.
  • Take Profit – Abstand vom Einstiegspreis, bei dem das Gewinnziel gesetzt wird.
  • Candle Type – Kerzen-Zeitrahmen für Berechnungen (Standard: 1 Minute).

Handelslogik

  1. Auf eine abgeschlossene Kerze warten.
  2. Wenn keine Position offen ist:
    • Kaufen wenn Close - Open >= Price Step.
    • Verkaufen wenn Open - Close >= Price Step.
  3. Wenn eine Position existiert:
    • Wenn der Kurs um Price Step vom letzten Einstieg voranschreitet, eine weitere Order in dieselbe Richtung hinzufügen.
    • Keine weiteren Orders hinzufügen, sobald die Anzahl Max Orders erreicht.
  4. Stop-Loss und Take-Profit werden für jede Order automatisch verwaltet.

Die Strategie ist vom MQL5-Experten "Exp Fishing" adaptiert und demonstriert einen einfachen Grid-artigen Trendfolge-Ansatz.

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>
/// Trend-following strategy that adds to position every time price moves by configured step.
/// Based on MQL5 Exp_Fishing expert.
/// </summary>
public class ExpFishingStrategy : Strategy
{
	private readonly StrategyParam<decimal> _priceStep;
	private readonly StrategyParam<int> _maxOrders;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _entryPrice;
	private int _ordersCount;
	private bool _isLong;

	/// <summary>
	/// Initializes a new instance of <see cref="ExpFishingStrategy"/>.
	/// </summary>
	public ExpFishingStrategy()
	{
		_priceStep = Param(nameof(PriceStep), 300m)
			.SetGreaterThanZero()
			.SetDisplay("Price Step", "Minimum price move to enter or add", "Parameters")
			;

		_maxOrders = Param(nameof(MaxOrders), 10)
			.SetGreaterThanZero()
			.SetDisplay("Max Orders", "Maximum number of orders in one direction", "Parameters")
			;

		_stopLoss = Param(nameof(StopLoss), 1000m)
			.SetGreaterThanZero()
			.SetDisplay("Stop Loss", "Stop loss distance in price units", "Parameters")
			;

		_takeProfit = Param(nameof(TakeProfit), 2000m)
			.SetGreaterThanZero()
			.SetDisplay("Take Profit", "Take profit distance in price units", "Parameters")
			;

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles for analysis", "Parameters");
	}

	/// <summary>
	/// Price move required to open or add position.
	/// </summary>
	public decimal PriceStep
	{
		get => _priceStep.Value;
		set => _priceStep.Value = value;
	}

	/// <summary>
	/// Maximum number of orders in single direction.
	/// </summary>
	public int MaxOrders
	{
		get => _maxOrders.Value;
		set => _maxOrders.Value = value;
	}

	/// <summary>
	/// Stop loss distance in price units.
	/// </summary>
	public decimal StopLoss
	{
		get => _stopLoss.Value;
		set => _stopLoss.Value = value;
	}

	/// <summary>
	/// Take profit distance in price units.
	/// </summary>
	public decimal TakeProfit
	{
		get => _takeProfit.Value;
		set => _takeProfit.Value = value;
	}

	/// <summary>
	/// Candle type used for strategy calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_entryPrice = 0m;
		_ordersCount = 0;
		_isLong = false;
	}

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

		StartProtection(new Unit(TakeProfit, UnitTypes.Absolute), new Unit(StopLoss, UnitTypes.Absolute));

		SubscribeCandles(CandleType)
			.Bind(ProcessCandle)
			.Start();
	}

	private void ProcessCandle(ICandleMessage candle)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var move = candle.ClosePrice - candle.OpenPrice;

		if (Position == 0)
		{
			_ordersCount = 0;

			if (move >= PriceStep)
			{
				BuyMarket();
				_entryPrice = candle.ClosePrice;
				_ordersCount = 1;
				_isLong = true;
			}
			else if (move <= -PriceStep)
			{
				SellMarket();
				_entryPrice = candle.ClosePrice;
				_ordersCount = 1;
				_isLong = false;
			}

			return;
		}

		if (_ordersCount >= MaxOrders)
			return;

		if (_isLong)
		{
			if (candle.ClosePrice - _entryPrice >= PriceStep)
			{
				BuyMarket();
				_entryPrice = candle.ClosePrice;
				_ordersCount++;
			}
		}
		else
		{
			if (_entryPrice - candle.ClosePrice >= PriceStep)
			{
				SellMarket();
				_entryPrice = candle.ClosePrice;
				_ordersCount++;
			}
		}
	}
}