feat: show entry type as category/subtype (反转/启动A)
Format持仓与交易记录开仓类型为两级展示;新平仓写入与旧短标签自动展开。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -185,6 +185,7 @@ from lib.trade.entry_model_lib import (
|
||||
open_position_button_label,
|
||||
parse_manual_order_style_fields,
|
||||
resolve_effective_trade_entry_reason,
|
||||
format_entry_type_display,
|
||||
resolve_trade_record_entry_reason,
|
||||
trend_manual_entry_reason_count,
|
||||
)
|
||||
@@ -2115,6 +2116,7 @@ def to_effective_trade_dict(row):
|
||||
item["effective_entry_reason"] = resolve_effective_trade_entry_reason(
|
||||
reviewed_entry_reason=reviewed_er,
|
||||
entry_reason=item.get("entry_reason"),
|
||||
entry_model=item.get("entry_model"),
|
||||
key_signal_type=(item.get("key_signal_type") or "").strip() or None,
|
||||
monitor_type=item.get("monitor_type"),
|
||||
trade_style=item.get("trade_style"),
|
||||
@@ -8856,7 +8858,11 @@ def export_trade_records():
|
||||
er0 = (r["entry_reason"] or "").strip() if r["entry_reason"] else ""
|
||||
er1 = (r["reviewed_entry_reason"] or "").strip() if r["reviewed_entry_reason"] else ""
|
||||
kst = (r["key_signal_type"] or "").strip() if "key_signal_type" in r.keys() else ""
|
||||
eff = er1 or er0 or entry_reason_from_key_signal(kst) or ""
|
||||
eff = format_entry_type_display(
|
||||
er1 or er0 or entry_reason_from_key_signal(kst) or "",
|
||||
entry_model=r["entry_model"] if "entry_model" in r.keys() else None,
|
||||
trade_style=r["trade_style"] if "trade_style" in r.keys() else None,
|
||||
)
|
||||
snap = r["initial_stop_loss"] if r["initial_stop_loss"] not in (None, "") else r["stop_loss"]
|
||||
data.append((
|
||||
r["id"], r["symbol"], r["monitor_type"], kst, r["direction"], r["trigger_price"],
|
||||
|
||||
@@ -185,6 +185,7 @@ from lib.trade.entry_model_lib import (
|
||||
open_position_button_label,
|
||||
parse_manual_order_style_fields,
|
||||
resolve_effective_trade_entry_reason,
|
||||
format_entry_type_display,
|
||||
resolve_trade_record_entry_reason,
|
||||
trend_manual_entry_reason_count,
|
||||
)
|
||||
@@ -2075,6 +2076,7 @@ def to_effective_trade_dict(row):
|
||||
item["effective_entry_reason"] = resolve_effective_trade_entry_reason(
|
||||
reviewed_entry_reason=reviewed_er,
|
||||
entry_reason=item.get("entry_reason"),
|
||||
entry_model=item.get("entry_model"),
|
||||
key_signal_type=(item.get("key_signal_type") or "").strip() or None,
|
||||
monitor_type=item.get("monitor_type"),
|
||||
trade_style=item.get("trade_style"),
|
||||
@@ -8751,7 +8753,11 @@ def export_trade_records():
|
||||
er0 = (r["entry_reason"] or "").strip() if r["entry_reason"] else ""
|
||||
er1 = (r["reviewed_entry_reason"] or "").strip() if r["reviewed_entry_reason"] else ""
|
||||
kst = (r["key_signal_type"] or "").strip() if "key_signal_type" in r.keys() else ""
|
||||
eff = er1 or er0 or entry_reason_from_key_signal(kst) or ""
|
||||
eff = format_entry_type_display(
|
||||
er1 or er0 or entry_reason_from_key_signal(kst) or "",
|
||||
entry_model=r["entry_model"] if "entry_model" in r.keys() else None,
|
||||
trade_style=r["trade_style"] if "trade_style" in r.keys() else None,
|
||||
)
|
||||
snap = r["initial_stop_loss"] if r["initial_stop_loss"] not in (None, "") else r["stop_loss"]
|
||||
data.append((
|
||||
r["id"], r["symbol"], r["monitor_type"], kst, r["direction"], r["trigger_price"],
|
||||
|
||||
@@ -183,6 +183,7 @@ from lib.trade.entry_model_lib import (
|
||||
open_position_button_label,
|
||||
parse_manual_order_style_fields,
|
||||
resolve_effective_trade_entry_reason,
|
||||
format_entry_type_display,
|
||||
resolve_trade_record_entry_reason,
|
||||
trend_manual_entry_reason_count,
|
||||
)
|
||||
@@ -2022,6 +2023,7 @@ def to_effective_trade_dict(row):
|
||||
item["effective_entry_reason"] = resolve_effective_trade_entry_reason(
|
||||
reviewed_entry_reason=reviewed_er,
|
||||
entry_reason=item.get("entry_reason"),
|
||||
entry_model=item.get("entry_model"),
|
||||
key_signal_type=(item.get("key_signal_type") or "").strip() or None,
|
||||
monitor_type=item.get("monitor_type"),
|
||||
trade_style=item.get("trade_style"),
|
||||
@@ -8276,7 +8278,11 @@ def export_trade_records():
|
||||
er0 = (r["entry_reason"] or "").strip() if r["entry_reason"] else ""
|
||||
er1 = (r["reviewed_entry_reason"] or "").strip() if r["reviewed_entry_reason"] else ""
|
||||
kst = (r["key_signal_type"] or "").strip() if "key_signal_type" in r.keys() else ""
|
||||
eff = er1 or er0 or entry_reason_from_key_signal(kst) or ""
|
||||
eff = format_entry_type_display(
|
||||
er1 or er0 or entry_reason_from_key_signal(kst) or "",
|
||||
entry_model=r["entry_model"] if "entry_model" in r.keys() else None,
|
||||
trade_style=r["trade_style"] if "trade_style" in r.keys() else None,
|
||||
)
|
||||
snap = r["initial_stop_loss"] if r["initial_stop_loss"] not in (None, "") else r["stop_loss"]
|
||||
data.append((
|
||||
r["id"], r["symbol"], r["monitor_type"], kst, r["direction"], r["trigger_price"],
|
||||
|
||||
@@ -10,6 +10,7 @@ from lib.strategy.strategy_trade_labels import (
|
||||
entry_reason_for_monitor_type,
|
||||
)
|
||||
from lib.trade.time_close_lib import TIME_CLOSE_RESULT
|
||||
from lib.trade.entry_model_lib import format_entry_type_display
|
||||
|
||||
TRADE_COMPLETED_RESULTS = (
|
||||
"止盈",
|
||||
@@ -132,7 +133,13 @@ def display_entry_type_label(d: dict) -> str:
|
||||
label = effective_entry_type(d).strip()
|
||||
if not label:
|
||||
return "—"
|
||||
return _normalize_monitor_type_label(label) or label
|
||||
formatted = format_entry_type_display(
|
||||
label,
|
||||
entry_model=d.get("entry_model"),
|
||||
trade_style=d.get("trade_style"),
|
||||
)
|
||||
out = _normalize_monitor_type_label(formatted) or formatted
|
||||
return out or "—"
|
||||
|
||||
|
||||
def effective_hold_minutes(
|
||||
|
||||
@@ -223,6 +223,55 @@ def entry_model_label(code: Optional[str]) -> str:
|
||||
return _CODE_TO_LABEL.get(c, "")
|
||||
|
||||
|
||||
def entry_category_display_prefix(category: str) -> str:
|
||||
"""两级展示用的一级前缀:反转 / 顺势 / 波段单(含日内)。"""
|
||||
cat = (category or "").strip()
|
||||
if cat in (ENTRY_CATEGORY_SWING, ENTRY_CATEGORY_INTRADAY):
|
||||
return "波段单"
|
||||
return ENTRY_CATEGORY_LABELS.get(cat, "")
|
||||
|
||||
|
||||
def entry_model_display_label(code: Optional[str]) -> str:
|
||||
"""两级展示:反转/启动A、顺势/大分歧A、波段单/小分歧、波段单/假破。"""
|
||||
c = normalize_entry_model_code(code)
|
||||
if not c:
|
||||
return ""
|
||||
label = entry_model_label(c)
|
||||
if not label:
|
||||
return ""
|
||||
prefix = entry_category_display_prefix(entry_model_category(c))
|
||||
if prefix:
|
||||
return f"{prefix}/{label}"
|
||||
return label
|
||||
|
||||
|
||||
def format_entry_type_display(
|
||||
text: Optional[str] = None,
|
||||
*,
|
||||
entry_model: Optional[str] = None,
|
||||
trade_style: Optional[str] = None,
|
||||
) -> str:
|
||||
"""交易记录/持仓展示:已知 entry_model 或短标签 → 两级文案。"""
|
||||
if entry_model:
|
||||
disp = entry_model_display_label(entry_model)
|
||||
if disp:
|
||||
return disp
|
||||
raw = (text or "").strip()
|
||||
if not raw:
|
||||
ts = (trade_style or "").strip().lower()
|
||||
if ts in ("trend", "swing"):
|
||||
return trade_style_label_zh(ts)
|
||||
return ""
|
||||
if "/" in raw:
|
||||
return raw
|
||||
code = normalize_entry_model_code(raw)
|
||||
if code:
|
||||
disp = entry_model_display_label(code)
|
||||
if disp:
|
||||
return disp
|
||||
return raw
|
||||
|
||||
|
||||
def trade_style_for_entry_model(code: Optional[str]) -> str:
|
||||
c = normalize_entry_model_code(code)
|
||||
return _CODE_TO_STYLE.get(c, "trend")
|
||||
@@ -297,7 +346,7 @@ def resolve_trade_record_entry_reason(
|
||||
er = (entry_reason or "").strip()
|
||||
if er:
|
||||
return er
|
||||
label = entry_model_label(entry_model)
|
||||
label = entry_model_display_label(entry_model)
|
||||
if label:
|
||||
return label
|
||||
kst = (key_signal_type or "").strip()
|
||||
@@ -330,14 +379,22 @@ def resolve_effective_trade_entry_reason(
|
||||
for raw in (reviewed_entry_reason, entry_reason):
|
||||
er = (raw or "").strip()
|
||||
if er:
|
||||
return er
|
||||
return resolve_trade_record_entry_reason(
|
||||
return format_entry_type_display(
|
||||
er,
|
||||
entry_model=entry_model,
|
||||
trade_style=trade_style,
|
||||
)
|
||||
return format_entry_type_display(
|
||||
resolve_trade_record_entry_reason(
|
||||
entry_model=entry_model,
|
||||
key_signal_type=key_signal_type,
|
||||
monitor_type=monitor_type,
|
||||
trade_style=trade_style,
|
||||
entry_reason_from_key_signal=entry_reason_from_key_signal,
|
||||
entry_reason_for_monitor_type=entry_reason_for_monitor_type,
|
||||
),
|
||||
entry_model=entry_model,
|
||||
key_signal_type=key_signal_type,
|
||||
monitor_type=monitor_type,
|
||||
trade_style=trade_style,
|
||||
entry_reason_from_key_signal=entry_reason_from_key_signal,
|
||||
entry_reason_for_monitor_type=entry_reason_for_monitor_type,
|
||||
)
|
||||
|
||||
|
||||
@@ -345,7 +402,7 @@ def enrich_entry_model_display(item: dict) -> dict:
|
||||
code = normalize_entry_model_code(item.get("entry_model"))
|
||||
if code:
|
||||
item["entry_model"] = code
|
||||
item["entry_model_label"] = entry_model_label(code)
|
||||
item["entry_model_label"] = entry_model_display_label(code)
|
||||
cat = entry_model_category(code)
|
||||
if cat:
|
||||
item["entry_model_category"] = cat
|
||||
|
||||
@@ -11,7 +11,9 @@ from lib.trade.entry_model_lib import (
|
||||
build_trend_div_entry_reason_options,
|
||||
entry_model_categories,
|
||||
entry_model_category,
|
||||
entry_model_display_label,
|
||||
entry_model_label,
|
||||
format_entry_type_display,
|
||||
hub_meta_entry_context,
|
||||
intraday_entry_model_options,
|
||||
is_intraday_trading_profile,
|
||||
@@ -123,9 +125,16 @@ class TestEntryModelLib(unittest.TestCase):
|
||||
|
||||
def test_resolve_entry_reason_from_model(self):
|
||||
er = resolve_trade_record_entry_reason(entry_model=ENTRY_MODEL_BIG_DIV_B)
|
||||
self.assertEqual(er, "大分歧B")
|
||||
self.assertEqual(er, "顺势/大分歧B")
|
||||
er2 = resolve_trade_record_entry_reason(entry_model=ENTRY_MODEL_LAUNCH_A)
|
||||
self.assertEqual(er2, "启动A")
|
||||
self.assertEqual(er2, "反转/启动A")
|
||||
|
||||
def test_entry_model_display_label(self):
|
||||
self.assertEqual(entry_model_display_label(ENTRY_MODEL_LAUNCH_A), "反转/启动A")
|
||||
self.assertEqual(entry_model_display_label(ENTRY_MODEL_SMALL_DIV), "波段单/小分歧")
|
||||
self.assertEqual(entry_model_display_label("liquidity_false_break"), "波段单/假破")
|
||||
self.assertEqual(format_entry_type_display("启动A"), "反转/启动A")
|
||||
self.assertEqual(entry_model_label(ENTRY_MODEL_LAUNCH_B), "启动B")
|
||||
|
||||
def test_resolve_entry_reason_trade_style_fallback(self):
|
||||
er = resolve_trade_record_entry_reason(trade_style="swing")
|
||||
|
||||
Reference in New Issue
Block a user