Split journal order type from entry reason and fix review edit toggle in embed shell.
Adds order_type to journal uploads, removes legacy swing/trend labels from entry reason options, and ensures review-edit buttons sync when the records tab loads dynamically. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
"""复盘表单:下单类型与开仓类型校验(三所共用)."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Optional, Sequence, Tuple
|
||||
|
||||
from lib.strategy.strategy_trade_labels import (
|
||||
JOURNAL_ORDER_TYPE_OPTIONS,
|
||||
STRATEGY_ENTRY_REASON_OPTIONS,
|
||||
normalize_journal_order_type,
|
||||
)
|
||||
from lib.trade.entry_model_lib import (
|
||||
TRADE_STYLE_FALLBACK_ENTRY_REASONS,
|
||||
normalize_review_entry_reason,
|
||||
)
|
||||
|
||||
_LEGACY_JOURNAL_ENTRY_REASONS: Tuple[str, ...] = (
|
||||
*TRADE_STYLE_FALLBACK_ENTRY_REASONS,
|
||||
*STRATEGY_ENTRY_REASON_OPTIONS,
|
||||
)
|
||||
|
||||
|
||||
def normalize_journal_entry_reason(
|
||||
raw: Optional[str],
|
||||
allowed: Sequence[str],
|
||||
*,
|
||||
allow_legacy: bool = False,
|
||||
) -> str:
|
||||
s = normalize_review_entry_reason(raw, allowed)
|
||||
if s:
|
||||
return s
|
||||
if not allow_legacy:
|
||||
return ""
|
||||
legacy = (raw or "").strip()
|
||||
if legacy in _LEGACY_JOURNAL_ENTRY_REASONS:
|
||||
return legacy
|
||||
return ""
|
||||
|
||||
|
||||
def journal_entry_reason_valid(raw: Optional[str], allowed: Sequence[str]) -> bool:
|
||||
return bool(normalize_journal_entry_reason(raw, allowed, allow_legacy=False))
|
||||
|
||||
|
||||
def journal_order_type_valid(raw: Optional[str]) -> bool:
|
||||
return bool(normalize_journal_order_type(raw))
|
||||
@@ -1,5 +1,6 @@
|
||||
<script>
|
||||
const JOURNAL_ENTRY_REASON_OPTIONS = {{ entry_reason_options | tojson }};
|
||||
const JOURNAL_ORDER_TYPE_OPTIONS = {{ order_type_options | tojson }};
|
||||
|
||||
function reloadInstancePage(){
|
||||
if(document.body && document.body.getAttribute("data-embed-shell") === "1" && window.InstanceEmbed){
|
||||
@@ -12,6 +13,11 @@ function reloadInstancePage(){
|
||||
function validateJournalEntryReason(){
|
||||
const form = document.getElementById("journal-form");
|
||||
if(!form) return true;
|
||||
const orderSel = form.querySelector('[name="order_type"]');
|
||||
if(!orderSel || !orderSel.value){
|
||||
alert("请选择下单类型");
|
||||
return false;
|
||||
}
|
||||
const sel = form.querySelector('[name="entry_reason"]');
|
||||
if(!sel || !sel.value){
|
||||
alert("请选择开仓类型");
|
||||
@@ -147,6 +153,10 @@ function normalizeBeijingDatetimeString(v){
|
||||
}
|
||||
|
||||
function toggleReviewMode(){
|
||||
if(window.InstanceTheme && typeof InstanceTheme.syncReviewEditButtons === "function"){
|
||||
InstanceTheme.syncReviewEditButtons();
|
||||
return;
|
||||
}
|
||||
const on = !!(document.getElementById("review-mode-toggle") || {}).checked;
|
||||
document.querySelectorAll(".review-edit-btn").forEach(btn=>{
|
||||
btn.disabled = !on;
|
||||
@@ -537,11 +547,18 @@ function fillJournalFromTrade(t){
|
||||
setJournalField("early_exit_note", "");
|
||||
const kst = String(t.key_signal_type || "").trim();
|
||||
const mt = String(t.monitor_type || "").trim();
|
||||
if(mt === "趋势回调" && JOURNAL_ENTRY_REASON_OPTIONS.includes("趋势回调")){
|
||||
setJournalField("entry_reason", "趋势回调");
|
||||
} else if(mt === "顺势加仓" && JOURNAL_ENTRY_REASON_OPTIONS.includes("顺势加仓")){
|
||||
setJournalField("entry_reason", "顺势加仓");
|
||||
} else if(t.effective_entry_reason && JOURNAL_ENTRY_REASON_OPTIONS.includes(t.effective_entry_reason)){
|
||||
const orderType = (function(){
|
||||
if(mt === "趋势回调" && JOURNAL_ORDER_TYPE_OPTIONS.includes("趋势回调")) return "趋势回调";
|
||||
if(mt === "顺势加仓" && JOURNAL_ORDER_TYPE_OPTIONS.includes("顺势加仓")) return "顺势加仓";
|
||||
if(mt === "关键位监控" || mt.includes("关键位")) return "关键位监控";
|
||||
return "下单监控";
|
||||
})();
|
||||
if(JOURNAL_ORDER_TYPE_OPTIONS.includes(orderType)){
|
||||
setJournalField("order_type", orderType);
|
||||
} else {
|
||||
setJournalField("order_type", "");
|
||||
}
|
||||
if(t.effective_entry_reason && JOURNAL_ENTRY_REASON_OPTIONS.includes(t.effective_entry_reason)){
|
||||
setJournalField("entry_reason", t.effective_entry_reason);
|
||||
} else {
|
||||
const erFromKey = KEY_ENTRY_REASON_BY_SIGNAL[kst] || "";
|
||||
@@ -554,7 +571,7 @@ function fillJournalFromTrade(t){
|
||||
const er = String(t.result || "").trim();
|
||||
const exitTrigMap = { 止盈: "止盈", 保本止盈: "保本止盈", 移动止盈: "移动止盈", 时间平仓: "时间平仓", 强制清仓: "强制清仓", 手动平仓: "手动平仓", 止损: "止损" };
|
||||
if(exitTrigMap[er]) setJournalField("early_exit_trigger", exitTrigMap[er]);
|
||||
const note = `来自交易记录自动填充:${t.symbol || "-"} ${t.direction || "-"} | 入场:${entryPx || "-"} 止损:${slPx || "-"} 止盈:${tpPx || "-"} | 类型:${t.monitor_type || "-"}`;
|
||||
const note = `来自交易记录自动填充:${t.symbol || "-"} ${t.direction || "-"} | 入场:${entryPx || "-"} 止损:${slPx || "-"} 止盈:${tpPx || "-"} | 下单类型:${orderType || t.monitor_type || "-"}`;
|
||||
setJournalField("note", note);
|
||||
const form = document.getElementById("journal-form");
|
||||
if(form && typeof form.scrollIntoView === "function"){
|
||||
@@ -632,8 +649,12 @@ if(document.getElementById("review-list")) loadReviews();
|
||||
const reviewToggle = document.getElementById("review-mode-toggle");
|
||||
if(reviewToggle){
|
||||
reviewToggle.addEventListener("change", toggleReviewMode);
|
||||
reviewToggle.addEventListener("input", toggleReviewMode);
|
||||
toggleReviewMode();
|
||||
}
|
||||
if(window.InstanceTheme && typeof InstanceTheme.initReviewEditModeSync === "function"){
|
||||
InstanceTheme.initReviewEditModeSync();
|
||||
}
|
||||
const journalForm = document.getElementById("journal-form");
|
||||
if(journalForm){
|
||||
const pnlInput = journalForm.querySelector('[name="pnl"]');
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<tr><th>品种</th><th>类型</th><th>开仓类型</th><th>方向</th><th>成交</th><th>止损(开仓)</th><th>止盈</th><th>基数</th><th>杠杆</th><th>持仓分钟</th><th>开仓时间(北京)</th><th>平仓时间(北京)</th><th>盈亏U</th><th>结果</th><th>操作</th></tr>
|
||||
<tr><th>品种</th><th>下单类型</th><th>开仓类型</th><th>方向</th><th>成交</th><th>止损(开仓)</th><th>止盈</th><th>基数</th><th>杠杆</th><th>持仓分钟</th><th>开仓时间(北京)</th><th>平仓时间(北京)</th><th>盈亏U</th><th>结果</th><th>操作</th></tr>
|
||||
{% for r in record %}
|
||||
<tr id="trade-row-{{ r.id }}">
|
||||
{% set pnl_val = (r.pnl_amount or 0)|float %}
|
||||
@@ -309,7 +309,7 @@
|
||||
<input type="hidden" name="exit_price_hint" id="exit-price-hint">
|
||||
<input type="hidden" name="direction_hint" id="direction-hint">
|
||||
{% from 'journal_form_fields.html' import journal_form_fields %}
|
||||
{{ journal_form_fields(entry_reason_options) }}
|
||||
{{ journal_form_fields(entry_reason_options, order_type_options) }}
|
||||
{% from 'journal_upload_slots.html' import journal_upload_slots %}
|
||||
{{ journal_upload_slots() }}
|
||||
<div class="form-row journal-chart-options" style="flex-wrap:wrap;align-items:center">
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<script src="/static/instance_theme.js?v=49"></script>
|
||||
<script src="/static/instance_theme.js?v=50"></script>
|
||||
<link rel="stylesheet" href="/static/instance_theme_early.css?v=4">
|
||||
<link rel="stylesheet" href="/static/account_risk_badge.css?v=4">
|
||||
<link rel="stylesheet" href="/static/instance_page.css?v=4">
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=75">
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=76">
|
||||
<script src="/static/account_risk_badge.js?v=4"></script>
|
||||
<meta name="theme-color" content="#0b0d14">
|
||||
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
|
||||
@@ -83,7 +83,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/instance_ui.js?v=7"></script>
|
||||
<script src="/static/instance_ui.js?v=8"></script>
|
||||
<script src="/static/journal_upload_slots.js?v=3"></script>
|
||||
<script src="/static/instance_records_mobile.js?v=2"></script>
|
||||
<script src="/static/time_close_ui.js?v=3"></script>
|
||||
@@ -105,6 +105,6 @@ window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
|
||||
</script>
|
||||
<script src="/static/instance_settings_prefs.js?v=12"></script>
|
||||
<script src="/static/instance_live.js?v=4"></script>
|
||||
<script src="/static/instance_embed.js?v=21"></script>
|
||||
<script src="/static/instance_embed.js?v=22"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<script src="/static/instance_theme.js?v=49"></script>
|
||||
<script src="/static/instance_theme.js?v=50"></script>
|
||||
<link rel="stylesheet" href="/static/instance_theme_early.css?v=4">
|
||||
<link rel="stylesheet" href="/static/account_risk_badge.css?v=4">
|
||||
<script src="/static/account_risk_badge.js?v=4"></script>
|
||||
@@ -17,7 +17,7 @@
|
||||
<link rel="manifest" href="/static/icons/manifest.webmanifest">
|
||||
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
|
||||
<link rel="stylesheet" href="/static/instance_page.css?v=1">
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=75">
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=76">
|
||||
|
||||
</head>
|
||||
<body
|
||||
@@ -309,7 +309,7 @@
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<tr><th>品种</th><th>类型</th><th>开仓类型</th><th>方向</th><th>成交</th><th>止损(开仓)</th><th>止盈</th><th>基数</th><th>杠杆</th><th>持仓分钟</th><th>开仓时间(北京)</th><th>平仓时间(北京)</th><th>盈亏U</th><th>结果</th><th>操作</th></tr>
|
||||
<tr><th>品种</th><th>下单类型</th><th>开仓类型</th><th>方向</th><th>成交</th><th>止损(开仓)</th><th>止盈</th><th>基数</th><th>杠杆</th><th>持仓分钟</th><th>开仓时间(北京)</th><th>平仓时间(北京)</th><th>盈亏U</th><th>结果</th><th>操作</th></tr>
|
||||
{% for r in record %}
|
||||
<tr id="trade-row-{{ r.id }}">
|
||||
{% set pnl_val = (r.pnl_amount or 0)|float %}
|
||||
@@ -391,7 +391,7 @@
|
||||
<input type="hidden" name="exit_price_hint" id="exit-price-hint">
|
||||
<input type="hidden" name="direction_hint" id="direction-hint">
|
||||
{% from 'journal_form_fields.html' import journal_form_fields %}
|
||||
{{ journal_form_fields(entry_reason_options) }}
|
||||
{{ journal_form_fields(entry_reason_options, order_type_options) }}
|
||||
{% from 'journal_upload_slots.html' import journal_upload_slots %}
|
||||
{{ journal_upload_slots() }}
|
||||
<div class="form-row journal-chart-options" style="flex-wrap:wrap;align-items:center">
|
||||
@@ -542,7 +542,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/instance_ui.js?v=7"></script>
|
||||
<script src="/static/instance_ui.js?v=8"></script>
|
||||
<script src="/static/journal_upload_slots.js?v=3"></script>
|
||||
<script src="/static/instance_records_mobile.js?v=2"></script>
|
||||
<script src="/static/time_close_ui.js?v=3"></script>
|
||||
@@ -559,10 +559,16 @@ const ORDER_ENTRY_MODEL_CODE_TO_CATEGORY = {{ entry_model_code_to_category | toj
|
||||
<script src="/static/strategy_roll.js?v=6"></script>
|
||||
<script>
|
||||
const JOURNAL_ENTRY_REASON_OPTIONS = {{ entry_reason_options | tojson }};
|
||||
const JOURNAL_ORDER_TYPE_OPTIONS = {{ order_type_options | tojson }};
|
||||
|
||||
function validateJournalEntryReason(){
|
||||
const form = document.getElementById("journal-form");
|
||||
if(!form) return true;
|
||||
const orderSel = form.querySelector('[name="order_type"]');
|
||||
if(!orderSel || !orderSel.value){
|
||||
alert("请选择下单类型");
|
||||
return false;
|
||||
}
|
||||
const sel = form.querySelector('[name="entry_reason"]');
|
||||
if(!sel || !sel.value){
|
||||
alert("请选择开仓类型");
|
||||
@@ -698,6 +704,10 @@ function normalizeBeijingDatetimeString(v){
|
||||
}
|
||||
|
||||
function toggleReviewMode(){
|
||||
if(window.InstanceTheme && typeof InstanceTheme.syncReviewEditButtons === "function"){
|
||||
InstanceTheme.syncReviewEditButtons();
|
||||
return;
|
||||
}
|
||||
const on = !!(document.getElementById("review-mode-toggle") || {}).checked;
|
||||
document.querySelectorAll(".review-edit-btn").forEach(btn=>{
|
||||
btn.disabled = !on;
|
||||
@@ -1088,11 +1098,18 @@ function fillJournalFromTrade(t){
|
||||
setJournalField("early_exit_note", "");
|
||||
const kst = String(t.key_signal_type || "").trim();
|
||||
const mt = String(t.monitor_type || "").trim();
|
||||
if(mt === "趋势回调" && JOURNAL_ENTRY_REASON_OPTIONS.includes("趋势回调")){
|
||||
setJournalField("entry_reason", "趋势回调");
|
||||
} else if(mt === "顺势加仓" && JOURNAL_ENTRY_REASON_OPTIONS.includes("顺势加仓")){
|
||||
setJournalField("entry_reason", "顺势加仓");
|
||||
} else if(t.effective_entry_reason && JOURNAL_ENTRY_REASON_OPTIONS.includes(t.effective_entry_reason)){
|
||||
const orderType = (function(){
|
||||
if(mt === "趋势回调" && JOURNAL_ORDER_TYPE_OPTIONS.includes("趋势回调")) return "趋势回调";
|
||||
if(mt === "顺势加仓" && JOURNAL_ORDER_TYPE_OPTIONS.includes("顺势加仓")) return "顺势加仓";
|
||||
if(mt === "关键位监控" || mt.includes("关键位")) return "关键位监控";
|
||||
return "下单监控";
|
||||
})();
|
||||
if(JOURNAL_ORDER_TYPE_OPTIONS.includes(orderType)){
|
||||
setJournalField("order_type", orderType);
|
||||
} else {
|
||||
setJournalField("order_type", "");
|
||||
}
|
||||
if(t.effective_entry_reason && JOURNAL_ENTRY_REASON_OPTIONS.includes(t.effective_entry_reason)){
|
||||
setJournalField("entry_reason", t.effective_entry_reason);
|
||||
} else {
|
||||
const erFromKey = KEY_ENTRY_REASON_BY_SIGNAL[kst] || "";
|
||||
@@ -1105,7 +1122,7 @@ function fillJournalFromTrade(t){
|
||||
const er = String(t.result || "").trim();
|
||||
const exitTrigMap = { 止盈: "止盈", 保本止盈: "保本止盈", 移动止盈: "移动止盈", 时间平仓: "时间平仓", 强制清仓: "强制清仓", 手动平仓: "手动平仓", 止损: "止损" };
|
||||
if(exitTrigMap[er]) setJournalField("early_exit_trigger", exitTrigMap[er]);
|
||||
const note = `来自交易记录自动填充:${t.symbol || "-"} ${t.direction || "-"} | 入场:${entryPx || "-"} 止损:${slPx || "-"} 止盈:${tpPx || "-"} | 类型:${t.monitor_type || "-"}`;
|
||||
const note = `来自交易记录自动填充:${t.symbol || "-"} ${t.direction || "-"} | 入场:${entryPx || "-"} 止损:${slPx || "-"} 止盈:${tpPx || "-"} | 下单类型:${orderType || t.monitor_type || "-"}`;
|
||||
setJournalField("note", note);
|
||||
const form = document.getElementById("journal-form");
|
||||
if(form && typeof form.scrollIntoView === "function"){
|
||||
@@ -1170,8 +1187,12 @@ if(document.getElementById("review-list")) loadReviews();
|
||||
const reviewToggle = document.getElementById("review-mode-toggle");
|
||||
if(reviewToggle){
|
||||
reviewToggle.addEventListener("change", toggleReviewMode);
|
||||
reviewToggle.addEventListener("input", toggleReviewMode);
|
||||
toggleReviewMode();
|
||||
}
|
||||
if(window.InstanceTheme && typeof InstanceTheme.initReviewEditModeSync === "function"){
|
||||
InstanceTheme.initReviewEditModeSync();
|
||||
}
|
||||
const journalForm = document.getElementById("journal-form");
|
||||
if(journalForm){
|
||||
const pnlInput = journalForm.querySelector('[name="pnl"]');
|
||||
|
||||
Reference in New Issue
Block a user