add more files

This commit is contained in:
jackyu66git
2025-04-25 21:39:24 +08:00
parent 761d73cdac
commit bb0b70fa44
12 changed files with 787 additions and 108 deletions
+16 -3
View File
@@ -128,6 +128,7 @@ def get_kl_data(symbol, timeframe, limit=1000, start_time=None, end_time=None):
# 按时间排序
df = df.sort_values('timestamp')
"""
chan = ChanLun()
klc_list = chan.get_klc_list(df)
klc_index = 0
@@ -140,13 +141,14 @@ def get_kl_data(symbol, timeframe, limit=1000, start_time=None, end_time=None):
if index == klc.start_klu.index:
ret_df.loc[klc_index] = df_copy.loc[index]
klc_index += 1
"""
# 如果过滤后没有数据,返回None
if len(ret_df) == 0:
if len(df) == 0:
print("过滤后无数据")
return None
print(f"获取到总共 {len(ret_df)} 条数据")
return ret_df
print(f"获取到总共 {len(df)} 条数据")
return df
except Exception as e:
print(f"获取数据错误: {e}")
@@ -471,6 +473,9 @@ def analyze():
'direction': convert_direction(bi.dir)
} for bi in element_analysis['bi_list'] if bi.end_klc]
# 添加小周期K线数据
result['element_kline_data'] = element_df.to_dict('records')
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,
@@ -503,6 +508,14 @@ def analyze():
'desc': point['desc']
} for point in element_analysis['trade_points']]
# 添加小周期分型信息
result['element_klc_fx_info'] = [{
'time': format_time_safely(point['time'], client_tz),
'price': point['price'],
'fx_type': point['fx_type'],
'is_bottom': point['is_bottom']
} for point in element_analysis['klc_fx_info']]
print(f"小周期分析完成: {element_timeframe}, 笔数量: {len(result['element_bi_list'])}, {'仅元素数据' if elements_only else '包含主周期数据'}")
else:
print(f"无法获取小周期数据: {element_timeframe}")
+13 -5
View File
@@ -1,5 +1,13 @@
flask==2.0.1
ccxt==4.4.70
pandas==1.3.3
numpy==1.21.2
plotly==5.3.1
flask>=2.0.1
ccxt>=4.4.70
pandas>=1.3.3
numpy>=1.21.2
plotly>=5.3.1
matplotlib>=3.4.3
pytz>=2021.1
python-dateutil>=2.8.2
xgboost>=1.5.0
scikit-learn>=1.0.1
ta-lib>=0.4.19
bootstrap-flask>=2.0.0
gunicorn>=20.1.0
+241 -43
View File
@@ -5,10 +5,12 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.js"></script>
<link href="https://cdn.datatables.net/1.11.5/css/jquery.dataTables.min.css" rel="stylesheet">
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- TradingView Widget BEGIN -->
<script src="https://cdn.jsdelivr.net/npm/lightweight-charts@4.0.1/dist/lightweight-charts.standalone.production.js"></script>
<!-- TradingView Widget END -->
@@ -271,6 +273,23 @@
<input class="form-check-input" type="checkbox" id="showOriginalKline" checked>
<label class="form-check-label" for="showOriginalKline">原始K线</label>
</div>
<!-- 添加K线周期切换 -->
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="klinePeriod" id="mainPeriodKline" checked>
<label class="form-check-label" for="mainPeriodKline">主周期</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="klinePeriod" id="elementPeriodKline">
<label class="form-check-label" for="elementPeriodKline">小周期</label>
<i class="bi bi-info-circle" data-bs-toggle="tooltip" title="显示小周期K线,同时可以叠加大周期分型和笔段"></i>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="showVolume" checked>
<label class="form-check-label" for="showVolume">成交量</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="showMacd" checked>
<label class="form-check-label" for="showMacd">MACD</label>
@@ -279,8 +298,15 @@
<input class="form-check-input" type="checkbox" id="showKlcFxType">
<label class="form-check-label" for="showKlcFxType">分型类型</label>
</div>
<div class="form-check form-check-inline" style="display: none;">
<input class="form-check-input" type="checkbox" id="showTradePoints">
<!-- 添加小周期分型显示控制 -->
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="showElementKlcFxType" checked>
<label class="form-check-label" for="showElementKlcFxType">小周期分型</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="showTradePoints" checked>
<label class="form-check-label" for="showTradePoints">买卖点</label>
</div>
</div>
@@ -731,7 +757,7 @@
// 添加买卖点复选框变更事件
$('#showTradePoints').change(function() {
updateChartDisplay();
refreshChart(currentData);
});
// 添加分型类型复选框变更事件
@@ -924,8 +950,11 @@
console.log('- 显示中枢:', $('#showMainZs').is(':checked'));
console.log('- 显示未完成中枢:', $('#showMainUncompletedZs').is(':checked'));
console.log('- 显示MACD:', $('#showMacd').is(':checked'));
console.log('- 显示买卖点:', $('#showTradePoints').is(':checked'));
console.log('- 显示成交量:', $('#showVolume').is(':checked'));
console.log('- 显示分型类型:', $('#showKlcFxType').is(':checked'));
console.log('- 显示小周期分型:', $('#showElementKlcFxType').is(':checked'));
console.log('- 显示买卖点:', $('#showTradePoints').is(':checked'));
console.log('- 显示原始K线:', $('#showOriginalKline').is(':checked'));
// 重新初始化图表,这将清除旧图形并重新绘制
initTradingView($('#symbol').val(), $('#timeframe').val());
@@ -1212,18 +1241,42 @@
macdChart = LightweightCharts.createChart(macdChartContainer, createChartOptions(false));
}
// 转换K线数据 - 始终使用主时间周期数据
const 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),
};
});
// 转换K线数据 - 根据选中的周期使用主周期或小周期数据
let candles;
const useElementPeriod = $('#elementPeriodKline').is(':checked') &&
currentData.element_timeframe &&
currentData.element_kline_data;
// 输出K线周期选择状态
console.log('K线周期选择:', useElementPeriod ? '小周期' : '主周期');
if (useElementPeriod) {
// 使用小周期K线数据
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 {
// 使用主周期K线数据
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),
};
});
}
// 创建蜡烛图系列并设置数据
if (showOriginalKline) {
@@ -1257,14 +1310,23 @@
}
// 转换成交量数据 - 始终使用主K线周期数据
const volumes = currentData.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(220, 53, 69, 0.5)' : 'rgba(40, 167, 69, 0.5)',
};
});
const volumes = useElementPeriod ?
currentData.element_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(220, 53, 69, 0.5)' : 'rgba(40, 167, 69, 0.5)',
};
}) :
currentData.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(220, 53, 69, 0.5)' : 'rgba(40, 167, 69, 0.5)',
};
});
// 添加成交量图表
const volumeSeries = volumeChart.addHistogramSeries({
@@ -2440,6 +2502,66 @@
console.log('绘制分型类型标签 - 已禁用或无数据');
}
// 绘制小周期分型标记
if ($('#showElementKlcFxType').is(':checked') && currentData.element_klc_fx_info && currentData.element_klc_fx_info.length > 0) {
console.log(`绘制小周期分型标记,共${currentData.element_klc_fx_info.length}`);
currentData.element_klc_fx_info.forEach(function(fx) {
try {
// 直接使用UTC时间戳(秒)
const timestamp = Math.floor(new Date(fx.time).getTime() / 1000);
const price = parseFloat(fx.price);
if (isNaN(timestamp) || isNaN(price)) {
console.error('小周期分型时间或价格转换错误:', fx.time, fx.price);
return;
}
// 小周期分型使用红色标记,不同于主周期分型
const redColor = '#FF0000'; // 红色
// 创建标记系列
const markerSeries = mainChart.addLineSeries({
lastValueVisible: false,
priceLineVisible: false,
});
// 设置文本标记
markerSeries.setMarkers([
{
time: timestamp,
position: fx.is_bottom ? 'belowBar' : 'aboveBar',
color: redColor,
shape: 'arrowUp', // 使用箭头形状,与主周期分型区分
text: fx.is_bottom ? '↓' : '↑', // 显示箭头
size: 1
}
]);
// 为小周期分型添加明显的箭头标记
const arrowSeries = mainChart.addLineSeries({
lastValueVisible: false,
priceLineVisible: false,
lineWidth: 1,
color: redColor
});
// 计算标记位置,底分型在价格下方,顶分型在价格上方
const offset = fx.is_bottom ? -0.001 * price : 0.001 * price;
arrowSeries.setData([{
time: timestamp,
value: price + offset
}]);
} catch (e) {
console.error('绘制小周期分型标记出错:', e);
}
});
} else {
console.log('绘制小周期分型标记 - 已禁用或无数据');
}
// 调整所有图表以适应数据
mainChart.timeScale().fitContent();
volumeChart.timeScale().fitContent();
@@ -2487,18 +2609,40 @@
// 检查是否显示原始K线
const showOriginalKline = $('#showOriginalKline').is(':checked');
// 检查是否使用小周期数据
const useElementPeriod = $('#elementPeriodKline').is(':checked') &&
currentData.element_timeframe &&
currentData.element_kline_data;
// 转换K线数据
const 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 candles;
if (useElementPeriod) {
console.log('使用小周期K线数据');
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 {
console.log('使用主周期K线数据');
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),
};
});
}
// 更新K线数据
if (showOriginalKline && tvWidget.series.candleSeries) {
@@ -2514,14 +2658,23 @@
}
// 更新成交量数据
const volumes = currentData.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(220, 53, 69, 0.5)' : 'rgba(40, 167, 69, 0.5)',
};
});
const volumes = useElementPeriod ?
currentData.element_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(220, 53, 69, 0.5)' : 'rgba(40, 167, 69, 0.5)',
};
}) :
currentData.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(220, 53, 69, 0.5)' : 'rgba(40, 167, 69, 0.5)',
};
});
if (tvWidget.series.volumeSeries) {
tvWidget.series.volumeSeries.setData(volumes);
@@ -3572,6 +3725,51 @@
// 更新表格数据
updateTables(data);
}
// 绑定分型类型显示开关
$('#showKlcFxType').change(function() {
refreshChart(currentData);
});
// 绑定小周期分型显示开关
$('#showElementKlcFxType').change(function() {
refreshChart(currentData);
});
// 绑定买卖点显示开关
$('#showTradePoints').change(function() {
refreshChart(currentData);
});
// 绑定K线周期切换
$('input[name="klinePeriod"]').change(function() {
refreshChart(currentData);
});
// 在控制台输出当前显示状态
console.log('当前显示状态:', {
'showOriginalKline': $('#showOriginalKline').is(':checked'),
'showMainBi': $('#showMainBi').is(':checked'),
'showMainSeg': $('#showMainSeg').is(':checked'),
'showMainZs': $('#showMainZs').is(':checked'),
'showMainUncompletedZs': $('#showMainUncompletedZs').is(':checked'),
'showVolume': $('#showVolume').is(':checked'),
'showMacd': $('#showMacd').is(':checked'),
'showKlcFxType': $('#showKlcFxType').is(':checked'),
'showElementKlcFxType': $('#showElementKlcFxType').is(':checked'),
'showTradePoints': $('#showTradePoints').is(':checked'),
'timeframe': $('#timeframe').val(),
'elementTimeframe': $('#elementTimeframe').val(),
'timezone': $('#timezone').val(),
'start_time': $('#start_time').val(),
'end_time': $('#end_time').val()
});
// 初始化提示工具
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
})
</script>
</body>
</html>