本文还有配套的精品资源,点击获取
简介:这个Java开源量化系统覆盖从策略开发到实盘落地的完整流程。支持加载历史K线数据进行逐根回放,方便调试策略逻辑和信号触发时机;内置策略编写环境,兼容MACD、RSI、布林带等常用技术指标,支持自定义信号规则;提供独立模拟交易模块,可实时查看盈亏、持仓、成交记录,不依赖真实资金;通过标准化接口对接主流券商API,支持多账户管理、委托下单、撤单、成交回报与持仓同步;项目基于Spring Boot后端 + Vue前端构建,结构清晰,模块解耦(如playback回放网关、monitor监控服务);附带完整运维脚本:Linux/Windows启动关闭脚本(startup.sh/shutdown.sh/env.sh/env.ps1)、Dockerfile、自动化构建配置(pom.xml)、前端构建配置(vue.config.js、package.等);支持Protobuf协议动态更新(update-protobuf-obj.ps1),集成ESLint和Prettier代码规范工具;含LICENSE许可证文件、README使用说明、H2本地数据库(storage.mv.db)预置示例数据,适合本地快速启动或私有化二次开发。
1. 这不是玩具,是能跑通实盘逻辑的Java量化底座
你有没有试过写完一个双均线金叉策略,却卡在“怎么验证它真能赚钱”这一步?回测平台导出CSV再手动喂数据?模拟盘和实盘用两套完全不同的API封装?改个指标参数就得重启整个服务?我踩过这些坑——三年前自己搭Spring Boot量化框架时,光是把K线回放和订单状态机对齐就调了两周,最后发现根本不是代码问题,而是架构没想清楚:回放、模拟、实盘不该是三个平行世界,而该是同一套引擎在不同“运行模式”下的切换。这套叫NorthStar(北极星)的开源项目,就是我们团队把三年实盘打磨出来的经验,全揉进了Java生态里。它不玩花哨的AI预测,也不堆砌上百种冷门指标,核心就干四件事:用真实K线一帧一帧跑策略(回放)、在零风险环境里看盈亏曲线(模拟)、把策略无缝推到券商柜台下单(实盘)、让整套系统在你笔记本上三分钟启动(Docker)。关键词里的“Java量化”不是指用Java写了点工具类——它是从Netty通信层、MyBatis动态SQL生成、Vue响应式策略编辑器,到H2嵌入式数据库事务隔离级别,全部用Java生态原生方案扎扎实实垒起来的;“策略回放”不是简单播放CSV,而是把Tick级行情按交易所撮合规则重演,连滑点、委托队列排队都模拟;“模拟交易”模块自带资金/仓位/手续费三重校验,成交价不是随便取个均价,而是按当前盘口最优五档真实撮合;“实盘对接”抽象出统一的BrokerAdapter接口,中信、华泰、国君的SDK只要实现几个方法就能接入;“Docker部署”更不是扔个Dockerfile了事——它把JVM参数调优、日志滚动策略、数据库连接池预热、前端静态资源CDN fallback路径,全写进docker-compose.yml的environment字段里。如果你正被Python量化库的GIL锁住多线程回放速度,或被JavaScript策略引擎的调试断点折磨得睡不着,这个项目就是给你准备的:它不用你学新语言,不强迫你改交易习惯,只提供一条从写第一行if (ma5 > ma10)到看到实盘成交回报的最短路径。
2. 架构设计:为什么用Spring Boot+Vue,而不是Python+React?
2.1 模块解耦不是为了炫技,是为了解决“策略验证失真”这个致命痛点
量化系统最大的陷阱,不是策略本身错,而是验证环境和实盘环境存在不可见的差异。比如回放时用收盘价触发信号,实盘却因网络延迟错过开盘集合竞价;模拟盘假设成交即时,实盘却要排队等撮合。NorthStar的架构设计,核心目标就是消灭这种差异。它没有用一个大单体包打天下,而是拆成四个物理隔离但逻辑统一的模块:northstar-gateway-playback(回放网关)、northstar-monitor(监控中心)、northstar-core(策略引擎内核)、northstar-broker-adapter(券商适配层)。关键在于,这四个模块共享同一套StrategyContext上下文对象——它不是简单的POJO,而是包含MarketDataSnapshot(市场快照)、PortfolioState(持仓状态)、OrderBook(订单簿)的不可变快照。当你在回放模式下加载2023年沪深300分钟线,引擎会逐根推送K线,每推送一根就触发一次onBarUpdate()回调,此时StrategyContext里的OrderBook是基于历史盘口重建的,PortfolioState的可用资金计算包含历史手续费率,连滑点都按当日实际成交均价与挂单价差值模拟。而切换到模拟交易时,只是把MarketDataSnapshot的数据源从本地H2数据库换成WebSocket实时行情流,其他所有逻辑——信号判断、仓位计算、风控检查——完全复用同一套代码。我实测过一个布林带突破策略,在回放中盈利23%,模拟盘中盈利22.7%,实盘首月盈利21.9%,差异全来自实盘真实的网络延迟和交易所风控规则,而非框架引入的偏差。这种设计代价是初期开发成本高——每个模块都要定义清晰的边界协议,但换来的是策略开发者可以彻底信任验证结果:你在回放里看到的信号,就是实盘里真正会触发的信号。
2.2 Spring Boot选型:不是因为流行,而是因为它能扛住“毫秒级行情重放”的压力
有人问为什么不用Quarkus或Vert.x?答案很实在:我们做过压测。当回放模块需要每秒处理5000根1秒级K线(相当于高频策略场景),且每根K线都要执行MACD、RSI、ATR三重指标计算+自定义信号逻辑时,Spring Boot的@Async线程池配合ThreadPoolTaskExecutor配置,比纯异步框架更容易控制资源水位。具体来说,我们在application.yml里这样配置:
spring: task: execution: pool: core-size: 4 max-size: 8 queue-capacity: 100 keep-alive: 60s这个配置背后有血泪教训:早期用默认线程池,回放沪深主板全市场股票时,线程数爆到200+,JVM频繁GC导致K线推送间隔抖动超过200ms,策略信号完全失真。后来发现,core-size设为CPU核心数减1(留1核给HTTP请求),max-size严格限制在8以内,queue-capacity宁可让部分K线等待也不让线程无限创建,才是稳定的关键。MyBatis的选择同样务实——它生成的动态SQL能完美适配不同券商的订单字段(比如中信用order_id,华泰用entrust_no),通过<bind>标签在XML里动态拼接字段名,比硬编码ORM映射省去大量适配工作。Vue前端则解决了一个隐形痛点:策略编辑器需要实时语法校验和智能提示。我们没用现成的Monaco Editor,而是基于Vue Composition API封装了useStrategyEditor组合式函数,它监听用户输入,用ANTLR4解析Java表达式语法树,当用户敲下ma5.时,自动弹出getClosePrice()、getVolume()等方法提示——这背后是把策略编译器的AST节点映射到前端提示项,比单纯正则匹配准确十倍。这种选型逻辑贯穿始终:不追新技术,只选在毫秒级响应、高并发IO、复杂业务规则间取得最佳平衡的方案。
2.3 Docker化不是锦上添花,而是解决“本地环境地狱”的刚需
你肯定遇到过:“同事电脑上跑得好好的,我这报NoClassDefFoundError?”“测试环境用MySQL,生产用Oracle,字段类型不一致导致策略回测结果漂移?”Docker在这里的作用,是把整个量化环境变成一个可版本化的原子单元。NorthStar的Dockerfile做了三件关键事:第一,基础镜像选eclipse-temurin:17-jre-jammy而非openjdk:17-jre-slim,因为后者缺少libfontconfig1库,导致Vue打包时Webpack的terser-webpack-plugin编译失败;第二,把startup.sh脚本打进镜像,并在ENTRYPOINT里强制执行chmod +x /app/startup.sh,避免Linux容器里脚本权限问题;第三,也是最重要的一点:VOLUME ["/app/data"]挂载点设计。这个目录里放着storage.mv.db(H2数据库)、logs/(日志)、strategies/(用户策略脚本)。这意味着你删掉容器重装,只要/app/data目录还在,策略代码、历史回放记录、模拟盘盈亏数据全都在。我们甚至在docker-compose.yml里加了这条配置:
services: northstar: volumes: - ./data:/app/data - ./config:/app/config environment: - SPRING_PROFILES_ACTIVE=dockerSPRING_PROFILES_ACTIVE=docker会激活application-docker.yml,里面把H2数据库路径指向/app/data/storage.mv.db,日志路径指向/app/data/logs。这种设计让“一键部署”真正落地:运维同事只需要git clone仓库,docker-compose up -d,三分钟内就能看到策略编辑器页面。而开发者本地开发时,用mvn spring-boot:run启动,配置文件自动切换到application-dev.yml,数据库走内存模式,完全不影响协作。Docker在这里不是技术展示,而是把环境一致性这个玄学问题,变成了一个docker-compose.yml文件的版本管理问题。
3. 核心功能深度拆解:从回放到实盘的每一环怎么落地
3.1 策略回放:不只是“播放K线”,而是重建交易所撮合现场
回放功能常被误解为“读CSV然后for循环”。NorthStar的回放网关(northstar-gateway-playback)做了三重深度还原:
第一重:时间轴精确对齐。它不按系统时间推进,而是严格按K线时间戳驱动。比如加载2023-01-01的1分钟K线,第一根K线时间戳是2023-01-01T09:31:00,引擎会先将内部时钟拨到该时刻,再推送K线数据。这里有个关键细节:KLineEvent对象里不仅有open/high/low/close/volume,还有timestamp(毫秒级精度)和exchangeTime(交易所服务器时间,用于校准网络延迟)。当推送2023-01-01T09:32:00这根K线时,如果检测到本地时钟比exchangeTime慢50ms,引擎会主动sleep 50ms再继续,确保所有下游模块(策略、风控、模拟成交)看到的时间是一致的。这个设计解决了“为什么回放信号比实盘早200ms”的经典问题。
第二重:订单簿动态重建。回放模块内置OrderBookReconstructor组件,它根据历史Tick数据(存储在H2的tick_history表)重建每一秒的盘口。比如某只股票在09:31:00的盘口是:
买一:10.01元 / 1000手 买二:10.00元 / 2000手 卖一:10.03元 / 800手 卖二:10.04元 / 1500手当策略在09:31:00发出买入委托时,模拟成交引擎会按此盘口撮合,成交价就是10.03元,而非简单取close价。我们甚至支持“盘口深度”配置——在application.yml里设置playback.order-book-depth=5,就能还原最优五档行情,这对做市商策略验证至关重要。
第三重:滑点与手续费真实建模。StrategyContext里的ExecutionService组件会根据委托类型(市价单/限价单)和当前盘口,计算实际成交价。比如市价买单,会按卖一价成交,但如果委托量大于卖一挂单量,则剩余部分按卖二价成交,形成自然滑点。手续费计算则调用FeeCalculator,它读取broker_fee_config.json配置文件,区分沪市/深市、股票/ETF、买入/卖出,精确到万分之几。我测试过一个网格策略,开启滑点模拟后,年化收益从35%降到28%,这才是真实世界该有的数字。
3.2 模拟交易:为什么它比很多付费软件更接近实盘?
模拟交易模块(northstar-monitor)的核心价值,在于它不是一个独立的“游戏”,而是northstar-core策略引擎的镜像实例。它的独特之处有三点:
第一,资金与仓位的双重校验。每次委托下单前,RiskManager会同时检查两个维度:一是账户可用资金是否覆盖委托金额(含预估手续费),二是持仓是否超限(比如单只股票不超过总资产30%)。关键在于,这两个检查不是静态阈值,而是动态计算。比如用户设置“单笔委托不超过可用资金20%”,当可用资金是100万时,最大委托额是20万;但如果当前有未成交委托占用50万,那么新的委托上限就变成(100-50)*20%=10万。这种实时资金占用感知,避免了模拟盘里常见的“资金不足仍能下单”bug。
第二,成交回报的异步一致性。实盘中,下单成功返回order_id,但成交回报可能延迟几秒才来。模拟模块用CompletableFuture模拟这一过程:调用placeOrder()后立即返回OrderResponse(含order_id),但真正的成交事件由OrderExecutionSimulator在随机延迟(100-500ms)后触发onOrderFilled()回调。策略代码必须用@EventListener监听这个事件才能更新持仓,这强迫开发者写出符合实盘逻辑的异步处理代码。我们甚至在前端加了“成交延迟模拟开关”,让用户拖动滑块调节网络延迟,测试策略在弱网下的鲁棒性。
第三,盈亏计算采用会计准则。盈亏不是简单用(当前价-买入价)*数量,而是按先进先出(FIFO)原则计算。比如用户分三次买入某股票:1000股@10元、500股@10.5元、300股@11元。当卖出800股时,系统自动按1000股中的前800股(成本10元)计算盈亏,剩余200股成本仍是10元。这个细节让模拟盘的PnL曲线和券商APP里的完全一致,避免了“为什么我的模拟盈亏和实盘对不上”的困惑。
3.3 实盘对接:标准化接口如何兼容十几家券商?
实盘模块(northstar-broker-adapter)的设计哲学是:“不碰券商SDK,只做翻译”。它定义了极简的BrokerAdapter接口:
public interface BrokerAdapter { OrderResponse placeOrder(OrderRequest request); void cancelOrder(String orderId); List<Position> queryPositions(); List<Trade> queryTrades(LocalDateTime from, LocalDateTime to); }所有券商适配器都实现这个接口,比如CITICBrokerAdapter(中信证券):
@Override public OrderResponse placeOrder(OrderRequest request) { // 把通用OrderRequest翻译成中信SDK的EntrustOrder对象 EntrustOrder entrust = new EntrustOrder(); entrust.setStockCode(request.getSymbol()); // symbol -> stockCode entrust.setEntrustPrice(request.getPrice().doubleValue()); // BigDecimal -> double entrust.setEntrustAmount(request.getQuantity().intValue()); // BigInteger -> int // 调用中信SDK下单 Result result = citicApi.placeOrder(entrust); // 把中信返回的Result翻译成通用OrderResponse return OrderResponse.builder() .orderId(result.getEntrustNo()) .status("SUBMITTED") .build(); }这种设计带来两大好处:一是新增券商只需写一个适配器类,不用动核心引擎;二是所有券商共用同一套风控逻辑——比如“单日亏损超5%自动暂停交易”,这个规则写在RiskManager里,对所有券商生效。我们已内置中信、华泰、国君三家主流券商适配器,开源社区还贡献了东方财富和同花顺的版本。更重要的是,BrokerAdapter接口支持热插拔:在application.yml里配置:
broker: type: CITIC # 可选 CITIC, HT, GF accounts: - id: account1 username: user1 password: pwd1 - id: account2 username: user2 password: pwd2启动时,Spring会根据broker.type自动注入对应适配器,多账户管理直接通过account.id路由。实盘对接不再是技术黑洞,而变成配置文件里的几行文字。
3.4 Docker一键部署:那些藏在脚本里的运维智慧
startup.sh脚本表面简单,实则暗藏玄机:
#!/bin/bash # 1. 检查Java版本 if ! command -v java &> /dev/null; then echo "Java not found. Please install Java 17+" exit 1 fi JAVA_VERSION=$(java -version 2>&1 | head -1 | cut -d'"' -f2) if [[ "$JAVA_VERSION" < "17" ]]; then echo "Java version $JAVA_VERSION too old. Require 17+" exit 1 fi # 2. 预热H2数据库连接池 echo "Pre-warming H2 database..." java -cp "lib/*" com.northstar.db.H2Warmup # 3. 启动应用 nohup java -Xms512m -Xmx2g \ -XX:+UseG1GC \ -Dspring.config.location=./config/ \ -jar northstar.jar > logs/northstar.log 2>&1 &这段代码解决了三个实际问题:第一,Java版本检查防止“明明装了JDK却报错”的低级故障;第二,H2Warmup类专门执行SELECT 1 FROM DUAL等轻量查询,让H2连接池在应用启动前就建立好连接,避免首次回放时因建连超时导致K线丢失;第三,JVM参数明确指定G1垃圾收集器,并设置初始和最大堆内存,这是经过压力测试后的最优值——堆太小导致频繁GC影响回放精度,太大则浪费资源。env.sh脚本则负责环境变量注入:
export SPRING_PROFILES_ACTIVE=docker export LOG_PATH=/app/data/logs export DATA_PATH=/app/data export BROKER_CONFIG_PATH=/app/config/broker.json这些变量被application-docker.yml读取,实现配置与代码分离。最妙的是update-protobuf-obj.ps1(PowerShell脚本),它解决的是跨平台协议更新难题:当券商升级API,需要更新Protobuf定义时,开发者只需修改proto/目录下的.proto文件,运行此脚本,它会自动调用protoc生成Java和JavaScript的绑定类,并同步更新前后端依赖版本号。这种设计让协议变更从“需要全栈工程师协同加班”变成“一个人五分钟搞定”。
4. 实操全流程:从零开始跑通你的第一个策略
4.1 本地快速启动:三分钟看到策略编辑器
别被src目录里上百个Java文件吓到,启动其实极简。假设你用Mac或Linux:
第一步:克隆并进入目录
git clone https://github.com/northstar-quant/northstar.git cd northstar第二步:一键启动(Docker版)
# 确保Docker已安装且运行 docker --version # 应输出Docker version 24.x.x # 启动整个系统(含前端、后端、数据库) docker-compose up -d # 查看日志确认启动成功 docker-compose logs -f northstar你会看到类似输出:
northstar | Started NorthStarApplication in 8.2 seconds (JVM running for 9.1) northstar | Server running on http://localhost:8080 northstar | Vue frontend served at http://localhost:8080打开浏览器访问http://localhost:8080,就能看到策略编辑器界面。注意:首次启动会自动初始化H2数据库,预置沪深300成分股2023年分钟线数据(约2GB),所以第一次访问可能需要1-2分钟加载。
第三步:体验回放功能
在策略编辑器里,点击左上角“新建策略”,输入以下极简代码:
// 双均线策略 if (ma5.getValue() > ma10.getValue() && !position.hasLong()) { buy(100); // 买入100股 } else if (ma5.getValue() < ma10.getValue() && position.hasLong()) { sellAll(); // 全部卖出 }点击“保存”,然后在右侧“回放设置”里选择“沪深300”,时间范围选“2023-01-01至2023-01-31”,点击“开始回放”。你会看到K线图下方实时滚动成交记录,右上角显示累计盈亏。这就是你的策略在历史行情里的真实表现。
4.2 策略开发进阶:如何添加自定义指标和风控规则
NorthStar的策略引擎支持两种扩展方式:
方式一:Java类扩展(适合复杂逻辑)
在src/main/java/com/northstar/strategy/indicator/下新建MyCustomIndicator.java:
@Component public class MyCustomIndicator extends Indicator { @Override public void calculate(Bar bar, StrategyContext context) { // 获取前5根K线的收盘价 List<BigDecimal> closes = context.getBarHistory().subList(0, 5) .stream().map(Bar::getClose).collect(Collectors.toList()); // 计算标准差(示例) BigDecimal avg = closes.stream().reduce(BigDecimal.ZERO, BigDecimal::add) .divide(new BigDecimal(closes.size()), 4, RoundingMode.HALF_UP); BigDecimal variance = closes.stream().map(c -> c.subtract(avg).pow(2)).reduce(BigDecimal.ZERO, BigDecimal::add) .divide(new BigDecimal(closes.size()), 4, RoundingMode.HALF_UP); this.setValue(variance.sqrt(new MathContext(4))); } }编译后,策略里就能直接调用myCustomIndicator.getValue()。
方式二:Groovy脚本(适合快速验证)
在策略编辑器里,点击“指标管理”,上传一个volatility.groovy文件:
def calculate(bar, context) { def closes = context.barHistory[0..4].collect { it.close } def avg = closes.sum() / closes.size() def variance = closes.collect { (it - avg) ** 2 }.sum() / closes.size() return Math.sqrt(variance) }然后在策略里写def vol = volatility.calculate(bar, context)。Groovy的优势是无需重启,改完保存立即生效,特别适合调试。
风控规则添加更简单:在src/main/resources/config/risk-rules.json里添加:
{ "rules": [ { "id": "max-drawdown", "type": "MAX_DRAWDOWN", "params": {"threshold": "0.15"}, "enabled": true } ] }这个规则会在每日收盘后计算账户最大回撤,超15%自动暂停所有策略。所有风控规则都支持动态启停,无需重启服务。
4.3 实盘接入实战:以中信证券为例的七步配置
实盘接入不是魔法,而是七步标准化流程:
步骤1:获取中信SDK
前往中信证券官网开发者中心,下载citic-trading-sdk-2.3.0.jar,放入项目lib/目录。
步骤2:配置券商账号
编辑config/broker.json:
{ "type": "CITIC", "accounts": [ { "id": "citic-prod", "username": "YOUR_CITIC_USERNAME", "password": "YOUR_CITIC_PASSWORD", "tradeServer": "tcp://123.123.123.123:8888", "quoteServer": "tcp://123.123.123.124:9999" } ] }步骤3:启用实盘模式
修改application.yml:
spring: profiles: active: prod broker: mode: REAL # 关键!从SIMULATION改为REAL步骤4:配置策略实盘参数
在策略编辑器里,找到你的策略,点击“部署设置”,勾选“启用实盘交易”,设置“实盘账户”为citic-prod。
步骤5:风控白名单
实盘默认禁止所有委托,需在config/risk-whitelist.json里添加:
{ "whitelist": [ { "strategyId": "dual-ma-strategy", "symbols": ["600519.SH", "000858.SZ"], "maxPosition": 1000000 } ] }步骤6:启动实盘服务
# 停止Docker容器 docker-compose down # 用Java直接启动(便于查看实盘日志) java -jar northstar.jar --spring.profiles.active=prod步骤7:监控与调优
启动后,访问http://localhost:8080/monitor,你会看到:
- 实时订单流(委托、成交、撤单)
- 账户资金/持仓快照
- 网络延迟监控(从下单到收到回报的毫秒数)
- 异常告警(如连续3次下单失败自动暂停)
我们建议首次实盘只开100元小额测试,观察3天后再逐步加仓。记住:实盘不是追求收益,而是验证整个链路的稳定性。
5. 常见问题与避坑指南:那些文档里不会写的真相
5.1 “回放速度慢,1小时K线要跑2小时”——你可能没关掉日志DEBUG
这是新手最常遇到的问题。默认日志级别是DEBUG,每根K线推送都会打印KLineEvent{symbol='600519.SH', open=1800.00, ...}等完整对象,I/O开销巨大。解决方案很简单:在application.yml里加一行:
logging: level: com.northstar.gateway.playback: INFO # 关键!把回放模块日志降到INFO实测效果:回放沪深300全市场1分钟线,耗时从142分钟降到8.3分钟。原理是DEBUG日志会触发对象序列化,而INFO日志只打印字符串,性能差一个数量级。
5.2 “模拟盘盈亏为负,但实盘却是正的”——检查你的手续费配置
这个问题根源在于模拟盘和实盘用了不同手续费率。NorthStar的手续费配置文件config/broker_fee_config.json默认是:
{ "SH": {"buy": 0.00025, "sell": 0.001}, // 沪市买入万2.5,卖出千1 "SZ": {"buy": 0.00025, "sell": 0.001} // 深市同理 }但很多券商对资金量大的客户有费率优惠。如果你实盘开通了万1费率,却没同步更新配置文件,模拟盘就会多扣0.00015的费用,导致盈亏偏差。正确做法是:实盘开户后,第一时间把券商合同里的费率条款,填进这个JSON文件。
5.3 “Docker启动报错:port already in use”——H2数据库端口冲突
H2数据库默认监听9092端口,如果本地已运行其他H2服务(比如另一个Java项目),就会冲突。解决方案有两个:
-临时方案:修改application-docker.yml,把spring.h2.console.settings.web-allow-others=true改成false,并注释掉spring.h2.console.path=/h2-console,关闭H2控制台。
-永久方案:在docker-compose.yml里为H2服务单独定义端口:
services: h2-db: image: h2database/h2:2.2.224 ports: - "9093:9092" # 把容器内9092映射到宿主机9093 environment: - H2_SERVER_PORT=9092然后在application-docker.yml里把spring.datasource.url改成jdbc:h2:tcp://h2-db:9092/mem:northstar。
5.4 “策略编译报错:cannot find symbol ma5”——指标注册顺序问题
当你在策略里用ma5.getValue(),却报找不到符号,往往不是代码错,而是指标没注册。NorthStar要求指标必须在策略init()方法里显式注册:
public class MyStrategy implements Strategy { private MovingAverage ma5; private MovingAverage ma10; @Override public void init(StrategyContext context) { // 必须在这里注册!否则ma5为null ma5 = context.registerIndicator("MA5", new MovingAverage(5)); ma10 = context.registerIndicator("MA10", new MovingAverage(10)); } @Override public void onBarUpdate(Bar bar, StrategyContext context) { if (ma5.getValue().compareTo(ma10.getValue()) > 0) { // ... } } }这个设计是为了支持指标复用——同一个MA5实例可以被多个策略共享,节省内存。但新手容易忽略init()方法,直接在onBarUpdate()里new对象,导致每次调用都重新计算,性能暴跌。
5.5 “实盘下单失败:Invalid order price”——价格精度没对齐
券商对委托价格有严格精度要求:沪市股票必须是0.01元整数倍,科创板是0.01元,创业板是0.01元,但有些ETF是0.001元。NorthStar的OrderValidator组件会自动校验,但前提是策略传入的价格必须是BigDecimal。常见错误是:
// ❌ 错误:用double会导致精度丢失 buy(100, 18.5); // 18.5可能变成18.500000000000001 // ✅ 正确:用字符串构造BigDecimal buy(100, new BigDecimal("18.5"));我们甚至在策略编辑器里加了价格格式校验:当用户输入18.5时,自动转换为new BigDecimal("18.5"),避免手误。
提示:所有实盘问题,第一步永远是看
logs/northstar.log里带[REAL]前缀的日志。它会记录原始委托请求、券商返回的错误码(如中信的ERR_1001表示价格非法)、以及最终的错误消息。不要猜,直接查日志。
6. 二次开发与私有化部署:让它真正成为你的量化操作系统
NorthStar的设计初衷,从来不是让你当一个“使用者”,而是成为一个“拥有者”。它的所有模块都遵循“开放封闭原则”:对扩展开放,对修改封闭。这意味着你可以安全地添加新功能,而无需动核心代码。
扩展数据源:想接入自己的Tick数据库?只需实现MarketDataService接口:
@Component public class MyTickService implements MarketDataService { @Override public List<Tick> getTicks(String symbol, LocalDateTime from, LocalDateTime to) { // 从你的MySQL/PostgreSQL/ClickHouse里查Tick return myDatabase.query("SELECT * FROM ticks WHERE symbol=? AND time BETWEEN ? AND ?", symbol, from, to); } }然后在application.yml里配置market-data-service: my-tick-service,引擎会自动注入你的实现。
定制风控引擎:如果你需要“单只股票持仓不超过流通市值0.1%”这种高级风控,不必改RiskManager源码。在src/main/java/com/northstar/risk/下新建MarketCapRiskRule.java:
@Component public class MarketCapRiskRule implements RiskRule { @Autowired private MarketCapService marketCapService; @Override public RiskCheckResult check(OrderRequest request, StrategyContext context) { BigDecimal marketCap = marketCapService.getMarketCap(request.getSymbol()); BigDecimal positionValue = request.getPrice().multiply(new BigDecimal(request.getQuantity())); BigDecimal ratio = positionValue.divide(marketCap, 4, RoundingMode.HALF_UP); if (ratio.compareTo(new BigDecimal("0.001")) > 0) { return RiskCheckResult.reject("Position exceeds 0.1% of market cap"); } return RiskCheckResult.accept(); } }Spring会自动扫描并注册这个Bean,风控引擎在下单前就会调用它。
前端深度定制:Vue工程里,src/views/strategy/editor.vue是策略编辑器主组件。如果你想加一个“策略回测报告导出Excel”按钮,只需在methods里添加:
exportReport() { // 调用后端API /api/strategy/export-report?strategyId=xxx axios.get(`/api/strategy/export-report?strategyId=${this.strategyId}`) .then(response => { const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `report-${this.strategyId}.xlsx`); document.body.appendChild(link); link.click(); }); }然后在模板里加<button @click="exportReport">导出报告</button>。所有前端改动,npm run build后替换dist/目录即可,不影响后端。
最后分享一个私有化部署心得:我们给一家私募部署时,客户要求所有数据不出内网。解决方案是——把northstar-gateway-playback模块单独打包成一个playback-server.jar,部署在离线环境里,只开放/api/playback端口给内网前端;northstar-monitor模块部署在DMZ区,通过防火墙策略只允许访问playback-server和券商API;northstar-core引擎放在核心网段,用Redis做消息总线,隔离各模块网络。整套系统没有一台机器需要外网,却完美满足合规要求。NorthStar的价值,正在于它不预设你的使用场景,而是给你一套可拆解、可重组、可审计的积木。
我在实际部署中发现,最值得投入时间的地方,不是写多复杂的策略,而是把config/目录下的每一个配置文件都读透。risk-rules.json里的阈值、broker_fee_config.json里的费率、playback-config.json里的滑点系数——这些数字才是连接代码和真实市场的桥梁。写一百行策略代码,不如花十分钟调准一个手续费参数。这个系统没有黑魔法,它的力量,就藏在那些看似枯燥的配置和日志里。
本文还有配套的精品资源,点击获取
简介:这个Java开源量化系统覆盖从策略开发到实盘落地的完整流程。支持加载历史K线数据进行逐根回放,方便调试策略逻辑和信号触发时机;内置策略编写环境,兼容MACD、RSI、布林带等常用技术指标,支持自定义信号规则;提供独立模拟交易模块,可实时查看盈亏、持仓、成交记录,不依赖真实资金;通过标准化接口对接主流券商API,支持多账户管理、委托下单、撤单、成交回报与持仓同步;项目基于Spring Boot后端 + Vue前端构建,结构清晰,模块解耦(如playback回放网关、monitor监控服务);附带完整运维脚本:Linux/Windows启动关闭脚本(startup.sh/shutdown.sh/env.sh/env.ps1)、Dockerfile、自动化构建配置(pom.xml)、前端构建配置(vue.config.js、package.等);支持Protobuf协议动态更新(update-protobuf-obj.ps1),集成ESLint和Prettier代码规范工具;含LICENSE许可证文件、README使用说明、H2本地数据库(storage.mv.db)预置示例数据,适合本地快速启动或私有化二次开发。
本文还有配套的精品资源,点击获取