问题描述
解决方案
在PTrade中,要根据当前账户的总资产来动态决定交易仓位,核心在于获取 context.portfolio.portfolio_value(账户总资产),然后根据你设定的比例计算出目标金额,最后使用 order_target_value 或 order_value 函数进行下单。
以下是具体的实现思路和代码示例。
核心逻辑
- 获取总资产:使用
context.portfolio.portfolio_value。它包含了可用资金加上所有持仓的当前市值。 - 计算目标金额:
目标持仓金额 = 总资产 * 目标百分比。 - 下单执行:
- 如果希望将某只股票的持仓调整到总资产的特定比例(例如始终保持20%),使用
order_target_value。 - 如果希望用总资产的特定比例买入(例如用总资产的10%买入,不考虑已有持仓),使用
order_value。
- 如果希望将某只股票的持仓调整到总资产的特定比例(例如始终保持20%),使用
策略代码示例
下面的策略展示了如何实现**“目标仓位管理”**。假设策略逻辑是:每天检查,始终让 600570.SS 这只股票的持仓市值保持在账户总资产的 20%。
def initialize(context):
# 初始化股票池
g.security = '600570.SS'
set_universe(g.security)
# 设定目标仓位比例 (例如 20%)
g.target_ratio = 0.2
def handle_data(context, data):
# 1. 获取当前账户的总资产 (现金 + 持仓市值)
total_value = context.portfolio.portfolio_value
# 2. 计算该股票的目标持仓市值
# 目标市值 = 总资产 * 目标比例
target_value = total_value * g.target_ratio
# 3. 获取当前该股票的持仓市值(用于日志打印对比,非必须)
position = get_position(g.security)
current_value = position.last_sale_price * position.amount
# 打印日志方便调试
log.info("当前总资产: %.2f, 目标持仓市值: %.2f, 当前持仓市值: %.2f" % (total_value, target_value, current_value))
# 4. 使用 order_target_value 进行调仓
# 该函数会自动计算买入或卖出的差额:
# - 如果当前持仓不足 target_value,系统会自动买入差额
# - 如果当前持仓超过 target_value,系统会自动卖出差额
# - 如果资金不足,系统会尽可能买入
order_target_value(g.security, target_value)
进阶场景:根据信号动态分配仓位
如果你想根据不同的信号强度来决定使用总资产的多少比例,可以参考以下代码:
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
def handle_data(context, data):
# 获取总资产
total_assets = context.portfolio.portfolio_value
# 获取历史收盘价计算均线
close_data = get_history(20, '1d', 'close', g.security)
if len(close_data) < 20:
return
# 提取收盘价数组
closes = close_data['close'].values
ma5 = closes[-5:].mean()
ma20 = closes[-20:].mean()
# 动态决定仓位比例
target_ratio = 0.0
if ma5 > ma20:
# 金叉,激进仓位,占用总资产的 50%
target_ratio = 0.5
log.info("金叉信号,目标仓位调整为 50%")
else:
# 死叉,空仓或低仓位,占用总资产的 0%
target_ratio = 0.0
log.info("死叉信号,目标仓位调整为 0%")
# 计算目标金额
target_value = total_assets * target_ratio
# 执行调仓
order_target_value(g.security, target_value)
注意事项
- 最小交易单位:股票交易通常以100股为单位(一手)。如果计算出的
target_value对应的股数不足100股,或者不是100的整数倍,PTrade会自动向下取整到最近的100股(买入时)或根据剩余资金处理。 - 资金充足性:
order_target_value会尝试达到目标,但如果账户context.portfolio.cash(可用资金)不足以支付买入部分,系统只会买入当前资金能买的最大数量。 - 手续费与滑点:在计算总资产时,并未预扣即将发生的手续费。因此,如果全仓买入(比例设为1.0),可能会因为资金不足扣除手续费而导致下单失败或买入数量略少于预期。建议最大仓位比例设置在
0.98或0.99左右以预留费用。 - Python版本兼容:代码中使用了
%格式化字符串,这是为了兼容 Python 3.5 及以上版本,避免使用 f-string。
Q&A
Q: order_value 和 order_target_value 有什么区别?
A: order_value(stock, 10000) 表示再买入 10000元的股票(增量)。order_target_value(stock, 10000) 表示将该股票的持仓调整为 10000元(存量)。如果是为了控制总仓位比例,通常使用 order_target_value。
Q: 如何获取当前的可用现金而不是总资产?
A: 使用 context.portfolio.cash 可以获取当前账户中未冻结的可用资金。
Q: 如果我想平均买入5只股票,每只占总资产的20%,怎么写?
A: 可以遍历股票列表,对每一只股票调用 order_target_value(stock, context.portfolio.portfolio_value * 0.2)。注意,由于价格波动和手续费,最后一只股票可能因为资金微小差异无法精确买入20%,通常建议设置比例总和略小于1(如每只19.5%)。