diff --git a/app.py b/app.py index a5caf38..c3341c9 100644 --- a/app.py +++ b/app.py @@ -24,7 +24,13 @@ from werkzeug.security import check_password_hash, generate_password_hash from functools import wraps -from symbols import search_symbols, ths_to_codes, list_main_contracts_grouped, refresh_main_index +from symbols import ( + search_symbols, + ths_to_codes, + list_main_contracts_grouped, + list_recommended_symbols_grouped, + refresh_main_index, +) from contract_specs import calc_position_metrics from fee_specs import ( calc_fee_breakdown, @@ -742,6 +748,26 @@ def api_symbols_mains(): return jsonify(list_main_contracts_grouped()) +@app.route("/api/symbols/recommended") +@login_required +def api_symbols_recommended(): + """品种下拉:仅展示当前资金下推荐的品种(与下方品种推荐表一致)。""" + from recommend_store import recommend_payload + from trading_context import get_account_capital, get_max_margin_pct + + conn = get_db() + try: + capital = get_account_capital(conn, get_setting) + payload = recommend_payload( + conn, + live_capital=capital, + max_margin_pct=get_max_margin_pct(get_setting), + ) + return jsonify(list_recommended_symbols_grouped(payload.get("rows") or [])) + finally: + conn.close() + + @app.route("/api/key_prices") @login_required def api_key_prices(): diff --git a/static/js/symbol.js b/static/js/symbol.js index 6e37c78..3514688 100644 --- a/static/js/symbol.js +++ b/static/js/symbol.js @@ -1,8 +1,12 @@ (function () { function formatSub(item) { - return '同花顺 ' + item.ths_code + + var sub = '同花顺 ' + item.ths_code + (item.market_code ? ' · ' + item.market_code : '') + ' · ' + (item.exchange || ''); + if (item.max_lots != null && item.max_lots > 0) { + sub += ' · 最大 ' + item.max_lots + ' 手'; + } + return sub; } function formatInputLabel(item) { @@ -132,17 +136,23 @@ return; } if (mainsLoading) { - dropdown.innerHTML = '
正在识别主力合约…
'; + dropdown.innerHTML = '
正在加载推荐品种…
'; dropdown.classList.add('show'); return; } mainsLoading = true; - dropdown.innerHTML = '
正在识别主力合约…
'; + dropdown.innerHTML = '
正在加载推荐品种…
'; dropdown.classList.add('show'); - fetch('/api/symbols/mains') + fetch('/api/symbols/recommended') .then(function (r) { return r.json(); }) .then(function (groups) { mainsCache = groups; + if (!groups.length) { + dropdown.innerHTML = + '
当前资金下暂无推荐品种,可输入合约代码搜索
'; + dropdown.classList.add('show'); + return; + } showMarketMains(filterQ, onEmpty); }) .catch(function () { diff --git a/symbols.py b/symbols.py index ced42c2..3ed0dde 100644 --- a/symbols.py +++ b/symbols.py @@ -419,6 +419,63 @@ def search_symbols(query: str) -> list: return results +_THS_TO_PRODUCT = {p["ths"]: p for p in PRODUCTS} +for _p in PRODUCTS: + _THS_TO_PRODUCT.setdefault(_p["ths"].lower(), _p) + + +def _product_for_ths(ths: str) -> Optional[dict]: + key = (ths or "").strip() + if not key: + return None + return _THS_TO_PRODUCT.get(key) or _THS_TO_PRODUCT.get(key.lower()) + + +def _main_for_product(product: dict) -> Optional[dict]: + with _main_index_lock: + index = dict(_main_index) + main = index.get(product["sina"]) + if not main: + resolved = resolve_main_contract(product) + if resolved: + main = _enrich_item(resolved) + return main + + +def list_recommended_symbols_grouped(recommend_rows: list[dict]) -> list[dict]: + """按交易所分类返回推荐品种对应的主力合约(品种选择下拉用)。""" + if not recommend_rows: + return [] + + buckets: dict[str, list] = defaultdict(list) + seen: set[str] = set() + for row in recommend_rows: + if row.get("status") not in ("ok", "margin_ok"): + continue + ths_key = (row.get("ths") or "").strip() + if not ths_key or ths_key in seen: + continue + product = _product_for_ths(ths_key) + if not product: + continue + seen.add(ths_key) + main = _main_for_product(product) + if not main: + continue + item = dict(main) + max_lots = row.get("max_lots") + if max_lots is not None: + item["max_lots"] = max_lots + buckets[product["exchange"]].append(_enrich_item(item)) + + groups: list[dict] = [] + for cat in EXCHANGE_ORDER: + items = buckets.get(cat) + if items: + groups.append({"category": cat, "items": items}) + return groups + + def list_main_contracts_grouped() -> list[dict]: """按交易所分类返回全部品种主力合约(行情页下拉用)。""" with _main_index_lock: diff --git a/templates/keys.html b/templates/keys.html index 6d848c3..403a82e 100644 --- a/templates/keys.html +++ b/templates/keys.html @@ -7,7 +7,7 @@
-
+
diff --git a/templates/plans.html b/templates/plans.html index 09936f4..b72aaad 100644 --- a/templates/plans.html +++ b/templates/plans.html @@ -8,7 +8,7 @@

开盘前制定,当日有效;请先选择主力合约,下方为进行中计划。

-
+