add more files
This commit is contained in:
+16
-3
@@ -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
@@ -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
@@ -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>
|
||||
Reference in New Issue
Block a user