三周期分开关控制,只画数字不画图标;线段面积比沿用同向笔面积口径。 Co-authored-by: Cursor <cursoragent@cursor.com>
1017 lines
54 KiB
JavaScript
1017 lines
54 KiB
JavaScript
/* chart_tv_chan.js — BI / SEG / ZS */
|
||
|
||
/** 按界面结束时间裁掉被 recent 合并进来的更晚 K 线 */
|
||
function klinesUpToSelectedEnd(klineData) {
|
||
if (!Array.isArray(klineData) || !klineData.length) return [];
|
||
const endVal = $('#end_time').val();
|
||
if (!endVal) return klineData;
|
||
const endMs = new Date(endVal).getTime();
|
||
if (isNaN(endMs)) return klineData;
|
||
const out = [];
|
||
for (let i = 0; i < klineData.length; i++) {
|
||
const k = klineData[i];
|
||
let t;
|
||
if (k.timestamp != null && k.timestamp !== '') {
|
||
t = Number(k.timestamp);
|
||
} else {
|
||
t = new Date(k.date).getTime();
|
||
}
|
||
if (!isNaN(t) && t <= endMs) out.push(k);
|
||
}
|
||
return out;
|
||
}
|
||
|
||
function alignTimeToChartCandles(targetSec, chartCandles) {
|
||
if (targetSec == null || isNaN(targetSec)) return targetSec;
|
||
if (!Array.isArray(chartCandles) || !chartCandles.length) return targetSec;
|
||
const t = Math.floor(Number(targetSec));
|
||
let best = Math.floor(Number(chartCandles[0].time));
|
||
let bestDiff = Math.abs(best - t);
|
||
for (let i = 1; i < chartCandles.length; i++) {
|
||
const ct = Math.floor(Number(chartCandles[i].time));
|
||
if (!isFinite(ct)) continue;
|
||
const d = Math.abs(ct - t);
|
||
if (d < bestDiff) {
|
||
best = ct;
|
||
bestDiff = d;
|
||
}
|
||
}
|
||
return best;
|
||
}
|
||
|
||
function getLastBarFromChartCandles(chartCandles) {
|
||
if (!Array.isArray(chartCandles) || !chartCandles.length) return null;
|
||
const c = chartCandles[chartCandles.length - 1];
|
||
if (!c || c.time == null) return null;
|
||
return {
|
||
time: Math.floor(Number(c.time)),
|
||
high: parseFloat(c.high),
|
||
low: parseFloat(c.low),
|
||
close: parseFloat(c.close)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 未完成笔终点:优先分析 end_price;时间接到该周期末根并 snap 到图表 candles。
|
||
*/
|
||
function resolveUncompletedBiEndpoint(bi, klineData, chartCandles) {
|
||
const clipped = klinesUpToSelectedEnd(klineData);
|
||
const startTime = Math.floor(new Date(bi.start_time).getTime() / 1000);
|
||
const startPrice = parseFloat(bi.start_price);
|
||
let endPrice = parseFloat(bi.end_price);
|
||
let endTime = bi.end_time ? Math.floor(new Date(bi.end_time).getTime() / 1000) : NaN;
|
||
const lastFromChart = getLastBarFromChartCandles(chartCandles);
|
||
const lastK = clipped.length ? clipped[clipped.length - 1] : null;
|
||
|
||
if (lastFromChart) {
|
||
endTime = lastFromChart.time;
|
||
if (isNaN(endPrice)) {
|
||
endPrice = bi.direction === 1 ? lastFromChart.high : lastFromChart.low;
|
||
}
|
||
} else if (lastK) {
|
||
const lastTime = Math.floor(new Date(lastK.date).getTime() / 1000);
|
||
if (!isNaN(lastTime)) endTime = lastTime;
|
||
if (isNaN(endPrice)) {
|
||
endPrice = bi.direction === 1 ? parseFloat(lastK.high) : parseFloat(lastK.low);
|
||
}
|
||
}
|
||
endTime = alignTimeToChartCandles(endTime, chartCandles);
|
||
return { startTime: startTime, endTime: endTime, startPrice: startPrice, endPrice: endPrice };
|
||
}
|
||
|
||
function resolveUncompletedSegEndpoint(seg, klineData, chartCandles) {
|
||
const startTime = Math.floor(new Date(seg.start_time).getTime() / 1000);
|
||
const startPrice = parseFloat(seg.start_price);
|
||
let endTime;
|
||
let endPrice;
|
||
|
||
if (seg.end_time != null && seg.end_price != null && seg.end_price !== '' && !isNaN(parseFloat(seg.end_price))) {
|
||
endTime = Math.floor(new Date(seg.end_time).getTime() / 1000);
|
||
endPrice = parseFloat(seg.end_price);
|
||
endTime = alignTimeToChartCandles(endTime, chartCandles);
|
||
} else {
|
||
const ep = resolveUncompletedBiEndpoint({
|
||
start_time: seg.start_time,
|
||
start_price: seg.start_price,
|
||
end_price: null,
|
||
end_time: null,
|
||
direction: seg.direction
|
||
}, klineData, chartCandles);
|
||
endTime = ep.endTime;
|
||
endPrice = ep.endPrice;
|
||
}
|
||
return { startTime: startTime, endTime: endTime, startPrice: startPrice, endPrice: endPrice };
|
||
}
|
||
|
||
function chartTvRenderChan(ctx) {
|
||
var symbol = ctx.symbol;
|
||
var timeframe = ctx.timeframe;
|
||
var symbolConfig = ctx.symbolConfig;
|
||
var useSubSubPeriod = ctx.useSubSubPeriod;
|
||
var useElementPeriod = ctx.useElementPeriod;
|
||
var klinePeriodLabel = ctx.klinePeriodLabel;
|
||
var candles = ctx.candles;
|
||
var klineDataSource = ctx.klineDataSource;
|
||
var container = ctx.container;
|
||
var showMacd = ctx.showMacd;
|
||
var showOriginalKline = ctx.showOriginalKline;
|
||
var mainChartContainer = ctx.mainChartContainer;
|
||
var volumeChartContainer = ctx.volumeChartContainer;
|
||
var atrChartContainer = ctx.atrChartContainer;
|
||
var macdChartContainer = ctx.macdChartContainer;
|
||
var chanMacdChartContainer = ctx.chanMacdChartContainer;
|
||
var mainChart = ctx.mainChart;
|
||
var volumeChart = ctx.volumeChart;
|
||
var atrChart = ctx.atrChart;
|
||
var macdChart = ctx.macdChart;
|
||
var chanMacdChart = ctx.chanMacdChart;
|
||
var createChartOptions = ctx.createChartOptions;
|
||
// 图表同步事件统一由文末 bindSyncEvents 注册(带 cleanup),此处不再重复 addEventListener,
|
||
// 否则每次自动刷新/重建都会在 document/window 上堆积监听导致内存泄漏。
|
||
// 显示笔的绘制 - 分别处理主周期、次周期和次次周期
|
||
if ($('#showMainBi').is(':checked') || $('#showElementBi').is(':checked') || $('#showSubSubBi').is(':checked')) {
|
||
console.log('绘制笔 - 已启用');
|
||
let biLines = [];
|
||
|
||
// 主周期笔
|
||
if ($('#showMainBi').is(':checked') && currentData.bi_list && currentData.bi_list.length > 0) {
|
||
console.log(`绘制主周期笔数据,共${currentData.bi_list.length}条`);
|
||
|
||
// 清空已有的主周期笔系列
|
||
tvWidget.series.mainBiSeries = [];
|
||
tvWidget.series.mainUncompletedBiSeries = [];
|
||
|
||
// 遍历处理每个笔
|
||
currentData.bi_list.forEach(function(bi) {
|
||
try {
|
||
// 直接使用UTC时间戳(秒)
|
||
const startTime = Math.floor(new Date(bi.start_time).getTime() / 1000);
|
||
const endTime = Math.floor(new Date(bi.end_time).getTime() / 1000);
|
||
|
||
if (isNaN(startTime) || isNaN(endTime)) {
|
||
console.error('主周期笔时间转换错误:', bi.start_time, bi.end_time);
|
||
return;
|
||
}
|
||
|
||
const startPrice = parseFloat(bi.start_price);
|
||
const endPrice = parseFloat(bi.end_price);
|
||
|
||
if (isNaN(startPrice) || isNaN(endPrice)) {
|
||
console.error('主周期笔价格转换错误:', bi.start_price, bi.end_price);
|
||
return;
|
||
}
|
||
|
||
// 添加线段
|
||
biLines.push({
|
||
startTime: startTime,
|
||
endTime: endTime,
|
||
startPrice: startPrice,
|
||
endPrice: endPrice,
|
||
color: bi.direction === 1 ? '#dc3545' : '#28a745', // 主周期笔颜色
|
||
lineWidth: 1,
|
||
});
|
||
|
||
// 添加到图表对象
|
||
tvWidget.series.mainBiSeries.push({
|
||
time: startTime,
|
||
value: startPrice,
|
||
color: bi.direction === 1 ? '#dc3545' : '#28a745',
|
||
lineWidth: 1
|
||
});
|
||
} catch (e) {
|
||
console.error('主周期笔处理出错:', e);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 次周期笔
|
||
if ($('#showElementBi').is(':checked') && currentData.element_bi_list && currentData.element_bi_list.length > 0) {
|
||
console.log(`绘制次周期笔数据,共${currentData.element_bi_list.length}条`);
|
||
|
||
// 清空已有的次周期笔系列
|
||
tvWidget.series.elementBiSeries = [];
|
||
tvWidget.series.elementUncompletedBiSeries = [];
|
||
|
||
currentData.element_bi_list.forEach(function(bi) {
|
||
try {
|
||
// 直接使用UTC时间戳(秒)
|
||
const startTime = Math.floor(new Date(bi.start_time).getTime() / 1000);
|
||
const endTime = Math.floor(new Date(bi.end_time).getTime() / 1000);
|
||
|
||
if (isNaN(startTime) || isNaN(endTime)) {
|
||
console.error('次周期笔时间转换错误:', bi.start_time, bi.end_time);
|
||
return;
|
||
}
|
||
|
||
const startPrice = parseFloat(bi.start_price);
|
||
const endPrice = parseFloat(bi.end_price);
|
||
|
||
if (isNaN(startPrice) || isNaN(endPrice)) {
|
||
console.error('次周期笔价格转换错误:', bi.start_price, bi.end_price);
|
||
return;
|
||
}
|
||
|
||
// 添加线段
|
||
biLines.push({
|
||
startTime: startTime,
|
||
endTime: endTime,
|
||
startPrice: startPrice,
|
||
endPrice: endPrice,
|
||
color: bi.direction === 1 ? '#9c27b0' : '#673ab7', // 次周期笔颜色
|
||
lineWidth: 1,
|
||
});
|
||
|
||
// 添加到图表对象
|
||
tvWidget.series.elementBiSeries.push({
|
||
time: startTime,
|
||
value: startPrice,
|
||
color: bi.direction === 1 ? '#9c27b0' : '#673ab7',
|
||
lineWidth: 1
|
||
});
|
||
} catch (e) {
|
||
console.error('次周期笔处理出错:', e);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 绘制未完成笔 - 主周期
|
||
if ($('#showMainBi').is(':checked') && currentData.uncompleted_bi_list && currentData.uncompleted_bi_list.length > 0) {
|
||
console.log(`绘制主周期未完成笔数据,共${currentData.uncompleted_bi_list.length}条`);
|
||
|
||
currentData.uncompleted_bi_list.forEach(function(bi) {
|
||
try {
|
||
const ep = resolveUncompletedBiEndpoint(bi, currentData.kline_data, candles);
|
||
if (isNaN(ep.startTime) || isNaN(ep.endTime) || isNaN(ep.startPrice) || isNaN(ep.endPrice)) {
|
||
console.error('主周期未完成笔时间/价格转换错误:', bi.start_time, bi.end_price);
|
||
return;
|
||
}
|
||
|
||
// 添加未完成笔(红色虚线)
|
||
biLines.push({
|
||
startTime: ep.startTime,
|
||
endTime: ep.endTime,
|
||
startPrice: ep.startPrice,
|
||
endPrice: ep.endPrice,
|
||
color: '#FF0000', // 红色
|
||
lineWidth: 1,
|
||
lineStyle: 2 // 虚线
|
||
});
|
||
|
||
// 添加到图表对象
|
||
tvWidget.series.mainUncompletedBiSeries.push({
|
||
time: ep.startTime,
|
||
value: ep.startPrice,
|
||
color: '#FF0000',
|
||
lineWidth: 1,
|
||
lineStyle: 2
|
||
});
|
||
} catch (e) {
|
||
console.error('主周期未完成笔处理出错:', e);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 绘制未完成笔 - 次周期
|
||
if ($('#showElementBi').is(':checked') && currentData.element_uncompleted_bi_list && currentData.element_uncompleted_bi_list.length > 0) {
|
||
console.log(`绘制次周期未完成笔数据,共${currentData.element_uncompleted_bi_list.length}条`);
|
||
|
||
currentData.element_uncompleted_bi_list.forEach(function(bi) {
|
||
try {
|
||
const ep = resolveUncompletedBiEndpoint(
|
||
bi,
|
||
currentData.element_kline_data || currentData.kline_data,
|
||
candles
|
||
);
|
||
if (isNaN(ep.startTime) || isNaN(ep.endTime) || isNaN(ep.startPrice) || isNaN(ep.endPrice)) {
|
||
console.error('次周期未完成笔时间/价格转换错误:', bi.start_time, bi.end_price);
|
||
return;
|
||
}
|
||
|
||
// 添加未完成笔(红色虚线)
|
||
biLines.push({
|
||
startTime: ep.startTime,
|
||
endTime: ep.endTime,
|
||
startPrice: ep.startPrice,
|
||
endPrice: ep.endPrice,
|
||
color: '#FF0000', // 红色
|
||
lineWidth: 1,
|
||
lineStyle: 2 // 虚线
|
||
});
|
||
|
||
// 添加到图表对象
|
||
tvWidget.series.elementUncompletedBiSeries.push({
|
||
time: ep.startTime,
|
||
value: ep.startPrice,
|
||
color: '#FF0000',
|
||
lineWidth: 1,
|
||
lineStyle: 2
|
||
});
|
||
} catch (e) {
|
||
console.error('次周期未完成笔处理出错:', e);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 次次周期笔
|
||
if ($('#showSubSubBi').is(':checked') && currentData.sub_sub_bi_list && currentData.sub_sub_bi_list.length > 0) {
|
||
tvWidget.series.subSubBiSeries = [];
|
||
tvWidget.series.subSubUncompletedBiSeries = [];
|
||
currentData.sub_sub_bi_list.forEach(function(bi) {
|
||
try {
|
||
const startTime = Math.floor(new Date(bi.start_time).getTime() / 1000);
|
||
const endTime = bi.end_time ? Math.floor(new Date(bi.end_time).getTime() / 1000) : 0;
|
||
if (isNaN(startTime) || !endTime) return;
|
||
const startPrice = parseFloat(bi.start_price);
|
||
const endPrice = parseFloat(bi.end_price);
|
||
if (isNaN(startPrice) || isNaN(endPrice)) return;
|
||
biLines.push({
|
||
startTime: startTime, endTime: endTime, startPrice: startPrice, endPrice: endPrice,
|
||
color: bi.direction === 1 ? '#00897b' : '#26a69a', lineWidth: 1, lineStyle: 0
|
||
});
|
||
tvWidget.series.subSubBiSeries.push({ time: startTime, value: startPrice, color: '#00897b', lineWidth: 1 });
|
||
} catch (e) { console.error('次次周期笔处理出错:', e); }
|
||
});
|
||
}
|
||
// 次次周期未完成笔
|
||
if ($('#showSubSubBi').is(':checked') && currentData.sub_sub_uncompleted_bi_list && currentData.sub_sub_uncompleted_bi_list.length > 0) {
|
||
if (!tvWidget.series.subSubBiSeries) tvWidget.series.subSubBiSeries = [];
|
||
if (!tvWidget.series.subSubUncompletedBiSeries) tvWidget.series.subSubUncompletedBiSeries = [];
|
||
currentData.sub_sub_uncompleted_bi_list.forEach(function(bi) {
|
||
try {
|
||
const ep = resolveUncompletedBiEndpoint(
|
||
bi,
|
||
currentData.sub_sub_kline_data || currentData.kline_data,
|
||
candles
|
||
);
|
||
if (isNaN(ep.startTime) || isNaN(ep.endTime) || isNaN(ep.startPrice) || isNaN(ep.endPrice)) return;
|
||
biLines.push({
|
||
startTime: ep.startTime, endTime: ep.endTime, startPrice: ep.startPrice, endPrice: ep.endPrice,
|
||
color: '#00695c', lineWidth: 1, lineStyle: 2
|
||
});
|
||
tvWidget.series.subSubUncompletedBiSeries.push({ time: ep.startTime, value: ep.startPrice, color: '#00695c', lineWidth: 1, lineStyle: 2 });
|
||
} catch (e) { console.error('次次周期未完成笔处理出错:', e); }
|
||
});
|
||
}
|
||
|
||
// 添加所有笔到图表
|
||
// 1m 等小周期叠加到大周期时,笔数量会非常大;每条笔创建一个 series 会导致主图渲染退化
|
||
// 这里限制绘制数量,优先保留最新笔,避免把主K线和其他元素“挤没”
|
||
const MAX_BI_LINE_SERIES = 800;
|
||
if (biLines.length > MAX_BI_LINE_SERIES) {
|
||
console.warn(`BI线条过多(${biLines.length}),仅绘制最新 ${MAX_BI_LINE_SERIES} 条以保障主图稳定`);
|
||
}
|
||
const linesToDraw = biLines.length > MAX_BI_LINE_SERIES
|
||
? biLines.slice(-MAX_BI_LINE_SERIES)
|
||
: biLines;
|
||
|
||
linesToDraw.forEach(line => {
|
||
try {
|
||
if (!Number.isFinite(line.startTime) || !Number.isFinite(line.endTime)) return;
|
||
if (!Number.isFinite(line.startPrice) || !Number.isFinite(line.endPrice)) return;
|
||
if (line.endTime <= line.startTime) return;
|
||
|
||
const lineSeries = mainChart.addLineSeries({
|
||
color: line.color,
|
||
lineWidth: line.lineWidth,
|
||
lineStyle: line.lineStyle || 0, // 支持虚线样式
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
lineSeries.setData([
|
||
{ time: line.startTime, value: line.startPrice },
|
||
{ time: line.endTime, value: line.endPrice }
|
||
]);
|
||
} catch (e) {
|
||
console.warn('绘制BI线段失败,已跳过单条异常数据:', e);
|
||
}
|
||
});
|
||
} else {
|
||
console.log('绘制笔 - 已禁用');
|
||
}
|
||
// 显示线段的绘制 - 分别处理主周期、次周期和次次周期
|
||
if ($('#showMainSeg').is(':checked') || $('#showElementSeg').is(':checked') || $('#showSubSubSeg').is(':checked')) {
|
||
console.log('绘制线段 - 已启用');
|
||
let segLines = [];
|
||
|
||
// 主周期线段
|
||
if ($('#showMainSeg').is(':checked') && currentData.seg_list && currentData.seg_list.length > 0) {
|
||
console.log(`绘制主周期线段数据,共${currentData.seg_list.length}条`);
|
||
|
||
// 清空已有的主周期线段系列
|
||
tvWidget.series.mainSegSeries = [];
|
||
tvWidget.series.mainUncompletedSegSeries = [];
|
||
|
||
currentData.seg_list.forEach(function(seg) {
|
||
try {
|
||
// 直接使用UTC时间戳(秒)
|
||
const startTime = Math.floor(new Date(seg.start_time).getTime() / 1000);
|
||
const endTime = Math.floor(new Date(seg.end_time).getTime() / 1000);
|
||
|
||
if (isNaN(startTime) || isNaN(endTime)) {
|
||
console.error('主周期线段时间转换错误:', seg.start_time, seg.end_time);
|
||
return;
|
||
}
|
||
|
||
const startPrice = parseFloat(seg.start_price);
|
||
const endPrice = parseFloat(seg.end_price);
|
||
|
||
if (isNaN(startPrice) || isNaN(endPrice)) {
|
||
console.error('主周期线段价格转换错误:', seg.start_price, seg.end_price);
|
||
return;
|
||
}
|
||
|
||
// 添加线段
|
||
segLines.push({
|
||
startTime: startTime,
|
||
endTime: endTime,
|
||
startPrice: startPrice,
|
||
endPrice: endPrice,
|
||
color: seg.direction === 1 ? '#FF6B6B' : '#4CAF50', // 主周期线段颜色
|
||
lineWidth: 2,
|
||
});
|
||
|
||
// 添加到图表对象
|
||
tvWidget.series.mainSegSeries.push({
|
||
time: startTime,
|
||
value: startPrice,
|
||
color: seg.direction === 1 ? '#FF6B6B' : '#4CAF50',
|
||
lineWidth: 2
|
||
});
|
||
} catch (e) {
|
||
console.error('主周期线段处理出错:', e);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 次周期线段
|
||
if ($('#showElementSeg').is(':checked') && currentData.element_seg_list && currentData.element_seg_list.length > 0) {
|
||
console.log(`绘制次周期线段数据,共${currentData.element_seg_list.length}条`);
|
||
|
||
// 清空已有的次周期线段系列
|
||
tvWidget.series.elementSegSeries = [];
|
||
tvWidget.series.elementUncompletedSegSeries = [];
|
||
|
||
currentData.element_seg_list.forEach(function(seg) {
|
||
try {
|
||
// 直接使用UTC时间戳(秒)
|
||
const startTime = Math.floor(new Date(seg.start_time).getTime() / 1000);
|
||
const endTime = Math.floor(new Date(seg.end_time).getTime() / 1000);
|
||
|
||
if (isNaN(startTime) || isNaN(endTime)) {
|
||
console.error('次周期线段时间转换错误:', seg.start_time, seg.end_time);
|
||
return;
|
||
}
|
||
|
||
const startPrice = parseFloat(seg.start_price);
|
||
const endPrice = parseFloat(seg.end_price);
|
||
|
||
if (isNaN(startPrice) || isNaN(endPrice)) {
|
||
console.error('次周期线段价格转换错误:', seg.start_price, seg.end_price);
|
||
return;
|
||
}
|
||
|
||
// 添加线段
|
||
segLines.push({
|
||
startTime: startTime,
|
||
endTime: endTime,
|
||
startPrice: startPrice,
|
||
endPrice: endPrice,
|
||
color: seg.direction === 1 ? '#673ab7' : '#9c27b0', // 次周期线段颜色
|
||
lineWidth: 2,
|
||
});
|
||
|
||
// 添加到图表对象
|
||
tvWidget.series.elementSegSeries.push({
|
||
time: startTime,
|
||
value: startPrice,
|
||
color: seg.direction === 1 ? '#673ab7' : '#9c27b0',
|
||
lineWidth: 2
|
||
});
|
||
} catch (e) {
|
||
console.error('次周期线段处理出错:', e);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 绘制未完成线段 - 主周期
|
||
if ($('#showMainSeg').is(':checked') && currentData.uncompleted_seg_list && currentData.uncompleted_seg_list.length > 0) {
|
||
console.log(`绘制主周期未完成线段数据,共${currentData.uncompleted_seg_list.length}条`);
|
||
|
||
currentData.uncompleted_seg_list.forEach(function(seg) {
|
||
try {
|
||
const ep = resolveUncompletedSegEndpoint(seg, currentData.kline_data, candles);
|
||
if (isNaN(ep.startTime) || isNaN(ep.endTime) || isNaN(ep.startPrice) || isNaN(ep.endPrice)) {
|
||
console.error('主周期未完成线段时间/价格转换错误:', seg.start_time, seg.end_price);
|
||
return;
|
||
}
|
||
|
||
// 添加未完成线段(红色虚线)
|
||
segLines.push({
|
||
startTime: ep.startTime,
|
||
endTime: ep.endTime,
|
||
startPrice: ep.startPrice,
|
||
endPrice: ep.endPrice,
|
||
color: '#FF0000', // 红色
|
||
lineWidth: 2,
|
||
lineStyle: 2 // 虚线
|
||
});
|
||
|
||
// 添加到图表对象
|
||
tvWidget.series.mainUncompletedSegSeries.push({
|
||
time: ep.startTime,
|
||
value: ep.startPrice,
|
||
color: '#FF0000',
|
||
lineWidth: 2,
|
||
lineStyle: 2
|
||
});
|
||
} catch (e) {
|
||
console.error('主周期未完成线段处理出错:', e);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 绘制未完成线段 - 次周期
|
||
if ($('#showElementSeg').is(':checked') && currentData.element_uncompleted_seg_list && currentData.element_uncompleted_seg_list.length > 0) {
|
||
console.log(`绘制次周期未完成线段数据,共${currentData.element_uncompleted_seg_list.length}条`);
|
||
|
||
currentData.element_uncompleted_seg_list.forEach(function(seg) {
|
||
try {
|
||
const ep = resolveUncompletedSegEndpoint(
|
||
seg,
|
||
currentData.element_kline_data || currentData.kline_data,
|
||
candles
|
||
);
|
||
if (isNaN(ep.startTime) || isNaN(ep.endTime) || isNaN(ep.startPrice) || isNaN(ep.endPrice)) {
|
||
console.error('次周期未完成线段时间/价格转换错误:', seg.start_time, seg.end_price);
|
||
return;
|
||
}
|
||
|
||
// 添加未完成线段(红色虚线)
|
||
segLines.push({
|
||
startTime: ep.startTime,
|
||
endTime: ep.endTime,
|
||
startPrice: ep.startPrice,
|
||
endPrice: ep.endPrice,
|
||
color: '#FF0000', // 红色
|
||
lineWidth: 2,
|
||
lineStyle: 2 // 虚线
|
||
});
|
||
|
||
// 添加到图表对象
|
||
tvWidget.series.elementUncompletedSegSeries.push({
|
||
time: ep.startTime,
|
||
value: ep.startPrice,
|
||
color: '#FF0000',
|
||
lineWidth: 2,
|
||
lineStyle: 2
|
||
});
|
||
} catch (e) {
|
||
console.error('次周期未完成线段处理出错:', e);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 次次周期线段
|
||
if ($('#showSubSubSeg').is(':checked') && currentData.sub_sub_seg_list && currentData.sub_sub_seg_list.length > 0) {
|
||
tvWidget.series.subSubSegSeries = [];
|
||
tvWidget.series.subSubUncompletedSegSeries = [];
|
||
currentData.sub_sub_seg_list.forEach(function(seg) {
|
||
try {
|
||
const startTime = Math.floor(new Date(seg.start_time).getTime() / 1000);
|
||
const endTime = seg.end_time ? Math.floor(new Date(seg.end_time).getTime() / 1000) : 0;
|
||
if (isNaN(startTime) || !endTime) return;
|
||
const startPrice = parseFloat(seg.start_price);
|
||
const endPrice = parseFloat(seg.end_price);
|
||
if (isNaN(startPrice) || isNaN(endPrice)) return;
|
||
segLines.push({
|
||
startTime: startTime, endTime: endTime, startPrice: startPrice, endPrice: endPrice,
|
||
color: seg.direction === 1 ? '#00897b' : '#26a69a', lineWidth: 2, lineStyle: 0
|
||
});
|
||
tvWidget.series.subSubSegSeries.push({ time: startTime, value: startPrice, color: '#00897b', lineWidth: 2 });
|
||
} catch (e) { console.error('次次周期线段处理出错:', e); }
|
||
});
|
||
}
|
||
// 次次周期未完成线段
|
||
if ($('#showSubSubSeg').is(':checked') && currentData.sub_sub_uncompleted_seg_list && currentData.sub_sub_uncompleted_seg_list.length > 0) {
|
||
if (!tvWidget.series.subSubUncompletedSegSeries) tvWidget.series.subSubUncompletedSegSeries = [];
|
||
currentData.sub_sub_uncompleted_seg_list.forEach(function(seg) {
|
||
try {
|
||
const ep = resolveUncompletedSegEndpoint(
|
||
seg,
|
||
currentData.sub_sub_kline_data || currentData.kline_data,
|
||
candles
|
||
);
|
||
if (isNaN(ep.startTime) || isNaN(ep.endTime) || isNaN(ep.startPrice) || isNaN(ep.endPrice)) return;
|
||
segLines.push({
|
||
startTime: ep.startTime, endTime: ep.endTime, startPrice: ep.startPrice, endPrice: ep.endPrice,
|
||
color: '#00695c', lineWidth: 2, lineStyle: 2
|
||
});
|
||
tvWidget.series.subSubUncompletedSegSeries.push({ time: ep.startTime, value: ep.startPrice, color: '#00695c', lineWidth: 2, lineStyle: 2 });
|
||
} catch (e) { console.error('次次周期未完成线段处理出错:', e); }
|
||
});
|
||
}
|
||
|
||
// 添加所有线段到图表
|
||
segLines.forEach(line => {
|
||
const lineSeries = mainChart.addLineSeries({
|
||
color: line.color,
|
||
lineWidth: line.lineWidth,
|
||
lineStyle: line.lineStyle || 0, // 支持虚线样式
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
lineSeries.setData([
|
||
{ time: line.startTime, value: line.startPrice },
|
||
{ time: line.endTime, value: line.endPrice }
|
||
]);
|
||
});
|
||
} else {
|
||
console.log('绘制线段 - 已禁用');
|
||
}
|
||
// 显示中枢的绘制 - 分别处理主周期、次周期和次次周期(包含BI中枢,沿用同样样式与开关)
|
||
if ($('#showMainZs').is(':checked') || $('#showElementZs').is(':checked') || $('#showSubSubZs').is(':checked')) {
|
||
console.log('绘制中枢 - 已启用');
|
||
|
||
// 主周期中枢
|
||
if ($('#showMainZs').is(':checked') && currentData.zs_list && currentData.zs_list.length > 0) {
|
||
console.log(`绘制主周期中枢数据,共${currentData.zs_list.length}条`);
|
||
|
||
currentData.zs_list.forEach(function(zs) {
|
||
try {
|
||
// 直接使用UTC时间戳(秒)
|
||
const startTime = Math.floor(new Date(zs.start_time).getTime() / 1000);
|
||
const endTime = Math.floor(new Date(zs.end_time).getTime() / 1000);
|
||
|
||
if (isNaN(startTime) || isNaN(endTime)) {
|
||
console.error('主周期中枢时间转换错误:', zs.start_time, zs.end_time);
|
||
return;
|
||
}
|
||
|
||
const zg = parseFloat(zs.zg); // 中枢上沿
|
||
const zd = parseFloat(zs.zd); // 中枢下沿
|
||
const gg = parseFloat(zs.gg); // 中枢高高
|
||
const dd = parseFloat(zs.dd); // 中枢低低
|
||
|
||
if (isNaN(zg) || isNaN(zd)) {
|
||
console.error('主周期中枢价格转换错误:', zs.zg, zs.zd);
|
||
return;
|
||
}
|
||
|
||
// 创建中枢上边界
|
||
const topSeries = mainChart.addLineSeries({
|
||
color: '#F1C40F', // 主周期中枢颜色
|
||
lineWidth: 1,
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
topSeries.setData([
|
||
{ time: startTime, value: zg },
|
||
{ time: endTime, value: zg }
|
||
]);
|
||
|
||
// 为下边界创建另一条线
|
||
const bottomSeries = mainChart.addLineSeries({
|
||
color: '#F1C40F', // 主周期中枢颜色
|
||
lineWidth: 1,
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
bottomSeries.setData([
|
||
{ time: startTime, value: zd },
|
||
{ time: endTime, value: zd }
|
||
]);
|
||
|
||
// 添加左边界
|
||
const leftSeries = mainChart.addLineSeries({
|
||
color: '#F1C40F', // 主周期中枢颜色
|
||
lineWidth: 1,
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
leftSeries.setData([
|
||
{ time: startTime, value: zd },
|
||
{ time: startTime, value: zg }
|
||
]);
|
||
|
||
// 添加右边界
|
||
const rightSeries = mainChart.addLineSeries({
|
||
color: '#F1C40F', // 主周期中枢颜色
|
||
lineWidth: 1,
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
rightSeries.setData([
|
||
{ time: endTime, value: zd },
|
||
{ time: endTime, value: zg }
|
||
]);
|
||
|
||
// 绘制gg线(中枢高高)
|
||
if (!isNaN(gg) && gg > 0) {
|
||
const ggSeries = mainChart.addLineSeries({
|
||
color: '#F1C40F', // 使用中枢自己的颜色
|
||
lineWidth: 1,
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
ggSeries.setData([
|
||
{ time: startTime, value: gg },
|
||
{ time: endTime, value: gg }
|
||
]);
|
||
}
|
||
|
||
// 绘制dd线(中枢低低)
|
||
if (!isNaN(dd) && dd > 0) {
|
||
const ddSeries = mainChart.addLineSeries({
|
||
color: '#F1C40F', // 使用中枢自己的颜色
|
||
lineWidth: 1,
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
ddSeries.setData([
|
||
{ time: startTime, value: dd },
|
||
{ time: endTime, value: dd }
|
||
]);
|
||
}
|
||
|
||
// 添加到图表对象
|
||
tvWidget.series.mainZsSeries.push({
|
||
time: startTime,
|
||
value: zg,
|
||
color: '#F1C40F',
|
||
lineWidth: 1
|
||
});
|
||
tvWidget.series.mainZsSeries.push({
|
||
time: endTime,
|
||
value: zg,
|
||
color: '#F1C40F',
|
||
lineWidth: 1
|
||
});
|
||
tvWidget.series.mainZsSeries.push({
|
||
time: startTime,
|
||
value: zd,
|
||
color: '#F1C40F',
|
||
lineWidth: 1
|
||
});
|
||
tvWidget.series.mainZsSeries.push({
|
||
time: endTime,
|
||
value: zd,
|
||
color: '#F1C40F',
|
||
lineWidth: 1
|
||
});
|
||
} catch (e) {
|
||
console.error('主周期中枢处理出错:', e);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 次周期中枢
|
||
if ($('#showElementZs').is(':checked') && currentData.element_zs_list && currentData.element_zs_list.length > 0) {
|
||
console.log(`绘制次周期中枢数据,共${currentData.element_zs_list.length}条`);
|
||
|
||
currentData.element_zs_list.forEach(function(zs) {
|
||
try {
|
||
// 直接使用UTC时间戳(秒)
|
||
const startTime = Math.floor(new Date(zs.start_time).getTime() / 1000);
|
||
const endTime = Math.floor(new Date(zs.end_time).getTime() / 1000);
|
||
|
||
if (isNaN(startTime) || isNaN(endTime)) {
|
||
console.error('次周期中枢时间转换错误:', zs.start_time, zs.end_time);
|
||
return;
|
||
}
|
||
|
||
const zg = parseFloat(zs.zg); // 中枢上沿
|
||
const zd = parseFloat(zs.zd); // 中枢下沿
|
||
const gg = parseFloat(zs.gg); // 中枢高高
|
||
const dd = parseFloat(zs.dd); // 中枢低低
|
||
|
||
if (isNaN(zg) || isNaN(zd)) {
|
||
console.error('次周期中枢价格转换错误:', zs.zg, zs.zd);
|
||
return;
|
||
}
|
||
|
||
// 创建中枢上边界
|
||
const topSeries = mainChart.addLineSeries({
|
||
color: '#3f51b5', // 次周期中枢颜色
|
||
lineWidth: 1,
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
topSeries.setData([
|
||
{ time: startTime, value: zg },
|
||
{ time: endTime, value: zg }
|
||
]);
|
||
|
||
// 为下边界创建另一条线
|
||
const bottomSeries = mainChart.addLineSeries({
|
||
color: '#3f51b5', // 次周期中枢颜色
|
||
lineWidth: 1,
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
bottomSeries.setData([
|
||
{ time: startTime, value: zd },
|
||
{ time: endTime, value: zd }
|
||
]);
|
||
|
||
// 添加左边界
|
||
const leftSeries = mainChart.addLineSeries({
|
||
color: '#3f51b5', // 次周期中枢颜色
|
||
lineWidth: 1,
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
leftSeries.setData([
|
||
{ time: startTime, value: zd },
|
||
{ time: startTime, value: zg }
|
||
]);
|
||
|
||
// 添加右边界
|
||
const rightSeries = mainChart.addLineSeries({
|
||
color: '#3f51b5', // 次周期中枢颜色
|
||
lineWidth: 1,
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
rightSeries.setData([
|
||
{ time: endTime, value: zd },
|
||
{ time: endTime, value: zg }
|
||
]);
|
||
|
||
// 绘制gg线(中枢高高)
|
||
if (!isNaN(gg) && gg > 0) {
|
||
const ggSeries = mainChart.addLineSeries({
|
||
color: '#3f51b5', // 使用次周期中枢自己的颜色
|
||
lineWidth: 1,
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
ggSeries.setData([
|
||
{ time: startTime, value: gg },
|
||
{ time: endTime, value: gg }
|
||
]);
|
||
}
|
||
|
||
// 绘制dd线(中枢低低)
|
||
if (!isNaN(dd) && dd > 0) {
|
||
const ddSeries = mainChart.addLineSeries({
|
||
color: '#3f51b5', // 使用次周期中枢自己的颜色
|
||
lineWidth: 1,
|
||
lastValueVisible: false,
|
||
priceLineVisible: false,
|
||
});
|
||
|
||
ddSeries.setData([
|
||
{ time: startTime, value: dd },
|
||
{ time: endTime, value: dd }
|
||
]);
|
||
}
|
||
|
||
// 添加到图表对象
|
||
tvWidget.series.elementZsSeries.push({
|
||
time: startTime,
|
||
value: zg,
|
||
color: '#3f51b5',
|
||
lineWidth: 1
|
||
});
|
||
tvWidget.series.elementZsSeries.push({
|
||
time: endTime,
|
||
value: zg,
|
||
color: '#3f51b5',
|
||
lineWidth: 1
|
||
});
|
||
tvWidget.series.elementZsSeries.push({
|
||
time: startTime,
|
||
value: zd,
|
||
color: '#3f51b5',
|
||
lineWidth: 1
|
||
});
|
||
tvWidget.series.elementZsSeries.push({
|
||
time: endTime,
|
||
value: zd,
|
||
color: '#3f51b5',
|
||
lineWidth: 1
|
||
});
|
||
} catch (e) {
|
||
console.error('次周期中枢处理出错:', e);
|
||
}
|
||
});
|
||
}
|
||
// 次次周期SEG中枢
|
||
if ($('#showSubSubZs').is(':checked') && currentData.sub_sub_zs_list && currentData.sub_sub_zs_list.length > 0) {
|
||
const subSubZsColor = '#00897b';
|
||
currentData.sub_sub_zs_list.forEach(function(zs) {
|
||
try {
|
||
const startTime = Math.floor(new Date(zs.start_time).getTime() / 1000);
|
||
const endTime = zs.end_time ? Math.floor(new Date(zs.end_time).getTime() / 1000) : 0;
|
||
if (isNaN(startTime) || !endTime) return;
|
||
const zg = parseFloat(zs.zg); const zd = parseFloat(zs.zd); const gg = parseFloat(zs.gg); const dd = parseFloat(zs.dd);
|
||
if (isNaN(zg) || isNaN(zd)) return;
|
||
mainChart.addLineSeries({ color: subSubZsColor, lineWidth: 1, lastValueVisible: false, priceLineVisible: false }).setData([{ time: startTime, value: zg }, { time: endTime, value: zg }]);
|
||
mainChart.addLineSeries({ color: subSubZsColor, lineWidth: 1, lastValueVisible: false, priceLineVisible: false }).setData([{ time: startTime, value: zd }, { time: endTime, value: zd }]);
|
||
mainChart.addLineSeries({ color: subSubZsColor, lineWidth: 1, lastValueVisible: false, priceLineVisible: false }).setData([{ time: startTime, value: zd }, { time: startTime, value: zg }]);
|
||
mainChart.addLineSeries({ color: subSubZsColor, lineWidth: 1, lastValueVisible: false, priceLineVisible: false }).setData([{ time: endTime, value: zd }, { time: endTime, value: zg }]);
|
||
if (!isNaN(gg) && gg > 0) mainChart.addLineSeries({ color: subSubZsColor, lineWidth: 1, lastValueVisible: false, priceLineVisible: false }).setData([{ time: startTime, value: gg }, { time: endTime, value: gg }]);
|
||
if (!isNaN(dd) && dd > 0) mainChart.addLineSeries({ color: subSubZsColor, lineWidth: 1, lastValueVisible: false, priceLineVisible: false }).setData([{ time: startTime, value: dd }, { time: endTime, value: dd }]);
|
||
} catch (e) { console.error('次次周期中枢处理出错:', e); }
|
||
});
|
||
}
|
||
} else {
|
||
console.log('绘制中枢 - 已禁用');
|
||
}
|
||
// BI中枢(已完成)- 使用独立的BI开关
|
||
if ($('#showMainBiZs').is(':checked') && currentData.bi_zs_list && currentData.bi_zs_list.length > 0) {
|
||
try {
|
||
console.log(`绘制主周期BI中枢数据,共${currentData.bi_zs_list.length}条`);
|
||
} catch (e) {}
|
||
currentData.bi_zs_list.forEach(function(zs) {
|
||
try {
|
||
const startTime = Math.floor(new Date(zs.start_time).getTime() / 1000);
|
||
const endTime = zs.end_time ? Math.floor(new Date(zs.end_time).getTime() / 1000) : Math.floor(new Date(currentData.kline_data[currentData.kline_data.length-1].date).getTime() / 1000);
|
||
if (isNaN(startTime) || isNaN(endTime)) { return; }
|
||
const zg = parseFloat(zs.zg); const zd = parseFloat(zs.zd); const gg = parseFloat(zs.gg); const dd = parseFloat(zs.dd);
|
||
if (isNaN(zg) || isNaN(zd)) { return; }
|
||
const color = '#F1C40F';
|
||
const topSeries = mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false });
|
||
topSeries.setData([{ time: startTime, value: zg }, { time: endTime, value: zg }]);
|
||
const bottomSeries = mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false });
|
||
bottomSeries.setData([{ time: startTime, value: zd }, { time: endTime, value: zd }]);
|
||
const leftSeries = mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false });
|
||
leftSeries.setData([{ time: startTime, value: zd }, { time: startTime, value: zg }]);
|
||
const rightSeries = mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false });
|
||
rightSeries.setData([{ time: endTime, value: zd }, { time: endTime, value: zg }]);
|
||
if (!isNaN(gg) && gg > 0) {
|
||
const ggSeries = mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false });
|
||
ggSeries.setData([{ time: startTime, value: gg }, { time: endTime, value: gg }]);
|
||
}
|
||
if (!isNaN(dd) && dd > 0) {
|
||
const ddSeries = mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false });
|
||
ddSeries.setData([{ time: startTime, value: dd }, { time: endTime, value: dd }]);
|
||
}
|
||
} catch (e) { console.error('主周期BI中枢处理出错:', e); }
|
||
});
|
||
}
|
||
if ($('#showSubSubBiZs').is(':checked') && currentData.sub_sub_bi_zs_list && currentData.sub_sub_bi_zs_list.length > 0) {
|
||
currentData.sub_sub_bi_zs_list.forEach(function(zs) {
|
||
try {
|
||
const startTime = Math.floor(new Date(zs.start_time).getTime() / 1000);
|
||
const kd = currentData.kline_data || [];
|
||
const endTime = zs.end_time ? Math.floor(new Date(zs.end_time).getTime() / 1000) : (kd.length ? Math.floor(new Date(kd[kd.length-1].date).getTime() / 1000) : 0);
|
||
if (isNaN(startTime) || !endTime) return;
|
||
const zg = parseFloat(zs.zg); const zd = parseFloat(zs.zd); const gg = parseFloat(zs.gg); const dd = parseFloat(zs.dd);
|
||
if (isNaN(zg) || isNaN(zd)) return;
|
||
const color = '#00897b';
|
||
mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false }).setData([{ time: startTime, value: zg }, { time: endTime, value: zg }]);
|
||
mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false }).setData([{ time: startTime, value: zd }, { time: endTime, value: zd }]);
|
||
mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false }).setData([{ time: startTime, value: zd }, { time: startTime, value: zg }]);
|
||
mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false }).setData([{ time: endTime, value: zd }, { time: endTime, value: zg }]);
|
||
if (!isNaN(gg) && gg > 0) mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false }).setData([{ time: startTime, value: gg }, { time: endTime, value: gg }]);
|
||
if (!isNaN(dd) && dd > 0) mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false }).setData([{ time: startTime, value: dd }, { time: endTime, value: dd }]);
|
||
} catch (e) { console.error('次次周期BI中枢处理出错:', e); }
|
||
});
|
||
}
|
||
if ($('#showElementBiZs').is(':checked') && currentData.element_bi_zs_list && currentData.element_bi_zs_list.length > 0) {
|
||
try {
|
||
console.log(`绘制次周期BI中枢数据,共${currentData.element_bi_zs_list.length}条`);
|
||
} catch (e) {}
|
||
currentData.element_bi_zs_list.forEach(function(zs) {
|
||
try {
|
||
const startTime = Math.floor(new Date(zs.start_time).getTime() / 1000);
|
||
const endTime = zs.end_time ? Math.floor(new Date(zs.end_time).getTime() / 1000) : Math.floor(new Date(currentData.kline_data[currentData.kline_data.length-1].date).getTime() / 1000);
|
||
if (isNaN(startTime) || isNaN(endTime)) { return; }
|
||
const zg = parseFloat(zs.zg); const zd = parseFloat(zs.zd); const gg = parseFloat(zs.gg); const dd = parseFloat(zs.dd);
|
||
if (isNaN(zg) || isNaN(zd)) { return; }
|
||
const color = '#3f51b5';
|
||
const topSeries = mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false });
|
||
topSeries.setData([{ time: startTime, value: zg }, { time: endTime, value: zg }]);
|
||
const bottomSeries = mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false });
|
||
bottomSeries.setData([{ time: startTime, value: zd }, { time: endTime, value: zd }]);
|
||
const leftSeries = mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false });
|
||
leftSeries.setData([{ time: startTime, value: zd }, { time: startTime, value: zg }]);
|
||
const rightSeries = mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false });
|
||
rightSeries.setData([{ time: endTime, value: zd }, { time: endTime, value: zg }]);
|
||
if (!isNaN(gg) && gg > 0) {
|
||
const ggSeries = mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false });
|
||
ggSeries.setData([{ time: startTime, value: gg }, { time: endTime, value: gg }]);
|
||
}
|
||
if (!isNaN(dd) && dd > 0) {
|
||
const ddSeries = mainChart.addLineSeries({ color, lineWidth: 1, lastValueVisible: false, priceLineVisible: false });
|
||
ddSeries.setData([{ time: startTime, value: dd }, { time: endTime, value: dd }]);
|
||
}
|
||
} catch (e) { console.error('次周期BI中枢处理出错:', e); }
|
||
});
|
||
}
|
||
}
|