新增行情K线页,支持分时与多周期图表

扩展新浪K线拉取与合成逻辑,提供 ECharts 交互图表及实时报价 API。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-15 17:07:04 +08:00
parent 28875078f1
commit 6f3ac3deb6
5 changed files with 621 additions and 22 deletions
+61 -1
View File
@@ -30,7 +30,7 @@ from fee_specs import (
from fee_sync import sync_fees_from_akshare
from contract_profile import get_contract_profile
from stats_engine import STATS_VIEWS, load_stats_cache, refresh_stats_cache
from kline_chart import generate_review_kline_chart
from kline_chart import generate_review_kline_chart, fetch_market_klines, MARKET_PERIODS
from market import get_price as market_get_price, set_ths_refresh_token, get_quote_source_label
load_dotenv(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env"))
@@ -1297,6 +1297,66 @@ def api_stats_refresh():
return jsonify(data)
@app.route("/market")
@login_required
def market_page():
symbol = request.args.get("symbol", "").strip()
period = request.args.get("period", "15m").strip()
valid = {p["key"] for p in MARKET_PERIODS}
if period not in valid:
period = "15m"
return render_template(
"market.html",
symbol=symbol,
period=period,
market_periods=MARKET_PERIODS,
)
@app.route("/api/kline")
@login_required
def api_kline():
symbol = request.args.get("symbol", "").strip()
period = request.args.get("period", "15m").strip()
if not symbol:
return jsonify({"error": "请提供合约代码"}), 400
try:
data = fetch_market_klines(symbol, period)
except Exception as exc:
app.logger.warning("kline api failed: %s", exc)
return jsonify({"error": str(exc)}), 500
if not data.get("chart_symbol"):
return jsonify({"error": "无法识别合约代码"}), 400
if not data.get("bars"):
return jsonify({"error": "未获取到K线数据,请稍后重试或更换合约"}), 404
return jsonify(data)
@app.route("/api/market_quote")
@login_required
def api_market_quote():
symbol = request.args.get("symbol", "").strip()
market_code = request.args.get("market_code", "").strip()
sina_code = request.args.get("sina_code", "").strip()
if not symbol and not market_code:
return jsonify({"error": "请提供合约"}), 400
if not market_code or not sina_code:
codes = ths_to_codes(symbol)
if codes:
market_code = codes.get("market_code", "") or market_code
sina_code = codes.get("sina_code", "") or sina_code
price = market_get_price(market_code, sina_code)
name = symbol
codes = ths_to_codes(symbol)
if codes:
name = codes.get("name", symbol)
return jsonify({
"symbol": symbol,
"name": name,
"price": price,
})
@app.route("/contract")
@login_required
def contract_profile_page():