问题描述
解决方案
这是一个关于香农恶魔 (Shannon's Demon) 策略的 QMT 实现方案。
策略概述
香农恶魔 (Shannon's Demon),也称为固定比例再平衡策略 (Constant Rebalanced Portfolio, CRP),是由信息论之父克劳德·香农提出的投资理论。
- 核心逻辑:将资金在“风险资产”(如股票)和“无风险资产”(如现金)之间保持固定的比例(通常为 50:50)。
- 操作方式:
- 当股票上涨,持仓占比超过 50% 时,卖出部分股票(止盈),将比例调回 50%。
- 当股票下跌,持仓占比低于 50% 时,用现金买入部分股票(补仓),将比例调回 50%。
- 盈利来源:通过不断的“高抛低吸”来捕获资产的波动率收益。即使资产长期价格没有上涨(但在过程中有剧烈波动),该策略理论上也能产生正收益。
QMT 策略实现
在 QMT 中,实现该策略最简便的方法是使用 order_target_percent 函数。该函数会自动计算当前总资产(现金+持仓市值),并根据设定的目标比例自动计算需要买入或卖出的数量。
以下是完整的策略代码:
# -*- coding: gbk -*-
import pandas as pd
def init(ContextInfo):
"""
初始化函数,策略启动时调用一次
"""
# 1. 设置要交易的标的(风险资产)
# 这里以 510300.SH (沪深300ETF) 为例,ETF费率低,适合再平衡策略
ContextInfo.stock_code = '510300.SH'
# 2. 设置目标持仓比例 (Shannon's Demon 通常为 50%)
ContextInfo.target_ratio = 0.5
# 3. 设置资金账号 (请修改为您的实际账号)
ContextInfo.account_id = '6000000000'
ContextInfo.account_type = 'STOCK' # 股票账号
ContextInfo.set_account(ContextInfo.account_id)
# 4. 设置再平衡的频率或时间
# 如果跑日线回测,handlebar 每天都会执行。
# 如果是实盘,可以通过时间控制在尾盘执行。
print("策略初始化完成:香农恶魔 - 目标持仓比例 {:.0%}".format(ContextInfo.target_ratio))
def handlebar(ContextInfo):
"""
行情驱动函数,每根K线调用一次
"""
# 获取当前K线的时间
index = ContextInfo.barpos
realtime = ContextInfo.get_bar_timetag(index)
# --- 过滤逻辑 ---
# 1. 如果不是最后一根K线(回测中),或者实盘中未到收盘时间,可以根据需求跳过
# 这里为了演示简单,假设运行周期为“日线”,则每根Bar代表一天,直接执行再平衡
# 2. 检查标的是否停牌
if ContextInfo.is_suspended_stock(ContextInfo.stock_code):
print(f"标的 {ContextInfo.stock_code} 今日停牌,跳过再平衡")
return
# --- 核心再平衡逻辑 ---
# 使用 order_target_percent 进行目标市值再平衡
# 该函数会自动计算:(账户总资产 * target_ratio) - 当前持仓市值
# 并自动发出买入或卖出指令
# 参数说明:
# stockcode: 标的代码
# percent: 目标仓位比例 (0.5 代表 50%)
# style: 下单选价类型 (这里用最新价 'LATEST')
# price: 价格 (使用最新价时填 -1)
order_target_percent(
ContextInfo.stock_code,
ContextInfo.target_ratio,
"LATEST",
-1,
ContextInfo,
ContextInfo.account_id
)
# --- 打印日志方便调试 ---
# 注意:回测模式下 get_trade_detail_data 可能无法实时获取刚下的单对资金的影响,
# 这里仅打印执行信号
print(f"执行再平衡: {ContextInfo.stock_code} 目标比例调整至 {ContextInfo.target_ratio}")
def stop(ContextInfo):
print("策略停止")
代码详解
-
init初始化:- 定义了风险资产标的(
ContextInfo.stock_code)。 - 定义了核心参数
ContextInfo.target_ratio = 0.5,即 50% 股票 + 50% 现金。 - 绑定了交易账号。
- 定义了风险资产标的(
-
handlebar核心逻辑:order_target_percent:这是 QMT 中实现此类策略的神器。- 假设账户总资产为 100万。
- 如果当前股票市值涨到了 60万(占比60%),目标是 50%(50万)。函数会自动卖出 10万元的股票。
- 如果当前股票市值跌到了 40万(占比40%),目标是 50%(50万)。函数会自动买入 10万元的股票。
- 周期选择:建议在日线周期上运行此策略。如果在分钟线上运行,会导致极其频繁的交易,手续费会吞噬所有利润。
运行建议与注意事项
-
交易成本(关键):
- 香农恶魔策略是典型的“波动率捕获”策略,其最大的敌人是手续费和印花税。
- 如果标的波动不够大,或者再平衡频率过高(例如每分钟都在调仓),交易成本将超过波动带来的收益。
- 建议:使用 ETF(免印花税)作为标的,或者降低再平衡频率(例如每周或每月再平衡,或者设置阈值,仅当比例偏离超过 5% 时才调仓)。
-
回测设置:
- 在 QMT 策略编辑器的“回测参数”中,务必设置真实的手续费率(例如万分之二或万分之三),否则回测结果会严重失真。
- 设置“初始资金”足够大,以便能买入一手标的。
-
阈值再平衡(进阶优化):
- 为了减少磨损,可以不每天强制调仓,而是判断偏离度。
- 例如:只有当持仓比例 > 55% 或 < 45% 时,才触发
order_target_percent。如果需要此功能,可以在handlebar中先获取持仓市值计算比例,判断后再下单。
Q&A
Q: 为什么使用 order_target_percent 而不是手动计算买卖数量?
A: order_target_percent 内部封装了获取总资产、计算目标市值、对比当前持仓、计算差额并取整(按手)下单的逻辑。使用它可以避免手动计算时出现的资金冻结计算错误或手数取整错误,代码更简洁健壮。
Q: 这个策略适合什么行情?
A: 最适合震荡行情(高波动、无明显趋势)。在单边上涨行情中,它会不断止盈,跑输全仓持有;在单边下跌行情中,它会不断补仓,虽然亏损比全仓少,但仍会亏损。
Q: 如何在实盘中仅在收盘前执行?
A: 可以在 handlebar 中加入时间判断:
import datetime
# 将毫秒时间戳转为 datetime 对象
timetag = ContextInfo.get_tick_timetag()
now_time = datetime.datetime.fromtimestamp(timetag / 1000).strftime('%H%M%S')
# 例如只在 14:55:00 到 14:57:00 之间执行一次
if "145500" <= now_time <= "145700":
# 执行逻辑...