Auf GitHub ansehen

GO Risk Managed Strategy

This strategy is a C# port of the original MetaTrader script "GO". It calculates a custom oscillator from moving averages of open, high, low and close prices and uses it to determine market direction.

Strategy Logic

  1. Four moving averages are built using the same period and method for the open, high, low and close series.

  2. The GO value is computed on every finished candle:

    GO = ((MA_close - MA_open) + (MA_high - MA_open) + (MA_low - MA_open) + (MA_close - MA_low) + (MA_close - MA_high)) * Volume

  3. When the GO value becomes positive, all short positions are closed and a new long position is opened.

  4. When the GO value becomes negative, all long positions are closed and a new short position is opened.

  5. Only one trade per bar is allowed. New entries are taken until the total number of open positions reaches Max Positions.

Parameters

  • Risk % – percentage of account equity used to calculate trade volume.
  • Max Positions – maximum number of open positions allowed in one direction.
  • MA Type – type of moving average (SMA, EMA, DEMA, TEMA, WMA, VWMA).
  • MA Period – period for all moving averages.
  • Candle Type – candle series used for indicator calculations.

Notes

The implementation uses the high-level API of StockSharp. It subscribes to candles, binds indicators and draws them on the chart. The trade volume is adjusted according to the specified risk percentage and the security volume limits.

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>
/// GO strategy based on moving averages of open, high, low and close prices.
/// Closes opposite positions when the GO value changes sign.
/// Opens new trades in the direction of the GO value.
/// </summary>
public class GoRiskManagedStrategy : Strategy
{
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private SimpleMovingAverage _openMa;
	private SimpleMovingAverage _closeMa;
	private decimal? _prevGo;

	/// <summary>
	/// Moving average period.
	/// </summary>
	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	/// <summary>
	/// Candle type used for indicators and trading logic.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes <see cref="GoRiskManagedStrategy"/>.
	/// </summary>
	public GoRiskManagedStrategy()
	{
		_maPeriod = Param(nameof(MaPeriod), 10)
			.SetDisplay("MA Period", "Moving average period", "Indicator")
			.SetGreaterThanZero();

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).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();
		_prevGo = null;
	}

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

		_openMa = new SimpleMovingAverage { Length = MaPeriod };
		_closeMa = new SimpleMovingAverage { Length = MaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_closeMa, (candle, close) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				var openResult = _openMa.Process(candle.OpenPrice, candle.CloseTime, true);
				if (!_openMa.IsFormed || !_closeMa.IsFormed)
					return;

				var open = openResult.ToDecimal();
				var go = close - open;

				if (_prevGo is not decimal prevGo)
				{
					_prevGo = go;
					return;
				}

				if (prevGo <= 0m && go > 0m && Position <= 0)
					BuyMarket();
				else if (prevGo >= 0m && go < 0m && Position >= 0)
					SellMarket();

				_prevGo = go;
			})
			.Start();

		StartProtection(
			new Unit(2000m, UnitTypes.Absolute),
			new Unit(1000m, UnitTypes.Absolute));
	}
}