1873 lines
232 KiB
Plaintext
1873 lines
232 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": [
|
||
"/mnt/d/PyProject/NewStock\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"%load_ext autoreload\n",
|
||
"%autoreload 2\n",
|
||
"\n",
|
||
"import gc\n",
|
||
"import os\n",
|
||
"import sys\n",
|
||
"sys.path.append('/mnt/d/PyProject/NewStock/')\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: 8713571 entries, 0 to 8713570\n",
|
||
"Data columns (total 33 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 amount float64 \n",
|
||
" 9 turnover_rate float64 \n",
|
||
" 10 pe_ttm float64 \n",
|
||
" 11 circ_mv float64 \n",
|
||
" 12 total_mv float64 \n",
|
||
" 13 volume_ratio float64 \n",
|
||
" 14 is_st bool \n",
|
||
" 15 up_limit float64 \n",
|
||
" 16 down_limit float64 \n",
|
||
" 17 buy_sm_vol float64 \n",
|
||
" 18 sell_sm_vol float64 \n",
|
||
" 19 buy_lg_vol float64 \n",
|
||
" 20 sell_lg_vol float64 \n",
|
||
" 21 buy_elg_vol float64 \n",
|
||
" 22 sell_elg_vol float64 \n",
|
||
" 23 net_mf_vol float64 \n",
|
||
" 24 his_low float64 \n",
|
||
" 25 his_high float64 \n",
|
||
" 26 cost_5pct float64 \n",
|
||
" 27 cost_15pct float64 \n",
|
||
" 28 cost_50pct float64 \n",
|
||
" 29 cost_85pct float64 \n",
|
||
" 30 cost_95pct float64 \n",
|
||
" 31 weight_avg float64 \n",
|
||
" 32 winner_rate float64 \n",
|
||
"dtypes: bool(1), datetime64[ns](1), float64(30), object(1)\n",
|
||
"memory usage: 2.1+ 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('/mnt/d/PyProject/NewStock/data/daily_data.h5', key='daily_data',\n",
|
||
" columns=['ts_code', 'trade_date', 'open', 'close', 'high', 'low', 'vol', 'pct_chg', 'amount'],\n",
|
||
" df=None)\n",
|
||
"\n",
|
||
"print('daily basic')\n",
|
||
"df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/data/daily_basic.h5', key='daily_basic',\n",
|
||
" columns=['ts_code', 'trade_date', 'turnover_rate', 'pe_ttm', 'circ_mv', 'total_mv', 'volume_ratio',\n",
|
||
" 'is_st'], df=df, join='inner')\n",
|
||
"\n",
|
||
"print('stk limit')\n",
|
||
"df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/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('/mnt/d/PyProject/NewStock/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('/mnt/d/PyProject/NewStock/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('/mnt/d/PyProject/NewStock/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": [
|
||
"from main.factor.factor import *\n",
|
||
"\n",
|
||
"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",
|
||
" # df = sentiment_panic_greed_index(df)\n",
|
||
" # df = sentiment_market_breadth_proxy(df)\n",
|
||
" # df = sentiment_reversal_indicator(df)\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', \n",
|
||
" 'RSI', 'MACD', 'Signal_line', 'MACD_hist', \n",
|
||
" # 'sentiment_panic_greed_index',\n",
|
||
" '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 = '/mnt/d/PyProject/NewStock/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": [
|
||
"import talib\n",
|
||
"import numpy as np"
|
||
]
|
||
},
|
||
{
|
||
"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",
|
||
"\n",
|
||
" # cs_rank_intraday_range(industry_data)\n",
|
||
" # cs_rank_close_pos_in_range(industry_data)\n",
|
||
"\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('/mnt/d/PyProject/NewStock/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', 'amount', 'circ_mv', 'total_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": [],
|
||
"source": [
|
||
"fina_indicator_df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/data/fina_indicator.h5', key='fina_indicator',\n",
|
||
" columns=['ts_code', 'ann_date', 'undist_profit_ps', 'ocfps', 'bps'],\n",
|
||
" df=None)\n",
|
||
"cashflow_df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/data/cashflow.h5', key='cashflow',\n",
|
||
" columns=['ts_code', 'ann_date', 'n_cashflow_act'],\n",
|
||
" df=None)\n",
|
||
"balancesheet_df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/data/balancesheet.h5', key='balancesheet',\n",
|
||
" columns=['ts_code', 'ann_date', 'money_cap', 'total_liab'],\n",
|
||
" df=None)\n",
|
||
"top_list_df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/data/top_list.h5', key='top_list',\n",
|
||
" columns=['ts_code', 'trade_date', 'reason'],\n",
|
||
" df=None)\n",
|
||
"\n",
|
||
"top_list_df = top_list_df.sort_values(by='trade_date', ascending=False).drop_duplicates(subset=['ts_code', 'trade_date'], keep='first').sort_values(by='trade_date')\n",
|
||
"\n",
|
||
"stk_holdertrade_df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/data/stk_holdertrade.h5', key='stk_holdertrade',\n",
|
||
" columns=['ts_code', 'ann_date', 'in_de', 'change_ratio'],\n",
|
||
" df=None)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"id": "ba5935c8",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"✅ 成功从 Redis Hash 'concept_stocks_daily_lists_pickle' 读取 1794 条每日概念股票数据。\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"import redis\n",
|
||
"import pickle\n",
|
||
"from datetime import date, datetime\n",
|
||
"\n",
|
||
"# --- 配置 Redis 连接 ---\n",
|
||
"REDIS_HOST = '140.143.91.66'\n",
|
||
"REDIS_PORT = 6389\n",
|
||
"REDIS_DB = 0\n",
|
||
"\n",
|
||
"# --- 定义 Redis 键名 ---\n",
|
||
"HASH_KEY = \"concept_stocks_daily_lists_pickle\" # 区分之前的 JSON 版本\n",
|
||
"MAX_DATE_KEY = \"concept_stocks_max_date_pickle\" # 区分之前的 JSON 版本\n",
|
||
"\n",
|
||
"concept_dict = {}\n",
|
||
"\n",
|
||
"# --- 连接 Redis ---\n",
|
||
"try:\n",
|
||
" r = redis.StrictRedis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB, password='Redis520102')\n",
|
||
"\n",
|
||
" all_data_from_redis = r.hgetall(HASH_KEY) # 返回的是字典,键是字节,值是字节\n",
|
||
" \n",
|
||
" if all_data_from_redis:\n",
|
||
" for date_bytes, stocks_bytes in all_data_from_redis.items(): # 将变量名改为 date_bytes 更清晰\n",
|
||
" try:\n",
|
||
" # *** 修正点:将日期字节解码为字符串 ***\n",
|
||
" date_str = date_bytes.decode('utf-8') \n",
|
||
" date_obj = datetime.strptime(date_str, '%Y%m%d').date()\n",
|
||
" \n",
|
||
" stocks_list = pickle.loads(stocks_bytes)\n",
|
||
" concept_dict[date_obj] = stocks_list\n",
|
||
" except (ValueError, pickle.UnpicklingError) as e:\n",
|
||
" print(f\"⚠️ 警告: 解析 Redis 数据时出错 (日期键: '{date_bytes.decode('utf-8', errors='ignore')}'),跳过此条数据: {e}\") # 打印警告时也解码一下\n",
|
||
" print(f\"✅ 成功从 Redis Hash '{HASH_KEY}' 读取 {len(concept_dict)} 条每日概念股票数据。\")\n",
|
||
" else:\n",
|
||
" print(f\"ℹ️ Redis Hash '{HASH_KEY}' 中没有找到任何数据。\")\n",
|
||
"\n",
|
||
"except redis.exceptions.ConnectionError as e:\n",
|
||
" print(f\"❌ 错误: 无法连接到 Redis 服务器,请检查 Redis 是否正在运行或连接配置: {e}\")\n",
|
||
"except Exception as e:\n",
|
||
" print(f\"❌ 从 Redis 读取数据时发生未知错误: {e}\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"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": [
|
||
"4566757\n",
|
||
"开始生成概念相关因子...\n",
|
||
"开始计算概念内截面排序因子,基于: ['pct_chg', 'turnover_rate', 'volume_ratio']\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Ranking Features in Concepts: 100%|██████████| 3/3 [00:00<00:00, 15.60it/s]\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"概念相关因子生成完毕。\n",
|
||
"4566757\n",
|
||
"开始计算股东增减持因子...\n",
|
||
"警告: 'in_de' 列中存在未映射的值,可能导致 _direction 列出现NaN。\n",
|
||
"股东增减持因子计算完成。\n",
|
||
"Calculating cat_senti_mom_vol_spike...\n",
|
||
"Finished cat_senti_mom_vol_spike.\n",
|
||
"Calculating cat_senti_pre_breakout...\n",
|
||
"Calculating atr_10 as it's missing...\n",
|
||
"Calculating atr_40 as it's missing...\n",
|
||
"Finished cat_senti_pre_breakout.\n",
|
||
"计算因子 ts_turnover_rate_acceleration_5_20\n",
|
||
"计算因子 ts_vol_sustain_10_30\n",
|
||
"计算因子 cs_amount_outlier_10\n",
|
||
"计算因子 ts_ff_to_total_turnover_ratio\n",
|
||
"计算因子 ts_price_volume_trend_coherence_5_20\n",
|
||
"计算因子 ts_ff_turnover_rate_surge_10\n",
|
||
"使用 'ann_date' 作为财务数据生效日期。\n",
|
||
"警告: 从 financial_data_subset 中移除了 366 行,因为其 'ts_code' 或 'ann_date' 列存在空值。\n",
|
||
"使用 'ann_date' 作为财务数据生效日期。\n",
|
||
"警告: 从 financial_data_subset 中移除了 366 行,因为其 'ts_code' 或 'ann_date' 列存在空值。\n",
|
||
"开始计算因子: AR, BR (原地修改)...\n",
|
||
"因子 AR, BR 计算成功。\n",
|
||
"因子 AR, BR 计算流程结束。\n",
|
||
"使用 'ann_date' 作为财务数据生效日期。\n",
|
||
"使用 'ann_date' 作为财务数据生效日期。\n",
|
||
"使用 'ann_date' 作为财务数据生效日期。\n",
|
||
"使用 'ann_date' 作为财务数据生效日期。\n",
|
||
"警告: 从 financial_data_subset 中移除了 366 行,因为其 'ts_code' 或 'ann_date' 列存在空值。\n",
|
||
"计算 BBI...\n",
|
||
"--- 计算日级别偏离度 (使用 pct_chg) ---\n",
|
||
"--- 计算日级别动量基准 (使用 pct_chg) ---\n",
|
||
"日级别动量基准计算完成 (使用 pct_chg)。\n",
|
||
"日级别偏离度计算完成 (使用 pct_chg)。\n",
|
||
"--- 计算日级别行业偏离度 (使用 pct_chg 和行业基准) ---\n",
|
||
"--- 计算日级别行业动量基准 (使用 pct_chg 和 cat_l2_code) ---\n",
|
||
"错误: 计算日级别行业动量基准需要以下列: ['pct_chg', 'cat_l2_code', 'trade_date', 'ts_code']。\n",
|
||
"错误: 计算日级别行业偏离度需要以下列: ['pct_chg', 'daily_industry_positive_benchmark', 'daily_industry_negative_benchmark']。请先运行 daily_industry_momentum_benchmark(df)。\n",
|
||
"Index(['ts_code', 'trade_date', 'open', 'close', 'high', 'low', 'vol',\n",
|
||
" 'pct_chg', 'amount', 'turnover_rate',\n",
|
||
" ...\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', length=104)\n",
|
||
"Calculating senti_strong_inflow...\n",
|
||
"Finished senti_strong_inflow.\n",
|
||
"Calculating lg_flow_mom_corr_20_60...\n",
|
||
"Finished lg_flow_mom_corr_20_60.\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 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",
|
||
"Finished cs_rank_ind_adj_lg_flow.\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",
|
||
"<class 'pandas.core.frame.DataFrame'>\n",
|
||
"RangeIndex: 4566757 entries, 0 to 4566756\n",
|
||
"Columns: 197 entries, ts_code to cs_rank_cost_dist_vol_ratio\n",
|
||
"dtypes: bool(10), datetime64[ns](1), float64(175), int64(6), int8(1), object(4)\n",
|
||
"memory usage: 6.4+ GB\n",
|
||
"None\n",
|
||
"['ts_code', 'trade_date', 'open', 'close', 'high', 'low', 'vol', 'pct_chg', 'amount', 'turnover_rate', 'pe_ttm', 'circ_mv', 'total_mv', 'volume_ratio', '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', 'winner_rate', 'cat_l2_code', 'cat_hot_concept_stock', 'concept_rank_pct_chg', 'concept_rank_turnover_rate', 'concept_rank_volume_ratio', 'holder_net_change_sum_10d', 'holder_increase_days_10d', 'holder_decrease_days_10d', 'holder_any_increase_flag_10d', 'holder_any_decrease_flag_10d', 'holder_direction_score_10d', 'cat_senti_mom_vol_spike', 'cat_senti_pre_breakout', 'ts_turnover_rate_acceleration_5_20', 'ts_vol_sustain_10_30', 'cs_amount_outlier_10', 'ts_ff_to_total_turnover_ratio', 'ts_price_volume_trend_coherence_5_20', 'ts_ff_turnover_rate_surge_10', 'undist_profit_ps', 'ocfps', 'AR', 'BR', 'AR_BR', 'log_circ_mv', 'cashflow_to_ev_factor', 'book_to_price_ratio', 'turnover_rate_mean_5', 'variance_20', 'bbi_ratio_factor', 'daily_deviation', 'lg_elg_net_buy_vol', 'flow_lg_elg_intensity', 'sm_net_buy_vol', 'flow_divergence_diff', 'flow_divergence_ratio', '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', 'vol_break', 'weight_roc5', 'price_cost_divergence', 'smallcap_concentration', 'cost_stability', 'high_cost_break_days', 'liquidity_risk', 'turnover_std', 'mv_volatility', 'volume_growth', 'mv_growth', 'momentum_factor', 'resonance_factor', 'log_close', 'cat_vol_spike', 'up', 'down', 'obv_maobv_6', 'std_return_5_over_std_return_90', 'std_return_90_minus_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', 'senti_strong_inflow', '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_flow_divergence', 'cs_rank_ind_adj_lg_flow', '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_opening_gap', '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_ind_cap_neutral_pe', 'cs_rank_volume_ratio', 'cs_rank_elg_buy_sell_sm_ratio', 'cs_rank_cost_dist_vol_ratio']\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"import numpy as np\n",
|
||
"from main.factor.factor import *\n",
|
||
"from main.factor.money_factor import * \n",
|
||
"from main.factor.concept_factor import * \n",
|
||
"\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\"] >= \"2019-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",
|
||
"gc.collect()\n",
|
||
"\n",
|
||
"df = filter_data(df)\n",
|
||
"df = df.sort_values(by=[\"ts_code\", \"trade_date\"])\n",
|
||
"\n",
|
||
"# df = price_minus_deduction_price(df, n=120)\n",
|
||
"# df = price_deduction_price_diff_ratio_to_sma(df, n=120)\n",
|
||
"# df = cat_price_vs_sma_vs_deduction_price(df, n=120)\n",
|
||
"# df = cat_reason(df, top_list_df)\n",
|
||
"# df = cat_is_on_top_list(df, top_list_df)\n",
|
||
"print(len(df))\n",
|
||
"df = generate_concept_factors(df, concept_dict)\n",
|
||
"print(len(df))\n",
|
||
"\n",
|
||
"df = holder_trade_factors(df, stk_holdertrade_df)\n",
|
||
"\n",
|
||
"df = cat_senti_mom_vol_spike(\n",
|
||
" df,\n",
|
||
" return_period=3,\n",
|
||
" return_threshold=0.03, # 近3日涨幅超3%\n",
|
||
" volume_ratio_threshold=1.3,\n",
|
||
" current_pct_chg_min=0.0, # 当日必须收红\n",
|
||
" current_pct_chg_max=0.05,\n",
|
||
") # 当日涨幅不宜过大\n",
|
||
"\n",
|
||
"df = cat_senti_pre_breakout(\n",
|
||
" df,\n",
|
||
" atr_short_N=10,\n",
|
||
" atr_long_M=40,\n",
|
||
" vol_atrophy_N=10,\n",
|
||
" vol_atrophy_M=40,\n",
|
||
" price_stab_N=5,\n",
|
||
" price_stab_threshold=0.06,\n",
|
||
" current_pct_chg_min_signal=0.002,\n",
|
||
" current_pct_chg_max_signal=0.05,\n",
|
||
" volume_ratio_signal_threshold=1.1,\n",
|
||
")\n",
|
||
"\n",
|
||
"df = ts_turnover_rate_acceleration_5_20(df)\n",
|
||
"df = ts_vol_sustain_10_30(df)\n",
|
||
"# df = cs_turnover_rate_relative_strength_20(df)\n",
|
||
"df = cs_amount_outlier_10(df)\n",
|
||
"df = ts_ff_to_total_turnover_ratio(df)\n",
|
||
"df = ts_price_volume_trend_coherence_5_20(df)\n",
|
||
"# df = ts_turnover_rate_trend_strength_5(df)\n",
|
||
"df = ts_ff_turnover_rate_surge_10(df)\n",
|
||
"\n",
|
||
"df = add_financial_factor(df, fina_indicator_df, factor_value_col=\"undist_profit_ps\")\n",
|
||
"df = add_financial_factor(df, fina_indicator_df, factor_value_col=\"ocfps\")\n",
|
||
"calculate_arbr(df, N=26)\n",
|
||
"df[\"log_circ_mv\"] = np.log(df[\"circ_mv\"])\n",
|
||
"df = calculate_cashflow_to_ev_factor(df, cashflow_df, balancesheet_df)\n",
|
||
"df = caculate_book_to_price_ratio(df, fina_indicator_df)\n",
|
||
"df = turnover_rate_n(df, n=5)\n",
|
||
"df = variance_n(df, n=20)\n",
|
||
"df = bbi_ratio_factor(df)\n",
|
||
"df = daily_deviation(df)\n",
|
||
"df = daily_industry_deviation(df)\n",
|
||
"df, _ = get_rolling_factor(df)\n",
|
||
"df, _ = get_simple_factor(df)\n",
|
||
"\n",
|
||
"df = calculate_strong_inflow_signal(df)\n",
|
||
"\n",
|
||
"df = df.rename(columns={\"l1_code\": \"cat_l1_code\"})\n",
|
||
"df = df.rename(columns={\"l2_code\": \"cat_l2_code\"})\n",
|
||
"\n",
|
||
"lg_flow_mom_corr(df, N=20, M=60)\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",
|
||
"\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",
|
||
"\n",
|
||
"\n",
|
||
"# df = df.merge(index_data, on='trade_date', how='left')\n",
|
||
"\n",
|
||
"print(df.info())\n",
|
||
"print(df.columns.tolist())"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"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": 12,
|
||
"id": "47c12bb34062ae7a",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T14:57:50.841165Z",
|
||
"start_time": "2025-04-03T14:49:25.889057Z"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"days = 5\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', group_keys=False)['close'].apply(lambda x: x.shift(-days) / x - 1) + df.groupby('ts_code', group_keys=False)['close'].apply(lambda x: x.shift(-2 * days) / x - 1)\n",
|
||
"\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",
|
||
"\n",
|
||
"# df['cat_up_limit'] = df['pct_chg'] > 5\n",
|
||
"# df['label'] = (df.groupby('ts_code')['cat_up_limit']\n",
|
||
"# .rolling(window=5, min_periods=1).sum()\n",
|
||
"# .groupby('ts_code') # 再次按 ts_code 分组\n",
|
||
"# .shift(-5)\n",
|
||
"# .fillna(0) # 填充每个股票组最后的 NaN\n",
|
||
"# .astype(int)\n",
|
||
"# .reset_index(level=0, drop=True))\n",
|
||
"df['label'] = df.groupby('trade_date', group_keys=False)['future_return'].transform(\n",
|
||
" lambda x: pd.qcut(x, q=50, labels=False, duplicates='drop')\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_return'].between(df['future_return'].quantile(0.001), 0.6)\n",
|
||
"\n",
|
||
"# for col in [col for col in df.columns]:\n",
|
||
"# train_data[col] = train_data[col].astype('str')\n",
|
||
"# test_data[col] = test_data[col].astype('str')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 13,
|
||
"id": "29221dde",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"207\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"feature_columns = [col for col in df.head(10)\n",
|
||
" .merge(industry_df, on=['cat_l2_code', 'trade_date'], how='left')\n",
|
||
" .merge(index_data, on='trade_date', how='left')\n",
|
||
" .columns\n",
|
||
" ]\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 'circ_mv' not in col]\n",
|
||
"\n",
|
||
"feature_columns = [col for col in feature_columns if '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",
|
||
"feature_columns = [col for col in feature_columns if col not in ['cat_reason', 'cat_is_on_top_list']]\n",
|
||
"print(len(feature_columns))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"id": "03ee5daf",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# df = fill_nan_with_daily_median(df, feature_columns)\n",
|
||
"for feature_col in [col for col in feature_columns if col in df.columns]:\n",
|
||
" # median_val = df[feature_col].median()\n",
|
||
" df[feature_col].fillna(0, inplace=True)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"id": "b76ea08a",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
" ts_code trade_date log_circ_mv\n",
|
||
"0 000001.SZ 2019-01-02 16.574219\n",
|
||
"1 000001.SZ 2019-01-03 16.583965\n",
|
||
"2 000001.SZ 2019-01-04 16.633371\n",
|
||
"['vol', 'pct_chg', 'turnover_rate', 'volume_ratio', 'winner_rate', 'cat_hot_concept_stock', 'concept_rank_pct_chg', 'concept_rank_turnover_rate', 'concept_rank_volume_ratio', 'holder_net_change_sum_10d', 'holder_increase_days_10d', 'holder_decrease_days_10d', 'holder_any_increase_flag_10d', 'holder_any_decrease_flag_10d', 'cat_senti_mom_vol_spike', 'cat_senti_pre_breakout', 'ts_turnover_rate_acceleration_5_20', 'ts_vol_sustain_10_30', 'cs_amount_outlier_10', 'ts_ff_to_total_turnover_ratio', 'ts_price_volume_trend_coherence_5_20', 'ts_ff_turnover_rate_surge_10', 'undist_profit_ps', 'ocfps', 'AR', 'BR', 'AR_BR', 'cashflow_to_ev_factor', 'book_to_price_ratio', 'turnover_rate_mean_5', 'variance_20', 'bbi_ratio_factor', 'daily_deviation', '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', 'vol_break', 'weight_roc5', 'smallcap_concentration', 'cost_stability', 'high_cost_break_days', 'liquidity_risk', 'turnover_std', 'mv_volatility', 'volume_growth', 'mv_growth', 'momentum_factor', 'resonance_factor', 'log_close', 'cat_vol_spike', 'up', 'down', 'obv_maobv_6', 'std_return_5_over_std_return_90', 'std_return_90_minus_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', 'senti_strong_inflow', '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', 'industry_obv', 'industry_return_5', 'industry_return_20', 'industry__ema_5', 'industry__ema_13', 'industry__ema_20', 'industry__ema_60', 'industry_act_factor1', 'industry_act_factor2', 'industry_act_factor3', 'industry_act_factor4', 'industry_act_factor5', 'industry_act_factor6', 'industry_rank_act_factor1', 'industry_rank_act_factor2', 'industry_rank_act_factor3', 'industry_return_5_percentile', 'industry_return_20_percentile', '000852.SH_MACD', '000905.SH_MACD', '399006.SZ_MACD', '000852.SH_MACD_hist', '000905.SH_MACD_hist', '399006.SZ_MACD_hist', '000852.SH_RSI', '000905.SH_RSI', '399006.SZ_RSI', '000852.SH_Signal_line', '000905.SH_Signal_line', '399006.SZ_Signal_line', '000852.SH_amount_change_rate', '000905.SH_amount_change_rate', '399006.SZ_amount_change_rate', '000852.SH_amount_mean', '000905.SH_amount_mean', '399006.SZ_amount_mean', '000852.SH_daily_return', '000905.SH_daily_return', '399006.SZ_daily_return', '000852.SH_up_ratio_20d', '000905.SH_up_ratio_20d', '399006.SZ_up_ratio_20d', '000852.SH_volatility', '000905.SH_volatility', '399006.SZ_volatility', '000852.SH_volume_change_rate', '000905.SH_volume_change_rate', '399006.SZ_volume_change_rate']\n",
|
||
"去除极值\n",
|
||
"开始截面 MAD 去极值处理 (k=3.0)...\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"MAD Filtering: 100%|██████████| 145/145 [00:07<00:00, 19.05it/s]\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"截面 MAD 去极值处理完成。\n",
|
||
"标准化\n",
|
||
"开始截面 Z-Score 标准化...\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Standardizing: 100%|██████████| 145/145 [00:02<00:00, 61.44it/s]\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"截面 Z-Score 标准化完成。\n",
|
||
"开始截面 MAD 去极值处理 (k=3.0)...\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"MAD Filtering: 100%|██████████| 145/145 [00:05<00:00, 27.24it/s]\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"截面 MAD 去极值处理完成。\n",
|
||
"开始截面 Z-Score 标准化...\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Standardizing: 100%|██████████| 145/145 [00:01<00:00, 85.11it/s]\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"截面 Z-Score 标准化完成。\n",
|
||
"开始截面 MAD 去极值处理 (k=3.0)...\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"MAD Filtering: 0it [00:00, ?it/s]\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"截面 MAD 去极值处理完成。\n",
|
||
"开始截面 MAD 去极值处理 (k=3.0)...\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"MAD Filtering: 0it [00:00, ?it/s]\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"截面 MAD 去极值处理完成。\n",
|
||
"feature_columns: ['vol', 'pct_chg', 'turnover_rate', 'volume_ratio', 'winner_rate', 'cat_hot_concept_stock', 'concept_rank_pct_chg', 'concept_rank_turnover_rate', 'concept_rank_volume_ratio', 'holder_net_change_sum_10d', 'holder_increase_days_10d', 'holder_decrease_days_10d', 'holder_any_increase_flag_10d', 'holder_any_decrease_flag_10d', 'cat_senti_mom_vol_spike', 'cat_senti_pre_breakout', 'ts_turnover_rate_acceleration_5_20', 'ts_vol_sustain_10_30', 'cs_amount_outlier_10', 'ts_ff_to_total_turnover_ratio', 'ts_price_volume_trend_coherence_5_20', 'ts_ff_turnover_rate_surge_10', 'undist_profit_ps', 'ocfps', 'AR', 'BR', 'AR_BR', 'cashflow_to_ev_factor', 'book_to_price_ratio', 'turnover_rate_mean_5', 'variance_20', 'bbi_ratio_factor', 'daily_deviation', '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', 'vol_break', 'weight_roc5', 'smallcap_concentration', 'cost_stability', 'high_cost_break_days', 'liquidity_risk', 'turnover_std', 'mv_volatility', 'volume_growth', 'mv_growth', 'momentum_factor', 'resonance_factor', 'log_close', 'cat_vol_spike', 'up', 'down', 'obv_maobv_6', 'std_return_5_over_std_return_90', 'std_return_90_minus_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', 'senti_strong_inflow', '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', 'industry_obv', 'industry_return_5', 'industry_return_20', 'industry__ema_5', 'industry__ema_13', 'industry__ema_20', 'industry__ema_60', 'industry_act_factor1', 'industry_act_factor2', 'industry_act_factor3', 'industry_act_factor4', 'industry_act_factor5', 'industry_act_factor6', 'industry_rank_act_factor1', 'industry_rank_act_factor2', 'industry_rank_act_factor3', 'industry_return_5_percentile', 'industry_return_20_percentile', '000852.SH_MACD', '000905.SH_MACD', '399006.SZ_MACD', '000852.SH_MACD_hist', '000905.SH_MACD_hist', '399006.SZ_MACD_hist', '000852.SH_RSI', '000905.SH_RSI', '399006.SZ_RSI', '000852.SH_Signal_line', '000905.SH_Signal_line', '399006.SZ_Signal_line', '000852.SH_amount_change_rate', '000905.SH_amount_change_rate', '399006.SZ_amount_change_rate', '000852.SH_amount_mean', '000905.SH_amount_mean', '399006.SZ_amount_mean', '000852.SH_daily_return', '000905.SH_daily_return', '399006.SZ_daily_return', '000852.SH_up_ratio_20d', '000905.SH_up_ratio_20d', '399006.SZ_up_ratio_20d', '000852.SH_volatility', '000905.SH_volatility', '399006.SZ_volatility', '000852.SH_volume_change_rate', '000905.SH_volume_change_rate', '399006.SZ_volume_change_rate']\n",
|
||
"df最小日期: 2019-01-02\n",
|
||
"df最大日期: 2025-06-06\n",
|
||
"1091062\n",
|
||
"train_data最小日期: 2020-01-02\n",
|
||
"train_data最大日期: 2022-12-30\n",
|
||
"875950\n",
|
||
"test_data最小日期: 2023-01-03\n",
|
||
"test_data最大日期: 2025-06-06\n",
|
||
" ts_code trade_date log_circ_mv\n",
|
||
"0 000001.SZ 2019-01-02 16.574219\n",
|
||
"1 000001.SZ 2019-01-03 16.583965\n",
|
||
"2 000001.SZ 2019-01-04 16.633371\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"from main.utils.data_process import *\n",
|
||
"\n",
|
||
"split_date = '2023-01-01'\n",
|
||
"train_data = df[filter_index & (df['trade_date'] <= split_date) & (df['trade_date'] >= '2020-01-01')].groupby(\n",
|
||
" 'trade_date', group_keys=False).apply(lambda x: x.nsmallest(1500, 'total_mv'))\n",
|
||
"test_data = df[(df['trade_date'] >= split_date)].groupby(\n",
|
||
" 'trade_date', group_keys=False).apply(lambda x: x.nsmallest(1500, 'total_mv'))\n",
|
||
"\n",
|
||
"print(df[['ts_code', 'trade_date', 'log_circ_mv']].head(3))\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",
|
||
"# train_data['label'] = train_data.groupby('trade_date', group_keys=False)['future_return'].transform(\n",
|
||
"# lambda x: pd.qcut(x, q=100, labels=False, duplicates='drop')\n",
|
||
"# )\n",
|
||
"# test_data['label'] = test_data.groupby('trade_date', group_keys=False)['future_return'].transform(\n",
|
||
"# lambda x: pd.qcut(x, q=100, labels=False, duplicates='drop')\n",
|
||
"# )\n",
|
||
"\n",
|
||
"# feature_columns_new = feature_columns[:]\n",
|
||
"# train_data, _ = create_deviation_within_dates(train_data, [col for col in feature_columns if col in train_data.columns])\n",
|
||
"# test_data, _ = create_deviation_within_dates(test_data, [col for col in feature_columns if col in train_data.columns])\n",
|
||
"\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",
|
||
"# feature_columns = select_top_features_by_rankic(df, numeric_columns, n=10)\n",
|
||
"print(feature_columns)\n",
|
||
"\n",
|
||
"# train_data = fill_nan_with_daily_median(train_data, feature_columns)\n",
|
||
"# test_data = fill_nan_with_daily_median(test_data, feature_columns)\n",
|
||
"\n",
|
||
"train_data = train_data.dropna(subset=[col for col in feature_columns if col in train_data.columns])\n",
|
||
"train_data = train_data.dropna(subset=['label'])\n",
|
||
"train_data = train_data.reset_index(drop=True)\n",
|
||
"# print(test_data.tail())\n",
|
||
"test_data = test_data.dropna(subset=[col for col in feature_columns if col in train_data.columns])\n",
|
||
"# test_data = test_data.dropna(subset=['label'])\n",
|
||
"test_data = test_data.reset_index(drop=True)\n",
|
||
"\n",
|
||
"transform_feature_columns = feature_columns\n",
|
||
"transform_feature_columns = [col for col in transform_feature_columns if col in feature_columns and not col.startswith('cat') and col in train_data.columns]\n",
|
||
"# transform_feature_columns.remove('undist_profit_ps')\n",
|
||
"print('去除极值')\n",
|
||
"cs_mad_filter(train_data, transform_feature_columns)\n",
|
||
"# print('中性化')\n",
|
||
"# cs_neutralize_industry_cap(train_data, transform_feature_columns)\n",
|
||
"print('标准化')\n",
|
||
"cs_zscore_standardize(train_data, transform_feature_columns)\n",
|
||
"\n",
|
||
"cs_mad_filter(test_data, transform_feature_columns)\n",
|
||
"# cs_neutralize_industry_cap(test_data, transform_feature_columns)\n",
|
||
"cs_zscore_standardize(test_data, transform_feature_columns)\n",
|
||
"\n",
|
||
"mad_filter_feature_columns = [col for col in feature_columns if col not in transform_feature_columns and not col.startswith('cat') and col in train_data.columns]\n",
|
||
"cs_mad_filter(train_data, mad_filter_feature_columns)\n",
|
||
"cs_mad_filter(test_data, mad_filter_feature_columns)\n",
|
||
"\n",
|
||
"\n",
|
||
"print(f'feature_columns: {feature_columns}')\n",
|
||
"\n",
|
||
"\n",
|
||
"print(f\"df最小日期: {df['trade_date'].min().strftime('%Y-%m-%d')}\")\n",
|
||
"print(f\"df最大日期: {df['trade_date'].max().strftime('%Y-%m-%d')}\")\n",
|
||
"print(len(train_data))\n",
|
||
"print(f\"train_data最小日期: {train_data['trade_date'].min().strftime('%Y-%m-%d')}\")\n",
|
||
"print(f\"train_data最大日期: {train_data['trade_date'].max().strftime('%Y-%m-%d')}\")\n",
|
||
"print(len(test_data))\n",
|
||
"print(f\"test_data最小日期: {test_data['trade_date'].min().strftime('%Y-%m-%d')}\")\n",
|
||
"print(f\"test_data最大日期: {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",
|
||
"print(df[['ts_code', 'trade_date', 'log_circ_mv']].head(3))\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 126,
|
||
"id": "3ff2d1c5",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from sklearn.preprocessing import StandardScaler\n",
|
||
"from sklearn.linear_model import LogisticRegression\n",
|
||
"import matplotlib.pyplot as plt # 保持 matplotlib 导入,尽管LightGBM的绘图功能已移除\n",
|
||
"from sklearn.decomposition import PCA\n",
|
||
"import pandas as pd\n",
|
||
"import numpy as np\n",
|
||
"import datetime # 用于日期计算\n",
|
||
"from catboost import CatBoostClassifier, CatBoostRanker, CatBoostRegressor\n",
|
||
"from catboost import Pool\n",
|
||
"import lightgbm as lgb\n",
|
||
"from lightgbm import LGBMRanker, LGBMRegressor\n",
|
||
"\n",
|
||
"def train_model(train_data_df, feature_columns,\n",
|
||
" print_info=True, # 调整参数名,更通用\n",
|
||
" validation_days=180, use_pca=False, split_date=None,\n",
|
||
" target_column='label', type='light'): # 增加目标列参数\n",
|
||
"\n",
|
||
" print('train data size: ', len(train_data_df))\n",
|
||
" print(train_data_df[['ts_code', 'trade_date', 'log_circ_mv']])\n",
|
||
" # 确保数据按时间排序\n",
|
||
" train_data_df = train_data_df.sort_values(by='trade_date')\n",
|
||
"\n",
|
||
" # 识别数值型特征列\n",
|
||
" numeric_feature_columns = train_data_df[feature_columns].select_dtypes(include=['float64', 'int64']).columns.tolist()\n",
|
||
"\n",
|
||
" # 去除标签为空的样本\n",
|
||
" initial_len = len(train_data_df)\n",
|
||
" train_data_df = train_data_df.dropna(subset=[target_column])\n",
|
||
"\n",
|
||
" if print_info:\n",
|
||
" print(f'原始样本数: {initial_len}, 去除标签为空后样本数: {len(train_data_df)}')\n",
|
||
"\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",
|
||
" train_data_split = train_data_split.sort_values('trade_date')\n",
|
||
" val_data_split = val_data_split.sort_values('trade_date')\n",
|
||
"\n",
|
||
" \n",
|
||
" X_train = train_data_split[feature_columns]\n",
|
||
" y_train = train_data_split[target_column]\n",
|
||
" \n",
|
||
" X_val = val_data_split[feature_columns]\n",
|
||
" y_val = val_data_split[target_column]\n",
|
||
"\n",
|
||
"\n",
|
||
" # # 标准化数值特征 (使用 StandardScaler 对训练集fit并transform, 对验证集只transform)\n",
|
||
" scaler = StandardScaler()\n",
|
||
" # X_train = scaler.fit_transform(X_train)\n",
|
||
"\n",
|
||
" # 训练线性回归模型\n",
|
||
" # model = LogisticRegression(random_state=42)\n",
|
||
" \n",
|
||
" # # 使用处理后的特征和样本权重进行训练\n",
|
||
" # model.fit(X_train, y_train)\n",
|
||
"\n",
|
||
"\n",
|
||
" if type == 'cat':\n",
|
||
" params = {\n",
|
||
" 'loss_function': 'QueryRMSE', # 适用于二分类\n",
|
||
" 'eval_metric': 'NDCG', # 评估指标\n",
|
||
" 'iterations': 1500,\n",
|
||
" 'learning_rate': 0.03,\n",
|
||
" 'depth': 8, # 控制模型复杂度\n",
|
||
" 'l2_leaf_reg': 1, # L2 正则化\n",
|
||
" 'verbose': 5000,\n",
|
||
" 'early_stopping_rounds': 300,\n",
|
||
" 'one_hot_max_size': 50,\n",
|
||
" # 'class_weights': [0.6, 1.2],\n",
|
||
" 'task_type': 'GPU',\n",
|
||
" 'has_time': True,\n",
|
||
" 'random_seed': 7\n",
|
||
" }\n",
|
||
" cat_features = [i for i, col in enumerate(feature_columns) if col.startswith('cat')]\n",
|
||
" group_train = train_data_split['trade_date'].factorize()[0]\n",
|
||
" group_val = val_data_split['trade_date'].factorize()[0]\n",
|
||
" train_pool = Pool(\n",
|
||
" data=X_train,\n",
|
||
" label=y_train,\n",
|
||
" group_id=group_train,\n",
|
||
" cat_features=cat_features\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",
|
||
"\n",
|
||
" model = CatBoostRanker(**params)\n",
|
||
" model.fit(train_pool,\n",
|
||
" eval_set=val_pool, \n",
|
||
" plot=True, \n",
|
||
" use_best_model=True\n",
|
||
" )\n",
|
||
" elif type == 'light':\n",
|
||
" label_gain = list(range(len(train_data_split['label'].unique())))\n",
|
||
" \n",
|
||
" params = {\n",
|
||
" 'label_gain': [gain for gain in label_gain],\n",
|
||
" 'objective': 'lambdarank',\n",
|
||
" 'metric': 'ndcg',\n",
|
||
" 'learning_rate': 0.01,\n",
|
||
" 'num_leaves': 1024,\n",
|
||
" 'min_data_in_leaf': 256,\n",
|
||
" # 'max_depth': 10,\n",
|
||
" 'max_bin': 1024,\n",
|
||
" 'feature_fraction': 0.5,\n",
|
||
" 'bagging_fraction': 0.5,\n",
|
||
" 'bagging_freq': 5,\n",
|
||
" 'lambda_l1': 0.1,\n",
|
||
" 'lambda_l2': 10,\n",
|
||
" 'boosting': 'gbdt',\n",
|
||
" 'verbosity': -1,\n",
|
||
" 'extra_trees': True,\n",
|
||
" # 'max_position': 5,\n",
|
||
" 'ndcg_at': '5',\n",
|
||
" 'quant_train_renew_leaf': True,\n",
|
||
" 'lambdarank_truncation_level': 10,\n",
|
||
" # 'lambdarank_position_bias_regularization': 1,\n",
|
||
" 'seed': 7\n",
|
||
" }\n",
|
||
" feature_contri = [2 if 'concept' in feat else 1 for feat in feature_columns]\n",
|
||
" params['feature_contri'] = feature_contri\n",
|
||
"\n",
|
||
" train_groups = train_data_split.groupby('trade_date').size().tolist()\n",
|
||
" val_groups = val_data_split.groupby('trade_date').size().tolist()\n",
|
||
"\n",
|
||
" categorical_feature = [col for col in feature_columns if 'cat' in col]\n",
|
||
" train_dataset = lgb.Dataset(\n",
|
||
" X_train, label=y_train, \n",
|
||
" group=train_groups,\n",
|
||
" categorical_feature=categorical_feature\n",
|
||
" )\n",
|
||
" val_dataset = lgb.Dataset(\n",
|
||
" X_val, label=y_val, \n",
|
||
" group=val_groups,\n",
|
||
" categorical_feature=categorical_feature\n",
|
||
" )\n",
|
||
"\n",
|
||
" evals = {}\n",
|
||
" callbacks = [lgb.log_evaluation(period=3000),\n",
|
||
" lgb.callback.record_evaluation(evals),\n",
|
||
" lgb.early_stopping(300, first_metric_only=True)\n",
|
||
" ]\n",
|
||
" # 训练模型\n",
|
||
" model = lgb.train(\n",
|
||
" params, train_dataset, num_boost_round=1000,\n",
|
||
" valid_sets=[train_dataset, val_dataset], valid_names=['train', 'valid'],\n",
|
||
" callbacks=callbacks\n",
|
||
" )\n",
|
||
"\n",
|
||
" # 打印特征重要性(如果需要)\n",
|
||
" if True:\n",
|
||
" lgb.plot_metric(evals)\n",
|
||
" lgb.plot_importance(model, importance_type='split', max_num_features=20)\n",
|
||
" plt.show()\n",
|
||
"\n",
|
||
" # from flaml import AutoML\n",
|
||
" # from sklearn.datasets import fetch_california_housing\n",
|
||
"\n",
|
||
" # # Initialize an AutoML instance\n",
|
||
" # model = AutoML()\n",
|
||
" # # Specify automl goal and constraint\n",
|
||
" # automl_settings = {\n",
|
||
" # \"time_budget\": 600, # in seconds\n",
|
||
" # \"metric\": \"ndcg@1\",\n",
|
||
" # \"task\": \"rank\",\n",
|
||
" # \"estimator_list\": [\n",
|
||
" # \"catboost\",\n",
|
||
" # \"lgbm\",\n",
|
||
" # \"xgboost\"\n",
|
||
" # ], \n",
|
||
" # \"ensemble\": {\n",
|
||
" # \"final_estimator\": LGBMRanker(),\n",
|
||
" # \"passthrough\": False,\n",
|
||
" # },\n",
|
||
" # }\n",
|
||
" # model.fit(X_train=X_train, y_train=y_train, groups=train_groups,\n",
|
||
" # X_val=X_val, y_val=y_val,groups_val=val_groups,\n",
|
||
" # mlflow_logging=False, **automl_settings)\n",
|
||
"\n",
|
||
"\n",
|
||
" return model, scaler, None # 返回训练好的模型、scaler 和 pca 对象"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 127,
|
||
"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: 364000\n",
|
||
" ts_code trade_date log_circ_mv\n",
|
||
"0 600306.SH 2020-01-02 11.552040\n",
|
||
"1 603269.SH 2020-01-02 11.324801\n",
|
||
"2 002633.SZ 2020-01-02 11.759023\n",
|
||
"3 603991.SH 2020-01-02 11.181150\n",
|
||
"4 000691.SZ 2020-01-02 11.677910\n",
|
||
"... ... ... ...\n",
|
||
"363995 605218.SH 2022-12-30 11.710093\n",
|
||
"363996 603519.SH 2022-12-30 12.592329\n",
|
||
"363997 600293.SH 2022-12-30 12.593635\n",
|
||
"363998 603182.SH 2022-12-30 11.207510\n",
|
||
"363999 600749.SH 2022-12-30 12.594148\n",
|
||
"\n",
|
||
"[364000 rows x 3 columns]\n",
|
||
"原始样本数: 364000, 去除标签为空后样本数: 364000\n",
|
||
"Training until validation scores don't improve for 300 rounds\n",
|
||
"Did not meet early stopping. Best iteration is:\n",
|
||
"[728]\ttrain's ndcg@5: 0.764617\tvalid's ndcg@5: 0.577452\n",
|
||
"Evaluated only: ndcg@5\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAlEAAAHHCAYAAACfqw0dAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAd81JREFUeJzt3Xd4U1UDBvA3STO696a0hZZRNgVq2UjZIuBkyPITFEHFfqggshX8HIADwQGCA0EcoLIsZShSKLJnoXQxukv3SpP7/XFpSuigDW2Ttu/vefrYnDtyco+Ql3POPVciCIIAIiIiIqoRqbErQERERNQQMUQRERERGYAhioiIiMgADFFEREREBmCIIiIiIjIAQxQRERGRARiiiIiIiAzAEEVERERkAIYoIiIiIgMwRBFRtWzcuBESiQRxcXF19h6LFy+GRCJpMOc1tri4OEgkEmzcuNGg4yUSCRYvXlyrdSJqShiiiExMaViRSCQ4fPhwue2CIMDLywsSiQSPPPKIQe/x2WefGfzFSzWzefNmrF692tjVIKI6wBBFZKJUKhU2b95crvzQoUO4ceMGlEqlwec2JERNnDgRBQUF8Pb2Nvh9jeWtt95CQUGBUd67LkOUt7c3CgoKMHHiRIOOLygowFtvvVXLtSJqOhiiiEzU8OHDsW3bNpSUlOiVb968GYGBgXBzc6uXeuTl5QEAZDIZVCpVgxoWK627mZkZVCqVkWtzf4WFhdBqtdXeXyKRQKVSQSaTGfR+KpUKZmZmBh1LRAxRRCZr3LhxSE9PR1hYmK6suLgYP/30E8aPH1/hMVqtFqtXr0a7du2gUqng6uqK559/Hrdv39bt4+PjgwsXLuDQoUO6YcP+/fsDKBtKPHToEF588UW4uLigWbNmetvunRO1e/du9OvXD9bW1rCxsUH37t0r7EG71+HDh9G9e3eoVCq0bNkSn3/+ebl9qprzc+98ntJ5TxcvXsT48eNhb2+P3r1762279/hZs2Zh+/btaN++PZRKJdq1a4c9e/aUe6+DBw+iW7duenWtzjyr/v37Y+fOnYiPj9ddax8fH905JRIJtmzZgrfeeguenp6wsLBAdnY2MjIyMGfOHHTo0AFWVlawsbHBsGHDcObMmftenylTpsDKygo3b97E6NGjYWVlBWdnZ8yZMwcajaZa1zA6OhpTpkyBnZ0dbG1tMXXqVOTn5+sdW1BQgJdffhlOTk6wtrbGo48+ips3b3KeFTUp/CcIkYny8fFBcHAwfvjhBwwbNgyAGFiysrIwduxYfPzxx+WOef7557Fx40ZMnToVL7/8MmJjY/Hpp5/i1KlT+OeffyCXy7F69Wq89NJLsLKywvz58wEArq6ueud58cUX4ezsjIULF+p6cyqyceNGPPvss2jXrh3mzZsHOzs7nDp1Cnv27Kk06AHAuXPnMHjwYDg7O2Px4sUoKSnBokWLytXDEE8++ST8/f2xfPlyCIJQ5b6HDx/GL7/8ghdffBHW1tb4+OOP8fjjjyMhIQGOjo4AgFOnTmHo0KFwd3fHkiVLoNFosHTpUjg7O9+3LvPnz0dWVhZu3LiBVatWAQCsrKz09lm2bBkUCgXmzJmDoqIiKBQKXLx4Edu3b8eTTz4JX19fJCcn4/PPP0e/fv1w8eJFeHh4VPm+Go0GQ4YMQVBQED744APs27cPH374IVq2bIkZM2bct95PPfUUfH19sWLFCpw8eRJfffUVXFxc8L///U+3z5QpU/Djjz9i4sSJeOihh3Do0CGMGDHivucmalQEIjIpX3/9tQBAOH78uPDpp58K1tbWQn5+viAIgvDkk08KAwYMEARBELy9vYURI0bojvv7778FAML333+vd749e/aUK2/Xrp3Qr1+/St+7d+/eQklJSYXbYmNjBUEQhMzMTMHa2loICgoSCgoK9PbVarVVfsbRo0cLKpVKiI+P15VdvHhRkMlkwt1/LcXGxgoAhK+//rrcOQAIixYt0r1etGiRAEAYN25cuX1Lt917vEKhEKKjo3VlZ86cEQAIn3zyia5s5MiRgoWFhXDz5k1d2dWrVwUzM7Ny56zIiBEjBG9v73LlBw4cEAAILVq00LVvqcLCQkGj0eiVxcbGCkqlUli6dKle2b3XZ/LkyQIAvf0EQRC6dOkiBAYGlrsGFV3DZ599Vm+/MWPGCI6OjrrXJ06cEAAIs2fP1ttvypQp5c5J1JhxOI/IhD311FMoKCjAH3/8gZycHPzxxx+V9vBs27YNtra2GDRoENLS0nQ/gYGBsLKywoEDB6r9vtOmTbvvPJuwsDDk5ORg7ty55eYbVTXMpdFosHfvXowePRrNmzfXlbdt2xZDhgypdh0r88ILL1R735CQELRs2VL3umPHjrCxsUFMTIyurvv27cPo0aP1en/8/Px0vYMPavLkyTA3N9crUyqVkEqlujqkp6fDysoKrVu3xsmTJ6t13nuvQ58+fXSfy5Bj09PTkZ2dDQC6Ic8XX3xRb7+XXnqpWucnaiw4nEdkwpydnRESEoLNmzcjPz8fGo0GTzzxRIX7Xr16FVlZWXBxcalwe0pKSrXf19fX9777XLt2DQDQvn37ap8XAFJTU1FQUAB/f/9y21q3bo1du3bV6Hz3qk7dS90d4krZ29vr5pClpKSgoKAAfn5+5farqMwQFdVXq9Xio48+wmeffYbY2Fi9uUylw4xVUalU5YYb7/5c93PvdbG3twcA3L59GzY2NoiPj4dUKi1X99q6JkQNBUMUkYkbP348pk2bhqSkJAwbNgx2dnYV7qfVauHi4oLvv/++wu3VmcNT6t6eEWOprEfr3gnSd6tJ3SvrbRPuM5eqNlVU3+XLl2PBggV49tlnsWzZMjg4OEAqlWL27NnVunvP0Lv17nd8fV4XooaAIYrIxI0ZMwbPP/88jh49iq1bt1a6X8uWLbFv3z706tXrvkGiNpYpKB0GO3/+fI16IJydnWFubo6rV6+W2xYVFaX3urQHJDMzU688Pj6+hrU1jIuLC1QqFaKjo8ttq6isIoZc659++gkDBgzA+vXr9cozMzPh5ORU4/PVNm9vb2i1WsTGxur1KFb3mhA1FpwTRWTirKyssHbtWixevBgjR46sdL+nnnoKGo0Gy5YtK7etpKREL4hYWlqWCyY1NXjwYFhbW2PFihUoLCzU21ZVj4VMJsOQIUOwfft2JCQk6MovXbqEvXv36u1rY2MDJycn/PXXX3rln3322QPVvbpkMhlCQkKwfft23Lp1S1ceHR2N3bt3V+sclpaWyMrKqvH73nsNt23bhps3b9boPHWldO7ave3wySefGKM6REbDniiiBmDy5Mn33adfv354/vnnsWLFCpw+fRqDBw+GXC7H1atXsW3bNnz00Ue6+VSBgYFYu3Yt3n77bfj5+cHFxQUPP/xwjepkY2ODVatW4bnnnkP37t11azOdOXMG+fn52LRpU6XHLlmyBHv27EGfPn3w4osvoqSkBJ988gnatWuHs2fP6u373HPP4d1338Vzzz2Hbt264a+//sKVK1dqVNcHsXjxYvz555/o1asXZsyYAY1Gg08//RTt27fH6dOn73t8YGAgtm7ditDQUHTv3h1WVlZVhmEAeOSRR7B06VJMnToVPXv2xLlz5/D999+jRYsWtfSpHkxgYCAef/xxrF69Gunp6bolDkrbpSEtyEr0IBiiiBqRdevWITAwEJ9//jnefPNNmJmZwcfHB8888wx69eql22/hwoWIj4/He++9h5ycHPTr16/GIQoA/vOf/8DFxQXvvvsuli1bBrlcjjZt2uDVV1+t8riOHTti7969CA0NxcKFC9GsWTMsWbIEiYmJ5ULUwoULkZqaip9++gk//vgjhg0bht27d1c6gb62BQYGYvfu3ZgzZw4WLFgALy8vLF26FJcuXcLly5fve/yLL76I06dP4+uvv8aqVavg7e193xD15ptvIi8vD5s3b8bWrVvRtWtX7Ny5E3Pnzq2tj/XAvvnmG7i5ueGHH37Ar7/+ipCQEGzduhWtW7duEKvDE9UGicCZgkRENTZ69GhcuHChwrldTdXp06fRpUsXfPfdd5gwYYKxq0NU5zgniojoPu59ePHVq1exa9cu3eNymqKKHui8evVqSKVS9O3b1wg1Iqp/HM4jIrqPFi1aYMqUKWjRogXi4+Oxdu1aKBQKvP7668aumtG89957OHHiBAYMGAAzMzPs3r0bu3fvxvTp0+Hl5WXs6hHVCw7nERHdx9SpU3HgwAEkJSVBqVQiODgYy5cvR9euXY1dNaMJCwvDkiVLcPHiReTm5qJ58+aYOHEi5s+fDzMz/vucmgaGKCIiIiIDcE4UERERkQEYooiIiIgMwIHrCmi1Wty6dQvW1tZcNI6IiKiBEAQBOTk58PDwgFRa9/1EDFEVuHXrFu8uISIiaqCuX7+OZs2a1fn7MERVwNraGgAQGxsLBwcHI9emaVOr1fjzzz91jzAh42FbmBa2h+lgW5iOjIwM+Pr66r7H6xpDVAVKh/Csra1hY2Nj5No0bWq1GhYWFrCxseFfTkbGtjAtbA/TwbYwHWq1GkD9Pb+RE8uJiIiIDMAQRURERGQAhigiIiIiA3BOFBERUT3RarUoLi42djUaLLlcDplMZuxq6DBEERER1YPi4mLExsZCq9UauyoNmp2dHdzc3ExiHUeGKCIiojomCAISExMhk8ng5eVVLwtBNjaCICA/Px8pKSkAAHd3dyPXiCGKiIiozpWUlCA/Px8eHh6wsLAwdnUaLHNzcwBASkoKXFxcjD60xyhMRERUxzQaDQBAoVAYuSYNX2kILV0TypgYooiIiOqJKczjaehM6RoyRBEREREZgCGKiIiI6pyPjw9Wr15t7GrUKk4sJyIiogr1798fnTt3rpXwc/z4cVhaWj54pUwIQxQREREZRBAEaDQamJndP044OzvXQ43qF4fziIiIqJwpU6bg0KFD+OijjyCRSCCRSLBx40ZIJBLs3r0bgYGBUCqVOHz4MK5du4ZRo0bB1dUVVlZW6N69O/bt26d3vnuH8yQSCb766iuMGTMGFhYW8Pf3x2+//VbPn/LBMEQRERHVM0EQkF9cYpQfQRCqVcePPvoIwcHBmDZtGhITE5GYmAgvLy8AwNy5c/Huu+/i0qVL6NixI3JzczF8+HCEh4fj1KlTGDp0KEaOHImEhIQq32PJkiV46qmncPbsWQwfPhwTJkxARkbGA1/f+sLhPCIionpWoNYgYOFeo7z3xaVDYKG4/9e/ra0tFAoFLCws4ObmBgC4fPkyAGDp0qUYNGiQbl8HBwd06tRJ93rZsmX49ddf8dtvv2HWrFmVvseUKVMwbtw4AMDy5cvx8ccfIzIyEkOHDjXos9U39kQRERFRjXTr1k3vdW5uLubMmYO2bdvCzs4OVlZWuHTp0n17ojp27Kj73dLSEjY2NrrHujQE7IkiIiKqZ+ZyGS4uHWK0935Q995lN2fOHISFheGDDz6An58fzM3N8cQTT6C4uLjK88jlcr3XEomkQT2gmSGKiIionkkkkmoNqRmbQqHQPbKmKv/88w+mTJmCMWPGABB7puLi4uq4dsbH4TwiIiKqkI+PD44dO4a4uDikpaVV2kvk7++PX375BadPn8aZM2cwfvz4BtWjZCiGKCIiIqrQnDlzIJPJEBAQAGdn50rnOK1cuRL29vbo2bMnRo4ciSFDhqBr1671XNv6Z/p9iURERGQUrVq1QkREhF7ZlClTyu3n4+OD/fv365XNnDlT7/W9w3sVLbWQmZlpUD2NhT1RRERERAZgiCIiIiIyAEMUERERkQEYooiIiIgMwBBFREREZACGKCIiIiIDMEQRERERGYAhioiIiMgADFFEREREBjB6iFqzZg18fHygUqkQFBSEyMjIKvdfvXo1WrduDXNzc3h5eeHVV19FYWHhA52TiIiIap+Pjw9Wr16tey2RSLB9+/ZK94+Li4NEIsHp06frvG61waghauvWrQgNDcWiRYtw8uRJdOrUCUOGDEFKSkqF+2/evBlz587FokWLcOnSJaxfvx5bt27Fm2++afA5iYiIqH4kJiZi2LBhxq5GrTFqiFq5ciWmTZuGqVOnIiAgAOvWrYOFhQU2bNhQ4f5HjhxBr169MH78ePj4+GDw4MEYN26cXk9TTc9JRERE9cPNzQ1KpdLY1ag1RgtRxcXFOHHiBEJCQsoqI5UiJCSk3MMOS/Xs2RMnTpzQhaaYmBjs2rULw4cPN/icREREVN4XX3wBDw8PaLVavfJRo0bh2WefxbVr1zBq1Ci4urrCysoK3bt3x759+6o8573DeZGRkejSpQtUKhW6deuGU6dO1cVHqTNmxnrjtLQ0aDQauLq66pW7urri8uXLFR4zfvx4pKWloXfv3hAEASUlJXjhhRd0w3mGnBMAioqKUFRUpHudnZ0NAFCr1VCr1QZ9Pqodpdef7WB8bAvTwvYwHdVpC7VaDUEQoNVqxVAiCIA6v76qqE9uAUgk993t8ccfx0svvYTw8HAMHDgQAJCRkYE9e/bgjz/+QHZ2NoYOHYply5ZBqVTi22+/xciRI3Hp0iU0b95cd57Sz12q9Brk5ubikUceQUhICL755hvExsbi1Vdf1dunIlqtFoIgQK1WQyaT6W2r7z8PRgtRhjh48CCWL1+Ozz77DEFBQYiOjsYrr7yCZcuWYcGCBQafd8WKFViyZEm58gMHDsDCwuJBqky1JCwszNhVoDvYFqaF7WE6qmoLMzMzuLm5ITc3F8XFxYA6H3Zr2tZj7cpkzrwkBqn7kMlkuoDTvXt3AMB3330HR0dHBAYGQiqVwtfXV7f/nDlz8PPPP+PHH3/E9OnTAYiBp7CwUNc5AQAFBQXIzs7Gxo0bodFosHLlSqhUKnh5eWHmzJn473//i7y8PL1j7lZcXIyCggL89ddfKCkp0duWn1+/wdRoIcrJyQkymQzJycl65cnJyXBzc6vwmAULFmDixIl47rnnAAAdOnRAXl4epk+fjvnz5xt0TgCYN28eQkNDda+zs7Ph5eWFAQMGwNHR0dCPSLVArVYjLCwMgwYNglwuN3Z1mjS2hWlhe5iO6rRFYWEhrl+/DisrK6hUKqBYVuF+9cHG2hpQWFZr30mTJuH555/HF198AaVSiV9//RVjx46FnZ0dcnNzsWTJEuzatQuJiYkoKSlBQUEBUlNTYWNjA0CcUqNSqXSvAcDc3Bw2NjaIi4tDp06d4OLiots2YMAAAIClpaXeMXcrLCyEubk5+vbtK17Lu6Snp9foWjwoo4UohUKBwMBAhIeHY/To0QDExBoeHo5Zs2ZVeEx+fj6kUv1pXKVdeYIgGHROAFAqlRVOdJPL5fzLyUSwLUwH28K0sD1MR1VtodFoIJFIIJVKxe8xpRXw5q16rqFIWs3hPECc/zR9+nTs3r0b3bt3x99//41Vq1ZBKpXi9ddfR1hYGD744AP4+fnB3NwcTzzxBNRqtd53denn1r3/nWsguVOHe7fdvU+F9b9zbEXXu77/LBh1OC80NBSTJ09Gt27d0KNHD6xevRp5eXmYOnUqADEBe3p6YsWKFQCAkSNHYuXKlejSpYtuOG/BggUYOXKkLkzd75xERERGJ5FUuzfImFQqFR577DF8//33iI6ORuvWrdG1a1cAwD///IMpU6ZgzJgxAIDc3FzExcVV+9xt27bFt99+i8LCQl2P0tGjR2v9M9Qlo4aop59+GqmpqVi4cCGSkpLQuXNn7NmzRzcxPCEhQS+JvvXWW5BIJHjrrbdw8+ZNODs7Y+TIkXjnnXeqfU4iIiKqvgkTJuCRRx7BhQsX8Mwzz+jK/f398csvv2DkyJGQSCRYsGBBpZPBKzJ+/HjMnz8f06ZNw7x58xAXF4cPPvigLj5CnTH6xPJZs2ZVOtR28OBBvddmZmZYtGgRFi1aZPA5iYiIqPoefvhhODg4ICoqCuPHj9eVr1y5Es8++yx69uwJJycnvPHGG5VOBq+IlZUVfv/9d7zwwgvo0qULAgIC8L///Q+PP/54XXyMOmH0EEVERESmSyqV4tat8vO3fHx8sH//fr2ymTNn6r2+d3hPEAS91w899FC5R7zcu48pM/qz84iIiIgaIoYoIiIiIgMwRBEREREZgCGKiIiIyAAMUURERPWkIU2aNlWmdA0ZooiIiOpY6YLQxcXFRq5Jw1f6fLx7VyfPKypBTmFJRYfUGS5xQEREVMfMzMxgYWGB1NRUyOXySh9pQpUTBAF5eXlITU2F0sIaR2IykJpThMjYDByLzUBceh40hU3kAcRERERNhUQigbu7O2JjYxEfH2/s6jQI4rCdBCVaLQrVGhSqtcgtKkF4TC5+uRQDUxjUY4giIiKqBwqFAv7+/hzSgxiQMvKLYaOSQy6TIj23CGdvZOFUQiZu3s5HRn4xrt/Ox93Tn7QCcLtQi8ISsVAll8LBQoFefk4Y0dEdHTxtkXX7Nlqurr/PwRBFRERUT6RSqe5hu43Z7bxipOYWIS23CJcSc3DhZhYuJ+VAYSZFXlEJMvKKkZ5XDJVcCguFGTLyKg+WcpkED7VwxMA2LnC0UqJQrUE7D1u0dbeGRCLR37lIXvFJ6ghDFBERERkkKasQ525mITI2HZFxt6EykyIhIx+JWYXVOr5QrUWhWgxQ1kozjOriAU87C7RytUKAhw1UZjKo5DKYK2R1+TEMxhBFREREFcouVONIdBr+iU5HG3drWChkSMoqwsXEbFxOzMbVlNxKj5VIAE87c7R1t0EHT1u0dbeBRqtFUYlWVx6blofMfDVauljC3da8Hj9Z7WCIIiIiasLyi0tw7kYWMvKKcTQmHWduZKFQrUFWgbpaPUqeduZo6WKFRzt5QKsV0MzeHO08bWGpkMFMVvVdiO09bWvrYxgFQxQREVEjll9cggOXU3E8LgNqjRY3bhfg3M0suNmokJRdWOV8JAAwl8vg52IFOws5SjQCkrMLcf12PgYHuKGbjz0mBHlDYdY0l2xgiCIiImpECtUa/PjvdawMuwI3GxWiU3JRoi2/IMDd4cnNRgV3OxV8HS3R0sUKbdysYS6XoYWzFZysFPftUWqqGKKIiIgamEuJ2TiZcBsFxRrEpuXBwVKBi7eycSLhNjLz1br9Sn93sFRgWHs32FsocOFWFuQyKcZ08YSPkyU8bM1hY25W/k43ui+GKCIiIhOVklOIi7eykZglDrul5hThSnIOjsako4LOJT3+LlYY0MYFEx/yhpeDRf1UuIlhiCIiIjIheUUl2HUuEaevZ2LbiRsoLtFWuF8HT1u4WCthayFHTmEJAtxt4ONkAVcbFZo7WKCZPYNTXWOIIiIiMoLiEvExJudvZmHfpWScSsiEXCbBrcxCJGWX3RXXzN4cablF6NrcHq1crdHC2RL+LtYIbuloxNoTwBBFRERUr1JzirDhn1hsPX69yjvjvB0tMGuAH54IbAYAnLNkghiiiIiIaolao8XZG1lIzi6ErbkcEol4F9y/cbeRmluEnMISHI/NQIFaozvGyUqJh9s4o7e/MwRBQH6xBsPau8HOQmHET0LVwRBFRERkAEEQcDUlF//GpmNnjBRHf7uIIzEZiE/Pv++xzR0s8Obwtujl5wgLhRlkUvYyNUQMUURERFWISc3FzrOJSMjIh7O1ElkFaiRnF+HczUwkZxfd2UuKf5JvAAAUMilaOFsCEHumbmUWoktzO4S0dYW1ygw25nL08XeChYJfwQ0dW5CIiAjiRO89F5KgNJPC2VqJ747GY9/FZGQXllR6jEwqQRs3K7gKWWjTyg++zlYYHOAGWwt5PdacjIUhioiImozI2AxEJWXjVlYhribnIi49D2m5RbCQy5CWV1zpcgJt3KyRV1wCfxdrOFgqYKOSw9fJAn38neFpq8CuXbswPMQPcjnDU1PCEEVERI1OZn4xijVa3M5T40BUCrIK1IhOyUXYxeSK94da77WFQoZAb3s8EdgM3X0c4GFnXul7qdXqSrdR48YQRUREDdr1jHyk5BTh0/1Xcf5WNmxUZriWmlfhvlIJ0LOlE5o7WqCFkyXkMil8nCxhoZDBWmWG1q7WXEqAqo0hioiIGpSsfDXm/XoWJ+MzkVWg1lsuABDXYbqbl4M5OjWzgwDghb4t0aGZbT3WlhozhigiIjJpSVmF+Dc+A+ZyGfKLNfgmIg7H426X2y/A3QZvjWiL2/lqdPC0ha25HAKEO+s1sXeJah9DFBERmZxCtQZzfz6Lw9FpSM8rhnDPw3aVZlJ88GQneNip4GqjgpOVEkozKcMS1SuGKCIiMqqsfDXW/XUNtzILYG+hQLFGi4OXU3Arq+z5cf4uVsgtKtFN+H6uTwu0crU2Yq2JGKKIiKieRafkYPOx6zgel4FbmQXIKSxBsab80gJOVko82a0ZxvdoDi8HCyPUlKhqDFFERFSnsvLV2B+VjIu3snEpMQf/XEsrNzzn5WCOIF9H2KjkuJ1fjI7NbDGuR3Oo5DLjVJqoGhiiiIio1gmCgJ9P3sSO0zcRcS0dJVr91BTS1hUD2jijs5cdlGZStHS24nwmanAYooiIyCCFag2iU3JRrNEiJjUPj3R0R3ahGjvPJuL9vVHILy5besDeQg53W3M82tkDw9u7o7kjh+eo4WOIIiKiGjkRfxtbIhNwODoNiXdN/p6z7Uy5fcf18ML4Ht5cm4kaJYYoIiIqRxAEqDUC/o3PwNXkXIRfTkF8eh5KNAJuZhZUeWw7DxsEt3DEsA5uCPR2qKcaE9U/higiItI5mXAby3dewtmbWdBoBWjumcsEAHKZBK3drPFwG1c80bUZknMK4WFnjivJObBRydG1uR3nN1GTwBBFRNREZReKD+VVyKTY9u91bIqIr3A/iQTo6++MHr4O8HWyRDcfe7hYq3TbS+c3eVbxkF6ixoghioioiRAEAak5RbiUlINP91+t8NEpAODrZImFjwTA39UKHrbmEADIpOxZIrqX1NgVAIA1a9bAx8cHKpUKQUFBiIyMrHTf/v37QyKRlPsZMWKEbp8pU6aU2z506ND6+ChERCbnVmYBFu04D7/5u9FjeTgmb4gsF6CslGbo5eeIP17qjQNz+mNAGxc0s7eAVCphgCKqhNF7orZu3YrQ0FCsW7cOQUFBWL16NYYMGYKoqCi4uLiU2/+XX35BcXGx7nV6ejo6deqEJ598Um+/oUOH4uuvv9a9ViqVdfchiIhMjCAI0ArA8l2X8E1EHNQa/blNQb4OmDe8LTo1s+X8JSIDGT1ErVy5EtOmTcPUqVMBAOvWrcPOnTuxYcMGzJ07t9z+Dg76d3ps2bIFFhYW5UKUUqmEm5tb3VWciMjE5BaV4FTCbXx24BpOJtxGUUnZo1SCWzjiicBmsDGXw9POHAEeNkasKVHjYNQQVVxcjBMnTmDevHm6MqlUipCQEERERFTrHOvXr8fYsWNhaWmpV37w4EG4uLjA3t4eDz/8MN5++204OjrWav2JiOqTcOdZKRKJBGqNFmczJNj/0znkq7WIT8/DtdS8cnfTWSvNsOjRdngisJkxqkzUqBk1RKWlpUGj0cDV1VWv3NXVFZcvX77v8ZGRkTh//jzWr1+vVz506FA89thj8PX1xbVr1/Dmm29i2LBhiIiIgExW/jlMRUVFKCoq0r3Ozs4GAKjVaqjVakM+GtWS0uvPdjA+toVxCIKAmLR8ZOQVY3V4NK4k56KtuzVi0/KQlC0DkFjumEFtXfDqQD8ozKTwsFNBLpOy3eoQ/2yYjvpuA6MP5z2I9evXo0OHDujRo4de+dixY3W/d+jQAR07dkTLli1x8OBBDBw4sNx5VqxYgSVLlpQrP3DgACws+GgCUxAWFmbsKtAdbIu6p9ECx9MkyCiSIDpLgms5+nOWImIyAACWZgI6OghoZinAVgE4KAW4WwBSyS1cPXELAHCh3mvfdPHPhvHl5+fX6/sZNUQ5OTlBJpMhOTlZrzw5Ofm+85ny8vKwZcsWLF269L7v06JFCzg5OSE6OrrCEDVv3jyEhobqXmdnZ8PLywsDBgzgEKCRqdVqhIWFYdCgQZDL5cauTpPGtqhbao0W8en5OHQ1DRuPxCMpu6jcPv4ulujt5wQJAF9HFaSJFzBmONvD2Phnw3Skp6fX6/sZNUQpFAoEBgYiPDwco0ePBgBotVqEh4dj1qxZVR67bds2FBUV4Zlnnrnv+9y4cQPp6elwd3evcLtSqazw7j25XM4/ECaCbWE62Ba1K7eoBDtO38Tnh2KQkKH/r2iVXIqeLZ0wf0RbuFgrYaU0091Jp1arsWvXBbaHCWFbGF99X3+jD+eFhoZi8uTJ6NatG3r06IHVq1cjLy9Pd7fepEmT4OnpiRUrVugdt379eowePbpcT1Fubi6WLFmCxx9/HG5ubrh27Rpef/11+Pn5YciQIfX2uYiIqpKVr8aynRfx04kbeuUtnCzR088R0/q0gLejZSVHE5EpMHqIevrpp5GamoqFCxciKSkJnTt3xp49e3STzRMSEiCV6q8JGhUVhcOHD+PPP/8sdz6ZTIazZ89i06ZNyMzMhIeHBwYPHoxly5ZxrSgiMhqNVsBnB6Kx73IKJABOX8/UbVOYSTG9TwuMC2rOR6cQNSBGD1EAMGvWrEqH7w4ePFiurHXr1rpbfe9lbm6OvXv31mb1iIgMEp+eh9Afz0AC4NzNLL11mwBAIZPitSGtMaarJ5ys+I88oobGJEIUEVFjUVSiwWcHruGj8KsVbp85oCVUZjK087RBLz8nKM3KL7tCRA0DQxQR0QPILSrBv3EZiE3Lw6+nbuLsjSy97f4uVni6uxdcbFRo42aNVq7WRqopEdU2higiomq4cTsfKTlFcLdVYUvkdaTkFOJYTAZi0vLK7WutMkNnLztM7eWDAa1d+Gw6okaKIYqIqBIXb2Xjv9vO4EZGPnKKSirdz9VGCTtzBXr5OeGxrp7wc7GCSs5hOqLGjiGKiAhAQno+NvwTi7M3MqHRCrBQmCEyLkP3LDqJBCi9nyXQ2x49fB2QlFWIAHcbPPOQN8wVDE1ETQ1DFBE1eWsORGNl2JVyD+8FgH6tnDG5pzd6+DpCAiAjrxjN7M05REdEDFFE1PQkZhXgVmYhfj11A0eupSMmtWxek5+LFZo7WKCzlx0GBbiirbuN3rGWSv61SUQi/m1ARE2CRivgYFQKvj0aj4NRqeW2vxrSCi8P9GMPExFVG0MUETVKWq2AI9fSceRaGo7GpONyUg7yizV6+3TwtMX0vi3g62SJ9p62RqopETVUDFFE1ChotAJ+OnEdv59JRG5RCRIy8pGRV6y3j43KDGN7NMeTgc2QmFWIHr4OvIuOiAzGEEVEDdbNzALsOZ+E3ecS8W/87XLbrZVm6NDMFg+1cISHnTn6t3bWPV7Fn4teEtEDYogiIpMnCALyijVIzi7E2RuZyCvS4N+4DPx25hbuvaGumb05HuvaDK1crTCwjSuXHiCiOsMQRUQmK6tAjec2HcfxuPK9TKU87cwxuJ0r/F2s8VhXTw7PEVG9YYgiIpOTnluEzw5ew7Z/ryO7sPxK4XKZBJ525njpYX881tWTd9QRkVEwRBGRycgvLkHYxWQs+u0CMvPVuvKOzWzx8sP+aONuDTsLBay4VhMRmQD+TURERiUIAs7cyMLCHedx9kaWrtzNRoVXB/ljYFtX3WRwIiJTwhBFRPXqzwtJ2Hr8OnKLSnDjdgGyCtTIvevhvtYqM0wI8sazvXzgYqMyYk2JiKrGEEVEtS4zvxinrmfiVPxttHSxQr9Wzpiz7SzO3MhEak5RhccE+Tpg4cgAtHWzgVTKOU5EZPoYooioVh2LScfEDZEoLtFWuk8PHwcMbe8GOws5vB0t4O9qDRuVvB5rSUT04BiiiKhWRKfkYs2BaPx66qauzFIhQ95dj1pp6WyJj8Z24SNWiKhRYIgiohq7mpwDQFz1u6BYg9X7ruDLv2N0C186WytxYE5/WCnNcPFWNtLziiCTStCzpZMRa01EVLsYooioUoVqDTYfS8DFxGy4WSsQe0OChcv3I6tAnAguk0qguWvJcE87c/Txd8LMAX66ZQgCPGyMUnciorrGEEVEFTpyLQ3jvzx2T6kMQNmddKUBqrmDBRY+EoCQANf6qyARkZExRBGRnqwCNV7bdgZ/XkzWldlZyJFTWAKNVoBMKsHyMe0xtL07rmfkQyaVoJWrNWS8o46ImhiGKKImLiWnEDtO3YKZTILuPg7YdCROF6A87czxeGAzhA5qBbVajR+278KIIYPgaGMBALDlBHEiasIYooiasMz8Yoz69B8kZhWW29a3lTM2Te2u91w6WwVgY86lCIiIAEBq7AoQkXFk5BVj8obICgPUwDYu2DilOx/sS0RUBfZEETURf11JxYn42wCAH/+9rgtP9hZyfPdcENq42aBEq0VGXjHcbFQMUERE98EQRdQEbPwnFot/v1iu3N1WhW//0wN+LtYAAJlUBndb8/quHhFRg8QQRdTIpecWYcXuywAAfxcryKQSxKfn4+nuXpg3vA2UZjIj15CIqGFiiCJqpARBwM5ziXjjp7MoKtGiUzNbbJ/Zi8N0RES1hCGKqBE6GJWCpX9cRExqHgBAYSbFm8PbMkAREdUihiiiRuarv2Pw9s5LAAC5TIJxPZpj1sN+cLFWGblmRESNC0MUUSNwMCoF4ZdSsPdCElJyinTl+0L7wdvR0og1IyJqvBiiiBqo9Nwi5BSWIDI2A/O3n4NaU/Yg4Ke6NcPSUe2hknPSOBFRXWGIImpA1Botfj5xAz9EJuDMjawK93n5YT/MDmkFKZ9lR0RUpxiiiBqA3KISnIy/jW8i4rDvUoreNguFDH39nfHu4x1gZ6EwUg2JiJoehigiEyYIArYcv47/7bmMzHy13rbuPvZYNro92rjZGKl2RERNG0MUkQlbe+ga3tsTpXvdytUK80cEILiFIxRmfPQlEZExMUQRmZDcohLcvF2A747GY/f5RKTlFgMAQge1wuOBzeBmo4KMc52IiEwCQxSRCfgnOg1v77yEK8k50GgFvW2Tgr3x8kB/I9WMiIgqYxLjAWvWrIGPjw9UKhWCgoIQGRlZ6b79+/eHRCIp9zNixAjdPoIgYOHChXB3d4e5uTlCQkJw9erV+vgoRNUiCAJKNFqsPXgN/vN3YcJXx3ApMVsXoCQSoF8rZ3w9tTuWPNrOyLUlIqKKGL0nauvWrQgNDcW6desQFBSE1atXY8iQIYiKioKLi0u5/X/55RcUFxfrXqenp6NTp0548skndWXvvfcePv74Y2zatAm+vr5YsGABhgwZgosXL0Kl4qrNZHyLf7uATRHxemXjejTHC/1awEJhBoWZFLbmciPVjoiIqsPoIWrlypWYNm0apk6dCgBYt24ddu7ciQ0bNmDu3Lnl9ndwcNB7vWXLFlhYWOhClCAIWL16Nd566y2MGjUKAPDNN9/A1dUV27dvx9ixY+v4ExFVTBAERFxLx9Z/r2PH6Vu68snB3pj1sD+crZVGrB0REdWUUUNUcXExTpw4gXnz5unKpFIpQkJCEBERUa1zrF+/HmPHjoWlpfhoi9jYWCQlJSEkJES3j62tLYKCghAREcEQRfVOEAQUlWgx9+ez2H5XeOruY4+XHvZHH38nPhiYiKgBMmqISktLg0ajgaurq165q6srLl++fN/jIyMjcf78eaxfv15XlpSUpDvHvecs3XavoqIiFBWVPW8sOzsbAKBWq6FWqys8hupH6fVvqO1wLTUPEzccR2pusV75u2Pa4bEuHpBIJCgpKTFS7WqmobdFY8P2MB1sC9NR321g9OG8B7F+/Xp06NABPXr0eKDzrFixAkuWLClXfuDAAVhYWDzQual2hIWFGbsKNRKfC/waJ0Nsjn4P09gWGgS5CJAmncHu3WeMVLsH09DaorFje5gOtoXx5efn1+v7GTVEOTk5QSaTITk5Wa88OTkZbm5uVR6bl5eHLVu2YOnSpXrlpcclJyfD3d1d75ydO3eu8Fzz5s1DaGio7nV2dja8vLwwYMAAODo61uQjUS1Tq9UICwvDoEGDIJc3jInW20/fwrrfLyG/WAMAaO5gjjmD/NHGzRq+TpZGrp3hGmJbNGZsD9PBtjAd6enp9fp+Rg1RCoUCgYGBCA8Px+jRowEAWq0W4eHhmDVrVpXHbtu2DUVFRXjmmWf0yn19feHm5obw8HBdaMrOzsaxY8cwY8aMCs+lVCqhVJaf1CuXy/kHwkQ0hLbIylfjo/Cr2PBPLAAg0Nseq57qDC8H80Y156khtEVTwvYwHWwL46vv62/04bzQ0FBMnjwZ3bp1Q48ePbB69Wrk5eXp7tabNGkSPD09sWLFCr3j1q9fj9GjR5frKZJIJJg9ezbefvtt+Pv765Y48PDw0AU1opoSBAGZ+WpM3HAMSjMZ5g5rA7lMit3nE5GRW4z0vGIcvpqGYo0WAGCtNMOGyd1ha8G/UImIGiujh6inn34aqampWLhwIZKSktC5c2fs2bNHNzE8ISEBUqn+mqBRUVE4fPgw/vzzzwrP+frrryMvLw/Tp09HZmYmevfujT179nCNKDLYNxHxWPTbBd3rJ9dVfveouVyGjc/2YIAiImrkjB6iAGDWrFmVDt8dPHiwXFnr1q0hCEL5ne+QSCRYunRpuflSRIY4Ep2mF6AAQCWXQiaRwNVWBa1WwCMdPfBIJ3e0cbOBIAiNaviOiIgqZhIhisjUFJVocPhqGnKLSrBwR1mA+umFYAR626PkzuNZ5LLyT05igCIiahoYoojukplfjO+PJeDrf+KQllukt23/f/uhhbMVAEAuY1AiImrqGKKoSSsdFl617yryi0oQEZOOC7eyddutlWZ4tLMHJgZ76wIUERERwBBFTVhBsQbjvzqKUwmZeuUKmRR9Wznj+X4tENjcHlIpe52IiKg8hihqkgRBwDu7LpYLUHKZBB+P64yh7d0rPpCIiOgOhihqMvKKShCfno/sQjV2nL6JHyKvAwD6+DshpK0rBrdzhcpMBntLhZFrSkREDQFDFDUJPx6/jiW/X0DenUexAIBEAiwe2Q6Te/oYr2JERNRgMURRo5WSXYjD0Wk4FpOBrf+KvU52FnI4WCrgZKnE8/1aYGBbVyPXkoiIGiqGKGp0olNy8eGfUdh9PkmvPKStC76c1I3rOBERUa1giKJG5WZmAZ76PAIZecUAAAdLBRwsFRjRwR0vDmjJAEVERLWGIYoajf2XkxH64xlk5qvh5WCOryZ1R2s3a2NXi4iIGimGKGrwolNy8eO/1/HFXzEAgHYeNvhobBf4uXBxTCIiqjsPFKLy8vLw448/Ijo6Gu7u7hg3bhwcHR1rq25EVcovLsHqfVex/nAsNHeeZdfDxwHfPRcEhVn5Z9oRERHVphqFqICAABw+fBgODg64fv06+vbti9u3b6NVq1a4du0ali1bhqNHj8LX17eu6ksEANBqBUxaH4l/428DAPxdrDC6iyee7eXLAEVERPWiRiHq8uXLKCkpAQDMmzcPHh4eOH36NGxtbZGbm4sxY8Zg/vz52Lx5c51Ulpq2QrUG8en5OHItDe/tiUKBWgOlmRRrxndFSACXKiAiovpl8HBeREQE1q1bB1tbWwCAlZUVlixZgrFjx9Za5YgAQBCA9NwiTN54ElHJOXrbljzajgGKiIiMosYhqvQW8cLCQri76z9fzNPTE6mpqbVTMyKIk8aXnpIh4+ihctv2hfaFnwvvviMiIuOocYgaOHAgzMzMkJ2djaioKLRv3163LT4+nhPLqVYUqjX48M8ofPl3LAAJJBLA2UqJMV088W/8bTzdzYsBioiIjKpGIWrRokV6r62s9G8h//3339GnT58HrxU1aZcSszHso791r+USAXtf7YMWLrZGrBUREZG+BwpR93r//fcfqDJEgiDglS2n9MrG+WnhZW9hpBoRERFVjPeCk8mIT8/DM+uP4UpyLgDg8a7NcH7hQAQ6CUauGRERUXkGhai4uDhMmTIF7u7uMDc3R4cOHfDtt9/Wdt2oCUnJKcS4L47in+h0AMDLD/vhw6c6QSmXGblmREREFatxiIqIiMBDDz2E5s2b459//kFGRgbWrl2L999/H+vXr6+LOlIjJwgCXt16GreyCuFkpcTikQF4eaC/satFRERUpRrNicrIyMBjjz2GDRs2YPjw4bry3r17Y8uWLRg2bBj+85//YOzYsfj444/h4uJS6xWmxiO7UI01B6Kx6UgcCtVaAMBXk7uhs5edcStGRERUDTUKUZ988gkGDBiA4cOHo3379sjPz9fbfuPGDaSmpsLV1RVLly7Fp59+WquVpcbhVmYBEjLy8eav5xCTmqcr93a0YIAiIqIGo0bDeX/88QfGjx8PAPjvf/8LlUqFt99+G6tWrYKvry/mzp0LR0dHzJo1C1u3bq2TClPDdiL+Nnq+ux9jvziqC1C+TpYY2MYFX07qZuTaERERVV+NeqLi4+PRokULAGKv1Nq1a9GvXz8AQN++fdG8eXMsWLAA/v7+yMrKQlJSEtzc3Gq/1tSgJGcXYs62M4hJzUNmfrGuvIWzJX58PhhOVkoj1o6IiMgwNQpR5ubmyMjIAACkpKRAKi3ryJJIJMjPz0deXh7kcjm0Wi3MzAx+NB81Eum5RRi95h8kZhXqyhQyKcb18MKsh/0ZoIiIqMGqUcrp1KkTTpw4gd69e2PMmDGYPn06Fi9eDAsLC6xevRo9e/aEo6Mjjh8/DicnJzg5OdVVvakByMgrRvCK/SjWiJPGH27jgqm9fNCzpRNkUomRa0dERPRgajQnasKECfj000+h0Wjw4YcfYvz48Vi5ciUWLlyIgIAAbN++HYA41Dd27Ni6qC81EIIgYPFvF3QBavNzQdgwpTv6+DszQBERUaNQo56op556CmvXrsWMGTPw+eefY8GCBViwYIHePuvXr0d4eDjOnDlTqxUl05aVr8bu84k4lZCJvOISWCrM8NuZW5BKgC8ndUNPP/ZKEhFR41KjECWRSPDzzz/j0UcfRd++ffHmm28iODgY5ubmOHfuHD799FPs378fO3fu5FBeE6HVCsgrLsE7uy7ix39vlNv+akgrDGzraoSaERER1a0az/x2dHTEX3/9ha+++grvvPMOzp07B41GAz8/P4wePRpnz56FnZ1dHVSVTElsWh7GfhGB5OyicttauVqJyxa0dcUTXZsZoXZERER1z6Db52QyGZ5//nk8//zztV0fagAy84vxn03HKwxQUW8PhdKMz7sjIqLGj2sQULWVaLTYcvw63tp+Xlf2WBdPZBaosf9yCl4Z6M8ARURETYZBIapLly6QSMrfYSWRSKBSqeDn54cpU6ZgwIABD1xBMh2r9l3BmgPXdK9/eiEY3XwcUKjW4FRCJh5q4WDE2hEREdWvGi1xUGro0KGIiYmBpaUlBgwYgAEDBsDKygrXrl1D9+7dkZiYiJCQEOzYsaO260tGkpJdiG8j4gEAbdysETqoFbr5iKFJJZchuKVjhcGaiIiosTKoJyotLQ3//e9/yy1v8PbbbyM+Ph5//vknFi1ahGXLlmHUqFG1UlEynhPxt/HmL+eQXViC1q7W2PlyH671RERETZ5BPVE//vgjxo0bV6587Nix+PHHHwEA48aNQ1RU1IPVjozuq79j8PjaI4hKzoG9hRxfTApkgCIiIoKBPVEqlQpHjhyBn5+fXvmRI0egUqkAAFqtVvc7NTx5RSUY+elhxKTmAQDsLeTY/UpfuNmyTYmIiAADQ9RLL72EF154ASdOnED37t0BAMePH8dXX32FN998EwCwd+9edO7cudYqSvXrf3su6wIUAKx4rCMDFBER0V0MGs5766238OWXXyIyMhIvv/wyXn75ZURGRuLLL7/E/PnzAQAvvPACfv/99/uea82aNfDx8YFKpUJQUBAiIyOr3D8zMxMzZ86Eu7s7lEolWrVqhV27dum2L168GBKJRO+nTZs2hnzMJuurv2PwzZ1J5B+N7YzYFcMxtL2bkWtFRERkWgxeJ2rChAmYMGFCpdvNzc3ve46tW7ciNDQU69atQ1BQEFavXo0hQ4YgKioKLi4u5fYvLi7GoEGD4OLigp9++gmenp6Ij48vt0J6u3btsG/fPt1rMzMuh1Vd529m4e2dlwAAE4KaY1RnTyPXiIiIyDQZlC6OHz8OrVaLoKAgvfJjx45BJpOhW7du1TrPypUrMW3aNEydOhUAsG7dOuzcuRMbNmzA3Llzy+2/YcMGZGRk4MiRI5DL5QAAHx+fcvuZmZnBzY09JzWx4/RN7DqXiL0XkgEAD7VwwLJR7Y1cKyIiItNlUIiaOXMmXn/99XIh6ubNm/jf//6HY8eO3fccxcXFOHHiBObNm6crk0qlCAkJQURERIXH/PbbbwgODsbMmTOxY8cOODs7Y/z48XjjjTcgk5WtlH316lV4eHhApVIhODgYK1asQPPmzSutS1FREYqKyh5hkp2dDQBQq9VQq9X3/SwNWaFagwU7LmL7mURdmbXKDB883h4aTQk0GiNWDtBd/8beDg0B28K0sD1MB9vCdNR3GxgUoi5evIiuXbuWK+/SpQsuXrxYrXOkpaVBo9HA1dVVr9zV1RWXL1+u8JiYmBjs378fEyZMwK5duxAdHY0XX3wRarUaixYtAgAEBQVh48aNaN26NRITE7FkyRL06dMH58+fh7W1dYXnXbFiBZYsWVKu/MCBA7CwsKjW52mIkguAr6/IkJhftmSBi0rAo95FOHF4vxFrVl5YWJixq0B3sC1MC9vDdLAtjC8/P79e38+gEKVUKpGcnIwWLVrolScmJtbp/COtVgsXFxd88cUXkMlkCAwMxM2bN/H+++/rQtSwYcN0+3fs2BFBQUHw9vbGjz/+iP/85z8VnnfevHkIDQ3Vvc7OzoaXlxcGDBgAR0fHOvs8xnQ7vxhDP/4HGfliane1UeLjpzuha3M741bsHmq1GmFhYRg0aJBuCJeMg21hWtgepoNtYTrS09Pr9f0MSjyDBw/GvHnzsGPHDtja2gIQ75p78803MWjQoGqdw8nJCTKZDMnJyXrlycnJlc5ncnd3h1wu1xu6a9u2LZKSklBcXAyFQlHuGDs7O7Rq1QrR0dGV1kWpVEKpVJYrl8vljfIPRHahGkt2RiEjTw0/Fytsfi4ILjamvXxBY22LhohtYVrYHqaDbWF89X39DVri4IMPPsD169fh7e2te3aer68vkpKS8OGHH1brHAqFAoGBgQgPD9eVabVahIeHIzg4uMJjevXqhejoaGi1Wl3ZlStX4O7uXmGAAoDc3Fxcu3YN7u7uNfiEjVeJRosn10Zg51lxDtSKxzqYfIAiIiIyRQaFKE9PT5w9exbvvfceAgICEBgYiI8++gjnzp2Dl5dXtc8TGhqKL7/8Eps2bcKlS5cwY8YM5OXl6e7WmzRpkt7E8xkzZiAjIwOvvPIKrly5gp07d2L58uWYOXOmbp85c+bg0KFDiIuLw5EjRzBmzBjIZLIKH1PTFG08Eoeo5BwoZFJ8PjEQ3e88RJiIiIhqxuAJTJaWlpg+ffoDvfnTTz+N1NRULFy4EElJSejcuTP27Nmjm2yekJAAqbQs53l5eWHv3r149dVX0bFjR3h6euKVV17BG2+8odvnxo0bGDduHNLT0+Hs7IzevXvj6NGjcHZ2fqC6NgbfHY3XrQE1Z0grDGnHZSCIiIgMVe0Q9dtvv1X7pI8++mi19501axZmzZpV4baDBw+WKwsODsbRo0crPd+WLVuq/d5NiVqjxcqwKwCAsd298FzvFvc5goiIiKpS7RA1evRovdcSiQSCIOi9LqUx9uJCVM7hq2nIyCuGk5UCb49uD6lUcv+DiIiIqFLVnhOl1Wp1P3/++Sc6d+6M3bt3IzMzE5mZmdi1axe6du2KPXv21GV9yQB5RSVY9oe4fteIDu4wkxk0FY6IiIjuYtCcqNmzZ2PdunXo3bu3rmzIkCGwsLDA9OnTcenSpVqrID0YQRDw1vbziEnLg5uNCq8OamXsKhERETUKBoWoa9eulXvoLwDY2toiLi7uAatEtSW/uASzt5zGnxeTIZNK8PG4LrCzqHgpCCIiIqoZg8Z1unfvjtDQUL2FMpOTk/Haa6+hR48etVY5Mtz5m1kIWLgXf14U2yh0UCv08OVyBkRERLXFoBC1YcMGJCYmonnz5vDz84Ofnx+8vLxw8+ZNfPXVV7VdRzLAJ/uv6n6fFOyNGf1aGrE2REREjY9Bw3l+fn44e/Ys9u3bp5v/1LZtW4SEhOjdpUfGcSAqBXsviD1QX03qhpAA1/scQURERDVl8GKb+/fvx4EDB5CSkgKtVovTp0/jhx9+ACD2VFH9yypQQyIB3vr1PABgSk8fBigiIqI6YlCIWrJkCZYuXYpu3brB3d2dvU9GEp2SCw87FX4/cwtv/HxOb5vSTIpZD/sZqWZERESNn0Ehat26ddi4cSMmTpxY2/Whatp3MRnPffNvpdtf6NcSTlbKeqwRERFR02JQiCouLkbPnj1ruy5UDbfzivHJ/mhs+CdWr9zZWol3H+uA9p62cLZSgp2DREREdcugEPXcc89h8+bNWLBgQW3Xh6qQV1SC8V8dw6XEbF3ZiA7uKNFqsXxMBziy54mIiKjeGBSiCgsL8cUXX2Dfvn3o2LEj5HK53vaVK1fWSuVI329nbukFqPFBzbF8TAcj1oiIiKjpMihEnT17Fp07dwYAnD9/Xm8bJ5nXDUEQsOP0TQDAqyGtMK2vL8zlMiPXioiIqOkyKEQdOHCgtutB97HzXCKOxmQAAAYFuMJCYfDqFERERFQLDFqxnOrXjtM3MWvzKQDA1F4+CPCwMXKNiIiIiN0ZJiw+PQ9ymRTz7yyeaaU0w7O9fI1cKyIiIgIYokxObFoefohMwPG4DJxKyNSV+7tYYefLfaAwY+chERGRKWCIMhGFag3+u+0Mdp5NrHD7fwe3YoAiIiIyIfxWNhG/nrpZaYB6a0RbDG3vXs81IiIioqqwJ8oIzlzPxMYjccgpVCOnsATP9WmBr/6OAQA81tUTy0a1R1J2IVyslbBWye9zNiIiIjIGhigjeHf3ZUTEpOteH4sVly6QSIDXh7SBpdIMLZ2tjFU9IiIiqgYO59UzQRBwKSm7wm2Pd20GN1tVPdeIiIiIDMGeqHokCAKSsguRma8GALwxtA2+PxaPRzt5ICTAFZ2b2Rm3gkRERFRtDFH1aNW+q/g4/CoAwM/FCjP6t8SM/i2NXCsiIiIyBENUPdBoBby1/Rx+iLyuK+vt52TEGhEREdGD4pyoOpCaU4TcohLd6wOXU/QClJlUgpGdPIxRNSIiIqol7ImqZdcz8jH8o78BABuf7Y5AbwfsPFe2/tO6ZwLRw9cBDpYKY1WRiIiIagF7omrZukPXkFNUgpyiEjy+NgKHr6Zh38VkAMBPLwRjaHs3BigiIqJGgD1RtSgrX41t/97QK3tm/TEAgLO1El2b2xujWkRERFQH2BNViy7cykKxRgsvB3M836+F3rZ2HjaQSiVGqhkRERHVNoaoWnQlOQcA0MbNBm8MaYMDc/rrtvVs6WikWhEREVFd4HBeLTp3U1yJvJWrFaRSCXydLLHr5T7Ycfomxgd5G7l2REREVJsYomrJrcwC7D4v3oXX289ZVx7gYYMADxtjVYuIiIjqCEPUA0rJLsT87ecRducOvE7NbPFQCwcj14qIiIjqGudEPaD/7YnSBSgAeGdMB0gknEBORETU2DFEPQBBEPDX1VTd63nD2qC9p60Ra0RERET1hcN5D+BqSi5Sc4qgkktxeuFgqOQyY1eJiIiI6gl7oh7A4atpAIDuPg4MUERERE0Me6IMkF9cgmMxGTgakw4ACOYaUERERE0OQ5QBPg6PxrpD13Svu3jxcS5ERERNjdGH89asWQMfHx+oVCoEBQUhMjKyyv0zMzMxc+ZMuLu7Q6lUolWrVti1a9cDnbOm7g5QMqkEHZpxMjkREVFTY9QQtXXrVoSGhmLRokU4efIkOnXqhCFDhiAlJaXC/YuLizFo0CDExcXhp59+QlRUFL788kt4enoafM6ayi8ugezOM/D6t3bG+090hJWSHXpERERNjVFD1MqVKzFt2jRMnToVAQEBWLduHSwsLLBhw4YK99+wYQMyMjKwfft29OrVCz4+PujXrx86depk8DlrQhAEDPvob2i0Alyslfh6Snc81rXZA5+XiIiIGh6jdaEUFxfjxIkTmDdvnq5MKpUiJCQEERERFR7z22+/ITg4GDNnzsSOHTvg7OyM8ePH44033oBMJjPonABQVFSEoqIi3evsbPEZeGq1Gmq1Wld+43YB4tPzAQB25nKUlJQY9uGp2kqv/93tQMbBtjAtbA/TwbYwHfXdBkYLUWlpadBoNHB1ddUrd3V1xeXLlys8JiYmBvv378eECROwa9cuREdH48UXX4RarcaiRYsMOicArFixAkuWLClXfuDAAVhYWOheX82SABCXMgi2zSo3F4vqTlhYmLGrQHewLUwL28N0sC2MLz8/v17fr0FN5tFqtXBxccEXX3wBmUyGwMBA3Lx5E++//z4WLVpk8HnnzZuH0NBQ3evs7Gx4eXlhwIABcHQsW77gp5M3gYsX0KmZLeZP7MHHu9QDtVqNsLAwDBo0CHK53NjVadLYFqaF7WE62BamIz09vV7fz2ghysnJCTKZDMnJyXrlycnJcHNzq/AYd3d3yOVyyGRlC1u2bdsWSUlJKC4uNuicAKBUKqFUKsuVy+VyvT8Qt7LEIb92nrZQKBT3/5BUa+5tCzIetoVpYXuYDraF8dX39TfaxHKFQoHAwECEh4fryrRaLcLDwxEcHFzhMb169UJ0dDS0Wq2u7MqVK3B3d4dCoTDonNUlCILuQcMB7jYPdC4iIiJq+Ix6d15oaCi+/PJLbNq0CZcuXcKMGTOQl5eHqVOnAgAmTZqkN0l8xowZyMjIwCuvvIIrV65g586dWL58OWbOnFntcxoqNbcIl5NyIJUAIzt6PNC5iIiIqOEz6pyop59+GqmpqVi4cCGSkpLQuXNn7NmzRzcxPCEhAVJpWc7z8vLC3r178eqrr6Jjx47w9PTEK6+8gjfeeKPa5zTU9Qxxspq7rTlsLdhdS0RE1NQZfWL5rFmzMGvWrAq3HTx4sFxZcHAwjh49avA5DXXjdgEAoJm9ea2el4iIiBomoz/2paGY/+t5AICXg8V99iQiIqKmgCGqGlKyC5FbJC6s2YnPySMiIiIwRFXL9TtDeQDwzEPeRqwJERERmQqGqGq4cVucVB7k68AFNomIiAgAQ1S1lE4q9+SkciIiIrqDIeo+rqXm4v29UQCAZvacVE5EREQihqj7eGLtEd3vXN6AiIiISjFEVUGjFXA7X617zRBFREREpRiiqpCSU6j3upkdh/OIiIhIxBBVheSsIt3vjpYKuNupjFgbIiIiMiUMUVVIzBZ7otq4WWP/f/tDLuPlIiIiIhFTQRWSssWeqLbuNnzoMBEREelhiKpC8p2eKA8O4xEREdE9GKKqkJhVGqJ4Vx4RERHpY4iqQvKd4TwPW4YoIiIi0scQVYUk9kQREZkWrRa48ieQfavi7YIg/jRmggAU5Zb/nIZ8bkEACrNrp17GVpgFyflf6vUtzer13RqYrMISSJUKzokiIqotWg0gaIH8DMDatWbHpl8DPukq/i5TAl49gOCZQNYN4GoYkHYFuB0LyC2A5g8BI1YCDr5Vn1MQgJgDgIUj4N5Jf1vmdeDCr4C1O9BuDCAz8CtTqwHU+YDSuur9CjIBlS1QcBtIPg84+gFRuwC/EMDOG8iIARKOAjtDgZJCQCIVr6WlMyA3B7ITgf5zgY5PA3ZeVdfn2gGgMBOI/Qs4uQkwUwFTdwOeXYHEM2JdHVqU7R/3N+DUGrBxr8Hn1gInNgAKK6DDk4BUVvl+JQXAwRVAwjFg0FLAKwjISxGvhZ03oLAo2/d2rFg/K5eyc9yOAz7qBLOi+g3QDFH34WajgrWKd+YRkZHkZ4g/Tn4Pdp6bJ4GCDMC3v+FhwBAlxUDYQuDY2vLb5BbAgPmARxfxC929M6C0AiLWiGHByR/IiAVSLgIt+gMxh8qO1RSJX+xxf5c/rzofuLYf+Liz+NqplfgemdfFgAAB8B8khqar+4CEO4/3mvirWN9fpwPFeYC2pOycJ74GujwDtBigHyRKiiC5uAPO2VchiZYDNm5i+Dm7FUg6B3QaC3w9TAx9/ecCHZ4A7JqXHa/ViJ/38h/A9WM1u7aCVvxvXmpZ2f5l4o9UDgx+W/ycRdkAJEDUbiDyC/E9i7L0z1VSCPz0LNDvDWDHi+K5B78DnP8JuHWqbL+WD4vXMD9dDEZ9XwecW4lhVJ0vXmNze+D0d+Jxl34Xj7sdB/SaDZgpxWC0+w2xrRPPioGx5K7Frb8eql83uYUYpAqzgJzSHkgJEPAokJkA5CQBOYk1u3a1RCIIjb3fs+ays7Nha2sLr9k/on8Hb3zzbA9jV6nJUqvV2LVrF4YPHw65nGHWmBpMW2i14pdRzEHxX6yWzkDLAUDLgYBEUr1zlBSJf9kbW9w/wMbh4u9OrYERHwC/PA+0GQ71w0uw689w/fZIOg/8MVvszbBrDji3EXtnsm+JPRoAYOkC9H5VvDYJEYC6ELDxEHt1mj8kfvaT3wKDl4khpiqCAFwLF3uCki+I79duDGDhULbPyW+B32bV7nV56EUxjER+CZzbph92fPsCAaOAo+uA9KsP/l4OLcUvaHW++NrMHPAbCHh0BmyaAZGf64eM6ujwlNhTFLUHSLlQ8zq1eURsn+hwsX0jv6j5OVS2gKM/kHha//oZysoNyE2qxo4SAHUXOzKbhcB+2i/IysqCjY1Nnb1PKYaoCtwdol4c3AFzh7UxdpWarAbzxd0EmFRb3PgX+PUFQGEpfoF3Hgf0mwukRgG3TgK75lRwkET8cm89HHDrIPYoFOeK4eLib0BalFimKQbijwBdJgAeXQF7b3E4JeYgIJEBvn3E8CCRiMMv538GnFsDPr1r9hlKisQeptJejaJc8V/c0jtTVbUaYKlDpYcLTq2xx+0lhPRoA3n2dbE3YvfrNavD/bxyVvz8Wi3w1/uAlbPY+6C0Fuv751tiD829Rq8FPAPFnpif/6O/7YkNgLkDcD0SOLtF7PG4HVf+HLbNAe+e4nU+84MYgi2dgD5zxJ6PUlk3xJ8re8VhLJc7f18X54m9HVf2AN2eFXtOFJaA1Ayw8RSHxO7m6K8fumybAz2mAb1eBpIvAn/OF3u3qiBYOEGSn1bxRntfMbhWpstEwLU9UJwDtB4h/j+Vny7+v3Z4FWDvA7QZAQga8fe73fhX7KVxbCn23BVmieH21HdlvVWlPLuJPWLNg8WeoMIs8f/r5PPAby+L7yk1E/8RobQBmnUTA19RDpAeLYZKx5bAby9VeS10vB4Sh+Iqu3ZtHhGHDY99Lr7vjH/EYb+CTLFcbi62bUaM2M7H1orXx7Or2LYuAeK1yogBuj+HdJkLnJycGKKM6e4Q9fMrA9Hdp/K/yKhumdQXdxNn9LaIOwyELxNDzq1TqMt/zZZj4QTc++Vo5QrkJpe9fi5c/MKpzOFVwOkfgAnbxGDy/ZPA1T+B7tPE4Z89b4j7ObUShy5ykoDkc4bVN3AqkJsCRO0sK5v0mzh89cNYsQcKEENip7Fi2Ek8AySd1T+PTx9g2Htib8X2GZW/n6Wz/pBSRabuFoNVRT18WTfFL0htiRiaLJ3v3wv2oBKOAvsWiz12vn3FobrUK2IPTWVztYpyxLlEJ74W62umAgpuQ9N5IiJvFKPbU69BnnJWHMJqNwbIui4GlBb9xcBSlCMGu4SjZb2dncaKYaH949XvKa2u1CviXKNbp8SA4t1LDGC18T6ln3/fInGouMOTgEYt9tLZ+4hzzAStGIgKs4GD74o9nlYuYmj2HyT+f17aa1mUIx5v8WDft+np6QxRxnZ3iIr632MwV1QyGY7qnNG/uA1VnC8Ob3h1N3ZNak2FbZF+TfzXqpVzzU4mCGLPjlMrwNazrLx0Am5+OpAWLX753DwB/P4ykHq5/Hmq+vKeuluceOvoL/Y4HXoPiN4nBpbUS+J7VMTWC2g1BDj+Vc0+EwA8skrs9SiVekWsX/ZN4JdpZeU2zYDsG9U7Z5dngEdWAx93Eb+UR6wU55z8NLXi/f8TJg7NAeJdbFvGA49+DHQeX7aPulDs0VBYlpUJgtgbkZ8uhqo/36pe/UZ+BAROEdsu5SKw7p4eOWsPYNZxMUQ0Ug3276lGqL5DFCeW34dKzlUgyAC/Pg9c+g149FOg60Rj16ZiJzaKcyokEnFCb8+XK59wXHAbkqv7Ibl7ZODu+TpKG3E4ok+o+AV/7104giDOK/llutiTdPcEWue2Ytd8QoTYJV8pidh1L5ECFvbAk5vE4a+SQvFf2TmJQMol8V+53r2AZoFlh1o6AqPXlL3OSxcnOyssxJ6InCSg/zyxJ0QmF8NF0AxxKCE3SZx8LDcX3z8/HciMB1zaisNCUbuAiM8A9Z3ho4JMsS6Xd1UelCoql8jEYROJVAwk/oPFIUX3zmIbTdohzm3y7QMA0F4Jg/TsZggSKSQzIsTeolZDAXO7snO2GgwsrGB4SV7BHccSiTjMCYjh1d4XCFtQ1ibmDsDzf4mToI+tBZr3FIfmSocjpTLx+JdOAmt7iu0SNEMcEmvEAYqaNvZEVaC0J8rvtZ9w9b3HjV2dJs0k/oUXc0j8Yru4Q/ySdWwJNOsh3u2TcU38Mi1VUgSc3ixO7i018mMgcHLV76EuAOL/EQOFracYBn59Xhxi8R8MPPF1xV9EJUXi5NpWQ8TbsJVW4tDI0c/EXiKJBAgYDXR6uuyYW6fF+USpl/TP1esV8dbiUtf2i7c/H/tcN6n2kvtj8Bs9F/LT3wARn1b+efrMEScv3zop9gDFHxF7PgzVrDvw8AKgRT/Dz1GXtFrg29FA7KHK92nziDi36vzPYht0fxbo+Yo4TOY/SAwbNaDOSkLCdy/B+5HXYOZdRze/aDXi/0eplwG39nfd8q4V/9+qbFgoL038f/PuXsZGzCT+niIA7IkyKeZm7IVq0uKPAL+/It79Uo5E/FJJOgd0Gg8MmAfILYHPHhLXNrnb76+IPQjZN8SJyx2eECfVhi8V5wyo8/Xv7lHa6t9+fPVPIDpMnGMRHyEOzxRkiIFHUwzsf1uc9KqwAsZ8Lk4uzr5ZdnzULvE28MyEO5Mzr+vXr/T9Ij4DukwSe21iDgLbpuLeeUdtE38B1t6zmJ17J3F+xN3DY39/IP5UpNuz4nBnYabYE6ZVA779xPkQts0A72DAraM4ifjaAbFnJWB07c8XqU1SqTiZetNIMVgDgMIaGLdZnFdUmAmo7MTP0O2eYbgJPxr2nhaOON/sGTT36PIgNa+aVCZO4r57IjdQNvm9MpZOdVcnIhPCEFUFBUNU45V0XhwCsvMS707592uxN6d0YvC1/cC3Y6o4gSAGKAA4s1n8kZqV3Srs6Cd+qR5dC1z4BTj0rlh+6jvx3Ge3Vn5b8b3rtwDAzv+KvV93r58StlB/n+JcYOsE/TKfPmKAOvVtxe/18FtA39fKJjl/Gli2gB8gBqxmgYBXEIRT30FybwB7chPQbrT4e8FtcfL39UjxbqrSuUrNuovzjDqNE9eYuXvIsKQIkCkqD0j3Bg5TZusJvHxS/L307r1S5vbGqRMR1SmGqCqYyzmh3ChyksX5RLfjIEu9ApVqhDi/4vdZ4powDi2AqbvKr1abEXvnVt9MYOAiwExR/tyld8ec/r78tiMfA1N2ineM/HDXJNxh74vnb/+YGH40xeJdVpoi/eNLQ9GgpeLQGCDeeluYdef23ju9One/t08fcQ5Os+7i77GHxFvJAXFi9K3TwN55Yi/PqoCy42yaiSFFUySu+9OsW9k6QIB4R5X/YPEumYg1YpAryhXv1HHrKPYeefcUbz8GgCHLxV4frVoMUBIp0PZRYMSHul4FjVdPmH07Utz/sa8Aazfd/BwAYlBoO1L8GTBfHP508hPvyKqMKazFVBdMudeMiGoNQ1QVlAxR9S8jBvi8350VdsWHOw6QHYa0WZG4pgwgruXygT8w87gYQG6eEIew7h5OMrcTe1jupikB9s6vOEABYlD7aqB+We9QIGh62evSnqoe04ETm8QF9059J85nAoCxm8W1XEqpbIGJv4hzntQFwOqO4jowTq3E1ZFtm+m/n28foOdLYmhz7yRO7t07r2y7pQswdIU4JJifId5K7T9IXOgu9pB463VuqnhHV+mdVz1niT9VcfIXb70/u1W83bvTuHJBQGgejEifWeja62GY+Q+s5ER3yFX687CIiBohhqgqqDicVz+ybwHnfxHv2Lr0W7nNCk0+hEMryh+3porlA/a/Lc67sW0mLroXe0i8vb0iU3eLjx4oXacHEB/RMGmHOD+nIq7tgOHvib/beADfPyUGo9bDK95fbi7+vHJanGvVamjFPWWAGLxKn+Fl4w4sSAf+WS2GxIcXlD1DysJBf8J6ywHij6GqcXyifQ8IPn0Nfw8iokaEIaoKHM6DuGDf6e+BrpMfeBE0HXWhuAZN1C7g6e+AbVPEW8arICm4Lf4y5nPxrrXKDFkhzhXSqoHDKyvex7ktMORt8fEZIz4Uh7W8ewKuAeLcoJJC8ZlTlQWoe7XoD4ReFEPS/YZxLJ3E5z3VhMwM6FvRCtxERGRMDFFVmHN7MXDTvuo5HY2VIIjzh74aKN7VlZcGDHmnds67dUJZr9CXlfR8vHoB2DMX2rx0SEsfDmrpLA6VvRYjLr7oFSSuY1MqeBYQ/KI4F+jTStrspZPinCqJBHj9mv42377A/CTxc6tqeGss70YiImpyGKKq0LboLLB+MLCwkpWNGxutVpxULDMTJ3DfvcLy6c1iiDq9WZwM7D9EXBfHxhN4alP5c8X+Jc7fKX2OVam/P6x4WG3CT2JYS4gQ5xvZNgOe/g6ajOvI+WIYbMzNIHlklfjMLiWAsXfmNbl3Ep+XFjCqLMg4+QGvx4pLB5iZi3OQki+Kk6wdW1Z9DSSSmgcoIiJqkhii7qc2nm5dE+nXxGdy1fcKv1qNOKE7+Zx4K/2NSP3tBRni3Vblnp91XJwEbe8j3kmmshHvRts0Unyu0puJZWvKnNkK7F8m/j78A/GxGqWP8mgxQAxv3e95WKm1Gw62fafyRexa9Kt4AUYLBwB3hh8tHcs/sJOIiOgBMURVxzejxFu+J/wsPundqVX5x1rUhuQL4nOn3DoAz+2v/BEcdeHmibKHnd4boEr9OKni8lPfiXee3buCdUmhOFz3/CFxkvef88XyjmPF1ZnbPSZO5i4NUERERA0Iv7mqI+ag+N+fpgIXt1fvMR6GOLFRHE5LPANcCxcXf6xNgiA+bdu9o7g0gFYLxB4U1xw6vKriY5xaiQskHlunX27rVbbydem6RhVJPA0sti17bdMMGHUnbFk6Ao8b8JBXIiIiE8AQVRMXt5f9tyYhSqsFIJT1Xl2PFOcWtRst3tl17QDww1ix56ZU6uXaD1HHvwJ2zQE6TwAGLQPeb6G/XSIFLJzEx5Z0fBro9h+geZA4POfRtWzl69JVqhOOAhsqqaO5gzgEeK/HvxIDHBERUQPHEGUIpXX19y3MAj7tLt7x5d5JXFPo/M/ithNfi48HSY8uf1zYQnEC9lPflD0yIu4fcait58uGDSf+eedOttPfV7zg5Oh1FS+QqLIVyzs9Ld76X/qU+GbdxefGKSyBAW+Kj/CwcRefYm+mFCeXb36q7Dz/CQO86uhBqURERPWMIcoQF3eIoaiqMJV8AVDaiAEpN1ksS4gov9/dAcqzm/hw1h0viq9j/wIubBefH3boPeDAnSUGrh0QV7uuSZDKThQf+VGZ7s9Vb4Xp0gAFiO8/Zm3l+7QaAizMEB9PorCq/8nyREREdYghylB/hAKPfyn+fm+gSrsq3ummVQOu7Ss+vssz4oRsHYm4QnZBhnhXW+nQ3h+zgZyksgfYAuLq20sdxOAz+B3xERv3U/rIFEc/QKMuW9yyzxxxBezeodX51DUnlYnPWCMiImpkGKIMde5HoN8b4npKh94Fxm0FWg8Vt0V+IQYoAEg+X3bMa9fEp9tDIt6dFjQDKM4VJ5J3f04MHEorYPpBIGwRcHWveNzdAepux78CUi4Doz8D7L0rr2tJEfD3nYnj3r2AYf8DUi6Kz5JrHvQgV4GIiKjJ4sPhHsSRj8sCzrlt4n/zM8S77O4VOEVcDLLnS+LDYM2UgFt7oPlDQNDz+kNzLm3FBSzvXSm99XAxiN0t/jCw855eJEEAbp0SwxMgDiMWZQESGTB4mfh4Es9ABigiIqIHYBIhas2aNfDx8YFKpUJQUBAiIytZpwjAxo0bIZFI9H5UKv3hrClTppTbZ+jQobVT2Ydmlv1+ZW/Z77qepwuAphiwbQ5M2Vm2vTTQVJfcHJi2X5wjpbACer0iPjfu7seLKO8sHRC9D/j9FbFnCQAu/wF80R94xx346wNg91yxvNM4cZI4ERERPTCjD+dt3boVoaGhWLduHYKCgrB69WoMGTIEUVFRcHFxqfAYGxsbREVF6V5LKnjo69ChQ/H111/rXiuVytqpcPBMwKu7+NDc3KSy8swEcdmCyC/E186tAZ/ewKjPgEP/M3zO0SOrxJ+7vXBYfIxJhyeBpXfu3DuxUeypunUKOLhCLBM0ZSuEA+I8LCIiIqoVRg9RK1euxLRp0zB16lQAwLp167Bz505s2LABc+fOrfAYiUQCN7eqJysrlcr77lNjcgvAykVcaPJet07pPxKl9BltXSaIP7XJrYP4A4gLf/7+svj73csJ3Kvva+LQIREREdUKo4ao4uJinDhxAvPmzdOVSaVShISEICKiguUA7sjNzYW3tze0Wi26du2K5cuXo127dnr7HDx4EC4uLrC3t8fDDz+Mt99+G46OjhWer6ioCEVFZcNt2dnZ5fZRTz8szinSArB0x/2WiyxxaQ9Brb7PXrWg43hIrD1htvlxvWKtR1doJvwK3I6DpKQIgmdXoKSenwNYC9R3rqG6Pq4lVYltYVrYHqaDbWE66rsNJIIgCPX6jne5desWPD09ceTIEQQHB+vKX3/9dRw6dAjHjh0rd0xERASuXr2Kjh07IisrCx988AH++usvXLhwAc2aNQMAbNmyBRYWFvD19cW1a9fw5ptvwsrKChEREZDJyq+ttHjxYixZsqRcedZca9goxaHCHV2+0ds27OwMKDR5yJc7wkKdris/2Xw6tBIZbto/BFQwzFhXvNL/RtcEccmFaOehuNBsfL29NxERkSnIz8/H+PHjkZWVBRsbmzp/vwYXou6lVqvRtm1bjBs3DsuWLatwn5iYGLRs2RL79u3DwIEDy22vqCfKy8tLL0Sp56fpHSO5fhTSv/4HzaB3IMm+CdmBZSh5dC3gqt8jVu/y0sQVzuviAclGoFarERYWhkGDBkEu5+NijIltYVrYHqaDbWE60tPT4e7uXm8hyqjDeU5OTpDJZEhOTtYrT05OrvZ8Jrlcji5duiA6uoJHp9zRokULODk5ITo6usIQpVQq7zvxvNwfjBZ9gBZ9xNsbPTsBbYffd4ivXti5G7sGdUIul/MvJxPBtjAtbA/TwbYwvvq+/kZd4kChUCAwMBDh4eG6Mq1Wi/DwcL2eqapoNBqcO3cO7u6Vh4cbN27o0ikRERFRbTD6OlGhoaH48ssvsWnTJly6dAkzZsxAXl6e7m69SZMm6U08X7p0Kf7880/ExMTg5MmTeOaZZxAfH4/nnnsOgDjp/LXXXsPRo0cRFxeH8PBwjBo1Cn5+fhgyZIhRPiMRERE1PkZf4uDpp59GamoqFi5ciKSkJHTu3Bl79uyBq6srACAhIQFSaVnWu337NqZNm4akpCTY29sjMDAQR44cQUBAAABAJpPh7Nmz2LRpEzIzM+Hh4YHBgwdj2bJltbdWFBERETV5Rg9RADBr1izMmjWrwm0HDx7Ue71q1SqsWrWqwn0BwNzcHHv37q10u0Hq6uG8RERE1GCZRIgyVRqpCnjxEODU2thVISIiIhPDEFUFiVAiPgyYiIiI6B5Gn1huyqRCw1vhm4iIiOoHQxQRERGRARiiiIiIiAzAEEVERERkAIYoIiIiIgMwRBEREREZgCGqCiWWfNYeERERVYwhqgppI9YbuwpERERkohiiquLQwtg1ICIiIhPFEFUFmVRi7CoQERGRiWKIqgJDFBEREVWGIaoK1iq5satAREREJoohioiIiMgADFFEREREBmCIIiIiIjIAQxQRERGRARiiiIiIiAzAEEVERERkAIYoIiIiIgMwRBEREREZgCGKiIiIyAAMUUREREQGYIgiIiIiMgBDFBEREZEBGKKIiIiIDMAQRURERGQAhigiIiIiAzBEERERERmAIYqIiIjIAAxRRERERAZgiCIiIiIyAEMUERERkQEYooiIiIgMwBBFREREZACGKCIiIiIDMEQRERERGYAhioiIiMgADFFEREREBmCIIiIiIjKASYSoNWvWwMfHByqVCkFBQYiMjKx0340bN0Iikej9qFQqvX0EQcDChQvh7u4Oc3NzhISE4OrVq3X9MYiIiKgJMXqI2rp1K0JDQ7Fo0SKcPHkSnTp1wpAhQ5CSklLpMTY2NkhMTNT9xMfH621/77338PHHH2PdunU4duwYLC0tMWTIEBQWFtb1xyEiIqImwughauXKlZg2bRqmTp2KgIAArFu3DhYWFtiwYUOlx0gkEri5uel+XF1dddsEQcDq1avx1ltvYdSoUejYsSO++eYb3Lp1C9u3b6+HT0RERERNgZkx37y4uBgnTpzAvHnzdGVSqRQhISGIiIio9Ljc3Fx4e3tDq9Wia9euWL58Odq1awcAiI2NRVJSEkJCQnT729raIigoCBERERg7dmy58xUVFaGoqEj3Ojs7GwCgVquhVqsf+HOS4UqvP9vB+NgWpoXtYTrYFqajvtvAqCEqLS0NGo1GrycJAFxdXXH58uUKj2ndujU2bNiAjh07IisrCx988AF69uyJCxcuoFmzZkhKStKd495zlm6714oVK7BkyZJy5QcOHICFhYUhH41qWVhYmLGrQHewLUwL28N0sC2MLz8/v17fz6ghyhDBwcEIDg7Wve7Zsyfatm2Lzz//HMuWLTPonPPmzUNoaKjudXZ2Nry8vDBgwAA4Ojo+cJ3JcGq1GmFhYRg0aBDkcrmxq9OksS1MC9vDdLAtTEd6enq9vp9RQ5STkxNkMhmSk5P1ypOTk+Hm5latc8jlcnTp0gXR0dEAoDsuOTkZ7u7ueufs3LlzhedQKpVQKpUVnpt/IEwD28J0sC1MC9vDdLAtjK++r79RJ5YrFAoEBgYiPDxcV6bVahEeHq7X21QVjUaDc+fO6QKTr68v3Nzc9M6ZnZ2NY8eOVfucRERERPdj9OG80NBQTJ48Gd26dUOPHj2wevVq5OXlYerUqQCASZMmwdPTEytWrAAALF26FA899BD8/PyQmZmJ999/H/Hx8XjuuecAiHfuzZ49G2+//Tb8/f3h6+uLBQsWwMPDA6NHjzbWxyQiIqJGxugh6umnn0ZqaioWLlyIpKQkdO7cGXv27NFNDE9ISIBUWtZhdvv2bUybNg1JSUmwt7dHYGAgjhw5goCAAN0+r7/+OvLy8jB9+nRkZmaid+/e2LNnT7lFOYmIiIgMZfQQBQCzZs3CrFmzKtx28OBBvderVq3CqlWrqjyfRCLB0qVLsXTp0tqqIhEREZEeoy+2SURERNQQMUQRERERGYAhioiIiMgADFFEREREBmCIIiIiIjIAQxQRERGRARiiiIiIiAzAEEVERERkAIYoIiIiIgMwRBEREREZgCGKiIiIyAAMUUREREQGMIkHEJsaQRAAADk5OZDL5UauTdOmVquRn5+P7OxstoWRsS1MC9vDdLAtTEdOTg6Asu/xusYQVYH09HQAgK+vr5FrQkRERDWVnp4OW1vbOn8fhqgKODg4AAASEhLqpRGoctnZ2fDy8sL169dhY2Nj7Oo0aWwL08L2MB1sC9ORlZWF5s2b677H6xpDVAWkUnGqmK2tLf9AmAgbGxu2hYlgW5gWtofpYFuYjtLv8Tp/n3p5FyIiIqJGhiGKiIiIyAAMURVQKpVYtGgRlEqlsavS5LEtTAfbwrSwPUwH28J01HdbSIT6ug+QiIiIqBFhTxQRERGRARiiiIiIiAzAEEVERERkAIYoIiIiIgMwRFVgzZo18PHxgUqlQlBQECIjI41dpUZlxYoV6N69O6ytreHi4oLRo0cjKipKb5/CwkLMnDkTjo6OsLKywuOPP47k5GS9fRISEjBixAhYWFjAxcUFr732GkpKSurzozQ67777LiQSCWbPnq0rY1vUn5s3b+KZZ56Bo6MjzM3N0aFDB/z777+67YIgYOHChXB3d4e5uTlCQkJw9epVvXNkZGRgwoQJsLGxgZ2dHf7zn/8gNze3vj9Kg6fRaLBgwQL4+vrC3NwcLVu2xLJly/Seycb2qBt//fUXRo4cCQ8PD0gkEmzfvl1ve21d97Nnz6JPnz5QqVTw8vLCe++9V/PKCqRny5YtgkKhEDZs2CBcuHBBmDZtmmBnZyckJycbu2qNxpAhQ4Svv/5aOH/+vHD69Glh+PDhQvPmzYXc3FzdPi+88ILg5eUlhIeHC//++6/w0EMPCT179tRtLykpEdq3by+EhIQIp06dEnbt2iU4OTkJ8+bNM8ZHahQiIyMFHx8foWPHjsIrr7yiK2db1I+MjAzB29tbmDJlinDs2DEhJiZG2Lt3rxAdHa3b59133xVsbW2F7du3C2fOnBEeffRRwdfXVygoKNDtM3ToUKFTp07C0aNHhb///lvw8/MTxo0bZ4yP1KC98847gqOjo/DHH38IsbGxwrZt2wQrKyvho48+0u3D9qgbu3btEubPny/88ssvAgDh119/1dteG9c9KytLcHV1FSZMmCCcP39e+OGHHwRzc3Ph888/r1FdGaLu0aNHD2HmzJm61xqNRvDw8BBWrFhhxFo1bikpKQIA4dChQ4IgCEJmZqYgl8uFbdu26fa5dOmSAECIiIgQBEH8QyaVSoWkpCTdPmvXrhVsbGyEoqKi+v0AjUBOTo7g7+8vhIWFCf369dOFKLZF/XnjjTeE3r17V7pdq9UKbm5uwvvvv68ry8zMFJRKpfDDDz8IgiAIFy9eFAAIx48f1+2ze/duQSKRCDdv3qy7yjdCI0aMEJ599lm9sscee0yYMGGCIAhsj/pyb4iqrev+2WefCfb29np/R73xxhtC69ata1Q/Dufdpbi4GCdOnEBISIiuTCqVIiQkBBEREUasWeOWlZUFoOzBzydOnIBardZrhzZt2qB58+a6doiIiECHDh3g6uqq22fIkCHIzs7GhQsX6rH2jcPMmTMxYsQIvWsOsC3q02+//YZu3brhySefhIuLC7p06YIvv/xStz02NhZJSUl6bWFra4ugoCC9trCzs0O3bt10+4SEhEAqleLYsWP192EagZ49eyI8PBxXrlwBAJw5cwaHDx/GsGHDALA9jKW2rntERAT69u0LhUKh22fIkCGIiorC7du3q10fPoD4LmlpadBoNHpfBgDg6uqKy5cvG6lWjZtWq8Xs2bPRq1cvtG/fHgCQlJQEhUIBOzs7vX1dXV2RlJSk26eidirdRtW3ZcsWnDx5EsePHy+3jW1Rf2JiYrB27VqEhobizTffxPHjx/Hyyy9DoVBg8uTJumtZ0bW+uy1cXFz0tpuZmcHBwYFtUUNz585FdnY22rRpA5lMBo1Gg3feeQcTJkwAALaHkdTWdU9KSoKvr2+5c5Rus7e3r1Z9GKLIqGbOnInz58/j8OHDxq5Kk3T9+nW88sorCAsLg0qlMnZ1mjStVotu3bph+fLlAIAuXbrg/PnzWLduHSZPnmzk2jU9P/74I77//nts3rwZ7dq1w+nTpzF79mx4eHiwPUiHw3l3cXJygkwmK3fnUXJyMtzc3IxUq8Zr1qxZ+OOPP3DgwAE0a9ZMV+7m5obi4mJkZmbq7X93O7i5uVXYTqXbqHpOnDiBlJQUdO3aFWZmZjAzM8OhQ4fw8ccfw8zMDK6urmyLeuLu7o6AgAC9srZt2yIhIQFA2bWs6u8nNzc3pKSk6G0vKSlBRkYG26KGXnvtNcydOxdjx45Fhw4dMHHiRLz66qtYsWIFALaHsdTWda+tv7cYou6iUCgQGBiI8PBwXZlWq0V4eDiCg4ONWLPGRRAEzJo1C7/++iv2799frks1MDAQcrlcrx2ioqKQkJCga4fg4GCcO3dO7w9KWFgYbGxsyn0RUeUGDhyIc+fO4fTp07qfbt26YcKECbrf2Rb1o1evXuWW+rhy5Qq8vb0BAL6+vnBzc9Nri+zsbBw7dkyvLTIzM3HixAndPvv374dWq0VQUFA9fIrGIz8/H1Kp/lekTCaDVqsFwPYwltq67sHBwfjrr7+gVqt1+4SFhaF169bVHsoDwCUO7rVlyxZBqVQKGzduFC5evChMnz5dsLOz07vziB7MjBkzBFtbW+HgwYNCYmKi7ic/P1+3zwsvvCA0b95c2L9/v/Dvv/8KwcHBQnBwsG576W31gwcPFk6fPi3s2bNHcHZ25m31teDuu/MEgW1RXyIjIwUzMzPhnXfeEa5evSp8//33goWFhfDdd9/p9nn33XcFOzs7YceOHcLZs2eFUaNGVXhrd5cuXYRjx44Jhw8fFvz9/XlLvQEmT54seHp66pY4+OWXXwQnJyfh9ddf1+3D9qgbOTk5wqlTp4RTp04JAISVK1cKp06dEuLj4wVBqJ3rnpmZKbi6ugoTJ04Uzp8/L2zZskWwsLDgEge14ZNPPhGaN28uKBQKoUePHsLRo0eNXaVGBUCFP19//bVun4KCAuHFF18U7O3tBQsLC2HMmDFCYmKi3nni4uKEYcOGCebm5oKTk5Pw3//+V1Cr1fX8aRqfe0MU26L+/P7770L79u0FpVIptGnTRvjiiy/0tmu1WmHBggWCq6uroFQqhYEDBwpRUVF6+6Snpwvjxo0TrKysBBsbG2Hq1KlCTk5OfX6MRiE7O1t45ZVXhObNmwsqlUpo0aKFMH/+fL1b4tkedePAgQMVfkdMnjxZEITau+5nzpwRevfuLSiVSsHT01N49913a1xXiSDctfwqEREREVUL50QRERERGYAhioiIiMgADFFEREREBmCIIiIiIjIAQxQRERGRARiiiIiIiAzAEEVERERkAIYoIiIAPj4+WL16tbGrQUQNCEMUEdW7KVOmYPTo0QCA/v37Y/bs2fX23hs3boSdnV258uPHj2P69On1Vg8iavjMjF0BIqLaUFxcDIVCYfDxzs7OtVgbImoK2BNFREYzZcoUHDp0CB999BEkEgkkEgni4uIAAOfPn8ewYcNgZWUFV1dXTJw4EWlpabpj+/fvj1mzZmH27NlwcnLCkCFDAAArV65Ehw4dYGlpCS8vL7z44ovIzc0FABw8eBBTp05FVlaW7v0WL14MoPxwXkJCAkaNGgUrKyvY2NjgqaeeQnJysm774sWL0blzZ3z77bfw8fGBra0txo4di5ycHN0+P/30Ezp06ABzc3M4OjoiJCQEeXl5dXQ1iai+MUQRkdF89NFHCA4OxrRp05CYmIjExER4eXkhMzMTDz/8MLp06YJ///0Xe/bsQXJyMp566im94zdt2gSFQoF//vkH69atAwBIpVJ8/PHHuHDhAjZt2oT9+/fj9ddfBwD07NkTq1evho2Nje795syZU65eWq0Wo0aNQkZGBg4dOoSwsDDExMTg6aef1tvv2rVr2L59O/744w/88ccfOHToEN59910AQGJiIsaNG4dnn30Wly5dwsGDB/HYY4+Bjyslajw4nEdERmNrawuFQgELCwu4ubnpyj/99FN06dIFy5cv15Vt2LABXl5euHLlClq1agUA8Pf3x3vvvad3zrvnV/n4+ODtt9/GCy+8gM8++wwKhQK2traQSCR673ev8PBwnDt3DrGxsfDy8gIAfPPNN2jXrh2OHz+O7t27AxDD1saNG2FtbQ0AmDhxIsLDw/HOO+8gMTERJSUleOyxx+Dt7Q0A6NChwwNcLSIyNeyJIiKTc+bMGRw4cABWVla6nzZt2gAQe39KBQYGljt23759GDhwIDw9PWFtbY2JEyciPT0d+fn51X7/S5cuwcvLSxegACAgIAB2dna4dOmSrszHx0cXoADA3d0dKSkpAIBOnTph4MCB6NChA5588kl8+eWXuH37dvUvAhGZPIYoIjI5ubm5GDlyJE6fPq33c/XqVfTt21e3n6Wlpd5xcXFxeOSRR9CxY0f8/PPPOHHiBNasWQNAnHhe2+Ryud5riUQCrVYLAJDJZAgLC8Pu3bsREBCATz75BK1bt0ZsbGyt14OIjIMhioiMSqFQQKPR6JV17doVFy5cgI+PD/z8/PR+7g1Odztx4gS0Wi0+/PBDPPTQQ2jVqhVu3bp13/e7V9u2bXH9+nVcv35dV3bx4kVkZmYiICCg2p9NIpGgV69eWLJkCU6dOgWFQoFff/212scTkWljiCIio/Lx8cGxY8cQFxeHtLQ0aLVazJw5ExkZGRg3bhyOHz+Oa9euYe/evZg6dWqVAcjPzw9qtRqffPIJYmJi8O233+omnN/9frm5uQgPD0daWlqFw3whISHo0KEDJkyYgJMnTyIyMhKTJk1Cv3790K1bt2p9rmPHjmH58uX4999/kZCQgF9++QWpqalo27ZtzS4QEZkshigiMqo5c+ZAJpMhICAAzs7OSEhIgIeHB/755x9oNBoMHjwYHTp0wOzZs2FnZweptPK/tjp16oSVK1fif//7H9q3b4/vv/8eK1as0NunZ8+eeOGFF/D000/D2dm53MR0QOxB2rFjB+zt7dG3b1+EhISgRYsW2Lp1a7U/l42NDf766y8MHz4crVq1wltvvYUPP/wQw4YNq/7FISKTJhF4vy0RERFRjbEnioiIiMgADFFEREREBmCIIiIiIjIAQxQRERGRARiiiIiIiAzAEEVERERkAIYoIiIiIgMwRBEREREZgCGKiIiIyAAMUUREREQGYIgiIiIiMgBDFBEREZEB/g/HNERXvcgrmQAAAABJRU5ErkJggg==",
|
||
"text/plain": [
|
||
"<Figure size 640x480 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"image/png": "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P36s9XRXKysrXFxc8t3n/fffJzIykqpVq+Ll5UXnzp3x8fHBwODFfdRnz57FwMBAKy5ra2tcXFw4e/bsC2unfv36WnPzmzVrRlpaGikpKZo/xpo2baqZPpJTJyIiguzsbE6ePEl2djY1atTQOm5GRgbW1taa90ZGRnmurpCXW7ducf369XynMp09exYHBwdNZx2gVq1alC1blrNnz9KoUSNGjx7NgAEDWLNmDR4eHrz//vtUq1atSO3nCA4OZvTo0Zr3qampODg40K5dO63cdEVmZiZxcXF06NChRJ9q/LLocn66nBuUXH6tWrXK9XTngQMH4uLiwtixYzXTBZ924MABAHx8fKhXrx56enps2rSJhg0baq4srlixAgsLCwYOHIixsbF8fqWcLuenK7nlXCEvTKnrsBf0mPm3336bK1eusHPnTuLj4/H19cXDw4NNmzYV6dhlymjP/Y2JiWHs2LFERETQrFkzlEolc+bM4fDhw1r1nv1GUSgUuW5cbNWqFTt27GDDhg2MHz++SPEUh4ODA+fPnyc+Pp64uDiGDRvGnDlz2Ldv32vzDa2np5dr7vzLuKSVlpaGvr4+v/32W66Rpqenmpiammp1+gtS0PdfUYWGhtKrVy927NjBzp07mTJlCjExMbz77rtFPoaxsTHGxsa5yg0NDV+bz/llkPxKL13ODV59fnk93dnc3BwbGxvc3d25dOkS33zzDZ07d8ba2po//viDUaNG0bp1axo0aABA586dqVWrFp988gnh4eHcvHmTKVOmMHz48FzT8eTzK910Ob/SnltRYy91q8Q4OztjamrKnj178txuYWGBn58fy5cvZ/369WzevJl//vmnWG3lTPkYNmwY7u7uVK9enUuXLhXrWI0bN2bnzp18/vnnzJ07t0j7VKtWDUNDQ60/EO7evcuFCxcK3M/U1BQfHx8WLlxIQkICBw8e1Iz4GxkZkZ1d9CkTedV3dXUlKytLK66///6b8+fPU6tWrUKPaWNjw82bN7U67U/fgJrjxIkTPHr0SPP+0KFDmJuba41eP/vH06FDh3B2dkZfXx93d3eys7O5desW1atX13oVZUpQXpRKJY6Ojvl+/7m6uua6d+LMmTPcu3dP69zUqFGDUaNGsXv3bt577z2ioqKA5/98hBAiL0ZGRsTHx9OxY0dq1qzJmDFj6NGjB9u3b9fU0dfX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",
|
||
"text/plain": [
|
||
"<Figure size 640x480 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"\n",
|
||
"gc.collect()\n",
|
||
"\n",
|
||
"use_pca = False\n",
|
||
"type = 'light'\n",
|
||
"\n",
|
||
"train_data['label2'] = train_data.groupby('trade_date', group_keys=False).apply(lambda x: x.nsmallest(500, 'total_mv'))['future_return'].transform(\n",
|
||
" lambda x: pd.qcut(x, q=20, labels=False, duplicates='drop')\n",
|
||
")\n",
|
||
"test_data['label2'] = test_data.groupby('trade_date', group_keys=False).apply(lambda x: x.nsmallest(500, 'total_mv'))['future_return'].transform(\n",
|
||
" lambda x: pd.qcut(x, q=20, labels=False, duplicates='drop')\n",
|
||
")\n",
|
||
"\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_model(train_data\n",
|
||
" # .dropna(subset=['label'])\n",
|
||
" .groupby('trade_date', group_keys=False)\n",
|
||
" .apply(lambda x: x.nsmallest(500, 'total_mv'))\n",
|
||
" .merge(industry_df, on=['cat_l2_code', 'trade_date'], how='left')\n",
|
||
" .merge(index_data, on='trade_date', how='left'), \n",
|
||
" feature_columns, type=type, target_column='label2')\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 128,
|
||
"id": "5d1522a7538db91b",
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-04-03T15:04:39.656944Z",
|
||
"start_time": "2025-04-03T15:04:39.298483Z"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"score_df = test_data.groupby('trade_date', group_keys=False).apply(lambda x: x.nsmallest(500, 'total_mv'))\n",
|
||
"# score_df = fill_nan_with_daily_median(score_df, ['pe_ttm'])\n",
|
||
"# score_df = score_df[score_df['pe_ttm'] > 0]\n",
|
||
"score_df = score_df.merge(industry_df, on=['cat_l2_code', 'trade_date'], how='left')\n",
|
||
"score_df = score_df.merge(index_data, on='trade_date', how='left')\n",
|
||
"# score_df = score_df.groupby('trade_date', group_keys=False).apply(lambda x: x.nsmallest(50, 'total_mv')).reset_index()\n",
|
||
"numeric_columns = score_df.select_dtypes(include=['float64', 'int64']).columns\n",
|
||
"numeric_columns = [col for col in feature_columns if col in numeric_columns]\n",
|
||
"\n",
|
||
"if type == 'cat':\n",
|
||
" score_df['score'] = model.predict(score_df[feature_columns])\n",
|
||
"elif type == 'light':\n",
|
||
" score_df['score'] = model.predict(score_df[feature_columns])\n",
|
||
"score_df['score_ranks'] = score_df.groupby('trade_date')['score'].rank(ascending=True)\n",
|
||
"\n",
|
||
"score_df = score_df.groupby('trade_date', group_keys=False).apply(\n",
|
||
" lambda x: \n",
|
||
" x[\n",
|
||
" # (x['score'] <= x['score'].quantile(0.99)) & \n",
|
||
" (x['score'] >= x['score'].quantile(0.90))\n",
|
||
" ] # 计算90%分位数作为阈值,筛选分数>=阈值的行\n",
|
||
").reset_index(drop=True) # drop=True 避免添加旧索引列\n",
|
||
"# df_to_drop = score_df.loc[score_df.groupby('trade_date')['score'].idxmax()]\n",
|
||
"# score_df = score_df.drop(df_to_drop.index)\n",
|
||
"save_df = score_df.groupby('trade_date', group_keys=False).apply(lambda x: x.nlargest(2, 'score')).reset_index()\n",
|
||
"# save_df = score_df.groupby('trade_date', group_keys=False).apply(lambda x: x.nsmallest(2, 'total_mv')).reset_index()\n",
|
||
"save_df = save_df.sort_values(['trade_date', 'score'])\n",
|
||
"save_df[['trade_date', 'score', 'ts_code']].to_csv('predictions_test.tsv', index=False)\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 129,
|
||
"id": "fed2d6c3",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"2023-01-03 00:00:00\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"print(test_data['trade_date'].min())"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 130,
|
||
"id": "1f3c1331",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"成功连接到 Redis 服务器: 140.143.91.66:6389,数据库 0\n",
|
||
"DataFrame 已使用 Pickle 序列化并写入 Redis,键为 'save_df'\n",
|
||
"从 Redis 读取到的 Pickle 序列化数据 (前 20 字节):\n",
|
||
"b'\\x80\\x04\\x95\\x16u\\x00\\x00\\x00\\x00\\x00\\x00\\x8c\\x11pandas.'\n",
|
||
"\n",
|
||
"从 Redis 加载的 DataFrame (使用 Pickle):\n",
|
||
" index ts_code trade_date open close high low vol \\\n",
|
||
"1 35 603133.SH 2023-01-03 12.16 12.15 12.31 11.92 -0.734431 \n",
|
||
"0 30 603321.SH 2023-01-03 7.25 7.51 7.52 7.20 -0.849729 \n",
|
||
"3 99 603090.SH 2023-01-04 30.06 30.15 30.23 29.53 -1.002912 \n",
|
||
"2 79 603321.SH 2023-01-04 7.57 7.56 7.59 7.49 -0.889013 \n",
|
||
"5 125 002963.SZ 2023-01-05 14.91 14.65 14.91 14.53 -1.006545 \n",
|
||
"... ... ... ... ... ... ... ... ... \n",
|
||
"1164 29102 603177.SH 2025-06-04 8.61 8.67 8.69 8.54 -0.947619 \n",
|
||
"1167 29151 001211.SZ 2025-06-05 23.48 23.32 23.68 23.20 -1.106178 \n",
|
||
"1166 29152 603177.SH 2025-06-05 8.63 8.67 8.73 8.58 -0.941981 \n",
|
||
"1169 29202 603177.SH 2025-06-06 8.73 8.80 8.81 8.61 -0.895431 \n",
|
||
"1168 29207 605567.SH 2025-06-06 10.13 10.18 10.22 10.01 -0.825091 \n",
|
||
"\n",
|
||
" pct_chg amount ... 000905.SH_up_ratio_20d \\\n",
|
||
"1 -1.037757 36429.924 ... 0.30 \n",
|
||
"0 0.854849 15236.182 ... 0.30 \n",
|
||
"3 -0.214829 23633.991 ... 0.30 \n",
|
||
"2 -0.005288 12436.182 ... 0.30 \n",
|
||
"5 -0.614732 12390.384 ... 0.35 \n",
|
||
"... ... ... ... ... \n",
|
||
"1164 0.303152 20382.162 ... 0.60 \n",
|
||
"1167 -0.095098 16985.707 ... 0.60 \n",
|
||
"1166 0.143034 22574.106 ... 0.60 \n",
|
||
"1169 0.707494 25728.599 ... 0.55 \n",
|
||
"1168 0.407593 37040.344 ... 0.55 \n",
|
||
"\n",
|
||
" 399006.SZ_up_ratio_20d 000852.SH_volatility 000905.SH_volatility \\\n",
|
||
"1 0.40 1.036997 0.828596 \n",
|
||
"0 0.40 1.036997 0.828596 \n",
|
||
"3 0.35 1.037707 0.828639 \n",
|
||
"2 0.35 1.037707 0.828639 \n",
|
||
"5 0.35 1.071637 0.869955 \n",
|
||
"... ... ... ... \n",
|
||
"1164 0.45 0.942048 0.748797 \n",
|
||
"1167 0.45 0.954604 0.757642 \n",
|
||
"1166 0.45 0.954604 0.757642 \n",
|
||
"1169 0.40 0.941305 0.752701 \n",
|
||
"1168 0.40 0.941305 0.752701 \n",
|
||
"\n",
|
||
" 399006.SZ_volatility 000852.SH_volume_change_rate \\\n",
|
||
"1 0.935322 5.203088 \n",
|
||
"0 0.935322 5.203088 \n",
|
||
"3 0.938230 4.492401 \n",
|
||
"2 0.938230 4.492401 \n",
|
||
"5 1.120001 -1.639926 \n",
|
||
"... ... ... \n",
|
||
"1164 1.132207 -1.062074 \n",
|
||
"1167 1.154128 9.866900 \n",
|
||
"1166 1.154128 9.866900 \n",
|
||
"1169 1.103436 -4.268643 \n",
|
||
"1168 1.103436 -4.268643 \n",
|
||
"\n",
|
||
" 000905.SH_volume_change_rate 399006.SZ_volume_change_rate score \\\n",
|
||
"1 -0.750721 8.827360 0.527536 \n",
|
||
"0 -0.750721 8.827360 0.675714 \n",
|
||
"3 -0.552539 5.415982 0.524954 \n",
|
||
"2 -0.552539 5.415982 0.628866 \n",
|
||
"5 1.034360 1.155365 0.566081 \n",
|
||
"... ... ... ... \n",
|
||
"1164 -4.589323 1.251375 0.741102 \n",
|
||
"1167 4.793307 14.960862 0.776248 \n",
|
||
"1166 4.793307 14.960862 0.805704 \n",
|
||
"1169 -8.367502 -0.972266 0.705210 \n",
|
||
"1168 -8.367502 -0.972266 0.914980 \n",
|
||
"\n",
|
||
" score_ranks \n",
|
||
"1 499.0 \n",
|
||
"0 500.0 \n",
|
||
"3 499.0 \n",
|
||
"2 500.0 \n",
|
||
"5 499.0 \n",
|
||
"... ... \n",
|
||
"1164 500.0 \n",
|
||
"1167 499.0 \n",
|
||
"1166 500.0 \n",
|
||
"1169 499.0 \n",
|
||
"1168 500.0 \n",
|
||
"\n",
|
||
"[1170 rows x 251 columns]\n",
|
||
"\n",
|
||
"验证成功:原始 DataFrame 和从 Redis 加载的 DataFrame 一致。\n",
|
||
"\n",
|
||
"清理了 Redis 中键 'save_df' 的数据。\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"import redis\n",
|
||
"import pickle\n",
|
||
"\n",
|
||
"redis_host = '140.143.91.66'\n",
|
||
"redis_port = 6389\n",
|
||
"redis_db = 0\n",
|
||
"redis_key = 'save_df'\n",
|
||
"\n",
|
||
"try:\n",
|
||
" # 1. 连接到 Redis 服务器\n",
|
||
" r = redis.Redis(host=redis_host, port=redis_port, db=redis_db, password='Redis520102')\n",
|
||
" r.ping()\n",
|
||
" print(f\"\\n成功连接到 Redis 服务器: {redis_host}:{redis_port},数据库 {redis_db}\")\n",
|
||
"\n",
|
||
" # 2. 将 DataFrame 写入 Redis (使用 Pickle 序列化)\n",
|
||
" df_serialized = pickle.dumps(save_df)\n",
|
||
" r.set(redis_key, df_serialized)\n",
|
||
" print(f\"DataFrame 已使用 Pickle 序列化并写入 Redis,键为 '{redis_key}'\")\n",
|
||
"\n",
|
||
" # 3. 从 Redis 读取数据 (获取 Pickle 序列化的字节流)\n",
|
||
" retrieved_serialized = r.get(redis_key)\n",
|
||
"\n",
|
||
" if retrieved_serialized:\n",
|
||
" print(f\"从 Redis 读取到的 Pickle 序列化数据 (前 20 字节):\")\n",
|
||
" print(retrieved_serialized[:20])\n",
|
||
"\n",
|
||
" # 4. 使用 Pickle 反序列化回 Pandas DataFrame\n",
|
||
" loaded_df = pickle.loads(retrieved_serialized)\n",
|
||
" print(\"\\n从 Redis 加载的 DataFrame (使用 Pickle):\")\n",
|
||
" print(loaded_df)\n",
|
||
"\n",
|
||
" # 5. 验证原始 DataFrame 和加载的 DataFrame 是否一致\n",
|
||
" if save_df.equals(loaded_df):\n",
|
||
" print(\"\\n验证成功:原始 DataFrame 和从 Redis 加载的 DataFrame 一致。\")\n",
|
||
" else:\n",
|
||
" print(\"\\n验证失败:原始 DataFrame 和从 Redis 加载的 DataFrame 不一致!\")\n",
|
||
"\n",
|
||
" else:\n",
|
||
" print(f\"错误:无法从 Redis 获取键 '{redis_key}' 的值。\")\n",
|
||
"\n",
|
||
" # 6. 清理测试数据 (可选)\n",
|
||
" r.delete(redis_key)\n",
|
||
" print(f\"\\n清理了 Redis 中键 '{redis_key}' 的数据。\")\n",
|
||
"\n",
|
||
"except redis.exceptions.ConnectionError as e:\n",
|
||
" print(f\"无法连接到 Redis 服务器: {e}\")\n",
|
||
" print(\"请确保您的 Redis 服务器已启动并且主机和端口配置正确。\")\n",
|
||
"except redis.exceptions.TimeoutError as e:\n",
|
||
" print(f\"连接 Redis 服务器超时: {e}\")\n",
|
||
" print(\"请检查您的网络连接和 Redis 服务器状态。\")\n",
|
||
"except Exception as e:\n",
|
||
" print(f\"测试 Redis 时发生未知错误: {e}\")\n",
|
||
" print(f\"测试 Redis 时发生未知错误: {e}\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 131,
|
||
"id": "09b1799e",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"207\n",
|
||
"['vol', 'pct_chg', 'turnover_rate', 'volume_ratio', 'winner_rate', 'cat_hot_concept_stock', 'concept_rank_pct_chg', 'concept_rank_turnover_rate', 'concept_rank_volume_ratio', 'holder_net_change_sum_10d', 'holder_increase_days_10d', 'holder_decrease_days_10d', 'holder_any_increase_flag_10d', 'holder_any_decrease_flag_10d', 'cat_senti_mom_vol_spike', 'cat_senti_pre_breakout', 'ts_turnover_rate_acceleration_5_20', 'ts_vol_sustain_10_30', 'cs_amount_outlier_10', 'ts_ff_to_total_turnover_ratio', 'ts_price_volume_trend_coherence_5_20', 'ts_ff_turnover_rate_surge_10', 'undist_profit_ps', 'ocfps', 'AR', 'BR', 'AR_BR', 'cashflow_to_ev_factor', 'book_to_price_ratio', 'turnover_rate_mean_5', 'variance_20', 'bbi_ratio_factor', 'daily_deviation', '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', 'vol_break', 'weight_roc5', 'smallcap_concentration', 'cost_stability', 'high_cost_break_days', 'liquidity_risk', 'turnover_std', 'mv_volatility', 'volume_growth', 'mv_growth', 'momentum_factor', 'resonance_factor', 'log_close', 'cat_vol_spike', 'up', 'down', 'obv_maobv_6', 'std_return_5_over_std_return_90', 'std_return_90_minus_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', 'senti_strong_inflow', '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', 'industry_obv', 'industry_return_5', 'industry_return_20', 'industry__ema_5', 'industry__ema_13', 'industry__ema_20', 'industry__ema_60', 'industry_act_factor1', 'industry_act_factor2', 'industry_act_factor3', 'industry_act_factor4', 'industry_act_factor5', 'industry_act_factor6', 'industry_rank_act_factor1', 'industry_rank_act_factor2', 'industry_rank_act_factor3', 'industry_return_5_percentile', 'industry_return_20_percentile', '000852.SH_MACD', '000905.SH_MACD', '399006.SZ_MACD', '000852.SH_MACD_hist', '000905.SH_MACD_hist', '399006.SZ_MACD_hist', '000852.SH_RSI', '000905.SH_RSI', '399006.SZ_RSI', '000852.SH_Signal_line', '000905.SH_Signal_line', '399006.SZ_Signal_line', '000852.SH_amount_change_rate', '000905.SH_amount_change_rate', '399006.SZ_amount_change_rate', '000852.SH_amount_mean', '000905.SH_amount_mean', '399006.SZ_amount_mean', '000852.SH_daily_return', '000905.SH_daily_return', '399006.SZ_daily_return', '000852.SH_up_ratio_20d', '000905.SH_up_ratio_20d', '399006.SZ_up_ratio_20d', '000852.SH_volatility', '000905.SH_volatility', '399006.SZ_volatility', '000852.SH_volume_change_rate', '000905.SH_volume_change_rate', '399006.SZ_volume_change_rate']\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"print(len(feature_columns))\n",
|
||
"print(feature_columns)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 132,
|
||
"id": "bceabd1f",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"警告: DataFrame 中没有 'group_id' 列。假设整个 DataFrame 是一个需要排序的组。\n",
|
||
"\n",
|
||
"NDCG 结果\n",
|
||
"{'ndcg@1': np.float64(0.5102040816326531), 'ndcg@3': np.float64(0.6258109632386283), 'ndcg@5': np.float64(0.6760105470779576)}\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"import pandas as pd\n",
|
||
"import numpy as np\n",
|
||
"\n",
|
||
"def calculate_ndcg(df: pd.DataFrame, score_col: str, label_col: str, group_id: str = 'trade_date', k_values: list = [1, 3, 5, 10]):\n",
|
||
" \"\"\"\n",
|
||
" 计算 DataFrame 中 score 列和 label 列的 NDCG 值。\n",
|
||
"\n",
|
||
" Args:\n",
|
||
" df (pd.DataFrame): 包含 score (排序学习预测分数) 和 label (相关性标签) 的 DataFrame。\n",
|
||
" 假设每个需要排序的组(例如,每天的股票)在 DataFrame 中是连续的。\n",
|
||
" score_col (str): 包含模型预测分数的列名。\n",
|
||
" label_col (str): 包含相关性标签的列名。标签值越高表示相关性越高。\n",
|
||
" k_values (list): 一个整数列表,表示计算 NDCG 的 top-k 值。\n",
|
||
" 例如,[1, 3, 5] 将计算 NDCG@1, NDCG@3 和 NDCG@5。\n",
|
||
"\n",
|
||
" Returns:\n",
|
||
" dict: 一个字典,包含每个 k 值对应的平均 NDCG 值。\n",
|
||
" 例如: {'ndcg@1': 0.85, 'ndcg@3': 0.78, 'ndcg@5': 0.72, 'ndcg@10': 0.65}\n",
|
||
" \"\"\"\n",
|
||
" ndcg_scores = {f'ndcg@{k}': [] for k in k_values}\n",
|
||
"\n",
|
||
" def dcg_at_k(r, k):\n",
|
||
" r = np.asarray(r)[:k] if len(r) > 0 else np.zeros(k)\n",
|
||
" return np.sum(r / np.log2(np.arange(2, r.size + 2)))\n",
|
||
"\n",
|
||
" def ndcg_at_k(r, k):\n",
|
||
" dcg_max = dcg_at_k(sorted(r, reverse=True), k)\n",
|
||
" if not dcg_max:\n",
|
||
" return 0.\n",
|
||
" return dcg_at_k(r, k) / dcg_max\n",
|
||
"\n",
|
||
" # 假设 DataFrame 已经按照需要排序的组(例如,'trade_date')进行了分组,\n",
|
||
" # 并且每个组内的顺序不重要,我们只需要计算每个组的 NDCG。\n",
|
||
" # 如果需要按特定组计算 NDCG,请先对 DataFrame 进行分组。\n",
|
||
" if group_id not in df.columns:\n",
|
||
" print(\"警告: DataFrame 中没有 'group_id' 列。假设整个 DataFrame 是一个需要排序的组。\")\n",
|
||
" group_df = df.sort_values(by=score_col, ascending=False)\n",
|
||
" relevant_labels = group_df[label_col].values\n",
|
||
" for k in k_values:\n",
|
||
" ndcg_scores[f'ndcg@{k}'].append(ndcg_at_k(relevant_labels, k))\n",
|
||
" else:\n",
|
||
" for _, group_df in df.groupby(group_id):\n",
|
||
" group_df_sorted = group_df.sort_values(by=score_col, ascending=False)\n",
|
||
" relevant_labels = group_df_sorted[label_col].values\n",
|
||
" for k in k_values:\n",
|
||
" ndcg_scores[f'ndcg@{k}'].append(ndcg_at_k(relevant_labels, k))\n",
|
||
"\n",
|
||
" avg_ndcg = {k: np.mean(v) if v else np.nan for k, v in ndcg_scores.items()}\n",
|
||
" return avg_ndcg\n",
|
||
"\n",
|
||
"\n",
|
||
"ndcg_results_single_group = calculate_ndcg(score_df, score_col='score', label_col='label', k_values=[1, 3, 5], group_id=None)\n",
|
||
"print(\"\\nNDCG 结果\")\n",
|
||
"print(ndcg_results_single_group)\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 133,
|
||
"id": "44f64679",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
" ts_code trade_date open close high low vol pct_chg \\\n",
|
||
"1636230 002652.SZ 2019-01-02 19.59 19.64 19.89 19.28 20196.79 1.03 \n",
|
||
"1636231 002652.SZ 2019-01-03 19.74 19.44 19.84 19.33 15731.99 -1.02 \n",
|
||
"1636232 002652.SZ 2019-01-04 19.33 19.94 19.99 19.08 21099.93 2.57 \n",
|
||
"1636233 002652.SZ 2019-01-07 20.04 21.95 21.95 20.04 83534.19 10.08 \n",
|
||
"1636234 002652.SZ 2019-01-08 23.21 21.65 23.87 21.65 149377.97 -1.37 \n",
|
||
"... ... ... ... ... ... ... ... ... \n",
|
||
"1637782 002652.SZ 2025-05-30 15.36 15.11 15.41 14.95 107732.00 -1.63 \n",
|
||
"1637783 002652.SZ 2025-06-03 15.11 15.41 15.71 14.90 163459.00 1.99 \n",
|
||
"1637784 002652.SZ 2025-06-04 15.41 15.71 15.71 15.36 140521.00 1.95 \n",
|
||
"1637785 002652.SZ 2025-06-05 15.76 15.61 16.51 15.51 246994.40 -0.64 \n",
|
||
"1637786 002652.SZ 2025-06-06 15.71 16.01 16.36 15.66 228370.40 2.56 \n",
|
||
"\n",
|
||
" amount turnover_rate ... cs_rank_pos_in_hist_range \\\n",
|
||
"1636230 7867.047 0.3964 ... 0.730643 \n",
|
||
"1636231 6121.460 0.3088 ... 0.732202 \n",
|
||
"1636232 8245.083 0.4141 ... 0.727920 \n",
|
||
"1636233 35514.117 1.6394 ... 0.725182 \n",
|
||
"1636234 67160.354 2.9317 ... 0.726095 \n",
|
||
"... ... ... ... ... \n",
|
||
"1637782 32385.927 2.1039 ... 0.657143 \n",
|
||
"1637783 50114.396 3.1922 ... 0.657133 \n",
|
||
"1637784 43515.970 2.7442 ... 0.653207 \n",
|
||
"1637785 77669.905 4.8235 ... 0.652427 \n",
|
||
"1637786 72598.629 4.4598 ... 0.653092 \n",
|
||
"\n",
|
||
" cs_rank_vol_x_profit_margin cs_rank_lg_flow_price_concordance \\\n",
|
||
"1636230 0.608839 0.203142 \n",
|
||
"1636231 0.586710 0.156684 \n",
|
||
"1636232 0.682847 0.184009 \n",
|
||
"1636233 0.987591 0.734940 \n",
|
||
"1636234 0.765693 0.874042 \n",
|
||
"... ... ... \n",
|
||
"1637782 0.702990 0.705316 \n",
|
||
"1637783 0.842368 0.333222 \n",
|
||
"1637784 0.851113 0.101695 \n",
|
||
"1637785 0.490691 0.137965 \n",
|
||
"1637786 0.916556 0.923205 \n",
|
||
"\n",
|
||
" cs_rank_turnover_per_winner cs_rank_ind_cap_neutral_pe \\\n",
|
||
"1636230 0.864865 NaN \n",
|
||
"1636231 0.763417 NaN \n",
|
||
"1636232 0.660949 NaN \n",
|
||
"1636233 0.700000 NaN \n",
|
||
"1636234 0.914234 NaN \n",
|
||
"... ... ... \n",
|
||
"1637782 0.419934 NaN \n",
|
||
"1637783 0.466578 NaN \n",
|
||
"1637784 0.440678 NaN \n",
|
||
"1637785 0.686170 NaN \n",
|
||
"1637786 0.648604 NaN \n",
|
||
"\n",
|
||
" cs_rank_volume_ratio cs_rank_elg_buy_sell_sm_ratio \\\n",
|
||
"1636230 0.646930 0.341855 \n",
|
||
"1636231 0.251279 0.318912 \n",
|
||
"1636232 0.311724 0.260036 \n",
|
||
"1636233 0.988313 0.796350 \n",
|
||
"1636234 0.990142 0.598905 \n",
|
||
"... ... ... \n",
|
||
"1637782 0.537542 0.133056 \n",
|
||
"1637783 0.852843 0.129697 \n",
|
||
"1637784 0.726653 0.740113 \n",
|
||
"1637785 0.932846 0.645279 \n",
|
||
"1637786 0.863531 0.724069 \n",
|
||
"\n",
|
||
" cs_rank_cost_dist_vol_ratio future_return label \n",
|
||
"1636230 0.678941 0.158859 40.0 \n",
|
||
"1636231 0.402916 0.136831 37.0 \n",
|
||
"1636232 0.460713 0.106319 39.0 \n",
|
||
"1636233 0.988501 -0.072893 4.0 \n",
|
||
"1636234 0.991571 -0.057737 5.0 \n",
|
||
"... ... ... ... \n",
|
||
"1637782 0.703987 NaN NaN \n",
|
||
"1637783 0.895910 NaN NaN \n",
|
||
"1637784 0.820871 NaN NaN \n",
|
||
"1637785 0.958112 NaN NaN \n",
|
||
"1637786 0.912566 NaN NaN \n",
|
||
"\n",
|
||
"[1557 rows x 199 columns]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"print(df[df['ts_code'] == '002652.SZ'])"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "stock",
|
||
"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.13.2"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 5
|
||
}
|