diff --git a/install_trading.py b/install_trading.py index 932df70..240c33a 100644 --- a/install_trading.py +++ b/install_trading.py @@ -13,6 +13,7 @@ from kline_stream import sse_format from position_sizing import ( MODE_FIXED, MODE_RISK, + DEFAULT_MAX_ORDER_LOTS, calc_lots_by_risk, calc_order_tick_metrics, normalize_sizing_mode, @@ -540,11 +541,19 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se if sl <= 0: conn.close() return jsonify({"ok": False, "error": "以损定仓模式须填写止损价"}), 400 - lots_calc, err = calc_lots_by_risk(price, sl, direction, _capital(conn), get_risk_percent(get_setting), sym) + lots_calc, err = calc_lots_by_risk( + price, sl, direction, _capital(conn), get_risk_percent(get_setting), sym, + ) if err: conn.close() return jsonify({"ok": False, "error": err}), 400 lots = lots_calc or lots + if lots > DEFAULT_MAX_ORDER_LOTS: + conn.close() + return jsonify({ + "ok": False, + "error": f"单笔手数 {lots} 超过上限 {DEFAULT_MAX_ORDER_LOTS},请加大止损距离或改固定手数", + }), 400 try: result = execute_order( conn, diff --git a/position_sizing.py b/position_sizing.py index 42e9b0d..ab12e00 100644 --- a/position_sizing.py +++ b/position_sizing.py @@ -9,6 +9,9 @@ from contract_specs import get_contract_spec MODE_FIXED = "fixed" MODE_RISK = "risk" +# 单笔报单手数上限(防止以损定仓在止损过近时算出超大手数) +DEFAULT_MAX_ORDER_LOTS = 50 + def normalize_sizing_mode(raw: str) -> str: m = (raw or MODE_RISK).strip().lower() @@ -63,8 +66,8 @@ def calc_lots_by_risk( if max_by_margin < 1: return None, "可用资金不足以覆盖 1 手保证金" lots = min(lots, max_by_margin) - if max_lots is not None: - lots = min(lots, int(max_lots)) + cap_lots = max_lots if max_lots is not None else DEFAULT_MAX_ORDER_LOTS + lots = min(lots, cap_lots) return lots, None