添加ema52显示

This commit is contained in:
jackyu66git
2025-09-27 01:14:53 +08:00
parent 68e9c38922
commit 6139af98c3
5 changed files with 389 additions and 88 deletions
+45 -9
View File
@@ -346,10 +346,43 @@ def calculate_macd(df):
'histogram': histogram.tolist()
}
def analyze_chan(df):
def analyze_chan(df, symbol=None, timeframe=None):
"""进行缠论分析"""
chan = ChanLun()
# 初始化多时间周期数据以获取EMA52
ema52_dict = None
if symbol and timeframe:
try:
# 获取不同时间周期的数据用于初始化
df_1h = get_kl_data(symbol, '1h', limit=800) if timeframe != '1h' else df
df_1d = get_kl_data(symbol, '1d', limit=800) if timeframe != '1d' else df
df_1M = get_kl_data(symbol, '1M', limit=800) if timeframe != '1M' else df
# 添加指标
if df_1h is not None and len(df_1h) > 0:
df_1h = add_indicators(df_1h)
if df_1d is not None and len(df_1d) > 0:
df_1d = add_indicators(df_1d)
if df_1M is not None and len(df_1M) > 0:
df_1M = add_indicators(df_1M)
# 初始化多时间周期数据
chan.init_dataframes(df, df_1h, df_1d, df_1M)
# 获取EMA52数据
ema52_dict = chan.get_ema52_dict()
# 处理NaN值
if ema52_dict:
for key, value in ema52_dict.items():
if pd.isna(value) or value is None:
ema52_dict[key] = None
else:
ema52_dict[key] = float(value)
except Exception as e:
print(f"获取多时间周期EMA52数据失败: {e}")
ema52_dict = None
# 获取分析结果
klc_list = chan.get_klc_list(df)
bi_list = chan.cal_bi_list(klc_list)
@@ -546,7 +579,8 @@ def analyze_chan(df):
'trade_points': buy_sell_points,
'klc_fx_info': klc_fx_info, # KLC分型信息
'klu_fx_info': klu_fx_info, # 添加KLU分型信息
'chan_macd': chan_macd_data # 添加ChanMACD分析数据
'chan_macd': chan_macd_data, # 添加ChanMACD分析数据
'ema52_dict': ema52_dict # 添加多时间周期EMA52数据
}
def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, start_time=None, end_time=None):
@@ -572,7 +606,7 @@ def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, sta
current_df = add_indicators(current_df)
# 进行缠论分析
analysis_result = analyze_chan(current_df)
analysis_result = analyze_chan(current_df, symbol, timeframe)
# 计算MACD
macd_data = calculate_macd(current_df)
@@ -590,7 +624,7 @@ def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, sta
if len(element_current_df) > 0:
# 重新对当前时间范围的次周期数据进行缠论分析
# 这样可以确保数据的准确性,避免时间筛选的复杂性
element_current_analysis = analyze_chan(element_current_df)
element_current_analysis = analyze_chan(element_current_df, symbol, element_timeframe)
# 直接使用分析结果,无需复杂的时间筛选
filtered_bi_list = element_current_analysis['bi_list']
@@ -1614,7 +1648,7 @@ def analyze():
df = add_indicators(df)
# 进行缠论分析
analysis_result = analyze_chan(df)
analysis_result = analyze_chan(df, symbol, timeframe)
# 计算MACD
macd_data = calculate_macd(df)
@@ -1717,7 +1751,9 @@ def analyze():
'fx_confirmed': bool(point['fx_confirmed']) # 分型是否确认
} for point in analysis_result['klu_fx_info']],
# 添加ChanMACD分析数据
'chan_macd': serialize_chan_macd_data(analysis_result.get('chan_macd', {}), client_tz)
'chan_macd': serialize_chan_macd_data(analysis_result.get('chan_macd', {}), client_tz),
# 添加多时间周期EMA52数据
'ema52_dict': analysis_result.get('ema52_dict', {})
})
# 如果生成了回放数据,添加到返回结果中
@@ -1734,7 +1770,7 @@ def analyze():
element_df = add_indicators(element_df)
# 对小周期数据进行缠论分析
element_analysis = analyze_chan(element_df)
element_analysis = analyze_chan(element_df, symbol, element_timeframe)
# 计算小周期MACD数据
element_macd_data = calculate_macd(element_df)
@@ -1936,7 +1972,7 @@ def test_element_data():
# 分析次周期数据
element_df = add_indicators(element_df)
element_analysis = analyze_chan(element_df)
element_analysis = analyze_chan(element_df, symbol, element_timeframe)
return jsonify({
'main_data_count': len(main_df),
@@ -2123,7 +2159,7 @@ def filter_stocks():
continue
# 进行缠论分析
analysis_result = analyze_chan(df)
analysis_result = analyze_chan(df, symbol, timeframe)
if not analysis_result or 'klc_fx_info' not in analysis_result:
continue
+201 -2
View File
@@ -1788,6 +1788,7 @@
elementBollingerSeries: [],
maSeries: [], // 添加均线系列
bbSeries: [], // 添加布林带系列
ema52Series: [], // 添加EMA52系列数组
chanMacdLineSeries: null, // ChanMACD线
chanMacdSignalSeries: null, // ChanMACD信号线
chanMacdHistSeries: null, // ChanMACD柱状图
@@ -2426,7 +2427,8 @@
mainBollingerSeries: [],
elementBollingerSeries: [],
maSeries: [], // 添加均线系列数组
bbSeries: [] // 添加布林带系列数组
bbSeries: [], // 添加布林带系列数组
ema52Series: [] // 添加EMA52系列数组
},
state: {
isInitialized: false,
@@ -5680,6 +5682,11 @@
displayTradePoints();
}
// 更新EMA52显示
if (currentData) {
updateEMA52Display(currentData);
}
console.log('图表初始化完成');
} catch (e) {
console.error('图表初始化错误:', e);
@@ -5912,6 +5919,9 @@
// 重新显示笔、线段和中枢等图形
redrawFractalElements();
// 更新EMA52显示
updateEMA52Display(currentData);
// 恢复之前的可视范围 - 优先使用visibleRange以确保时间轴对齐
if (tvWidget.mainChart) {
if (tvWidget.state.visibleRange) {
@@ -7121,6 +7131,8 @@
// 先销毁现有图表实例
if (tvWidget.mainChart) {
try {
// 清理EMA52系列
clearEMA52Series();
// 销毁主图表及其关联的线系列
tvWidget.mainChart = null;
tvWidget.volumeChart = null;
@@ -7147,7 +7159,8 @@
mainBollingerSeries: [],
elementBollingerSeries: [],
maSeries: [], // 添加均线系列
bbSeries: [] // 添加布林带系列
bbSeries: [], // 添加布林带系列
ema52Series: [] // 添加EMA52系列数组
};
} catch (e) {
console.error('销毁图表错误:', e);
@@ -7576,6 +7589,12 @@
// 更新表格数据
updateTables(data);
// 只有在图表已初始化且调用了updateTradingViewData时才不需要重复调用EMA52显示
// 如果图表未初始化,调用了initTradingView,那么EMA52显示已经在initTradingView中处理了
// 但为了确保在所有情况下都能正确显示,这里统一调用一次
if (currentData && currentData.ema52_dict) {
updateEMA52Display(currentData);
}
}
@@ -8653,6 +8672,186 @@
let bollingerBands = []; // 存储所有布林带配置
let bbIdCounter = 0; // 布林带ID计数器
// 清理EMA52系列
function clearEMA52Series() {
// 清理所有EMA52相关系列(包括线系列和标记系列)
if (tvWidget && tvWidget.series && tvWidget.series.ema52Series) {
tvWidget.series.ema52Series.forEach(series => {
try {
if (tvWidget.mainChart) {
tvWidget.mainChart.removeSeries(series);
}
} catch (e) {
console.warn('移除EMA52系列失败:', e);
}
});
tvWidget.series.ema52Series = [];
}
console.log('✅ EMA52系列已清理');
}
// 存储上次的EMA52数据,用于比较
let lastEMA52Data = null;
// 更新EMA52显示
function updateEMA52Display(data) {
console.log('更新EMA52显示', data.ema52_dict);
// 检查是否有EMA52数据
if (!data.ema52_dict || Object.keys(data.ema52_dict).length === 0) {
// 即使没有数据也要清理之前的系列
clearEMA52Series();
lastEMA52Data = null;
return;
}
// 检查数据是否与上次相同,如果相同则跳过更新
const currentDataStr = JSON.stringify(data.ema52_dict);
if (lastEMA52Data === currentDataStr) {
console.log('EMA52数据未变化,跳过更新');
return;
}
// 清除之前的EMA52线系列
clearEMA52Series();
// 保存当前数据
lastEMA52Data = currentDataStr;
// 定义时间周期的显示顺序和颜色
const timeframeColors = {
'1m': '#FF0000', // 红色
'3m': '#FF6600', // 橙红色
'5m': '#FF9900', // 橙色
'15m': '#FFCC00', // 黄色
'30m': '#99FF00', // 黄绿色
'1h': '#00FF00', // 绿色
'2h': '#00FF99', // 青绿色
'4h': '#00FFFF', // 青色
'6h': '#0099FF', // 蓝青色
'8h': '#0066FF', // 蓝色
'12h': '#3300FF', // 蓝紫色
'16h': '#6600FF', // 紫色
'1d': '#9900FF', // 紫红色
'2d': '#CC00FF', // 品红色
'3d': '#FF00CC', // 粉红色
'1w': '#FF0099', // 玫瑰色
'2w': '#FF3366' // 深粉色
};
// 按照预定义顺序排列时间周期
const orderedTimeframes = ['1m', '3m', '5m', '15m', '30m', '1h', '2h', '4h', '6h', '8h', '12h', '16h', '1d', '2d', '3d', '1w', '2w'];
// 获取主图表容器
const chartContainer = document.getElementById('tradingview_chart');
if (!chartContainer || !tvWidget.mainChart) {
return;
}
orderedTimeframes.forEach(timeframe => {
if (data.ema52_dict[timeframe] !== undefined && data.ema52_dict[timeframe] !== null) {
const value = data.ema52_dict[timeframe];
const color = timeframeColors[timeframe] || '#800080';
// 添加虚线到主图表
if (tvWidget.mainChart) {
try {
// 使用LightweightCharts的addLineSeries创建虚线
const lineSeries = tvWidget.mainChart.addLineSeries({
color: color,
lineWidth: 1,
lineStyle: 2, // 虚线样式
title: `EMA52-${timeframe}`,
lastValueVisible: false, // 不在价格标尺显示数值
priceLineVisible: false, // 不显示默认价格线
crosshairMarkerVisible: false,
priceFormat: {
type: 'price',
precision: 2,
minMove: 0.01,
},
priceScaleId: 'right',
});
// 创建横线数据(使用K线数据的时间范围)
if (data.kline_data && data.kline_data.length > 0) {
const firstKline = data.kline_data[0];
const lastKline = data.kline_data[data.kline_data.length - 1];
const startTime = Math.floor(new Date(firstKline.date).getTime() / 1000);
const endTime = Math.floor(new Date(lastKline.date).getTime() / 1000);
const lineData = [
{ time: startTime, value: value },
{ time: endTime, value: value }
];
lineSeries.setData(lineData);
// 使用标记在K线右侧显示文字
if (data.kline_data && data.kline_data.length > 0) {
const lastKline = data.kline_data[data.kline_data.length - 1];
const lastTime = Math.floor(new Date(lastKline.date).getTime() / 1000);
// 计算时间间隔(用于右偏移)
let timeInterval = 60; // 默认1分钟
if (data.kline_data.length > 1) {
const secondLastKline = data.kline_data[data.kline_data.length - 2];
const secondLastTime = Math.floor(new Date(secondLastKline.date).getTime() / 1000);
timeInterval = lastTime - secondLastTime;
}
// 创建右偏移的时间点(在最后一根K线右边)
const rightOffsetTime = lastTime + timeInterval * 0.3;
// 创建一个新的线系列用于显示文字标记
const markerSeries = tvWidget.mainChart.addLineSeries({
color: 'transparent',
lineWidth: 0,
lastValueVisible: false,
priceLineVisible: false,
crosshairMarkerVisible: false,
priceScaleId: 'right',
});
// 添加一个透明的数据点在右偏移位置
markerSeries.setData([{
time: rightOffsetTime,
value: value
}]);
// 在右偏移位置添加文字标记
markerSeries.setMarkers([{
time: rightOffsetTime,
position: 'inBar',
color: color,
shape: 'square',
text: `${timeframe} ${value.toFixed(2)}`,
size: 1,
}]);
// 保存标记系列引用
if (!tvWidget.series.ema52Series) {
tvWidget.series.ema52Series = [];
}
tvWidget.series.ema52Series.push(markerSeries);
}
}
// 保存系列引用以便后续清理
if (!tvWidget.series.ema52Series) {
tvWidget.series.ema52Series = [];
}
tvWidget.series.ema52Series.push(lineSeries);
} catch (e) {
console.warn('添加EMA52虚线失败:', timeframe, e);
}
}
}
});
}
// 获取随机颜色
function getRandomColor() {
const colors = ['#2962FF', '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4',