"""
配置管理器 - 从数据库读取配置，兼容原有config.py
支持Redis缓存，实现配置即时生效
"""
import sys
import os
import json
import re
from pathlib import Path
from typing import Optional, Any

# 加载.env文件
try:
    from dotenv import load_dotenv
    backend_dir = Path(__file__).parent
    project_root = backend_dir.parent
    env_files = [
        backend_dir / '.env',
        project_root / '.env',
    ]
    for env_file in env_files:
        if env_file.exists():
            load_dotenv(env_file, override=True)
            break
    else:
        load_dotenv(project_root / '.env', override=False)
except ImportError:
    pass
except Exception:
    pass

# 添加项目根目录到路径
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

# 延迟导入，避免在trading_system中导入时因为缺少依赖而失败
try:
    from database.models import TradingConfig, Account
except ImportError as e:
    TradingConfig = None
    Account = None
    import logging
    logger = logging.getLogger(__name__)
    logger.warning(f"无法导入TradingConfig: {e}，配置管理器将无法使用数据库")

import logging

logger = logging.getLogger(__name__)

# 平台兜底：策略核心使用全局配置表（global_strategy_config），普通用户账号只允许调整“风险旋钮”
# 执行策略合并顺序：普通用户（账号）配置优先，未设置时使用全局配置，允许用户简单控制自己的交易并只影响本人执行
# - 风险旋钮：每个账号独立（仓位/频次等），账号有则用账号，无则用全局
# - 其它策略参数：账号有则用账号，无则用全局（管理员可在全局配置设默认，用户可覆盖）
# 注意：不再依赖account_id=1，全局配置存储在独立的global_strategy_config表中

_MISSING = object()  # 用于区分“账号未设置”与“值为 None/0/False”

RISK_KNOBS_KEYS = {
    "MIN_MARGIN_USDT",
    "MIN_POSITION_PERCENT",
    "MAX_POSITION_PERCENT",
    "MAX_TOTAL_POSITION_PERCENT",
    "AUTO_TRADE_ENABLED",
    "MAX_OPEN_POSITIONS",
    "MAX_DAILY_ENTRIES",
    "SUNDAY_MAX_OPENS",
    "SUNDAY_MIN_SIGNAL_STRENGTH",
    "NIGHT_HOURS_NO_OPEN_ENABLED",
    "NIGHT_HOURS_START",
    "NIGHT_HOURS_END",
    # 2026-02-06 Added for Altcoin Strategy presets
    "TOP_N_SYMBOLS",
    "MIN_SIGNAL_STRENGTH",
    "MIN_VOLUME_24H",
    "MIN_VOLATILITY",
    "SCAN_EXTRA_SYMBOLS_FOR_SUPPLEMENT",
    "EXCLUDE_MAJOR_COINS",
    # 2026-02-06 Added for User Customization
    "MAX_SCAN_SYMBOLS",
    "SCAN_INTERVAL",
}

# 尝试导入同步Redis客户端（用于配置缓存）
try:
    import redis
    REDIS_SYNC_AVAILABLE = True
except ImportError:
    REDIS_SYNC_AVAILABLE = False
    redis = None


class GlobalStrategyConfigManager:
    """全局策略配置管理器（独立于账户，管理员专用）"""
    
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self):
        if hasattr(self, '_initialized'):
            return
        self._initialized = True
        self._cache = {}
        self._redis_client: Optional[redis.Redis] = None
        self._redis_connected = False
        self._redis_hash_key = "global_strategy_config_v5"  # 独立的Redis键 (v5: 强制刷新缓存 - 2025-02-14)
        self._init_redis()
        self._load_from_db()
    
    def _init_redis(self):
        """初始化Redis客户端（同步）"""
        if not REDIS_SYNC_AVAILABLE:
            logger.debug("redis-py未安装，全局配置缓存将不使用Redis")
            return
        
        try:
            redis_url = os.getenv('REDIS_URL', 'redis://localhost:6379')
            redis_use_tls = os.getenv('REDIS_USE_TLS', 'False').lower() == 'true'
            redis_username = os.getenv('REDIS_USERNAME', None)
            redis_password = os.getenv('REDIS_PASSWORD', None)
            
            if not redis_url or not isinstance(redis_url, str):
                redis_url = 'redis://localhost:6379'
            
            if redis_use_tls and not redis_url.startswith('rediss://'):
                if redis_url.startswith('redis://'):
                    redis_url = redis_url.replace('redis://', 'rediss://', 1)
            
            connection_kwargs = {
                'username': redis_username,
                'password': redis_password,
                'decode_responses': True
            }
            
            if redis_url.startswith('rediss://') or redis_use_tls:
                ssl_cert_reqs = os.getenv('REDIS_SSL_CERT_REQS', 'required')
                ssl_ca_certs = os.getenv('REDIS_SSL_CA_CERTS', None)
                connection_kwargs['select'] = int(os.getenv('REDIS_SELECT', 0))
                connection_kwargs['ssl_cert_reqs'] = ssl_cert_reqs
                if ssl_ca_certs:
                    connection_kwargs['ssl_ca_certs'] = ssl_ca_certs
                if ssl_cert_reqs == 'none':
                    connection_kwargs['ssl_check_hostname'] = False
                elif ssl_cert_reqs == 'required':
                    connection_kwargs['ssl_check_hostname'] = True
                else:
                    connection_kwargs['ssl_check_hostname'] = False
            
            self._redis_client = redis.from_url(redis_url, **connection_kwargs)
            self._redis_client.ping()
            self._redis_connected = True
            logger.info("✓ 全局策略配置Redis缓存连接成功")
        except Exception as e:
            logger.debug(f"全局策略配置Redis缓存连接失败: {e}，将使用数据库缓存")
            self._redis_client = None
            self._redis_connected = False
    
    def _get_from_redis(self, key: str) -> Optional[Any]:
        """从Redis获取全局配置值"""
        if not self._redis_connected or not self._redis_client:
            return None
        
        try:
            value = self._redis_client.hget(self._redis_hash_key, key)
            if value is not None and value != '':
                return ConfigManager._coerce_redis_value(value)
        except Exception as e:
            logger.debug(f"从Redis获取全局配置失败 {key}: {e}")
            try:
                self._redis_client.ping()
                self._redis_connected = True
            except:
                self._redis_connected = False
        
        return None
    
    def _set_to_redis(self, key: str, value: Any):
        """设置全局配置到Redis"""
        if not self._redis_connected or not self._redis_client:
            return False
        
        try:
            if isinstance(value, (dict, list, bool, int, float)):
                value_str = json.dumps(value, ensure_ascii=False)
            else:
                value_str = str(value)
            
            self._redis_client.hset(self._redis_hash_key, key, value_str)
            self._redis_client.expire(self._redis_hash_key, 3600)
            return True
        except Exception as e:
            logger.debug(f"设置全局配置到Redis失败 {key}: {e}")
            try:
                self._redis_client.ping()
                self._redis_connected = True
            except:
                self._redis_connected = False
            return False
    
    def _load_from_db(self):
        """从数据库加载全局配置"""
        try:
            from database.models import GlobalStrategyConfig
        except ImportError:
            logger.warning("GlobalStrategyConfig未导入，无法从数据库加载全局配置")
            self._cache = {}
            return
        
        try:
            # 先尝试从Redis加载
            if self._redis_connected and self._redis_client:
                try:
                    self._redis_client.ping()
                    redis_configs = self._redis_client.hgetall(self._redis_hash_key)
                    if redis_configs and len(redis_configs) > 0:
                        for key, value_str in redis_configs.items():
                            self._cache[key] = ConfigManager._coerce_redis_value(value_str)
                        logger.info(f"从Redis加载了 {len(self._cache)} 个全局配置项")
                        return
                except Exception as e:
                    logger.debug(f"从Redis加载全局配置失败: {e}，回退到数据库")
                    try:
                        self._redis_client.ping()
                    except:
                        self._redis_connected = False
            
            # 从数据库加载
            configs = GlobalStrategyConfig.get_all()
            for config in configs:
                key = config['config_key']
                # 使用TradingConfig的转换方法（GlobalStrategyConfig复用）
                from database.models import TradingConfig
                value = TradingConfig._convert_value(
                    config['config_value'],
                    config['config_type']
                )
                self._cache[key] = value
                self._set_to_redis(key, value)
            
            logger.info(f"从数据库加载了 {len(self._cache)} 个全局配置项，已同步到Redis")
        except Exception as e:
            logger.warning(f"从数据库加载全局配置失败，使用默认配置: {e}")
            self._cache = {}
    
    def get(self, key: str, default: Any = None) -> Any:
        """获取全局配置值"""
        # 1. 优先从Redis缓存读取
        if self._redis_connected and self._redis_client:
            redis_value = self._get_from_redis(key)
            if redis_value is not None:
                self._cache[key] = redis_value
                return redis_value
        
        # 2. 从本地缓存读取
        if key in self._cache:
            return self._cache[key]
        
        # 3. 从数据库读取
        try:
            from database.models import GlobalStrategyConfig
            db_value = GlobalStrategyConfig.get_value(key)
            if db_value is not None:
                self._cache[key] = db_value
                self._set_to_redis(key, db_value)
                return db_value
        except Exception:
            pass
        
        # 4. 从环境变量读取
        env_value = os.getenv(key)
        if env_value is not None:
            return env_value
        
        # 5. 返回默认值
        return default
    
    def reload_from_redis(self):
        """强制从Redis重新加载全局配置"""
        if not self._redis_connected or not self._redis_client:
            return
        
        try:
            self._redis_client.ping()
        except Exception as e:
            logger.debug(f"Redis连接不可用: {e}，跳过从Redis重新加载")
            self._redis_connected = False
            return
        
        try:
            redis_configs = self._redis_client.hgetall(self._redis_hash_key)
            if redis_configs and len(redis_configs) > 0:
                self._cache = {}
                for key, value_str in redis_configs.items():
                    self._cache[key] = ConfigManager._coerce_redis_value(value_str)
                logger.debug(f"从Redis重新加载了 {len(self._cache)} 个全局配置项")
        except Exception as e:
            logger.debug(f"从Redis重新加载全局配置失败: {e}，保持现有缓存")


