程序员量化交易实战 03:量化交易中的核心概念

前两篇做了两件事:先把量化交易放回工程语境,再把 Python 项目骨架搭起来。

从这一篇开始,我们要统一词汇。量化系统里很多词看着熟悉,但如果不落到代码对象,很快就会混在一起:股票池和持仓不是一回事,因子和策略不是一回事,信号和订单也不是一回事。

这一篇的目标很简单:把后面会反复出现的概念翻译成 ZiQuant 里的模型、字段和函数。

股票不是一个字符串

程序里最容易犯的第一个错误,是把股票当成一个字符串。

600519.SH 当然是股票代码,但一个可运行的平台还需要知道它的名称、市场、行业、交易单位和元数据。ZiQuant 里用 Stock 表保存这些主数据:

class Stock(Base):
    __tablename__ = "zi_quant_stocks"

    symbol = mapped_column(String(16), primary_key=True)
    name = mapped_column(String(80), index=True)
    market = mapped_column(String(8), index=True)
    sector = mapped_column(String(80), index=True)
    lot_size = mapped_column(Integer, default=100)
    metadata_json = mapped_column(JSONB, default=dict)

这里的 lot_size=100 不是装饰字段。A 股普通买入按 100 股整数手处理,后面订单检查、回测成交和模拟盘都会用到它。

股票主数据解决的是“这个标的是什么”。它不回答“今天多少钱”,也不回答“该不该买”。

股票池是策略运行范围

股票池不是持仓。

股票池表示策略允许观察和选择的范围。比如公共 A 股 500 股票池,是给策略、因子刷新和推荐接口使用的候选集合;持仓则是某个账户已经买入的股票。

ZiQuant 里用 StockPool 和 StockPoolMember 表达这个关系:

class StockPool(Base):
    __tablename__ = "zi_quant_stock_pools"

    name = mapped_column(String(120), index=True)
    visibility = mapped_column(Enum(Visibility), default=Visibility.private)
    refresh_strategy_id = mapped_column(UUID(as_uuid=True), nullable=True)


class StockPoolMember(Base):
    __tablename__ = "zi_quant_stock_pool_members"

    pool_id = mapped_column(ForeignKey("zi_quant_stock_pools.id"))
    symbol = mapped_column(ForeignKey("zi_quant_stocks.symbol"))
    weight = mapped_column(Float, nullable=True)
    reason = mapped_column(Text, default="")

这层设计的好处是:公共股票池、用户私有股票池、按策略重建的股票池可以共存。后面我们做 500 只 A 股股票池时,会继续完善这部分。

K 线是行情事实,不是策略结论

行情数据通常会以 K 线形式进入系统。日频系统里,最常用的是日 K:开盘价、最高价、最低价、收盘价、成交量、成交额。

ZiQuant 的 MarketBar 表是这样设计的:

class MarketBar(Base):
    __tablename__ = "zi_quant_market_bars"

    symbol = mapped_column(String(16), index=True)
    trade_date = mapped_column(Date, index=True)
    frequency = mapped_column(String(16), default="1d", index=True)
    open = mapped_column(Float)
    high = mapped_column(Float)
    low = mapped_column(Float)
    close = mapped_column(Float)
    volume = mapped_column(Float, default=0)
    amount = mapped_column(Float, default=0)
    source = mapped_column(String(40), default="unknown", index=True)
    payload = mapped_column(JSONB, default=dict)

注意两个字段:source 和 payload

source 用来记录数据来自 QVeris、东方财富、Tushare、同花顺,还是 fallback。payload 用来保留供应商原始字段或清洗信息。后面排查数据问题时,这两个字段会救命。

行情数据只是事实记录。它告诉我们某天发生了什么,不直接告诉我们该不该买。

复权要尽早想清楚

A 股会分红、送股、拆股。价格序列如果不处理复权,很多因子会被历史价格跳变污染。

例如一只股票除权后,价格从 100 变成 50,并不代表真实跌了 50%。如果策略直接用原始价格计算 20 日动量,就可能误判。

本系列前期会先把字段和来源留好,后面接入真实行情时再明确前复权、后复权和不复权的口径。这里先定一个工程原则:同一张行情表不能混入不同价格口径而不标记。供应商返回的复权方式,要进入 payload 或单独字段。

因子不是策略

