79e869eeda
- P0资金面:DB数据过期时用麦蕊API获取资金流向 - P1市场情绪:去掉turnover字段依赖(DB无此字段) - P2南向资金:北向实时数据已停公布,改用南向资金(港股通)替代 - P3美股:用腾讯财经API替代失效的AKShare接口 - P4大宗商品:用腾讯财经API替代,修复var_name解析 - P7汇率:用新浪财经API替代失效的AKShare接口 - 修复评分详情API技术得分硬编码问题 - 前端传入tech_score参数确保明细与列表分数一致
104 lines
2.8 KiB
Python
104 lines
2.8 KiB
Python
"""
|
||
股票投资分析系统 - 主应用入口
|
||
"""
|
||
from flask import Flask, render_template, jsonify
|
||
from flask_cors import CORS
|
||
from config import Config
|
||
|
||
# 初始化配置
|
||
Config.init_app()
|
||
|
||
# 创建Flask应用
|
||
app = Flask(__name__, template_folder='templates', static_folder='static')
|
||
app.config['SECRET_KEY'] = Config.SECRET_KEY
|
||
CORS(app, supports_credentials=True)
|
||
|
||
# 初始化数据库连接池
|
||
from db import init_db_pool
|
||
init_db_pool()
|
||
|
||
# 注册路由蓝图
|
||
from routes.auth import bp as auth_bp
|
||
from routes.trades import bp as trades_bp
|
||
from routes.watchlist import bp as watchlist_bp
|
||
from routes.analysis import bp as analysis_bp
|
||
from routes.market import bp as market_bp
|
||
from routes.sim_trade import bp as sim_trade_bp
|
||
from routes.admin import bp as admin_bp
|
||
from routes.smart_trade import bp as smart_trade_bp
|
||
|
||
app.register_blueprint(auth_bp)
|
||
app.register_blueprint(trades_bp)
|
||
app.register_blueprint(watchlist_bp)
|
||
app.register_blueprint(analysis_bp)
|
||
app.register_blueprint(market_bp)
|
||
app.register_blueprint(sim_trade_bp)
|
||
app.register_blueprint(admin_bp)
|
||
app.register_blueprint(smart_trade_bp)
|
||
|
||
|
||
# ========== 基础路由 ==========
|
||
|
||
@app.route('/')
|
||
def index():
|
||
"""首页"""
|
||
return render_template('index.html')
|
||
|
||
|
||
@app.route('/api/health', methods=['GET'])
|
||
def health():
|
||
"""健康检查"""
|
||
return jsonify({'status': 'ok', 'message': '服务运行正常'})
|
||
|
||
|
||
# ========== 静态文件安全 ==========
|
||
|
||
@app.route('/robots.txt')
|
||
def robots():
|
||
return "User-agent: *\nDisallow: /api/\nDisallow: /admin\n", 200, {'Content-Type': 'text/plain'}
|
||
|
||
|
||
@app.route('/.env')
|
||
def block_env():
|
||
from flask import abort
|
||
abort(404)
|
||
|
||
|
||
# ========== 启动 ==========
|
||
|
||
_scheduler_started = False
|
||
|
||
|
||
def _start_scheduler_once():
|
||
"""确保调度器只启动一次(兼容 gunicorn preload + Flask dev reloader)"""
|
||
global _scheduler_started
|
||
if _scheduler_started:
|
||
return
|
||
_scheduler_started = True
|
||
from services.scheduler import start_scheduler
|
||
start_scheduler()
|
||
# 启动时预热市场级外部因素缓存(后台线程,不阻塞启动)
|
||
import threading
|
||
def _preheat():
|
||
try:
|
||
from services.score_engine import precompute_market_factors
|
||
precompute_market_factors()
|
||
except Exception as e:
|
||
print(f"[启动] 外部因素预热失败: {e}")
|
||
threading.Thread(target=_preheat, daemon=True).start()
|
||
|
||
|
||
if __name__ == '__main__':
|
||
print("=" * 60)
|
||
print("股票投资分析系统启动")
|
||
print("=" * 60)
|
||
print(f"Web界面: http://localhost:{Config.PORT}")
|
||
print(f"API地址: http://localhost:{Config.PORT}/api/")
|
||
print(f"健康检查: http://localhost:{Config.PORT}/api/health")
|
||
print("=" * 60)
|
||
|
||
_start_scheduler_once()
|
||
app.run(debug=True, host='0.0.0.0', port=Config.PORT)
|
||
else:
|
||
_start_scheduler_once()
|