添加识别中继分型
This commit is contained in:
+67
-5
@@ -439,6 +439,11 @@ def add_indicators(df):
|
||||
df['ema24'] = (ta.EMA(df, timeperiod=24)).fillna(0)
|
||||
df['ema52'] = (ta.EMA(df, timeperiod=52)).fillna(0)
|
||||
df['ema26'] = (ta.EMA(df, timeperiod=26)).fillna(0)
|
||||
df['ema13'] = (ta.EMA(df, timeperiod=13)).fillna(0)
|
||||
df['ema7'] = (ta.EMA(df, timeperiod=7)).fillna(0)
|
||||
df['ema104'] = (ta.EMA(df, timeperiod=104)).fillna(0)
|
||||
df['ema156'] = (ta.EMA(df, timeperiod=156)).fillna(0)
|
||||
df['ema208'] = (ta.EMA(df, timeperiod=208)).fillna(0)
|
||||
# 常用SMA 24/52
|
||||
try:
|
||||
df['sma24'] = (ta.SMA(df, timeperiod=24)).fillna(0)
|
||||
@@ -624,6 +629,16 @@ def analyze_chan(df, symbol=None, timeframe=None):
|
||||
# 如果分型强度小于1,设为0
|
||||
if fx_strength < 1:
|
||||
fx_strength = 0
|
||||
|
||||
# KLC 分型框(起止时间+高低价):
|
||||
# 仅使用 cal_fx_box 通过 display 条件后生成的 klc.fx_box。
|
||||
# 若无 fx_box,则前端不应绘制分型框。
|
||||
fx_box = getattr(klc, 'fx_box', None)
|
||||
box_start_time = getattr(fx_box, 'start_time', None) if fx_box else None
|
||||
box_end_time = getattr(fx_box, 'end_time', None) if fx_box else None
|
||||
box_high = getattr(fx_box, 'high', None) if fx_box else None
|
||||
box_low = getattr(fx_box, 'low', None) if fx_box else None
|
||||
|
||||
if klc.bb_out:
|
||||
klc_fx_info.append({
|
||||
'time': klc.end_time,
|
||||
@@ -632,10 +647,22 @@ def analyze_chan(df, symbol=None, timeframe=None):
|
||||
'is_bottom': klc.fx == Chan_FX_TYPE.BOTTOM,
|
||||
'fx_strength': fx_strength, # 分型强度分数 (0-100)
|
||||
'fx_strength_level': fx_strength_level, # 分型强度等级 (极强/强/中等/弱/极弱)
|
||||
'is_strong_fx': is_strong_fx # 是否为强分型
|
||||
'is_strong_fx': is_strong_fx, # 是否为强分型
|
||||
|
||||
# 虚线分型框信息(给前端画框用)
|
||||
'start_time': box_start_time,
|
||||
'end_time': box_end_time,
|
||||
'high': float(box_high) if box_high is not None else None,
|
||||
'low': float(box_low) if box_low is not None else None,
|
||||
})
|
||||
except Exception as e:
|
||||
# 如果出错,仍然添加基本信息,但分型强度为0
|
||||
fx_box = getattr(klc, 'fx_box', None)
|
||||
box_start_time = getattr(fx_box, 'start_time', None) if fx_box else None
|
||||
box_end_time = getattr(fx_box, 'end_time', None) if fx_box else None
|
||||
box_high = getattr(fx_box, 'high', None) if fx_box else None
|
||||
box_low = getattr(fx_box, 'low', None) if fx_box else None
|
||||
|
||||
klc_fx_info.append({
|
||||
'time': klc.end_time,
|
||||
'price': klc.low if klc.fx == Chan_FX_TYPE.BOTTOM else klc.high,
|
||||
@@ -643,7 +670,13 @@ def analyze_chan(df, symbol=None, timeframe=None):
|
||||
'is_bottom': klc.fx == Chan_FX_TYPE.BOTTOM,
|
||||
'fx_strength': 0,
|
||||
'fx_strength_level': "",
|
||||
'is_strong_fx': False
|
||||
'is_strong_fx': False,
|
||||
|
||||
# 虚线分型框信息(给前端画框用)
|
||||
'start_time': box_start_time,
|
||||
'end_time': box_end_time,
|
||||
'high': float(box_high) if box_high is not None else None,
|
||||
'low': float(box_low) if box_low is not None else None,
|
||||
})
|
||||
|
||||
|
||||
@@ -1391,12 +1424,17 @@ def analyze():
|
||||
# 添加K线分型信息
|
||||
'klc_fx_info': [{
|
||||
'time': format_time_safely(point['time'], client_tz),
|
||||
'start_time': format_time_safely(point['start_time'], client_tz),
|
||||
'end_time': format_time_safely(point['end_time'], client_tz),
|
||||
'price': float(point['price']),
|
||||
'fx_type': point['fx_type'],
|
||||
'is_bottom': bool(point['is_bottom']),
|
||||
'fx_strength': float(point['fx_strength']), # 分型强度分数
|
||||
'fx_strength_level': str(point['fx_strength_level']), # 分型强度等级
|
||||
'is_strong_fx': bool(point['is_strong_fx']) # 是否为强分型
|
||||
'is_strong_fx': bool(point['is_strong_fx']), # 是否为强分型
|
||||
# 分型框(虚线矩形)用到的高低价
|
||||
'high': float(point['high']) if point.get('high') is not None else None,
|
||||
'low': float(point['low']) if point.get('low') is not None else None
|
||||
} for point in analysis_result['klc_fx_info']],
|
||||
# 添加ChanMACD分析数据
|
||||
'chan_macd': serialize_chan_macd_data(analysis_result.get('chan_macd', {}), client_tz),
|
||||
@@ -1587,12 +1625,17 @@ def analyze():
|
||||
# 添加小周期分型信息
|
||||
result['element_klc_fx_info'] = [{
|
||||
'time': format_time_safely(point['time'], client_tz),
|
||||
'start_time': format_time_safely(point['start_time'], client_tz),
|
||||
'end_time': format_time_safely(point['end_time'], client_tz),
|
||||
'price': float(point['price']),
|
||||
'fx_type': point['fx_type'],
|
||||
'is_bottom': bool(point['is_bottom']),
|
||||
'fx_strength': float(point['fx_strength']), # 分型强度分数
|
||||
'fx_strength_level': str(point['fx_strength_level']), # 分型强度等级
|
||||
'is_strong_fx': bool(point['is_strong_fx']) # 是否为强分型
|
||||
'is_strong_fx': bool(point['is_strong_fx']), # 是否为强分型
|
||||
# 分型框(虚线矩形)用到的高低价
|
||||
'high': float(point['high']) if point.get('high') is not None else None,
|
||||
'low': float(point['low']) if point.get('low') is not None else None
|
||||
} for point in element_analysis['klc_fx_info']]
|
||||
|
||||
# 添加次周期ChanMACD分析数据
|
||||
@@ -1640,6 +1683,20 @@ def analyze():
|
||||
'direction': convert_direction(bi.dir),
|
||||
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
|
||||
} for bi in sub_sub_analysis['bi_list'] if not bi.end_klc]
|
||||
# 次次周期 KLC 列表
|
||||
result['sub_sub_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 sub_sub_analysis.get('klc_list', []) if hasattr(klc, 'end_time') and klc.end_time]
|
||||
|
||||
result['sub_sub_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,
|
||||
@@ -1677,12 +1734,17 @@ def analyze():
|
||||
} for zs in sub_sub_analysis.get('bi_zs_list', []) if not getattr(zs, 'is_sure', False)]
|
||||
result['sub_sub_klc_fx_info'] = [{
|
||||
'time': format_time_safely(point['time'], client_tz),
|
||||
'start_time': format_time_safely(point['start_time'], client_tz),
|
||||
'end_time': format_time_safely(point['end_time'], client_tz),
|
||||
'price': float(point['price']),
|
||||
'fx_type': point['fx_type'],
|
||||
'is_bottom': bool(point['is_bottom']),
|
||||
'fx_strength': float(point['fx_strength']),
|
||||
'fx_strength_level': str(point['fx_strength_level']),
|
||||
'is_strong_fx': bool(point['is_strong_fx'])
|
||||
'is_strong_fx': bool(point['is_strong_fx']),
|
||||
# 分型框(虚线矩形)用到的高低价
|
||||
'high': float(point['high']) if point.get('high') is not None else None,
|
||||
'low': float(point['low']) if point.get('low') is not None else None
|
||||
} for point in sub_sub_analysis['klc_fx_info']]
|
||||
result['sub_sub_bsp_list'] = [{
|
||||
'time': format_time_safely(bsp.end_time, client_tz),
|
||||
|
||||
+255
-45
@@ -5817,6 +5817,64 @@
|
||||
|
||||
allMainFxMarkers.push(markerConfig);
|
||||
|
||||
// 画虚线分型框(根据 start/end + high/low)
|
||||
if (fx.start_time && fx.end_time && fx.high !== null && fx.high !== undefined && fx.low !== null && fx.low !== undefined) {
|
||||
const startTs = Math.floor(new Date(fx.start_time).getTime() / 1000);
|
||||
const endTs = Math.floor(new Date(fx.end_time).getTime() / 1000);
|
||||
const high = parseFloat(fx.high);
|
||||
const low = parseFloat(fx.low);
|
||||
|
||||
if (!isNaN(startTs) && !isNaN(endTs) && !isNaN(high) && !isNaN(low)) {
|
||||
const boxHigh = Math.max(high, low);
|
||||
const boxLow = Math.min(high, low);
|
||||
const boxColor = strengthColor;
|
||||
|
||||
const topSeries = mainChart.addLineSeries({
|
||||
color: boxColor,
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
});
|
||||
topSeries.setData([{ time: startTs, value: boxHigh }, { time: endTs, value: boxHigh }]);
|
||||
|
||||
const bottomSeries = mainChart.addLineSeries({
|
||||
color: boxColor,
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
});
|
||||
bottomSeries.setData([{ time: startTs, value: boxLow }, { time: endTs, value: boxLow }]);
|
||||
|
||||
const leftSeries = mainChart.addLineSeries({
|
||||
color: boxColor,
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
});
|
||||
// 左边竖线:同一 time 上下两个点(和你已有ZS绘制写法保持一致)
|
||||
leftSeries.setData([{ time: startTs, value: boxLow }, { time: startTs, value: boxHigh }]);
|
||||
|
||||
const rightSeries = mainChart.addLineSeries({
|
||||
color: boxColor,
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
});
|
||||
rightSeries.setData([{ time: endTs, value: boxLow }, { time: endTs, value: boxHigh }]);
|
||||
|
||||
if (!tvWidget.series.mainKlcFxBoxSeries) tvWidget.series.mainKlcFxBoxSeries = [];
|
||||
tvWidget.series.mainKlcFxBoxSeries.push(topSeries, bottomSeries, leftSeries, rightSeries);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建分型标记对象,包含tooltip信息
|
||||
const fxMarker = {
|
||||
time: timestamp,
|
||||
@@ -5966,6 +6024,63 @@
|
||||
|
||||
allElementFxMarkers.push(markerConfig);
|
||||
|
||||
// 画虚线分型框(小周期)
|
||||
if (fx.start_time && fx.end_time && fx.high !== null && fx.high !== undefined && fx.low !== null && fx.low !== undefined) {
|
||||
const startTs = Math.floor(new Date(fx.start_time).getTime() / 1000);
|
||||
const endTs = Math.floor(new Date(fx.end_time).getTime() / 1000);
|
||||
const high = parseFloat(fx.high);
|
||||
const low = parseFloat(fx.low);
|
||||
|
||||
if (!isNaN(startTs) && !isNaN(endTs) && !isNaN(high) && !isNaN(low)) {
|
||||
const boxHigh = Math.max(high, low);
|
||||
const boxLow = Math.min(high, low);
|
||||
const boxColor = strengthColor;
|
||||
|
||||
const topSeries = mainChart.addLineSeries({
|
||||
color: boxColor,
|
||||
lineWidth: 1,
|
||||
lineStyle: 2,
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
});
|
||||
topSeries.setData([{ time: startTs, value: boxHigh }, { time: endTs, value: boxHigh }]);
|
||||
|
||||
const bottomSeries = mainChart.addLineSeries({
|
||||
color: boxColor,
|
||||
lineWidth: 1,
|
||||
lineStyle: 2,
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
});
|
||||
bottomSeries.setData([{ time: startTs, value: boxLow }, { time: endTs, value: boxLow }]);
|
||||
|
||||
const leftSeries = mainChart.addLineSeries({
|
||||
color: boxColor,
|
||||
lineWidth: 1,
|
||||
lineStyle: 2,
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
});
|
||||
leftSeries.setData([{ time: startTs, value: boxLow }, { time: startTs, value: boxHigh }]);
|
||||
|
||||
const rightSeries = mainChart.addLineSeries({
|
||||
color: boxColor,
|
||||
lineWidth: 1,
|
||||
lineStyle: 2,
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
});
|
||||
rightSeries.setData([{ time: endTs, value: boxLow }, { time: endTs, value: boxHigh }]);
|
||||
|
||||
if (!tvWidget.series.elementKlcFxBoxSeries) tvWidget.series.elementKlcFxBoxSeries = [];
|
||||
tvWidget.series.elementKlcFxBoxSeries.push(topSeries, bottomSeries, leftSeries, rightSeries);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建小周期分型标记对象,包含tooltip信息
|
||||
const elementFxMarker = {
|
||||
time: timestamp,
|
||||
@@ -6061,6 +6176,63 @@
|
||||
size: (fx.is_strong_fx ? 0.6 : 0.5)
|
||||
};
|
||||
allElementFxMarkers.push(markerConfig);
|
||||
|
||||
// 画虚线分型框(次次周期)
|
||||
if (fx.start_time && fx.end_time && fx.high !== null && fx.high !== undefined && fx.low !== null && fx.low !== undefined) {
|
||||
const startTs = Math.floor(new Date(fx.start_time).getTime() / 1000);
|
||||
const endTs = Math.floor(new Date(fx.end_time).getTime() / 1000);
|
||||
const high = parseFloat(fx.high);
|
||||
const low = parseFloat(fx.low);
|
||||
|
||||
if (!isNaN(startTs) && !isNaN(endTs) && !isNaN(high) && !isNaN(low)) {
|
||||
const boxHigh = Math.max(high, low);
|
||||
const boxLow = Math.min(high, low);
|
||||
const boxColor = strengthColor;
|
||||
|
||||
const topSeries = mainChart.addLineSeries({
|
||||
color: boxColor,
|
||||
lineWidth: 1,
|
||||
lineStyle: 2,
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
});
|
||||
topSeries.setData([{ time: startTs, value: boxHigh }, { time: endTs, value: boxHigh }]);
|
||||
|
||||
const bottomSeries = mainChart.addLineSeries({
|
||||
color: boxColor,
|
||||
lineWidth: 1,
|
||||
lineStyle: 2,
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
});
|
||||
bottomSeries.setData([{ time: startTs, value: boxLow }, { time: endTs, value: boxLow }]);
|
||||
|
||||
const leftSeries = mainChart.addLineSeries({
|
||||
color: boxColor,
|
||||
lineWidth: 1,
|
||||
lineStyle: 2,
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
});
|
||||
leftSeries.setData([{ time: startTs, value: boxLow }, { time: startTs, value: boxHigh }]);
|
||||
|
||||
const rightSeries = mainChart.addLineSeries({
|
||||
color: boxColor,
|
||||
lineWidth: 1,
|
||||
lineStyle: 2,
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
});
|
||||
rightSeries.setData([{ time: endTs, value: boxLow }, { time: endTs, value: boxHigh }]);
|
||||
|
||||
if (!tvWidget.series.subSubKlcFxBoxSeries) tvWidget.series.subSubKlcFxBoxSeries = [];
|
||||
tvWidget.series.subSubKlcFxBoxSeries.push(topSeries, bottomSeries, leftSeries, rightSeries);
|
||||
}
|
||||
}
|
||||
} catch (e) { console.error('绘制次次周期KLC分型标记出错:', e); }
|
||||
});
|
||||
}
|
||||
@@ -6200,7 +6372,11 @@
|
||||
else if (klineType === 'baseline') targetSeries = tvWidget.series.baselineSeries;
|
||||
else if (klineType === 'klc') targetSeries = tvWidget.series.klcSeries;
|
||||
if (targetSeries) {
|
||||
targetSeries.setMarkers(combinedMarkers);
|
||||
try {
|
||||
targetSeries.setMarkers(combinedMarkers);
|
||||
} catch (e) {
|
||||
console.warn('设置主系列标记失败(可能series已释放):', e);
|
||||
}
|
||||
} else {
|
||||
console.log('未找到主数据系列,无法设置标记');
|
||||
}
|
||||
@@ -6324,7 +6500,11 @@
|
||||
else if (klineType2 === 'baseline') targetSeries2 = tvWidget.series.baselineSeries;
|
||||
else if (klineType2 === 'klc') targetSeries2 = tvWidget.series.klcSeries;
|
||||
if (targetSeries2) {
|
||||
targetSeries2.setMarkers(onlyMainAndU);
|
||||
try {
|
||||
targetSeries2.setMarkers(onlyMainAndU);
|
||||
} catch (e) {
|
||||
console.warn('设置主系列标记失败(可能series已释放):', e);
|
||||
}
|
||||
} else {
|
||||
console.log('未找到主数据系列,无法设置标记');
|
||||
}
|
||||
@@ -6342,7 +6522,11 @@
|
||||
else if (klineType3 === 'baseline') targetSeries3 = tvWidget.series.baselineSeries;
|
||||
else if (klineType3 === 'klc') targetSeries3 = tvWidget.series.klcSeries;
|
||||
if (targetSeries3) {
|
||||
targetSeries3.setMarkers([]);
|
||||
try {
|
||||
targetSeries3.setMarkers([]);
|
||||
} catch (e) {
|
||||
console.warn('清空主系列标记失败(可能series已释放):', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6552,15 +6736,33 @@
|
||||
// 检查是否显示原始K线
|
||||
const showOriginalKline = $('#showOriginalKline').is(':checked');
|
||||
|
||||
// 检查是否使用小周期数据
|
||||
const useElementPeriod = $('#elementPeriodKline').is(':checked') &&
|
||||
// 检查是否使用次次周期 / 小周期数据
|
||||
const useSubSubPeriod = $('#subSubPeriodKline').is(':checked') &&
|
||||
currentData.sub_sub_timeframe &&
|
||||
currentData.sub_sub_kline_data &&
|
||||
Array.isArray(currentData.sub_sub_kline_data);
|
||||
const useElementPeriod = !useSubSubPeriod &&
|
||||
$('#elementPeriodKline').is(':checked') &&
|
||||
currentData.element_timeframe &&
|
||||
currentData.element_kline_data &&
|
||||
Array.isArray(currentData.element_kline_data);
|
||||
|
||||
// 转换K线数据
|
||||
let candles = [];
|
||||
if (useElementPeriod) {
|
||||
if (useSubSubPeriod) {
|
||||
console.log('使用次次周期K线数据');
|
||||
candles = currentData.sub_sub_kline_data.map((kline) => {
|
||||
const date = new Date(kline.date);
|
||||
const timestamp = date.getTime() / 1000;
|
||||
return {
|
||||
time: timestamp,
|
||||
open: parseFloat(kline.open),
|
||||
high: parseFloat(kline.high),
|
||||
low: parseFloat(kline.low),
|
||||
close: parseFloat(kline.close),
|
||||
};
|
||||
});
|
||||
} else if (useElementPeriod) {
|
||||
console.log('使用小周期K线数据');
|
||||
candles = currentData.element_kline_data.map((kline) => {
|
||||
const date = new Date(kline.date);
|
||||
@@ -6622,7 +6824,16 @@
|
||||
|
||||
// 更新成交量数据
|
||||
let volumes = [];
|
||||
if (useElementPeriod && currentData.element_kline_data && Array.isArray(currentData.element_kline_data)) {
|
||||
if (useSubSubPeriod && currentData.sub_sub_kline_data && Array.isArray(currentData.sub_sub_kline_data)) {
|
||||
volumes = currentData.sub_sub_kline_data.map(kline => {
|
||||
const timestamp = Math.floor(new Date(kline.date).getTime() / 1000);
|
||||
return {
|
||||
time: timestamp,
|
||||
value: parseFloat(kline.volume),
|
||||
color: parseFloat(kline.close) >= parseFloat(kline.open) ? 'rgba(40, 167, 69, 0.5)' : 'rgba(220, 53, 69, 0.5)',
|
||||
};
|
||||
});
|
||||
} else if (useElementPeriod && currentData.element_kline_data && Array.isArray(currentData.element_kline_data)) {
|
||||
volumes = currentData.element_kline_data.map(kline => {
|
||||
const timestamp = Math.floor(new Date(kline.date).getTime() / 1000);
|
||||
return {
|
||||
@@ -6649,9 +6860,9 @@
|
||||
// 更新ATR数据
|
||||
if (tvWidget.series.atrLineSeries) {
|
||||
const atrData = [];
|
||||
const atrDataSource = useElementPeriod ?
|
||||
(currentData.element_atr || currentData.atr) :
|
||||
currentData.atr;
|
||||
const atrDataSource = useSubSubPeriod ?
|
||||
(currentData.sub_sub_atr || currentData.atr) :
|
||||
(useElementPeriod ? (currentData.element_atr || currentData.atr) : currentData.atr);
|
||||
|
||||
if (atrDataSource && Array.isArray(atrDataSource)) {
|
||||
const klineDataSource = useSubSubPeriod ? (currentData.sub_sub_kline_data || []) : (useElementPeriod ? currentData.element_kline_data : currentData.kline_data);
|
||||
@@ -9187,44 +9398,39 @@
|
||||
try { updateIndicatorPanel(); } catch(e) {}
|
||||
try { if ($('#maConfigModal').is(':visible')) { hideMAConfig(); } } catch(e) {}
|
||||
}
|
||||
// 获取当前K线数据的辅助函数
|
||||
// 获取当前K线数据的辅助函数(与基础显示的主/小/次次周期保持一致)
|
||||
function getCurrentCandleData() {
|
||||
if (!currentData || !currentData.kline_data) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 检查是否使用小周期数据
|
||||
const useElementPeriod = $('#elementPeriodKline').is(':checked') &&
|
||||
const useSubSubPeriod = $('#subSubPeriodKline').is(':checked') &&
|
||||
currentData.sub_sub_kline_data &&
|
||||
Array.isArray(currentData.sub_sub_kline_data);
|
||||
const useElementPeriod = !useSubSubPeriod &&
|
||||
$('#elementPeriodKline').is(':checked') &&
|
||||
currentData.element_kline_data &&
|
||||
Array.isArray(currentData.element_kline_data);
|
||||
|
||||
let candles = [];
|
||||
if (useElementPeriod) {
|
||||
candles = currentData.element_kline_data.map((kline) => {
|
||||
const date = new Date(kline.date);
|
||||
const timestamp = date.getTime() / 1000;
|
||||
return {
|
||||
time: timestamp,
|
||||
open: parseFloat(kline.open),
|
||||
high: parseFloat(kline.high),
|
||||
low: parseFloat(kline.low),
|
||||
close: parseFloat(kline.close),
|
||||
};
|
||||
});
|
||||
} else {
|
||||
candles = currentData.kline_data.map((kline) => {
|
||||
const date = new Date(kline.date);
|
||||
const timestamp = date.getTime() / 1000;
|
||||
return {
|
||||
time: timestamp,
|
||||
open: parseFloat(kline.open),
|
||||
high: parseFloat(kline.high),
|
||||
low: parseFloat(kline.low),
|
||||
close: parseFloat(kline.close),
|
||||
};
|
||||
});
|
||||
let source = currentData.kline_data;
|
||||
if (useSubSubPeriod) {
|
||||
source = currentData.sub_sub_kline_data;
|
||||
} else if (useElementPeriod) {
|
||||
source = currentData.element_kline_data;
|
||||
}
|
||||
|
||||
const candles = source.map((kline) => {
|
||||
const date = new Date(kline.date);
|
||||
const timestamp = date.getTime() / 1000;
|
||||
return {
|
||||
time: timestamp,
|
||||
open: parseFloat(kline.open),
|
||||
high: parseFloat(kline.high),
|
||||
low: parseFloat(kline.low),
|
||||
close: parseFloat(kline.close),
|
||||
};
|
||||
});
|
||||
|
||||
return candles;
|
||||
}
|
||||
// 从蜡烛数据生成 Heikin-Ashi(平均K)
|
||||
@@ -9253,14 +9459,20 @@
|
||||
function buildKLCFromAnalysis(data) {
|
||||
if (!data) return [];
|
||||
|
||||
// 检查是否使用小周期数据
|
||||
const useElementPeriod = $('#elementPeriodKline').is(':checked') &&
|
||||
data.element_klc_list &&
|
||||
// 根据基础显示的K线周期选择:次次周期 / 小周期 / 主周期
|
||||
const useSubSubPeriod = $('#subSubPeriodKline').is(':checked') &&
|
||||
data.sub_sub_klc_list &&
|
||||
Array.isArray(data.sub_sub_klc_list);
|
||||
const useElementPeriod = !useSubSubPeriod &&
|
||||
$('#elementPeriodKline').is(':checked') &&
|
||||
data.element_klc_list &&
|
||||
Array.isArray(data.element_klc_list);
|
||||
|
||||
const klcList = useElementPeriod ? data.element_klc_list : data.klc_list;
|
||||
const klcList = useSubSubPeriod
|
||||
? data.sub_sub_klc_list
|
||||
: (useElementPeriod ? data.element_klc_list : data.klc_list);
|
||||
|
||||
if (!klcList) return [];
|
||||
if (!klcList || !Array.isArray(klcList)) return [];
|
||||
|
||||
const klcCandles = [];
|
||||
|
||||
@@ -9268,11 +9480,9 @@
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user