From a14313fdbdb27afdb6c1f48bf68f6218b4f4ab62 Mon Sep 17 00:00:00 2001 From: zzlgreat Date: Wed, 3 Dec 2025 07:26:12 +0800 Subject: [PATCH] update pay ui --- app.py | 133 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 87 insertions(+), 46 deletions(-) diff --git a/app.py b/app.py index 29d70bdf..f023aab3 100755 --- a/app.py +++ b/app.py @@ -5897,6 +5897,21 @@ def get_stock_quotes(): start_datetime = datetime.combine(trading_day, start_time) end_datetime = datetime.combine(trading_day, end_time) + # 获取前一个交易日(用于计算涨跌幅基准) + prev_trading_day = None + with engine.connect() as conn: + result = conn.execute(text(""" + SELECT EXCHANGE_DATE + FROM trading_days + WHERE EXCHANGE_DATE < :date + ORDER BY EXCHANGE_DATE DESC + LIMIT 1 + """), {"date": trading_day}).fetchone() + if result: + prev_trading_day = result[0].date() if hasattr(result[0], 'date') else result[0] + + print(f"当前交易日: {trading_day}, 前一交易日: {prev_trading_day}") + # If the trading day is in the future relative to current time, # return only names without data if trading_day > current_time.date(): @@ -5912,20 +5927,38 @@ def get_stock_quotes(): # ==================== 性能优化:批量查询所有股票数据 ==================== # 使用 IN 子句一次查询所有股票,避免逐只循环查询 try: - # 批量查询价格和涨跌幅数据(使用窗口函数) - # 涨跌幅基于当日开盘价计算:(最新价 - 开盘价) / 开盘价 * 100 + # 先从 MySQL ea_trade 表查询前一交易日的收盘价(日线数据,查询更快) + prev_close_map = {} + if prev_trading_day: + with engine.connect() as conn: + # 提取不带后缀的股票代码用于查询 + base_codes = list(set([code.split('.')[0] for code in codes])) + if base_codes: + placeholders = ','.join([f':code{i}' for i in range(len(base_codes))]) + params = {f'code{i}': code for i, code in enumerate(base_codes)} + params['trade_date'] = prev_trading_day + + prev_close_result = conn.execute(text(f""" + SELECT SECCODE, F007N as close_price + FROM ea_trade + WHERE SECCODE IN ({placeholders}) + AND TRADEDATE = :trade_date + """), params).fetchall() + + # 构建代码到收盘价的映射(需要匹配完整代码格式) + base_close_map = {row[0]: float(row[1]) if row[1] else None for row in prev_close_result} + + # 为每个完整代码(带后缀)分配收盘价 + for code in codes: + base_code = code.split('.')[0] + if base_code in base_close_map: + prev_close_map[code] = base_close_map[base_code] + + print(f"前一交易日({prev_trading_day})收盘价查询返回 {len(prev_close_result)} 条数据") + + # 批量查询当前价格数据 batch_price_query = """ - WITH open_prices AS ( - SELECT - code, - open as open_price, - ROW_NUMBER() OVER (PARTITION BY code ORDER BY timestamp ASC) as rn - FROM stock_minute - WHERE code IN %(codes)s - AND timestamp >= %(start)s - AND timestamp <= %(end)s - ), - last_prices AS ( + WITH last_prices AS ( SELECT code, close as last_price, @@ -5935,13 +5968,9 @@ def get_stock_quotes(): AND timestamp >= %(start)s AND timestamp <= %(end)s ) - SELECT - op.code, - lp.last_price, - (lp.last_price - op.open_price) / op.open_price * 100 as change_pct - FROM open_prices op - INNER JOIN last_prices lp ON op.code = lp.code - WHERE op.rn = 1 AND lp.rn = 1 + SELECT code, last_price + FROM last_prices + WHERE rn = 1 """ batch_data = client.execute(batch_price_query, { @@ -5952,12 +5981,18 @@ def get_stock_quotes(): print(f"批量查询返回 {len(batch_data)} 条价格数据") - # 解析批量查询结果 + # 解析批量查询结果,使用前一交易日收盘价计算涨跌幅 price_data_map = {} for row in batch_data: code = row[0] last_price = float(row[1]) if row[1] is not None else None - change_pct = float(row[2]) if row[2] is not None else None + prev_close = prev_close_map.get(code) + + # 计算涨跌幅:(当前价 - 前一交易日收盘价) / 前一交易日收盘价 * 100 + change_pct = None + if last_price is not None and prev_close is not None and prev_close > 0: + change_pct = (last_price - prev_close) / prev_close * 100 + price_data_map[code] = { 'price': last_price, 'change': change_pct @@ -5982,34 +6017,40 @@ def get_stock_quotes(): except Exception as e: print(f"批量查询 ClickHouse 失败: {e},回退到逐只查询") - # 降级方案:逐只股票查询(保持向后兼容) + # 降级方案:逐只股票查询(使用前一交易日收盘价计算涨跌幅) for code in codes: try: - data = client.execute(""" - WITH first_price AS ( - SELECT close FROM stock_minute - WHERE code = %(code)s AND timestamp >= %(start)s AND timestamp <= %(end)s - ORDER BY timestamp LIMIT 1 - ), - last_price AS ( - SELECT close FROM stock_minute - WHERE code = %(code)s AND timestamp >= %(start)s AND timestamp <= %(end)s - ORDER BY timestamp DESC LIMIT 1 - ) - SELECT last_price.close as last_price, - (last_price.close - first_price.close) / first_price.close * 100 as change - FROM last_price CROSS JOIN first_price - WHERE EXISTS (SELECT 1 FROM first_price) AND EXISTS (SELECT 1 FROM last_price) + # 查询当前价格 + current_data = client.execute(""" + SELECT close FROM stock_minute + WHERE code = %(code)s AND timestamp >= %(start)s AND timestamp <= %(end)s + ORDER BY timestamp DESC LIMIT 1 """, {'code': code, 'start': start_datetime, 'end': end_datetime}) - if data and data[0] and data[0][0] is not None: - results[code] = { - 'price': float(data[0][0]) if data[0][0] is not None else None, - 'change': float(data[0][1]) if data[0][1] is not None else None, - 'name': stock_names.get(code, f'股票{code.split(".")[0]}') - } - else: - results[code] = {'price': None, 'change': None, 'name': stock_names.get(code, f'股票{code.split(".")[0]}')} + last_price = float(current_data[0][0]) if current_data and current_data[0] and current_data[0][0] else None + + # 从 MySQL ea_trade 表查询前一交易日收盘价 + prev_close = None + if prev_trading_day and last_price is not None: + base_code = code.split('.')[0] + with engine.connect() as conn: + prev_result = conn.execute(text(""" + SELECT F007N as close_price + FROM ea_trade + WHERE SECCODE = :code AND TRADEDATE = :trade_date + """), {'code': base_code, 'trade_date': prev_trading_day}).fetchone() + prev_close = float(prev_result[0]) if prev_result and prev_result[0] else None + + # 计算涨跌幅 + change_pct = None + if last_price is not None and prev_close is not None and prev_close > 0: + change_pct = (last_price - prev_close) / prev_close * 100 + + results[code] = { + 'price': last_price, + 'change': change_pct, + 'name': stock_names.get(code, f'股票{code.split(".")[0]}') + } except Exception as inner_e: print(f"Error processing stock {code}: {inner_e}") results[code] = {'price': None, 'change': None, 'name': stock_names.get(code, f'股票{code.split(".")[0]}')}