Replay is ok now
This commit is contained in:
+184
-65
@@ -5288,6 +5288,7 @@
|
||||
// 数据回放相关变量
|
||||
let replayTimer = null;
|
||||
let replayData = null;
|
||||
let replayStepData = null; // 存储逐步计算的回放数据
|
||||
let currentReplayIndex = 0;
|
||||
let totalReplaySteps = 0;
|
||||
let isReplaying = false;
|
||||
@@ -5373,7 +5374,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 请求整个时间范围的数据
|
||||
// 请求整个时间范围的数据,包含回放数据
|
||||
$.ajax({
|
||||
url: '/api/analyze',
|
||||
data: {
|
||||
@@ -5383,7 +5384,8 @@
|
||||
element_timeframe: elementTimeframe,
|
||||
start_time: replayStartTime,
|
||||
end_time: replayEndTime,
|
||||
elements_only: false
|
||||
elements_only: false,
|
||||
need_replay_data: true // 请求逐步计算的回放数据
|
||||
},
|
||||
success: function(data) {
|
||||
// 检查是否有有效数据
|
||||
@@ -5414,7 +5416,24 @@
|
||||
|
||||
// 初始化回放
|
||||
function initReplay() {
|
||||
if (!replayData || !replayData.kline_data || replayData.kline_data.length === 0) {
|
||||
// 检查是否有新的回放数据结构
|
||||
if (replayData && replayData.replay_data) {
|
||||
console.log('使用新的逐步计算回放数据');
|
||||
replayStepData = replayData.replay_data; // 存储逐步计算的数据
|
||||
totalReplaySteps = Object.keys(replayStepData).length;
|
||||
|
||||
if (totalReplaySteps === 0) {
|
||||
$('#replayStatus').text('没有可回放的数据');
|
||||
$('#replayProgress').hide();
|
||||
$('#startReplay').show();
|
||||
$('#stopReplay').hide();
|
||||
return;
|
||||
}
|
||||
} else if (replayData && replayData.kline_data && replayData.kline_data.length > 0) {
|
||||
console.log('使用传统回放数据结构');
|
||||
replayStepData = null; // 标记使用传统方式
|
||||
totalReplaySteps = replayData.kline_data.length;
|
||||
} else {
|
||||
$('#replayStatus').text('没有可回放的数据');
|
||||
$('#replayProgress').hide();
|
||||
$('#startReplay').show();
|
||||
@@ -5425,7 +5444,6 @@
|
||||
// 设置回放变量
|
||||
isReplaying = true;
|
||||
currentReplayIndex = 0;
|
||||
totalReplaySteps = replayData.kline_data.length;
|
||||
|
||||
// 更新回放状态
|
||||
$('#replayStatus').text(`准备回放 (0/${totalReplaySteps})`);
|
||||
@@ -5440,59 +5458,90 @@
|
||||
|
||||
// 准备初始回放数据
|
||||
function prepareInitialReplayData() {
|
||||
// 创建初始数据集,只包含第一根K线
|
||||
const initialData = $.extend(true, {}, replayData);
|
||||
let initialData;
|
||||
|
||||
// 确保第一根K线数据有效
|
||||
if (!replayData.kline_data || replayData.kline_data.length === 0) {
|
||||
console.error('无有效K线数据用于回放');
|
||||
$('#replayStatus').text('无有效数据用于回放');
|
||||
$('#replayProgress').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
initialData.kline_data = [replayData.kline_data[0]];
|
||||
|
||||
// 确保初始K线数据的所有字段都有值
|
||||
const firstKline = initialData.kline_data[0];
|
||||
if (firstKline) {
|
||||
// 确保K线数据的每个字段都是有效的数值
|
||||
['open', 'high', 'low', 'close', 'volume'].forEach(field => {
|
||||
if (firstKline[field] === null || firstKline[field] === undefined || isNaN(firstKline[field])) {
|
||||
console.warn(`K线数据的${field}字段无效,设置为默认值`);
|
||||
firstKline[field] = field === 'volume' ? 0 : firstKline.close || 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 清空其他数据列表,因为还没有处理
|
||||
initialData.bi_list = [];
|
||||
initialData.seg_list = [];
|
||||
initialData.zs_list = [];
|
||||
initialData.uncompleted_zs_list = [];
|
||||
initialData.element_bi_list = [];
|
||||
initialData.element_seg_list = [];
|
||||
initialData.element_zs_list = [];
|
||||
initialData.element_uncompleted_zs_list = [];
|
||||
initialData.macd_divergence = [];
|
||||
initialData.klc_fx_type = [];
|
||||
|
||||
// 初始化MACD数据
|
||||
if (initialData.macd && initialData.macd.length > 0) {
|
||||
initialData.macd = [initialData.macd[0]];
|
||||
// 检查是否使用新的逐步计算回放数据
|
||||
if (replayStepData) {
|
||||
// 使用第一步的数据作为初始数据
|
||||
initialData = $.extend(true, {}, replayStepData[0]);
|
||||
console.log('使用逐步计算的初始数据');
|
||||
} else {
|
||||
// 使用传统方式,创建初始数据集,只包含第一根K线
|
||||
initialData = $.extend(true, {}, replayData);
|
||||
|
||||
// 确保MACD数据有效
|
||||
const firstMacd = initialData.macd[0];
|
||||
if (firstMacd) {
|
||||
['dif', 'dea', 'macd'].forEach(field => {
|
||||
if (firstMacd[field] === null || firstMacd[field] === undefined || isNaN(firstMacd[field])) {
|
||||
console.warn(`MACD数据的${field}字段无效,设置为0`);
|
||||
firstMacd[field] = 0;
|
||||
// 确保第一根K线数据有效
|
||||
if (!replayData.kline_data || replayData.kline_data.length === 0) {
|
||||
console.error('无有效K线数据用于回放');
|
||||
$('#replayStatus').text('无有效数据用于回放');
|
||||
$('#replayProgress').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// 传统方式的数据清空逻辑
|
||||
initialData.kline_data = [replayData.kline_data[0]];
|
||||
|
||||
// 确保初始K线数据的所有字段都有值
|
||||
const firstKline = initialData.kline_data[0];
|
||||
if (firstKline) {
|
||||
// 确保K线数据的每个字段都是有效的数值
|
||||
['open', 'high', 'low', 'close', 'volume'].forEach(field => {
|
||||
if (firstKline[field] === null || firstKline[field] === undefined || isNaN(firstKline[field])) {
|
||||
console.warn(`K线数据的${field}字段无效,设置为默认值`);
|
||||
firstKline[field] = field === 'volume' ? 0 : firstKline.close || 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 清空其他数据列表,因为还没有处理
|
||||
initialData.bi_list = [];
|
||||
initialData.seg_list = [];
|
||||
initialData.zs_list = [];
|
||||
initialData.uncompleted_zs_list = [];
|
||||
initialData.element_bi_list = [];
|
||||
initialData.element_seg_list = [];
|
||||
initialData.element_zs_list = [];
|
||||
initialData.element_uncompleted_zs_list = [];
|
||||
initialData.trade_points = [];
|
||||
initialData.element_trade_points = [];
|
||||
initialData.macd_divergence = [];
|
||||
initialData.klc_fx_type = [];
|
||||
// 清空分型相关数据
|
||||
initialData.klc_fx_info = [];
|
||||
initialData.klu_fx_info = [];
|
||||
initialData.element_klc_fx_info = [];
|
||||
initialData.element_klu_fx_info = [];
|
||||
|
||||
// 初始化MACD数据
|
||||
if (initialData.macd && typeof initialData.macd === 'object') {
|
||||
// MACD数据是对象结构 {macd: [], signal: [], histogram: []}
|
||||
if (initialData.macd.macd && initialData.macd.macd.length > 0) {
|
||||
initialData.macd = {
|
||||
macd: [initialData.macd.macd[0] || 0],
|
||||
signal: [initialData.macd.signal[0] || 0],
|
||||
histogram: [initialData.macd.histogram[0] || 0]
|
||||
};
|
||||
} else {
|
||||
// 如果没有MACD数据,创建默认值
|
||||
initialData.macd = {
|
||||
macd: [0],
|
||||
signal: [0],
|
||||
histogram: [0]
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// 如果MACD数据结构不正确,创建默认值
|
||||
initialData.macd = {
|
||||
macd: [0],
|
||||
signal: [0],
|
||||
histogram: [0]
|
||||
};
|
||||
}
|
||||
|
||||
console.log('使用传统方式生成初始数据');
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 更新图表,固定坐标轴范围
|
||||
currentData = initialData;
|
||||
|
||||
@@ -5507,6 +5556,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 输出调试信息,确认数据已正确清空
|
||||
console.log('回放初始化完成,数据统计:');
|
||||
console.log('K线数据:', initialData.kline_data ? initialData.kline_data.length : 0, '条');
|
||||
console.log('笔数据:', initialData.bi_list ? initialData.bi_list.length : 0, '条');
|
||||
console.log('线段数据:', initialData.seg_list ? initialData.seg_list.length : 0, '条');
|
||||
console.log('中枢数据:', initialData.zs_list ? initialData.zs_list.length : 0, '条');
|
||||
console.log('KLC分型数据:', initialData.klc_fx_info ? initialData.klc_fx_info.length : 0, '条');
|
||||
console.log('KLU分型数据:', initialData.klu_fx_info ? initialData.klu_fx_info.length : 0, '条');
|
||||
console.log('买卖点数据:', initialData.trade_points ? initialData.trade_points.length : 0, '条');
|
||||
|
||||
// 刷新图表
|
||||
refreshChart(initialData);
|
||||
|
||||
@@ -5581,15 +5640,35 @@
|
||||
currentReplayIndex++;
|
||||
updateReplayStatus();
|
||||
|
||||
// 创建截止到当前索引的数据子集
|
||||
const subsetData = createDataSubset(currentReplayIndex);
|
||||
let subsetData;
|
||||
|
||||
// 检查是否使用新的逐步计算数据
|
||||
if (replayStepData) {
|
||||
// 直接使用预计算的数据
|
||||
subsetData = $.extend(true, {}, replayStepData[currentReplayIndex - 1]);
|
||||
console.log(`回放步骤 ${currentReplayIndex}/${totalReplaySteps} (使用预计算数据)`);
|
||||
} else {
|
||||
// 使用传统方式创建数据子集
|
||||
subsetData = createDataSubset(currentReplayIndex);
|
||||
console.log(`回放步骤 ${currentReplayIndex}/${totalReplaySteps} (传统方式)`);
|
||||
}
|
||||
|
||||
// 输出回放进度调试信息
|
||||
if (currentReplayIndex % 10 === 0 || currentReplayIndex <= 5) { // 每10步输出一次,或前5步
|
||||
console.log('K线数据:', subsetData.kline_data ? subsetData.kline_data.length : 0, '条');
|
||||
console.log('笔数据:', subsetData.bi_list ? subsetData.bi_list.length : 0, '条');
|
||||
console.log('KLC分型:', subsetData.klc_fx_info ? subsetData.klc_fx_info.length : 0, '条');
|
||||
console.log('KLU分型:', subsetData.klu_fx_info ? subsetData.klu_fx_info.length : 0, '条');
|
||||
}
|
||||
|
||||
// 更新图表
|
||||
currentData = subsetData;
|
||||
refreshChart(subsetData);
|
||||
|
||||
// 固定Y轴范围
|
||||
fixYAxisRange();
|
||||
if (!replayStepData) { // 只有传统方式需要固定Y轴
|
||||
fixYAxisRange();
|
||||
}
|
||||
|
||||
// 保持最新数据可见
|
||||
keepLatestDataVisible();
|
||||
@@ -5699,19 +5778,32 @@
|
||||
subsetData.element_uncompleted_zs_list = filterDataByTime(replayData.element_uncompleted_zs_list, currentEndTime);
|
||||
}
|
||||
|
||||
// 过滤MACD
|
||||
if (subsetData.macd && subsetData.macd.length) {
|
||||
subsetData.macd = replayData.macd.slice(0, endIndex);
|
||||
|
||||
// 验证MACD数据
|
||||
subsetData.macd.forEach((item, index) => {
|
||||
['dif', 'dea', 'macd'].forEach(field => {
|
||||
if (item[field] === null || item[field] === undefined || isNaN(item[field])) {
|
||||
console.warn(`MACD数据[${index}]的${field}字段无效,设置为0`);
|
||||
item[field] = 0;
|
||||
}
|
||||
// 过滤MACD数据
|
||||
if (subsetData.macd && typeof subsetData.macd === 'object') {
|
||||
if (replayData.macd.macd && replayData.macd.macd.length > 0) {
|
||||
subsetData.macd = {
|
||||
macd: replayData.macd.macd.slice(0, endIndex),
|
||||
signal: replayData.macd.signal.slice(0, endIndex),
|
||||
histogram: replayData.macd.histogram.slice(0, endIndex)
|
||||
};
|
||||
|
||||
// 验证MACD数据
|
||||
['macd', 'signal', 'histogram'].forEach(field => {
|
||||
subsetData.macd[field].forEach((value, index) => {
|
||||
if (value === null || value === undefined || isNaN(value)) {
|
||||
console.warn(`MACD ${field}[${index}]数据无效,设置为0`);
|
||||
subsetData.macd[field][index] = 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 如果没有有效的MACD数据,创建默认数组
|
||||
subsetData.macd = {
|
||||
macd: new Array(endIndex).fill(0),
|
||||
signal: new Array(endIndex).fill(0),
|
||||
histogram: new Array(endIndex).fill(0)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤MACD背离
|
||||
@@ -5723,6 +5815,32 @@
|
||||
if (subsetData.klc_fx_type && subsetData.klc_fx_type.length) {
|
||||
subsetData.klc_fx_type = filterDataByTime(replayData.klc_fx_type, currentEndTime, 'time');
|
||||
}
|
||||
|
||||
// 过滤分型信息数据
|
||||
if (subsetData.klc_fx_info && subsetData.klc_fx_info.length) {
|
||||
subsetData.klc_fx_info = filterDataByTime(replayData.klc_fx_info, currentEndTime, 'time');
|
||||
}
|
||||
|
||||
if (subsetData.klu_fx_info && subsetData.klu_fx_info.length) {
|
||||
subsetData.klu_fx_info = filterDataByTime(replayData.klu_fx_info, currentEndTime, 'time');
|
||||
}
|
||||
|
||||
if (subsetData.element_klc_fx_info && subsetData.element_klc_fx_info.length) {
|
||||
subsetData.element_klc_fx_info = filterDataByTime(replayData.element_klc_fx_info, currentEndTime, 'time');
|
||||
}
|
||||
|
||||
if (subsetData.element_klu_fx_info && subsetData.element_klu_fx_info.length) {
|
||||
subsetData.element_klu_fx_info = filterDataByTime(replayData.element_klu_fx_info, currentEndTime, 'time');
|
||||
}
|
||||
|
||||
// 过滤买卖点数据
|
||||
if (subsetData.trade_points && subsetData.trade_points.length) {
|
||||
subsetData.trade_points = filterDataByTime(replayData.trade_points, currentEndTime, 'time');
|
||||
}
|
||||
|
||||
if (subsetData.element_trade_points && subsetData.element_trade_points.length) {
|
||||
subsetData.element_trade_points = filterDataByTime(replayData.element_trade_points, currentEndTime, 'time');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('过滤数据时出错:', e);
|
||||
}
|
||||
@@ -5777,6 +5895,7 @@
|
||||
isReplaying = false;
|
||||
currentReplayIndex = 0;
|
||||
replayData = null;
|
||||
replayStepData = null; // 清理逐步计算数据
|
||||
|
||||
// 更新UI
|
||||
$('#replayStatus').text('');
|
||||
|
||||
Reference in New Issue
Block a user