diff --git a/backend_api_python/app/routes/strategy.py b/backend_api_python/app/routes/strategy.py index a9b6834..17d7df5 100644 --- a/backend_api_python/app/routes/strategy.py +++ b/backend_api_python/app/routes/strategy.py @@ -816,9 +816,6 @@ def get_strategy_notifications(): user_strategy_ids = [r.get('id') for r in rows if r.get('id')] cur.close() - if not user_strategy_ids: - return jsonify({'code': 1, 'msg': 'success', 'data': {'items': []}}) - where = [] args = [] @@ -830,9 +827,15 @@ def get_strategy_notifications(): else: return jsonify({'code': 1, 'msg': 'success', 'data': {'items': []}}) else: - placeholders = ",".join(["?"] * len(user_strategy_ids)) - where.append(f"strategy_id IN ({placeholders})") - args.extend(user_strategy_ids) + if user_strategy_ids: + placeholders = ",".join(["?"] * len(user_strategy_ids)) + where.append(f"(strategy_id IN ({placeholders}) OR (strategy_id IS NULL AND user_id = ?))") + args.extend(user_strategy_ids) + args.append(user_id) + else: + # Only portfolio monitor notifications (strategy_id is NULL) + where.append("strategy_id IS NULL AND user_id = ?") + args.append(user_id) if since_id: where.append("id > ?") @@ -889,15 +892,18 @@ def mark_notification_read(): if not notification_id: return jsonify({'code': 0, 'msg': 'Missing id'}), 400 - # Only update notifications for user's strategies + # Update notifications for user's strategies OR portfolio monitor notifications with get_db_connection() as db: cur = db.cursor() cur.execute( """ UPDATE qd_strategy_notifications SET is_read = 1 - WHERE id = ? AND strategy_id IN (SELECT id FROM qd_strategies_trading WHERE user_id = ?) + WHERE id = ? AND ( + strategy_id IN (SELECT id FROM qd_strategies_trading WHERE user_id = ?) + OR (strategy_id IS NULL AND user_id = ?) + ) """, - (int(notification_id), user_id) + (int(notification_id), user_id, user_id) ) db.commit() cur.close() @@ -920,8 +926,9 @@ def mark_all_notifications_read(): """ UPDATE qd_strategy_notifications SET is_read = 1 WHERE strategy_id IN (SELECT id FROM qd_strategies_trading WHERE user_id = ?) + OR (strategy_id IS NULL AND user_id = ?) """, - (user_id,) + (user_id, user_id) ) db.commit() cur.close() @@ -944,8 +951,9 @@ def clear_notifications(): """ DELETE FROM qd_strategy_notifications WHERE strategy_id IN (SELECT id FROM qd_strategies_trading WHERE user_id = ?) + OR (strategy_id IS NULL AND user_id = ?) """, - (user_id,) + (user_id, user_id) ) db.commit() cur.close() diff --git a/backend_api_python/app/services/portfolio_monitor.py b/backend_api_python/app/services/portfolio_monitor.py index 0c35f03..9288153 100644 --- a/backend_api_python/app/services/portfolio_monitor.py +++ b/backend_api_python/app/services/portfolio_monitor.py @@ -768,8 +768,9 @@ def _send_monitor_notification( cur.close() elif ch == 'telegram': chat_id = targets.get('telegram', '') + token_override = targets.get('telegram_bot_token', '') if chat_id: - notifier._notify_telegram(chat_id=chat_id, text=f"{error_title}\n\n{error_msg}", parse_mode="HTML") + notifier._notify_telegram(chat_id=chat_id, text=f"{error_title}\n\n{error_msg}", token_override=token_override, parse_mode="HTML") elif ch == 'email': to_email = targets.get('email', '') if to_email: @@ -815,11 +816,13 @@ def _send_monitor_notification( elif ch == 'telegram': chat_id = targets.get('telegram', '') + token_override = targets.get('telegram_bot_token', '') if chat_id: # Use Telegram-optimized format notifier._notify_telegram( chat_id=chat_id, text=telegram_report, + token_override=token_override, parse_mode="HTML" ) @@ -1099,8 +1102,9 @@ def _check_position_alerts(): cur.close() elif ch == 'telegram': chat_id = targets.get('telegram', '') + token_override = targets.get('telegram_bot_token', '') if chat_id: - notifier._notify_telegram(chat_id=chat_id, text=alert_message, parse_mode="HTML") + notifier._notify_telegram(chat_id=chat_id, text=alert_message, token_override=token_override, parse_mode="HTML") elif ch == 'email': to_email = targets.get('email', '') if to_email: diff --git a/backend_api_python/app/services/trading_executor.py b/backend_api_python/app/services/trading_executor.py index 1c49b80..a026f29 100644 --- a/backend_api_python/app/services/trading_executor.py +++ b/backend_api_python/app/services/trading_executor.py @@ -52,29 +52,48 @@ class TradingExecutor: self._ensure_db_columns() def _ensure_db_columns(self): - """确保必要的数据库字段存在""" + """确保必要的数据库字段存在(支持 SQLite 和 PostgreSQL)""" try: + db_type = os.getenv('DB_TYPE', 'sqlite').lower() with get_db_connection() as db: cursor = db.cursor() + col_names = set() - # SQLite 兼容:使用 PRAGMA table_info 检查列是否存在 - try: - cursor.execute("PRAGMA table_info(qd_strategy_positions)") - cols = cursor.fetchall() or [] - col_names = {c.get('name') for c in cols if isinstance(c, dict)} - except Exception: - col_names = set() + if db_type == 'postgresql': + # PostgreSQL: 使用 information_schema 查询列 + try: + cursor.execute(""" + SELECT column_name FROM information_schema.columns + WHERE table_name = 'qd_strategy_positions' + """) + cols = cursor.fetchall() or [] + col_names = {c.get('column_name') or c.get('COLUMN_NAME') for c in cols if isinstance(c, dict)} + except Exception: + col_names = set() + else: + # SQLite: 使用 PRAGMA table_info + try: + cursor.execute("PRAGMA table_info(qd_strategy_positions)") + cols = cursor.fetchall() or [] + col_names = {c.get('name') for c in cols if isinstance(c, dict)} + except Exception: + col_names = set() if 'highest_price' not in col_names: - logger.info("Adding highest_price column to qd_strategy_positions (SQLite)...") - # SQLite 不支持 AFTER 子句,类型用 REAL 即可 - cursor.execute("ALTER TABLE qd_strategy_positions ADD COLUMN highest_price REAL DEFAULT 0") + logger.info(f"Adding highest_price column to qd_strategy_positions ({db_type})...") + if db_type == 'postgresql': + cursor.execute("ALTER TABLE qd_strategy_positions ADD COLUMN IF NOT EXISTS highest_price DOUBLE PRECISION DEFAULT 0") + else: + cursor.execute("ALTER TABLE qd_strategy_positions ADD COLUMN highest_price REAL DEFAULT 0") db.commit() logger.info("highest_price column added") if 'lowest_price' not in col_names: - logger.info("Adding lowest_price column to qd_strategy_positions (SQLite)...") - cursor.execute("ALTER TABLE qd_strategy_positions ADD COLUMN lowest_price REAL DEFAULT 0") + logger.info(f"Adding lowest_price column to qd_strategy_positions ({db_type})...") + if db_type == 'postgresql': + cursor.execute("ALTER TABLE qd_strategy_positions ADD COLUMN IF NOT EXISTS lowest_price DOUBLE PRECISION DEFAULT 0") + else: + cursor.execute("ALTER TABLE qd_strategy_positions ADD COLUMN lowest_price REAL DEFAULT 0") db.commit() logger.info("lowest_price column added")