我学Python的目的很明确,就是量化交易。从一开始就有关注vn.py,但我学的是Python3,那时vn.py还处于版本1.x时期,所以只能望vn.py兴叹。
vn.py 2.0出来之后我并没有及时注意,等反应过来已经是2.0.7版。很兴奋,认真研究,并将心得写成《vn.py 2.0.7源代码深入分析》,分享在vn.py社区的经验分享板块。
出于对量化交易的爱好,出于对Python在量化交易中作用的认同,一定程度受vn.py强大功能的鼓舞,我与同事合写了《Python量化交易从入门到实战》一书,对vn.py的讨论是其中很重要的一部分内容。
后续又写了《vn.py 2.1.4源代码深入分析》和《vn.py 2.2.0源代码深入分析》两个文档,感谢各位老师的认可。
vn.py 3.0.0版发布于2022-03-23,这是我一直期待的一个版本,所以它刚一推出,我就立刻开始试用,并着手整理《vn.py 3.0.0源代码深入分析》。夜以继日,终于在前天完成。先发到了书籍的资源群中,接受了两天批评,现分享到此处。
写作本文档的一个主要目的是对vn.py的开源精神做出一点支持,希望本文档能够对大家学习使用vn.py有所帮助。
百度网盘链接:https://pan.baidu.com/s/1cl2MA9hNFhHlxfHM0gGe2A
提取码:s7u6
发布于VeighNa社区公众号【vnpy-community】
原文作者:VeighNa小助手 | 发布时间:2025-09-07
去年【社区活动尊享卡】的受欢迎程度大幅超出我们的预期,为了保证每场社区活动的交流质量,尊享卡已经变更为仅对部分专业交易员用户定向提供。对于参加活动较多的同学强烈推荐!购买请扫描二维码添加小助手咨询:
最近,我们注意到社区和论坛中,有越来越多Mac用户在咨询VeighNa的安装与使用问题。考虑到国内量化交易的相关生态(尤其是API接口方面),一般并不推荐初学者将Mac作为首选平台。为了解决大家的困扰,我们决定举办一场专题社区活动,并提供一份详尽的Mac版快速上手教程,旨在帮助Mac用户扫清障碍,顺利入门VeighNa。
本次活动将于9月20日(周六)下午2:00至5:00在上海举办。普通报名仅支持线下参会,尊享卡持有者和Elite会员可通过线上直播参与。活动具体地址将在微信群中公布,请在报名成功后扫码加入社区活动群,以便获取相关信息!
搭建Mac量化交易环境
a. Mac系统在量化领域的主要优缺点
b. 安装配置Python 3.13版本
c. 使用uv来实现虚拟环境的管理
d. 各种常用开发工具的准备
在Mac上完成API接口编译
a. 安装VeighNa 4.0核心框架
b. Mac上目前支持的交易接口一览
c. CTP接口的Mac版本区别处理
d. 准备XCode编译器(C++)
e. vnpy_ctp接口模块编译安装
Mac上的进阶量化应用案例
a. 使用Mac完成期货穿透式测试
b. 基于Docker的VeighNa运行方案
c. 虚拟机的选择:Parallel Desktop
闭门交流环节
时间:9月20日 14:00-17:00
地点:上海(具体地址后续在微信群中通知)
报名费:99元(Elite会员免费参加)
报名方式:扫描下方二维码报名(报名后请扫码加入社区活动微信群获取参会地址)
一、提前下载需要的安装包:
1、Miniconda3
https://docs.conda.io/en/latest/miniconda.html#
选择MacOSX installers里的最新版本,这里是Python 3.9下载。
2、pycharm
pycharm-community-2020.3.3.dmg
从官网上下载社区版https://www.jetbrains.com/pycharm/
3、vnpy安装包(解压后,复制文件夹到自己喜欢的位置)
从vnpy在gitee的官方地址下载最新的安装包,采用zip格式下载。
https://gitee.com/vnpy/vnpy
二、安装
1、安装Miniconda,这里是Miniconda3-latest-MacOSX-x86_64.pkg
2、添加国内源:
添加国内源:在当前用户下,编辑.condarc,内容如下:
channels:
3、创建虚拟环境
conda create -n py37_vnpy python=3.7
conda activate py37_vnpy
(退出:conda deactivate)
4、安装python.app
conda install -c conda-forge python.app
可能会因为网络问题不成功,多试几次。
5、安装pycharm-community-2020.3.3.dmg
从官网上下载社区版https://www.jetbrains.com/pycharm/
7、打开vnpy所在的文件夹,进行配置
点击‘PyCharm’菜单->Preferences菜单->Project:vnpy一级菜单->Python Interpreter二级菜单->点击右上齿轮->Add菜单->Conda Environment->Existing enviroment->Interpreter:/opy/miniconda3/envs/py37_vnpy/bin/pythonw(选择前面新建的虚拟环境的pythonw)->点OK->点OK->点OK
8、(确认在PyCharm里已经打开了vnpy项目),在PyCharm的底部,找到Terminal的标签,点击,进入py37_vnpy环境的终端,并且当前路径位于vnpy项目的文件夹。
执行以下的安装语句(requirements.txt是vnpy项目文件夹下面的一个文件),这个安装时间比较长,需要较好的网络。
pip install -r requirements.txt -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
9、创建run.py文件,复制以下代码,来源 README.md
from vnpy.event import EventEngine
from vnpy.trader.engine import MainEngine
from vnpy.trader.ui import MainWindow, create_qapp
from vnpy.app.cta_strategy import CtaStrategyApp
from vnpy.app.cta_backtester import CtaBacktesterApp
def main():
"""Start VN Trader"""
qapp = create_qapp()
event_engine = EventEngine()
main_engine = MainEngine(event_engine)
# main_engine.add_gateway(CtpGateway)
main_engine.add_app(CtaStrategyApp)
main_engine.add_app(CtaBacktesterApp)
main_window = MainWindow(main_engine, event_engine)
main_window.showMaximized()
qapp.exec()
if name == "main":
main()
10、运行 python run.py,注意环境名称是 py37_vnpy
0.修改OrderData如下:
@dataclass
class OrderData(BaseData):
"""
Order data contains information for tracking lastest status
of a specific order.
"""
symbol: str
exchange: Exchange
orderid: str
type: OrderType = OrderType.LIMIT
direction: Direction = Direction.NET
offset: Offset = Offset.NONE
price: float = 0
volume: float = 0
traded: float = 0
status: Status = Status.SUBMITTING
datetime: datetime = None
cancel_time: str = ""
def __post_init__(self):
""""""
self.vt_symbol = f"{self.symbol}_{self.exchange.value}/{self.gateway_name}"
self.vt_orderid = f"{self.gateway_name}_{self.orderid}"
#未成交量
self.untrade = self.volume - self.traded
1.策略init初始化参数
#状态控制初始化
self.chase_long_trigger = False
self.chase_sell_trigger = False
self.chase_short_trigger = False
self.chase_cover_trigger = False
self.cancel_status = False
self.last_vt_orderid = ""
self.long_trade_volume = 0
self.short_trade_volume = 0
self.sell_trade_volume = 0
self.cover_trade_volume = 0
self.chase_interval = 10 #拆单间隔:秒
2.on_tick里面的代码如下
from vnpy.trader.object import TickData, BarData, TradeData, OrderData,Status
def __init__(self, strategy_engine: StrategyEngine, strategy_name: str,vt_symbols: List[str], setting: dict):
"""
"""
super().__init__(strategy_engine, strategy_name, vt_symbols, setting)
#撤单条件选择,默认使用超时撤单,为False使用突破价格范围撤单
self.cancel_timer_trigger = True
def on_tick(self, tick: TickData):
active_orders = self.get_position_detail(chase_vt_symbol).active_orders
vt_orderid = ""
if active_orders:
#委托完成状态
order_finished = False
self.last_vt_orderid = list(active_orders.items())[0][0] #委托单vt_orderid
active_order:OrderData = list(active_orders.items())[0][1] #委托单类
if self.cancel_timer_trigger:
#撤单触发条件,超时撤单
trigger_status = (raw_tick.datetime - active_order.datetime).total_seconds() > self.chase_interval
else:
price_tick = self.get_contract_detail(chase_vt_symbol).price_tick
#突破价格范围撤单
trigger_status = not active_order.price - price_tick * self.cancel_trigger_payup <= raw_tick.last_price <= active_order.price + price_tick * self.cancel_trigger_payup
#开平仓追单,部分交易没有平仓指令(Offset.NONE)
if active_order.offset in (Offset.NONE,Offset.OPEN):
if active_order.direction == Direction.LONG:
self.long_trade_volume = active_order.untrade
if trigger_status and self.long_trade_volume > 0 and (not self.chase_long_trigger) and self.last_vt_orderid:
#撤销之前发出的未成交订单
self.cancel_order(self.last_vt_orderid)
self.chase_long_trigger = True
elif active_order.direction == Direction.SHORT:
self.short_trade_volume = active_order.untrade
if trigger_status and self.short_trade_volume > 0 and (not self.chase_short_trigger) and self.last_vt_orderid:
self.cancel_order(self.last_vt_orderid)
self.chase_short_trigger = True
#平仓追单
elif active_order.offset in (Offset.CLOSE,Offset.CLOSETODAY,Offset.CLOSEYESTERDAY):
if active_order.direction == Direction.SHORT:
self.sell_trade_volume = active_order.untrade
if trigger_status and self.sell_trade_volume > 0 and (not self.chase_sell_trigger) and self.last_vt_orderid:
self.cancel_order(self.last_vt_orderid)
self.chase_sell_trigger = True
if active_order.direction == Direction.LONG:
self.cover_trade_volume = active_order.untrade
if trigger_status and self.cover_trade_volume > 0 and (not self.chase_cover_trigger) and self.last_vt_orderid:
self.cancel_order(self.last_vt_orderid)
self.chase_cover_trigger = True
else:
order_finished = True
self.cancel_status = False
#追单的委托单状态是正常的撤销状态则发出追单指令
if self.get_order(self.last_vt_orderid) and self.get_order(self.last_vt_orderid).status == Status.CANCELLED:
if self.chase_long_trigger:
if order_finished:
self.buy(chase_vt_symbol,raw_tick.ask_price_1,self.long_trade_volume)
self.long_trade_volume = 0
self.chase_long_trigger = False
else:
self.cancel_surplus_order(list(active_orders))
elif self.chase_short_trigger:
if order_finished:
self.short(chase_vt_symbol,raw_tick.bid_price_1,self.short_trade_volume)
self.short_trade_volume = 0
self.chase_short_trigger = False
else:
self.cancel_surplus_order(list(active_orders))
elif self.chase_sell_trigger:
if order_finished:
self.sell(chase_vt_symbol,raw_tick.bid_price_1,self.sell_trade_volume)
self.sell_trade_volume = 0
self.chase_sell_trigger = False
else:
self.cancel_surplus_order(list(active_orders))
elif self.chase_cover_trigger:
if order_finished:
self.cover(chase_vt_symbol,raw_tick.ask_price_1,self.cover_trade_volume)
self.cover_trade_volume = 0
self.chase_cover_trigger = False
else:
self.cancel_surplus_order(list(active_orders))
#------------------------------------------------------------------------------------
def cancel_surplus_order(self,orderids:list):
"""
撤销剩余活动委托单
"""
if not self.cancel_status:
for vt_orderid in orderids:
self.cancel_order(vt_orderid)
self.cancel_status = True
# template.py里面增加
#------------------------------------------------------------------
def get_order(self,vt_orderid:str) -> Union[OrderData,None]:
"""
通过vt_orderid获取委托单
"""
return self.cta_engine.get_order(vt_orderid)
# cta_strategy\engine.py里面增加
#------------------------------------------------------------------------------------
def get_order(self,vt_orderid:str) -> Union[OrderData,None]:
"""
通过vt_orderid获取委托单
"""
self.main_engine.get_order(vt_orderid)
耗时2个多月和迅投团队配合测试对接,VeighNa框架的迅投研数据服务的接口vnpy_xt正式上线,支持股票、期货、期权、基金等历史量价数据的获取。
迅投为VeighNa社区提供了专属的试用申请链接:https://xuntou.net/#/signup?utm_source=vnpy
注册申请后即可获取14天的免费试用,目前数据流量上限较高,推荐有需要的同学不要错过!!!(在有效期内多下载一些数据)
整体使用流程如下:
使用过程中遇到任何问题可以通过社区论坛寻投研专区提问交流:https://www.vnpy.com/forum/forum/35-xun-tou-yan
问题1:
同样的bar为什么在一个函数里是5分钟K线,又在另一个函数里是10分钟K线呢?
def on_5min_bar(self, bar: BarData):
am = self.am
am.update_bar(bar) 为什么这里的bar是5分钟呢?
def on_10min_bar(self, bar: BarData):
am = self.am
am.update_bar(bar) 为什么这里的bar是10分钟呢?
以下AI的回答:
这个问题涉及到金融市场的数据处理,尤其是在使用不同时间框架的K线数据进行交易策略开发时常见。在你提供的代码片段中,on_5min_bar和on_10min_bar函数分别处理不同时间周期的K线数据。原因在于
虽然他们的内部逻辑(如更新数据、进行计算等)可能相似或相同,但是这两个函数被设计用来响应特定的时间间隔的数据更新(一个是5分钟,一个是10分钟),所以会出你所说的情况。
如何区分5分钟和10分钟K线
触发机制: 这些函数通常由不同的触发事件调用。例如,在一个交易系统中,可能有一个计时器或监听器,
当5分钟K线数据更新时,触发on_5min_bar函数,此时bar就是5分钟K线;
当10分钟K线数据更新时,触发on_10min_bar函数,此时bar就是10分钟K线。
数据源: 每个函数接收的bar参数代表一个特定时间段的K线数据。这个数据通常是由市场数据提供商按照不同的时间间隔生成并发送的,例如每5分钟或每10分钟更新一次。
代码结构
函数定义: 你的函数on_5min_bar和on_10min_bar通过名称就已经隐含了它们处理的是不同时间框架的数据。
数据处理: 函数内部,调用am.update_bar(bar)实际上是将传入的bar数据(无论是5分钟还是10分钟的数据)更新到某个数据管理系统(如am)中。这里am可能是一个累积/聚合数据的类实例,用于进一步的数据分析或交易信号生成。
实际应用
在实际应用中,确保正确的数据被送到正确的处理函数是很重要的,通常需要在数据传入系统之前就对其进行正确的分类和调度。这样的设计允许策略开发者针对不同的数据粒度制定不同的交易逻辑和管理策略。
总结来说,每个函数处理的K线时间长度由触发这些函数的事件决定,这些事件依据K线数据的生成频率来区分。
另一回答:
在交易策略或回测系统中,不同的K线周期(如1分钟、5分钟、10分钟等)通常是通过不同的回调函数或处理函数来处理的。在您提供的代码片段中,on_5min_bar 和 on_10min_bar 函数分别处理5分钟和10分钟的K线数据。
这里的 bar 之所以在 on_5min_bar 函数中是5分钟K线,在 on_10min_bar 函数中是10分钟K线,是因为这些函数是分别设计用来处理相应周期的K线数据的。通常,这样的设计是通过某种机制(可能是内部的事件驱动或回调函数注册)来实现的,该机制在特定周期的K线数据准备好时调用相应的处理函数。
例如,在vn.py这样的量化交易框架中,您可能会设置一个BarGenerator来监听实时数据流或历史数据,并根据设置的周期(如5分钟或10分钟)来生成不同周期的K线数据。当5分钟K线完成时,on_5min_bar 函数会被调用,并传入这个5分钟的K线数据。同理,当10分钟K线完成时,on_10min_bar 函数会被调用,并传入这个10分钟的K线数据。
简单来说,不同的回调函数处理不同周期的K线数据,是因为它们在设计时就被指定用来处理特定周期的K线。在您的策略代码中,您应该已经定义了这些回调函数,并且将它们与相应的K线周期进行了关联。
请注意,这里的 bar 变量只是一个参数,它代表当前处理的K线数据。在不同的函数调用中,传入的 bar 参数值会根据上下文(即当前的K线周期)而有所不同。因此,尽管变量名都是 bar,但它们代表的数据内容和周期是不同的。
发布于VeighNa社区公众号【vnpy-community】
原文作者:VeighNa小助手 | 发布时间:2025-08-11
去年【社区活动尊享卡】的受欢迎程度大幅超出我们的预期,为了保证每场社区活动的交流质量,尊享卡已经变更为仅对部分专业交易员用户定向提供。对于参加活动较多的同学强烈推荐!购买请扫描二维码添加小助手咨询:
8月8日,五家期货交易所联合发布了《程序化交易管理办法》,新规将于2025年10月9日正式实施。 尽管尚有6个月的过渡期,但许多期货公司已提前行动,着手联系客户办理委托协议签署及程序化交易的报备事宜。 我们注意到近期VeighNa社区内关于此事的讨论与疑问也日益增多。 为此计划举办一场社区活动,将我们与期货公司的沟通要点进行梳理,为大家集中答疑解惑。
本次活动将于8月30日(周六)下午2:00至5:00在上海举办。普通报名仅支持线下参会,尊享卡持有者和Elite会员可通过线上直播参与。活动具体地址将在微信群中公布,请在报名成功后扫码加入社区活动群,以便获取相关信息!
监管公告文件解读
a. 两大公告文件
i. 证监会《期货市场程序化交易管理规定(试行)》
ii. 期货交易所《程序化交易管理办法》
b. 监管规定梳理
i. 程序化交易报告管理
ii. 外部系统接入管理
iii. 主机托管和席位管理
iv. 交易行为监控管理
穿透式认证测试细节
a. 穿透式认证中的核心概念
i. 关于AppID和AuthCode
ii. 什么是直连和中继接入
iii. API的测试和生产版本
b. 更加严格的认证测试流程
i. 完整测试流程步骤梳理
ii. 选择合适的测试硬件环境
iii. 交易环节所需的信息采集记录
iv. 测试表格中的填写细节
新规下的VeighNa适配
a. RiskEngine风控引擎扩展
i. 委托撤单相关
ii. 验资验券相关
iii. 交易行为相关
b. 策略开发中的注意事项
i. 优先选择简单化模式
ii. 细粒度挂撤单算法管理
iii. 交易时间段筛选控制
闭门交流环节
时间:8月30日 14:00-17:00
地点:上海(具体地址后续在微信群中通知)
报名费:99元(Elite会员免费参加)
报名方式:扫描下方二维码报名(报名后请扫码加入社区活动微信群获取参会地址)
发布于VeighNa社区公众号【vnpy-community】
原文作者:VeighNa小助手 | 发布时间:2025-07-23
特别说明:本文内容基于我们团队在特定时间点的研究和信息收集。由于技术迭代迅速,部分信息可能存在时效性或未能完全覆盖所有细节。我们非常欢迎并期待来自社区的反馈和讨论,共同完善认知。
AI 正在重塑软件开发的各个环节。当我们讨论 AI 编程时,已不再仅仅局限于代码补全。如今,我们选取了三款具有代表性的工具:Cursor、Gemini CLI 与 Claude Code,它们各自代表了不同的产品理念与技术路径。本文将对它们进行深入的对比分析,以帮助开发者理解其核心差异和独特优势。
产品特点:
产品特点:
产品特点:
生态支持:支持与 VS Code、JetBrains 等多种 IDE 深度集成,提供多层级配置体系。
功能 | Cursor | Gemini CLI | Claude Code |
---|---|---|---|
选区上下文共享 | 原生支持 | 通过选定文件 | 通过插件支持 |
标签页同步 | 完全集成 | 通过选定文件 | 通过插件支持 |
诊断信息共享 | 编辑器内置 | 纯命令行模式 | 通过插件支持 |
快捷键支持 | 多种操作快捷键 | 暂不支持 | 仅有启动快捷键 |
支持的 IDE | Cursor (VS Code) | 基础编辑器支持 | VS Code、JetBrains 系列 |
功能 | Cursor | Gemini CLI | Claude Code |
---|---|---|---|
项目级AI规则 | .cursorrules 或 .cursor/rules/ |
项目级GEMINI.md |
项目级CLAUDE.md |
用户级AI规则 | User Rules | 全局~/.gemini/GEMINI.md + save_memory 命令 |
全局~/.claude/CLAUDE.md + # 快速添加 |
规则执行效果 | 不够稳定 | 较为可靠 | 较为可靠 |
历史对话记录 | @past chats 当前对话中一键引用历史对话 | /chat save/resume 可恢复之前手动保存的对话 |
--resume 开启对话前可选择恢复自动保存的对话 |
理论对比完成后,还是要看看这三款工具在实际工作中的表现。接下来,我们将通过一个简单的 VeighNa 数据导出脚本开发任务,来对比三款工具在同一个编程任务中的生成结果与工作流程。
以下是统一使用的提示词:
作为一名精通VeighNa框架的Python开发专家,请提供一个可以直接运行的Python脚本。
核心任务:
通过调用 'get_database' 函数来创建数据库实例,进而批量导出所有K线数据。
具体要求:
1. 参考实现:
a. 'get_database' 的用法,请参考文件 'E:\github\vnpy\vnpy\trader\database.py'。
b. 数据查询和文件生成的逻辑,请参考当前 'vnpy_datamanager' 插件内的实现。
2. 本地优先:为避免使用网上过时或不兼容的代码,请完全基于本地已有的代码和您对VeighNa框架的理解来完成任务。
3. 运行时输出:脚本执行时,每处理一个数据集,都需要在控制台清晰地打印出其合约代码、时间频率和数据长度。
4. 代码质量:
a. 确保代码风格清晰、可读性好。
b. 优先使用条件判断(如 'if')处理可预见的流程,避免不必要的 'try-except' 语句。
import csv
from pathlib import Path
from vnpy.trader.database import get_database
from vnpy.trader.object import BarData
# 获取数据库实例
db = get_database()
# 获取所有K线数据的概览信息
overviews = db.get_bar_overview()
# 检查导出的数据存放路径
data_path = Path("output_data")
if not data_path.exists():
data_path.mkdir()
# 遍历所有K线数据
for overview in overviews:
# 加载特定K线的全部历史数据
bars: list[BarData] = db.load_bar_data(
symbol=overview.symbol,
exchange=overview.exchange,
interval=overview.interval,
start=overview.start,
end=overview.end
)
# 在控制台打印信息
print(f"合约代码:{overview.symbol}")
print(f"时间频率:{overview.interval.value}")
print(f"数据长度:{len(bars)}")
print("-" * 30)
# 将数据写入到CSV文件中
fieldnames: list = [
"symbol",
"exchange",
"datetime",
"open",
"high",
"low",
"close",
"volume",
"turnover",
"open_interest"
]
filename = (
f"{overview.symbol}_"
f"{overview.exchange.value}_"
f"{overview.interval.value}.csv"
)
file_path: Path = data_path.joinpath(filename)
with open(file_path, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for bar in bars:
d: dict = {
"symbol": bar.symbol,
"exchange": bar.exchange.value,
"datetime": bar.datetime.strftime("%Y-%m-%d %H:%M:%S"),
"open": bar.open_price,
"high": bar.high_price,
"low": bar.low_price,
"close": bar.close_price,
"volume": bar.volume,
"turnover": bar.turnover,
"open_interest": bar.open_interest,
}
writer.writerow(d)
从上图可以看出,Cursor 作为一款 AI 原生 IDE,其优势体现在与编码过程的深度融合上:
@
符号引用代码片段或历史对话,上下文控制灵活直观。# export_all_data.py
import os
import csv
from datetime import datetime
from typing import List
from vnpy.trader.database import get_database, BarOverview
from vnpy.trader.object import BarData
from vnpy.trader.constant import Exchange, Interval
# 创建用于存放导出数据的文件夹
output_folder = "kline_data_exported"
if not os.path.exists(output_folder):
os.makedirs(output_folder)
# 获取数据库实例
# 该函数会自动读取全局配置(通常是 settings.json)来连接数据库
database = get_database()
# 获取所有K线数据的概要信息
overviews: List[BarOverview] = database.get_bar_overview()
print(f"发现 {len(overviews)} 个K线数据集,开始处理...")
print("-" * 60)
# 遍历所有数据集
for overview in overviews:
symbol: str = overview.symbol
exchange: Exchange = overview.exchange
interval: Interval = overview.interval
start: datetime = overview.start
end: datetime = overview.end
# 从数据库加载该合约的全部K线数据
bars: List[BarData] = database.load_bar_data(
symbol=symbol,
exchange=exchange,
interval=interval,
start=start,
end=end
)
data_length = len(bars)
# 检查是否有数据
if not data_length:
print(f"合约: {symbol}, 频率: {interval.value} -> 数据长度为 0, 跳过")
continue
# 打印处理信息
print(f"合约: {symbol}, 频率: {interval.value} -> 正在导出 {data_length} 条数据...")
# 构建CSV文件名和路径
file_name = f"{symbol}_{exchange.value}_{interval.value}.csv"
file_path = os.path.join(output_folder, file_name)
# 定义CSV表头
fieldnames: list = [
"symbol",
"exchange",
"datetime",
"interval",
"open",
"high",
"low",
"close",
"volume",
"turnover",
"open_interest"
]
# 将数据写入CSV文件
with open(file_path, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for bar in bars:
row_data = {
"symbol": bar.symbol,
"exchange": bar.exchange.value,
"datetime": bar.datetime.strftime("%Y-%m-%d %H:%M:%S"),
"interval": bar.interval.value,
"open": bar.open_price,
"high": bar.high_price,
"low": bar.low_price,
"close": bar.close_price,
"volume": bar.volume,
"turnover": bar.turnover,
"open_interest": bar.open_interest,
}
writer.writerow(row_data)
print("-" * 60)
print(f"所有数据导出完成,文件已保存至 '{output_folder}' 文件夹。")
从上图可以看出,Gemini CLI 体现了其作为命令行工具的独特工作流:
#!/usr/bin/env python3
"""
批量导出所有K线数据的Python脚本
基于VeighNa框架的vnpy_datamanager插件实现
"""
import csv
import os
from datetime import datetime
from pathlib import Path
from vnpy.trader.database import BaseDatabase, get_database, BarOverview
from vnpy.trader.constant import Interval, Exchange
from vnpy.trader.object import BarData
def create_export_directory() -> Path:
"""创建导出目录"""
export_dir = Path("exported_kline_data")
export_dir.mkdir(exist_ok=True)
return export_dir
def generate_filename(symbol: str, exchange: Exchange, interval: Interval) -> str:
"""生成导出文件名"""
interval_name_map = {
Interval.MINUTE: "1min",
Interval.HOUR: "1hour",
Interval.DAILY: "1day"
}
interval_suffix = interval_name_map.get(interval, interval.value)
return f"{symbol}_{exchange.value}_{interval_suffix}.csv"
def export_bar_data_to_csv(
database: BaseDatabase,
file_path: str,
symbol: str,
exchange: Exchange,
interval: Interval,
start: datetime,
end: datetime
) -> bool:
"""导出K线数据到CSV文件"""
bars = database.load_bar_data(symbol, exchange, interval, start, end)
if not bars:
print(f" 警告: {symbol}.{exchange.value} {interval.value} 无数据")
return False
fieldnames = [
"symbol",
"exchange",
"datetime",
"open",
"high",
"low",
"close",
"volume",
"turnover",
"open_interest"
]
with open(file_path, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for bar in bars:
data_row = {
"symbol": bar.symbol,
"exchange": bar.exchange.value,
"datetime": bar.datetime.strftime("%Y-%m-%d %H:%M:%S"),
"open": bar.open_price,
"high": bar.high_price,
"low": bar.low_price,
"close": bar.close_price,
"volume": bar.volume,
"turnover": bar.turnover,
"open_interest": bar.open_interest,
}
writer.writerow(data_row)
return True
def main():
"""主函数:批量导出所有K线数据"""
print("=== VeighNa K线数据批量导出工具 ===")
print("正在初始化数据库连接...")
# 获取数据库实例
database: BaseDatabase = get_database()
# 创建导出目录
export_dir = create_export_directory()
print(f"导出目录: {export_dir.absolute()}")
# 获取所有K线数据概览
print("正在获取数据库中的K线数据概览...")
overviews: list[BarOverview] = database.get_bar_overview()
if not overviews:
print("数据库中没有找到任何K线数据")
return
print(f"发现 {len(overviews)} 个数据集")
print("-" * 80)
success_count = 0
failed_count = 0
# 遍历所有数据集进行导出
for i, overview in enumerate(overviews, 1):
# 生成文件名和完整路径
filename = generate_filename(overview.symbol, overview.exchange, overview.interval)
file_path = export_dir / filename
# 输出处理信息
print(f"[{i:3d}/{len(overviews)}] 正在处理: {overview.symbol}.{overview.exchange.value} | "
f"频率: {overview.interval.value} | 数据量: {overview.count:,} 条")
print(f" 时间范围: {overview.start.strftime('%Y-%m-%d %H:%M:%S')} "
f"至 {overview.end.strftime('%Y-%m-%d %H:%M:%S')}")
# 导出数据
success = export_bar_data_to_csv(
database,
str(file_path),
overview.symbol,
overview.exchange,
overview.interval,
overview.start,
overview.end
)
if success:
file_size = os.path.getsize(file_path)
print(f" ✓ 导出成功: {filename} ({file_size:,} 字节)")
success_count += 1
else:
print(f" ✗ 导出失败: {filename}")
failed_count += 1
print()
# 输出汇总信息
print("=" * 80)
print("导出完成!")
print(f"成功导出: {success_count} 个文件")
print(f"导出失败: {failed_count} 个文件")
print(f"导出位置: {export_dir.absolute()}")
if success_count > 0:
print("\n导出的文件列表:")
for file_path in sorted(export_dir.glob("*.csv")):
file_size = os.path.getsize(file_path)
print(f" - {file_path.name} ({file_size:,} 字节)")
if __name__ == "__main__":
main()
从输出过程可以看出,Claude Code 强调的是结构化的任务管理和丰富的工具生态:
TodoWrite
工具将任务分解为清晰的步骤并实时展示进度,让用户对AI的工作状态一目了然。多模态辅助:支持便捷的图片输入,可以直接分析截图中的UI或错误信息,拓宽了交互的维度。
经过前面的详细对比和实战测试,我们对这三款工具有了全面的认识。它们各有千秋,而选择的关键在于开发者的具体需求和工作流偏好。
工具 | 核心优势 |
---|---|
Cursor | AI与IDE的无缝融合体验,强大的实时编码辅助。 |
Gemini CLI | 卓越的长上下文处理能力,高度可定制的开源框架。 |
Claude Code | 完善的工具链生态与结构化任务管理,深度集成主流IDE。 |
Cursor:
Gemini CLI:
Claude Code:
工具 | 成本水平 | 免费额度 |
---|---|---|
Cursor | 中等 | 提供两周免费试用 |
Gemini CLI | 低 | 包含免费层级的 API 调用,新用户可叠加 GCP 试用赠金 |
Claude Code | 高 | 无免费版,需订阅 Pro/Max |
三款工具各有其独特优势,选择应基于具体需求。随着工具的不断发展,未来的功能差距可能会缩小。每款工具都有其独特优势和适用场景,Cursor 更适合需要通过 IDE 实时编写代码的用户,Gemini CLI 适合对长上下文感知和项目安全有高要求的用户,Claude Code 则在 IDE 深度集成和丰富工具链方面表现突出。在实践中,建议开发者还是要根据自己的具体需求和工作方式选择合适的工具,或者考虑组合使用,以达到最佳的开发效率。
入门选手,参考了很多论坛和知乎的官方教程以及解决方案,在MacOS M1 Anaconda虚拟环境下安装成功 VeighNa 3.7.0 。具体功能还未探索,仅限于打开UI界面...
主要参考资料:https://zhuanlan.zhihu.com/p/608546190 和 https://www.vnpy.com/forum/topic/31679-macos-yin-te-er-xin-pian-lao-ban-an-zhuang-veighna-3-6-0-ban-ben-shi-jian-bi-ji
创建新环境,选择python3.10
下载vnpy3.7.0 (download zip并解压):https://github.com/vnpy/vnpy
terminal打开Anaconda vnpy 环境:
conda activate vnpy
安装TA-Lib和NumPy:
brew install ta-lib
pip install ta-lib==0.4.24
pip install numpy
安装vnpy和相关配置:
pip install vnpy
pip install vnpy_ctastrategy vnpy_ctabacktester vnpy_datamanager vnpy_sqlite vnpy_rqdata
相关配置可以根据需求调整上述只为例子包括CTA策略实盘和回测模块,历史数据管理模块,SQLite数据库驱动,RQData数据服务适配器
pip install vnpy_ctp
安装过程中如果出现报错某些依赖库的缺失,可以尝试pip install该依赖库打开run.py所在目录/路径:
cd 具体路径, 如cd /Users/name/Downloads/vnpy-master/vnpy
运行run.py:
python3 run.py
pip install PySide6==6.3.0
上述方法均是本人参考后使用的解决方案,以及中间不小心关了terminal,凭回忆记录了一部分过程,不保证百分百正确,具体情况也可能不一样,仅供参考。
发布于VeighNa社区公众号【vnpy-community】
原文作者:用Python的交易员 | 发布时间:2025-07-19
7月初发布了VeighNa的4.1.0版本,本次更新的主要内容是完成了绝大多数VeighNa开源社区版中的模块移植(接口、应用等),得益于Python 3.13带来的显著性能提升,强烈建议还在使用3.0大版本的用户升级,感受新一代版本带来的性能飞跃。
对于已经安装了VeighNa Studio 4.0版本的用户,可以使用快速更新功能完成自动升级。对于没有安装的用户,请下载\VeighNa Studio-4.1.0**,体验一键安装的量化交易Python发行版,下载链接:
https://download.vnpy.com/veighna_studio-4.1.0.exe
关于Python 3.13具体的性能提升水平,社区里已经有许多同学讨论了,这里借着4.1.0发布的机会,对互联网上的公开资料做个整理。
熟悉Python发展历史的同学可能知道,自3.10版本以来,CPython官方团队在性能优化上投入了巨大的精力,几乎每个新版本都是一次“提速”。下面就来回顾一下这几个版本中和性能相关的核心改动,看看3.13版本对比3.10究竟快了多少。
Python 3.11:革命性的性能飞跃
Python 3.11是“Faster CPython”项目第一个取得丰硕成果的版本,其性能相较于3.10有巨大提升。根据官方文档,Python 3.11在标准基准测试套件上比3.10平均快了1.25倍。
主要改进包括:
a + b
操作,如果a
和b
总是整数,解释器会使用专门处理整数加法的快速指令,大大提高了执行效率。Python 3.12延续了3.11的势头,在现有基础上进行了更多细致的优化。虽然不像3.11那样有革命性的飞跃,但它同样带来了稳固的性能增长。3.12的官方文档中没有提及具体的平均性能提升数字,但根据社区测试的结果,Intel平台上对比3.10的平均提升在5%。
主要改进包括:
Python 3.13继续沿着性能优化的道路前进,根据社区测试的结果,对比3.12的平均性能提升大约是5%(Intel平台)。
这一版本的改进主要集中在:
asyncio
库进行了大量优化,根据基准测试,asyncio
相关任务整体性能提升了\1.19倍**。**unpack_sequence
)、生成器(generators
)等都变得更快。综合来看,从Python 3.10到3.13,CPython的性能经历了持续且显著的增长。通过将各个版本的性能提升进行串联估算 (1.25 1.05 1.05),我们可以得出一个大致的结论:
对于VeighNa用户而言,这意味着策略回测、实盘交易中涉及的大量纯Python计算逻辑(例如信号计算、交易执行、投研分析等)都将运行得更快,从而降低延迟、提升策略执行效率。因此,我们强烈建议使用开源社区版的用户升级到基于Python 3.13的VeighNa 4.1.0版本,来享受这份免费的“性能午餐”。
新增
调整
修复