GoWind 开源生态GoWind 开源生态
首页
框架
GoWind Admin
GoWind CMS
GoWind IM
GoWind UBA
GoWind IoT
GoWind Toolkit
GoWind Quant
GitHub
首页
框架
GoWind Admin
GoWind CMS
GoWind IM
GoWind UBA
GoWind IoT
GoWind Toolkit
GoWind Quant
GitHub
  • GoWind Quant(非卖品)

    • GoWind Quant
    • 策略研究
    • 技术架构

技术架构

本页面拆解 GoWind Quant 的核心工程实现。所有内容聚焦于架构决策与工程方法,不涉及策略逻辑或业务数据。

一、整体架构

架构设计的三个核心原则:

  1. 事件驱动 —— 所有组件通过事件总线通信,组件之间无直接调用
  2. 回测/实盘同构 —— 策略代码不感知当前是回测还是实盘,差异在引擎层注入
  3. 风控前置 —— 任何订单在离开策略层之前必须经过风控引擎检查

二、事件驱动引擎

为什么用事件驱动

量化交易本质上是复杂事件处理(CEP)。一个策略的决策可能依赖于一连串事件的组合:「价格突破 + 成交量放大 + 订单簿不平衡 + 持仓未超限」。这种场景下,事件驱动架构相比请求-响应模型有天然优势。

事件驱动的核心收益:

  • 回测/实盘一致 —— 回测只需向总线注入历史事件,策略代码无需改动
  • 解耦 —— 策略不关心数据来源,数据源不关心谁在消费
  • 可观测 —— 每个事件都有完整链路,便于事后回放与归因

事件模型

// 事件类型
type EventType int

const (
    TickEvent EventType = iota      // Tick 行情
    BarEvent                        // K 线
    TradeEvent                      // 成交
    OrderEvent                      // 订单状态变更
    TimerEvent                      // 定时器
    RiskEvent                       // 风控触发
    CustomEvent                     // 策略自定义事件
)

// 事件统一结构
type Event struct {
    Type      EventType
    Timestamp time.Time      // 事件原始时间(交易所时间)
    RecvTime  time.Time      // 引擎接收时间(用于延迟统计)
    Source    string         // 事件来源
    Payload   interface{}    // 类型特定的负载
    TraceID   string         // 全链路追踪 ID
}

事件分发

事件分发是性能关键路径 —— 做市策略要求从 Tick 到达到策略响应在微秒级完成。

核心优化手段:

1. 零拷贝

行情数据(订单簿、Tick)通过环形缓冲区 + 偏移量引用传递,避免结构体拷贝:

// 事件分发持有的是 RingBuffer 中的索引
type EventRef struct {
    RingIndex uint64    // 指向 RingBuffer 的槽位
    EventType EventType
}

策略从 RingBuffer 读取数据,不产生拷贝。RingBuffer 的容量按品种数 × 每品种最大深度计算,预分配固定大小。

2. 无锁分发

对于单写多读的场景,使用无锁环形缓冲区(类似 LMAX Disruptor):

每个消费者维护自己的读取游标,互不阻塞。生产者通过 CAS 更新写入游标,消费者通过原子读取游标。

3. 内存池

事件对象本身通过 sync.Pool 复用,避免高频分配导致的 GC 压力:

var eventPool = sync.Pool{
    New: func() interface{} {
        return &Event{}
    },
}

func acquireEvent() *Event {
    return eventPool.Get().(*Event)
}

func releaseEvent(e *Event) {
    e.reset()
    eventPool.Put(e)
}

GC 抖动治理

Go 的 GC 是做市策略的天然敌人。我们的治理策略:

手段目的
零拷贝分发减少关键路径上的对象分配
sync.Pool 复用削减高频对象的分配频率
预分配大 slice行情缓冲区、策略状态数据在启动时一次性分配
GOGC 调优关键策略进程适当提高 GOGC 阈值,减少 GC 频率(代价是内存占用上升)
独立进程隔离做市策略运行在独立进程,不与回测/研究任务共享 GC

三、分布式回测引擎

架构

任务模型

每个回测任务是一个不可变单元:

type BacktestTask struct {
    ID            string            // 任务唯一 ID
    StrategyID    string            // 策略版本
    Params        map[string]float64 // 参数组合
    Symbols       []string           // 交易品种
    StartTime     time.Time
    EndTime       time.Time
    DataResolution Resolution        // Tick / 1s / 1min / Daily
    SlippageModel string             // 滑点模型
    CommissionModel string           // 手续费模型
    InitialCapital float64
    Status        TaskStatus         // PENDING / RUNNING / DONE / FAILED
    WorkerID      string             // 当前执行的 Worker
}

任务幂等性:(StrategyID, Params, Symbols, StartTime, EndTime) 唯一确定结果。协调器在分派前查询 PostgreSQL,已完成的任务不重复执行。

Worker 设计

每个 Worker 是一个独立的事件驱动引擎实例,包含完整的策略运行时:

type BacktestWorker struct {
    engine    *EventEngine     // 事件引擎(与实盘同构)
    replay    *DataReplayer    // 历史数据回放器
    matcher   *SimMatcher      // 撮合模拟器
    risk      *RiskEngine      // 风控引擎
    reporter  *ResultReporter  // 结果上报器
}

func (w *BacktestWorker) Run(task BacktestTask) (*BacktestResult, error) {
    // 1. 加载策略
    strategy := loadStrategy(task.StrategyID, task.Params)

    // 2. 初始化引擎组件(注入模拟实现)
    w.replay.Configure(task.Symbols, task.StartTime, task.EndTime)
    w.matcher.Configure(task.SlippageModel, task.CommissionModel)

    // 3. 启动事件循环
    w.engine.AddStrategy(strategy)
    w.replay.Start()  // 按时间顺序注入历史事件

    // 4. 等待回放完成
    <-w.replay.Done()

    // 5. 汇总结果
    return w.reporter.Summarize(), nil
}

