问题描述
解决方案
这是一个基于PTrade量化交易平台的策略代码。该策略主要用于融资融券账户(信用账户),逻辑是轮询当前持仓,当某只股票的浮动盈亏比例达到或超过15%时,执行“卖券还款”操作。
策略说明
- 适用账户:必须是开通了融资融券权限的信用账户。
- 核心逻辑:
- 在
handle_data中遍历当前所有持仓。 - 计算收益率公式:
(当前价格 - 持仓成本) / 持仓成本。 - 如果收益率 $\ge$ 15%,调用
margincash_close函数。
- 在
- 关键函数:
margincash_close(security, amount):这是PTrade中专门用于卖券还款的接口。它会卖出股票,并优先使用卖出的资金偿还融资负债。
策略代码
def initialize(context):
"""
初始化函数,设置全局变量和股票池
"""
# 设置我们要操作的股票池
# 注意:实际实盘中,get_positions会自动获取当前账户持仓,
# 这里设置universe主要是为了确保handle_data能收到行情推送。
# 您可以将关注的股票代码放入列表中,例如 ['600519.SS', '000001.SZ']
g.security = ['600519.SS']
set_universe(g.security)
# 设置止盈阈值,0.15 代表 15%
g.profit_target = 0.15
def handle_data(context, data):
"""
盘中运行函数,根据频率(分钟或日线)周期性执行
"""
# 获取当前账户的所有持仓信息
# context.portfolio.positions 返回的是一个字典,key是股票代码,value是Position对象
positions = context.portfolio.positions
# 遍历所有持仓股票
for security in positions:
# 获取该股票的持仓对象
pos = positions[security]
# 如果可用股份数为0,跳过(可能已经卖出、冻结或无持仓)
if pos.enable_amount <= 0:
continue
# 获取持仓成本价
cost = pos.cost_basis
# 获取当前市场价格
# 优先从data中获取最新行情,如果data中没有(例如停牌),则尝试取持仓快照中的价格
if security in data:
current_price = data[security]['close']
else:
current_price = pos.last_sale_price
# 计算收益率,需确保成本大于0以避免除零错误
if cost > 0:
# 收益率计算公式:(当前价 - 成本价) / 成本价
profit_rate = (current_price - cost) / cost
# 判断是否达到止盈目标 (>= 15%)
if profit_rate >= g.profit_target:
# 记录日志
log.info("股票 %s 达到止盈条件。" % security)
log.info("当前价格: %.2f, 成本价: %.2f, 收益率: %.2f%%" % (current_price, cost, profit_rate * 100))
log.info("执行卖券还款,数量: %d" % pos.enable_amount)
# 执行卖券还款操作
# margincash_close: 卖券还款接口
# 参数1: security 股票代码
# 参数2: amount 数量(这里卖出该股票所有可用持仓)
margincash_close(security, pos.enable_amount)
def before_trading_start(context, data):
"""
盘前处理函数(可选)
"""
pass
def after_trading_end(context, data):
"""
盘后处理函数(可选)
"""
pass
注意事项
- 卖券还款 vs 普通卖出:
- 代码中使用了
margincash_close,这是专门针对融资负债的接口。如果您只是想普通卖出(不优先还款,或者资金转入余额),可以使用order或order_target,但在两融账户中,通常为了减少利息支出,建议使用margincash_close。
- 代码中使用了
- 持仓成本 (
cost_basis):- PTrade 的
cost_basis通常是根据您的买入均价计算的。如果您的券商柜台计算成本的方式(如摊薄成本)与策略端不同,可能会导致收益率计算有细微偏差。
- PTrade 的
- 交易频率:
- 如果在回测或实盘中选择“分钟线”频率,
handle_data会每分钟运行一次,一旦盘中触及15%即刻卖出。 - 如果选择“日线”频率,则会在每日收盘前检测一次。
- 如果在回测或实盘中选择“分钟线”频率,
- Python版本兼容性:
- 代码已遵循 Python 3.5 兼容性规范(使用
%进行字符串格式化,未使用 f-string),可直接在 PTrade 环境中运行。
- 代码已遵循 Python 3.5 兼容性规范(使用
Q&A
Q1: 如果我只想卖出持仓的一半而不是全部,怎么修改?
A1: 将 margincash_close(security, pos.enable_amount) 修改为 margincash_close(security, int(pos.enable_amount * 0.5))。注意需要取整,因为股票交易数量通常需要是整数(且通常为100的倍数,但在清仓或还款时柜台通常允许零股)。
Q2: margincash_close 和 margincash_direct_refund 有什么区别?
A2: margincash_close 是卖券还款,即卖出股票,用卖得的钱还款。margincash_direct_refund 是直接还款,即直接使用账户里的可用现金(Cash)来偿还融资负债,不涉及卖股票的操作。
Q3: 如何在策略中同时设置止损(例如亏损10%卖出)?
A3: 在判断收益率的 if 语句中增加一个 elif 分支即可:
elif profit_rate <= -0.10:
log.info("股票 %s 触发止损,收益率: %.2f%%" % (security, profit_rate * 100))
margincash_close(security, pos.enable_amount)