Add Chinese side label and click-to-zoom review charts.
Crop thumbnails around entry/exit so short trades are visible; lightbox uses a tighter window. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+69
-2
@@ -130,8 +130,26 @@ th { color: var(--muted); font-weight: 600; }
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
min-height: 240px;
|
min-height: 240px;
|
||||||
}
|
}
|
||||||
.chart-box h4 { margin: 0 0 8px; font-size: 13px; color: var(--muted); }
|
.chart-box h4 {
|
||||||
.chart-canvas { width: 100%; height: 240px; display: block; }
|
margin: 0 0 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--muted);
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.chart-zoom-hint {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.chart-canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 240px;
|
||||||
|
display: block;
|
||||||
|
cursor: zoom-in;
|
||||||
|
}
|
||||||
.empty-chart {
|
.empty-chart {
|
||||||
height: 240px;
|
height: 240px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -140,3 +158,52 @@ th { color: var(--muted); font-weight: 600; }
|
|||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chart-lightbox {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
background: rgba(0, 0, 0, 0.72);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
.chart-lightbox[hidden] { display: none !important; }
|
||||||
|
.chart-lightbox-panel {
|
||||||
|
width: min(1100px, 96vw);
|
||||||
|
background: #12121c;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 14px 16px 16px;
|
||||||
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
.chart-lightbox-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.chart-lightbox-title {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.chart-lightbox-close {
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 28px;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
.chart-lightbox-close:hover { color: #fff; }
|
||||||
|
.chart-lightbox-hint { margin: 0 0 10px; font-size: 12px; }
|
||||||
|
.chart-lightbox-canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: min(62vh, 520px);
|
||||||
|
display: block;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #0e0e18;
|
||||||
|
}
|
||||||
|
|||||||
+138
-22
@@ -1,6 +1,7 @@
|
|||||||
/** 复盘四周期:按「包含成交时刻」的 K 线落点,避免偏到下一根 */
|
/** 复盘四周期:进出场落在包含时刻的 K 线;点击可放大 */
|
||||||
(function () {
|
(function () {
|
||||||
var TF_MAX = { M1: 500, M5: 200, M15: 100, H1: 50 };
|
var TF_MAX = { M1: 500, M5: 200, M15: 100, H1: 50 };
|
||||||
|
var TF_ZOOM = { M1: 90, M5: 48, M15: 32, H1: 20 };
|
||||||
var TF_SEC = { M1: 60, M5: 300, M15: 900, H1: 3600 };
|
var TF_SEC = { M1: 60, M5: 300, M15: 900, H1: 3600 };
|
||||||
|
|
||||||
function num(v) {
|
function num(v) {
|
||||||
@@ -9,7 +10,7 @@
|
|||||||
return Number.isFinite(n) ? n : null;
|
return Number.isFinite(n) ? n : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 找到覆盖 ts 的那根 K 线:barOpen <= ts < barOpen+period(最后一根含右边界) */
|
/** 找到覆盖 ts 的那根 K 线:barOpen <= ts < barOpen+period */
|
||||||
function barIndexAt(bars, ts, tf) {
|
function barIndexAt(bars, ts, tf) {
|
||||||
if (ts == null || !bars.length) return -1;
|
if (ts == null || !bars.length) return -1;
|
||||||
var period = TF_SEC[tf] || 60;
|
var period = TF_SEC[tf] || 60;
|
||||||
@@ -23,15 +24,19 @@
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 落在首根之前 / 末根之后:夹到边界
|
|
||||||
if (t < Number(bars[0].ts)) return 0;
|
if (t < Number(bars[0].ts)) return 0;
|
||||||
return bars.length - 1;
|
return bars.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cropBars(bars, markers, tf) {
|
/** 始终以成交为中心裁剪到 maxN,避免短单淹没在全天 K 线里 */
|
||||||
|
function cropBars(bars, markers, tf, maxN) {
|
||||||
if (!bars.length) return bars;
|
if (!bars.length) return bars;
|
||||||
var maxN = TF_MAX[tf] || 100;
|
maxN = maxN || TF_MAX[tf] || 100;
|
||||||
if (bars.length <= maxN) return bars;
|
markers = markers || {};
|
||||||
|
|
||||||
|
if (markers.openTs == null) {
|
||||||
|
return bars.length > maxN ? bars.slice(-maxN) : bars;
|
||||||
|
}
|
||||||
|
|
||||||
var a = barIndexAt(bars, markers.openTs, tf);
|
var a = barIndexAt(bars, markers.openTs, tf);
|
||||||
var b =
|
var b =
|
||||||
@@ -51,7 +56,6 @@
|
|||||||
function fmtBjt(ts) {
|
function fmtBjt(ts) {
|
||||||
if (ts == null) return "";
|
if (ts == null) return "";
|
||||||
var d = new Date(Number(ts) * 1000);
|
var d = new Date(Number(ts) * 1000);
|
||||||
// 用 UTC+8 显示,与复盘页北京时间一致
|
|
||||||
var utc = d.getTime() + d.getTimezoneOffset() * 60000;
|
var utc = d.getTime() + d.getTimezoneOffset() * 60000;
|
||||||
var bjt = new Date(utc + 8 * 3600000);
|
var bjt = new Date(utc + 8 * 3600000);
|
||||||
var hh = String(bjt.getHours()).padStart(2, "0");
|
var hh = String(bjt.getHours()).padStart(2, "0");
|
||||||
@@ -59,14 +63,23 @@
|
|||||||
return hh + ":" + mm;
|
return hh + ":" + mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawCandleChart(canvas, bars, markers, tf) {
|
function sideLabel(side) {
|
||||||
|
var s = (side || "").toLowerCase();
|
||||||
|
if (s === "buy") return "买入(多)";
|
||||||
|
if (s === "sell") return "卖出(空)";
|
||||||
|
return side || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawCandleChart(canvas, bars, markers, tf, opts) {
|
||||||
if (!canvas || !bars || !bars.length) return;
|
if (!canvas || !bars || !bars.length) return;
|
||||||
bars = cropBars(bars, markers || {}, tf);
|
opts = opts || {};
|
||||||
|
var maxN = opts.maxN || TF_MAX[tf] || 100;
|
||||||
|
bars = cropBars(bars, markers || {}, tf, maxN);
|
||||||
markers = markers || {};
|
markers = markers || {};
|
||||||
|
|
||||||
var dpr = window.devicePixelRatio || 1;
|
var dpr = window.devicePixelRatio || 1;
|
||||||
var cssW = canvas.clientWidth || 400;
|
var cssW = canvas.clientWidth || opts.width || 400;
|
||||||
var cssH = canvas.clientHeight || 220;
|
var cssH = canvas.clientHeight || opts.height || 220;
|
||||||
canvas.width = cssW * dpr;
|
canvas.width = cssW * dpr;
|
||||||
canvas.height = cssH * dpr;
|
canvas.height = cssH * dpr;
|
||||||
var ctx = canvas.getContext("2d");
|
var ctx = canvas.getContext("2d");
|
||||||
@@ -75,7 +88,7 @@
|
|||||||
var padL = 4;
|
var padL = 4;
|
||||||
var padR = 4;
|
var padR = 4;
|
||||||
var padT = 4;
|
var padT = 4;
|
||||||
var padB = 16; // 底部时间轴
|
var padB = 16;
|
||||||
|
|
||||||
var min = Infinity;
|
var min = Infinity;
|
||||||
var max = -Infinity;
|
var max = -Infinity;
|
||||||
@@ -112,7 +125,7 @@
|
|||||||
return padL + i * slot + slot * 0.5;
|
return padL + i * slot + slot * 0.5;
|
||||||
};
|
};
|
||||||
|
|
||||||
var bodyW = Math.max(1, Math.min(6, slot * 0.6));
|
var bodyW = Math.max(1, Math.min(opts.zoom ? 10 : 6, slot * 0.6));
|
||||||
bars.forEach(function (b, i) {
|
bars.forEach(function (b, i) {
|
||||||
var x = xOf(i);
|
var x = xOf(i);
|
||||||
var up = b.close >= b.open;
|
var up = b.close >= b.open;
|
||||||
@@ -130,7 +143,6 @@
|
|||||||
ctx.fillRect(x - bodyW / 2, top, bodyW, bh);
|
ctx.fillRect(x - bodyW / 2, top, bodyW, bh);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 底部左右时间(北京时间),方便对照成交时刻
|
|
||||||
ctx.fillStyle = "#888899";
|
ctx.fillStyle = "#888899";
|
||||||
ctx.font = "10px Microsoft YaHei UI, sans-serif";
|
ctx.font = "10px Microsoft YaHei UI, sans-serif";
|
||||||
ctx.textBaseline = "top";
|
ctx.textBaseline = "top";
|
||||||
@@ -154,7 +166,7 @@
|
|||||||
var x = xOf(i);
|
var x = xOf(i);
|
||||||
var y = yOf(price);
|
var y = yOf(price);
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(x, y, 4.5, 0, Math.PI * 2);
|
ctx.arc(x, y, opts.zoom ? 6 : 4.5, 0, Math.PI * 2);
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.lineWidth = 1.5;
|
ctx.lineWidth = 1.5;
|
||||||
@@ -176,7 +188,7 @@
|
|||||||
y = pe.y - 8;
|
y = pe.y - 8;
|
||||||
}
|
}
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(x, y, 4.5, 0, Math.PI * 2);
|
ctx.arc(x, y, opts.zoom ? 6 : 4.5, 0, Math.PI * 2);
|
||||||
ctx.fillStyle = exitColor;
|
ctx.fillStyle = exitColor;
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.lineWidth = 1.5;
|
ctx.lineWidth = 1.5;
|
||||||
@@ -202,15 +214,18 @@
|
|||||||
ctx.fillText("出", px.x, px.y - 6);
|
ctx.fillText("出", px.x, px.y - 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
var meta = canvas.parentElement && canvas.parentElement.querySelector(".chart-meta");
|
var meta =
|
||||||
|
canvas.parentElement && canvas.parentElement.querySelector(".chart-meta");
|
||||||
if (meta) {
|
if (meta) {
|
||||||
|
var sideBit = markers.side ? " · " + sideLabel(markers.side) : "";
|
||||||
meta.textContent =
|
meta.textContent =
|
||||||
bars.length +
|
bars.length +
|
||||||
" 根 · " +
|
" 根 · " +
|
||||||
fmtBjt(bars[0].ts) +
|
fmtBjt(bars[0].ts) +
|
||||||
"–" +
|
"–" +
|
||||||
fmtBjt(bars[n - 1].ts) +
|
fmtBjt(bars[n - 1].ts) +
|
||||||
" 北京时间";
|
" 北京时间" +
|
||||||
|
sideBit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,18 +239,119 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function paintCanvas(el, opts) {
|
||||||
|
var bars = JSON.parse(el.dataset.bars || "[]");
|
||||||
|
var tf = el.dataset.tf || "M1";
|
||||||
|
drawCandleChart(el, bars, readMarkers(el), tf, opts);
|
||||||
|
}
|
||||||
|
|
||||||
function paintAll() {
|
function paintAll() {
|
||||||
document.querySelectorAll("canvas.chart-canvas").forEach(function (el) {
|
document.querySelectorAll("canvas.chart-canvas").forEach(function (el) {
|
||||||
try {
|
try {
|
||||||
var bars = JSON.parse(el.dataset.bars || "[]");
|
paintCanvas(el, {});
|
||||||
var tf = el.dataset.tf || "M1";
|
|
||||||
drawCandleChart(el, bars, readMarkers(el), tf);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ensureLightbox() {
|
||||||
|
var box = document.getElementById("chart-lightbox");
|
||||||
|
if (box) return box;
|
||||||
|
box = document.createElement("div");
|
||||||
|
box.id = "chart-lightbox";
|
||||||
|
box.className = "chart-lightbox";
|
||||||
|
box.hidden = true;
|
||||||
|
box.innerHTML =
|
||||||
|
'<div class="chart-lightbox-panel">' +
|
||||||
|
'<div class="chart-lightbox-head">' +
|
||||||
|
'<span class="chart-lightbox-title"></span>' +
|
||||||
|
'<button type="button" class="chart-lightbox-close" aria-label="关闭">×</button>' +
|
||||||
|
"</div>" +
|
||||||
|
'<p class="muted chart-lightbox-hint">围绕进出场收紧显示 · Esc / 点击遮罩关闭</p>' +
|
||||||
|
'<canvas class="chart-lightbox-canvas"></canvas>' +
|
||||||
|
"</div>";
|
||||||
|
document.body.appendChild(box);
|
||||||
|
|
||||||
|
box.addEventListener("click", function (e) {
|
||||||
|
if (e.target === box) closeLightbox();
|
||||||
|
});
|
||||||
|
box
|
||||||
|
.querySelector(".chart-lightbox-close")
|
||||||
|
.addEventListener("click", closeLightbox);
|
||||||
|
document.addEventListener("keydown", function (e) {
|
||||||
|
if (e.key === "Escape" && !box.hidden) closeLightbox();
|
||||||
|
});
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeLightbox() {
|
||||||
|
var box = document.getElementById("chart-lightbox");
|
||||||
|
if (box) box.hidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openLightbox(srcCanvas) {
|
||||||
|
var box = ensureLightbox();
|
||||||
|
var tf = srcCanvas.dataset.tf || "M1";
|
||||||
|
var markers = readMarkers(srcCanvas);
|
||||||
|
var title = box.querySelector(".chart-lightbox-title");
|
||||||
|
title.textContent =
|
||||||
|
tf +
|
||||||
|
" · " +
|
||||||
|
(markers.side ? sideLabel(markers.side) + " · " : "") +
|
||||||
|
"点击放大";
|
||||||
|
|
||||||
|
var canvas = box.querySelector(".chart-lightbox-canvas");
|
||||||
|
canvas.dataset.tf = tf;
|
||||||
|
canvas.dataset.bars = srcCanvas.dataset.bars;
|
||||||
|
canvas.dataset.openTs = srcCanvas.dataset.openTs || "";
|
||||||
|
canvas.dataset.closeTs = srcCanvas.dataset.closeTs || "";
|
||||||
|
canvas.dataset.openPrice = srcCanvas.dataset.openPrice || "";
|
||||||
|
canvas.dataset.closePrice = srcCanvas.dataset.closePrice || "";
|
||||||
|
canvas.dataset.side = srcCanvas.dataset.side || "";
|
||||||
|
|
||||||
|
box.hidden = false;
|
||||||
|
// 等面板可见后再量宽高
|
||||||
|
requestAnimationFrame(function () {
|
||||||
|
try {
|
||||||
|
drawCandleChart(
|
||||||
|
canvas,
|
||||||
|
JSON.parse(canvas.dataset.bars || "[]"),
|
||||||
|
markers,
|
||||||
|
tf,
|
||||||
|
{ zoom: true, maxN: TF_ZOOM[tf] || 60 }
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("click", function (e) {
|
||||||
|
var canvas = e.target.closest && e.target.closest("canvas.chart-canvas");
|
||||||
|
if (!canvas) return;
|
||||||
|
openLightbox(canvas);
|
||||||
|
});
|
||||||
|
|
||||||
paintAll();
|
paintAll();
|
||||||
window.addEventListener("resize", paintAll);
|
window.addEventListener("resize", function () {
|
||||||
|
paintAll();
|
||||||
|
var box = document.getElementById("chart-lightbox");
|
||||||
|
if (box && !box.hidden) {
|
||||||
|
var canvas = box.querySelector(".chart-lightbox-canvas");
|
||||||
|
if (canvas && canvas.dataset.bars) {
|
||||||
|
try {
|
||||||
|
drawCandleChart(
|
||||||
|
canvas,
|
||||||
|
JSON.parse(canvas.dataset.bars || "[]"),
|
||||||
|
readMarkers(canvas),
|
||||||
|
canvas.dataset.tf || "M1",
|
||||||
|
{ zoom: true, maxN: TF_ZOOM[canvas.dataset.tf] || 60 }
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}复盘 #{{ trade.id }} · {{ app_name }}{% endblock %}
|
{% block title %}复盘 #{{ trade.id }} · {{ app_name }}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% set side_cn = '买入(多)' if trade.side == 'buy' else ('卖出(空)' if trade.side == 'sell' else (trade.side or '—')) %}
|
||||||
|
{% set side_cls = 'green' if trade.side == 'buy' else ('red' if trade.side == 'sell' else 'gray') %}
|
||||||
<p><a href="{{ url_for('records_page') }}">← 返回列表</a></p>
|
<p><a href="{{ url_for('records_page') }}">← 返回列表</a></p>
|
||||||
<h2 style="margin:8px 0 14px">复盘 #{{ trade.id }} · {{ trade.symbol }} · {{ trade.side }}</h2>
|
<h2 style="margin:8px 0 14px">
|
||||||
|
复盘 #{{ trade.id }} · {{ trade.symbol }} ·
|
||||||
|
<span class="tag {{ side_cls }}" style="font-size:15px;vertical-align:middle">{{ side_cn }}</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
<div class="grid cols-2">
|
<div class="grid cols-2">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h3>成交信息</h3>
|
<h3>成交信息</h3>
|
||||||
<table>
|
<table>
|
||||||
|
<tr><th>方向</th><td><span class="tag {{ side_cls }}">{{ side_cn }}</span></td></tr>
|
||||||
<tr><th>账户</th><td>{{ trade.account_name or '—' }}</td></tr>
|
<tr><th>账户</th><td>{{ trade.account_name or '—' }}</td></tr>
|
||||||
<tr><th>机器</th><td>{{ trade.machine_name or '—' }}</td></tr>
|
<tr><th>机器</th><td>{{ trade.machine_name or '—' }}</td></tr>
|
||||||
<tr><th>手数</th><td>{{ trade.volume }}</td></tr>
|
<tr><th>手数</th><td>{{ trade.volume }}</td></tr>
|
||||||
@@ -63,7 +69,8 @@
|
|||||||
<div class="card" style="margin-top:14px">
|
<div class="card" style="margin-top:14px">
|
||||||
<h3>四周期 K 线(M1 / M5 / M15 / H1)</h3>
|
<h3>四周期 K 线(M1 / M5 / M15 / H1)</h3>
|
||||||
<p class="muted">
|
<p class="muted">
|
||||||
显示根数:M1 500 · M5 200 · M15 100 · H1 50。入/出落在<strong>包含成交时刻</strong>的那根 K 线(北京时间)。
|
方向 <span class="tag {{ side_cls }}">{{ side_cn }}</span> ·
|
||||||
|
入/出落在<strong>包含成交时刻</strong>的 K 线 · <strong>点击图可放大</strong>(放大时围绕进出场收紧)。
|
||||||
<span style="color:#4cc2ff">● 入场 {{ trade.open_price|fmt_price }}{% if trade.open_time_fmt %} · {{ trade.open_time_fmt }}{% endif %}</span>
|
<span style="color:#4cc2ff">● 入场 {{ trade.open_price|fmt_price }}{% if trade.open_time_fmt %} · {{ trade.open_time_fmt }}{% endif %}</span>
|
||||||
{% if trade.close_price is not none %}
|
{% if trade.close_price is not none %}
|
||||||
· <span style="color:#f0b429">● 出场 {{ trade.close_price|fmt_price }}{% if trade.close_time_fmt %} · {{ trade.close_time_fmt }}{% endif %}</span>
|
· <span style="color:#f0b429">● 出场 {{ trade.close_price|fmt_price }}{% if trade.close_time_fmt %} · {{ trade.close_time_fmt }}{% endif %}</span>
|
||||||
@@ -72,9 +79,12 @@
|
|||||||
<div class="chart-grid" style="margin-top:10px">
|
<div class="chart-grid" style="margin-top:10px">
|
||||||
{% for tf in ['M1','M5','M15','H1'] %}
|
{% for tf in ['M1','M5','M15','H1'] %}
|
||||||
<div class="chart-box">
|
<div class="chart-box">
|
||||||
<h4>{{ tf }} <span class="chart-meta muted" style="font-weight:400"></span></h4>
|
<h4>{{ tf }} <span class="chart-meta muted" style="font-weight:400"></span>
|
||||||
|
{% if charts[tf] %}<span class="chart-zoom-hint muted">点击放大</span>{% endif %}
|
||||||
|
</h4>
|
||||||
{% if charts[tf] %}
|
{% if charts[tf] %}
|
||||||
<canvas class="chart-canvas" id="chart-{{ tf }}"
|
<canvas class="chart-canvas" id="chart-{{ tf }}"
|
||||||
|
title="点击放大"
|
||||||
data-tf="{{ tf }}"
|
data-tf="{{ tf }}"
|
||||||
data-bars='{{ charts[tf]|tojson }}'
|
data-bars='{{ charts[tf]|tojson }}'
|
||||||
data-open-ts="{{ trade.open_time or '' }}"
|
data-open-ts="{{ trade.open_time or '' }}"
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{{ t.id }}</td>
|
<td>{{ t.id }}</td>
|
||||||
<td>{{ t.symbol }}</td>
|
<td>{{ t.symbol }}</td>
|
||||||
<td><span class="tag {% if t.side=='buy' %}green{% else %}red{% endif %}">{{ t.side }}</span></td>
|
<td><span class="tag {% if t.side=='buy' %}green{% else %}red{% endif %}">{% if t.side=='buy' %}买入{% elif t.side=='sell' %}卖出{% else %}{{ t.side }}{% endif %}</span></td>
|
||||||
<td>{{ t.volume }}</td>
|
<td>{{ t.volume }}</td>
|
||||||
<td>{{ t.open_price|fmt_price }}</td>
|
<td>{{ t.open_price|fmt_price }}</td>
|
||||||
<td>{{ t.close_price|fmt_price }}</td>
|
<td>{{ t.close_price|fmt_price }}</td>
|
||||||
|
|||||||
Reference in New Issue
Block a user