Files
crypto-atr-signal/templates/index.html
T
2026-06-22 22:52:21 +02:00

385 lines
9.1 KiB
HTML
Raw Permalink 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.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Crypto ATR Signal</title>
<style>
:root {
color-scheme: light;
--bg: #f3f5f7;
--panel: #ffffff;
--panel-soft: #f8fafb;
--line: #d8dee6;
--text: #17202a;
--muted: #657184;
--bull: #087f5b;
--bear: #c92a2a;
--accent: #0b7285;
--shadow: 0 8px 18px rgba(23, 32, 42, .05);
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: Arial, "Microsoft YaHei", sans-serif;
background: var(--bg);
color: var(--text);
}
main {
width: min(1180px, calc(100% - 32px));
margin: 0 auto;
padding: 22px 0 36px;
}
header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-bottom: 16px;
}
h1 {
margin: 0;
font-size: 26px;
line-height: 1.2;
letter-spacing: 0;
}
.subtitle {
margin-top: 6px;
color: var(--muted);
font-size: 13px;
}
.tabs {
display: inline-flex;
margin-top: 10px;
border: 1px solid var(--line);
border-radius: 8px;
overflow: hidden;
background: var(--panel);
}
.tab {
display: inline-flex;
align-items: center;
min-height: 30px;
padding: 6px 12px;
color: var(--muted);
text-decoration: none;
font-size: 13px;
border-right: 1px solid var(--line);
}
.tab:last-child {
border-right: 0;
}
.tab.active {
color: var(--text);
background: var(--panel-soft);
font-weight: 700;
}
.meta {
color: var(--muted);
font-size: 14px;
text-align: right;
}
.status {
display: grid;
grid-template-columns: auto auto;
gap: 5px 10px;
justify-content: end;
font-size: 12px;
line-height: 1.35;
}
.status-label {
color: var(--muted);
text-align: right;
}
.status-value {
color: var(--muted);
text-align: left;
font-variant-numeric: tabular-nums;
}
.stats {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 10px;
margin-bottom: 10px;
}
.stat {
background: var(--panel);
border: 1px solid var(--line);
border-radius: 8px;
padding: 12px 14px;
box-shadow: none;
}
.sort-heading {
color: var(--muted);
text-decoration: none;
}
.sort-heading:hover,
.sort-heading:focus {
color: var(--accent);
}
.stat-label {
color: var(--muted);
font-size: 12px;
line-height: 1.2;
margin-bottom: 7px;
}
.stat-value {
font-size: 20px;
font-weight: 800;
line-height: 1.1;
}
.table-wrap {
overflow-x: auto;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 8px;
box-shadow: var(--shadow);
}
.market-section + .market-section {
margin-top: 18px;
}
.market-heading {
display: flex;
align-items: baseline;
gap: 8px;
margin: 0 0 8px;
font-size: 15px;
line-height: 1.3;
}
.market-count {
color: var(--muted);
font-size: 12px;
font-weight: 400;
}
table {
width: 100%;
border-collapse: collapse;
min-width: 760px;
}
th, td {
padding: 11px 15px;
border-bottom: 1px solid var(--line);
text-align: left;
white-space: nowrap;
font-size: 14px;
}
th:last-child,
td:last-child {
width: 190px;
}
th {
color: var(--muted);
font-weight: 600;
background: var(--panel-soft);
position: sticky;
top: 0;
}
tbody tr:hover { background: #fbfcfd; }
tbody tr:last-child td { border-bottom: 0; }
.symbol {
font-weight: 700;
font-size: 15px;
}
.symbol a {
color: var(--text);
text-decoration: none;
}
.symbol a:hover,
.symbol a:focus {
color: var(--accent);
text-decoration: underline;
}
.badge {
display: inline-flex;
align-items: center;
min-width: 48px;
justify-content: center;
padding: 4px 8px;
border-radius: 6px;
font-weight: 700;
font-size: 13px;
}
.multiple {
font-weight: 800;
color: var(--accent);
}
.bullish {
color: var(--bull);
background: rgba(8, 127, 91, .1);
}
.bearish {
color: var(--bear);
background: rgba(201, 42, 42, .1);
}
.empty {
padding: 44px 16px;
color: var(--muted);
text-align: center;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 8px;
box-shadow: var(--shadow);
}
@media (max-width: 680px) {
main {
width: min(100% - 20px, 1180px);
padding-top: 18px;
}
header {
display: block;
}
h1 {
font-size: 23px;
margin-bottom: 8px;
}
.meta {
text-align: left;
}
.status {
justify-content: start;
}
.stats {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
</style>
</head>
<body>
<main>
<header>
<div>
<h1>Crypto ATR Signal</h1>
<div class="subtitle">
{{ strategy.market }} · {{ strategy.timeframe }} / 大阳 / 大阴 / {{ strategy.atr }} / {{ strategy.threshold }}{% if strategy.body_filter %} / {{ strategy.body_filter }}{% endif %}
</div>
<nav class="tabs" aria-label="市场切换">
{% if page_config.show_all %}<a class="tab {% if market == 'all' %}active{% endif %}" href="/?market=all&sort={{ sort_order }}">全部</a>{% endif %}
{% if page_config.show_crypto %}<a class="tab {% if market == 'crypto' %}active{% endif %}" href="/?market=crypto&sort={{ sort_order }}">Crypto</a>{% endif %}
{% if page_config.show_tradfi %}<a class="tab {% if market == 'tradfi' %}active{% endif %}" href="/?market=tradfi&sort={{ sort_order }}">TradFi</a>{% endif %}
</nav>
</div>
<div class="status" aria-label="系统状态">
<div class="status-label">交易对列表校对:</div>
<div class="status-value">{{ symbol_checked_at }}</div>
<div class="status-label">最新已收盘K线:</div>
<div class="status-value">{{ latest_closed_kline }}</div>
{% if page_config.show_version %}
<div class="status-label">Version</div>
<div class="status-value">{{ app_meta.version }} · {{ app_meta.release_date }} · by {{ app_meta.author }}</div>
{% endif %}
</div>
</header>
<section class="stats" aria-label="信号概览">
<div class="stat">
<div class="stat-label">当前信号</div>
<div class="stat-value">{{ signal_count }}</div>
</div>
<div class="stat">
<div class="stat-label">大阳</div>
<div class="stat-value">{{ bullish_count }}</div>
</div>
<div class="stat">
<div class="stat-label">大阴</div>
<div class="stat-value">{{ bearish_count }}</div>
</div>
<div class="stat">
<div class="stat-label">扫描品种</div>
<div class="stat-value">{{ active_symbols }}</div>
</div>
</section>
{% for group in groups %}
<section class="market-section">
{% if market == 'all' and page_config.group_by_market %}
<h2 class="market-heading">{{ group.label }} <span class="market-count">{{ group.signals|length }} 个信号</span></h2>
{% endif %}
{% if group.signals %}
<div class="table-wrap">
<table>
<thead>
<tr>
<th>币种</th>
<th>方向</th>
<th>ATR</th>
<th>波幅</th>
<th>
<a class="sort-heading" href="/?market={{ market }}&sort={{ next_sort_order }}" title="点击切换 ATR倍数排序">
ATR倍数 {{ sort_indicator }}
</a>
</th>
<th>K线收盘时间</th>
</tr>
</thead>
<tbody>
{% for signal in group.signals %}
<tr>
<td class="symbol">
<a href="{{ signal.tradingview_url }}" rel="noopener noreferrer">
{{ signal.symbol }}
</a>
</td>
<td><span class="badge {{ signal.direction_class }}">{{ signal.direction }}</span></td>
<td>{{ signal.atr14 }}</td>
<td>{{ signal.range }}</td>
<td class="multiple">{{ signal.multiple }}</td>
<td title="{{ signal.time_title }}">{{ signal.close_time_madrid }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="empty">暂无信号</div>
{% endif %}
</section>
{% endfor %}
</main>
</body>
</html>