Пример стратегии на C#

Создание стратегии из исходного кода будет рассмотрено на примере стратегии SMA - аналогичный пример-стратегии SMA, собранной из кубиков в пункте Создание алгоритма из кубиков.

Данный раздел не будет описывать конструкции C# языка (как и Strategy, на базе чего создаются стратегии), но будут упомянуты особенности для работы кода в Дизайнере.

Tip

Стратегии, создающиеся в Дизайнере совместимы со стратегиями, создающиеся в API за счет использования общего базового класса Strategy. Это делает возможность запуска таких стратегий вне Дизайнера значительно проще, чем схем.

  1. Параметры стратегии создаются через специальный подход:
_candleTypeParam = this.Param(nameof(CandleType), DataType.TimeFrame(TimeSpan.FromMinutes(1)));
_long = this.Param(nameof(Long), 80);
_short = this.Param(nameof(Short), 20);


private readonly StrategyParam<DataType> _candleTypeParam;

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

private readonly StrategyParam<int> _long;

public int Long
{
	get => _long.Value;
	set => _long.Value = value;
}

private readonly StrategyParam<int> _short;

public int Short
{
	get => _short.Value;
	set => _short.Value = value;
}

При использовании класса StrategyParam автоматически используется подход сохранения и восстановления настроек.

  1. При создании индикаторов и подписки на маркет-данные необходимо связать их, чтобы поступающие данные из подписки могли обновлять значения индикаторов:
// ---------- создать индикаторы -----------

var longSma = new SMA { Length = Long };
var shortSma = new SMA { Length = Short };

// ----------------------------------------

// --- связать набор свечей и индикаторы ----

var subscription = SubscribeCandles(CandleType);

subscription
	// связать индикаторы со свечами
	.Bind(longSma, shortSma, OnProcess)
	// запустить обработку
	.Start();
  1. При работе с графиком необходимо учитывать, что в случае запуска стратегии вне Дизайнера объект графика может быть отсутствовать.
var area = CreateChartArea();

// area can be null in case of no GUI (strategy hosted in Runner or in own console app)
if (area != null)
{
	DrawCandles(area, subscription);

	DrawIndicator(area, shortSma, System.Drawing.Color.Coral);
	DrawIndicator(area, longSma);

	DrawOwnTrades(area);
}
  1. Запустить защиту позиций через StartProtection, если такое требует логика стратегии:
// запустить защиту по take profit и/или stop loss
StartProtection(TakeValue, StopValue);
  1. Сама логика стратегии, реализованная в методе OnProcess. Метод вызывается подпиской, созданной на этапе 1:
private void OnProcess(ICandleMessage candle, decimal longValue, decimal shortValue)
{
	LogInfo(LocalizedStrings.SmaNewCandleLog, candle.OpenTime, candle.OpenPrice, candle.HighPrice, candle.LowPrice, candle.ClosePrice, candle.TotalVolume, candle.SecurityId);

	// если мы подписались только на незавершённые свечи
	if (candle.State != CandleStates.Finished)
		return;

	// рассчитать новые значения short и long
	var isShortLessThenLong = shortValue < longValue;

	if (_isShortLessThenLong == null)
	{
		_isShortLessThenLong = isShortLessThenLong;
	}
	else if (_isShortLessThenLong != isShortLessThenLong)
	{
		// произошло пересечение

		// if short less than long, the sale, otherwise buy
		var direction = isShortLessThenLong ? Sides.Sell : Sides.Buy;

		// рассчитать размер для открытия позиции или разворота
		var volume = Position == 0 ? Volume : Position.Abs().Min(Volume) * 2;

		var priceStep = GetSecurity().PriceStep ?? 1;

		// рассчитать цену заявки как цену закрытия + смещение
		var price = candle.ClosePrice + (direction == Sides.Buy ? priceStep : -priceStep);

		if (direction == Sides.Buy)
			BuyLimit(price, volume);
		else
			SellLimit(price, volume);

		// сохранить текущие значения short и long
		_isShortLessThenLong = isShortLessThenLong;
	}
}