1985 lines
223 KiB
Plaintext
1985 lines
223 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"id": "79a7758178bafdd3",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T12:46:06.987506Z",
|
||
"start_time": "2025-04-03T12:46:06.259551Z"
|
||
},
|
||
"jupyter": {
|
||
"source_hidden": true
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"e:\\PyProject\\NewStock\\main\\train\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# %load_ext autoreload\n",
|
||
"# %autoreload 2\n",
|
||
"\n",
|
||
"import gc\n",
|
||
"import os\n",
|
||
"import sys\n",
|
||
"sys.path.append('../../')\n",
|
||
"print(os.getcwd())\n",
|
||
"import pandas as pd\n",
|
||
"from main.factor.factor import get_rolling_factor, get_simple_factor\n",
|
||
"from main.utils.factor import read_industry_data\n",
|
||
"from main.utils.factor_processor import calculate_score\n",
|
||
"from main.utils.utils import read_and_merge_h5_data, merge_with_industry_data\n",
|
||
"\n",
|
||
"import warnings\n",
|
||
"\n",
|
||
"warnings.filterwarnings(\"ignore\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"id": "a79cafb06a7e0e43",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T12:47:00.212859Z",
|
||
"start_time": "2025-04-03T12:46:06.998047Z"
|
||
},
|
||
"scrolled": true
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"daily data\n",
|
||
"daily basic\n",
|
||
"inner merge on ['ts_code', 'trade_date']\n",
|
||
"stk limit\n",
|
||
"left merge on ['ts_code', 'trade_date']\n",
|
||
"money flow\n",
|
||
"left merge on ['ts_code', 'trade_date']\n",
|
||
"cyq perf\n",
|
||
"left merge on ['ts_code', 'trade_date']\n",
|
||
"<class 'pandas.core.frame.DataFrame'>\n",
|
||
"RangeIndex: 8514978 entries, 0 to 8514977\n",
|
||
"Data columns (total 31 columns):\n",
|
||
" # Column Dtype \n",
|
||
"--- ------ ----- \n",
|
||
" 0 ts_code object \n",
|
||
" 1 trade_date datetime64[ns]\n",
|
||
" 2 open float64 \n",
|
||
" 3 close float64 \n",
|
||
" 4 high float64 \n",
|
||
" 5 low float64 \n",
|
||
" 6 vol float64 \n",
|
||
" 7 pct_chg float64 \n",
|
||
" 8 turnover_rate float64 \n",
|
||
" 9 pe_ttm float64 \n",
|
||
" 10 circ_mv float64 \n",
|
||
" 11 volume_ratio float64 \n",
|
||
" 12 is_st bool \n",
|
||
" 13 up_limit float64 \n",
|
||
" 14 down_limit float64 \n",
|
||
" 15 buy_sm_vol float64 \n",
|
||
" 16 sell_sm_vol float64 \n",
|
||
" 17 buy_lg_vol float64 \n",
|
||
" 18 sell_lg_vol float64 \n",
|
||
" 19 buy_elg_vol float64 \n",
|
||
" 20 sell_elg_vol float64 \n",
|
||
" 21 net_mf_vol float64 \n",
|
||
" 22 his_low float64 \n",
|
||
" 23 his_high float64 \n",
|
||
" 24 cost_5pct float64 \n",
|
||
" 25 cost_15pct float64 \n",
|
||
" 26 cost_50pct float64 \n",
|
||
" 27 cost_85pct float64 \n",
|
||
" 28 cost_95pct float64 \n",
|
||
" 29 weight_avg float64 \n",
|
||
" 30 winner_rate float64 \n",
|
||
"dtypes: bool(1), datetime64[ns](1), float64(28), object(1)\n",
|
||
"memory usage: 1.9+ GB\n",
|
||
"None\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"from main.utils.utils import read_and_merge_h5_data\n",
|
||
"\n",
|
||
"print('daily data')\n",
|
||
"df = read_and_merge_h5_data('../../data/daily_data.h5', key='daily_data',\n",
|
||
" columns=['ts_code', 'trade_date', 'open', 'close', 'high', 'low', 'vol', 'pct_chg'],\n",
|
||
" df=None)\n",
|
||
"\n",
|
||
"print('daily basic')\n",
|
||
"df = read_and_merge_h5_data('../../data/daily_basic.h5', key='daily_basic',\n",
|
||
" columns=['ts_code', 'trade_date', 'turnover_rate', 'pe_ttm', 'circ_mv', 'volume_ratio',\n",
|
||
" 'is_st'], df=df, join='inner')\n",
|
||
"\n",
|
||
"print('stk limit')\n",
|
||
"df = read_and_merge_h5_data('../../data/stk_limit.h5', key='stk_limit',\n",
|
||
" columns=['ts_code', 'trade_date', 'pre_close', 'up_limit', 'down_limit'],\n",
|
||
" df=df)\n",
|
||
"print('money flow')\n",
|
||
"df = read_and_merge_h5_data('../../data/money_flow.h5', key='money_flow',\n",
|
||
" columns=['ts_code', 'trade_date', 'buy_sm_vol', 'sell_sm_vol', 'buy_lg_vol', 'sell_lg_vol',\n",
|
||
" 'buy_elg_vol', 'sell_elg_vol', 'net_mf_vol'],\n",
|
||
" df=df)\n",
|
||
"print('cyq perf')\n",
|
||
"df = read_and_merge_h5_data('../../data/cyq_perf.h5', key='cyq_perf',\n",
|
||
" columns=['ts_code', 'trade_date', 'his_low', 'his_high', 'cost_5pct', 'cost_15pct',\n",
|
||
" 'cost_50pct',\n",
|
||
" 'cost_85pct', 'cost_95pct', 'weight_avg', 'winner_rate'],\n",
|
||
" df=df)\n",
|
||
"print(df.info())"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"id": "cac01788dac10678",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T12:47:10.527104Z",
|
||
"start_time": "2025-04-03T12:47:00.488715Z"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"industry\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"print('industry')\n",
|
||
"industry_df = read_and_merge_h5_data('../../data/industry_data.h5', key='industry_data',\n",
|
||
" columns=['ts_code', 'l2_code', 'in_date'],\n",
|
||
" df=None, on=['ts_code'], join='left')\n",
|
||
"\n",
|
||
"\n",
|
||
"def merge_with_industry_data(df, industry_df):\n",
|
||
" # 确保日期字段是 datetime 类型\n",
|
||
" df['trade_date'] = pd.to_datetime(df['trade_date'])\n",
|
||
" industry_df['in_date'] = pd.to_datetime(industry_df['in_date'])\n",
|
||
"\n",
|
||
" # 对 industry_df 按 ts_code 和 in_date 排序\n",
|
||
" industry_df_sorted = industry_df.sort_values(['in_date', 'ts_code'])\n",
|
||
"\n",
|
||
" # 对原始 df 按 ts_code 和 trade_date 排序\n",
|
||
" df_sorted = df.sort_values(['trade_date', 'ts_code'])\n",
|
||
"\n",
|
||
" # 使用 merge_asof 进行向后合并\n",
|
||
" merged = pd.merge_asof(\n",
|
||
" df_sorted,\n",
|
||
" industry_df_sorted,\n",
|
||
" by='ts_code', # 按 ts_code 分组\n",
|
||
" left_on='trade_date',\n",
|
||
" right_on='in_date',\n",
|
||
" direction='backward'\n",
|
||
" )\n",
|
||
"\n",
|
||
" # 获取每个 ts_code 的最早 in_date 记录\n",
|
||
" min_in_date_per_ts = (industry_df_sorted\n",
|
||
" .groupby('ts_code')\n",
|
||
" .first()\n",
|
||
" .reset_index()[['ts_code', 'l2_code']])\n",
|
||
"\n",
|
||
" # 填充未匹配到的记录(trade_date 早于所有 in_date 的情况)\n",
|
||
" merged['l2_code'] = merged['l2_code'].fillna(\n",
|
||
" merged['ts_code'].map(min_in_date_per_ts.set_index('ts_code')['l2_code'])\n",
|
||
" )\n",
|
||
"\n",
|
||
" # 保留需要的列并重置索引\n",
|
||
" result = merged.reset_index(drop=True)\n",
|
||
" return result\n",
|
||
"\n",
|
||
"\n",
|
||
"# 使用示例\n",
|
||
"df = merge_with_industry_data(df, industry_df)\n",
|
||
"# print(mdf[mdf['ts_code'] == '600751.SH'][['ts_code', 'trade_date', 'l2_code']])"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"id": "c4e9e1d31da6dba6",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T12:47:10.719252Z",
|
||
"start_time": "2025-04-03T12:47:10.541247Z"
|
||
},
|
||
"jupyter": {
|
||
"source_hidden": true
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def calculate_indicators(df):\n",
|
||
" \"\"\"\n",
|
||
" 计算四个指标:当日涨跌幅、5日移动平均、RSI、MACD。\n",
|
||
" \"\"\"\n",
|
||
" df = df.sort_values('trade_date')\n",
|
||
" df['daily_return'] = (df['close'] - df['pre_close']) / df['pre_close'] * 100\n",
|
||
" # df['5_day_ma'] = df['close'].rolling(window=5).mean()\n",
|
||
" delta = df['close'].diff()\n",
|
||
" gain = delta.where(delta > 0, 0)\n",
|
||
" loss = -delta.where(delta < 0, 0)\n",
|
||
" avg_gain = gain.rolling(window=14).mean()\n",
|
||
" avg_loss = loss.rolling(window=14).mean()\n",
|
||
" rs = avg_gain / avg_loss\n",
|
||
" df['RSI'] = 100 - (100 / (1 + rs))\n",
|
||
"\n",
|
||
" # 计算MACD\n",
|
||
" ema12 = df['close'].ewm(span=12, adjust=False).mean()\n",
|
||
" ema26 = df['close'].ewm(span=26, adjust=False).mean()\n",
|
||
" df['MACD'] = ema12 - ema26\n",
|
||
" df['Signal_line'] = df['MACD'].ewm(span=9, adjust=False).mean()\n",
|
||
" df['MACD_hist'] = df['MACD'] - df['Signal_line']\n",
|
||
"\n",
|
||
" # 4. 情绪因子1:市场上涨比例(Up Ratio)\n",
|
||
" df['up_ratio'] = df['daily_return'].apply(lambda x: 1 if x > 0 else 0)\n",
|
||
" df['up_ratio_20d'] = df['up_ratio'].rolling(window=20).mean() # 过去20天上涨比例\n",
|
||
"\n",
|
||
" # 5. 情绪因子2:成交量变化率(Volume Change Rate)\n",
|
||
" df['volume_mean'] = df['vol'].rolling(window=20).mean() # 过去20天的平均成交量\n",
|
||
" df['volume_change_rate'] = (df['vol'] - df['volume_mean']) / df['volume_mean'] * 100 # 成交量变化率\n",
|
||
"\n",
|
||
" # 6. 情绪因子3:波动率(Volatility)\n",
|
||
" df['volatility'] = df['daily_return'].rolling(window=20).std() # 过去20天的日收益率标准差\n",
|
||
"\n",
|
||
" # 7. 情绪因子4:成交额变化率(Amount Change Rate)\n",
|
||
" df['amount_mean'] = df['amount'].rolling(window=20).mean() # 过去20天的平均成交额\n",
|
||
" df['amount_change_rate'] = (df['amount'] - df['amount_mean']) / df['amount_mean'] * 100 # 成交额变化率\n",
|
||
"\n",
|
||
" return df\n",
|
||
"\n",
|
||
"\n",
|
||
"def generate_index_indicators(h5_filename):\n",
|
||
" df = pd.read_hdf(h5_filename, key='index_data')\n",
|
||
" df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d')\n",
|
||
" df = df.sort_values('trade_date')\n",
|
||
"\n",
|
||
" # 计算每个ts_code的相关指标\n",
|
||
" df_indicators = []\n",
|
||
" for ts_code in df['ts_code'].unique():\n",
|
||
" df_index = df[df['ts_code'] == ts_code].copy()\n",
|
||
" df_index = calculate_indicators(df_index)\n",
|
||
" df_indicators.append(df_index)\n",
|
||
"\n",
|
||
" # 合并所有指数的结果\n",
|
||
" df_all_indicators = pd.concat(df_indicators, ignore_index=True)\n",
|
||
"\n",
|
||
" # 保留trade_date列,并将同一天的数据按ts_code合并成一行\n",
|
||
" df_final = df_all_indicators.pivot_table(\n",
|
||
" index='trade_date',\n",
|
||
" columns='ts_code',\n",
|
||
" values=['daily_return', 'RSI', 'MACD', 'Signal_line',\n",
|
||
" 'MACD_hist', 'up_ratio_20d', 'volume_change_rate', 'volatility',\n",
|
||
" 'amount_change_rate', 'amount_mean'],\n",
|
||
" aggfunc='last'\n",
|
||
" )\n",
|
||
"\n",
|
||
" df_final.columns = [f\"{col[1]}_{col[0]}\" for col in df_final.columns]\n",
|
||
" df_final = df_final.reset_index()\n",
|
||
"\n",
|
||
" return df_final\n",
|
||
"\n",
|
||
"\n",
|
||
"# 使用函数\n",
|
||
"h5_filename = '../../data/index_data.h5'\n",
|
||
"index_data = generate_index_indicators(h5_filename)\n",
|
||
"index_data = index_data.dropna()\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"id": "a735bc02ceb4d872",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T12:47:10.821169Z",
|
||
"start_time": "2025-04-03T12:47:10.751831Z"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"\n",
|
||
"import talib\n",
|
||
"\n",
|
||
"\n",
|
||
"def get_rolling_factor(df):\n",
|
||
" old_columns = df.columns.tolist()[:]\n",
|
||
"\n",
|
||
" # 按股票和日期排序(如果尚未排序)\n",
|
||
" df = df.sort_values(by=['ts_code', 'trade_date'])\n",
|
||
"\n",
|
||
" grouped = df.groupby('ts_code', group_keys=False)\n",
|
||
"\n",
|
||
" epsilon = 1e-8\n",
|
||
" df['lg_elg_net_buy_vol'] = df['buy_lg_vol'] + df['buy_elg_vol'] - df['sell_lg_vol'] - df['sell_elg_vol']\n",
|
||
" # 检查 'volume' 列是否存在且有效\n",
|
||
" df['flow_lg_elg_intensity'] = df['lg_elg_net_buy_vol'] / (df['vol'] + epsilon)\n",
|
||
" \n",
|
||
" \n",
|
||
" # 2. 散户与主力背离度 (Retail vs Institutional Divergence)\n",
|
||
" # 衡量小单净流入与(大单+超大单)净流入的差异或比率\n",
|
||
" df['sm_net_buy_vol'] = df['buy_sm_vol'] - df['sell_sm_vol']\n",
|
||
" df['flow_divergence_diff'] = df['sm_net_buy_vol'] - df['lg_elg_net_buy_vol']\n",
|
||
" # 比率形式可能更稳定\n",
|
||
" df['flow_divergence_ratio'] = df['sm_net_buy_vol'] / (df['lg_elg_net_buy_vol'] + np.sign(df['lg_elg_net_buy_vol']) * epsilon + epsilon) # 复杂处理避免0/0\n",
|
||
" \n",
|
||
" # 3. 资金流结构变动 (Flow Structure Change - Relative Strength of Large Flow)\n",
|
||
" # 大单+超大单买入额占总买入额的比例的变化\n",
|
||
" df['total_buy_vol'] = df['buy_sm_vol'] + df['buy_lg_vol'] + df['buy_elg_vol']\n",
|
||
" df['lg_elg_buy_prop'] = (df['buy_lg_vol'] + df['buy_elg_vol']) / (df['total_buy_vol'] + epsilon)\n",
|
||
" df['flow_struct_buy_change'] = grouped['lg_elg_buy_prop'].diff(1) # 1日变化\n",
|
||
" \n",
|
||
" # 4. 资金流加速度 (Flow Acceleration)\n",
|
||
" # 净主力资金流的变化率(二阶导)\n",
|
||
" df['lg_elg_net_buy_vol_change'] = grouped['lg_elg_net_buy_vol'].diff(1)\n",
|
||
" df['flow_lg_elg_accel'] = grouped['lg_elg_net_buy_vol_change'].diff(1)\n",
|
||
" \n",
|
||
" # # 5. 极端资金流事件 (Categorical: Extreme Flow Event)\n",
|
||
" # # 定义主力资金流强度是否处于其历史极端水平(例如,过去N天的90分位数以上或10分位数以下)\n",
|
||
" # rolling_window = 20 # 可调整窗口期\n",
|
||
" \n",
|
||
" # # Step 1: Calculate the rolling quantiles separately\n",
|
||
" # rolling_high = grouped['flow_lg_elg_intensity'].rolling(rolling_window, min_periods=1).quantile(0.9) # min_periods=1 保证窗口未满时也有输出\n",
|
||
" # rolling_low = grouped['flow_lg_elg_intensity'].rolling(rolling_window, min_periods=1).quantile(0.1)\n",
|
||
" \n",
|
||
" # # Step 2: Assign the results to the DataFrame\n",
|
||
" # # 确保 df 和 rolling_high/low 的索引是一致的\n",
|
||
" # # 如果 df 的索引在此期间没有被修改过,这通常是安全的\n",
|
||
" # df['flow_lg_elg_intensity_rolling_high'] = rolling_high\n",
|
||
" # df['flow_lg_elg_intensity_rolling_low'] = rolling_low\n",
|
||
" \n",
|
||
" # # Step 3: Continue with the logic using the new columns\n",
|
||
" # conditions_flow = [\n",
|
||
" # df['flow_lg_elg_intensity'] > df['flow_lg_elg_intensity_rolling_high'],\n",
|
||
" # df['flow_lg_elg_intensity'] < df['flow_lg_elg_intensity_rolling_low']\n",
|
||
" # ]\n",
|
||
" # choices_flow = [1, -1] # 1: 极端流入, -1: 极端流出\n",
|
||
" # df['cat_extreme_flow'] = np.select(conditions_flow, choices_flow, default=0)\n",
|
||
" \n",
|
||
" # --- 筹码分布因子 ---\n",
|
||
" \n",
|
||
" # 6. 筹码集中度 (Chip Concentration)\n",
|
||
" # 衡量筹码分布的紧密程度,例如 95% 与 5% 成本价的差距,相对于当前价格进行标准化\n",
|
||
" # 检查 'close' 列是否存在且有效\n",
|
||
" df['chip_concentration_range'] = (df['cost_95pct'] - df['cost_5pct']) / (df['close'] + epsilon)\n",
|
||
" \n",
|
||
" \n",
|
||
" # 7. 筹码分布偏度 (Chip Distribution Skewness Proxy)\n",
|
||
" # 比较中位数成本 (cost_50pct) 和加权平均成本 (weight_avg)\n",
|
||
" # weight_avg > cost_50pct 暗示高成本区有较多筹码(右偏)\n",
|
||
" df['chip_skewness'] = (df['weight_avg'] - df['cost_50pct']) / (df['cost_50pct'] + epsilon)\n",
|
||
" \n",
|
||
" # 8. 浮筹比例 (Floating Chips Proxy)\n",
|
||
" # 衡量短期内(例如15%成本线以下)的筹码比例与总获利盘比例的关系\n",
|
||
" # winner_rate 高但 cost_15pct 接近当前价,可能意味着大部分获利盘成本不高,易浮动\n",
|
||
" # 这里简化为:获利盘比例 与 (当前价-15%成本价)/当前价 的乘积\n",
|
||
" price_dist_cost15 = (df['close'] - df['cost_15pct']) / (df['close'] + epsilon)\n",
|
||
" df['floating_chip_proxy'] = df['winner_rate'] * np.maximum(0, price_dist_cost15) # 只考虑价格高于15%成本线的情况\n",
|
||
" \n",
|
||
" # 9. 成本支撑强度变化 (Cost Support Strength Change)\n",
|
||
" # 观察低位筹码成本(如 5% 或 15% 分位点)的变化率,看支撑位是上移还是下移\n",
|
||
" df['cost_support_15pct_change'] = grouped['cost_15pct'].pct_change(1) * 100 # 百分比变化\n",
|
||
" \n",
|
||
" # 10. 获利盘压力/支撑区 (Categorical: Winner Rate Zone & Price Position)\n",
|
||
" # 结合获利盘比例和当前价格相对于筹码成本的位置\n",
|
||
" # 例如: 价格在 85% 成本线之上 & 获利盘 > 0.8 -> 高位派发风险区?\n",
|
||
" # 价格在 15% 成本线之下 & 获利盘 < 0.2 -> 低位吸筹潜力区?\n",
|
||
" conditions_winner = [\n",
|
||
" (df['close'] > df['cost_85pct']) & (df['winner_rate'] > 0.8), # 高位 & 高获利盘\n",
|
||
" (df['close'] < df['cost_15pct']) & (df['winner_rate'] < 0.2), # 低位 & 低获利盘\n",
|
||
" (df['close'] > df['cost_50pct']) & (df['winner_rate'] > 0.5), # 中高位 & 多数获利\n",
|
||
" (df['close'] < df['cost_50pct']) & (df['winner_rate'] < 0.5), # 中低位 & 多数亏损\n",
|
||
" ]\n",
|
||
" choices_winner = [1, 2, 3, 4] # 1:高风险区, 2:低潜力区, 3:中上获利区, 4:中下亏损区\n",
|
||
" df['cat_winner_price_zone'] = np.select(conditions_winner, choices_winner, default=0) # 0: 其他\n",
|
||
" \n",
|
||
" \n",
|
||
" # --- 结合因子 ---\n",
|
||
" \n",
|
||
" # 11. 主力行为与筹码结构一致性 (Flow-Chip Consistency)\n",
|
||
" # 例如:主力净买入发生在价格接近下方筹码密集区(如 cost_15pct 到 cost_50pct)时\n",
|
||
" price_near_low_support = (df['close'] > df['cost_15pct']) & (df['close'] < df['cost_50pct'])\n",
|
||
" df['flow_chip_consistency'] = df['lg_elg_net_buy_vol'] * price_near_low_support.astype(int)\n",
|
||
" # 可以进一步标准化或做成 categorical\n",
|
||
" \n",
|
||
" # 12. 获利了结压力/承接盘强度 (Profit-Taking Pressure vs Absorption)\n",
|
||
" # 在高获利盘(winner_rate > 0.7)的情况下,观察主力资金是净流出(了结)还是净流入(高位换手/承接)\n",
|
||
" high_winner_rate_flag = (df['winner_rate'] > 0.7).astype(int)\n",
|
||
" df['profit_taking_vs_absorb'] = df['lg_elg_net_buy_vol'] * high_winner_rate_flag\n",
|
||
" # 正值表示高获利盘下主力仍在买入(承接),负值表示主力在卖出(了结)\n",
|
||
" \n",
|
||
" \n",
|
||
" # 清理临时列和可能产生的 NaN (可选,根据需要处理)\n",
|
||
" cols_to_drop = ['lg_elg_net_buy_vol', 'sm_net_buy_vol', 'total_buy_vol', 'lg_elg_buy_prop',\n",
|
||
" 'lg_elg_net_buy_vol_change', 'flow_lg_elg_intensity_rolling_high',\n",
|
||
" 'flow_lg_elg_intensity_rolling_low']\n",
|
||
" # df = df.drop(columns=cols_to_drop)\n",
|
||
"\n",
|
||
"\n",
|
||
" window = 20\n",
|
||
" df['_is_positive'] = (df['pct_chg'] > 0).astype(int)\n",
|
||
" df['_is_negative'] = (df['pct_chg'] < 0).astype(int)\n",
|
||
" df['cat_is_positive'] = (df['pct_chg'] > 0).astype(int)\n",
|
||
"\n",
|
||
" # 分离正负收益率 (用于计算各自的均值和平方均值)\n",
|
||
" # 注意:这里我们保留原始收益率用于计算,而不是 clip 到 0\n",
|
||
" df['_pos_returns'] = df['pct_chg'].where(df['pct_chg'] > 0, 0) # 非正设为0,便于求和\n",
|
||
" df['_neg_returns'] = df['pct_chg'].where(df['pct_chg'] < 0, 0) # 非负设为0,便于求和\n",
|
||
"\n",
|
||
" # 计算收益率的平方 (用于计算 E[X^2])\n",
|
||
" df['_pos_returns_sq'] = np.square(df['_pos_returns'])\n",
|
||
" df['_neg_returns_sq'] = np.square(df['_neg_returns']) # 平方后负数变正\n",
|
||
"\n",
|
||
" # 4. 计算滚动统计量 (使用内置函数,速度较快)\n",
|
||
" # 计算正收益日的统计量\n",
|
||
" rolling_pos_count = grouped['_is_positive'].rolling(window, min_periods=max(1, window // 2)).sum()\n",
|
||
" rolling_pos_sum = grouped['_pos_returns'].rolling(window, min_periods=max(1, window // 2)).sum()\n",
|
||
" rolling_pos_sum_sq = grouped['_pos_returns_sq'].rolling(window, min_periods=max(1, window // 2)).sum()\n",
|
||
"\n",
|
||
" # 计算负收益日的统计量\n",
|
||
" rolling_neg_count = grouped['_is_negative'].rolling(window, min_periods=max(1, window // 2)).sum()\n",
|
||
" rolling_neg_sum = grouped['_neg_returns'].rolling(window, min_periods=max(1, window // 2)).sum()\n",
|
||
" rolling_neg_sum_sq = grouped['_neg_returns_sq'].rolling(window, min_periods=max(1, window // 2)).sum()\n",
|
||
"\n",
|
||
" # 5. 计算方差和标准差\n",
|
||
" pos_mean_sq = rolling_pos_sum_sq / rolling_pos_count\n",
|
||
" pos_mean = rolling_pos_sum / rolling_pos_count\n",
|
||
" pos_var = pos_mean_sq - np.square(pos_mean)\n",
|
||
" pos_var = pos_var.where(rolling_pos_count >= 2, np.nan).clip(lower=0)\n",
|
||
" upside_vol = np.sqrt(pos_var)\n",
|
||
"\n",
|
||
" neg_mean_sq = rolling_neg_sum_sq / rolling_neg_count\n",
|
||
" neg_mean = rolling_neg_sum / rolling_neg_count # 注意 neg_mean 是负数\n",
|
||
" neg_var = neg_mean_sq - np.square(neg_mean)\n",
|
||
" neg_var = neg_var.where(rolling_neg_count >= 2, np.nan).clip(lower=0)\n",
|
||
" downside_vol = np.sqrt(neg_var)\n",
|
||
"\n",
|
||
" # rolling 操作后结果带有 MultiIndex,需要去除股票代码层级以便合并\n",
|
||
" df['upside_vol'] = upside_vol.reset_index(level=0, drop=True)\n",
|
||
" df['downside_vol'] = downside_vol.reset_index(level=0, drop=True)\n",
|
||
"\n",
|
||
" df['vol_ratio'] = df['upside_vol'] / df['downside_vol']\n",
|
||
" df['vol_ratio'] = df['vol_ratio'].replace([np.inf, -np.inf], np.nan).fillna(0) # 或 fillna(np.nan)\n",
|
||
"\n",
|
||
" df['return_skew'] = grouped['pct_chg'].rolling(window=5).skew().reset_index(0, drop=True)\n",
|
||
" df['return_kurtosis'] = grouped['pct_chg'].rolling(window=5).kurt().reset_index(0, drop=True)\n",
|
||
"\n",
|
||
" # 因子 1:短期成交量变化率\n",
|
||
" df['volume_change_rate'] = (\n",
|
||
" grouped['vol'].rolling(window=2).mean() /\n",
|
||
" grouped['vol'].rolling(window=10).mean() - 1\n",
|
||
" ).reset_index(level=0, drop=True) # 确保索引对齐\n",
|
||
"\n",
|
||
" # 因子 2:成交量突破信号\n",
|
||
" max_volume = grouped['vol'].rolling(window=5).max().reset_index(level=0, drop=True) # 确保索引对齐\n",
|
||
" df['cat_volume_breakout'] = (df['vol'] > max_volume)\n",
|
||
"\n",
|
||
" # 因子 3:换手率均线偏离度\n",
|
||
" mean_turnover = grouped['turnover_rate'].rolling(window=3).mean().reset_index(level=0, drop=True)\n",
|
||
" std_turnover = grouped['turnover_rate'].rolling(window=3).std().reset_index(level=0, drop=True)\n",
|
||
" df['turnover_deviation'] = (df['turnover_rate'] - mean_turnover) / std_turnover\n",
|
||
"\n",
|
||
" # 因子 4:换手率激增信号\n",
|
||
" df['cat_turnover_spike'] = (df['turnover_rate'] > mean_turnover + 2 * std_turnover)\n",
|
||
"\n",
|
||
" # 因子 5:量比均值\n",
|
||
" df['avg_volume_ratio'] = grouped['volume_ratio'].rolling(window=3).mean().reset_index(level=0, drop=True)\n",
|
||
"\n",
|
||
" # 因子 6:量比突破信号\n",
|
||
" max_volume_ratio = grouped['volume_ratio'].rolling(window=5).max().reset_index(level=0, drop=True)\n",
|
||
" df['cat_volume_ratio_breakout'] = (df['volume_ratio'] > max_volume_ratio)\n",
|
||
"\n",
|
||
" df['vol_spike'] = grouped.apply(\n",
|
||
" lambda x: pd.Series(x['vol'].rolling(20).mean(), index=x.index)\n",
|
||
" )\n",
|
||
" df['vol_std_5'] = grouped['vol'].pct_change().rolling(window=5).std()\n",
|
||
"\n",
|
||
" # 计算 ATR\n",
|
||
" df['atr_14'] = grouped.apply(\n",
|
||
" lambda x: pd.Series(talib.ATR(x['high'].values, x['low'].values, x['close'].values, timeperiod=14),\n",
|
||
" index=x.index)\n",
|
||
" )\n",
|
||
" df['atr_6'] = grouped.apply(\n",
|
||
" lambda x: pd.Series(talib.ATR(x['high'].values, x['low'].values, x['close'].values, timeperiod=6),\n",
|
||
" index=x.index)\n",
|
||
" )\n",
|
||
"\n",
|
||
" # 计算 OBV 及其均线\n",
|
||
" df['obv'] = grouped.apply(\n",
|
||
" lambda x: pd.Series(talib.OBV(x['close'].values, x['vol'].values), index=x.index)\n",
|
||
" )\n",
|
||
" print(df.columns)\n",
|
||
" df['maobv_6'] = grouped.apply(\n",
|
||
" lambda x: pd.Series(talib.SMA(x['obv'].values, timeperiod=6), index=x.index)\n",
|
||
" )\n",
|
||
"\n",
|
||
" df['rsi_3'] = grouped.apply(\n",
|
||
" lambda x: pd.Series(talib.RSI(x['close'].values, timeperiod=3), index=x.index)\n",
|
||
" )\n",
|
||
" # df['rsi_6'] = grouped.apply(\n",
|
||
" # lambda x: pd.Series(talib.RSI(x['close'].values, timeperiod=6), index=x.index)\n",
|
||
" # )\n",
|
||
" # df['rsi_9'] = grouped.apply(\n",
|
||
" # lambda x: pd.Series(talib.RSI(x['close'].values, timeperiod=9), index=x.index)\n",
|
||
" # )\n",
|
||
"\n",
|
||
" # 计算 return_10 和 return_20\n",
|
||
" df['return_5'] = grouped['close'].apply(lambda x: x / x.shift(5) - 1)\n",
|
||
" # df['return_10'] = grouped['close'].apply(lambda x: x / x.shift(10) - 1)\n",
|
||
" df['return_20'] = grouped['close'].apply(lambda x: x / x.shift(20) - 1)\n",
|
||
"\n",
|
||
" # df['avg_close_5'] = grouped['close'].apply(lambda x: x.rolling(window=5).mean() / x)\n",
|
||
"\n",
|
||
" # 计算标准差指标\n",
|
||
" df['std_return_5'] = grouped['close'].apply(lambda x: x.pct_change().rolling(window=5).std())\n",
|
||
" # df['std_return_15'] = grouped['close'].apply(lambda x: x.pct_change().rolling(window=15).std())\n",
|
||
" # df['std_return_25'] = grouped['close'].apply(lambda x: x.pct_change().rolling(window=25).std())\n",
|
||
" df['std_return_90'] = grouped['close'].apply(lambda x: x.pct_change().rolling(window=90).std())\n",
|
||
" df['std_return_90_2'] = grouped['close'].apply(lambda x: x.shift(10).pct_change().rolling(window=90).std())\n",
|
||
"\n",
|
||
" # 计算 EMA 指标\n",
|
||
" df['_ema_5'] = grouped['close'].apply(\n",
|
||
" lambda x: pd.Series(talib.EMA(x.values, timeperiod=5), index=x.index)\n",
|
||
" )\n",
|
||
" df['_ema_13'] = grouped['close'].apply(\n",
|
||
" lambda x: pd.Series(talib.EMA(x.values, timeperiod=13), index=x.index)\n",
|
||
" )\n",
|
||
" df['_ema_20'] = grouped['close'].apply(\n",
|
||
" lambda x: pd.Series(talib.EMA(x.values, timeperiod=20), index=x.index)\n",
|
||
" )\n",
|
||
" df['_ema_60'] = grouped['close'].apply(\n",
|
||
" lambda x: pd.Series(talib.EMA(x.values, timeperiod=60), index=x.index)\n",
|
||
" )\n",
|
||
"\n",
|
||
" # 计算 act_factor1, act_factor2, act_factor3, act_factor4\n",
|
||
" df['act_factor1'] = grouped['_ema_5'].apply(\n",
|
||
" lambda x: np.arctan((x / x.shift(1) - 1) * 100) * 57.3 / 50\n",
|
||
" )\n",
|
||
" df['act_factor2'] = grouped['_ema_13'].apply(\n",
|
||
" lambda x: np.arctan((x / x.shift(1) - 1) * 100) * 57.3 / 40\n",
|
||
" )\n",
|
||
" df['act_factor3'] = grouped['_ema_20'].apply(\n",
|
||
" lambda x: np.arctan((x / x.shift(1) - 1) * 100) * 57.3 / 21\n",
|
||
" )\n",
|
||
" df['act_factor4'] = grouped['_ema_60'].apply(\n",
|
||
" lambda x: np.arctan((x / x.shift(1) - 1) * 100) * 57.3 / 10\n",
|
||
" )\n",
|
||
"\n",
|
||
" # 根据 trade_date 截面计算排名\n",
|
||
" df['rank_act_factor1'] = df.groupby('trade_date', group_keys=False)['act_factor1'].rank(ascending=False, pct=True)\n",
|
||
" df['rank_act_factor2'] = df.groupby('trade_date', group_keys=False)['act_factor2'].rank(ascending=False, pct=True)\n",
|
||
" df['rank_act_factor3'] = df.groupby('trade_date', group_keys=False)['act_factor3'].rank(ascending=False, pct=True)\n",
|
||
"\n",
|
||
" df['log(circ_mv)'] = np.log(df['circ_mv'])\n",
|
||
"\n",
|
||
" window_high_volume = 5\n",
|
||
" window_close_stddev = 20\n",
|
||
" period_delta = 5\n",
|
||
"\n",
|
||
" # 计算每只股票的滚动协方差\n",
|
||
" def calculate_rolling_cov(group):\n",
|
||
" return group['high'].rolling(window_high_volume).cov(group['vol'])\n",
|
||
"\n",
|
||
" df['cov'] = grouped.apply(calculate_rolling_cov)\n",
|
||
"\n",
|
||
" # 计算每只股票的协方差差分\n",
|
||
" def calculate_delta_cov(group):\n",
|
||
" return group['cov'].diff(period_delta)\n",
|
||
"\n",
|
||
" df['delta_cov'] = grouped.apply(calculate_delta_cov)\n",
|
||
"\n",
|
||
" # 计算每只股票的滚动标准差\n",
|
||
" def calculate_stddev_close(group):\n",
|
||
" return group['close'].rolling(window_close_stddev).std()\n",
|
||
"\n",
|
||
" df['_stddev_close'] = grouped.apply(calculate_stddev_close)\n",
|
||
" df['_rank_stddev'] = df.groupby('trade_date')['_stddev_close'].rank(pct=True)\n",
|
||
" df['alpha_22_improved'] = -1 * df['delta_cov'] * df['_rank_stddev']\n",
|
||
"\n",
|
||
" df['alpha_003'] = np.where(df['high'] != df['low'],\n",
|
||
" (df['close'] - df['open']) / (df['high'] - df['low']),\n",
|
||
" 0)\n",
|
||
"\n",
|
||
" df['alpha_007'] = grouped.apply(lambda x: x['close'].rolling(5).corr(x['vol']))\n",
|
||
" df['alpha_007'] = df.groupby('trade_date', group_keys=False)['alpha_007'].rank(ascending=True, pct=True)\n",
|
||
"\n",
|
||
" df['alpha_013'] = grouped['close'].transform(lambda x: x.rolling(5).sum() - x.rolling(20).sum())\n",
|
||
" df['alpha_013'] = df.groupby('trade_date', group_keys=False)['alpha_013'].rank(ascending=True, pct=True)\n",
|
||
"\n",
|
||
" df['cat_up_limit'] = (df['close'] == df['up_limit']) # 是否涨停(1表示涨停,0表示未涨停)\n",
|
||
" df['cat_down_limit'] = (df['close'] == df['down_limit']) # 是否跌停(1表示跌停,0表示未跌停)\n",
|
||
" df['up_limit_count_10d'] = grouped['cat_up_limit'].rolling(window=10, min_periods=1).sum().reset_index(level=0,\n",
|
||
" drop=True)\n",
|
||
" df['down_limit_count_10d'] = grouped['cat_down_limit'].rolling(window=10, min_periods=1).sum().reset_index(level=0,\n",
|
||
" drop=True)\n",
|
||
"\n",
|
||
" # 3. 最近连续涨跌停天数\n",
|
||
" def calculate_consecutive_limits(series):\n",
|
||
" \"\"\"\n",
|
||
" 计算连续涨停/跌停天数。\n",
|
||
" \"\"\"\n",
|
||
" consecutive_up = series * (series.groupby((series != series.shift()).cumsum()).cumcount() + 1)\n",
|
||
" consecutive_down = series * (series.groupby((series != series.shift()).cumsum()).cumcount() + 1)\n",
|
||
" return consecutive_up, consecutive_down\n",
|
||
"\n",
|
||
" # 连续涨停天数\n",
|
||
" df['consecutive_up_limit'] = grouped['cat_up_limit'].apply(\n",
|
||
" lambda x: calculate_consecutive_limits(x)[0]\n",
|
||
" )\n",
|
||
"\n",
|
||
" df['vol_break'] = np.where((df['close'] > df['cost_85pct']) & (df['volume_ratio'] > 2), 1, 0)\n",
|
||
"\n",
|
||
" df['weight_roc5'] = grouped['weight_avg'].apply(lambda x: x.pct_change(5))\n",
|
||
"\n",
|
||
" def rolling_corr(group):\n",
|
||
" roc_close = group['close'].pct_change()\n",
|
||
" roc_weight = group['weight_avg'].pct_change()\n",
|
||
" return roc_close.rolling(10).corr(roc_weight)\n",
|
||
"\n",
|
||
" df['price_cost_divergence'] = grouped.apply(rolling_corr)\n",
|
||
"\n",
|
||
" df['smallcap_concentration'] = (1 / df['log(circ_mv)']) * (df['cost_85pct'] - df['cost_15pct'])\n",
|
||
"\n",
|
||
" # 16. 筹码稳定性指数 (20日波动率)\n",
|
||
" df['weight_std20'] = grouped['weight_avg'].apply(lambda x: x.rolling(20).std())\n",
|
||
" df['cost_stability'] = df['weight_std20'] / grouped['weight_avg'].transform(lambda x: x.rolling(20).mean())\n",
|
||
"\n",
|
||
" # 17. 成本区间突破标记\n",
|
||
" df['high_cost_break_days'] = grouped.apply(lambda g: g['close'].gt(g['cost_95pct']).rolling(5).sum())\n",
|
||
"\n",
|
||
" # 20. 筹码-流动性风险\n",
|
||
" df['liquidity_risk'] = (df['cost_95pct'] - df['cost_5pct']) * (\n",
|
||
" 1 / grouped['vol'].transform(lambda x: x.rolling(10).mean()))\n",
|
||
"\n",
|
||
" # 7. 市值波动率因子 (使用 grouped)\n",
|
||
" df['turnover_std'] = grouped['turnover_rate'].transform(lambda x: x.rolling(window=20).std())\n",
|
||
" df['mv_volatility'] = grouped.apply(lambda x: x['turnover_std'] / x['log(circ_mv)'])\n",
|
||
"\n",
|
||
" # 8. 市值成长性因子\n",
|
||
" df['volume_growth'] = grouped['vol'].pct_change(periods=20)\n",
|
||
" df['mv_growth'] = df['volume_growth'] / df['log(circ_mv)']\n",
|
||
"\n",
|
||
" # AR 指标\n",
|
||
" df[\"ar\"] = grouped.apply(\n",
|
||
" lambda x: (x[\"high\"].div(x[\"open\"]).rolling(3).sum()) / (x[\"open\"].div(x[\"low\"]).rolling(3).sum()) * 100)\n",
|
||
"\n",
|
||
" # BR 指标\n",
|
||
" df[\"pre_close\"] = grouped[\"close\"].shift(1)\n",
|
||
" df[\"br_up\"] = (df[\"high\"] - df[\"pre_close\"]).clip(lower=0)\n",
|
||
" df[\"br_down\"] = (df[\"pre_close\"] - df[\"low\"]).clip(lower=0)\n",
|
||
" df[\"br\"] = grouped.apply(lambda x: (x[\"br_up\"].rolling(3).sum()) / (x[\"br_down\"].rolling(3).sum()) * 100)\n",
|
||
"\n",
|
||
" # ARBR\n",
|
||
" df['arbr'] = df['ar'] - df['br']\n",
|
||
" df.drop(columns=[\"pre_close\", \"br_up\", \"br_down\", 'ar', 'br'], inplace=True)\n",
|
||
"\n",
|
||
" df.drop(columns=['weight_std20'], inplace=True, errors='ignore')\n",
|
||
" df.drop(\n",
|
||
" columns=['_is_positive', '_is_negative', '_pos_returns', '_neg_returns', '_pos_returns_sq', '_neg_returns_sq'],\n",
|
||
" inplace=True, errors='ignore')\n",
|
||
" new_columns = [col for col in df.columns.tolist()[:] if col not in old_columns]\n",
|
||
"\n",
|
||
" return df, new_columns\n",
|
||
"\n",
|
||
"\n",
|
||
"def get_simple_factor(df):\n",
|
||
" old_columns = df.columns.tolist()[:]\n",
|
||
" df = df.sort_values(by=['ts_code', 'trade_date'])\n",
|
||
"\n",
|
||
" alpha = 0.5\n",
|
||
" df['momentum_factor'] = df['volume_change_rate'] + alpha * df['turnover_deviation']\n",
|
||
" df['resonance_factor'] = df['volume_ratio'] * df['pct_chg']\n",
|
||
" df['log_close'] = np.log(df['close'])\n",
|
||
"\n",
|
||
" df['cat_vol_spike'] = df['vol'] > 2 * df['vol_spike']\n",
|
||
"\n",
|
||
" df['up'] = (df['high'] - df[['close', 'open']].max(axis=1)) / df['close']\n",
|
||
" df['down'] = (df[['close', 'open']].min(axis=1) - df['low']) / df['close']\n",
|
||
"\n",
|
||
" df['obv-maobv_6'] = df['obv'] - df['maobv_6']\n",
|
||
"\n",
|
||
" # 计算比值指标\n",
|
||
" df['std_return_5 / std_return_90'] = df['std_return_5'] / df['std_return_90']\n",
|
||
" # df['std_return_5 / std_return_25'] = df['std_return_5'] / df['std_return_25']\n",
|
||
"\n",
|
||
" # 计算标准差差值\n",
|
||
" df['std_return_90 - std_return_90_2'] = df['std_return_90'] - df['std_return_90_2']\n",
|
||
"\n",
|
||
" # df['cat_af1'] = df['act_factor1'] > 0\n",
|
||
" df['cat_af2'] = df['act_factor2'] > df['act_factor1']\n",
|
||
" df['cat_af3'] = df['act_factor3'] > df['act_factor2']\n",
|
||
" df['cat_af4'] = df['act_factor4'] > df['act_factor3']\n",
|
||
"\n",
|
||
" # 计算 act_factor5 和 act_factor6\n",
|
||
" df['act_factor5'] = df['act_factor1'] + df['act_factor2'] + df['act_factor3'] + df['act_factor4']\n",
|
||
" df['act_factor6'] = (df['act_factor1'] - df['act_factor2']) / np.sqrt(\n",
|
||
" df['act_factor1'] ** 2 + df['act_factor2'] ** 2)\n",
|
||
"\n",
|
||
" df['active_buy_volume_large'] = df['buy_lg_vol'] / df['net_mf_vol']\n",
|
||
" df['active_buy_volume_big'] = df['buy_elg_vol'] / df['net_mf_vol']\n",
|
||
" df['active_buy_volume_small'] = df['buy_sm_vol'] / df['net_mf_vol']\n",
|
||
"\n",
|
||
" df['buy_lg_vol_minus_sell_lg_vol'] = (df['buy_lg_vol'] - df['sell_lg_vol']) / df['net_mf_vol']\n",
|
||
" df['buy_elg_vol_minus_sell_elg_vol'] = (df['buy_elg_vol'] - df['sell_elg_vol']) / df['net_mf_vol']\n",
|
||
"\n",
|
||
" df['log(circ_mv)'] = np.log(df['circ_mv'])\n",
|
||
"\n",
|
||
" df['ctrl_strength'] = (df['cost_85pct'] - df['cost_15pct']) / (df['his_high'] - df['his_low'])\n",
|
||
"\n",
|
||
" df['low_cost_dev'] = (df['close'] - df['cost_5pct']) / (df['cost_50pct'] - df['cost_5pct'])\n",
|
||
"\n",
|
||
" df['asymmetry'] = (df['cost_95pct'] - df['cost_50pct']) / (df['cost_50pct'] - df['cost_5pct'])\n",
|
||
"\n",
|
||
" df['lock_factor'] = df['turnover_rate'] * (\n",
|
||
" 1 - (df['cost_95pct'] - df['cost_5pct']) / (df['his_high'] - df['his_low']))\n",
|
||
"\n",
|
||
" df['cat_vol_break'] = (df['close'] > df['cost_85pct']) & (df['volume_ratio'] > 2)\n",
|
||
"\n",
|
||
" df['cost_atr_adj'] = (df['cost_95pct'] - df['cost_5pct']) / df['atr_14']\n",
|
||
"\n",
|
||
" # 12. 小盘股筹码集中度\n",
|
||
" df['smallcap_concentration'] = (1 / df['log(circ_mv)']) * (df['cost_85pct'] - df['cost_15pct'])\n",
|
||
"\n",
|
||
" df['cat_golden_resonance'] = ((df['close'] > df['weight_avg']) &\n",
|
||
" (df['volume_ratio'] > 1.5) &\n",
|
||
" (df['winner_rate'] > 0.7))\n",
|
||
"\n",
|
||
" df['mv_turnover_ratio'] = df['turnover_rate'] / df['log(circ_mv)']\n",
|
||
"\n",
|
||
" df['mv_adjusted_volume'] = df['vol'] / df['log(circ_mv)']\n",
|
||
"\n",
|
||
" df['mv_weighted_turnover'] = df['turnover_rate'] * (1 / df['log(circ_mv)'])\n",
|
||
"\n",
|
||
" df['nonlinear_mv_volume'] = df['vol'] / df['log(circ_mv)']\n",
|
||
"\n",
|
||
" df['mv_volume_ratio'] = df['volume_ratio'] / df['log(circ_mv)']\n",
|
||
"\n",
|
||
" df['mv_momentum'] = df['turnover_rate'] * df['volume_ratio'] / df['log(circ_mv)']\n",
|
||
"\n",
|
||
" drop_columns = [col for col in df.columns if col.startswith('_')]\n",
|
||
" df.drop(columns=drop_columns, inplace=True, errors='ignore')\n",
|
||
"\n",
|
||
" new_columns = [col for col in df.columns.tolist()[:] if col not in old_columns]\n",
|
||
" return df, new_columns\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"id": "53f86ddc0677a6d7",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T12:47:15.944254Z",
|
||
"start_time": "2025-04-03T12:47:10.826179Z"
|
||
},
|
||
"jupyter": {
|
||
"source_hidden": true
|
||
},
|
||
"scrolled": true
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"from main.utils.factor import get_act_factor\n",
|
||
"\n",
|
||
"\n",
|
||
"def read_industry_data(h5_filename):\n",
|
||
" # 读取 H5 文件中所有的行业数据\n",
|
||
" industry_data = pd.read_hdf(h5_filename, key='sw_daily', columns=[\n",
|
||
" 'ts_code', 'trade_date', 'open', 'close', 'high', 'low', 'pe', 'pb', 'vol'\n",
|
||
" ]) # 假设 H5 文件的键是 'industry_data'\n",
|
||
" industry_data = industry_data.sort_values(by=['ts_code', 'trade_date'])\n",
|
||
" industry_data = industry_data.reindex()\n",
|
||
" industry_data['trade_date'] = pd.to_datetime(industry_data['trade_date'], format='%Y%m%d')\n",
|
||
"\n",
|
||
" grouped = industry_data.groupby('ts_code', group_keys=False)\n",
|
||
" industry_data['obv'] = grouped.apply(\n",
|
||
" lambda x: pd.Series(talib.OBV(x['close'].values, x['vol'].values), index=x.index)\n",
|
||
" )\n",
|
||
" industry_data['return_5'] = grouped['close'].apply(lambda x: x / x.shift(5) - 1)\n",
|
||
" industry_data['return_20'] = grouped['close'].apply(lambda x: x / x.shift(20) - 1)\n",
|
||
"\n",
|
||
" industry_data = get_act_factor(industry_data, cat=False)\n",
|
||
" industry_data = industry_data.sort_values(by=['trade_date', 'ts_code'])\n",
|
||
"\n",
|
||
" # # 计算每天每个 ts_code 的因子和当天所有 ts_code 的中位数的偏差\n",
|
||
" # factor_columns = ['obv', 'return_5', 'return_20', 'act_factor1', 'act_factor2', 'act_factor3', 'act_factor4'] # 因子列\n",
|
||
" # \n",
|
||
" # for factor in factor_columns:\n",
|
||
" # if factor in industry_data.columns:\n",
|
||
" # # 计算每天每个 ts_code 的因子值与当天所有 ts_code 的中位数的偏差\n",
|
||
" # industry_data[f'{factor}_deviation'] = industry_data.groupby('trade_date')[factor].transform(\n",
|
||
" # lambda x: x - x.mean())\n",
|
||
"\n",
|
||
" industry_data['return_5_percentile'] = industry_data.groupby('trade_date')['return_5'].transform(\n",
|
||
" lambda x: x.rank(pct=True))\n",
|
||
" industry_data['return_20_percentile'] = industry_data.groupby('trade_date')['return_20'].transform(\n",
|
||
" lambda x: x.rank(pct=True))\n",
|
||
" industry_data = industry_data.drop(columns=['open', 'close', 'high', 'low', 'pe', 'pb', 'vol'])\n",
|
||
"\n",
|
||
" industry_data = industry_data.rename(\n",
|
||
" columns={col: f'industry_{col}' for col in industry_data.columns if col not in ['ts_code', 'trade_date']})\n",
|
||
"\n",
|
||
" industry_data = industry_data.rename(columns={'ts_code': 'cat_l2_code'})\n",
|
||
" return industry_data\n",
|
||
"\n",
|
||
"\n",
|
||
"industry_df = read_industry_data('../../data/sw_daily.h5')\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"id": "dbe2fd8021b9417f",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T12:47:15.969344Z",
|
||
"start_time": "2025-04-03T12:47:15.963327Z"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"['ts_code', 'open', 'close', 'high', 'low', 'circ_mv', 'is_st', 'up_limit', 'down_limit', 'buy_sm_vol', 'sell_sm_vol', 'buy_lg_vol', 'sell_lg_vol', 'buy_elg_vol', 'sell_elg_vol', 'net_mf_vol', 'his_low', 'his_high', 'cost_5pct', 'cost_15pct', 'cost_50pct', 'cost_85pct', 'cost_95pct', 'weight_avg', 'in_date']\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"origin_columns = df.columns.tolist()\n",
|
||
"origin_columns = [col for col in origin_columns if\n",
|
||
" col not in ['turnover_rate', 'pe_ttm', 'volume_ratio', 'vol', 'pct_chg', 'l2_code', 'winner_rate']]\n",
|
||
"origin_columns = [col for col in origin_columns if col not in index_data.columns]\n",
|
||
"origin_columns = [col for col in origin_columns if 'cyq' not in col]\n",
|
||
"print(origin_columns)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"id": "85c3e3d0235ffffa",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T12:47:16.089879Z",
|
||
"start_time": "2025-04-03T12:47:15.990101Z"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
" ts_code trade_date is_st\n",
|
||
"29 000037.SZ 2017-01-03 True\n",
|
||
"72 000408.SZ 2017-01-03 True\n",
|
||
"95 000504.SZ 2017-01-03 True\n",
|
||
"96 000505.SZ 2017-01-03 True\n",
|
||
"101 000511.SZ 2017-01-03 True\n",
|
||
"... ... ... ...\n",
|
||
"8513971 603869.SH 2025-04-09 True\n",
|
||
"8513976 603879.SH 2025-04-09 True\n",
|
||
"8514023 603959.SH 2025-04-09 True\n",
|
||
"8514406 688282.SH 2025-04-09 True\n",
|
||
"8514410 688287.SH 2025-04-09 True\n",
|
||
"\n",
|
||
"[193456 rows x 3 columns]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"print(df[df['is_st']][['ts_code', 'trade_date', 'is_st']])"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"id": "92d84ce15a562ec6",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T13:08:01.612695Z",
|
||
"start_time": "2025-04-03T12:47:16.121802Z"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Index(['ts_code', 'trade_date', 'open', 'close', 'high', 'low', 'vol',\n",
|
||
" 'pct_chg', 'turnover_rate', 'pe_ttm', 'circ_mv', 'volume_ratio',\n",
|
||
" 'is_st', 'up_limit', 'down_limit', 'buy_sm_vol', 'sell_sm_vol',\n",
|
||
" 'buy_lg_vol', 'sell_lg_vol', 'buy_elg_vol', 'sell_elg_vol',\n",
|
||
" 'net_mf_vol', 'his_low', 'his_high', 'cost_5pct', 'cost_15pct',\n",
|
||
" 'cost_50pct', 'cost_85pct', 'cost_95pct', 'weight_avg', 'winner_rate',\n",
|
||
" 'l2_code', 'lg_elg_net_buy_vol', 'flow_lg_elg_intensity',\n",
|
||
" 'sm_net_buy_vol', 'flow_divergence_diff', 'flow_divergence_ratio',\n",
|
||
" 'total_buy_vol', 'lg_elg_buy_prop', 'flow_struct_buy_change',\n",
|
||
" 'lg_elg_net_buy_vol_change', 'flow_lg_elg_accel',\n",
|
||
" 'chip_concentration_range', 'chip_skewness', 'floating_chip_proxy',\n",
|
||
" 'cost_support_15pct_change', 'cat_winner_price_zone',\n",
|
||
" 'flow_chip_consistency', 'profit_taking_vs_absorb', '_is_positive',\n",
|
||
" '_is_negative', 'cat_is_positive', '_pos_returns', '_neg_returns',\n",
|
||
" '_pos_returns_sq', '_neg_returns_sq', 'upside_vol', 'downside_vol',\n",
|
||
" 'vol_ratio', 'return_skew', 'return_kurtosis', 'volume_change_rate',\n",
|
||
" 'cat_volume_breakout', 'turnover_deviation', 'cat_turnover_spike',\n",
|
||
" 'avg_volume_ratio', 'cat_volume_ratio_breakout', 'vol_spike',\n",
|
||
" 'vol_std_5', 'atr_14', 'atr_6', 'obv'],\n",
|
||
" dtype='object')\n",
|
||
"Calculating lg_flow_mom_corr_20_60...\n",
|
||
"Finished lg_flow_mom_corr_20_60.\n",
|
||
"Calculating lg_buy_consolidation_20...\n",
|
||
"Finished lg_buy_consolidation_20.\n",
|
||
"Calculating lg_flow_accel...\n",
|
||
"Finished lg_flow_accel.\n",
|
||
"Calculating profit_pressure...\n",
|
||
"Finished profit_pressure.\n",
|
||
"Calculating underwater_resistance...\n",
|
||
"Finished underwater_resistance.\n",
|
||
"Calculating cost_conc_std_20...\n",
|
||
"Finished cost_conc_std_20.\n",
|
||
"Calculating profit_decay_20...\n",
|
||
"Finished profit_decay_20.\n",
|
||
"Calculating vol_amp_loss_20...\n",
|
||
"Finished vol_amp_loss_20.\n",
|
||
"Calculating vol_drop_profit_cnt_5...\n",
|
||
"Finished vol_drop_profit_cnt_5.\n",
|
||
"Calculating lg_flow_vol_interact_20...\n",
|
||
"Finished lg_flow_vol_interact_20.\n",
|
||
"Calculating cost_break_confirm_cnt_5...\n",
|
||
"Finished cost_break_confirm_cnt_5.\n",
|
||
"Calculating atr_norm_channel_pos_14...\n",
|
||
"Finished atr_norm_channel_pos_14.\n",
|
||
"Calculating turnover_diff_skew_20...\n",
|
||
"Finished turnover_diff_skew_20.\n",
|
||
"Calculating lg_sm_flow_diverge_20...\n",
|
||
"Finished lg_sm_flow_diverge_20.\n",
|
||
"Calculating pullback_strong_20_20...\n",
|
||
"Finished pullback_strong_20_20.\n",
|
||
"Calculating vol_wgt_hist_pos_20...\n",
|
||
"Finished vol_wgt_hist_pos_20.\n",
|
||
"Calculating vol_adj_roc_20...\n",
|
||
"Finished vol_adj_roc_20.\n",
|
||
"Calculating intraday_lg_flow_corr_20 (Placeholder - complex implementation)...\n",
|
||
"Finished intraday_lg_flow_corr_20 (Placeholder).\n",
|
||
"Calculating cap_neutral_cost_metric (Placeholder - requires statsmodels)...\n",
|
||
"Finished cap_neutral_cost_metric (Placeholder).\n",
|
||
"Calculating hurst_net_mf_vol_60 (Placeholder - requires hurst library)...\n",
|
||
"Error: 'hurst' library not installed. Cannot calculate factor.\n",
|
||
"Finished hurst_net_mf_vol_60 (Placeholder).\n",
|
||
"Calculating cs_rank_net_lg_flow_val...\n",
|
||
"Finished cs_rank_net_lg_flow_val.\n",
|
||
"Calculating cs_rank_flow_divergence...\n",
|
||
"Finished cs_rank_flow_divergence.\n",
|
||
"Calculating cs_rank_ind_adj_lg_flow...\n",
|
||
"Error calculating cs_rank_ind_adj_lg_flow: Missing 'cat_l2_code' column. Assigning NaN.\n",
|
||
"Calculating cs_rank_elg_buy_ratio...\n",
|
||
"Finished cs_rank_elg_buy_ratio.\n",
|
||
"Calculating cs_rank_rel_profit_margin...\n",
|
||
"Finished cs_rank_rel_profit_margin.\n",
|
||
"Calculating cs_rank_cost_breadth...\n",
|
||
"Finished cs_rank_cost_breadth.\n",
|
||
"Calculating cs_rank_dist_to_upper_cost...\n",
|
||
"Finished cs_rank_dist_to_upper_cost.\n",
|
||
"Calculating cs_rank_winner_rate...\n",
|
||
"Finished cs_rank_winner_rate.\n",
|
||
"Calculating cs_rank_intraday_range...\n",
|
||
"Finished cs_rank_intraday_range.\n",
|
||
"Calculating cs_rank_close_pos_in_range...\n",
|
||
"Finished cs_rank_close_pos_in_range.\n",
|
||
"Calculating cs_rank_opening_gap...\n",
|
||
"Error calculating cs_rank_opening_gap: Missing 'pre_close' column. Assigning NaN.\n",
|
||
"Calculating cs_rank_pos_in_hist_range...\n",
|
||
"Finished cs_rank_pos_in_hist_range.\n",
|
||
"Calculating cs_rank_vol_x_profit_margin...\n",
|
||
"Finished cs_rank_vol_x_profit_margin.\n",
|
||
"Calculating cs_rank_lg_flow_price_concordance...\n",
|
||
"Finished cs_rank_lg_flow_price_concordance.\n",
|
||
"Calculating cs_rank_turnover_per_winner...\n",
|
||
"Finished cs_rank_turnover_per_winner.\n",
|
||
"Calculating cs_rank_ind_cap_neutral_pe (Placeholder - requires statsmodels)...\n",
|
||
"Finished cs_rank_ind_cap_neutral_pe (Placeholder).\n",
|
||
"Calculating cs_rank_volume_ratio...\n",
|
||
"Finished cs_rank_volume_ratio.\n",
|
||
"Calculating cs_rank_elg_buy_sell_sm_ratio...\n",
|
||
"Finished cs_rank_elg_buy_sell_sm_ratio.\n",
|
||
"Calculating cs_rank_cost_dist_vol_ratio...\n",
|
||
"Finished cs_rank_cost_dist_vol_ratio.\n",
|
||
"Calculating cs_rank_size...\n",
|
||
"Finished cs_rank_size.\n",
|
||
"<class 'pandas.core.frame.DataFrame'>\n",
|
||
"Index: 3830570 entries, 0 to 3830569\n",
|
||
"Columns: 176 entries, ts_code to cs_rank_size\n",
|
||
"dtypes: bool(12), datetime64[ns](1), float64(157), int32(3), int64(1), object(2)\n",
|
||
"memory usage: 4.7+ GB\n",
|
||
"None\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"import numpy as np\n",
|
||
"\n",
|
||
"def filter_data(df):\n",
|
||
" # df = df.groupby('trade_date').apply(lambda x: x.nlargest(1000, 'act_factor1'))\n",
|
||
" df = df[~df['is_st']]\n",
|
||
" df = df[~df['ts_code'].str.endswith('BJ')]\n",
|
||
" df = df[~df['ts_code'].str.startswith('30')]\n",
|
||
" df = df[~df['ts_code'].str.startswith('68')]\n",
|
||
" df = df[~df['ts_code'].str.startswith('8')]\n",
|
||
" df = df[df['trade_date'] >= '2020-01-01']\n",
|
||
" if 'in_date' in df.columns:\n",
|
||
" df = df.drop(columns=['in_date'])\n",
|
||
" df = df.reset_index(drop=True)\n",
|
||
" return df\n",
|
||
"\n",
|
||
"\n",
|
||
"df = filter_data(df)\n",
|
||
"# df = get_technical_factor(df)\n",
|
||
"# df = get_act_factor(df)\n",
|
||
"# df = get_money_flow_factor(df)\n",
|
||
"# df = get_alpha_factor(df)\n",
|
||
"# df = get_limit_factor(df)\n",
|
||
"# df = get_cyp_perf_factor(df)\n",
|
||
"# df = get_mv_factors(df)\n",
|
||
"df, _ = get_rolling_factor(df)\n",
|
||
"df, _ = get_simple_factor(df)\n",
|
||
"from main.factor.factor import *\n",
|
||
"lg_flow_mom_corr(df, N=20, M=60)\n",
|
||
"lg_buy_consolidation(df, N=20)\n",
|
||
"lg_flow_accel(df)\n",
|
||
"profit_pressure(df)\n",
|
||
"underwater_resistance(df)\n",
|
||
"cost_conc_std(df, N=20)\n",
|
||
"profit_decay(df, N=20)\n",
|
||
"vol_amp_loss(df, N=20)\n",
|
||
"vol_drop_profit_cnt(df, N=20, M=5)\n",
|
||
"lg_flow_vol_interact(df, N=20)\n",
|
||
"cost_break_confirm_cnt(df, M=5)\n",
|
||
"atr_norm_channel_pos(df, N=14)\n",
|
||
"turnover_diff_skew(df, N=20)\n",
|
||
"lg_sm_flow_diverge(df, N=20)\n",
|
||
"pullback_strong(df, N=20, M=20)\n",
|
||
"vol_wgt_hist_pos(df, N=20)\n",
|
||
"vol_adj_roc(df, N=20)\n",
|
||
"intraday_lg_flow_corr(df, N=20) # Placeholder\n",
|
||
"cap_neutral_cost_metric(df) # Placeholder\n",
|
||
"hurst_exponent_flow(df, N=60) # Placeholder\n",
|
||
"# calculate_complex_factor(df)\n",
|
||
"cs_rank_net_lg_flow_val(df)\n",
|
||
"cs_rank_flow_divergence(df)\n",
|
||
"cs_rank_industry_adj_lg_flow(df) # Needs cat_l2_code\n",
|
||
"cs_rank_elg_buy_ratio(df)\n",
|
||
"cs_rank_rel_profit_margin(df)\n",
|
||
"cs_rank_cost_breadth(df)\n",
|
||
"cs_rank_dist_to_upper_cost(df)\n",
|
||
"cs_rank_winner_rate(df)\n",
|
||
"cs_rank_intraday_range(df)\n",
|
||
"cs_rank_close_pos_in_range(df)\n",
|
||
"cs_rank_opening_gap(df) # Needs pre_close\n",
|
||
"cs_rank_pos_in_hist_range(df) # Needs his_low, his_high\n",
|
||
"cs_rank_vol_x_profit_margin(df)\n",
|
||
"cs_rank_lg_flow_price_concordance(df)\n",
|
||
"cs_rank_turnover_per_winner(df)\n",
|
||
"cs_rank_ind_cap_neutral_pe(df) # Placeholder - needs external libraries\n",
|
||
"cs_rank_volume_ratio(df) # Needs volume_ratio\n",
|
||
"cs_rank_elg_buy_sell_sm_ratio(df)\n",
|
||
"cs_rank_cost_dist_vol_ratio(df) # Needs volume_ratio\n",
|
||
"cs_rank_size(df) # Needs circ_mv\n",
|
||
"# df = df.merge(industry_df, on=['l1_code', 'trade_date'], how='left')\n",
|
||
"df = df.rename(columns={'l1_code': 'cat_l1_code'})\n",
|
||
"df = df.rename(columns={'l2_code': 'cat_l2_code'})\n",
|
||
"\n",
|
||
"# df = df.merge(index_data, on='trade_date', how='left')\n",
|
||
"\n",
|
||
"print(df.info())"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"id": "b87b938028afa206",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T13:08:03.658725Z",
|
||
"start_time": "2025-04-03T13:08:02.469611Z"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"from scipy.stats import ks_2samp, wasserstein_distance\n",
|
||
"\n",
|
||
"\n",
|
||
"def remove_shifted_features(train_data, test_data, feature_columns, ks_threshold=0.05, wasserstein_threshold=0.1,\n",
|
||
" importance_threshold=0.05):\n",
|
||
" dropped_features = []\n",
|
||
"\n",
|
||
" # **统计数据漂移**\n",
|
||
" numeric_columns = train_data.select_dtypes(include=['float64', 'int64']).columns\n",
|
||
" numeric_columns = [col for col in numeric_columns if col in feature_columns]\n",
|
||
" for feature in numeric_columns:\n",
|
||
" ks_stat, p_value = ks_2samp(train_data[feature], test_data[feature])\n",
|
||
" wasserstein_dist = wasserstein_distance(train_data[feature], test_data[feature])\n",
|
||
"\n",
|
||
" if p_value < ks_threshold or wasserstein_dist > wasserstein_threshold:\n",
|
||
" dropped_features.append(feature)\n",
|
||
"\n",
|
||
" print(f\"检测到 {len(dropped_features)} 个可能漂移的特征: {dropped_features}\")\n",
|
||
"\n",
|
||
" # **应用阈值进行最终筛选**\n",
|
||
" filtered_features = [f for f in feature_columns if f not in dropped_features]\n",
|
||
"\n",
|
||
" return filtered_features, dropped_features\n",
|
||
"\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"id": "f4f16d63ad18d1bc",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T13:08:03.670700Z",
|
||
"start_time": "2025-04-03T13:08:03.665739Z"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def create_deviation_within_dates(df, feature_columns):\n",
|
||
" groupby_col = 'cat_l2_code' # 使用 trade_date 进行分组\n",
|
||
" new_columns = {}\n",
|
||
" ret_feature_columns = feature_columns[:]\n",
|
||
"\n",
|
||
" # 自动选择所有数值型特征\n",
|
||
" num_features = [col for col in feature_columns if 'cat' not in col and 'index' not in col]\n",
|
||
"\n",
|
||
" # num_features = ['vol', 'pct_chg', 'turnover_rate', 'volume_ratio', 'cat_vol_spike', 'obv', 'maobv_6', 'return_5', 'return_10', 'return_20', 'std_return_5', 'std_return_15', 'std_return_90', 'std_return_90_2', 'act_factor1', 'act_factor2', 'act_factor3', 'act_factor4', 'act_factor5', 'act_factor6', 'rank_act_factor1', 'rank_act_factor2', 'rank_act_factor3', 'active_buy_volume_large', 'active_buy_volume_big', 'active_buy_volume_small', 'alpha_022', 'alpha_003', 'alpha_007', 'alpha_013']\n",
|
||
" num_features = [col for col in num_features if 'cat' not in col and 'industry' not in col]\n",
|
||
" num_features = [col for col in num_features if 'limit' not in col]\n",
|
||
" num_features = [col for col in num_features if 'cyq' not in col]\n",
|
||
"\n",
|
||
" # 遍历所有数值型特征\n",
|
||
" for feature in num_features:\n",
|
||
" if feature == 'trade_date': # 不需要对 'trade_date' 计算偏差\n",
|
||
" continue\n",
|
||
"\n",
|
||
" # grouped_mean = df.groupby(['trade_date'])[feature].transform('mean')\n",
|
||
" # deviation_col_name = f'deviation_mean_{feature}'\n",
|
||
" # new_columns[deviation_col_name] = df[feature] - grouped_mean\n",
|
||
" # ret_feature_columns.append(deviation_col_name)\n",
|
||
"\n",
|
||
" grouped_mean = df.groupby(['trade_date', groupby_col])[feature].transform('mean')\n",
|
||
" deviation_col_name = f'deviation_mean_{feature}'\n",
|
||
" new_columns[deviation_col_name] = df[feature] - grouped_mean\n",
|
||
" ret_feature_columns.append(deviation_col_name)\n",
|
||
"\n",
|
||
" # 将新计算的偏差特征与原始 DataFrame 合并\n",
|
||
" df = pd.concat([df, pd.DataFrame(new_columns)], axis=1)\n",
|
||
"\n",
|
||
" # for feature in ['obv', 'return_20', 'act_factor1', 'act_factor2', 'act_factor3', 'act_factor4']:\n",
|
||
" # df[f'deviation_industry_{feature}'] = df[feature] - df[f'industry_{feature}']\n",
|
||
"\n",
|
||
" return df, ret_feature_columns\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 12,
|
||
"id": "40e6b68a91b30c79",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T13:08:04.694262Z",
|
||
"start_time": "2025-04-03T13:08:03.694904Z"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"import pandas as pd\n",
|
||
"\n",
|
||
"\n",
|
||
"def remove_outliers_label_percentile(label: pd.Series, lower_percentile: float = 0.01, upper_percentile: float = 0.99,\n",
|
||
" log=True):\n",
|
||
" if not (0 <= lower_percentile < upper_percentile <= 1):\n",
|
||
" raise ValueError(\"Percentile values must satisfy 0 <= lower_percentile < upper_percentile <= 1.\")\n",
|
||
"\n",
|
||
" # Calculate lower and upper bounds based on percentiles\n",
|
||
" lower_bound = label.quantile(lower_percentile)\n",
|
||
" upper_bound = label.quantile(upper_percentile)\n",
|
||
"\n",
|
||
" # Filter out values outside the bounds\n",
|
||
" filtered_label = label[(label >= lower_bound) & (label <= upper_bound)]\n",
|
||
"\n",
|
||
" # Print the number of removed outliers\n",
|
||
" if log:\n",
|
||
" print(f\"Removed {len(label) - len(filtered_label)} outliers.\")\n",
|
||
" return filtered_label\n",
|
||
"\n",
|
||
"\n",
|
||
"def calculate_risk_adjusted_target(df, days=5):\n",
|
||
" df = df.sort_values(by=['ts_code', 'trade_date'])\n",
|
||
"\n",
|
||
" df['future_close'] = df.groupby('ts_code')['close'].shift(-days)\n",
|
||
" df['future_open'] = df.groupby('ts_code')['open'].shift(-1)\n",
|
||
" df['future_return'] = (df['future_close'] - df['future_open']) / df['future_open']\n",
|
||
"\n",
|
||
" df['future_volatility'] = df.groupby('ts_code')['future_return'].rolling(days, min_periods=1).std().reset_index(\n",
|
||
" level=0, drop=True)\n",
|
||
" sharpe_ratio = df['future_return'] * df['future_volatility']\n",
|
||
" sharpe_ratio.replace([np.inf, -np.inf], np.nan, inplace=True)\n",
|
||
"\n",
|
||
" return sharpe_ratio\n",
|
||
"\n",
|
||
"\n",
|
||
"def calculate_score(df, days=5, lambda_param=1.0):\n",
|
||
" def calculate_max_drawdown(prices):\n",
|
||
" peak = prices.iloc[0] # 初始化峰值\n",
|
||
" max_drawdown = 0 # 初始化最大回撤\n",
|
||
"\n",
|
||
" for price in prices:\n",
|
||
" if price > peak:\n",
|
||
" peak = price # 更新峰值\n",
|
||
" else:\n",
|
||
" drawdown = (peak - price) / peak # 计算当前回撤\n",
|
||
" max_drawdown = max(max_drawdown, drawdown) # 更新最大回撤\n",
|
||
"\n",
|
||
" return max_drawdown\n",
|
||
"\n",
|
||
" def compute_stock_score(stock_df):\n",
|
||
" stock_df = stock_df.sort_values(by=['trade_date'])\n",
|
||
" future_return = stock_df['future_return']\n",
|
||
" # 使用已有的 pct_chg 字段计算波动率\n",
|
||
" volatility = stock_df['pct_chg'].rolling(days).std().shift(-days)\n",
|
||
" max_drawdown = stock_df['close'].rolling(days).apply(calculate_max_drawdown, raw=False).shift(-days)\n",
|
||
" score = future_return - lambda_param * max_drawdown\n",
|
||
" return score\n",
|
||
"\n",
|
||
" # # 确保 DataFrame 按照股票代码和交易日期排序\n",
|
||
" # df = df.sort_values(by=['ts_code', 'trade_date'])\n",
|
||
"\n",
|
||
" # 对每个股票分别计算 score\n",
|
||
" df['score'] = df.groupby('ts_code').apply(compute_stock_score).reset_index(level=0, drop=True)\n",
|
||
"\n",
|
||
" return df['score']\n",
|
||
"\n",
|
||
"\n",
|
||
"def remove_highly_correlated_features(df, feature_columns, threshold=0.9):\n",
|
||
" numeric_features = df[feature_columns].select_dtypes(include=[np.number]).columns.tolist()\n",
|
||
" if not numeric_features:\n",
|
||
" raise ValueError(\"No numeric features found in the provided data.\")\n",
|
||
"\n",
|
||
" corr_matrix = df[numeric_features].corr().abs()\n",
|
||
" upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(bool))\n",
|
||
" to_drop = [column for column in upper.columns if any(upper[column] > threshold)]\n",
|
||
" remaining_features = [col for col in feature_columns if col not in to_drop\n",
|
||
" or 'act' in col or 'af' in col]\n",
|
||
" return remaining_features\n",
|
||
"\n",
|
||
"\n",
|
||
"def cross_sectional_standardization(df, features):\n",
|
||
" df_sorted = df.sort_values(by='trade_date') # 按时间排序\n",
|
||
" df_standardized = df_sorted.copy()\n",
|
||
"\n",
|
||
" for date in df_sorted['trade_date'].unique():\n",
|
||
" # 获取当前时间点的数据\n",
|
||
" current_data = df_standardized[df_standardized['trade_date'] == date]\n",
|
||
"\n",
|
||
" # 只对指定特征进行标准化\n",
|
||
" scaler = StandardScaler()\n",
|
||
" standardized_values = scaler.fit_transform(current_data[features])\n",
|
||
"\n",
|
||
" # 将标准化结果重新赋值回去\n",
|
||
" df_standardized.loc[df_standardized['trade_date'] == date, features] = standardized_values\n",
|
||
"\n",
|
||
" return df_standardized\n",
|
||
"\n",
|
||
"\n",
|
||
"import numpy as np\n",
|
||
"import pandas as pd\n",
|
||
"\n",
|
||
"\n",
|
||
"def neutralize_manual(df, features, industry_col, mkt_cap_col):\n",
|
||
" \"\"\" 手动实现简单回归以提升速度 \"\"\"\n",
|
||
"\n",
|
||
" for col in features:\n",
|
||
" residuals = []\n",
|
||
" for _, group in df.groupby(industry_col):\n",
|
||
" if len(group) > 1:\n",
|
||
" x = np.log(group[mkt_cap_col]) # 市值对数\n",
|
||
" y = group[col] # 因子值\n",
|
||
" beta = np.cov(y, x)[0, 1] / np.var(x) # 计算斜率\n",
|
||
" alpha = np.mean(y) - beta * np.mean(x) # 计算截距\n",
|
||
" resid = y - (alpha + beta * x) # 计算残差\n",
|
||
" residuals.extend(resid)\n",
|
||
" else:\n",
|
||
" residuals.extend(group[col]) # 样本不足时保留原值\n",
|
||
"\n",
|
||
" df[col] = residuals\n",
|
||
"\n",
|
||
" return df\n",
|
||
"\n",
|
||
"\n",
|
||
"import gc\n",
|
||
"\n",
|
||
"gc.collect()\n",
|
||
"\n",
|
||
"\n",
|
||
"def mad_filter(df, features, n=3):\n",
|
||
" for col in features:\n",
|
||
" median = df[col].median()\n",
|
||
" mad = np.median(np.abs(df[col] - median))\n",
|
||
" upper = median + n * mad\n",
|
||
" lower = median - n * mad\n",
|
||
" df[col] = np.clip(df[col], lower, upper) # 截断极值\n",
|
||
" return df\n",
|
||
"\n",
|
||
"\n",
|
||
"def percentile_filter(df, features, lower_percentile=0.01, upper_percentile=0.99):\n",
|
||
" for col in features:\n",
|
||
" # 按日期分组计算上下百分位数\n",
|
||
" lower_bound = df.groupby('trade_date')[col].transform(\n",
|
||
" lambda x: x.quantile(lower_percentile)\n",
|
||
" )\n",
|
||
" upper_bound = df.groupby('trade_date')[col].transform(\n",
|
||
" lambda x: x.quantile(upper_percentile)\n",
|
||
" )\n",
|
||
" # 截断超出范围的值\n",
|
||
" df[col] = np.clip(df[col], lower_bound, upper_bound)\n",
|
||
" return df\n",
|
||
"\n",
|
||
"\n",
|
||
"from scipy.stats import iqr\n",
|
||
"\n",
|
||
"\n",
|
||
"def iqr_filter(df, features):\n",
|
||
" for col in features:\n",
|
||
" df[col] = df.groupby('trade_date')[col].transform(\n",
|
||
" lambda x: (x - x.median()) / iqr(x) if iqr(x) != 0 else x\n",
|
||
" )\n",
|
||
" return df\n",
|
||
"\n",
|
||
"\n",
|
||
"def quantile_filter(df, features, lower_quantile=0.01, upper_quantile=0.99, window=60):\n",
|
||
" df = df.copy()\n",
|
||
" for col in features:\n",
|
||
" # 计算 rolling 统计量,需要按日期进行 groupby\n",
|
||
" rolling_lower = df.groupby('trade_date')[col].transform(lambda x: x.rolling(window=min(len(x), window)).quantile(lower_quantile))\n",
|
||
" rolling_upper = df.groupby('trade_date')[col].transform(lambda x: x.rolling(window=min(len(x), window)).quantile(upper_quantile))\n",
|
||
"\n",
|
||
" # 对数据进行裁剪\n",
|
||
" df[col] = np.clip(df[col], rolling_lower, rolling_upper)\n",
|
||
" \n",
|
||
" return df\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 18,
|
||
"id": "47c12bb34062ae7a",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T14:57:50.841165Z",
|
||
"start_time": "2025-04-03T14:49:25.889057Z"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"['vol', 'pct_chg', 'turnover_rate', 'volume_ratio', 'winner_rate', 'lg_elg_net_buy_vol', 'flow_lg_elg_intensity', 'sm_net_buy_vol', 'total_buy_vol', 'lg_elg_buy_prop', 'flow_struct_buy_change', 'lg_elg_net_buy_vol_change', 'flow_lg_elg_accel', 'chip_concentration_range', 'chip_skewness', 'floating_chip_proxy', 'cost_support_15pct_change', 'cat_winner_price_zone', 'flow_chip_consistency', 'profit_taking_vs_absorb', 'cat_is_positive', 'upside_vol', 'downside_vol', 'vol_ratio', 'return_skew', 'return_kurtosis', 'volume_change_rate', 'cat_volume_breakout', 'turnover_deviation', 'cat_turnover_spike', 'avg_volume_ratio', 'cat_volume_ratio_breakout', 'vol_spike', 'vol_std_5', 'atr_14', 'atr_6', 'obv', 'maobv_6', 'rsi_3', 'return_5', 'return_20', 'std_return_5', 'std_return_90', 'std_return_90_2', 'act_factor1', 'act_factor2', 'act_factor3', 'act_factor4', 'rank_act_factor1', 'rank_act_factor2', 'rank_act_factor3', 'cov', 'delta_cov', 'alpha_22_improved', 'alpha_003', 'alpha_007', 'alpha_013', 'cat_up_limit', 'cat_down_limit', 'up_limit_count_10d', 'down_limit_count_10d', 'consecutive_up_limit', 'vol_break', 'weight_roc5', 'smallcap_concentration', 'cost_stability', 'high_cost_break_days', 'liquidity_risk', 'turnover_std', 'mv_volatility', 'volume_growth', 'mv_growth', 'arbr', 'momentum_factor', 'resonance_factor', 'log_close', 'cat_vol_spike', 'up', 'down', 'obv-maobv_6', 'std_return_5 / std_return_90', 'std_return_90 - std_return_90_2', 'cat_af2', 'cat_af3', 'cat_af4', 'act_factor5', 'act_factor6', 'active_buy_volume_large', 'active_buy_volume_big', 'active_buy_volume_small', 'buy_lg_vol_minus_sell_lg_vol', 'buy_elg_vol_minus_sell_elg_vol', 'ctrl_strength', 'low_cost_dev', 'asymmetry', 'lock_factor', 'cat_vol_break', 'cost_atr_adj', 'cat_golden_resonance', 'mv_turnover_ratio', 'mv_adjusted_volume', 'mv_weighted_turnover', 'nonlinear_mv_volume', 'mv_volume_ratio', 'mv_momentum', 'lg_flow_mom_corr_20_60', 'lg_flow_accel', 'profit_pressure', 'underwater_resistance', 'cost_conc_std_20', 'profit_decay_20', 'vol_amp_loss_20', 'vol_drop_profit_cnt_5', 'lg_flow_vol_interact_20', 'cost_break_confirm_cnt_5', 'atr_norm_channel_pos_14', 'turnover_diff_skew_20', 'lg_sm_flow_diverge_20', 'pullback_strong_20_20', 'vol_wgt_hist_pos_20', 'vol_adj_roc_20', 'cs_rank_net_lg_flow_val', 'cs_rank_elg_buy_ratio', 'cs_rank_rel_profit_margin', 'cs_rank_cost_breadth', 'cs_rank_dist_to_upper_cost', 'cs_rank_winner_rate', 'cs_rank_intraday_range', 'cs_rank_close_pos_in_range', 'cs_rank_pos_in_hist_range', 'cs_rank_vol_x_profit_margin', 'cs_rank_lg_flow_price_concordance', 'cs_rank_turnover_per_winner', 'cs_rank_volume_ratio', 'cs_rank_elg_buy_sell_sm_ratio', 'cs_rank_cost_dist_vol_ratio', 'cs_rank_size']\n",
|
||
"去极值\n",
|
||
"去极值\n",
|
||
"检测到 36 个可能漂移的特征: ['vol', 'pct_chg', 'turnover_rate', 'volume_ratio', 'vol_ratio', 'obv', 'alpha_003', 'resonance_factor', 'log_close', 'up', 'down', 'mv_turnover_ratio', 'mv_adjusted_volume', 'mv_weighted_turnover', 'nonlinear_mv_volume', 'mv_volume_ratio', 'mv_momentum', 'profit_decay_20', 'vol_drop_profit_cnt_5', 'cost_break_confirm_cnt_5', 'atr_norm_channel_pos_14', 'pullback_strong_20_20', 'vol_wgt_hist_pos_20', 'vol_adj_roc_20', 'cs_rank_elg_buy_ratio', 'cs_rank_rel_profit_margin', 'cs_rank_cost_breadth', 'cs_rank_dist_to_upper_cost', 'cs_rank_intraday_range', 'cs_rank_close_pos_in_range', 'cs_rank_pos_in_hist_range', 'cs_rank_vol_x_profit_margin', 'cs_rank_turnover_per_winner', 'cs_rank_volume_ratio', 'cs_rank_elg_buy_sell_sm_ratio', 'cs_rank_size']\n",
|
||
"feature_columns: ['winner_rate', 'lg_elg_net_buy_vol', 'flow_lg_elg_intensity', 'total_buy_vol', 'lg_elg_buy_prop', 'flow_struct_buy_change', 'lg_elg_net_buy_vol_change', 'flow_lg_elg_accel', 'chip_concentration_range', 'chip_skewness', 'floating_chip_proxy', 'cost_support_15pct_change', 'cat_winner_price_zone', 'flow_chip_consistency', 'cat_is_positive', 'upside_vol', 'downside_vol', 'return_skew', 'return_kurtosis', 'volume_change_rate', 'cat_volume_breakout', 'turnover_deviation', 'cat_turnover_spike', 'avg_volume_ratio', 'cat_volume_ratio_breakout', 'vol_spike', 'vol_std_5', 'atr_14', 'maobv_6', 'rsi_3', 'return_5', 'return_20', 'std_return_5', 'std_return_90', 'act_factor1', 'act_factor2', 'act_factor3', 'act_factor4', 'rank_act_factor1', 'rank_act_factor2', 'rank_act_factor3', 'cov', 'delta_cov', 'alpha_007', 'alpha_013', 'cat_up_limit', 'cat_down_limit', 'up_limit_count_10d', 'down_limit_count_10d', 'consecutive_up_limit', 'vol_break', 'weight_roc5', 'smallcap_concentration', 'cost_stability', 'high_cost_break_days', 'liquidity_risk', 'turnover_std', 'volume_growth', 'arbr', 'momentum_factor', 'cat_vol_spike', 'obv-maobv_6', 'std_return_5 / std_return_90', 'std_return_90 - std_return_90_2', 'cat_af2', 'cat_af3', 'cat_af4', 'act_factor5', 'act_factor6', 'active_buy_volume_large', 'active_buy_volume_big', 'active_buy_volume_small', 'buy_lg_vol_minus_sell_lg_vol', 'buy_elg_vol_minus_sell_elg_vol', 'ctrl_strength', 'low_cost_dev', 'asymmetry', 'lock_factor', 'cat_vol_break', 'cost_atr_adj', 'cat_golden_resonance', 'lg_flow_mom_corr_20_60', 'profit_pressure', 'underwater_resistance', 'cost_conc_std_20', 'vol_amp_loss_20', 'lg_flow_vol_interact_20', 'turnover_diff_skew_20', 'lg_sm_flow_diverge_20', 'cs_rank_net_lg_flow_val', 'cs_rank_winner_rate', 'cs_rank_lg_flow_price_concordance', 'cs_rank_cost_dist_vol_ratio']\n",
|
||
"739366\n",
|
||
"最小日期: 2020-06-04\n",
|
||
"最大日期: 2023-08-01\n",
|
||
"402667\n",
|
||
"最小日期: 2023-08-01\n",
|
||
"最大日期: 2025-04-09\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"days = 1\n",
|
||
"validation_days = 120\n",
|
||
"\n",
|
||
"import gc\n",
|
||
"\n",
|
||
"gc.collect()\n",
|
||
"\n",
|
||
"df = df.sort_values(by=['ts_code', 'trade_date'])\n",
|
||
"# df['future_return'] = df.groupby('ts_code', group_keys=False)['close'].apply(lambda x: x.shift(-days) / x - 1)\n",
|
||
"df['future_return'] = (df.groupby('ts_code')['close'].shift(-days) - df.groupby('ts_code')['open'].shift(-1)) / \\\n",
|
||
" df.groupby('ts_code')['open'].shift(-1)\n",
|
||
"df['future_volatility'] = (\n",
|
||
" df.groupby('ts_code')['pct_chg']\n",
|
||
" .transform(lambda x: x.rolling(days).std().shift(-days))\n",
|
||
")\n",
|
||
"\n",
|
||
"df['future_score'] = (\n",
|
||
" 0.7 * df['future_return']\n",
|
||
" + 0.3 * df['future_volatility']\n",
|
||
")\n",
|
||
"# df['future_score'] = calculate_score(df, days=2, lambda_param=0.3)\n",
|
||
"\n",
|
||
"filter_index = df['future_return'].between(df['future_return'].quantile(0.01), df['future_return'].quantile(0.99))\n",
|
||
"filter_index = df['future_volatility'].between(df['future_volatility'].quantile(0.01),\n",
|
||
" df['future_volatility'].quantile(0.99)) | filter_index\n",
|
||
"\n",
|
||
"# df['label'] = df.groupby('trade_date', group_keys=False)['future_volatility'].transform(\n",
|
||
"# lambda x: pd.qcut(x, q=30, labels=False, duplicates='drop')\n",
|
||
"# )\n",
|
||
"\n",
|
||
"df['label'] = df.groupby('trade_date', group_keys=False)['future_return'].transform(\n",
|
||
" lambda x: pd.qcut(x, q=20, labels=False, duplicates='drop')\n",
|
||
")\n",
|
||
"\n",
|
||
"\n",
|
||
"# df['1_score'] = df.groupby('ts_code', group_keys=False)['future_score'].shift(days)\n",
|
||
"# df['2_score'] = df.groupby('ts_code', group_keys=False)['future_score'].shift(1 + days)\n",
|
||
"# df['3_score'] = df.groupby('ts_code', group_keys=False)['future_score'].shift(3 + days - 1)\n",
|
||
"\n",
|
||
"def symmetric_log_transform(values):\n",
|
||
" return np.sign(values) * np.log1p(np.abs(values))\n",
|
||
"\n",
|
||
"\n",
|
||
"train_data = df[filter_index & (df['trade_date'] <= '2023-08-01') & (df['trade_date'] >= '2000-01-01')]\n",
|
||
"test_data = df[(df['trade_date'] >= '2023-08-01')]\n",
|
||
"\n",
|
||
"\n",
|
||
"def select_pre_zt_stocks_dynamic(stock_df):\n",
|
||
" # 排序数据\n",
|
||
" stock_df = stock_df.sort_values(by=['trade_date', 'ts_code'])\n",
|
||
" stock_df = stock_df.groupby('trade_date', group_keys=False).apply(\n",
|
||
" lambda x: x.nlargest(1000, 'return_20')\n",
|
||
" )\n",
|
||
"\n",
|
||
" return stock_df\n",
|
||
"\n",
|
||
"\n",
|
||
"train_data = select_pre_zt_stocks_dynamic(train_data)\n",
|
||
"test_data = select_pre_zt_stocks_dynamic(test_data)\n",
|
||
"\n",
|
||
"# train_data['label'] = train_data.groupby('trade_date', group_keys=False)['future_score'].transform(\n",
|
||
"# lambda x: pd.qcut(x, q=50, labels=False, duplicates='drop')\n",
|
||
"# )\n",
|
||
"# test_data['label'] = test_data.groupby('trade_date', group_keys=False)['future_score'].transform(\n",
|
||
"# lambda x: pd.qcut(x, q=50, labels=False, duplicates='drop')\n",
|
||
"# )\n",
|
||
"\n",
|
||
"industry_df = industry_df.sort_values(by=['trade_date'])\n",
|
||
"index_data = index_data.sort_values(by=['trade_date'])\n",
|
||
"\n",
|
||
"train_data = train_data.merge(industry_df, on=['cat_l2_code', 'trade_date'], how='left')\n",
|
||
"# train_data = train_data.merge(index_data, on='trade_date', how='left')\n",
|
||
"test_data = test_data.merge(industry_df, on=['cat_l2_code', 'trade_date'], how='left')\n",
|
||
"# test_data = test_data.merge(index_data, on='trade_date', how='left')\n",
|
||
"\n",
|
||
"train_data, test_data = train_data.replace([np.inf, -np.inf], np.nan), test_data.replace([np.inf, -np.inf], np.nan)\n",
|
||
"\n",
|
||
"# feature_columns_new = feature_columns[:]\n",
|
||
"# train_data, _ = create_deviation_within_dates(train_data, feature_columns)\n",
|
||
"# test_data, _ = create_deviation_within_dates(test_data, feature_columns)\n",
|
||
"\n",
|
||
"feature_columns = [col for col in df.columns if col in df.columns]\n",
|
||
"feature_columns = [col for col in feature_columns if col not in ['trade_date',\n",
|
||
" 'ts_code',\n",
|
||
" 'label']]\n",
|
||
"feature_columns = [col for col in feature_columns if 'future' not in col]\n",
|
||
"feature_columns = [col for col in feature_columns if 'label' not in col]\n",
|
||
"feature_columns = [col for col in feature_columns if 'score' not in col]\n",
|
||
"feature_columns = [col for col in feature_columns if 'gen' not in col]\n",
|
||
"feature_columns = [col for col in feature_columns if 'is_st' not in col]\n",
|
||
"feature_columns = [col for col in feature_columns if 'pe_ttm' not in col]\n",
|
||
"# feature_columns = [col for col in feature_columns if 'volatility' not in col]\n",
|
||
"feature_columns = [col for col in feature_columns if 'circ_mv' not in col]\n",
|
||
"feature_columns = [col for col in feature_columns if 'cat_l2_code' not in col]\n",
|
||
"feature_columns = [col for col in feature_columns if col not in origin_columns]\n",
|
||
"feature_columns = [col for col in feature_columns if not col.startswith('_')]\n",
|
||
"# feature_columns = [col for col in feature_columns if col not in ['ts_code', 'trade_date', 'vol_std_5', 'cov', 'delta_cov', 'alpha_22_improved', 'alpha_007', 'consecutive_up_limit', 'mv_volatility', 'volume_growth', 'mv_growth', 'arbr']]\n",
|
||
"feature_columns = [col for col in feature_columns if col not in ['intraday_lg_flow_corr_20', \n",
|
||
" 'cap_neutral_cost_metric', \n",
|
||
" 'hurst_net_mf_vol_60', \n",
|
||
" 'complex_factor_deap_1', \n",
|
||
" 'lg_buy_consolidation_20',\n",
|
||
" 'cs_rank_ind_cap_neutral_pe',\n",
|
||
" 'cs_rank_opening_gap',\n",
|
||
" 'cs_rank_ind_adj_lg_flow']]\n",
|
||
"print(feature_columns)\n",
|
||
"numeric_columns = df.select_dtypes(include=['float64', 'int64']).columns\n",
|
||
"numeric_columns = [col for col in numeric_columns if col in feature_columns]\n",
|
||
"print('去极值')\n",
|
||
"train_data = quantile_filter(train_data, numeric_columns) # 去极值\n",
|
||
"# print('中性化')\n",
|
||
"# train_data = neutralize_manual(train_data, numeric_columns, industry_col='cat_l2_code', mkt_cap_col='log(circ_mv)') # 中性化\n",
|
||
"print('去极值')\n",
|
||
"test_data = quantile_filter(test_data, numeric_columns) # 去极值\n",
|
||
"# print('中性化')\n",
|
||
"# test_data = neutralize_manual(test_data, numeric_columns, industry_col='cat_l2_code', mkt_cap_col='log(circ_mv)')\n",
|
||
"all_dates = train_data['trade_date'].unique() # 获取所有唯一的 trade_date\n",
|
||
"split_date = all_dates[-validation_days] # 划分点为倒数第 validation_days 天\n",
|
||
"train_data_split = train_data[train_data['trade_date'] < split_date] # 训练集\n",
|
||
"val_data_split = train_data[train_data['trade_date'] >= split_date] # 验证集\n",
|
||
"\n",
|
||
"feature_columns, _ = remove_shifted_features(\n",
|
||
" train_data_split,\n",
|
||
" val_data_split,\n",
|
||
" feature_columns)\n",
|
||
"\n",
|
||
"feature_columns = remove_highly_correlated_features(train_data,\n",
|
||
" feature_columns)\n",
|
||
"keep_columns = [col for col in train_data.columns if\n",
|
||
" col in feature_columns or col in ['ts_code', 'trade_date', 'label', 'future_return',\n",
|
||
" 'future_score', 'future_volatility']]\n",
|
||
"# train_data = train_data[keep_columns]\n",
|
||
"print(f'feature_columns: {feature_columns}')\n",
|
||
"\n",
|
||
"train_data = train_data.dropna(subset=feature_columns)\n",
|
||
"train_data = train_data.dropna(subset=['label'])\n",
|
||
"train_data = train_data.reset_index(drop=True)\n",
|
||
"\n",
|
||
"# print(test_data.tail())\n",
|
||
"test_data = test_data.dropna(subset=feature_columns)\n",
|
||
"# test_data = test_data.dropna(subset=['label'])\n",
|
||
"test_data = test_data.reset_index(drop=True)\n",
|
||
"\n",
|
||
"print(len(train_data))\n",
|
||
"print(f\"最小日期: {train_data['trade_date'].min().strftime('%Y-%m-%d')}\")\n",
|
||
"print(f\"最大日期: {train_data['trade_date'].max().strftime('%Y-%m-%d')}\")\n",
|
||
"print(len(test_data))\n",
|
||
"print(f\"最小日期: {test_data['trade_date'].min().strftime('%Y-%m-%d')}\")\n",
|
||
"print(f\"最大日期: {test_data['trade_date'].max().strftime('%Y-%m-%d')}\")\n",
|
||
"\n",
|
||
"cat_columns = [col for col in feature_columns if col.startswith('cat')]\n",
|
||
"for col in cat_columns:\n",
|
||
" train_data[col] = train_data[col].astype('category')\n",
|
||
" test_data[col] = test_data[col].astype('category')\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"# feature_columns_new.remove('cat_l2_code')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 19,
|
||
"id": "8f134d435f71e9e2",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T14:57:51.050696Z",
|
||
"start_time": "2025-04-03T14:57:51.034030Z"
|
||
},
|
||
"jupyter": {
|
||
"source_hidden": true
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"from sklearn.preprocessing import StandardScaler\n",
|
||
"import lightgbm as lgb\n",
|
||
"import matplotlib.pyplot as plt\n",
|
||
"from sklearn.decomposition import PCA\n",
|
||
"\n",
|
||
"\n",
|
||
"def train_light_model(train_data_df, params, feature_columns, callbacks, evals,\n",
|
||
" print_feature_importance=True, num_boost_round=100,\n",
|
||
" validation_days=180, use_pca=False, split_date=None): # 新增参数:validation_days\n",
|
||
" # 确保数据按时间排序\n",
|
||
" train_data_df = train_data_df.sort_values(by='trade_date')\n",
|
||
"\n",
|
||
" numeric_columns = train_data_df.select_dtypes(include=['float64', 'int64']).columns\n",
|
||
" numeric_columns = [col for col in numeric_columns if col in feature_columns]\n",
|
||
" # X_train.loc[:, numeric_columns] = scaler.fit_transform(X_train[numeric_columns])\n",
|
||
" # X_val.loc[:, numeric_columns] = scaler.transform(X_val[numeric_columns])\n",
|
||
" train_data_df = cross_sectional_standardization(train_data_df, numeric_columns)\n",
|
||
"\n",
|
||
" # 去除标签为空的样本\n",
|
||
" train_data_df = train_data_df.dropna(subset=['label'])\n",
|
||
" print('原始训练集大小: ', len(train_data_df))\n",
|
||
"\n",
|
||
" # 按时间顺序划分训练集和验证集\n",
|
||
" if split_date is None:\n",
|
||
" all_dates = train_data_df['trade_date'].unique() # 获取所有唯一的 trade_date\n",
|
||
" split_date = all_dates[-validation_days] # 划分点为倒数第 validation_days 天\n",
|
||
" train_data_split = train_data_df[train_data_df['trade_date'] < split_date] # 训练集\n",
|
||
" val_data_split = train_data_df[train_data_df['trade_date'] >= split_date] # 验证集\n",
|
||
"\n",
|
||
" # 打印划分结果\n",
|
||
" print(f\"划分后的训练集大小: {len(train_data_split)}, 验证集大小: {len(val_data_split)}\")\n",
|
||
"\n",
|
||
" # 提取特征和标签\n",
|
||
" X_train = train_data_split[feature_columns]\n",
|
||
" y_train = train_data_split['label']\n",
|
||
"\n",
|
||
" X_val = val_data_split[feature_columns]\n",
|
||
" y_val = val_data_split['label']\n",
|
||
"\n",
|
||
" # 标准化数值特征\n",
|
||
" scaler = StandardScaler()\n",
|
||
"\n",
|
||
" # 计算每个 trade_date 内的样本数(LTR 需要 group 信息)\n",
|
||
" train_groups = train_data_split.groupby('trade_date').size().tolist()\n",
|
||
" val_groups = val_data_split.groupby('trade_date').size().tolist()\n",
|
||
"\n",
|
||
" # 处理类别特征\n",
|
||
" categorical_feature = [col for col in feature_columns if 'cat' in col]\n",
|
||
"\n",
|
||
" pca = None\n",
|
||
" if use_pca:\n",
|
||
" pca = PCA(n_components=0.95) # 或指定 n_components=固定值(如 10)\n",
|
||
" numeric_features = [col for col in feature_columns if col not in categorical_feature]\n",
|
||
" numeric_pca = pca.fit_transform(X_train[numeric_features])\n",
|
||
" X_train = pd.concat([pd.DataFrame(numeric_pca, index=X_train.index), X_train[categorical_feature]], axis=1)\n",
|
||
"\n",
|
||
" numeric_pca = pca.transform(X_val[numeric_features])\n",
|
||
" X_val = pd.concat([pd.DataFrame(numeric_pca, index=X_val.index), X_val[categorical_feature]], axis=1)\n",
|
||
"\n",
|
||
" # 计算权重(基于时间)\n",
|
||
" # trade_date = train_data_split['trade_date'] # 交易日期\n",
|
||
" # weights = (trade_date - trade_date.min()).dt.days / (trade_date.max() - trade_date.min()).days + 1\n",
|
||
" # weights = train_data_split.groupby('trade_date')['std_return_5'].transform(\n",
|
||
" # lambda x: x / x.mean()\n",
|
||
" # )\n",
|
||
" ud = sorted(train_data_split[\"trade_date\"].unique().tolist())\n",
|
||
" date_weights = {date: weight * weight for date, weight in zip(ud, np.linspace(1, 10, len(ud)))}\n",
|
||
" params['weight'] = train_data_split[\"trade_date\"].map(date_weights).tolist()\n",
|
||
"\n",
|
||
" print('feature_columns size: ', len(X_train.columns.tolist()))\n",
|
||
"\n",
|
||
" train_dataset = lgb.Dataset(\n",
|
||
" X_train, label=y_train, group=train_groups,\n",
|
||
" categorical_feature=categorical_feature\n",
|
||
" )\n",
|
||
"\n",
|
||
" # weights = val_data_split.groupby('trade_date')['std_return_5'].transform(\n",
|
||
" # lambda x: x / x.mean()\n",
|
||
" # )\n",
|
||
" val_dataset = lgb.Dataset(\n",
|
||
" X_val, label=y_val, group=val_groups,\n",
|
||
" categorical_feature=categorical_feature\n",
|
||
" )\n",
|
||
"\n",
|
||
" # 训练模型\n",
|
||
" model = lgb.train(\n",
|
||
" params, train_dataset, num_boost_round=num_boost_round,\n",
|
||
" valid_sets=[train_dataset, val_dataset], valid_names=['train', 'valid'],\n",
|
||
" callbacks=callbacks\n",
|
||
" )\n",
|
||
"\n",
|
||
" # 打印特征重要性(如果需要)\n",
|
||
" if print_feature_importance:\n",
|
||
" lgb.plot_metric(evals)\n",
|
||
" lgb.plot_importance(model, importance_type='split', max_num_features=20)\n",
|
||
" plt.show()\n",
|
||
"\n",
|
||
" return model, scaler, pca\n",
|
||
"\n",
|
||
"\n",
|
||
"from catboost import CatBoostRanker, Pool\n",
|
||
"import numpy as np\n",
|
||
"\n",
|
||
"\n",
|
||
"def train_catboost(train_data_df, test_data_df, feature_columns, params=None, plot=False):\n",
|
||
" X_train = train_data_df[feature_columns]\n",
|
||
" y_train = train_data_df['label']\n",
|
||
"\n",
|
||
" X_val = test_data_df[feature_columns]\n",
|
||
" y_val = test_data_df['label']\n",
|
||
"\n",
|
||
" scaler = StandardScaler()\n",
|
||
" numeric_columns = X_train.select_dtypes(include=['float64', 'int64']).columns\n",
|
||
" X_train.loc[:, numeric_columns] = scaler.fit_transform(X_train[numeric_columns])\n",
|
||
" X_val.loc[:, numeric_columns] = scaler.transform(X_val[numeric_columns])\n",
|
||
"\n",
|
||
" group_train = train_data_df['trade_date'].factorize()[0]\n",
|
||
" group_val = test_data_df['trade_date'].factorize()[0]\n",
|
||
"\n",
|
||
" cat_features = [i for i, col in enumerate(feature_columns) if col.startswith('cat')]\n",
|
||
" print(f'cat_features: {cat_features}')\n",
|
||
"\n",
|
||
" train_pool = Pool(\n",
|
||
" data=X_train,\n",
|
||
" label=y_train,\n",
|
||
" group_id=group_train,\n",
|
||
" cat_features=cat_features\n",
|
||
" )\n",
|
||
"\n",
|
||
" val_pool = Pool(\n",
|
||
" data=X_val,\n",
|
||
" label=y_val,\n",
|
||
" group_id=group_val,\n",
|
||
" cat_features=cat_features\n",
|
||
" )\n",
|
||
"\n",
|
||
" # CatBoost 排序学习模型\n",
|
||
" model = CatBoostRanker(**params)\n",
|
||
" model.fit(train_pool, eval_set=val_pool, plot=plot, use_best_model=True)\n",
|
||
"\n",
|
||
" return model, scaler\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 20,
|
||
"id": "c6eb5cd4-e714-420a-ac48-39af3e11ee81",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T15:03:18.426481Z",
|
||
"start_time": "2025-04-03T15:02:19.926352Z"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"train data size: 739366\n",
|
||
"原始训练集大小: 739366\n",
|
||
"划分后的训练集大小: 621433, 验证集大小: 117933\n",
|
||
"feature_columns size: 93\n",
|
||
"Training until validation scores don't improve for 100 rounds\n",
|
||
"[100]\ttrain's ndcg@1: 0.790171\tvalid's ndcg@1: 0.396168\n",
|
||
"Early stopping, best iteration is:\n",
|
||
"[22]\ttrain's ndcg@1: 0.653157\tvalid's ndcg@1: 0.479455\n",
|
||
"Evaluated only: ndcg@1\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"image/png": "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5MgCrSotW7a0tLpV1sSJE3F0dCywzd7eHr1ebylDfHw8Li4utGnThn379pXputfXw80332x5XRU5Nz4+nuTkZABLt9/UqVMLHPfvf/+7TNcXoqaSLi0hrMTb25shQ4awbNky0tPTMZlM3H///UUee+rUKZKSkvDx8Slyf2xsbJnv26xZs1KPOXPmDAAdO3Ys83UBrly5QkZGBq1atSq0r02bNvz111/lut71ylL2PNcGXHk8PDwsOU+xsbFkZGTQsmXLQscVta0iiiqv2Wzm/fff55NPPuHcuXMFcm/yutpK4uDgUKjL7drXVZrr68XDwwOAq1ev4ubmRkREBHq9vlDZq6pOhLAWCXiEsKKxY8cyZcoUoqOjueOOO3B3dy/yOLPZjI+PD99//32R+8uSc5Ln+hYHaymupej65NtrlafsxbViaaXk/lSlosr7xhtv8PLLL/PII4/w6quv0rBhQ/R6Pc8880yZRnFVdNRWaeffyHoRwhok4BHCiu69914ef/xxdu7cyfLly4s9rkWLFqxfv55+/fqV+qFfFUPL87qCjhw5Uq5v9t7e3jg6OnLq1KlC+8LDwws8z2tZSExMLLA9IiKinKWtGB8fHxwcHDh9+nShfUVtK0pF6nrFihUMHjyYr776qsD2xMREvLy8yn29qta0aVPMZjPnzp0r0FJX1joRoqaSHB4hrMjFxYVPP/2UuXPnMmLEiGKPe/DBBzGZTLz66quF9uXk5BQIGpydnQsFEeV122234erqyvz588nMzCywr6SWAIPBwLBhw1i1ahWRkZGW7cePH2fdunUFjnVzc8PLy4stW7YU2P7JJ59UquxlZTAYGDJkCKtWreLy5cuW7adPn2bNmjVluoazszNJSUnlvu/1dfjzzz9z6dKlcl2nuuTlWl3/7/Dhhx9aozhCVBlp4RHCyiZOnFjqMQMHDuTxxx9n/vz5HDhwgNtuuw1bW1tOnTrFzz//zPvvv2/J/wkODubTTz/ltddeo2XLlvj4+HDLLbeUq0xubm689957PProo/Ts2dMy983BgwdJT0/nm2++KfbcefPmsXbtWm6++WamTp1KTk4OH374IR06dODQoUMFjn300Ud58803efTRR+nRowdbtmzh5MmT5SprZcydO5e///6bfv368eSTT2Iymfjoo4/o2LEjBw4cKPX84OBgli9fzowZM+jZsycuLi4lBq4Ad911F6+88gqTJ0+mb9++HD58mO+//57mzZtX0auqnODgYO677z4WLlxIfHy8ZVh63r9LbZqcUohrScAjRC2xaNEigoOD+eyzz3jhhRewsbEhKCiIhx9+mH79+lmOmz17NhEREfzvf/8jJSWFgQMHljvgAfjXv/6Fj48Pb775Jq+++iq2tra0bduW//znPyWe17lzZ9atW8eMGTOYPXs2jRs3Zt68eURFRRUKeGbPns2VK1dYsWIFP/30E3fccQdr1qwpNjm7qgUHB7NmzRpmzpzJyy+/TGBgIK+88grHjx/nxIkTpZ4/depUDhw4wNdff817771H06ZNSw14XnjhBdLS0li2bBnLly+ne/furF69mueff76qXlalffvtt/j5+fHDDz/w66+/MmTIEJYvX06bNm1qxazWQhRFp0mmmhBCFDBy5EiOHj1aZC5SfXXgwAG6devGd999x7hx46xdHCHKTXJ4hBD12vULj546dYq//vrLsiRHfVTUYqwLFy5Er9czYMAAK5RIiMqTLi0hRL3WvHlzJk2aRPPmzYmIiODTTz/Fzs6OZ5991tpFs5r//e9/hIWFMXjwYGxsbFizZg1r1qzhscceIzAw0NrFE6JCpEtLCFGvTZ48mY0bNxIdHY29vT19+vThjTfeoHv37tYumtWEhIQwb948jh07RmpqKk2aNGH8+PG8+OKLsgK7qLUk4BFCCCFEnSc5PEIIIYSo8yTgEUIIIUSdV+86Y81mM5cvX8bV1VUm0BJCCCFqCU3TSElJwd/fH72+Au01mpV99NFHWtOmTTV7e3utV69e2q5du4o9Njs7W5s3b57WvHlzzd7eXuvcubO2Zs2act3vwoULGiAPechDHvKQhzxq4ePChQsVijes2sKTNyX7okWL6N27NwsXLmTYsGGEh4cXOdPqSy+9xHfffccXX3xB27ZtWbduHffeey/bt2+nW7duZbqnq6srAOfOnaNhw4ZV+nrqE6PRyN9//21Z4kCUn9Rh5UkdVg2px8qTOqy80uowOTmZwMBAy+d4eVk14FmwYAFTpkxh8uTJgJo6f/Xq1SxevLjIadaXLl3Kiy++yPDhwwF48sknWb9+Pe+++y7fffddme6Z143l6uqKm5tbFb2S+sdoNOLk5ISbm5v8564gqcPKkzqsGlKPlSd1WHllrcOKpqNYLeDJzs4mLCyMWbNmWbbp9XqGDBnCjh07ijwnKyur0Doujo6ObN26tdj7ZGVlkZWVZXmenJwMqIo1Go2VeQn1Wl7dSR1WnNRh5UkdVg2px8qTOqy80uqwsnVrtYAnLi4Ok8mEr69vge2+vr7FLto3bNgwFixYwIABA2jRogWhoaGsXLkSk8lU7H3mz5/PvHnzCm3fuHEjTk5OlXsRgpCQEGsXodaTOqw8qcOqIfVYeVKHlVdcHaanp1fqurVqlNb777/PlClTaNu2LTqdjhYtWjB58mQWL15c7DmzZs1ixowZlud5fYCDBw/G09PzRhS7TjIajYSEhDB06FBpvq0gqcPKkzqsGlKPlSd1WHml1WFeD01FWS3g8fLywmAwEBMTU2B7TEwMfn5+RZ7j7e3NqlWryMzMJD4+Hn9/f55//nmaN29e7H3s7e2xt7cvtN3W1rbEN6XJZJKmyRKYTCZsbGwwmUxFDg+0tbXFYDBYoWS1T2nvRVE6qcOqIfVYeVKHlVdcHVa2Xq0W8NjZ2REcHExoaCgjR44E1Bw5oaGhTJ8+vcRzHRwcCAgIwGg08ssvv/Dggw9WWbk0TSM6OprExMQqu2ZdpGkafn5+XLhwodgEMnd3d/z8/GS+IyGEEFZn1S6tGTNmMHHiRHr06EGvXr1YuHAhaWlpllFbEyZMICAggPnz5wOwa9cuLl26RNeuXbl06RJz587FbDZX6arGecGOj48PTk5O8mFdDLPZTGpqKi4uLoVaeDRNIz09ndjYWAAaNWpkjSIKIYQQFlYNeB566CGuXLnC7NmziY6OpmvXrqxdu9aSyBwZGVngwzQzM5OXXnqJs2fP4uLiwvDhw1m6dCnu7u5VUh6TyWQJdiS/p2Rms5ns7GwcHByK7NJydHQEIDY2Fh8fH+neEkIIYVVWT1qePn16sV1YmzZtKvB84MCBHDt2rNrKkpezI6O3qkZePRqNRgl4hBBCWJUsHloE6caqGlKPQgghagoJeIQQQghR50nAIwoJCgpi4cKF1i6GEEIIUWWsnsMjqsagQYPo2rVrlQQqe/bswdnZufKFEkIIIWoICXjqCU3TLJMFlsbb2/sGlEgIIYS4caRLqw6YNGkSmzdv5v3330en06HT6ViyZAk6nY41a9YQHByMvb09W7du5cyZM9xzzz34+vri4uJCz549Wb9+fYHrXd+lpdPp+PLLL7n33ntxcnKiVatW/P777zf4VQohhBAVJwFPKTRNIz07xyoPTdPKVMb333+fPn36MGXKFKKiooiKiiIwMBCA559/njfffJPjx4/TuXNnUlNTGT58OKGhoezfv5/bb7+dESNGEBkZWeI95s2bx4MPPsihQ4cYPnw448eP5+rVq5WuXyGEEOJGkC6tUmQYTbSfvc4q9z72yjCc7Er/J2rQoAF2dnY4OTlZ1iHLW3H+lVdeYejQoZZjGzZsSJcuXSzPX331VX799Vd+//33Epf0mDRpEmPGjAHgjTfe4IMPPiAsLIymTZtW6LUJIYQQN5K08NRxPXr0KPA8NTWVmTNn0q5dO9zd3XFxceH48eOltvB07tzZ8ruzszNubm7ExcVVS5mFEEKIqiYtPKVwtDVw7JVhVrt3ZV0/2mrmzJmEhITwzjvv0LJlSxwdHbn//vvJzs4u8TrXr1Kr0+kwm82VLp8QQghxI0jAUwqdTlembiVrs7Ozw2QylXrctm3bmDRpEvfeey+gWnzOnz9fzaUTQgghrEu6tOqIoKAgdu3axfnz54mLiyu29aVVq1asXLmSAwcOcPDgQcaOHSstNUIIIeo8CXjqiJkzZ2IwGGjfvj3e3t7F5uQsWLAADw8P+vbty4gRIxg2bBjdu3e/waUVQgghbqya31cjyqR169bs2LGjwLZJkyYVOi4oKIgNGzYU2DZt2rQCz6/v4ipqeHxCQgLJyckVK6wQQghxg0kLjxBCCCHqPAl4hBBCCFHnScAjhBBCiDpPAh4hhBBC1HkS8AghhBCizpOARwghhBB1ngQ8QgghhKjzJOARQgghRJ0nAY8QQggh6jwJeASgZmBeuHCh5blOp2PVqlXFHn/+/Hk8PDw4cOBAtZdNCCGEqCxZWkIUKSoqCg8PD2sXQwghhKgSEvCIIvn5+Vm7CEIIIUSVkS6tOuDzzz/H398fs9lcYPs999zDI488wpkzZ7jnnnvw9fXFxcWFnj17sn79+hKveX2X1u7du+nWrRsODg706NGD/fv3V8dLEUIIIaqFBDyl0TTITrPOo4hVyovywAMPEB8fz8aNGy3bEhISWLt2LePGjSM1NZXhw4cTGhrK/v37uf322xkxYgSRkZFlun5qaip33XUX7du3JywsjLlz5/Lss89WqDqFEEIIa5AurdIY0+ENf+vc+4XLYOdc6mEeHh7ccccdLFu2jFtvvRWAFStW4OXlxeDBg9Hr9XTp0sVy/Kuvvsqvv/7K77//zvTp00u9/rJlyzCbzXz11Vc4ODjQoUMHIiMjmTZtWsVfmxBCCHEDSQtPHTFu3Dh++eUXsrKyAPj+++8ZPXo0er2e1NRUZs6cSbt27XB3d8fFxYXjx4+XuYXn+PHjdO7cGQcHB8u2Pn36VMvrEEIIIaqDtPCUxtZJtbRY695lNGLECDRNY/Xq1fTs2ZN//vmH9957D4CZM2cSEhLCO++8Q8uWLXF0dOT+++8nOzu7ukouhBBC1CgS8JRGpytTt5K1OTg4MGrUKL7//ntOnz5NmzZt6N69OwDbtm1j0qRJ3HvvvYDKyTl//nyZr92uXTuWLl1KZmampZVn586dVf4ahBBCiOoiXVp1yLhx41i9ejWLFy9m3Lhxlu2tWrVi5cqVHDhwgIMHDzJ27NhCI7pKMnbsWHQ6HVOmTOHYsWP89ddfLFiwoDpeghBCCFEtJOCpQ2655RYaNmxIeHg4Y8eOtWxfsGABHh4e9O3blxEjRjBs2DBL609ZuLi48Mcff3D48GG6devGiy++yPz586vjJQghhBDVQrq06hC9Xs/ly4XzjYKCgtiwYUOBbdePsLq+i0u7bkj8TTfdVGAZCbPZzNWrV3Fzc6tcoYUQQogbQFp4hBBCCFHnScAjhBBCiDpPAh4hhBBC1HkS8AghhBCizpOApwjXJ+yKipF6FEIIUVNIwHMNW1tbANLT061ckrohrx7z6lUIIYQoTlaOmTRj9X1ZlmHp1zAYDLi7uxMbGwuAk5MTOp3OyqWqmcxmM9nZ2WRmZqLXF4ybNU0jPT2d2NhY3N3dMRgMViqlEEKImkrTNM5cSWPLySv8c+oKO8/Gk2G04fVDGwhs6EST3MdDPQNp5eta6ftJwHMdPz8/AEvQI4qmaRoZGRk4OjoWGxS6u7tb6lMIIYQASMvKYeW+i3yzI4LTsamF92ebOBGdwonoFABuaesjAU910Ol0NGrUCB8fH4xGo7WLU2MZjUa2bNnCgAEDiuyysrW1lZYdIYSoR/K6oor6EqxpGqdjU/lh9wV+3nuBlKwcAOxs9PQKasjNrbzo29yDE3v+ofNNA7mcks2FhHQi49Np6eNSJeWTgKcYBoNBPrBLYDAYyMnJwcHBQXJ0hBCiHjCbNfT6olv0z1xJZewXO8k0munexJ3gph50b+JBcqaRzSfj2HLyCpcSMyzHN/dyZmLfIEZ1D8DVQX2GGI1Gzhqgubczbfzdq7z8EvAIIYQQokhms8bOc/H8tOcCa45E06+lF++P7moJUgBikjOZ8NVuYpKzANgYfoWN4VcKXcvORs/NLb0Y36cpA1p5Fxs8VRcJeIQQQog67mpaNptOxnJLW18aOBZulb+QkM7nW86SYTThbGfA0c4GDY01h6OJTMgfubzhRCwPLNrB15N70qiBI8mZRiZ9vYdLiRk083LmzVGdOB6VzN6Iq+yPTMTBVs/NrbwZ2Mabm5p54mhnvZ4Tqwc8H3/8MW+//TbR0dF06dKFDz/8kF69ehV7/MKFC/n000+JjIzEy8uL+++/n/nz5+Pg4HADSy2EEELUDhvDY3l2xSGupGTR2MORT8Z1p3Njd8v+7WfimPb9Pq6mF5236mpvw4iu/vRp7skrfx7jRHQK9368nc/GB/PmmhMcj0rGy8Webx/pRWBDJ3o392RSv2Y36NWVnVUDnuXLlzNjxgwWLVpE7969WbhwIcOGDSM8PBwfH59Cxy9btoznn3+exYsX07dvX06ePMmkSZPQ6XQsWLDACq9ACCGEqJnSs3N4ffVxvt8VCYBeBxevZnD/pzt4+a52PHxTU5bujGDeH8cwmTU6N27AHR0bkZ6dQ3q2iUyjie5NPBjeqZGlZaZbE3cmf72HU7Gp3PPxNgBc7G1YMrkngQ2drPZay8KqAc+CBQuYMmUKkydPBmDRokWsXr2axYsX8/zzzxc6fvv27fTr14+xY8cCEBQUxJgxY9i1a9cNLbcQQghR08SlZnE+Lo3IhHQi4tP57cAlzser7qhH+jXjiYHNeWnVEf4+FsPLvx3lu52RhMeood8ju/rz5n2dcbAtucupsYcTK57syxNLw9hxNh5bg45FDwfTMaBBtb++yrJawJOdnU1YWBizZs2ybNPr9QwZMoQdO3YUeU7fvn357rvv2L17N7169eLs2bP89ddfjB8/vtj7ZGVlkZWVZXmenJwMqGxwGXZecXl1J3VYcVKHlSd1WDWkHivPmnVoMmvM+eMYy/deKrTPz82et0Z1pG8LTwA+Gt2Zr7dH8PbfpwiPSUGng//e1opH+wWhw4zRaC71fk428OX4bvy49yJt/VzoFdSgSl53aXVY2XvoNCsteHT58mUCAgLYvn07ffr0sWx/9tln2bx5c7GtNh988AEzZ85E0zRycnJ44okn+PTTT4u9z9y5c5k3b16h7cuWLcPJqWY3vwkhhBAlMWnw/Wk9YXFqxnsPOw0vBw0vB/B11Ojto+FURNPGuRTYHKWnt49GO/fase5heno6Y8eOJSkpCTc3t3Kfb/Wk5fLYtGkTb7zxBp988gm9e/fm9OnTPP3007z66qu8/PLLRZ4za9YsZsyYYXmenJxMYGAggwcPxtPT80YVvc4xGo2EhIQwdOhQmYengqQOK0/qsGpIPVaeNeowx2Rm5i9HCIuLxkav470HO3N7B98ynz+tGstWEaXVYV4PTUVZLeDx8vLCYDAQExNTYHtMTEyxyxG8/PLLjB8/nkcffRSATp06kZaWxmOPPcaLL75YaE0nAHt7e+zt7Qttt7W1lf/YVUDqsfKkDitP6rBqSD1WXnF1mJqVg0GnK3ZY9pWULGKSM2nj54qtofR1vY0mMzN/Oszqw9HYGnR8NLY7wzrUjaV8iqvDyr43rRbw2NnZERwcTGhoKCNHjgTUgpShoaFMnz69yHPS09MLBTV5syFbqWdOCCGEKFKm0UTo8Vh+3X+JTeGx+Lja89MTfWjsUTCdIiI+jVGfbCc+LRsHWz2dG6uZinsGedCrmScu9vkf1dk5ZlYfvsyX/5zj6OVkbA06Ph0XzJD2ZW/Zqa+s2qU1Y8YMJk6cSI8ePejVqxcLFy4kLS3NMmprwoQJBAQEMH/+fABGjBjBggUL6Natm6VL6+WXX2bEiBGyDIQQQogbIiopg5BjMbjY29CjaUMCGzpa9l1Nz2bn+StsCo8l5GiMZc0ogMtJmUxYvJtfnuiLh7MdAAlp2Uz6eg/xadkY9DoyjWZ2n0tg97kEPgVs9Dq6NXGnf0tv9Dr4bleEZUZjR1sDH4/rxi1tJdgpC6sGPA899BBXrlxh9uzZREdH07VrV9auXYuvr/rHi4yMLNCi89JLL6HT6XjppZe4dOkS3t7ejBgxgtdff91aL0EIIUQtE5uSyYmoFC5cTefS1QwuJWaQkpnDmF5NGFpMS0lGtom/j0WzIuwiW0/HcW2ngo+rPV0DG3AiwsCFnZsK7Atwd+Serv70b+XF//10kLNX0njkmz0se/QmdDqY8u1ezsWlEeDuyK9T+5KcmcO+iKvsjUhg59kEIhPS2XP+KnvOXy1wvwl9mjK2d1Ma5gZOonRWT1qePn16sV1YmzZtKvDcxsaGOXPmMGfOnBtQMiGEELWVpmkkZRiJiE8nIiGds1dSOXIpicOXkiwtJNfbcCKWp29txdO3trKs82Qya3y3M4J3/w4nOTO/taZHUw9yzBpHLycRm5LF38diAXVOG19XBrT24tZ2vvQKami51reP9OL+RTvYH5nI9GX7sLfVExZxFTcHG755pCc+bg74uEFLHxce7BkIQGR8OltPx7H19BVSMnO4t1sAd3X2x86m9DwfUZDVAx4hhBCiMjKNJnaejedUTCqnYlM4FZvKmdjUAgHKtXQ6tVp3kKczAR6OBLg7EpmQzve7Ink/9BTHopJ576GunLuSxgu/HubwpSQAGns4Mqp7Y+7rHkBTT2fLvQ9eSGRfRAKRp48zddRgAj1di7xvK19XvprYg3Ff7iL0RCwAdgY9X0zoQUufos9p4unEWM8mjO3dpLLVVO9JwCOEEKLW2hQey4u/HuFSYkaR+31c7Wnq6URTT2faN3KjU+MGtG/khrN94Y+/7k08mPXrYUKOxTB0wWZikjMxa+DqYMOzt7dlbK8mGK5b4dvB1kDv5p50D3Tjr+Rj+LmVvK5jj6CGfDCmG09+F4ZZg7cf6Ezv5jJFyo0gAY8QQogyM5rMhEenEODuaEm8rSyzWSMhPRt3R1tsyjAkGyA+NYtX/zzGqgOXARXY9AxqSEsfF1r5utDSx4WmDZ3LtTr3fcGNaeHjwuNL9xKVlAnAPV39efHOdvi4Vt0C1cM6+PHLk33JzjFLsHMDScAjhBCiRDHJmWwKj2VT+BW2noojJSsHW4OOwW18uC+4MYPb+BTKKTGbNS4nZXA6NpXzcWl0CGhAz6CGha59Pi6NSV/v5nx8OjodeDjZ4elsh5O9DcYcMzlmM0aTygJ2sbdRDwcb9p5P4Gq6Eb0OJvdrxoyhrYtstSmvroHu/DG9P0u2n6d/Sy/6tvSq9DWL0q2JR7VcVxRPAh4hhBAFZOWYCDt/lc0nr7D55BVORKcU2O9sZyAt28Tfx2L4+1gMHk62NPF0JsdkJsekYTSZiUrKJMNoKnDeU7e05JkhrS1JvKdjUxn35U5LErGmqWHaCWnZZSpnu0ZuvDmqE10C3Sv/oq/h4+bAs7e3rdJrCuuTgEcIIQSgWmWWbDvHO3+fJPWa+WN0OujS2J3BbXwY3Nabjv4NOBWbysp9F/l1/yViU7K4mp5Y6Hq2Bh1Bns54udiz42w8H2w4zYnoFBY81JWLV9N5+MtdxKVm08bXlW//1QuDXkd8ajbxqVmkZ5uwtdFja9BhZ9Bj1iAtK4eUrBxSM3NwcbDhjo5+ZZqVWAiQgEcIIQSQlA3/WrqPrafjAfBysWdAay8Gtvbm5lbeheZ7aePnyqzh7Xj29rbsPZ9AcmYONgYdtno9NgYdPq72NGnoZMnJWRF2kRdWHubvYzHc+/E24lKzuJpupIO/G0v/1dtyfS8Xe6DoEUtCVIYEPEIIUc+tPRrDmwcNpOfEY2+j58U72/Fw76aWrqeSGPS6MiXe3h/cmBbezjy+NIxTsakAdAl059vJvWjgJOt3ieonAY8QQtQCmqbxz6k4Pt54motXM5g2uCUP9mhc5lFN18vINvHHocv8sDuS/ZGJgI4O/q68P7pbsXPCVFa3Jh788e/+zFp5GDuDnrcf6IyrgwQ74saQgEcIIWowTdNYfzyWjzac4uDFJMv2F349zDfbz/PSXe24uZV3sefvi7zKb/svodPpsLfRY2+jJz4tm98PXiYld2I+G72OQY1MvP9ob5wd7av19fi6ObB4Us9qvYcQRZGARwghaqgck5l/fbOXzSevAOBgq2dc76Y0auDAhxtOEx6TwvivdjOojTf/vqUVwU3zhzpn5ZhYuP4Un20+g1kr+vpNGjoxulcg93bxY/eWUFmuQNRpEvAIIUQN9X7oKTafvIKDrZ7J/Zrxr/7NcpN6VU7MB6Gn+XbHeTaFX2FT+BV6BTXk8YHNadTAkRk/HbAMJ7+zUyOaeTmTlWMiO8eMTqfj1nY+9GvhhV6vw2g0WvNlCnFDSMAjhBA10LbTcXy08TQA/7u/C3d38S+w393Jjtkj2jO+T1M+3XSaX/dfYvf5BHafT7Ac09DZjjfu7cjtHRvd0LILURNJ+6UQQtQwV1KyeGb5ATQNRvcMLBTsXKuZlzP/u78L/zx7C48PbI5r7mzDQ9r5su6ZARLsCJFLWniEEKIGMZs1Zvx0gCspWbT2dWHOiA5lOs+vgQOz7mjHtMEtiYhLp2OAGzpd6cPKhagvJOARQogaIsdkZuH6U/xzKg4HWz0fj+1ersUvAdwcbOnUuEE1lVCI2ksCHiGEsLL07Bx+2nOBL/45x6XEDADm3d2BVr4y47AQVUUCHiGEsAKzWePQpSTWHolm+Z5IrqarkVKeznZMHdySB3sEWrmEQtQtEvAIIcQNoGkaMclZHLqYyKaTV1h/LIbYlCzL/iYNnZgyoDkPBDfGwbZ83VhCiNJJwCOEELniUrP4/cBlHGwNNGnoRJOGTjRydyjXitxRSRmcu5LGldQsrqRkcSU1i5PRKRy+lExcalaBY53tDAxq48NdnRtxWwc/DGVYu0oIUTES8AghBHDkUhKPfbuXy0mZBbbb6HXc3tGPp25tResScmoyjSbeW3+SL7acLXZmY70OWvm40iPIg6HtfenTwhN7G2nNEeJGkIBHCFHvrTkcxYyfDpJhNNHU04nmXs5cuJrBhYR0snLM/HkoitWHoxjeqRFP3dKKNn4FA599kVf5788HOXMlDYDm3s74uNrj5aIezbyc6RjQgPaN3Mo96koIUTUk4BFC1CtJGUayjCayTWaMJo1V+y/xfugpAG5u5cVHY7rTwEmt4G02axyLSubjjadZcySa1YeiWH0oisCGjvg3cMTf3RGdDlbtv4RZA29Xe964txND2/ta8yUKIYogAY8Qos6LjE/nj0OX+ePgZcv6Utf7V/9mzLqjLTbX5Ovo9To6BjTg04eDOR6VzIcbTvHX4WguJGRwISGjwPmjugUwe0R73J3sqvW1CCEqRgIeIUSdFRZxlVf+PMbBC4kFthv0OmwNOmwNetwcbHl6SKtSh4G3a+TGJ+OCiU3JJDI+nUuJGUQlZXIlJYubW3kxqI1PNb4SIURlScAjhKiTUrNyePK7MGJTstDroG8LL+7u4s+wDn6WLquK8HF1wMfVgR5VWFYhRPWTgEcIUSd9GHqK2JQsmno68fMTffBxdbB2kYQQViSrpQsh6pzTsaks3nYOgDkj2kuwI4SQgEcIUbdomsa8P45iNGnc0taHW9rKiCkhhAQ8Qog65u9jMfxzKg47g57Zd7W3dnGEEDWEBDxCiForNSuHyFSISsokx2Qm02ji1T+PATBlQDOCvJytXEIhRE0hSctCiFrHbNZYEXaR+WuOczXdhncPb0GvA1cHW5IyjDRq4MC0wS2tXUwhRA0iAY8QolY5HpXMy6uOsDfiKgCOBg2jpifHrJGUYQRg9l3tcbKTP29CiHzyF0EIUeOZzRp7I67yS9hFVuy7iMms4WRn4KlbWuBz9Rh3Dr+NpGwz0UmZ6HVqdmQhhLiWBDxCiBrrfFwaP4ddYNX+y1xKzF/KYXgnP16+qz1eTjb89dcx9HqdZUJAIYQoigQ8QogaJzopk/dDT/LTXtWaA+Bqb8Mdnfy4PziQXs0aAmA0Gq1ZTCFELSIBjxCixkjKMLJo8xm+3naOTKMZgIGtvXmwRyC3tvPBwdZg5RIKIWorCXiEEDXCubg0xny+k+jkTAB6NPXg+Tva0iOooZVLJoSoCyTgEUJYXWR8OmO/UMFOkKcTL97ZniHtfNDpdNYumhCijpCARwhRLa6mZbPjbDzp2SYcbQ042RlwsDXQwtsZH7f85OILCemM+WInUUmZtPRx4YcpN+Htam/Fkgsh6iIJeIQQVcJk1jh2OZlN4bFsDI/lwIVEcvONC+nSuAFD2/vSvakHz644xKXEDJp7ObPs0d4S7AghqoUEPEKICjtzJZWtp+LYfiaOnWcTLBP/5Wnr54pfAwfSs01kGk2kZuZwNi6NgxeTOHgxyXJckKcTy6bcVKDlRwghqpIEPEKIIkUlZfBB6Ck6+DdgRGd/GjjZWvbti7zK++tPsfnklQLnuNrb0KeFJ4Pb+jCojTeNGjgWum5sSiahx2MJORbD1tNxNHZ35LtHe+PXQIIdIUT1kYBHCFGk11YfZ/WhKOACr/x5jGEd/LilrTe/7r/MltxAx6DX0ae5J31betK3hRcd/d2wMZS8JrGPqwNjejVhTK8mZOWY0Ot02JZyjhBCVJYEPEKIQiLi01hzOAqAlj4unI5N5Y+Dl/nj4GVABTqjugUw/ZaWNPWs+Irk9jYyr44Q4saQgEeIWkzTNI5eTibkWAzrj8dwISGdIC9nWni70NLHhe5NPOjTwrPc1/3yn3OYNTXp35LJPTlyKZkVYRfYdiae7k3cmT64FU08narhFQkhRPWQgEeIGyQ504i9jb7MrRqr9l8iLjWLUd0b09DZrsC+2ORMvtp2jt8PXCYqKbPAvkMXkzh0TULwqyM7Mv6mpmUuZ3xqFj/tvQDA4wObo9Pp6NS4AZ0ay4KcQojaq0YEPB9//DFvv/020dHRdOnShQ8//JBevXoVeeygQYPYvHlzoe3Dhw9n9erV1V1UISpkf+RVxn25CzsbPaN7NmFCn6Z4Oxf/32/5nkie++UwAG+vC2dU9wAm92uGo62Bz7ac4ae9F8nOUUsvONkZGNDKmyHtfWnfyI3IhHTOXEllf+RV1h+P5Y3Vx7m5pRdBXmXrevp2RwRZOWY6N25An+blbx0SQoiayOoBz/Lly5kxYwaLFi2id+/eLFy4kGHDhhEeHo6Pj0+h41euXEl2drbleXx8PF26dOGBBx64kcUWosziU7OY+v0+0rNNpGebWLT5DF/8c5ah7XzoUESu7tZTcbz46xEAAtwduZSYwQ+7L/DD7gvodVjmtunexJ3HB7ZgYGvvAmtMtfd3A8Bs1hj35S52nI1n5s8HWf54Hwz6kmcuTs/O4dsd5wF4bEBzmelYCFFnWH1oxIIFC5gyZQqTJ0+mffv2LFq0CCcnJxYvXlzk8Q0bNsTPz8/yCAkJwcnJSQIeUSOZzBpP/bifqKRMmns58/HY7vRp7onJrLH2aAwLDhuY88cxkjPV/DUnY1J48rswcswa93T1Z+tzg/n5iT7c0dHPEuzc3MqLHx+7iV+e7MuwDn7FLqip1+t4+4HOuNjbsDfiKl9tPVtqeX/ee5Gr6UaaNHTi9g5+VVoXQghhTVZt4cnOziYsLIxZs2ZZtun1eoYMGcKOHTvKdI2vvvqK0aNH4+xcdHN9VlYWWVlZlufJyckAGI1GjEZjkeeI0uXVndRhyd4NOcW20/E42ur5aHQXWvm6cFs7L05Ep/DZlrP8eTiGZbsvEnIslv8MacnHm86SkpVDj6buvH53O3Jycuga4MoHD3UmOrk1WTlmmjZUycI5OTml3t/XxZYX7mjDC6uO8va6cPo3b0grX5cij80xmfliyxkAHunbBM1swmg2VV1lVAN5H1YNqcfKkzqsvNLqsLJ1q9M0rZjJ36vf5cuXCQgIYPv27fTp08ey/dlnn2Xz5s3s2rWrxPN3795N79692bVrV7E5P3PnzmXevHmFti9btgwnJxllIqrP4QQdX4ar1peJrUx09yr8X+1Uko6fzuqJzczvOvJy0PhPRxMutoUOrxBNg89P6DmWqKexs8aMjiaKmvZmR4yOH88acLbRmNvdhJ2MGBdC1CDp6emMHTuWpKQk3Nzcyn2+1XN4KuOrr76iU6dOxQY7ALNmzWLGjBmW58nJyQQGBjJ48GA8PSUhs6KMRiMhISEMHToUW9sq+mSuQyLi03nx051ADhP7NOGl4W0LHWM0GiEkhHUzBrJ4x0UWbTmHi70Ny6b0olkZE4zLqueALO78cDsX04z8dtWPhQ+qrq48fx6K4uddRwCNxwa2YuSg5lV6/+oi78OqIfVYeVKHlVdaHeb10FSUVQMeLy8vDAYDMTExBbbHxMTg51dy/kBaWho//vgjr7zySonH2dvbY29feDFCW1tbeVNWAanHwjKyTUz/8SCpWTn0aOrBS3d1KHEmYRdHB/5vWDsm9WuOQa/D3cmu2GMrKqChLe+N7sqT34Wx+WQcY7/ay1cTe+Dv7sgvYRf574rDmDUY1T2A6be2LjW5uaaR92HVkHqsPKnDyiuuDitbr1ZNWrazsyM4OJjQ0FDLNrPZTGhoaIEurqL8/PPPZGVl8fDDD1d3MYUAwGgyE5OcydHLSWw5eYU1h6O4mpZd6LjZvx3hRHQKXi52fDS2e5mXTfB0sa+WYCfP4DY+LH+sD96u9hyPSmbkx9t49+9wZq44iFmD0T0Deef+LrUu2BFCiLKwepfWjBkzmDhxIj169KBXr14sXLiQtLQ0Jk+eDMCECRMICAhg/vz5Bc776quvGDlypHRLiRti6Y7zvPHXCTKMBZN4Gzrb8eo9HbmzcyNAzZ/zc9hF9Dr4YHS3GrcgZpdAd1ZN68cjX+8hPCaFDzecBmD8TU2Zd3cH9BLsCCHqKKsHPA899BBXrlxh9uzZREdH07VrV9auXYuvry8AkZGR6PUFvyGHh4ezdetW/v77b2sUWdQjZrPGW+tO8NlmNaRbr4OGzvZ4udiRlp3DhYQMpi3bx1+HGzG6VyAv/3YUgP+7rQ19W3pZs+jFCnB3ZMWTfZi+bD+bT17h0f7NePHOdjLnjhCiTrN6wAMwffp0pk+fXuS+TZs2FdrWpk0brDi4TNQTWTkmnl1xiN8OqAUzZ97WmqmDWlpaQbJzzHy04RQfbzrD6sNRrM5dbPPWtj48ObCF1cpdFq4OtiyZ3JMrqVn4uNasVighhKgONSLgEcLaTsem8vW2c9jodTjb2+Bsb8M/p66w82wCNnodb97XmfuDGxc4x85Gz4zb2nBbBz9m/nyQE9EpNPZw5N0Hu9SKriGdTifBjhCi3pCAR9QLmqZhMmvYFJFAbDSZmfb9PsJjUgrtc7Yz8OnDwQxo7V3stTsGNOC36f0IORZDz6CG1Zp4LIQQomIk4BF1SqbRxMmYFI5HJXMqJpWIhHQi49OJTEhHQ+Pz8T0KBS9f/nOO8JgUPJxsGde7KalZOaRl5aDX6ZjYN8iyNlVJ7G0M3NXZv7pelhBCiEqSgEfUekaTmUWbzvDbwcucvZJqWVyzKNOW7WPVtH608FbLK1xISOf90JMAvHRne+67rttKCCFE3SABj6jVIuPTeXr5fvZHJlq2NXS2o10jV9r4uhHk5USThk409nDiuV8OERZxlSnf7OXXaf1wc7DhpVVHyDSa6dPck1HdA6z3QoQQQlQrCXhErbVq/yVeWnWE1KwcXB1sePnO9gxs442Pq32RQ6wXPRzM3R9t5WxcGv/+YT/3dQ9g88kr2Bn0vHZvRxmWLYQQdZgEPKLWycg28dKqI/yy7yIAPZp6sHB0Vxp7lLwYrLerPV9M6MH9i7az5eQVtp2OA2Dq4BaWLi4hhBB1k1WXlhCiODHJmVxOzCi0PTI+nVGfbueXfWo242eGtOLHx24qNdjJ0zGgAe880AUAk1mjuZczTw6q2XPmCCGEqDxp4RE1zs6z8Uz+eg8ZRhM3t/JiTK8mDGnny7YzcTz9w36SM3PwdFbrVPVpUf6lRe7q7M/Fqxks2Xaetx/ojL2NoRpehRBCiJpEAh5Ro+y6JtgB+OdUHP+cisPDyZbEDCOaBl0D3fn04e40auBY4fs8MbAFT9Tw2ZCFEEJUHenSEjXG7nMJTF6igp0Brb1ZP2Mg/76lJT6u9lxNV8HOuN5NWP74TZUKdoQQQtQ/0sIjaoTd5xKY9PVu0rNVN9bn44NxsDXwf7e14elbW7H55BX0eh2D2/hYu6hCCCFqIQl4hNUdj0pm8jXBzhcTeuBgm59XY2PQc2s7XyuWUAghRG0nXVrCquJTs3j0m72kZZu4qXnDQsGOEEIIURUk4BE3xKGLiUQnZRbYlp1j5snv9nEpMYOmnk4sejhYgh0hhBDVQrq0RLVbtPkMb645gZ1Bz5hegUwb3BJvV3vm/H6E3ecTcLG34csJPWSVcSGEENVGAh5Rrb785yxvrjkBQLbJzDc7IvhxzwX6t/Qi9EQsOh18OKYbrXxdrVxSIYQQdZkEPKJUEfFpfLLxDClZRnTo0OnAoAPnVB0Ds3Jwt7Ut8rwl287x2urjgJoRuVdQQ94NOUlYxFVCT8QCMOuOtgxuKyOvhBBCVC8JeESJEtKyGf/VbiIT0ovYa+C3/21mRBd/7g9uTICHI8YcDaPZzKbwK7z65zEApg9uydO3tkKn09GnhSebTl5h8dZzdAxowJSbm9/YFySEEKJekoBHFEslFYcRmZBOk4ZOPHpzMzQNNE0jLiWTH3eeIS7TxI97LvDjngtFXuPxAc35v9taW1Yi1+nUXDoyn44QQogbSQIeUSRN05jz+1F2nctNKp7Yg9bX5NkYjUZaZp7Eu8NNrNwfzbqj0WTlmLA16LHR67C3NTC2VxOeGdLKEuwIIYQQ1iIBjyjStzsi+GF3JDodvD+6a4FgJ49OB72CGtKvlS/v0sUKpRRCCCHKRubhEYWsPRLFK7n5N8/f3lZmORZCCFHrSQuPsMgxmVkQcpJPNp0BYFT3AB4bIEnFQgghaj8JeAQAcalZPPXDfrafiQdgcr8gXhjeTvJvhBBC1AkS8AgOXkjk8aVhRCdn4mRn4M37OnN3F39rF0sIIYSoMhLw1HP/nLrC40vDSM820dzbmc8eDpZZj4UQQtQ5EvDUY38djuLpH/djNGn0b+nFpw93x9Wh6FmThRBCiNpMAp566ofdkbz462HMGgzv5Md7D3XF3kZWKhdCCFE3ScBTDxy6mMjqw1HEp2aTkJZNfGoWBy8mATC6ZyCv39sJg16Sk4UQQtRdEvDUYWazxuf/nOXtdeGYzFqh/Y8PbM7zt7eVkVhCCCHqPAl46oDjUckcuZREtybutPB2QafTkZCWzYyfDrAp/AoAQ9r50r2pOw2d7GjobEdTT2fa+ElyshBCiPpBAp5aLivHxLgvd5GQlg2Ap7MdPYMacvBiIlFJmdjb6Jl7dwdG9wyUlhwhhBD1lgQ8tdz6Y7EkpGXjYKtH0yA+LZu1R6MBaO7lzMfjutOukZuVSymEEEJYV5UGPBcuXGDOnDksXry4Ki8rSvBz2AUA/tW/GU/d2orDF5PYdS4Bg17Hwzc1xcVeYlohhBCiSj8NExIS+OabbyTguUGikzLZclLl6NzXvTH2NgZ6BDWkR1BDK5dMCCGEqFnKFfD8/vvvJe4/e/ZspQojyufX/Zcwa9CjqQfNvV2sXRwhhBCixipXwDNy5Eh0Oh2aVniIcx5JjL0xNE2zdGc90KOxlUsjhBBC1Gz68hzcqFEjVq5cidlsLvKxb9++6iqnuM6+yETOXknD0dbAnZ1loU8hhBCiJOUKeIKDgwkLCyt2f2mtP6LqrAi7CMAdnfwkMVkIIYQoRbk+Kf/73/+SlpZW7P6WLVuycePGShdKlCwj28SfBy8DcH+wdGcJIYQQpSlXwHPzzTeXuN/Z2ZmBAwdWqkCisO2n4zgTl0b7Rm60b+TGuqPRpGTl0NjDkZuaeVq7eEIIIUSNJ30hNVxSupFJX+8h22QGQK8DB1u1qvn9wY3Ry6KfQgghRKnKlcOT5/z580yaNIlGjRrh6OhIp06dWLp0aVWXTQD7L1wl22TGyc6At6s9Zg3Ss03YGnTc1126s4QQQoiyKHcLz44dO7j33nt57LHH2LZtG40aNSIsLIypU6eSnZ3Nv/71r+ooZ721PzIRgNs7+LHgoa7EJmdy9HIy3q72BDZ0sm7hhBBCiFqiXC08CQkJjBo1isWLF/PKK6/QvHlzHB0d6d+/Pz/++COvvPIKAKNHjyY2NrZaClzf7L+QCEC3Ju4A+Lg5MLitDx0DGlivUEIIIUQtU66A58MPP2Tw4MEMHz6cjh070rx5c8vjrrvu4uLFi1y5cgVfX19L8FOajz/+mKCgIBwcHOjduze7d+8u8fjExESmTZtGo0aNsLe3p3Xr1vz111/leRm1htmscSDyKgDdmnhYuTRCCCFE7VWugOfPP/9k7NixAPzf//0fDg4OvPbaa7z33ns0a9aM559/Hk9PT6ZPn87y5ctLvd7y5cuZMWMGc+bMYd++fXTp0oVhw4YV2zqUnZ3N0KFDOX/+PCtWrCA8PJwvvviCgICA8ryMWuNsXBrJmTk42Opp4+dq7eIIIYQQtVa5cngiIiJo3rw5oFp7Pv30U8sw9AEDBtCkSRNefvllWrVqRVJSEtHR0fj5+RV7vQULFjBlyhQmT54MwKJFi1i9ejWLFy/m+eefL3T84sWLSUhIYPv27dja2gIQFBRUnpdQq+zLbd3p3NgdW0OF8suFEEIIQTlbeBwdHUlISAAgNjYWvT7/dJ1OR3p6OmlpaZhMJsxmMzY2xcdT2dnZhIWFMWTIkPzC6PUMGTKEHTt2FHnO77//Tp8+fZg2bRq+vr507NiRN954A5PJVJ6XUWvkJSzn5e8IIYQQomLK1cLTpUsXwsLC6N+/v2Wk1ty5c3FycmLhwoX07dsXT09P9uzZg5eXF15eXsVeKy4uDpPJhK+vb4Htvr6+nDhxoshzzp49y4YNGxg3bhx//fUXp0+fZurUqRiNRubMmVPkOVlZWWRlZVmeJycnA2A0GjEajeV5+Tfc/ggVXHb2d61xZc0rT00rV20idVh5UodVQ+qx8qQOK6+0Oqxs3eq0cix+tXz5cl566SVOnDiByWTirbfe4s8//yQ7O5v+/fszd+5cPD09mTBhAg0bNmThwoXFXuvy5csEBASwfft2+vTpY9n+7LPPsnnzZnbt2lXonNatW5OZmcm5c+cwGNTkewsWLODtt98mKiqqyPvMnTuXefPmFdq+bNkynJxq7rDuTBM8v9uAho5XgnNoYGftEgkhhBDWk56eztixY0lKSsLNza3c55cr4NE0jcGDB9O6dWs+++wzdLrCs/x+9dVXzJ49m4MHD5bYwpOdnY2TkxMrVqxg5MiRlu0TJ04kMTGR3377rdA5AwcOxNbWlvXr11u2rVmzhuHDh5OVlYWdXeGooKgWnsDAQKKiovD0rLnLMuw8m8D4r/fi38CBzTMHWLs4hRiNRkJCQhg6dKgln0qUj9Rh5UkdVg2px8qTOqy80uowOTkZLy+vCgc85erS0ul0/PLLL9x9990MGDCAF154gT59+uDo6Mjhw4f56KOP2LBhA6tXry4x2AGws7MjODiY0NBQS8BjNpsJDQ1l+vTpRZ7Tr18/li1bhtlstuQPnTx5kkaNGhUZ7ADY29tjb29faLutrW2NflMeupwCQPemHjW6nDW9HmsDqcPKkzqsGlKPlSd1WHnF1WFl67XcQ388PT3ZsmULDz/8MK+//jpNmzbF09OTRx99lKCgIA4dOkTXrl3LdK0ZM2bwxRdf8M0333D8+HGefPJJ0tLSLKO2JkyYwKxZsyzHP/nkkyQkJPD0009z8uRJVq9ezRtvvMG0adPK+zJqvP0y/44QQghRZSq0eKjBYODxxx/n8ccfr9TNH3roIa5cucLs2bOJjo6ma9eurF271pLIHBkZWWAkWGBgIOvWreM///kPnTt3JiAggKeffprnnnuuUuWoaTRNkxFaQgghRBWy+mrp06dPL7YLa9OmTYW29enTh507d1ZzqazrQkIG8WnZ2Bn0dPAvfz+lEEIIIQqqUMDTrVu3IhOWdTodDg4OtGzZkkmTJjF48OBKF7A+2n9BdWe193fD3sZg5dIIIYQQtV+Fpu+9/fbbOXv2LM7OzgwePJjBgwfj4uLCmTNn6NmzJ1FRUQwZMqTIkVaioIxsEz/tvcBvBy6Rka0mUMzrzuou+TtCCCFElahQC09cXBz/93//x8svv1xg+2uvvUZERAR///03c+bM4dVXX+Wee+6pkoLWNTkmM7/su8iCkJPEJKth8y72Nozo0ohd59SEg5K/I4QQQlSNCrXw/PTTT4wZM6bQ9tGjR/PTTz8BMGbMGMLDwytXujpqU3gsd7z/D8/9cpiY5CwC3B1p0tCJ1Kwcfth9gbNX0gAJeIQQQoiqUqEWHgcHB7Zv307Lli0LbN++fTsODg6AmlMn73eRb8eZeCZ9vQcAdydbpg9uyfg+TbHV69l1LoGf917gryNRdPBvQIC7o5VLK4QQQtQNFQp4/v3vf/PEE08QFhZGz549AdizZw9ffvklL7zwAgDr1q0r83w89YWmaby9Tq0TdkdHP968rzMNHPMnUurTwpM+LTz53/2dMeh1RSaGCyGEEKL8KhTwvPTSSzRr1oyPPvqIpUuXAtCmTRu++OILxo4dC8ATTzzBk08+WXUlrQM2hV9hX2Qi9jZ65t3doUCwcy0bQ4V6GoUQQghRjArPwzNu3DjGjRtX7H5HR+mOuZamabzzt8ppmtg3CB836e4TQgghbpQKNSXs2bOnyNXMd+3axd69eytdqLpo3dFojl5OxtnOwOMDmlu7OEIIIUS9UqGAZ9q0aVy4cKHQ9kuXLtXJda0qy2TWWBByEoBH+jfD06XwYqZCCCGEqD4V6tI6duwY3bt3L7S9W7duHDt2rNKFqs2OXU5m3Jc7CWzoxOieTbi7qz+hx2M4GZOKm4MNj94srTtCCCHEjVahgMfe3p6YmBiaNy/44R0VFYWNjdWX57Kqr7ae42q6kavpSRy6eJjXVh/D3kY1pD0+sEWxicpCCCGEqD4V6tK67bbbmDVrFklJSZZtiYmJvPDCCwwdOrTKClfbpGfnsOZIFACT+gbR3NuZ9GwTV9ONNHS2Y1LfIOsWUAghhKinKtQc88477zBgwACaNm1Kt27dADhw4AC+vr6WYer10bqj0aRnm2jq6cScEe0B2HP+Kn8fjebWdr4429fv1i8hhBDCWir0CRwQEMChQ4f4/vvvOXjwII6OjkyePJkxY8Zga1t/u2x+CbsEwKhujS2TBvZq1pBezRpas1hCCCFEvVfhJgdnZ2cee+yxqixLrRaVlMG2M3EAjOoeYOXSCCGEEOJaZQ54fv/99zJf9O67765QYWqzX/dfQtNUi05gQydrF0cIIYQQ1yhzwDNy5MgCz3U6HZqmFXiex2QyVb5ktYimaazcp7qz7u/e2MqlEUIIIcT1yjxKy2w2Wx5///03Xbt2Zc2aNSQmJpKYmMhff/1F9+7dWbt2bXWWt0Y6dDGJ07GpONjquaOTn7WLI4QQQojrVCiH55lnnmHRokX079/fsm3YsGE4OTnx2GOPcfz48SorYG2wct9FAIZ18MPVof4mbQshhBA1VYXm4Tlz5gzu7u6Ftjdo0IDz589Xski1S3aOmd8PXgZglHRnCSGEEDVShQKenj17MmPGDGJiYizbYmJi+O9//0uvXr2qrHC1wabwWK6mG/Fxtad/Sy9rF0cIIYQQRahQwLN48WKioqJo0qQJLVu2pGXLlgQGBnLp0iW+/PLLqi5jjbbjbDwAt3f0w6DXlXK0EEIIIayhQjk8LVu25NChQ6xfv96Sr9OuXTuGDBlSYLRWfXDoolpeo1sTd+sWRAghhBDFqvDEgxs2bGDjxo3ExsZiNps5cOAAP/zwA6BagOoDo8nM0csq4Onc2N26hRFCCCFEsSoU8MybN49XXnmFHj160KhRo3rXqpPnZEwKmUYzrvY2NPN0tnZxhBBCCFGMCgU8ixYtYsmSJYwfP76qy1Or5HVndQ5sgF7yd4QQQogaq0JJy9nZ2fTt27eqy1LrHLyQCEh3lhBCCFHTVSjgefTRR1m2bFlVl6XWOZjbwtNFAh4hhBCiRqtQl1ZmZiaff/4569evp3PnztjaFpxdeMGCBVVSuJosI9vEyZgUALoENrByaYQQQghRkgoFPIcOHaJr164AHDlypMC++pLAfPRyEiazho+rPX5uDtYujhBCCCFKUKGAZ+PGjVVdjlonrzurc2P3ehPkCSGEELVVhXJ4RH7CcpfG0p0lhBBC1HQS8FTQoYuJAHQJdLdqOYQQQghROgl4KiAxPZvz8ekAdJYWHiGEEKLGk4CnAvImHAzydMLdyc7KpRFCCCFEaSTgqYC87iyZcFAIIYSoHSTgqYADF/JGaEl3lhBCCFEbSMBTTpqmcTC3haerJCwLIYQQtYIEPOUUnZzJlZQsDHodHfylhUcIIYSoDSTgKaeDud1ZrX1dcbQzWLk0QgghhCgLCXjK6a/DUQB0lfWzhBBCiFpDAp5yOHIpid8PXgZgXO+mVi6NEEIIIcpKAp4y0jSNN/46DsDIrv50DJAWHiGEEKK2kICnjDafvML2M/HYGfT8321trF0cIYQQQpSDBDxlYDJrvLnmBAAT+jQlsKGTlUskhBBCiPKQgKcMft1/iRPRKbg52DD9lpbWLo4QQgghyqlGBDwff/wxQUFBODg40Lt3b3bv3l3ssUuWLEGn0xV4ODg4VFvZMo0mFvwdDsDUwS1l7SwhhBCiFrJ6wLN8+XJmzJjBnDlz2LdvH126dGHYsGHExsYWe46bmxtRUVGWR0RERLWVb9muSC4nZeLfwIFJfYOq7T5CCCGEqD5WD3gWLFjAlClTmDx5Mu3bt2fRokU4OTmxePHiYs/R6XT4+flZHr6+vtVWvr+PRQMwZUBzHGxlokEhhBCiNrJqwJOdnU1YWBhDhgyxbNPr9QwZMoQdO3YUe15qaipNmzYlMDCQe+65h6NHj1ZL+TKyTeyLSARgYGvvarmHEEIIIaqfjTVvHhcXh8lkKtRC4+vry4kTJ4o8p02bNixevJjOnTuTlJTEO++8Q9++fTl69CiNGzcudHxWVhZZWVmW58nJyQAYjUaMRmOJ5dt5Jp5skxlfN3saN7Ar9fj6JK8upE4qTuqw8qQOq4bUY+VJHVZeaXVY2brVaZqmVeoKlXD58mUCAgLYvn07ffr0sWx/9tln2bx5M7t27Sr1GkajkXbt2jFmzBheffXVQvvnzp3LvHnzCm1ftmwZTk4lDy//PUJP6GU9Pb3NPNzSXIZXJIQQQojqkJ6eztixY0lKSsLNza3c51u1hcfLywuDwUBMTEyB7TExMfj5+ZXpGra2tnTr1o3Tp08XuX/WrFnMmDHD8jw5OZnAwEAGDx6Mp6dnidf+ctFOIJkHbu7M8G7+ZSpPfWE0GgkJCWHo0KHY2tpauzi1ktRh5UkdVg2px8qTOqy80uowr4emoqwa8NjZ2REcHExoaCgjR44EwGw2ExoayvTp08t0DZPJxOHDhxk+fHiR++3t7bG3ty+03dbWtsQ3ZVK6kaOXVeUOaOMrb+BilFaPonRSh5UndVg1pB4rT+qw8oqrw8rWq1UDHoAZM2YwceJEevToQa9evVi4cCFpaWlMnjwZgAkTJhAQEMD8+fMBeOWVV7jpppto2bIliYmJvP3220RERPDoo49Wabl2novHrEFzb2f8GlTfPD9CCCGEqH5WD3geeughrly5wuzZs4mOjqZr166sXbvWksgcGRmJXp8/mOzq1atMmTKF6OhoPDw8CA4OZvv27bRv375Ky7X9dBwA/Vp4Vel1hRBCCHHjWT3gAZg+fXqxXVibNm0q8Py9997jvffeq/YybTsTD0C/liXn+QghhBCi5rP6xIM1UUxyJqdjU9Hp4KbmEvAIIYQQtZ0EPEXYfkZ1Z3Xwd5O1s4QQQog6QAKeImw/ndudJfk7QgghRJ0gAc91NE1je27+Tt+WEvAIIYQQdYEEPNeJiE/nUmIGtgYdPYM8rF2cmk8zQ8xROPADJEdZuzRCCCFEkWrEKK2aZFtu/k63Jh442Un1FMmYgX7X5/Q+8ws2C/4NmUlqu6s/TPgNvFtbt3xCCCHEdaSF5zph568C0EdGZxVv/3cY1s/GL/kguswksHUGZx9IuQxf3w5RB61dQiGEEKIACXiuczYuDYC2fq5WLkkNFncKgCi3buRMDoHnI2HqTmjUBdLjYckIiNxp5UIKIYQQ+STguU5EvAp4mno6W7kkNVjSRQBi3Tqj+XcDgw04e8LEP6BJH8hKgqX3wvmtVi6oEEIIoUjAc42kdCNX040ABHk5Wbk0NVhSJAAZdtd1+zk0gIdXQotbwJgO6160QuGEEEKIwiTgucb53NYdH1d7SVguSW4LT/r1AQ+AnRPc84n6PfpQfkKzEEIIYUUS8FwjL+AJku6s4mWlQoZK7C7UwpPHrRF4NFND1i/svoGFE0IIIYomAc81IuLTAWjqKd1ZxUq+BIBm70aOoYR6atpP/YzYdgMKJYQQQpRMAp5rnM8doRXkJS08xUq8oH42aFzycU37qp8R26u3PEIIIUQZSMBzDenSKoMkFfBobgElH5cX8FzaB9np1VwowGwCk7H67yOEEKJWkoDnGtKlVQa5CcuaWyktPB5BauZlsxEu7a3+cv04Dt5uCcmXq/9eQgghah0JeHIlZxqJT8sGJOApUW7AQ4PAko/T6W5ct9bFMDi5BjIT4fgf1XsvIYQQtZIEPLki4lTrjpeLHa4OtlYuTQ2W16XVoJQuLbgm4KnmxOVdi/J/P/V39d5LCCFErSQBTy7J3ymj3ICH0rq0IH+k1oU9kJNdPeVJiYajv+Y/P7/1xuQMCSGEqFUk4MklS0qUgdlkyZHRShulBeDdBpw8IScDog5UT5n2LlZ5QoG9VTdbTqYsaSGEEKIQCXhync9NWA6q7vwdswm2vQ9nN1fvfapDagyYc0BnABe/0o/X6dTaWlA93Vo5WSrgAej9BLQcon4vqlsr+TIcXQWmnKovhxBCiBpPAp5ceXPwNK3uOXgOfA8hs2H5w5CeUL33qmp5CctuAaA3lO0cywSE1ZC4fOQXSLuiytNuBLS6TW0/HQKaln+cpqlRXD9PhD+fKbhPCCFEvSABT668Fp5m1dmlZcqBre+p37OSYfuH1Xev6pCoFg0tddLBa+UlLkfuVK1bFaFp8N198H5XOLAMzGa1beenan/PR8FgC80GgMEOrp6H+NP5558Jhcv71O/7l8Km+RUrhxBCiFpLAh4gNSuHuNQsAJpUZ5fWsVWQcBb0uaPAdn0GqVcKH1dTWyAsQ9LLEfD4dQI7VxXgxRyp2H3jz8Dp9XD1HKx6Er68RY3Mij4ENg4QPEkdZ++SH2CdCsk/f8u7uWXprH5ufgv2fl2xsgghhKiVJOAhP2G5obMdDRyraUi62Qz/LFC/D/gv+HcDYxpsW1jwuKsR8HFv1aJR0wKfvIDHvZQ5eK6lN0CTm9TvFe3WishNQnb1V8HT5f2w9nm1rfOD4NQw/9iWQ9XPvDyeiO0QuV21/IxdDgOfU9tXz4ATf1WsPEIIIWodCXiA83E3YIblU+sg9qj6wO79GAx+SW3f8yUkR6nfU6Lh23sgLly1aMQeq77yVERFWnggv9WloqOn8gKlbg/DU/ug+wRAB3oblax8rbw8nohtamX3f3Jbd7qOBTd/GDRLna+ZYcVkiDlasTIJIYSoVSTgoRrm4Ik/A8aM/OeaBlveUb/3/Bc4ekDLWyHwJjWM+p93VQLz0ntVt02e439WTXmqSt4cPKXNsny9oP7q5/mt5R8lpWlwPneEV9O+4OIDd38I0/fClI3g26Hg8V6twL0JmLJVjtTp9WpUWb9n1H6dDu58D5oPUnW/b2n5yiOEEKJWkoCH/C6tKgl4zm6CD7vD+11g9xdqwr1zW9R6UjYO0GeaOk6ng1teVL+HLVEtO7HH1HDvAf9V20/U1ICnnC08/t3BoYFa+iEvebisEiMh+aJqzQnslb/dqyU06lz4eJ0uv5Vn81vqZ6f7oWGz/GMMNtBzivr95Jqa13UohBCiyknAwzVz8HhVQZfWxdyFMlNj4K+Z8FFwfr5J9wmqhSJPswHqYTaqBFzHhjDhN9VNo9OrbVcjKl+mqpCZDJlJ6vfyBjwGG2hxi/r92mTissibv8e/G9iVMSDNy+MhN5DpP6PwMc0H5Y/oijtVvjIJIYSodSTgoZRZljUNEi+UvRUgr0uqaX/VWpMYqVpu9DbQ96nCx9/yMqBTuT0P/wI+bcHZC5rk5r2cWF3+F1Qdki+pnw7uYO9a/vPzJgU8vb585+UFPHnz+ZRFs5vBYK9+bzdC1en17F0g6Gb1+8m15SuTEEKIWqfeBzzp2TnEJKsh6UXOsrz9A1jYEQ7+ULYLJpxXP4MnwlP7Yegr4NEMBjxb9OimwF7wyFp4fDMEdM/f3vZO9bOmBDyJFczfyZMX8FzeD2lxZT/vfAUCHjtn6PyACiIHPl/8ca1vVz9Priv7tYUQQtRK9T7gicjtzmrgaIu7k13BnSYj7PhY/R5exiHMeS08Hs3Azgn6PQ1PH4BBzxV/TpObwLNFwW15AU/k9vIFCNWlovk7eVz9wLcToMGZDQX3GTPUMPzfphVsSUu+rOpTp4cmvct3v7s/gmfPgF/H4o9pnZvrE7kDMq6W7/pCCCFqFQl48hKWi1pSIvwvlYsDcPlA6RczZloW1yyQJFsRHk3VRHmaGcLXVO5aVaGiQ9Kv1fJW9fP6bq19S9W2/d8V7F7KG47u10klPZeHTgc29iUf4xEE3u1AM8Hp0PJdX4jaKnwtLOwMETusXRIhbqh6H/CUuGjotbPxJl0oelbkayVGAhrYuahVwiur7V3qZ03o1qrIpIPXa5WbTHw6VE3ECGoU27b3849ZPzd/CYqK5O+UV+th6uf13VqaBrHH88spxI1yZiMc+736rr/jI0iMKDzpqRB1nAQ8ccUkLCechbMbAR04ealtUQdKvti13Vk6XeUL1y434DmzQU2iZ02V7dICaNxL5dWkx+XX5eGf1LBzZx+VEH3lhFovC/JbeKo14MnN4zkdUnCOoNX/B5/clD+0XYgbIeEcfH8//DQeoiu4FEtJslLVunagvnhkJFb9PYSooep9wBMekwJAC+/rAp6wb9TPFrfkd8Vc3l/yxRJyA56GQVVTOJ/2KngyZZV/dFNVs3RpVaKFx8YOmg9Uv58OVS05ectt9J0OA2aq3ze+oZKkr5xQz5v0qfg9S9O4p5oIMuMqXNyjtu1dDHu/Ur9ve1/NgC3EjbDpTTDnBt77v6v665/fqqbBAPWzrLmJQtQB9Trgyc4xc/RyMgCdG7vn78jJhgPfq997TFZzwEDpAc+1LTxVQafLb+Wx5iSEppz83KTKtPBAweHpx36DhDOqZafHI2oywAaBkHIZfnlUHefTHpyroHuwOAab/Hl7Tq5V337/elY9t28AORn5s2QLUZ1ij8Oh5fnPDy2HnKyqvceZ3Fw1G0f18+ivVXt9IWqweh3wHI9KJjvHjLuTbcEcnhN/QtoVNY9O69vLHvBYWniqKOCB/Dyek+sgNbbqrnutS2Gw7sXir58arRJ79baqTiojr7Xs4m7YNF/93vsJNbePrQMMzp19+kJus3veOlzVKS+P5+ivsHy8+ubb/h4YnfsNO2yJmqBQWF/cadjwmgqIvxyKzcL2DDk6E1KirF2yytv4OqBBm+Hg2ggyEqp+wEJecv7A3Nncz2yQEYqi3qjXAc+BC4kAdGnsju7anJuw3GTl7uPBYKtGCen06o9qcgl/WKu6hQdU3otPe8hKhpVT8hN6q8rl/fDN3SqRccUjRV8/bw4eN3/QV/It494EvNqo0WdxJ8HWGXo/nr+/84Pgc836WNWZv5On5a1qva3ECEiLVfe/5xM1C3aLW1QAtHF+yddIjYW//quWFhHVIy0evrwVtrwNh3+Gi7vRpcXinB2Lfv+31i5d5VzaB8f/AHRw62zoMkZtr8puravnVYuqzgA9H1Xvc3NOzRgUIcQNIAEP0DXQPX9j/Bm19hW63FW5URPZeefO1ltcK4/ZnL8MhEdQ1RVSr4f7vwZbJ/Vhmrf6d1WIO6Xmv8nOTYg+/49acPN6VZG/c6280VoAPR8Bp4b5z/UGGDI3//mNaOFx9MjPE3L0gNHfq5mYIXcmbFT3Qkwxq9dnJMLSUbD7c/hhjCxVUV02vaHWY/NsqSb0fPBbTIPVv4/+0I+1e0TdhtfUz84Pgk876Pawen4mFJIulXzu1Qg4uqr0L0N5818F9lLTPHS4Vz2Xbi1RT0jAA3Rt4p6/MWyJ+tlqqGqNyOOfOwtycQFPSpRKLtbbVF1gkMenLdyZm9y7aX5uQFZJSZfU6uzp8dCoKwzLbcHY8FrBOYdMOWoEE1Q+fydPXh6PwR76TC+8v9VQ9YE2/B01YeGN0P8/quvyoe8KdkkGdId2dwNa/ofStYwZKsiJOZz7PF21lFV17kV9F3NMJZMD3LVQTejZ/h7MPadg1DuiS7qgAvbqlhYHf/4HzlXhvSK2q8BGbwODcmcG92yhlpfRzCXP8n41Ar4YDD9PzO8iLk5ed1aL3G7lDiPVz7ObpFtL1Av1NuBJSjdyLndIete8hGWTEQ7+qH7vPrHgCf5d1c/iAp687qwGgSoRtqp1HQNdH1Z/AH95tHL5POkJKthJuqC+LT/8C9z0pMoXMhtV11l2urrH0pH5iZR5uS6V1XyQajm578uiAxqdTn2g9ZpSNfcri1ZD4LFNENS/8L5bXlJdmuGr4eByFeSACgZ/nqxmw7Z3g7E/qwVgow9B6Cs3rux1nabBulnqvd9uhForLY+tExc9blK/5w00qC6mHPh5kgq8fp6o/h9VlqZB6Kvq927joWHz/H15rTz7vyt6Lb+sVBVsp8er51veKX4CTZMx/4tS3kK+Xq3U7OfmHHQyWkvUA/U24DkSpUZnBXk64eGcu6TEqRCVw+HsXfjD/doWnqL++FRHwvL1hr+tZgZOjVFBSVkXNL3en89AXDi4+sP4X9VipTodjPhAJSXHnVRB1aKb1bdmW2e47yvoOKpqXodOp4agt7+7aq5X3bzbQJex6vdfH4P/NYcfxsLyh+HkGrBxgDE/qqUqRn6ijtvxUeWnEog5ClEHK3eNuuDkWtUKYbCDoa8W2n3Bc4D65djvkJlUfeXY+Hp+K1J6PIS8XPlrnt2oAmaDPQz4b8F97e9Rk5hePZc/J1UesxlWPgaxR9UcVh3vAzS1rag8w0thKg/Q0SP/yxtYWnn0x3+r/GsRooarvwHPRRXwFMjfyfuG2Pkhlax8Ld8Oqsk5PS4/p+Va1ZGwfD07J3hgiRpSenYTnNtc/mtcPZ+bHAmM+aFgt52zJ4zMWztstRqd5dUGHtsIne6vZOFrudvnq9FkbgGq2yp8tQp2dAaVYxWUm1zd5g41vB7g1ydLn527KMZM+Psl+LQffD4ov5u1PsrJViMIAfpMK/ILxVWn5mherdUUAkdWVk85wtfA1rw5o55SP/d/p+a1qShNy0+G7/EINAgouN/eJT/P5vrk5Y2vq/egwQ5GL1NJ9r6d1N+nXx4tOIkm5Lf8NB+s8uTy5F5fd24ztjkpFX8tQtQC9TbgOXz5uoAnNTZ/Hae8puRr2Tqo0VJQdLfWjWjhAZXP022c+n33F+U/f8+Xqmug+eCC3/TytByiupMAOt4PUzaoFo76zsEN7ngL/nMUHt8Cg15QXXP3fwVthxc89rZX1XslLRbW/LfIyxUr6qAKcrZ/CGjq3+qPp2Hre1X0QmqZ3Z+rkUXOPnDz/xV9jE6HuXPuqKbq6Na6eh5+zR1J2PsJ9e8bPFk9//M/Fc/XOrNBTc9g4wD9nyn6mG7j1c/DP8Gi/mqQwU8T4Z/cuaFGfACBPdXfpwe/US1CEVth85vX3Ss34MmbFiKPZwvw64xOMxGYsK1ir0OIWqLeBjxHL6um765NPNSGQ8vVEM2AYDVKoiiW+Xj2Fd5naeEJqtqCFiWvBSH8r/wh42WRnQb7cofv9n6i+OOGvgL/Pas+zPNGKwlFp4NGXWDQczDht/xv4NeydYR7clvKTqwu+7Ig296HL26BK8dVt+roH1QyNag1xkJmV7wbszY69BOEzlO/3zpbzdVUDHOnB1Vr28U9cCW86spgzISfJqiusoAe+V1qQ+aoICzuZMG14MpK0/KTjHs8UnxyfmAv1Z1uzoHow7kTdq5S+/o+pXL78ni2gBG5ZdnyDvwyRX05S09Qw95BfdG5Xu4Q+A6XlqM79XfJ5Y4+ooK8/zXPb3kTopaotwFPYkYOdgY97Rq5qj8+eU3GRbXu5ClpAsK8iemqs0srj09bCLpZffvPmzOoLA79pP5wezSDVreVfGx1zm5cH/h3U8GvKbtsc/McXqECGnOOSsydulO1HA2ZqwJQUB+sq2fU3qAnJ0slzpYWkJjNsOF1ladmylaj5LqOK/kcF9/893RVtvJs/0C1ujk2zO1Ozs33c/RQ3Zyggou408VfIyUasq7rLjodqoIzG0fo90zx5+p08MhaeGwzjFuhAulb56gRjNdO35Cn0/25Ix811Sr0+SAVRKOp/L/ru80Aej+Ouf296DFh+GVy4VGgOVnqb8dXt8GifippOz1e5alV5yKnQlSxGhHwfPzxxwQFBeHg4EDv3r3ZvXt3mc778ccf0el0jBw5skL3be/vhr2NQX37uXJCNS13vK/4E64NeK790MlIzB/WeSNaeCB/BFPYN2VrUtc02PVZ/rmVnUBQlEyny1+Y9GQps+UmRqhvzQD9Z8CDS1UieZ5+T6uuC51efdjkrflVG2Snqw/FXx6Ft1vCNyPg416wbDRcDCt8vDEDfnkEtvxPPe/3DDzwTdner3ldvQd/LJzDUhHpCfnzUg1/G9yvm26i432qC9iUBT+OgdgTBfdrGmz/CN7rAAs7w/7v1bZrW3d6/gtcfUsuh4296n5uNVR9Ibt5Ru7/YUPRxw97XY047PSgyjvMa32+vjsrj96A6e5PiGrQDZ0pS/3bXNitkp83vqHKv3IKXNilrtd+ZH4S/x9Py1pzotaohvHT5bN8+XJmzJjBokWL6N27NwsXLmTYsGGEh4fj4+NT7Hnnz59n5syZ3HzzzcUeUxpL/s6B3NaddnerCbmK49NeJQlmJqk/InlDSPP+oDj73LguoDZ3qlFWKZfVmlSdHyz5+HNbVFeJrXPp35ZF1Wh9O+xaBCf/Vq0WRXxo67QcDKseVyNoAnurpTWunfU7T/BElSB7+CfVGhTYq/T7b3tfvTfu/gh821fBCyqjq+fViMdTf6v3XU5m/j4nL9U6cHKNerS4RU0umRipzrsSrkYh6m1hxMKSW1yv12oYOHmq88O+rvy0Bts/VP8uvh2hQxEjFHU6NT/WV7eprq0vBquWl27j1BegVdNUYjGoZSJ+m6rm1Gl3N1zam9u683Tlylgc/25w3xcwdJ7K9Ys5UnI3tsGWvUHTuDP5O/TnNsG3I1Ugl7eQqWsjlbcUPFF1v+Vkq2tGH4JVU9XUFkW9b63l/Db1/8W7jfq/4uZv7RKJGsDqAc+CBQuYMmUKkyerJMBFixaxevVqFi9ezPPPP1/kOSaTiXHjxjFv3jz++ecfEhMTK3Tvbk3c1TfKw7/kbijlj6uNnfrjd3mfauXJC3huVMLytQw2qu9/42sqsbO0gGf35+pn1zHg6F7txROoZTHsXFXy8uX90Di40CFtolahj9mrFiod9UXJczh1ekAFPEdXwrA3Sj42r4sMYPk4mLKx+v/dr55Xa5FFHyq43b2J+pBvd7danT7hjErCPvijStzNmwE4j2NDeGhp0XMilcTGTiU2r3sB1s5SuVZlCQw1rfCHdWqsClZBBaHFtTB5NIUntqoWkLMbVVBzer0aBp4Yob4gDXtDjezbOF8Na88b2t7rUXAp/ktdlXDzV/lGZWDW22G6/xv0y0dD5A61MfAmtfRLuxEFR67a2Kl5tD4boBKid38BvR+rhhdQDpqm6nbTWypx+1pujaFJb2h9h5pyxMGtbNeLOZL/Hr2wW+XsjXi/8CheUStYNeDJzs4mLCyMWbNmWbbp9XqGDBnCjh07ij3vlVdewcfHh3/961/880/FZzztGugOx/+ErCT1RzmoDK1FAd1VwHNmQ373140Ykl6U4Imw+S3VxXH5gGr2NhlV2a6eVxOL+XRQw3XzJhbrZeU/SvWJjR20vEW1spxcUyjg0UVso3VM7hQBI95TH54laTFYBQNpV+D8lvwJ5K4XfQR+y53B2mAHCWdh1ZPw0PfV15WZkQjfP6jmd9IZ1FIdrYaqvBqfdgUDCq9War6igc+pQDw9XnUFewSBe1Pw61hignKJbpqqul6O/aaSjR/bXHKX0cEfYc2zcNM0GPhsfjm3vqeCFP/uaqqBkrh4w8Mr1bIvm95QASmo1/LgN/ld4e3vgT9nqADBzgX6VlPrTmXYOcO4n9UgjoAeRY/kzOPdRiVxr/mvmpOo2QCVX1gdNE21rNvYq9QDnU4tpZEYoZYDijsFx3/PD9T0tiqwSYxQ81klX4QjF+HIL2rOo5a3qgC8SW9wD8r/f2E2qTmPjv6qFpFOjSlYjgPfq/f6/YvVyDhRq1g14ImLi8NkMuHrW/APkq+vLydOnCjynK1bt/LVV19x4MCBMt0jKyuLrKz8HJfkZDUc3d3RhkautpiP/IIeMHV6CLPJBKaS16PRtRmBzZ4v0Q4sIyf4UfDtiCHujLpGg0DMRmOZylUl7D0wtBuB/uhKzBteR3Nvgv7Yr+jyZl7NpRns0WlmzM0GYXJvDlVQRmPuNYw38vXWQroWt2Fz7De08LXk3Pxc/o7MZAy/PYkOjZxOo9Ha3F2mfxd9u7sx7FuC+eBPmJoUEaBnJGLz4zh0ORmYmw/GPGAWhqUj0IX/hWnLu5hLSpCtKJMRw08T0MeFo7k2ImfSWjVfUZ6cYvJpXPzhlrlF7yvj+6rI9+HwhdjEnkAXF475pwmYxq1Ugd/1slKwWTsLXWYSbHoDc/xpTHcuhLQ4bPZ8hQ7IGTgLrbjyX6/vM+gCemBY+xyabwdMt7+tusjzyuYSAA/9iC5iK5qTJ9i7V8n/xapQoB5tHaDrxLwdJZ/YbRKG8DXoz25AW3In5gHPYu42QeX65NE0SDit/i4Z7NFs7FXgor/u48fJSwVc19PMGH4cg/5s/izSmo2jmiHaXLB8msEec7fxmPv8O/89mJ2K7vI+dOf+QX/id3QJZ9QXwNwvgZqdC5pvR2jQGN25LejS8mex12yd0Jr2Q2s+GM3OFcOamejCV2Ne9iCm+78tUF75m1h5pdVhZevW6l1a5ZGSksL48eP54osv8PLyKv0EYP78+cybN6/Qdl+7bNasWcPQ83twAnZE2xL/V9mmV+/h3ouAxN0k/fg421q+QN8z+/AGDkQmc7GM16gqHtkdGMBK9Kfzh5Nm2rhx1akFrllROGfFqEREYKe+B1equHwhISFVer26xs6ocTs6dDGH2bBqKZl2avRb5wtLaJZymVR7XzbpbsFUxn8Xz1R/+gOmI6tYq7sVs/6aD3LNzE1nF+CbfJ40Oy82O9+P8WA0TfzH0e3CYvSbXmfXhWyuuHWsuheoaXS58DVB8ZvJ0dvzj/9UkrceBG7sDNHXvw+dvR9hYMJcbC/s5PyXEzgcOKHQOW2iVtI2I4FMGzfsclLRH/6J+HOHybT1INCURZxLG7YdT4cT5fw/E5g7XHtDSfPapADny3fdG6Ai/5/tnUbSz+EErumXMax9lvSN73E0YDRZNm74J+6lUdJeXLJiSr1Opk0DNreZa/k/kqdJ/Ga6RRZcMkOXo5Z3MelsSbP3JdWhEckOjYnwGkSmyQOKfA92gyZdcfW5hH/ibnyTD+KWcRFDdiq6Czshd4aPbIMTUQ16cNmjF3Eu7TDrbSF3/lCvZv+h99n3sDm3maufDOFg4GQ0XX7yuM7eu9b8TdSbswm4uoso92ByDE7WLk4BxdVhenp6pa6r0zTrjXHNzs7GycmJFStWFBhpNXHiRBITE/ntt4LTnR84cIBu3bphMOS/wcy5KyTr9XrCw8Np0aJFgXOKauEJDAzk1RU7eW5YK2zfUd1Qxhmny57jkHQRm0V90OVkkDPycwwbXkGXfJGciX+hNS5DzkBV0jQMP45GF7kdrc0dmDs+iNZ8UP63J2MGxJ1Ep5nR8prWq4DRaCQkJIShQ4diayv92SUxfDMc/cXdmG5/G3PwZHQX92D4Zjg6NLa1fJ5uo54uex1qZmw+7Iou5TI5932D1vZOyy79pvkYtr2LZuNAzsS/wK9zfhn+fBr9we/RnDwxDXkVrc2dRX+bLif9zo8xhM5BQ4fpgaVoeSPTbpCS3oe6k2uw+VlN3Jdz5/to1ybrp8Vh80kwuuw0ckZ9BXauGFZORpedZjkkZ/zvaE363pDXYW2V/v9sMqLf9w36f/6HLqPwGmOawU61uJiy1cOYoabVsJyfjc6cg7lJH0zjVuWPQEuLw+azPugyrmK6ZTbm7pPVuTmZatSim7/6WVHmHIg/jS7mMLqEc2j+3dGaDSi6RTCX7uIeDD8+hC4rudC+OJc2OD25EVu74s+vKfQhL2HYvQhzu3swjfrK2sUBSn8fJicn4+XlRVJSEm5uZcjDuo5VW3js7OwIDg4mNDTUEvCYzWZCQ0OZPr3wKtpt27bl8OHDBba99NJLpKSk8P777xMYWHiVcnt7e+zt7Qtt7xLogW3CKfXE1R9bN++yF9yrmRoauvF1bELnWIZl2ni3Amt8+E9YCZqGTqcrPM+ArS006VFtt7a1tZWApzRtboeLuzGcCcHQczKs+T9Aw9x5DHGG9uWvw073wfYPsTm+EjqNVNsO/Qzb3gVAN+J9bAOvS5C+awHEHkEXdRCb36eqHJL296gRe3nLYpTXhd0QOlfdc9gb2HQYUbHrVIEi67DD3RD7HGx+C5s1M8G7ZX4i9M4P1UScjbpg03GUyuF4ZJ3KQ0q5DC1uwabFwBv/Qqyswv+fbW2h75PQfazKZdq5SCX2troN2o1A12poyXlZ8WfgswHoI3eg3/G+mtgTYOM8NeLNtxOGfk9jqPKFmW3Bv5N6lFWzvjBptcqLS8qf+FXLTMYrNZyc2APYNKvg/6kbJS0O9qtJaPXHf0efdF7l1tUQxb0PK/tZY/XJWGbMmMEXX3zBN998w/Hjx3nyySdJS0uzjNqaMGGCJanZwcGBjh07Fni4u7vj6upKx44dsStHVN0poIFaeA8qNmS371MqKTElCtDUcG/ncgRNVa0mDQkVBbXOTXo9u1klmcceAydPTLcW7motk04PqJ8n10FmMkTugt+mqW39noYuowufY+ugZoYe9IJKrs9OVQmYS4ZXbIkSgD1fAZpK3r/pyYpdo7oNfF7NG2M2qsVe48+otfD2fKn23zI7P2HVr5NaSuW219WIOVF+Dg3URJmzLsKzZ+GBr9Wiw6UloXu2UEP8QS2LEbFDTWlw8AdAp6YoqPJgpxIadYYnt8HzkZaHljs3kX7P51YuXBnsWqSS8gHQYOvC0s8xZqhJNk+uq86SVSurBzwPPfQQ77zzDrNnz6Zr164cOHCAtWvXWhKZIyMjiYoqYvXfSnJ1sIGYY+qJTwUCHluH/JlWQQ1Jl6BDFMWnnRoFaMqCLW+rbcPeAKeGFbueX2fwbKWa9Xd+Cj+OVdduexfcOrf48xw91Dfnp/ar1oy8wGn9vKJX2C5JVooaFQNqfpea+t7X62Hkp2q0VcZV+GG0Gq5vylLTBlw/GZ9bI+g7veDEj6L8bOxUYnJ5dHlILXOhmdVElX88o7b3/Bc0rr5W6qpi6vEoALoTf0LyZSuXpgSZyfnTlPT9t/p56MeSlynSNDXCcMOrsOxBWPm4Gq12PVPNTti2esADMH36dCIiIsjKymLXrl307t3bsm/Tpk0sWbKk2HOXLFnCqlWrKnbj2NyAx7dDxc5vMxxa5P7BvJFz8Ija5dpZlwGaDYTOD1XuennByqY31ArZfp3g3s/KNuxcp4MmN8G9n6t5cbJT4O9yrot07Hf1DbFhC3WNmszOCcb8oHJI4k6qocmg1ueqqYFafTX8bTW/WfJFNV+Ti6/6d6oN/DoR59wGnTlHzYheU4V9rYb4e7aCIa+o6VjMOWqpkGLPWQIHl6l8KZ1eBUif9lVToCRHqVbib0fC637wYY+iZ1GvAWpEwGMVmqbmZ4DiFwstjU4Hd38IXR/OX+RRiKLkzeVi4wB3vVf5D9pO9+f/7uIHY5aXf5ZvvR7ufFf9ATvyS9nW/Mpz8Af1s+uY2hE0uPrBmB9V1zOoWZmb3GTdMonC7F3VHDf63FyN298sefb7Guas91D1y96vy7bkz41mzIQduQsb939G/Q24eYZ6HvaNyu253qUwNVcVqODzkXW5QeklWHovLGgLf81UE2+acyD+FCy+Tc1lZTYXvp4V1d+AJzUGMhPVJGlebSp+nQYBMPJjtcq6EMVpPlj98R7zg8pXqCzPFioh1MEdxiwrelHIsmjUBXqqpnj++q9aMqA0VyNyZwvWQeci8oVqqkadVV21vQvueMvapRHF8e+mlqq49zM1s3EtEu0ejObqr1pdj6y0dnEKO/C9+uxza6zWWgP1t6lRVzVBbd7s4nnS4uGniWpkXdu71Np2gb3U7OLXTmLbuCcMmQePb8nNmcuB9XPhu3trVPdeDcoCu7F0cbkTG3q2kBkzRfXT6ao+sXfsT+pbZGXfv4NfhKOrVHfPjo/yv/EV59By9bPZzYUX1Kzpmg9SD1GzNa+dI+Q0nQFz8CMYNr2mgocuo2tOC6gpR62vByp3xyZ3kI9Op5Zk+Wk87Poc+kxTOXqJF9QivkkXVIvOyE/yX4uds+p+7P8f1ULs6pd/nweWwP6lsOY51Wr8Xge1TmDezOu+Ha1WJ/W2hUd3JVz9UpGEZSFqAp2uaoJ1R3e47VX1+5a3S09etHRnySK0QlzP3G28Wr4i6oBa9sfaTEY4HarWe0uMUAvsdr9uIs62d4FXa7XM0ltBsLCTGsF5dpNa5PbBpUV3Lbr5Fwx2QP1d6p67rEvjXioJPXIHhL4Ci/qra//9klpf8AZPA1iPW3hyA56KJiwLUZd0fgj2fQsR29Qfxgm/538DvNaFXWptLjsXtaCkEKIgJ081qODAd2pOoge/Lf+ItTxpcer/5Pmt6gFqdHBRrZRpcXAqRE05kTc5Y2IknFgN104GOeC/KpH/Wno9DJoFK9R0MORNFOnRVHVj+VVgdnbv1vBoiCrDqRD1OLdZtRht/1A9PJqpkXk3PXFDcrXqb8AjLTxC5MtLwP98kPo29veLqsn6ege+Vz/b31MlMzULUSf1flwFPCfXqtFMt78FrYaU/fzMJFg1VS1ger2lo+C211QXuU6nWkkO/QRrn1NTLxTFyQva3w0dRqmu6KJ0HKUWxzbYq9FxVbXQsHsTNbVAz3+pQOxUiFpgN3ytWnh70xuw61PVrdZtUtXcsxj1NuAh/jTYUrFJB4WoizxbqAn3fnhIzdPh3w26js3fb8xQuT6gvpUJIYrWqDPc/zWsfV591nx/n5rG5Pb54BFU8rlxp9V8UfG5KwH4tFczhDftpwKogz/AulkQfQgGPgtrZ6ntoLqlvNuCraMaEerQQM011bR/2SZuLK1slWXrqAKv9ndDVqpqffrnHZU/+PdL2Oz4hFYufdHvuZi/vAio1uSKDsy4Rr0NeHTmbLB1AfcgaxdFiJqjze1qduLNb6qJ33zaqYkOT6xWCc1ZydCgifrjK4QoXsdR0HKIml191yK1OvulMPj3vuKnkDi9Hn5+ROXSuAXA6O/VF4887e9RIyvXvagCn7x8Or2tmlS03zNqSY/awN5FTTbZ8T71OjbNR5d8ifYpKyBqRcFjfdtLwFNpPm2rrtlOiLpi4HMq4fLkWvhhjPoDmhip9ult4NaX5f+NEGXh4AbDXldJvN/dD0mR6sO915TCx+7+Qs13o5nVqKaHvgMXn4LH5I329GkPP09SuTn+3dUIqorOJ2dtBhvoPh46PYBp95dE7fkDf/9G6K/9G1NFyzbV84BHurOEKESvV3OgfHGLmu0WwLEh9Jis5uxx87du+YSobbzbQL+n1AR9Oz+BHo8U7LKJO6WGcWtm6PawWlespETn5gNh6g6IOqhm+69J64xVlK0D5l6PExYXiO/w4eirYVHqOlBLlSAjtIQomqO7mudny9vQtI+apOz6kR1CiLLrOhY2vKZGOZ5cC23vzN+3fi5oJrUEzd0flW2eGle/wkPCRYnqd7u0tPAIUTyvljDqMwieJMGOEJVl56xaSSF/eQeAC7vVaCydXs1WXFMmKqyD6nfAIy08QgghbpRej6k8uIhtcGmfGlIekrs4atdxKq9UVJt6G/BoTt7g7GXtYgghhKgv3PzVqCRQuTzha9S8VzYOauI/Ua3qb8Dj3draRRBCCFHf9Jmmfh5ZqebTATXyqgqGXYuS1d+ApzIrpAshhBAV0agLBN2skpSvngdHDzV/jqh29Tjgkb5SIYQQVtBnev7vN89UoyJFtau3w9I1b2nhEUIIYQWtblNLTWSnqrmtxA1RbwMe/DpbuwRCCCHqI70exvxg7VLUO/W2S0sIIYQQ9YcEPEIIIYSo8yTgEUIIIUSdJwGPEEIIIeo8CXiEEEIIUedJwCOEEEKIOk8CHiGEEELUeRLwCCGEEKLOk4BHCCGEEHWeBDxCCCGEqPMk4BFCCCFEnScBjxBCCCHqPAl4hBBCCFHnScAjhBBCiDpPAh4hhBBC1HkS8AghhBCizpOARwghhBB1ngQ8QgghhKjzJOARQgghRJ0nAY8QQggh6jwJeIQQQghR50nAI4QQQog6TwIeIYQQQtR5EvAIIYQQos6TgEcIIYQQdZ4EPEIIIYSo8yTgEUIIIUSdJwGPEEIIIeq8GhHwfPzxxwQFBeHg4EDv3r3ZvXt3sceuXLmSHj164O7ujrOzM127dmXp0qU3sLRCCCGEqG2sHvAsX76cGTNmMGfOHPbt20eXLl0YNmwYsbGxRR7fsGFDXnzxRXbs2MGhQ4eYPHkykydPZt26dTe45EIIIYSoLawe8CxYsIApU6YwefJk2rdvz6JFi3BycmLx4sVFHj9o0CDuvfde2rVrR4sWLXj66afp3LkzW7duvcElF0IIIURtYdWAJzs7m7CwMIYMGWLZptfrGTJkCDt27Cj1fE3TCA0NJTw8nAEDBlRnUYUQQghRi9lY8+ZxcXGYTCZ8fX0LbPf19eXEiRPFnpeUlERAQABZWVkYDAY++eQThg4dWuSxWVlZZGVlWZ4nJycDYDQaMRqNVfAq6qe8upM6rDipw8qTOqwaUo+VJ3VYeaXVYWXr1qoBT0W5urpy4MABUlNTCQ0NZcaMGTRv3pxBgwYVOnb+/PnMmzev0PaNGzfi5OR0A0pbt4WEhFi7CLWe1GHlSR1WDanHypM6rLzi6jA9Pb1S19VpmqZV6gqVkJ2djZOTEytWrGDkyJGW7RMnTiQxMZHffvutTNd59NFHuXDhQpGJy0W18AQGBhIVFYWnp2elX0N9ZTQaCQkJYejQodja2lq7OLWS1GHlSR1WDanHypM6rLzS6jA5ORkvLy+SkpJwc3Mr9/Wt2sJjZ2dHcHAwoaGhloDHbDYTGhrK9OnTy3wds9lcIKi5lr29Pfb29oW229raypuyCkg9Vp7UYeVJHVYNqcfKkzqsvOLqsLL1avUurRkzZjBx4kR69OhBr169WLhwIWlpaUyePBmACRMmEBAQwPz58wHVRdWjRw9atGhBVlYWf/31F0uXLuXTTz+15ssQQgghRA1m9YDnoYce4sqVK8yePZvo6Gi6du3K2rVrLYnMkZGR6PX5g8nS0tKYOnUqFy9exNHRkbZt2/Ldd9/x0EMPWeslCCGEEKKGs3rAAzB9+vRiu7A2bdpU4Plrr73Ga6+9dgNKJYQQQoi6wuoTDwohhBBCVDcJeIQQQghR50nAI4QQQog6TwIeIYQQQtR5EvAIIYQQos6TgEcIIYQQdZ4EPEIIIYSo8yTgEUIIIUSdJwGPEEIIIeo8CXiEEEIIUedJwCOEEEKIOq9GrKV1I2maBkBKSkqll5qvz4xGI+np6SQnJ0s9VpDUYeVJHVYNqcfKkzqsvNLqMDk5Gcj/HC+vehfwxMfHA9CsWTMrl0QIIYQQ5ZWSkkKDBg3KfV69C3gaNmwIQGRkZIUqTCjJyckEBgZy4cIF3NzcrF2cWknqsPKkDquG1GPlSR1WXml1qGkaKSkp+Pv7V+j69S7g0etV2lKDBg3kTVkF3NzcpB4rSeqw8qQOq4bUY+VJHVZeSXVYmYYKSVoWQgghRJ0nAY8QQggh6rx6F/DY29szZ84c7O3trV2UWk3qsfKkDitP6rBqSD1WntRh5VV3Heq0io7vEkIIIYSoJepdC48QQggh6h8JeIQQQghR50nAI4QQQog6TwIeIYQQQtR59S7g+fjjjwkKCsLBwYHevXuze/duaxepxpo/fz49e/bE1dUVHx8fRo4cSXh4eIFjMjMzmTZtGp6enri4uHDfffcRExNjpRLXfG+++SY6nY5nnnnGsk3qsHSXLl3i4YcfxtPTE0dHRzp16sTevXst+zVNY/bs2TRq1AhHR0eGDBnCqVOnrFjimsdkMvHyyy/TrFkzHB0dadGiBa+++mqBdYmkHgvasmULI0aMwN/fH51Ox6pVqwrsL0t9JSQkMG7cONzc3HB3d+df//oXqampN/BVWF9J9Wg0Gnnuuefo1KkTzs7O+Pv7M2HCBC5fvlzgGlVRj/Uq4Fm+fDkzZsxgzpw57Nu3jy5dujBs2DBiY2OtXbQaafPmzUybNo2dO3cSEhKC0WjktttuIy0tzXLMf/7zH/744w9+/vlnNm/ezOXLlxk1apQVS11z7dmzh88++4zOnTsX2C51WLKrV6/Sr18/bG1tWbNmDceOHePdd9/Fw8PDcsz//vc/PvjgAxYtWsSuXbtwdnZm2LBhZGZmWrHkNctbb73Fp59+ykcffcTx48d56623+N///seHH35oOUbqsaC0tDS6dOnCxx9/XOT+stTXuHHjOHr0KCEhIfz5559s2bKFxx577Ea9hBqhpHpMT09n3759vPzyy+zbt4+VK1cSHh7O3XffXeC4KqlHrR7p1auXNm3aNMtzk8mk+fv7a/Pnz7diqWqP2NhYDdA2b96saZqmJSYmara2ttrPP/9sOeb48eMaoO3YscNaxayRUlJStFatWmkhISHawIEDtaefflrTNKnDsnjuuee0/v37F7vfbDZrfn5+2ttvv23ZlpiYqNnb22s//PDDjShirXDnnXdqjzzySIFto0aN0saNG6dpmtRjaQDt119/tTwvS30dO3ZMA7Q9e/ZYjlmzZo2m0+m0S5cu3bCy1yTX12NRdu/erQFaRESEpmlVV4/1poUnOzubsLAwhgwZYtmm1+sZMmQIO3bssGLJao+kpCQgfwHWsLAwjEZjgTpt27YtTZo0kTq9zrRp07jzzjsL1BVIHZbF77//To8ePXjggQfw8fGhW7dufPHFF5b9586dIzo6ukAdNmjQgN69e0sdXqNv376EhoZy8uRJAA4ePMjWrVu54447AKnH8ipLfe3YsQN3d3d69OhhOWbIkCHo9Xp27dp1w8tcWyQlJaHT6XB3dweqrh7rzeKhcXFxmEwmfH19C2z39fXlxIkTVipV7WE2m3nmmWfo168fHTt2BCA6Oho7OzvLmzKPr68v0dHRVihlzfTjjz+yb98+9uzZU2if1GHpzp49y6effsqMGTN44YUX2LNnD0899RR2dnZMnDjRUk9F/d+WOsz3/PPPk5ycTNu2bTEYDJhMJl5//XXGjRsHIPVYTmWpr+joaHx8fArst7GxoWHDhlKnxcjMzOS5555jzJgxlgVEq6oe603AIypn2rRpHDlyhK1bt1q7KLXKhQsXePrppwkJCcHBwcHaxamVzGYzPXr04I033gCgW7duHDlyhEWLFjFx4kQrl672+Omnn/j+++9ZtmwZHTp04MCBAzzzzDP4+/tLPYoawWg08uCDD6JpGp9++mmVX7/edGl5eXlhMBgKjX6JiYnBz8/PSqWqHaZPn86ff/7Jxo0bady4sWW7n58f2dnZJCYmFjhe6jRfWFgYsbGxdO/eHRsbG2xsbNi8eTMffPABNjY2+Pr6Sh2WolGjRrRv377Atnbt2hEZGQlgqSf5v12y//73vzz//POMHj2aTp06MX78eP7zn/8wf/58QOqxvMpSX35+foUGxeTk5JCQkCB1ep28YCciIoKQkBBL6w5UXT3Wm4DHzs6O4OBgQkNDLdvMZjOhoaH06dPHiiWruTRNY/r06fz6669s2LCBZs2aFdgfHByMra1tgToNDw8nMjJS6jTXrbfeyuHDhzlw4IDl0aNHD8aNG2f5XeqwZP369Ss0HcLJkydp2rQpAM2aNcPPz69AHSYnJ7Nr1y6pw2ukp6ej1xf8k28wGDCbzYDUY3mVpb769OlDYmIiYWFhlmM2bNiA2Wymd+/eN7zMNVVesHPq1CnWr1+Pp6dngf1VVo8VSLKutX788UfN3t5eW7JkiXbs2DHtscce09zd3bXo6GhrF61GevLJJ7UGDRpomzZt0qKioiyP9PR0yzFPPPGE1qRJE23Dhg3a3r17tT59+mh9+vSxYqlrvmtHaWma1GFpdu/erdnY2Givv/66durUKe3777/XnJyctO+++85yzJtvvqm5u7trv/32m3bo0CHtnnvu0Zo1a6ZlZGRYseQ1y8SJE7WAgADtzz//1M6dO6etXLlS8/Ly0p599lnLMVKPBaWkpGj79+/X9u/frwHaggULtP3791tGD5Wlvm6//XatW7du2q5du7StW7dqrVq10saMGWOtl2QVJdVjdna2dvfdd2uNGzfWDhw4UOCzJisry3KNqqjHehXwaJqmffjhh1qTJk00Ozs7rVevXtrOnTutXaQaCyjy8fXXX1uOycjI0KZOnap5eHhoTk5O2r333qtFRUVZr9C1wPUBj9Rh6f744w+tY8eOmr29vda2bVvt888/L7DfbDZrL7/8subr66vZ29trt956qxYeHm6l0tZMycnJ2tNPP601adJEc3Bw0Jo3b669+OKLBT5UpB4L2rhxY5F/AydOnKhpWtnqKz4+XhszZozm4uKiubm5aZMnT9ZSUlKs8Gqsp6R6PHfuXLGfNRs3brRcoyrqUadp10yzKYQQQghRB9WbHB4hhBBC1F8S8AghhBCizpOARwghhBB1ngQ8QgghhKjzJOARQgghRJ0nAY8QQggh6jwJeIQQQghR50nAI4SoF4KCgli4cKG1iyGEsBIJeIQQVW7SpEmMHDkSgEGDBvHMM8/csHsvWbIEd3f3Qtv37NnDY489dsPKIYSoWWysXQAhhCiL7Oxs7OzsKny+t7d3FZZGCFHbSAuPEKLaTJo0ic2bN/P++++j0+nQ6XScP38egCNHjnDHHXfg4uKCr68v48ePJy4uznLuoEGDmD59Os888wxeXl4MGzYMgAULFtCpUyecnZ0JDAxk6tSppKamArBp0yYmT55MUlKS5X5z584FCndpRUZGcs899+Di4oKbmxsPPvggMTExlv1z586la9euLF26lKCgIBo0aMDo0aNJSUmxHLNixQo6deqEo6Mjnp6eDBkyhLS0tGqqTSFEZUjAI4SoNu+//z59+vRhypQpREVFERUVRWBgIImJidxyyy1069aNvXv3snbtWmJiYnjwwQcLnP/NN99gZ2fHtm3bWLRoEQB6vZ4PPviAo0eP8s0337BhwwaeffZZAPr27cvChQtxc3Oz3G/mzJmFymU2m7nnnntISEhg8+bNhISEcPbsWR566KECx505c4ZVq1bx559/8ueff7J582befPNNAKKiohgzZgyPPPIIx48fZ9OmTYwaNQpZnlCImkm6tIQQ1aZBgwbY2dnh5OSEn5+fZftHH31Et27deOONNyzbFi9eTGBgICdPnqR169YAtGrViv/9738FrnltPlBQUBCvvfYaTzzxBJ988gl2dnY0aNAAnU5X4H7XCw0N5fDhw5w7d47AwEAAvv32Wzp06MCePXvo2bMnoAKjJUuW4OrqCsD48eMJDQ3l9ddfJyoqipycHEaNGkXTpk0B6NSpUyVqSwhRnaSFRwhxwx08eJCNGzfi4uJiebRt2xZQrSp5goODC527fv16br31VgICAnB1dWX8+PHEx8eTnp5e5vsfP36cwMBAS7AD0L59e9zd3Tl+/LhlW1BQkCXYAWjUqBGxsbEAdOnShVtvvZVOnTrxwAMP8MUXX3D16tWyV4IQ4oaSgEcIccOlpqYyYsQIDhw4UOBx6tQpBgwYYDnO2dm5wHnnz5/nrrvuonPnzvzyyy+EhYXx8ccfAyqpuarZ2toWeK7T6TCbzQAYDAZCQkJYs2YN7du358MPP6RNmzacO3euysshhKg8CXiEENXKzs4Ok8lUYFv37t05evQoQUFBtGzZssDj+iDnWmFhYZjNZt59911uuukmWrduzeXLl0u93/XatWvHhQsXuHDhgmXbsWPHSExMpH379mV+bTqdjn79+jFv3jz279+PnZ0dv/76a5nPF0LcOBLwCCGqVVBQELt27eL8+fPExcVhNpuZNm0aCQkJjBkzhj179nDmzBnWrVvH5P9v325VFIjiMIy/q100TDGKCIqDxWTQMgh6AwZBsBkNxskOE7R4CWKwCF6ARTAo4iUYpmq0ieyGhWVlP3DDGv48v3xgOCcMD+ej2/01VrLZrK7XqyaTiY7Ho6bT6cdl5s/fu1wuWq1WOp/P3x51eZ4n13XVbrd1OBy02+3U6XRUq9VULpcfmtd2u9VwONR+v1cURVosFjqdTsrn839bIABPQfAA+FeDwUDxeFyFQkGO4yiKIqXTaW02G91uN9Xrdbmuq36/r2QyqVjs599SqVTSeDxWGIYqFouazWYKguBuTKVSUa/XU6vVkuM4Xy49S+87M8vlUqlUStVqVZ7nKZPJaD6fPzyvRCKh9XqtZrOpXC4n3/c1Go3UaDQeXxwAT/PyyhtKAABgHDs8AADAPIIHAACYR/AAAADzCB4AAGAewQMAAMwjeAAAgHkEDwAAMI/gAQAA5hE8AADAPIIHAACYR/AAAADzCB4AAGDeG+z1HD9lXy3tAAAAAElFTkSuQmCC",
|
||
"text/plain": [
|
||
"<Figure size 640x480 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"image/png": "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",
|
||
"text/plain": [
|
||
"<Figure size 640x480 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"train data size: 739366\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"print('train data size: ', len(train_data))\n",
|
||
"\n",
|
||
"label_gain = list(range(len(train_data['label'].unique())))\n",
|
||
"label_gain = [gain * gain for gain in label_gain]\n",
|
||
"light_params = {\n",
|
||
" 'label_gain': label_gain,\n",
|
||
" 'objective': 'lambdarank',\n",
|
||
" 'metric': 'ndcg',\n",
|
||
" 'learning_rate': 0.03,\n",
|
||
" 'num_leaves': 32,\n",
|
||
" # 'min_data_in_leaf': 128,\n",
|
||
" 'max_depth': 8,\n",
|
||
" 'max_bin': 32,\n",
|
||
" 'feature_fraction': 0.7,\n",
|
||
" 'bagging_fraction': 0.7,\n",
|
||
" 'bagging_freq': 5,\n",
|
||
" 'lambda_l1': 0.1,\n",
|
||
" 'lambda_l2': 0.1,\n",
|
||
" 'boosting': 'gbdt',\n",
|
||
" 'verbosity': -1,\n",
|
||
" 'extra_trees': True,\n",
|
||
" 'max_position': 5,\n",
|
||
" 'ndcg_at': 1,\n",
|
||
" 'quant_train_renew_leaf': True,\n",
|
||
" 'lambdarank_truncation_level': 1,\n",
|
||
" 'lambdarank_position_bias_regularization': 1,\n",
|
||
" 'seed': 7\n",
|
||
"}\n",
|
||
"evals = {}\n",
|
||
"\n",
|
||
"gc.collect()\n",
|
||
"\n",
|
||
"use_pca = False\n",
|
||
"# feature_contri = [2 if feat.startswith('act_factor') or 'buy' in feat or 'sell' in feat else 1 for feat in feature_columns]\n",
|
||
"# light_params['feature_contri'] = feature_contri\n",
|
||
"# print(f'feature_contri: {feature_contri}')\n",
|
||
"model, scaler, pca = train_light_model(train_data.dropna(subset=['label']),\n",
|
||
" light_params, feature_columns,\n",
|
||
" [lgb.log_evaluation(period=100),\n",
|
||
" lgb.callback.record_evaluation(evals),\n",
|
||
" lgb.early_stopping(100, first_metric_only=True)\n",
|
||
" ], evals,\n",
|
||
" num_boost_round=1000, validation_days=120,\n",
|
||
" print_feature_importance=True, use_pca=use_pca)\n",
|
||
"\n",
|
||
"print('train data size: ', len(train_data))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 21,
|
||
"id": "5d1522a7538db91b",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T15:04:39.656944Z",
|
||
"start_time": "2025-04-03T15:04:39.298483Z"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"9.663390663390663\n",
|
||
" trade_date ts_code future_return future_score label\n",
|
||
"29 2023-08-01 605188.SH 0.046809 NaN 19.0\n",
|
||
"1017 2023-08-02 000014.SZ 0.062638 NaN 19.0\n",
|
||
"1988 2023-08-03 000890.SZ 0.132200 NaN 19.0\n",
|
||
"2958 2023-08-04 603536.SH -0.062907 NaN 0.0\n",
|
||
"3921 2023-08-07 603828.SH -0.016221 NaN 2.0\n",
|
||
"4948 2023-08-08 002336.SZ -0.032209 NaN 0.0\n",
|
||
"5902 2023-08-09 600155.SH 0.027813 NaN 19.0\n",
|
||
"6964 2023-08-10 002787.SZ 0.085946 NaN 19.0\n",
|
||
"7842 2023-08-11 601136.SH 0.103558 NaN 19.0\n",
|
||
"8841 2023-08-14 603536.SH -0.028928 NaN 0.0\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# train_data = train_data.sort_values(by='trade_date')\n",
|
||
"# all_dates = train_data['trade_date'].unique() # 获取所有唯一的 trade_date\n",
|
||
"# split_date = all_dates[-120] # 划分点为倒数第 validation_days 天\n",
|
||
"# print(split_date)\n",
|
||
"# print(all_dates)\n",
|
||
"# val_data_split = train_data[train_data['trade_date'] >= split_date] # 验证集\n",
|
||
"\n",
|
||
"score_df = test_data\n",
|
||
"numeric_columns = score_df.select_dtypes(include=['float64', 'int64']).columns\n",
|
||
"numeric_columns = [col for col in numeric_columns if col in feature_columns]\n",
|
||
"# score_df.loc[:, numeric_columns] = scaler.transform(score_df[numeric_columns])\n",
|
||
"score_df = cross_sectional_standardization(score_df, numeric_columns)\n",
|
||
"\n",
|
||
"if use_pca and pca is not None:\n",
|
||
" categorical_feature = [col for col in feature_columns if 'cat' in col]\n",
|
||
" numeric_features = [col for col in feature_columns if col not in categorical_feature]\n",
|
||
" numeric_pca = pca.transform(score_df[numeric_features])\n",
|
||
" score_df = pd.concat([pd.DataFrame(numeric_pca), score_df[categorical_feature],\n",
|
||
" score_df[['trade_date', 'ts_code', 'future_return', 'future_score', 'label']]], axis=1)\n",
|
||
" score_df['score'] = model.predict(score_df[[col for col in score_df.columns if\n",
|
||
" col not in ['trade_date', 'ts_code', 'future_return', 'future_score',\n",
|
||
" 'label']]])\n",
|
||
"else:\n",
|
||
" score_df['score'] = model.predict(score_df[feature_columns])\n",
|
||
"# train_data['score'] = catboost_model.predict(train_data[feature_columns])\n",
|
||
"score_df = score_df.loc[score_df.groupby('trade_date')['score'].idxmax()]\n",
|
||
"# score_df = score_df[score_df['score'] > 0]\n",
|
||
"score_df[['trade_date', 'score', 'ts_code']].to_csv('predictions_test.tsv', index=False)\n",
|
||
"print(score_df['label'].mean())\n",
|
||
"print(score_df[['trade_date', 'ts_code', 'future_return', 'future_score', 'label']].head(10))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 22,
|
||
"id": "d86af99d15cb3bdd",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T15:03:25.791021Z",
|
||
"start_time": "2025-04-03T15:03:25.537833Z"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
" trade_date ts_code close open future_return\n",
|
||
"2563 2020-01-02 603577.SH 16.43 16.34 0.001819\n",
|
||
"5354 2020-01-03 603577.SH 16.52 16.49 -0.007251\n",
|
||
"8146 2020-01-06 603577.SH 16.43 16.55 0.007299\n",
|
||
"10936 2020-01-07 603577.SH 16.56 16.44 -0.012689\n",
|
||
"13725 2020-01-08 603577.SH 16.34 16.55 0.003636\n",
|
||
"... ... ... ... ... ...\n",
|
||
"3817882 2025-04-02 603577.SH 19.74 19.78 0.003579\n",
|
||
"3820967 2025-04-03 603577.SH 19.63 19.56 -0.066596\n",
|
||
"3824052 2025-04-07 603577.SH 17.66 18.92 -0.078398\n",
|
||
"3827137 2025-04-08 603577.SH 16.34 17.73 0.047170\n",
|
||
"3830225 2025-04-09 603577.SH 16.65 15.90 NaN\n",
|
||
"\n",
|
||
"[1275 rows x 5 columns]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"print(df[(df['ts_code'] == '603577.SH') & (df['trade_date'] >= '2018-06-04')][\n",
|
||
" ['trade_date', 'ts_code', 'close', 'open', 'future_return']])"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 23,
|
||
"id": "ef9d068e-67f7-412c-bbd8-cdee7492dbc9",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T15:03:25.893508Z",
|
||
"start_time": "2025-04-03T15:03:25.878525Z"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"nan\n",
|
||
"nan\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"print(train_data[\"future_score\"].corr(train_data[\"label\"]))\n",
|
||
"print(test_data[\"future_score\"].corr(test_data[\"label\"]))\n"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "new_trader",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.11.11"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 5
|
||
}
|