Show tablet trade records as close-record table with action column.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+103
-69
@@ -181,33 +181,16 @@
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.records-trade-actions {
|
||||
display: none;
|
||||
align-items: center;
|
||||
gap: .3rem;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.records-trade-verify-form {
|
||||
display: inline-flex;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.records-trade-actions .btn-link,
|
||||
.records-trade-actions a,
|
||||
.records-trade-actions button {
|
||||
font-size: .72rem;
|
||||
padding: .3rem .5rem;
|
||||
border-radius: 6px;
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
.records-trade-row-actions {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.records-trade-actions .btn-link {
|
||||
.records-trade-row-actions .btn-link {
|
||||
background: transparent;
|
||||
color: var(--accent);
|
||||
}
|
||||
@@ -218,6 +201,76 @@
|
||||
margin-top: .35rem;
|
||||
}
|
||||
|
||||
.records-phone-only,
|
||||
.records-tablet-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 平板交易记录表格(对齐数据看板平仓记录) */
|
||||
.records-trade-table-wrap {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.records-trade-table-wrap .dashboard-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: .82rem;
|
||||
}
|
||||
|
||||
.records-trade-table-wrap .dashboard-table th,
|
||||
.records-trade-table-wrap .dashboard-table td {
|
||||
padding: .45rem .55rem;
|
||||
border-bottom: 1px solid var(--table-border);
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
font-variant-numeric: tabular-nums;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.records-trade-table-wrap .dashboard-table tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.records-trade-table-wrap .dash-symbol-ex {
|
||||
font-weight: 400;
|
||||
font-size: .78rem;
|
||||
}
|
||||
|
||||
.records-trade-table-wrap .dash-main-badge {
|
||||
font-size: .68rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.records-trade-table-wrap .dashboard-table .badge.dir-long,
|
||||
.records-trade-table-wrap .dashboard-table .badge.dir-short {
|
||||
font-size: .72rem;
|
||||
}
|
||||
|
||||
.records-trade-table-wrap .dashboard-table .badge.dir-long {
|
||||
background: var(--profit-bg);
|
||||
color: var(--profit);
|
||||
}
|
||||
|
||||
.records-trade-table-wrap .dashboard-table .badge.dir-short {
|
||||
background: var(--loss-bg);
|
||||
color: var(--loss);
|
||||
}
|
||||
|
||||
.records-trade-table-wrap .pnl-pos {
|
||||
color: var(--profit);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.records-trade-table-wrap .pnl-neg {
|
||||
color: var(--loss);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.records-trade-table-wrap .trade-actions {
|
||||
min-width: 17rem;
|
||||
}
|
||||
|
||||
html:is([data-mobile="1"], .layout-phone) .records-trade-row,
|
||||
html:is([data-layout="phone"], .layout-phone) .records-trade-row {
|
||||
cursor: pointer;
|
||||
@@ -229,56 +282,18 @@ html:is([data-layout="phone"], .layout-phone) .records-trade-row:hover {
|
||||
box-shadow: 0 0 0 1px rgba(56, 189, 248, .2);
|
||||
}
|
||||
|
||||
/* 平板横屏:单行 + 右侧操作 */
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: .5rem .65rem;
|
||||
padding: .5rem .65rem;
|
||||
overflow: hidden;
|
||||
html:is([data-mobile="1"], .layout-phone) .records-page .records-phone-only,
|
||||
html:is([data-layout="phone"], .layout-phone) .records-page .records-phone-only,
|
||||
html:is([data-mobile="1"], .layout-phone) .records-page .records-review-mobile,
|
||||
html:is([data-layout="phone"], .layout-phone) .records-page .records-review-mobile {
|
||||
display: block;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-main {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: .55rem .75rem;
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-page .records-tablet-only {
|
||||
display: block;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-head {
|
||||
margin-bottom: 0;
|
||||
flex: 0 1 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-symbol {
|
||||
font-size: .84rem;
|
||||
max-width: 6.5rem;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-summary {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: .76rem;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-actions {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-phone-foot {
|
||||
display: none;
|
||||
}
|
||||
|
||||
html:is([data-mobile="1"], .layout-phone) .records-page .records-mobile-list,
|
||||
html:is([data-layout="phone"], .layout-phone) .records-page .records-mobile-list,
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-page .records-mobile-list {
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-page .records-review-mobile {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -293,11 +308,29 @@ html:is([data-layout="phone"], .layout-phone) .records-page .records-trade-card
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-page .records-trade-card .card-body,
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-page .records-split .card .card-body {
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-page .records-trade-card .card-body {
|
||||
padding: 0 .75rem .35rem;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-table-wrap .dashboard-table {
|
||||
font-size: .78rem;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-table-wrap .dashboard-table th,
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-table-wrap .dashboard-table td {
|
||||
padding: .4rem .45rem;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-table-wrap .trade-actions {
|
||||
min-width: 15.5rem;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-table-wrap .trade-actions a,
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-table-wrap .trade-actions button {
|
||||
font-size: .68rem;
|
||||
padding: .28rem .45rem;
|
||||
}
|
||||
|
||||
html:is([data-mobile="1"], .layout-phone) .records-page .records-equity-card #equity-curve-chart,
|
||||
html:is([data-layout="phone"], .layout-phone) .records-page .records-equity-card #equity-curve-chart {
|
||||
min-height: 180px;
|
||||
@@ -336,6 +369,7 @@ html:is([data-layout="phone"], .layout-phone) #review-modal .review-detail-value
|
||||
}
|
||||
|
||||
@media (pointer: coarse) and (max-width: 600px) {
|
||||
.records-page .records-mobile-list { display: block; }
|
||||
.records-page .records-phone-only,
|
||||
.records-page .records-review-mobile { display: block; }
|
||||
.records-page .records-desktop-only { display: none !important; }
|
||||
}
|
||||
|
||||
+21
-17
@@ -12,11 +12,6 @@
|
||||
return String(v).replace('T', ' ').slice(0, 16);
|
||||
}
|
||||
|
||||
function isTabletLayout() {
|
||||
var root = document.documentElement;
|
||||
return root.dataset.layout === 'tablet' || root.classList.contains('layout-tablet');
|
||||
}
|
||||
|
||||
function showTradeModal(data) {
|
||||
var mask = document.getElementById('trade-detail-modal');
|
||||
var body = document.getElementById('trade-detail-modal-body');
|
||||
@@ -53,7 +48,7 @@
|
||||
|
||||
html += '<div class="records-detail-actions">';
|
||||
if (data.fill_review_url) {
|
||||
html += '<a href="' + data.fill_review_url + '" class="btn-fill">复盘</a>';
|
||||
html += '<a href="' + data.fill_review_url + '" class="btn-fill">填入复盘</a>';
|
||||
}
|
||||
if (data.del_url) {
|
||||
html += '<a href="' + data.del_url + '" class="btn-del" onclick="return confirm(\'删除?\')">删除</a>';
|
||||
@@ -64,6 +59,13 @@
|
||||
mask.classList.add('show');
|
||||
}
|
||||
|
||||
function openRowDetail(row) {
|
||||
if (!row) return;
|
||||
try {
|
||||
showTradeModal(JSON.parse(row.getAttribute('data-trade')));
|
||||
} catch (err) { /* ignore */ }
|
||||
}
|
||||
|
||||
function bindTradeModal() {
|
||||
var mask = document.getElementById('trade-detail-modal');
|
||||
if (!mask) return;
|
||||
@@ -77,18 +79,20 @@
|
||||
if (e.target === mask) mask.classList.remove('show');
|
||||
});
|
||||
|
||||
var list = document.getElementById('records-trade-mobile');
|
||||
if (!list) return;
|
||||
var phoneList = document.getElementById('records-trade-mobile');
|
||||
if (phoneList) {
|
||||
phoneList.addEventListener('click', function (e) {
|
||||
openRowDetail(e.target.closest('.records-trade-row'));
|
||||
});
|
||||
}
|
||||
|
||||
list.addEventListener('click', function (e) {
|
||||
if (e.target.closest('.records-trade-actions')) return;
|
||||
var row = e.target.closest('.records-trade-row');
|
||||
if (!row) return;
|
||||
if (isTabletLayout() && !e.target.closest('.records-trade-detail-btn')) return;
|
||||
try {
|
||||
showTradeModal(JSON.parse(row.getAttribute('data-trade')));
|
||||
} catch (err) { /* ignore */ }
|
||||
});
|
||||
var tabletWrap = document.querySelector('.records-trade-table-wrap');
|
||||
if (tabletWrap) {
|
||||
tabletWrap.addEventListener('click', function (e) {
|
||||
if (!e.target.closest('.records-tablet-detail-btn')) return;
|
||||
openRowDetail(e.target.closest('tr[data-trade]'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function bootRecordsPage() {
|
||||
|
||||
+109
-49
@@ -5,6 +5,75 @@
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/records.css') }}?v={{ asset_v }}">
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% macro trade_detail_json(t) -%}
|
||||
{{ {
|
||||
"symbol": t.symbol_name or t.symbol,
|
||||
"symbol_code": t.symbol,
|
||||
"monitor_type": t.monitor_type,
|
||||
"source": "柜台" if t.source == "ctp" else "本地",
|
||||
"direction": "做多" if t.direction == "long" else "做空",
|
||||
"entry_price": t.entry_price,
|
||||
"close_price": t.close_price,
|
||||
"stop_loss": t.stop_loss,
|
||||
"take_profit": t.take_profit,
|
||||
"lots": t.lots,
|
||||
"margin": t.margin,
|
||||
"margin_pct": t.margin_pct,
|
||||
"holding_minutes": t.holding_minutes or 0,
|
||||
"open_time": t.open_time,
|
||||
"close_time": t.close_time,
|
||||
"pnl": t.pnl,
|
||||
"fee": t.fee,
|
||||
"pnl_net": t.pnl_net,
|
||||
"equity_after": t.equity_after,
|
||||
"result": t.result,
|
||||
"verified": t.verified,
|
||||
"fill_review_url": url_for("fill_review_from_trade", tid=t.id),
|
||||
"del_url": url_for("del_trade", tid=t.id)
|
||||
} | tojson }}
|
||||
{%- endmacro %}
|
||||
{% macro trade_symbol_cell(t) %}
|
||||
<div class="dash-symbol-cell">
|
||||
<div class="dash-symbol-title">
|
||||
{{ t.symbol_name or t.symbol }}
|
||||
{% if t.symbol_exchange %}<span class="dash-symbol-ex text-muted">{{ t.symbol_exchange }}</span>{% endif %}
|
||||
{% if t.symbol_is_main %}<span class="badge planned dash-main-badge">主力</span>{% endif %}
|
||||
{% if t.symbol and (t.symbol_name or '')|lower != (t.symbol or '')|lower %}
|
||||
<span class="text-accent">{{ t.symbol }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
{% macro trade_pnl_cell(v) %}
|
||||
{% if v is not none %}{% set n = v|float %}<span class="{% if n > 0 %}pnl-pos{% elif n < 0 %}pnl-neg{% endif %}">{{ ('+' if n > 0 else '') ~ ('%.2f'|format(n)) }} 元</span>{% else %}—{% endif %}
|
||||
{% endmacro %}
|
||||
{% macro trade_verify_form(t) %}
|
||||
<form method="post" action="{{ url_for('update_trade', tid=t.id) }}" class="records-trade-verify-form">
|
||||
<input type="hidden" name="symbol_name" value="{{ t.symbol_name or t.symbol }}">
|
||||
<input type="hidden" name="monitor_type" value="{{ t.monitor_type }}">
|
||||
<input type="hidden" name="direction" value="{{ t.direction }}">
|
||||
<input type="hidden" name="entry_price" value="{{ t.entry_price }}">
|
||||
<input type="hidden" name="stop_loss" value="{{ t.stop_loss }}">
|
||||
<input type="hidden" name="take_profit" value="{{ t.take_profit }}">
|
||||
<input type="hidden" name="close_price" value="{{ t.close_price or '' }}">
|
||||
<input type="hidden" name="lots" value="{{ t.lots }}">
|
||||
<input type="hidden" name="margin" value="{{ t.margin or '' }}">
|
||||
<input type="hidden" name="holding_minutes" value="{{ t.holding_minutes or 0 }}">
|
||||
<input type="hidden" name="open_time" value="{{ t.open_time or '' }}">
|
||||
<input type="hidden" name="close_time" value="{{ t.close_time or '' }}">
|
||||
<input type="hidden" name="pnl" value="{{ t.pnl or '' }}">
|
||||
<input type="hidden" name="result" value="{{ t.result }}">
|
||||
<button type="submit" class="btn-verify" {% if t.verified %}disabled{% endif %}>核对修改</button>
|
||||
</form>
|
||||
{% endmacro %}
|
||||
{% macro trade_row_actions(t, detail_class) %}
|
||||
<div class="trade-actions records-trade-row-actions">
|
||||
<button type="button" class="btn-link {{ detail_class }}">详情</button>
|
||||
<a href="{{ url_for('fill_review_from_trade', tid=t.id) }}" class="btn-fill">填入复盘</a>
|
||||
{{ trade_verify_form(t) }}
|
||||
<a href="{{ url_for('del_trade', tid=t.id) }}" class="btn-del" onclick="return confirm('删除?')">删除</a>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
<div class="records-page">
|
||||
<div class="card records-equity-card" style="margin-bottom:1.25rem">
|
||||
<h2>资金曲线</h2>
|
||||
@@ -28,37 +97,12 @@
|
||||
<input type="checkbox" id="trade-edit-switch">
|
||||
<span>修改/核对开关(开启后可编辑关键字段)</span>
|
||||
</label>
|
||||
<div class="records-mobile-list" id="records-trade-mobile">
|
||||
<div class="records-mobile-list records-phone-only" id="records-trade-mobile">
|
||||
{% for t in trades %}
|
||||
{% set trade_pnl = t.pnl_net if t.pnl_net is not none else t.pnl %}
|
||||
{% set trade_px = t.close_price if t.close_price else t.entry_price %}
|
||||
{% set pnl_cls = 'is-profit' if trade_pnl and trade_pnl > 0 else ('is-loss' if trade_pnl and trade_pnl < 0 else 'is-flat') %}
|
||||
<div class="records-trade-row" data-trade-id="{{ t.id }}" data-trade='{{ {
|
||||
"symbol": t.symbol_name or t.symbol,
|
||||
"symbol_code": t.symbol,
|
||||
"monitor_type": t.monitor_type,
|
||||
"source": "柜台" if t.source == "ctp" else "本地",
|
||||
"direction": "做多" if t.direction == "long" else "做空",
|
||||
"entry_price": t.entry_price,
|
||||
"close_price": t.close_price,
|
||||
"stop_loss": t.stop_loss,
|
||||
"take_profit": t.take_profit,
|
||||
"lots": t.lots,
|
||||
"margin": t.margin,
|
||||
"margin_pct": t.margin_pct,
|
||||
"holding_minutes": t.holding_minutes or 0,
|
||||
"open_time": t.open_time,
|
||||
"close_time": t.close_time,
|
||||
"pnl": t.pnl,
|
||||
"fee": t.fee,
|
||||
"pnl_net": t.pnl_net,
|
||||
"equity_after": t.equity_after,
|
||||
"result": t.result,
|
||||
"verified": t.verified,
|
||||
"fill_review_url": url_for("fill_review_from_trade", tid=t.id),
|
||||
"del_url": url_for("del_trade", tid=t.id),
|
||||
"verify_url": url_for("update_trade", tid=t.id)
|
||||
} | tojson }}'>
|
||||
<div class="records-trade-row" data-trade-id="{{ t.id }}" data-trade='{{ trade_detail_json(t)|trim }}'>
|
||||
<div class="records-trade-main">
|
||||
<div class="records-trade-head">
|
||||
<span class="records-trade-title">
|
||||
@@ -75,28 +119,6 @@
|
||||
盈亏 <span class="records-mobile-pnl {{ pnl_cls }}">{{ trade_pnl if trade_pnl is not none else '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="records-trade-actions">
|
||||
<button type="button" class="btn-link records-trade-detail-btn">详情</button>
|
||||
<a href="{{ url_for('fill_review_from_trade', tid=t.id) }}" class="btn-fill">复盘</a>
|
||||
<form method="post" action="{{ url_for('update_trade', tid=t.id) }}" class="records-trade-verify-form">
|
||||
<input type="hidden" name="symbol_name" value="{{ t.symbol_name or t.symbol }}">
|
||||
<input type="hidden" name="monitor_type" value="{{ t.monitor_type }}">
|
||||
<input type="hidden" name="direction" value="{{ t.direction }}">
|
||||
<input type="hidden" name="entry_price" value="{{ t.entry_price }}">
|
||||
<input type="hidden" name="stop_loss" value="{{ t.stop_loss }}">
|
||||
<input type="hidden" name="take_profit" value="{{ t.take_profit }}">
|
||||
<input type="hidden" name="close_price" value="{{ t.close_price or '' }}">
|
||||
<input type="hidden" name="lots" value="{{ t.lots }}">
|
||||
<input type="hidden" name="margin" value="{{ t.margin or '' }}">
|
||||
<input type="hidden" name="holding_minutes" value="{{ t.holding_minutes or 0 }}">
|
||||
<input type="hidden" name="open_time" value="{{ t.open_time or '' }}">
|
||||
<input type="hidden" name="close_time" value="{{ t.close_time or '' }}">
|
||||
<input type="hidden" name="pnl" value="{{ t.pnl or '' }}">
|
||||
<input type="hidden" name="result" value="{{ t.result }}">
|
||||
<button type="submit" class="btn-verify" {% if t.verified %}disabled{% endif %}>{% if t.verified %}已核对{% else %}核对{% endif %}</button>
|
||||
</form>
|
||||
<a href="{{ url_for('del_trade', tid=t.id) }}" class="btn-del" onclick="return confirm('删除?')">删除</a>
|
||||
</div>
|
||||
<div class="records-trade-phone-foot">
|
||||
<span class="records-mobile-chevron">详情 ›</span>
|
||||
</div>
|
||||
@@ -105,6 +127,44 @@
|
||||
<p class="records-mobile-empty">暂无交易记录</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="card-scroll records-trade-table-wrap records-tablet-only">
|
||||
<table class="dashboard-table records-trade-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>品种</th>
|
||||
<th>方向</th>
|
||||
<th>手数</th>
|
||||
<th>开仓</th>
|
||||
<th>平仓</th>
|
||||
<th>盈亏</th>
|
||||
<th>净盈亏</th>
|
||||
<th>平仓时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for t in trades %}
|
||||
<tr data-trade-id="{{ t.id }}" data-trade='{{ trade_detail_json(t)|trim }}'>
|
||||
<td>{{ trade_symbol_cell(t) }}</td>
|
||||
<td>
|
||||
<span class="badge dir {% if t.direction == 'long' %}dir-long{% else %}dir-short{% endif %}">
|
||||
{{ '做多' if t.direction == 'long' else '做空' }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{% if t.lots is not none %}{{ '%.2f'|format(t.lots|float) }}{% else %}—{% endif %}</td>
|
||||
<td>{% if t.entry_price is not none %}{{ '%.2f'|format(t.entry_price|float) }}{% else %}—{% endif %}</td>
|
||||
<td>{% if t.close_price is not none %}{{ '%.2f'|format(t.close_price|float) }}{% elif t.entry_price is not none %}{{ '%.2f'|format(t.entry_price|float) }}{% else %}—{% endif %}</td>
|
||||
<td>{{ trade_pnl_cell(t.pnl) }}</td>
|
||||
<td>{{ trade_pnl_cell(t.pnl_net) }}</td>
|
||||
<td>{{ (t.close_time or '')[:16].replace('T', ' ') or '—' }}</td>
|
||||
<td>{{ trade_row_actions(t, 'records-tablet-detail-btn') }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="9" class="text-muted">暂无交易记录</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="trade-table-wrap records-desktop-only">
|
||||
<table class="trade-table">
|
||||
<thead>
|
||||
|
||||
@@ -77,6 +77,21 @@ def purge_duplicate_local_trade_logs(conn) -> int:
|
||||
return removed
|
||||
|
||||
|
||||
def _attach_symbol_meta(t: dict[str, Any]) -> None:
|
||||
try:
|
||||
from symbols import position_symbol_meta
|
||||
|
||||
sym = (t.get("symbol") or "").strip()
|
||||
meta = position_symbol_meta(sym)
|
||||
if not t.get("symbol_name"):
|
||||
t["symbol_name"] = meta.get("name") or sym
|
||||
t["symbol_exchange"] = meta.get("exchange") or ""
|
||||
t["symbol_is_main"] = bool(meta.get("is_main"))
|
||||
except Exception:
|
||||
t.setdefault("symbol_exchange", "")
|
||||
t.setdefault("symbol_is_main", False)
|
||||
|
||||
|
||||
def enrich_trades_for_records(
|
||||
trades: list[dict[str, Any]],
|
||||
*,
|
||||
@@ -92,6 +107,7 @@ def enrich_trades_for_records(
|
||||
curve: list[dict[str, Any]] = []
|
||||
|
||||
for t in chrono:
|
||||
_attach_symbol_meta(t)
|
||||
pnl_net = float(t.get("pnl_net") or 0)
|
||||
eq = t.get("equity_after")
|
||||
if eq is None:
|
||||
|
||||
Reference in New Issue
Block a user