class ConfigManager:
    """配置管理器 - 优先从Redis缓存读取，其次从数据库读取，回退到环境变量和默认值"""
    
    _instances = {}

    def __init__(self, account_id: int = 1):
        self.account_id = int(account_id or 1)
        self._cache = {}
        self._redis_client: Optional[redis.Redis] = None
        self._redis_connected = False
        self._redis_hash_key = f"trading_config:{self.account_id}"
        self._legacy_hash_key = "trading_config" if self.account_id == 1 else None
        self._init_redis()
        self._load_from_db()

    @classmethod
    def for_account(cls, account_id: int):
        aid = int(account_id or 1)
        inst = cls._instances.get(aid)
        if inst:
            return inst
        inst = cls(account_id=aid)
        cls._instances[aid] = inst
        return inst
    
    def _init_redis(self):
        """初始化Redis客户端（同步）"""
        if not REDIS_SYNC_AVAILABLE:
            logger.debug("redis-py未安装，配置缓存将不使用Redis")
            return
        
        try:
            # 从环境变量或配置获取Redis连接信息
            redis_url = os.getenv('REDIS_URL', 'redis://localhost:6379')
            redis_use_tls = os.getenv('REDIS_USE_TLS', 'False').lower() == 'true'
            redis_username = os.getenv('REDIS_USERNAME', None)
            redis_password = os.getenv('REDIS_PASSWORD', None)
            
            # 验证URL格式
            if not redis_url or not isinstance(redis_url, str):
                logger.warning(f"Redis URL无效: {redis_url}，使用默认值")
                redis_url = 'redis://localhost:6379'
            
            # 如果使用TLS但URL不是rediss://，自动转换
            if redis_use_tls and not redis_url.startswith('rediss://'):
                if redis_url.startswith('redis://'):
                    redis_url = redis_url.replace('redis://', 'rediss://', 1)
                else:
                    # 如果URL格式不正确，构建新的URL
                    logger.warning(f"Redis URL格式不正确且需要TLS: {redis_url}，尝试构建rediss://URL")
                    # 尝试从URL中提取主机和端口
                    if '://' in redis_url:
                        parts = redis_url.split('://', 1)
                        host_port = parts[1].split('/')[0] if '/' in parts[1] else parts[1]
                        redis_url = f"rediss://{host_port}"
                    else:
                        # 如果完全没有scheme，添加rediss://
                        redis_url = f"rediss://{redis_url}"
                logger.info(f"已自动转换Redis URL为TLS格式: {redis_url}")
            
            # 解析Redis URL
            # redis-py的同步客户端也支持通过ssl_cert_reqs等参数配置TLS
            # 当URL是rediss://时，会自动启用SSL
            connection_kwargs = {
                'username': redis_username,
                'password': redis_password,
                'decode_responses': True
            }
            
            if redis_url.startswith('rediss://') or redis_use_tls:
                # TLS连接 - 使用redis-py支持的SSL参数
                # 从环境变量获取SSL配置（如果未设置，使用默认值）
                ssl_cert_reqs = os.getenv('REDIS_SSL_CERT_REQS', 'required')
                ssl_ca_certs = os.getenv('REDIS_SSL_CA_CERTS', None)
                
                connection_kwargs['select'] = os.getenv('REDIS_SELECT', 0)
                if connection_kwargs['select'] is not None:
                    connection_kwargs['select'] = int(connection_kwargs['select'])
                else:
                    connection_kwargs['select'] = 0
                logger.info(f"使用 Redis 数据库: {connection_kwargs['select']}")
                # 设置SSL参数
                connection_kwargs['ssl_cert_reqs'] = ssl_cert_reqs
                if ssl_ca_certs:
                    connection_kwargs['ssl_ca_certs'] = ssl_ca_certs
                
                # 根据ssl_cert_reqs设置主机名验证
                if ssl_cert_reqs == 'none':
                    connection_kwargs['ssl_check_hostname'] = False
                elif ssl_cert_reqs == 'required':
                    connection_kwargs['ssl_check_hostname'] = True
                else:  # optional
                    connection_kwargs['ssl_check_hostname'] = False
                
                logger.info(f"使用 TLS 连接 Redis: {redis_url} (ssl_cert_reqs={ssl_cert_reqs})")
            
            # 创建Redis客户端（同步）
            self._redis_client = redis.from_url(
                redis_url,
                **connection_kwargs
            )
            
            # 测试连接
            self._redis_client.ping()
            self._redis_connected = True
            logger.info("✓ Redis配置缓存连接成功")
        except Exception as e:
            logger.debug(f"Redis配置缓存连接失败: {e}，将使用数据库缓存")
            self._redis_client = None
            self._redis_connected = False
    
    def _get_from_redis(self, key: str) -> Optional[Any]:
        """从Redis获取配置值"""
        if not self._redis_connected or not self._redis_client:
            return None
        
        try:
            # 使用账号维度 Hash 存储所有配置
            value = self._redis_client.hget(self._redis_hash_key, key)
            if (value is None or value == '') and self._legacy_hash_key:
                value = self._redis_client.hget(self._legacy_hash_key, key)
            if value is not None and value != '':
                return self._coerce_redis_value(value)
        except Exception as e:
            logger.debug(f"从Redis获取配置失败 {key}: {e}")
            # 连接失败时，尝试重新连接
            try:
                self._redis_client.ping()
                self._redis_connected = True
            except:
                self._redis_connected = False
        
        return None

    @staticmethod
    def _coerce_redis_value(value_str: Any) -> Any:
        """
        将 Redis Hash 中的字符串值尽量还原为正确类型。

        兼容历史写法：
        - 之前 bool 会被写成 "True"/"False"（非 JSON），导致读取后变成字符串，进而在逻辑判断里永远为 True。
        - 现在会优先把 bool/int/float/dict/list 用 JSON 序列化写入（见 _set_to_redis）。
        """
        if value_str is None:
            return None

        # redis-py decode_responses=True 时是 str；否则可能是 bytes
        if isinstance(value_str, bytes):
            try:
                value_str = value_str.decode('utf-8', errors='ignore')
            except Exception:
                value_str = str(value_str)

        s = str(value_str).strip()
        if s == '':
            return ''

        # 1) JSON 优先（dict/list/bool/number 都能覆盖）
        try:
            return json.loads(s)
        except Exception:
            pass

        sl = s.lower()
        # 2) bool 兼容（历史 "True"/"False"）
        if sl in ('true', 'false', '1', '0', 'yes', 'no', 'on', 'off'):
            return sl in ('true', '1', 'yes', 'on')

        # 3) number 兼容（避免把 "1h" 之类误判）
        # int: -?\d+
        if re.fullmatch(r'-?\d+', s):
            try:
                return int(s)
            except Exception:
                return s
        # float: -?\d+\.\d+
        if re.fullmatch(r'-?\d+\.\d+', s):
            try:
                return float(s)
            except Exception:
                return s

        return s
    
    def _set_to_redis(self, key: str, value: Any):
        """设置配置到Redis（账号维度 + legacy兼容）"""
        if not self._redis_connected or not self._redis_client:
            return False
        
        try:
            # 将值序列化：复杂类型/基础类型使用 JSON，避免 bool 被写成 "False" 字符串后逻辑误判
            if isinstance(value, (dict, list, bool, int, float)):
                value_str = json.dumps(value, ensure_ascii=False)
            else:
                value_str = str(value)
            
            self._redis_client.hset(self._redis_hash_key, key, value_str)
            self._redis_client.expire(self._redis_hash_key, 3600)
            if self._legacy_hash_key:
                self._redis_client.hset(self._legacy_hash_key, key, value_str)
                self._redis_client.expire(self._legacy_hash_key, 3600)
            return True
        except Exception as e:
            logger.debug(f"设置配置到Redis失败 {key}: {e}")
            # 连接失败时，尝试重新连接
            try:
                self._redis_client.ping()
                self._redis_connected = True
                # 重试一次
                if isinstance(value, (dict, list, bool, int, float)):
                    value_str = json.dumps(value, ensure_ascii=False)
                else:
                    value_str = str(value)
                self._redis_client.hset(self._redis_hash_key, key, value_str)
                self._redis_client.expire(self._redis_hash_key, 3600)
                if self._legacy_hash_key:
                    self._redis_client.hset(self._legacy_hash_key, key, value_str)
                    self._redis_client.expire(self._legacy_hash_key, 3600)
                return True
            except:
                self._redis_connected = False
                return False
    
    def _load_all_to_redis(self):
        """将所有配置加载到Redis"""
        if not self._redis_connected or not self._redis_client:
            return
        
        try:
            # 批量设置所有配置到Redis（账号维度）
            pipe = self._redis_client.pipeline()
            for key, value in self._cache.items():
                if isinstance(value, (dict, list, bool, int, float)):
                    value_str = json.dumps(value, ensure_ascii=False)
                else:
                    value_str = str(value)
                pipe.hset(self._redis_hash_key, key, value_str)
            pipe.expire(self._redis_hash_key, 3600)
            if self._legacy_hash_key:
                for key, value in self._cache.items():
                    if isinstance(value, (dict, list, bool, int, float)):
                        value_str = json.dumps(value, ensure_ascii=False)
                    else:
                        value_str = str(value)
                    pipe.hset(self._legacy_hash_key, key, value_str)
                pipe.expire(self._legacy_hash_key, 3600)
            pipe.execute()
            logger.debug(f"已将 {len(self._cache)} 个配置项同步到Redis")
        except Exception as e:
            logger.debug(f"同步配置到Redis失败: {e}")
    
    def _load_from_db(self):
        """从数据库加载配置（如果Redis中没有）"""
        if TradingConfig is None:
            logger.warning("TradingConfig未导入，无法从数据库加载配置")
            self._cache = {}
            return
        
        try:
            # 先尝试从Redis加载所有配置
            if self._redis_connected and self._redis_client:
                try:
                    # 测试连接是否真正可用
                    self._redis_client.ping()
                    redis_configs = self._redis_client.hgetall(self._redis_hash_key)
                    if (not redis_configs) and self._legacy_hash_key:
                        redis_configs = self._redis_client.hgetall(self._legacy_hash_key)
                    if redis_configs and len(redis_configs) > 0:
                        # 解析Redis中的配置
                        for key, value_str in redis_configs.items():
                            self._cache[key] = self._coerce_redis_value(value_str)
                        logger.info(f"从Redis加载了 {len(self._cache)} 个配置项")
                        return
                    else:
                        # Redis中没有配置，需要从数据库加载并同步到Redis
                        logger.debug("Redis中没有配置数据，从数据库加载并同步到Redis")
                except Exception as e:
                    logger.debug(f"从Redis加载配置失败: {e}，回退到数据库")
                    # 连接失败时，标记为未连接
                    try:
                        self._redis_client.ping()
                    except:
                        self._redis_connected = False
            
            # 从数据库加载配置（仅在Redis不可用或Redis中没有数据时）
            configs = TradingConfig.get_all(account_id=self.account_id)
            for config in configs:
                key = config['config_key']
                value = TradingConfig._convert_value(
                    config['config_value'], 
                    config['config_type']
                )
                self._cache[key] = value
                # 同时写入Redis缓存
                self._set_to_redis(key, value)
            
            logger.info(f"从数据库加载了 {len(self._cache)} 个配置项，已同步到Redis")
        except Exception as e:
            logger.warning(f"从数据库加载配置失败，使用默认配置: {e}")
            self._cache = {}
    
    def get(self, key, default=None):
        """获取配置值"""
        # 账号私有：API Key/Secret/Testnet 从 accounts 表读取（不走 trading_config）
        if key in ("BINANCE_API_KEY", "BINANCE_API_SECRET", "USE_TESTNET") and Account is not None:
            try:
                api_key, api_secret, use_testnet, status = Account.get_credentials(self.account_id)
                logger.debug(f"ConfigManager.get({key}, account_id={self.account_id}): api_key存在={bool(api_key)}, api_secret存在={bool(api_secret)}, status={status}")
                if key == "BINANCE_API_KEY":
                    # 如果 api_key 为空字符串，返回 None 而不是 default（避免返回 'your_api_key_here'）
                    if not api_key or api_key.strip() == "":
                        logger.warning(f"ConfigManager.get(BINANCE_API_KEY, account_id={self.account_id}): API密钥为空字符串")
                        return None  # 返回 None，让调用方知道密钥未配置
                    return api_key
                if key == "BINANCE_API_SECRET":
                    # 如果 api_secret 为空字符串，返回 None 而不是 default（避免返回 'your_api_secret_here'）
                    if not api_secret or api_secret.strip() == "":
                        logger.warning(f"ConfigManager.get(BINANCE_API_SECRET, account_id={self.account_id}): API密钥Secret为空字符串")
                        return None  # 返回 None，让调用方知道密钥未配置
                    return api_secret
                return bool(use_testnet)
            except Exception as e:
                # 回退到后续逻辑（旧数据/无表）
                logger.warning(f"ConfigManager.get({key}, account_id={self.account_id}): Account.get_credentials 失败: {e}")
                pass

        # 1. 优先从Redis缓存读取（最新）
        # 注意：只在Redis连接正常时尝试读取，避免频繁连接失败
        if self._redis_connected and self._redis_client:
            redis_value = self._get_from_redis(key)
            if redis_value is not None:
                # 同时更新本地缓存
                self._cache[key] = redis_value
                return redis_value
        
        # 2. 从本地缓存读取
        if key in self._cache:
            return self._cache[key]
        
        # 3. 从全局策略配置读取（如果账号未设置）
        # API密钥等敏感信息不走全局配置
        if key not in ("BINANCE_API_KEY", "BINANCE_API_SECRET", "USE_TESTNET"):
            try:
                # GlobalStrategyConfigManager是单例，开销很小
                global_val = GlobalStrategyConfigManager().get(key)
                if global_val is not None:
                    return global_val
            except Exception:
                pass

        # 4. 从环境变量读取
        env_value = os.getenv(key)
        if env_value is not None:
            return env_value
        
        # 4. 返回默认值
        return default
    
    def set(self, key, value, config_type='string', category='general', description=None):
        """设置配置（同时更新数据库、Redis缓存和本地缓存）"""
        # 账号私有：API Key/Secret/Testnet 写入 accounts 表
        if key in ("BINANCE_API_KEY", "BINANCE_API_SECRET", "USE_TESTNET") and Account is not None:
            try:
                if key == "BINANCE_API_KEY":
                    Account.update_credentials(self.account_id, api_key=str(value or ""))
                elif key == "BINANCE_API_SECRET":
                    Account.update_credentials(self.account_id, api_secret=str(value or ""))
                else:
                    Account.update_credentials(self.account_id, use_testnet=bool(value))
                self._cache[key] = value
                return
            except Exception as e:
                logger.error(f"更新账号API配置失败: {e}")
                raise

        if TradingConfig is None:
            logger.warning("TradingConfig未导入，无法更新数据库配置")
            self._cache[key] = value
            # 仍然尝试更新Redis
            self._set_to_redis(key, value)
            return
        
        try:
            # 1. 更新数据库
            TradingConfig.set(key, value, config_type, category, description, account_id=self.account_id)
            
            # 2. 更新本地缓存
            self._cache[key] = value
            
            # 3. 更新Redis缓存（确保trading_system能立即读取到最新配置）
            self._set_to_redis(key, value)
            
            logger.info(f"配置已更新: {key} = {value} (已同步到数据库和Redis)")
        except Exception as e:
            logger.error(f"更新配置失败: {e}")
            raise
    
    def reload(self):
        """重新加载配置（优先从Redis，其次从数据库）"""
        self._cache = {}
        self._load_from_db()
    
    def reload_from_redis(self):
        """强制从Redis重新加载配置（用于trading_system即时获取最新配置）"""
        # 如果Redis不可用，不重新加载，保持现有缓存
        if not self._redis_connected or not self._redis_client:
            logger.debug("Redis未连接，跳过从Redis重新加载，保持现有缓存")
            return
        
        try:
            # 测试连接是否真正可用
            self._redis_client.ping()
        except Exception as e:
            logger.debug(f"Redis连接不可用: {e}，跳过从Redis重新加载")
            self._redis_connected = False
            return
        
        try:
            redis_configs = self._redis_client.hgetall(self._redis_hash_key)
            if (not redis_configs) and self._legacy_hash_key:
                redis_configs = self._redis_client.hgetall(self._legacy_hash_key)
            if redis_configs and len(redis_configs) > 0:
                self._cache = {}  # 清空缓存
                for key, value_str in redis_configs.items():
                    self._cache[key] = self._coerce_redis_value(value_str)
                logger.debug(f"从Redis重新加载了 {len(self._cache)} 个配置项")
            else:
                # Redis中没有配置，但不回退到数据库（避免频繁从数据库加载）
                logger.debug("Redis中没有配置数据，保持现有缓存")
        except Exception as e:
            logger.debug(f"从Redis重新加载配置失败: {e}，保持现有缓存")
            # 连接失败时，标记为未连接
            try:
                self._redis_client.ping()
            except:
                self._redis_connected = False
    
    def get_trading_config(self):
        """获取交易配置字典（兼容原有config.py的TRADING_CONFIG）"""
        # 全局策略配置管理器（从独立的global_strategy_config表读取）
        global_config_mgr = GlobalStrategyConfigManager()
        try:
            global_config_mgr.reload_from_redis()
        except Exception:
            pass

        def eff_get(key: str, default: Any):
            """
            执行策略合并：账号（用户）配置优先，未设置时使用全局配置，只影响该账号的交易执行。
            - API key/secret/testnet 仅账号，无全局兜底。
            - 其余项：先读账号，有则用；无则用全局，再无则用 default。
            """
            value_from_account = False
            if key in ("BINANCE_API_KEY", "BINANCE_API_SECRET", "USE_TESTNET"):
                value = self.get(key, default)
                value_from_account = True
            else:
                account_val = self.get(key, _MISSING)
                if account_val is not _MISSING:
                    value = account_val
                    value_from_account = True
                else:
                    try:
                        value = global_config_mgr.get(key, default)
                    except Exception:
                        value = default

            # ⚠️ 临时兼容性处理：百分比配置值格式转换
            # 如果配置值是百分比形式（>1），转换为比例形式（除以100）
            # 兼容数据库中可能存在的旧数据（百分比形式，如30表示30%）
            # 数据迁移完成后，可以移除此逻辑
            # 统一格式：数据库、前端、后端都使用比例形式（0.30表示30%）
            if isinstance(value, (int, float)) and value is not None:
                # 需要转换的百分比配置项
                percent_keys = [
                    'TRAILING_STOP_ACTIVATION',
                    'TRAILING_STOP_PROTECT',
                    'LOCK_PROFIT_STAGE1_TRIGGER_PCT',
                    'LOCK_PROFIT_STAGE1_PCT',
                    'LOCK_PROFIT_STAGE2_TRIGGER_PCT',
                    'LOCK_PROFIT_STAGE2_PCT',
                    'MIN_VOLATILITY',
                    'TAKE_PROFIT_PERCENT',
                    'TAKE_PROFIT_1_PERCENT',  # 分步止盈第一目标（默认15%）
                    'STOP_LOSS_PERCENT',
                    'MIN_STOP_LOSS_PRICE_PCT',
                    'MIN_TAKE_PROFIT_PRICE_PCT',
                    'FIXED_RISK_PERCENT',
                    'MAX_POSITION_PERCENT',
                    'MAX_TOTAL_POSITION_PERCENT',
                    'MIN_POSITION_PERCENT',
                ]
                
                if key in percent_keys:
                    # 如果值>1，认为是百分比形式（旧数据），转换为比例形式
                    # 静默转换，不输出警告（用户已确认数据库应存储小数形式）
                    if value > 1:
                        value = value / 100.0
                        # 静默更新缓存：值来自账号则写回账号，否则写回全局
                        try:
                            if value_from_account:
                                self._set_to_redis(key, value)
                                self._cache[key] = value
                            else:
                                global_config_mgr._set_to_redis(key, value)
                                global_config_mgr._cache[key] = value
                        except Exception as e:
                            logger.debug(f"更新Redis缓存失败（不影响使用）: {key} = {e}")
            
            return value

        # 交易预设：控制一组参数的“默认性格”
        profile = str(eff_get('TRADING_PROFILE', 'conservative') or 'conservative').lower()
        is_fast = profile in ('fast', 'fast_test', 'aggressive')

        max_daily_default = 30 if is_fast else 8
        scan_interval_default = 900 if is_fast else 1800
        min_signal_default = 7 if is_fast else 8  # 2026-01-29优化：稳健模式从9降到8（平衡胜率和交易频率）
        cooldown_default = 900 if is_fast else 1800
        allow_neutral_default = True if is_fast else False
        short_filter_default = False if is_fast else True
        max_trend_move_default = 0.08 if is_fast else 0.05

        result = {
            # 仓位控制
            'MAX_POSITION_PERCENT': eff_get('MAX_POSITION_PERCENT', 0.12),  # 单笔最大保证金占比（12%，加大单笔盈利空间）
            'MAX_TOTAL_POSITION_PERCENT': eff_get('MAX_TOTAL_POSITION_PERCENT', 0.40),  # 总保证金占比上限
            'MIN_POSITION_PERCENT': eff_get('MIN_POSITION_PERCENT', 0.02),  # 最小保证金占比
            'MIN_MARGIN_USDT': eff_get('MIN_MARGIN_USDT', 2.0),  # 最小保证金（USDT）

            # 用户风险旋钮：自动交易开关/频次控制
            'AUTO_TRADE_ENABLED': eff_get('AUTO_TRADE_ENABLED', True),
            'MAX_OPEN_POSITIONS': eff_get('MAX_OPEN_POSITIONS', 3),
            'MAX_DAILY_ENTRIES': eff_get('MAX_DAILY_ENTRIES', max_daily_default),
            'SUNDAY_MAX_OPENS': eff_get('SUNDAY_MAX_OPENS', 3),  # 周日开仓上限，0=不限制
            'SUNDAY_MIN_SIGNAL_STRENGTH': eff_get('SUNDAY_MIN_SIGNAL_STRENGTH', 8),  # 周日最低信号强度，0=不提高
            'NIGHT_HOURS_NO_OPEN_ENABLED': eff_get('NIGHT_HOURS_NO_OPEN_ENABLED', True),
            'NIGHT_HOURS_START': eff_get('NIGHT_HOURS_START', 21),
            'NIGHT_HOURS_END': eff_get('NIGHT_HOURS_END', 6),
            'NIGHT_HOURS_ONLY_SUNDAY': eff_get('NIGHT_HOURS_ONLY_SUNDAY', True),
            'NO_OPEN_HOURS_BJ': (eff_get('NO_OPEN_HOURS_BJ', '') or '').strip(),  # 禁止开仓小时（北京），逗号分隔如 "17,19,22"，空则不限制

            # 同步/系统单标识（全局配置，账号可覆盖）
            'ONLY_AUTO_TRADE_CREATES_RECORDS': eff_get('ONLY_AUTO_TRADE_CREATES_RECORDS', True),  # True=不补建「仅币安有仓」；False 时配合 SYNC_RECOVER 可补建
            'SYNC_RECOVER_MISSING_POSITIONS': eff_get('SYNC_RECOVER_MISSING_POSITIONS', True),
            'SYNC_RECOVER_ONLY_WHEN_HAS_SLTP': eff_get('SYNC_RECOVER_ONLY_WHEN_HAS_SLTP', True),
            'SYSTEM_ORDER_ID_PREFIX': eff_get('SYSTEM_ORDER_ID_PREFIX', 'SYS') or '',
            
            # 涨跌幅阈值
            'MIN_CHANGE_PERCENT': eff_get('MIN_CHANGE_PERCENT', 2.0),
            
            # 风险控制
            # ⚠️ 2026-01-29优化：放宽止损，减少被正常波动扫出
            # - 提高ATR倍数（从1.5到2.0），给市场波动更多空间
            # - 提高最小价格变动百分比（从2%到2.5%），避免止损过紧
            'STOP_LOSS_PERCENT': eff_get('STOP_LOSS_PERCENT', 0.12),  # 默认12%（保证金百分比）
            'TAKE_PROFIT_PERCENT': eff_get('TAKE_PROFIT_PERCENT', 0.30),  # 默认30%（第二目标/单目标止盈）
            'TAKE_PROFIT_1_PERCENT': eff_get('TAKE_PROFIT_1_PERCENT', 0.20),  # 默认20%（2026-02-12优化：拉高第一目标改善盈亏比）
            'MIN_STOP_LOSS_PRICE_PCT': eff_get('MIN_STOP_LOSS_PRICE_PCT', 0.025),  # 默认2.5%（2026-01-29优化：从2%提高到2.5%，给波动更多空间）
            'MIN_TAKE_PROFIT_PRICE_PCT': eff_get('MIN_TAKE_PROFIT_PRICE_PCT', 0.02),  # 默认2%（防止ATR过小时计算出不切实际的微小止盈距离）
            'USE_ATR_STOP_LOSS': eff_get('USE_ATR_STOP_LOSS', True),  # 是否使用ATR动态止损
            'ATR_STOP_LOSS_MULTIPLIER': eff_get('ATR_STOP_LOSS_MULTIPLIER', 3.0),  # ATR止损倍数3.0（2026-02-12优化：减少噪音止损，配合止盈拉远）
            'ATR_TAKE_PROFIT_MULTIPLIER': eff_get('ATR_TAKE_PROFIT_MULTIPLIER', 2.0),  # ATR止盈倍数2.0（2026-01-27优化：降低止盈目标，更容易触发）
            'RISK_REWARD_RATIO': eff_get('RISK_REWARD_RATIO', 3.0),  # 盈亏比3:1（2026-01-27优化：降低，更容易触发，保证胜率）
            'ATR_PERIOD': eff_get('ATR_PERIOD', 14),  # ATR计算周期
            'USE_DYNAMIC_ATR_MULTIPLIER': eff_get('USE_DYNAMIC_ATR_MULTIPLIER', False),  # 是否根据波动率动态调整ATR倍数
            'ATR_MULTIPLIER_MIN': eff_get('ATR_MULTIPLIER_MIN', 1.5),  # 动态ATR倍数最小值
            'ATR_MULTIPLIER_MAX': eff_get('ATR_MULTIPLIER_MAX', 2.5),  # 动态ATR倍数最大值
            
            # 固定风险百分比仓位计算（凯利公式）
            'USE_FIXED_RISK_SIZING': eff_get('USE_FIXED_RISK_SIZING', True),  # 使用固定风险百分比计算仓位
            'FIXED_RISK_PERCENT': eff_get('FIXED_RISK_PERCENT', 0.02),  # 每笔单子承受的风险（2%）
            # 仓位放大系数：1.0=正常，1.2=+20% 仓位，上限 2.0，仍受 MAX_POSITION_PERCENT 约束（盈利时适度放大用）
            'POSITION_SCALE_FACTOR': eff_get('POSITION_SCALE_FACTOR', 1.0),

            # 市场扫描（30分钟主周期）
            'SCAN_INTERVAL': eff_get('SCAN_INTERVAL', scan_interval_default),  # 30分钟（增加交易机会）
            'TOP_N_SYMBOLS': eff_get('TOP_N_SYMBOLS', 20),  # 每次扫描后优先处理的交易对数量
            'SCAN_EXTRA_SYMBOLS_FOR_SUPPLEMENT': eff_get('SCAN_EXTRA_SYMBOLS_FOR_SUPPLEMENT', 15),  # 智能补单：多返回的候选数量，冷却时仍可尝试后续交易对
            'MAX_SCAN_SYMBOLS': eff_get('MAX_SCAN_SYMBOLS', 500),  # 扫描的最大交易对数量（增加到500）
            'EXCLUDE_MAJOR_COINS': eff_get('EXCLUDE_MAJOR_COINS', True),  # 是否排除主流币（BTC、ETH、BNB等），专注于山寨币
            'KLINE_INTERVAL': eff_get('KLINE_INTERVAL', '1h'),
            'PRIMARY_INTERVAL': eff_get('PRIMARY_INTERVAL', '1h'),
            'CONFIRM_INTERVAL': eff_get('CONFIRM_INTERVAL', '4h'),
            'ENTRY_INTERVAL': eff_get('ENTRY_INTERVAL', '15m'),
            
            # 过滤条件
            'MIN_VOLUME_24H': eff_get('MIN_VOLUME_24H', 10000000),
            'MIN_VOLATILITY': eff_get('MIN_VOLATILITY', 0.02),
            
            # 高胜率策略参数
            # ⚠️ 2026-01-29优化：提高信号强度门槛（稳健模式从9到8），减少低质量信号，提升胜率
            'MIN_SIGNAL_STRENGTH': eff_get('MIN_SIGNAL_STRENGTH', min_signal_default),  # 默认值随 profile 调整（快速模式7，稳健模式8）
            'LEVERAGE': eff_get('LEVERAGE', 10),
            'USE_DYNAMIC_LEVERAGE': eff_get('USE_DYNAMIC_LEVERAGE', True),
            'MAX_LEVERAGE': eff_get('MAX_LEVERAGE', 20),  # 动态杠杆上限 20，配合单笔仓位提高收益
            'MIN_LEVERAGE': eff_get('MIN_LEVERAGE', 8),   # 动态杠杆下限，不低于此值（之前盈利阶段多为 8x，避免被压到 2–4x 导致单笔盈利过少）
            'MAX_LEVERAGE_SMALL_CAP': eff_get('MAX_LEVERAGE_SMALL_CAP', 8),  # 高波动/小众币最大杠杆，默认 8 与之前盈利阶段一致
            # 盈利保护总开关与保本：关闭后不执行保本、不执行移动止损
            'PROFIT_PROTECTION_ENABLED': eff_get('PROFIT_PROTECTION_ENABLED', True),  # True=启用保本+移动止损，False=全部关闭
            'LOCK_PROFIT_AT_BREAKEVEN_AFTER_PCT': eff_get('LOCK_PROFIT_AT_BREAKEVEN_AFTER_PCT', 0.03),  # 盈利达保证金比例时移至保本（0.03=3%，0=关闭）
            'LOCK_PROFIT_STAGE1_TRIGGER_PCT': eff_get('LOCK_PROFIT_STAGE1_TRIGGER_PCT', 0.08),  # 盈利达该比例后进入第一层锁盈
            'LOCK_PROFIT_STAGE1_PCT': eff_get('LOCK_PROFIT_STAGE1_PCT', 0.02),  # 第一层锁住的利润比例
            'LOCK_PROFIT_STAGE2_TRIGGER_PCT': eff_get('LOCK_PROFIT_STAGE2_TRIGGER_PCT', 0.15),  # 盈利达该比例后进入第二层锁盈
            'LOCK_PROFIT_STAGE2_PCT': eff_get('LOCK_PROFIT_STAGE2_PCT', 0.05),  # 第二层锁住的利润比例
            # 移动止损
            'USE_TRAILING_STOP': eff_get('USE_TRAILING_STOP', True),  # 默认启用（2026-01-27优化：启用移动止损，保护利润）
            'TRAILING_STOP_ACTIVATION': eff_get('TRAILING_STOP_ACTIVATION', 0.05),  # 默认5%（2026-01-27优化：更早保护利润，避免回吐）
            'TRAILING_STOP_PROTECT': eff_get('TRAILING_STOP_PROTECT', 0.025),  # 默认2.5%（2026-01-27优化：给回撤足够空间，避免被震荡扫出）
            
            # 最小持仓时间锁（强制波段持仓纪律，避免分钟级平仓）
            'MIN_HOLD_TIME_SEC': eff_get('MIN_HOLD_TIME_SEC', 1800),  # 默认30分钟（1800秒）

            # 自动交易过滤（用于提升胜率/控频）
            # 说明：这两个 key 需要出现在 TRADING_CONFIG 中，否则 trading_system 在每次 reload_from_redis 后会丢失它们，
            # 导致始终按默认值拦截自动交易（用户在配置页怎么开都没用）。
            'AUTO_TRADE_ONLY_TRENDING': eff_get('AUTO_TRADE_ONLY_TRENDING', True),
            'AUTO_TRADE_ALLOW_RANGING': eff_get('AUTO_TRADE_ALLOW_RANGING', False),
            'AUTO_TRADE_ALLOW_UNKNOWN': eff_get('AUTO_TRADE_ALLOW_UNKNOWN', False),
            'AUTO_TRADE_ALLOW_4H_NEUTRAL': eff_get('AUTO_TRADE_ALLOW_4H_NEUTRAL', allow_neutral_default),
            'RANGING_MARKET_SIGNAL_BOOST': eff_get('RANGING_MARKET_SIGNAL_BOOST', 2),

            # 智能入场/限价偏移（部分逻辑会直接读取 TRADING_CONFIG）
            'LIMIT_ORDER_OFFSET_PCT': eff_get('LIMIT_ORDER_OFFSET_PCT', 0.5),
            'SMART_ENTRY_ENABLED': eff_get('SMART_ENTRY_ENABLED', False),
            'SMART_ENTRY_STRONG_SIGNAL': eff_get('SMART_ENTRY_STRONG_SIGNAL', min_signal_default),
            'ENTRY_SYMBOL_COOLDOWN_SEC': eff_get('ENTRY_SYMBOL_COOLDOWN_SEC', cooldown_default),
            'ENTRY_TIMEOUT_SEC': eff_get('ENTRY_TIMEOUT_SEC', 180),
            'ENTRY_STEP_WAIT_SEC': eff_get('ENTRY_STEP_WAIT_SEC', 15),
            'ENTRY_CHASE_MAX_STEPS': eff_get('ENTRY_CHASE_MAX_STEPS', 4),
            'ENTRY_MARKET_FALLBACK_AFTER_SEC': eff_get('ENTRY_MARKET_FALLBACK_AFTER_SEC', 45),
            'ENTRY_CONFIRM_TIMEOUT_SEC': eff_get('ENTRY_CONFIRM_TIMEOUT_SEC', 30),
            'ENTRY_MAX_DRIFT_PCT_TRENDING': eff_get('ENTRY_MAX_DRIFT_PCT_TRENDING', 0.006),
            'ENTRY_MAX_DRIFT_PCT_RANGING': eff_get('ENTRY_MAX_DRIFT_PCT_RANGING', 0.3),
            # Algo 条件单（止损/止盈）单次请求超时（秒），币安接口高负载时易超时，网络不稳可调大至 60
            'ALGO_ORDER_TIMEOUT_SEC': eff_get('ALGO_ORDER_TIMEOUT_SEC', 45),

            # 持仓详细监控日志开关（用于排查问题时观察每次检查的当前价/目标价/ROE 等）
            'POSITION_DETAILED_LOG_ENABLED': eff_get('POSITION_DETAILED_LOG_ENABLED', False),
            
            # 动态过滤优化
            'BETA_FILTER_ENABLED': eff_get('BETA_FILTER_ENABLED', True),  # 大盘共振过滤：BTC/ETH下跌时屏蔽多单
            'BETA_FILTER_THRESHOLD': eff_get('BETA_FILTER_THRESHOLD', -0.005),  # -0.5%（2026-01-27优化：更敏感地过滤大盘风险，15分钟内跌幅超过0.5%即屏蔽多单）
            # RSI / 24h 涨跌幅过滤（避免追高杀跌）
            'MAX_RSI_FOR_LONG': eff_get('MAX_RSI_FOR_LONG', 65),  # 做多时 RSI 超过此值则不开多（2026-02-12：65 避免追高）
            'MAX_CHANGE_PERCENT_FOR_LONG': eff_get('MAX_CHANGE_PERCENT_FOR_LONG', 25),  # 做多时 24h 涨跌幅超过此值则不开多
            'MIN_RSI_FOR_SHORT': eff_get('MIN_RSI_FOR_SHORT', 30),  # 做空时 RSI 低于此值则不做空
            'MAX_CHANGE_PERCENT_FOR_SHORT': eff_get('MAX_CHANGE_PERCENT_FOR_SHORT', 10),  # 做空时 24h 涨跌幅超过此值则不做空
            # RSI 极限反转（与盈利期对齐：关闭可避免趋势里逆势止损）
            'RSI_EXTREME_REVERSE_ENABLED': eff_get('RSI_EXTREME_REVERSE_ENABLED', False),
            'RSI_EXTREME_REVERSE_ONLY_NEUTRAL_4H': eff_get('RSI_EXTREME_REVERSE_ONLY_NEUTRAL_4H', True),
            # 止盈/止损按保证金封顶（避免 TP 过远、SL 过宽扛单）
            'USE_MARGIN_CAP_FOR_TP': eff_get('USE_MARGIN_CAP_FOR_TP', True),
            'USE_MARGIN_CAP_FOR_SL': eff_get('USE_MARGIN_CAP_FOR_SL', True),

            # 趋势尾部入场过滤 & 15m 短周期方向过滤开关（由 profile 控制默认值）
            'ENTRY_SHORT_INTERVAL': eff_get('ENTRY_SHORT_INTERVAL', '15m'),
            'ENTRY_SHORT_TREND_FILTER_ENABLED': eff_get('ENTRY_SHORT_TREND_FILTER_ENABLED', short_filter_default),
            'ENTRY_SHORT_TREND_MIN_PCT': eff_get('ENTRY_SHORT_TREND_MIN_PCT', 0.003),
            'ENTRY_SHORT_CONFIRM_CANDLES': eff_get('ENTRY_SHORT_CONFIRM_CANDLES', 3),
            'USE_TREND_ENTRY_FILTER': eff_get('USE_TREND_ENTRY_FILTER', True),
            # ⚠️ 2026-01-29优化：收紧趋势尾部过滤（稳健模式从0.05到0.04），更严格避免追高杀跌
            'MAX_TREND_MOVE_BEFORE_ENTRY': eff_get('MAX_TREND_MOVE_BEFORE_ENTRY', max_trend_move_default),  # 快速模式0.08，稳健模式0.04
            'TREND_STATE_TTL_SEC': eff_get('TREND_STATE_TTL_SEC', 3600),
            'RECO_USE_TREND_ENTRY_FILTER': eff_get('RECO_USE_TREND_ENTRY_FILTER', True),
            'RECO_MAX_TREND_MOVE_BEFORE_ENTRY': eff_get('RECO_MAX_TREND_MOVE_BEFORE_ENTRY', 0.04),
            # 回撤/区间入场（前低前高）
            'ENTRY_PULLBACK_FILTER_ENABLED': eff_get('ENTRY_PULLBACK_FILTER_ENABLED', False),
            'ENTRY_PULLBACK_INTERVAL': eff_get('ENTRY_PULLBACK_INTERVAL', None),
            'ENTRY_PULLBACK_LOOKBACK_BARS': eff_get('ENTRY_PULLBACK_LOOKBACK_BARS', 24),
            'ENTRY_PULLBACK_MIN_BARS': eff_get('ENTRY_PULLBACK_MIN_BARS', 5),
            'ENTRY_PULLBACK_MAX_LONG_IN_RANGE': eff_get('ENTRY_PULLBACK_MAX_LONG_IN_RANGE', 0.62),
            'ENTRY_PULLBACK_MIN_SHORT_IN_RANGE': eff_get('ENTRY_PULLBACK_MIN_SHORT_IN_RANGE', 0.38),

            # 影子模式半自动化
            'SHADOW_MODE_AUTO_APPLY': eff_get('SHADOW_MODE_AUTO_APPLY', False),
            'SHADOW_MODE_MIN_CONFIDENCE': eff_get('SHADOW_MODE_MIN_CONFIDENCE', 0.7),
            'SHADOW_MODE_SUGGESTIONS_PATH': eff_get('SHADOW_MODE_SUGGESTIONS_PATH', 'config/current_suggestions.json'),
            'SHADOW_MODE_TRACKING_PATH': eff_get('SHADOW_MODE_TRACKING_PATH', 'config/shadow_mode_tracking.json'),
            'SHADOW_MODE_INCREASE_LEVERAGE_MULT': eff_get('SHADOW_MODE_INCREASE_LEVERAGE_MULT', 1.5),
            'SHADOW_MODE_DECREASE_LEVERAGE_MULT': eff_get('SHADOW_MODE_DECREASE_LEVERAGE_MULT', 0.5),

            # 当前交易预设（让 trading_system 能知道是哪种模式）
            'TRADING_PROFILE': profile,
            
            # ⚠️ 2026-01-29新增：同一交易对连续亏损过滤（避免连续亏损后继续交易）
            'SYMBOL_LOSS_COOLDOWN_ENABLED': eff_get('SYMBOL_LOSS_COOLDOWN_ENABLED', True),
            'SYMBOL_MAX_CONSECUTIVE_LOSSES': eff_get('SYMBOL_MAX_CONSECUTIVE_LOSSES', 2),
            'SYMBOL_LOSS_COOLDOWN_SEC': eff_get('SYMBOL_LOSS_COOLDOWN_SEC', 3600),
            # 第一目标止盈最小盈亏比（相对止损距离）
            'MIN_RR_FOR_TP1': eff_get('MIN_RR_FOR_TP1', 1.5),  # 2026-02-12：保证 TP1 至少 1.5 倍止损距离，改善盈亏比

            # 市场状态方案（便于在不同行情间切换）
            'MARKET_SCHEME': str(eff_get('MARKET_SCHEME', 'normal') or 'normal').lower(),
            'BLOCK_LONG_WHEN_4H_DOWN': eff_get('BLOCK_LONG_WHEN_4H_DOWN', False),  # 4H 下跌时禁止开多（熊市/保守用）
            'BLOCK_SHORT_WHEN_4H_UP': eff_get('BLOCK_SHORT_WHEN_4H_UP', True),  # 4H 上涨时禁止开空（默认 True，避免逆势做空）
            # 全局市场方案下禁空/禁多：牛市不推空单、熊市不推多单
            'BLOCK_SHORT_WHEN_BULL_MARKET': eff_get('BLOCK_SHORT_WHEN_BULL_MARKET', True),  # 市场方案=牛市时禁止开空
            'BLOCK_LONG_WHEN_BEAR_MARKET': eff_get('BLOCK_LONG_WHEN_BEAR_MARKET', True),  # 市场方案=熊市时禁止开多
        }

        # 根据市场方案覆盖关键参数（便于快速切换熊市/牛市/保守等预设）
        _SCHEME_PRESETS = {
            'normal': {
                'MIN_STOP_LOSS_PRICE_PCT': 0.03,
                'MAX_POSITION_PERCENT': 0.12,
                'ATR_STOP_LOSS_MULTIPLIER': 2.5,
                'BLOCK_LONG_WHEN_4H_DOWN': False,
                'BLOCK_SHORT_WHEN_4H_UP': True,    # 4H 上涨不开空
            },
            'bear': {
                'MIN_STOP_LOSS_PRICE_PCT': 0.05,   # 放宽止损约 -5%
                'MAX_POSITION_PERCENT': 0.08,      # 单仓 ≤ 8%
                'ATR_STOP_LOSS_MULTIPLIER': 2.5,
                'BLOCK_LONG_WHEN_4H_DOWN': True,   # 4H 下跌不开多
                'BLOCK_SHORT_WHEN_4H_UP': True,    # 4H 上涨不开空
                'BETA_FILTER_ENABLED': True,
            },
            'bull': {
                'MIN_STOP_LOSS_PRICE_PCT': 0.03,
                'MAX_POSITION_PERCENT': 0.12,
                'ATR_STOP_LOSS_MULTIPLIER': 2.0,
                'BLOCK_LONG_WHEN_4H_DOWN': False,
                'BLOCK_SHORT_WHEN_4H_UP': True,    # 4H 上涨不开空（牛市尤需）
            },
            'conservative': {
                'MIN_STOP_LOSS_PRICE_PCT': 0.06,   # 最宽松止损
                'MAX_POSITION_PERCENT': 0.06,      # 最小仓位
                'ATR_STOP_LOSS_MULTIPLIER': 2.5,
                'BLOCK_LONG_WHEN_4H_DOWN': True,
                'BLOCK_SHORT_WHEN_4H_UP': True,
                'BETA_FILTER_ENABLED': True,
            },
        }
        scheme = result.get('MARKET_SCHEME', 'normal') or 'normal'
        if scheme in _SCHEME_PRESETS:
            for k, v in _SCHEME_PRESETS[scheme].items():
                result[k] = v
        return result

    def _sync_to_redis(self):
        """将配置同步到Redis缓存（账号维度）"""
        if not self._redis_connected or not self._redis_client:
            return
        try:
            payload = {k: json.dumps(v) for k, v in self._cache.items()}
            self._redis_client.hset(self._redis_hash_key, mapping=payload)
            self._redis_client.expire(self._redis_hash_key, 3600)
            if self._legacy_hash_key:
                self._redis_client.hset(self._legacy_hash_key, mapping=payload)
                self._redis_client.expire(self._legacy_hash_key, 3600)
        except Exception as e:
            logger.debug(f"同步配置到Redis失败: {e}")

# 全局配置管理器实例（默认账号；trading_system 进程可通过 ATS_ACCOUNT_ID 指定）
try:
    _default_account_id = int(os.getenv("ATS_ACCOUNT_ID") or os.getenv("ACCOUNT_ID") or 1)
except Exception:
    _default_account_id = 1
config_manager = ConfigManager.for_account(_default_account_id)

# 兼容原有config.py的接口
def get_config(key, default=None):
    """获取配置（兼容函数）"""
    return config_manager.get(key, default)

def get_trading_config():
    """获取交易配置（兼容函数）"""
    return config_manager.get_trading_config()