因子是一个可排序的证据,不是完整决策。

20 日动量可以是因子,ROE 可以是因子,波动率可以是因子,财报质量分也可以是因子。但“动量前 20 名等权买入、每周调仓、跌破止损卖出”才更接近策略。

ZiQuant 里用 FactorDefinition 描述因子定义,用 FactorValue 保存某日某股票的因子值:

class FactorValue(Base):
    __tablename__ = "zi_quant_factor_values"

    factor_id = mapped_column(ForeignKey("zi_quant_factor_definitions.id"))
    symbol = mapped_column(String(16), index=True)
    trade_date = mapped_column(Date, index=True)
    value = mapped_column(Float)
    payload = mapped_column(JSONB, default=dict)

当前项目里已经有一个早期的 compute_factor(),会把 MACD、RSI、动量、波动率和质量分合成一个 FactorRow

row = compute_factor(stock)
print(row.symbol, row.momentum, row.volatility, row.quality, row.score)

这还不是最终策略,只是后续推荐、回测和模拟盘会消费的证据层。

信号不是订单

信号是策略输出的观察结论,订单是账户动作。

这个区分很重要。我们会用 BUY_WATCHHOLD_WATCHRISK_WATCH 这样的名字,而不是直接叫 BUYSELL。原因很简单:系统做的是研究和模拟观察,不做真实下单。

一个信号至少应该包含:

  • 股票代码。
  • 信号类型。
  • 置信度或排序分。
  • 触发原因。
  • 风控提示。
  • 数据来源和交易日期。

类似这样的结构比一句“建议买入”可靠得多:

signal = {
    "symbol": "600519.SH",
    "signal": "BUY_WATCH",
    "score": 0.73,
    "reasons": ["20日动量靠前", "财报质量分较高", "波动率未超限"],
    "risk": {"max_position_pct": 0.10, "paper_trading_only": True},
}

后面推荐工作台、飞书提醒和昨日复盘都会围绕这种结构展开。

持仓、订单和账户要分开

模拟盘里至少有三类对象。

账户是 PaperPortfolio:现金、关联策略、配置。

持仓是 PaperPosition:某只股票持有多少股,平均成本是多少,已实现盈亏是多少。

订单是 PaperOrder:某次纸面买入或卖出的价格、数量、费用、状态和原因。

如果把这三者混成一张表,后面净值曲线、风险检查、复盘都会很痛苦。比如持仓只表示当前状态,订单才是历史流水;账户现金变化也应该能追到具体订单。

回测是一次实验记录

回测不是“跑一个函数得到收益率”。它应该是一条实验记录。

ZiQuant 用 BacktestRun 保存回测参数、区间、初始资金、最终权益和指标:

class BacktestRun(Base):
    __tablename__ = "zi_quant_backtest_runs"

    strategy_id = mapped_column(ForeignKey("zi_quant_strategies.id"), nullable=True)
    stock_pool_id = mapped_column(ForeignKey("zi_quant_stock_pools.id"), nullable=True)
    start_date = mapped_column(Date, index=True)
    end_date = mapped_column(Date, index=True)
    initial_cash = mapped_column(Float, default=100000.0)
    final_equity = mapped_column(Float, default=0)
    metrics = mapped_column(JSONB, default=dict)
    params = mapped_column(JSONB, default=dict)

交易明细则放在 BacktestTrade。这样做是为了以后回答:这次回测为什么赚钱,费用花了多少,哪些股票贡献了收益,哪些交易被涨跌停或成交量限制拒绝。

胜率不等于赚钱

很多人喜欢问策略胜率多少。胜率当然可以看,但它不是唯一指标。

一个策略可能 90% 的交易都赚小钱,剩下 10% 一次亏掉全部利润。另一个策略可能胜率只有 45%,但亏损很小、盈利交易更大,整体仍然赚钱。

所以我们后面会一起看总收益、最大回撤、Sharpe、交易次数、样本外表现和基准对比。单个指标都不够,组合起来才接近策略健康状况。

可运行基础校验

概念统一以后,需要能在代码里找到对应对象。当前统一用这条命令复现第 01-08 篇的基础能力:

uv run python -m scripts.chapter_examples foundation-check

本章对应输出如下:

