添加未完成笔和线段
This commit is contained in:
+103
-4
@@ -538,6 +538,15 @@ def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, sta
|
||||
'direction': convert_direction(bi.dir),
|
||||
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
|
||||
} for bi in filtered_bi_list if bi.end_klc],
|
||||
'element_uncompleted_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': None, # 未完成笔没有结束时间
|
||||
'sure_time': format_time_safely(bi.sure_time, client_tz) if bi.sure_time else None,
|
||||
'start_price': bi.start_klc.low if convert_direction(bi.dir) == 1 else bi.start_klc.high,
|
||||
'end_price': None, # 未完成笔没有结束价格
|
||||
'direction': convert_direction(bi.dir),
|
||||
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
|
||||
} for bi in filtered_bi_list if not bi.end_klc],
|
||||
'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,
|
||||
@@ -545,12 +554,15 @@ def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, sta
|
||||
'start_price': seg.start_bi.start_klc.low if convert_direction(seg.dir) == 1 else seg.start_bi.start_klc.high,
|
||||
'end_price': seg.end_bi.end_klc.high if convert_direction(seg.dir) == 1 else seg.end_bi.end_klc.low if seg.end_bi else None,
|
||||
'direction': convert_direction(seg.dir)
|
||||
} for seg in filtered_seg_list if seg.end_bi],
|
||||
} for seg in filtered_seg_list if seg.is_sure],
|
||||
'element_uncompleted_seg_list': get_uncompleted_seg_list(filtered_seg_list, client_tz),
|
||||
'element_zs_list': [{
|
||||
'start_time': zs.start_klc.end_time if isinstance(zs.start_klc.end_time, str) else zs.start_klc.end_time.astimezone(client_tz).isoformat(),
|
||||
'end_time': (zs.end_klc.end_time if isinstance(zs.end_klc.end_time, str) else zs.end_klc.end_time.astimezone(client_tz).isoformat()) if zs.end_klc else None,
|
||||
'zg': zs.zg,
|
||||
'zd': zs.zd,
|
||||
'gg': zs.gg,
|
||||
'dd': zs.dd,
|
||||
'is_sure': zs.is_sure
|
||||
} for zs in filtered_zs_list if zs.end_klc],
|
||||
'element_uncompleted_zs_list': [{
|
||||
@@ -558,6 +570,8 @@ def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, sta
|
||||
'end_time': None,
|
||||
'zg': zs.zg,
|
||||
'zd': zs.zd,
|
||||
'gg': zs.gg,
|
||||
'dd': zs.dd,
|
||||
'is_sure': zs.is_sure
|
||||
} for zs in filtered_zs_list if not zs.is_sure],
|
||||
'element_trade_points': [{
|
||||
@@ -616,6 +630,15 @@ def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, sta
|
||||
'direction': convert_direction(bi.dir),
|
||||
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
|
||||
} for bi in analysis_result['bi_list'] if bi.end_klc],
|
||||
'uncompleted_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': None, # 未完成笔没有结束时间
|
||||
'sure_time': format_time_safely(bi.sure_time, client_tz) if bi.sure_time else None,
|
||||
'start_price': bi.start_klc.low if convert_direction(bi.dir) == 1 else bi.start_klc.high,
|
||||
'end_price': None, # 未完成笔没有结束价格
|
||||
'direction': convert_direction(bi.dir),
|
||||
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
|
||||
} for bi in analysis_result['bi_list'] if not bi.end_klc],
|
||||
'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,
|
||||
@@ -623,12 +646,15 @@ def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, sta
|
||||
'start_price': seg.start_bi.start_klc.low if convert_direction(seg.dir) == 1 else seg.start_bi.start_klc.high,
|
||||
'end_price': seg.end_bi.end_klc.high if convert_direction(seg.dir) == 1 else seg.end_bi.end_klc.low if seg.end_bi else None,
|
||||
'direction': convert_direction(seg.dir)
|
||||
} for seg in analysis_result['seg_list'] if seg.end_bi],
|
||||
} for seg in analysis_result['seg_list'] if seg.is_sure],
|
||||
'uncompleted_seg_list': get_uncompleted_seg_list(analysis_result['seg_list'], client_tz),
|
||||
'zs_list': [{
|
||||
'start_time': zs.start_klc.end_time if isinstance(zs.start_klc.end_time, str) else zs.start_klc.end_time.astimezone(client_tz).isoformat(),
|
||||
'end_time': (zs.end_klc.end_time if isinstance(zs.end_klc.end_time, str) else zs.end_klc.end_time.astimezone(client_tz).isoformat()) if zs.end_klc else None,
|
||||
'zg': zs.zg,
|
||||
'zd': zs.zd,
|
||||
'gg': zs.gg,
|
||||
'dd': zs.dd,
|
||||
'is_sure': zs.is_sure
|
||||
} for zs in analysis_result['zs_list'] if zs.end_klc],
|
||||
'uncompleted_zs_list': [{
|
||||
@@ -636,6 +662,8 @@ def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, sta
|
||||
'end_time': None,
|
||||
'zg': zs.zg,
|
||||
'zd': zs.zd,
|
||||
'gg': zs.gg,
|
||||
'dd': zs.dd,
|
||||
'is_sure': zs.is_sure
|
||||
} for zs in analysis_result['zs_list'] if not zs.is_sure],
|
||||
'trade_points': [{
|
||||
@@ -686,7 +714,9 @@ def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, sta
|
||||
step_data.update({
|
||||
'element_kline_data': [],
|
||||
'element_bi_list': [],
|
||||
'element_uncompleted_bi_list': [],
|
||||
'element_seg_list': [],
|
||||
'element_uncompleted_seg_list': [],
|
||||
'element_zs_list': [],
|
||||
'element_uncompleted_zs_list': [],
|
||||
'element_trade_points': [],
|
||||
@@ -1089,6 +1119,16 @@ def analyze():
|
||||
'direction': convert_direction(bi.dir),
|
||||
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
|
||||
} for bi in analysis_result['bi_list'] if bi.end_klc],
|
||||
# 添加未完成笔列表
|
||||
'uncompleted_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': None, # 未完成笔没有结束时间
|
||||
'sure_time': format_time_safely(bi.sure_time, client_tz) if bi.sure_time else None,
|
||||
'start_price': bi.start_klc.low if convert_direction(bi.dir) == 1 else bi.start_klc.high,
|
||||
'end_price': None, # 未完成笔没有结束价格
|
||||
'direction': convert_direction(bi.dir),
|
||||
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
|
||||
} for bi in analysis_result['bi_list'] if not bi.end_klc],
|
||||
'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,
|
||||
@@ -1096,12 +1136,16 @@ def analyze():
|
||||
'start_price': seg.start_bi.start_klc.low if convert_direction(seg.dir) == 1 else seg.start_bi.start_klc.high,
|
||||
'end_price': seg.end_bi.end_klc.high if convert_direction(seg.dir) == 1 else seg.end_bi.end_klc.low if seg.end_bi else None,
|
||||
'direction': convert_direction(seg.dir)
|
||||
} for seg in analysis_result['seg_list'] if seg.end_bi],
|
||||
} for seg in analysis_result['seg_list'] if seg.is_sure],
|
||||
# 添加未完成线段列表
|
||||
'uncompleted_seg_list': get_uncompleted_seg_list(analysis_result['seg_list'], client_tz),
|
||||
'zs_list': [{
|
||||
'start_time': zs.start_klc.end_time if isinstance(zs.start_klc.end_time, str) else zs.start_klc.end_time.astimezone(client_tz).isoformat(),
|
||||
'end_time': (zs.end_klc.end_time if isinstance(zs.end_klc.end_time, str) else zs.end_klc.end_time.astimezone(client_tz).isoformat()) if zs.end_klc else None,
|
||||
'zg': zs.zg,
|
||||
'zd': zs.zd,
|
||||
'gg': zs.gg,
|
||||
'dd': zs.dd,
|
||||
'is_sure': zs.is_sure # 添加中枢是否完成的标志
|
||||
} for zs in analysis_result['zs_list'] if zs.end_klc],
|
||||
# 添加未完成中枢列表
|
||||
@@ -1110,6 +1154,8 @@ def analyze():
|
||||
'end_time': None, # 未完成中枢没有结束时间
|
||||
'zg': zs.zg,
|
||||
'zd': zs.zd,
|
||||
'gg': zs.gg,
|
||||
'dd': zs.dd,
|
||||
'is_sure': zs.is_sure # 未完成中枢的is_sure为False
|
||||
} for zs in analysis_result['zs_list'] if not zs.is_sure],
|
||||
'trade_points': [{
|
||||
@@ -1201,6 +1247,16 @@ def analyze():
|
||||
'direction': convert_direction(bi.dir),
|
||||
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
|
||||
} for bi in element_analysis['bi_list'] if bi.end_klc]
|
||||
# 添加次周期未完成笔列表
|
||||
result['element_uncompleted_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': None, # 未完成笔没有结束时间
|
||||
'sure_time': format_time_safely(bi.sure_time, client_tz) if bi.sure_time else None,
|
||||
'start_price': bi.start_klc.low if convert_direction(bi.dir) == 1 else bi.start_klc.high,
|
||||
'end_price': None, # 未完成笔没有结束价格
|
||||
'direction': convert_direction(bi.dir),
|
||||
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
|
||||
} for bi in element_analysis['bi_list'] if not bi.end_klc]
|
||||
|
||||
# 添加小周期K线数据
|
||||
result['element_kline_data'] = clean_dataframe_for_json(element_df).to_dict('records')
|
||||
@@ -1212,13 +1268,17 @@ def analyze():
|
||||
'start_price': seg.start_bi.start_klc.low if convert_direction(seg.dir) == 1 else seg.start_bi.start_klc.high,
|
||||
'end_price': seg.end_bi.end_klc.high if convert_direction(seg.dir) == 1 else seg.end_bi.end_klc.low if seg.end_bi else None,
|
||||
'direction': convert_direction(seg.dir)
|
||||
} for seg in element_analysis['seg_list'] if seg.end_bi]
|
||||
} for seg in element_analysis['seg_list'] if seg.is_sure]
|
||||
# 添加次周期未完成线段列表
|
||||
result['element_uncompleted_seg_list'] = get_uncompleted_seg_list(element_analysis['seg_list'], client_tz)
|
||||
|
||||
result['element_zs_list'] = [{
|
||||
'start_time': zs.start_klc.end_time if isinstance(zs.start_klc.end_time, str) else zs.start_klc.end_time.astimezone(client_tz).isoformat(),
|
||||
'end_time': (zs.end_klc.end_time if isinstance(zs.end_klc.end_time, str) else zs.end_klc.end_time.astimezone(client_tz).isoformat()) if zs.end_klc else None,
|
||||
'zg': zs.zg,
|
||||
'zd': zs.zd,
|
||||
'gg': zs.gg,
|
||||
'dd': zs.dd,
|
||||
'is_sure': zs.is_sure # 添加中枢是否完成的标志
|
||||
} for zs in element_analysis['zs_list'] if zs.end_klc]
|
||||
|
||||
@@ -1227,6 +1287,8 @@ def analyze():
|
||||
'end_time': None, # 未完成中枢没有结束时间
|
||||
'zg': zs.zg,
|
||||
'zd': zs.zd,
|
||||
'gg': zs.gg,
|
||||
'dd': zs.dd,
|
||||
'is_sure': zs.is_sure # 未完成中枢的is_sure为False
|
||||
} for zs in element_analysis['zs_list'] if not zs.is_sure]
|
||||
|
||||
@@ -1605,6 +1667,43 @@ def filter_stocks():
|
||||
else:
|
||||
return jsonify({'error': str(e)})
|
||||
|
||||
def get_uncompleted_seg_list(seg_list, client_tz):
|
||||
"""获取未完成线段列表,正确处理倒数第二个和最后一个未完成线段"""
|
||||
uncompleted_segs = [seg for seg in seg_list if not seg.is_sure]
|
||||
|
||||
if len(uncompleted_segs) == 0:
|
||||
return []
|
||||
|
||||
result = []
|
||||
|
||||
for i, seg in enumerate(uncompleted_segs):
|
||||
is_last = (i == len(uncompleted_segs) - 1) # 是否为最后一个未完成线段
|
||||
|
||||
seg_data = {
|
||||
'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(),
|
||||
'sure_time': format_time_safely(seg.sure_time, client_tz) if seg.sure_time else None,
|
||||
'start_price': seg.start_bi.start_klc.low if convert_direction(seg.dir) == 1 else seg.start_bi.start_klc.high,
|
||||
'direction': convert_direction(seg.dir)
|
||||
}
|
||||
|
||||
if is_last:
|
||||
# 最后一个未完成线段:没有结束时间和价格
|
||||
seg_data['end_time'] = None
|
||||
seg_data['end_price'] = None
|
||||
else:
|
||||
# 倒数第二个及之前的未完成线段:使用实际的结束时间和价格
|
||||
if seg.end_bi and seg.end_bi.end_klc:
|
||||
seg_data['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()
|
||||
seg_data['end_price'] = seg.end_bi.end_klc.high if convert_direction(seg.dir) == 1 else seg.end_bi.end_klc.low
|
||||
else:
|
||||
# 如果没有结束笔,设为None
|
||||
seg_data['end_time'] = None
|
||||
seg_data['end_price'] = None
|
||||
|
||||
result.append(seg_data)
|
||||
|
||||
return result
|
||||
|
||||
def format_fx_type(fx_type):
|
||||
"""格式化分型类型显示"""
|
||||
fx_type_map = {
|
||||
|
||||
+459
-28
@@ -1111,6 +1111,7 @@
|
||||
<th>起始价格</th>
|
||||
<th>结束价格</th>
|
||||
<th>方向</th>
|
||||
<th>状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
@@ -2578,6 +2579,7 @@
|
||||
|
||||
// 清空已有的主周期笔系列
|
||||
tvWidget.series.mainBiSeries = [];
|
||||
tvWidget.series.mainUncompletedBiSeries = [];
|
||||
|
||||
// 遍历处理每个笔
|
||||
currentData.bi_list.forEach(function(bi) {
|
||||
@@ -2658,6 +2660,10 @@
|
||||
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时间戳(秒)
|
||||
@@ -2732,11 +2738,130 @@
|
||||
});
|
||||
}
|
||||
|
||||
// 绘制未完成笔 - 主周期
|
||||
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 {
|
||||
// 直接使用UTC时间戳(秒)
|
||||
const startTime = Math.floor(new Date(bi.start_time).getTime() / 1000);
|
||||
// 未完成笔的结束时间设为当前K线的最后时间
|
||||
const endTime = Math.floor(new Date(currentData.kline_data[currentData.kline_data.length-1].date).getTime() / 1000);
|
||||
|
||||
if (isNaN(startTime) || isNaN(endTime)) {
|
||||
console.error('主周期未完成笔时间转换错误:', bi.start_time);
|
||||
return;
|
||||
}
|
||||
|
||||
const startPrice = parseFloat(bi.start_price);
|
||||
|
||||
if (isNaN(startPrice)) {
|
||||
console.error('主周期未完成笔价格转换错误:', bi.start_price);
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据笔的方向确定终点价格
|
||||
let endPrice;
|
||||
const latestKline = currentData.kline_data[currentData.kline_data.length-1];
|
||||
if (bi.direction === 1) {
|
||||
// 向上笔,终点为最新K线的最高点
|
||||
endPrice = parseFloat(latestKline.high);
|
||||
} else {
|
||||
// 向下笔,终点为最新K线的最低点
|
||||
endPrice = parseFloat(latestKline.low);
|
||||
}
|
||||
|
||||
// 添加未完成笔(红色虚线)
|
||||
biLines.push({
|
||||
startTime: startTime,
|
||||
endTime: endTime,
|
||||
startPrice: startPrice,
|
||||
endPrice: endPrice,
|
||||
color: '#FF0000', // 红色
|
||||
lineWidth: 1,
|
||||
lineStyle: 2 // 虚线
|
||||
});
|
||||
|
||||
// 添加到图表对象
|
||||
tvWidget.series.mainUncompletedBiSeries.push({
|
||||
time: startTime,
|
||||
value: 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 {
|
||||
// 直接使用UTC时间戳(秒)
|
||||
const startTime = Math.floor(new Date(bi.start_time).getTime() / 1000);
|
||||
// 未完成笔的结束时间设为当前K线的最后时间
|
||||
const endTime = Math.floor(new Date(currentData.kline_data[currentData.kline_data.length-1].date).getTime() / 1000);
|
||||
|
||||
if (isNaN(startTime) || isNaN(endTime)) {
|
||||
console.error('次周期未完成笔时间转换错误:', bi.start_time);
|
||||
return;
|
||||
}
|
||||
|
||||
const startPrice = parseFloat(bi.start_price);
|
||||
|
||||
if (isNaN(startPrice)) {
|
||||
console.error('次周期未完成笔价格转换错误:', bi.start_price);
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据笔的方向确定终点价格
|
||||
let endPrice;
|
||||
const latestKline = currentData.kline_data[currentData.kline_data.length-1];
|
||||
if (bi.direction === 1) {
|
||||
// 向上笔,终点为最新K线的最高点
|
||||
endPrice = parseFloat(latestKline.high);
|
||||
} else {
|
||||
// 向下笔,终点为最新K线的最低点
|
||||
endPrice = parseFloat(latestKline.low);
|
||||
}
|
||||
|
||||
// 添加未完成笔(红色虚线)
|
||||
biLines.push({
|
||||
startTime: startTime,
|
||||
endTime: endTime,
|
||||
startPrice: startPrice,
|
||||
endPrice: endPrice,
|
||||
color: '#FF0000', // 红色
|
||||
lineWidth: 1,
|
||||
lineStyle: 2 // 虚线
|
||||
});
|
||||
|
||||
// 添加到图表对象
|
||||
tvWidget.series.elementUncompletedBiSeries.push({
|
||||
time: startTime,
|
||||
value: startPrice,
|
||||
color: '#FF0000',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('次周期未完成笔处理出错:', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 添加所有笔到图表
|
||||
biLines.forEach(line => {
|
||||
const lineSeries = mainChart.addLineSeries({
|
||||
color: line.color,
|
||||
lineWidth: line.lineWidth,
|
||||
lineStyle: line.lineStyle || 0, // 支持虚线样式
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
});
|
||||
@@ -2759,6 +2884,10 @@
|
||||
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时间戳(秒)
|
||||
@@ -2805,6 +2934,10 @@
|
||||
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时间戳(秒)
|
||||
@@ -2847,11 +2980,166 @@
|
||||
});
|
||||
}
|
||||
|
||||
// 绘制未完成线段 - 主周期
|
||||
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 {
|
||||
// 直接使用UTC时间戳(秒)
|
||||
const startTime = Math.floor(new Date(seg.start_time).getTime() / 1000);
|
||||
|
||||
if (isNaN(startTime)) {
|
||||
console.error('主周期未完成线段时间转换错误:', seg.start_time);
|
||||
return;
|
||||
}
|
||||
|
||||
const startPrice = parseFloat(seg.start_price);
|
||||
|
||||
if (isNaN(startPrice)) {
|
||||
console.error('主周期未完成线段价格转换错误:', seg.start_price);
|
||||
return;
|
||||
}
|
||||
|
||||
let endTime, endPrice;
|
||||
|
||||
if (seg.end_time && seg.end_price) {
|
||||
// 有结束时间和价格的未完成线段(倒数第二个等)
|
||||
endTime = Math.floor(new Date(seg.end_time).getTime() / 1000);
|
||||
endPrice = parseFloat(seg.end_price);
|
||||
|
||||
if (isNaN(endTime) || isNaN(endPrice)) {
|
||||
console.error('主周期未完成线段结束时间或价格转换错误:', seg.end_time, seg.end_price);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 没有结束时间和价格的未完成线段(最后一个)
|
||||
endTime = Math.floor(new Date(currentData.kline_data[currentData.kline_data.length-1].date).getTime() / 1000);
|
||||
|
||||
if (isNaN(endTime)) {
|
||||
console.error('主周期未完成线段结束时间转换错误');
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据线段的方向确定终点价格
|
||||
const latestKline = currentData.kline_data[currentData.kline_data.length-1];
|
||||
if (seg.direction === 1) {
|
||||
// 向上线段,终点为最新K线的最高点
|
||||
endPrice = parseFloat(latestKline.high);
|
||||
} else {
|
||||
// 向下线段,终点为最新K线的最低点
|
||||
endPrice = parseFloat(latestKline.low);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加未完成线段(红色虚线)
|
||||
segLines.push({
|
||||
startTime: startTime,
|
||||
endTime: endTime,
|
||||
startPrice: startPrice,
|
||||
endPrice: endPrice,
|
||||
color: '#FF0000', // 红色
|
||||
lineWidth: 2,
|
||||
lineStyle: 2 // 虚线
|
||||
});
|
||||
|
||||
// 添加到图表对象
|
||||
tvWidget.series.mainUncompletedSegSeries.push({
|
||||
time: startTime,
|
||||
value: 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 {
|
||||
// 直接使用UTC时间戳(秒)
|
||||
const startTime = Math.floor(new Date(seg.start_time).getTime() / 1000);
|
||||
|
||||
if (isNaN(startTime)) {
|
||||
console.error('次周期未完成线段时间转换错误:', seg.start_time);
|
||||
return;
|
||||
}
|
||||
|
||||
const startPrice = parseFloat(seg.start_price);
|
||||
|
||||
if (isNaN(startPrice)) {
|
||||
console.error('次周期未完成线段价格转换错误:', seg.start_price);
|
||||
return;
|
||||
}
|
||||
|
||||
let endTime, endPrice;
|
||||
|
||||
if (seg.end_time && seg.end_price) {
|
||||
// 有结束时间和价格的未完成线段(倒数第二个等)
|
||||
endTime = Math.floor(new Date(seg.end_time).getTime() / 1000);
|
||||
endPrice = parseFloat(seg.end_price);
|
||||
|
||||
if (isNaN(endTime) || isNaN(endPrice)) {
|
||||
console.error('次周期未完成线段结束时间或价格转换错误:', seg.end_time, seg.end_price);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 没有结束时间和价格的未完成线段(最后一个)
|
||||
endTime = Math.floor(new Date(currentData.kline_data[currentData.kline_data.length-1].date).getTime() / 1000);
|
||||
|
||||
if (isNaN(endTime)) {
|
||||
console.error('次周期未完成线段结束时间转换错误');
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据线段的方向确定终点价格
|
||||
const latestKline = currentData.kline_data[currentData.kline_data.length-1];
|
||||
if (seg.direction === 1) {
|
||||
// 向上线段,终点为最新K线的最高点
|
||||
endPrice = parseFloat(latestKline.high);
|
||||
} else {
|
||||
// 向下线段,终点为最新K线的最低点
|
||||
endPrice = parseFloat(latestKline.low);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加未完成线段(红色虚线)
|
||||
segLines.push({
|
||||
startTime: startTime,
|
||||
endTime: endTime,
|
||||
startPrice: startPrice,
|
||||
endPrice: endPrice,
|
||||
color: '#FF0000', // 红色
|
||||
lineWidth: 2,
|
||||
lineStyle: 2 // 虚线
|
||||
});
|
||||
|
||||
// 添加到图表对象
|
||||
tvWidget.series.elementUncompletedSegSeries.push({
|
||||
time: startTime,
|
||||
value: startPrice,
|
||||
color: '#FF0000',
|
||||
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,
|
||||
});
|
||||
@@ -2886,6 +3174,8 @@
|
||||
|
||||
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);
|
||||
@@ -2944,6 +3234,36 @@
|
||||
{ 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,
|
||||
@@ -2992,6 +3312,8 @@
|
||||
|
||||
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);
|
||||
@@ -3050,6 +3372,36 @@
|
||||
{ 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,
|
||||
@@ -3106,6 +3458,8 @@
|
||||
|
||||
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);
|
||||
@@ -3116,7 +3470,6 @@
|
||||
const topSeries = mainChart.addLineSeries({
|
||||
color: '#F1C40F', // 主周期中枢颜色
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
});
|
||||
@@ -3130,7 +3483,6 @@
|
||||
const bottomSeries = mainChart.addLineSeries({
|
||||
color: '#F1C40F', // 主周期中枢颜色
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
});
|
||||
@@ -3144,7 +3496,6 @@
|
||||
const leftSeries = mainChart.addLineSeries({
|
||||
color: '#F1C40F', // 主周期中枢颜色
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
});
|
||||
@@ -3171,34 +3522,60 @@
|
||||
}
|
||||
]);
|
||||
|
||||
// 绘制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.mainUncompletedZsSeries.push({
|
||||
time: startTime,
|
||||
value: zg,
|
||||
color: '#F1C40F',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2
|
||||
lineWidth: 1
|
||||
});
|
||||
tvWidget.series.mainUncompletedZsSeries.push({
|
||||
time: endTime,
|
||||
value: zg,
|
||||
color: '#F1C40F',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2
|
||||
lineWidth: 1
|
||||
});
|
||||
tvWidget.series.mainUncompletedZsSeries.push({
|
||||
time: startTime,
|
||||
value: zd,
|
||||
color: '#F1C40F',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2
|
||||
lineWidth: 1
|
||||
});
|
||||
tvWidget.series.mainUncompletedZsSeries.push({
|
||||
time: endTime,
|
||||
value: zd,
|
||||
color: '#F1C40F',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2
|
||||
lineWidth: 1
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('主周期未完成中枢处理出错:', e);
|
||||
@@ -3224,6 +3601,8 @@
|
||||
|
||||
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);
|
||||
@@ -3234,7 +3613,6 @@
|
||||
const topSeries = mainChart.addLineSeries({
|
||||
color: '#3f51b5', // 次周期中枢颜色
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
});
|
||||
@@ -3248,7 +3626,6 @@
|
||||
const bottomSeries = mainChart.addLineSeries({
|
||||
color: '#3f51b5', // 次周期中枢颜色
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
});
|
||||
@@ -3262,7 +3639,6 @@
|
||||
const leftSeries = mainChart.addLineSeries({
|
||||
color: '#3f51b5', // 次周期中枢颜色
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
});
|
||||
@@ -3289,34 +3665,60 @@
|
||||
}
|
||||
]);
|
||||
|
||||
// 绘制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.elementUncompletedZsSeries.push({
|
||||
time: startTime,
|
||||
value: zg,
|
||||
color: '#3f51b5',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2
|
||||
lineWidth: 1
|
||||
});
|
||||
tvWidget.series.elementUncompletedZsSeries.push({
|
||||
time: endTime,
|
||||
value: zg,
|
||||
color: '#3f51b5',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2
|
||||
lineWidth: 1
|
||||
});
|
||||
tvWidget.series.elementUncompletedZsSeries.push({
|
||||
time: startTime,
|
||||
value: zd,
|
||||
color: '#3f51b5',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2
|
||||
lineWidth: 1
|
||||
});
|
||||
tvWidget.series.elementUncompletedZsSeries.push({
|
||||
time: endTime,
|
||||
value: zd,
|
||||
color: '#3f51b5',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2
|
||||
lineWidth: 1
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('次周期未完成中枢处理出错:', e);
|
||||
@@ -5233,27 +5635,56 @@
|
||||
}
|
||||
|
||||
// 根据用户选择决定使用哪个周期的数据
|
||||
let segData, segSource;
|
||||
let segData, segSource, uncompletedSegData;
|
||||
if (useElementPeriod && data.element_seg_list && data.element_seg_list.length > 0) {
|
||||
segData = data.element_seg_list;
|
||||
uncompletedSegData = data.element_uncompleted_seg_list || [];
|
||||
segSource = '小周期';
|
||||
} else {
|
||||
segData = data.seg_list;
|
||||
uncompletedSegData = data.uncompleted_seg_list || [];
|
||||
segSource = '主周期';
|
||||
}
|
||||
console.log(`表格显示${segSource}线段数据,共${segData ? segData.length : 0}条`);
|
||||
|
||||
// 合并已完成和未完成的线段数据
|
||||
let allSegData = [];
|
||||
if (segData && segData.length > 0) {
|
||||
allSegData = allSegData.concat(segData.map(seg => ({...seg, status: '已完成'})));
|
||||
}
|
||||
if (uncompletedSegData && uncompletedSegData.length > 0) {
|
||||
allSegData = allSegData.concat(uncompletedSegData.map(seg => ({...seg, status: '未完成'})));
|
||||
}
|
||||
|
||||
console.log(`表格显示${segSource}线段数据,已完成${segData ? segData.length : 0}条,未完成${uncompletedSegData ? uncompletedSegData.length : 0}条,总计${allSegData.length}条`);
|
||||
|
||||
tables.seg = $('#segTable').DataTable({
|
||||
data: segData || [],
|
||||
data: allSegData,
|
||||
order: [[0, 'desc']],
|
||||
pageLength: 25,
|
||||
columns: [
|
||||
{ data: 'start_time', render: formatTime },
|
||||
{ data: 'end_time', render: formatTime },
|
||||
{ data: 'end_time', render: function(data, type, row) {
|
||||
if (data === null || data === undefined) {
|
||||
return type === 'display' ? '<span style="color: red;">未完成</span>' : '';
|
||||
}
|
||||
return formatTime(data, type, row);
|
||||
}},
|
||||
{ data: 'sure_time', render: formatConfirmTime },
|
||||
{ data: 'start_price', render: formatPrice },
|
||||
{ data: 'end_price', render: formatPrice },
|
||||
{ data: 'direction', render: formatDirection }
|
||||
{ data: 'end_price', render: function(data, type, row) {
|
||||
if (data === null || data === undefined) {
|
||||
return type === 'display' ? '<span style="color: red;">未完成</span>' : '';
|
||||
}
|
||||
return formatPrice(data, type, row);
|
||||
}},
|
||||
{ data: 'direction', render: formatDirection },
|
||||
{ data: 'status', render: function(data, type, row) {
|
||||
if (type === 'display') {
|
||||
const color = data === '已完成' ? 'green' : 'red';
|
||||
return `<span style="color: ${color}; font-weight: bold;">${data}</span>`;
|
||||
}
|
||||
return data;
|
||||
}}
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user