Java量化系列(四十): 一键搞定节假日和周末,交易日期判断终极方案
做量化开发的都懂交易日期判断看似是小细节却能直接决定策略成败 比如“周末误触发策略执行导致空单挂单失败”“漏算法定节假日抓取到空数据拖垮整个同步任务”“计算前后交易日时重复过滤节假日效率极低”…… 这些坑几乎每个量化开发者都踩过。交易日期判断的核心本质是“区分周末过滤法定节假日”但手动维护节假日列表、重复编写判断逻辑不仅耗时费力还容易出错。尤其是A股节假日每年更新手动同步更是麻烦到崩溃。今天带来Java量化系列第40篇实战——交易日期判断全流程落地方案从节假日数据定时同步、实体类封装到工具类一站式适配多场景需求、对外接口开发全套可运行代码直接奉上覆盖“判断是否交易日、查询前后交易日、统计区间交易日”等所有高频场景彻底解决量化开发中日期判断的痛点。一、核心认知交易日期判断的关键要点先理清核心逻辑避免开发走弯路明确量化场景下交易日期判断的核心诉求• 核心判断逻辑交易日 非周末非周六、周日 非法定节假日二者缺一不可。• 数据支撑需维护法定节假日列表每年更新一次避免手动录入出错通过定时任务自动同步无需人工干预。• 高频场景判断指定日期是否为交易日、获取前后N个交易日、统计区间内所有交易日、查询最近交易日列表适配策略执行、数据抓取等场景。• 核心优势封装通用工具类一键复用所有日期判断逻辑定时同步节假日数据适配每年节假日调整对外提供标准化接口支撑多服务调用。关键提醒A股交易日遵循“周末休市、法定节假日休市”规则无特殊调休补班调休上班日若为周末仍不算交易日本文方案完全贴合A股规则。二、核心实现从数据同步到工具类封装全流程⚙️整套方案分为“实体类封装-节假日数据定时同步-DateHelper工具类开发-对外接口开发”四步每一步都附完整代码详细注释所有代码可直接导入项目运行无需额外修改。2.1 实体类封装HolidayCalendarDo数据存储核心用于存储法定节假日数据关联数据库表holiday_calendar区分日期类型交易日/周末/法定节假日为后续判断提供数据支撑完整代码如下DataEqualsAndHashCode(callSuperfalse)TableName(holiday_calendar)// 关联数据库表publicclassHolidayCalendarDoimplementsSerializable{privatestaticfinallongserialVersionUID1L;/** 主键自增 */TableId(valueid,typeIdType.AUTO)privateIntegerid;/** 法定日期,不开盘存储节假日日期 */TableField(holiday_date)privateDateholidayDate;/** 当前年用于按年筛选提升查询效率 */TableField(curr_year)privateIntegercurrYear;/** 日期类型 3为法定节假日 */TableField(date_type)privateIntegerdateType;}设计亮点按年存储节假日数据查询时可精准筛选对应年份的节假日避免全表扫描日期类型字段只放置 法定节假日。2.2 定时任务每年自动同步节假日数据解放双手核心需求每年1月1日自动同步当年法定节假日数据避免重复同步无需人工维护。通过syncYear方法调用第三方接口获取数据批量保存到数据库完整代码如下/** * 同步指定年份的节假日数据定时任务每年1月1日执行 * param year 需同步的年份 * return 同步结果成功/失败/已存在 */publicOutputResultVoidsyncYear(Integeryear){// 1. 校验该年份数据是否已存在避免重复同步HolidayQueryParamqueryParamnewHolidayQueryParam();queryParam.setYear(year);ListHolidayCalendarDoholidayCalendarDoListholidayCalendarDomainService.listByCondition(queryParam);if(!CollUtil.isEmpty(holidayCalendarDoList)){log.info(已经存在 {}年的假期数据不需要同步,year);returnOutputResult.buildAlert(ResultCode.HOLIDAY_EXISTS);}Map?,?data;try{// 2. 调用第三方接口获取当年节假日数据接口返回格式年份-日期映射0工作日非0节假日datarestTemplate.getForObject(http://tool.bitefu.net/jiari/?dyear,Map.class);}catch(Exceptione){log.error(获取同步假期数据时出现异常,e);returnOutputResult.buildFail();}// 3. 解析接口返回数据封装为实体类列表MapString,IntegerdateInfo(MapString,Integer)data.get(String.valueOf(year));ListHolidayCalendarDolistdateInfo.entrySet().stream().filter(entry-entry.getValue()!0)// 筛选出节假日非0即为节假日.map(entry-{Datedate;try{// 格式化日期接口返回日期为MMdd拼接年份转为yyyyMMdd格式dateDateUtils.parseDate(yearentry.getKey(),yyyyMMdd);}catch(ParseExceptione){thrownewIllegalArgumentException(e);}HolidayCalendarDoholidayCalendarDonewHolidayCalendarDo();holidayCalendarDo.setHolidayDate(date);holidayCalendarDo.setCurrYear(year);holidayCalendarDo.setDateType(3);// 标记为法定节假日date_type3returnholidayCalendarDo;}).collect(Collectors.toList());// 4. 批量保存节假日数据到数据库holidayCalendarDomainService.saveBatch(list);returnOutputResult.buildSucc();}定时任务配置说明关键// 定时任务注解每年1月1日0点10分执行同步当年节假日数据Scheduled(cron0 10 0 1 1 ?)publicvoidsyncHolidayData(){intcurrentYearLocalDate.now().getYear();syncYear(currentYear);}避坑重点第三方接口返回日期为MMdd格式需拼接年份转为yyyyMMdd再解析避免日期格式错误添加异常捕获防止接口调用失败导致定时任务崩溃。对应的地址是:http://tool.bitefu.net/jiari/?d2026返回内容是:{2026:{1001:2,1002:2,1003:2,1004:1,1005:1,1006:1,1007:1,0101:2,0102:1,0103:1,0215:1,0216:2,0217:2,0218:2,0219:2,0220:1,0221:1,0222:1,0223:1,0404:1,0405:2,0406:1,0501:2,0502:2,0503:1,0504:1,0505:1,0619:2,0620:1,0621:1,0925:2,0926:1,0927:1}}3. 核心工具类DateHelper一站式日期判断解决方案封装所有交易日期相关工具方法覆盖量化开发全场景无需重复编写判断逻辑直接调用即可。核心方法分类讲解完整代码附注释3.1 基础判断是否为交易日核心方法isWorkingDay判断指定日期是否为交易日非周末非法定节假日适配策略执行、数据抓取等基础场景/** * 判断指定时间是否为工作日非周末且不在节假日列表中 * param currDate 指定的时间为null则使用当前系统日期 * return 当前时间是否是工作日, 是为 true, 否则为 false */publicbooleanisWorkingDay(DatecurrDate){if(currDatenull){currDateDateUtil.date();}// 1. 查询当前年份的节假日列表按年查询提升效率ListStringholidayDateListholidayCalendarService.listHolidayDateByYear(DateUtil.year(currDate));// 2. 先判断是否为周末是则直接返回falseif(DateUtil.isWeekend(currDate)){returnfalse;}// 3. 判断是否在节假日列表中不在则为交易日StringformatDateDateUtil.format(currDate,Const.SIMPLE_DATE_FORMAT);return!holidayDateList.contains(formatDate);}3.2 场景化工具前后交易日查询覆盖“获取前N个交易日、后N个交易日、排除当天的前后交易日”等高频场景以两个核心方法为例其余方法可直接复用/** * 查询距离指定日期N天前的工作日日期包含当天不包含假期与周末 * param date 日期 * param days 天数 * return N天前的工作日 */publicDategetBeforeWorkingDateByDay(Datedate,intdays){returnDateUtil.beginOfDay(getBeforeWorkingByCount(date,days,true).getFirst());}/** * 查询距离指定日期N天前的工作日日期不包含当天 * param date 日期 * param days 天数 * return N天前的工作日不含当天 */publicDategetBeforeWorkingDateByDayRemoveToday(Datedate,intdays){returnDateUtil.beginOfDay(getBeforeWorkingByCountRemoveToday(date,days,true).getFirst());}3.3 进阶工具区间交易日统计计算两个日期之间的所有交易日适配区间数据统计、策略回测等场景核心方法如下/** * 计算两个日期之间的所有工作日包含起始日期 * param startDate 开始日期 * param endDate 结束日期 * return 工作日的日期列表 */publicListDatebetweenWorkDay(DatestartDate,DateendDate){if(!(startDate!nullendDate!null)){returnCollections.emptyList();}// 格式化日期为当天开始/结束时间避免时间戳干扰startDateDateUtil.beginOfDay(startDate);endDateDateUtil.endOfDay(endDate);ListDateresultnewArrayList();// 循环遍历区间内所有日期筛选出交易日while(endDate.after(startDate)){if(isWorkingDay(startDate)){result.add(DateUtil.beginOfDay(startDate));}startDateDateUtil.offsetDay(startDate,1);// 日期加1天}returnresult;}工具类亮点所有方法均做了空值处理和效率优化按年查询节假日列表避免全表扫描日期格式化统一规避时间戳干扰适配多场景调用。3.4 对外接口开发支撑多服务调用基于工具类开发标准化对外接口覆盖前端查询、其他服务调用等场景接口文档清晰直接对接业务核心接口代码如下/** * 判断指定日期是否为交易日核心接口 * param day 日期字符串格式yyyy-MM-dd * return 1是交易日0非交易日 */Operation(summary查询某天是否是交易日)GetMapping(/getTradeDay/{day})publicOutputResultIntegergetTradeDay(PathVariable(day)Stringday){DatedateDateUtil.parse(day);returnOutputResult.buildSucc(dateHelper.isWorkingDay(date)?1:0);}/** * 查询最近十天的交易日日期列表 * return 最近10个交易日的日期字符串列表格式yyyy-MM-dd */Operation(summary查询最近十天的交易日日期列表)GetMapping(/getTenTradeDay)publicOutputResultListStringgetTenTradeDay(){returnholidayCalendarBusiness.getTenTradeDay();}/** * 查询日期段内的交易日日期列表 * param dateRo 日期对象包含开始日期、结束日期 * return 区间内所有交易日日期列表 */Operation(summary查询日期段内的交易日日期列表)PostMapping(/getTradeDay)publicOutputResultListStringgetTradeDay(RequestBodyDateRodateRo){returnholidayCalendarBusiness.getTradeDay(dateRo);}/** * 查询前N天的交易日日期不含当天 * param days 天数 * return 前N天的交易日日期 */Operation(summary查询前几天的对应日期)GetMapping(/getBeforeLastDay/{days})publicOutputResultDategetBeforeLastDay(PathVariableIntegerdays){returnholidayCalendarBusiness.getBeforeLastDay(days);}接口使用场景前端页面交易日筛选、量化策略调度仅在交易日执行、数据同步任务仅抓取交易日数据、回测系统日期校验等通用性极强。大家可以通过:https://stock-api.apifox.cn/api-391134756看响应的数据进行理解四、实战场景工具类接口的落地案例结合量化开发高频场景举例说明如何使用本文方案帮你快速落地场景1量化策略仅在交易日执行// 策略执行入口publicvoidexecuteStrategy(){// 1. 判断当前日期是否为交易日if(!dateHelper.isWorkingDay(null)){log.info(今日非交易日不执行策略);return;}// 2. 执行策略逻辑选股、下单、复盘等strategyService.run();}场景2抓取最近10个交易日的股票数据// 数据抓取入口publicvoidsyncStockData(){// 1. 查询最近10个交易日OutputResultListStringresultholidayCalendarBusiness.getTenTradeDay();if(!result.isSuccess()||CollUtil.isEmpty(result.getData())){log.error(查询交易日失败无法同步数据);return;}// 2. 循环抓取每个交易日的股票数据ListStringtradeDaysresult.getData();tradeDays.forEach(day-{stockDataService.syncDailyData(day);// 抓取单个交易日数据});}场景3统计区间内交易日数量回测场景// 回测统计入口publicintcountTradeDays(StringstartDateStr,StringendDateStr){// 1. 计算区间内所有交易日ListStringtradeDaysdateHelper.betweenWorkDay(startDateStr,endDateStr);// 2. 返回交易日数量returntradeDays.size();}五、避坑指南8个实战踩雷教训⚠️必看交易日期判断看似简单实则暗藏很多细节坑整理了实战中踩过的雷帮你少走弯路坑1日期格式不统一导致判断失效✅ 原因工具类中日期格式化与数据库存储格式不一致如工具类用yyyy-MM-dd数据库用yyyyMMdd导致节假日匹配失败。✅ 解决统一日期格式为yyyy-MM-ddConst.SIMPLE_DATE_FORMAT定义数据库与工具类保持一致。坑2定时任务执行时机错误遗漏节假日✅ 原因定时任务未在1月1日执行或执行时第三方接口未更新当年节假日数据导致数据缺失。✅ 解决定时任务设置为1月1日0点10分执行避开接口更新高峰期添加执行日志失败时触发告警。坑3未处理跨年节假日查询失败✅ 原因12月查询次年1月节假日时仅查询当年节假日列表导致跨年节假日未被过滤。✅ 解决工具类中添加跨年处理逻辑如12月查询时同时加载当年和次年节假日数据参考getAfterWorkingByCount方法实现。坑4频繁查询数据库性能瓶颈✅ 原因每次判断交易日都查询数据库高并发场景下导致服务卡顿。✅ 解决将当年节假日列表缓存到Redis设置过期时间为1年查询时先查缓存再查数据库。坑5日期为null未处理报空指针异常✅ 原因未处理currDatenull的情况直接调用日期工具类方法导致空指针。✅ 解决所有工具类方法均添加空值处理默认使用当前系统日期。坑6第三方接口调用失败未做兜底✅ 原因第三方接口宕机或超时未做降级处理导致定时任务崩溃。✅ 解决添加接口重试机制最多重试3次失败时手动同步接口数据避免任务中断。坑7混淆“交易日”与“工作日”✅ 原因误将调休上班日当作交易日调休上班日若为周末仍不算交易日。✅ 解决严格遵循“非周末非法定节假日”双重判断第三方接口已处理调休逻辑无需额外开发。坑8区间交易日统计遗漏起始日期✅ 原因循环判断时未包含起始日期导致统计结果少1天。✅ 解决将起始日期格式化为本日开始时间DateUtil.beginOfDay(startDate)确保起始日期被纳入判断。五、福利领取完整可运行代码包免费送为了帮大家快速落地我整理了本次交易日期判断实战的完整可运行代码包包含• ① holiday_calendar 对应的sql 语句 和近三年的数据。• ② DateHelper工具类完整代码所有日期判断方法• ③ 对外接口完整代码接口文档私信回复【交易日期判断】即可免费领取所有代码均可直接导入项目运行无需修改帮你节省1天以上开发时间彻底搞定量化开发中日期判断的所有难题。下期预告✨本次我们搞定了交易日期判断的全流程方案下期将聚焦 股票池获取涨停股票跌停股票 等数据 为量化策略筑牢数据基础敬请期待结尾互动你在量化开发中还遇到过哪些日期判断的坑欢迎在评论区留言讨论如果觉得这篇文章对你有帮助别忘了点赞在看转发让更多量化开发者告别日期判断的困扰 关注我持续解锁Java量化实战干货

