问题描述
解决方案
在PTrade中实现动态追踪止损(Trailing Stop)策略,核心逻辑是记录持仓后的最高价格,并根据设定的回撤比例(如5%)计算动态止损线。当当前价格跌破该止损线时触发卖出,否则如果价格创新高,则上调止损线。
以下是该策略的详细逻辑与代码实现。
策略逻辑说明
-
初始化 (
initialize):- 设置标的股票。
- 设定回撤阈值(例如 5%)。
- 初始化一个全局变量(如
g.highest_price)用于记录持仓期间出现的最高价。
-
盘中运行 (
handle_data):- 持仓判断: 检查当前是否有持仓。
- 更新最高价: 如果有持仓,对比当前价格与
g.highest_price。如果当前价格更高,则更新g.highest_price。 - 计算止损线:
止损价 = 最高价 * (1 - 回撤阈值)。 - 触发止损: 如果
当前价格 < 止损价,则清仓卖出,并重置最高价变量。 - 开仓逻辑: (为了演示完整性) 如果无持仓,则买入,并将当前价格设为初始最高价。
PTrade 策略代码实现
def initialize(context):
"""
策略初始化函数
"""
# 1. 设置要操作的股票,这里以恒生电子为例
g.security = '600570.SS'
set_universe(g.security)
# 2. 设置追踪止损的回撤比例 (例如 5%)
g.trailing_gap = 0.05
# 3. 用于记录持仓期间的最高价格,初始化为0
g.highest_price = 0
def before_trading_start(context, data):
"""
盘前处理
"""
pass
def handle_data(context, data):
"""
盘中每个时间单位(分钟或日)运行一次
"""
security = g.security
# 获取当前价格
# 注意:data[security] 返回的是 SecurityUnitData 对象
current_price = data[security].close
# 获取当前持仓数量
position = get_position(security)
curr_amount = position.amount
# --- 止损逻辑 (有持仓时执行) ---
if curr_amount > 0:
# 1. 更新持仓期间的最高价
# 如果当前价格大于记录的最高价,或者刚买入尚未记录最高价
if current_price > g.highest_price:
g.highest_price = current_price
log.info("股价创新高,更新最高价为: %.2f" % g.highest_price)
# 2. 计算动态止损线
stop_price = g.highest_price * (1 - g.trailing_gap)
# 3. 判断是否触发止损
if current_price < stop_price:
log.info("触发追踪止损!当前价: %.2f, 历史最高: %.2f, 止损线: %.2f" % (current_price, g.highest_price, stop_price))
# 卖出所有持仓
order_target(security, 0)
# 卖出后重置最高价,以便下次开仓重新计算
g.highest_price = 0
# --- 开仓逻辑 (无持仓时执行,仅作演示用) ---
else:
# 这里简单演示:如果没有持仓就全仓买入
# 实际策略中,这里应该是你的买入信号逻辑(如均线金叉等)
cash = context.portfolio.cash
if cash > 0:
# 买入
order_value(security, cash)
# 买入成交后,立即初始化最高价为当前价格
g.highest_price = current_price
log.info("开仓买入,初始最高价设定为: %.2f" % g.highest_price)
代码关键点解析
-
g.highest_price的维护:- 这是追踪止损的核心。它必须是全局变量(使用
g.前缀),这样它的值才能在不同的handle_data周期之间保存。 - 重要: 每次卖出清仓后,必须将
g.highest_price重置为 0,否则下次买入时会错误地使用旧的(可能很高的)价格作为基准,导致瞬间止损。
- 这是追踪止损的核心。它必须是全局变量(使用
-
止损线计算:
- 公式:
stop_price = g.highest_price * (1 - g.trailing_gap)。 - 这意味着止损线会随着股价上涨而不断上移,锁住利润;但股价下跌时,止损线保持不变。
- 公式:
-
Python 版本兼容性:
- 代码中使用了
%格式化字符串(如"%.2f" % var),这是为了兼容 Python 3.5 及更早版本,避免使用 PTrade 可能不支持的 f-string。
- 代码中使用了
-
API 使用:
get_position(security): 获取持仓对象,通过.amount属性判断是否持有。order_target(security, 0): 这是一个方便的函数,用于将仓位调整为 0(即清仓),无需手动计算要卖多少股。
常见问题 (Q&A)
Q: 这个策略可以在分钟级别回测吗?
A: 可以。如果在 initialize 中设置回测频率为分钟级,handle_data 会每分钟执行一次,这样能更灵敏地捕捉盘中波动进行止损。
Q: 如果我有多个股票,怎么管理最高价?
A: 如果操作多只股票,建议将 g.highest_price 改为一个字典。例如:
# 初始化
g.highest_prices = {}
# 盘中逻辑
if security not in g.highest_prices:
g.highest_prices[security] = current_price
# 更新逻辑
if current_price > g.highest_prices[security]:
g.highest_prices[security] = current_price
Q: 为什么卖出后要重置 g.highest_price = 0?
A: 如果不重置,假设你以 100 元卖出,下次以 80 元买回。如果不重置,系统仍认为最高价是 100 元,止损线可能是 95 元。现价 80 元远低于 95 元,会导致刚买入就立即被卖出。