跟量下单算法(Percentage of Volume,POV)(难度:初级)
一、跟量下单算法详解
在算法交易的各种策略中,按执行行为对市场的主动程度,可以将其划分为三类:被动型算法交易、主动型算法交易以及综合型算法交易。 其中,跟量下单(Percentage of Volume, 简称POV)策略被归类为主动型算法交易方法。它通过监测市场成交量的实时变化,动态调整下单节奏,是一种将执行行为与市场活跃度紧密挂钩的策略。
跟量下单(POV)算法的核心思想是:按照市场成交量的一定比例来执行订单。交易者预先设定一个跟量比例(如10%),系统在运行过程中持续获取市场成交量的最新数据,并据此计算当前应执行的交易手数。 例如,当某一时间段内市场成交量新增了500手,设定的比例为10%,那么策略此阶段应成交50手。这种机制可以使策略在市场流动性高时自动加快交易速度,而在流动性较低时放慢执行节奏,从而降低市场冲击和滑点风险。
POV策略的优势较为明显,它能够根据市场的流动性自动调节交易节奏,在流动性充足时迅速完成交易,提升效率;而在市场冷清时则主动减速,降低对盘口的冲击这种“顺势而为”的执行逻辑,使交易行为更加自然,有效提升了执行的隐蔽性和整体质量。 但POV策略也存在一定的局限性。首先,它强依赖市场成交量,在成交量骤降或出现价格急变时,可能会错失最佳交易时机,导致未能及时建仓或平仓。其次,由于严格受限于市场成交量占比,当市场情绪剧烈波动或临近收盘时,其被动性可能导致交易不完全或执行滞后。此外,POV策略的执行路径容易被高频交易者捕捉,在极端市场中存在被“跟单”或“反向打击”的风险,从而降低策略的隐蔽性和执行效率。
二、天勤介绍
天勤平台概述
天勤(TqSdk)是一个由信易科技开发的开源量化交易系统,为期货、期权等衍生品交易提供专业的量化交易解决方案。平台具有以下特 点:
- 丰富的行情数据: 提供所有可交易合约的全部Tick和K线数据,基于内存数据库实现零延迟访问。
- 一站式的解决方案: 从历史数据分析到实盘交易的完整工具链,打通开发、回测、模拟到实盘的全流程。
- 专业的技术支持: 近百个技术指标源码,深度集成pandas和numpy,采用单线程异步模型保证性能。
策略开发流程
- 环境准备
- 安装Python环境(推荐Python 3.6或以上版本)
- 安装tqsdk包:pip install tqsdk
- 注册天勤账户获取访问密钥
- 数据准备
- 订阅近月与远月合约行情
- 获取历史K线或者Tick数据(用于分析与行情推进)
- 策略编写
- 设计信号生成逻辑(基于价差、均值和标准差)
- 编写交易执行模块(开仓、平仓逻辑)
- 实现风险控制措施(止损、资金管理)
- 回测验证
- 设置回测时间区间和初始资金
- 运行策略获取回测结果
- 分析绩效指标(胜率、收益率、夏普率等)
- 策略优化
- 调整参数(标准差倍数、窗口大小等)
- 添加过滤条件(成交量、波动率等)
- 完善风险控制机制
三、跟量下单算法代码实现
本策略POV基于天勤量化交易平台(TqSdk)开发,使用Python语言进行编写。该策略的设计目标是在市场成交量波动的基础上,精细控制下单节奏与手数,从而在控制市场冲击的前提下完成指定规模的成交任务。
从策略设计角度来看,核心在于如何“以量定速”,即通过追踪市场成交量的变化动态调整订单执行频率。为实现这一点,系统需持续采集并比较市场的累计成交量变化,计算新增成交量,并将其乘以预设的比例系数得到应执行的交易手数。随后根据剩余目标手数进行约束,防止过量提交订单。考虑到不同市场条件下的订单需求与滑点控制,本策略允许用户选择“对价”或“挂价”两种报单方式,以适应不同的流动性环境。
策略在整个执行过程中保持一个清晰的状态更新机制:每轮订单提交后,系统等待其成交完成,再更新成交基准量,并进入下一轮判断与执行。该过程既保证了成交控制的准确性,也为后续扩展(如加滑价保护、延迟处理、成交日志记录等)提供了良好的结构基础。
该策略的实现可分为以下四个步骤:
-
设定策略初始参数,包括交易合约代码、方向(买入/卖出)、目标交易总手数、跟量比例,以及报单方式(如“对价”或“挂价”)等。
-
初始化变量并读取当前市场累计成交量作为基准值,同时设置已成交手数为零,用于后续累计与判断。
-
在策略主循环中,实时监控市场成交量的变化,计算成交量的增量部分,并按设定比例计算应挂出的订单手数;随后根据报单类型选择合适价格提交限价单,并等待订单成交。
-
每轮交易完成后更新成交基准和累计成交量,循环执行,直到完成全部目标手数为止。
天勤实现算法代码
#!/usr/bin/env python
# coding=utf-8
__author__ = "Chaos"
from tqsdk import TqApi, TqAuth, TqKq
import math
# === 用户参数 ===
SYMBOL = "SHFE.ag2506" # 交易合约
DIRECTION = "BUY" # "BUY"为买入,"SELL"为卖出
OFFSET = "OPEN" # "OPEN"为开仓,"CLOSE"为平仓,"CLOSETODAY"为平今仓
TOTAL_VOLUME = 30 # 目标总手数
POV_RATIO = 0.1 # 跟量比例(如0.1表示10%)
ORDER_TYPE = "对价" # "对价"为对价报单,"报价"为挂价报单
# === 初始化API ===
acc = TqKq()
api = TqApi(account=acc, auth=TqAuth("快期账号", "快期密码"))
quote = api.get_quote(SYMBOL)
# === 初始化变量 ===
base_volume = quote.volume # 启动时的市场累计成交量
traded_volume = 0 # 已成交手数
last_printed_volume = 0 # 上次打印的成交手数
print(f"POV算法启动,合约: {SYMBOL},目标: {TOTAL_VOLUME}手,方向: {DIRECTION},量比比例: {POV_RATIO*100}%")
try:
while traded_volume < TOTAL_VOLUME:
api.wait_update()
new_volume = quote.volume
delta = new_volume - base_volume
# 计算本轮应下单手数
order_volume = int(math.floor(delta * POV_RATIO))
# 不能超过剩余目标
order_volume = min(order_volume, TOTAL_VOLUME - traded_volume)
if order_volume > 0:
print(f"\n市场成交量: {base_volume} -> {new_volume}手")
print(f"变化量: {delta}手")
print(f"计算下单手数: {delta} * {POV_RATIO} = {order_volume}手")
# 根据报单类型选择价格
if ORDER_TYPE == "对价":
# 对价报单
price = quote.ask_price1 if DIRECTION == "BUY" else quote.bid_price1
else:
# 挂价报单
price = quote.bid_price1 if DIRECTION == "BUY" else quote.ask_price1
order = api.insert_order(
symbol=SYMBOL,
direction=DIRECTION,
offset=OFFSET,
volume=order_volume,
limit_price=price
)
print(f"下单: {order_volume}手,价格: {price},报单类型: {ORDER_TYPE}")
# 记录上一次的状态和剩余量
last_status = order.status
last_volume_left = order.volume_left
# 等待订单状态更新
while order.status == "ALIVE":
api.wait_update()
# 只在状态或剩余量发生变化时打印
if order.status != last_status or order.volume_left != last_volume_left:
print(f"订单状态更新: {order.status}, 剩余量: {order.volume_left}")
last_status = order.status
last_volume_left = order.volume_left
# 检查订单是否出错
if order.is_error:
print(f"下单失败: {order.last_msg}")
break
# 计算实际成交量
actual_trade = order.volume_orign - order.volume_left
if actual_trade > 0:
print(f"本轮成交: {actual_trade}手")
traded_volume += actual_trade
base_volume = new_volume # 更新基准成交量
# 只在成交手数变化时打印进度
if traded_volume > last_printed_volume:
print(f"当前进度: {traded_volume} / {TOTAL_VOLUME}")
last_printed_volume = traded_volume
else:
print(f"订单未成交: {order.last_msg}")
print("POV算法执行完毕")
except Exception as e:
print(f"捕获到异常: {e}")
finally:
api.close()