相关新闻

安卓 网上家教信息系统app

安卓 网上家教信息系统app

目录 功能概述技术架构用户角色特色功能开发要点 项目技术支持可定制开发之功能亮点源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作 功能概述 安卓网上家教信息系统App旨在连接学生与家教教师,提供便捷的在线教学管理平台。核心…

2026/7/3 19:53:03 阅读更多 →
【Django毕设源码分享】基于Django的羽毛球服务管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

【Django毕设源码分享】基于Django的羽毛球服务管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/5/17 4:03:01 阅读更多 →
基于Matlab车牌识别系统

基于Matlab车牌识别系统

基于Matlab的车牌识别系统 第一章 系统整体设计 基于Matlab的车牌识别系统以“低成本、易实现、高精准、适配性强”为核心设计目标,面向停车场收费、交通违章抓拍、小区门禁等场景,解决传统车牌识别系统硬件成本高、算法移植复杂、小型场景部署难的痛点。…

2026/7/3 11:17:24 阅读更多 →

最新新闻

dotnet-framework-docker高级技巧:优化镜像大小与提升运行时性能的10个方法

dotnet-framework-docker高级技巧:优化镜像大小与提升运行时性能的10个方法

dotnet-framework-docker高级技巧:优化镜像大小与提升运行时性能的10个方法 【免费下载链接】dotnet-framework-docker The repo for the official docker images for .NET Framework on Windows Server Core. 项目地址: https://gitcode.com/gh_mirrors/do/dotne…

