Пример стратегии на Python
Создание стратегии из исходного кода будет рассмотрено на примере стратегии SMA — аналогичный пример стратегии SMA, собранной из кубиков в пункте Создание алгоритма из кубиков.
Данный раздел не будет описывать конструкции Python языка (как и Strategy, на базе чего создаются стратегии), но будут упомянуты особенности для работы кода в Дизайнере.
Tip
Стратегии, создающиеся в Дизайнере, совместимы со стратегиями, создающимися в API за счет использования общего базового класса Strategy. Это делает запуск таких стратегий вне Дизайнера значительно проще, чем запуск схем из визуального редактора.
- Перед началом разработки на Python необходимо импортировать зависимости .NET через модуль clr, который предоставляется IronPython для взаимодействия с .NET:
import clr
clr.AddReference("System.Drawing")
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
Основные библиотеки, которые требуется подключить:
- Модуль clr - импортируется для обеспечения взаимодействия Python кода с .NET Framework
- System.Drawing - библиотека, необходимая для работы с цветами и графикой
- StockSharp.Messages - содержит основные сообщения и типы данных S#
- StockSharp.Algo - содержит основные алгоритмические компоненты S#, включая базовый класс Strategy
Note
Важно подключать библиотеки в начале файла, до использования любых типов из этих библиотек. После подключения библиотек можно импортировать конкретные типы через обычный Python import.
- Параметры стратегии создаются через специальный подход:
def __init__(self):
super(sma_strategy, self).__init__()
self._isShortLessThenLong = None
# Инициализировать параметры стратегии
self._candleTypeParam = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))) \
.SetDisplay("Тип свечи", "Тип свечи для расчета стратегии.", "Общие")
self._long = self.Param("Long", 80)
self._short = self.Param("Short", 30)
self._takeValue = self.Param("TakeValue", Unit(0, UnitTypes.Absolute))
self._stopValue = self.Param("StopValue", Unit(2, UnitTypes.Percent))
@property
def CandleType(self):
return self._candleTypeParam.Value
@CandleType.setter
def CandleType(self, value):
self._candleTypeParam.Value = value
@property
def Long(self):
return self._long.Value
@Long.setter
def Long(self, value):
self._long.Value = value
@property
def Short(self):
return self._short.Value
@Short.setter
def Short(self, value):
self._short.Value = value
@property
def TakeValue(self):
return self._takeValue.Value
@TakeValue.setter
def TakeValue(self, value):
self._takeValue.Value = value
@property
def StopValue(self):
return self._stopValue.Value
@StopValue.setter
def StopValue(self, value):
self._stopValue.Value = value
При использовании класса StrategyParam автоматически используется подход сохранения и восстановления настроек.
- При создании индикаторов и подписки на маркет-данные необходимо связать их, чтобы поступающие данные из подписки могли обновлять значения индикаторов:
# Создать индикаторы
longSma = SMA()
longSma.Length = self.Long
shortSma = SMA()
shortSma.Length = self.Short
# Связать набор свечей и индикаторы
subscription = self.SubscribeCandles(self.CandleType)
# Связать индикаторы со свечами и запустить обработку
subscription.Bind(longSma, shortSma, self.OnProcess).Start()
- При работе с графиком необходимо учитывать, что в случае запуска стратегии вне Дизайнера объект графика может быть отсутствовать.
# Настроить график, если доступен GUI
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, shortSma, Color.Coral)
self.DrawIndicator(area, longSma)
self.DrawOwnTrades(area)
- Запустить защиту позиций через StartProtection, если такое требует логика стратегии:
self.StartProtection(self.TakeValue, self.StopValue)
- Сама логика стратегии, реализованная в методе OnProcess. Метод вызывается подпиской, созданной на этапе 1:
def OnProcess(self, candle, longValue, shortValue):
"""
Обрабатывает каждую завершенную свечу, логирует информацию и выполняет торговую логику при пересечении SMA.
:param candle: Обработанное сообщение свечи.
:param longValue: Текущее значение длинной SMA.
:param shortValue: Текущее значение короткой SMA.
"""
self.LogInfo("Новая свеча {0}: {6} {1};{2};{3};{4}; объем {5}", candle.OpenTime, candle.OpenPrice, candle.HighPrice, candle.LowPrice, candle.ClosePrice, candle.TotalVolume, candle.SecurityId)
# Если свеча не завершена, ничего не делаем
if candle.State != CandleStates.Finished:
return
# Определить, меньше ли короткая SMA длинной SMA
isShortLessThenLong = shortValue < longValue
if self._isShortLessThenLong is None:
self._isShortLessThenLong = isShortLessThenLong
elif self._isShortLessThenLong != isShortLessThenLong:
# Произошло пересечение
direction = Sides.Sell if isShortLessThenLong else Sides.Buy
# Рассчитать объём для открытия позиции или разворота
volume = self.Volume if self.Position == 0 else Math.Min(Math.Abs(self.Position), self.Volume) * 2
# Получить шаг цены (по умолчанию 1, если не задан)
priceStep = self.GetSecurity().PriceStep or 1
# Рассчитать цену заявки со смещением
price = candle.ClosePrice + (priceStep if direction == Sides.Buy else -priceStep)
if direction == Sides.Buy:
self.BuyLimit(price, volume)
else:
self.SellLimit(price, volume)
# Обновить состояние
self._isShortLessThenLong = isShortLessThenLong
- Обязательным требованием для стратегий на Python является переопределение виртуального метода CreateClone. Этот метод нужен для создания новых экземпляров стратегии, которые требуются для Designer при оптимизации параметров стратегии или при тестировании. Без его переопределения эти операции будут невозможны.
def CreateClone(self):
"""
!! ОБЯЗАТЕЛЬНО!! Создает новый экземпляр стратегии.
"""
return sma_strategy()
Important
Отсутствие переопределения метода CreateClone приведет к невозможности тестирования стратегии на исторических данных или проведения оптимизации параметров. При создании стратегии на Python всегда добавляйте этот метод.