#!/usr/bin/env python3 """Patch binance/okx/gate app.py for entry_model support.""" from __future__ import annotations import os import re REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) IMPORT_BLOCK = """from lib.trade.entry_model_lib import ( build_intraday_entry_reason_options, build_trend_div_entry_reason_options, enrich_entry_model_display, migrate_entry_model_columns, order_entry_template_context, parse_manual_order_style_fields, resolve_trade_record_entry_reason, trend_manual_entry_reason_count, ) """ KEY_IMPORT = "from lib.key_monitor.key_auto_order_lib import (\n check_monitor_type_add_allowed,\n effective_entry_reason_options,\n effective_stats_segment_defs,\n load_key_auto_order_enabled," KEY_IMPORT_WITH_KEY_OPTS = "from lib.key_monitor.key_auto_order_lib import (\n KEY_ENTRY_REASON_OPTIONS,\n check_monitor_type_add_allowed,\n effective_entry_reason_options,\n effective_stats_segment_defs,\n load_key_auto_order_enabled," def patch_file(path: str, exchange: str) -> bool: with open(path, "r", encoding="utf-8") as f: text = f.read() orig = text if "from lib.trade.entry_model_lib import" not in text: text = text.replace( "from lib.trade.trade_policy_app_lib import (", IMPORT_BLOCK + "from lib.trade.trade_policy_app_lib import (", 1, ) if exchange == "gate": old_er = '''# 与用户约定的固定开仓类型 ENTRY_REASON_OPTIONS = ( "趋势多头:4h大结构突破前进场,确认条件:三次探顶,5m收敛不创新低", "趋势空头:4h大结构突破前进场,确认条件:三次探底,5m收敛不创新高", "趋势多头:小分歧低吸入场(左侧),确认条件:二次探底", "趋势空头:小分歧高吸入场(左侧),确认条件:二次探顶", "波段单:5m顺势突破,确认条件:2根k线+成交量放大+4h同向+日成交量前20", "关键位箱体突破", "关键位收敛突破", "关键位斐波0.618", "关键位斐波0.786", "关键位假突破", "关键位回调触价开仓", "关键位突破触价开仓", ) + STRATEGY_ENTRY_REASON_OPTIONS''' new_er = """# 日内户:长句开仓类型 + 关键位 + 策略(大分歧 A/B/小分歧 仅趋势户) ENTRY_REASON_OPTIONS = build_intraday_entry_reason_options( KEY_ENTRY_REASON_OPTIONS, STRATEGY_ENTRY_REASON_OPTIONS, )""" text = text.replace(old_er, new_er) if "KEY_ENTRY_REASON_OPTIONS," not in text.split("load_key_auto_order_enabled")[0]: text = text.replace(KEY_IMPORT, KEY_IMPORT_WITH_KEY_OPTS, 1) else: old_er = '''# 与用户约定的固定开仓类型(仅做这几类单子) ENTRY_REASON_OPTIONS = ( "趋势多头:4h大结构突破前进场,确认条件:三次探顶,5m收敛不创新低", "趋势空头:4h大结构突破前进场,确认条件:三次探底,5m收敛不创新高", "趋势多头:小分歧低吸入场(左侧),确认条件:二次探底", "趋势空头:小分歧高吸入场(左侧),确认条件:二次探顶", "波段单:5m顺势突破,确认条件:2根k线+成交量放大+4h同向+日成交量前20", "关键位箱体突破", "关键位收敛突破", "关键位斐波0.618", "关键位斐波0.786", "关键位假突破", "关键位回调触价开仓", "关键位突破触价开仓", ) + STRATEGY_ENTRY_REASON_OPTIONS''' new_er = """# 趋势户:大分歧A/B/小分歧 + 策略(关键位本实例关闭) ENTRY_REASON_OPTIONS = build_trend_div_entry_reason_options(STRATEGY_ENTRY_REASON_OPTIONS)""" text = text.replace(old_er, new_er) if "migrate_entry_model_columns(conn)" not in text: text = text.replace( " conn.commit()\n conn.close()\n\n\ndef get_db", " migrate_entry_model_columns(conn)\n conn.commit()\n conn.close()\n\n\ndef get_db", 1, ) text = re.sub( r" er = \(\n \(entry_reason or \"\"\)\.strip\(\)\n or entry_reason_from_key_signal\(kst\)\n or entry_reason_for_monitor_type\(monitor_type\)\n or \"\"\n \)", """ er = resolve_trade_record_entry_reason( entry_reason=entry_reason, entry_model=entry_model, key_signal_type=kst, monitor_type=monitor_type, entry_reason_from_key_signal=entry_reason_from_key_signal, entry_reason_for_monitor_type=entry_reason_for_monitor_type, )""", text, count=1, ) if "entry_model=None," not in text: text = text.replace( " entry_reason=None,\n trend_plan_id=None,", " entry_reason=None,\n entry_model=None,\n trend_plan_id=None,", 1, ) if "enrich_entry_model_display(item)" not in text: text = text.replace( " enrich_order_display_fields(item, calc_rr_ratio)\n try:", " enrich_order_display_fields(item, calc_rr_ratio)\n enrich_entry_model_display(item)\n try:", 1, ) text = text.replace( """ trade_style = (d.get("trade_style") or DEFAULT_TRADE_STYLE or "trend").strip().lower() if trade_style not in ("trend", "swing"): trade_style = "trend" available_usdt = get_available_trading_usdt()""", """ trade_style, entry_model, style_err = parse_manual_order_style_fields( TRADE_POLICY, d, default_trade_style=DEFAULT_TRADE_STYLE or "trend" ) if style_err: conn.close() flash(style_err) return redirect("/trade") available_usdt = get_available_trading_usdt()""", 1, ) old_insert = ( '"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 (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",\n' " (\n" " symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,\n" " margin_capital, leverage, trade_style, risk_percent_db, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,\n" " breakeven_enabled,\n" " notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day,\n" " ORDER_MONITOR_TYPE_MANUAL,\n" " tc_en, tc_h, tc_at,\n" " )" ) new_insert = ( '"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 (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",\n' " (\n" " symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,\n" " 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,\n" " breakeven_enabled,\n" " notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day,\n" " ORDER_MONITOR_TYPE_MANUAL,\n" " tc_en, tc_h, tc_at,\n" " )" ) text = text.replace(old_insert, new_insert) text = text.replace( """ effective_entry_reason_options( ENTRY_REASON_OPTIONS, POSITION_SIZING_MODE, KEY_AUTO_ORDER_ENABLED, )""", """ effective_entry_reason_options( ENTRY_REASON_OPTIONS, POSITION_SIZING_MODE, KEY_AUTO_ORDER_ENABLED, trend_manual_count=trend_manual_entry_reason_count(TRADE_POLICY), )""", 1, ) if "**order_entry_template_context(TRADE_POLICY)," not in text: text = text.replace( " trade_policy=trade_policy_template_context(TRADE_POLICY),", " trade_policy=trade_policy_template_context(TRADE_POLICY),\n **order_entry_template_context(TRADE_POLICY),", 1, ) # insert_trade_record from order row: add entry_model text = re.sub( r"(insert_trade_record\(\n\s+conn,\n(?:[^\n]+\n)+?\s+trade_style=r\[\"trade_style\"\],\n)", r"\1 entry_model=(r[\"entry_model\"] if \"entry_model\" in r.keys() else None),\n", text, ) if text != orig: with open(path, "w", encoding="utf-8", newline="\n") as f: f.write(text) return True return False def main(): for ex in ("binance", "okx", "gate"): path = os.path.join(REPO, f"crypto_monitor_{ex}", "app.py") changed = patch_file(path, ex) print(f"{ex}: {'patched' if changed else 'no change'}") if __name__ == "__main__": main()