这里列出的表不是完整 schema,而是概念主线:股票、行情、因子、回测和模拟盘订单。后面的信号链路也不会直接从 signal 变成真实订单,而是经过风险检查后落到 paper order。

本篇实战任务

这一篇不要求新增复杂功能,但要确认当前项目里核心表已经存在。

运行测试:

cd ~/projects/zi-quant-platform
uv run pytest tests/test_services.py -k schema

如果从 GitHub 拉取这一章对应代码:

git clone https://github.com/ax2/zi-quant-platform.git
cd zi-quant-platform
git checkout chapter-03
uv sync --extra dev
uv run pytest tests/test_services.py -k schema

已有测试会检查关键表名:

def test_schema_contains_core_tables():
    names = table_names()
    assert "zi_quant_stocks" in names
    assert "zi_quant_stock_pools" in names
    assert "zi_quant_market_bars" in names
    assert "zi_quant_backtest_runs" in names
    assert "zi_quant_paper_portfolios" in names

如果你从零实现,也可以先补这类测试。它不验证业务正确性,但能保证工程骨架里已经有承载后续业务的对象。

本章更新与代码仓库

本章更新内容:

  • 梳理股票、股票池、K 线、因子、策略、回测和模拟盘这些核心概念。
  • 对应 ZiQuant 里的核心 ORM 表和测试入口。
  • 明确回测应该是一条可追溯的实验记录,而不是一次函数调用。

代码仓库:

https://github.com/ax2/zi-quant-platform

本章代码:

git clone https://github.com/ax2/zi-quant-platform.git
cd zi-quant-platform
git checkout chapter-03
uv sync --extra dev
uv run pytest tests/test_services.py -k schema

本篇小结

这一篇做的是概念对齐。

股票主数据、股票池、K 线、因子、信号、持仓、订单、回测和指标,都应该有清晰边界。边界清楚,后面写数据同步、因子计算和策略回测才不会互相污染。

下一篇进入 A 股交易规则:100 股整数手、T+1、涨跌停、停牌、ST、手续费和印花税。这些规则会直接进入订单检查、回测成交和模拟盘风控。

