refactor: 缠论引擎包化与 Web 分层(ECR-001)

将根目录引擎迁入 chanlun/ 并保留兼容 shim;拆分 TF_DF 与 web 服务;
前端模块化;strategies 改用 chanlun 导入;补充 ESS 文档与 golden 回归。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-05 18:48:20 +08:00
co-authored by Cursor
parent e2e45bc1bc
commit 74dec4e50b
160 changed files with 25576 additions and 23104 deletions
+73
View File
@@ -0,0 +1,73 @@
"""页面路由。"""
from flask import Blueprint, render_template, send_from_directory
from services.runtime import * # noqa: F403
from services import runtime as R
bp = Blueprint("pages", __name__)
@bp.route('/chan_tv')
def chan_tv():
"""缠论 TradingView 高级图表页面"""
return render_template('chan_tv.html')
@bp.route('/charting_library/<path:filename>')
def serve_charting_library(filename):
"""提供 TradingView Charting Library 静态文件"""
return send_from_directory('charting_library', filename)
@bp.route('/')
def index():
"""主页"""
refresh_data_service_metadata()
tf_map = TIMEFRAMES if TIMEFRAMES else DEFAULT_TIMEFRAME_LABELS.copy()
default_main, default_element, default_sub_sub, timeframe_keys = compute_timeframe_defaults(OrderedDict(tf_map))
symbols = SYMBOLS if SYMBOLS else DEFAULT_SYMBOLS
default_symbol = 'BTC/USDT:USDT' if 'BTC/USDT:USDT' in symbols else (symbols[0] if symbols else '')
return render_template(
'index.html',
timeframes=tf_map,
symbols=symbols,
a_stock_symbols=A_STOCK_SYMBOLS,
default_main_timeframe=default_main,
default_element_timeframe=default_element,
default_sub_sub_timeframe=default_sub_sub,
default_symbol=default_symbol,
timeframe_keys_json=json.dumps(timeframe_keys),
data_service_available=DATA_SERVICE_AVAILABLE,
)
@bp.route('/api/chart_metadata')
def api_chart_metadata():
"""
按数据源返回图表用 K 线周期(中文标签)及主/次/次次默认周期。
crypto:强制刷新 DATA_SERVICE_URL /health 元信息;
a_stock:读取 ASHARE_DP_URL 的 /api/v1/klines/available-freqs,不修改全局加密货币 TIMEFRAMES。
"""
source = (request.args.get('source') or 'crypto').strip().lower()
if source not in ('crypto', 'a_stock'):
source = 'crypto'
try:
if source == 'a_stock':
raw = china_stock.get_available_kline_freqs()
labels_od = build_timeframe_labels(raw)
else:
refresh_data_service_metadata(force=True)
labels_od = OrderedDict(TIMEFRAMES if TIMEFRAMES else DEFAULT_TIMEFRAME_LABELS.copy())
default_main, default_element, default_sub_sub, keys = compute_timeframe_defaults(labels_od)
return jsonify({
'source': source,
'timeframes': {k: v for k, v in labels_od.items()},
'timeframe_keys': keys,
'default_main': default_main,
'default_element': default_element,
'default_sub_sub': default_sub_sub,
})
except Exception as exc:
logger.exception('chart_metadata 失败: %s', exc)
return jsonify({'error': str(exc)}), 500