Change layout
This commit is contained in:
+49
-20
@@ -201,8 +201,6 @@ def get_crypto_kl_data(symbol, timeframe, limit=1000, start_time=None, end_time=
|
||||
print(f"未指定明确时间范围,应用默认限制,返回最新的 {limit} 条记录")
|
||||
df = df.tail(limit).reset_index(drop=True)
|
||||
|
||||
df = add_indicators(df)
|
||||
|
||||
# 如果过滤后没有数据,返回None
|
||||
if len(df) == 0:
|
||||
print("过滤后无数据")
|
||||
@@ -290,6 +288,19 @@ def add_indicators(df):
|
||||
df['ma30'] = (ta.EMA(df, timeperiod=30)).fillna(0)
|
||||
df['ma250'] = (ta.MA(df, timeperiod=250)).fillna(0)
|
||||
df['rsi'] = ta.RSI(df, timeperiod=14)
|
||||
|
||||
# 计算布林带 (当前周期 - 20周期,2标准差)
|
||||
bb = ta.BBANDS(df, timeperiod=20, nbdevup=2.0, nbdevdn=2.0, matype=0)
|
||||
df['bb_upper'] = bb['upperband'].fillna(0)
|
||||
df['bb_middle'] = bb['middleband'].fillna(0)
|
||||
df['bb_lower'] = bb['lowerband'].fillna(0)
|
||||
|
||||
# 计算次周期布林带 (14周期,2标准差)
|
||||
bb_element = ta.BBANDS(df, timeperiod=14, nbdevup=2.0, nbdevdn=2.0, matype=0)
|
||||
df['element_bb_upper'] = bb_element['upperband'].fillna(0)
|
||||
df['element_bb_middle'] = bb_element['middleband'].fillna(0)
|
||||
df['element_bb_lower'] = bb_element['lowerband'].fillna(0)
|
||||
|
||||
df['macd'] = df['macd'].fillna(0)
|
||||
df['macdsignal'] = df['macdsignal'].fillna(0)
|
||||
df['macdhist'] = df['macdhist'].fillna(0)
|
||||
@@ -532,25 +543,14 @@ def is_smaller_or_equal_timeframe(tf1, tf2):
|
||||
return tf1_value <= tf2_value
|
||||
|
||||
def clean_dataframe_for_json(df):
|
||||
"""清理DataFrame中的NaN值,确保JSON序列化正常"""
|
||||
# 创建副本以避免修改原数据
|
||||
df_clean = df.copy()
|
||||
"""清理DataFrame数据用于JSON序列化"""
|
||||
# 创建副本避免修改原始数据
|
||||
clean_df = df.copy()
|
||||
|
||||
# 将NaN、inf、-inf替换为None
|
||||
df_clean = df_clean.replace([np.nan, np.inf, -np.inf], None)
|
||||
# 替换NaN值为None
|
||||
clean_df = clean_df.where(pd.notnull(clean_df), None)
|
||||
|
||||
# 处理数值列,确保值为有限数字或None
|
||||
numeric_columns = df_clean.select_dtypes(include=[np.number]).columns
|
||||
for col in numeric_columns:
|
||||
# 确保所有数值都是有限的
|
||||
df_clean[col] = df_clean[col].apply(lambda x: x if (x is not None and np.isfinite(x)) else None)
|
||||
|
||||
# 处理时间列,确保格式正确
|
||||
datetime_columns = df_clean.select_dtypes(include=['datetime64']).columns
|
||||
for col in datetime_columns:
|
||||
df_clean[col] = df_clean[col].dt.strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
return df_clean
|
||||
return clean_df
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
@@ -615,6 +615,10 @@ def analyze():
|
||||
# 如果不是只需要分形元素数据,则添加主周期数据
|
||||
if not elements_only:
|
||||
print(f"处理主周期数据 (elements_only={elements_only})")
|
||||
|
||||
# 添加技术指标(包括布林带)
|
||||
df = add_indicators(df)
|
||||
|
||||
# 进行缠论分析
|
||||
analysis_result = analyze_chan(df)
|
||||
|
||||
@@ -661,6 +665,17 @@ def analyze():
|
||||
'desc': point['desc']
|
||||
} for point in analysis_result['trade_points']],
|
||||
'macd': macd_data,
|
||||
# 添加布林带数据
|
||||
'bollinger': {
|
||||
'upper': df['bb_upper'].tolist(),
|
||||
'middle': df['bb_middle'].tolist(),
|
||||
'lower': df['bb_lower'].tolist()
|
||||
},
|
||||
'element_bollinger': {
|
||||
'upper': df['element_bb_upper'].tolist(),
|
||||
'middle': df['element_bb_middle'].tolist(),
|
||||
'lower': df['element_bb_lower'].tolist()
|
||||
},
|
||||
# 添加K线分型信息
|
||||
'klc_fx_info': [{
|
||||
'time': format_time_safely(point['time'], client_tz),
|
||||
@@ -682,6 +697,9 @@ def analyze():
|
||||
element_df = get_kl_data(symbol, element_timeframe, start_time=start_time, end_time=end_time)
|
||||
|
||||
if element_df is not None and len(element_df) > 0:
|
||||
# 添加小周期技术指标(包括布林带)
|
||||
element_df = add_indicators(element_df)
|
||||
|
||||
# 对小周期数据进行缠论分析
|
||||
element_analysis = analyze_chan(element_df)
|
||||
|
||||
@@ -692,6 +710,18 @@ def analyze():
|
||||
result['element_timeframe'] = element_timeframe
|
||||
result['element_macd'] = element_macd_data # 添加小周期MACD数据
|
||||
|
||||
# 添加小周期布林带数据
|
||||
result['element_bollinger'] = {
|
||||
'upper': element_df['bb_upper'].tolist(),
|
||||
'middle': element_df['bb_middle'].tolist(),
|
||||
'lower': element_df['bb_lower'].tolist()
|
||||
}
|
||||
result['element_element_bollinger'] = {
|
||||
'upper': element_df['element_bb_upper'].tolist(),
|
||||
'middle': element_df['element_bb_middle'].tolist(),
|
||||
'lower': element_df['element_bb_lower'].tolist()
|
||||
}
|
||||
|
||||
result['element_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,
|
||||
@@ -720,7 +750,6 @@ def analyze():
|
||||
'is_sure': zs.is_sure # 添加中枢是否完成的标志
|
||||
} for zs in element_analysis['zs_list'] if zs.end_klc]
|
||||
|
||||
# 添加小周期未完成中枢列表
|
||||
result['element_uncompleted_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': None, # 未完成中枢没有结束时间
|
||||
|
||||
+253
-53
@@ -327,7 +327,7 @@
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="col-md-1">
|
||||
<label for="timezone" class="form-label">时区:</label>
|
||||
<select id="timezone" class="form-select">
|
||||
<option value="UTC">UTC</option>
|
||||
@@ -338,21 +338,23 @@
|
||||
<option value="Asia/Tokyo">Asia/Tokyo (UTC+9)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="col-md-3">
|
||||
<label for="start_time" class="form-label">开始时间:</label>
|
||||
<input type="datetime-local" id="start_time" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="col-md-3">
|
||||
<label for="end_time" class="form-label">结束时间:</label>
|
||||
<input type="datetime-local" id="end_time" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<button class="btn btn-primary w-100" onclick="updateChart()">分析</button>
|
||||
<button class="btn btn-primary w-100" onclick="updateChart()" style="padding: 8px 6px; font-size: 14px;">
|
||||
分析
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-md-7">
|
||||
<div class="col-md-8">
|
||||
<div class="d-flex align-items-center">
|
||||
<label class="form-label me-3 mb-0">基础显示:</label>
|
||||
<div class="form-check form-check-inline">
|
||||
@@ -397,6 +399,10 @@
|
||||
<input class="form-check-input" type="checkbox" id="showKlcFxType" checked>
|
||||
<label class="form-check-label" for="showKlcFxType">分型</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" id="showMainBollinger">
|
||||
<label class="form-check-label" for="showMainBollinger">布林带</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mt-2">
|
||||
<label class="form-label me-3 mb-0">次周期:</label>
|
||||
@@ -424,22 +430,25 @@
|
||||
<input class="form-check-input" type="checkbox" id="showElementKlcFxType">
|
||||
<label class="form-check-label" for="showElementKlcFxType">分型</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" id="showElementBollinger">
|
||||
<label class="form-check-label" for="showElementBollinger">布林带</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="d-flex align-items-center">
|
||||
<label for="elementTimeframe" class="form-label me-3 mb-0">次级别时间周期:</label>
|
||||
<select id="elementTimeframe" class="form-select form-select-sm" style="width: auto;">
|
||||
<div class="col-md-4">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<label for="elementTimeframe" class="form-label me-2 mb-0">次级别时间周期:</label>
|
||||
<select id="elementTimeframe" class="form-select form-select-sm me-2" style="width: 120px;">
|
||||
{% for value, label in timeframes.items() %}
|
||||
<option value="{{ value }}" {% if value == '1m' %}selected{% endif %}>{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<small class="text-muted ms-2">仅影响笔、线段和中枢分析</small>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center mt-2">
|
||||
<label for="refreshInterval" class="form-label me-3 mb-0">自动刷新:</label>
|
||||
<select id="refreshInterval" class="form-select form-select-sm me-2" style="width: auto;">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<label for="refreshInterval" class="form-label me-2 mb-0">自动刷新:</label>
|
||||
<select id="refreshInterval" class="form-select form-select-sm me-2" style="width: 80px;">
|
||||
<option value="0.0833">5秒</option>
|
||||
<option value="0.1667">10秒</option>
|
||||
<option value="0.25">15秒</option>
|
||||
@@ -450,18 +459,18 @@
|
||||
<option value="5" selected>5分钟</option>
|
||||
<option value="10">10分钟</option>
|
||||
</select>
|
||||
<div class="form-check form-check-inline m-0">
|
||||
<div class="form-check form-check-inline me-2">
|
||||
<input class="form-check-input" type="checkbox" id="autoRefresh">
|
||||
<label class="form-check-label" for="autoRefresh">启用</label>
|
||||
</div>
|
||||
<span id="nextRefreshTime" class="ms-2 text-muted" style="display:none;font-size:0.85rem;"></span>
|
||||
<span id="nextRefreshTime" class="text-muted" style="display:none;font-size:0.85rem;"></span>
|
||||
<div id="refreshLoadingSpinner" class="loading-spinner ms-2" style="display:none;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 添加数据回放控制面板 -->
|
||||
<div class="d-flex align-items-center mt-2">
|
||||
<label for="replayInterval" class="form-label me-3 mb-0">数据回放:</label>
|
||||
<select id="replayInterval" class="form-select form-select-sm me-2" style="width: auto;">
|
||||
<div class="d-flex align-items-center">
|
||||
<label for="replayInterval" class="form-label me-2 mb-0">数据回放:</label>
|
||||
<select id="replayInterval" class="form-select form-select-sm me-2" style="width: 80px;">
|
||||
<option value="0.5">0.5秒</option>
|
||||
<option value="1" selected>1秒</option>
|
||||
<option value="2">2秒</option>
|
||||
@@ -479,8 +488,8 @@
|
||||
<i class="bi bi-stop-fill"></i> 停止
|
||||
</button>
|
||||
</div>
|
||||
<span id="replayStatus" class="ms-2 text-muted" style="font-size:0.85rem;"></span>
|
||||
<div id="replayProgress" class="progress ms-2" style="width: 100px; height: 8px; display: none;">
|
||||
<span id="replayStatus" class="text-muted" style="font-size:0.85rem;"></span>
|
||||
<div id="replayProgress" class="progress ms-2" style="width: 80px; height: 8px; display: none;">
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -733,7 +742,9 @@
|
||||
elementSegSeries: [],
|
||||
elementZsSeries: [],
|
||||
elementUncompletedZsSeries: [],
|
||||
tradePointSeries: []
|
||||
tradePointSeries: [],
|
||||
mainBollingerSeries: [],
|
||||
elementBollingerSeries: []
|
||||
},
|
||||
state: {
|
||||
isInitialized: false,
|
||||
@@ -955,6 +966,15 @@
|
||||
refreshChartOnly();
|
||||
});
|
||||
|
||||
// 添加布林带显示变更事件
|
||||
$('#showMainBollinger').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
|
||||
$('#showElementBollinger').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
|
||||
// 添加K线周期切换事件监听器
|
||||
$('input[name="klinePeriod"]').change(function() {
|
||||
console.log('K线周期切换:', $(this).attr('id'), $(this).is(':checked'));
|
||||
@@ -1055,6 +1075,8 @@
|
||||
console.log('- 显示小周期分型:', $('#showElementKlcFxType').is(':checked'));
|
||||
console.log('- 显示买卖点:', $('#showTradePoints').is(':checked'));
|
||||
console.log('- 显示原始K线:', $('#showOriginalKline').is(':checked'));
|
||||
console.log('- 显示主周期布林带:', $('#showMainBollinger').is(':checked'));
|
||||
console.log('- 显示次周期布林带:', $('#showElementBollinger').is(':checked'));
|
||||
|
||||
// 重新初始化图表,这将清除旧图形并重新绘制
|
||||
initTradingView($('#symbol').val(), $('#timeframe').val());
|
||||
@@ -1302,7 +1324,9 @@
|
||||
elementSegSeries: [],
|
||||
elementZsSeries: [],
|
||||
elementUncompletedZsSeries: [],
|
||||
tradePointSeries: []
|
||||
tradePointSeries: [],
|
||||
mainBollingerSeries: [],
|
||||
elementBollingerSeries: []
|
||||
},
|
||||
state: {
|
||||
isInitialized: false,
|
||||
@@ -1914,33 +1938,32 @@
|
||||
|
||||
// 在笔的末端添加macd_div值标记
|
||||
if (bi.macd_div && bi.macd_div !== 0 && $('#showMainMacdDiv').is(':checked')) {
|
||||
console.log(`添加macd_div标记: ${bi.macd_div.toFixed(2)}, 在时间点: ${endTime}`);
|
||||
console.log(`添加主周期macd_div标记: ${bi.macd_div.toFixed(2)}, 在时间点: ${endTime}`);
|
||||
|
||||
const macdDivLabel = mainChart.addLineSeries({
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
color: 'transparent', // 设置为透明色
|
||||
lineWidth: 0, // 线宽为0
|
||||
});
|
||||
|
||||
// 确定标记位置
|
||||
const markerPosition = bi.direction === 1 ? 'aboveBar' : 'belowBar';
|
||||
const labelValue = bi.direction === 1 ? endPrice + (endPrice * 0.005) : endPrice - (endPrice * 0.005);
|
||||
const arrayShape = bi.direction === 1 ? 'arrowDown' : 'arrowUp';
|
||||
// 简化标记显示
|
||||
// 添加一个透明的数据点用于承载标记
|
||||
macdDivLabel.setData([
|
||||
{ time: endTime, value: labelValue }
|
||||
{ time: endTime, value: endPrice }
|
||||
]);
|
||||
|
||||
// 使用不同方式添加文本标记
|
||||
// 主周期MACD背离标记根据笔方向显示,远离K线避免与分型重叠
|
||||
const markerPosition = bi.direction === 1 ? 'aboveBar' : 'belowBar';
|
||||
const textColor = bi.macd_div > 0 ? '#dc3545' : '#28a745';
|
||||
const textSize = Math.min(14, Math.max(10, Math.abs(bi.macd_div) * 2));
|
||||
|
||||
// 只使用标记,不添加数据点
|
||||
macdDivLabel.setMarkers([
|
||||
{
|
||||
time: endTime,
|
||||
position: markerPosition,
|
||||
color: textColor,
|
||||
shape: arrayShape,
|
||||
text: bi.macd_div.toFixed(2),
|
||||
text: `${bi.macd_div.toFixed(2)}`, // 添加M前缀区分
|
||||
size: 0.6, // 更小的尺寸,远离分型标记
|
||||
}
|
||||
]);
|
||||
}
|
||||
@@ -1998,29 +2021,27 @@
|
||||
const macdDivLabel = mainChart.addLineSeries({
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
color: 'transparent', // 设置为透明色
|
||||
lineWidth: 0, // 线宽为0
|
||||
});
|
||||
|
||||
// 确定标记位置
|
||||
const markerPosition = bi.direction === 1 ? 'aboveBar' : 'belowBar';
|
||||
const labelValue = bi.direction === 1 ? endPrice + (endPrice * 0.005) : endPrice - (endPrice * 0.005);
|
||||
const arrayShape = bi.direction === 1 ? 'arrowDown' : 'arrowUp';
|
||||
// 简化标记显示
|
||||
// 添加一个透明的数据点用于承载标记
|
||||
macdDivLabel.setData([
|
||||
{ time: endTime, value: labelValue }
|
||||
{ time: endTime, value: endPrice }
|
||||
]);
|
||||
|
||||
// 使用不同方式添加文本标记
|
||||
// 次周期MACD背离标记使用不同位置,进一步避免重叠
|
||||
const markerPosition = bi.direction === 1 ? 'aboveBar' : 'belowBar';
|
||||
const textColor = bi.macd_div > 0 ? '#9c27b0' : '#673ab7';
|
||||
const textSize = Math.min(14, Math.max(10, Math.abs(bi.macd_div) * 2));
|
||||
|
||||
// 只使用标记,不添加数据点
|
||||
macdDivLabel.setMarkers([
|
||||
{
|
||||
time: endTime,
|
||||
position: markerPosition,
|
||||
color: textColor,
|
||||
shape: arrayShape,
|
||||
text: bi.macd_div.toFixed(2),
|
||||
transparent: true,
|
||||
color: textColor,
|
||||
text: `${bi.macd_div.toFixed(2)}`, // 添加E前缀区分次周期
|
||||
size: 0.4, // 更小的尺寸,让分型标记有更多空间
|
||||
}
|
||||
]);
|
||||
}
|
||||
@@ -2977,6 +2998,171 @@
|
||||
console.log('绘制买卖点 - 已禁用');
|
||||
}
|
||||
|
||||
// 绘制布林带
|
||||
if ($('#showMainBollinger').is(':checked') || $('#showElementBollinger').is(':checked')) {
|
||||
console.log('绘制布林带 - 已启用');
|
||||
|
||||
// 主周期布林带
|
||||
if ($('#showMainBollinger').is(':checked') && currentData.bollinger && currentData.bollinger.upper && currentData.bollinger.lower && currentData.bollinger.middle) {
|
||||
console.log(`绘制主周期布林带数据,共${currentData.bollinger.upper.length}条`);
|
||||
|
||||
// 准备布林带数据
|
||||
const upperBandData = [];
|
||||
const lowerBandData = [];
|
||||
const middleBandData = [];
|
||||
|
||||
// 主周期布林带始终使用主周期K线数据作为时间源
|
||||
const mainKlineData = currentData.kline_data;
|
||||
|
||||
for (let i = 0; i < mainKlineData.length && i < currentData.bollinger.upper.length; i++) {
|
||||
const kline = mainKlineData[i];
|
||||
const timestamp = Math.floor(new Date(kline.date).getTime() / 1000);
|
||||
|
||||
// 只添加非0的有效数据点
|
||||
if (currentData.bollinger.upper[i] && currentData.bollinger.upper[i] !== 0) {
|
||||
upperBandData.push({
|
||||
time: timestamp,
|
||||
value: currentData.bollinger.upper[i]
|
||||
});
|
||||
}
|
||||
|
||||
if (currentData.bollinger.lower[i] && currentData.bollinger.lower[i] !== 0) {
|
||||
lowerBandData.push({
|
||||
time: timestamp,
|
||||
value: currentData.bollinger.lower[i]
|
||||
});
|
||||
}
|
||||
|
||||
if (currentData.bollinger.middle[i] && currentData.bollinger.middle[i] !== 0) {
|
||||
middleBandData.push({
|
||||
time: timestamp,
|
||||
value: currentData.bollinger.middle[i]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 创建布林带上轨
|
||||
const upperBandSeries = mainChart.addLineSeries({
|
||||
color: '#2196F3',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
title: '布林上轨'
|
||||
});
|
||||
upperBandSeries.setData(upperBandData);
|
||||
|
||||
// 创建布林带下轨
|
||||
const lowerBandSeries = mainChart.addLineSeries({
|
||||
color: '#2196F3',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
title: '布林下轨'
|
||||
});
|
||||
lowerBandSeries.setData(lowerBandData);
|
||||
|
||||
// 创建布林带中轨(移动平均线)
|
||||
const middleBandSeries = mainChart.addLineSeries({
|
||||
color: '#FF9800',
|
||||
lineWidth: 1,
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
title: '布林中轨'
|
||||
});
|
||||
middleBandSeries.setData(middleBandData);
|
||||
|
||||
// 保存到tvWidget.series对象
|
||||
tvWidget.series.mainBollingerSeries.push(upperBandSeries);
|
||||
tvWidget.series.mainBollingerSeries.push(lowerBandSeries);
|
||||
tvWidget.series.mainBollingerSeries.push(middleBandSeries);
|
||||
|
||||
console.log('主周期布林带绘制完成');
|
||||
}
|
||||
|
||||
// 次周期布林带
|
||||
if ($('#showElementBollinger').is(':checked') && currentData.element_bollinger && currentData.element_bollinger.upper && currentData.element_bollinger.lower && currentData.element_bollinger.middle) {
|
||||
console.log(`绘制次周期布林带数据,共${currentData.element_bollinger.upper.length}条`);
|
||||
|
||||
// 准备次周期布林带数据
|
||||
const elementUpperBandData = [];
|
||||
const elementLowerBandData = [];
|
||||
const elementMiddleBandData = [];
|
||||
|
||||
// 使用次周期K线数据
|
||||
const elementKlineData = currentData.element_kline_data || currentData.kline_data;
|
||||
|
||||
for (let i = 0; i < elementKlineData.length && i < currentData.element_bollinger.upper.length; i++) {
|
||||
const kline = elementKlineData[i];
|
||||
const timestamp = Math.floor(new Date(kline.date).getTime() / 1000);
|
||||
|
||||
// 只添加非0的有效数据点
|
||||
if (currentData.element_bollinger.upper[i] && currentData.element_bollinger.upper[i] !== 0) {
|
||||
elementUpperBandData.push({
|
||||
time: timestamp,
|
||||
value: currentData.element_bollinger.upper[i]
|
||||
});
|
||||
}
|
||||
|
||||
if (currentData.element_bollinger.lower[i] && currentData.element_bollinger.lower[i] !== 0) {
|
||||
elementLowerBandData.push({
|
||||
time: timestamp,
|
||||
value: currentData.element_bollinger.lower[i]
|
||||
});
|
||||
}
|
||||
|
||||
if (currentData.element_bollinger.middle[i] && currentData.element_bollinger.middle[i] !== 0) {
|
||||
elementMiddleBandData.push({
|
||||
time: timestamp,
|
||||
value: currentData.element_bollinger.middle[i]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 创建次周期布林带上轨
|
||||
const elementUpperBandSeries = mainChart.addLineSeries({
|
||||
color: '#9C27B0',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
title: '次周期布林上轨'
|
||||
});
|
||||
elementUpperBandSeries.setData(elementUpperBandData);
|
||||
|
||||
// 创建次周期布林带下轨
|
||||
const elementLowerBandSeries = mainChart.addLineSeries({
|
||||
color: '#9C27B0',
|
||||
lineWidth: 1,
|
||||
lineStyle: 2, // 虚线
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
title: '次周期布林下轨'
|
||||
});
|
||||
elementLowerBandSeries.setData(elementLowerBandData);
|
||||
|
||||
// 创建次周期布林带中轨
|
||||
const elementMiddleBandSeries = mainChart.addLineSeries({
|
||||
color: '#E91E63',
|
||||
lineWidth: 1,
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
title: '次周期布林中轨'
|
||||
});
|
||||
elementMiddleBandSeries.setData(elementMiddleBandData);
|
||||
|
||||
// 保存到tvWidget.series对象
|
||||
tvWidget.series.elementBollingerSeries.push(elementUpperBandSeries);
|
||||
tvWidget.series.elementBollingerSeries.push(elementLowerBandSeries);
|
||||
tvWidget.series.elementBollingerSeries.push(elementMiddleBandSeries);
|
||||
|
||||
console.log('次周期布林带绘制完成');
|
||||
}
|
||||
} else {
|
||||
console.log('绘制布林带 - 已禁用');
|
||||
}
|
||||
|
||||
// 绘制分型类型标签
|
||||
console.log('=== 开始检查分型显示条件 ===');
|
||||
console.log('showKlcFxType勾选状态:', $('#showKlcFxType').is(':checked'));
|
||||
@@ -3034,8 +3220,8 @@
|
||||
is_strong_fx: fx.is_strong_fx
|
||||
});
|
||||
let displayText = `${fx.fx_strength_level} ${fx.fx_strength.toFixed(1)}`;
|
||||
if (fx.fx_strength < 1.4) {
|
||||
displayText = ''
|
||||
if (fx.fx_strength < 1.0) { // 降低阈值,让更多分型显示
|
||||
displayText = fx.fx_strength >= 0.8 ? '•' : '' // 0.8以上显示点,0.8以下不显示文本
|
||||
}
|
||||
console.log('显示文本:', displayText);
|
||||
|
||||
@@ -3044,9 +3230,9 @@
|
||||
time: timestamp,
|
||||
position: fx.is_bottom ? 'belowBar' : 'aboveBar',
|
||||
color: strengthColor,
|
||||
shape: fx.is_strong_fx ? 'square' : 'circle',
|
||||
shape: 'circle',
|
||||
text: displayText,
|
||||
size: fx.is_strong_fx ? 2 : 1
|
||||
size: fx.is_strong_fx ? 1 : 0.6 // 调整尺寸,强分型稍大,普通分型更小
|
||||
};
|
||||
console.log('标记配置:', markerConfig);
|
||||
|
||||
@@ -3125,8 +3311,8 @@
|
||||
}
|
||||
let displayText = `${fx.fx_strength_level} ${fx.fx_strength.toFixed(1)}`;
|
||||
// 构建小周期分型显示文本
|
||||
if (fx.fx_strength < 1){
|
||||
displayText = ''
|
||||
if (fx.fx_strength < 0.8){ // 调整小周期阈值
|
||||
displayText = fx.fx_strength >= 0.6 ? '•' : '' // 0.6以上显示点
|
||||
}
|
||||
|
||||
// 小周期分型标记配置 - 根据分型类型使用正确的箭头形状
|
||||
@@ -3134,8 +3320,9 @@
|
||||
time: timestamp,
|
||||
position: fx.is_bottom ? 'belowBar' : 'aboveBar',
|
||||
color: strengthColor,
|
||||
shape: 'circle',
|
||||
text: displayText,
|
||||
size: fx.is_strong_fx ? 2 : 1
|
||||
size: fx.is_strong_fx ? 0.8 : 0.6 // 小周期标记整体更小一些
|
||||
};
|
||||
|
||||
console.log('小周期分型标记配置:', markerConfig);
|
||||
@@ -4353,7 +4540,9 @@
|
||||
elementSegSeries: [],
|
||||
elementZsSeries: [],
|
||||
elementUncompletedZsSeries: [],
|
||||
tradePointSeries: []
|
||||
tradePointSeries: [],
|
||||
mainBollingerSeries: [],
|
||||
elementBollingerSeries: []
|
||||
};
|
||||
} catch (e) {
|
||||
console.error('销毁图表错误:', e);
|
||||
@@ -4797,6 +4986,15 @@
|
||||
refreshChart(currentData);
|
||||
});
|
||||
|
||||
// 绑定布林带显示变更事件
|
||||
$('#showMainBollinger').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
|
||||
$('#showElementBollinger').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
|
||||
// 绑定K线周期切换
|
||||
$('input[name="klinePeriod"]').change(function() {
|
||||
refreshChart(currentData);
|
||||
@@ -4814,6 +5012,8 @@
|
||||
'showKlcFxType': $('#showKlcFxType').is(':checked'),
|
||||
'showElementKlcFxType': $('#showElementKlcFxType').is(':checked'),
|
||||
'showTradePoints': $('#showTradePoints').is(':checked'),
|
||||
'showMainBollinger': $('#showMainBollinger').is(':checked'),
|
||||
'showElementBollinger': $('#showElementBollinger').is(':checked'),
|
||||
'timeframe': $('#timeframe').val(),
|
||||
'elementTimeframe': $('#elementTimeframe').val(),
|
||||
'timezone': $('#timezone').val(),
|
||||
|
||||
Reference in New Issue
Block a user