添加裸K形态,前端添加KLC显示
This commit is contained in:
+26
@@ -1167,6 +1167,18 @@ def analyze():
|
||||
# 添加主周期分析结果到返回数据
|
||||
result.update({
|
||||
'kline_data': clean_dataframe_for_json(df).to_dict('records'),
|
||||
'klc_list': [{
|
||||
'date': klc.end_time if isinstance(klc.end_time, str) else klc.end_time.astimezone(client_tz).isoformat(),
|
||||
'open': float(klc.open),
|
||||
'high': float(klc.high),
|
||||
'low': float(klc.low),
|
||||
'close': float(klc.close),
|
||||
'volume': float(klc.volume) if hasattr(klc, 'volume') else 0,
|
||||
'direction': str(klc.dir).replace('Chan_KLINE_DIR.', ''),
|
||||
'fx_type': str(klc.fx).replace('Chan_FX_TYPE.', ''),
|
||||
'klc_fx_type': str(klc.klc_fx_type).replace('Chan_KLC_FX.', ''),
|
||||
'trend': str(klc.trend).replace('Chan_PRICE_TREND.', '')
|
||||
} for klc in analysis_result['klc_list'] if hasattr(klc, 'end_time') and klc.end_time],
|
||||
'bi_list': [{
|
||||
'start_time': bi.start_klc.end_time if isinstance(bi.start_klc.end_time, str) else bi.start_klc.end_time.astimezone(client_tz).isoformat(),
|
||||
'end_time': (bi.end_klc.end_time if isinstance(bi.end_klc.end_time, str) else bi.end_klc.end_time.astimezone(client_tz).isoformat()) if bi.end_klc else None,
|
||||
@@ -1354,6 +1366,20 @@ def analyze():
|
||||
# 添加小周期K线数据
|
||||
result['element_kline_data'] = clean_dataframe_for_json(element_df).to_dict('records')
|
||||
|
||||
# 添加小周期KLC列表
|
||||
result['element_klc_list'] = [{
|
||||
'date': klc.end_time if isinstance(klc.end_time, str) else klc.end_time.astimezone(client_tz).isoformat(),
|
||||
'open': float(klc.open),
|
||||
'high': float(klc.high),
|
||||
'low': float(klc.low),
|
||||
'close': float(klc.close),
|
||||
'volume': float(klc.volume) if hasattr(klc, 'volume') else 0,
|
||||
'direction': str(klc.dir).replace('Chan_KLINE_DIR.', ''),
|
||||
'fx_type': str(klc.fx).replace('Chan_FX_TYPE.', ''),
|
||||
'klc_fx_type': str(klc.klc_fx_type).replace('Chan_KLC_FX.', ''),
|
||||
'trend': str(klc.trend).replace('Chan_PRICE_TREND.', '')
|
||||
} for klc in element_analysis['klc_list'] if hasattr(klc, 'end_time') and klc.end_time]
|
||||
|
||||
result['element_seg_list'] = [{
|
||||
'start_time': seg.start_bi.start_klc.end_time if isinstance(seg.start_bi.start_klc.end_time, str) else seg.start_bi.start_klc.end_time.astimezone(client_tz).isoformat(),
|
||||
'end_time': (seg.end_bi.end_klc.end_time if isinstance(seg.end_bi.end_klc.end_time, str) else seg.end_bi.end_klc.end_time.astimezone(client_tz).isoformat()) if seg.end_bi else None,
|
||||
|
||||
+130
-94
@@ -648,7 +648,6 @@
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.bb-config-content {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
@@ -817,6 +816,7 @@
|
||||
<option value="baseline">基线</option>
|
||||
<option value="renko">砖型</option>
|
||||
<option value="heikin">平均K</option>
|
||||
<option value="klc">KLC</option>
|
||||
</select>
|
||||
<!-- 为兼容现有逻辑,保留隐藏的原始K线开关,与下拉同步 -->
|
||||
<input class="form-check-input" type="checkbox" id="showOriginalKline" checked style="display:none;">
|
||||
@@ -2548,6 +2548,19 @@
|
||||
const baseData = candles.map(c => ({ time: c.time, value: c.close }));
|
||||
series.setData(baseData);
|
||||
tvWidget.series.baselineSeries = series;
|
||||
} else if (klineType === 'klc') {
|
||||
// KLC显示模式 - 使用蜡烛线显示KLC数据
|
||||
const series = mainChart.addCandlestickSeries({
|
||||
upColor: '#dc3545',
|
||||
downColor: '#28a745',
|
||||
borderVisible: false,
|
||||
wickUpColor: '#dc3545',
|
||||
wickDownColor: '#28a745',
|
||||
});
|
||||
// 使用KLC数据创建蜡烛图
|
||||
const klcCandles = buildKLCFromAnalysis(currentData);
|
||||
series.setData(klcCandles);
|
||||
tvWidget.series.klcSeries = series;
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -2717,7 +2730,6 @@
|
||||
tvWidget.series.signalLineSeries = signalLineSeries;
|
||||
tvWidget.series.histogramSeries = histogramSeries;
|
||||
}
|
||||
|
||||
// 添加ChanMACD图表
|
||||
console.log('ChanMACD图表创建条件检查:', {
|
||||
showMacd: showMacd,
|
||||
@@ -2733,7 +2745,6 @@
|
||||
if (typeof window.showUOnElement === 'undefined') {
|
||||
window.showUOnElement = $('#toggleUOnElement').is(':checked');
|
||||
}
|
||||
|
||||
if (showMacd && chanMacdChart && ((useElementPeriod && currentData.element_macd) || currentData.macd) && (useElementPeriod ? currentData.element_kline_data : currentData.kline_data)) {
|
||||
console.log('✅ 开始创建 ChanMACD 系列');
|
||||
// 创建ChanMACD线系列
|
||||
@@ -4338,7 +4349,6 @@
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 主周期未完成中枢
|
||||
if ($('#showMainZs').is(':checked') && currentData.uncompleted_zs_list && currentData.uncompleted_zs_list.length > 0) {
|
||||
console.log(`绘制主周期未完成中枢数据,共${currentData.uncompleted_zs_list.length}条`);
|
||||
@@ -5305,7 +5315,6 @@
|
||||
// 收集所有主周期分型标记
|
||||
const allMainFxMarkers = [];
|
||||
const mainFxMarkers = []; // 用于tooltip支持
|
||||
|
||||
// 处理主周期KLC分型
|
||||
if ($('#showKlcFxType').is(':checked') && currentData.klc_fx_info && currentData.klc_fx_info.length > 0) {
|
||||
console.log(`绘制主周期K线合并分型标签,共${currentData.klc_fx_info.length}条`);
|
||||
@@ -5671,6 +5680,7 @@
|
||||
else if (klineType === 'line') targetSeries = tvWidget.series.lineSeries;
|
||||
else if (klineType === 'area') targetSeries = tvWidget.series.areaSeries;
|
||||
else if (klineType === 'baseline') targetSeries = tvWidget.series.baselineSeries;
|
||||
else if (klineType === 'klc') targetSeries = tvWidget.series.klcSeries;
|
||||
if (targetSeries) {
|
||||
targetSeries.setMarkers(combinedMarkers);
|
||||
} else {
|
||||
@@ -5765,6 +5775,7 @@
|
||||
else if (klineType2 === 'line') targetSeries2 = tvWidget.series.lineSeries;
|
||||
else if (klineType2 === 'area') targetSeries2 = tvWidget.series.areaSeries;
|
||||
else if (klineType2 === 'baseline') targetSeries2 = tvWidget.series.baselineSeries;
|
||||
else if (klineType2 === 'klc') targetSeries2 = tvWidget.series.klcSeries;
|
||||
if (targetSeries2) {
|
||||
targetSeries2.setMarkers(onlyMainAndU);
|
||||
} else {
|
||||
@@ -5782,6 +5793,7 @@
|
||||
else if (klineType3 === 'line') targetSeries3 = tvWidget.series.lineSeries;
|
||||
else if (klineType3 === 'area') targetSeries3 = tvWidget.series.areaSeries;
|
||||
else if (klineType3 === 'baseline') targetSeries3 = tvWidget.series.baselineSeries;
|
||||
else if (klineType3 === 'klc') targetSeries3 = tvWidget.series.klcSeries;
|
||||
if (targetSeries3) {
|
||||
targetSeries3.setMarkers([]);
|
||||
}
|
||||
@@ -6024,6 +6036,9 @@
|
||||
} else if (klineType === 'baseline' && tvWidget.series.baselineSeries) {
|
||||
const baseData = candles.map(c => ({ time: c.time, value: c.close }));
|
||||
tvWidget.series.baselineSeries.setData(baseData);
|
||||
} else if (klineType === 'klc' && tvWidget.series.klcSeries) {
|
||||
const klcCandles = buildKLCFromAnalysis(currentData);
|
||||
tvWidget.series.klcSeries.setData(klcCandles);
|
||||
}
|
||||
|
||||
// 更新均线数据
|
||||
@@ -7010,7 +7025,6 @@
|
||||
// 更新数据源信息
|
||||
setupDataSourceInfo(data);
|
||||
}
|
||||
|
||||
// 设置数据源信息显示
|
||||
function setupDataSourceInfo(data) {
|
||||
// 获取用户当前的周期选择
|
||||
@@ -7103,7 +7117,6 @@
|
||||
$('#end_time').val(formatDatetimeLocal(now));
|
||||
$('#start_time').val(formatDatetimeLocal(oneDayAgo));
|
||||
}
|
||||
|
||||
// 格式化日期为datetime-local输入框格式
|
||||
function formatDatetimeLocal(date) {
|
||||
const year = date.getFullYear();
|
||||
@@ -7753,7 +7766,6 @@
|
||||
console.error('加载A股股票列表失败');
|
||||
});
|
||||
}
|
||||
|
||||
// 检测交易对类型并返回相应的配置
|
||||
function getSymbolConfig(symbol) {
|
||||
const isAStock = symbol && symbol.length === 6 && /^\d+$/.test(symbol);
|
||||
@@ -7811,7 +7823,6 @@
|
||||
|
||||
return chartOptions;
|
||||
}
|
||||
|
||||
// 过滤非交易时间的数据(仅用于显示优化)
|
||||
function filterTradingHours(data, symbolConfig) {
|
||||
if (symbolConfig.type !== 'a_stock') {
|
||||
@@ -8402,7 +8413,6 @@
|
||||
function updateMAPanel() {
|
||||
updateIndicatorPanel();
|
||||
}
|
||||
|
||||
// 切换均线可见性
|
||||
function toggleMAVisibility(maId) {
|
||||
console.log('👁️ 切换均线可见性,ID:', maId, 'Type:', typeof maId);
|
||||
@@ -8605,7 +8615,6 @@
|
||||
|
||||
return candles;
|
||||
}
|
||||
|
||||
// 从蜡烛数据生成 Heikin-Ashi(平均K)
|
||||
function buildHeikinFromCandles(candles) {
|
||||
if (!Array.isArray(candles) || candles.length === 0) return [];
|
||||
@@ -8627,7 +8636,45 @@
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// 从分析数据生成KLC蜡烛数据
|
||||
function buildKLCFromAnalysis(data) {
|
||||
if (!data) return [];
|
||||
|
||||
// 检查是否使用小周期数据
|
||||
const useElementPeriod = $('#elementPeriodKline').is(':checked') &&
|
||||
data.element_klc_list &&
|
||||
Array.isArray(data.element_klc_list);
|
||||
|
||||
const klcList = useElementPeriod ? data.element_klc_list : data.klc_list;
|
||||
|
||||
if (!klcList) return [];
|
||||
|
||||
const klcCandles = [];
|
||||
|
||||
// 遍历KLC列表,转换为蜡烛数据格式
|
||||
klcList.forEach(klc => {
|
||||
if (!klc || !klc.date) return;
|
||||
|
||||
// 使用KLC的date字段,转换为时间戳格式
|
||||
const date = new Date(klc.date);
|
||||
const timestamp = date.getTime() / 1000;
|
||||
|
||||
// 创建KLC蜡烛数据
|
||||
const candle = {
|
||||
time: timestamp,
|
||||
open: klc.open || 0,
|
||||
high: klc.high || 0,
|
||||
low: klc.low || 0,
|
||||
close: klc.close || 0
|
||||
};
|
||||
|
||||
klcCandles.push(candle);
|
||||
});
|
||||
|
||||
return klcCandles;
|
||||
}
|
||||
|
||||
// 计算默认砖大小(优先使用ATR的最新非零值,否则按收盘价的0.5%)
|
||||
function computeDefaultBrickSize(candles) {
|
||||
try {
|
||||
@@ -8881,10 +8928,10 @@
|
||||
|
||||
console.log('🔄 按钮已切换为更新模式');
|
||||
|
||||
$('#bbConfigModal').css('display', 'flex');
|
||||
|
||||
// 更新预览
|
||||
setTimeout(updateBBLinePreview, 50);
|
||||
$('#bbConfigModal').css('display', 'flex');
|
||||
|
||||
// 更新预览
|
||||
setTimeout(updateBBLinePreview, 50);
|
||||
}
|
||||
// 更新布林带
|
||||
function updateBollingerBand(bbId) {
|
||||
@@ -9008,78 +9055,78 @@
|
||||
console.warn('addBollingerBandsToChart 未就绪');
|
||||
}
|
||||
|
||||
// 更新均线预览
|
||||
// 更新均线预览
|
||||
function updateLinePreview() {
|
||||
// 检查是否在均线配置窗口
|
||||
if ($('#maConfigModal').is(':visible')) {
|
||||
const color = $('#maColor').val();
|
||||
const width = $('#maLineWidth').val();
|
||||
const style = $('#maLineStyle').val();
|
||||
// 检查是否在均线配置窗口
|
||||
if ($('#maConfigModal').is(':visible')) {
|
||||
const color = $('#maColor').val();
|
||||
const width = $('#maLineWidth').val();
|
||||
const style = $('#maLineStyle').val();
|
||||
|
||||
const line = $('#previewLine');
|
||||
line.attr('stroke', color);
|
||||
line.attr('stroke-width', width);
|
||||
|
||||
// 设置线条样式
|
||||
switch(parseInt(style)) {
|
||||
case 0: // 实线
|
||||
line.attr('stroke-dasharray', 'none');
|
||||
break;
|
||||
case 1: // 点线
|
||||
line.attr('stroke-dasharray', '2,3');
|
||||
break;
|
||||
case 2: // 虚线
|
||||
line.attr('stroke-dasharray', '5,5');
|
||||
break;
|
||||
case 3: // 大虚线
|
||||
line.attr('stroke-dasharray', '10,5');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 更新布林带预览
|
||||
function updateBBLinePreview() {
|
||||
const upperColor = $('#bbUpperColor').val();
|
||||
const middleColor = $('#bbMiddleColor').val();
|
||||
const lowerColor = $('#bbLowerColor').val();
|
||||
const width = $('#bbLineWidth').val();
|
||||
const style = $('#bbLineStyle').val();
|
||||
|
||||
const line = $('#previewLine');
|
||||
line.attr('stroke', color);
|
||||
line.attr('stroke-width', width);
|
||||
const upperLine = $('#bbPreviewUpper');
|
||||
const middleLine = $('#bbPreviewMiddle');
|
||||
const lowerLine = $('#bbPreviewLower');
|
||||
|
||||
// 设置线条样式
|
||||
switch(parseInt(style)) {
|
||||
case 0: // 实线
|
||||
line.attr('stroke-dasharray', 'none');
|
||||
break;
|
||||
case 1: // 点线
|
||||
line.attr('stroke-dasharray', '2,3');
|
||||
break;
|
||||
case 2: // 虚线
|
||||
line.attr('stroke-dasharray', '5,5');
|
||||
break;
|
||||
case 3: // 大虚线
|
||||
line.attr('stroke-dasharray', '10,5');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新布林带预览
|
||||
function updateBBLinePreview() {
|
||||
const upperColor = $('#bbUpperColor').val();
|
||||
const middleColor = $('#bbMiddleColor').val();
|
||||
const lowerColor = $('#bbLowerColor').val();
|
||||
const width = $('#bbLineWidth').val();
|
||||
const style = $('#bbLineStyle').val();
|
||||
|
||||
const upperLine = $('#bbPreviewUpper');
|
||||
const middleLine = $('#bbPreviewMiddle');
|
||||
const lowerLine = $('#bbPreviewLower');
|
||||
|
||||
// 设置各条线的颜色
|
||||
upperLine.attr('stroke', upperColor);
|
||||
middleLine.attr('stroke', middleColor);
|
||||
lowerLine.attr('stroke', lowerColor);
|
||||
|
||||
// 设置线条宽度和样式
|
||||
[upperLine, middleLine, lowerLine].forEach(line => {
|
||||
line.attr('stroke-width', width);
|
||||
|
||||
// 设置线条样式
|
||||
switch(parseInt(style)) {
|
||||
case 0: // 实线
|
||||
line.attr('stroke-dasharray', 'none');
|
||||
break;
|
||||
case 1: // 点线
|
||||
line.attr('stroke-dasharray', '2,3');
|
||||
break;
|
||||
case 2: // 虚线
|
||||
line.attr('stroke-dasharray', '5,5');
|
||||
break;
|
||||
case 3: // 大虚线
|
||||
line.attr('stroke-dasharray', '10,5');
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
// 设置各条线的颜色
|
||||
upperLine.attr('stroke', upperColor);
|
||||
middleLine.attr('stroke', middleColor);
|
||||
lowerLine.attr('stroke', lowerColor);
|
||||
|
||||
// 设置线条宽度和样式
|
||||
[upperLine, middleLine, lowerLine].forEach(line => {
|
||||
line.attr('stroke-width', width);
|
||||
|
||||
// 设置线条样式
|
||||
switch(parseInt(style)) {
|
||||
case 0: // 实线
|
||||
line.attr('stroke-dasharray', 'none');
|
||||
break;
|
||||
case 1: // 点线
|
||||
line.attr('stroke-dasharray', '2,3');
|
||||
break;
|
||||
case 2: // 虚线
|
||||
line.attr('stroke-dasharray', '5,5');
|
||||
break;
|
||||
case 3: // 大虚线
|
||||
line.attr('stroke-dasharray', '10,5');
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 监听配置变化以更新预览
|
||||
$(document).on('change', '#maColor, #maLineWidth, #maLineStyle', updateLinePreview);
|
||||
$(document).on('change', '#bbUpperColor, #bbMiddleColor, #bbLowerColor, #bbLineWidth, #bbLineStyle', updateBBLinePreview);
|
||||
$(document).on('change', '#bbUpperColor, #bbMiddleColor, #bbLowerColor, #bbLineWidth, #bbLineStyle', updateBBLinePreview);
|
||||
|
||||
// 点击弹窗外部关闭
|
||||
$(document).on('click', '#bbConfigModal', function(e) {
|
||||
if (e.target === this) {
|
||||
@@ -9128,8 +9175,6 @@
|
||||
const now = new Date();
|
||||
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
|
||||
|
||||
|
||||
|
||||
// 添加页面滚动事件监听器,清除十字线延长线
|
||||
$(window).on('scroll', function() {
|
||||
try {
|
||||
@@ -9146,18 +9191,10 @@
|
||||
console.debug('清除滚动中的十字线时出错:', e);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
// ====== ChanMACD图表相关函数 ======
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 清除ChanMACD标注
|
||||
function clearChanMacdMarkers() {
|
||||
// 清除所有系列的标记
|
||||
@@ -9219,7 +9256,7 @@
|
||||
color: seg.seg_dir === 'ABOVE' ? '#e91e63' : '#4caf50',
|
||||
shape: 'square',
|
||||
text: `S${index}E`,
|
||||
size: 0.5
|
||||
size: 0.5
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -9369,7 +9406,6 @@
|
||||
addStateMarkers(stateMarkers);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加状态标记
|
||||
function addStateMarkers(stateMarkers) {
|
||||
const stateMarkersList = [];
|
||||
|
||||
Reference in New Issue
Block a user