请教:能否实现手动开仓后,系统自动发出指定价平仓呢?譬如在成交价+1或者-1,指定价,不滑点那种。
我注册了simnow,然后安装了veighna station。我登录交易连接进去之后,完全是懵的。接下来如何实现一步步这个需求呢?有知道的大神吗?谢谢!

请教:能否实现手动开仓后,系统自动发出指定价平仓呢?譬如在成交价+1或者-1,指定价,不滑点那种。
我注册了simnow,然后安装了veighna station。我登录交易连接进去之后,完全是懵的。接下来如何实现一步步这个需求呢?有知道的大神吗?谢谢!

CTA 策略模块会过滤掉非本策略发出的委托和成交,所以 on_trade 回调无法收到手动交易的成交推送。
以下是完整的解决方案:
改用 ScriptTrader 脚本交易模块,通过轮询持仓变化或成交记录来检测手动交易,然后自动挂限价平仓单。
创建文件 auto_exit_script.py:
"""
手动开仓自动平仓脚本
通过轮询持仓变化检测手动交易,自动挂指定价平仓单
"""
import time
from vnpy.trader.constant import Direction
def run(engine):
"""
脚本主函数,由 ScriptTrader 调用
"""
# ==================== 配置参数 ====================
vt_symbol = "rb2505.SHFE" # 修改为你交易的合约
offset_price = 1.0 # 平仓偏移价格(盈利1个点)
check_interval = 1 # 轮询间隔(秒)
# =================================================
# 状态记录
last_positions = {} # 上次持仓状态 {pos_id: volume}
entry_prices = {} # 开仓价格记录 {pos_id: price}
exit_orders = {} # 已挂平仓单记录 {pos_id: order_id}
engine.write_log("=" * 60)
engine.write_log("自动平仓脚本启动")
engine.write_log(f"监控合约: {vt_symbol}")
engine.write_log(f"平仓偏移: {offset_price} 个点")
engine.write_log(f"轮询间隔: {check_interval} 秒")
engine.write_log("=" * 60)
# 主循环
while engine.strategy_active:
try:
# 获取当前持仓
current_positions = get_positions_dict(engine, vt_symbol)
# 检测新开仓(持仓增加或新持仓)
for pos_id, pos in current_positions.items():
last_vol = last_positions.get(pos_id, 0)
if pos.volume > last_vol:
# 发现新开仓或加仓
new_volume = pos.volume - last_vol
entry_price = pos.price # 使用持仓均价作为开仓价
engine.write_log(f"【开仓检测】{pos_id} | "
f"方向: {pos.direction.value} | "
f"数量: {new_volume} | "
f"均价: {entry_price}")
# 计算平仓价格
if pos.direction == Direction.LONG:
# 多头:在更高价格平仓(盈利)
exit_price = entry_price + offset_price
# 发送卖出平仓限价单
order_id = engine.sell(vt_symbol, exit_price, new_volume)
action = "多头平仓"
else:
# 空头:在更低价格平仓(盈利)
exit_price = entry_price - offset_price
# 发送买入平仓限价单
order_id = engine.cover(vt_symbol, exit_price, new_volume)
action = "空头平仓"
engine.write_log(f"【挂单】{action} | "
f"价格: {exit_price} | "
f"数量: {new_volume} | "
f"订单号: {order_id}")
# 记录
entry_prices[pos_id] = entry_price
exit_orders[pos_id] = order_id
# 检测已平仓(持仓减少或清零)
for pos_id in list(last_positions.keys()):
if pos_id not in current_positions:
engine.write_log(f"【持仓清零】{pos_id},清理记录")
entry_prices.pop(pos_id, None)
exit_orders.pop(pos_id, None)
elif current_positions[pos_id].volume < last_positions[pos_id]:
engine.write_log(f"【部分平仓】{pos_id},更新记录")
# 更新状态
last_positions = {k: v.volume for k, v in current_positions.items()}
# 休眠
time.sleep(check_interval)
except Exception as e:
engine.write_log(f"【错误】{e}")
time.sleep(check_interval)
engine.write_log("脚本已停止")
def get_positions_dict(engine, vt_symbol: str) -> dict:
"""
获取指定合约的持仓字典
key: gateway_name + direction
value: PositionData
"""
positions = {}
all_positions = engine.get_all_positions()
if not all_positions:
return positions
for pos in all_positions:
if pos.vt_symbol == vt_symbol:
pos_id = f"{pos.gateway_name}_{pos.direction.value}"
positions[pos_id] = pos
return positions
如果需要在成交瞬间立即挂单,可以轮询成交记录:
"""
基于成交记录的自动平仓脚本
能精确获取每笔成交的价格,立即挂平仓单
"""
import time
def run(engine):
# ==================== 配置参数 ====================
vt_symbol = "rb2505.SHFE"
offset_price = 1.0
check_interval = 0.5 # 成交检测需要更频繁
# =================================================
processed_trades = set() # 已处理的成交ID
engine.write_log("=" * 60)
engine.write_log("自动平仓脚本启动(基于成交记录)")
engine.write_log(f"监控合约: {vt_symbol}")
engine.write_log("=" * 60)
while engine.strategy_active:
try:
# 通过 main_engine 获取所有成交
all_trades = engine.main_engine.get_all_trades()
for trade in all_trades:
# 筛选条件:指定合约、未处理过、开仓成交
if (trade.vt_symbol == vt_symbol and
trade.tradeid not in processed_trades and
trade.offset.value == "开"):
processed_trades.add(trade.tradeid)
engine.write_log(f"【成交检测】"
f"方向: {trade.direction.value} | "
f"价格: {trade.price} | "
f"数量: {trade.volume} | "
f"时间: {trade.datetime}")
# 计算平仓价格并下单
if trade.direction.value == "多":
exit_price = trade.price + offset_price
order_id = engine.sell(vt_symbol, exit_price, trade.volume)
engine.write_log(f"【挂单】多头平仓 | 价格: {exit_price}")
else:
exit_price = trade.price - offset_price
order_id = engine.cover(vt_symbol, exit_price, trade.volume)
engine.write_log(f"【挂单】空头平仓 | 价格: {exit_price}")
time.sleep(check_interval)
except Exception as e:
engine.write_log(f"【错误】{e}")
time.sleep(check_interval)
在 VeighNa Station 中配置 CTP 连接:
| 配置项 | 值 |
|---|---|
| 用户名 | 6位 InvestorID(非手机号) |
| 密码 | 修改后的密码 |
| 经纪商代码 | 9999 |
| 交易服务器 | 182.254.243.31:30001 |
| 行情服务器 | 182.254.243.31:30011 |
| 产品名称 | simnow_client_test |
| 授权编码 | 0000000000000000 |
路径:菜单栏【系统】->【连接CTP】
方法 A:通过 VeighNa Station GUI
vt_setting.json 中启用)auto_exit_script.py方法 B:命令行运行
python -m vnpy_scripttrader auto_exit_script.py
| 对比项 | CTA 策略 | ScriptTrader |
|---|---|---|
| 成交监听 | 只接收本策略成交(过滤外部) | 可轮询所有成交/持仓 |
| 手动交易支持 | ❌ 不支持 | ✅ 支持 |
| 实现方式 | 事件驱动(on_trade) | 主动轮询 |
| 适用场景 | 全自动策略 | 手动+自动辅助 |
代码中使用:
engine.sell(vt_symbol, exit_price, volume) - 限价卖出平仓engine.cover(vt_symbol, exit_price, volume) - 限价买入平仓这些都是限价单(Limit Order),确保以指定价格或更好价格成交,不会产生滑点。
offset_price = 1.0(1个点)offset_price = 10.0(10个点,即1个指数点)exit_price 符合合约的最小变动价位(如螺纹钢是 1,股指是 0.2)通过 ScriptTrader + 轮询检测 的方案,你可以实现:
将代码保存为 .py 文件,在 VeighNa Station 的脚本交易模块中运行即可。