783 lines
102 KiB
Plaintext
783 lines
102 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"metadata": {},
|
||
"cell_type": "raw",
|
||
"source": "# Please replace 'your_futures_data.csv' with the actual path to your CSV file",
|
||
"id": "fb1975346060eb6d"
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"id": "initial_id",
|
||
"metadata": {
|
||
"collapsed": true,
|
||
"ExecuteTime": {
|
||
"end_time": "2025-09-24T08:34:05.116565Z",
|
||
"start_time": "2025-09-24T08:34:05.113703Z"
|
||
}
|
||
},
|
||
"source": [
|
||
"import pandas as pd\n",
|
||
"import numpy as np\n",
|
||
"import matplotlib.pyplot as plt\n",
|
||
"import seaborn as sns\n",
|
||
"import talib as ta # Make sure TA-Lib is installed: pip install TA-Lib\n",
|
||
"import statsmodels.api as sm\n",
|
||
"\n",
|
||
"import warnings\n",
|
||
"\n",
|
||
"# 忽略所有警告\n",
|
||
"warnings.filterwarnings(\"ignore\")\n",
|
||
"\n",
|
||
"# --- 0. Configure your file path ---\n",
|
||
"# Please replace 'your_futures_data.csv' with the actual path to your CSV file\n",
|
||
"file_path = '/mnt/d/PyProject/NewQuant/data/data/KQ_m@CZCE_SA/KQ_m@CZCE_SA_min15.csv'\n",
|
||
"\n",
|
||
"sns.set(style='whitegrid')\n",
|
||
"plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签\n",
|
||
"plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号\n"
|
||
],
|
||
"outputs": [],
|
||
"execution_count": 27
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-09-24T08:34:05.158770Z",
|
||
"start_time": "2025-09-24T08:34:05.127669Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"\n",
|
||
"# --- 1. Data Loading and Preprocessing ---\n",
|
||
"def load_and_preprocess_data(file_path):\n",
|
||
" \"\"\"\n",
|
||
" Loads historical futures data and performs basic preprocessing.\n",
|
||
" Assumes data contains 'datetime', 'open', 'high', 'low', 'close', 'volume' columns.\n",
|
||
" \"\"\"\n",
|
||
" try:\n",
|
||
" df = pd.read_csv(file_path, parse_dates=['datetime'], index_col='datetime')\n",
|
||
" # Ensure data is sorted by time\n",
|
||
" df = df.sort_index()\n",
|
||
" # Check and handle missing values\n",
|
||
" initial_rows = len(df)\n",
|
||
" df.dropna(inplace=True)\n",
|
||
" if len(df) < initial_rows:\n",
|
||
" print(f\"Warning: Missing values found in data, deleted {initial_rows - len(df)} rows.\")\n",
|
||
"\n",
|
||
" # Check if necessary columns exist\n",
|
||
" required_columns = ['open', 'high', 'low', 'close', 'volume']\n",
|
||
" if not all(col in df.columns for col in required_columns):\n",
|
||
" raise ValueError(f\"CSV file is missing required columns. Please ensure it contains: {required_columns}\")\n",
|
||
"\n",
|
||
" print(f\"Successfully loaded {len(df)} rows of data.\")\n",
|
||
" print(\"First 5 rows of data:\")\n",
|
||
" print(df.head())\n",
|
||
" return df\n",
|
||
" except FileNotFoundError:\n",
|
||
" print(f\"Error: File '{file_path}' not found. Please check the path.\")\n",
|
||
" return None\n",
|
||
" except Exception as e:\n",
|
||
" print(f\"Error during data loading or preprocessing: {e}\")\n",
|
||
" return None\n",
|
||
"\n",
|
||
"\n",
|
||
"df_raw = load_and_preprocess_data(file_path)\n",
|
||
"df_raw = df_raw[df_raw.index >= '2024-01-01']"
|
||
],
|
||
"id": "1638e05ca7ef1ac8",
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Successfully loaded 25662 rows of data.\n",
|
||
"First 5 rows of data:\n",
|
||
" open high low close volume open_oi \\\n",
|
||
"datetime \n",
|
||
"2020-12-31 14:45:00 1607.0 1611.0 1603.0 1611.0 19480.0 148833.0 \n",
|
||
"2021-01-04 09:00:00 1610.0 1636.0 1601.0 1620.0 55486.0 146448.0 \n",
|
||
"2021-01-04 09:15:00 1620.0 1620.0 1601.0 1604.0 30314.0 153373.0 \n",
|
||
"2021-01-04 09:30:00 1604.0 1606.0 1590.0 1595.0 30803.0 157091.0 \n",
|
||
"2021-01-04 09:45:00 1595.0 1601.0 1594.0 1600.0 10031.0 158730.0 \n",
|
||
"\n",
|
||
" close_oi underlying_symbol \n",
|
||
"datetime \n",
|
||
"2020-12-31 14:45:00 146448.0 CZCE.SA105 \n",
|
||
"2021-01-04 09:00:00 153373.0 CZCE.SA105 \n",
|
||
"2021-01-04 09:15:00 157091.0 CZCE.SA105 \n",
|
||
"2021-01-04 09:30:00 158730.0 CZCE.SA105 \n",
|
||
"2021-01-04 09:45:00 160031.0 CZCE.SA105 \n"
|
||
]
|
||
}
|
||
],
|
||
"execution_count": 28
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-09-24T08:34:05.651602Z",
|
||
"start_time": "2025-09-24T08:34:05.175334Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"import pandas as pd\n",
|
||
"import numpy as np\n",
|
||
"import talib\n",
|
||
"import matplotlib.pyplot as plt\n",
|
||
"import seaborn as sns\n",
|
||
"\n",
|
||
"\n",
|
||
"# --- 1. 数据准备与事件识别函数 ---\n",
|
||
"\n",
|
||
"def analyze_ma_channel_events(df_raw: pd.DataFrame, ma_periods: list) -> pd.DataFrame:\n",
|
||
" \"\"\"\n",
|
||
" 分析不同MA周期下,价格在动态通道中的 bounce 和 penetration 事件。\n",
|
||
"\n",
|
||
" Args:\n",
|
||
" df_raw (pd.DataFrame): 原始数据,必须包含 'high', 'low', 'close', 'open' 列。\n",
|
||
" ma_periods (list): 需要分析的移动平均线周期列表。\n",
|
||
"\n",
|
||
" Returns:\n",
|
||
" pd.DataFrame: 包含每个MA周期事件概率的统计结果。\n",
|
||
" \"\"\"\n",
|
||
" # 确保有足够的数据\n",
|
||
" if df_raw.empty or len(df_raw) < max(ma_periods) + 2:\n",
|
||
" raise ValueError(\"数据量不足以进行分析\")\n",
|
||
"\n",
|
||
" # 预先计算ATR\n",
|
||
" atr = talib.ATR(df_raw['high'], df_raw['low'], df_raw['close'], timeperiod=14)\n",
|
||
" df = df_raw.copy()\n",
|
||
" df['atr'] = atr\n",
|
||
" df.dropna(inplace=True)\n",
|
||
"\n",
|
||
" results = []\n",
|
||
"\n",
|
||
" for period in ma_periods:\n",
|
||
" # 计算MA和动态上下轨\n",
|
||
" ma = talib.SMA(df['close'], timeperiod=period)\n",
|
||
" upper_band = ma + 0.5 * df['atr']\n",
|
||
" lower_band = ma - 0.5 * df['atr']\n",
|
||
"\n",
|
||
" # 初始化状态变量\n",
|
||
" in_band_state = 'outside' # outside, inside_from_top, inside_from_bottom\n",
|
||
" bounce_count = 0\n",
|
||
" penetration_count = 0\n",
|
||
"\n",
|
||
" # 遍历数据以识别事件\n",
|
||
" for i in range(1, len(df)):\n",
|
||
" close = df['close'].iloc[i]\n",
|
||
" prev_close = df['close'].iloc[i - 1]\n",
|
||
" ub = upper_band.iloc[i]\n",
|
||
" lb = lower_band.iloc[i]\n",
|
||
"\n",
|
||
" # --- 核心事件识别逻辑 ---\n",
|
||
" if in_band_state == 'outside':\n",
|
||
" # 判断是否从上方穿入\n",
|
||
" if prev_close >= ub and close < ub:\n",
|
||
" in_band_state = 'inside_from_top'\n",
|
||
" # 判断是否从下方穿入\n",
|
||
" elif prev_close <= lb and close > lb:\n",
|
||
" in_band_state = 'inside_from_bottom'\n",
|
||
"\n",
|
||
" elif in_band_state == 'inside_from_top':\n",
|
||
" # 判断是否从上轨穿出 (bounce)\n",
|
||
" if close > ub:\n",
|
||
" bounce_count += 1\n",
|
||
" in_band_state = 'outside' # 重置状态\n",
|
||
" # 判断是否从下轨穿出 (penetration)\n",
|
||
" elif close < lb:\n",
|
||
" penetration_count += 1\n",
|
||
" in_band_state = 'outside' # 重置状态\n",
|
||
"\n",
|
||
" elif in_band_state == 'inside_from_bottom':\n",
|
||
" # 判断是否从下轨穿出 (bounce)\n",
|
||
" if close < lb:\n",
|
||
" bounce_count += 1\n",
|
||
" in_band_state = 'outside' # 重置状态\n",
|
||
" # 判断是否从上轨穿出 (penetration)\n",
|
||
" elif close > ub:\n",
|
||
" penetration_count += 1\n",
|
||
" in_band_state = 'outside' # 重置状态\n",
|
||
"\n",
|
||
" # --- 概率计算 ---\n",
|
||
" total_events = bounce_count + penetration_count\n",
|
||
" if total_events > 0:\n",
|
||
" bounce_prob = bounce_count / total_events\n",
|
||
" penetration_prob = penetration_count / total_events\n",
|
||
" else:\n",
|
||
" bounce_prob = 0\n",
|
||
" penetration_prob = 0\n",
|
||
"\n",
|
||
" results.append({\n",
|
||
" 'ma_period': period,\n",
|
||
" 'total_events': total_events,\n",
|
||
" 'bounce_count': bounce_count,\n",
|
||
" 'penetration_count': penetration_count,\n",
|
||
" 'bounce_probability': bounce_prob,\n",
|
||
" 'penetration_probability': penetration_prob\n",
|
||
" })\n",
|
||
"\n",
|
||
" return pd.DataFrame(results)\n",
|
||
"\n",
|
||
"\n",
|
||
"# --- 2. 可视化函数 ---\n",
|
||
"\n",
|
||
"def plot_event_probabilities(results_df: pd.DataFrame):\n",
|
||
" \"\"\"\n",
|
||
" 将事件概率结果进行可视化。\n",
|
||
" \"\"\"\n",
|
||
" if results_df.empty:\n",
|
||
" print(\"没有可供可视化的数据。\")\n",
|
||
" return\n",
|
||
"\n",
|
||
" # 数据重塑以适应seaborn的条形图\n",
|
||
" plot_data = results_df.melt(id_vars='ma_period',\n",
|
||
" value_vars=['bounce_probability', 'penetration_probability'],\n",
|
||
" var_name='event_type',\n",
|
||
" value_name='probability')\n",
|
||
"\n",
|
||
" # 美化标签\n",
|
||
" plot_data['event_type'] = plot_data['event_type'].str.replace('_probability', '').str.capitalize()\n",
|
||
"\n",
|
||
" # 绘图\n",
|
||
" fig, ax = plt.subplots(figsize=(14, 8))\n",
|
||
"\n",
|
||
" sns.barplot(data=plot_data, x='ma_period', y='probability', hue='event_type', ax=ax, palette='viridis')\n",
|
||
"\n",
|
||
" # 添加标题和标签\n",
|
||
" ax.set_title('事件概率 vs. MA周期 (MA ± 0.5 ATR Channel)', fontsize=16, fontweight='bold')\n",
|
||
" ax.set_xlabel('移动平均线周期 (MA Period)', fontsize=12)\n",
|
||
" ax.set_ylabel('事件发生概率 (Probability)', fontsize=12)\n",
|
||
" ax.legend(title='事件类型 (Event Type)', fontsize=10)\n",
|
||
" ax.yaxis.set_major_formatter(plt.FuncFormatter('{:.0%}'.format)) # 格式化y轴为百分比\n",
|
||
"\n",
|
||
" # 在每个条形上显示数值\n",
|
||
" for container in ax.containers:\n",
|
||
" ax.bar_label(container, fmt='{:.1%}', fontsize=9, padding=3)\n",
|
||
"\n",
|
||
" plt.tight_layout()\n",
|
||
" plt.show()\n",
|
||
" # 保存图像\n",
|
||
" print(\"图表已保存为 ma_channel_event_probability.png\")\n",
|
||
"\n",
|
||
"\n",
|
||
"# 定义您想分析的MA周期\n",
|
||
"ma_periods_to_analyze = [10, 20, 30, 50, 60, 100, 120]\n",
|
||
"\n",
|
||
"# 执行分析\n",
|
||
"event_statistics = analyze_ma_channel_events(df_raw, ma_periods_to_analyze)\n",
|
||
"\n",
|
||
"# 打印统计结果\n",
|
||
"print(\"--- 事件统计结果 ---\")\n",
|
||
"print(event_statistics.to_string())\n",
|
||
"\n",
|
||
"# 可视化结果\n",
|
||
"plot_event_probabilities(event_statistics)"
|
||
],
|
||
"id": "e0a36ae978d73ecc",
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"--- 事件统计结果 ---\n",
|
||
" ma_period total_events bounce_count penetration_count bounce_probability penetration_probability\n",
|
||
"0 10 1104 557 547 0.504529 0.495471\n",
|
||
"1 20 890 496 394 0.557303 0.442697\n",
|
||
"2 30 763 432 331 0.566186 0.433814\n",
|
||
"3 50 610 364 246 0.596721 0.403279\n",
|
||
"4 60 567 319 248 0.562610 0.437390\n",
|
||
"5 100 418 238 180 0.569378 0.430622\n",
|
||
"6 120 359 219 140 0.610028 0.389972\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<Figure size 1400x800 with 1 Axes>"
|
||
],
|
||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABWgAAAMQCAYAAAC60ozSAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAzZxJREFUeJzs3Xd8zef///HnyRYRe6tRLUKJETRmBTUqtqKKllIlRqs1an5sWnu1VLW01N4zdpEGofbeM0FCEhKZvz/88v46TUIiiWM87rfb5/bJud7v93Wu6+TNx+d5rvfrMsXGxsYKAAAAAAAAAPDCWVl6AAAAAAAAAADwpiKgBQAAAAAAAAALIaAFAAAAAAAAAAshoAUAAAAAAAAACyGgBQAAAAAAAAALIaAFAAAAAAAAAAshoAUAAAAAAAAACyGgBQAAAAAAAAALIaAFAAAAAAAAAAshoAUA4BXQpUsX9e7dO0V9HDhwQJ9++qkOHDiQ4PHLly/r22+/1dq1a5PUX1hYmFatWqXDhw+naFzJdevWLd2+ffuFvifSxl9//aW6devKx8fHrL1FixZq2rSphUYFAAAAvFg2lh4AAABvulOnTunGjRtycHCQtbV1guecPXtW6dKlk6+vb4LHo6OjFRERofTp06t8+fIJnrNkyRLt37/fCDfDwsKULl0643hYWJjWrFmj/PnzJ2ncDx48UJ8+ffTFF1/I1dVVUVFRCgoKMjvHyspKDx8+1K5du+To6Cgrq//7bjg6Olp2dnZq0KBBkt5PkjZs2KBevXrp448/1vDhw5N8HVLm559/1oQJE577+t69e6tz587x2sPDw3Xx4kXFxsaatQcEBCg8PNx4PW/ePI0ZMybBvtOnT6/9+/c/99gSs2rVKmXPnl2VKlVK9b7TUr9+/bRv3z5t27bN0kMBXqiVK1cqZ86ccnd3t/RQAABINgJaAAAsbNmyZZo3b16Szm3Xrt1Tj5ctW1YLFy6M1x4YGKiNGzeqUqVKqlevniTpp59+0u7du/Xtt9/K3d1dtra2kiQbm6T98yAu3M2QIYMk6eLFi/HC1mzZsumHH37QL7/8IgcHBz169EjXr19Xvnz5ZGdnp9y5c8e75vDhw7K3tzfG86R8+fLJyspKmzZtUvv27WUymcyOx8bGKjIyUjExMSpRokSS5oFns7OzkyR17txZhQoVMjsWEhKiR48eKUuWLGYBvCRduHBBs2fPNq6PExkZqUePHhn32n9/1zY2NrK3t1dERIRiY2Nla2ur6OhotW3bVu+//75x3tChQxUTE5Nq84yzc+dO9e/fX19++eUrF9ACb6o9e/Zoy5Yt+vPPP1W8eHFLDwcAgGQhoAUAwMLat2+vJk2aKF26dAmGktLjYMzJySnRVYwRERGKiIhI9PpZs2YpPDxcPXv2NNp8fX115swZvf3228817v+Ga/b29pKkYcOGqV69evrf//6ngwcPqlKlStq+fbskae/evfr88881YcIEubq6Jtjvxx9//Mz3vn//vj766KNEj2fLlk179uxJ1nxeVVOnTtW0adMkPQ7da9SoYRyrWLGi7t27p7x58ya4orJXr17asGGDxo4dq8aNGyf6HnEBa7Vq1eKt0B4wYICWLl2q/fv3y9nZ2eyYr6+vZs+eHe++PHz4sNq0aWO8/vTTTxN835IlS6p///5Knz69JKl48eKqVauWcXzs2LGKiIhIdNzP4+rVq/rmm2/UvHlz489Lv379tGLFCknSmjVrVKRIEUlSaGio3NzcFBsbqwoVKmj+/Pnx+mvRooWOHDmiP//8U25ubqk6Vkvau3evpk2bplOnTsnR0VHNmjVT9+7dk/wFT0JCQ0NVvnz5BEN3Ozs7HT16NCVDlvTse75o0aLP7OP06dOSpLZt22rfvn1Gu8lkUsaMGeXq6qrPP/88xSs5Q0JCNGXKFG3atElBQUEqWLCg2rZta/Z35LVr11SzZk01adIk0VXmr5OiRYsm+mdt1KhRun//vrp166bVq1cbXx4CAPAqIKAFAMDC8uXLZ/y8adMmPXjwIN45Dx8+VExMjFkYEMdkMqlJkyaJ9u/v76+FCxcqa9asKl26tCTp7t27Onr0qOrXr6+cOXMmem1UVJQePnyo9OnTJ1p+IU7c6kkHBwc5OzvL1tY23jWRkZGS4q+YfNLGjRvl6Oio9OnTm5VFCA4OVqtWrYz//HdVZmxsrCIiInTv3j3jfd40J0+eNALamzdv6t69e4meGxUVZYTYu3btempAG/d7NJlMioqK0o0bN2RnZyc7OzvjWGRkpIKCgowvCrJkyWJc/9+VtUWKFNGSJUu0Y8cOTZ8+XVOmTNE777xjHP/iiy8UFRWl6dOnK3v27PFq1D7pv32n1IABA1SgQAENGTIkweMnT540AtpTp07FK8/wpMDAQCNU3Llz52sT0K5du1bfffedHBwc1KBBA0VEROiXX37R7du3NWrUqOfu9/jx44qJiVGdOnXirdR+2t8ZSZWUe75Lly7GzwcOHNCBAwfk5ub21N9dw4YNlSdPHj18+FCnT5/Wzp07tXPnTo0YMUItWrR4rrEGBwerdevWOnfunCpVqqTChQvrn3/+0aBBg3TlyhV9++23z9Xv68zW1lYTJkxQgwYNNHbsWI0YMcLSQwIAIMkIaAEAeIlMnjxZ58+fT/R4//7947WlS5fuqQHtkCFDFB4eLicnJ6Nt3bp1ioqK0urVq7V69ep4Y5g8ebJZ2/r161W4cGFJj0OLMWPGyMHBQdLjjZ7WrVtnrDa8ffu2zp8/r5CQEJlMJp07d06LFi3Sp59+agSncattExISEqLhw4erb9++ZqvZxo4dqwsXLigkJES2trbav3+/YmJiVLFiRUmPw8PZs2fL29tbv/zyS6L9v85OnjyZ4M8JOXTokIKDgyU9fjQ4Ojo60RD+yVWRt27dUu3ateOd82QpgHbt2mnAgAGJvrezs7NKlSql48ePS5Ly5Mlj3F9x72cymVSqVClJTw9h/1vmIiV27NghPz8/LVu2LNHP4uTJk2rUqJHx89Ps2rXLCHB37tyZ4o3+XgZ37tzR4MGDZWtrqz/++MMoJVKmTBkNGTJE9evXV5UqVZ6r7yNHjkh6HJKmxSPqSbnnv/76a+PnqVOn6sCBA3r//ffVvXv3RPtt3ry58feQJC1fvlz9+/fXDz/8oCZNmjzXquLRo0fr3Llz6tSpkxHGhoeH65NPPtEvv/yiBg0aqFixYsnu93Xn5OSkoUOH6quvvtJnn31m9sUPAAAvMwJaAABeIunSpZOrq6sWL15s1t6oUSM5OzvHe6yzbdu2Onv2bKL9rVy50igvECcmJkZ//vmncubMafZoeWBgoObOnasqVaoYYUNUVJTCw8OVOXNm47xMmTKpXLlyxmZjuXLlUtGiRY3H0H/44Qf98MMPkqT8+fPrxo0bmjdvnj755BOFhoZK0lMfPT158qQOHTqkFi1aaOTIkfL09NSCBQu0YsUK/fDDD/L09FRAQIB69+6tO3fu6LffflPp0qU1atQoLVy4UC4uLgoICFD27NkTfY/X1YkTJxL8OSE7d+6UJLVs2VKLFi3Sv//+q3LlyiV4blwIam1trYwZM6p3796ys7OTra2tvL295ePjo+HDhysmJkYRERF69913kzXuGzduyNHR0XgdFRWVYPAaF/4/67zn9ccff8jDw+OpwVdyP2MbGxs1atRIy5Ytk7+//1NXrCfV5s2bjXA7ofEFBwdr4sSJCR5///33U/To/cqVK/XgwQN99tlnZnWemzdvrp9++knLli177oD26NGjsrOzS/b9k1TJuedTomnTppo6dapu3Lih8+fPJ6lswpPu3LmjlStXKlOmTGbBsIODg1q3bq2BAwdq/fr1BLSJ+OCDD1SsWDEtWLBAgwcPtvRwAABIEgJaAABeIlFRUbp//76WL19u1n7//n09evQoXvvt27cVHR2dYF///vuvhgwZoiJFisjBwUE3btyQ9LiG5qVLl9SvXz99/vnnxvnnz5/X3LlzVa5cOXXu3DnRMb7zzjvq37+/FixYoHXr1umDDz5Qx44dde3aNUnSuHHj1KhRI/Xr108HDhwwVj/a2toaj9z/t1bpk1q2bKmyZcuqU6dOCgsL04gRIzR//nyVKFFC586d08SJE7V161aFhIRo9uzZqlChghYtWqSFCxeqadOmGjZsWKo8Dv2qcXd3l4+Pj4KDg+Xs7KxTp06pQIECioqKSvD8nTt3KmvWrGratKkWLVqkXbt2PTOssra2VoYMGczuj0uXLsnHxydJtYMT06NHj3htefPmNX6OC2EnTJgQrw7zk+elxMOHD/XPP/8kWudZevwZPxnKnjp1SpUqVdLevXvjnRsdHa09e/bIxcVFVapU0bJly7Rz584UfU5xtm3bZtTETcxPP/2UYLuNjU2KAtr9+/dLkj788MN4/b7//vvxvhBKjqNHj6pkyZJp9uf3ee7555UlSxbduHFDjx49Sva1O3bsUExMjN5///14TxvElX542hdzkDw9PTVv3jwCWgDAK4OAFgCAl0hYWJiuXr2aYCkDKeESB4mFGePGjZOVlZUmTpyo//3vf5Ie1wmdPHmyMmXKpJYtW6ZorHG1NU+cOKH169cbj6M/KTo6WuHh4ZIer7w7cuSIrKystHTpUsXGxiosLEyffvqp2epJSXr33Xe1ceNGOTg46M8//5SVlZUePHiggwcPat++fcqQIYPmzp1r1NRt2bKlcubMqQ8++CBFc4qOjlb16tVlMpm0c+fOeI/We3h46OHDh/r777+Nzz08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zQ9/+MP8/e9/z/vvv58nnngiq622Wn3VCAAAAADQKC1XQDtixIh85zvfyfjx47P77rtn1qxZ2X777fO3v/0t++67b33VCAAAAADQKC3XHrRrrLFGrrzyyuLtO++8M48//njatWuXzTbbbLmLAwAAAABozJYroP281VZbLT/+8Y/rc0oAAAAAgEZruQPaMWPG5Oqrr87bb7+d6urqdO7cOfvuu2/69etXH/UBAAAAADRay7UH7fXXX58DDzwwc+bMyXbbbZcdd9wxCxcuzGGHHZabb765vmoEAAAAAGiUlmsF7SWXXJIDDzwwv/vd72qNn3POObn88suz5557LldxAAAAAACN2XKtoJ09e3a22mqrJcZ/+MMfZurUqcszNQAAAABAo7dcAe1uu+2W//3f/83cuXOLY5WVlbn22muz8847L3dxAAAAAACN2VJtcTBs2LBatwuFQsaOHZttt902G264YcrKyvLqq69mzpw56dOnT70WCgAAAADQ2CxVQNu2bdslxgYMGFDr9ne/+93lqwgAAAAAYCWxVAHtyJEjV1QdAAAAAAArnaUKaL/IpEmTctlll+XFF19MknTv3j0HH3xwvve97y3v1AAAAAAAjdpyXSTsxRdfzG677ZZnnnkmm2yySTbZZJOMGzcuu+22W1566aX6qhEAAAAAoFFarhW0p512WrbeeuuMGjUqzZp9OlV1dXWOPPLInHbaabnhhhvqpUgAAAAAgMZouVbQvvzyy9l7772L4WySNG3aNHvvvXfGjx+/3MUBAAAAADRmyxXQdujQIU8//fQS408//XQ6dOiwPFMDAAAAADR6y7XFwbBhw3L88cfngw8+yBZbbJEkefLJJ3PnnXfmtNNOq5cCAQAAAAAaq+UKaHfdddcUCoVccMEFuf3225MkHTt2zKmnnprBgwfXR30AAAAAAI3WcgW0SbLbbrtlt912y/Tp05Mk7dq1W+6iAAAAAABWBssd0C4mmAUAAAAAWDrLdZGwO++8M5MmTaqvWgAAAAAAVirLFdCec845eeyxx+qrFgAAAACAlcpyBbQ//elPc99999VXLQAAAAAAK5XlCmh/85vfZLXVVstvf/vbTJkypb5qAgAAAABYKSzXRcJ+8pOfJEnef//9PPzww/n2t79d6/iDDz64PNMDAAAAADRqyxXQDh8+vL7qAAAAAABY6SxXQLvrrrvWVx0AAAAAACudZdqDdtGiRXnnnXdSWVlZ3/UAAAAAAKw0liqgraqqyqmnnpoePXpkp512ymabbZZhw4Zl6tSpK6o+AAAAAIBGa6m2OLjgggvyj3/8I7///e+z7rrr5qOPPsrll1+eY445JldcccWKqhEAAAAAoFFaqoD27rvvzpFHHpmf//znxbHvf//72WuvvTJnzpy0bNmy3gsEAAAAAGislmqLg/fffz8bbrhhrbGuXbumUCjk/fffr9fCAAAAAAAau6UKaAuFQioqKmqNlZeXF48BAAAAAFB3S7XFQZIMHz48zZs3X2L8sMMOqxXelpWV5e67716+6gAAAAAAGrGlCmgHDx6csrKyJcY33XTTeisIAAAAAGBlsVQB7Z///OcVVQcAAAAAwEqnTnvQvv322znhhBNSVVVV54lnzpyZY489NrNnz17m4gAAAAAAGrM6BbQdOnRIZWVlhgwZkkmTJn3t+S+++GJ+/vOfZ80118zqq6++3EUCAAAAADRGddrioKKiImeddVauu+667LPPPtlxxx2zyy67pGfPnmnatGmSpKqqKs8880zuuOOOPPnkkzn66KPTv3//FVo8AAAAAMA32VLtQbvPPvtk5513zs0335zTTz89r732WlZfffXU1NSksrIyXbt2zU477ZQTTjghLVu2XFE1AwAAAAA0CksV0CZJu3btMmzYsAwbNixJMn369DRp0iRt2rSp79oAAAAAABq1pQ5oP69du3b1UQcAAAAAwEqnThcJAwAAAACg/gloAQAAAABKREALAAAAAFAiAloAAAAAgBIR0AIAAAAAlIiAFgAAAACgRAS0AAAAAAAlIqAFAAAAACgRAS0AAAAAQIkIaAEAAAAASqTeA9qqqqr6nhIAAAAAoFGqc0BbXV2dp59++guPvf3221m0aFHmz5+fTTfdNPPnz6+3AgEAAAAAGqs6B7RVVVXZb7/9MmXKlBx66KGprq5OksyaNSu//OUvc+WVV6Z58+YpFApp3rz5CisYAAAAAKCxqHNA27x581RUVGTRokWZMGFCTjnllCTJCSeckNatW2e//fZLWVlZ8QMAAAAAgK9W54C2SZMmadGiRdZaa61ccsklefTRR/POO++kpqYm5557bj766KMVWScAAAAAQKPTbGlOXrwytmPHjrn33ntTUVGRY445Jscff3zee++93H///SkUCiukUAAAAACAxqbOK2g/69BDD80DDzyQqqqq7LXXXhk3blyGDRtW37UBAAAAADRqdV5BO27cuOLX/fr1y3HHHZeKiopcfPHFueOOO1IoFDJz5swkySeffJJCoZCamppUVVXlO9/5Tp0eo6qqKq+88kqaN2+eDTbYYJn3sp08eXI6deq0TPcFAAAAAPhvqdMK2jPPPDP77LNPkuS+++7Lvvvum5///Oc54ogj8sEHH+Tb3/52jj/++PTp0ydJ8sMf/jB9+vTJlltume22265OhbzwwgvZbrvtMmLEiOy///7ZY489MmvWrCTJI488kv79+6dXr14ZMWJEFixYkCSprKzML37xi/Tr1y9vvPFG8dx333136V4FAAAAAIASqFNAO2DAgFx77bVZtGhRTj/99Bx//PFp2bJltttuu5x00kmZNGlSdt1119xwww1JkhtvvDE33nhjrr/++lx55ZVfO391dXWOOuqo/M///E/uvPPOPPjgg5k7d26uv/76TJw4MYcddlh22WWX3HHHHfnkk08yatSoJMlTTz2Vpk2bZsCAAbn99tuTJE888UQxKAYAAAAAaMjqFNB27do1m2++eZo1a5abb74506ZNy7XXXpuWLVvmb3/7W/75z3+mqqoqPXr0SJJsuumm2XTTTbPZZpvVKSydPXt29ttvv+y2225JktVWWy3rrrtuPvnkk4wePTpdu3bNoYcemk6dOmXEiBG55ZZbsmDBgsyYMSMdOnRIp06dMmPGjLz88svp2rXrsr8aAAAAAAD/RXXeg3ax9u3b5+KLL86QIUPSsmXLdO/ePb/85S8zderUZS6iTZs22W+//Yq3n3zyyTz++OMZNmxYTjzxxPTt27fW47dt2zavvvpqVl999cycOTMzZ87M6quvnrvvvjtHHHHEMteRJIVCIfPmzVuuOZKkrKwsLVq0WO554PMqKytTKBRKXUYSfc6KpddZGehzVhZ6nZVBQ+rzRK+z4jSkXtfnrCj10eeFQqHO19daqoC2pqYmSfLBBx9k0KBB2XvvvXPGGWekS5cuGT58eJIs84W9FhswYEBeffXVHHHEEdlkk00ye/bsrL322rXOad26daZMmZLevXtn5MiRGTduXE499dRMmTIl5eXly/X4CxcuzIQJE5ZrjiRp0aJFunXrttzzwOdNmjQplZWVpS4jiT5nxdLrrAz0OSsLvc7KoCH1eaLXWXEaUq/rc1aU+urzioqKOp1X54C2UCiksrIyCxcuzBFHHJGOHTtm7733zlZbbZWjjjoqPXv2TOfOnZe54MUuv/zy3HPPPRk1alR69OiRpk2bpnnz5rXOWWWVVTJv3ry0atUq9957b6qqqnLllVdm2223zcCBA9OxY8ecd955dX4RPqu8vDzrr7/+cj+P5Q2q4cuss846DeqvlbCi6HVWBvqclYVeZ2XQkPo80eusOA2p1/U5K0p99Pnrr79e53PrHNBWVlamqqoqs2fPTtu2bYsX6vrRj36UHXfcMYcddlhuvfXWJJ+uQl3Wlazt27fPAQcckNdeey033HBD2rZtm2nTptU6Z/bs2cXwtby8PPPnz09ZWVnuu+++bLnllnn++efzxBNPZJtttlnqxy8rK8uqq666TLXDf4O3b7Cy0OusDPQ5Kwu9zspAn7Oy0OusDOqjz5fmDwh1ukhY8mlhDz74YNq1a5crrrii1urUo446KqecckpqampSXl6ehQsXLlXB48ePz/Dhw2sl0xUVFWnatGl69OiRcePGFcfnzp2bSZMmpWPHjsWxW2+9NbvvvntmzJiR9ddfv3jRMAAAAACAhqzOAW1ZWVnWWmutLzzWrl279OzZM6uuumpeeOGFpV6Bus466+TZZ5/NiSeemPfeey///ve/849//CMDBgzIgAED8sADD+Tpp59OklxwwQVp27ZtNt544yRJVVVVpk6dmg4dOqR169aZPHlyPvjgg7Rp02apagAAAAAA+G9bqouE1dU777yTK6+8MgMGDEivXr2+9vxVV101l19+eU477bTssssuad++ff74xz+mX79+SZLhw4dn6NChadOmTebNm5dzzz03TZp8mi2PGTMmP/3pT5MkgwcPzrBhw9KhQ4f07t17RTw1AAAAAIB6U+eA9qmnnsqDDz6YY489tjh244035p133skf/vCHWud+/PHHqayszLBhw4orX7/OhhtumNGjR3/hsUMOOST9+/fPxIkT071797Rv3754bHGImyRdunTJww8/XNenBAAAAABQUnUOaGfOnLlE2Lpo0aLMmzcvSfLyyy9n0aJFadasWVq0aJEdd9wxd999d70V2qlTp3Tq1Kne5gMAAAAAKLU6B7RNmjTJ22+/nUMOOSTNmzdP69at8+6776Z58+aZPn16Tj755Lz99tvFC32VlZVll112WWGFAwAAAAB80y3VHrRt2rTJj3/841RVVWX27Nl599138/TTT2ebbbZJt27dcsghh2TQoEFp27btiqoXAAAAAKDRaFLXExcuXJhWrVrlxz/+cT766KMkSfPmzTNgwIA8+uijGTJkSP71r39lu+22yznnnJOFCxeusKIBAAAAABqDOge03/rWt7LlllumUChk2rRpmTZtWjp06JDNNtssbdu2zYABA3LVVVfl8MMPz2OPPZY99tijGOQCAAAAALCkOm9x8IMf/CCjRo3K+PHj06RJk9TU1KSmpiYTJkzIwIEDM378+IwaNSr/+c9/cuGFF+ahhx7KkCFDcsMNN6Rdu3Yr8jkAAAAAAHwj1XkFbZI899xzGTRoUB5//PEMHjw4gwcPzvPPP58kefTRR9O2bdusttpqWW+99TJixIjsueeead269QopHAAAAADgm26pLhKWpLjNweLPSfLRRx9l1113TZJceOGF+e1vf5trrrkmv/rVr+q3WgAAAACARmSpAtpCoZC+ffsmSbbZZpvi+LbbblvrnCQ57bTTctJJJ9VDiQAAAAAAjdNSBbQvvPBCPvroo0yYMCE77LBDKisrc++99+b+++/Pueeem+bNm6eqqipjx45Nz549V1TNAAAAAACNQp0C2vfeey+TJ09Oy5Yt89JLL+Wxxx7LWmutldtuuy3//Oc/s+uuu+bNN99MeXl5kuS73/1uPvjgg7z99tvZZJNNVugTAAAAAAD4pqpTQPuvf/0rZ555ZioqKrJo0aJUVlbmgQceKG5ncM011+Smm24q3k6S6urqVFVV5aWXXloxlQMAAAAAfMPVKaDdZ599ss8++yRJHn/88dx222352c9+lmeffTaPPPJIxo8fny222CL77rtvtthiixVaMAAAAABAY9Fkae/QoUOHbLnllundu3cOOeSQXH/99bntttvSpEmT3HzzzVm4cOGKqBMAAAAAoNFZqouEJcn3vve9fO9736s1tt566+Xcc8+tr5oAAAAAAFYKS72Ctq4WLFiQN954Y0VNDwAAAADwjbdMAe2cOXO+9pw333wzgwYNWpbpAQAAAABWCksd0M6fPz8/+MEPMnny5OLYxx9/nEKhUOu8ioqKlJeXL3+FAAAAAACN1FIHtM2bN0+hUEjz5s2TJPPmzcuPfvSjvPfee7XOKysrE9ACAAAAAHyFpQ5oy8rKkny6QjZJWrRoUSuwBQAAAACgbpb7ImGLA9smTVbY9cYAAAAAABqlZU5VFwezX3YbAAAAAICv1qwuJ2299dZZZZVVaq2S3WOPPWrd3nPPPdO0adPi7YULF9ZjmQAAAAAAjU+dAtqBAwemefPmadKkSQqFQi688MLsuOOOxf1nL7zwwuywww5ZbbXViveZPn167rrrrhVWOAAAAADAN12dAtrf//73tW5feOGFOeigg9KmTZvi7QMPPDBrrLFG8Zw333xTQAsAAAAA8BVc2QsAAAAAoETqHNBeddVVeemll5YYX7zX7KJFi+qvKgAAAACAlUCdtjiYN29ezj333MyfPz8bbbRRysrKioHswoULs+mmm67QIgEAAAAAGqM6raBdddVV8/DDD+e8885Lx44d07Rp0wwcODCXXnppmjZtmptuuint27evdZ9FixYVV9cCAAAAALCkOm9x0KZNm+ywww4577zz8tBDD+XHP/5xzj333Dz99NNfep/Ph7YAAAAAAPw/ddri4PPWXHPNnHzyyRk4cGA22WSTLzxngw02yD//+c/lKg4AAAAAoDFbpoB2sc0337y+6gAAAAAAWOnUeYuDz5oxY0buuOOOrz3vpZdeyvjx45flIQAAAAAAGr1lCmg/+uijnHTSSV973tixY3PwwQcvy0MAAAAAADR6SxXQvv322znppJPStGnTVFRUJEnmzJmTgw8+OK+88soS5z/77LPZaqut6qdSAAAAAIBGps4B7dNPP50999wzL7/8cmbOnJkmTT69a6FQyL///e/st99++d3vfpc5c+YkSSorK/Pkk0+mb9++K6RwAAAAAIBvujoFtNXV1fnTn/6UAQMG5Lrrrku7du1qHS8rK8tdd92VBQsWZO+9987777+f2267Lauuump22GGHFVI4AAAAAMA3XbO6nNS0adPcfPPNadmy5Zees+aaa+b888/P+eefnz333DOLFi3KEUcckfLy8norFgAAAACgManzFgdz586t03l77LFHCoVCFixYkF133XWZCwMAAAAAaOzqtIK2pqYmu+++e1q3bp0f/ehHWWuttb7wvBdeeCGHH354+vTpk/Hjx2f06NE58MAD67VgAAAAAIDGok4raBcuXJjjjz8+O++8c95+++1cdNFFmTlzZg444IA8+OCDSZJzzjkn++23X/bdd9+cffbZOfLII/O///u/qaqqWqFPAAAAAADgm6pOK2ibN2+enXfeuXj7jTfeyM9+9rN06dIlp59+egqFQq699tpcd9112WijjZIkP/7xj3P66afnwQcfrHVfAAAAAAA+Vec9aGtqarJo0aIkSVlZWZo1a5Zjjjkm//rXv3LIIYekqqoqZ5xxRqZPn/7pxE2aZIcddsi99967YioHAAAAAPiGq3NA+/DDD6dv374577zz8s4776SysjJJsuqqq+bII4/MLbfckg8//DA///nP8+GHHyZJ+vTpk3//+9+ZP3/+iqkeAAAAAOAbrM4BbefOnTN06NCMHz8+w4cPz6JFizJz5szi8Q033DC33HJLWrVqlYMPPjhz587NpptumosuuiirrLLKiqgdAAAAAOAbrc4B7frrr58DDzwwl1xySW666ab87Gc/W+Kc1q1b54orrsiCBQtyxBFHZI011kifPn3qtWAAAAAAgMaiThcJ+7xu3brl5JNP/sJjrVu3zl/+8pc88sgjy1UYAAAAAEBjt0wB7dfZeOONs/HGG6+IqQEAAAAAGo06b3HwVaZOnZrLL7+8PqYCAAAAAFhpLHVAO3/+/FxwwQWZNWtWcWz69Ok599xz67UwAAAAAIDGbqkD2urq6lx44YWZN29ecaxZs2apqKio18IAAAAAABq7pQ5oy8vLUygUUl5eXhwrKytL06ZN67UwAAAAAIDGrk4B7aJFi5YYKysr+8r7FAqFzJ8/f9mqAgAAAABYCTSry0knnnhi/u///q/W2FZbbbXEeV27dl1ibMKECctYGgAAAABA41angHbo0KEZNGhQmjRpkqqqqhxwwAG58MIL07p16yTJ+++/nxNPPDGXXnpp8T41NTVW0AIAAAAAfIU6BbTrr79+kk+3LVi4cGGSZNNNN80aa6yRJGnbtm2aNm2aXr16raAyAQAAAAAanzpfJOzDDz9M//79c8MNN6SsrOxr96AFAAAAAOCr1TmgnTt3bvr06ZObbrophUIhf/zjH/P0008n+XRlbU1NzQorEgAAAACgMapTQDtnzpyst956OeGEE3LPPffkjjvuSLt27fLLX/4yN910UxYuXJgFCxas6FoBAAAAABqVOgW0Z5xxRn7xi19k3LhxSZINN9wwp5xySu6+++7ssssu6dChQ0aOHLlCCwUAAAAAaGzqdJGwQYMG5dZbb82vfvWrtGvXLuXl5V943vnnn1/8uqamJlVVVbnnnnuy2mqr1U+1AAAAAACNSJ0C2s033zybb755fv/73+fyyy/Ptddem5YtW+aQQw5J69atv/A+iwPaioqKei0YAAAAAKCxqFNAu9gaa6yRo48+OnvssUeOP/74XHnllTnjjDPSp0+fFVUfAAAAAECjVac9aD9vvfXWy+jRo7PTTjvl29/+dn3XBAAAAACwUliqFbSfVV5enuOPP74+awEAAAAAWKnUaQVtVVVVRo0alVmzZn3pOTNmzMhBBx2UhQsX1ltxAAAAAACNWZ0C2rKyslx22WWprKz80nMKhULGjBmT8vLyeisOAAAAAKAxq9MWB4tD1/Ly8pxzzjmpqKhIoVDIwoUL8+tf/zonnHBC8dwRI0akuro66667bg466KAVUzUAAAAAQCNQ54uENW3aNE2aNMkll1ySxx57LGPHjs2ll16ahQsX5s4778z8+fOTJLNmzcodd9yxouoFAAAAAGg06hzQJp9uY5Akl156aS6++OLieFlZWU477bQkyWmnnZZCoWD1LAAAAADA11iqgPazysrK6rMOAAAAAICVzlIFtF8Uyi4e+/xnAAAAAAC+2tcGtK+99lq23nrrVFdXZ7fddkuSDBw4MIMGDSp+/fnPZWVl2X777TN48OC8+OKLK6p2AAAAAIBvtK8NaL/zne/khBNOSJMmTXLUUUclSX73u9/ld7/7XfHrL/r8xz/+MWVlZbn22mtXSOEAAAAAAN90zb7uhNVXXz077LBDysrKstVWWyVJttlmm9TU1CRJtt566y/83Ldv39x3330pLy9fIYUDAAAAAHzTfW1A+2W+aq/ZQqGQJDnuuOOy+uqrL+tDAAAAAAA0assU0N57773FEParCGcBAAAAAL7cUgW0ZWVl6dSpU6655poUCoWsvfbaWbhwYQqFQhYtWpQkqa6uTvLpKtqvWmULAAAAALCyq3NAW11dnUWLFuX/+//+v1rjM2bMSP/+/VNVVZUkqampSf/+/bNo0SL7zwIAAAAAfIUmdTmpqqoqa665ZnF17Ge1bds2o0aNSnl5edZff/20bNmyeBsAAAAAgC9XpxW0FRUVeeSRR77ynHbt2uUf//hHvRQFAAAAALAyqNMKWgAAAAAA6p+AFgAAAACgRAS0AAAAAAAlIqAFAAAAACgRAS0AAAAAQIkIaAEAAAAASkRACwAAAABQIgJaAAAAAIASEdACAAAAAJSIgBYAAAAAoEQEtAAAAAAAJSKgBQAAAAAoEQEtAAAAAECJCGgBAAAAAEpEQAsAAAAAUCKNMqCdPHlyqUsAAAAAAPhaDSagnTBhQvbaa69svPHG6dWrV84444zU1NQkSR555JH0798/vXr1yogRI7JgwYIkSWVlZX7xi1+kX79+eeONN4rnvvvuuyV7HgAAAAAAddUgAto5c+bkoIMOyhZbbJGHHnoof/3rX3P99dfn9ttvz8SJE3PYYYdll112yR133JFPPvkko0aNSpI89dRTadq0aQYMGJDbb789SfLEE0+kT58+pXw6AAAAAAB10qzUBSTJ66+/ngEDBuSoo45Kkqy55prp1atXnn/++Tz77LPp2rVrDj300CTJiBEjsvPOO+eoo47KjBkz0qFDh3Tq1CnPPvtsXn755XTt2rWUTwUAAAAAoM4aREDbo0eP9OjRo3i7uro6b7zxRrbZZpvceeed6du3b/FY+/bt07Zt27z66qtZffXVM3PmzMycOTOrr7567r777hxxxBHLVUuhUMi8efOWa44kKSsrS4sWLZZ7Hvi8ysrKFAqFUpeRRJ+zYul1Vgb6nJWFXmdl0JD6PNHrrDgNqdf1OStKffR5oVBIWVlZnc5tEAHt5914442ZP39+dtttt1x33XVZe+21ax1v3bp1pkyZkt69e2fkyJEZN25cTj311EyZMiXl5eXL9dgLFy7MhAkTlmuOJGnRokW6deu23PPA502aNCmVlZWlLiOJPmfF0uusDPQ5Kwu9zsqgIfV5otdZcRpSr+tzVpT66vOKioo6ndfgAtrXXnstZ511Vk4++eS0atUqTZs2TfPmzWuds8oqq2TevHlp1apV7r333lRVVeXKK6/Mtttum4EDB6Zjx44577zz6vwifFZ5eXnWX3/95X4edU3IYWmts846DeqvlbCi6HVWBvqclYVeZ2XQkPo80eusOA2p1/U5K0p99Pnrr79e53MbVEA7c+bMHH744dl9990zcODAJEnbtm0zbdq0WufNnj27GL6Wl5dn/vz5KSsry3333Zctt9wyzz//fJ544olss802S11DWVlZVl111eV/MrCCePsGKwu9zspAn7Oy0OusDPQ5Kwu9zsqgPvp8af6A0GS5H62eVFZW5rDDDst3v/vd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W2ndunWJqwYAAAAA+HoNfg/aJBk5cmQOOeSQ/POf/8zs2bMzaNCgbLPNNlm4cGGaNWuW1q1bp1WrVll//fVz3nnn5Zxzzil1yQAAAAAAX6usUCgUSl1EXcybNy9PP/102rZtm0022aTU5QAAAAAALLdvTEALAAAAANDYNPg9aAEAAAAAGisBLQAAAABAiQhoAQAAAABKREALAAAAAFAiAloAAAAAgBIR0AIAy6SqqiovvPBCJk6cmEKhUOpyAAAAvpEEtPxX1dTUZPjw4Tn//PNrjT/yyCPp379/evXqlREjRmTBggUlqhCW34QJE7LXXntl4403Tq9evXLGGWekpqYmiV6n8XjhhRey3XbbZcSIEdl///2zxx57ZNasWUn0OY3L6NGj06VLl1ofV111VZJP/x/svvvu6dmzZw4//PDMnDmzpLVCfXjttdfSo0ePPP/888Ux39f5JluW30Grq6tzxhlnZIsttsh2222Xe+65579dNiy1L+v10aNHZ5tttkm3bt2y4447ZsyYMcVjer3hENDyX7NgwYIcc8wxuf/++2uNT5w4MYcddlh22WWX3HHHHfnkk08yatSoElUJy2fOnDk56KCDssUWW+Shhx7KX//611x//fW5/fbb9TqNRnV1dY466qj8z//8T+688848+OCDmTt3bq6//np9TqPz7LPP5vDDD8/TTz9d/PjFL36RadOm5Ve/+lW6d++eO++8M2uuuWZGjBhR6nJhuSxcuDBHH3109tprr2y66aZJ/KzON9uy/g7617/+NX//+99z/vnnZ9SoUTn99NMzfvz4/3b5UGdf1uv33ntvLrroopx88skZM2ZMtt566/zmN7/JnDlzkuj1hkRAy3/NiSeemPLy8vTs2bPW+OjRo9O1a9cceuih6dSpU0aMGJFbbrnFX+b5Rnr99dczYMCAHHXUUVlzzTWz9dZbp1evXnn++ef1Oo3G7Nmzs99++2W33XZLkqy22mpZd91188knn+hzGp1nn302W265ZVq1alX8qKioyC233JIWLVrk+OOPT6dOnXL00UfnqaeeyocffljqkmGZXXTRRZk1a1aOOOKI4pjv63yTLcvvoFVVVbn22mtz+OGHp3fv3unZs2f222+/XH/99SV6FvD1vqzX33nnnYwcOTJ9+/ZNu3btcvDBB2fu3Ll57bXX9HoDI6Dlv2bYsGE57bTTUl5eXmv85ZdfztZbb1283b59+7Rt2zavvvrqf7tEWG49evTI0UcfXbxdXV2dN954I+uuu65ep9Fo06ZN9ttvv+LtJ598Mo8//nh23nlnfU6j8uGHH+b999/PySefnO7du2f77bfPNddck+TTn1/69OlT/LmmefPm2XDDDfPcc8+VsGJYdi+99FIuueSS7LDDDrn33nvz1ltvJfGzOt9sy/I76KRJkzJv3rxax3v27Flr2w9oaL6s1w855JBsu+22xduvvfZamjRpks6dO+v1BkZAy39N586dv3B89uzZWXvttWuNtW7dOlOmTPlvlAUr1I033pj58+dnt9120+s0SgMGDMh+++2Xgw8+OJtssok+p1F55ZVXsvbaa+eoo47Kgw8+mOHDh+fMM8/MI488otdpVAqFQv70pz9ltdVWS1lZWSZOnJi99torV111lV7nG21ZfgedPXt2mjZtmk6dOhWPtWrVSs/ToH1Zr39WTU1NzjvvvOy6665p166dXm9gmpW6AGjatGmaN29ea2yVVVbJvHnzSlQR1I/XXnstZ511Vk4++eS0atVKr9MoXX755bnnnnsyatSo9OjRQ5/TqPTt2zd9+/Yt3h48eHDGjh2bv//973qdRmXcuHF56aWXcvHFF2e77bZLkmy++eb57W9/m44dO+p1Gp2v+h7+rW99KxUVFbWOtWjRQs/zjXfBBRfk/fffz8UXX5wkadasmV5vQKygpeTatm2badOm1RqbPXv2Et8o4Jtk5syZOfzww7P77rtn4MCBSfQ6jVP79u1zwAEHZMCAAbnhhhv0OY3emmuumXfffVev06h88MEHadasWbbZZpvi2CabbJLq6uq89957ep1G56u+h7dt2zaVlZXFiyh99hh8Uz344IO5/PLLc95556Vdu3ZJotcbGAEtJdejR4+MGzeueHvu3LmZNGlSOnbsWMKqYNlVVlbmsMMOy3e/+90ce+yxxXG9TmMxfvz4DB8+PIVCoThWUVGRpk2b6nMalfPPPz+XXnpprbFx48alQ4cO6dmzZ61eLxQKGT9+fDp06PDfLhOWW8eOHVNTU5P58+cXx959990kn64c932dxuarfl7p1KlTvvWtb9U6/uKLL/r+zjfWc889l9/97nc5+eSTs9lmmxXH9XrDIqCl5AYMGJAHHnggTz/9dJJPl923bds2G2+8cYkrg6VXKBRy5JFHZsaMGRk5cmQWLFiQuXPnZv78+XqdRmOdddbJs88+mxNPPDHvvfde/v3vf+cf//hHBgwYoM9pVDbZZJNceumlue+++zJ+/Piceuqpee6557Lvvvtmp512yoQJE3L33XcnSa6//vrMmjUrW221VYmrhqW36aabZp111skJJ5yQyZMnZ/z48TnttNOy5ZZbZsiQIb6v0+h81c8rTZo0Sf/+/XPeeedlzpw5mTFjRq666qr069evxFXD0nvrrbdy4IEHZp999skOO+yQuXPnZu7cuVm0aJFeb2DsQUvJdevWLcOHD8/QoUPTpk2bzJs3L+eee26aNPH3A755Jk6cmIcffjhJal0Ns3fv3hk9erRep1FYddVVc/nll+e0007LLrvskvbt2+ePf/xj8Yc5fU5jse222+bII4/MaaedlpkzZ6Zbt2655ppr8oMf/CBJcuqpp+bYY4/NyJEjM3PmzJx44olp3bp1iauGpdesWbNcccUVOeOMM7LHHnukqqoqffr0ySmnnJI11ljD93Uana/7HfQ3v/lNDjrooGyzzTYpFArp3Llzhg0bVuKqYendcMMNmT17di677LJcdtllxfGRI0dmt9120+sNSFnhs+9PhBKaPHlyJk6cmO7du6d9+/alLgdWGL3OykCfs7L46KOP8sILL6RLly61roIMjY3v6zRGX9XXNTU1GTduXKqqqtK7d++Ul5eXqEpYsfR6wyCgBQAAAAAoEe9LAQAAAAAoEQEtAAAAAECJCGgBAAAAAEpEQAsAAAAAUCICWgAA/mtqamoyd+7cOp9fXV29xJhr3AIA0JgIaAEAGqDq6uo899xzueaaa4pjkydPzjHHHJMXX3xxueY+44wzctRRR33p8aqqqixYsOBrg9CamprMnz8/VVVVX3h8p512qlV/krz00kv54Q9/mHHjxn1tnW+99Va23377PPHEE7XGjz766PzkJz9JoVDIG2+8kfnz53/h/RctWpRZs2bV+aOysnKJOd54441MmzateHvy5MmZPHny19a+PN58880sXLhwhT5GY7No0aK8+eabpS4DAGCZNCt1AQAAfOq6667L+PHjM3ny5Lz88stp0aJFOnfunK233jrrrLNOrr766jz55JM57rjjvnSO+fPnp2nTpikvL0/yaYi6YMGCNGvWrDhWVVWVGTNmfOkcV111Vf7yl7/Uue4TTzwxe++99xLjlZWVqampqTX21FNPpWPHjtlss82+dt4bbrghq666ajbddNNa423atEmLFi1SKBTy+9//Puuss84X1jt27NgcdNBBdX4e/fv3zznnnFNr7Ne//nX23HPPHHjggUmSkSNHplAo5KKLLsorr7ySu+66a4l59t9//3z729+u8+N+1gcffJChQ4dm1KhR2XzzzZdpjpXRc889lyOPPDI333xzOnToUOpyAACWihW0AAANRLt27dKxY8cMHTo0NTU1ueiii3LddddlnXXWyUcffZT/+7//y/vvv58f/OAH6dKlS7p06ZItttgi8+bNK85x2GGHZeONNy4e79q1a3r06JExY8YUz2nSpElWXXXVL61jr732ykMPPZRHH300Y8aMyZgxY3LnnXcmSf7yl78Ux/7973/ngQceyC677PKF8zRr1izNmtVeD/DQQw9l3XXXzX333Zd//vOftT5mzZpVPG/atGm5+eabc/LJJ6dQKNRapbv66qunefPmadKkSc4+++wk+cJtEyoqKpIkEydOLH78+9//zh577JFx48bVGt91111r1VpTU5OqqqpUVFQU50mS8vLyrLLKKqmqqspbb72Vyy67LK1atUqrVq1SVVWVyy67LHPmzPnS1/ar1NTU5De/+U2GDh2azTffPE8++WS6dOmSAQMGFM+577770qVLlwwZMqTWfcePH58uXbrkjjvuWOrH7devX7FfNt544wwYMGCZ5qmL2267Lf369auXuRa/Pkmy+eab54ADDshvf/tbW2AAAN84VtACADQQO++8c/Hrpk2bFr+urq7Osccemy222CIXX3xxcXzIkCHp3bt3rbD19NNPz6JFi4qh4uKgsVAo5Pnnn09FRUWmT5+euXPnZsKECcX7rb322llttdWSJK1bt84tt9yStddeOzvuuGOtGlu1alVcHXrPPffk6quvzkUXXVQ8XigUUllZmRYtWhTHqqqqUlZWlo8//jj/+c9/0rVr11x66aW1jr/22mu5884706pVqyTJmWeemR122CGbb755Lrjggtx222257bbb0qZNm+Lz+vDDD/P2229nrbXWyv77759DDz20VvjXrFmzNGny6XqEDz/8MIsWLcrUqVNz66235le/+lXmzJmTJk2aZM0110yS4grjJHn99deLwehpp52W0047rdbr8Oabb2b48OFJkoMPPjhJ8uqrr+bqq69eIpSuq1tuuSUVFRX55S9/WWt80qRJxbD4lVde+cL7PvbYY8XPgwcPXurH3nHHHXPwwQdn3rx5GTt2bI455pi0aNEiO+2001LP9VW22267bLTRRvU652K//OUv88ADD+TWW2/Nz372sxXyGAAAK4KAFgCgASgUCpk7d24qKiqKQWGhUMi8efNy3XXX5bnnnsuoUaMyZMiQnHvuufnPf/6TyZMn1wpsk6R9+/ZfOP8tt9ySESNG1Br7bJB3880319pK4MUXX8yll16a7t27f+FbxmtqanLBBRdklVVWKYamSTJjxoz06dOnePuUU07JKaeckmOPPTYzZsxIt27dctttt9Wa69VXX82AAQPSvHnzJMn111+fRx55JHfeeWemT5+e0aNHZ+jQofnXv/6VN998Mw8++GBef/31/PSnP023bt3SpUuXDB48OOuvv36teT8b0P7+97/PU089VTy2OAzv27dvLrnkkiRJWVlZ8fj3v//9vPjii/nZz36WgQMH5le/+lWS5Mgjj0zTpk1z+umn11qV/FmfnWdpXHHFFTnzzDOXGF+4cGHeeOONdO3aNRMnTvzC+44dOzbl5eV5/PHHUygUlrqGtm3bpnv37kmSLbbYIq+99lquueaaeg9o27Ztm7Zt29brnJ/1hz/8Iccee6yAFgD4RhHQAgA0AB9//HG22267VFRUpKysLLNnz87QoUNTXV2d008/PTfffHPWWmut3HLLLdl7772zYMGCXHjhhcVVr8mnK1GbNGmyxArORYsWZfvtt8+OO+6YZs2aZeTIkZkzZ05OO+20zJ07N1tvvXVat25d6z4nnXRSBgwYkOOOOy7/+7//u0S9N9xwQyZNmpQbb7yxGIImn66wvf3229O8efMMHTo0u+++e3bcccc0b948v/jFL/K73/0u//u//5uf/exnadmyZZIUL4i1OKD95z//mZkzZ2bbbbdNkyZN0qVLlxx88ME56KCDstZaa6V79+6ZO3duHn744VpB5Of31S0rKyvWduGFF6ZQKGTatGnp379/Hn/88VRUVCyxR+5n77t4FfJ1112XBx54IMmnFy7baqutiv9OSYr7737Zxcrq4pVXXkl1dXV69OixxLGePXtm4sSJ6dq1a1555ZVssskmtY7Pnz8/48aNy5AhQ3LllVdm4sSJ2XDDDZe5liRZd9118/e//3255iiFHj16pKqqKq+++mo22GCDUpcDAFAn9qAFAGgAvvWtb+XFF1/MuHHjcsIJJyRJrr766jz//PP56U9/mvbt22fMmDGpqqrK3Llzc8UVVyzxVvETTjghG220UXE/0cUfG220UX7xi1+kdevWWW211bJgwYK0adMmq622WnG/zs8GvcmnF+I68sgjM3bs2OL+s4u9++67Ofvss7P33nsvcQGvZs2apVu3bllvvfVSXl6eb33rW+nWrVsefPDBrLrqqtl5551z44035uijjy7eZ3FAuzgQPe6443LnnXfm8ccfzxprrJE//elPadq0aa688sqccsop2XHHHTNr1qxMmjQp99xzT84+++zsvvvu2XLLLTNlypTivNXV1WnWrFmmTZuWd955Jx988EHx+Pvvv58PPvgg77//fiZPnvyV/zb77LNPbrjhhtxwww3Zdttti+OLX7vFx84444yvnOerTJw4MT179vzCYxtssEFeeeWVzJkzJ++//35x39XFnnnmmVRVVWXIkCFp06ZNxo4du8x1LDZ16tRaFzp75ZVXMnTo0Gy66abZfvvtc9VVV9U6f/HeslVVVTn77LPTt2/fL9zH9qv2oH3++efz85//PN27d8+OO+64xP3feuutDBkyJN27d8+gQYO+dLuHxYE2AMA3hRW0AAANzOjRo5MkV111VTbbbLO89tpruemmm4oXjHryySfzyCOPZL311qt1v2OPPTZ/+MMfUl1dnR//+Mf505/+lO233z7V1dWprq4unjd9+vR897vfTfL/Lq712T1jFxs0aFCefvrp/OhHP6p1/48//jjrrbdejjrqqDo/p1/96lfZYYcd0rJly/z1r3/NHnvskUceeSTbbrvtEitoF6/+PPXUU7PddtsVV5VeffXVefnll/P8889n7ty52XPPPYsXQtt7773TtWvXfOtb3yo+5pw5c9K8efPcfffdOeuss1JRUZEmTZpk9dVXL16IbdGiRfnJT35SaxXw55155pm1th5YvDftl62+XRafD0Q/a4MNNsiDDz6YV155Ja1atUr79u3z9ttvF48/9thjWXvttdOxY8f07t07jz322BL72NbV3Llz8/jjj+fee+/Nb37zmySfrkzef//9s/nmm+fSSy/NxIkT8+c//zmrrbbaElsJDB8+PHPmzMkBBxxQ3DKhLl5//fXsv//+2XrrrXPJJZfkySefzLHHHpuysrIMGjQo1dXVOeyww9KkSZNccMEFmTx5cv7yl7984Vzf/va389FHHy3T8wcAKAUBLQBAA3LPPfdk3rx5admyZTp06JA///nPOeWUU7L//vunc+fOOeywwzJ//vycccYZxRWbO+ywQy644ILiNgUPPvhgVlllleyyyy5ZuHBhPvjgg1pveX/33Xezww47JFkyoH3ttddSXV1d3Af3wAMPzIwZM4rbB0yZMiVrrbVWzjjjjEyZMiVTpkzJggULUlNTk4033vhLn1fTpk2zzjrrJEm6du2aCy+8MOuuu26eeeaZLFq0KMn/W0GbfLrS8p///GfuueeeVFVVZd68eZkyZUo6d+6cn/70p/nDH/6Qs88+Oz/60Y9y1113ZcKECRk0aFCti6vNnDkzq622Wvbff//stddeqaqqWqKu5s2bp3nz5jnmmGO+tPY//OEPxT1ojznmmGK9i0PrxRc8mzZt2pfO8XWaNGlSXJH7eRtssEH+9re/ZeLEiV/4tv2xY8emd+/eST7dP/ass84qXlSsrm666abcdNNNST79t9p7772z//77J/l0i4cmTZrknHPOSUVFRbbYYos89dRT+fvf/14roH3vvfey0UYbZfTo0V8ZeH+Ryy67LN/61rcyatSolJeXZ8stt8yHH36Yc889N4MGDcpjjz2W119/Pbfccktxi4fJkycvsZI3+TQ4/2wfAAA0dAJaAIAG4r333stJJ52UP/zhDxk5cmT69u2bNdZYIy1btkzbtm1z2GGH5cMPP8xTTz2V1q1bp6amJv369VviQk633nprBg8enIqKilxyySW5++67c9ddd6VZs2aprKzMO++8U1x9O2/evJSXlxcDrT/+8Y+ZMGFCMaBdbHF4ePrpp9cKvwqFQqqqqtKmTZs8+uijdX6ubdq0yd57752f/OQn2XrrrWvt+Tp27Ngce+yxadGiRfr27Zu5c+fm5z//eU466aTi/TfeeOM8++yzWX311fPHP/4xPXv2zPTp02tdJO3dd9/NmmuumSQ577zzcsUVVyxRx7Bhw3LkkUcuMT579uxUVVWlpqYmCxYsyKxZs5J8uh3DwoULM2XKlFRWVqZp06bFi54tXgm8LL797W/npZde+sJjG2ywQT7++OOMGTNmie0NPv7440ycODGvvPJKbr311uL4uHHjal2s7evstNNO+fWvf53y8vJ06tSpuJo5+XT7henTpy+xIvbzK37Ly8tz3HHHLXU4myQvvfRSNt9881p916dPn9xxxx2ZPn163nrrrTRr1qzWHwF+8IMffGFAO3Xq1CX26QUAaMgEtAAADcAnn3ySAw44IGuuuWYGDx6ckSNHJkkOOOCAzJgxIwMHDsx3vvOd/OEPf8htt92WAw44IP/3f/+XsrKyWgHtm2++mcceeyx/+tOfkiRDhw7N1VdfXby42Pjx49OsWbNi2DZ37tysuuqqxfvfeOONX1jf9OnT06dPn5x77rnZZptt6vy8Fi1alPvvvz9rrLFGevXqlZqamlxzzTU5++yz87Of/SxHH310HnnkkVqrPTfZZJMcccQR6dq1azp16pT27dsXLyi2WN++fXPxxRfnyiuvTL9+/XLmmWcusWry1VdfLW7l0KJFi/Tp06dWoDdkyJBaQeRnXXbZZbnmmmuKe99eeeWVST4NpBcuXJg33ngjAwcOzPe+973cc889xcdbvP3B0tpoo41y1llnpVAo1LrwWfJpmL3mmmvmoYceysknn1zr7ftjx45NoVDIddddV9xH+MADD8yYMWOWKqBt06ZNunbt+qXHN9lkk5x88sm1xj7/eq+55prp0KFDnR/zs75s9fBiNTU1KSsrq/XafFEQXCgU8swzzxS3ZwAA+CYQ0AIANACtW7fOPvvsk0022WSJ4Ktt27Y5//zzs+GGG+btt9/OhRdemJkzZ+b666/Pn/70p2K4OX/+/IwYMSIbbrhhHn300bz77rt56623UlZWlr/97W/Zfffdc/vtt2ebbbbJKquskuTTFbSLv64vs2bNytixYzNr1qyceeaZadasWc4+++y8/fbbOe644/LCCy/k1FNPzeDBg5N8uvL0s0Fpy5Yt8+tf/zo1NTV555138tBDD+W5557Lvvvum3XXXTdJsmDBgkydOjU9e/bMWWedVdwiYHGAV1NTk2eeeSYHHnhgkq8PAD/vqKOOylFHHZV77rkn3bt3T6dOnTJv3rzcf//9xbqHDRu2xIrWZbXuuuumdevWeeKJJ74wWN1ggw3y0UcfFT8vNnbs2Ky77rrZfPPNi2O9evWqlwuFLfb9738/zz77bNZbb71ir91zzz155plnihe0W17du3fPuHHjsmjRojRr9umvKE8++WTWWmuttGvXLp07d87ChQszceLE4nYd//nPf5aY54knnki7du3yve99r17qAgD4b1j69x8BALBC7L///unZs2eSJQPFTTfdNM2bN88GG2yQfffdNxdffHEGDRqUXXbZpXjOlClT8txzz2XixIm56aabMmXKlGy88cY54YQTMmfOnNx+++254447su+++xbvM3fu3C+8QNiyeuihh9K7d+/89re/zfrrr58//elPeeyxx7Ljjjvm4Ycfzuuvv57Ro0cXQ87k01W2nw1oL7/88uy8887ZdNNNM2DAgNx0001ZZZVV0rp168ycOTO///3vi3uTvvTSS8WtAX7+85/nwQcfTJI888wzmTp1anFv1srKyjz++OPp0qVL8eOpp57KggULvvS5TJo0Kccdd1weeeSRJMnbb7+dE088Mddcc00++uijjBkzJn379q231+7Xv/51/vznP9e6INtiG2ywQcrKypbYg/axxx6rFc4mn771f8KECZk+fXq91LXvvvumqqoqRx55ZB5//PHcddddOemkk5ZpK4Mvc9BBB2Xq1Kk56qij8vjjj+fcc8/NHXfcUVwJ+6Mf/SidO3cu/nvccMMNufbaa2vNUV1dnT//+c/59a9/XW91AQD8N1hBCwDQAFVXVxeDutmzZ2fy5Ml55ZVXcv/99+fRRx/NoYcemt/+9re17tO5c+fccccdWXfddYurEBfr0aNHDjzwwGy//fbFFZqFQiEvvvhiWrVq9bX11NTUFO/zVX74wx9m4MCB+eUvf1nrwmTJp1sK9OvXL2uvvXat8XfeeadWQLvVVlvlnXfeydFHH50+ffqkefPm+fjjj3PVVVflhhtuyBprrJGbb745G264YZo3b55f/vKX+dGPfpTnnnsuLVu2TE1NTf7yl7+kU6dO6datW5Lkt7/97RLB3cKFC/PWW2/lhRdeyFtvvVVrf9NPPvkkw4cPz+67714MtLt27Zrjjz8+V1xxRZ555pm0bt261vYSi/+9Pr9FQV31798/t912W84888wce+yxtY516dIla621VnEbgyR54403MmXKlPTq1avWuT/4wQ9SKBQyduzYWgH+smrXrl2uuuqq/PnPf84hhxyS1q1bZ4899lii/5bH+uuvn6uvvjqnn356DjrooHTo0CEjR44sBvnl5eW5/PLLc+KJJ+aII47Id77znQwbNiznnHNOcY4zzjgja6655hJ7MgMANHRlhaV9vxcAACtct27dcvHFF6dXr14ZPHhw3nnnnbRp0yY77bRThgwZku9///t1nmv69OkZOnRo5s+fn1tvvTWtWrXKWWedlRtvvDFz5szJsccem6FDh37lHO+//3622267XHjhhfnxj3+8nM/u0zDzV7/6VSorKzN+/PhsscUWX3gRr8Xmz5+fAw88ML169cqvf/3r4rYM1dXVOfvss3P11Vdnjz32yMknn5wFCxbkxBNPzEYbbVRrtfDnFQqFDBgwIG+//Xa+973v5fTTTy/uzfuvf/0r1157bS666KIlLph27bXX5pRTTsnJJ5+cvfbaK0ny6KOP5ve//33mz5+fJ554Ypm3jZg1a1b23nvvnHDCCdliiy2WaY6V0ZNPPpmTTjopN954Y53+4AAA0JAIaAEAGrjx48dnwYIF6dGjxzK9rbympiZXXXVVtttuu6yzzjpJPl19+eSTT2azzTZbYqXrF3nrrbey00475a9//Wt23nnnpa7hixxwwAF5++2307Nnz/zmN79J586dl3muBQsWLHHBr+rq6iX28/28qqqqWhcoq4tFixblzjvvzG677VYcmzNnTi688MIMGjSoTq/nV5k5c2batGmzXHOsjLxuAMA3lYAWAAAAAKBEXCQMAAAAAKBEBLQAAAAAACUioAUAAAAAKBEBLQAAAABAiQhoAQAAAABKREALAAAAAFAiAloAAAAAgBIR0AIAAAAAlIiAFgAAAACgRP5/h5fgY3mW2DsAAAAASUVORK5CYII="
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"图表已保存为 ma_channel_event_probability.png\n"
|
||
]
|
||
}
|
||
],
|
||
"execution_count": 29
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-09-24T08:36:29.890785Z",
|
||
"start_time": "2025-09-24T08:36:29.734715Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"import pandas as pd\n",
|
||
"import numpy as np\n",
|
||
"import talib\n",
|
||
"\n",
|
||
"\n",
|
||
"# --- 1. Core Backtesting Engine with ATR Stop-Loss ---\n",
|
||
"\n",
|
||
"def run_backtest(df_raw: pd.DataFrame, ma_period: int, atr_period: int, atr_multiplier: float, stop_loss_multiplier: float):\n",
|
||
" \"\"\"\n",
|
||
" Executes a channel breakout backtest with a fixed ATR-based stop-loss.\n",
|
||
"\n",
|
||
" Args:\n",
|
||
" df_raw (pd.DataFrame): The original OHLCV data.\n",
|
||
" ma_period (int): The period for the moving average.\n",
|
||
" atr_period (int): The period for ATR calculation.\n",
|
||
" atr_multiplier (float): The ATR multiplier for the channel.\n",
|
||
" stop_loss_multiplier (float): The ATR multiplier for the stop-loss distance.\n",
|
||
"\n",
|
||
" Returns:\n",
|
||
" pd.DataFrame: A DataFrame of all completed trades.\n",
|
||
" \"\"\"\n",
|
||
" # --- Data Preparation and Indicator Calculation ---\n",
|
||
" df = df_raw.copy()\n",
|
||
" df.dropna(inplace=True)\n",
|
||
"\n",
|
||
" df['ma'] = talib.SMA(df['close'], timeperiod=ma_period)\n",
|
||
" df['atr'] = talib.ATR(df['high'], df['low'], df['close'], timeperiod=atr_period)\n",
|
||
"\n",
|
||
" df['upper_band'] = df['ma'] + atr_multiplier * df['atr']\n",
|
||
" df['lower_band'] = df['ma'] - atr_multiplier * df['atr']\n",
|
||
"\n",
|
||
" df.dropna(inplace=True)\n",
|
||
"\n",
|
||
" # --- Backtesting Loop ---\n",
|
||
" position = 0 # 0: flat, 1: long, -1: short\n",
|
||
" entry_price = 0.0\n",
|
||
" stop_loss_price = 0.0\n",
|
||
" trades = []\n",
|
||
"\n",
|
||
" print(\"Starting backtest...\")\n",
|
||
" for i in range(1, len(df)):\n",
|
||
" # Get current and previous bar data\n",
|
||
" prev_close = df['close'].iloc[i - 1]\n",
|
||
" current_close = df['close'].iloc[i]\n",
|
||
" current_low = df['low'].iloc[i]\n",
|
||
" current_high = df['high'].iloc[i]\n",
|
||
"\n",
|
||
" prev_upper = df['upper_band'].iloc[i - 1]\n",
|
||
" current_upper = df['upper_band'].iloc[i]\n",
|
||
"\n",
|
||
" prev_lower = df['lower_band'].iloc[i - 1]\n",
|
||
" current_lower = df['lower_band'].iloc[i]\n",
|
||
"\n",
|
||
" current_atr = df['atr'].iloc[i]\n",
|
||
"\n",
|
||
" # --- Core Trading Logic ---\n",
|
||
"\n",
|
||
" # Entry Logic (when no position is held)\n",
|
||
" if position == 0:\n",
|
||
" # Short signal: Crossing down through the upper band from above\n",
|
||
" if prev_close > prev_upper and current_close < current_upper:\n",
|
||
" position = -1\n",
|
||
" entry_price = current_close\n",
|
||
" stop_loss_price = entry_price + stop_loss_multiplier * current_atr\n",
|
||
" trades.append({'entry_time': df.index[i], 'type': 'short', 'entry_price': entry_price})\n",
|
||
" # print(f\"{df.index[i]}: Short entry @ {entry_price:.2f}, SL @ {stop_loss_price:.2f}\")\n",
|
||
"\n",
|
||
" # Long signal: Crossing up through the lower band from below\n",
|
||
" elif prev_close < prev_lower and current_close > current_lower:\n",
|
||
" position = 1\n",
|
||
" entry_price = current_close\n",
|
||
" stop_loss_price = entry_price - stop_loss_multiplier * current_atr\n",
|
||
" trades.append({'entry_time': df.index[i], 'type': 'long', 'entry_price': entry_price})\n",
|
||
" # print(f\"{df.index[i]}: Long entry @ {entry_price:.2f}, SL @ {stop_loss_price:.2f}\")\n",
|
||
"\n",
|
||
" # Exit Logic (when a position is held)\n",
|
||
" elif position == 1: # Long position\n",
|
||
" # Take-profit exit: Crossing up through the upper band from inside\n",
|
||
" if prev_close < prev_upper and current_close > current_upper:\n",
|
||
" exit_price = current_close\n",
|
||
" trade = trades[-1]\n",
|
||
" trade['exit_time'] = df.index[i]\n",
|
||
" trade['exit_price'] = exit_price\n",
|
||
" trade['pnl'] = exit_price - trade['entry_price']\n",
|
||
" position = 0\n",
|
||
" # print(f\"{df.index[i]}: Long exit (TP) @ {exit_price:.2f}, PnL: {trade['pnl']:.2f}\")\n",
|
||
"\n",
|
||
" # Stop-loss exit\n",
|
||
" elif current_low < stop_loss_price:\n",
|
||
" exit_price = stop_loss_price\n",
|
||
" trade = trades[-1]\n",
|
||
" trade['exit_time'] = df.index[i]\n",
|
||
" trade['exit_price'] = exit_price\n",
|
||
" trade['pnl'] = exit_price - trade['entry_price']\n",
|
||
" position = 0\n",
|
||
" # print(f\"{df.index[i]}: Long exit (SL) @ {exit_price:.2f}, PnL: {trade['pnl']:.2f}\")\n",
|
||
"\n",
|
||
" elif position == -1: # Short position\n",
|
||
" # Take-profit exit: Crossing down through the lower band from inside\n",
|
||
" if prev_close > prev_lower and current_close < current_lower:\n",
|
||
" exit_price = current_close\n",
|
||
" trade = trades[-1]\n",
|
||
" trade['exit_time'] = df.index[i]\n",
|
||
" trade['exit_price'] = exit_price\n",
|
||
" trade['pnl'] = trade['entry_price'] - exit_price\n",
|
||
" position = 0\n",
|
||
" # print(f\"{df.index[i]}: Short exit (TP) @ {exit_price:.2f}, PnL: {trade['pnl']:.2f}\")\n",
|
||
"\n",
|
||
" # Stop-loss exit\n",
|
||
" elif current_high > stop_loss_price:\n",
|
||
" exit_price = stop_loss_price\n",
|
||
" trade = trades[-1]\n",
|
||
" trade['exit_time'] = df.index[i]\n",
|
||
" trade['exit_price'] = exit_price\n",
|
||
" trade['pnl'] = trade['entry_price'] - exit_price\n",
|
||
" position = 0\n",
|
||
" # print(f\"{df.index[i]}: Short exit (SL) @ {exit_price:.2f}, PnL: {trade['pnl']:.2f}\")\n",
|
||
"\n",
|
||
" print(\"Backtest finished.\")\n",
|
||
"\n",
|
||
" completed_trades = [t for t in trades if 'exit_price' in t]\n",
|
||
" return pd.DataFrame(completed_trades)\n",
|
||
"\n",
|
||
"\n",
|
||
"# --- 2. Performance Analysis Function (Unchanged) ---\n",
|
||
"\n",
|
||
"def analyze_performance(trades_df: pd.DataFrame):\n",
|
||
" \"\"\"\n",
|
||
" Analyzes trade records and prints a performance summary.\n",
|
||
" \"\"\"\n",
|
||
" if trades_df.empty:\n",
|
||
" print(\"No completed trades to analyze.\")\n",
|
||
" return\n",
|
||
"\n",
|
||
" total_trades = len(trades_df)\n",
|
||
" winning_trades = trades_df[trades_df['pnl'] > 0]\n",
|
||
" losing_trades = trades_df[trades_df['pnl'] <= 0]\n",
|
||
"\n",
|
||
" win_rate = len(winning_trades) / total_trades if total_trades > 0 else 0\n",
|
||
"\n",
|
||
" avg_profit = winning_trades['pnl'].mean() if len(winning_trades) > 0 else 0\n",
|
||
" avg_loss = losing_trades['pnl'].mean() if len(losing_trades) > 0 else 0\n",
|
||
"\n",
|
||
" profit_loss_ratio = abs(avg_profit / avg_loss) if avg_loss != 0 else float('inf')\n",
|
||
"\n",
|
||
" total_pnl = trades_df['pnl'].sum()\n",
|
||
"\n",
|
||
" profit_factor = winning_trades['pnl'].sum() / abs(losing_trades['pnl'].sum()) if abs(\n",
|
||
" losing_trades['pnl'].sum()) > 0 else float('inf')\n",
|
||
"\n",
|
||
" print(\"\\n--- Strategy Performance Summary ---\")\n",
|
||
" print(f\"Total Trades : {total_trades}\")\n",
|
||
" print(f\"Winning Trades : {len(winning_trades)}\")\n",
|
||
" print(f\"Losing Trades : {len(losing_trades)}\")\n",
|
||
" print(f\"Win Rate : {win_rate:.2%}\")\n",
|
||
" print(f\"Avg. Profit : {avg_profit:.2f}\")\n",
|
||
" print(f\"Avg. Loss : {avg_loss:.2f}\")\n",
|
||
" print(f\"Profit/Loss Ratio : {profit_loss_ratio:.2f}\")\n",
|
||
" print(f\"Total PnL : {total_pnl:.2f}\")\n",
|
||
" print(f\"Profit Factor : {profit_factor:.2f}\")\n",
|
||
" print(\"----------------------------------\\n\")\n",
|
||
"\n",
|
||
"\n",
|
||
"# --- 3. Main Execution Block ---\n",
|
||
"\n",
|
||
"# --- Strategy Parameters ---\n",
|
||
"MA_PERIOD = 10\n",
|
||
"ATR_PERIOD = 14\n",
|
||
"ATR_MULTIPLIER = 0.5 # Channel width\n",
|
||
"STOP_LOSS_MULTIPLIER = 1 # Stop-loss distance\n",
|
||
"\n",
|
||
"\n",
|
||
"# Run the backtest\n",
|
||
"trades_log = run_backtest(df_raw,\n",
|
||
" ma_period=MA_PERIOD,\n",
|
||
" atr_period=ATR_PERIOD,\n",
|
||
" atr_multiplier=ATR_MULTIPLIER,\n",
|
||
" stop_loss_multiplier=STOP_LOSS_MULTIPLIER)\n",
|
||
"\n",
|
||
"# Analyze performance\n",
|
||
"print(trades_log.head().to_string())\n",
|
||
"analyze_performance(trades_log)"
|
||
],
|
||
"id": "5b6585671d20a1f",
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Starting backtest...\n",
|
||
"Backtest finished.\n",
|
||
" entry_time type entry_price exit_time exit_price pnl\n",
|
||
"0 2024-01-02 21:30:00 long 2020.0 2024-01-02 21:45:00 2033.000000 13.000000\n",
|
||
"1 2024-01-03 10:45:00 short 2062.0 2024-01-03 13:45:00 2052.000000 10.000000\n",
|
||
"2 2024-01-03 14:00:00 long 2063.0 2024-01-03 14:45:00 2074.000000 11.000000\n",
|
||
"3 2024-01-03 21:00:00 short 2064.0 2024-01-03 21:30:00 2080.403936 -16.403936\n",
|
||
"4 2024-01-03 22:15:00 short 2079.0 2024-01-04 09:00:00 2062.000000 17.000000\n",
|
||
"\n",
|
||
"--- Strategy Performance Summary ---\n",
|
||
"Total Trades : 1099\n",
|
||
"Winning Trades : 581\n",
|
||
"Losing Trades : 518\n",
|
||
"Win Rate : 52.87%\n",
|
||
"Avg. Profit : 10.04\n",
|
||
"Avg. Loss : -10.50\n",
|
||
"Profit/Loss Ratio : 0.96\n",
|
||
"Total PnL : 396.16\n",
|
||
"Profit Factor : 1.07\n",
|
||
"----------------------------------\n",
|
||
"\n"
|
||
]
|
||
}
|
||
],
|
||
"execution_count": 33
|
||
},
|
||
{
|
||
"metadata": {
|
||
"ExecuteTime": {
|
||
"end_time": "2025-09-24T08:36:56.505148Z",
|
||
"start_time": "2025-09-24T08:36:56.387310Z"
|
||
}
|
||
},
|
||
"cell_type": "code",
|
||
"source": [
|
||
"import pandas as pd\n",
|
||
"import numpy as np\n",
|
||
"import talib\n",
|
||
"\n",
|
||
"\n",
|
||
"# --- 1. 回测引擎核心函数 ---\n",
|
||
"\n",
|
||
"def run_backtest_mean_reversion(df_raw: pd.DataFrame, ma_period: int, atr_period: int, atr_multiplier: float, stop_loss_multiplier: float):\n",
|
||
" \"\"\"\n",
|
||
" 执行一个基于ATR通道的均值回归回测。\n",
|
||
"\n",
|
||
" Args:\n",
|
||
" df_raw (pd.DataFrame): 原始OHLCV数据。\n",
|
||
" ma_period (int): 移动平均线周期。\n",
|
||
" atr_period (int): ATR计算周期。\n",
|
||
" atr_multiplier (float): ATR乘数,用于构建通道。\n",
|
||
" stop_loss_multiplier (float): ATR乘数,用于计算止损距离。\n",
|
||
"\n",
|
||
" Returns:\n",
|
||
" pd.DataFrame: 包含所有已完成交易记录的DataFrame。\n",
|
||
" \"\"\"\n",
|
||
" # --- 数据准备和指标计算 ---\n",
|
||
" df = df_raw.copy()\n",
|
||
" df.dropna(inplace=True)\n",
|
||
"\n",
|
||
" df['ma'] = talib.SMA(df['close'], timeperiod=ma_period)\n",
|
||
" df['atr'] = talib.ATR(df['high'], df['low'], df['close'], timeperiod=atr_period)\n",
|
||
"\n",
|
||
" df['upper_band'] = df['ma'] + atr_multiplier * df['atr']\n",
|
||
" df['lower_band'] = df['ma'] - atr_multiplier * df['atr']\n",
|
||
"\n",
|
||
" df.dropna(inplace=True)\n",
|
||
"\n",
|
||
" # --- 回测循环 ---\n",
|
||
" position = 0 # 0: 平仓, 1: 持有多单, -1: 持有空单\n",
|
||
" entry_price = 0.0\n",
|
||
" stop_loss_price = 0.0\n",
|
||
" trades = []\n",
|
||
"\n",
|
||
" print(\"开始执行均值回归回测...\")\n",
|
||
" for i in range(1, len(df)):\n",
|
||
" # 获取当前和前一根K线的数据\n",
|
||
" prev_close = df['close'].iloc[i - 1]\n",
|
||
" current_close = df['close'].iloc[i]\n",
|
||
" current_low = df['low'].iloc[i]\n",
|
||
" current_high = df['high'].iloc[i]\n",
|
||
" current_atr = df['atr'].iloc[i]\n",
|
||
"\n",
|
||
" prev_upper = df['upper_band'].iloc[i - 1]\n",
|
||
" prev_lower = df['lower_band'].iloc[i - 1]\n",
|
||
"\n",
|
||
" # --- 核心交易逻辑 ---\n",
|
||
"\n",
|
||
" # 开仓逻辑 (当前无持仓)\n",
|
||
" if position == 0:\n",
|
||
" # 做空信号:从通道内部向上穿过上轨\n",
|
||
" if prev_close < prev_upper and current_close > prev_upper:\n",
|
||
" position = -1\n",
|
||
" entry_price = current_close\n",
|
||
" # 止损价 = 入场价 + 止损距离\n",
|
||
" stop_loss_price = entry_price + stop_loss_multiplier * current_atr\n",
|
||
" trades.append({'entry_time': df.index[i], 'type': 'short', 'entry_price': entry_price, 'stop_loss': stop_loss_price})\n",
|
||
" # print(f\"{df.index[i]}: 开空单 @ {entry_price:.2f}, 止损 @ {stop_loss_price:.2f}\")\n",
|
||
"\n",
|
||
" # 做多信号:从通道内部向下穿过下轨\n",
|
||
" elif prev_close > prev_lower and current_close < prev_lower:\n",
|
||
" position = 1\n",
|
||
" entry_price = current_close\n",
|
||
" # 止损价 = 入场价 - 止损距离\n",
|
||
" stop_loss_price = entry_price - stop_loss_multiplier * current_atr\n",
|
||
" trades.append({'entry_time': df.index[i], 'type': 'long', 'entry_price': entry_price, 'stop_loss': stop_loss_price})\n",
|
||
" # print(f\"{df.index[i]}: 开多单 @ {entry_price:.2f}, 止损 @ {stop_loss_price:.2f}\")\n",
|
||
"\n",
|
||
" # 平仓逻辑 (当前有持仓)\n",
|
||
" elif position == 1: # 持有多单\n",
|
||
" # 止损平仓:触及止损价\n",
|
||
" if current_low < stop_loss_price:\n",
|
||
" exit_price = stop_loss_price\n",
|
||
" trade = trades[-1]\n",
|
||
" trade['exit_time'] = df.index[i]\n",
|
||
" trade['exit_price'] = exit_price\n",
|
||
" trade['pnl'] = exit_price - trade['entry_price']\n",
|
||
" position = 0\n",
|
||
" # print(f\"{df.index[i]}: 多单止损 @ {exit_price:.2f}, PnL: {trade['pnl']:.2f}\")\n",
|
||
" # 获利平仓:价格穿回通道内\n",
|
||
" elif current_close > df['lower_band'].iloc[i]:\n",
|
||
" exit_price = current_close\n",
|
||
" trade = trades[-1]\n",
|
||
" trade['exit_time'] = df.index[i]\n",
|
||
" trade['exit_price'] = exit_price\n",
|
||
" trade['pnl'] = exit_price - trade['entry_price']\n",
|
||
" position = 0\n",
|
||
" # print(f\"{df.index[i]}: 多单获利平仓 @ {exit_price:.2f}, PnL: {trade['pnl']:.2f}\")\n",
|
||
"\n",
|
||
" elif position == -1: # 持有空单\n",
|
||
" # 止损平仓:触及止损价\n",
|
||
" if current_high > stop_loss_price:\n",
|
||
" exit_price = stop_loss_price\n",
|
||
" trade = trades[-1]\n",
|
||
" trade['exit_time'] = df.index[i]\n",
|
||
" trade['exit_price'] = exit_price\n",
|
||
" trade['pnl'] = trade['entry_price'] - exit_price\n",
|
||
" position = 0\n",
|
||
" # print(f\"{df.index[i]}: 空单止损 @ {exit_price:.2f}, PnL: {trade['pnl']:.2f}\")\n",
|
||
" # 获利平仓:价格穿回通道内\n",
|
||
" elif current_close < df['upper_band'].iloc[i]:\n",
|
||
" exit_price = current_close\n",
|
||
" trade = trades[-1]\n",
|
||
" trade['exit_time'] = df.index[i]\n",
|
||
" trade['exit_price'] = exit_price\n",
|
||
" trade['pnl'] = trade['entry_price'] - exit_price\n",
|
||
" position = 0\n",
|
||
" # print(f\"{df.index[i]}: 空单获利平仓 @ {exit_price:.2f}, PnL: {trade['pnl']:.2f}\")\n",
|
||
"\n",
|
||
" print(\"回测结束。\")\n",
|
||
"\n",
|
||
" completed_trades = [t for t in trades if 'exit_price' in t]\n",
|
||
" return pd.DataFrame(completed_trades)\n",
|
||
"\n",
|
||
"\n",
|
||
"# --- 2. 性能统计函数 (与之前相同) ---\n",
|
||
"\n",
|
||
"def analyze_performance(trades_df: pd.DataFrame):\n",
|
||
" \"\"\"\n",
|
||
" 分析交易记录并打印性能摘要。\n",
|
||
" \"\"\"\n",
|
||
" if trades_df.empty:\n",
|
||
" print(\"没有完成的交易记录,无法进行分析。\")\n",
|
||
" return\n",
|
||
"\n",
|
||
" total_trades = len(trades_df)\n",
|
||
" winning_trades = trades_df[trades_df['pnl'] > 0]\n",
|
||
" losing_trades = trades_df[trades_df['pnl'] <= 0]\n",
|
||
"\n",
|
||
" win_rate = len(winning_trades) / total_trades if total_trades > 0 else 0\n",
|
||
"\n",
|
||
" avg_profit = winning_trades['pnl'].mean() if len(winning_trades) > 0 else 0\n",
|
||
" avg_loss = losing_trades['pnl'].mean() if len(losing_trades) > 0 else 0\n",
|
||
"\n",
|
||
" profit_loss_ratio = abs(avg_profit / avg_loss) if avg_loss != 0 else float('inf')\n",
|
||
"\n",
|
||
" total_pnl = trades_df['pnl'].sum()\n",
|
||
"\n",
|
||
" profit_factor = winning_trades['pnl'].sum() / abs(losing_trades['pnl'].sum()) if abs(\n",
|
||
" losing_trades['pnl'].sum()) > 0 else float('inf')\n",
|
||
"\n",
|
||
" print(\"\\n--- 策略性能摘要 ---\")\n",
|
||
" print(f\"总交易次数 : {total_trades}\")\n",
|
||
" print(f\"盈利交易次数 : {len(winning_trades)}\")\n",
|
||
" print(f\"亏损交易次数 : {len(losing_trades)}\")\n",
|
||
" print(f\"胜率 : {win_rate:.2%}\")\n",
|
||
" print(f\"平均每次盈利 : {avg_profit:.2f}\")\n",
|
||
" print(f\"平均每次亏损 : {avg_loss:.2f}\")\n",
|
||
" print(f\"盈亏比 : {profit_loss_ratio:.2f}\")\n",
|
||
" print(f\"总盈亏 : {total_pnl:.2f}\")\n",
|
||
" print(f\"盈利因子 : {profit_factor:.2f}\")\n",
|
||
" print(\"----------------------\\n\")\n",
|
||
"\n",
|
||
"\n",
|
||
"# --- 3. 主执行流程 ---\n",
|
||
"\n",
|
||
"# --- 策略参数 ---\n",
|
||
"MA_PERIOD = 120\n",
|
||
"ATR_PERIOD = 14\n",
|
||
"ATR_MULTIPLIER = 1.0 # 通道宽度乘数\n",
|
||
"STOP_LOSS_MULTIPLIER = 1 # 止损距离乘数\n",
|
||
"\n",
|
||
"# 执行回测\n",
|
||
"trades_log = run_backtest_mean_reversion(df_raw,\n",
|
||
" ma_period=MA_PERIOD,\n",
|
||
" atr_period=ATR_PERIOD,\n",
|
||
" atr_multiplier=ATR_MULTIPLIER,\n",
|
||
" stop_loss_multiplier=STOP_LOSS_MULTIPLIER)\n",
|
||
"\n",
|
||
"# 分析性能\n",
|
||
"print(trades_log.head().to_string())\n",
|
||
"analyze_performance(trades_log)"
|
||
],
|
||
"id": "5b6b9340f8783522",
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"开始执行均值回归回测...\n",
|
||
"回测结束。\n",
|
||
" entry_time type entry_price stop_loss exit_time exit_price pnl\n",
|
||
"0 2024-01-16 09:00:00 short 1880.0 1891.771265 2024-01-16 09:15:00 1876.000000 4.000000\n",
|
||
"1 2024-01-16 09:45:00 short 1882.0 1893.647037 2024-01-16 10:00:00 1893.647037 -11.647037\n",
|
||
"2 2024-01-18 09:15:00 short 1882.0 1896.720622 2024-01-18 10:00:00 1875.000000 7.000000\n",
|
||
"3 2024-01-18 11:00:00 short 1883.0 1896.979547 2024-01-18 14:15:00 1881.000000 2.000000\n",
|
||
"4 2024-01-18 14:30:00 short 1894.0 1907.606606 2024-01-18 14:45:00 1907.606606 -13.606606\n",
|
||
"\n",
|
||
"--- 策略性能摘要 ---\n",
|
||
"总交易次数 : 368\n",
|
||
"盈利交易次数 : 207\n",
|
||
"亏损交易次数 : 161\n",
|
||
"胜率 : 56.25%\n",
|
||
"平均每次盈利 : 6.79\n",
|
||
"平均每次亏损 : -10.39\n",
|
||
"盈亏比 : 0.65\n",
|
||
"总盈亏 : -266.73\n",
|
||
"盈利因子 : 0.84\n",
|
||
"----------------------\n",
|
||
"\n"
|
||
]
|
||
}
|
||
],
|
||
"execution_count": 36
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Python 3",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 2
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython2",
|
||
"version": "2.7.6"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 5
|
||
}
|