代码转载自:https://pan.quark.cn/s/8ce4326d996e 对于在 CentOS 7 系统中修改网卡配置文件后无法使设置生效的情况,经过实践验证,可以通过使用 nmcli 命令来进行调整。完成修改之后,需要重新启动虚拟机以使更改生效,这样操作流程即告完成。如果设置仍然无法生效,则表明虚拟机在启动过程中所获取的 IP 地址配置并非针对 eth0,此时可以对其它网卡的配置文件进行修改或将其移除。在 CentOS 7 系统中,网络配置的管理机制与早期版本存在差异,主要体现为采用了 Network Manager 服务来负责网络接口的管理。在某些情形下,尽管修改了 `/etc/sysconfig/network-scripts` 目录下的 `ifcfg-eth0` 文件,但网络配置却未能即时生效。此类问题的发生通常源于 CentOS 7 采用了不同于以往的配置读取方法。接下来将具体阐述如何借助 nmcli 命令来处理这一挑战。 以 root 用户身份登录系统并打开终端界面。nmcli 是 Network Manager 提供的命令行界面工具,它支持在命令行环境下执行网络连接的建立、编辑、查询及管理任务。针对修改 eth0 网卡配置的需求,可以遵循以下步骤进行操作: 1. 导航至 `/etc/sysconfig/network-scripts` 目录: ``` cd /etc/sysconfig/network-scripts ``` 2. 检查该目录内是否存在 `ifcfg-eth0.bak` 文件,该备份文件可能是先前调整配置时遗留下来的,若存在可能造成冲突。若发现该文件,可以选择将其删除: ``` [root@localhost netw...
代码转载自:https://pan.quark.cn/s/46fd08fb879c 网管教程 从入门到精通软件篇 ★一。★详尽的xp修复控制台指令及其应用!!! 放入xp(2000)的光盘,安装时选择R,执行修复! Windows XP(涵盖 Windows 2000)的控制台指令是在系统遭遇某些意外状况时的一种极具效用的诊断、检测以及恢复系统功能的工具。笔者确实一直期望能够将这方面的指令进行归纳,此次由老范辛苦整理了这份极具价值的秘籍。 Bootcfg bootcfg 命令用于启动配置与故障恢复(对大多数计算机而言,即 boot.ini 文件)。 带有特定参数的 bootcfg 命令仅在运用故障恢复控制台时方可使用。能够在命令行界面下运用带有不同参数的 bootcfg 命令。 用法: bootcfg /default 设定默认引导选项。 bootcfg /add 向引导清单中增添 Windows 安装。 bootcfg /rebuild 重复整个 Windows 安装流程并让用户选择需添加的项目。 注意:运用 bootcfg /rebuild 之前,应先借助 bootcfg /copy 命令备份 boot.ini 文件。 bootcfg /scan 探查用于 Windows 安装的全部磁盘并展示结果。 注意:这些结果被静态存储,并用于当前会话。若在当前会话期间磁盘配置发生变动,为获取更新的探查结果,必须先重启计算机,然后再次探查磁盘。 bootcfg /list 列示引导清单中已有的项目。 bootcfg /disableredirect 在启动引导程序中禁用重定向。 bootcfg /redirect [ PortBaudRrate] |[ useBio...
代码下载链接: https://pan.quark.cn/s/fc524f791b68 AA制程,即Active Alignment,被理解为主动对准,是一种用于确定零部件装配中相对位置的方法。在摄像头封装阶段,涉及图像传感器、镜座、马达、镜头、线路板等多个部件的重复组装,而传统的封装设备如CSP及COB等,均是依据设备设定的参数进行零部件的移动装配,因而零部件的叠加误差会逐渐增大,最终在摄像头上表现为拍照最清晰的位置可能偏离画面中心、四边清晰度不均等现象。伴随智能手机和其他高端电子产品的普及,摄像头模组的性能正日益受到重视。高分辨率、卓越的低光表现以及稳定视频输出是现代用户所期望的。在摄像头模组的制造环节,各部件的精准定位对成像质量具有决定性作用。因此,一种名为“AA制程”(Active Alignment)的前沿技术被开发出来,成为摄像头精密对准的核心技术。 AA制程,即Active Alignment,是一种在摄像头封装过程中应用的主动对准方法。该方法在多个组件装配阶段发挥作用,涵盖图像传感器、镜座、马达、镜头和线路板等部件。传统的封装方式,例如CSP(Chip Scale Package)和COB(Chip On Board),依赖于设备预设的参数进行组装,但随着组件数量的增加,误差也会累积,最终影响摄像头的表现。例如在成像质量上可能出现中心位置偏移、四角清晰度不一致等问题。 AA制程技术的核心在于实时监测与主动调整。在组装过程中,它借助先进的检测设备持续监控半成品的状态,并根据实时信息对组装部件进行精确修正,从而显著降低装配误差。通过这种技术,能够确保摄像头模组中各组件的相对位置准确无误,从而使得最终的成像效果更加稳定,特别是在中心区域和四角的清晰度上...
内容概要:本文介绍了一套基于Matlab实现的光子晶体90度弯曲波导的二维时域有限差分法(2D FDTD)仿真代码,旨在通过数值模拟手段深入研究光子晶体波导中的光传播特性。该资源聚焦于电磁场与光子学领域的仿真技术应用,系统实现了FDTD算法在复杂介质结构中的建模过程,涵盖空间网格剖分、时间步进迭代、完美匹配层(UPML)边界条件处理、总场散射场(TFSF)激励源设置、介电常数分布定义及电磁场演化可视化等核心模块,能够有效分析光在90度弯曲波导中的传输效率、模式分布与反射损耗等关键性能指标。; 适合人群:具备电磁场理论基础和Matlab编程能力的研究生、科研人员以及从事光子晶体器件设计与仿真的工程技术人员。; 使用场景及目标:①用于教学演示FDTD方法的基本原理与算法流程,帮助理解麦克斯韦方程的离散化求解过程;②支撑科研工作中对光子晶体弯曲波导结构的传输特性进行仿真分析与性能优化;③作为开发更复杂光子集成器件(如分束器、滤波器)数值仿真工具的基础框架; 阅读建议:建议使用者结合经典FDTD教材(如Taflove著作)深入理解算法理论,并在Matlab环境中逐模块调试代码,重点关注电场与磁场的交替更新过程、UPML吸收边界的设计实现以及TFSF源的引入方式,从而全面提升对时域电磁仿真机制的掌握与应用能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值