2026/7/4 5:24:31 阅读更多 →
5分钟快速上手lighterhtml:构建高性能Web应用的最佳实践

5分钟快速上手lighterhtml:构建高性能Web应用的最佳实践

5分钟快速上手lighterhtml:构建高性能Web应用的最佳实践 【免费下载链接】lighterhtml The hyperHTML strength & experience without its complexity 🎉 项目地址: https://gitcode.com/gh_mirrors/li/lighterhtml lighterhtml是一款兼具hyp…

2026/7/4 5:22:29 阅读更多 →
StudioPlugins Json助手:JsonHelper插件格式化与验证JSON数据

StudioPlugins Json助手:JsonHelper插件格式化与验证JSON数据

StudioPlugins Json助手:JsonHelper插件格式化与验证JSON数据 【免费下载链接】StudioPlugins Android Studio 精品插件合集,不在于多只在于精 项目地址: https://gitcode.com/gh_mirrors/st/StudioPlugins JsonHelper是Android Studio精品插件合…

2026/7/4 5:22:29 阅读更多 →
RestFB版本升级指南:从旧版本迁移到最新API的最佳实践

RestFB版本升级指南:从旧版本迁移到最新API的最佳实践

RestFB版本升级指南:从旧版本迁移到最新API的最佳实践 【免费下载链接】restfb RestFB is a simple and flexible Facebook Graph API client written in Java. 项目地址: https://gitcode.com/gh_mirrors/re/restfb RestFB是Java开发者连接Facebook Graph A…

