"""全局配置：路径、日期、资金、策略参数等。

所有路径尽量通过 BASE_DIR 派生，避免硬编码。
"""
from pathlib import Path

from utils.logger import setup_logger

logger = setup_logger(__name__)

# 项目根目录：假设本文件位于 strategy_backtest/config/settings.py
BASE_DIR: Path = Path(__file__).resolve().parent.parent.parent

# 数据与结果目录
DATA_DAY_DIR: Path = BASE_DIR / "data" / "day"
DATA_INDEX_DIR: Path = BASE_DIR / "data" / "index"  # 指数数据目录
CODE_DIR: Path = BASE_DIR / "data" / "code"
RESULTS_DIR: Path = BASE_DIR / "strategy_backtest" / "results"

# 股票代码列表文件（如果存在，可以作为股票池来源）
STOCK_CODE_FILE: Path = CODE_DIR / "all_stock_codes.txt"

# 基准指数配置
BENCHMARK_FILE: Path = DATA_INDEX_DIR / "000001.SH.txt"  # 上证指数
BENCHMARK_NAME: str = "上证指数"  # 基准指数名称

# 回测时间区间（含首尾），格式：YYYYMMDD
START_DATE: str = "20220101"
END_DATE: str = "20251231"

# 初始资金
INITIAL_CASH: float = 1000000.0

# ==================== 策略参数配置 ====================
# 每个策略都有自己独立的一套参数

# 均线交叉策略参数
MACROSS_MA_SHORT: int = 5       # 快速均线周期
MACROSS_MA_LONG: int = 15       # 慢速均线周期
MACROSS_HOLD_DAYS: int = 3     # 持有天数
MACROSS_MAX_POSITIONS: int = 2  # 最多持仓股票数
MACROSS_POSITION_PCT_PER_STOCK: float = 0.2  # 每只个股占总资金的比例（0.2 = 20%）

# 均线交叉策略风控参数
MACROSS_RISK_CONTROL = {
    "stop_loss": {
        "method": "fixed_pct",      # 止损方法：fixed_pct / atr / trailing
        "stop_pct": 0.05,           # 固定百分比止损（5%）
        "atr_period": 14,           # ATR周期
        "atr_multiplier": 2.0,      # ATR倍数
        "trailing_pct": 0.10,       # 跟踪止损回撤比例
    },
    "take_profit": {
        "method": "fixed_pct",      # 止盈方法：fixed_pct / atr / trailing
        "stop_pct": 0.10,           # 固定百分比止盈（10%）
        "atr_period": 14,
        "atr_multiplier": 3.0,
        "trailing_pct": 0.15,       # 跟踪止盈回撤比例
    },
}

# OCZ策略参数
OCZ_N: int = 30          # 阻力回望长度
OCZ_B: float = 60.0      # 实体占比门槛(%)
OCZ_V1: float = 1.5      # 放量倍数
OCZ_TOL: float = 1.5     # 回踩容错(%)
OCZ_R: float = 6.0       # 收盘涨幅门槛(%)
OCZ_HOLD_DAYS: int = 5   # 持有天数
OCZ_MAX_POSITIONS: int = 2  # 最多持仓股票数
OCZ_POSITION_PCT_PER_STOCK: float = 0.2  # 每只个股占总资金的比例
OCZ_VOLATILITY_MIN: float = 2.5  # 最小波动率(%)
OCZ_VOLATILITY_MAX: float = 8.0  # 最大波动率(%)

# OCZ策略风控参数（突破回踩策略特点：特殊止损止盈逻辑）
# 注意：OCZ策略使用策略内部的特殊止损止盈逻辑，不使用通用风控模块
# 止损位 = 突破的阻力位，止盈位 = 买入价 + (买入价 - 阻力位) * 2 (盈亏比1:2)
OCZ_RISK_CONTROL = {
    "stop_loss": {
        "method": "custom",            # 使用策略自定义逻辑，不使用通用风控模块
        "stop_pct": 0,                 # 占位参数，实际不使用
    },
    "take_profit": {
        "method": "custom",            # 使用策略自定义逻辑
        "stop_pct": 0,                 # 占位参数，实际不使用
    },
}

# ====================  策略配置 ====================
# 所有策略定义（统一管理）
STRATEGIES = {
    "MaCrossStrategy": {
        "module": "strategies.ma_cross",
        "params": {
            "ma_short": MACROSS_MA_SHORT,
            "ma_long": MACROSS_MA_LONG,
            "hold_days": MACROSS_HOLD_DAYS,
            "max_positions": MACROSS_MAX_POSITIONS,
            "position_pct_per_stock": MACROSS_POSITION_PCT_PER_STOCK,
        },
        "risk_control": MACROSS_RISK_CONTROL,  # 每个策略独立的风控配置
    },
    "OczStrategy": {
        "module": "strategies.ocz_strategy",
        "params": {
            "N": OCZ_N,
            "B": OCZ_B,
            "V1": OCZ_V1,
            "TOL": OCZ_TOL,
            "R": OCZ_R,
            "hold_days": OCZ_HOLD_DAYS,
            "volatility_min": OCZ_VOLATILITY_MIN,
            "volatility_max": OCZ_VOLATILITY_MAX,
            "max_positions": OCZ_MAX_POSITIONS,
            "position_pct_per_stock": OCZ_POSITION_PCT_PER_STOCK,
        },
        "risk_control": OCZ_RISK_CONTROL,  # 每个策略独立的风控配置
    },
}

# 策略开关（0=不回测, 1=回测）
# 作用：控制哪些策略需要回测，无需注释代码
STRATEGY_SWITCHES = {
    "MaCrossStrategy": 1,  # 1=开启均线交叉策略回测
    "OczStrategy": 0,      # 1=开启OCZ策略回测
}

