Ver en GitHub

Estrategia Geedo

Estrategia basada en el tiempo que compara los precios de apertura de dos barras pasadas en una hora específica. Si la barra más antigua está por encima de la reciente por un umbral, se abre una operación corta. Si la barra reciente está por encima de la más antigua, se abre una operación larga. Cada posición usa stop loss y take profit fijos y se cierra después de un tiempo máximo de mantenimiento.

Detalles

  • Criterios de entrada: A TradeTime comparar precios de apertura de T1 y T2 barras atrás. Si Open[T1] - Open[T2] supera DeltaShort, vender; si Open[T2] - Open[T1] supera DeltaLong, comprar.
  • Largo/Corto: Ambas direcciones.
  • Criterios de salida: Stop loss, take profit o MaxOpenTime horas tras la entrada.
  • Stops: Stop loss y take profit fijos en puntos.
  • Valores predeterminados:
    • TakeProfitLong = 39
    • StopLossLong = 147
    • TakeProfitShort = 15
    • StopLossShort = 6000
    • TradeTime = 18
    • T1 = 6
    • T2 = 2
    • DeltaLong = 6
    • DeltaShort = 21
    • Volume = 0.01
    • MaxOpenTime = 504
  • Filtros:
    • Categoría: Basada en tiempo
    • Dirección: Ambos
    • Indicadores: Ninguno
    • Stops: Fijo
    • Complejidad: Principiante
    • Marco temporal: Intradía (1h)
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Medio
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>
/// Time-based strategy comparing open prices with ATR-based stop/take.
/// </summary>
public class GeedoStrategy : Strategy
{
	private readonly StrategyParam<int> _lookback;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private readonly List<decimal> _openHistory = new();
	private decimal _entryPrice;

	public int Lookback { get => _lookback.Value; set => _lookback.Value = value; }
	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public GeedoStrategy()
	{
		_lookback = Param(nameof(Lookback), 6)
			.SetGreaterThanZero()
			.SetDisplay("Lookback", "Open price lookback bars", "Indicators");
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR period for stops", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_openHistory.Clear();
		_entryPrice = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var atr = new StandardDeviation { Length = AtrPeriod };
		SubscribeCandles(CandleType).Bind(atr, ProcessCandle).Start();
	}

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

		_openHistory.Add(candle.OpenPrice);
		if (_openHistory.Count > Lookback + 1)
			_openHistory.RemoveAt(0);

		if (_openHistory.Count <= Lookback) return;
		if (atrVal <= 0) return;

		var close = candle.ClosePrice;

		// Exit check
		if (Position > 0 && _entryPrice > 0)
		{
			if (close <= _entryPrice - atrVal * 2 || close >= _entryPrice + atrVal * 1.5m)
			{
				SellMarket();
				_entryPrice = 0;
				return;
			}
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (close >= _entryPrice + atrVal * 2 || close <= _entryPrice - atrVal * 1.5m)
			{
				BuyMarket();
				_entryPrice = 0;
				return;
			}
		}

		var pastOpen = _openHistory[0];
		var currentOpen = _openHistory[^1];
		var diff = currentOpen - pastOpen;

		// Price rising => long
		if (diff > atrVal * 0.5m && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_entryPrice = close;
		}
		// Price falling => short
		else if (diff < -atrVal * 0.5m && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_entryPrice = close;
		}
	}
}