关键设计:Worker 与实盘引擎共享同一套事件分发、策略接口、风控接口的代码,仅在数据来源(回放 vs 实时行情)和撮合(模拟 vs 真实)上有差异。

结果流式回传

传统回测在结束时一次性写入所有结果,对于大规模寻优任务会导致内存压力。我们采用流式增量写入:

事件 N: 资金曲线点 (timestamp, equity, drawdown)
         │
         ▼
    Doris Stream Load (批量微批写入)
         │
         ▼
    Web 仪表盘实时刷新

每个 N 个事件(例如每 1000 个 Tick)将资金曲线增量写入 Doris,协调器可实时监控任意参数组合的回测进展。

四、数据管线

数据分层

PostgreSQL vs Doris 的职责划分

数据类型存储理由
策略元数据、参数、版本PostgreSQL关系型,强一致性,事务
账户、持仓、订单记录PostgreSQL交易数据,绝对不能丢
回测任务、寻优结果汇总PostgreSQL任务调度需要状态机
Tick / K 线 / 因子历史Doris列存 OLAP,海量范围查询
资金曲线明细Doris流式写入 + 实时分析
风控事件、审计日志PostgreSQL合规要求,不可删改

Doris Schema 设计要点

时序数据在 Doris 上的 schema 设计直接影响查询性能。关键决策:

1. 分区与分桶

CREATE TABLE tick_clean (
    trade_date   DATE,
    ts           DATETIME,
    symbol       VARCHAR(32),
    price        DOUBLE,
    volume       BIGINT,
    -- ... 其他字段
)
PARTITION BY RANGE(trade_date) (
    -- 按日分区,便于按日期裁剪
)
DISTRIBUTED BY HASH(symbol) BUCKETS 32
-- 按品种哈希分桶,同一品种数据落同一节点,减少 shuffle
PROPERTIES (
    "dynamic_partition.enable" = "true",
    "dynamic_partition.time_unit" = "DAY",
    "dynamic_partition.start" = "-3650",
    "dynamic_partition.end" = "3",
    "dynamic_partition.replication_num" = "2"
);

2. 物化视图预聚合

-- 从 tick 自动聚合到 1 分钟 K 线
CREATE MATERIALIZED VIEW bar_1min AS
SELECT
    trade_date,
    DATE_TRUNC(ts, 'minute') AS bar_time,
    symbol,
    FIRST(price) AS open,
    MAX(price) AS high,
    MIN(price) AS low,
    LAST(price) AS close,
    SUM(volume) AS volume
FROM tick_clean
GROUP BY trade_date, DATE_TRUNC(ts, 'minute'), symbol;

物化视图让上层策略查询直接读取预聚合的 K 线,无需每次从 Tick 聚合。

数据质量

数据质量是量化系统的根基。错误数据会直接污染回测结果,产生虚假 alpha。

数据质量检查清单:

检查项方法处置
时间戳乱序按 (symbol, ts) 排序后检查丢弃或重排
价格跳变相邻 Tick 价格变动超过 N 个标准差标记异常,人工审核
成交量为负字段约束丢弃
时间段缺失检查交易时段内是否有数据空洞记录缺口,回测时标记为不可成交
跨源不一致同时段多数据源对比以交易所原始数据为准

所有数据质量检查通过独立的质检 Worker 异步执行,结果记录到 PostgreSQL 的 data_quality_log 表。策略在回测时可配置是否使用通过质检的数据子集。

五、策略热更新

目标

实盘运行中的策略不停机更新,是量化系统的进阶能力。我们的需求场景:

  • 参数微调(不改代码)
  • 信号逻辑迭代(改代码)
  • 紧急停止并替换为新版本

实现方案

状态序列化

策略切换的核心是状态移交。策略的内部状态(如趋势判断的中间变量、库存状态)必须可序列化:

type Strategy interface {
    // ...
    Snapshot() ([]byte, error)    // 导出当前状态
    Restore(data []byte) error     // 恢复状态
}

新策略启动时,可选择从旧策略的快照恢复(适用于参数微调),或从零开始初始化(适用于逻辑变更)。

灰度发布

对于多实例运行的策略,支持按比例灰度:

  1. 10% 实例更新到新版本,观察 1 个交易日
  2. 如表现正常,逐步扩大到 50%、100%
  3. 任何阶段出现异常,回滚到旧版本

灰度状态保存在 PostgreSQL 中,引擎重启后不丢失。

六、反哺 GoWind 生态

GoWind Quant 的技术成果并非孤岛,其工程实践已经反哺到 GoWind 生态的其他产品:

量化系统的能力反哺到的产品具体收益
事件驱动引擎IoT 规则引擎复杂事件检测(CEP)的设计范式
分布式任务调度UBA 批量分析任务大规模用户分群的分片调度器
零拷贝事件分发IM WebSocket 网关百万长连接下的内存优化
Doris 时序 schemaIoT 时序数据存储列存表设计与物化视图预聚合
热更新与灰度框架层平滑发布插件热加载与配置热更新
风控前置模式Admin 权限引擎操作前的规则拦截机制

这种内部技术流转是 GoWind 生态的核心优势之一 —— 每个产品线的工程深度都在反哺其他产品,形成正向循环。


  • 返回 GoWind Quant 首页
  • 查看 策略研究
Edit this page
Last Updated:: 6/22/26, 12:03 PM
Contributors: Bobo
Prev
策略研究