refactor: 将共用代码迁入 lib/ 模块化目录

统一 strategy、key_monitor、trade、hub 等共用库到 lib/ 子包,并补充 lib-structure 文档,便于四所与中控维护。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-02 16:23:09 +08:00
parent 4742a0bb9d
commit 5797d49d8a
190 changed files with 27946 additions and 27499 deletions
+65 -64
View File
@@ -34,14 +34,15 @@ import sys
if _REPO_ROOT not in sys.path:
sys.path.insert(0, _REPO_ROOT)
from ai_client import ai_generate, ai_review, ai_short_advice
from ai_review_lib import (
from lib.paths import common_static_dir
from lib.ai.ai_client import ai_generate, ai_review, ai_short_advice
from lib.ai.ai_review_lib import (
build_journal_ai_chart_path,
collect_images_for_ai_review,
journal_row_lines_for_ai,
)
from form_submit_lib import check_duplicate_submit, submit_scope_add_key, submit_scope_add_order
from fib_key_monitor_lib import (
from lib.common.form_submit_lib import check_duplicate_submit, submit_scope_add_key, submit_scope_add_order
from lib.key_monitor.fib_key_monitor_lib import (
FIB_KEY_MONITOR_TYPES,
KEY_ENTRY_REASON_BY_SIGNAL,
backfill_missing_key_signal_types,
@@ -53,7 +54,7 @@ from fib_key_monitor_lib import (
key_signal_type_for_trade_record,
stored_key_signal_type,
)
from false_breakout_key_monitor_lib import (
from lib.key_monitor.false_breakout_key_monitor_lib import (
FALSE_BREAKOUT_MONITOR_TYPE,
FALSE_BREAKOUT_VALIDITY_HOURS,
calc_false_breakout_plan,
@@ -66,7 +67,7 @@ from false_breakout_key_monitor_lib import (
normalize_false_breakout_symbol,
storage_bounds_from_key_price,
)
from strategy_trade_labels import (
from lib.strategy.strategy_trade_labels import (
STRATEGY_ENTRY_REASON_OPTIONS,
apply_order_monitor_source_labels,
entry_reason_for_monitor_type,
@@ -75,7 +76,7 @@ from strategy_trade_labels import (
trade_record_monitor_type as resolve_trade_record_monitor_type,
trend_plan_id_from_monitor_row,
)
from journal_chart_lib import (
from lib.instance.journal_chart_lib import (
JOURNAL_CHART_DEFAULT_LIMIT,
JOURNAL_CHART_DEFAULT_TF1,
JOURNAL_CHART_DEFAULT_TF2,
@@ -91,7 +92,7 @@ from journal_chart_lib import (
trade_review_fetch_window,
trim_rows_for_trade_review,
)
from key_sl_tp_lib import (
from lib.key_monitor.key_sl_tp_lib import (
breakeven_enabled_from_row,
normalize_sl_tp_mode,
parse_breakeven_enabled_form,
@@ -100,7 +101,7 @@ from key_sl_tp_lib import (
sl_tp_mode_label,
sl_tp_plan_summary_text,
)
from time_close_lib import (
from lib.trade.time_close_lib import (
TIME_CLOSE_RESULT,
apply_time_close_to_payload,
ensure_time_close_schema,
@@ -111,13 +112,13 @@ from time_close_lib import (
time_close_label,
time_close_settings_from_row,
)
from manual_sltp_lib import (
from lib.trade.manual_sltp_lib import (
normalize_open_sltp_mode,
resolve_entrust_sltp_prices,
resolve_open_sltp_prices,
)
from key_monitor_schema_lib import ensure_key_monitor_schema
from trigger_entry_key_monitor_lib import (
from lib.key_monitor.key_monitor_schema_lib import ensure_key_monitor_schema
from lib.key_monitor.trigger_entry_key_monitor_lib import (
BREAKOUT_TRIGGER_ENTRY_MONITOR_TYPE,
CALLBACK_TRIGGER_ENTRY_MONITOR_TYPE,
TRIGGER_ENTRY_CLOSE_EXCHANGE_FAILED,
@@ -140,7 +141,7 @@ from trigger_entry_key_monitor_lib import (
validate_trigger_entry_geometry,
validate_trigger_entry_rr,
)
from position_sizing_lib import (
from lib.trade.position_sizing_lib import (
OPEN_SOURCE_KEY_AUTO,
OPEN_SOURCE_KEY_TRIGGER,
OPEN_SOURCE_MANUAL,
@@ -154,12 +155,12 @@ from position_sizing_lib import (
mode_label_zh,
risk_percent_for_storage,
)
from key_monitor_full_margin_lib import (
from lib.key_monitor.key_monitor_full_margin_lib import (
monitor_type_disallowed_in_full_margin,
purge_disallowed_key_monitors,
)
from auto_transfer_daily_lib import run_auto_transfer_once_per_day
from key_monitor_lib import (
from lib.common.auto_transfer_daily_lib import run_auto_transfer_once_per_day
from lib.key_monitor.key_monitor_lib import (
KEY_DIRECTION_WATCH,
KEY_MONITOR_ALERT_ONLY_TYPES,
KEY_MONITOR_AUTO_TYPES,
@@ -179,16 +180,16 @@ from key_monitor_lib import (
rs_break_from_direction,
run_rs_level_alert_tick,
)
from order_monitor_display_lib import (
from lib.trade.order_monitor_display_lib import (
apply_order_price_display_fields,
enrich_order_display_fields,
order_monitor_tpsl_needs_sync,
)
from wechat_notify_lib import build_wechat_rs_level_message, send_wechat_webhook
from hub_auth import request_allowed as hub_request_allowed
from instance_nav_lib import request_is_hub_soft_nav
from hub_volume_rank_lib import resolve_daily_volume_rank
from history_window_lib import (
from lib.common.wechat_notify_lib import build_wechat_rs_level_message, send_wechat_webhook
from lib.hub.hub_auth import request_allowed as hub_request_allowed
from lib.instance.instance_nav_lib import request_is_hub_soft_nav
from lib.hub.hub_volume_rank_lib import resolve_daily_volume_rank
from lib.common.history_window_lib import (
PRESET_CUSTOM,
PRESET_UTC_LAST24H,
PRESET_UTC_LAST7D,
@@ -201,8 +202,8 @@ from history_window_lib import (
utc_window_to_bj_sql_strings,
utc_window_to_utc_sql_strings,
)
from trade_result_lib import count_winning_trades, normalize_result_with_pnl
from trade_exchange_stats_lib import attach_exchange_stats_to_trade, filter_position_lifecycle_fills
from lib.trade.trade_result_lib import count_winning_trades, normalize_result_with_pnl
from lib.trade.trade_exchange_stats_lib import attach_exchange_stats_to_trade, filter_position_lifecycle_fills
def load_env_file(path):
@@ -343,7 +344,7 @@ ORDER_CHART_ENABLED = os.getenv("ORDER_CHART_ENABLED", "true").lower() == "true"
ORDER_CHART_TFS = [x.strip() for x in (os.getenv("ORDER_CHART_TFS", "4h,1h,15m,5m") or "").split(",") if x.strip()]
ORDER_CHART_LIMIT = int(os.getenv("ORDER_CHART_LIMIT", "100"))
ORDER_CHART_DIR = resolve_path(os.getenv("ORDER_CHART_DIR", "static/images/order_charts"))
from daily_open_limit_lib import (
from lib.trade.daily_open_limit_lib import (
build_daily_open_alert_prompt,
can_trade_new_open,
check_daily_open_hard_limit,
@@ -1506,10 +1507,10 @@ def init_db():
close_reason TEXT, closed_at TEXT)"""
)
from strategy_db import init_strategy_tables
from lib.strategy.strategy_db import init_strategy_tables
init_strategy_tables(conn)
from account_risk_lib import ensure_account_risk_schema
from lib.trade.account_risk_lib import ensure_account_risk_schema
ensure_account_risk_schema(conn)
backfill_missing_key_signal_types(conn, monitor_type=ORDER_MONITOR_TYPE_KEY_AUTO)
@@ -1546,7 +1547,7 @@ def get_db():
def hub_account_risk_status(conn):
from account_risk_lib import (
from lib.trade.account_risk_lib import (
apply_position_limit_risk,
compute_account_risk_status,
enrich_risk_status_countdown,
@@ -1562,7 +1563,7 @@ def hub_account_risk_status(conn):
fmt_local_ms=ms_to_app_local_str,
)
st = enrich_risk_status_countdown(st, now=now, daily_reset_hour=TRADING_DAY_RESET_HOUR)
from strategy_trade_labels import count_position_limit_active_monitors
from lib.strategy.strategy_trade_labels import count_position_limit_active_monitors
return apply_position_limit_risk(
st,
@@ -1579,7 +1580,7 @@ def hub_user_initiated_close(
trade_record_id=None,
closed_at_ms=None,
):
from account_risk_lib import CLOSE_SOURCE_USER_HUB, on_user_initiated_close
from lib.trade.account_risk_lib import CLOSE_SOURCE_USER_HUB, on_user_initiated_close
src = (source or "").strip() or CLOSE_SOURCE_USER_HUB
on_user_initiated_close(
@@ -2072,7 +2073,7 @@ def get_effective_trade_field(row, reviewed_key, base_key, default=None):
def to_effective_trade_dict(row):
item = row_to_dict(row)
from order_monitor_display_lib import snapshot_stop_loss
from lib.trade.order_monitor_display_lib import snapshot_stop_loss
open_stop = snapshot_stop_loss(item.get("initial_stop_loss"), item.get("stop_loss"))
item["display_open_stop_loss"] = open_stop
@@ -2370,7 +2371,7 @@ def insert_trade_record(
open_ts_ms = _to_ms_with_fallback(opened_at_ms, open_ts)
close_ts_ms = _to_ms_with_fallback(closed_at_ms, close_ts)
kst = key_signal_type_for_trade_record(key_signal_type, KEY_MONITOR_AUTO_TYPES)
from order_monitor_display_lib import snapshot_stop_loss
from lib.trade.order_monitor_display_lib import snapshot_stop_loss
snap_sl = snapshot_stop_loss(initial_stop_loss, stop_loss)
er = (
@@ -2761,7 +2762,7 @@ def get_exchange_capitals(force=False):
def execute_transfer_usdt(amount, from_account, to_account):
from gate_transfer_lib import execute_transfer_usdt as _gate_execute_transfer_usdt
from lib.exchange.gate_transfer_lib import execute_transfer_usdt as _gate_execute_transfer_usdt
return _gate_execute_transfer_usdt(
exchange,
@@ -2794,7 +2795,7 @@ def get_account_usdt_total(account_type):
def _auto_transfer_active_count(conn):
from gate_transfer_lib import count_auto_transfer_blockers
from lib.exchange.gate_transfer_lib import count_auto_transfer_blockers
return count_auto_transfer_blockers(conn, count_order_monitors=get_active_position_count)
@@ -2878,7 +2879,7 @@ def resolve_capital_base_for_key_open(conn, trading_day, live_capital):
def precheck_risk(conn, symbol, direction):
now = app_now()
from account_risk_lib import account_risk_blocks_trading
from lib.trade.account_risk_lib import account_risk_blocks_trading
ok_risk, risk_reason = account_risk_blocks_trading(
conn,
@@ -2890,7 +2891,7 @@ def precheck_risk(conn, symbol, direction):
return False, risk_reason
if not trading_day_reset_allows_new_open(now):
return False, f"北京时间 {TRADING_DAY_RESET_HOUR}:00 前不允许持仓"
from account_risk_lib import position_limit_reached
from lib.trade.account_risk_lib import position_limit_reached
reached, active_count, mx = position_limit_reached(conn, max_active_positions=MAX_ACTIVE_POSITIONS)
if reached:
@@ -3670,7 +3671,7 @@ def parse_ccxt_position_metrics(position, order_leverage=None):
cs = float(get_contract_size(sym)) if sym else 1.0
except Exception:
cs = 1.0
from hub_position_metrics import enrich_ccxt_position_metrics_out
from lib.hub.hub_position_metrics import enrich_ccxt_position_metrics_out
enrich_ccxt_position_metrics_out(p, out, contract_size=cs, funds_decimals=2)
return out or None
@@ -3854,7 +3855,7 @@ def fetch_latest_closing_fill(exchange_symbol, direction, opened_at_str, opened_
except Exception:
pass
try:
from gate_position_history_lib import pick_gate_position_close
from lib.exchange.gate_position_history_lib import pick_gate_position_close
pos = pick_gate_position_close(
fetch_gate_positions_close_history(),
@@ -4114,7 +4115,7 @@ def reconcile_hub_external_close(conn, symbol, direction):
"""中控市价全平后:立即同步匹配 order_monitor,并读 Gate 平仓历史。"""
if not exchange_private_api_configured():
return {"ok": False, "msg": "未配置 GATE_API_KEY / GATE_API_SECRET", "synced": 0}
from gate_position_history_lib import unified_symbol_for_match
from lib.exchange.gate_position_history_lib import unified_symbol_for_match
sym_u = unified_symbol_for_match(symbol)
dir_l = (direction or "").strip().lower()
@@ -6513,14 +6514,14 @@ def background_task():
check_trigger_entry_key_monitors()
_roll_cfg = app.extensions.get("strategy_roll_cfg")
if _roll_cfg:
from strategy_roll_monitor_lib import check_roll_monitors
from lib.strategy.strategy_roll_monitor_lib import check_roll_monitors
check_roll_monitors(_roll_cfg)
check_key_monitors()
check_order_monitors()
cfg = app.extensions.get("strategy_trend_cfg")
if cfg:
from strategy_trend_register import check_trend_pullback_plans
from lib.strategy.strategy_trend_register import check_trend_pullback_plans
check_trend_pullback_plans(cfg)
except:
@@ -6848,7 +6849,7 @@ def render_main_page(page="trade", embed_mode=None):
conn = get_db()
session_row = ensure_session(conn, trading_day)
local_current_capital = float(session_row["current_capital"])
from instance_embed_context_lib import (
from lib.instance.instance_embed_context_lib import (
embed_render_plan,
minimal_stats_bundle,
trade_records_summary,
@@ -6921,7 +6922,7 @@ def render_main_page(page="trade", embed_mode=None):
records = []
total = miss_count = rate = occupied_miss_total = 0
active_count = len(order_list)
from strategy_trade_labels import count_position_limit_active_monitors
from lib.strategy.strategy_trade_labels import count_position_limit_active_monitors
position_limit_count = count_position_limit_active_monitors(conn)
opens_today = count_opens_for_trading_day(conn, trading_day)
@@ -6952,7 +6953,7 @@ def render_main_page(page="trade", embed_mode=None):
)
strategy_extra = {}
if plan.strategy:
from strategy_ui import strategy_render_extras
from lib.strategy.strategy_ui import strategy_render_extras
strategy_extra = strategy_render_extras(
conn,
@@ -6962,7 +6963,7 @@ def render_main_page(page="trade", embed_mode=None):
trend_cfg=app.extensions.get("strategy_trend_cfg"),
)
conn.close()
from instance_embed_lib import embed_context_extras
from lib.instance.instance_embed_lib import embed_context_extras
template_ctx = dict(
page=page,
@@ -7104,7 +7105,7 @@ def api_account_snapshot():
funding_usdt = round(funding_capital, 2) if funding_capital is not None else None
current_capital = round(trading_capital, 2) if trading_capital is not None else round(local_current_capital, 2)
recommended_capital = round(float(get_recommended_capital(current_capital)), 2)
from strategy_trade_labels import count_position_limit_active_monitors
from lib.strategy.strategy_trade_labels import count_position_limit_active_monitors
position_limit_count = count_position_limit_active_monitors(conn)
opens_today = count_opens_for_trading_day(conn, trading_day)
@@ -7414,7 +7415,7 @@ def api_price_snapshot():
pass
conn.close()
from hub_position_metrics import build_position_marks_list
from lib.hub.hub_position_metrics import build_position_marks_list
position_marks = build_position_marks_list(
all_swap_positions,
@@ -7647,7 +7648,7 @@ def api_order_kline():
"volume": float(bar[5]),
})
from focus_chart_lib import (
from lib.instance.focus_chart_lib import (
build_order_kline_order_payload,
load_swap_positions_for_order_kline,
metrics_for_order_item,
@@ -7675,7 +7676,7 @@ def api_order_kline():
ex_metrics=ex_metrics,
)
from focus_chart_lib import kline_api_price_fields
from lib.instance.focus_chart_lib import kline_api_price_fields
price_fields = kline_api_price_fields(
exchange,
@@ -7792,7 +7793,7 @@ def api_key_kline():
"lower_pct": lower_pct,
}
from focus_chart_lib import enrich_key_kline_response
from lib.instance.focus_chart_lib import enrich_key_kline_response
price_display, key_info = enrich_key_kline_response(
symbol=symbol,
@@ -7801,7 +7802,7 @@ def api_key_kline():
format_price_fn=format_price_for_symbol,
)
from focus_chart_lib import kline_api_price_fields
from lib.instance.focus_chart_lib import kline_api_price_fields
price_fields = kline_api_price_fields(
exchange,
@@ -8756,7 +8757,7 @@ def del_order(id):
opened_at=opened_at,
closed_at=closed_at,
)
from account_risk_lib import CLOSE_SOURCE_USER_INSTANCE, insert_trade_record_id, on_user_initiated_close
from lib.trade.account_risk_lib import CLOSE_SOURCE_USER_INSTANCE, insert_trade_record_id, on_user_initiated_close
on_user_initiated_close(
conn,
@@ -8770,7 +8771,7 @@ def del_order(id):
try:
_rcfg = app.extensions.get("strategy_roll_cfg")
if isinstance(_rcfg, dict):
from strategy_register import roll_sync_after_external_close
from lib.strategy.strategy_register import roll_sync_after_external_close
roll_sync_after_external_close(_rcfg, conn, row["symbol"], row["direction"])
except Exception:
@@ -8832,7 +8833,7 @@ def del_order(id):
opened_at=opened_at,
closed_at=closed_at,
)
from account_risk_lib import CLOSE_SOURCE_USER_INSTANCE, insert_trade_record_id, on_user_initiated_close
from lib.trade.account_risk_lib import CLOSE_SOURCE_USER_INSTANCE, insert_trade_record_id, on_user_initiated_close
on_user_initiated_close(
conn,
@@ -8846,7 +8847,7 @@ def del_order(id):
try:
_rcfg = app.extensions.get("strategy_roll_cfg")
if isinstance(_rcfg, dict):
from strategy_register import roll_sync_after_external_close
from lib.strategy.strategy_register import roll_sync_after_external_close
roll_sync_after_external_close(_rcfg, conn, row["symbol"], row["direction"])
except Exception:
@@ -9020,7 +9021,7 @@ def add_journal():
d.get("post_breakeven_stare"), d.get("new_trade_while_occupied"), d.get("note"), image_filename
)
)
from account_risk_lib import on_journal_saved
from lib.trade.account_risk_lib import on_journal_saved
on_journal_saved(
conn,
@@ -9108,7 +9109,7 @@ def api_reviews():
return jsonify([row_to_dict(r) for r in rows])
_REPO_STATIC_DIR = os.path.join(os.path.dirname(BASE_DIR), "static")
_REPO_STATIC_DIR = common_static_dir(os.path.dirname(BASE_DIR))
_AI_REVIEW_RENDER_JS = os.path.join(_REPO_STATIC_DIR, "ai_review_render.js")
_FORM_SUBMIT_GUARD_JS = os.path.join(_REPO_STATIC_DIR, "form_submit_guard.js")
_MANUAL_ORDER_RR_PREVIEW_JS = os.path.join(_REPO_STATIC_DIR, "manual_order_rr_preview.js")
@@ -9342,7 +9343,7 @@ def api_trade_record_review_update():
tuple(base_params + [rec_id]),
)
if reviewed_result == "手动平仓" and reviewed_miss_reason:
from account_risk_lib import apply_manual_close_journal_cooloff
from lib.trade.account_risk_lib import apply_manual_close_journal_cooloff
apply_manual_close_journal_cooloff(
conn,
@@ -9491,7 +9492,7 @@ def _hub_account_bundle():
def _hub_fetch_market(base=""):
from hub_market_info_lib import fetch_usdt_swap_market_info
from lib.hub.hub_market_info_lib import fetch_usdt_swap_market_info
return fetch_usdt_swap_market_info(
base_or_symbol=base,
@@ -9504,7 +9505,7 @@ def _hub_fetch_market(base=""):
def _hub_fetch_ohlcv(symbol, timeframe, since_ms=None, limit=500):
from hub_ohlcv_lib import fetch_ohlcv_for_hub
from lib.hub.hub_ohlcv_lib import fetch_ohlcv_for_hub
return fetch_ohlcv_for_hub(
symbol=symbol,
@@ -9520,7 +9521,7 @@ def _hub_fetch_ohlcv(symbol, timeframe, since_ms=None, limit=500):
def _hub_fetch_volume_rank(top_n=20):
from hub_volume_rank_lib import fetch_usdt_swap_volume_rank
from lib.hub.hub_volume_rank_lib import fetch_usdt_swap_volume_rank
return fetch_usdt_swap_volume_rank(
exchange=exchange,
@@ -9537,7 +9538,7 @@ try:
_repo_root = Path(__file__).resolve().parent.parent
if str(_repo_root) not in sys.path:
sys.path.insert(0, str(_repo_root))
from hub_bridge import install_on_app
from lib.hub.hub_bridge import install_on_app
install_on_app(
app,
@@ -9581,8 +9582,8 @@ def strategy_roll_page():
return redirect("/strategy")
from strategy_register import install_strategy_trading
from strategy_trend_register import install_strategy_trend
from lib.strategy.strategy_register import install_strategy_trading
from lib.strategy.strategy_trend_register import install_strategy_trend
install_strategy_trading(app, _REPO_ROOT, app_module=sys.modules[__name__])
install_strategy_trend(app, _REPO_ROOT, app_module=sys.modules[__name__])