默认主/次/次次改为 45m/15m/5m、开始时间一周;SD/CD 按 hist 摆位置和箭头;去掉笔线段背驰与第四类勾选。 Co-authored-by: Cursor <cursoragent@cursor.com>
1567 lines
64 KiB
HTML
1567 lines
64 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<!-- Google tag (gtag.js) -->
|
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-LVVXH3TL04"></script>
|
|
<script>
|
|
window.dataLayer = window.dataLayer || [];
|
|
function gtag(){dataLayer.push(arguments);}
|
|
gtag('js', new Date());
|
|
gtag('config', 'G-LVVXH3TL04');
|
|
</script>
|
|
|
|
<title>缠论分析系统</title>
|
|
<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>
|
|
<script defer src="{{ url_for('static', filename='js/indicators.js') }}?v=20260809i"></script>
|
|
<script defer src="{{ url_for('static', filename='js/charts.js') }}?v=20260809i"></script>
|
|
<!-- TradingView Widget END -->
|
|
<script>
|
|
window.AVAILABLE_TIMEFRAMES = JSON.parse('{{ timeframe_keys_json | safe }}');
|
|
window.DEFAULT_MAIN_TIMEFRAME = "{{ default_main_timeframe }}";
|
|
window.DEFAULT_ELEMENT_TIMEFRAME = "{{ default_element_timeframe }}";
|
|
window.DEFAULT_SUB_SUB_TIMEFRAME = "{{ default_sub_sub_timeframe }}";
|
|
window.timeframeToMs = function(tf) {
|
|
if (!tf) return null;
|
|
var unit = tf.slice(-1);
|
|
var value = parseInt(tf.slice(0, -1), 10);
|
|
if (isNaN(value)) return null;
|
|
var unitMap = {
|
|
m: 60 * 1000,
|
|
h: 60 * 60 * 1000,
|
|
d: 24 * 60 * 60 * 1000,
|
|
w: 7 * 24 * 60 * 60 * 1000,
|
|
M: 30 * 24 * 60 * 60 * 1000
|
|
};
|
|
return unitMap[unit] ? value * unitMap[unit] : null;
|
|
};
|
|
</script>
|
|
<style>
|
|
body {
|
|
font-family: "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
|
margin: 0;
|
|
padding: 10px;
|
|
background-color: #f8f9fa;
|
|
color: #333;
|
|
}
|
|
.container {
|
|
max-width: 100%;
|
|
margin: 0 auto;
|
|
background-color: white;
|
|
padding: 5px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
}
|
|
.header {
|
|
margin-bottom: 0px;
|
|
padding-bottom: 0px;
|
|
}
|
|
.controls {
|
|
margin-bottom: 10px;
|
|
padding: 10px;
|
|
background-color: #f8f9fa;
|
|
border-radius: 8px;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
|
}
|
|
.form-label {
|
|
font-weight: 500;
|
|
margin-bottom: 6px;
|
|
color: #495057;
|
|
}
|
|
/*主图大小*/
|
|
.chart-container {
|
|
width: 100%;
|
|
height: 1200px;
|
|
margin-top: 10px;
|
|
border: 1px solid #e9ecef;
|
|
border-radius: 8px;
|
|
padding: 10px;
|
|
background-color: #fff;
|
|
position: relative;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
|
margin-bottom: 20px; /* 增加下边距,防止被下方数据面板遮挡 */
|
|
}
|
|
#tradingview_chart {
|
|
width: 100%;
|
|
height: 100%;
|
|
position: relative;
|
|
z-index: 1; /* 确保图表在数据面板之上 */
|
|
}
|
|
.chart-options {
|
|
position: absolute;
|
|
top: 10px;
|
|
right: 10px;
|
|
z-index: 100;
|
|
background-color: rgba(255, 255, 255, 0.9);
|
|
padding: 12px;
|
|
border-radius: 8px;
|
|
font-size: 13px;
|
|
box-shadow: 0 1px 4px rgba(0,0,0,0.1);
|
|
}
|
|
.data-container {
|
|
margin-top: 30px; /* 增加上边距,避免与图表重叠 */
|
|
position: relative;
|
|
z-index: 10;
|
|
background-color: white;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
clear: both; /* 清除浮动 */
|
|
}
|
|
.nav-tabs {
|
|
margin-bottom: 10px;
|
|
position: relative;
|
|
z-index: 20;
|
|
background-color: white;
|
|
border-radius: 8px 8px 0 0;
|
|
padding: 10px 10px 0 10px;
|
|
}
|
|
.nav-tabs .nav-link {
|
|
border-radius: 6px 6px 0 0;
|
|
margin-right: 5px;
|
|
font-weight: 500;
|
|
transition: all 0.2s ease;
|
|
}
|
|
.nav-tabs .nav-link:hover {
|
|
background-color: #f8f9fa;
|
|
border-color: #dee2e6;
|
|
}
|
|
.nav-tabs .nav-link.active {
|
|
background-color: #0d6efd;
|
|
color: white;
|
|
border-color: #0d6efd;
|
|
}
|
|
|
|
.table-container {
|
|
overflow-x: auto;
|
|
}
|
|
.btn-primary {
|
|
background-color: #0d6efd;
|
|
border-color: #0d6efd;
|
|
color: white;
|
|
padding: 8px 16px;
|
|
font-weight: 500;
|
|
transition: all 0.2s;
|
|
}
|
|
.btn-primary:hover {
|
|
background-color: #0a58ca;
|
|
border-color: #0a53be;
|
|
}
|
|
#loadingIndicator {
|
|
display: none;
|
|
text-align: center;
|
|
padding: 20px;
|
|
font-size: 18px;
|
|
color: #666;
|
|
}
|
|
|
|
/* 方向列颜色 */
|
|
.direction-up {
|
|
color: #dc3545;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.direction-down {
|
|
color: #28a745;
|
|
font-weight: bold;
|
|
}
|
|
|
|
/* MACD列颜色 */
|
|
.positive {
|
|
color: #dc3545;
|
|
}
|
|
|
|
.negative {
|
|
color: #28a745;
|
|
}
|
|
|
|
/* 自定义控制面板 */
|
|
.form-check-label {
|
|
cursor: pointer;
|
|
user-select: none;
|
|
}
|
|
|
|
/* 增加表单元素间距 */
|
|
.g-3 {
|
|
--bs-gutter-y: 1rem;
|
|
}
|
|
|
|
/* 买卖点相关样式已移除 */
|
|
|
|
/* 主次周期元素样式区分 */
|
|
.main-bi {
|
|
color: #dc3545;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.element-bi {
|
|
color: #9c27b0;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.main-seg {
|
|
color: #FF6B6B;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.element-seg {
|
|
color: #673ab7;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.main-zs {
|
|
color: #F1C40F;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.element-zs {
|
|
color: #3f51b5;
|
|
font-weight: bold;
|
|
}
|
|
|
|
/* 加载指示器旋转动画 */
|
|
@keyframes spin {
|
|
0% { transform: rotate(0deg); }
|
|
100% { transform: rotate(360deg); }
|
|
}
|
|
|
|
.loading-spinner {
|
|
display: inline-block;
|
|
width: 18px;
|
|
height: 18px;
|
|
border: 2px solid rgba(0, 0, 0, 0.1);
|
|
border-left-color: #007bff;
|
|
border-radius: 50%;
|
|
animation: spin 1s linear infinite;
|
|
margin-left: 8px;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
/* 数据回放相关样式 */
|
|
#replayStatus {
|
|
min-width: 120px;
|
|
}
|
|
|
|
#replayProgress {
|
|
border-radius: 4px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.crosshair-tooltip {
|
|
position: absolute;
|
|
background: rgba(40, 40, 40, 0.9);
|
|
color: white;
|
|
padding: 8px 12px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
z-index: 1000;
|
|
pointer-events: none;
|
|
max-width: 300px;
|
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
|
display: none;
|
|
}
|
|
|
|
/* 主次周期元素样式区分 */
|
|
|
|
/* 均线系统样式 */
|
|
.ma-panel {
|
|
position: absolute;
|
|
top: 10px;
|
|
left: 10px;
|
|
z-index: 1000;
|
|
background: rgba(255, 255, 255, 0.95);
|
|
border: 1px solid #e0e0e0;
|
|
border-radius: 8px;
|
|
padding: 8px;
|
|
max-width: 300px;
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.ma-item {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 4px 0;
|
|
font-size: 12px;
|
|
border-bottom: 1px solid #f0f0f0;
|
|
}
|
|
|
|
.ma-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.ma-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.ma-label {
|
|
font-weight: 500;
|
|
}
|
|
|
|
.ma-value {
|
|
color: #666;
|
|
}
|
|
|
|
.ma-actions {
|
|
display: flex;
|
|
gap: 4px;
|
|
}
|
|
|
|
.ma-action-btn {
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
padding: 2px 4px;
|
|
border-radius: 3px;
|
|
font-size: 11px;
|
|
color: #666;
|
|
}
|
|
|
|
.ma-action-btn:hover {
|
|
background-color: #f0f0f0;
|
|
color: #333;
|
|
}
|
|
|
|
.ma-color-indicator {
|
|
width: 12px;
|
|
height: 2px;
|
|
border-radius: 1px;
|
|
margin-right: 4px;
|
|
}
|
|
|
|
.indicator-dropdown {
|
|
position: absolute;
|
|
top: 10px;
|
|
right: 120px;
|
|
z-index: 100;
|
|
}
|
|
|
|
.add-indicator-btn {
|
|
background-color: #0d6efd;
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 12px;
|
|
border-radius: 6px;
|
|
font-size: 13px;
|
|
cursor: pointer;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
}
|
|
|
|
.add-indicator-btn:hover {
|
|
background-color: #0a58ca;
|
|
}
|
|
|
|
.add-indicator-btn:focus {
|
|
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
|
}
|
|
|
|
.dropdown-menu {
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 0;
|
|
z-index: 1000;
|
|
display: none;
|
|
min-width: 160px;
|
|
padding: 0.5rem 0;
|
|
margin: 0.125rem 0 0;
|
|
font-size: 0.875rem;
|
|
color: #212529;
|
|
text-align: left;
|
|
background-color: #fff;
|
|
background-clip: padding-box;
|
|
border: 1px solid rgba(0,0,0,.15);
|
|
border-radius: 0.375rem;
|
|
box-shadow: 0 0.5rem 1rem rgba(0,0,0,.15);
|
|
}
|
|
|
|
.dropdown-menu.show {
|
|
display: block;
|
|
}
|
|
|
|
.dropdown-item {
|
|
display: block;
|
|
width: 100%;
|
|
padding: 0.375rem 1rem;
|
|
clear: both;
|
|
font-weight: 400;
|
|
color: #212529;
|
|
text-align: inherit;
|
|
text-decoration: none;
|
|
white-space: nowrap;
|
|
background-color: transparent;
|
|
border: 0;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.dropdown-item:hover,
|
|
.dropdown-item:focus {
|
|
background-color: #f8f9fa;
|
|
color: #16181b;
|
|
}
|
|
|
|
.dropdown-item i {
|
|
margin-right: 8px;
|
|
}
|
|
|
|
.indicator-panel {
|
|
position: absolute;
|
|
top: 10px;
|
|
left: 10px;
|
|
z-index: 1000;
|
|
background: rgba(255, 255, 255, 0.95);
|
|
border: 1px solid #e0e0e0;
|
|
border-radius: 8px;
|
|
padding: 8px;
|
|
max-width: 350px;
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.indicator-item {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 4px 0;
|
|
font-size: 12px;
|
|
border-bottom: 1px solid #f0f0f0;
|
|
}
|
|
|
|
.indicator-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.indicator-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.indicator-label {
|
|
font-weight: 500;
|
|
}
|
|
|
|
.indicator-value {
|
|
color: #666;
|
|
}
|
|
|
|
.indicator-actions {
|
|
display: flex;
|
|
gap: 4px;
|
|
}
|
|
|
|
.indicator-action-btn {
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
padding: 2px 4px;
|
|
border-radius: 3px;
|
|
font-size: 11px;
|
|
color: #666;
|
|
}
|
|
|
|
.indicator-action-btn:hover {
|
|
background-color: #f0f0f0;
|
|
color: #333;
|
|
}
|
|
|
|
.indicator-color-indicator {
|
|
width: 12px;
|
|
height: 2px;
|
|
border-radius: 1px;
|
|
margin-right: 4px;
|
|
}
|
|
|
|
/* 配置弹窗样式 */
|
|
.ma-config-modal {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(0,0,0,0.5);
|
|
z-index: 10000;
|
|
display: none;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.ma-config-content {
|
|
background: white;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
width: 400px;
|
|
max-width: 90vw;
|
|
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
|
}
|
|
|
|
.ma-config-title {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
margin-bottom: 20px;
|
|
color: #333;
|
|
}
|
|
|
|
.ma-config-form {
|
|
display: grid;
|
|
gap: 16px;
|
|
}
|
|
|
|
.ma-config-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
}
|
|
|
|
.ma-config-label {
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
color: #555;
|
|
}
|
|
|
|
.ma-config-input, .ma-config-select {
|
|
padding: 8px 12px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.ma-config-input:focus, .ma-config-select:focus {
|
|
outline: none;
|
|
border-color: #0d6efd;
|
|
box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.25);
|
|
}
|
|
|
|
.ma-config-actions {
|
|
display: flex;
|
|
gap: 12px;
|
|
justify-content: flex-end;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.ma-config-btn {
|
|
padding: 8px 16px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
font-size: 14px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.ma-config-btn-primary {
|
|
background-color: #0d6efd;
|
|
color: white;
|
|
}
|
|
|
|
.ma-config-btn-primary:hover {
|
|
background-color: #0a58ca;
|
|
}
|
|
|
|
.ma-config-btn-secondary {
|
|
background-color: #6c757d;
|
|
color: white;
|
|
}
|
|
|
|
.ma-config-btn-secondary:hover {
|
|
background-color: #5c636a;
|
|
}
|
|
|
|
.ma-line-preview {
|
|
width: 100%;
|
|
height: 30px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
margin-top: 8px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
.ma-line-preview svg {
|
|
width: 80%;
|
|
height: 20px;
|
|
}
|
|
|
|
/* 布林带面板样式 */
|
|
.bb-panel {
|
|
position: absolute;
|
|
bottom: 20px;
|
|
left: 20px;
|
|
background: rgba(255, 255, 255, 0.95);
|
|
border: 1px solid #ddd;
|
|
border-radius: 8px;
|
|
padding: 12px;
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
min-width: 200px;
|
|
max-width: 300px;
|
|
z-index: 50;
|
|
}
|
|
|
|
.bb-item {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 6px 0;
|
|
border-bottom: 1px solid #f0f0f0;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.bb-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.bb-info {
|
|
flex: 1;
|
|
margin-right: 10px;
|
|
}
|
|
|
|
.bb-label {
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
|
|
.bb-value {
|
|
color: #666;
|
|
font-size: 11px;
|
|
}
|
|
|
|
.bb-actions {
|
|
display: flex;
|
|
gap: 6px;
|
|
}
|
|
|
|
.bb-action-btn {
|
|
width: 20px;
|
|
height: 20px;
|
|
border: none;
|
|
background: #f8f9fa;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
font-size: 10px;
|
|
color: #666;
|
|
}
|
|
|
|
.bb-action-btn:hover {
|
|
background: #e9ecef;
|
|
color: #333;
|
|
}
|
|
|
|
.bb-color-indicator {
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: 2px;
|
|
margin-right: 4px;
|
|
display: inline-block;
|
|
}
|
|
.bb-config-modal {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
display: none;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 1000;
|
|
}
|
|
.bb-config-content {
|
|
background: white;
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
width: 400px;
|
|
max-width: 90vw;
|
|
max-height: 85vh;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.bb-config-title {
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
margin-bottom: 20px;
|
|
color: #333;
|
|
}
|
|
|
|
.bb-config-form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
}
|
|
|
|
.bb-config-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
}
|
|
|
|
.bb-config-label {
|
|
font-weight: 500;
|
|
color: #555;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.bb-config-input, .bb-config-select {
|
|
padding: 8px 12px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 6px;
|
|
font-size: 14px;
|
|
transition: border-color 0.2s;
|
|
}
|
|
|
|
.bb-config-input:focus, .bb-config-select:focus {
|
|
outline: none;
|
|
border-color: #667eea;
|
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
|
}
|
|
|
|
.bb-config-actions {
|
|
display: flex;
|
|
gap: 12px;
|
|
justify-content: flex-end;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.bb-config-btn {
|
|
padding: 10px 20px;
|
|
border: none;
|
|
border-radius: 6px;
|
|
font-size: 14px;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.bb-config-btn-primary {
|
|
background: #667eea;
|
|
color: white;
|
|
}
|
|
|
|
.bb-config-btn-primary:hover {
|
|
background: #5a67d8;
|
|
}
|
|
|
|
.bb-config-btn-secondary {
|
|
background: #f8f9fa;
|
|
color: #6c757d;
|
|
}
|
|
|
|
.bb-config-btn-secondary:hover {
|
|
background: #e9ecef;
|
|
}
|
|
|
|
.bb-line-preview {
|
|
height: 30px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
margin-top: 8px;
|
|
background: linear-gradient(to right, #f8f9fa, #fff);
|
|
position: relative;
|
|
}
|
|
|
|
.bb-line-preview svg {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.macd-config-modal {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(0,0,0,0.5);
|
|
z-index: 10000;
|
|
display: none;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
.macd-config-content {
|
|
background: white;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
width: 360px;
|
|
max-width: 90vw;
|
|
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
|
}
|
|
.macd-config-title {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
margin-bottom: 20px;
|
|
color: #333;
|
|
}
|
|
.macd-config-form {
|
|
display: grid;
|
|
gap: 14px;
|
|
}
|
|
.macd-config-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
}
|
|
.macd-config-label {
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
color: #555;
|
|
}
|
|
.macd-config-input {
|
|
padding: 8px 12px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
font-size: 14px;
|
|
}
|
|
.macd-config-input:focus {
|
|
outline: none;
|
|
border-color: #0d6efd;
|
|
box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.25);
|
|
}
|
|
.macd-config-actions {
|
|
display: flex;
|
|
gap: 10px;
|
|
justify-content: flex-end;
|
|
margin-top: 20px;
|
|
}
|
|
.macd-config-btn {
|
|
padding: 8px 18px;
|
|
border: none;
|
|
border-radius: 6px;
|
|
font-size: 14px;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
.macd-config-btn-primary {
|
|
background: #0d6efd;
|
|
color: white;
|
|
}
|
|
.macd-config-btn-primary:hover {
|
|
background: #0b5ed7;
|
|
}
|
|
.macd-config-btn-secondary {
|
|
background: #f8f9fa;
|
|
color: #6c757d;
|
|
}
|
|
.macd-config-btn-secondary:hover {
|
|
background: #e9ecef;
|
|
}
|
|
.macd-config-hint {
|
|
font-size: 12px;
|
|
color: #999;
|
|
margin-top: 2px;
|
|
}
|
|
.deriv-bar {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin: 0 0 8px;
|
|
padding: 6px 10px;
|
|
background: #f8f9fa;
|
|
border: 1px solid #e9ecef;
|
|
border-radius: 6px;
|
|
font-size: 13px;
|
|
}
|
|
.deriv-bar .deriv-label {
|
|
font-weight: 600;
|
|
color: #495057;
|
|
margin-right: 4px;
|
|
}
|
|
.deriv-bar .deriv-chip {
|
|
font-variant-numeric: tabular-nums;
|
|
color: #343a40;
|
|
padding: 1px 6px;
|
|
border-radius: 4px;
|
|
background: #fff;
|
|
border: 1px solid #e9ecef;
|
|
}
|
|
.deriv-bar .deriv-chip.up { color: #198754; }
|
|
.deriv-bar .deriv-chip.down { color: #dc3545; }
|
|
.deriv-bar .deriv-src {
|
|
color: #868e96;
|
|
font-size: 12px;
|
|
margin-left: auto;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="controls">
|
|
<div class="row g-1 d-flex align-items-end">
|
|
<div class="col-md-2">
|
|
<label for="dataSource" class="form-label">数据源:</label>
|
|
<select id="dataSource" class="form-select">
|
|
<option value="crypto" selected>加密货币</option>
|
|
<option value="a_stock">A股</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2" id="cryptoSymbolContainer">
|
|
<label for="symbol" class="form-label">交易对:</label>
|
|
<select id="symbol" class="form-select">
|
|
{% for symbol in symbols %}
|
|
<option value="{{ symbol }}" {% if symbol == default_symbol %}selected{% endif %}>{{ symbol }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2" id="astockSymbolContainer" style="display:none;">
|
|
<label for="astockSymbol" class="form-label">A股股票:</label>
|
|
<select id="astockSymbol" class="form-select">
|
|
{% for stock in a_stock_symbols %}
|
|
<option value="{{ stock.symbol }}" {% if stock.symbol == '000001' %}selected{% endif %}>{{ stock.symbol }} - {{ stock.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="col-md-1">
|
|
<label for="timezone" class="form-label">时区:</label>
|
|
<select id="timezone" class="form-select">
|
|
<option value="UTC">UTC</option>
|
|
<option value="Asia/Shanghai" selected>Asia/Shanghai (UTC+8)</option>
|
|
<option value="America/New_York">America/New_York (UTC-4/5)</option>
|
|
<option value="Europe/London">Europe/London (UTC+0/1)</option>
|
|
<option value="Europe/Berlin">Europe/Berlin (UTC+1/2)</option>
|
|
<option value="Asia/Tokyo">Asia/Tokyo (UTC+9)</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label for="start_time" class="form-label">开始时间:</label>
|
|
<input type="datetime-local" id="start_time" class="form-control">
|
|
</div>
|
|
<div class="col-md-2">
|
|
<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="analyzeChart()" style="padding: 8px 6px; font-size: 14px;" title="按开始/结束时间拉取并分析(与自动刷新无关)">
|
|
分析
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-3">
|
|
<div class="col-md-16">
|
|
<div class="d-flex align-items-center">
|
|
<label class="form-label me-3 mb-0">基础显示:</label>
|
|
<div class="form-check form-check-inline">
|
|
<select id="klineType" class="form-select form-select-sm me-2" style="width: 120px;">
|
|
<option value="candlestick" selected>蜡烛线</option>
|
|
<option value="bar">柱条</option>
|
|
<option value="line">折线</option>
|
|
<option value="area">面积</option>
|
|
<option value="baseline">基线</option>
|
|
<option value="renko">砖型</option>
|
|
<option value="heikin">平均K</option>
|
|
<option value="klc">KLC</option>
|
|
</select>
|
|
<!-- 为兼容现有逻辑,保留隐藏的原始K线开关,与下拉同步 -->
|
|
<input class="form-check-input" type="checkbox" id="showOriginalKline" checked style="display:none;">
|
|
</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>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="radio" name="klinePeriod" id="subSubPeriodKline">
|
|
<label class="form-check-label" for="subSubPeriodKline">次次</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>
|
|
<button class="btn btn-sm btn-outline-secondary ms-1 p-0" onclick="showMacdConfig()" style="width:22px;height:22px;line-height:1;font-size:12px;" title="MACD参数设置">⚙</button>
|
|
</div>
|
|
<span id="showSentimentWrap" class="d-inline-flex align-items-center">
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showOi" checked>
|
|
<label class="form-check-label" for="showOi">OI</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showDeriv" checked>
|
|
<label class="form-check-label" for="showDeriv">衍生品</label>
|
|
</div>
|
|
</span>
|
|
<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" selected>5秒</option>
|
|
<option value="0.1667">10秒</option>
|
|
<option value="0.25">15秒</option>
|
|
<option value="0.5">30秒</option>
|
|
<option value="1">1分钟</option>
|
|
<option value="2">2分钟</option>
|
|
<option value="3">3分钟</option>
|
|
<option value="5">5分钟</option>
|
|
<option value="10">10分钟</option>
|
|
</select>
|
|
<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>
|
|
<div class="form-check form-check-inline me-2">
|
|
<input class="form-check-input" type="checkbox" id="showMainStructureZone">
|
|
<label class="form-check-label" for="showMainStructureZone">结构区</label>
|
|
</div>
|
|
<input type="number" id="zoneKlLines" class="form-control form-control-sm" value="1000" min="100" max="5000" step="100" style="width:80px;" title="结构区K线数量">
|
|
<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>
|
|
<div class="d-flex align-items-center mt-1">
|
|
<label class="form-label me-0 mb-0">主:</label>
|
|
<div class="form-check form-check-inline">
|
|
<select id="timeframe" class="form-select form-select-sm me-2" style="width: 100px;">
|
|
{% for value, label in timeframes.items() %}
|
|
<option value="{{ value }}" {% if value == default_main_timeframe %}selected{% endif %}>{{ label }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showMainBi" checked>
|
|
<label class="form-check-label" for="showMainBi">笔</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showMainSeg">
|
|
<label class="form-check-label" for="showMainSeg">线段</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showMainZs">
|
|
<label class="form-check-label" for="showMainZs">SEG中枢</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showMainBiZs" checked>
|
|
<label class="form-check-label" for="showMainBiZs">BI中枢</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showKlcFxType">
|
|
<label class="form-check-label" for="showKlcFxType">KLC分型</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showMainTrend">
|
|
<label class="form-check-label" for="showMainTrend">Trend</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="toggleUOnMain" checked>
|
|
<label class="form-check-label" for="toggleUOnMain">显示U</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showMainBiArea">
|
|
<label class="form-check-label" for="showMainBiArea">笔面积</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showMainSegArea">
|
|
<label class="form-check-label" for="showMainSegArea">线段面积</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showMainBsp">
|
|
<label class="form-check-label" for="showMainBsp">买卖点</label>
|
|
</div>
|
|
</div>
|
|
<div class="d-flex align-items-center mt-1">
|
|
<label class="form-label me-0 mb-0">次:</label>
|
|
<div class="form-check form-check-inline">
|
|
<select id="elementTimeframe" class="form-select form-select-sm me-2" style="width: 100px;">
|
|
{% for value, label in timeframes.items() %}
|
|
<option value="{{ value }}" {% if value == default_element_timeframe %}selected{% endif %}>{{ label }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showElementBi">
|
|
<label class="form-check-label" for="showElementBi">笔</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showElementSeg">
|
|
<label class="form-check-label" for="showElementSeg">线段</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showElementZs">
|
|
<label class="form-check-label" for="showElementZs">SEG中枢</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showElementBiZs">
|
|
<label class="form-check-label" for="showElementBiZs">BI中枢</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showElementKlcFxType">
|
|
<label class="form-check-label" for="showElementKlcFxType">KLC分型</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showElementTrend">
|
|
<label class="form-check-label" for="showElementTrend">Trend</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="toggleUOnElement">
|
|
<label class="form-check-label" for="toggleUOnElement">显示U</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showElementBiArea">
|
|
<label class="form-check-label" for="showElementBiArea">笔面积</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showElementSegArea">
|
|
<label class="form-check-label" for="showElementSegArea">线段面积</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showElementBsp">
|
|
<label class="form-check-label" for="showElementBsp">买卖点</label>
|
|
</div>
|
|
</div>
|
|
<div class="d-flex align-items-center mt-1">
|
|
<label class="form-label me-0 mb-0">次次:</label>
|
|
<div class="form-check form-check-inline">
|
|
<select id="subSubTimeframe" class="form-select form-select-sm me-2" style="width: 100px;">
|
|
{% for value, label in timeframes.items() %}
|
|
<option value="{{ value }}" {% if value == default_sub_sub_timeframe %}selected{% endif %}>{{ label }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showSubSubBi">
|
|
<label class="form-check-label" for="showSubSubBi">笔</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showSubSubSeg">
|
|
<label class="form-check-label" for="showSubSubSeg">线段</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showSubSubZs">
|
|
<label class="form-check-label" for="showSubSubZs">SEG中枢</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showSubSubBiZs">
|
|
<label class="form-check-label" for="showSubSubBiZs">BI中枢</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showSubSubKlcFxType">
|
|
<label class="form-check-label" for="showSubSubKlcFxType">KLC分型</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showSubSubTrend">
|
|
<label class="form-check-label" for="showSubSubTrend">Trend</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="toggleUOnSubSub">
|
|
<label class="form-check-label" for="toggleUOnSubSub">显示U</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showSubSubBiArea">
|
|
<label class="form-check-label" for="showSubSubBiArea">笔面积</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showSubSubSegArea">
|
|
<label class="form-check-label" for="showSubSubSegArea">线段面积</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="checkbox" id="showSubSubBsp">
|
|
<label class="form-check-label" for="showSubSubBsp">买卖点</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="loadingIndicator" style="display:none;"></div>
|
|
<div id="derivBar" class="deriv-bar">
|
|
<span class="deriv-label">资金面</span>
|
|
<span class="deriv-chip" id="derivOi">OI —</span>
|
|
<span class="deriv-chip" id="derivOiChg">Δ —</span>
|
|
<span class="deriv-chip" id="derivFunding">费率 —</span>
|
|
<span class="deriv-chip" id="derivBasis">基差 —</span>
|
|
<span class="deriv-chip" id="derivTaker">买卖比 —</span>
|
|
<span class="deriv-chip" id="derivLs">多空 —</span>
|
|
<span class="deriv-chip" id="derivTop">大户 —</span>
|
|
<span class="deriv-src" id="derivSrc"></span>
|
|
</div>
|
|
|
|
<div class="chart-container">
|
|
<div id="tradingview_chart"></div>
|
|
<!-- 技术指标下拉菜单 -->
|
|
<div class="indicator-dropdown dropdown">
|
|
<button class="add-indicator-btn dropdown-toggle" type="button" id="indicatorDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
|
<i class="bi bi-plus-lg"></i> 添加指标
|
|
</button>
|
|
<ul class="dropdown-menu" aria-labelledby="indicatorDropdown">
|
|
<li><a class="dropdown-item" href="#" onclick="showMAConfig(); return false;">
|
|
<i class="bi bi-graph-up"></i> 添加均线
|
|
</a></li>
|
|
<li><a class="dropdown-item" href="#" onclick="showBBConfig(); return false;">
|
|
<i class="bi bi-arrows-expand"></i> 添加布林带
|
|
</a></li>
|
|
</ul>
|
|
</div>
|
|
<!-- 技术指标信息面板 -->
|
|
<div id="indicatorPanel" class="indicator-panel" style="display: none;"></div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="data-container">
|
|
<ul class="nav nav-tabs" id="dataTabs" role="tablist">
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link active" id="kline-tab" data-bs-toggle="tab" data-bs-target="#kline" type="button" role="tab">K线数据</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="bi-tab" data-bs-toggle="tab" data-bs-target="#bi" type="button" role="tab">笔</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="seg-tab" data-bs-toggle="tab" data-bs-target="#seg" type="button" role="tab">线段</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="zs-tab" data-bs-toggle="tab" data-bs-target="#zs" type="button" role="tab">中枢</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="macd-tab" data-bs-toggle="tab" data-bs-target="#macd" type="button" role="tab">MACD</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
|
|
</li>
|
|
</ul>
|
|
<div class="data-source-info alert alert-info py-2 mt-1 mb-2" style="display:none;">
|
|
<small id="dataSourceText"></small>
|
|
</div>
|
|
<div class="tab-content" id="dataTabsContent">
|
|
<div class="tab-pane fade show active" id="kline" role="tabpanel">
|
|
<div class="table-container">
|
|
<table id="klineTable" class="display compact" style="width:100%">
|
|
<thead>
|
|
<tr>
|
|
<th>时间</th>
|
|
<th>开盘价</th>
|
|
<th>最高价</th>
|
|
<th>最低价</th>
|
|
<th>收盘价</th>
|
|
<th>成交量</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="tab-pane fade" id="bi" role="tabpanel">
|
|
<div class="table-container">
|
|
<table id="biTable" class="display compact" style="width:100%">
|
|
<thead>
|
|
<tr>
|
|
<th>起始时间</th>
|
|
<th>结束时间</th>
|
|
<th>确认时间</th>
|
|
<th>起始价格</th>
|
|
<th>结束价格</th>
|
|
<th>方向</th>
|
|
<th>MACD背离值</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="tab-pane fade" id="seg" role="tabpanel">
|
|
<div class="table-container">
|
|
<table id="segTable" class="display compact" style="width:100%">
|
|
<thead>
|
|
<tr>
|
|
<th>起始时间</th>
|
|
<th>结束时间</th>
|
|
<th>确认时间</th>
|
|
<th>起始价格</th>
|
|
<th>结束价格</th>
|
|
<th>方向</th>
|
|
<th>状态</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="tab-pane fade" id="zs" role="tabpanel">
|
|
<div class="table-container">
|
|
<h5>已完成中枢</h5>
|
|
<table id="zsTable" class="display compact" style="width:100%">
|
|
<thead>
|
|
<tr>
|
|
<th>起始时间</th>
|
|
<th>结束时间</th>
|
|
<th>中枢上沿(ZG)</th>
|
|
<th>中枢下沿(ZD)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
|
|
<h5 class="mt-4">未完成中枢</h5>
|
|
<table id="uncompletedZsTable" class="display compact" style="width:100%">
|
|
<thead>
|
|
<tr>
|
|
<th>起始时间</th>
|
|
<th>中枢上沿(ZG)</th>
|
|
<th>中枢下沿(ZD)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="tab-pane fade" id="macd" role="tabpanel">
|
|
<div class="table-container">
|
|
<table id="macdTable" class="display compact" style="width:100%">
|
|
<thead>
|
|
<tr>
|
|
<th>时间</th>
|
|
<th>收盘价</th>
|
|
<th>MACD</th>
|
|
<th>信号线</th>
|
|
<th>直方图</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
|
|
<script defer src="{{ url_for('static', filename='js/app/api_client.js') }}?v=20260910c"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/deriv_ui.js') }}?v=20260911i"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/state.js') }}?v=20260808i"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/trend.js') }}?v=20260808i"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/macd_ui.js') }}?v=20260911j"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/chart_format.js') }}?v=20260810e"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/chart_view.js') }}?v=20260912a"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/chart_tv_lifecycle.js') }}?v=20260910c"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/chart_tv_shell.js') }}?v=20260911l"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/chart_tv_indicators.js') }}?v=20260911n"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/chart_tv_chan.js') }}?v=20260910a"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/chart_tv_overlays.js') }}?v=20260911j"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/chart_tv_finalize.js') }}?v=20260910c"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/chart_tv.js') }}?v=20260910c"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/chart_sync.js') }}?v=20260910c"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/chart_tables.js') }}?v=20260911j"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/ui.js') }}?v=20260912a"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/overlays.js') }}?v=20260808i"></script>
|
|
<script defer src="{{ url_for('static', filename='js/app/main.js') }}?v=20260901d"></script>
|
|
|
|
<!-- 均线配置弹窗 -->
|
|
<div id="maConfigModal" class="ma-config-modal">
|
|
<div class="ma-config-content">
|
|
<div class="ma-config-title">添加均线</div>
|
|
<div class="ma-config-form">
|
|
<div class="ma-config-group">
|
|
<label class="ma-config-label">类型</label>
|
|
<select id="maType" class="ma-config-select">
|
|
<option value="SMA">SMA (简单移动平均)</option>
|
|
<option value="EMA">EMA (指数移动平均)</option>
|
|
<option value="WMA">WMA (加权移动平均)</option>
|
|
</select>
|
|
</div>
|
|
<div class="ma-config-group">
|
|
<label class="ma-config-label">长度</label>
|
|
<input type="number" id="maLength" class="ma-config-input" value="20" min="1" max="200">
|
|
</div>
|
|
<div class="ma-config-group">
|
|
<label class="ma-config-label">数据来源</label>
|
|
<select id="maSource" class="ma-config-select">
|
|
<option value="close">收盘价</option>
|
|
<option value="open">开盘价</option>
|
|
<option value="high">最高价</option>
|
|
<option value="low">最低价</option>
|
|
<option value="hl2">最高最低平均价 (HL2)</option>
|
|
<option value="hlc3">典型价 (HLC3)</option>
|
|
<option value="ohlc4">平均价 (OHLC4)</option>
|
|
</select>
|
|
</div>
|
|
<div class="ma-config-group">
|
|
<label class="ma-config-label">平滑线类型</label>
|
|
<select id="maSmoothType" class="ma-config-select">
|
|
<option value="none">无平滑</option>
|
|
<option value="SMA">SMA</option>
|
|
<option value="EMA">EMA</option>
|
|
<option value="WMA">WMA</option>
|
|
</select>
|
|
</div>
|
|
<div class="ma-config-group">
|
|
<label class="ma-config-label">平滑长度</label>
|
|
<input type="number" id="maSmoothLength" class="ma-config-input" value="3" min="1" max="50" disabled>
|
|
</div>
|
|
<div class="ma-config-group">
|
|
<label class="ma-config-label">线条粗细</label>
|
|
<select id="maLineWidth" class="ma-config-select">
|
|
<option value="1">细线 (1px)</option>
|
|
<option value="2" selected>普通 (2px)</option>
|
|
<option value="3">粗线 (3px)</option>
|
|
<option value="4">很粗 (4px)</option>
|
|
<option value="5">超粗 (5px)</option>
|
|
</select>
|
|
</div>
|
|
<div class="ma-config-group">
|
|
<label class="ma-config-label">线条样式</label>
|
|
<select id="maLineStyle" class="ma-config-select">
|
|
<option value="0">实线</option>
|
|
<option value="1">点线</option>
|
|
<option value="2">虚线</option>
|
|
<option value="3">大虚线</option>
|
|
</select>
|
|
</div>
|
|
<div class="ma-config-group">
|
|
<label class="ma-config-label">颜色</label>
|
|
<input type="color" id="maColor" class="ma-config-input" value="#2962FF">
|
|
</div>
|
|
<div class="ma-config-group">
|
|
<label class="ma-config-label">预览</label>
|
|
<div id="maLinePreview" class="ma-line-preview">
|
|
<svg id="previewSvg">
|
|
<line id="previewLine" x1="10%" y1="50%" x2="90%" y2="50%" stroke="#2962FF" stroke-width="2"/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="ma-config-actions">
|
|
<button class="ma-config-btn ma-config-btn-secondary" onclick="hideMAConfig()">取消</button>
|
|
<button class="ma-config-btn ma-config-btn-primary" id="maConfigSubmitBtn">添加</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 布林带配置弹窗 -->
|
|
<div id="bbConfigModal" class="bb-config-modal">
|
|
<div class="bb-config-content">
|
|
<div class="bb-config-title">添加布林带</div>
|
|
<div class="bb-config-form">
|
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
|
|
<div class="bb-config-group">
|
|
<label class="bb-config-label">类型</label>
|
|
<select id="bbType" class="bb-config-select">
|
|
<option value="Bollinger Bands">BB</option>
|
|
</select>
|
|
</div>
|
|
<div class="bb-config-group">
|
|
<label class="bb-config-label">长度</label>
|
|
<input type="number" id="bbLength" class="bb-config-input" value="20" min="1" max="200">
|
|
</div>
|
|
</div>
|
|
|
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
|
|
<div class="bb-config-group">
|
|
<label class="bb-config-label">上轨倍数</label>
|
|
<input type="number" id="bbUpperMultiplier" class="bb-config-input" value="2" min="0.1" max="10" step="0.1">
|
|
</div>
|
|
<div class="bb-config-group">
|
|
<label class="bb-config-label">下轨倍数</label>
|
|
<input type="number" id="bbLowerMultiplier" class="bb-config-input" value="2" min="0.1" max="10" step="0.1">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bb-config-group">
|
|
<label class="bb-config-label">数据来源</label>
|
|
<select id="bbSource" class="bb-config-select">
|
|
<option value="close">收盘价</option>
|
|
<option value="open">开盘价</option>
|
|
<option value="high">最高价</option>
|
|
<option value="low">最低价</option>
|
|
<option value="hl2">最高最低平均价 (HL2)</option>
|
|
<option value="hlc3">典型价 (HLC3)</option>
|
|
<option value="ohlc4">平均价 (OHLC4)</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
|
|
<div class="bb-config-group">
|
|
<label class="bb-config-label">线条粗细</label>
|
|
<select id="bbLineWidth" class="bb-config-select">
|
|
<option value="1">细线 (1px)</option>
|
|
<option value="2" selected>普通 (2px)</option>
|
|
<option value="3">粗线 (3px)</option>
|
|
</select>
|
|
</div>
|
|
<div class="bb-config-group">
|
|
<label class="bb-config-label">线条样式</label>
|
|
<select id="bbLineStyle" class="bb-config-select">
|
|
<option value="0">实线</option>
|
|
<option value="1">点线</option>
|
|
<option value="2">虚线</option>
|
|
<option value="3">大虚线</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bb-config-group">
|
|
<label class="bb-config-label">颜色配置</label>
|
|
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px;">
|
|
<div>
|
|
<label style="font-size: 11px; color: #666;">上轨</label>
|
|
<input type="color" id="bbUpperColor" class="bb-config-input" value="#ff6b6b" style="height: 30px;">
|
|
</div>
|
|
<div>
|
|
<label style="font-size: 11px; color: #666;">中轨</label>
|
|
<input type="color" id="bbMiddleColor" class="bb-config-input" value="#667eea" style="height: 30px;">
|
|
</div>
|
|
<div>
|
|
<label style="font-size: 11px; color: #666;">下轨</label>
|
|
<input type="color" id="bbLowerColor" class="bb-config-input" value="#4ecdc4" style="height: 30px;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bb-config-group">
|
|
<label class="bb-config-label">预览</label>
|
|
<div id="bbLinePreview" class="bb-line-preview">
|
|
<svg width="100%" height="30">
|
|
<line id="bbPreviewUpper" x1="10%" y1="25%" x2="90%" y2="25%" stroke="#ff6b6b" stroke-width="2"/>
|
|
<line id="bbPreviewMiddle" x1="10%" y1="50%" x2="90%" y2="50%" stroke="#667eea" stroke-width="2"/>
|
|
<line id="bbPreviewLower" x1="10%" y1="75%" x2="90%" y2="75%" stroke="#4ecdc4" stroke-width="2"/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="bb-config-actions">
|
|
<button class="bb-config-btn bb-config-btn-secondary" onclick="hideBBConfig()">取消</button>
|
|
<button class="bb-config-btn bb-config-btn-primary" id="bbConfigSubmitBtn">添加</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- MACD参数配置弹窗 -->
|
|
<div id="macdConfigModal" class="macd-config-modal">
|
|
<div class="macd-config-content">
|
|
<div class="macd-config-title">MACD 参数设置</div>
|
|
<div class="macd-config-form">
|
|
<div class="macd-config-group">
|
|
<label class="macd-config-label">快线周期 (Fast)</label>
|
|
<input type="number" id="macdFastPeriod" class="macd-config-input" value="13" min="2" max="200">
|
|
<div class="macd-config-hint">默认: 13</div>
|
|
</div>
|
|
<div class="macd-config-group">
|
|
<label class="macd-config-label">慢线周期 (Slow)</label>
|
|
<input type="number" id="macdSlowPeriod" class="macd-config-input" value="26" min="2" max="500">
|
|
<div class="macd-config-hint">默认: 26</div>
|
|
</div>
|
|
<div class="macd-config-group">
|
|
<label class="macd-config-label">信号线周期 (Signal)</label>
|
|
<input type="number" id="macdSignalPeriod" class="macd-config-input" value="9" min="2" max="200">
|
|
<div class="macd-config-hint">默认: 9</div>
|
|
</div>
|
|
</div>
|
|
<div class="macd-config-actions">
|
|
<button class="macd-config-btn macd-config-btn-secondary" onclick="hideMacdConfig()">取消</button>
|
|
<button class="macd-config-btn macd-config-btn-secondary" onclick="resetMacdConfig()">恢复默认</button>
|
|
<button class="macd-config-btn macd-config-btn-primary" onclick="saveMacdConfig()">应用</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html> |