|
@@ -2,61 +2,93 @@ import { useState, useCallback } from 'react';
|
|
|
import type { StockData } from '../types/index';
|
|
import type { StockData } from '../types/index';
|
|
|
|
|
|
|
|
export function useStockDataFilter(fullData: StockData[]) {
|
|
export function useStockDataFilter(fullData: StockData[]) {
|
|
|
- const [dayNum, setDayNum] = useState(120); // 默认120天
|
|
|
|
|
- const [offsetNum, setOffsetNum] = useState(120); // 默认偏移120天
|
|
|
|
|
|
|
+ const [selectedDays, setSelectedDays] = useState(120); // 默认120天
|
|
|
|
|
+ const [trainingProgress, setTrainingProgress] = useState(0); // 训练日进度
|
|
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
|
|
|
|
|
|
const filterData = useCallback(() => {
|
|
const filterData = useCallback(() => {
|
|
|
- if (!isInitialized) {
|
|
|
|
|
- return []; // 未初始化时返回空数组
|
|
|
|
|
|
|
+ if (!isInitialized || fullData.length === 0) {
|
|
|
|
|
+ return []; // 未初始化或数据为空时返回空数组
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const arrLen = fullData.length;
|
|
|
|
|
- // 从最后一天开始往前数 offsetNum 天
|
|
|
|
|
- let endIndex = arrLen - offsetNum;
|
|
|
|
|
- // 从 endIndex 再往前数 dayNum 天
|
|
|
|
|
- let startIndex = endIndex - dayNum;
|
|
|
|
|
|
|
+ const totalDays = fullData.length;
|
|
|
|
|
|
|
|
- // 确保索引在有效范围内
|
|
|
|
|
- startIndex = Math.max(0, startIndex);
|
|
|
|
|
- endIndex = Math.max(dayNum, endIndex); // 确保至少显示 dayNum 天的数据
|
|
|
|
|
|
|
+ // 计算训练日部分:从当前日期往前推选择的天数到当前日期
|
|
|
|
|
+ const trainingStartIndex = totalDays - selectedDays;
|
|
|
|
|
+ const trainingEndIndex = Math.min(
|
|
|
|
|
+ trainingStartIndex + trainingProgress,
|
|
|
|
|
+ totalDays
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
- return fullData.slice(startIndex, endIndex);
|
|
|
|
|
- }, [fullData, dayNum, offsetNum, isInitialized]);
|
|
|
|
|
|
|
+ // 计算历史天数部分:从训练日开始日期往前推至少365天
|
|
|
|
|
+ const historyEndIndex = trainingStartIndex;
|
|
|
|
|
+ const historyStartIndex = Math.max(0, historyEndIndex - Math.max(selectedDays, 365));
|
|
|
|
|
+
|
|
|
|
|
+ // 确保索引有效
|
|
|
|
|
+ if (historyStartIndex >= historyEndIndex) {
|
|
|
|
|
+ return []; // 没有历史数据时返回空数组
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 合并历史天数和已加载的训练日数据
|
|
|
|
|
+ const historyData = fullData.slice(historyStartIndex, historyEndIndex);
|
|
|
|
|
+ const trainingData = fullData.slice(trainingStartIndex, trainingEndIndex);
|
|
|
|
|
+
|
|
|
|
|
+ return [...historyData, ...trainingData];
|
|
|
|
|
+ }, [fullData, selectedDays, trainingProgress, isInitialized]);
|
|
|
|
|
|
|
|
const moveToNextDay = useCallback(() => {
|
|
const moveToNextDay = useCallback(() => {
|
|
|
return new Promise<string>((resolve) => {
|
|
return new Promise<string>((resolve) => {
|
|
|
- setOffsetNum((prev: number) => {
|
|
|
|
|
- const newOffset = Math.max(0, prev - 1);
|
|
|
|
|
- // 计算新的结束索引
|
|
|
|
|
- const endIndex = fullData.length - newOffset;
|
|
|
|
|
|
|
+ setTrainingProgress((prev) => {
|
|
|
|
|
+ const newProgress = prev + 1;
|
|
|
|
|
+ const totalDays = fullData.length;
|
|
|
|
|
+ const trainingStartIndex = totalDays - selectedDays;
|
|
|
|
|
+ const trainingEndIndex = Math.min(
|
|
|
|
|
+ trainingStartIndex + newProgress,
|
|
|
|
|
+ totalDays
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
// 返回最新日期
|
|
// 返回最新日期
|
|
|
- const nextDate = fullData[endIndex - 1]?.d || '';
|
|
|
|
|
|
|
+ const nextDate = fullData[trainingEndIndex - 1]?.d || '';
|
|
|
resolve(nextDate);
|
|
resolve(nextDate);
|
|
|
- return newOffset;
|
|
|
|
|
|
|
+ return newProgress;
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
- }, [fullData]);
|
|
|
|
|
|
|
+ }, [fullData, selectedDays]);
|
|
|
|
|
|
|
|
- const resetOffset = useCallback(() => {
|
|
|
|
|
- setOffsetNum(0);
|
|
|
|
|
|
|
+ const resetTrainingProgress = useCallback(() => {
|
|
|
|
|
+ setTrainingProgress(0);
|
|
|
}, []);
|
|
}, []);
|
|
|
|
|
|
|
|
- const setDayNumWithOffset = useCallback((num: number) => {
|
|
|
|
|
- setDayNum(num);
|
|
|
|
|
- setOffsetNum(num);
|
|
|
|
|
|
|
+ const setDayNumWithTraining = useCallback((days: number) => {
|
|
|
|
|
+ setSelectedDays(days);
|
|
|
|
|
+ setTrainingProgress(0); // 重置训练进度
|
|
|
}, []);
|
|
}, []);
|
|
|
|
|
|
|
|
const initializeView = useCallback(() => {
|
|
const initializeView = useCallback(() => {
|
|
|
setIsInitialized(true);
|
|
setIsInitialized(true);
|
|
|
}, []);
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
+ // 获取当前训练进度信息
|
|
|
|
|
+ const getTrainingInfo = useCallback(() => {
|
|
|
|
|
+ const totalDays = fullData.length;
|
|
|
|
|
+ const trainingStartIndex = totalDays - selectedDays;
|
|
|
|
|
+ const totalTrainingDays = Math.min(selectedDays, totalDays - trainingStartIndex);
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ currentProgress: trainingProgress,
|
|
|
|
|
+ totalTrainingDays,
|
|
|
|
|
+ remainingDays: totalTrainingDays - trainingProgress,
|
|
|
|
|
+ isTrainingComplete: trainingProgress >= totalTrainingDays
|
|
|
|
|
+ };
|
|
|
|
|
+ }, [fullData, selectedDays, trainingProgress]);
|
|
|
|
|
+
|
|
|
return {
|
|
return {
|
|
|
filteredData: filterData(),
|
|
filteredData: filterData(),
|
|
|
moveToNextDay,
|
|
moveToNextDay,
|
|
|
- resetOffset,
|
|
|
|
|
- setDayNum: setDayNumWithOffset,
|
|
|
|
|
|
|
+ resetTrainingProgress,
|
|
|
|
|
+ setDayNum: setDayNumWithTraining,
|
|
|
initializeView,
|
|
initializeView,
|
|
|
- isInitialized
|
|
|
|
|
|
|
+ isInitialized,
|
|
|
|
|
+ trainingInfo: getTrainingInfo()
|
|
|
};
|
|
};
|
|
|
-}
|
|
|
|
|
|
|
+}
|