Параметры стратегии
Для настройки стратегии и проведения оптимизации StockSharp предоставляет специальный класс StrategyParam<T>. Параметры стратегии позволяют изменять настройки торгового алгоритма без модификации программного кода, что особенно удобно при переключении между режимами тестирования и реальной торговли. Кроме того, эти параметры используются в процессе оптимизации для автоматического перебора значений и поиска оптимальных настроек стратегии.
В отличие от обычных свойств C#, параметры, созданные с помощью этого класса, автоматически отображаются в визуальных настройках (например, в Дизайнере) и могут использоваться при оптимизации стратегий.
Создание параметров стратегии
Параметры создаются в конструкторе стратегии с помощью метода Strategy.Param:
public class SmaStrategy : Strategy
{
private readonly StrategyParam<int> _longSmaLength;
public int LongSmaLength
{
get => _longSmaLength.Value;
set => _longSmaLength.Value = value;
}
public SmaStrategy()
{
_longSmaLength = Param(nameof(LongSmaLength), 80)
.SetGreaterThanZero()
.SetDisplay("Long SMA length", string.Empty, "Base settings");
}
}
В этом примере создается параметр LongSmaLength
с начальным значением 80, задается валидатор для проверки, что значение будет больше нуля, и устанавливаются настройки отображения в пользовательском интерфейсе.
Методы настройки параметров
Класс StrategyParam<T> предоставляет несколько методов для настройки параметра:
SetDisplay
Метод StrategyParam<T>.SetDisplay задает отображаемое имя, описание и категорию параметра:
_longSmaLength = Param(nameof(LongSmaLength), 80)
.SetDisplay("Long SMA length", "Период длинной скользящей средней", "Основные настройки");
SetValidator
Метод StrategyParam<T>.SetValidator устанавливает валидатор для проверки значения параметра. StockSharp предоставляет ряд предопределенных валидаторов, которые можно использовать для наиболее распространенных задач:
// Проверка, что число больше нуля
_longSmaLength = Param(nameof(LongSmaLength), 80)
.SetValidator(new IntGreaterThanZeroAttribute());
// Проверка, что число не отрицательное
_volume = Param(nameof(Volume), 1)
.SetValidator(new DecimalNotNegativeAttribute());
// Проверка на диапазон значений
_percentage = Param(nameof(Percentage), 50)
.SetValidator(new RangeAttribute(0, 100));
// Проверка на обязательное значение
_security = Param<Security>(nameof(Security))
.SetValidator(new RequiredAttribute());
Для удобства в StrategyParam<T> есть встроенные методы для наиболее распространенных валидаторов:
// Проверка, что число больше нуля
_longSmaLength = Param(nameof(LongSmaLength), 80).SetGreaterThanZero();
// Проверка, что число не отрицательное
_volume = Param(nameof(Volume), 1).SetNotNegative();
// Проверка, что значение NULL или не отрицательное
_interval = Param<TimeSpan?>(nameof(Interval)).SetNullOrNotNegative();
// Установка диапазона значений
_percentage = Param(nameof(Percentage), 50).SetRange(0, 100);
Если встроенных валидаторов недостаточно, вы можете создать свой собственный, унаследовав его от ValidationAttribute:
public class EvenNumberAttribute : ValidationAttribute
{
public EvenNumberAttribute()
: base("Значение должно быть четным числом.")
{
}
public override bool IsValid(object value)
{
if (value is int intValue)
return intValue % 2 == 0;
return false;
}
}
// Использование пользовательского валидатора
_barCount = Param(nameof(BarCount), 10)
.SetValidator(new EvenNumberAttribute());
SetHidden
Метод StrategyParam<T>.SetHidden скрывает параметр в редакторе свойств:
_systemParam = Param(nameof(SystemParam), "value")
.SetHidden(true);
SetBasic
Метод StrategyParam<T>.SetBasic отмечает параметр как базовый, что влияет на его отображение в пользовательском интерфейсе. Базовые параметры отображаются в упрощенном режиме редактора свойств:
_longSmaLength = Param(nameof(LongSmaLength), 80)
.SetBasic(true);
SetReadOnly
Метод StrategyParam<T>.SetReadOnly делает параметр только для чтения:
_calculatedParam = Param(nameof(CalculatedParam), 0)
.SetReadOnly(true);
SetCanOptimize и SetOptimize
Методы StrategyParam<T>.SetCanOptimize и StrategyParam<T>.SetOptimize указывают, может ли параметр использоваться для оптимизации, и задают диапазон значений для оптимизации:
_longSmaLength = Param(nameof(LongSmaLength), 80)
.SetCanOptimize(true)
.SetOptimize(10, 200, 10);
В примере выше параметр будет оптимизироваться в диапазоне от 10 до 200 с шагом 10.
Использование параметров в стратегии
Параметры стратегии используются так же, как обычные свойства:
protected override void OnStarted(DateTimeOffset time)
{
base.OnStarted(time);
_shortSma = new SimpleMovingAverage { Length = ShortSmaLength };
_longSma = new SimpleMovingAverage { Length = LongSmaLength };
// ...
}
Сохранение и загрузка параметров
Значения параметров автоматически сохраняются и загружаются в базовом классе Strategy. При переопределении методов Strategy.Save и Strategy.Load необходимо вызывать методы базового класса:
public override void Save(SettingsStorage settings)
{
base.Save(settings);
// Дополнительная логика сохранения...
}
public override void Load(SettingsStorage settings)
{
base.Load(settings);
// Дополнительная логика загрузки...
}
Пример: Стратегия с несколькими параметрами
Ниже представлен пример стратегии с несколькими параметрами:
public class SmaStrategy : Strategy
{
private readonly StrategyParam<DataType> _series;
private readonly StrategyParam<int> _longSmaLength;
private readonly StrategyParam<int> _shortSmaLength;
public DataType Series
{
get => _series.Value;
set => _series.Value = value;
}
public int LongSmaLength
{
get => _longSmaLength.Value;
set => _longSmaLength.Value = value;
}
public int ShortSmaLength
{
get => _shortSmaLength.Value;
set => _shortSmaLength.Value = value;
}
public SmaStrategy()
{
base.Name = "SMA strategy";
Param("TypeId", GetType().GetTypeName(false)).SetHidden();
_longSmaLength = Param(nameof(LongSmaLength), 80)
.SetGreaterThanZero()
.SetDisplay("Long SMA length", string.Empty, "Base settings")
.SetCanOptimize(true)
.SetOptimize(20, 200, 10);
_shortSmaLength = Param(nameof(ShortSmaLength), 30)
.SetGreaterThanZero()
.SetDisplay("Short SMA length", string.Empty, "Base settings")
.SetCanOptimize(true)
.SetOptimize(5, 50, 5);
_series = Param(nameof(Series), DataType.TimeFrame(TimeSpan.FromMinutes(15)))
.SetDisplay("Series", string.Empty, "Base settings");
}
// ...
}
В данном примере мы создали стратегию на основе пересечения двух скользящих средних с тремя настраиваемыми параметрами:
Series
- тип и таймфрейм данныхLongSmaLength
- период длинной скользящей среднейShortSmaLength
- период короткой скользящей средней
Для двух числовых параметров мы настроили возможность оптимизации с заданными диапазонами.