Files
NewQuant/data/ analysis/Volume.ipynb

340 lines
515 KiB
Plaintext
Raw Normal View History

{
"cells": [
{
2025-07-10 15:07:31 +08:00
"cell_type": "code",
"id": "b93c7ca1",
"metadata": {
2025-11-07 16:26:00 +08:00
"jupyter": {
"is_executing": true
}
},
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
2025-10-05 00:09:59 +08:00
"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",
2025-11-07 16:26:00 +08:00
"file_path = '/mnt/d/PyProject/NewQuant/data/data/KQ_m@CZCE_MA/KQ_m@CZCE_MA_min15.csv'\n",
2025-10-05 00:09:59 +08:00
"\n",
"sns.set(style='whitegrid')\n",
"plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签\n",
"plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号"
],
"outputs": [],
2025-11-07 16:26:00 +08:00
"execution_count": null
},
{
"metadata": {
"ExecuteTime": {
2025-11-07 16:26:00 +08:00
"end_time": "2025-10-09T13:27:36.143576Z",
"start_time": "2025-10-09T13:27:36.113790Z"
}
},
2025-10-05 00:09:59 +08:00
"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",
2025-10-05 00:09:59 +08:00
"# df_raw = df_raw[df_raw.index <= '2024-01-01']"
],
2025-10-05 00:09:59 +08:00
"id": "3dcf270c1da82220",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
2025-11-07 16:26:00 +08:00
"Successfully loaded 25596 rows of data.\n",
"First 5 rows of data:\n",
2025-11-07 16:26:00 +08:00
" open high low close volume open_oi \\\n",
"datetime \n",
"2020-12-31 14:45:00 2392.0 2398.0 2389.0 2397.0 48330.0 867110.0 \n",
"2021-01-04 09:00:00 2392.0 2413.0 2381.0 2385.0 173268.0 863234.0 \n",
"2021-01-04 09:15:00 2385.0 2386.0 2371.0 2384.0 89866.0 798140.0 \n",
"2021-01-04 09:30:00 2384.0 2385.0 2373.0 2380.0 54191.0 789219.0 \n",
"2021-01-04 09:45:00 2380.0 2382.0 2375.0 2380.0 35014.0 799193.0 \n",
"\n",
2025-10-05 00:09:59 +08:00
" close_oi underlying_symbol \n",
"datetime \n",
2025-11-07 16:26:00 +08:00
"2020-12-31 14:45:00 863234.0 CZCE.MA105 \n",
"2021-01-04 09:00:00 798140.0 CZCE.MA105 \n",
"2021-01-04 09:15:00 789219.0 CZCE.MA105 \n",
"2021-01-04 09:30:00 799193.0 CZCE.MA105 \n",
"2021-01-04 09:45:00 803201.0 CZCE.MA105 \n"
]
}
],
2025-11-07 16:26:00 +08:00
"execution_count": 69
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-10-09T13:27:36.158395Z",
"start_time": "2025-10-09T13:27:36.155400Z"
}
},
"cell_type": "code",
"source": [
"from tqdm import tqdm\n",
"from src.core_data import Bar\n",
"from src.strategies.ValueMigrationStrategy.ValueMigrationStrategy2 import compute_price_volume_distribution, \\\n",
" find_hvns_strict\n",
"\n",
"\n",
"\n",
"TICK_SIZE = 1\n",
"M_PROFILE_PERIOD = 200 # 用过去200根K线计算VP\n",
"N_RECALC_INTERVAL = 5 # K线重新计算一次VP\n",
"F_FUTURE_WINDOW = 5 # 观察事件发生后K线\n",
"HVN_WINDOW_RADIUS = 10 # 识别HVN的窗口半径\n",
"TOUCH_BUFFER_TICKS = 3 # 定义“触及”事件的缓冲区大小N个ticks\n",
"HVN_SCAN_ORDER = 'descending' # 'descending' (从高到低) 或 'ascending' (从低到高)\n"
],
"id": "5ac9056eead45cb2",
"outputs": [],
"execution_count": 70
},
{
"metadata": {
"ExecuteTime": {
2025-11-07 16:26:00 +08:00
"end_time": "2025-10-23T15:13:47.028547Z",
"start_time": "2025-10-23T15:13:45.463052Z"
}
},
2025-10-05 00:09:59 +08:00
"cell_type": "code",
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
2025-11-07 16:26:00 +08:00
"import seaborn as sns\n",
"from pandas.plotting import autocorrelation_plot\n",
"\n",
"# --- 0. 环境设置 ---\n",
"# 设置matplotlib样式使其更美观\n",
"sns.set_style(\"darkgrid\")\n",
"plt.rcParams['figure.figsize'] = (18, 12)\n",
"plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签\n",
"plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号\n",
"\n",
"# --- 1. 准备数据与计算指标 ---\n",
"\n",
"# 1.2 定义霍克斯过程计算函数\n",
"def calculate_hawkes_imbalance(df, lookback=60, alpha=0.8, beta=0.2):\n",
" \"\"\"\n",
" 在DataFrame上计算霍克斯过程强度和不均衡指标。\n",
" 这是一个向量化的近似实现,以提高效率。\n",
" \"\"\"\n",
" df['range'] = df['high'] - df['low']\n",
" df['mark'] = df['range'] * df['volume']\n",
"\n",
" # 定义事件类型\n",
" df['long_event_mark'] = np.where(df['close'] > df['open'], df['mark'], 0)\n",
" df['short_event_mark'] = np.where(df['close'] < df['open'], df['mark'], 0)\n",
"\n",
" # 创建衰减权重 (这是一个关键的向量化技巧)\n",
" # weights: [e^(-beta*59), e^(-beta*58), ..., e^(-beta*0)]\n",
" decay_weights = np.exp(-beta * np.arange(lookback - 1, -1, -1))\n",
"\n",
" # 使用 rolling apply 来计算加权和\n",
" # .apply(lambda x: (x * decay_weights).sum()) 效率会低,直接矩阵乘法更快\n",
" def weighted_sum(marks):\n",
" return (marks * decay_weights).sum()\n",
"\n",
" print(\"正在计算霍克斯强度...\")\n",
" df['lambda_long'] = alpha * df['long_event_mark'].rolling(window=lookback).apply(weighted_sum, raw=True)\n",
" df['lambda_short'] = alpha * df['short_event_mark'].rolling(window=lookback).apply(weighted_sum, raw=True)\n",
"\n",
" # 计算不均衡指标\n",
" df['imbalance'] = df['lambda_long'] - df['lambda_short']\n",
"\n",
" return df.dropna()\n",
"\n",
"# 1.3 在df_raw上运行计算\n",
"df_analysis = calculate_hawkes_imbalance(df_raw.copy())\n",
"print(\"霍克斯不均衡指标计算完成。\")\n",
"\n",
"\n",
"# --- 2. 核心假设验证:自相关性分析 ---\n",
"print(\"\\n--- 核心假设验证:自相关性分析 ---\")\n",
"\n",
"plt.figure(figsize=(18, 6))\n",
"autocorrelation_plot(df_analysis['imbalance'].resample('D').last().dropna()) # 按天重采样避免数据点过密\n",
"plt.title('多空力量差 (Imbalance) 的自相关性图', fontsize=16)\n",
"plt.xlabel('延迟阶数 (Lag in Days)', fontsize=12)\n",
"plt.ylabel('自相关系数', fontsize=12)\n",
"plt.show()\n",
"\n",
"# --- 3. 统计属性与“政体”划分 ---\n",
"print(\"\\n--- 统计属性与“政体”划分 ---\")\n",
"\n",
"# 3.1 描述性统计\n",
"print(\"Imbalance 指标的描述性统计:\")\n",
"print(df_analysis['imbalance'].describe())\n",
"\n",
"# 3.2 可视化 Imbalance 指标及其波动性\n",
"fig, axes = plt.subplots(3, 1, figsize=(18, 15), sharex=True)\n",
"\n",
"# 图1: Imbalance 指标本身\n",
"df_analysis['imbalance'].plot(ax=axes[0], color='purple', label='Imbalance')\n",
"axes[0].set_title('多空力量差 (Imbalance) 时间序列', fontsize=16)\n",
"axes[0].set_ylabel('Imbalance Value')\n",
"axes[0].legend()\n",
"\n",
"# 图2: Imbalance 指标的滚动标准差(波动性)\n",
"imbalance_volatility = df_analysis['imbalance'].rolling(window=50).std()\n",
"imbalance_volatility.plot(ax=axes[1], color='orange', label='Imbalance Volatility (Rolling Std)')\n",
"axes[1].set_title('Imbalance 指标的波动性', fontsize=16)\n",
"axes[1].set_ylabel('Volatility')\n",
"axes[1].legend()\n",
"\n",
"# 图3: 根据波动性划分“政体”\n",
"vol_threshold = imbalance_volatility.quantile(0.7) # 以70%分位数为界\n",
"df_analysis['regime'] = np.where(imbalance_volatility > vol_threshold, '高波动/趋势', '低波动/盘整')\n",
"\n",
"# 绘制背景色来显示政体\n",
"colors = {'高波动/趋势': 'lightcoral', '低波动/盘整': 'lightgreen'}\n",
"for i in range(len(df_analysis) - 1):\n",
" axes[2].axvspan(df_analysis.index[i], df_analysis.index[i+1],\n",
" facecolor=colors[df_analysis['regime'].iloc[i]], alpha=0.3)\n",
"\n",
"df_analysis['close'].plot(ax=axes[2], color='blue', label='收盘价')\n",
"axes[2].set_title('根据 Imbalance 波动性划分的市场“政体”', fontsize=16)\n",
"axes[2].set_ylabel('Price')\n",
"axes[2].legend()\n",
"\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"\n"
],
2025-11-07 16:26:00 +08:00
"id": "d7f8d5880319e8f0",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
2025-11-07 16:26:00 +08:00
"正在计算霍克斯强度...\n",
"霍克斯不均衡指标计算完成。\n",
"\n",
"--- 核心假设验证:自相关性分析 ---\n"
]
},
{
2025-11-07 16:26:00 +08:00
"data": {
"text/plain": [
"<Figure size 1800x600 with 1 Axes>"
],
"image/png": "iVBORw0KGgoAAAANSUhEUgAABckAAAInCAYAAABDQNGcAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAPYQAAD2EBqD+naQAA9pBJREFUeJzs3QdUU+cbBvAXQURRcS9wD1Tcirutta2jjmqtHbbabVu7rf23du+997K2tcO6q1ate++NEwUHKiKKiigKAv/zfMkXIwZIQsYNeX7neERZCSQ3977f+z1vQE5OTo4QEREREREREREREfmhYt6+AURERERERERERERE3sIiORERERERERERERH5LRbJiYiIiIiIiIiIiMhvsUhORERERERERERERH6LRXIiIiIiIiIiIiIi8lsskhMRERERERERERGR32KRnIiIiIiIiIiIiIj8FovkREREREREREREROS3WCQnIiIi8rJz5855+yYQERERERH5LRbJiYiIiPKRlpYmu3btcsvPKCMjQ5566inp0qWLJCcnu+zrZmVlyfPPPy+ff/65uv3OunjxosN/8L0duZ0//vhjnvf9q6++kpUrVzp9+4mcMWnSJNm7d2+e7584caJs2bKlUD/c06dPy6233irvvvtuoZ6j8NBDD0n37t3l/Pnz4g5Lly6VhIQEm+9bt26dLFy40KGv16tXL3n44YcL/PmMGDFCvvnmmwK/XkpKihw9erTQf3A8JiIiIv8V5O0bQERERGRU2dnZ8uKLL8qCBQvkzz//lBYtWrj06wcHB8uFCxdUJ/nvv/8uTz/9tEu+bmBgoEyfPl3dfhSanHHmzBlp166dw5/XtGlTmTp1ql0fu3jxYvnoo49k9erVMmbMmMveh8LhDz/8IMWKFVNfr27duuJOOTk58sUXX8jgwYOlRo0abv1e5DgsVOFxcs8997j1x4fnzBtvvCEhISGyZMkSKVmy5BUfg8LtkSNH5O+//5ZWrVo59X0SExNVoR0LS6VLly7UbUZB+fDhw1K8eHHL/509e1b++OOPAj83LCxMbrvttjzfv3PnThk+fLh6Xo8fP14ds6zhe8yePVvuv/9++d///mfX7cWiWJkyZa74fxwLS5QoYVlAw3EXx7KCPPvss7J8+XIprAkTJkjLli0L/XWIiIjIN7FITkRERGQDugpHjx4tc+bM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
},
"metadata": {},
"output_type": "display_data",
"jetTransient": {
"display_id": null
}
},
{
"name": "stdout",
"output_type": "stream",
"text": [
2025-11-07 16:26:00 +08:00
"\n",
"--- 统计属性与“政体”划分 ---\n",
"Imbalance 指标的描述性统计:\n",
"count 1941.000000\n",
"mean -217.855332\n",
"std 1425.960979\n",
"min -4887.301888\n",
"25% -1211.389213\n",
"50% -256.446563\n",
"75% 696.119807\n",
"max 5469.393981\n",
"Name: imbalance, dtype: float64\n"
]
},
{
2025-11-07 16:26:00 +08:00
"name": "stderr",
"output_type": "stream",
"text": [
2025-11-07 16:26:00 +08:00
"D:\\Python\\conda\\envs\\quant\\Lib\\site-packages\\pandas\\plotting\\_matplotlib\\core.py:981: UserWarning: This axis already has a converter set and is updating to a potentially incompatible converter\n",
" return ax.plot(*args, **kwds)\n"
]
},
{
"data": {
"text/plain": [
2025-11-07 16:26:00 +08:00
"<Figure size 1800x1500 with 3 Axes>"
],
2025-11-07 16:26:00 +08:00
"image/png": "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
},
"metadata": {},
2025-10-05 00:09:59 +08:00
"output_type": "display_data",
"jetTransient": {
"display_id": null
}
}
],
2025-11-07 16:26:00 +08:00
"execution_count": 2
}
],
"metadata": {
"kernelspec": {
"display_name": "quant",
"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.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}