Web 加上资金面/情绪叠图,并收紧默认图面。
默认主/次/次次改为 45m/15m/5m、开始时间一周;SD/CD 按 hist 摆位置和箭头;去掉笔线段背驰与第四类勾选。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -82,11 +82,6 @@ var SUB_SUB_KLC_TREND_STYLE = {
|
||||
UNKNOWN: { position: 'inBar', color: '#004d40', shape: 'square', size: 0.5 }
|
||||
};
|
||||
|
||||
function parseAreaDivValue(v) {
|
||||
var n = Number(v);
|
||||
return (isFinite(n) && n !== 0) ? n : 0;
|
||||
}
|
||||
|
||||
function pushAreaTextLabel(out, item, style, text) {
|
||||
if (!item || !item.end_time || !text) return;
|
||||
var ts = Math.floor(new Date(item.end_time).getTime() / 1000);
|
||||
@@ -104,25 +99,6 @@ function pushAreaTextLabel(out, item, style, text) {
|
||||
});
|
||||
}
|
||||
|
||||
function pushAreaDivMarker(out, item, style) {
|
||||
var div = parseAreaDivValue(item && item.macd_div);
|
||||
if (!div) return;
|
||||
pushAreaTextLabel(out, item, style, div.toFixed(2));
|
||||
}
|
||||
|
||||
function collectAreaDivMarkers(biList, uncompletedBi, segList, uncompletedSeg, biStyle, segStyle, showBi, showSeg) {
|
||||
var out = [];
|
||||
if (showBi) {
|
||||
(biList || []).forEach(function (bi) { pushAreaDivMarker(out, bi, biStyle); });
|
||||
(uncompletedBi || []).forEach(function (bi) { pushAreaDivMarker(out, bi, biStyle); });
|
||||
}
|
||||
if (showSeg) {
|
||||
(segList || []).forEach(function (seg) { pushAreaDivMarker(out, seg, segStyle); });
|
||||
(uncompletedSeg || []).forEach(function (seg) { pushAreaDivMarker(out, seg, segStyle); });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function formatMacdAreaText(v) {
|
||||
var n = Number(v);
|
||||
if (!isFinite(n) || n === 0) return '';
|
||||
@@ -197,54 +173,6 @@ function buildAreaHistMarkersFromData(data) {
|
||||
return markers;
|
||||
}
|
||||
|
||||
function buildAreaDivMarkersFromData(data) {
|
||||
var markers = [];
|
||||
if (!data) return markers;
|
||||
var showMainBi = $('#showMainMacdDiv').is(':checked');
|
||||
var showMainSeg = $('#showMainSegMacdDiv').is(':checked');
|
||||
if (showMainBi || showMainSeg) {
|
||||
markers = markers.concat(collectAreaDivMarkers(
|
||||
data.bi_list,
|
||||
data.uncompleted_bi_list,
|
||||
data.seg_list,
|
||||
data.uncompleted_seg_list,
|
||||
{ color: '#e53935', size: 0.6 },
|
||||
{ color: '#fb8c00', size: 0.7 },
|
||||
showMainBi,
|
||||
showMainSeg
|
||||
));
|
||||
}
|
||||
var showElementBi = $('#showElementMacdDiv').is(':checked');
|
||||
var showElementSeg = $('#showElementSegMacdDiv').is(':checked');
|
||||
if (showElementBi || showElementSeg) {
|
||||
markers = markers.concat(collectAreaDivMarkers(
|
||||
data.element_bi_list,
|
||||
data.element_uncompleted_bi_list,
|
||||
data.element_seg_list,
|
||||
data.element_uncompleted_seg_list,
|
||||
{ color: '#8e24aa', size: 0.55 },
|
||||
{ color: '#5e35b1', size: 0.65 },
|
||||
showElementBi,
|
||||
showElementSeg
|
||||
));
|
||||
}
|
||||
var showSubSubBi = $('#showSubSubMacdDiv').is(':checked');
|
||||
var showSubSubSeg = $('#showSubSubSegMacdDiv').is(':checked');
|
||||
if (showSubSubBi || showSubSubSeg) {
|
||||
markers = markers.concat(collectAreaDivMarkers(
|
||||
data.sub_sub_bi_list,
|
||||
data.sub_sub_uncompleted_bi_list,
|
||||
data.sub_sub_seg_list,
|
||||
data.sub_sub_uncompleted_seg_list,
|
||||
{ color: '#00897b', size: 0.5 },
|
||||
{ color: '#00695c', size: 0.6 },
|
||||
showSubSubBi,
|
||||
showSubSubSeg
|
||||
));
|
||||
}
|
||||
return markers;
|
||||
}
|
||||
|
||||
function buildKlcTrendMarker(timeAligned, trendRaw, palette) {
|
||||
var kind = normalizeKlcTrendRaw(trendRaw);
|
||||
var style = palette[kind] || palette.UNKNOWN || palette.FLAT;
|
||||
@@ -299,6 +227,21 @@ function getMainPriceSeries() {
|
||||
s.lineSeries || s.areaSeries || s.baselineSeries || null;
|
||||
}
|
||||
|
||||
function plotLeftOffset(chart) {
|
||||
try {
|
||||
var left = chart && chart.priceScale && chart.priceScale('left');
|
||||
if (!left) return 0;
|
||||
var visible = true;
|
||||
try {
|
||||
var opts = left.options && left.options();
|
||||
if (opts && opts.visible === false) return 0;
|
||||
} catch (e) {}
|
||||
return (typeof left.width === 'function' ? left.width() : 0) || 0;
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function syncFxBoxVerticalOverlay(mainChart, mainChartContainer) {
|
||||
if (!mainChart || !mainChartContainer) return;
|
||||
if (typeof window._fxBoxOverlayCleanup === 'function') {
|
||||
@@ -330,7 +273,7 @@ function syncFxBoxVerticalOverlay(mainChart, mainChartContainer) {
|
||||
var series = getMainPriceSeries();
|
||||
if (!series || (!boxes.length && !labels.length)) return '0';
|
||||
var ts = mainChart.timeScale();
|
||||
var parts = [boxes.length, labels.length];
|
||||
var parts = [boxes.length, labels.length, quant(plotLeftOffset(mainChart))];
|
||||
if (boxes.length) {
|
||||
var a = boxes[0];
|
||||
var b = boxes[boxes.length - 1];
|
||||
@@ -374,18 +317,20 @@ function syncFxBoxVerticalOverlay(mainChart, mainChartContainer) {
|
||||
return;
|
||||
}
|
||||
var ts = mainChart.timeScale();
|
||||
var x0 = plotLeftOffset(mainChart);
|
||||
for (var i = 0; i < boxes.length; i++) {
|
||||
var box = boxes[i];
|
||||
var x = ts.timeToCoordinate(box.time);
|
||||
var y1 = series.priceToCoordinate(box.hi);
|
||||
var y2 = series.priceToCoordinate(box.lo);
|
||||
if (x == null || y1 == null || y2 == null) continue;
|
||||
var px = Math.round(x + x0) + 0.5;
|
||||
ctx2.beginPath();
|
||||
ctx2.strokeStyle = box.color;
|
||||
ctx2.lineWidth = 1;
|
||||
ctx2.setLineDash([4, 3]);
|
||||
ctx2.moveTo(Math.round(x) + 0.5, y1);
|
||||
ctx2.lineTo(Math.round(x) + 0.5, y2);
|
||||
ctx2.moveTo(px, y1);
|
||||
ctx2.lineTo(px, y2);
|
||||
ctx2.stroke();
|
||||
}
|
||||
ctx2.setLineDash([]);
|
||||
@@ -399,7 +344,7 @@ function syncFxBoxVerticalOverlay(mainChart, mainChartContainer) {
|
||||
if (lx == null || ly == null) continue;
|
||||
ctx2.fillStyle = lab.color;
|
||||
ctx2.textBaseline = lab.above ? 'bottom' : 'top';
|
||||
ctx2.fillText(lab.text, Math.round(lx), lab.above ? ly - 3 : ly + 3);
|
||||
ctx2.fillText(lab.text, Math.round(lx + x0), lab.above ? ly - 3 : ly + 3);
|
||||
}
|
||||
}
|
||||
lastSig = sampleSig();
|
||||
@@ -1182,56 +1127,6 @@ function chartTvRenderOverlays(ctx) {
|
||||
window.bspMarkers = [];
|
||||
}
|
||||
|
||||
// 第四类买卖点(B4/S4):中枢突破回抽后当根入场,位置同 B3/S3 但早 7~8 根。
|
||||
// 与 BSP 分开收集,因为它数量远多于 B1/B2/B3,混在一个开关里图会糊掉。
|
||||
if ($('#showMainFastBsp').is(':checked') || $('#showElementFastBsp').is(':checked') || $('#showSubSubFastBsp').is(':checked')) {
|
||||
// 深色 = 区间套(大级别分型同向) + 中枢顺向推进都满足;浅色 = 未通过过滤
|
||||
const FAST_BSP_STYLE = {
|
||||
'BUY': { strong: '#FF6D00', weak: '#FFCC80', text: 'B4', position: 'belowBar' },
|
||||
'SELL': { strong: '#0091EA', weak: '#81D4FA', text: 'S4', position: 'aboveBar' },
|
||||
};
|
||||
const onlyFiltered = ($('#fastBspFilterMode').val() || 'all') === 'filtered';
|
||||
const allFastBspMarkers = [];
|
||||
|
||||
const collectFastBsp = function(list, prefix, label) {
|
||||
(list || []).forEach(function(bsp) {
|
||||
try {
|
||||
const ts = Math.floor(new Date(bsp.time).getTime() / 1000);
|
||||
if (isNaN(ts)) return;
|
||||
const style = FAST_BSP_STYLE[(bsp.dir || '').toUpperCase()];
|
||||
if (!style) return;
|
||||
const passed = !!(bsp.htf_agree && bsp.ladder_ok);
|
||||
if (onlyFiltered && !passed) return;
|
||||
allFastBspMarkers.push({
|
||||
time: ts,
|
||||
position: style.position,
|
||||
color: passed ? style.strong : style.weak,
|
||||
text: prefix + (passed ? style.text : style.text.toLowerCase()),
|
||||
size: passed ? 2 : 1
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(label + '第四类买卖点处理出错:', e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if ($('#showMainFastBsp').is(':checked')) {
|
||||
collectFastBsp(currentData.fast_bsp_list, '', '主周期');
|
||||
}
|
||||
if ($('#showElementFastBsp').is(':checked')) {
|
||||
collectFastBsp(currentData.element_fast_bsp_list, 'e', '次周期');
|
||||
}
|
||||
if ($('#showSubSubFastBsp').is(':checked')) {
|
||||
collectFastBsp(currentData.sub_sub_fast_bsp_list, 's', '次次周期');
|
||||
}
|
||||
|
||||
allFastBspMarkers.sort((a, b) => a.time - b.time);
|
||||
window.fastBspMarkers = allFastBspMarkers;
|
||||
console.log(`绘制第四类买卖点,共${allFastBspMarkers.length}个标记(${onlyFiltered ? '仅过滤后' : '全部'})`);
|
||||
} else {
|
||||
window.fastBspMarkers = [];
|
||||
}
|
||||
|
||||
// 添加买卖点标记(旧版,保留兼容)
|
||||
// 这里为了与主面板上的「买卖点」开关保持一致,
|
||||
// 同时响应顶部的 `#showMainBsp` 复选框
|
||||
@@ -1807,7 +1702,7 @@ function chartTvRenderOverlays(ctx) {
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
title: '次周期布林上轨'
|
||||
title: '次布林上轨'
|
||||
});
|
||||
elementUpperBandSeries.setData(elementUpperBandData);
|
||||
|
||||
@@ -1818,7 +1713,7 @@ function chartTvRenderOverlays(ctx) {
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
title: '次周期布林下轨'
|
||||
title: '次布林下轨'
|
||||
});
|
||||
elementLowerBandSeries.setData(elementLowerBandData);
|
||||
|
||||
@@ -1828,7 +1723,7 @@ function chartTvRenderOverlays(ctx) {
|
||||
lineWidth: 1,
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
title: '次周期布林中轨'
|
||||
title: '次布林中轨'
|
||||
});
|
||||
elementMiddleBandSeries.setData(elementMiddleBandData);
|
||||
|
||||
@@ -1943,7 +1838,7 @@ function chartTvRenderOverlays(ctx) {
|
||||
const fxMarker = {
|
||||
time: timestamp,
|
||||
tooltip: `<div style="color: ${strengthColor}; font-weight: bold;">
|
||||
主周期${fx.is_bottom ? '底分型' : '顶分型'}(合): ${fx.fx_type}<br>
|
||||
主${fx.is_bottom ? '底分型' : '顶分型'}(合): ${fx.fx_type}<br>
|
||||
强度分数: ${fx.fx_strength}分<br>
|
||||
强度等级: ${fx.fx_strength_level}<br>
|
||||
是否强分型: ${fx.is_strong_fx ? '是' : '否'}<br>
|
||||
@@ -2007,7 +1902,7 @@ function chartTvRenderOverlays(ctx) {
|
||||
const fxMarker = {
|
||||
time: timestamp,
|
||||
tooltip: `<div style="color: ${strengthColor}; font-weight: bold;">
|
||||
主周期${fx.is_bottom ? '底分型' : '顶分型'}(原): ${fx.fx_type}<br>
|
||||
主${fx.is_bottom ? '底分型' : '顶分型'}(原): ${fx.fx_type}<br>
|
||||
强度分数: ${fx.fx_strength}分<br>
|
||||
强度等级: ${fx.fx_strength_level}<br>
|
||||
是否强分型: ${fx.is_strong_fx ? '是' : '否'}<br>
|
||||
@@ -2045,7 +1940,7 @@ function chartTvRenderOverlays(ctx) {
|
||||
window.fxMarkers = [];
|
||||
}
|
||||
window._areaTextLabels = alignMarkersToCandles(
|
||||
buildAreaDivMarkersFromData(currentData).concat(buildAreaHistMarkersFromData(currentData)),
|
||||
buildAreaHistMarkersFromData(currentData),
|
||||
candles
|
||||
);
|
||||
if (typeof window._redrawFxBoxVerticalOverlay === 'function') {
|
||||
@@ -2140,7 +2035,7 @@ function chartTvRenderOverlays(ctx) {
|
||||
const elementFxMarker = {
|
||||
time: timestamp,
|
||||
tooltip: `<div style="color: ${strengthColor}; font-weight: bold;">
|
||||
小周期${fx.is_bottom ? '底分型' : '顶分型'}(合): ${fx.fx_type}<br>
|
||||
次${fx.is_bottom ? '底分型' : '顶分型'}(合): ${fx.fx_type}<br>
|
||||
强度分数: ${fx.fx_strength}分<br>
|
||||
强度等级: ${fx.fx_strength_level}<br>
|
||||
是否强分型: ${fx.is_strong_fx ? '是' : '否'}<br>
|
||||
@@ -2196,7 +2091,7 @@ function chartTvRenderOverlays(ctx) {
|
||||
const elementFxMarker = {
|
||||
time: timestamp,
|
||||
tooltip: `<div style="color: ${strengthColor}; font-weight: bold;">
|
||||
小周期${fx.is_bottom ? '底分型' : '顶分型'}(原): ${fx.fx_type}<br>
|
||||
次${fx.is_bottom ? '底分型' : '顶分型'}(原): ${fx.fx_type}<br>
|
||||
强度分数: ${fx.fx_strength}分<br>
|
||||
强度等级: ${fx.fx_strength_level}<br>
|
||||
是否强分型: ${fx.is_strong_fx ? '是' : '否'}<br>
|
||||
@@ -2365,8 +2260,7 @@ function chartTvRenderOverlays(ctx) {
|
||||
...(window.kluDivMarkersElement || []),
|
||||
...(window.kluDivMarkersSubSub || []),
|
||||
...trendMarkersToUse,
|
||||
...(window.bspMarkers || []),
|
||||
...(window.fastBspMarkers || [])
|
||||
...(window.bspMarkers || [])
|
||||
];
|
||||
if (combinedMarkers.length > 0) {
|
||||
console.log(
|
||||
@@ -2375,7 +2269,6 @@ function chartTvRenderOverlays(ctx) {
|
||||
'个,小周期分型:', allElementFxMarkers.length,
|
||||
'个,背驰:', (window.kluDivMarkersMain || []).length,
|
||||
'个,BSP标记:', (window.bspMarkers || []).length,
|
||||
'个,第四类标记:', (window.fastBspMarkers || []).length,
|
||||
'个)'
|
||||
);
|
||||
|
||||
@@ -2477,15 +2370,14 @@ function chartTvRenderOverlays(ctx) {
|
||||
// 这里的 onlyMainAndU 实际上是「最终要挂到主K线上」的一组标记
|
||||
// 之前没有把 window.bspMarkers 合进去,导致上面已经合并了 BSP 标记,
|
||||
// 但在这里再次调用 setMarkers 时把 BSP 覆盖掉了,从而前端看不到买卖点。
|
||||
// 修复:把 BSP 标记一并合并进来。第四类买卖点同理,两处都要带上。
|
||||
// 修复:把 BSP 标记一并合并进来。两处都要带上,否则后面这次 setMarkers 会把买卖点盖掉。
|
||||
const onlyMainAndU = [
|
||||
...(window.mainFxMarkers || []),
|
||||
...(window.kluDivMarkersMain || []),
|
||||
...(window.kluDivMarkersElement || []),
|
||||
...(window.kluDivMarkersSubSub || []),
|
||||
...trendMarkersToUse,
|
||||
...(window.bspMarkers || []),
|
||||
...(window.fastBspMarkers || [])
|
||||
...(window.bspMarkers || [])
|
||||
];
|
||||
if (onlyMainAndU.length > 0) {
|
||||
console.log('仅设置', onlyMainAndU.length, '个主图标记(主周期分型:', (window.mainFxMarkers || []).length, ',背驰:', (window.kluDivMarkersMain || []).length, ')');
|
||||
|
||||
Reference in New Issue
Block a user