trading.ai/web/templates/signals.html
2025-09-23 16:12:18 +08:00

274 lines
17 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block title %}交易信号 - AI 智能选股大师{% endblock %}
{% block content %}
<!-- 页面标题和筛选 -->
<div class="row mb-4">
<div class="col-12">
<div class="d-flex justify-content-end align-items-center">
<!-- 筛选表单 -->
<form method="GET" class="d-flex gap-2 align-items-center">
<select name="strategy" class="form-select form-select-sm">
<option value="">所有策略</option>
<option value="K线形态策略" {% if strategy_name == 'K线形态策略' %}selected{% endif %}>K线形态策略</option>
</select>
<select name="timeframe" class="form-select form-select-sm">
<option value="">所有周期</option>
<option value="daily" {% if timeframe == 'daily' or not timeframe %}selected{% endif %}>日线</option>
<option value="weekly" {% if timeframe == 'weekly' %}selected{% endif %}>周线</option>
</select>
<select name="days" class="form-select form-select-sm">
<option value="7" {% if days == 7 %}selected{% endif %}>最近7天</option>
<option value="15" {% if days == 15 %}selected{% endif %}>最近15天</option>
<option value="30" {% if days == 30 %}selected{% endif %}>最近30天</option>
<option value="90" {% if days == 90 %}selected{% endif %}>最近90天</option>
</select>
<select name="per_page" class="form-select form-select-sm">
<option value="20" {% if per_page == 20 %}selected{% endif %}>每页20条</option>
<option value="50" {% if per_page == 50 %}selected{% endif %}>每页50条</option>
<option value="100" {% if per_page == 100 %}selected{% endif %}>每页100条</option>
</select>
<button type="submit" class="btn btn-primary btn-sm text-nowrap">
<i class="fas fa-filter me-1"></i>筛选
</button>
</form>
</div>
</div>
</div>
<!-- 信号表格 -->
<div class="row">
<div class="col-12">
<div class="card fade-in">
<div class="card-header">
<h5 class="mb-0 text-primary fw-bold">
<i class="fas fa-table me-2"></i>详细信号数据
</h5>
</div>
<div class="card-body p-0">
{% if signals_grouped %}
<div class="table-container">
{% for scan_hour, signals in signals_grouped.items() %}
<!-- 扫描时间分组标题 -->
<div class="scan-date-header bg-light px-3 py-2">
<h6 class="mb-0 text-primary fw-bold">
<i class="fas fa-clock me-2"></i>扫描时间: {{ scan_hour.strftime('%Y-%m-%d %H:%M') }}
<span class="badge bg-primary ms-2">{{ signals|length }} 条信号</span>
</h6>
</div>
<!-- 该扫描时间下的信号表格 -->
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th style="width: 250px;">股票</th>
<th style="width: 150px;">策略</th>
<th style="width: 100px;">周期</th>
<th style="width: 500px;">时间线流程</th>
</tr>
</thead>
<tbody>
{% for signal in signals %}
<tr>
<td>
<div class="d-flex align-items-center">
<a href="https://xueqiu.com/S/{% if signal.stock_code.endswith('.SZ') %}SZ{% elif signal.stock_code.endswith('.SH') %}SH{% elif signal.stock_code.startswith('0') or signal.stock_code.startswith('3') %}SZ{% else %}SH{% endif %}{{ signal.stock_code.split('.')[0] }}" target="_blank" class="stock-code-link me-2">
<div class="stock-code-badge">{{ signal.stock_code }}</div>
</a>
<div class="stock-name text-truncate">{{ signal.stock_name or '未知' }}</div>
</div>
</td>
<td>
<span class="badge bg-primary">{{ signal.strategy_name }}</span>
{% if signal.new_high_confirmed %}
<div class="mt-1">
<small class="badge bg-success">创新高回踩确认</small>
</div>
{% endif %}
</td>
<td>
<span class="badge bg-{% if signal.timeframe == 'daily' %}primary{% else %}success{% endif %}">
{{ '日线' if signal.timeframe == 'daily' else '周线' }}
</span>
</td>
<td style="min-width: 500px; padding: 12px 20px;">
{% if signal.new_high_confirmed %}
<!-- 新格式:优化的创新高回踩确认时间线 -->
<div class="timeline-enhanced-wide">
<div class="timeline-flow">
<div class="timeline-step-wide">
<div class="timeline-marker-wide pattern-marker">
<i class="fas fa-chart-line"></i>
</div>
<div class="timeline-content-wide">
<div class="timeline-title">📅 模式识别</div>
<div class="timeline-date-wide">{{ signal.signal_date | datetime_format('%m-%d') }}</div>
<div class="timeline-info">突破价: {{ signal.breakout_price | currency }}元</div>
</div>
</div>
<div class="timeline-arrow">
<i class="fas fa-arrow-right"></i>
</div>
{% if signal.new_high_date %}
<div class="timeline-step-wide">
<div class="timeline-marker-wide new-high-marker">
<i class="fas fa-rocket"></i>
</div>
<div class="timeline-content-wide">
<div class="timeline-title">🚀 创新高</div>
<div class="timeline-date-wide highlight">{{ signal.new_high_date | datetime_format('%m-%d') }}</div>
{% if signal.new_high_price %}
<div class="timeline-info">{{ signal.new_high_price | currency }}元</div>
{% endif %}
</div>
</div>
<div class="timeline-arrow">
<i class="fas fa-arrow-right"></i>
</div>
{% endif %}
{% if signal.confirmation_date %}
<div class="timeline-step-wide">
<div class="timeline-marker-wide confirmation-marker">
<i class="fas fa-check-circle"></i>
</div>
<div class="timeline-content-wide">
<div class="timeline-title">✅ 回踩确认</div>
<div class="timeline-date-wide highlight">{{ signal.confirmation_date | datetime_format('%m-%d') }}</div>
{% if signal.confirmation_days %}
<div class="timeline-info">用时{{ signal.confirmation_days }}天</div>
{% endif %}
</div>
</div>
{% endif %}
</div>
<!-- 技术指标概要 -->
<div class="timeline-summary mt-2">
<span class="badge bg-{% if signal.breakout_pct and signal.breakout_pct > 3 %}success{% elif signal.breakout_pct and signal.breakout_pct > 1 %}warning{% else %}secondary{% endif %} me-1 badge-sm">
突破{{ signal.breakout_pct | percentage }}
</span>
<span class="badge bg-{% if signal.final_yang_entity_ratio and signal.final_yang_entity_ratio > 0.6 %}success{% elif signal.final_yang_entity_ratio and signal.final_yang_entity_ratio > 0.4 %}warning{% else %}secondary{% endif %} me-1 badge-sm">
实体{{ signal.final_yang_entity_ratio | percentage }}
</span>
<span class="badge bg-{% if signal.above_ema20 %}success{% else %}secondary{% endif %} me-1 badge-sm">
EMA20{{ '✅' if signal.above_ema20 else '❌' }}
</span>
{% if signal.pullback_distance %}
<span class="badge bg-{% if signal.pullback_distance > -2 %}success{% elif signal.pullback_distance > -5 %}warning{% else %}danger{% endif %} me-1 badge-sm">
回踩{{ signal.pullback_distance | currency }}%
</span>
{% endif %}
<span class="badge bg-light text-muted me-1 badge-sm">
{{ signal.scan_time | datetime_format('%m-%d %H:%M') }}
</span>
</div>
</div>
{% else %}
<!-- 旧格式:兼容显示 -->
<div class="timeline-simple">
<div class="text-muted">{{ signal.signal_date | datetime_format('%Y-%m-%d') }}</div>
<div class="text-success fw-bold">{{ signal.breakout_price | currency }}元</div>
</div>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endfor %}
</div>
<!-- 分页 -->
{% if total_pages > 1 %}
<nav aria-label="信号分页" class="mt-4">
<ul class="pagination justify-content-center">
<!-- 上一页 -->
<li class="page-item {% if not has_prev %}disabled{% endif %}">
<a class="page-link" href="{% if has_prev %}{{ url_for('signals', page=current_page-1, strategy=strategy_name, timeframe=timeframe, days=days, per_page=per_page) }}{% else %}#{% endif %}">
<i class="fas fa-chevron-left"></i> 上一页
</a>
</li>
<!-- 页码 -->
{% set start_page = [1, current_page - 2]|max %}
{% set end_page = [total_pages, current_page + 2]|min %}
{% if start_page > 1 %}
<li class="page-item">
<a class="page-link" href="{{ url_for('signals', page=1, strategy=strategy_name, timeframe=timeframe, days=days, per_page=per_page) }}">1</a>
</li>
{% if start_page > 2 %}
<li class="page-item disabled"><span class="page-link">...</span></li>
{% endif %}
{% endif %}
{% for page_num in range(start_page, end_page + 1) %}
<li class="page-item {% if page_num == current_page %}active{% endif %}">
<a class="page-link" href="{{ url_for('signals', page=page_num, strategy=strategy_name, timeframe=timeframe, days=days, per_page=per_page) }}">{{ page_num }}</a>
</li>
{% endfor %}
{% if end_page < total_pages %}
{% if end_page < total_pages - 1 %}
<li class="page-item disabled"><span class="page-link">...</span></li>
{% endif %}
<li class="page-item">
<a class="page-link" href="{{ url_for('signals', page=total_pages, strategy=strategy_name, timeframe=timeframe, days=days, per_page=per_page) }}">{{ total_pages }}</a>
</li>
{% endif %}
<!-- 下一页 -->
<li class="page-item {% if not has_next %}disabled{% endif %}">
<a class="page-link" href="{% if has_next %}{{ url_for('signals', page=current_page+1, strategy=strategy_name, timeframe=timeframe, days=days, per_page=per_page) }}{% else %}#{% endif %}">
下一页 <i class="fas fa-chevron-right"></i>
</a>
</li>
</ul>
</nav>
{% endif %}
{% else %}
<div class="empty-state">
<i class="fas fa-signal"></i>
<h4>暂无信号数据</h4>
<p>请尝试调整筛选条件或稍后再试</p>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
$(document).ready(function() {
// 表格行点击高亮
$('tbody tr').on('click', function() {
$(this).toggleClass('table-active');
});
// 工具提示
$('[data-bs-toggle="tooltip"]').tooltip();
// 如果没有timeframe参数自动设置为daily并重新加载
const urlParams = new URLSearchParams(window.location.search);
if (!urlParams.has('timeframe')) {
urlParams.set('timeframe', 'daily');
window.location.search = urlParams.toString();
}
});
</script>
{% endblock %}