// src/utils/tradingDayUtils.js // 交易日计算工具函数 /** * 中国股市交易日工具类 * 包含节假日判断和交易日计算 */ class TradingDayUtils { constructor() { // 2024-2025年的法定节假日(需要定期更新) this.holidays = new Set([ // 2024年节假日 '2024-01-01', // 元旦 '2024-02-09', '2024-02-10', '2024-02-11', '2024-02-12', '2024-02-13', '2024-02-14', '2024-02-15', '2024-02-16', '2024-02-17', // 春节 '2024-04-04', '2024-04-05', '2024-04-06', // 清明节 '2024-05-01', '2024-05-02', '2024-05-03', '2024-05-04', '2024-05-05', // 劳动节 '2024-06-08', '2024-06-09', '2024-06-10', // 端午节 '2024-09-15', '2024-09-16', '2024-09-17', // 中秋节 '2024-10-01', '2024-10-02', '2024-10-03', '2024-10-04', '2024-10-05', '2024-10-06', '2024-10-07', // 国庆节 // 2025年节假日(预估,需要根据官方公告更新) '2025-01-01', // 元旦 '2025-01-28', '2025-01-29', '2025-01-30', '2025-01-31', '2025-02-01', '2025-02-02', '2025-02-03', '2025-02-04', // 春节 '2025-04-04', '2025-04-05', '2025-04-06', // 清明节 '2025-05-01', '2025-05-02', '2025-05-03', // 劳动节 '2025-05-31', '2025-06-01', '2025-06-02', // 端午节 '2025-10-01', '2025-10-02', '2025-10-03', '2025-10-04', '2025-10-05', '2025-10-06', '2025-10-07', '2025-10-08', // 国庆节+中秋节 ]); // A股交易时间 this.marketOpenTime = { hour: 9, minute: 30 }; this.marketCloseTime = { hour: 15, minute: 0 }; } /** * 判断是否为周末 * @param {Date} date * @returns {boolean} */ isWeekend(date) { const day = date.getDay(); return day === 0 || day === 6; // 0是周日,6是周六 } /** * 判断是否为节假日 * @param {Date} date * @returns {boolean} */ isHoliday(date) { const dateStr = this.formatDate(date); return this.holidays.has(dateStr); } /** * 判断是否为交易日 * @param {Date} date * @returns {boolean} */ isTradingDay(date) { return !this.isWeekend(date) && !this.isHoliday(date); } /** * 格式化日期为 YYYY-MM-DD * @param {Date} date * @returns {string} */ formatDate(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } /** * 判断时间是否在交易时间内 * @param {Date} datetime * @returns {boolean} */ isInTradingHours(datetime) { const hours = datetime.getHours(); const minutes = datetime.getMinutes(); // 上午交易时间:9:30-11:30 const morningStart = hours > 9 || (hours === 9 && minutes >= 30); const morningEnd = hours < 11 || (hours === 11 && minutes <= 30); // 下午交易时间:13:00-15:00 const afternoonStart = hours >= 13; const afternoonEnd = hours < 15; return (morningStart && morningEnd) || (afternoonStart && afternoonEnd); } /** * 判断事件是否发生在交易时间后 * @param {Date} datetime * @returns {boolean} */ isAfterTradingHours(datetime) { const hours = datetime.getHours(); const minutes = datetime.getMinutes(); return hours > 15 || (hours === 15 && minutes > 0); } /** * 获取下一个交易日 * @param {Date} date * @returns {Date} */ getNextTradingDay(date) { const nextDay = new Date(date); nextDay.setDate(nextDay.getDate() + 1); while (!this.isTradingDay(nextDay)) { nextDay.setDate(nextDay.getDate() + 1); } return nextDay; } /** * 获取上一个交易日 * @param {Date} date * @returns {Date} */ getPreviousTradingDay(date) { const prevDay = new Date(date); prevDay.setDate(prevDay.getDate() - 1); while (!this.isTradingDay(prevDay)) { prevDay.setDate(prevDay.getDate() - 1); } return prevDay; } /** * 根据事件时间获取对应的交易日 * 规则: * 1. 如果是交易日的交易时间内,返回当天 * 2. 如果是交易日的15:00后,返回下一个交易日 * 3. 如果是非交易日(周末或节假日),返回下一个交易日 * * @param {Date|string} eventDateTime 事件时间 * @returns {string} 交易日期 YYYY-MM-DD */ getEffectiveTradingDay(eventDateTime) { const datetime = typeof eventDateTime === 'string' ? new Date(eventDateTime) : eventDateTime; // 如果是非交易日,直接返回下一个交易日 if (!this.isTradingDay(datetime)) { return this.formatDate(this.getNextTradingDay(datetime)); } // 如果是交易日 // 检查是否在15:00之后 if (this.isAfterTradingHours(datetime)) { // 15:00后,返回下一个交易日 return this.formatDate(this.getNextTradingDay(datetime)); } // 交易日的15:00前,返回当天 return this.formatDate(datetime); } /** * 批量加载交易日数据(如果有CSV文件) * @param {string} csvContent CSV内容 */ loadTradingDaysFromCSV(csvContent) { const lines = csvContent.trim().split('\n'); const tradingDays = new Set(); // 跳过标题行 for (let i = 1; i < lines.length; i++) { const date = lines[i].trim(); if (date) { // 转换日期格式 2010/1/4 -> 2010-01-04 const parts = date.split('/'); if (parts.length === 3) { const year = parts[0]; const month = parts[1].padStart(2, '0'); const day = parts[2].padStart(2, '0'); tradingDays.add(`${year}-${month}-${day}`); } } } this.tradingDaysSet = tradingDays; } /** * 使用CSV数据判断是否为交易日(如果已加载) * @param {Date} date * @returns {boolean} */ isTradingDayByCSV(date) { if (this.tradingDaysSet) { return this.tradingDaysSet.has(this.formatDate(date)); } // 如果没有CSV数据,回退到默认判断 return this.isTradingDay(date); } } // 导出单例 export const tradingDayUtils = new TradingDayUtils(); export default tradingDayUtils;