fix: TradingView K线图表并修复品种推荐为空。

- 行情页改用 Lightweight Charts 标准蜡烛图(红跌绿涨)
- 修复 fee_rates 缺 source 列导致推荐刷新失败
- 空缓存自动重试,持仓页实时兜底计算推荐列表

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-25 12:33:49 +08:00
parent 074551490f
commit 32f1fa2c66
8 changed files with 458 additions and 527 deletions
+32 -13
View File
@@ -1,6 +1,7 @@
"""按账户资金推荐可交易品种(期货核心筛选)。"""
from __future__ import annotations
import logging
import math
from concurrent.futures import ThreadPoolExecutor
from typing import Callable, Optional
@@ -9,6 +10,8 @@ from contract_specs import get_contract_spec
from fee_specs import calc_fee_breakdown
from symbols import PRODUCTS
logger = logging.getLogger(__name__)
def _letters_from_ths(ths_code: str) -> str:
import re
@@ -61,9 +64,13 @@ def assess_product_for_capital(
ref_sl = round(p - stop_dist, 4)
ref_tp = round(p + stop_dist * reward_risk_ratio, 4)
fee_ths = ths + "8888"
fee_info = calc_fee_breakdown(
fee_ths, p, p, 1.0, open_time="", close_time="", trading_mode=trading_mode,
)
try:
fee_info = calc_fee_breakdown(
fee_ths, p, p, 1.0, open_time="", close_time="", trading_mode=trading_mode,
)
except Exception as exc:
logger.debug("recommend fee calc failed %s: %s", ths, exc)
fee_info = {"open_fee": 0.0, "total_fee": 0.0}
can_margin = max_lots >= 1
can_risk = cap > 0 and risk_one_lot <= cap * 0.01
@@ -109,16 +116,28 @@ def list_product_recommendations(
def _one(product: dict) -> dict:
ths = product["ths"]
quote = quote_fn(ths) or {}
price = quote.get("price")
row = assess_product_for_capital(
product, capital, price,
max_margin_pct=max_margin_pct,
trading_mode=trading_mode,
)
main_code = (quote.get("ths_code") or "").strip()
row["main_code"] = main_code
return row
try:
quote = quote_fn(ths) or {}
price = quote.get("price")
row = assess_product_for_capital(
product, capital, price,
max_margin_pct=max_margin_pct,
trading_mode=trading_mode,
)
main_code = (quote.get("ths_code") or "").strip()
row["main_code"] = main_code
return row
except Exception as exc:
logger.warning("recommend product failed %s: %s", ths, exc)
return {
"ths": ths,
"name": product.get("name") or ths,
"exchange": product.get("exchange") or "",
"status": "no_price",
"status_label": "计算失败",
"main_code": "",
"max_lots": 0,
}
with ThreadPoolExecutor(max_workers=10) as pool:
rows = list(pool.map(_one, PRODUCTS))