feat: 期货数据分析工具集 v2.0
## 核心功能 ### 1. 成交量序列分析 (volume_price_sequence.py) - 按累计成交量排序的价格趋势分析 - 三合一综合图表:价格序列+成交量分布+时间序列 - 关键价格水平自动标注 ### 2. 成交量分布深度分析 (volume_distribution_analysis.py) - 7种专业可视化图表 - 统计特征分析和分布拟合 - 交易模式识别和业务洞察 ### 3. 大额订单分析工具集 (large_orders/) - 买1/卖1量大单分析 (阈值99) - 买卖挂单合计分析 (阈值200) - 当前成交量分析 (阈值150) - 信号抑制优化算法 (38%抑制率) ## 技术特性 - 信号抑制算法:有效减少重复信号干扰 - 多维度分析:支持多种信号类型 - 专业可视化:四宫格综合分析图 - 业务洞察:基于数据的交易建议 ## 分析结果 - 卖1量大单:短期下跌,长期大幅上涨反转 - 买挂合计:各时间窗口小幅正收益 - 信号抑制:短期收益从-0.0778提升至+0.1347 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
9
.claude/settings.local.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(python:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
49
.ipynb_checkpoints/Untitled-checkpoint.ipynb
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6f7513b5-543f-4c2f-858f-9d93641d8490",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "43c042a3-9b67-4027-9577-bf4bb0875a75",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "41d31ae7-d867-41b4-a180-f9b391b101e8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.2"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
288
.ipynb_checkpoints/requirements-checkpoint.txt
Normal file
@ -0,0 +1,288 @@
|
||||
# 期货Tick数据分析项目 - 依赖包列表
|
||||
|
||||
## 环境信息
|
||||
- **Python版本**: 3.11
|
||||
- **平台**: Windows
|
||||
- **更新日期**: 2025-11-01
|
||||
|
||||
## 核心依赖包
|
||||
|
||||
### 数据处理核心库
|
||||
```
|
||||
polars==1.35.1
|
||||
numpy==2.3.4
|
||||
pandas==2.3.3
|
||||
pyarrow==22.0.0
|
||||
```
|
||||
|
||||
### 可视化库
|
||||
```
|
||||
matplotlib==3.10.7
|
||||
seaborn==0.13.2
|
||||
plotly==6.3.1
|
||||
```
|
||||
|
||||
### Jupyter开发环境
|
||||
```
|
||||
jupyterlab==4.4.10
|
||||
notebook==7.4.7
|
||||
```
|
||||
|
||||
### 科学计算与机器学习
|
||||
```
|
||||
scipy==1.16.3
|
||||
scikit-learn==1.7.2
|
||||
```
|
||||
|
||||
## 安装方法
|
||||
|
||||
### 方法1: 使用requirements.txt文件(推荐)
|
||||
|
||||
1. 创建 `requirements.txt` 文件,内容如下:
|
||||
```txt
|
||||
polars==1.35.1
|
||||
numpy==2.3.4
|
||||
pandas==2.3.3
|
||||
pyarrow==22.0.0
|
||||
matplotlib==3.10.7
|
||||
seaborn==0.13.2
|
||||
plotly==6.3.1
|
||||
jupyterlab==4.4.10
|
||||
notebook==7.4.7
|
||||
scipy==1.16.3
|
||||
scikit-learn==1.7.2
|
||||
```
|
||||
|
||||
2. 安装命令:
|
||||
```bash
|
||||
# 使用默认源
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 使用清华镜像源(推荐国内用户)
|
||||
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
```
|
||||
|
||||
### 方法2: 一键安装脚本
|
||||
|
||||
创建 `install_dependencies.py` 文件:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
期货Tick数据分析项目依赖包安装脚本
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def install_package(package_name, version=""):
|
||||
"""安装指定的包"""
|
||||
cmd = [sys.executable, "-m", "pip", "install"]
|
||||
if version:
|
||||
cmd.append(f"{package_name}=={version}")
|
||||
else:
|
||||
cmd.append(package_name)
|
||||
|
||||
# 使用清华镜像源
|
||||
cmd.extend(["-i", "https://pypi.tuna.tsinghua.edu.cn/simple"])
|
||||
|
||||
try:
|
||||
subprocess.run(cmd, check=True)
|
||||
print(f"✅ {package_name} {version} 安装成功")
|
||||
except subprocess.CalledProcessError:
|
||||
print(f"❌ {package_name} {version} 安装失败")
|
||||
return False
|
||||
return True
|
||||
|
||||
def main():
|
||||
"""主安装流程"""
|
||||
print("🚀 开始安装期货Tick数据分析项目依赖包...")
|
||||
print("=" * 60)
|
||||
|
||||
# 依赖包列表
|
||||
packages = [
|
||||
("polars", "1.35.1"),
|
||||
("numpy", "2.3.4"),
|
||||
("pandas", "2.3.3"),
|
||||
("pyarrow", "22.0.0"),
|
||||
("matplotlib", "3.10.7"),
|
||||
("seaborn", "0.13.2"),
|
||||
("plotly", "6.3.1"),
|
||||
("jupyterlab", "4.4.10"),
|
||||
("notebook", "7.4.7"),
|
||||
("scipy", "1.16.3"),
|
||||
("scikit-learn", "1.7.2"),
|
||||
]
|
||||
|
||||
success_count = 0
|
||||
total_count = len(packages)
|
||||
|
||||
for package_name, version in packages:
|
||||
print(f"\n📦 正在安装 {package_name}=={version}...")
|
||||
if install_package(package_name, version):
|
||||
success_count += 1
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print(f"📊 安装完成: {success_count}/{total_count} 个包安装成功")
|
||||
|
||||
if success_count == total_count:
|
||||
print("🎉 所有依赖包安装成功!")
|
||||
print("\n🚀 现在可以开始使用以下命令启动Jupyter Lab:")
|
||||
print(" jupyter lab")
|
||||
else:
|
||||
print("⚠️ 部分包安装失败,请检查错误信息")
|
||||
print("💡 建议手动安装失败的包")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
运行安装脚本:
|
||||
```bash
|
||||
python install_dependencies.py
|
||||
```
|
||||
|
||||
### 方法3: 手动安装命令
|
||||
|
||||
```bash
|
||||
# 核心数据处理库
|
||||
pip install polars==1.35.1 numpy==2.3.4 pandas==2.3.3 pyarrow==22.0.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
|
||||
# 可视化库
|
||||
pip install matplotlib==3.10.7 seaborn==0.13.2 plotly==6.3.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
|
||||
# Jupyter环境
|
||||
pip install jupyterlab==4.4.10 notebook==7.4.7 -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
|
||||
# 科学计算库
|
||||
pip install scipy==1.16.3 scikit-learn==1.7.2 -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
```
|
||||
|
||||
## 验证安装
|
||||
|
||||
安装完成后,运行以下验证脚本:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
依赖包安装验证脚本
|
||||
"""
|
||||
|
||||
def check_imports():
|
||||
"""检查所有包是否能正常导入"""
|
||||
packages = {
|
||||
'polars': '1.35.1',
|
||||
'numpy': '2.3.4',
|
||||
'pandas': '2.3.3',
|
||||
'pyarrow': '22.0.0',
|
||||
'matplotlib': '3.10.7',
|
||||
'seaborn': '0.13.2',
|
||||
'plotly': '6.3.1',
|
||||
'jupyterlab': '4.4.10',
|
||||
'scipy': '1.16.3',
|
||||
'sklearn': '1.7.2' # scikit-learn的导入名是sklearn
|
||||
}
|
||||
|
||||
print("🔍 验证依赖包安装状态...")
|
||||
print("=" * 50)
|
||||
|
||||
success_count = 0
|
||||
for package_name, expected_version in packages.items():
|
||||
try:
|
||||
if package_name == 'sklearn':
|
||||
import sklearn
|
||||
actual_version = sklearn.__version__
|
||||
else:
|
||||
module = __import__(package_name)
|
||||
actual_version = module.__version__
|
||||
|
||||
if actual_version == expected_version:
|
||||
print(f"✅ {package_name}: {actual_version}")
|
||||
success_count += 1
|
||||
else:
|
||||
print(f"⚠️ {package_name}: 期望 {expected_version}, 实际 {actual_version}")
|
||||
|
||||
except ImportError as e:
|
||||
print(f"❌ {package_name}: 导入失败 - {e}")
|
||||
|
||||
print("=" * 50)
|
||||
print(f"📊 验证结果: {success_count}/{len(packages)} 个包正常")
|
||||
|
||||
if success_count == len(packages):
|
||||
print("🎉 所有依赖包验证通过!")
|
||||
else:
|
||||
print("⚠️ 部分包存在问题,请检查安装")
|
||||
|
||||
if __name__ == "__main__":
|
||||
check_imports()
|
||||
```
|
||||
|
||||
## 项目说明
|
||||
|
||||
### 核心技术栈
|
||||
- **Polars**: 高性能数据处理库,比pandas快100倍
|
||||
- **NumPy**: 数值计算基础库
|
||||
- **PyArrow**: Parquet格式支持,高效数据存储
|
||||
- **Matplotlib/Seaborn**: 基础可视化
|
||||
- **Plotly**: 交互式图表
|
||||
- **JupyterLab**: 现代化数据分析环境
|
||||
|
||||
### 应用场景
|
||||
- 期货Tick数据处理
|
||||
- 高频数据分析
|
||||
- 实时数据可视化
|
||||
- 交易策略回测
|
||||
- 统计分析
|
||||
|
||||
### 性能优化建议
|
||||
1. 使用Polars替代pandas处理大数据
|
||||
2. 将数据保存为Parquet格式以减少存储空间
|
||||
3. 使用JupyterLab的惰性加载处理超大文件
|
||||
4. 利用Plotly创建交互式图表进行深入分析
|
||||
|
||||
## 镜像源配置
|
||||
|
||||
### 国内推荐镜像源
|
||||
```bash
|
||||
# 清华大学
|
||||
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
|
||||
# 阿里云
|
||||
pip install -i https://mirrors.aliyun.com/pypi/simple/
|
||||
|
||||
# 豆瓣
|
||||
pip install -i https://pypi.douban.com/simple/
|
||||
|
||||
# 中科大
|
||||
pip install -i https://mirrors.ustc.edu.cn/pypi/web/simple/
|
||||
```
|
||||
|
||||
### 永久配置镜像源
|
||||
```bash
|
||||
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
```
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
1. **编码问题**: 在Windows上可能出现GBK编码错误,建议使用UTF-8编码
|
||||
2. **权限问题**: 使用管理员权限运行命令提示符
|
||||
3. **网络问题**: 切换不同的镜像源或使用代理
|
||||
4. **版本冲突**: 建议使用虚拟环境隔离项目依赖
|
||||
|
||||
### 虚拟环境创建
|
||||
```bash
|
||||
# 创建虚拟环境
|
||||
python -m venv tick_analysis_env
|
||||
|
||||
# 激活虚拟环境 (Windows)
|
||||
tick_analysis_env\Scripts\activate
|
||||
|
||||
# 激活虚拟环境 (Linux/Mac)
|
||||
source tick_analysis_env/bin/activate
|
||||
|
||||
# 在虚拟环境中安装依赖
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
128
CLAUDE.md
Normal file
@ -0,0 +1,128 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## 项目概述
|
||||
|
||||
这是一个专门的期货数据分析项目,专注于中国期货市场的成交量-成交价序列可视化分析。项目采用创新的分析方法,通过按累计成交量排序来展示价格在交易过程中的真实变化轨迹。
|
||||
|
||||
**项目特色**: 提供高解释力的期货数据可视化工具,相比传统时间序列图表具有更强的业务相关性和决策价值。
|
||||
|
||||
## 核心工具
|
||||
|
||||
### volume_price_sequence.py
|
||||
这是项目的主要分析工具,专门用于生成成交量-成交价序列图表。
|
||||
|
||||
**功能特性**:
|
||||
- 按累计成交量升序排列数据
|
||||
- 生成高解释力的可视化图表
|
||||
- 提供详细的统计分析和业务洞察
|
||||
- 支持命令行参数,使用简单
|
||||
|
||||
**使用方法**:
|
||||
```bash
|
||||
python volume_price_sequence.py [data_file]
|
||||
python volume_price_sequence.py --help
|
||||
```
|
||||
|
||||
## 数据文件结构
|
||||
|
||||
### 数据存储位置
|
||||
所有数据文件位于 `/data/` 目录下:
|
||||
- `au2512_20251013.parquet` - AU2512合约2025年10月13日数据 (默认分析文件)
|
||||
- `au2512_20251013.csv` - AU2512合约CSV格式数据
|
||||
- `jm2509_20250709.csv` - JM2509合约2025年7月9日数据
|
||||
- `jm2509_20250710.csv` - JM2509合约2025年7月10日数据
|
||||
- `jm2509_20250711.csv` - JM2509合约2025年7月11日数据
|
||||
- `jm2509_20250717.csv` - JM2509合约2025年7月17日数据
|
||||
|
||||
### 数据格式
|
||||
数据包含以下字段(中文表头):
|
||||
```
|
||||
UTC,UTC.1,时间,累积成交量,成交价,成交额,
|
||||
买1价,卖1价,买1量,卖1量,
|
||||
买2价,卖2价,买2量,卖2量,
|
||||
买3价,卖3价,买3量,卖3量,
|
||||
买4价,卖4价,买4量,卖4量,
|
||||
买5价,卖5价,买5量,卖5量
|
||||
```
|
||||
|
||||
### 关键字段说明
|
||||
- `UTC`, `UTC.1`: UTC时间戳(毫秒级)
|
||||
- `时间`: 当日累计时间(格式:MM:SS.秒,从00:00:00开始)
|
||||
- `成交价`: 最新成交价格
|
||||
- `累积成交量`: 当日累计成交量
|
||||
- `买1价`~`买5价`: 买方五档价格
|
||||
- `卖1价`~`卖5价`: 卖方五档价格
|
||||
- `买1量`~`买5量`: 买方五档挂单量
|
||||
- `卖1量`~`卖5量`: 卖方五档挂单量
|
||||
|
||||
## 分析方法
|
||||
|
||||
### 核心理念
|
||||
**为什么选择成交量序列分析?**
|
||||
|
||||
传统时间序列的局限性:
|
||||
- 无法展示交易过程对价格的真实影响
|
||||
- 时间间隔不均等,影响趋势判断
|
||||
- 业务解释力有限
|
||||
|
||||
成交量序列的优势:
|
||||
- 清晰展示价格随交易推进的演变轨迹
|
||||
- 便于识别不同交易阶段的价格水平
|
||||
- 可以量化成交量对价格的影响
|
||||
- 更符合期货交易的实际业务逻辑
|
||||
|
||||
### 图表输出
|
||||
生成的图表 `au2512_volume_price_sequence.png` 包含:
|
||||
- 成交价序列线(蓝色)- 展示价格随成交量变化
|
||||
- 移动平均线(红色)- 平滑价格趋势
|
||||
- 价格波动区间(红色阴影)- 显示不确定性范围
|
||||
- 关键节点标注 - 重要成交量时点的价格信息
|
||||
- 分析结论框 - 完整的统计摘要
|
||||
|
||||
## 项目文件结构
|
||||
|
||||
```
|
||||
jm_ces/
|
||||
├── volume_price_sequence.py # 核心分析脚本
|
||||
├── au2512_volume_price_sequence.png # 生成的分析图表
|
||||
├── README.md # 项目说明文档
|
||||
├── CLAUDE.md # 本指导文档
|
||||
└── data/ # 数据文件目录
|
||||
├── au2512_20251013.parquet # 默认分析数据
|
||||
└── *.csv # 其他期货数据文件
|
||||
```
|
||||
|
||||
## 技术要求
|
||||
|
||||
### 依赖库
|
||||
- pandas (数据处理)
|
||||
- numpy (数值计算)
|
||||
- matplotlib (数据可视化)
|
||||
|
||||
### 系统要求
|
||||
- Python 3.7+
|
||||
- 支持中文字体的环境
|
||||
|
||||
## 使用指南
|
||||
|
||||
### 快速开始
|
||||
1. 确保安装了必要的依赖库
|
||||
2. 运行分析脚本:`python volume_price_sequence.py`
|
||||
3. 查看生成的图表和分析报告
|
||||
|
||||
### 高级用法
|
||||
- 指定不同的数据文件进行分析
|
||||
- 使用命令行参数自定义输出目录
|
||||
- 参考详细的README.md文档
|
||||
|
||||
## 分析价值
|
||||
|
||||
这个工具特别适用于:
|
||||
- 期货交易策略研究
|
||||
- 市场微观结构分析
|
||||
- 价格发现机制研究
|
||||
- 风险管理和决策支持
|
||||
|
||||
相比传统分析方法,成交量序列分析能够提供更具业务洞察力的可视化结果。
|
||||
438
README.md
Normal file
@ -0,0 +1,438 @@
|
||||
# AU2512期货成交量-成交价序列分析工具
|
||||
|
||||
[](https://python.org)
|
||||
[](LICENSE)
|
||||
[]()
|
||||
|
||||
一个专业完整的期货数据分析工具集。通过创新的**成交量序列分析方法**和**多维可视化技术**,提供从价格趋势到成交量分布的全方位分析解决方案,为期货交易者提供深入的市场洞察。
|
||||
|
||||
## 🎯 核心优势
|
||||
|
||||
### 🔄 创新分析方法
|
||||
- **按成交量排序** - 相比传统时间序列,更符合交易实际
|
||||
- **业务相关性高** - 直接反映交易行为对价格的影响
|
||||
- **高解释力** - 清晰展示价格随交易推进的演变轨迹
|
||||
|
||||
### 📊 专业可视化工具集
|
||||
|
||||
#### 1. 价格序列分析 (volume_price_sequence.py)
|
||||
- **主图**: 成交价序列图(简洁无干扰的价格轨迹)
|
||||
- **侧图**: 成交量在价格上的分布图(0.02间隔)
|
||||
- **下图**: 当前成交量时间序列图
|
||||
- **关键价格标注**: 成交量最大的10个价格水平(虚线+双向标注)
|
||||
|
||||
#### 2. 成交量分布深度分析 (volume_distribution_analysis.py)
|
||||
- **7种专业图表**: 直方图、箱线图、累积分布函数等
|
||||
- **统计摘要**: 完整的分布特征分析
|
||||
- **交易模式识别**: 大单分析、分组统计
|
||||
- **业务洞察**: 市场活跃度和机构参与度分析
|
||||
|
||||
#### 3. 成交量价格分布图 (volume_price_distribution.py)
|
||||
- **单一专注**: 成交量在价格上的分布
|
||||
- **前20排行**: 成交量最大的价格区间列表
|
||||
- **精确分析**: 0.02价格间隔的详细分布
|
||||
- **快速洞察**: 立即识别热门价格水平
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 安装依赖
|
||||
```bash
|
||||
pip install pandas numpy matplotlib
|
||||
```
|
||||
|
||||
### 基本使用
|
||||
```bash
|
||||
# 1. 价格序列分析(综合图表,推荐)
|
||||
python volume_price_sequence.py
|
||||
|
||||
# 2. 成交量分布深度分析(7种专业图表)
|
||||
python volume_distribution_analysis.py
|
||||
|
||||
# 3. 简化成交量价格分布图(快速分析)
|
||||
python volume_price_distribution.py
|
||||
|
||||
# 4. 分析其他数据文件
|
||||
python volume_price_sequence.py data/jm2509_20250709.csv
|
||||
python volume_distribution_analysis.py data/jm2509_20250709.csv
|
||||
python volume_price_distribution.py data/jm2509_20250710.csv
|
||||
|
||||
# 5. 查看帮助信息
|
||||
python volume_price_sequence.py --help
|
||||
python volume_distribution_analysis.py --help
|
||||
python volume_price_distribution.py --help
|
||||
```
|
||||
|
||||
### 系统要求
|
||||
- Python 3.7+
|
||||
- pandas, numpy, matplotlib, scipy
|
||||
- 支持中文字体的环境
|
||||
|
||||
## 📈 输出示例
|
||||
|
||||
### 生成的图表
|
||||
|
||||
#### 1. 综合价格序列分析图 (推荐)
|
||||
 - **1.0MB**
|
||||
**三合一综合分析图表**:
|
||||
- **主图**: 成交价序列图(简洁清晰,无技术指标干扰)
|
||||
- **侧图**: 成交量在价格上的分布(0.02间隔,水平柱状图)
|
||||
- **下图**: 当前成交量时间序列图(交易活跃度变化)
|
||||
- **关键价格标注**: 成交量最大的10个价格水平(浅绿色虚线+双向标注)
|
||||
|
||||
#### 2. 成交量分布深度分析图
|
||||
 - **1.1MB**
|
||||
**7种专业分析图表**:
|
||||
- 直方图 + 概率密度拟合
|
||||
- 箱线图(分位数分布)
|
||||
- 累积分布函数
|
||||
- 成交量时间序列
|
||||
- 成交量分组柱状图
|
||||
- 成交量贡献度条形图
|
||||
- 统计摘要表
|
||||
|
||||
#### 3. 简化成交量价格分布图
|
||||
 - **0.3MB**
|
||||
**专注单一分析**:
|
||||
- 成交量在价格上的分布(0.02间隔)
|
||||
- 前20个成交量最大价格区间列表
|
||||
- 关键统计信息标注
|
||||
|
||||
### 分析报告示例
|
||||
|
||||
#### 综合价格序列分析报告
|
||||
```
|
||||
开始AU2512期货成交量-成交价序列分析...
|
||||
数据加载成功: 66,596 条记录
|
||||
|
||||
=== 数据分析 ===
|
||||
数据概况:
|
||||
累计成交量: 893,404 手
|
||||
价格区间: 901.84 - 928.88
|
||||
平均价格: 914.54
|
||||
|
||||
关键成交量节点:
|
||||
起始: 成交量 320 手, 价格 904.76
|
||||
25%: 成交量 273,254 手, 价格 911.94
|
||||
50%: 成交量 527,232 手, 价格 909.18
|
||||
75%: 成交量 724,868 手, 价格 921.62
|
||||
结束: 成交量 893,404 手, 价格 927.48
|
||||
|
||||
综合价格序列图已保存: au2512_volume_price_sequence.png
|
||||
|
||||
【业务洞察】
|
||||
1. 价格随成交量变化的完整轨迹清晰可见
|
||||
2. 整体趋势: 上涨 (+2.51%)
|
||||
3. 交易过程中价格呈现逐步上涨趋势
|
||||
4. 关键价格水平与成交量分布密切关联
|
||||
```
|
||||
|
||||
#### 成交量分布深度分析报告
|
||||
```
|
||||
开始AU2512期货当前成交量分布分析...
|
||||
数据加载成功: 66,596 条记录
|
||||
|
||||
=== 基础统计分析 ===
|
||||
平均成交量: 14.96 手
|
||||
中位数成交量: 10.00 手
|
||||
成交量标准差: 17.07 手
|
||||
分布偏度: 2.939 (严重右偏)
|
||||
|
||||
=== 成交量模式分析 ===
|
||||
大单交易定义: > 34.0 手 (90%分位数)
|
||||
大单交易次数: 5,681
|
||||
大单交易占比: 9.71%
|
||||
大单成交量占比: 36.40%
|
||||
|
||||
成交量分组统计:
|
||||
2-5手: 16,887 次 (28.9%) | 成交量: 49,572 手 (5.7%)
|
||||
6-10手: 16,355 次 (27.9%) | 成交量: 126,216 手 (14.4%)
|
||||
11-20手: 12,558 次 (21.5%) | 成交量: 191,344 手 (21.9%)
|
||||
21-50手: 10,201 次 (17.4%) | 成交量: 321,680 手 (36.8%) 【主力】
|
||||
|
||||
【业务洞察】
|
||||
1. 成交量分布呈现严重的右偏特征,小单交易为主,大单影响显著
|
||||
2. 成交量波动较大,存在明显的活跃期和沉寂期
|
||||
3. 大单交易占比较为重要,对市场流动性有显著影响
|
||||
4. 21-50手交易是市场主力,贡献36.8%成交量
|
||||
5. 市场活跃度适中,交易较为频繁
|
||||
```
|
||||
|
||||
#### 成交量价格分布报告
|
||||
```
|
||||
开始AU2512期货成交量价格分布分析...
|
||||
数据加载成功: 66,596 条记录
|
||||
|
||||
【前20个成交最大的价格区间】
|
||||
排名 价格区间 成交量 占比 累计占比
|
||||
-----------------------------------------------------------------
|
||||
1 922.00-922.02 4,044 0.5% 0.5%
|
||||
2 921.90-921.92 2,678 0.3% 0.8%
|
||||
3 907.70-907.72 2,460 0.3% 1.0%
|
||||
4 908.00-908.02 2,434 0.3% 1.3%
|
||||
5 927.00-927.02 2,332 0.3% 1.6%
|
||||
...
|
||||
|
||||
分析完成!
|
||||
```
|
||||
|
||||
## 💡 为什么选择成交量序列分析?
|
||||
|
||||
| 特性 | 传统时间序列 | 成交量序列 |
|
||||
|------|-------------|------------|
|
||||
| **解释力** | ⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||||
| **业务相关性** | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||||
| **趋势识别** | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||||
| **决策价值** | ⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
### 传统方法的局限性
|
||||
- ❌ 无法展示交易过程对价格的真实影响
|
||||
- ❌ 时间间隔不均等,影响趋势判断
|
||||
- ❌ 难以识别关键交易时点的价格变化
|
||||
|
||||
### 成交量序列的优势
|
||||
- ✅ 清晰展示价格随交易推进的演变轨迹
|
||||
- ✅ 便于识别不同交易阶段的价格水平
|
||||
- ✅ 可以量化成交量对价格的影响
|
||||
- ✅ 更符合期货交易的实际业务逻辑
|
||||
|
||||
## 📁 项目结构
|
||||
|
||||
```
|
||||
jm_ces/
|
||||
├── 📊 核心分析脚本
|
||||
│ ├── volume_price_sequence.py # 综合价格序列分析 (22KB)
|
||||
│ ├── volume_distribution_analysis.py # 成交量分布深度分析 (23KB)
|
||||
│ └── volume_price_distribution.py # 简化成交量价格分布 (16KB)
|
||||
│
|
||||
├── 📈 生成的图表
|
||||
│ ├── au2512_volume_price_sequence.png # 综合价格序列图 (1.0MB)
|
||||
│ ├── au2512_volume_distribution_analysis.png # 成交量分布分析图 (1.1MB)
|
||||
│ └── au2512_volume_price_distribution.png # 简化价格分布图 (0.3MB)
|
||||
│
|
||||
├── 📄 文档文件
|
||||
│ ├── README.md # 项目说明文档
|
||||
│ └── CLAUDE.md # Claude指导文档
|
||||
│
|
||||
└── 📂 数据目录
|
||||
├── au2512_20251013.parquet # 增强后的数据(含当前成交量列)
|
||||
├── au2512_20251013_backup.parquet # 原始数据备份
|
||||
└── jm2509_*.csv # 其他期货数据文件
|
||||
```
|
||||
|
||||
## 🗄️ 数据格式
|
||||
|
||||
### 支持的文件格式
|
||||
- **Parquet文件** (推荐): `.parquet`
|
||||
- **CSV文件**: `.csv`
|
||||
|
||||
### 必需字段
|
||||
```
|
||||
UTC, UTC.1, 时间, 累积成交量, 成交价, 成交额,
|
||||
买1价, 卖1价, 买1量, 卖1量,
|
||||
买2价, 卖2价, 买2量, 卖2量,
|
||||
买3价, 卖3价, 买3量, 卖3量,
|
||||
买4价, 卖4价, 买4量, 卖4量,
|
||||
买5价, 卖5价, 买5量, 卖5量
|
||||
```
|
||||
|
||||
### 关键字段说明
|
||||
- `UTC`, `UTC.1`: UTC时间戳(毫秒级)
|
||||
- `时间`: 当日累计时间(格式:MM:SS.秒)
|
||||
- `成交价`: 最新成交价格
|
||||
- `累积成交量`: 当日累计成交量
|
||||
- `当前成交量`: 单笔成交量(由累计成交量差值计算)
|
||||
- `数列号`: 按累计成交量排序的序号
|
||||
- `买1价`~`买5价`: 买方五档价格
|
||||
- `卖1价`~`卖5价`: 卖方五档价格
|
||||
|
||||
### 数据增强功能
|
||||
- ✅ 自动计算当前成交量(累计成交量差值)
|
||||
- ✅ 自动生成按成交量排序的数列号
|
||||
- ✅ 支持原始数据和增强数据的无缝切换
|
||||
|
||||
## 🎯 应用场景
|
||||
|
||||
### 交易分析
|
||||
- 快速识别价格在交易过程中的主要趋势
|
||||
- 发现影响价格变化的重要成交量时点
|
||||
- 评估不同交易阶段的价格行为
|
||||
|
||||
### 风险控制
|
||||
- 通过价格波动区间评估风险水平
|
||||
- 识别价格异常变化的临界点
|
||||
- 制定基于成交量的风险管理策略
|
||||
|
||||
### 策略研究
|
||||
- 为交易策略提供量化的数据支持
|
||||
- 研究成交量对价格影响的历史规律
|
||||
- 优化基于成交量变化的交易时机
|
||||
|
||||
### 市场研究
|
||||
- 理解交易行为对价格的影响机制
|
||||
- 研究价格发现的动态过程
|
||||
- 分析市场微观结构特征
|
||||
- 识别机构投资者交易模式
|
||||
|
||||
## 🔧 技术特性
|
||||
|
||||
- **高分辨率输出**: 300 DPI高清图表
|
||||
- **智能字体检测**: 自动适配中文字体
|
||||
- **容错处理**: 完善的错误处理和用户提示
|
||||
- **灵活配置**: 支持命令行参数自定义
|
||||
- **详细分析**: 完整的统计报告和业务洞察
|
||||
- **数据增强**: 自动计算当前成交量和排序
|
||||
|
||||
## 🚀 核心功能亮点
|
||||
|
||||
### 🎯 创新分析方式
|
||||
- **成交量序列分析**: 按累计成交量排序,更符合交易实际
|
||||
- **关键价格标注**: 自动识别成交量最大的价格水平
|
||||
- **多维度可视化**: 价格趋势 + 成交量分布的综合展示
|
||||
- **精确价格间隔**: 0.02元标准间隔,符合期货市场特性
|
||||
|
||||
### 📊 三大分析工具对比
|
||||
|
||||
| 特性 | 综合序列分析 | 深度分布分析 | 简化分布图 |
|
||||
|------|----------------|----------------|------------|
|
||||
| **适用场景** | 日常综合分析 | 深度研究报告 | 快速价格扫描 |
|
||||
| **图表复杂度** | 高(三合一) | 最高(7种图表) | 低(单一图表) |
|
||||
| **分析深度** | 价格趋势+成交量 | 统计+模式识别 | 价格分布 |
|
||||
| **输出文件大小** | 1.0MB | 1.1MB | 0.3MB |
|
||||
| **推荐使用** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
|
||||
|
||||
### 🎨 视觉设计特点
|
||||
- **关键价格标注**: 浅绿色虚线标识重要价格水平
|
||||
- **双向标注**: 左侧显示价格,右侧显示成交量
|
||||
- **价格对齐**: 主图与侧图完美同步
|
||||
- **简洁清晰**: 移除技术指标干扰,专注原始数据
|
||||
|
||||
### 1. 价格序列分析 (volume_price_sequence.py)
|
||||
#### 数据处理
|
||||
- 自动检测并处理不同格式的数据文件
|
||||
- 按累计成交量升序排列
|
||||
- 计算关键成交量节点
|
||||
- 生成移动平均线和波动区间
|
||||
|
||||
#### 可视化
|
||||
- **成交价序列线**(蓝色主线):价格随成交量变化轨迹
|
||||
- **当前成交量柱状图**:下方显示交易活跃度分布
|
||||
- **移动平均线**(红色粗线):平滑价格趋势
|
||||
- **价格波动区间**(红色阴影):不确定性范围
|
||||
- **关键节点标注**:详细价格信息
|
||||
- **分析结论框**:统计摘要
|
||||
|
||||
#### 统计分析
|
||||
- 基础价格统计(最高、最低、平均)
|
||||
- 成交量分析(分布、变化率)
|
||||
- 关键节点影响分析
|
||||
- 数据质量检查
|
||||
|
||||
### 2. 成交量分布深度分析 (volume_distribution_analysis.py)
|
||||
#### 分布统计分析
|
||||
- 基础统计(均值、中位数、标准差、分位数)
|
||||
- 分布特征分析(偏度、峰度、变异系数)
|
||||
- 正态性检验和分布拟合
|
||||
- 异常值检测和处理
|
||||
|
||||
#### 交易模式分析
|
||||
- 大单交易识别和分析
|
||||
- 成交量分组统计(1手、2-5手、6-10手等)
|
||||
- 交易频率和成交量贡献度分析
|
||||
- 主力交易模式识别
|
||||
|
||||
#### 7种专业可视化
|
||||
- **直方图 + 概率密度拟合**:分布形态分析
|
||||
- **箱线图**:分位数分布和数据离散程度
|
||||
- **累积分布函数**:概率累积情况
|
||||
- **成交量时间序列**:交易活跃度变化
|
||||
- **成交量分组柱状图**:各分组交易笔数对比
|
||||
- **成交量贡献度条形图**:各分组成交量占比
|
||||
- **统计摘要表**:完整的统计信息展示
|
||||
|
||||
#### 业务洞察
|
||||
- 成交量分布特征解读
|
||||
- 市场活跃度评估
|
||||
- 机构参与度分析
|
||||
- 交易建议和风险提示
|
||||
|
||||
## 🛠️ 开发信息
|
||||
|
||||
### 依赖项
|
||||
- `pandas` - 数据处理和分析
|
||||
- `numpy` - 数值计算
|
||||
- `matplotlib` - 数据可视化
|
||||
- `scipy` - 统计分析和分布拟合
|
||||
- `seaborn` - 高级统计图表(可选)
|
||||
|
||||
### 代码质量
|
||||
- 面向对象设计,易于维护和扩展
|
||||
- 完整的错误处理和用户友好提示
|
||||
- 详细的代码注释和文档
|
||||
- 符合Python编码规范
|
||||
|
||||
## 🚀 快速导航
|
||||
|
||||
### 新手推荐流程
|
||||
```bash
|
||||
# 1. 先运行价格序列分析,了解整体价格趋势
|
||||
python volume_price_sequence.py
|
||||
|
||||
# 2. 再运行成交量分布分析,深入了解交易模式
|
||||
python volume_distribution_analysis.py
|
||||
|
||||
# 3. 查看生成的图表和报告
|
||||
# - au2512_volume_price_sequence.png
|
||||
# - au2512_volume_distribution_analysis.png
|
||||
```
|
||||
|
||||
### 数据文件准备
|
||||
```bash
|
||||
# 确保数据文件存在且格式正确
|
||||
ls -la data/au2512_20251013.parquet
|
||||
|
||||
# 如果需要处理新数据,确保包含必要字段
|
||||
# UTC, 累积成交量, 成交价, 等...
|
||||
```
|
||||
|
||||
## 📞 支持与反馈
|
||||
|
||||
### 问题报告
|
||||
如果在使用过程中遇到问题:
|
||||
1. **检查数据文件格式**:确保包含必需字段(累积成交量、成交价等)
|
||||
2. **确认依赖库安装**:`pip install pandas numpy matplotlib scipy`
|
||||
3. **查看错误信息**:命令行会显示详细的错误提示
|
||||
4. **中文字体问题**:确保系统支持中文字体显示
|
||||
|
||||
### 常见问题解决
|
||||
- **字体显示异常**:脚本会自动检测并设置合适的中文字体
|
||||
- **数据加载失败**:检查文件路径和文件格式
|
||||
- **图表生成失败**:确保有足够的磁盘空间和写入权限
|
||||
|
||||
### 功能建议
|
||||
欢迎提出改进建议和新功能需求,包括:
|
||||
- 新的图表类型
|
||||
- 更多的统计指标
|
||||
- 更好的数据预处理
|
||||
- 性能优化建议
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
本项目采用 MIT 许可证,详见 LICENSE 文件。
|
||||
|
||||
## 🙏 致谢
|
||||
|
||||
感谢所有为期货数据分析和可视化做出贡献的开发者和研究人员,以及提供宝贵反馈的用户。
|
||||
|
||||
---
|
||||
|
||||
**版本**: 2.0
|
||||
**最后更新**: 2025-11-02
|
||||
**核心工具**:
|
||||
- `volume_price_sequence.py` - 价格序列分析
|
||||
- `volume_distribution_analysis.py` - 成交量分布深度分析
|
||||
**项目状态**: ✅ 活跃维护中
|
||||
**新增功能**:
|
||||
- ✅ 成交量分布深度分析
|
||||
- ✅ 当前成交量柱状图
|
||||
- ✅ 7种专业可视化图表
|
||||
- ✅ 业务洞察和交易建议
|
||||
156
add_order_sum_columns.py
Normal file
@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
为AU2512期货数据添加买挂合计和卖挂合计列
|
||||
|
||||
这个脚本读取原始数据文件,计算买方和卖方的挂单总量,
|
||||
并添加两列:买挂合计(买1量至买5量之和)和卖挂合计(卖1量至卖5量之和)
|
||||
|
||||
使用方法:
|
||||
python add_order_sum_columns.py
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
def add_order_sum_columns():
|
||||
"""添加买挂合计和卖挂合计列到数据文件"""
|
||||
|
||||
# 文件路径
|
||||
input_file = 'data/au2512_20251013.parquet'
|
||||
backup_file = 'data/au2512_20251013_order_backup.parquet'
|
||||
output_file = 'data/au2512_20251013.parquet'
|
||||
|
||||
print("开始为AU2512期货数据添加买挂合计和卖挂合计列...")
|
||||
|
||||
# 检查输入文件是否存在
|
||||
if not os.path.exists(input_file):
|
||||
print(f"错误: 输入文件不存在 - {input_file}")
|
||||
return False
|
||||
|
||||
try:
|
||||
# 读取数据
|
||||
print(f"正在读取数据文件: {input_file}")
|
||||
df = pd.read_parquet(input_file)
|
||||
print(f"数据加载成功: {len(df):,} 条记录")
|
||||
|
||||
# 显示原始列名
|
||||
print(f"\n原始列名 ({len(df.columns)} 列):")
|
||||
for i, col in enumerate(df.columns):
|
||||
print(f" {i:2d}: {col}")
|
||||
|
||||
# 找到买量和卖量的列
|
||||
buy_volume_cols = []
|
||||
sell_volume_cols = []
|
||||
|
||||
for col in df.columns:
|
||||
if '买' in col and '量' in col:
|
||||
buy_volume_cols.append(col)
|
||||
elif '卖' in col and '量' in col:
|
||||
sell_volume_cols.append(col)
|
||||
|
||||
print(f"\n找到的买量列: {buy_volume_cols}")
|
||||
print(f"找到的卖量列: {sell_volume_cols}")
|
||||
|
||||
if len(buy_volume_cols) < 5 or len(sell_volume_cols) < 5:
|
||||
print("警告: 找到的买量或卖量列不足5个")
|
||||
|
||||
# 计算买挂合计(买1量至买5量之和)
|
||||
print(f"\n计算买挂合计...")
|
||||
df['买挂合计'] = df[buy_volume_cols[:5]].sum(axis=1)
|
||||
|
||||
# 计算卖挂合计(卖1量至卖5量之和)
|
||||
print(f"计算卖挂合计...")
|
||||
df['卖挂合计'] = df[sell_volume_cols[:5]].sum(axis=1)
|
||||
|
||||
# 显示添加的列信息
|
||||
print(f"\n添加的列信息:")
|
||||
print(f"买挂合计: 最小值 {df['买挂合计'].min()}, 最大值 {df['买挂合计'].max()}, 平均值 {df['买挂合计'].mean():.1f}")
|
||||
print(f"卖挂合计: 最小值 {df['卖挂合计'].min()}, 最大值 {df['卖挂合计'].max()}, 平均值 {df['卖挂合计'].mean():.1f}")
|
||||
|
||||
# 备份原始文件
|
||||
if not os.path.exists(backup_file):
|
||||
print(f"\n备份原始文件到: {backup_file}")
|
||||
df_original = pd.read_parquet(input_file)
|
||||
df_original.to_parquet(backup_file, index=False)
|
||||
print("原始文件备份完成")
|
||||
else:
|
||||
print(f"\n备份文件已存在: {backup_file},跳过备份")
|
||||
|
||||
# 保存增强后的数据
|
||||
print(f"\n保存增强后的数据到: {output_file}")
|
||||
df.to_parquet(output_file, index=False)
|
||||
|
||||
# 显示最终列信息
|
||||
print(f"\n最终数据列信息 ({len(df.columns)} 列):")
|
||||
for i, col in enumerate(df.columns):
|
||||
print(f" {i:2d}: {col}")
|
||||
|
||||
print(f"\n数据增强完成!")
|
||||
print(f"新增列:")
|
||||
print(f" - 买挂合计: 买1量至买5量之和")
|
||||
print(f" - 卖挂合计: 卖1量至卖5量之和")
|
||||
|
||||
# 显示一些统计信息
|
||||
print(f"\n统计信息:")
|
||||
print(f"买挂合计 > 0 的记录: {(df['买挂合计'] > 0).sum():,} ({(df['买挂合计'] > 0).mean()*100:.1f}%)")
|
||||
print(f"卖挂合计 > 0 的记录: {(df['卖挂合计'] > 0).sum():,} ({(df['卖挂合计'] > 0).mean()*100:.1f}%)")
|
||||
print(f"买挂合计最大值: {df['买挂合计'].max():,} 手")
|
||||
print(f"卖挂合计最大值: {df['卖挂合计'].max():,} 手")
|
||||
print(f"买挂合计平均值: {df['买挂合计'].mean():.1f} 手")
|
||||
print(f"卖挂合计平均值: {df['卖挂合计'].mean():.1f} 手")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"处理过程中发生错误: {e}")
|
||||
return False
|
||||
|
||||
def verify_columns():
|
||||
"""验证添加的列是否正确"""
|
||||
print("\n" + "="*60)
|
||||
print("验证添加的列")
|
||||
print("="*60)
|
||||
|
||||
try:
|
||||
# 读取增强后的数据
|
||||
df = pd.read_parquet('data/au2512_20251013.parquet')
|
||||
|
||||
if '买挂合计' in df.columns and '卖挂合计' in df.columns:
|
||||
print("[OK] 买挂合计和卖挂合计列已成功添加")
|
||||
|
||||
# 显示前5行的相关列
|
||||
buy_cols = [col for col in df.columns if '买' in col and '量' in col][:5]
|
||||
sell_cols = [col for col in df.columns if '卖' in col and '量' in col][:5]
|
||||
|
||||
print(f"\n前5行数据验证:")
|
||||
print("买量列 + 买挂合计:")
|
||||
for i in range(min(5, len(df))):
|
||||
buy_sum = df[buy_cols].iloc[i].sum()
|
||||
buy_total = df['买挂合计'].iloc[i]
|
||||
match = "[OK]" if abs(buy_sum - buy_total) < 0.001 else "[ERROR]"
|
||||
print(f" 行{i+1}: 买量列求和={buy_sum}, 买挂合计={buy_total} {match}")
|
||||
|
||||
print("卖量列 + 卖挂合计:")
|
||||
for i in range(min(5, len(df))):
|
||||
sell_sum = df[sell_cols].iloc[i].sum()
|
||||
sell_total = df['卖挂合计'].iloc[i]
|
||||
match = "[OK]" if abs(sell_sum - sell_total) < 0.001 else "[ERROR]"
|
||||
print(f" 行{i+1}: 卖量列求和={sell_sum}, 卖挂合计={sell_total} {match}")
|
||||
|
||||
else:
|
||||
print("[ERROR] 买挂合计或卖挂合计列未找到")
|
||||
|
||||
except Exception as e:
|
||||
print(f"验证过程中发生错误: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = add_order_sum_columns()
|
||||
|
||||
if success:
|
||||
verify_columns()
|
||||
print(f"\n[OK] 数据增强完成!")
|
||||
else:
|
||||
print(f"\n[ERROR] 数据增强失败!")
|
||||
82
add_volume_columns.py
Normal file
@ -0,0 +1,82 @@
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
def add_volume_and_sequence_columns(input_file, output_file=None):
|
||||
"""
|
||||
为期货数据添加当前成交量和数列号列
|
||||
|
||||
Parameters:
|
||||
- input_file: 输入的parquet文件路径
|
||||
- output_file: 输出文件路径,如果为None则覆盖原文件
|
||||
|
||||
Returns:
|
||||
- 处理后的DataFrame
|
||||
"""
|
||||
|
||||
# 读取数据
|
||||
print(f"正在读取文件: {input_file}")
|
||||
df = pd.read_parquet(input_file)
|
||||
print(f"原始数据形状: {df.shape}")
|
||||
|
||||
# 确定累计成交量列(第4列,索引为3)
|
||||
cumulative_volume_col = df.columns[3] # <20>ۻ<EFBFBD><DBBB>ɽ<EFBFBD><C9BD><EFBFBD>
|
||||
print(f"累计成交量列: {cumulative_volume_col}")
|
||||
|
||||
# 计算当前成交量(累计成交量的差值)
|
||||
print("正在计算当前成交量...")
|
||||
df['当前成交量'] = df[cumulative_volume_col].diff()
|
||||
|
||||
# 第一行的当前成交量设为第一行的累计成交量
|
||||
df.loc[df.index[0], '当前成交量'] = df.loc[df.index[0], cumulative_volume_col]
|
||||
|
||||
# 按累计成交量排序并添加数列号
|
||||
print("正在按累计成交量排序并添加数列号...")
|
||||
df_sorted = df.sort_values(by=cumulative_volume_col, ascending=True).copy()
|
||||
df_sorted['数列号'] = range(1, len(df_sorted) + 1)
|
||||
|
||||
# 恢复原始顺序(按时间顺序)
|
||||
df_final = df_sorted.sort_index().copy()
|
||||
|
||||
# 显示添加的列信息
|
||||
print("\n添加的新列信息:")
|
||||
print(f"当前成交量列统计:")
|
||||
print(f" 最小值: {df_final['当前成交量'].min()}")
|
||||
print(f" 最大值: {df_final['当前成交量'].max()}")
|
||||
print(f" 平均值: {df_final['当前成交量'].mean():.2f}")
|
||||
print(f" 总和: {df_final['当前成交量'].sum()}")
|
||||
print(f"数列号列统计:")
|
||||
print(f" 最小值: {df_final['数列号'].min()}")
|
||||
print(f" 最大值: {df_final['数列号'].max()}")
|
||||
|
||||
# 验证计算是否正确
|
||||
print("\n验证计算结果:")
|
||||
print(f"累计成交量最后一行: {df_final[cumulative_volume_col].iloc[-1]}")
|
||||
print(f"当前成交量总和: {df_final['当前成交量'].sum()}")
|
||||
print(f"两者是否相等: {df_final[cumulative_volume_col].iloc[-1] == df_final['当前成交量'].sum()}")
|
||||
|
||||
# 显示前几行数据以验证
|
||||
print("\n前5行数据(包含新列):")
|
||||
display_cols = [cumulative_volume_col, '当前成交量', '数列号']
|
||||
print(df_final[display_cols].head())
|
||||
|
||||
# 保存文件
|
||||
if output_file is None:
|
||||
output_file = input_file
|
||||
|
||||
print(f"\n正在保存到文件: {output_file}")
|
||||
df_final.to_parquet(output_file, index=False)
|
||||
print("文件保存完成!")
|
||||
|
||||
return df_final
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 处理au2512数据
|
||||
input_file = "data/au2512_20251013.parquet"
|
||||
output_file = "data/au2512_20251013_updated.parquet"
|
||||
|
||||
try:
|
||||
result_df = add_volume_and_sequence_columns(input_file, output_file)
|
||||
print(f"\n处理完成! 输出文件: {output_file}")
|
||||
print(f"最终数据形状: {result_df.shape}")
|
||||
except Exception as e:
|
||||
print(f"处理过程中出现错误: {e}")
|
||||
1041
analyze_large_orders.py
Normal file
BIN
au2512_volume_distribution_analysis.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
au2512_volume_price_distribution.png
Normal file
|
After Width: | Height: | Size: 325 KiB |
BIN
au2512_volume_price_sequence.png
Normal file
|
After Width: | Height: | Size: 1008 KiB |
194
check_buy1_price_decline.py
Normal file
@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
检查买1量大于99的挂单后是否出现低于当前价格的数据
|
||||
|
||||
详细分析买1量大单出现后的价格行为,验证是否真的全部上涨
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
def check_buy1_price_decline():
|
||||
"""检查买1量大单后的价格下跌情况"""
|
||||
|
||||
# 加载数据
|
||||
data_file = 'data/au2512_20251013.parquet'
|
||||
if not os.path.exists(data_file):
|
||||
print(f"数据文件不存在: {data_file}")
|
||||
return
|
||||
|
||||
print("正在加载数据...")
|
||||
df = pd.read_parquet(data_file)
|
||||
print(f"数据加载成功: {len(df):,} 条记录")
|
||||
|
||||
# 确保按数列号排序
|
||||
if '数列号' in df.columns:
|
||||
df = df.sort_values('数列号').reset_index(drop=True)
|
||||
|
||||
# 找到买1量列
|
||||
buy1_col = None
|
||||
for col in df.columns:
|
||||
if '买1量' in col:
|
||||
buy1_col = col
|
||||
break
|
||||
|
||||
if buy1_col is None:
|
||||
print("未找到买1量列")
|
||||
return
|
||||
|
||||
print(f"使用买1量列: {buy1_col}")
|
||||
|
||||
# 筛选买1量大于99的数据
|
||||
threshold = 99
|
||||
large_buy1_mask = df[buy1_col] > threshold
|
||||
large_buy1_orders = df[large_buy1_mask].copy().reset_index(drop=True)
|
||||
|
||||
print(f"\n买1量 > {threshold} 的记录数: {len(large_buy1_orders):,}")
|
||||
print(f"占总记录比例: {len(large_buy1_orders)/len(df)*100:.2f}%")
|
||||
|
||||
if len(large_buy1_orders) == 0:
|
||||
print("未找到符合条件的记录")
|
||||
return
|
||||
|
||||
# 详细分析每个大单后的价格行为
|
||||
print(f"\n" + "="*80)
|
||||
print("买1量大单后价格行为详细分析")
|
||||
print("="*80)
|
||||
|
||||
decline_100_count = 0
|
||||
decline_200_count = 0
|
||||
detailed_results = []
|
||||
|
||||
for idx, row in large_buy1_orders.iterrows():
|
||||
current_seq_num = row['数列号'] if '数列号' in row else idx
|
||||
current_price = row['成交价']
|
||||
buy1_volume = row[buy1_col]
|
||||
|
||||
# 获取后续100笔数据
|
||||
future_mask_100 = df['数列号'] >= current_seq_num + 1
|
||||
future_data_100 = df[future_mask_100].head(100)
|
||||
|
||||
# 获取后续200笔数据
|
||||
future_mask_200 = df['数列号'] >= current_seq_num + 1
|
||||
future_data_200 = df[future_mask_200].head(200)
|
||||
|
||||
# 分析100笔内的价格行为
|
||||
if len(future_data_100) > 0:
|
||||
min_price_100 = future_data_100['成交价'].min()
|
||||
max_price_100 = future_data_100['成交价'].max()
|
||||
price_decline_100 = current_price - min_price_100 # 价格下跌幅度
|
||||
price_rise_100 = max_price_100 - current_price # 价格上涨幅度
|
||||
|
||||
# 检查是否出现低于当前价格的情况
|
||||
has_decline_100 = min_price_100 < current_price
|
||||
|
||||
if has_decline_100:
|
||||
decline_100_count += 1
|
||||
decline_info_100 = f"是 (最低: {min_price_100:.2f}, 下跌: {price_decline_100:.2f})"
|
||||
else:
|
||||
decline_info_100 = f"否 (最低: {min_price_100:.2f})"
|
||||
|
||||
# 分析200笔内的价格行为
|
||||
if len(future_data_200) > 0:
|
||||
min_price_200 = future_data_200['成交价'].min()
|
||||
max_price_200 = future_data_200['成交价'].max()
|
||||
price_decline_200 = current_price - min_price_200 # 价格下跌幅度
|
||||
price_rise_200 = max_price_200 - current_price # 价格上涨幅度
|
||||
|
||||
# 检查是否出现低于当前价格的情况
|
||||
has_decline_200 = min_price_200 < current_price
|
||||
|
||||
if has_decline_200:
|
||||
decline_200_count += 1
|
||||
decline_info_200 = f"是 (最低: {min_price_200:.2f}, 下跌: {price_decline_200:.2f})"
|
||||
else:
|
||||
decline_info_200 = f"否 (最低: {min_price_200:.2f})"
|
||||
|
||||
# 记录详细结果
|
||||
detailed_results.append({
|
||||
'序号': idx + 1,
|
||||
'数列号': current_seq_num,
|
||||
'当前价格': current_price,
|
||||
'买1量': buy1_volume,
|
||||
'100笔样本数': len(future_data_100),
|
||||
'100笔最低价': min_price_100 if len(future_data_100) > 0 else None,
|
||||
'100笔最高价': max_price_100 if len(future_data_100) > 0 else None,
|
||||
'100笔是否下跌': has_decline_100 if len(future_data_100) > 0 else None,
|
||||
'100笔下跌幅度': price_decline_100 if len(future_data_100) > 0 else None,
|
||||
'100笔上涨幅度': price_rise_100 if len(future_data_100) > 0 else None,
|
||||
'200笔样本数': len(future_data_200),
|
||||
'200笔最低价': min_price_200 if len(future_data_200) > 0 else None,
|
||||
'200笔最高价': max_price_200 if len(future_data_200) > 0 else None,
|
||||
'200笔是否下跌': has_decline_200 if len(future_data_200) > 0 else None,
|
||||
'200笔下跌幅度': price_decline_200 if len(future_data_200) > 0 else None,
|
||||
'200笔上涨幅度': price_rise_200 if len(future_data_200) > 0 else None,
|
||||
})
|
||||
|
||||
# 保存详细结果
|
||||
results_df = pd.DataFrame(detailed_results)
|
||||
results_df.to_csv('large_orders/buy1_detailed_price_analysis.csv', index=False, encoding='utf-8-sig')
|
||||
|
||||
# 打印汇总统计
|
||||
print(f"\n【汇总统计】")
|
||||
print(f"总样本数: {len(large_buy1_orders)}")
|
||||
print(f"100笔内出现价格下跌的样本数: {decline_100_count} ({decline_100_count/len(large_buy1_orders)*100:.1f}%)")
|
||||
print(f"200笔内出现价格下跌的样本数: {decline_200_count} ({decline_200_count/len(large_buy1_orders)*100:.1f}%)")
|
||||
|
||||
# 打印详细分析
|
||||
print(f"\n【详细分析 - 前15个样本】")
|
||||
print(f"{'序号':>4} {'数列号':>8} {'当前价格':>10} {'买1量':>8} {'100笔下跌?':>12} {'200笔下跌?':>12}")
|
||||
print("-" * 80)
|
||||
|
||||
for i, result in enumerate(detailed_results[:15]):
|
||||
decline_100_status = "是" if result['100笔是否下跌'] else "否"
|
||||
decline_200_status = "是" if result['200笔是否下跌'] else "否"
|
||||
|
||||
print(f"{result['序号']:>4} {result['数列号']:>8.0f} {result['当前价格']:>10.2f} "
|
||||
f"{result['买1量']:>8.0f} {decline_100_status:>12} {decline_200_status:>12}")
|
||||
|
||||
# 分析下跌样本的详细信息
|
||||
decline_samples_100 = [r for r in detailed_results if r['100笔是否下跌']]
|
||||
decline_samples_200 = [r for r in detailed_results if r['200笔是否下跌']]
|
||||
|
||||
if decline_samples_100:
|
||||
print(f"\n【100笔内出现价格下跌的样本详情】")
|
||||
for result in decline_samples_100:
|
||||
print(f"序号{result['序号']}: 当前价格={result['当前价格']:.2f}, "
|
||||
f"最低价格={result['100笔最低价']:.2f}, "
|
||||
f"下跌幅度={result['100笔下跌幅度']:.2f}元, "
|
||||
f"买1量={result['买1量']:.0f}手")
|
||||
|
||||
if decline_samples_200:
|
||||
print(f"\n【200笔内出现价格下跌的样本详情】")
|
||||
for result in decline_samples_200:
|
||||
print(f"序号{result['序号']}: 当前价格={result['当前价格']:.2f}, "
|
||||
f"最低价格={result['200笔最低价']:.2f}, "
|
||||
f"下跌幅度={result['200笔下跌幅度']:.2f}元, "
|
||||
f"买1量={result['买1量']:.0f}手")
|
||||
|
||||
# 价格波动统计
|
||||
print(f"\n【价格波动统计】")
|
||||
if len(detailed_results) > 0:
|
||||
all_declines_100 = [r['100笔下跌幅度'] for r in detailed_results if r['100笔下跌幅度'] is not None]
|
||||
all_rises_100 = [r['100笔上涨幅度'] for r in detailed_results if r['100笔上涨幅度'] is not None]
|
||||
|
||||
if all_declines_100:
|
||||
avg_decline_100 = np.mean(all_declines_100)
|
||||
max_decline_100 = np.max(all_declines_100)
|
||||
print(f"100笔内平均下跌幅度: {avg_decline_100:.3f}元")
|
||||
print(f"100笔内最大下跌幅度: {max_decline_100:.3f}元")
|
||||
|
||||
if all_rises_100:
|
||||
avg_rise_100 = np.mean(all_rises_100)
|
||||
max_rise_100 = np.max(all_rises_100)
|
||||
print(f"100笔内平均上涨幅度: {avg_rise_100:.3f}元")
|
||||
print(f"100笔内最大上涨幅度: {max_rise_100:.3f}元")
|
||||
|
||||
print(f"\n分析完成!详细结果已保存到: large_orders/buy1_detailed_price_analysis.csv")
|
||||
|
||||
return decline_100_count, decline_200_count
|
||||
|
||||
if __name__ == "__main__":
|
||||
check_buy1_price_decline()
|
||||
66597
data/au2512_20251013.csv
Normal file
BIN
data/au2512_20251013.parquet
Normal file
BIN
data/au2512_20251013_backup.parquet
Normal file
BIN
data/au2512_20251013_order_backup.parquet
Normal file
237647
data/jm2509_20250709.csv
Normal file
245501
data/jm2509_20250710.csv
Normal file
280411
data/jm2509_20250711.csv
Normal file
215477
data/jm2509_20250717.csv
Normal file
BIN
large_buy1_price_sequences.png
Normal file
|
After Width: | Height: | Size: 475 KiB |
BIN
large_buy1_relative_price_changes.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
300
large_orders/README.md
Normal file
@ -0,0 +1,300 @@
|
||||
# 大额订单分析项目
|
||||
|
||||
## 项目概述
|
||||
|
||||
本项目专注于分析期货市场中不同类型的大额信号对后续价格走势的影响。通过多时间维度的统计分析,揭示大额订单、买卖挂单合计以及当前成交量对价格的短期、中期和长期影响规律。
|
||||
|
||||
**最新更新**:新增信号抑制优化算法,有效减少重复信号干扰,提供更准确的市场反应分析。
|
||||
|
||||
## 核心发现
|
||||
|
||||
### 📊 关键统计结果对比
|
||||
|
||||
#### 买1/卖1量分析(阈值99)
|
||||
| 数据类型 | 序列数量 | 100点平均变化 | 200点平均变化 | 500点平均变化 |
|
||||
|---------|---------|--------------|--------------|--------------|
|
||||
| **买1量>99** | 31个 | -0.0897 | -0.1271 | -0.0484 |
|
||||
| **卖1量>99** | 8个 | -0.1325 | **+0.3375** | **+1.1325** |
|
||||
|
||||
#### 买卖挂单合计分析(阈值200)
|
||||
| 数据类型 | 序列数量 | 100点平均变化 | 200点平均变化 | 500点平均变化 |
|
||||
|---------|---------|--------------|--------------|--------------|
|
||||
| **买挂合计>200** | 64个 | +0.0409 | +0.0316 | +0.0259 |
|
||||
| **卖挂合计>200** | 21个 | -0.2324 | -0.3362 | -0.4267 |
|
||||
|
||||
#### 当前成交量分析(阈值150)
|
||||
| 数据类型 | 序列数量 | 100点平均变化 | 200点平均变化 | 500点平均变化 |
|
||||
|---------|---------|--------------|--------------|--------------|
|
||||
| **原始分析** | 92个 | -0.0778 | -0.0200 | +0.3722 |
|
||||
| **信号抑制优化** | 57个 | **+0.1347** | **+0.1428** | **+0.2821** |
|
||||
|
||||
### 🔍 重要趋势洞察
|
||||
|
||||
1. **卖1量大单的反转效应**:
|
||||
- 短期(100点):明显下跌 -0.1325
|
||||
- 中期(200点):反转上涨 +0.3375
|
||||
- 长期(500点):大幅上涨 +1.1325
|
||||
|
||||
2. **买卖挂单合计的分化效应**:
|
||||
- 买挂合计大单:各时间窗口均为小幅正收益
|
||||
- 卖挂合计大单:各时间窗口均为明显负收益
|
||||
- 差异随时间扩大,表明市场反应持续
|
||||
|
||||
3. **信号抑制的显著效果**:
|
||||
- 信号抑制率:38.0%(92→57个信号)
|
||||
- 短期效果改善:100点从-0.0778转为+0.1347
|
||||
- 上涨比例提升:从39.1%提升至52.6%
|
||||
|
||||
4. **关键转折点**:
|
||||
- 第50点:买1下跌更多 (-0.0458 vs -0.0050)
|
||||
- 第200点:卖1开始反转 (+0.3375 vs -0.1593)
|
||||
- 第500点:卖1显著领先 (+1.3767 vs -0.0689)
|
||||
|
||||
## 文件说明
|
||||
|
||||
### 📜 分析脚本
|
||||
|
||||
| 文件名 | 功能描述 | 阈值 | 适用场景 |
|
||||
|--------|---------|------|----------|
|
||||
| `analyze_large_buy1_orders.py` | 买1量>99的单独分析 | 99 | 专门分析买方大额订单 |
|
||||
| `analyze_large_orders.py` | 买1和卖1综合分析(100点) | 99 | 基础对比分析 |
|
||||
| `analyze_large_orders_extended.py` | 多时间维度综合分析 | 99 | 完整的时间周期分析 |
|
||||
| `analyze_total_orders_extended.py` | 买卖挂单合计分析 | 200 | 分析五档挂单总量影响 |
|
||||
| `analyze_current_volume_extended.py` | 当前成交量分析 | 150 | 基于成交量的活跃度分析 |
|
||||
| `analyze_current_volume_optimized.py` | 信号抑制优化分析 | 150 | 去除重复信号的高质量分析 |
|
||||
|
||||
### 📈 分析图表
|
||||
|
||||
#### 买1/卖1量分析(阈值99)
|
||||
**100个数据点分析**
|
||||
- `large_orders_comprehensive_analysis_100points.png` - 综合对比四宫格图
|
||||
- `large_buy1_relative_price_changes_100points.png` - 买1量价格走势图
|
||||
- `large_sell1_relative_price_changes_100points.png` - 卖1量价格走势图
|
||||
|
||||
**200个数据点分析**
|
||||
- `large_orders_comprehensive_analysis_200points.png` - 综合对比四宫格图
|
||||
- `large_buy1_relative_price_changes_200points.png` - 买1量价格走势图
|
||||
- `large_sell1_relative_price_changes_200points.png` - 卖1量价格走势图
|
||||
|
||||
**500个数据点分析**
|
||||
- `large_orders_comprehensive_analysis_500points.png` - 综合对比四宫格图
|
||||
- `large_buy1_relative_price_changes_500points.png` - 买1量价格走势图
|
||||
- `large_sell1_relative_price_changes_500points.png` - 卖1量价格走势图
|
||||
|
||||
#### 买卖挂单合计分析(阈值200)
|
||||
- `total_orders_comprehensive_analysis_100points.png` - 综合对比四宫格图
|
||||
- `total_buy_relative_price_changes_100points.png` - 买挂合计价格走势图
|
||||
- `total_sell_relative_price_changes_100points.png` - 卖挂合计价格走势图
|
||||
- `total_orders_comprehensive_analysis_200points.png` - 200点综合分析
|
||||
- `total_orders_comprehensive_analysis_500points.png` - 500点综合分析
|
||||
|
||||
#### 当前成交量分析(阈值150)
|
||||
**原始分析**
|
||||
- `current_volume_comprehensive_analysis_100points.png` - 综合对比四宫格图
|
||||
- `current_volume_relative_price_changes_100points.png` - 成交量价格走势图
|
||||
- `current_volume_comprehensive_analysis_200points.png` - 200点综合分析
|
||||
- `current_volume_comprehensive_analysis_500points.png` - 500点综合分析
|
||||
|
||||
**信号抑制优化分析**
|
||||
- `current_volume_optimized_comprehensive_analysis_100points.png` - 优化版综合分析
|
||||
- `current_volume_optimized_relative_price_changes_100points.png` - 优化版价格走势
|
||||
- `current_volume_optimized_comprehensive_analysis_200points.png` - 200点优化分析
|
||||
- `current_volume_optimized_comprehensive_analysis_500points.png` - 500点优化分析
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 环境要求
|
||||
- Python 3.7+
|
||||
- pandas
|
||||
- numpy
|
||||
- matplotlib
|
||||
|
||||
### 运行脚本
|
||||
|
||||
1. **基础分析(100个数据点)**:
|
||||
```bash
|
||||
python analyze_large_orders.py
|
||||
```
|
||||
|
||||
2. **多时间维度分析(100/200/500个数据点)**:
|
||||
```bash
|
||||
python analyze_large_orders_extended.py
|
||||
```
|
||||
|
||||
3. **仅买1量分析**:
|
||||
```bash
|
||||
python analyze_large_buy1_orders.py
|
||||
```
|
||||
|
||||
4. **买卖挂单合计分析(阈值200)**:
|
||||
```bash
|
||||
python analyze_total_orders_extended.py
|
||||
```
|
||||
|
||||
5. **当前成交量分析(阈值150)**:
|
||||
```bash
|
||||
python analyze_current_volume_extended.py
|
||||
```
|
||||
|
||||
6. **信号抑制优化分析(推荐)**:
|
||||
```bash
|
||||
python analyze_current_volume_optimized.py
|
||||
```
|
||||
|
||||
### 数据要求
|
||||
- 数据文件位置:`../data/au2512_20251013.parquet`
|
||||
- 必需字段:买1量、卖1量、成交价、当前成交量、买1-5量、卖1-5量
|
||||
- 数据格式:Parquet文件
|
||||
|
||||
## 图表说明
|
||||
|
||||
### 📊 综合分析四宫格图
|
||||
|
||||
每个综合分析图表包含四个部分:
|
||||
|
||||
1. **左上:买1量>99价格走势**
|
||||
- 蓝色系线条表示各个序列
|
||||
- 显示所有买1量大单后的价格变化
|
||||
|
||||
2. **右上:卖1量>99价格走势**
|
||||
- 红色系线条表示各个序列
|
||||
- 显示所有卖1量大单后的价格变化
|
||||
|
||||
3. **左下:平均价格变化对比**
|
||||
- 蓝线:买1量平均变化
|
||||
- 红线:卖1量平均变化
|
||||
- 黑色虚线:基准价格线(0)
|
||||
|
||||
4. **右下:统计信息对比**
|
||||
- 序列数量、平均变化、标准差
|
||||
- 最大上涨/下跌幅度
|
||||
- 关键时间点对比
|
||||
|
||||
### 📈 单独分析图
|
||||
|
||||
- 横轴:数据点序号(相对于大额订单出现时刻)
|
||||
- 纵轴:相对价格变化(相对于基准点成交价)
|
||||
- 所有序列从0开始,便于对比相对变化
|
||||
|
||||
## 分析方法论
|
||||
|
||||
### 🔬 数据处理流程
|
||||
|
||||
1. **信号筛选**:
|
||||
- 买1量>99 或 卖1量>99
|
||||
- 买挂合计>200 或 卖挂合计>200
|
||||
- 当前成交量>150
|
||||
|
||||
2. **信号抑制优化**(仅优化版):
|
||||
- 按数列依次判断,当一个数列满足条件后
|
||||
- 其后20个数列如有相同信号则不画图,仅计数
|
||||
- 有效减少重复信号干扰
|
||||
|
||||
3. **基准点设定**:以大额信号出现时的成交价为基准(0点)
|
||||
|
||||
4. **相对变化计算**:后续价格 - 基准价格
|
||||
|
||||
5. **时间窗口**:分别分析100、200、500个后续数据点
|
||||
|
||||
### 📐 统计指标
|
||||
|
||||
- **平均最终变化**:所有序列在终点时刻的平均价格变化
|
||||
- **变化标准差**:价格变化的波动性指标
|
||||
- **最大上涨/下跌**:极值分析
|
||||
- **上涨比例**:正收益序列占总序列的比例
|
||||
- **信号抑制率**:被抑制信号数量占总信号数量的比例
|
||||
- **关键时间点**:第10、50、200、500点的平均变化
|
||||
|
||||
## 交易策略启示
|
||||
|
||||
### 💡 基于分析结果的策略建议
|
||||
|
||||
1. **卖1量大单的反转机会**:
|
||||
- 短期:避免立即入场,等待下跌结束
|
||||
- 中长期:可考虑在200点后布局做多
|
||||
|
||||
2. **买1量大单的谨慎态度**:
|
||||
- 短中期:保持谨慎,防范下跌风险
|
||||
- 长期:可关注压力缓解后的机会
|
||||
|
||||
3. **买卖挂单合计的分化策略**:
|
||||
- 买挂合计大单:小幅做多,适合稳健策略
|
||||
- 卖挂合计大单:明显做空,收益确定性较高
|
||||
- 差异随时间扩大,可考虑价差策略
|
||||
|
||||
4. **当前成交量的优化应用**:
|
||||
- 原始信号:存在噪声,短期效果不佳
|
||||
- 信号抑制优化:显著改善短期表现,建议优先使用
|
||||
- 大成交量后:短期转为正收益,可参与短线交易
|
||||
|
||||
5. **时间维度选择**:
|
||||
- 短线交易(100点内):使用信号抑制优化的成交量分析
|
||||
- 中线交易(200点):关注卖1量大单的反转信号
|
||||
- 长线交易(500点):卖1量大单后存在显著上涨机会
|
||||
|
||||
## 技术细节
|
||||
|
||||
### 🛠️ 代码特点
|
||||
|
||||
- **模块化设计**:函数式编程,便于维护和扩展
|
||||
- **信号抑制算法**:智能去除重复信号,提高分析质量
|
||||
- **容错处理**:完善的边界条件检查
|
||||
- **可视化优化**:专业的图表设计和配色方案
|
||||
- **统计严谨**:多维度统计分析
|
||||
- **多维度分析**:支持挂单量、成交量等多种信号类型
|
||||
|
||||
### 📁 项目结构
|
||||
```
|
||||
large_orders/
|
||||
├── README.md # 本文档
|
||||
├── analyze_large_buy1_orders.py # 买1量单独分析
|
||||
├── analyze_large_orders.py # 基础综合分析
|
||||
├── analyze_large_orders_extended.py # 扩展分析脚本
|
||||
├── analyze_total_orders_extended.py # 买卖挂单合计分析
|
||||
├── analyze_current_volume_extended.py # 当前成交量分析
|
||||
├── analyze_current_volume_optimized.py # 信号抑制优化分析
|
||||
├── large_orders_comprehensive_analysis_*.png # 买1/卖1量综合分析图表
|
||||
├── large_buy1_relative_price_changes_*.png # 买1量分析图表
|
||||
├── large_sell1_relative_price_changes_*.png # 卖1量分析图表
|
||||
├── total_orders_comprehensive_analysis_*.png # 挂单合计分析图表
|
||||
├── total_buy_relative_price_changes_*.png # 买挂合计分析图表
|
||||
├── total_sell_relative_price_changes_*.png # 卖挂合计分析图表
|
||||
├── current_volume_comprehensive_analysis_*.png # 当前成交量分析图表
|
||||
├── current_volume_relative_price_changes_*.png # 成交量价格走势图表
|
||||
├── current_volume_optimized_comprehensive_analysis_*.png # 优化版分析图表
|
||||
└── current_volume_optimized_relative_price_changes_*.png # 优化版价格走势图表
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
### ⚠️ 使用须知
|
||||
|
||||
1. **数据依赖**:确保数据文件路径正确
|
||||
2. **内存管理**:长时间序列分析可能占用较多内存
|
||||
3. **图表显示**:需要支持中文的环境才能正确显示图表中的中文
|
||||
4. **统计局限性**:部分信号类型样本较少,统计结果的代表性有限
|
||||
5. **信号抑制**:优化版脚本使用20个数据点的抑制窗口,可根据需要调整
|
||||
|
||||
### 🔮 后续扩展方向
|
||||
|
||||
1. **样本扩充**:增加更多交易日的数据
|
||||
2. **阈值优化**:测试不同的大额订单阈值(如>50, >200, >300)
|
||||
3. **品种扩展**:应用到其他期货品种
|
||||
4. **因子组合**:结合其他技术指标进行综合分析
|
||||
5. **动态抑制窗口**:根据市场波动性调整信号抑制窗口大小
|
||||
6. **实时分析**:开发实时信号监测和分析系统
|
||||
|
||||
### 📊 版本更新记录
|
||||
|
||||
- **v1.0**:基础买1/卖1量分析(2025年11月2日)
|
||||
- **v2.0**:新增买卖挂单合计分析(阈值200)
|
||||
- **v3.0**:新增当前成交量分析(阈值150)
|
||||
- **v4.0**:信号抑制优化算法,显著提升分析质量
|
||||
|
||||
---
|
||||
|
||||
**项目创建时间**:2025年11月2日
|
||||
**最后更新**:2025年11月2日
|
||||
**数据来源**:au2512_20251013.parquet
|
||||
**分析工具**:Python + pandas + matplotlib
|
||||
**作者**:Claude Code Assistant
|
||||
337
large_orders/analyze_current_volume_extended.py
Normal file
@ -0,0 +1,337 @@
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib as mpl
|
||||
import os
|
||||
|
||||
# 设置中文字体
|
||||
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
|
||||
def analyze_current_volume_extended():
|
||||
"""分析当前成交量大于150的数据点后不同长度的成交价走势"""
|
||||
|
||||
print("正在读取数据文件...")
|
||||
# 读取数据(从上级目录的data文件夹)
|
||||
df = pd.read_parquet('../data/au2512_20251013.parquet')
|
||||
|
||||
print(f"数据总行数: {len(df)}")
|
||||
print(f"数据列名: {df.columns.tolist()}")
|
||||
|
||||
# 查找当前成交量列的实际名称
|
||||
current_volume_col = None
|
||||
|
||||
for col in df.columns:
|
||||
if '当前成交量' in str(col) or 'cur_volume' in str(col).lower() or '成交量' in str(col):
|
||||
if '累积' not in str(col): # 排除累积成交量
|
||||
current_volume_col = col
|
||||
break
|
||||
|
||||
if current_volume_col is None:
|
||||
print("未找到当前成交量列,尝试查找其他可能的成交量列...")
|
||||
# 如果没找到当前成交量,尝试其他可能的列名
|
||||
for col in df.columns:
|
||||
if '量' in str(col) and '累积' not in str(col) and '买' not in str(col) and '卖' not in str(col):
|
||||
current_volume_col = col
|
||||
print(f"使用可能的成交量列: {col}")
|
||||
break
|
||||
|
||||
if current_volume_col is None:
|
||||
print("未找到合适的成交量列")
|
||||
return
|
||||
|
||||
print(f"使用当前成交量列: {current_volume_col}")
|
||||
|
||||
# 获取成交价列名
|
||||
price_col = None
|
||||
for col in df.columns:
|
||||
if '成交价' in str(col) or 'price' in str(col).lower():
|
||||
price_col = col
|
||||
break
|
||||
|
||||
if price_col is None:
|
||||
print("未找到成交价列")
|
||||
return
|
||||
|
||||
print(f"使用成交价列: {price_col}")
|
||||
|
||||
# 显示当前成交量的统计信息
|
||||
print(f"\n当前成交量统计信息:")
|
||||
print(f"最小值: {df[current_volume_col].min()}")
|
||||
print(f"最大值: {df[current_volume_col].max()}")
|
||||
print(f"平均值: {df[current_volume_col].mean():.2f}")
|
||||
print(f"中位数: {df[current_volume_col].median():.2f}")
|
||||
|
||||
# 筛选当前成交量大于150的数据点
|
||||
large_volume_mask = df[current_volume_col] > 150
|
||||
large_volume_indices = df[large_volume_mask].index.tolist()
|
||||
|
||||
print(f"\n找到当前成交量大于150的数据点数量: {len(large_volume_indices)}")
|
||||
|
||||
if len(large_volume_indices) > 0:
|
||||
large_volumes = df.loc[large_volume_indices, current_volume_col]
|
||||
print(f"大成交量统计: 最小={large_volumes.min():.0f}, 最大={large_volumes.max():.0f}, 平均={large_volumes.mean():.0f}")
|
||||
|
||||
# 提取价格序列的函数
|
||||
def extract_price_sequences(indices, max_points):
|
||||
sequences = []
|
||||
sequence_info = []
|
||||
|
||||
for idx in indices:
|
||||
remaining_points = len(df) - idx - 1
|
||||
take_points = min(max_points, remaining_points)
|
||||
|
||||
if take_points > 0:
|
||||
base_price = df.loc[idx, price_col]
|
||||
future_prices = df.loc[idx + 1: idx + take_points, price_col].values
|
||||
price_changes = future_prices - base_price
|
||||
sequences.append(price_changes)
|
||||
|
||||
sequence_info.append({
|
||||
'start_index': idx,
|
||||
'volume': df.loc[idx, current_volume_col],
|
||||
'base_price': base_price,
|
||||
'sequence_length': take_points
|
||||
})
|
||||
|
||||
return sequences, sequence_info
|
||||
|
||||
# 分析不同时间长度的数据
|
||||
analysis_lengths = [100, 200, 500] # 100, 200, 500个数据点
|
||||
|
||||
for length in analysis_lengths:
|
||||
print(f"\n{'='*60}")
|
||||
print(f"分析当前成交量>150后{length}个数据点的价格走势")
|
||||
print(f"{'='*60}")
|
||||
|
||||
# 提取大成交量的价格序列
|
||||
volume_sequences, volume_info = extract_price_sequences(large_volume_indices, length)
|
||||
|
||||
print(f"成功提取 {len(volume_sequences)} 个大成交量价格序列 (最大长度: {length})")
|
||||
|
||||
# 创建综合分析图表
|
||||
fig, axes = plt.subplots(2, 2, figsize=(20, 16))
|
||||
fig.suptitle(f'当前成交量>150的价格走势分析 (后{length}个数据点)',
|
||||
fontsize=16, fontweight='bold')
|
||||
|
||||
# 1. 大成交量价格变化图(所有序列)
|
||||
ax1 = axes[0, 0]
|
||||
if volume_sequences:
|
||||
# 使用渐变色
|
||||
colors = plt.cm.viridis(np.linspace(0.3, 0.9, len(volume_sequences)))
|
||||
for i, (sequence, info) in enumerate(zip(volume_sequences, volume_info)):
|
||||
x_axis = range(len(sequence))
|
||||
ax1.plot(x_axis, sequence, color=colors[i], alpha=0.6, linewidth=0.8)
|
||||
|
||||
ax1.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax1.set_xlabel('数据点序号')
|
||||
ax1.set_ylabel('相对价格变化')
|
||||
ax1.set_title(f'当前成交量>150的价格变化走势 (后{length}点)\n共{len(volume_sequences)}个序列')
|
||||
ax1.grid(True, alpha=0.3)
|
||||
ax1.text(0.02, 0.98, f'序列数: {len(volume_sequences)}', transform=ax1.transAxes,
|
||||
verticalalignment='top', bbox=dict(boxstyle='round', facecolor='lightgreen', alpha=0.8))
|
||||
|
||||
# 2. 按成交量大小分组显示(前20% vs 后80%)
|
||||
ax2 = axes[0, 1]
|
||||
if len(volume_info) > 0:
|
||||
# 按成交量排序
|
||||
sorted_indices = sorted(range(len(volume_info)), key=lambda i: volume_info[i]['volume'], reverse=True)
|
||||
top_20_percent = max(1, len(sorted_indices) // 5) # 至少1个
|
||||
|
||||
top_sequences = [volume_sequences[i] for i in sorted_indices[:top_20_percent]]
|
||||
bottom_sequences = [volume_sequences[i] for i in sorted_indices[top_20_percent:]]
|
||||
|
||||
# 显示最大的20%成交量序列(红色)
|
||||
for i, sequence in enumerate(top_sequences):
|
||||
x_axis = range(len(sequence))
|
||||
ax2.plot(x_axis, sequence, color='red', alpha=0.7, linewidth=1.2,
|
||||
label='最大20%成交量' if i == 0 else "")
|
||||
|
||||
# 显示较小的80%成交量序列(蓝色)
|
||||
for i, sequence in enumerate(bottom_sequences):
|
||||
x_axis = range(len(sequence))
|
||||
ax2.plot(x_axis, sequence, color='blue', alpha=0.4, linewidth=0.6,
|
||||
label='其他80%成交量' if i == 0 else "")
|
||||
|
||||
ax2.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax2.set_xlabel('数据点序号')
|
||||
ax2.set_ylabel('相对价格变化')
|
||||
ax2.set_title(f'按成交量大小分组的价格走势 (后{length}点)\n红色:最大20%({len(top_sequences) if len(volume_info) > 0 else 0}个) 蓝色:其他80%({len(bottom_sequences) if len(volume_info) > 0 else 0}个)')
|
||||
ax2.grid(True, alpha=0.3)
|
||||
if len(volume_info) > 0:
|
||||
ax2.legend(fontsize=10)
|
||||
|
||||
# 3. 平均变化和置信区间
|
||||
ax3 = axes[1, 0]
|
||||
|
||||
def calculate_avg_changes_and_std(sequences):
|
||||
if not sequences:
|
||||
return [], []
|
||||
max_len = max(len(seq) for seq in sequences)
|
||||
avg_changes = []
|
||||
std_changes = []
|
||||
for i in range(max_len):
|
||||
point_changes = [seq[i] for seq in sequences if len(seq) > i]
|
||||
if point_changes:
|
||||
avg_changes.append(np.mean(point_changes))
|
||||
std_changes.append(np.std(point_changes))
|
||||
return avg_changes, std_changes
|
||||
|
||||
avg_changes, std_changes = calculate_avg_changes_and_std(volume_sequences)
|
||||
|
||||
if avg_changes:
|
||||
x_axis = range(len(avg_changes))
|
||||
ax3.plot(x_axis, avg_changes, color='green', linewidth=2.5, label=f'平均变化 (n={len(volume_sequences)})')
|
||||
|
||||
# 添加置信区间(±1个标准差)
|
||||
upper_bound = [avg + std for avg, std in zip(avg_changes, std_changes)]
|
||||
lower_bound = [avg - std for avg, std in zip(avg_changes, std_changes)]
|
||||
ax3.fill_between(x_axis, lower_bound, upper_bound, alpha=0.3, color='green', label='±1标准差区间')
|
||||
|
||||
ax3.axhline(y=0, color='black', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax3.set_xlabel('数据点序号')
|
||||
ax3.set_ylabel('平均相对价格变化')
|
||||
ax3.set_title(f'平均价格变化及置信区间 (后{length}点)')
|
||||
ax3.legend(fontsize=12)
|
||||
ax3.grid(True, alpha=0.3)
|
||||
|
||||
# 4. 统计信息文本框
|
||||
ax4 = axes[1, 1]
|
||||
ax4.axis('off')
|
||||
|
||||
# 计算统计信息
|
||||
def calculate_stats(sequences):
|
||||
if not sequences:
|
||||
return {}
|
||||
final_changes = [seq[-1] for seq in sequences if len(seq) > 0]
|
||||
if final_changes:
|
||||
return {
|
||||
'count': len(sequences),
|
||||
'avg_final_change': np.mean(final_changes),
|
||||
'std_final_change': np.std(final_changes),
|
||||
'max_rise': np.max(final_changes),
|
||||
'max_fall': np.min(final_changes),
|
||||
'positive_ratio': sum(1 for change in final_changes if change > 0) / len(final_changes),
|
||||
'avg_max_gain': np.mean([np.max(seq) for seq in sequences if len(seq) > 0]),
|
||||
'avg_max_loss': np.mean([np.min(seq) for seq in sequences if len(seq) > 0])
|
||||
}
|
||||
return {}
|
||||
|
||||
volume_stats = calculate_stats(volume_sequences)
|
||||
|
||||
# 显示统计信息
|
||||
stats_text = f"=== 当前成交量>150 统计信息 (后{length}点) ===\n\n"
|
||||
|
||||
if volume_stats:
|
||||
stats_text += f"序列数量: {volume_stats['count']}\n"
|
||||
stats_text += f"平均最终变化: {volume_stats['avg_final_change']:.4f}\n"
|
||||
stats_text += f"变化标准差: {volume_stats['std_final_change']:.4f}\n"
|
||||
stats_text += f"最大上涨: {volume_stats['max_rise']:.4f}\n"
|
||||
stats_text += f"最大下跌: {volume_stats['max_fall']:.4f}\n"
|
||||
stats_text += f"上涨比例: {volume_stats['positive_ratio']:.1%}\n"
|
||||
stats_text += f"平均最大获利: {volume_stats['avg_max_gain']:.4f}\n"
|
||||
stats_text += f"平均最大亏损: {volume_stats['avg_max_loss']:.4f}\n\n"
|
||||
|
||||
# 添加关键时间点分析
|
||||
if avg_changes:
|
||||
stats_text += f"=== 关键时间点分析 ===\n"
|
||||
if length >= 500:
|
||||
points_to_check = [9, 49, 199, 499] # 第10、50、200、500点
|
||||
point_names = ['第10点', '第50点', '第200点', '第500点']
|
||||
elif length >= 200:
|
||||
points_to_check = [9, 49, 199] # 第10、50、200点
|
||||
point_names = ['第10点', '第50点', '第200点']
|
||||
else:
|
||||
points_to_check = [9, 49] # 第10、50点
|
||||
point_names = ['第10点', '第50点']
|
||||
|
||||
for i, point in enumerate(points_to_check):
|
||||
if point < len(avg_changes):
|
||||
stats_text += f"{point_names[i]}: {avg_changes[point]:.4f}"
|
||||
if point < len(std_changes):
|
||||
stats_text += f" (±{std_changes[point]:.4f})"
|
||||
stats_text += "\n"
|
||||
|
||||
# 添加成交量信息
|
||||
if len(volume_info) > 0:
|
||||
volumes = [info['volume'] for info in volume_info]
|
||||
stats_text += f"\n=== 成交量信息 ===\n"
|
||||
stats_text += f"成交量范围: {min(volumes):.0f} - {max(volumes):.0f}\n"
|
||||
stats_text += f"平均成交量: {np.mean(volumes):.0f}\n"
|
||||
stats_text += f"成交量中位数: {np.median(volumes):.0f}"
|
||||
|
||||
ax4.text(0.05, 0.95, stats_text, transform=ax4.transAxes, fontsize=11,
|
||||
verticalalignment='top',
|
||||
bbox=dict(boxstyle='round', facecolor='lightgray', alpha=0.8))
|
||||
|
||||
plt.tight_layout()
|
||||
|
||||
# 保存综合图表
|
||||
output_file = f'current_volume_comprehensive_analysis_{length}points.png'
|
||||
plt.savefig(output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"\n{length}点综合分析图表已保存为: {output_file}")
|
||||
print(f"完整路径: {os.path.abspath(output_file)}")
|
||||
|
||||
# 保存单独的大成交量走势图
|
||||
fig_volume, ax_volume = plt.subplots(figsize=(15, 10))
|
||||
if volume_sequences:
|
||||
colors = plt.cm.viridis(np.linspace(0.3, 0.9, len(volume_sequences)))
|
||||
for i, (sequence, info) in enumerate(zip(volume_sequences, volume_info)):
|
||||
x_axis = range(len(sequence))
|
||||
ax_volume.plot(x_axis, sequence, color=colors[i], alpha=0.6, linewidth=1)
|
||||
|
||||
ax_volume.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax_volume.set_xlabel(f'数据点序号 (相对于大成交量时刻, 后{length}点)', fontsize=12)
|
||||
ax_volume.set_ylabel('相对价格变化 (相对于基准点)', fontsize=12)
|
||||
ax_volume.set_title(f'当前成交量>150的数据点后{length}个相对价格变化走势\n所有序列从基准点(0)开始\n共{len(volume_sequences)}个序列',
|
||||
fontsize=14, fontweight='bold')
|
||||
ax_volume.grid(True, alpha=0.3)
|
||||
plt.tight_layout()
|
||||
|
||||
volume_output_file = f'current_volume_relative_price_changes_{length}points.png'
|
||||
plt.savefig(volume_output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"大成交量{length}点分析图表已保存为: {volume_output_file}")
|
||||
plt.close()
|
||||
|
||||
# 显示统计信息
|
||||
print(f"\n{'='*50}")
|
||||
print(f"详细统计信息 (后{length}点):")
|
||||
print(f"{'='*50}")
|
||||
|
||||
if volume_stats:
|
||||
print(f"\n【当前成交量>150】")
|
||||
print(f"序列数量: {volume_stats['count']}")
|
||||
print(f"平均最终变化: {volume_stats['avg_final_change']:.4f}")
|
||||
print(f"变化标准差: {volume_stats['std_final_change']:.4f}")
|
||||
print(f"最大上涨: {volume_stats['max_rise']:.4f}")
|
||||
print(f"最大下跌: {volume_stats['max_fall']:.4f}")
|
||||
print(f"上涨比例: {volume_stats['positive_ratio']:.1%}")
|
||||
print(f"平均最大获利: {volume_stats['avg_max_gain']:.4f}")
|
||||
print(f"平均最大亏损: {volume_stats['avg_max_loss']:.4f}")
|
||||
|
||||
# 关键时间点分析
|
||||
if avg_changes:
|
||||
print(f"\n关键时间点分析:")
|
||||
if length >= 500:
|
||||
key_points = [(9, '第10点'), (49, '第50点'), (199, '第200点'), (499, '第500点')]
|
||||
elif length >= 200:
|
||||
key_points = [(9, '第10点'), (49, '第50点'), (199, '第200点')]
|
||||
else:
|
||||
key_points = [(9, '第10点'), (49, '第50点')]
|
||||
|
||||
for point, name in key_points:
|
||||
if point < len(avg_changes):
|
||||
print(f"{name}: {avg_changes[point]:.4f}", end="")
|
||||
if point < len(std_changes):
|
||||
print(f" (±{std_changes[point]:.4f})")
|
||||
else:
|
||||
print()
|
||||
|
||||
plt.close('all') # 关闭所有图形以释放内存
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print("所有分析完成!")
|
||||
print(f"{'='*60}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
analyze_current_volume_extended()
|
||||
391
large_orders/analyze_current_volume_optimized.py
Normal file
@ -0,0 +1,391 @@
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib as mpl
|
||||
import os
|
||||
|
||||
# 设置中文字体
|
||||
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
|
||||
def analyze_current_volume_optimized():
|
||||
"""分析当前成交量大于150的数据点后不同长度的成交价走势(优化版:信号抑制)"""
|
||||
|
||||
print("正在读取数据文件...")
|
||||
# 读取数据(从上级目录的data文件夹)
|
||||
df = pd.read_parquet('../data/au2512_20251013.parquet')
|
||||
|
||||
print(f"数据总行数: {len(df)}")
|
||||
print(f"数据列名: {df.columns.tolist()}")
|
||||
|
||||
# 查找当前成交量列的实际名称
|
||||
current_volume_col = None
|
||||
|
||||
for col in df.columns:
|
||||
if '当前成交量' in str(col) or 'cur_volume' in str(col).lower() or '成交量' in str(col):
|
||||
if '累积' not in str(col): # 排除累积成交量
|
||||
current_volume_col = col
|
||||
break
|
||||
|
||||
if current_volume_col is None:
|
||||
print("未找到当前成交量列,尝试查找其他可能的成交量列...")
|
||||
# 如果没找到当前成交量,尝试其他可能的列名
|
||||
for col in df.columns:
|
||||
if '量' in str(col) and '累积' not in str(col) and '买' not in str(col) and '卖' not in str(col):
|
||||
current_volume_col = col
|
||||
print(f"使用可能的成交量列: {col}")
|
||||
break
|
||||
|
||||
if current_volume_col is None:
|
||||
print("未找到合适的成交量列")
|
||||
return
|
||||
|
||||
print(f"使用当前成交量列: {current_volume_col}")
|
||||
|
||||
# 获取成交价列名
|
||||
price_col = None
|
||||
for col in df.columns:
|
||||
if '成交价' in str(col) or 'price' in str(col).lower():
|
||||
price_col = col
|
||||
break
|
||||
|
||||
if price_col is None:
|
||||
print("未找到成交价列")
|
||||
return
|
||||
|
||||
print(f"使用成交价列: {price_col}")
|
||||
|
||||
# 显示当前成交量的统计信息
|
||||
print(f"\n当前成交量统计信息:")
|
||||
print(f"最小值: {df[current_volume_col].min()}")
|
||||
print(f"最大值: {df[current_volume_col].max()}")
|
||||
print(f"平均值: {df[current_volume_col].mean():.2f}")
|
||||
print(f"中位数: {df[current_volume_col].median():.2f}")
|
||||
|
||||
# 筛选当前成交量大于150的数据点
|
||||
large_volume_mask = df[current_volume_col] > 150
|
||||
large_volume_indices = df[large_volume_mask].index.tolist()
|
||||
|
||||
print(f"\n找到当前成交量大于150的数据点数量: {len(large_volume_indices)}")
|
||||
|
||||
if len(large_volume_indices) > 0:
|
||||
large_volumes = df.loc[large_volume_indices, current_volume_col]
|
||||
print(f"大成交量统计: 最小={large_volumes.min():.0f}, 最大={large_volumes.max():.0f}, 平均={large_volumes.mean():.0f}")
|
||||
|
||||
# 信号抑制逻辑:移除20个数据点内的重复信号
|
||||
def apply_signal_suppression(indices, suppression_window=20):
|
||||
"""应用信号抑制逻辑,移除指定窗口内的重复信号"""
|
||||
if not indices:
|
||||
return []
|
||||
|
||||
# 按索引排序
|
||||
sorted_indices = sorted(indices)
|
||||
filtered_indices = []
|
||||
suppressed_count = 0
|
||||
|
||||
for i, idx in enumerate(sorted_indices):
|
||||
# 检查是否与前面的有效信号距离太近
|
||||
is_suppressed = False
|
||||
for prev_idx in filtered_indices:
|
||||
if idx - prev_idx <= suppression_window:
|
||||
is_suppressed = True
|
||||
suppressed_count += 1
|
||||
break
|
||||
|
||||
if not is_suppressed:
|
||||
filtered_indices.append(idx)
|
||||
|
||||
return filtered_indices, suppressed_count
|
||||
|
||||
# 应用信号抑制
|
||||
print("\n应用信号抑制逻辑(20个数据点窗口)...")
|
||||
filtered_indices, suppressed_count = apply_signal_suppression(large_volume_indices, 20)
|
||||
|
||||
print(f"原始信号数量: {len(large_volume_indices)}")
|
||||
print(f"抑制后信号数量: {len(filtered_indices)}")
|
||||
print(f"被抑制的信号数量: {suppressed_count}")
|
||||
print(f"抑制率: {suppressed_count/len(large_volume_indices)*100:.1f}%")
|
||||
|
||||
if len(filtered_indices) > 0:
|
||||
filtered_volumes = df.loc[filtered_indices, current_volume_col]
|
||||
print(f"过滤后大成交量统计: 最小={filtered_volumes.min():.0f}, 最大={filtered_volumes.max():.0f}, 平均={filtered_volumes.mean():.0f}")
|
||||
|
||||
# 提取价格序列的函数
|
||||
def extract_price_sequences(indices, max_points):
|
||||
sequences = []
|
||||
sequence_info = []
|
||||
|
||||
for idx in indices:
|
||||
remaining_points = len(df) - idx - 1
|
||||
take_points = min(max_points, remaining_points)
|
||||
|
||||
if take_points > 0:
|
||||
base_price = df.loc[idx, price_col]
|
||||
future_prices = df.loc[idx + 1: idx + take_points, price_col].values
|
||||
price_changes = future_prices - base_price
|
||||
sequences.append(price_changes)
|
||||
|
||||
sequence_info.append({
|
||||
'start_index': idx,
|
||||
'volume': df.loc[idx, current_volume_col],
|
||||
'base_price': base_price,
|
||||
'sequence_length': take_points
|
||||
})
|
||||
|
||||
return sequences, sequence_info
|
||||
|
||||
# 分析不同时间长度的数据
|
||||
analysis_lengths = [100, 200, 500] # 100, 200, 500个数据点
|
||||
|
||||
for length in analysis_lengths:
|
||||
print(f"\n{'='*60}")
|
||||
print(f"分析当前成交量>150后{length}个数据点的价格走势(优化版)")
|
||||
print(f"{'='*60}")
|
||||
|
||||
# 提取过滤后大成交量的价格序列
|
||||
volume_sequences, volume_info = extract_price_sequences(filtered_indices, length)
|
||||
|
||||
print(f"成功提取 {len(volume_sequences)} 个过滤后大成交量价格序列 (最大长度: {length})")
|
||||
|
||||
# 创建综合分析图表
|
||||
fig, axes = plt.subplots(2, 2, figsize=(20, 16))
|
||||
fig.suptitle(f'当前成交量>150的价格走势分析(优化版)(后{length}个数据点)\n原始信号:{len(large_volume_indices)}个 → 过滤后:{len(filtered_indices)}个 (抑制{suppressed_count}个)',
|
||||
fontsize=14, fontweight='bold')
|
||||
|
||||
# 1. 过滤后大成交量价格变化图(所有序列)
|
||||
ax1 = axes[0, 0]
|
||||
if volume_sequences:
|
||||
# 使用渐变色
|
||||
colors = plt.cm.viridis(np.linspace(0.3, 0.9, len(volume_sequences)))
|
||||
for i, (sequence, info) in enumerate(zip(volume_sequences, volume_info)):
|
||||
x_axis = range(len(sequence))
|
||||
ax1.plot(x_axis, sequence, color=colors[i], alpha=0.6, linewidth=0.8)
|
||||
|
||||
ax1.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax1.set_xlabel('数据点序号')
|
||||
ax1.set_ylabel('相对价格变化')
|
||||
ax1.set_title(f'过滤后价格变化走势 (后{length}点)\n共{len(volume_sequences)}个有效序列')
|
||||
ax1.grid(True, alpha=0.3)
|
||||
|
||||
# 添加信号抑制信息
|
||||
suppression_text = f'原始: {len(large_volume_indices)}个\n过滤: {len(filtered_indices)}个\n抑制: {suppressed_count}个'
|
||||
ax1.text(0.02, 0.98, suppression_text, transform=ax1.transAxes,
|
||||
verticalalignment='top', bbox=dict(boxstyle='round', facecolor='lightgreen', alpha=0.8))
|
||||
|
||||
# 2. 按成交量大小分组显示(前20% vs 后80%)
|
||||
ax2 = axes[0, 1]
|
||||
if len(volume_info) > 0:
|
||||
# 按成交量排序
|
||||
sorted_indices = sorted(range(len(volume_info)), key=lambda i: volume_info[i]['volume'], reverse=True)
|
||||
top_20_percent = max(1, len(sorted_indices) // 5) # 至少1个
|
||||
|
||||
top_sequences = [volume_sequences[i] for i in sorted_indices[:top_20_percent]]
|
||||
bottom_sequences = [volume_sequences[i] for i in sorted_indices[top_20_percent:]]
|
||||
|
||||
# 显示最大的20%成交量序列(红色)
|
||||
for i, sequence in enumerate(top_sequences):
|
||||
x_axis = range(len(sequence))
|
||||
ax2.plot(x_axis, sequence, color='red', alpha=0.7, linewidth=1.2,
|
||||
label='最大20%成交量' if i == 0 else "")
|
||||
|
||||
# 显示较小的80%成交量序列(蓝色)
|
||||
for i, sequence in enumerate(bottom_sequences):
|
||||
x_axis = range(len(sequence))
|
||||
ax2.plot(x_axis, sequence, color='blue', alpha=0.4, linewidth=0.6,
|
||||
label='其他80%成交量' if i == 0 else "")
|
||||
|
||||
ax2.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax2.set_xlabel('数据点序号')
|
||||
ax2.set_ylabel('相对价格变化')
|
||||
ax2.set_title(f'按成交量大小分组的价格走势 (后{length}点)\n红色:最大20%({len(top_sequences) if len(volume_info) > 0 else 0}个) 蓝色:其他80%({len(bottom_sequences) if len(volume_info) > 0 else 0}个)')
|
||||
ax2.grid(True, alpha=0.3)
|
||||
if len(volume_info) > 0:
|
||||
ax2.legend(fontsize=10)
|
||||
|
||||
# 3. 平均变化和置信区间
|
||||
ax3 = axes[1, 0]
|
||||
|
||||
def calculate_avg_changes_and_std(sequences):
|
||||
if not sequences:
|
||||
return [], []
|
||||
max_len = max(len(seq) for seq in sequences)
|
||||
avg_changes = []
|
||||
std_changes = []
|
||||
for i in range(max_len):
|
||||
point_changes = [seq[i] for seq in sequences if len(seq) > i]
|
||||
if point_changes:
|
||||
avg_changes.append(np.mean(point_changes))
|
||||
std_changes.append(np.std(point_changes))
|
||||
return avg_changes, std_changes
|
||||
|
||||
avg_changes, std_changes = calculate_avg_changes_and_std(volume_sequences)
|
||||
|
||||
if avg_changes:
|
||||
x_axis = range(len(avg_changes))
|
||||
ax3.plot(x_axis, avg_changes, color='green', linewidth=2.5, label=f'平均变化 (n={len(volume_sequences)})')
|
||||
|
||||
# 添加置信区间(±1个标准差)
|
||||
upper_bound = [avg + std for avg, std in zip(avg_changes, std_changes)]
|
||||
lower_bound = [avg - std for avg, std in zip(avg_changes, std_changes)]
|
||||
ax3.fill_between(x_axis, lower_bound, upper_bound, alpha=0.3, color='green', label='±1标准差区间')
|
||||
|
||||
ax3.axhline(y=0, color='black', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax3.set_xlabel('数据点序号')
|
||||
ax3.set_ylabel('平均相对价格变化')
|
||||
ax3.set_title(f'平均价格变化及置信区间 (后{length}点)')
|
||||
ax3.legend(fontsize=12)
|
||||
ax3.grid(True, alpha=0.3)
|
||||
|
||||
# 4. 统计信息文本框
|
||||
ax4 = axes[1, 1]
|
||||
ax4.axis('off')
|
||||
|
||||
# 计算统计信息
|
||||
def calculate_stats(sequences):
|
||||
if not sequences:
|
||||
return {}
|
||||
final_changes = [seq[-1] for seq in sequences if len(seq) > 0]
|
||||
if final_changes:
|
||||
return {
|
||||
'count': len(sequences),
|
||||
'avg_final_change': np.mean(final_changes),
|
||||
'std_final_change': np.std(final_changes),
|
||||
'max_rise': np.max(final_changes),
|
||||
'max_fall': np.min(final_changes),
|
||||
'positive_ratio': sum(1 for change in final_changes if change > 0) / len(final_changes),
|
||||
'avg_max_gain': np.mean([np.max(seq) for seq in sequences if len(seq) > 0]),
|
||||
'avg_max_loss': np.mean([np.min(seq) for seq in sequences if len(seq) > 0])
|
||||
}
|
||||
return {}
|
||||
|
||||
volume_stats = calculate_stats(volume_sequences)
|
||||
|
||||
# 显示统计信息
|
||||
stats_text = f"=== 当前成交量>150 统计信息 (后{length}点) ===\n"
|
||||
stats_text += f"信号抑制效果:\n"
|
||||
stats_text += f" 原始信号: {len(large_volume_indices)}个\n"
|
||||
stats_text += f" 过滤信号: {len(filtered_indices)}个\n"
|
||||
stats_text += f" 抑制数量: {suppressed_count}个\n"
|
||||
stats_text += f" 抑制率: {suppressed_count/len(large_volume_indices)*100:.1f}%\n\n"
|
||||
|
||||
if volume_stats:
|
||||
stats_text += f"价格统计:\n"
|
||||
stats_text += f" 序列数量: {volume_stats['count']}\n"
|
||||
stats_text += f" 平均最终变化: {volume_stats['avg_final_change']:.4f}\n"
|
||||
stats_text += f" 变化标准差: {volume_stats['std_final_change']:.4f}\n"
|
||||
stats_text += f" 最大上涨: {volume_stats['max_rise']:.4f}\n"
|
||||
stats_text += f" 最大下跌: {volume_stats['max_fall']:.4f}\n"
|
||||
stats_text += f" 上涨比例: {volume_stats['positive_ratio']:.1%}\n"
|
||||
stats_text += f" 平均最大获利: {volume_stats['avg_max_gain']:.4f}\n"
|
||||
stats_text += f" 平均最大亏损: {volume_stats['avg_max_loss']:.4f}\n\n"
|
||||
|
||||
# 添加关键时间点分析
|
||||
if avg_changes:
|
||||
stats_text += f"=== 关键时间点分析 ===\n"
|
||||
if length >= 500:
|
||||
points_to_check = [9, 49, 199, 499] # 第10、50、200、500点
|
||||
point_names = ['第10点', '第50点', '第200点', '第500点']
|
||||
elif length >= 200:
|
||||
points_to_check = [9, 49, 199] # 第10、50、200点
|
||||
point_names = ['第10点', '第50点', '第200点']
|
||||
else:
|
||||
points_to_check = [9, 49] # 第10、50点
|
||||
point_names = ['第10点', '第50点']
|
||||
|
||||
for i, point in enumerate(points_to_check):
|
||||
if point < len(avg_changes):
|
||||
stats_text += f" {point_names[i]}: {avg_changes[point]:.4f}"
|
||||
if point < len(std_changes):
|
||||
stats_text += f" (±{std_changes[point]:.4f})"
|
||||
stats_text += "\n"
|
||||
|
||||
# 添加成交量信息
|
||||
if len(volume_info) > 0:
|
||||
volumes = [info['volume'] for info in volume_info]
|
||||
stats_text += f"\n=== 成交量信息 ===\n"
|
||||
stats_text += f" 成交量范围: {min(volumes):.0f} - {max(volumes):.0f}\n"
|
||||
stats_text += f" 平均成交量: {np.mean(volumes):.0f}\n"
|
||||
stats_text += f" 成交量中位数: {np.median(volumes):.0f}"
|
||||
|
||||
ax4.text(0.05, 0.95, stats_text, transform=ax4.transAxes, fontsize=10,
|
||||
verticalalignment='top',
|
||||
bbox=dict(boxstyle='round', facecolor='lightgray', alpha=0.8))
|
||||
|
||||
plt.tight_layout()
|
||||
|
||||
# 保存综合图表
|
||||
output_file = f'current_volume_optimized_comprehensive_analysis_{length}points.png'
|
||||
plt.savefig(output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"\n{length}点优化版综合分析图表已保存为: {output_file}")
|
||||
print(f"完整路径: {os.path.abspath(output_file)}")
|
||||
|
||||
# 保存单独的过滤后大成交量走势图
|
||||
fig_volume, ax_volume = plt.subplots(figsize=(15, 10))
|
||||
if volume_sequences:
|
||||
colors = plt.cm.viridis(np.linspace(0.3, 0.9, len(volume_sequences)))
|
||||
for i, (sequence, info) in enumerate(zip(volume_sequences, volume_info)):
|
||||
x_axis = range(len(sequence))
|
||||
ax_volume.plot(x_axis, sequence, color=colors[i], alpha=0.6, linewidth=1)
|
||||
|
||||
ax_volume.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax_volume.set_xlabel(f'数据点序号 (相对于过滤后大成交量时刻, 后{length}点)', fontsize=12)
|
||||
ax_volume.set_ylabel('相对价格变化 (相对于基准点)', fontsize=12)
|
||||
ax_volume.set_title(f'当前成交量>150过滤后数据点{length}个相对价格变化走势\n信号抑制: {len(large_volume_indices)}→{len(filtered_indices)} (抑制{suppressed_count}个)\n共{len(volume_sequences)}个有效序列',
|
||||
fontsize=14, fontweight='bold')
|
||||
ax_volume.grid(True, alpha=0.3)
|
||||
plt.tight_layout()
|
||||
|
||||
volume_output_file = f'current_volume_optimized_relative_price_changes_{length}points.png'
|
||||
plt.savefig(volume_output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"过滤后大成交量{length}点分析图表已保存为: {volume_output_file}")
|
||||
plt.close()
|
||||
|
||||
# 显示统计信息
|
||||
print(f"\n{'='*50}")
|
||||
print(f"详细统计信息 (后{length}点) - 优化版:")
|
||||
print(f"{'='*50}")
|
||||
|
||||
print(f"\n【信号抑制效果】")
|
||||
print(f"原始信号数量: {len(large_volume_indices)}")
|
||||
print(f"过滤后信号数量: {len(filtered_indices)}")
|
||||
print(f"被抑制信号数量: {suppressed_count}")
|
||||
print(f"信号抑制率: {suppressed_count/len(large_volume_indices)*100:.1f}%")
|
||||
|
||||
if volume_stats:
|
||||
print(f"\n【过滤后价格统计】")
|
||||
print(f"序列数量: {volume_stats['count']}")
|
||||
print(f"平均最终变化: {volume_stats['avg_final_change']:.4f}")
|
||||
print(f"变化标准差: {volume_stats['std_final_change']:.4f}")
|
||||
print(f"最大上涨: {volume_stats['max_rise']:.4f}")
|
||||
print(f"最大下跌: {volume_stats['max_fall']:.4f}")
|
||||
print(f"上涨比例: {volume_stats['positive_ratio']:.1%}")
|
||||
print(f"平均最大获利: {volume_stats['avg_max_gain']:.4f}")
|
||||
print(f"平均最大亏损: {volume_stats['avg_max_loss']:.4f}")
|
||||
|
||||
# 关键时间点分析
|
||||
if avg_changes:
|
||||
print(f"\n关键时间点分析:")
|
||||
if length >= 500:
|
||||
key_points = [(9, '第10点'), (49, '第50点'), (199, '第200点'), (499, '第500点')]
|
||||
elif length >= 200:
|
||||
key_points = [(9, '第10点'), (49, '第50点'), (199, '第200点')]
|
||||
else:
|
||||
key_points = [(9, '第10点'), (49, '第50点')]
|
||||
|
||||
for point, name in key_points:
|
||||
if point < len(avg_changes):
|
||||
print(f"{name}: {avg_changes[point]:.4f}", end="")
|
||||
if point < len(std_changes):
|
||||
print(f" (±{std_changes[point]:.4f})")
|
||||
else:
|
||||
print()
|
||||
|
||||
plt.close('all') # 关闭所有图形以释放内存
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print("优化版分析完成!")
|
||||
print("信号抑制逻辑已成功应用,减少了重复信号的影响。")
|
||||
print(f"{'='*60}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
analyze_current_volume_optimized()
|
||||
333
large_orders/analyze_large_orders_extended.py
Normal file
@ -0,0 +1,333 @@
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib as mpl
|
||||
import os
|
||||
|
||||
# 设置中文字体
|
||||
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
|
||||
def analyze_large_orders_extended():
|
||||
"""分析买1量和卖1量大于99的数据点后不同长度的成交价走势"""
|
||||
|
||||
print("正在读取数据文件...")
|
||||
# 读取数据(从上级目录的data文件夹)
|
||||
df = pd.read_parquet('../data/au2512_20251013.parquet')
|
||||
|
||||
print(f"数据总行数: {len(df)}")
|
||||
print(f"数据列名: {df.columns.tolist()}")
|
||||
|
||||
# 查找买1量和卖1量列的实际名称
|
||||
buy1_vol_col = None
|
||||
sell1_vol_col = None
|
||||
|
||||
for col in df.columns:
|
||||
if '买1量' in str(col) or 'buy1' in str(col).lower():
|
||||
buy1_vol_col = col
|
||||
if '卖1量' in str(col) or 'sell1' in str(col).lower():
|
||||
sell1_vol_col = col
|
||||
|
||||
if buy1_vol_col is None:
|
||||
print("未找到买1量列")
|
||||
return
|
||||
if sell1_vol_col is None:
|
||||
print("未找到卖1量列")
|
||||
return
|
||||
|
||||
print(f"使用买1量列: {buy1_vol_col}")
|
||||
print(f"使用卖1量列: {sell1_vol_col}")
|
||||
|
||||
# 获取成交价列名
|
||||
price_col = None
|
||||
for col in df.columns:
|
||||
if '成交价' in str(col) or 'price' in str(col).lower():
|
||||
price_col = col
|
||||
break
|
||||
|
||||
if price_col is None:
|
||||
print("未找到成交价列")
|
||||
return
|
||||
|
||||
print(f"使用成交价列: {price_col}")
|
||||
|
||||
# 筛选大额买1和卖1订单
|
||||
large_buy1_mask = df[buy1_vol_col] > 99
|
||||
large_sell1_mask = df[sell1_vol_col] > 99
|
||||
|
||||
large_buy1_indices = df[large_buy1_mask].index.tolist()
|
||||
large_sell1_indices = df[large_sell1_mask].index.tolist()
|
||||
|
||||
print(f"找到买1量大于99的数据点数量: {len(large_buy1_indices)}")
|
||||
print(f"找到卖1量大于99的数据点数量: {len(large_sell1_indices)}")
|
||||
|
||||
# 提取价格序列的函数
|
||||
def extract_price_sequences(indices, order_type, max_points):
|
||||
sequences = []
|
||||
sequence_info = []
|
||||
|
||||
for idx in indices:
|
||||
remaining_points = len(df) - idx - 1
|
||||
take_points = min(max_points, remaining_points)
|
||||
|
||||
if take_points > 0:
|
||||
base_price = df.loc[idx, price_col]
|
||||
future_prices = df.loc[idx + 1: idx + take_points, price_col].values
|
||||
price_changes = future_prices - base_price
|
||||
sequences.append(price_changes)
|
||||
|
||||
volume_col = buy1_vol_col if order_type == 'buy' else sell1_vol_col
|
||||
sequence_info.append({
|
||||
'start_index': idx,
|
||||
'volume': df.loc[idx, volume_col],
|
||||
'base_price': base_price,
|
||||
'sequence_length': take_points
|
||||
})
|
||||
|
||||
return sequences, sequence_info
|
||||
|
||||
# 分析不同时间长度的数据
|
||||
analysis_lengths = [100, 200, 500] # 100, 200, 500个数据点
|
||||
|
||||
for length in analysis_lengths:
|
||||
print(f"\n{'='*60}")
|
||||
print(f"分析后{length}个数据点的价格走势")
|
||||
print(f"{'='*60}")
|
||||
|
||||
# 提取买1和卖1的价格序列
|
||||
buy1_sequences, buy1_info = extract_price_sequences(large_buy1_indices, 'buy', length)
|
||||
sell1_sequences, sell1_info = extract_price_sequences(large_sell1_indices, 'sell', length)
|
||||
|
||||
print(f"成功提取 {len(buy1_sequences)} 个买1价格序列 (最大长度: {length})")
|
||||
print(f"成功提取 {len(sell1_sequences)} 个卖1价格序列 (最大长度: {length})")
|
||||
|
||||
# 创建综合对比图表
|
||||
fig, axes = plt.subplots(2, 2, figsize=(20, 16))
|
||||
fig.suptitle(f'大额订单对比分析:买1量>99 vs 卖1量>99 (后{length}个数据点)',
|
||||
fontsize=16, fontweight='bold')
|
||||
|
||||
# 1. 买1量价格变化图
|
||||
ax1 = axes[0, 0]
|
||||
if buy1_sequences:
|
||||
colors_buy = plt.cm.Blues(np.linspace(0.3, 0.9, len(buy1_sequences)))
|
||||
for i, (sequence, info) in enumerate(zip(buy1_sequences, buy1_info)):
|
||||
x_axis = range(len(sequence))
|
||||
ax1.plot(x_axis, sequence, color=colors_buy[i], alpha=0.6, linewidth=0.8)
|
||||
|
||||
ax1.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax1.set_xlabel('数据点序号')
|
||||
ax1.set_ylabel('相对价格变化')
|
||||
ax1.set_title(f'买1量>99的价格变化走势 (后{length}点)\n共{len(buy1_sequences)}个序列')
|
||||
ax1.grid(True, alpha=0.3)
|
||||
ax1.text(0.02, 0.98, f'序列数: {len(buy1_sequences)}', transform=ax1.transAxes,
|
||||
verticalalignment='top', bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.8))
|
||||
|
||||
# 2. 卖1量价格变化图
|
||||
ax2 = axes[0, 1]
|
||||
if sell1_sequences:
|
||||
colors_sell = plt.cm.Reds(np.linspace(0.3, 0.9, len(sell1_sequences)))
|
||||
for i, (sequence, info) in enumerate(zip(sell1_sequences, sell1_info)):
|
||||
x_axis = range(len(sequence))
|
||||
ax2.plot(x_axis, sequence, color=colors_sell[i], alpha=0.6, linewidth=0.8)
|
||||
|
||||
ax2.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax2.set_xlabel('数据点序号')
|
||||
ax2.set_ylabel('相对价格变化')
|
||||
ax2.set_title(f'卖1量>99的价格变化走势 (后{length}点)\n共{len(sell1_sequences)}个序列')
|
||||
ax2.grid(True, alpha=0.3)
|
||||
ax2.text(0.02, 0.98, f'序列数: {len(sell1_sequences)}', transform=ax2.transAxes,
|
||||
verticalalignment='top', bbox=dict(boxstyle='round', facecolor='lightcoral', alpha=0.8))
|
||||
|
||||
# 3. 平均变化对比图
|
||||
ax3 = axes[1, 0]
|
||||
|
||||
def calculate_avg_changes(sequences):
|
||||
if not sequences:
|
||||
return []
|
||||
max_len = max(len(seq) for seq in sequences)
|
||||
avg_changes = []
|
||||
for i in range(max_len):
|
||||
point_changes = [seq[i] for seq in sequences if len(seq) > i]
|
||||
if point_changes:
|
||||
avg_changes.append(np.mean(point_changes))
|
||||
return avg_changes
|
||||
|
||||
buy1_avg_changes = calculate_avg_changes(buy1_sequences)
|
||||
sell1_avg_changes = calculate_avg_changes(sell1_sequences)
|
||||
|
||||
if buy1_avg_changes:
|
||||
ax3.plot(range(len(buy1_avg_changes)), buy1_avg_changes,
|
||||
color='blue', linewidth=2.5, label=f'买1量>99 (n={len(buy1_sequences)})')
|
||||
if sell1_avg_changes:
|
||||
ax3.plot(range(len(sell1_avg_changes)), sell1_avg_changes,
|
||||
color='red', linewidth=2.5, label=f'卖1量>99 (n={len(sell1_sequences)})')
|
||||
|
||||
ax3.axhline(y=0, color='black', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax3.set_xlabel('数据点序号')
|
||||
ax3.set_ylabel('平均相对价格变化')
|
||||
ax3.set_title(f'平均价格变化对比 (后{length}点)')
|
||||
ax3.legend(fontsize=12)
|
||||
ax3.grid(True, alpha=0.3)
|
||||
|
||||
# 4. 统计信息文本框
|
||||
ax4 = axes[1, 1]
|
||||
ax4.axis('off')
|
||||
|
||||
# 计算统计信息
|
||||
def calculate_stats(sequences, name):
|
||||
if not sequences:
|
||||
return {}
|
||||
final_changes = [seq[-1] for seq in sequences if len(seq) > 0]
|
||||
if final_changes:
|
||||
return {
|
||||
'name': name,
|
||||
'count': len(sequences),
|
||||
'avg_final_change': np.mean(final_changes),
|
||||
'std_final_change': np.std(final_changes),
|
||||
'max_rise': np.max(final_changes),
|
||||
'max_fall': np.min(final_changes)
|
||||
}
|
||||
return {}
|
||||
|
||||
buy1_stats = calculate_stats(buy1_sequences, '买1量>99')
|
||||
sell1_stats = calculate_stats(sell1_sequences, '卖1量>99')
|
||||
|
||||
# 显示统计信息
|
||||
stats_text = f"=== 统计信息对比 (后{length}点) ===\n\n"
|
||||
|
||||
if buy1_stats:
|
||||
stats_text += f"【买1量>99】\n"
|
||||
stats_text += f"序列数量: {buy1_stats['count']}\n"
|
||||
stats_text += f"平均最终变化: {buy1_stats['avg_final_change']:.4f}\n"
|
||||
stats_text += f"变化标准差: {buy1_stats['std_final_change']:.4f}\n"
|
||||
stats_text += f"最大上涨: {buy1_stats['max_rise']:.4f}\n"
|
||||
stats_text += f"最大下跌: {buy1_stats['max_fall']:.4f}\n\n"
|
||||
|
||||
if sell1_stats:
|
||||
stats_text += f"【卖1量>99】\n"
|
||||
stats_text += f"序列数量: {sell1_stats['count']}\n"
|
||||
stats_text += f"平均最终变化: {sell1_stats['avg_final_change']:.4f}\n"
|
||||
stats_text += f"变化标准差: {sell1_stats['std_final_change']:.4f}\n"
|
||||
stats_text += f"最大上涨: {sell1_stats['max_rise']:.4f}\n"
|
||||
stats_text += f"最大下跌: {sell1_stats['max_fall']:.4f}\n\n"
|
||||
|
||||
# 添加关键时间点对比
|
||||
if buy1_avg_changes and sell1_avg_changes:
|
||||
stats_text += f"=== 关键时间点对比 (后{length}点) ===\n"
|
||||
# 根据数据长度选择关键点
|
||||
if length >= 500:
|
||||
points_to_check = [49, 199, 499] # 第50、200、500点
|
||||
point_names = ['第50点', '第200点', '第500点']
|
||||
elif length >= 200:
|
||||
points_to_check = [49, 199] # 第50、200点
|
||||
point_names = ['第50点', '第200点']
|
||||
else:
|
||||
points_to_check = [49] # 第50点
|
||||
point_names = ['第50点']
|
||||
|
||||
for i, point in enumerate(points_to_check):
|
||||
if point < len(buy1_avg_changes) and point < len(sell1_avg_changes):
|
||||
stats_text += f"{point_names[i]}: "
|
||||
stats_text += f"买1={buy1_avg_changes[point]:.4f}, "
|
||||
stats_text += f"卖1={sell1_avg_changes[point]:.4f}, "
|
||||
stats_text += f"差值={buy1_avg_changes[point] - sell1_avg_changes[point]:.4f}\n"
|
||||
|
||||
ax4.text(0.05, 0.95, stats_text, transform=ax4.transAxes, fontsize=11,
|
||||
verticalalignment='top',
|
||||
bbox=dict(boxstyle='round', facecolor='lightgray', alpha=0.8))
|
||||
|
||||
plt.tight_layout()
|
||||
|
||||
# 保存综合图表
|
||||
output_file = f'large_orders_comprehensive_analysis_{length}points.png'
|
||||
plt.savefig(output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"\n{length}点综合分析图表已保存为: {output_file}")
|
||||
print(f"完整路径: {os.path.abspath(output_file)}")
|
||||
|
||||
# 保存单独的买1和卖1图表
|
||||
# 买1量单独图表
|
||||
fig_buy, ax_buy = plt.subplots(figsize=(15, 10))
|
||||
if buy1_sequences:
|
||||
colors_buy = plt.cm.Blues(np.linspace(0.3, 0.9, len(buy1_sequences)))
|
||||
for i, (sequence, info) in enumerate(zip(buy1_sequences, buy1_info)):
|
||||
x_axis = range(len(sequence))
|
||||
ax_buy.plot(x_axis, sequence, color=colors_buy[i], alpha=0.6, linewidth=1)
|
||||
|
||||
ax_buy.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax_buy.set_xlabel(f'数据点序号 (相对于大额买1订单, 后{length}点)', fontsize=12)
|
||||
ax_buy.set_ylabel('相对价格变化 (相对于基准点)', fontsize=12)
|
||||
ax_buy.set_title(f'买1量>99的数据点后{length}个相对价格变化走势\n所有序列从基准点(0)开始\n共{len(buy1_sequences)}个序列',
|
||||
fontsize=14, fontweight='bold')
|
||||
ax_buy.grid(True, alpha=0.3)
|
||||
plt.tight_layout()
|
||||
|
||||
buy_output_file = f'large_buy1_relative_price_changes_{length}points.png'
|
||||
plt.savefig(buy_output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"买1量{length}点分析图表已保存为: {buy_output_file}")
|
||||
plt.close()
|
||||
|
||||
# 卖1量单独图表
|
||||
fig_sell, ax_sell = plt.subplots(figsize=(15, 10))
|
||||
if sell1_sequences:
|
||||
colors_sell = plt.cm.Reds(np.linspace(0.3, 0.9, len(sell1_sequences)))
|
||||
for i, (sequence, info) in enumerate(zip(sell1_sequences, sell1_info)):
|
||||
x_axis = range(len(sequence))
|
||||
ax_sell.plot(x_axis, sequence, color=colors_sell[i], alpha=0.6, linewidth=1)
|
||||
|
||||
ax_sell.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax_sell.set_xlabel(f'数据点序号 (相对于大额卖1订单, 后{length}点)', fontsize=12)
|
||||
ax_sell.set_ylabel('相对价格变化 (相对于基准点)', fontsize=12)
|
||||
ax_sell.set_title(f'卖1量>99的数据点后{length}个相对价格变化走势\n所有序列从基准点(0)开始\n共{len(sell1_sequences)}个序列',
|
||||
fontsize=14, fontweight='bold')
|
||||
ax_sell.grid(True, alpha=0.3)
|
||||
plt.tight_layout()
|
||||
|
||||
sell_output_file = f'large_sell1_relative_price_changes_{length}points.png'
|
||||
plt.savefig(sell_output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"卖1量{length}点分析图表已保存为: {sell_output_file}")
|
||||
plt.close()
|
||||
|
||||
# 显示统计信息
|
||||
print(f"\n{'='*50}")
|
||||
print(f"详细统计信息 (后{length}点):")
|
||||
print(f"{'='*50}")
|
||||
|
||||
if buy1_stats:
|
||||
print(f"\n【买1量>99】")
|
||||
print(f"序列数量: {buy1_stats['count']}")
|
||||
print(f"平均最终变化: {buy1_stats['avg_final_change']:.4f}")
|
||||
print(f"变化标准差: {buy1_stats['std_final_change']:.4f}")
|
||||
print(f"最大上涨: {buy1_stats['max_rise']:.4f}")
|
||||
print(f"最大下跌: {buy1_stats['max_fall']:.4f}")
|
||||
|
||||
if sell1_stats:
|
||||
print(f"\n【卖1量>99】")
|
||||
print(f"序列数量: {sell1_stats['count']}")
|
||||
print(f"平均最终变化: {sell1_stats['avg_final_change']:.4f}")
|
||||
print(f"变化标准差: {sell1_stats['std_final_change']:.4f}")
|
||||
print(f"最大上涨: {sell1_stats['max_rise']:.4f}")
|
||||
print(f"最大下跌: {sell1_stats['max_fall']:.4f}")
|
||||
|
||||
# 关键时间点分析
|
||||
if buy1_avg_changes and sell1_avg_changes:
|
||||
print(f"\n关键时间点对比:")
|
||||
if length >= 500:
|
||||
key_points = [(49, '第50点'), (199, '第200点'), (499, '第500点')]
|
||||
elif length >= 200:
|
||||
key_points = [(49, '第50点'), (199, '第200点')]
|
||||
else:
|
||||
key_points = [(49, '第50点')]
|
||||
|
||||
for point, name in key_points:
|
||||
if point < len(buy1_avg_changes) and point < len(sell1_avg_changes):
|
||||
diff = buy1_avg_changes[point] - sell1_avg_changes[point]
|
||||
print(f"{name}: 买1={buy1_avg_changes[point]:.4f}, 卖1={sell1_avg_changes[point]:.4f}, 差值={diff:.4f}")
|
||||
|
||||
plt.close('all') # 关闭所有图形以释放内存
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print("所有分析完成!")
|
||||
print(f"{'='*60}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
analyze_large_orders_extended()
|
||||
347
large_orders/analyze_total_orders_extended.py
Normal file
@ -0,0 +1,347 @@
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib as mpl
|
||||
import os
|
||||
|
||||
# 设置中文字体
|
||||
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
|
||||
def analyze_total_orders_extended():
|
||||
"""分析买挂合计和卖挂合计大于200的数据点后不同长度的成交价走势"""
|
||||
|
||||
print("正在读取数据文件...")
|
||||
# 读取数据(从上级目录的data文件夹)
|
||||
df = pd.read_parquet('../data/au2512_20251013.parquet')
|
||||
|
||||
print(f"数据总行数: {len(df)}")
|
||||
print(f"数据列名: {df.columns.tolist()}")
|
||||
|
||||
# 查找买1-5量和卖1-5量列的实际名称
|
||||
buy_vol_cols = []
|
||||
sell_vol_cols = []
|
||||
|
||||
for col in df.columns:
|
||||
if '买' in str(col) and '量' in str(col):
|
||||
buy_vol_cols.append(col)
|
||||
if '卖' in str(col) and '量' in str(col):
|
||||
sell_vol_cols.append(col)
|
||||
|
||||
print(f"找到买量列: {buy_vol_cols}")
|
||||
print(f"找到卖量列: {sell_vol_cols}")
|
||||
|
||||
if len(buy_vol_cols) < 5:
|
||||
print("警告: 未找到完整的买1-5量列")
|
||||
return
|
||||
if len(sell_vol_cols) < 5:
|
||||
print("警告: 未找到完整的卖1-5量列")
|
||||
return
|
||||
|
||||
# 获取成交价列名
|
||||
price_col = None
|
||||
for col in df.columns:
|
||||
if '成交价' in str(col) or 'price' in str(col).lower():
|
||||
price_col = col
|
||||
break
|
||||
|
||||
if price_col is None:
|
||||
print("未找到成交价列")
|
||||
return
|
||||
|
||||
print(f"使用成交价列: {price_col}")
|
||||
|
||||
# 计算买挂合计和卖挂合计
|
||||
print("正在计算买挂合计和卖挂合计...")
|
||||
df['买挂合计'] = df[buy_vol_cols].sum(axis=1)
|
||||
df['卖挂合计'] = df[sell_vol_cols].sum(axis=1)
|
||||
|
||||
# 筛选大额买挂和卖挂订单
|
||||
large_buy_mask = df['买挂合计'] > 200
|
||||
large_sell_mask = df['卖挂合计'] > 200
|
||||
|
||||
large_buy_indices = df[large_buy_mask].index.tolist()
|
||||
large_sell_indices = df[large_sell_mask].index.tolist()
|
||||
|
||||
print(f"找到买挂合计大于200的数据点数量: {len(large_buy_indices)}")
|
||||
print(f"找到卖挂合计大于200的数据点数量: {len(large_sell_indices)}")
|
||||
|
||||
# 显示一些统计信息
|
||||
if len(large_buy_indices) > 0:
|
||||
buy_total_volumes = df.loc[large_buy_indices, '买挂合计']
|
||||
print(f"买挂合计统计: 最小={buy_total_volumes.min():.0f}, 最大={buy_total_volumes.max():.0f}, 平均={buy_total_volumes.mean():.0f}")
|
||||
|
||||
if len(large_sell_indices) > 0:
|
||||
sell_total_volumes = df.loc[large_sell_indices, '卖挂合计']
|
||||
print(f"卖挂合计统计: 最小={sell_total_volumes.min():.0f}, 最大={sell_total_volumes.max():.0f}, 平均={sell_total_volumes.mean():.0f}")
|
||||
|
||||
# 提取价格序列的函数
|
||||
def extract_price_sequences(indices, order_type, max_points):
|
||||
sequences = []
|
||||
sequence_info = []
|
||||
|
||||
for idx in indices:
|
||||
remaining_points = len(df) - idx - 1
|
||||
take_points = min(max_points, remaining_points)
|
||||
|
||||
if take_points > 0:
|
||||
base_price = df.loc[idx, price_col]
|
||||
future_prices = df.loc[idx + 1: idx + take_points, price_col].values
|
||||
price_changes = future_prices - base_price
|
||||
sequences.append(price_changes)
|
||||
|
||||
volume_col = '买挂合计' if order_type == 'buy' else '卖挂合计'
|
||||
sequence_info.append({
|
||||
'start_index': idx,
|
||||
'volume': df.loc[idx, volume_col],
|
||||
'base_price': base_price,
|
||||
'sequence_length': take_points
|
||||
})
|
||||
|
||||
return sequences, sequence_info
|
||||
|
||||
# 分析不同时间长度的数据
|
||||
analysis_lengths = [100, 200, 500] # 100, 200, 500个数据点
|
||||
|
||||
for length in analysis_lengths:
|
||||
print(f"\n{'='*60}")
|
||||
print(f"分析后{length}个数据点的价格走势")
|
||||
print(f"{'='*60}")
|
||||
|
||||
# 提取买挂和卖挂的价格序列
|
||||
buy_sequences, buy_info = extract_price_sequences(large_buy_indices, 'buy', length)
|
||||
sell_sequences, sell_info = extract_price_sequences(large_sell_indices, 'sell', length)
|
||||
|
||||
print(f"成功提取 {len(buy_sequences)} 个买挂价格序列 (最大长度: {length})")
|
||||
print(f"成功提取 {len(sell_sequences)} 个卖挂价格序列 (最大长度: {length})")
|
||||
|
||||
# 创建综合对比图表
|
||||
fig, axes = plt.subplots(2, 2, figsize=(20, 16))
|
||||
fig.suptitle(f'大额订单对比分析:买挂合计>200 vs 卖挂合计>200 (后{length}个数据点)',
|
||||
fontsize=16, fontweight='bold')
|
||||
|
||||
# 1. 买挂价格变化图
|
||||
ax1 = axes[0, 0]
|
||||
if buy_sequences:
|
||||
colors_buy = plt.cm.Blues(np.linspace(0.3, 0.9, len(buy_sequences)))
|
||||
for i, (sequence, info) in enumerate(zip(buy_sequences, buy_info)):
|
||||
x_axis = range(len(sequence))
|
||||
ax1.plot(x_axis, sequence, color=colors_buy[i], alpha=0.6, linewidth=0.8)
|
||||
|
||||
ax1.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax1.set_xlabel('数据点序号')
|
||||
ax1.set_ylabel('相对价格变化')
|
||||
ax1.set_title(f'买挂合计>200的价格变化走势 (后{length}点)\n共{len(buy_sequences)}个序列')
|
||||
ax1.grid(True, alpha=0.3)
|
||||
ax1.text(0.02, 0.98, f'序列数: {len(buy_sequences)}', transform=ax1.transAxes,
|
||||
verticalalignment='top', bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.8))
|
||||
|
||||
# 2. 卖挂价格变化图
|
||||
ax2 = axes[0, 1]
|
||||
if sell_sequences:
|
||||
colors_sell = plt.cm.Reds(np.linspace(0.3, 0.9, len(sell_sequences)))
|
||||
for i, (sequence, info) in enumerate(zip(sell_sequences, sell_info)):
|
||||
x_axis = range(len(sequence))
|
||||
ax2.plot(x_axis, sequence, color=colors_sell[i], alpha=0.6, linewidth=0.8)
|
||||
|
||||
ax2.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax2.set_xlabel('数据点序号')
|
||||
ax2.set_ylabel('相对价格变化')
|
||||
ax2.set_title(f'卖挂合计>200的价格变化走势 (后{length}点)\n共{len(sell_sequences)}个序列')
|
||||
ax2.grid(True, alpha=0.3)
|
||||
ax2.text(0.02, 0.98, f'序列数: {len(sell_sequences)}', transform=ax2.transAxes,
|
||||
verticalalignment='top', bbox=dict(boxstyle='round', facecolor='lightcoral', alpha=0.8))
|
||||
|
||||
# 3. 平均变化对比图
|
||||
ax3 = axes[1, 0]
|
||||
|
||||
def calculate_avg_changes(sequences):
|
||||
if not sequences:
|
||||
return []
|
||||
max_len = max(len(seq) for seq in sequences)
|
||||
avg_changes = []
|
||||
for i in range(max_len):
|
||||
point_changes = [seq[i] for seq in sequences if len(seq) > i]
|
||||
if point_changes:
|
||||
avg_changes.append(np.mean(point_changes))
|
||||
return avg_changes
|
||||
|
||||
buy_avg_changes = calculate_avg_changes(buy_sequences)
|
||||
sell_avg_changes = calculate_avg_changes(sell_sequences)
|
||||
|
||||
if buy_avg_changes:
|
||||
ax3.plot(range(len(buy_avg_changes)), buy_avg_changes,
|
||||
color='blue', linewidth=2.5, label=f'买挂合计>200 (n={len(buy_sequences)})')
|
||||
if sell_avg_changes:
|
||||
ax3.plot(range(len(sell_avg_changes)), sell_avg_changes,
|
||||
color='red', linewidth=2.5, label=f'卖挂合计>200 (n={len(sell_sequences)})')
|
||||
|
||||
ax3.axhline(y=0, color='black', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax3.set_xlabel('数据点序号')
|
||||
ax3.set_ylabel('平均相对价格变化')
|
||||
ax3.set_title(f'平均价格变化对比 (后{length}点)')
|
||||
ax3.legend(fontsize=12)
|
||||
ax3.grid(True, alpha=0.3)
|
||||
|
||||
# 4. 统计信息文本框
|
||||
ax4 = axes[1, 1]
|
||||
ax4.axis('off')
|
||||
|
||||
# 计算统计信息
|
||||
def calculate_stats(sequences, name):
|
||||
if not sequences:
|
||||
return {}
|
||||
final_changes = [seq[-1] for seq in sequences if len(seq) > 0]
|
||||
if final_changes:
|
||||
return {
|
||||
'name': name,
|
||||
'count': len(sequences),
|
||||
'avg_final_change': np.mean(final_changes),
|
||||
'std_final_change': np.std(final_changes),
|
||||
'max_rise': np.max(final_changes),
|
||||
'max_fall': np.min(final_changes)
|
||||
}
|
||||
return {}
|
||||
|
||||
buy_stats = calculate_stats(buy_sequences, '买挂合计>200')
|
||||
sell_stats = calculate_stats(sell_sequences, '卖挂合计>200')
|
||||
|
||||
# 显示统计信息
|
||||
stats_text = f"=== 统计信息对比 (后{length}点) ===\n\n"
|
||||
|
||||
if buy_stats:
|
||||
stats_text += f"【买挂合计>200】\n"
|
||||
stats_text += f"序列数量: {buy_stats['count']}\n"
|
||||
stats_text += f"平均最终变化: {buy_stats['avg_final_change']:.4f}\n"
|
||||
stats_text += f"变化标准差: {buy_stats['std_final_change']:.4f}\n"
|
||||
stats_text += f"最大上涨: {buy_stats['max_rise']:.4f}\n"
|
||||
stats_text += f"最大下跌: {buy_stats['max_fall']:.4f}\n\n"
|
||||
|
||||
if sell_stats:
|
||||
stats_text += f"【卖挂合计>200】\n"
|
||||
stats_text += f"序列数量: {sell_stats['count']}\n"
|
||||
stats_text += f"平均最终变化: {sell_stats['avg_final_change']:.4f}\n"
|
||||
stats_text += f"变化标准差: {sell_stats['std_final_change']:.4f}\n"
|
||||
stats_text += f"最大上涨: {sell_stats['max_rise']:.4f}\n"
|
||||
stats_text += f"最大下跌: {sell_stats['max_fall']:.4f}\n\n"
|
||||
|
||||
# 添加关键时间点对比
|
||||
if buy_avg_changes and sell_avg_changes:
|
||||
stats_text += f"=== 关键时间点对比 (后{length}点) ===\n"
|
||||
# 根据数据长度选择关键点
|
||||
if length >= 500:
|
||||
points_to_check = [49, 199, 499] # 第50、200、500点
|
||||
point_names = ['第50点', '第200点', '第500点']
|
||||
elif length >= 200:
|
||||
points_to_check = [49, 199] # 第50、200点
|
||||
point_names = ['第50点', '第200点']
|
||||
else:
|
||||
points_to_check = [49] # 第50点
|
||||
point_names = ['第50点']
|
||||
|
||||
for i, point in enumerate(points_to_check):
|
||||
if point < len(buy_avg_changes) and point < len(sell_avg_changes):
|
||||
stats_text += f"{point_names[i]}: "
|
||||
stats_text += f"买挂={buy_avg_changes[point]:.4f}, "
|
||||
stats_text += f"卖挂={sell_avg_changes[point]:.4f}, "
|
||||
stats_text += f"差值={buy_avg_changes[point] - sell_avg_changes[point]:.4f}\n"
|
||||
|
||||
ax4.text(0.05, 0.95, stats_text, transform=ax4.transAxes, fontsize=11,
|
||||
verticalalignment='top',
|
||||
bbox=dict(boxstyle='round', facecolor='lightgray', alpha=0.8))
|
||||
|
||||
plt.tight_layout()
|
||||
|
||||
# 保存综合图表
|
||||
output_file = f'total_orders_comprehensive_analysis_{length}points.png'
|
||||
plt.savefig(output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"\n{length}点综合分析图表已保存为: {output_file}")
|
||||
print(f"完整路径: {os.path.abspath(output_file)}")
|
||||
|
||||
# 保存单独的买挂和卖挂图表
|
||||
# 买挂单独图表
|
||||
fig_buy, ax_buy = plt.subplots(figsize=(15, 10))
|
||||
if buy_sequences:
|
||||
colors_buy = plt.cm.Blues(np.linspace(0.3, 0.9, len(buy_sequences)))
|
||||
for i, (sequence, info) in enumerate(zip(buy_sequences, buy_info)):
|
||||
x_axis = range(len(sequence))
|
||||
ax_buy.plot(x_axis, sequence, color=colors_buy[i], alpha=0.6, linewidth=1)
|
||||
|
||||
ax_buy.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax_buy.set_xlabel(f'数据点序号 (相对于大额买挂订单, 后{length}点)', fontsize=12)
|
||||
ax_buy.set_ylabel('相对价格变化 (相对于基准点)', fontsize=12)
|
||||
ax_buy.set_title(f'买挂合计>200的数据点后{length}个相对价格变化走势\n所有序列从基准点(0)开始\n共{len(buy_sequences)}个序列',
|
||||
fontsize=14, fontweight='bold')
|
||||
ax_buy.grid(True, alpha=0.3)
|
||||
plt.tight_layout()
|
||||
|
||||
buy_output_file = f'total_buy_relative_price_changes_{length}points.png'
|
||||
plt.savefig(buy_output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"买挂{length}点分析图表已保存为: {buy_output_file}")
|
||||
plt.close()
|
||||
|
||||
# 卖挂单独图表
|
||||
fig_sell, ax_sell = plt.subplots(figsize=(15, 10))
|
||||
if sell_sequences:
|
||||
colors_sell = plt.cm.Reds(np.linspace(0.3, 0.9, len(sell_sequences)))
|
||||
for i, (sequence, info) in enumerate(zip(sell_sequences, sell_info)):
|
||||
x_axis = range(len(sequence))
|
||||
ax_sell.plot(x_axis, sequence, color=colors_sell[i], alpha=0.6, linewidth=1)
|
||||
|
||||
ax_sell.axhline(y=0, color='red', linestyle='--', alpha=0.7, linewidth=1.5)
|
||||
ax_sell.set_xlabel(f'数据点序号 (相对于大额卖挂订单, 后{length}点)', fontsize=12)
|
||||
ax_sell.set_ylabel('相对价格变化 (相对于基准点)', fontsize=12)
|
||||
ax_sell.set_title(f'卖挂合计>200的数据点后{length}个相对价格变化走势\n所有序列从基准点(0)开始\n共{len(sell_sequences)}个序列',
|
||||
fontsize=14, fontweight='bold')
|
||||
ax_sell.grid(True, alpha=0.3)
|
||||
plt.tight_layout()
|
||||
|
||||
sell_output_file = f'total_sell_relative_price_changes_{length}points.png'
|
||||
plt.savefig(sell_output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"卖挂{length}点分析图表已保存为: {sell_output_file}")
|
||||
plt.close()
|
||||
|
||||
# 显示统计信息
|
||||
print(f"\n{'='*50}")
|
||||
print(f"详细统计信息 (后{length}点):")
|
||||
print(f"{'='*50}")
|
||||
|
||||
if buy_stats:
|
||||
print(f"\n【买挂合计>200】")
|
||||
print(f"序列数量: {buy_stats['count']}")
|
||||
print(f"平均最终变化: {buy_stats['avg_final_change']:.4f}")
|
||||
print(f"变化标准差: {buy_stats['std_final_change']:.4f}")
|
||||
print(f"最大上涨: {buy_stats['max_rise']:.4f}")
|
||||
print(f"最大下跌: {buy_stats['max_fall']:.4f}")
|
||||
|
||||
if sell_stats:
|
||||
print(f"\n【卖挂合计>200】")
|
||||
print(f"序列数量: {sell_stats['count']}")
|
||||
print(f"平均最终变化: {sell_stats['avg_final_change']:.4f}")
|
||||
print(f"变化标准差: {sell_stats['std_final_change']:.4f}")
|
||||
print(f"最大上涨: {sell_stats['max_rise']:.4f}")
|
||||
print(f"最大下跌: {sell_stats['max_fall']:.4f}")
|
||||
|
||||
# 关键时间点分析
|
||||
if buy_avg_changes and sell_avg_changes:
|
||||
print(f"\n关键时间点对比:")
|
||||
if length >= 500:
|
||||
key_points = [(49, '第50点'), (199, '第200点'), (499, '第500点')]
|
||||
elif length >= 200:
|
||||
key_points = [(49, '第50点'), (199, '第200点')]
|
||||
else:
|
||||
key_points = [(49, '第50点')]
|
||||
|
||||
for point, name in key_points:
|
||||
if point < len(buy_avg_changes) and point < len(sell_avg_changes):
|
||||
diff = buy_avg_changes[point] - sell_avg_changes[point]
|
||||
print(f"{name}: 买挂={buy_avg_changes[point]:.4f}, 卖挂={sell_avg_changes[point]:.4f}, 差值={diff:.4f}")
|
||||
|
||||
plt.close('all') # 关闭所有图形以释放内存
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print("所有分析完成!")
|
||||
print(f"{'='*60}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
analyze_total_orders_extended()
|
||||
BIN
large_orders/current_volume_comprehensive_analysis_100points.png
Normal file
|
After Width: | Height: | Size: 5.4 MiB |
BIN
large_orders/current_volume_comprehensive_analysis_200points.png
Normal file
|
After Width: | Height: | Size: 6.5 MiB |
BIN
large_orders/current_volume_comprehensive_analysis_500points.png
Normal file
|
After Width: | Height: | Size: 6.6 MiB |
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 4.6 MiB |
|
After Width: | Height: | Size: 5.0 MiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 3.7 MiB |
BIN
large_orders/current_volume_relative_price_changes_100points.png
Normal file
|
After Width: | Height: | Size: 4.0 MiB |
BIN
large_orders/current_volume_relative_price_changes_200points.png
Normal file
|
After Width: | Height: | Size: 5.1 MiB |
BIN
large_orders/current_volume_relative_price_changes_500points.png
Normal file
|
After Width: | Height: | Size: 5.2 MiB |
BIN
large_orders/large_buy1_relative_price_changes.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
large_orders/large_buy1_relative_price_changes_100points.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
large_orders/large_buy1_relative_price_changes_200points.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
large_orders/large_buy1_relative_price_changes_500points.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
large_orders/large_orders_comprehensive_analysis.png
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
BIN
large_orders/large_orders_comprehensive_analysis_100points.png
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
BIN
large_orders/large_orders_comprehensive_analysis_200points.png
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
BIN
large_orders/large_orders_comprehensive_analysis_500points.png
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
BIN
large_orders/large_sell1_relative_price_changes.png
Normal file
|
After Width: | Height: | Size: 821 KiB |
BIN
large_orders/large_sell1_relative_price_changes_100points.png
Normal file
|
After Width: | Height: | Size: 824 KiB |
BIN
large_orders/large_sell1_relative_price_changes_200points.png
Normal file
|
After Width: | Height: | Size: 770 KiB |
BIN
large_orders/large_sell1_relative_price_changes_500points.png
Normal file
|
After Width: | Height: | Size: 825 KiB |
BIN
large_orders/total_buy_relative_price_changes_100points.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
large_orders/total_buy_relative_price_changes_200points.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
large_orders/total_buy_relative_price_changes_500points.png
Normal file
|
After Width: | Height: | Size: 628 KiB |
BIN
large_orders/total_orders_comprehensive_analysis_100points.png
Normal file
|
After Width: | Height: | Size: 2.8 MiB |
BIN
large_orders/total_orders_comprehensive_analysis_200points.png
Normal file
|
After Width: | Height: | Size: 2.5 MiB |
BIN
large_orders/total_orders_comprehensive_analysis_500points.png
Normal file
|
After Width: | Height: | Size: 2.7 MiB |
BIN
large_orders/total_sell_relative_price_changes_100points.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
large_orders/total_sell_relative_price_changes_200points.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
large_orders/total_sell_relative_price_changes_500points.png
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
109
requirements.txt
Normal file
@ -0,0 +1,109 @@
|
||||
# AU2512期货成交量-成交价序列分析工具 - 依赖包列表
|
||||
|
||||
## 环境信息
|
||||
- **Python版本**: 3.7+
|
||||
- **更新日期**: 2025-11-02
|
||||
- **工具类型**: 期货数据可视化分析
|
||||
|
||||
## 核心依赖包
|
||||
|
||||
### 数据处理和数值计算
|
||||
```
|
||||
pandas>=1.3.0
|
||||
numpy>=1.20.0
|
||||
```
|
||||
|
||||
### 数据可视化
|
||||
```
|
||||
matplotlib>=3.3.0
|
||||
```
|
||||
|
||||
## 快速安装
|
||||
|
||||
### 方法1: 直接安装核心依赖
|
||||
```bash
|
||||
pip install pandas numpy matplotlib
|
||||
```
|
||||
|
||||
### 方法2: 使用requirements.txt文件
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### 方法3: 使用国内镜像源(推荐)
|
||||
```bash
|
||||
pip install pandas numpy matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
```
|
||||
|
||||
## 验证安装
|
||||
|
||||
创建简单的验证脚本:
|
||||
```python
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
print("✅ 核心依赖包验证通过")
|
||||
print(f"pandas: {pd.__version__}")
|
||||
print(f"numpy: {np.__version__}")
|
||||
print(f"matplotlib: {plt.__version__}")
|
||||
```
|
||||
|
||||
运行验证:
|
||||
```bash
|
||||
python -c "import pandas as pd, numpy as np, matplotlib.pyplot as plt; print('✅ 依赖包验证通过')"
|
||||
```
|
||||
|
||||
## 项目说明
|
||||
|
||||
### 技术栈精简
|
||||
- **pandas**: 数据处理和分析
|
||||
- **numpy**: 数值计算基础
|
||||
- **matplotlib**: 静态数据可视化
|
||||
|
||||
### 功能专注
|
||||
本项目专注于成交量-成交价序列分析,相比复杂的多功能工具,具有以下优势:
|
||||
- ✅ 安装简单,依赖最少
|
||||
- ✅ 专注核心功能,易于维护
|
||||
- ✅ 运行快速,资源占用少
|
||||
- ✅ 学习成本低,易于使用
|
||||
|
||||
### 可选依赖(非必需)
|
||||
如果需要额外功能,可以选择性安装:
|
||||
```bash
|
||||
# 支持更多数据格式
|
||||
pip install pyarrow openpyxl
|
||||
|
||||
# 增强统计分析
|
||||
pip install scipy
|
||||
|
||||
# 交互式可视化
|
||||
pip install seaborn plotly
|
||||
```
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
1. **中文字体问题**: 确保系统安装了中文字体(如Microsoft YaHei、SimHei等)
|
||||
2. **编码问题**: 在Windows上建议使用UTF-8编码环境
|
||||
3. **权限问题**: 使用适当的权限安装包
|
||||
|
||||
### 国内用户推荐
|
||||
使用国内镜像源提高下载速度:
|
||||
```bash
|
||||
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
```
|
||||
|
||||
## 版本兼容性
|
||||
|
||||
| Python版本 | pandas | numpy | matplotlib |
|
||||
|------------|---------|--------|------------|
|
||||
| 3.7+ | >=1.3.0 | >=1.20.0 | >=3.3.0 |
|
||||
| 3.8+ | >=1.4.0 | >=1.21.0 | >=3.4.0 |
|
||||
| 3.9+ | >=1.5.0 | >=1.22.0 | >=3.5.0 |
|
||||
| 3.10+ | >=1.6.0 | >=1.23.0 | >=3.6.0 |
|
||||
| 3.11+ | >=2.0.0 | >=1.24.0 | >=3.7.0 |
|
||||
|
||||
---
|
||||
|
||||
**注意**: 本项目采用最小依赖原则,只包含核心功能所需的基础包,确保工具的简洁性和可靠性。
|
||||
586
volume_distribution_analysis.py
Normal file
@ -0,0 +1,586 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
AU2512期货当前成交量分布分析工具
|
||||
|
||||
这个脚本专门用于分析期货交易中当前成交量的分布特征,
|
||||
提供深入的成交量模式分析和可视化展示。
|
||||
|
||||
使用方法:
|
||||
python volume_distribution_analysis.py [data_file]
|
||||
|
||||
如果不指定文件,默认分析 data/au2512_20251013.parquet
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.gridspec import GridSpec
|
||||
import seaborn as sns
|
||||
from datetime import datetime
|
||||
import warnings
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from scipy import stats
|
||||
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
class VolumeDistributionAnalyzer:
|
||||
"""当前成交量分布分析器"""
|
||||
|
||||
def __init__(self, data_file=None):
|
||||
"""
|
||||
初始化分析器
|
||||
|
||||
Args:
|
||||
data_file (str): 数据文件路径,默认为 data/au2512_20251013.parquet
|
||||
"""
|
||||
self.data_file = data_file or "data/au2512_20251013.parquet"
|
||||
self.df = None
|
||||
self.current_volume = None
|
||||
self.setup_chinese_font()
|
||||
|
||||
def setup_chinese_font(self):
|
||||
"""设置中文字体支持"""
|
||||
try:
|
||||
# 直接使用已知可用的中文字体
|
||||
chinese_fonts = ['Microsoft YaHei', 'SimHei', 'SimSun', 'KaiTi', 'FangSong', 'DengXian']
|
||||
|
||||
for font in chinese_fonts:
|
||||
try:
|
||||
plt.rcParams['font.sans-serif'] = [font]
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
plt.rcParams['font.size'] = 10
|
||||
plt.rcParams['axes.titlesize'] = 12
|
||||
plt.rcParams['axes.labelsize'] = 10
|
||||
plt.rcParams['xtick.labelsize'] = 9
|
||||
plt.rcParams['ytick.labelsize'] = 9
|
||||
|
||||
# 简单测试字体
|
||||
fig, ax = plt.subplots(figsize=(1, 1))
|
||||
ax.text(0.5, 0.5, '测试', fontsize=12)
|
||||
plt.close(fig)
|
||||
print(f"[*] 成功设置中文字体: {font}")
|
||||
return
|
||||
except:
|
||||
continue
|
||||
|
||||
# 如果都失败,使用默认设置
|
||||
print("[!] 无法设置中文字体,使用默认字体")
|
||||
plt.rcParams['font.sans-serif'] = ['DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
plt.rcParams['font.size'] = 10
|
||||
|
||||
except Exception as e:
|
||||
print(f"[!] 字体设置警告: {e}")
|
||||
plt.rcParams['font.sans-serif'] = ['DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
plt.rcParams['font.size'] = 10
|
||||
|
||||
def load_data(self):
|
||||
"""加载数据"""
|
||||
try:
|
||||
if not os.path.exists(self.data_file):
|
||||
raise FileNotFoundError(f"数据文件不存在: {self.data_file}")
|
||||
|
||||
print(f"正在加载数据: {self.data_file}")
|
||||
|
||||
# 根据文件扩展名选择读取方式
|
||||
if self.data_file.endswith('.parquet'):
|
||||
self.df = pd.read_parquet(self.data_file)
|
||||
elif self.data_file.endswith('.csv'):
|
||||
self.df = pd.read_csv(self.data_file)
|
||||
else:
|
||||
raise ValueError("不支持的文件格式,请使用 .parquet 或 .csv 文件")
|
||||
|
||||
print(f"数据加载成功: {len(self.df):,} 条记录")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"数据加载失败: {e}")
|
||||
return False
|
||||
|
||||
def prepare_volume_data(self):
|
||||
"""准备当前成交量数据"""
|
||||
print("\n=== 准备成交量数据 ===")
|
||||
|
||||
# 确保有当前成交量列
|
||||
if '当前成交量' not in self.df.columns:
|
||||
cumulative_col = None
|
||||
for col in self.df.columns:
|
||||
if '累计' in col and '成交量' in col:
|
||||
cumulative_col = col
|
||||
break
|
||||
|
||||
if cumulative_col is None:
|
||||
raise ValueError("无法找到累计成交量列")
|
||||
|
||||
print(f"使用累计成交量列: {cumulative_col}")
|
||||
self.df['当前成交量'] = self.df[cumulative_col].diff().fillna(0)
|
||||
self.df.loc[self.df.index[0], '当前成交量'] = self.df.loc[self.df.index[0], cumulative_col]
|
||||
|
||||
# 提取当前成交量数据
|
||||
self.current_volume = self.df['当前成交量'].copy()
|
||||
|
||||
# 移除零值和异常值(超过99.9%分位数的值)
|
||||
q99_9 = self.current_volume.quantile(0.999)
|
||||
self.current_volume_clean = self.current_volume[
|
||||
(self.current_volume > 0) & (self.current_volume <= q99_9)
|
||||
]
|
||||
|
||||
print(f"原始成交量数据点: {len(self.current_volume):,}")
|
||||
print(f"有效成交量数据点: {len(self.current_volume_clean):,}")
|
||||
print(f"移除零值和异常值后: {len(self.current_volume_clean):,} 个")
|
||||
|
||||
return True
|
||||
|
||||
def calculate_basic_statistics(self):
|
||||
"""计算基础统计信息"""
|
||||
print("\n=== 基础统计分析 ===")
|
||||
|
||||
self.stats = {
|
||||
'total_ticks': len(self.current_volume),
|
||||
'valid_ticks': len(self.current_volume_clean),
|
||||
'zero_volume_ticks': sum(self.current_volume == 0),
|
||||
'mean_volume': self.current_volume_clean.mean(),
|
||||
'median_volume': self.current_volume_clean.median(),
|
||||
'std_volume': self.current_volume_clean.std(),
|
||||
'min_volume': self.current_volume_clean.min(),
|
||||
'max_volume': self.current_volume_clean.max(),
|
||||
'q25': self.current_volume_clean.quantile(0.25),
|
||||
'q75': self.current_volume_clean.quantile(0.75),
|
||||
'q90': self.current_volume_clean.quantile(0.90),
|
||||
'q95': self.current_volume_clean.quantile(0.95),
|
||||
'q99': self.current_volume_clean.quantile(0.99)
|
||||
}
|
||||
|
||||
print(f"总Tick数: {self.stats['total_ticks']:,}")
|
||||
print(f"有效成交量Tick数: {self.stats['valid_ticks']:,}")
|
||||
print(f"零成交量Tick数: {self.stats['zero_volume_ticks']:,}")
|
||||
print(f"平均成交量: {self.stats['mean_volume']:.2f} 手")
|
||||
print(f"中位数成交量: {self.stats['median_volume']:.2f} 手")
|
||||
print(f"成交量标准差: {self.stats['std_volume']:.2f} 手")
|
||||
print(f"最小成交量: {self.stats['min_volume']:.2f} 手")
|
||||
print(f"最大成交量: {self.stats['max_volume']:.2f} 手")
|
||||
print(f"25%分位数: {self.stats['q25']:.2f} 手")
|
||||
print(f"75%分位数: {self.stats['q75']:.2f} 手")
|
||||
print(f"90%分位数: {self.stats['q90']:.2f} 手")
|
||||
print(f"95%分位数: {self.stats['q95']:.2f} 手")
|
||||
print(f"99%分位数: {self.stats['q99']:.2f} 手")
|
||||
|
||||
# 计算变异系数
|
||||
cv = self.stats['std_volume'] / self.stats['mean_volume']
|
||||
print(f"变异系数 (CV): {cv:.3f}")
|
||||
|
||||
# 检查分布偏度
|
||||
skewness = stats.skew(self.current_volume_clean)
|
||||
print(f"分布偏度: {skewness:.3f}")
|
||||
|
||||
self.stats['cv'] = cv
|
||||
self.stats['skewness'] = skewness
|
||||
|
||||
def analyze_volume_patterns(self):
|
||||
"""分析成交量模式"""
|
||||
print("\n=== 成交量模式分析 ===")
|
||||
|
||||
# 分析大单交易
|
||||
large_threshold = self.stats['q90']
|
||||
large_trades = self.current_volume_clean[self.current_volume_clean > large_threshold]
|
||||
|
||||
print(f"大单交易定义: > {large_threshold:.1f} 手 (90%分位数)")
|
||||
print(f"大单交易次数: {len(large_trades):,}")
|
||||
print(f"大单交易占比: {len(large_trades)/len(self.current_volume_clean)*100:.2f}%")
|
||||
print(f"大单成交量总和: {large_trades.sum():,} 手")
|
||||
print(f"大单成交量占比: {large_trades.sum()/self.current_volume_clean.sum()*100:.2f}%")
|
||||
|
||||
# 分析成交量聚集模式
|
||||
volume_groups = pd.cut(self.current_volume_clean,
|
||||
bins=[0, 1, 5, 10, 20, 50, 100, float('inf')],
|
||||
labels=['1手', '2-5手', '6-10手', '11-20手', '21-50手', '51-100手', '100+手'])
|
||||
|
||||
print(f"\n成交量分组统计:")
|
||||
for group_name, group_data in self.current_volume_clean.groupby(volume_groups):
|
||||
if not pd.isna(group_name):
|
||||
count = len(group_data)
|
||||
percentage = count / len(self.current_volume_clean) * 100
|
||||
volume_sum = group_data.sum()
|
||||
volume_percentage = volume_sum / self.current_volume_clean.sum() * 100
|
||||
print(f" {group_name:>6}: {count:>6,} 次 ({percentage:>5.1f}%) | "
|
||||
f"成交量: {volume_sum:>8,.0f} 手 ({volume_percentage:>5.1f}%)")
|
||||
|
||||
# 存储模式分析结果
|
||||
self.pattern_analysis = {
|
||||
'large_threshold': large_threshold,
|
||||
'large_trades_count': len(large_trades),
|
||||
'large_trades_percentage': len(large_trades)/len(self.current_volume_clean)*100,
|
||||
'large_volume_sum': large_trades.sum(),
|
||||
'large_volume_percentage': large_trades.sum()/self.current_volume_clean.sum()*100,
|
||||
'volume_groups': volume_groups,
|
||||
'group_stats': {}
|
||||
}
|
||||
|
||||
for group_name, group_data in self.current_volume_clean.groupby(volume_groups):
|
||||
if not pd.isna(group_name):
|
||||
self.pattern_analysis['group_stats'][group_name] = {
|
||||
'count': len(group_data),
|
||||
'percentage': len(group_data)/len(self.current_volume_clean)*100,
|
||||
'volume_sum': group_data.sum(),
|
||||
'volume_percentage': group_data.sum()/self.current_volume_clean.sum()*100
|
||||
}
|
||||
|
||||
def create_distribution_charts(self):
|
||||
"""创建分布图表"""
|
||||
print("\n=== 生成成交量分布图表 ===")
|
||||
|
||||
# 确保字体设置正确
|
||||
plt.rcParams['font.sans-serif'] = plt.rcParams['font.sans-serif']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
|
||||
# 创建复合图表布局
|
||||
fig = plt.figure(figsize=(20, 16))
|
||||
gs = GridSpec(3, 3, figure=fig, hspace=0.3, wspace=0.3)
|
||||
|
||||
# 1. 直方图 + 概率密度图
|
||||
ax1 = fig.add_subplot(gs[0, 0])
|
||||
n, bins, patches = ax1.hist(self.current_volume_clean, bins=50,
|
||||
alpha=0.7, color='skyblue', density=True,
|
||||
edgecolor='black', linewidth=0.5)
|
||||
|
||||
# 拟合正态分布
|
||||
mu, sigma = self.stats['mean_volume'], self.stats['std_volume']
|
||||
x = np.linspace(self.current_volume_clean.min(), self.current_volume_clean.max(), 100)
|
||||
ax1.plot(x, stats.norm.pdf(x, mu, sigma), 'r-', linewidth=2,
|
||||
label=f'正态分布拟合\n(μ={mu:.1f}, σ={sigma:.1f})')
|
||||
|
||||
ax1.set_title('当前成交量分布直方图', fontsize=14, fontweight='bold')
|
||||
ax1.set_xlabel('成交量 (手)', fontsize=12)
|
||||
ax1.set_ylabel('概率密度', fontsize=12)
|
||||
ax1.legend(fontsize=10)
|
||||
ax1.grid(True, alpha=0.3)
|
||||
|
||||
# 2. 箱线图
|
||||
ax2 = fig.add_subplot(gs[0, 1])
|
||||
boxplot_data = [self.current_volume_clean[self.current_volume_clean <= q]
|
||||
for q in [self.stats['q90'], self.stats['q95'], self.stats['q99']]]
|
||||
boxplot_labels = ['90%分位数内', '95%分位数内', '99%分位数内']
|
||||
|
||||
bp = ax2.boxplot(boxplot_data, labels=boxplot_labels, patch_artist=True)
|
||||
for patch in bp['boxes']:
|
||||
patch.set_facecolor('lightgreen')
|
||||
patch.set_alpha(0.7)
|
||||
|
||||
ax2.set_title('当前成交量箱线图', fontsize=14, fontweight='bold')
|
||||
ax2.set_ylabel('成交量 (手)', fontsize=12)
|
||||
ax2.grid(True, alpha=0.3)
|
||||
|
||||
# 3. 累积分布函数
|
||||
ax3 = fig.add_subplot(gs[0, 2])
|
||||
sorted_data = np.sort(self.current_volume_clean)
|
||||
cumulative = np.arange(1, len(sorted_data) + 1) / len(sorted_data)
|
||||
ax3.plot(sorted_data, cumulative, linewidth=2, color='purple')
|
||||
ax3.set_title('当前成交量累积分布函数', fontsize=14, fontweight='bold')
|
||||
ax3.set_xlabel('成交量 (手)', fontsize=12)
|
||||
ax3.set_ylabel('累积概率', fontsize=12)
|
||||
ax3.grid(True, alpha=0.3)
|
||||
ax3.axhline(y=0.5, color='red', linestyle='--', alpha=0.7, label='中位数')
|
||||
ax3.axhline(y=0.9, color='orange', linestyle='--', alpha=0.7, label='90%分位数')
|
||||
ax3.legend(fontsize=10)
|
||||
|
||||
# 4. 成交量时间序列
|
||||
ax4 = fig.add_subplot(gs[1, :])
|
||||
sample_indices = np.linspace(0, len(self.current_volume)-1, 1000, dtype=int)
|
||||
ax4.plot(sample_indices, self.current_volume.iloc[sample_indices],
|
||||
linewidth=0.8, alpha=0.8, color='steelblue')
|
||||
ax4.fill_between(sample_indices, 0, self.current_volume.iloc[sample_indices],
|
||||
alpha=0.3, color='steelblue')
|
||||
ax4.set_title('当前成交量时间序列 (采样显示)', fontsize=14, fontweight='bold')
|
||||
ax4.set_xlabel('时间序列索引', fontsize=12)
|
||||
ax4.set_ylabel('成交量 (手)', fontsize=12)
|
||||
ax4.grid(True, alpha=0.3)
|
||||
|
||||
# 添加大单标记
|
||||
large_threshold = self.stats['q90']
|
||||
large_indices = np.where(self.current_volume > large_threshold)[0]
|
||||
if len(large_indices) > 0:
|
||||
sample_large_indices = np.intersect1d(sample_indices, large_indices)
|
||||
if len(sample_large_indices) > 0:
|
||||
ax4.scatter(sample_large_indices, self.current_volume.iloc[sample_large_indices],
|
||||
color='red', s=20, alpha=0.8, zorder=5,
|
||||
label=f'大单交易 (>{large_threshold:.0f}手)')
|
||||
ax4.legend(fontsize=10)
|
||||
|
||||
# 5. 成交量分组柱状图
|
||||
ax5 = fig.add_subplot(gs[2, 0])
|
||||
group_names = list(self.pattern_analysis['group_stats'].keys())
|
||||
group_counts = [self.pattern_analysis['group_stats'][name]['count']
|
||||
for name in group_names]
|
||||
|
||||
colors = plt.cm.Set3(np.linspace(0, 1, len(group_names)))
|
||||
bars = ax5.bar(group_names, group_counts, color=colors, alpha=0.8, edgecolor='black', linewidth=0.5)
|
||||
|
||||
# 在柱子上添加数值标签
|
||||
for bar, count in zip(bars, group_counts):
|
||||
height = bar.get_height()
|
||||
ax5.text(bar.get_x() + bar.get_width()/2., height + max(group_counts)*0.01,
|
||||
f'{count:,}', ha='center', va='bottom', fontsize=10, fontweight='bold')
|
||||
|
||||
ax5.set_title('成交量分组分布 (按交易笔数)', fontsize=14, fontweight='bold')
|
||||
ax5.set_xlabel('成交量分组', fontsize=12)
|
||||
ax5.set_ylabel('交易笔数', fontsize=12)
|
||||
ax5.grid(True, alpha=0.3, axis='y')
|
||||
|
||||
# 旋转x轴标签以便更好地显示
|
||||
plt.setp(ax5.get_xticklabels(), rotation=45, ha='right')
|
||||
|
||||
# 6. 成交量贡献度条形图
|
||||
ax6 = fig.add_subplot(gs[2, 1])
|
||||
volume_contributions = [self.pattern_analysis['group_stats'][name]['volume_percentage']
|
||||
for name in group_names]
|
||||
|
||||
bars = ax6.barh(group_names, volume_contributions, color=colors, alpha=0.7)
|
||||
ax6.set_title('成交量贡献度 (按成交量占比)', fontsize=14, fontweight='bold')
|
||||
ax6.set_xlabel('成交量占比 (%)', fontsize=12)
|
||||
ax6.grid(True, alpha=0.3, axis='x')
|
||||
|
||||
# 在条形上添加数值标签
|
||||
for i, (bar, contribution) in enumerate(zip(bars, volume_contributions)):
|
||||
ax6.text(contribution + 0.5, bar.get_y() + bar.get_height()/2,
|
||||
f'{contribution:.1f}%', va='center', fontsize=10)
|
||||
|
||||
# 7. 统计摘要表
|
||||
ax7 = fig.add_subplot(gs[2, 2])
|
||||
ax7.axis('off')
|
||||
|
||||
# 创建统计摘要文本
|
||||
summary_text = f"""成交量统计摘要
|
||||
|
||||
数据量: {self.stats['total_ticks']:,} Tick
|
||||
有效成交量: {self.stats['valid_ticks']:,} Tick
|
||||
|
||||
基础统计:
|
||||
* 平均值: {self.stats['mean_volume']:.2f} 手
|
||||
* 中位数: {self.stats['median_volume']:.2f} 手
|
||||
* 标准差: {self.stats['std_volume']:.2f} 手
|
||||
* 变异系数: {self.stats['cv']:.3f}
|
||||
* 偏度: {self.stats['skewness']:.3f}
|
||||
|
||||
分位数统计:
|
||||
* 最小值: {self.stats['min_volume']:.2f} 手
|
||||
* 25%分位: {self.stats['q25']:.2f} 手
|
||||
* 75%分位: {self.stats['q75']:.2f} 手
|
||||
* 90%分位: {self.stats['q90']:.2f} 手
|
||||
* 95%分位: {self.stats['q95']:.2f} 手
|
||||
* 最大值: {self.stats['max_volume']:.2f} 手
|
||||
|
||||
大单交易分析:
|
||||
* 大单阈值: {self.pattern_analysis['large_threshold']:.1f} 手
|
||||
* 大单次数: {self.pattern_analysis['large_trades_count']:,}
|
||||
* 大单占比: {self.pattern_analysis['large_trades_percentage']:.2f}%
|
||||
* 大单成交量占比: {self.pattern_analysis['large_volume_percentage']:.2f}%
|
||||
"""
|
||||
|
||||
ax7.text(0.05, 0.95, summary_text, transform=ax7.transAxes,
|
||||
fontsize=10, va='top', ha='left', wrap=True,
|
||||
bbox=dict(boxstyle='round,pad=0.5', facecolor='lightyellow', alpha=0.9))
|
||||
|
||||
# 设置总标题
|
||||
fig.suptitle('AU2512期货当前成交量分布综合分析',
|
||||
fontsize=18, fontweight='bold', y=0.98)
|
||||
|
||||
# 保存图表
|
||||
plt.tight_layout()
|
||||
chart_file = 'au2512_volume_distribution_analysis.png'
|
||||
plt.savefig(chart_file, dpi=300, bbox_inches='tight',
|
||||
facecolor='white', edgecolor='none')
|
||||
plt.close()
|
||||
|
||||
print(f"成交量分布分析图表已保存: {chart_file}")
|
||||
return chart_file
|
||||
|
||||
def generate_insights_report(self):
|
||||
"""生成业务洞察报告"""
|
||||
print("\n=== 业务洞察报告 ===")
|
||||
|
||||
insights = []
|
||||
|
||||
# 成交量分布特征分析
|
||||
if self.stats['skewness'] > 1:
|
||||
insights.append("1. 成交量分布呈现严重的右偏特征,表明大部分交易集中在小单,大单交易较少但影响显著")
|
||||
elif self.stats['skewness'] > 0.5:
|
||||
insights.append("1. 成交量分布呈现中等程度的右偏特征,存在一定比例的大单交易")
|
||||
else:
|
||||
insights.append("1. 成交量分布相对均匀,大小单交易分布较为均衡")
|
||||
|
||||
# 变异系数分析
|
||||
if self.stats['cv'] > 2:
|
||||
insights.append("2. 成交量波动极大,市场交易活跃度变化剧烈,需要关注市场情绪变化")
|
||||
elif self.stats['cv'] > 1:
|
||||
insights.append("2. 成交量波动较大,市场存在明显的活跃期和沉寂期")
|
||||
else:
|
||||
insights.append("2. 成交量波动相对稳定,市场交易活跃度较为一致")
|
||||
|
||||
# 大单交易分析
|
||||
if self.pattern_analysis['large_volume_percentage'] > 50:
|
||||
insights.append("3. 大单交易占据主导地位,可能表明机构投资者参与度较高")
|
||||
elif self.pattern_analysis['large_volume_percentage'] > 30:
|
||||
insights.append("3. 大单交易占比较为重要,对市场流动性有显著影响")
|
||||
else:
|
||||
insights.append("3. 小单交易为主,市场参与者可能以散户为主")
|
||||
|
||||
# 交易模式分析
|
||||
dominant_group = max(self.pattern_analysis['group_stats'].items(),
|
||||
key=lambda x: x[1]['volume_percentage'])
|
||||
insights.append(f"4. 主要成交量贡献来自{dominant_group[0]}的交易,占比{dominant_group[1]['volume_percentage']:.1f}%")
|
||||
|
||||
# 市场活跃度分析
|
||||
if self.stats['mean_volume'] > 20:
|
||||
insights.append("5. 市场整体活跃度较高,平均单笔成交量较大")
|
||||
elif self.stats['mean_volume'] > 10:
|
||||
insights.append("5. 市场活跃度适中,交易较为频繁")
|
||||
else:
|
||||
insights.append("5. 市场活跃度相对较低,交易较为谨慎")
|
||||
|
||||
# 风险提示
|
||||
if self.stats['max_volume'] / self.stats['mean_volume'] > 50:
|
||||
insights.append("6. 风险提示:存在超大单交易,可能导致价格剧烈波动")
|
||||
|
||||
# 打印所有洞察
|
||||
for insight in insights:
|
||||
print(f" {insight}")
|
||||
|
||||
self.insights = insights
|
||||
return insights
|
||||
|
||||
def print_detailed_report(self):
|
||||
"""打印详细分析报告"""
|
||||
print("\n" + "="*80)
|
||||
print("AU2512期货当前成交量分布分析报告")
|
||||
print("="*80)
|
||||
|
||||
# 数据概况
|
||||
print(f"\n【数据概况】")
|
||||
print(f"数据文件: {self.data_file}")
|
||||
print(f"分析时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f"总记录数: {self.stats['total_ticks']:,}")
|
||||
print(f"有效成交量记录: {self.stats['valid_ticks']:,}")
|
||||
print(f"数据完整性: {self.stats['valid_ticks']/self.stats['total_ticks']*100:.2f}%")
|
||||
|
||||
# 基础统计
|
||||
print(f"\n【基础统计】")
|
||||
print(f"平均成交量: {self.stats['mean_volume']:.2f} 手")
|
||||
print(f"中位数成交量: {self.stats['median_volume']:.2f} 手")
|
||||
print(f"成交量标准差: {self.stats['std_volume']:.2f} 手")
|
||||
print(f"变异系数: {self.stats['cv']:.3f}")
|
||||
print(f"分布偏度: {self.stats['skewness']:.3f}")
|
||||
|
||||
# 分位数分析
|
||||
print(f"\n【分位数分析】")
|
||||
percentiles = [0, 25, 50, 75, 90, 95, 99, 100]
|
||||
percentile_names = ['最小值', '25%分位', '中位数', '75%分位', '90%分位', '95%分位', '99%分位', '最大值']
|
||||
for name, pct in zip(percentile_names, percentiles):
|
||||
value = self.current_volume_clean.quantile(pct/100) if pct > 0 else self.stats['min_volume']
|
||||
if pct == 100:
|
||||
value = self.stats['max_volume']
|
||||
print(f"{name:>8}: {value:>8.2f} 手")
|
||||
|
||||
# 大单交易分析
|
||||
print(f"\n【大单交易分析】")
|
||||
print(f"大单阈值 (90%分位数): {self.pattern_analysis['large_threshold']:.1f} 手")
|
||||
print(f"大单交易次数: {self.pattern_analysis['large_trades_count']:,}")
|
||||
print(f"大单交易占比: {self.pattern_analysis['large_trades_percentage']:.2f}%")
|
||||
print(f"大单成交量占比: {self.pattern_analysis['large_volume_percentage']:.2f}%")
|
||||
|
||||
# 成交量分组分析
|
||||
print(f"\n【成交量分组分析】")
|
||||
print(f"{'分组':>8} {'次数':>8} {'占比':>8} {'成交量':>10} {'占比':>8}")
|
||||
print("-" * 50)
|
||||
for group_name in self.pattern_analysis['group_stats']:
|
||||
stats = self.pattern_analysis['group_stats'][group_name]
|
||||
print(f"{group_name:>8} {stats['count']:>8,} {stats['percentage']:>7.1f}% "
|
||||
f"{stats['volume_sum']:>10,.0f} {stats['volume_percentage']:>7.1f}%")
|
||||
|
||||
# 业务洞察
|
||||
print(f"\n【业务洞察】")
|
||||
for insight in self.insights:
|
||||
print(f" {insight}")
|
||||
|
||||
# 交易建议
|
||||
print(f"\n【交易建议】")
|
||||
if self.stats['cv'] > 2:
|
||||
print(" * 建议关注市场情绪变化,适时调整交易策略")
|
||||
if self.pattern_analysis['large_volume_percentage'] > 40:
|
||||
print(" * 关注大单流向,可能预示价格趋势变化")
|
||||
if self.stats['mean_volume'] < 10:
|
||||
print(" * 市场活跃度较低,建议谨慎交易")
|
||||
else:
|
||||
print(" * 市场活跃度适中,适合正常交易策略")
|
||||
|
||||
print(f"\n【生成的文件】")
|
||||
print(f" au2512_volume_distribution_analysis.png - 成交量分布综合分析图表")
|
||||
|
||||
print(f"\n" + "="*80)
|
||||
print("分析完成!")
|
||||
print("="*80)
|
||||
|
||||
def run_analysis(self):
|
||||
"""运行完整分析"""
|
||||
print("开始AU2512期货当前成交量分布分析...")
|
||||
|
||||
# 加载数据
|
||||
if not self.load_data():
|
||||
return False
|
||||
|
||||
# 准备成交量数据
|
||||
if not self.prepare_volume_data():
|
||||
return False
|
||||
|
||||
# 计算基础统计
|
||||
self.calculate_basic_statistics()
|
||||
|
||||
# 分析成交量模式
|
||||
self.analyze_volume_patterns()
|
||||
|
||||
# 创建图表
|
||||
self.create_distribution_charts()
|
||||
|
||||
# 生成业务洞察
|
||||
self.generate_insights_report()
|
||||
|
||||
# 打印详细报告
|
||||
self.print_detailed_report()
|
||||
|
||||
return True
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
parser = argparse.ArgumentParser(description='AU2512期货当前成交量分布分析工具')
|
||||
parser.add_argument('data_file', nargs='?',
|
||||
default='data/au2512_20251013.parquet',
|
||||
help='数据文件路径 (默认: data/au2512_20251013.parquet)')
|
||||
parser.add_argument('--output-dir', '-o', default='.',
|
||||
help='输出目录 (默认: 当前目录)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# 检查数据文件是否存在
|
||||
if not os.path.exists(args.data_file):
|
||||
print(f"错误: 数据文件不存在 - {args.data_file}")
|
||||
print("\n使用方法:")
|
||||
print(" python volume_distribution_analysis.py [数据文件路径]")
|
||||
print(f" python volume_distribution_analysis.py # 使用默认文件: {args.data_file}")
|
||||
sys.exit(1)
|
||||
|
||||
# 创建分析器并运行
|
||||
analyzer = VolumeDistributionAnalyzer(args.data_file)
|
||||
success = analyzer.run_analysis()
|
||||
|
||||
if success:
|
||||
print(f"\n分析完成!图表已保存到: {args.output_dir}")
|
||||
else:
|
||||
print(f"\n分析失败!")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
355
volume_price_distribution.py
Normal file
@ -0,0 +1,355 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
AU2512期货成交量在价格上的分布图
|
||||
|
||||
这个脚本专门用于生成当前成交量在价格上的分布图,
|
||||
简单直观地展示不同价格水平下的成交量分布情况。
|
||||
|
||||
使用方法:
|
||||
python volume_price_distribution.py [data_file]
|
||||
|
||||
如果不指定文件,默认分析 data/au2512_20251013.parquet
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import warnings
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
class VolumePriceDistributionAnalyzer:
|
||||
"""成交量-价格分布分析器"""
|
||||
|
||||
def __init__(self, data_file=None):
|
||||
"""
|
||||
初始化分析器
|
||||
|
||||
Args:
|
||||
data_file (str): 数据文件路径,默认为 data/au2512_20251013.parquet
|
||||
"""
|
||||
self.data_file = data_file or "data/au2512_20251013.parquet"
|
||||
self.df = None
|
||||
self.setup_chinese_font()
|
||||
|
||||
def setup_chinese_font(self):
|
||||
"""设置中文字体支持"""
|
||||
try:
|
||||
# 直接使用已知可用的中文字体
|
||||
chinese_fonts = ['Microsoft YaHei', 'SimHei', 'SimSun', 'KaiTi', 'FangSong', 'DengXian']
|
||||
|
||||
for font in chinese_fonts:
|
||||
try:
|
||||
plt.rcParams['font.sans-serif'] = [font]
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
plt.rcParams['font.size'] = 12
|
||||
plt.rcParams['axes.titlesize'] = 16
|
||||
plt.rcParams['axes.labelsize'] = 14
|
||||
plt.rcParams['xtick.labelsize'] = 12
|
||||
plt.rcParams['ytick.labelsize'] = 12
|
||||
|
||||
# 简单测试字体
|
||||
fig, ax = plt.subplots(figsize=(1, 1))
|
||||
ax.text(0.5, 0.5, '测试', fontsize=12)
|
||||
plt.close(fig)
|
||||
print(f"[*] 成功设置中文字体: {font}")
|
||||
return
|
||||
except:
|
||||
continue
|
||||
|
||||
# 如果都失败,使用默认设置
|
||||
print("[!] 无法设置中文字体,使用默认字体")
|
||||
plt.rcParams['font.sans-serif'] = ['DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
plt.rcParams['font.size'] = 12
|
||||
|
||||
except Exception as e:
|
||||
print(f"[!] 字体设置警告: {e}")
|
||||
plt.rcParams['font.sans-serif'] = ['DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
plt.rcParams['font.size'] = 12
|
||||
|
||||
def load_data(self):
|
||||
"""加载数据"""
|
||||
try:
|
||||
if not os.path.exists(self.data_file):
|
||||
raise FileNotFoundError(f"数据文件不存在: {self.data_file}")
|
||||
|
||||
print(f"正在加载数据: {self.data_file}")
|
||||
|
||||
# 根据文件扩展名选择读取方式
|
||||
if self.data_file.endswith('.parquet'):
|
||||
self.df = pd.read_parquet(self.data_file)
|
||||
elif self.data_file.endswith('.csv'):
|
||||
self.df = pd.read_csv(self.data_file)
|
||||
else:
|
||||
raise ValueError("不支持的文件格式,请使用 .parquet 或 .csv 文件")
|
||||
|
||||
print(f"数据加载成功: {len(self.df):,} 条记录")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"数据加载失败: {e}")
|
||||
return False
|
||||
|
||||
def prepare_data(self):
|
||||
"""准备分析数据"""
|
||||
print("\n=== 准备价格-成交量分布数据 ===")
|
||||
|
||||
# 获取列名
|
||||
price_col = None
|
||||
cumulative_volume_col = None
|
||||
|
||||
# 自动检测关键列
|
||||
for i, col in enumerate(self.df.columns):
|
||||
if '成交价' in col and price_col is None:
|
||||
price_col = col
|
||||
elif cumulative_volume_col is None and i == 3: # 累计成交量通常在第4列
|
||||
cumulative_volume_col = col
|
||||
|
||||
if price_col is None or cumulative_volume_col is None:
|
||||
raise ValueError("无法找到成交价或累计成交量列")
|
||||
|
||||
print(f"使用价格列: {price_col}")
|
||||
print(f"使用累计成交量列: {cumulative_volume_col}")
|
||||
|
||||
# 准备分析数据
|
||||
analysis_data = self.df[[price_col, cumulative_volume_col]].copy()
|
||||
analysis_data.columns = ['价格', '累计成交量']
|
||||
|
||||
# 计算当前成交量
|
||||
analysis_data['当前成交量'] = analysis_data['累计成交量'].diff().fillna(0)
|
||||
analysis_data.loc[analysis_data.index[0], '当前成交量'] = analysis_data.loc[analysis_data.index[0], '累计成交量']
|
||||
|
||||
# 移除零值和异常值
|
||||
valid_data = analysis_data[
|
||||
(analysis_data['当前成交量'] > 0) &
|
||||
(analysis_data['当前成交量'] < analysis_data['当前成交量'].quantile(0.999))
|
||||
].copy()
|
||||
|
||||
print(f"原始数据点: {len(analysis_data):,}")
|
||||
print(f"有效数据点: {len(valid_data):,}")
|
||||
print(f"价格范围: {valid_data['价格'].min():.2f} - {valid_data['价格'].max():.2f}")
|
||||
print(f"成交量范围: {valid_data['当前成交量'].min():.2f} - {valid_data['当前成交量'].max():.2f} 手")
|
||||
print(f"价格间隔: 0.02 元/格")
|
||||
|
||||
self.analysis_data = valid_data
|
||||
return True
|
||||
|
||||
def create_volume_distribution_chart(self):
|
||||
"""创建成交量在价格上的分布图"""
|
||||
print("\n=== 生成成交量价格分布图 ===")
|
||||
|
||||
# 创建图表
|
||||
plt.figure(figsize=(16, 10))
|
||||
|
||||
# 创建价格分组
|
||||
prices = self.analysis_data['价格']
|
||||
min_price = prices.min()
|
||||
max_price = prices.max()
|
||||
|
||||
# 使用固定0.02价格间隔
|
||||
interval_size = 0.02
|
||||
price_bins = np.arange(np.floor(min_price * 50) / 50, # 向下取整到0.02的倍数
|
||||
np.ceil(max_price * 50) / 50 + interval_size, # 向上取整
|
||||
interval_size)
|
||||
bin_centers = (price_bins[:-1] + price_bins[1:]) / 2
|
||||
|
||||
# 计算每个价格分组的成交量
|
||||
volume_by_price = []
|
||||
for i in range(len(price_bins) - 1):
|
||||
mask = (self.analysis_data['价格'] >= price_bins[i]) & (self.analysis_data['价格'] < price_bins[i + 1])
|
||||
volume_sum = self.analysis_data.loc[mask, '当前成交量'].sum()
|
||||
volume_by_price.append(volume_sum)
|
||||
|
||||
volume_by_price = np.array(volume_by_price)
|
||||
|
||||
# 绘制成交量分布柱状图
|
||||
colors = plt.cm.RdYlBu_r(np.linspace(0, 1, len(bin_centers)))
|
||||
bars = plt.bar(bin_centers, volume_by_price,
|
||||
width=(price_bins[1] - price_bins[0]) * 0.8,
|
||||
color=colors, alpha=0.8, edgecolor='black', linewidth=0.5)
|
||||
|
||||
# 设置标题和标签
|
||||
plt.title('AU2512期货成交量在价格上的分布 (价格间隔: 0.02)', fontsize=20, fontweight='bold', pad=20)
|
||||
plt.xlabel('价格', fontsize=16, labelpad=10)
|
||||
plt.ylabel('累计成交量 (手)', fontsize=16, labelpad=10)
|
||||
plt.grid(True, alpha=0.3, axis='y')
|
||||
|
||||
# 找出成交量最大的几个价格区间
|
||||
top_indices = np.argsort(volume_by_price)[-5:] # 取前5个
|
||||
|
||||
# 标注成交量最大的价格区间
|
||||
for i in top_indices:
|
||||
if volume_by_price[i] > 0:
|
||||
plt.annotate(f'{volume_by_price[i]:.0f}手',
|
||||
xy=(bin_centers[i], volume_by_price[i]),
|
||||
xytext=(0, 20), textcoords='offset points',
|
||||
ha='center', va='bottom',
|
||||
fontsize=11, fontweight='bold', color='red',
|
||||
bbox=dict(boxstyle='round,pad=0.3', facecolor='yellow', alpha=0.8),
|
||||
arrowprops=dict(arrowstyle='->', color='red', alpha=0.7))
|
||||
|
||||
# 添加统计信息
|
||||
max_volume = volume_by_price.max()
|
||||
max_price_range = price_bins[np.argmax(volume_by_price)]
|
||||
max_price_range_end = price_bins[np.argmax(volume_by_price) + 1]
|
||||
|
||||
total_volume = volume_by_price.sum()
|
||||
max_volume_percentage = (max_volume / total_volume) * 100
|
||||
|
||||
stats_text = f'''统计信息:
|
||||
• 价格区间: {min_price:.2f} - {max_price:.2f}
|
||||
• 总成交量: {total_volume:,.0f} 手
|
||||
• 最大成交量: {max_volume:,.0f} 手 ({max_volume_percentage:.1f}%)
|
||||
• 最活跃价格区间: {max_price_range:.2f} - {max_price_range_end:.2f}'''
|
||||
|
||||
plt.text(0.98, 0.98, stats_text, transform=plt.gca().transAxes,
|
||||
fontsize=12, ha='right', va='top',
|
||||
bbox=dict(boxstyle='round,pad=0.5', facecolor='lightgreen', alpha=0.9))
|
||||
|
||||
# 格式化y轴标签
|
||||
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'{x/1000:.0f}K'))
|
||||
|
||||
# 调整布局
|
||||
plt.tight_layout()
|
||||
|
||||
# 保存图表
|
||||
chart_file = 'au2512_volume_price_distribution.png'
|
||||
plt.savefig(chart_file, dpi=300, bbox_inches='tight',
|
||||
facecolor='white', edgecolor='none')
|
||||
plt.close()
|
||||
|
||||
print(f"成交量价格分布图已保存: {chart_file}")
|
||||
return chart_file
|
||||
|
||||
def print_summary(self):
|
||||
"""打印分析摘要"""
|
||||
print("\n" + "="*60)
|
||||
print("成交量在价格上分布分析摘要")
|
||||
print("="*60)
|
||||
|
||||
prices = self.analysis_data['价格']
|
||||
volumes = self.analysis_data['当前成交量']
|
||||
|
||||
print(f"\n【数据概况】")
|
||||
print(f"数据文件: {self.data_file}")
|
||||
print(f"有效记录数: {len(self.analysis_data):,}")
|
||||
print(f"价格范围: {prices.min():.2f} - {prices.max():.2f}")
|
||||
print(f"成交量范围: {volumes.min():.2f} - {volumes.max():.2f} 手")
|
||||
print(f"平均成交量: {volumes.mean():.2f} 手")
|
||||
|
||||
# 创建价格分组的详细数据
|
||||
min_price = prices.min()
|
||||
max_price = prices.max()
|
||||
interval_size = 0.02
|
||||
|
||||
price_bins = np.arange(np.floor(min_price * 50) / 50,
|
||||
np.ceil(max_price * 50) / 50 + interval_size,
|
||||
interval_size)
|
||||
|
||||
bin_centers = (price_bins[:-1] + price_bins[1:]) / 2
|
||||
|
||||
# 计算每个价格分组的成交量
|
||||
volume_by_price = []
|
||||
for i in range(len(price_bins) - 1):
|
||||
mask = (self.analysis_data['价格'] >= price_bins[i]) & (self.analysis_data['价格'] < price_bins[i + 1])
|
||||
volume_sum = self.analysis_data.loc[mask, '当前成交量'].sum()
|
||||
volume_by_price.append(volume_sum)
|
||||
|
||||
volume_by_price = np.array(volume_by_price)
|
||||
total_volume = volume_by_price.sum()
|
||||
|
||||
# 找出成交量最大的价格区间
|
||||
max_idx = np.argmax(volume_by_price)
|
||||
max_volume = volume_by_price[max_idx]
|
||||
max_price_start = price_bins[max_idx]
|
||||
max_price_end = price_bins[max_idx + 1]
|
||||
|
||||
print(f"\n【最活跃价格区间】")
|
||||
print(f"价格区间: {max_price_start:.2f} - {max_price_end:.2f}")
|
||||
print(f"区间成交量: {max_volume:,.0f} 手")
|
||||
print(f"占总成交量比例: {(max_volume/total_volume*100):.1f}%")
|
||||
|
||||
# 列出前20个成交最大的价格区间
|
||||
print(f"\n【前20个成交最大的价格区间】")
|
||||
print(f"{'排名':>4} {'价格区间':>15} {'成交量':>12} {'占比':>8} {'累计占比':>10}")
|
||||
print("-" * 65)
|
||||
|
||||
# 获取排序后的索引
|
||||
sorted_indices = np.argsort(volume_by_price)[::-1] # 降序排列
|
||||
|
||||
cumulative_percentage = 0
|
||||
for rank in range(min(20, len(sorted_indices))):
|
||||
idx = sorted_indices[rank]
|
||||
if volume_by_price[idx] > 0: # 只显示有成交量的区间
|
||||
price_start = price_bins[idx]
|
||||
price_end = price_bins[idx + 1]
|
||||
volume = volume_by_price[idx]
|
||||
percentage = (volume / total_volume) * 100
|
||||
cumulative_percentage += percentage
|
||||
|
||||
print(f"{rank+1:>4} {price_start:>7.2f}-{price_end:<7.2f} {volume:>10,.0f} {percentage:>6.1f}% {cumulative_percentage:>8.1f}%")
|
||||
|
||||
print(f"\n【生成的图表】")
|
||||
print(f" au2512_volume_price_distribution.png - 成交量价格分布图")
|
||||
|
||||
print(f"\n" + "="*60)
|
||||
print("分析完成!")
|
||||
print("="*60)
|
||||
|
||||
def run_analysis(self):
|
||||
"""运行完整分析"""
|
||||
print("开始AU2512期货成交量价格分布分析...")
|
||||
|
||||
# 加载数据
|
||||
if not self.load_data():
|
||||
return False
|
||||
|
||||
# 准备数据
|
||||
if not self.prepare_data():
|
||||
return False
|
||||
|
||||
# 创建图表
|
||||
self.create_volume_distribution_chart()
|
||||
|
||||
# 打印摘要
|
||||
self.print_summary()
|
||||
|
||||
return True
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
parser = argparse.ArgumentParser(description='AU2512期货成交量价格分布分析工具')
|
||||
parser.add_argument('data_file', nargs='?',
|
||||
default='data/au2512_20251013.parquet',
|
||||
help='数据文件路径 (默认: data/au2512_20251013.parquet)')
|
||||
parser.add_argument('--output-dir', '-o', default='.',
|
||||
help='输出目录 (默认: 当前目录)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# 检查数据文件是否存在
|
||||
if not os.path.exists(args.data_file):
|
||||
print(f"错误: 数据文件不存在 - {args.data_file}")
|
||||
print("\n使用方法:")
|
||||
print(" python volume_price_distribution.py [数据文件路径]")
|
||||
print(f" python volume_price_distribution.py # 使用默认文件: {args.data_file}")
|
||||
sys.exit(1)
|
||||
|
||||
# 创建分析器并运行
|
||||
analyzer = VolumePriceDistributionAnalyzer(args.data_file)
|
||||
success = analyzer.run_analysis()
|
||||
|
||||
if success:
|
||||
print(f"\n分析完成!图表已保存到: {args.output_dir}")
|
||||
else:
|
||||
print(f"\n分析失败!")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
497
volume_price_sequence.py
Normal file
@ -0,0 +1,497 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
AU2512期货成交量-成交价序列图生成工具
|
||||
|
||||
这个脚本专门用于生成高解释力的成交量-成交价序列图。
|
||||
通过按累计成交量升序排列,清晰展示价格随交易推进的演变轨迹。
|
||||
|
||||
使用方法:
|
||||
python volume_price_sequence.py [data_file]
|
||||
|
||||
如果不指定文件,默认分析 data/au2512_20251013.parquet
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.gridspec import GridSpec
|
||||
from datetime import datetime, timedelta
|
||||
import pytz
|
||||
import warnings
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
class VolumePriceAnalyzer:
|
||||
"""成交量-成交价序列分析器"""
|
||||
|
||||
def __init__(self, data_file=None):
|
||||
"""
|
||||
初始化分析器
|
||||
|
||||
Args:
|
||||
data_file (str): 数据文件路径,默认为 data/au2512_20251013.parquet
|
||||
"""
|
||||
self.data_file = data_file or "data/au2512_20251013.parquet"
|
||||
self.df = None
|
||||
self.setup_chinese_font()
|
||||
|
||||
def setup_chinese_font(self):
|
||||
"""设置中文字体支持"""
|
||||
try:
|
||||
# 尝试不同的中文字体
|
||||
chinese_fonts = ['Microsoft YaHei', 'SimHei', 'SimSun', 'KaiTi', 'FangSong']
|
||||
|
||||
for font in chinese_fonts:
|
||||
try:
|
||||
plt.rcParams['font.sans-serif'] = [font]
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
# 测试字体是否可用
|
||||
fig, ax = plt.subplots(figsize=(1, 1))
|
||||
ax.text(0.5, 0.5, '测试', fontsize=12)
|
||||
plt.close(fig)
|
||||
print(f"使用中文字体: {font}")
|
||||
return
|
||||
except:
|
||||
continue
|
||||
|
||||
# 如果都不行,使用默认字体
|
||||
plt.rcParams['font.sans-serif'] = ['DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
print("警告: 无法加载中文字体,使用默认字体")
|
||||
|
||||
except Exception as e:
|
||||
print(f"字体设置警告: {e}")
|
||||
plt.rcParams['font.sans-serif'] = ['DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
|
||||
def load_data(self):
|
||||
"""加载数据"""
|
||||
try:
|
||||
if not os.path.exists(self.data_file):
|
||||
raise FileNotFoundError(f"数据文件不存在: {self.data_file}")
|
||||
|
||||
print(f"正在加载数据: {self.data_file}")
|
||||
|
||||
# 根据文件扩展名选择读取方式
|
||||
if self.data_file.endswith('.parquet'):
|
||||
self.df = pd.read_parquet(self.data_file)
|
||||
elif self.data_file.endswith('.csv'):
|
||||
self.df = pd.read_csv(self.data_file)
|
||||
else:
|
||||
raise ValueError("不支持的文件格式,请使用 .parquet 或 .csv 文件")
|
||||
|
||||
print(f"数据加载成功: {len(self.df):,} 条记录")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"数据加载失败: {e}")
|
||||
return False
|
||||
|
||||
def analyze_data(self):
|
||||
"""分析数据并按成交量排序"""
|
||||
print("\n=== 数据分析 ===")
|
||||
|
||||
# 按累计成交量升序排列
|
||||
self.df = self.df.sort_values('累积成交量').reset_index(drop=True)
|
||||
|
||||
# 计算基础指标
|
||||
self.total_volume = self.df['累积成交量'].max()
|
||||
self.min_price = self.df['成交价'].min()
|
||||
self.max_price = self.df['成交价'].max()
|
||||
self.avg_price = self.df['成交价'].mean()
|
||||
|
||||
print(f"数据概况:")
|
||||
print(f" 累计成交量: {self.total_volume:,} 手")
|
||||
print(f" 价格区间: {self.min_price:.2f} - {self.max_price:.2f}")
|
||||
print(f" 平均价格: {self.avg_price:.2f}")
|
||||
print(f" 记录数量: {len(self.df):,}")
|
||||
|
||||
# 计算成交量变化
|
||||
if '当前成交量' not in self.df.columns:
|
||||
self.df['当前成交量'] = self.df['累积成交量'].diff().fillna(0)
|
||||
self.df.loc[self.df.index[0], '当前成交量'] = self.df.loc[self.df.index[0], '累积成交量']
|
||||
|
||||
self.df['volume_change'] = self.df['当前成交量'] # 使用当前成交量
|
||||
print(f" 平均单笔成交量: {self.df['volume_change'].mean():.1f} 手")
|
||||
print(f" 最大单笔成交量: {self.df['volume_change'].max():.0f} 手")
|
||||
print(f" 成交量标准差: {self.df['volume_change'].std():.1f} 手")
|
||||
|
||||
# 计算关键节点
|
||||
self.calculate_key_milestones()
|
||||
|
||||
def calculate_key_milestones(self):
|
||||
"""计算关键成交量节点"""
|
||||
self.milestones = {
|
||||
'起始': self.df.iloc[0],
|
||||
'10%': self.df.iloc[len(self.df)//10],
|
||||
'25%': self.df.iloc[len(self.df)//4],
|
||||
'50%': self.df.iloc[len(self.df)//2],
|
||||
'75%': self.df.iloc[3*len(self.df)//4],
|
||||
'90%': self.df.iloc[9*len(self.df)//10],
|
||||
'结束': self.df.iloc[-1]
|
||||
}
|
||||
|
||||
print(f"\n关键成交量节点:")
|
||||
for label, point in self.milestones.items():
|
||||
print(f" {label}: 成交量 {point['累积成交量']:,} 手, 价格 {point['成交价']:.2f}")
|
||||
|
||||
def create_volume_price_chart(self):
|
||||
"""创建成交量-成交价序列图(包含当前成交量柱状图)"""
|
||||
print("\n=== 生成成交量-成交价序列图 ===")
|
||||
|
||||
# 创建复合图表布局:主图 + 右侧成交量分布图
|
||||
fig = plt.figure(figsize=(28, 14))
|
||||
gs = GridSpec(2, 3, figure=fig, width_ratios=[3, 0.1, 1], height_ratios=[3, 1],
|
||||
hspace=0.1, wspace=0.05)
|
||||
|
||||
# 主图:成交价序列图
|
||||
ax1 = fig.add_subplot(gs[0, 0])
|
||||
|
||||
# 右侧成交量分布图
|
||||
ax_volume_dist = fig.add_subplot(gs[0, 2], sharey=ax1)
|
||||
|
||||
# 下方当前成交量图
|
||||
ax2 = fig.add_subplot(gs[1, 0], sharex=ax1)
|
||||
|
||||
# 上方图表:成交价序列图
|
||||
# 绘制主要序列图
|
||||
ax1.plot(self.df['累积成交量'], self.df['成交价'],
|
||||
linewidth=2.0, alpha=0.9, color='navy', label='成交价序列')
|
||||
|
||||
# 添加关键价格标注(右侧成交量分布图中累计成交量最大的10个价格区间)
|
||||
# 使用与右侧成交量分布图相同的逻辑:按价格分组计算累计成交量
|
||||
prices = self.df['成交价']
|
||||
min_price = prices.min()
|
||||
max_price = prices.max()
|
||||
|
||||
# 使用固定0.02价格间隔(与右侧图一致)
|
||||
interval_size = 0.02
|
||||
price_bins = np.arange(np.floor(min_price * 50) / 50,
|
||||
np.ceil(max_price * 50) / 50 + interval_size,
|
||||
interval_size)
|
||||
bin_centers = (price_bins[:-1] + price_bins[1:]) / 2
|
||||
|
||||
# 确保有当前成交量列
|
||||
if '当前成交量' not in self.df.columns:
|
||||
self.df['当前成交量'] = self.df['累积成交量'].diff().fillna(0)
|
||||
self.df.loc[self.df.index[0], '当前成交量'] = self.df.loc[self.df.index[0], '累积成交量']
|
||||
|
||||
# 计算每个价格分组的累计成交量(与右侧图完全一致)
|
||||
volume_by_price = []
|
||||
for i in range(len(price_bins) - 1):
|
||||
mask = (self.df['成交价'] >= price_bins[i]) & (self.df['成交价'] < price_bins[i + 1])
|
||||
volume_sum = self.df.loc[mask, '当前成交量'].sum()
|
||||
volume_by_price.append(volume_sum)
|
||||
|
||||
volume_by_price = np.array(volume_by_price)
|
||||
|
||||
# 找出累计成交量最大的10个价格区间
|
||||
top_indices = np.argsort(volume_by_price)[-10:] # 取最大的10个
|
||||
top_volume_points = []
|
||||
|
||||
for idx in sorted(top_indices, reverse=True): # 按成交量降序排列
|
||||
if volume_by_price[idx] > 0: # 只显示有成交量的区间
|
||||
price = bin_centers[idx]
|
||||
volume = volume_by_price[idx]
|
||||
# 找到该价格区间内的任意一个数据点来获取累计成交量
|
||||
mask = (self.df['成交价'] >= price_bins[idx]) & (self.df['成交价'] < price_bins[idx + 1])
|
||||
if mask.any():
|
||||
sample_point = self.df[mask].iloc[0]
|
||||
top_volume_points.append({
|
||||
'成交价': price,
|
||||
'当前成交量': volume,
|
||||
'累积成交量': sample_point['累积成交量']
|
||||
})
|
||||
|
||||
# 获取最大累计成交量作为右边界
|
||||
max_cumulative_volume = self.df['累积成交量'].max()
|
||||
|
||||
# 为每个关键价格添加浅绿色虚线标注
|
||||
for point in top_volume_points:
|
||||
price = point['成交价']
|
||||
volume = point['当前成交量'] # 这是价格区间的累计成交量
|
||||
cumulative_vol = point['累积成交量']
|
||||
|
||||
# 绘制水平虚线
|
||||
ax1.axhline(y=price, color='lightgreen', linestyle='--', linewidth=1.5, alpha=0.7, zorder=1)
|
||||
|
||||
# 添加价格标注(左侧)
|
||||
ax1.text(cumulative_vol, price, f'{price:.2f}',
|
||||
fontsize=10, color='darkgreen', fontweight='bold',
|
||||
ha='left', va='bottom',
|
||||
bbox=dict(boxstyle='round,pad=0.2', facecolor='lightgreen', alpha=0.8))
|
||||
|
||||
# 添加成交量标注(右侧)
|
||||
ax1.text(max_cumulative_volume, price, f'{volume:.0f}手',
|
||||
fontsize=9, color='darkgreen', fontweight='bold',
|
||||
ha='right', va='bottom',
|
||||
bbox=dict(boxstyle='round,pad=0.2', facecolor='lightyellow', alpha=0.9))
|
||||
|
||||
# 添加关键价格说明
|
||||
ax1.text(0.02, 0.98, f'关键价格标注\n(右侧图中累计成交量前10)', transform=ax1.transAxes,
|
||||
fontsize=11, ha='left', va='top', color='darkgreen', fontweight='bold',
|
||||
bbox=dict(boxstyle='round,pad=0.4', facecolor='lightgreen', alpha=0.9))
|
||||
|
||||
# 设置上方图表标题和标签
|
||||
ax1.set_title('AU2512期货成交价序列图 (按累计成交量升序排列)',
|
||||
fontsize=20, fontweight='bold', pad=20)
|
||||
ax1.set_ylabel('成交价', fontsize=16, labelpad=10)
|
||||
ax1.grid(True, alpha=0.3, linestyle='-', linewidth=0.5)
|
||||
|
||||
# 添加分析结论到上方图表
|
||||
final_price = self.df['成交价'].iloc[-1]
|
||||
initial_price = self.df['成交价'].iloc[0]
|
||||
total_change = final_price - initial_price
|
||||
total_change_pct = (total_change / initial_price) * 100
|
||||
|
||||
conclusion_text = f'''分析结论:
|
||||
• 整体价格趋势: {"上涨" if total_change > 0 else "下跌"} ({total_change:+.2f}, {total_change_pct:+.2f}%)
|
||||
• 价格波动区间: {self.min_price:.2f} - {self.max_price:.2f}
|
||||
• 总成交量: {self.total_volume:,} 手
|
||||
• 总Tick数: {len(self.df):,}
|
||||
• 平均每1000手成交量影响: {abs(total_change)/(self.total_volume/1000):.4f}'''
|
||||
|
||||
ax1.text(0.98, 0.02, conclusion_text, transform=ax1.transAxes,
|
||||
fontsize=12, ha='right', va='bottom',
|
||||
bbox=dict(boxstyle='round,pad=0.5', facecolor='lightgreen', alpha=0.9))
|
||||
|
||||
# 下方图表:当前成交量柱状图
|
||||
# 确保有当前成交量列,如果没有则计算
|
||||
if '当前成交量' not in self.df.columns:
|
||||
self.df['当前成交量'] = self.df['累积成交量'].diff().fillna(0)
|
||||
self.df.loc[self.df.index[0], '当前成交量'] = self.df.loc[self.df.index[0], '累积成交量']
|
||||
|
||||
# 直接绘制所有当前成交量数据点
|
||||
# 使用细线图代替柱状图,因为数据点太多
|
||||
ax2.plot(self.df['累积成交量'], self.df['当前成交量'],
|
||||
linewidth=0.5, alpha=0.8, color='steelblue', label='当前成交量')
|
||||
|
||||
# 添加填充区域以增强视觉效果
|
||||
ax2.fill_between(self.df['累积成交量'], 0, self.df['当前成交量'],
|
||||
alpha=0.3, color='steelblue')
|
||||
|
||||
# 设置下方图表标题和标签
|
||||
ax2.set_title('当前成交量分布 (按累计成交量)', fontsize=16, fontweight='bold', pad=10)
|
||||
ax2.set_xlabel('累计成交量 (手)', fontsize=16, labelpad=10)
|
||||
ax2.set_ylabel('当前成交量 (手)', fontsize=14, labelpad=10)
|
||||
ax2.grid(True, alpha=0.3, linestyle='-', linewidth=0.5)
|
||||
ax2.legend(fontsize=14, loc='upper right')
|
||||
|
||||
# 添加成交量统计信息
|
||||
max_volume = self.df['当前成交量'].max()
|
||||
avg_volume = self.df['当前成交量'].mean()
|
||||
total_ticks = len(self.df)
|
||||
volume_stats = f'''成交量统计:
|
||||
• 最大单笔成交量: {max_volume:.0f} 手
|
||||
• 平均成交量: {avg_volume:.1f} 手
|
||||
• 总Tick数: {total_ticks:,}'''
|
||||
|
||||
ax2.text(0.02, 0.98, volume_stats, transform=ax2.transAxes,
|
||||
fontsize=11, ha='left', va='top',
|
||||
bbox=dict(boxstyle='round,pad=0.4', facecolor='lightyellow', alpha=0.9))
|
||||
|
||||
# 右侧图表:成交量在价格上的分布
|
||||
# 创建价格分组(0.02间隔)
|
||||
prices = self.df['成交价']
|
||||
min_price = prices.min()
|
||||
max_price = prices.max()
|
||||
|
||||
# 使用固定0.02价格间隔
|
||||
interval_size = 0.02
|
||||
price_bins = np.arange(np.floor(min_price * 50) / 50,
|
||||
np.ceil(max_price * 50) / 50 + interval_size,
|
||||
interval_size)
|
||||
bin_centers = (price_bins[:-1] + price_bins[1:]) / 2
|
||||
|
||||
# 计算每个价格分组的成交量
|
||||
if '当前成交量' not in self.df.columns:
|
||||
self.df['当前成交量'] = self.df['累积成交量'].diff().fillna(0)
|
||||
self.df.loc[self.df.index[0], '当前成交量'] = self.df.loc[self.df.index[0], '累积成交量']
|
||||
|
||||
volume_by_price = []
|
||||
for i in range(len(price_bins) - 1):
|
||||
mask = (self.df['成交价'] >= price_bins[i]) & (self.df['成交价'] < price_bins[i + 1])
|
||||
volume_sum = self.df.loc[mask, '当前成交量'].sum()
|
||||
volume_by_price.append(volume_sum)
|
||||
|
||||
volume_by_price = np.array(volume_by_price)
|
||||
|
||||
# 绘制右侧成交量分布图(水平柱状图)
|
||||
colors = plt.cm.RdYlBu_r(np.linspace(0, 1, len(bin_centers)))
|
||||
bars = ax_volume_dist.barh(bin_centers, volume_by_price,
|
||||
height=0.015, # 设置柱子高度
|
||||
color=colors, alpha=0.8, edgecolor='black', linewidth=0.3)
|
||||
|
||||
# 设置右侧图表标题和标签
|
||||
ax_volume_dist.set_title('成交量分布', fontsize=14, fontweight='bold', pad=10)
|
||||
ax_volume_dist.set_xlabel('成交量 (手)', fontsize=12)
|
||||
ax_volume_dist.grid(True, alpha=0.3, axis='x')
|
||||
|
||||
# 格式化x轴标签
|
||||
ax_volume_dist.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'{x/1000:.0f}K'))
|
||||
|
||||
# 隐藏右侧图表的y轴刻度(与主图共享)
|
||||
ax_volume_dist.tick_params(axis='y', which='both', left=False, right=False,
|
||||
labelleft=False, labelright=False)
|
||||
|
||||
# 找出成交量最大的几个价格区间并标注
|
||||
max_volume = volume_by_price.max()
|
||||
if max_volume > 0:
|
||||
max_idx = np.argmax(volume_by_price)
|
||||
max_price_range = f"{price_bins[max_idx]:.2f}-{price_bins[max_idx+1]:.2f}"
|
||||
|
||||
ax_volume_dist.annotate(f'{max_volume:.0f}手\n{max_price_range}',
|
||||
xy=(max_volume, bin_centers[max_idx]),
|
||||
xytext=(max_volume * 0.7, bin_centers[max_idx]),
|
||||
ha='right', va='center',
|
||||
fontsize=10, fontweight='bold', color='red',
|
||||
bbox=dict(boxstyle='round,pad=0.3', facecolor='yellow', alpha=0.8))
|
||||
|
||||
# 设置两个图表的坐标轴格式
|
||||
from matplotlib.ticker import FuncFormatter
|
||||
formatter = FuncFormatter(lambda x, p: f'{x/1000:.0f}K')
|
||||
ax1.xaxis.set_major_formatter(formatter)
|
||||
ax2.xaxis.set_major_formatter(formatter)
|
||||
|
||||
# 设置y轴格式
|
||||
ax2.yaxis.set_major_formatter(FuncFormatter(lambda x, p: f'{x/1000:.1f}K' if x >= 1000 else f'{x:.0f}'))
|
||||
|
||||
# 调整布局
|
||||
plt.tight_layout()
|
||||
plt.subplots_adjust(wspace=0.05) # 调整子图间距
|
||||
|
||||
# 保存图表
|
||||
chart_file = 'au2512_volume_price_sequence.png'
|
||||
plt.savefig(chart_file, dpi=300, bbox_inches='tight',
|
||||
facecolor='white', edgecolor='none')
|
||||
plt.close()
|
||||
|
||||
print(f"成交量-成交价序列图已保存: {chart_file}")
|
||||
return chart_file
|
||||
|
||||
def print_detailed_analysis(self):
|
||||
"""打印详细分析结果"""
|
||||
print("\n" + "="*60)
|
||||
print("AU2512期货成交量-成交价序列分析报告")
|
||||
print("="*60)
|
||||
|
||||
# 基础信息
|
||||
print(f"\n【基础数据】")
|
||||
print(f"数据文件: {self.data_file}")
|
||||
print(f"记录数量: {len(self.df):,} 条")
|
||||
print(f"累计成交量: {self.total_volume:,} 手")
|
||||
|
||||
# 价格分析
|
||||
print(f"\n【价格分析】")
|
||||
print(f"起始价格: {self.df['成交价'].iloc[0]:.2f}")
|
||||
print(f"结束价格: {self.df['成交价'].iloc[-1]:.2f}")
|
||||
print(f"最高价格: {self.max_price:.2f}")
|
||||
print(f"最低价格: {self.min_price:.2f}")
|
||||
print(f"平均价格: {self.avg_price:.2f}")
|
||||
print(f"价格波动: {(self.max_price - self.min_price):.2f}")
|
||||
|
||||
# 成交量分析
|
||||
print(f"\n【成交量分析】")
|
||||
print(f"平均单笔成交量: {self.df['volume_change'].mean():.1f} 手")
|
||||
print(f"最大单笔成交量: {self.df['volume_change'].max():.0f} 手")
|
||||
print(f"成交量标准差: {self.df['volume_change'].std():.1f} 手")
|
||||
|
||||
# 价格变化分析
|
||||
final_price = self.df['成交价'].iloc[-1]
|
||||
initial_price = self.df['成交价'].iloc[0]
|
||||
total_change = final_price - initial_price
|
||||
total_change_pct = (total_change / initial_price) * 100
|
||||
|
||||
print(f"\n【价格变化分析】")
|
||||
print(f"总体变化: {total_change:+.2f} ({total_change_pct:+.2f}%)")
|
||||
print(f"最大涨幅: {self.max_price - initial_price:+.2f}")
|
||||
print(f"最大跌幅: {self.min_price - initial_price:+.2f}")
|
||||
|
||||
# 关键节点分析
|
||||
print(f"\n【关键节点分析】")
|
||||
for label, point in self.milestones.items():
|
||||
if label != '起始':
|
||||
prev_point = self.milestones.get('起始', self.df.iloc[0])
|
||||
if label in ['10%', '25%', '50%', '75%', '90%', '结束']:
|
||||
price_change = point['成交价'] - prev_point['成交价']
|
||||
price_change_pct = (price_change / prev_point['成交价']) * 100
|
||||
volume_added = point['累积成交量'] - prev_point['累积成交量']
|
||||
|
||||
print(f" {label:>6}: 价格 {point['成交价']:7.2f} ({price_change_pct:+6.2f}%) | "
|
||||
f"成交量 +{volume_added:7,} 手")
|
||||
|
||||
print(f"\n【数据质量】")
|
||||
missing_values = self.df.isnull().sum().sum()
|
||||
duplicates = self.df.duplicated().sum()
|
||||
print(f"缺失值: {missing_values} 个")
|
||||
print(f"重复记录: {duplicates} 行")
|
||||
print(f"数据完整性: {'优秀' if missing_values == 0 else '需要关注'}")
|
||||
|
||||
print(f"\n【业务洞察】")
|
||||
print(f"1. 价格随成交量变化的完整轨迹清晰可见")
|
||||
print(f"2. 整体趋势: {'上涨' if total_change > 0 else '下跌'} ({total_change_pct:+.2f}%)")
|
||||
print(f"3. 交易过程中价格呈现 {'逐步上涨' if total_change > 0 else '逐步下跌'} 趋势")
|
||||
print(f"4. 关键成交量节点对价格的影响显著")
|
||||
|
||||
print(f"\n【生成的图表】")
|
||||
print(f" au2512_volume_price_sequence.png - 成交量-成交价序列图(含当前成交量柱状图)")
|
||||
|
||||
print(f"\n" + "="*60)
|
||||
print("分析完成!")
|
||||
print("="*60)
|
||||
|
||||
def run_analysis(self):
|
||||
"""运行完整分析"""
|
||||
print("开始AU2512期货成交量-成交价序列分析...")
|
||||
|
||||
# 加载数据
|
||||
if not self.load_data():
|
||||
return False
|
||||
|
||||
# 分析数据
|
||||
self.analyze_data()
|
||||
|
||||
# 创建图表
|
||||
self.create_volume_price_chart()
|
||||
|
||||
# 打印详细分析
|
||||
self.print_detailed_analysis()
|
||||
|
||||
return True
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
parser = argparse.ArgumentParser(description='AU2512期货成交量-成交价序列分析工具')
|
||||
parser.add_argument('data_file', nargs='?',
|
||||
default='data/au2512_20251013.parquet',
|
||||
help='数据文件路径 (默认: data/au2512_20251013.parquet)')
|
||||
parser.add_argument('--output-dir', '-o', default='.',
|
||||
help='输出目录 (默认: 当前目录)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# 检查数据文件是否存在
|
||||
if not os.path.exists(args.data_file):
|
||||
print(f"错误: 数据文件不存在 - {args.data_file}")
|
||||
print("\n使用方法:")
|
||||
print(" python volume_price_sequence.py [数据文件路径]")
|
||||
print(f" python volume_price_sequence.py # 使用默认文件: {args.data_file}")
|
||||
sys.exit(1)
|
||||
|
||||
# 创建分析器并运行
|
||||
analyzer = VolumePriceAnalyzer(args.data_file)
|
||||
success = analyzer.run_analysis()
|
||||
|
||||
if success:
|
||||
print(f"\n分析完成!图表已保存到: {args.output_dir}")
|
||||
else:
|
||||
print(f"\n分析失败!")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
28
工作流.md
Normal file
@ -0,0 +1,28 @@
|
||||
一个给您的推荐工作流
|
||||
对于您作为专业交易员进行初步统计分析的场景,我推荐以下这个务实且高效的流程:
|
||||
|
||||
数据初始转换 (一次性工作)
|
||||
|
||||
工具: Python脚本 + Polars
|
||||
|
||||
流程:
|
||||
|
||||
读取您原始的(可能是CSV或二进制格式的)数据文件。
|
||||
|
||||
|
||||
使用Polars进行所有的数据清洗、预处理和衍生计算(如计算单笔成交量)。
|
||||
|
||||
将处理干净的数据按天、按品种保存为 Parquet 格式。例如,data/im_20251031.parquet。这会极大压缩文件体积并为后续分析提速百倍。
|
||||
|
||||
探索性数据分析 (日常工作)
|
||||
|
||||
|
||||
工具: Jupyter Lab/Notebook + Polars + NumPy + 可视化库 (Matplotlib, Seaborn, Plotly)
|
||||
|
||||
流程:
|
||||
|
||||
在Jupyter中,使用Polars的scan_parquet()函数惰性加载您需要的Parquet文件。这意味着它不会立刻把数据读入内存,只有在真正需要计算时才会执行,能处理远超内存大小的数据。
|
||||
|
||||
执行您在方案中设计的所有统计分析(价差、深度、OBI等)。Polars的多核并行能力会让这些复杂计算飞快完成。
|
||||
|
||||
使用Plotly进行交互式图表绘制,以便缩放和平移观察价格和指标的细节。
|
||||