Python 策略示例
下面以 SMA 策略为例,演示如何通过源代码创建策略。该示例与通过模块创建算法中使用模块组装的 SMA 策略相似。
本节不介绍 Python 语言结构,也不详细说明作为策略基类的 Strategy,而是重点介绍在 Designer 中使用代码时需要注意的特性。
- 开始 Python 开发前,需要通过 clr 模块导入 .NET 依赖项。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("K线类型", "用于策略计算的K线类型。", "常规")
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
# 绑定K线集和指标
subscription = self.SubscribeCandles(self.CandleType)
# 将指标绑定到K线并开始处理
subscription.Bind(longSma, shortSma, self.OnProcess).Start()
- 使用图表时需要注意:在 Designer 外部运行策略时,图表对象可能不存在。
# 如果 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):
"""
处理每根已完成的 K 线,记录信息,并在 SMA 交叉时执行交易逻辑。
:param candle: 已处理的 K 线消息。
:param longValue: 长周期 SMA 的当前值。
:param shortValue: 短周期 SMA 的当前值。
"""
self.LogInfo("新K线 {0}: {6} {1};{2};{3};{4}; 成交量 {5}", candle.OpenTime, candle.OpenPrice, candle.HighPrice, candle.LowPrice, candle.ClosePrice, candle.TotalVolume, candle.SecurityId)
# 如果 K线尚未完成,则不执行任何操作
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 创建策略时,必须始终添加此方法。