2026/7/4 5:18:28 阅读更多 →
人大金仓数据库Linux安装超详细指南

人大金仓数据库Linux安装超详细指南

🔥关注墨瑾轩,带你探索编程的奥秘!🚀 🔥超萌技术攻略,轻松晋级编程高手🚀 🔥技术宝库已备好,就等你来挖掘🚀 🔥订阅墨瑾轩,智趣学习不…

2026/7/4 5:18:28 阅读更多 →
PMSM伺服控制三环架构设计与实现详解

PMSM伺服控制三环架构设计与实现详解

1. PMSM伺服控制系统仿真全解析永磁同步电机(PMSM)作为工业自动化领域的核心执行元件,其高性能伺服控制一直是工程师们面临的挑战。今天我将分享一个完整的三环控制架构实现方案,从理论框架到代码实现,再到参数整定技巧…

2026/7/4 5:18:28 阅读更多 →

日新闻

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 正式发布,这是一个关键的安全修复版本,修复了多个方面的问题,还对部分功能进行了优化。 安全修复亮点 此次发布在安全修复上表现突出。binprot 避免了项目引用计数溢出,mcmc 因安全问题提升了上游版本号&#xf…

2026/7/4 0:04:29 阅读更多 →
终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL HMCL(Hello Minecraft! Lau…

2026/7/4 0:06:29 阅读更多 →
KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

1. KMX63与PIC18F66K40的硬件协同架构解析KMX63作为一款三轴加速度计和磁力计组合传感器,与PIC18F66K40微控制器的搭配堪称嵌入式HMI开发的黄金组合。这套硬件组合的核心优势在于KMX63提供的高精度运动感知能力与PIC18F66K40强大的信号处理能力形成了完美互补。KMX6…

2026/7/4 0:06:29 阅读更多 →

周新闻

月新闻