Initial commit

This commit is contained in:
2025-10-11 11:55:25 +08:00
parent 467dad8449
commit 8107dee8d3
2879 changed files with 610575 additions and 0 deletions

View File

@@ -0,0 +1,214 @@
// 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;