# 为了兼容旧代码，保留STRATEGY变量（指向首个开启的策略）
STRATEGY = None
for strategy_name, switch in STRATEGY_SWITCHES.items():
    if switch == 1 and strategy_name in STRATEGIES:
        STRATEGY = {
            "name": strategy_name,
            "module": STRATEGIES[strategy_name]["module"],
            "params": STRATEGIES[strategy_name]["params"],
        }
        break

# 如果没有任何策略开启，默认使用第一个策略
if STRATEGY is None and STRATEGIES:
    first_strategy_name = list(STRATEGIES.keys())[0]
    STRATEGY = {
        "name": first_strategy_name,
        "module": STRATEGIES[first_strategy_name]["module"],
        "params": STRATEGIES[first_strategy_name]["params"],
    }

# 回测相关其他参数（预留）
TRADING_DAYS_PER_YEAR: int = 252

# 股票过滤规则
MIN_LISTING_DAYS: int = 60  # 最小上市天数，过滤新股（默认 60 天）

# Tushare 配置（仅用于获取交易日历）
# 注意：不要在公共仓库中提交真实 token，可在本地修改此值，
# 或设置环境变量 TUSHARE_TOKEN 来提供。
TUSHARE_TOKEN: str = "9343e641869058684afeadfcfe7fd6684160852e52e85332a7734c8d"  # 在这里填写你的 Tushare token，或留空使用环境变量
TUSHARE_CALENDAR_EXCHANGE: str = "SSE"  # 交易所代码：SSE 上交所，SZSE 深交所

# ==================== 参数优化配置 ====================
OPTIMIZATION_N_JOBS: int = 4  # 并行进程数
OPTIMIZATION_TOP_N: int = 10  # 保存前N个最优结果
OPTIMIZATION_METRIC: str = "sharpe"  # 排序指标：sharpe / total_return / max_drawdown / annual_return

# 参数空间定义（根据策略配置不同的参数范围）
# 格式：{参数名: [最小值, 最大值, 步长]} 或 {参数名: [离散值列表]}
PARAM_SPACES: dict = {
    # 均线交叉策略参数空间
    "ma_cross": {
        "ma_short": [5, 10, 2],      # 短期均线：3-20，步長2 -> [3,5,7,9,11,13,15,17,19]
        "ma_long": [15, 30, 5],       # 长期均线：20-60，步長5 -> [20,25,30,35,40,45,50,55]
        "hold_days": [3, 10, 1],      # 持有天数：3-10，步長1 -> [3,4,5,6,7,8,9]
        "position_pct_per_stock": [0.2, 0.4, 0.5],  # 单股仓位比例（离散值）
    },
    
    # OCZ策略参数空间
    "ocz": {
        "N": [20, 40, 5],            # 阻力回望长度：20-40，步長5
        "B": [50, 70, 10],           # 实体占比门槛：50-70%，步長10
        "V1": [1.2, 1.8, 0.2],       # 放量倍数：1.2-1.8，步長0.2
        "TOL": [1.0, 2.0, 0.5],      # 回踩容错：1.0-2.0%，步長0.5
        "R": [3, 5, 1],              # 涨幅门槛：3-5%，步長1
        "hold_days": [3, 10, 1],     # 持有天数：3-10，步長1
        "position_pct_per_stock": [0.2, 0.3, 0.5],  # 单股仓位比例
    },
    
    # 可以添加其他策略的参数空间
    # "other_strategy": {
    #     "param1": [1, 10, 1],
    #     "param2": [0.1, 0.5, 0.1],
    # },
}

# 参数约束条件（避免无意义的参数组合）
# 格式：lambda params: 返回True表示合法，False表示过滤
PARAM_CONSTRAINTS: dict = {
    "ma_cross": lambda params: (
        # 约束1：短期均线必须小于长期均线
        params.get("ma_short", 0) < params.get("ma_long", 999)
        # 可以添加更多约束，例如：
        # and params.get("hold_days", 0) >= 3
        # and params.get("position_pct_per_stock", 0) <= 0.6
    ),
    
    "ocz": lambda params: (
        # 约束1：N 必须大于持有天数（确保有足够历史数据）
        params.get("N", 30) > params.get("hold_days", 0)
        # 约束2：实体占比必须大于0且小于100
        and 0 < params.get("B", 60) < 100
        # 约束3：放量倍数必须大于1
        and params.get("V1", 1.5) > 1.0
    ),
}

# ==================== 风险控制配置 ====================
# 止损止盈方法：fixed_pct / atr / trailing
STOP_LOSS_METHOD: str = "fixed_pct"
STOP_LOSS_PCT: float = 0.05  # 固定百分比止损（5%）
TAKE_PROFIT_PCT: float = 0.10  # 固定百分比止盈（15%）
ATR_PERIOD: int = 14  # ATR周期
ATR_MULTIPLIER: float = 2.0  # ATR倍数
TRAILING_PCT: float = 0.10  # 跟踪止盈回撤比例（10%）

# ==================== 持仓规模优化配置 ====================
# 持仓方法：equal_weight / kelly / volatility_target
POSITION_METHOD: str = "equal_weight"
KELLY_RISK_FREE: float = 0.03  # Kelly公式无风险利率
KELLY_MAX_FRACTION: float = 0.25  # Kelly最大仓位比例（防止过度杠杆）
VOLATILITY_TARGET: float = 0.15  # 目标波动率（年化15%）
VOLATILITY_WINDOW: int = 20  # 计算波动率的窗口期（天）

logger.info("settings.py 已加载配置")
