fix: OKX manual orders save entry_model for trade record 开仓类型
OKX add_order omitted entry_model on insert; align with Binance/Gate and add trade_style fallback when resolving entry_reason for close and display. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -183,6 +183,7 @@ from lib.trade.entry_model_lib import (
|
|||||||
order_entry_template_context,
|
order_entry_template_context,
|
||||||
open_position_button_label,
|
open_position_button_label,
|
||||||
parse_manual_order_style_fields,
|
parse_manual_order_style_fields,
|
||||||
|
resolve_effective_trade_entry_reason,
|
||||||
resolve_trade_record_entry_reason,
|
resolve_trade_record_entry_reason,
|
||||||
trend_manual_entry_reason_count,
|
trend_manual_entry_reason_count,
|
||||||
)
|
)
|
||||||
@@ -2105,8 +2106,20 @@ def to_effective_trade_dict(row):
|
|||||||
item["effective_pnl_amount"] = get_effective_trade_field(row, "reviewed_pnl_amount", "pnl_amount", item.get("pnl_amount"))
|
item["effective_pnl_amount"] = get_effective_trade_field(row, "reviewed_pnl_amount", "pnl_amount", item.get("pnl_amount"))
|
||||||
item["effective_hold_minutes"] = get_effective_trade_field(row, "reviewed_hold_minutes", "hold_minutes", item.get("hold_minutes"))
|
item["effective_hold_minutes"] = get_effective_trade_field(row, "reviewed_hold_minutes", "hold_minutes", item.get("hold_minutes"))
|
||||||
item["effective_hold_seconds"] = get_effective_trade_field(row, "reviewed_hold_seconds", "hold_seconds", item.get("hold_seconds"))
|
item["effective_hold_seconds"] = get_effective_trade_field(row, "reviewed_hold_seconds", "hold_seconds", item.get("hold_seconds"))
|
||||||
er_eff = get_effective_trade_field(row, "reviewed_entry_reason", "entry_reason", item.get("entry_reason"))
|
try:
|
||||||
item["effective_entry_reason"] = (str(er_eff).strip() if er_eff is not None else "") or ""
|
_er_keys = row.keys() if hasattr(row, "keys") else []
|
||||||
|
except Exception:
|
||||||
|
_er_keys = []
|
||||||
|
reviewed_er = row["reviewed_entry_reason"] if "reviewed_entry_reason" in _er_keys else None
|
||||||
|
item["effective_entry_reason"] = resolve_effective_trade_entry_reason(
|
||||||
|
reviewed_entry_reason=reviewed_er,
|
||||||
|
entry_reason=item.get("entry_reason"),
|
||||||
|
key_signal_type=(item.get("key_signal_type") or "").strip() or None,
|
||||||
|
monitor_type=item.get("monitor_type"),
|
||||||
|
trade_style=item.get("trade_style"),
|
||||||
|
entry_reason_from_key_signal=entry_reason_from_key_signal,
|
||||||
|
entry_reason_for_monitor_type=entry_reason_for_monitor_type,
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
_keys = row.keys() if hasattr(row, "keys") else []
|
_keys = row.keys() if hasattr(row, "keys") else []
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -2642,6 +2655,7 @@ def insert_trade_record(
|
|||||||
entry_model=entry_model,
|
entry_model=entry_model,
|
||||||
key_signal_type=kst,
|
key_signal_type=kst,
|
||||||
monitor_type=monitor_type,
|
monitor_type=monitor_type,
|
||||||
|
trade_style=trade_style,
|
||||||
entry_reason_from_key_signal=entry_reason_from_key_signal,
|
entry_reason_from_key_signal=entry_reason_from_key_signal,
|
||||||
entry_reason_for_monitor_type=entry_reason_for_monitor_type,
|
entry_reason_for_monitor_type=entry_reason_for_monitor_type,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ from lib.trade.entry_model_lib import (
|
|||||||
order_entry_template_context,
|
order_entry_template_context,
|
||||||
open_position_button_label,
|
open_position_button_label,
|
||||||
parse_manual_order_style_fields,
|
parse_manual_order_style_fields,
|
||||||
|
resolve_effective_trade_entry_reason,
|
||||||
resolve_trade_record_entry_reason,
|
resolve_trade_record_entry_reason,
|
||||||
trend_manual_entry_reason_count,
|
trend_manual_entry_reason_count,
|
||||||
)
|
)
|
||||||
@@ -2064,8 +2065,20 @@ def to_effective_trade_dict(row):
|
|||||||
item["effective_pnl_amount"] = get_effective_trade_field(row, "reviewed_pnl_amount", "pnl_amount", item.get("pnl_amount"))
|
item["effective_pnl_amount"] = get_effective_trade_field(row, "reviewed_pnl_amount", "pnl_amount", item.get("pnl_amount"))
|
||||||
item["effective_hold_minutes"] = get_effective_trade_field(row, "reviewed_hold_minutes", "hold_minutes", item.get("hold_minutes"))
|
item["effective_hold_minutes"] = get_effective_trade_field(row, "reviewed_hold_minutes", "hold_minutes", item.get("hold_minutes"))
|
||||||
item["effective_hold_seconds"] = get_effective_trade_field(row, "reviewed_hold_seconds", "hold_seconds", item.get("hold_seconds"))
|
item["effective_hold_seconds"] = get_effective_trade_field(row, "reviewed_hold_seconds", "hold_seconds", item.get("hold_seconds"))
|
||||||
er_eff = get_effective_trade_field(row, "reviewed_entry_reason", "entry_reason", item.get("entry_reason"))
|
try:
|
||||||
item["effective_entry_reason"] = (str(er_eff).strip() if er_eff is not None else "") or ""
|
_er_keys = row.keys() if hasattr(row, "keys") else []
|
||||||
|
except Exception:
|
||||||
|
_er_keys = []
|
||||||
|
reviewed_er = row["reviewed_entry_reason"] if "reviewed_entry_reason" in _er_keys else None
|
||||||
|
item["effective_entry_reason"] = resolve_effective_trade_entry_reason(
|
||||||
|
reviewed_entry_reason=reviewed_er,
|
||||||
|
entry_reason=item.get("entry_reason"),
|
||||||
|
key_signal_type=(item.get("key_signal_type") or "").strip() or None,
|
||||||
|
monitor_type=item.get("monitor_type"),
|
||||||
|
trade_style=item.get("trade_style"),
|
||||||
|
entry_reason_from_key_signal=entry_reason_from_key_signal,
|
||||||
|
entry_reason_for_monitor_type=entry_reason_for_monitor_type,
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
_keys = row.keys() if hasattr(row, "keys") else []
|
_keys = row.keys() if hasattr(row, "keys") else []
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -2358,6 +2371,7 @@ def insert_trade_record(
|
|||||||
entry_model=entry_model,
|
entry_model=entry_model,
|
||||||
key_signal_type=kst,
|
key_signal_type=kst,
|
||||||
monitor_type=monitor_type,
|
monitor_type=monitor_type,
|
||||||
|
trade_style=trade_style,
|
||||||
entry_reason_from_key_signal=entry_reason_from_key_signal,
|
entry_reason_from_key_signal=entry_reason_from_key_signal,
|
||||||
entry_reason_for_monitor_type=entry_reason_for_monitor_type,
|
entry_reason_for_monitor_type=entry_reason_for_monitor_type,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ from lib.trade.entry_model_lib import (
|
|||||||
order_entry_template_context,
|
order_entry_template_context,
|
||||||
open_position_button_label,
|
open_position_button_label,
|
||||||
parse_manual_order_style_fields,
|
parse_manual_order_style_fields,
|
||||||
|
resolve_effective_trade_entry_reason,
|
||||||
resolve_trade_record_entry_reason,
|
resolve_trade_record_entry_reason,
|
||||||
trend_manual_entry_reason_count,
|
trend_manual_entry_reason_count,
|
||||||
)
|
)
|
||||||
@@ -2012,8 +2013,20 @@ def to_effective_trade_dict(row):
|
|||||||
item["effective_pnl_amount"] = get_effective_trade_field(row, "reviewed_pnl_amount", "pnl_amount", item.get("pnl_amount"))
|
item["effective_pnl_amount"] = get_effective_trade_field(row, "reviewed_pnl_amount", "pnl_amount", item.get("pnl_amount"))
|
||||||
item["effective_hold_minutes"] = get_effective_trade_field(row, "reviewed_hold_minutes", "hold_minutes", item.get("hold_minutes"))
|
item["effective_hold_minutes"] = get_effective_trade_field(row, "reviewed_hold_minutes", "hold_minutes", item.get("hold_minutes"))
|
||||||
item["effective_hold_seconds"] = get_effective_trade_field(row, "reviewed_hold_seconds", "hold_seconds", item.get("hold_seconds"))
|
item["effective_hold_seconds"] = get_effective_trade_field(row, "reviewed_hold_seconds", "hold_seconds", item.get("hold_seconds"))
|
||||||
er_eff = get_effective_trade_field(row, "reviewed_entry_reason", "entry_reason", item.get("entry_reason"))
|
try:
|
||||||
item["effective_entry_reason"] = (str(er_eff).strip() if er_eff is not None else "") or ""
|
_er_keys = row.keys() if hasattr(row, "keys") else []
|
||||||
|
except Exception:
|
||||||
|
_er_keys = []
|
||||||
|
reviewed_er = row["reviewed_entry_reason"] if "reviewed_entry_reason" in _er_keys else None
|
||||||
|
item["effective_entry_reason"] = resolve_effective_trade_entry_reason(
|
||||||
|
reviewed_entry_reason=reviewed_er,
|
||||||
|
entry_reason=item.get("entry_reason"),
|
||||||
|
key_signal_type=(item.get("key_signal_type") or "").strip() or None,
|
||||||
|
monitor_type=item.get("monitor_type"),
|
||||||
|
trade_style=item.get("trade_style"),
|
||||||
|
entry_reason_from_key_signal=entry_reason_from_key_signal,
|
||||||
|
entry_reason_for_monitor_type=entry_reason_for_monitor_type,
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
_keys = row.keys() if hasattr(row, "keys") else []
|
_keys = row.keys() if hasattr(row, "keys") else []
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -2253,6 +2266,7 @@ def insert_trade_record(
|
|||||||
entry_model=entry_model,
|
entry_model=entry_model,
|
||||||
key_signal_type=kst,
|
key_signal_type=kst,
|
||||||
monitor_type=monitor_type,
|
monitor_type=monitor_type,
|
||||||
|
trade_style=trade_style,
|
||||||
entry_reason_from_key_signal=entry_reason_from_key_signal,
|
entry_reason_from_key_signal=entry_reason_from_key_signal,
|
||||||
entry_reason_for_monitor_type=entry_reason_for_monitor_type,
|
entry_reason_for_monitor_type=entry_reason_for_monitor_type,
|
||||||
)
|
)
|
||||||
@@ -7984,10 +7998,10 @@ def add_order():
|
|||||||
tc_en = 0
|
tc_en = 0
|
||||||
tc_en, tc_h, tc_at = time_close_insert_values(tc_en, tc_h, opened_at_ms)
|
tc_en, tc_h, tc_at = time_close_insert_values(tc_en, tc_h, opened_at_ms)
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"INSERT INTO order_monitors (symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, margin_capital, leverage, trade_style, risk_percent, risk_amount, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type, time_close_enabled, time_close_hours, time_close_at_ms) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
"INSERT INTO order_monitors (symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, margin_capital, leverage, trade_style, entry_model, risk_percent, risk_amount, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type, time_close_enabled, time_close_hours, time_close_at_ms) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||||
(
|
(
|
||||||
symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,
|
symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,
|
||||||
margin_capital, leverage, trade_style, risk_percent_db, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,
|
margin_capital, leverage, trade_style, entry_model, risk_percent_db, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,
|
||||||
breakeven_enabled,
|
breakeven_enabled,
|
||||||
notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day, "下单监控",
|
notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day, "下单监控",
|
||||||
tc_en, tc_h, tc_at,
|
tc_en, tc_h, tc_at,
|
||||||
|
|||||||
@@ -290,6 +290,7 @@ def resolve_trade_record_entry_reason(
|
|||||||
entry_model: Optional[str] = None,
|
entry_model: Optional[str] = None,
|
||||||
key_signal_type: Optional[str] = None,
|
key_signal_type: Optional[str] = None,
|
||||||
monitor_type: Optional[str] = None,
|
monitor_type: Optional[str] = None,
|
||||||
|
trade_style: Optional[str] = None,
|
||||||
entry_reason_from_key_signal=None,
|
entry_reason_from_key_signal=None,
|
||||||
entry_reason_for_monitor_type=None,
|
entry_reason_for_monitor_type=None,
|
||||||
) -> str:
|
) -> str:
|
||||||
@@ -308,9 +309,38 @@ def resolve_trade_record_entry_reason(
|
|||||||
from_mt = (entry_reason_for_monitor_type(monitor_type) or "").strip()
|
from_mt = (entry_reason_for_monitor_type(monitor_type) or "").strip()
|
||||||
if from_mt:
|
if from_mt:
|
||||||
return from_mt
|
return from_mt
|
||||||
|
ts = (trade_style or "").strip().lower()
|
||||||
|
if ts in ("trend", "swing"):
|
||||||
|
return trade_style_label_zh(ts)
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_effective_trade_entry_reason(
|
||||||
|
*,
|
||||||
|
reviewed_entry_reason: Optional[str] = None,
|
||||||
|
entry_reason: Optional[str] = None,
|
||||||
|
entry_model: Optional[str] = None,
|
||||||
|
key_signal_type: Optional[str] = None,
|
||||||
|
monitor_type: Optional[str] = None,
|
||||||
|
trade_style: Optional[str] = None,
|
||||||
|
entry_reason_from_key_signal=None,
|
||||||
|
entry_reason_for_monitor_type=None,
|
||||||
|
) -> str:
|
||||||
|
"""交易记录展示/导出用:复盘优先,再回落 entry_model / 关键位 / 策略 / trade_style。"""
|
||||||
|
for raw in (reviewed_entry_reason, entry_reason):
|
||||||
|
er = (raw or "").strip()
|
||||||
|
if er:
|
||||||
|
return er
|
||||||
|
return 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,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def enrich_entry_model_display(item: dict) -> dict:
|
def enrich_entry_model_display(item: dict) -> dict:
|
||||||
code = normalize_entry_model_code(item.get("entry_model"))
|
code = normalize_entry_model_code(item.get("entry_model"))
|
||||||
if code:
|
if code:
|
||||||
|
|||||||
@@ -127,6 +127,12 @@ class TestEntryModelLib(unittest.TestCase):
|
|||||||
er2 = resolve_trade_record_entry_reason(entry_model=ENTRY_MODEL_LAUNCH_A)
|
er2 = resolve_trade_record_entry_reason(entry_model=ENTRY_MODEL_LAUNCH_A)
|
||||||
self.assertEqual(er2, "启动A")
|
self.assertEqual(er2, "启动A")
|
||||||
|
|
||||||
|
def test_resolve_entry_reason_trade_style_fallback(self):
|
||||||
|
er = resolve_trade_record_entry_reason(trade_style="swing")
|
||||||
|
self.assertEqual(er, "波段单")
|
||||||
|
er2 = resolve_trade_record_entry_reason(trade_style="trend")
|
||||||
|
self.assertEqual(er2, "趋势单")
|
||||||
|
|
||||||
def test_build_trend_div_journal_options(self):
|
def test_build_trend_div_journal_options(self):
|
||||||
opts = build_trend_div_entry_reason_options(("趋势回调",))
|
opts = build_trend_div_entry_reason_options(("趋势回调",))
|
||||||
self.assertEqual(opts[:5], ("启动A", "启动B", "大分歧A", "大分歧B", "小分歧"))
|
self.assertEqual(opts[:5], ("启动A", "启动B", "大分歧A", "大分歧B", "小分歧"))
|
||||||
|
|||||||
Reference in New Issue
Block a user