diff --git a/.gitignore b/.gitignore
index 57ffaad..5f95d9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,172 +1,173 @@
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
-*.egg
-MANIFEST
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.nox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*.cover
-*.py,cover
-.hypothesis/
-.pytest_cache/
-cover/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-.pybuilder/
-target/
-
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# IPython
-profile_default/
-ipython_config.py
-
-# pyenv
-# For a library or package, you might want to ignore these files since the code is
-# intended to run in multiple environments; otherwise, check them in:
-# .python-version
-
-# pipenv
-# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
-# However, in case of collaboration, if having platform-specific dependencies or dependencies
-# having no cross-platform support, pipenv may install dependencies that don't work, or not
-# install all needed dependencies.
-#Pipfile.lock
-
-# poetry
-# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
-# This is especially recommended for binary packages to ensure reproducibility, and is more
-# commonly ignored for libraries.
-# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
-
-# uv
-.venv/
-.uv/
-__pypackages__/
-.uvrc.local
-#poetry.lock
-
-# pdm
-# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
-#pdm.lock
-# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
-# in version control.
-# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
-.pdm.toml
-.pdm-python
-.pdm-build/
-
-# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
-__pypackages__/
-
-# Celery stuff
-celerybeat-schedule
-celerybeat.pid
-
-# SageMath parsed files
-*.sage.py
-
-# Environments
-.env
-.venv
-env/
-venv/
-ENV/
-env.bak/
-venv.bak/
-
-# Spyder project settings
-.spyderproject
-.spyproject
-
-# Rope project settings
-.ropeproject
-
-# mkdocs documentation
-/site
-
-# mypy
-.mypy_cache/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
-.pyre/
-
-# pytype static type analyzer
-.pytype/
-
-# Cython debug symbols
-cython_debug/
-
-# PyCharm
-# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
-# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
-# and can be added to the global gitignore or merged into this file. For a more nuclear
-# option (not recommended) you can uncomment the following to ignore the entire idea folder.
-#.idea/
-
-*.ipynb
-uv.lock
-output
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+
+# uv
+.venv/
+.uv/
+__pypackages__/
+.uvrc.local
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
+.pdm.toml
+.pdm-python
+.pdm-build/
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+
+*.ipynb
+uv.lock
+output
+datadir
\ No newline at end of file
diff --git a/README.md b/README.md
index 81947d0..d432469 100644
--- a/README.md
+++ b/README.md
@@ -1,65 +1,274 @@
-# qka (快量化)
+# QKA - 快量化
-快捷量化助手(Quick Quantitative Assistant)是一个简洁易用,可实操A股的量化交易框架。
+[](https://www.python.org/)
+[](LICENSE)
+[](https://pypi.org/project/qka/)
+
+**快捷量化助手(Quick Quantitative Assistant)** 是一个简洁易用、功能完整的A股量化交易框架,支持数据获取、策略回测、实盘交易等全流程量化交易功能。
+
+## 特性
+
+- 🚀 **简洁易用**: 统一的API设计,降低量化交易门槛
+- 📊 **数据丰富**: 支持Akshare数据源,提供多周期、多因子数据
+- 🔄 **高效回测**: 基于时间序列的回测引擎,支持多股票横截面处理
+- 💰 **实盘交易**: 集成QMT交易接口,支持实盘交易
+- 📈 **可视化**: 内置Plotly图表,提供交互式回测结果展示
+- 🔧 **模块化**: 高度模块化设计,易于扩展和维护
+- 📝 **文档完整**: 提供详细的API文档和使用示例
## 安装
+### 从PyPI安装
+
```bash
pip install qka
```
-## 使用方法
+### 从源码安装
+
+```bash
+git clone https://github.com/zsrl/qka.git
+cd qka
+pip install -e .
+```
+
+## 快速开始
-### QMTServer
+### 1. 数据获取
```python
-from qka.server import QMTServer
+import qka
-server = QMTServer("YOUR_ACCOUNT_ID", "YOUR_QMT_PATH")
-# 服务器启动时会打印生成的token
-server.start()
+# 创建数据对象
+data = qka.Data(
+ symbols=['000001.SZ', '600000.SH'], # 股票代码列表
+ period='1d', # 日线数据
+ adjust='qfq' # 前复权
+)
+
+# 获取数据
+df = data.get()
+print(df.head())
```
-### QMTClient
+### 2. 策略开发
+
+```python
+import qka
+
+class MyStrategy(qka.Strategy):
+ def __init__(self):
+ super().__init__()
+ self.cash = 100000 # 初始资金
+
+ def on_bar(self, date, get):
+ """每个bar的处理逻辑"""
+ # 获取当前价格数据
+ close_prices = get('close')
+
+ # 示例策略:当000001.SZ价格低于10元时买入
+ if '000001.SZ' in close_prices and close_prices['000001.SZ'] < 10:
+ # 买入1000股
+ self.broker.buy('000001.SZ', close_prices['000001.SZ'], 1000)
+```
-#### 查询
+### 3. 回测分析
```python
-from qka.client import QMTClient
+import qka
-client = QMTClient(token="服务器打印的token")
-# 调用接口
-result = client.api("query_stock_asset")
+# 创建策略实例
+strategy = MyStrategy()
+
+# 创建回测引擎
+backtest = qka.Backtest(data, strategy)
+
+# 运行回测
+backtest.run()
+
+# 绘制收益曲线
+backtest.plot("我的策略回测结果")
```
-#### 下单
+### 4. QMT实盘交易
+
+#### 启动交易服务器
```python
-from qka.client import QMTClient
+from qka.brokers.server import QMTServer
+
+# 创建交易服务器
+server = QMTServer(
+ account_id="YOUR_ACCOUNT_ID", # 你的账户ID
+ mini_qmt_path="YOUR_QMT_PATH" # QMT安装路径
+)
+
+# 启动服务器(会打印token供客户端使用)
+server.start()
+```
+
+#### 使用交易客户端
+
+```python
+from qka.brokers.client import QMTClient
+
+# 创建交易客户端
+client = QMTClient(
+ base_url="http://localhost:8000", # 服务器地址
+ token="服务器打印的token" # 访问令牌
+)
+
+# 查询账户资产
+assets = client.api("query_stock_asset")
+print(assets)
+
+# 下单交易
from xtquant import xtconstant
+result = client.api(
+ "order_stock",
+ stock_code='600000.SH',
+ order_type=xtconstant.STOCK_BUY,
+ order_volume=1000,
+ price_type=xtconstant.FIX_PRICE,
+ price=10.5
+)
+```
+
+## 核心模块
+
+### 数据模块 (qka.Data)
+
+- **多数据源**: 支持Akshare、QMT等数据源
+- **缓存机制**: 自动缓存数据,提高访问效率
+- **并发下载**: 多线程并发下载,提升数据获取速度
+- **数据标准化**: 统一数据格式,便于策略开发
+
+### 回测模块 (qka.Backtest)
+
+- **时间序列**: 基于时间序列的回测引擎
+- **多资产支持**: 支持多股票横截面数据处理
+- **交易记录**: 完整的交易记录和持仓跟踪
+- **可视化**: 交互式回测结果图表
+
+### 策略模块 (qka.Strategy)
-client = QMTClient(token="服务器打印的token", url="服务端地址")
-# 调用接口
-result = client.api("order_stock", stock_code='600000.SH', order_type=xtconstant.STOCK_BUY, order_volume =1000, price_type=xtconstant.FIX_PRICE, price=10.5)
+- **抽象基类**: 提供策略开发的标准接口
+- **事件驱动**: 基于bar的事件处理机制
+- **交易接口**: 内置买入卖出操作接口
+- **状态管理**: 自动管理资金和持仓状态
+
+### 经纪商模块 (qka.brokers)
+
+- **QMT集成**: 完整的QMT交易接口封装
+- **客户端/服务器**: 支持远程交易服务
+- **订单管理**: 完整的订单生命周期管理
+- **错误处理**: 完善的错误处理和日志记录
+
+### MCP模块 (qka.mcp)
+
+- **模型服务**: 提供模型上下文协议支持
+- **数据查询**: 支持Akshare数据查询工具
+- **异步处理**: 基于异步IO的高性能处理
+
+### 工具模块 (qka.utils)
+
+- **日志系统**: 结构化日志记录,支持文件和控制台输出
+- **颜色输出**: 带颜色的控制台输出
+- **工具函数**: 各种实用工具函数
+
+## 高级用法
+
+### 自定义因子计算
+
+```python
+import pandas as pd
+
+def calculate_ma_factor(df):
+ """计算移动平均因子"""
+ df['ma5'] = df['close'].rolling(5).mean()
+ df['ma20'] = df['close'].rolling(20).mean()
+ return df
+
+data = qka.Data(
+ symbols=['000001.SZ'],
+ factor=calculate_ma_factor # 应用自定义因子
+)
+```
+
+### 批量数据处理
+
+```python
+# 批量处理多只股票
+symbols = ['000001.SZ', '600000.SH', '000002.SZ', '600036.SH']
+data = qka.Data(
+ symbols=symbols,
+ pool_size=20 # 增加并发数提高下载速度
+)
+```
+
+### 事件驱动策略
+
+```python
+class EventDrivenStrategy(qka.Strategy):
+ def on_bar(self, date, get):
+ close_prices = get('close')
+ volumes = get('volume')
+
+ # 基于成交量的事件
+ for symbol in close_prices.index:
+ if volumes[symbol] > volumes.mean() * 2: # 成交量放大
+ self.broker.buy(symbol, close_prices[symbol], 100)
```
-
+**注意**: 量化交易存在风险,请在充分了解风险的情况下使用本框架。作者不对使用本框架产生的任何投资损失负责。
diff --git "a/docs/A\350\202\241\345\270\202\345\234\272\350\257\201\345\210\270\344\273\243\347\240\201\345\221\275\345\220\215\350\247\204\345\210\231.md" "b/docs/A\350\202\241\345\270\202\345\234\272\350\257\201\345\210\270\344\273\243\347\240\201\345\221\275\345\220\215\350\247\204\345\210\231.md"
deleted file mode 100644
index 30dd614..0000000
--- "a/docs/A\350\202\241\345\270\202\345\234\272\350\257\201\345\210\270\344\273\243\347\240\201\345\221\275\345\220\215\350\247\204\345\210\231.md"
+++ /dev/null
@@ -1,276 +0,0 @@
-# A股市场证券代码命名规则详解
-
-## 概述
-
-本文档详细记录了A股市场(沪深两市)所有证券品种的代码命名规则,包括股票、基金、指数等各类金融工具的代码分配方案。
-
-**最后更新时间**: 2025年6月20日
-
----
-
-## 1. 上海证券交易所(SH)代码规则
-
-### 1.1 股票代码
-
-#### 主板股票
-- **600001-600999**: 主板股票(最早批次)
- - 示例:600000 浦发银行、600036 招商银行
-- **601001-601999**: 主板股票(第二批次)
- - 示例:601318 中国平安、601398 工商银行
-- **603001-603999**: 主板股票(第三批次)
- - 示例:603993 洛阳钼业、603883 老百姓
-- **605001-605999**: 主板股票(第四批次)
- - 示例:605499 东鹏饮料
-
-#### 科创板股票
-- **688001-688999**: 科创板股票
- - 示例:688001 华兴源创、688009 中国通号
-
-### 1.2 基金代码
-
-#### ETF基金
-- **501001-501999**: 跨境ETF
- - 示例:501018 南方原油
-- **502001-502999**: 本市场股票ETF
- - 示例:502010 易方达创业板ETF
-- **510001-510999**: 本市场股票ETF(主要区间)
- - 示例:510050 50ETF、510300 300ETF
-- **511001-511999**: 债券ETF、货币ETF
- - 示例:511010 国债ETF、511880 银华日利
-- **512001-512999**: 行业ETF、主题ETF
- - 示例:512000 券商ETF、512170 医疗ETF
-- **513001-513999**: 境外市场ETF
- - 示例:513100 纳指ETF、513500 标普500
-- **515001-515999**: 创新型ETF
- - 示例:515050 5GETF、515030 新能源ETF
-- **516001-516999**: 创新型ETF(扩展)
- - 示例:516160 新能源车ETF
-- **518001-518999**: 黄金ETF等商品ETF
- - 示例:518800 黄金ETF、518880 黄金ETF
-
-#### 开放式基金
-- **519001-519999**: 开放式基金
- - 示例:519056 海富通股票、519066 汇添富蓝筹
-
-### 1.3 指数代码
-
-#### 上证指数系列
-- **000001-000999**: 上证指数
- - 000001: 上证指数
- - 000002: 上证A股指数
- - 000003: 上证B股指数
- - 000016: 上证50指数
- - 000300: 沪深300指数(跨市场)
- - 000905: 中证500指数(跨市场)
- - 000852: 中证1000指数(跨市场)
-
-#### 中证指数系列
-- **000001-009999**: 中证指数公司发布的指数
- - 注:部分与上证指数重叠
-
-### 1.4 债券代码
-- **010001-019999**: 国债
-- **020001-029999**: 企业债
-- **101001-109999**: 国债(新编码)
-- **110001-119999**: 可转债
- - 示例:110001 万科转债
-- **113001-113999**: 可转债(扩展)
-- **127001-127999**: 可转债(再扩展)
-
----
-
-## 2. 深圳证券交易所(SZ)代码规则
-
-### 2.1 股票代码
-
-#### 主板股票
-- **000001-000999**: 主板股票(最早批次)
- - 示例:000001 平安银行、000002 万科A
-- **001001-001999**: 主板股票(第二批次)
- - 示例:001979 招商蛇口
-- **002001-002999**: 中小板股票(已并入主板)
- - 示例:002001 新和成、002415 海康威视
-- **003001-003999**: 主板股票(第三批次)
- - 示例:003816 中国广核
-
-#### 创业板股票
-- **300001-300999**: 创业板股票
- - 示例:300001 特锐德、300059 东方财富
-
-### 2.2 基金代码
-
-#### ETF基金
-- **159001-159999**: ETF基金
- - 示例:159001 易方达深100ETF、159915 创业板ETF
-
-#### LOF基金
-- **160001-160999**: LOF基金(第一批次)
- - 示例:160105 南方积配、160119 南方中证500
-- **161001-161999**: LOF基金(第二批次)
- - 示例:161005 富国天惠、161725 招商中证白酒
-- **162001-162999**: LOF基金(第三批次)
-- **163001-163999**: LOF基金(第四批次)
-- **164001-164999**: LOF基金(第五批次)
-- **165001-165999**: LOF基金(第六批次)
-- **166001-166999**: LOF基金(第七批次)
-- **167001-167999**: LOF基金(第八批次)
-- **168001-168999**: LOF基金(第九批次)
-
-### 2.3 指数代码
-
-#### 深证指数系列
-- **399001-399999**: 深证指数
- - 399001: 深证成指
- - 399002: 深成指R
- - 399003: 成份B指
- - 399006: 创业板指
- - 399300: 沪深300指数(跨市场)
- - 399905: 中证500指数(跨市场)
-
-### 2.4 债券代码
-- **100001-109999**: 国债
-- **111001-119999**: 企业债
-- **120001-129999**: 可转债
- - 示例:123001 蓝思转债
-- **128001-128999**: 可转债(扩展)
-
----
-
-## 3. 代码冲突分析
-
-### 3.1 已知冲突案例
-
-| 代码 | 上交所(SH) | 深交所(SZ) | 冲突类型 |
-|------|------------|------------|----------|
-| 000001 | 上证指数 | 平安银行 | 指数 vs 股票 |
-| 000002 | 上证A股指数 | 万科A | 指数 vs 股票 |
-| 000003 | 上证B股指数 | PT金田A | 指数 vs 股票 |
-| 000300 | 沪深300指数 | - | 跨市场指数 |
-
-### 3.2 潜在冲突区间
-
-| 代码区间 | 上交所用途 | 深交所用途 | 冲突风险 |
-|----------|------------|------------|----------|
-| 000001-000999 | 指数 | 主板股票 | 高 |
-| 100001-109999 | 国债 | 国债 | 低(同类型) |
-| 110001-119999 | 可转债 | 企业债 | 中 |
-
----
-
-## 4. 智能识别规则建议
-
-### 4.1 无歧义代码
-
-```python
-# 明确归属上交所的代码前缀
-SH_PREFIXES = [
- '6', # 所有股票
- '50', '51', '52', # ETF基金
- '519', # 开放式基金
- '68' # 科创板
-]
-
-# 明确归属深交所的代码前缀
-SZ_PREFIXES = [
- '30', # 创业板
- '159', # ETF基金
- '16', # LOF基金
- '399' # 指数
-]
-```
-
-### 4.2 歧义代码处理
-
-```python
-# 存在歧义的代码前缀
-AMBIGUOUS_PREFIXES = [
- '000', # SH:指数 vs SZ:主板股票
- '001', # SH:指数 vs SZ:主板股票
- '002', # SH:指数 vs SZ:中小板股票
- '003', # SH:指数 vs SZ:主板股票
- '1', # 两市都有债券产品
-]
-```
-
-### 4.3 推荐处理策略
-
-1. **股票优先原则**: 歧义代码默认当作股票处理
-2. **用途频次原则**: 按实际使用频率选择默认归属
-3. **显式指定原则**: 鼓励用户使用带后缀的完整代码
-4. **警告提示原则**: 遇到歧义代码时给出警告信息
-
----
-
-## 5. 实现建议
-
-### 5.1 代码标准化函数
-
-```python
-def normalize_security_code(code: str, prefer_type: str = 'stock') -> str:
- """
- 证券代码标准化
-
- Args:
- code: 原始代码 (6位数字或带后缀)
- prefer_type: 歧义时的偏好类型 ('stock', 'index', 'fund')
-
- Returns:
- 标准化后的代码 (格式: XXXXXX.XX)
-
- Raises:
- ValueError: 无法识别的代码格式
- """
- pass
-```
-
-### 5.2 歧义检测函数
-
-```python
-def detect_code_ambiguity(code: str) -> List[Dict]:
- """
- 检测代码歧义
-
- Returns:
- 可能的证券信息列表
- [
- {
- 'code': '000001.SH',
- 'name': '上证指数',
- 'type': 'index',
- 'exchange': 'SH'
- },
- {
- 'code': '000001.SZ',
- 'name': '平安银行',
- 'type': 'stock',
- 'exchange': 'SZ'
- }
- ]
- """
- pass
-```
-
----
-
-## 6. 参考资料
-
-- [上海证券交易所官网](https://www.sse.com.cn/)
-- [深圳证券交易所官网](https://www.szse.cn/)
-- [中证指数有限公司](https://www.csindex.com.cn/)
-- 各大数据服务商API文档
-
----
-
-## 7. 更新日志
-
-- 2025-06-20: 初始版本,整理基础命名规则
-- TODO: 补充港股通、债券等更多品种
-- TODO: 验证部分代码区间的准确性
-- TODO: 添加实际代码冲突案例
-
----
-
-**注意**:
-1. 本文档基于公开资料整理,部分细节可能存在变化
-2. 建议在实际应用前验证关键代码区间
-3. 监管规则可能调整,建议定期更新此文档
diff --git a/docs/api/brokers.md b/docs/api/brokers.md
new file mode 100644
index 0000000..aae3208
--- /dev/null
+++ b/docs/api/brokers.md
@@ -0,0 +1,166 @@
+# 交易模块 API 参考
+
+QKA 的交易接口模块,提供 QMT 交易服务器的客户端和服务器端实现。
+
+## qka.brokers.QMTClient
+
+QMT 交易客户端类,提供与 QMT 交易服务器的通信接口。
+
+::: qka.brokers.client.QMTClient
+ options:
+ show_root_heading: false
+ show_source: true
+ members_order: source
+ heading_level: 3
+
+### 使用示例
+
+```python
+from qka.brokers.client import QMTClient
+
+# 创建交易客户端
+client = QMTClient(
+ base_url="http://localhost:8000",
+ token="服务器打印的token"
+)
+
+# 调用交易接口
+assets = client.api("query_stock_asset")
+print(assets)
+```
+
+## qka.brokers.QMTServer
+
+QMT 交易服务器类,将 QMT 交易接口封装为 RESTful API。
+
+::: qka.brokers.server.QMTServer
+ options:
+ show_root_heading: false
+ show_source: true
+ members_order: source
+ heading_level: 3
+
+### 使用示例
+
+```python
+from qka.brokers.server import QMTServer
+
+# 创建交易服务器
+server = QMTServer(
+ account_id="YOUR_ACCOUNT_ID",
+ mini_qmt_path="YOUR_QMT_PATH"
+)
+
+# 启动服务器
+server.start()
+```
+
+## qka.brokers.trade
+
+交易执行相关类和函数,包含订单、交易和持仓管理。
+
+::: qka.brokers.trade
+ options:
+ show_root_heading: false
+ show_source: true
+ members_order: source
+ heading_level: 3
+
+### 主要组件
+
+#### Order 类
+订单对象,表示一个交易订单。
+
+#### Trade 类
+交易记录,表示一个已成交的交易。
+
+#### Position 类
+持仓信息,表示一个持仓头寸。
+
+#### create_trader 函数
+创建 QMT 交易对象的便捷函数。
+
+### 使用示例
+
+```python
+from qka.brokers.trade import create_trader, Order
+
+# 创建交易对象
+trader, account = create_trader(account_id, mini_qmt_path)
+
+# 创建订单
+order = Order(
+ symbol='000001.SZ',
+ side='buy',
+ quantity=1000,
+ order_type='market'
+)
+```
+
+## 模块导入方式
+
+交易模块需要从子模块导入:
+
+```python
+# 客户端
+from qka.brokers.client import QMTClient
+
+# 服务器
+from qka.brokers.server import QMTServer
+
+# 交易执行
+from qka.brokers.trade import create_trader, Order, Trade, Position
+```
+
+## 工作流程
+
+### 1. 启动交易服务器
+
+```python
+from qka.brokers.server import QMTServer
+
+server = QMTServer(
+ account_id="123456789",
+ mini_qmt_path="D:/qmt"
+)
+server.start() # 会打印token供客户端使用
+```
+
+### 2. 使用交易客户端
+
+```python
+from qka.brokers.client import QMTClient
+
+client = QMTClient(
+ base_url="http://localhost:8000",
+ token="服务器打印的token"
+)
+
+# 查询账户信息
+assets = client.api("query_stock_asset")
+
+# 下单交易
+from xtquant import xtconstant
+result = client.api(
+ "order_stock",
+ stock_code='600000.SH',
+ order_type=xtconstant.STOCK_BUY,
+ order_volume=1000,
+ price_type=xtconstant.FIX_PRICE,
+ price=10.5
+)
+```
+
+## 注意事项
+
+1. **QMT 依赖**: 需要安装 QMT 并正确配置环境
+2. **网络连接**: 确保服务器和客户端网络连通
+3. **权限验证**: 使用 token 进行身份验证
+4. **错误处理**: 妥善处理网络错误和交易失败
+
+## 相关链接
+
+- [用户指南 - 实盘交易](../../user-guide/trading.md)
+- [核心模块 API](core.md)
+- [工具模块 API](utils.md)
+- [xtquant 文档](https://github.com/ShiMiaoYS/xtquant)
\ No newline at end of file
diff --git a/docs/api/brokers/index.md b/docs/api/brokers/index.md
deleted file mode 100644
index 72278d5..0000000
--- a/docs/api/brokers/index.md
+++ /dev/null
@@ -1,106 +0,0 @@
-# Brokers 模块
-
-QKA系统的交易接口模块,提供与不同券商和交易平台的接口封装。
-
-## 模块列表
-
-### [client.py](client.md)
-交易客户端接口,提供统一的交易API封装。
-
-**主要类:**
-- `BrokerClient` - 基础交易客户端
-- `SimulatedClient` - 模拟交易客户端
-- `LiveClient` - 实盘交易客户端
-
-**核心功能:**
-- 账户信息查询
-- 订单管理
-- 持仓查询
-- 交易执行
-
-### [server.py](server.md)
-交易服务器实现,处理交易请求和订单路由。
-
-**主要类:**
-- `BrokerServer` - 交易服务器
-- `OrderRouter` - 订单路由器
-- `RiskManager` - 风险管理器
-
-**核心功能:**
-- 订单路由
-- 风险控制
-- 执行监控
-- 状态管理
-
-### [trade.py](trade.md)
-交易执行模块,处理具体的交易逻辑。
-
-**主要类:**
-- `Trade` - 交易记录
-- `Order` - 订单对象
-- `Position` - 持仓信息
-- `Portfolio` - 投资组合
-
-**核心功能:**
-- 交易执行
-- 持仓管理
-- 盈亏计算
-- 组合分析
-
-## 使用示例
-
-```python
-from qka.brokers import BrokerClient, Order
-
-# 创建交易客户端
-client = BrokerClient(broker='simulation')
-
-# 连接到券商
-client.connect()
-
-# 查询账户信息
-account = client.get_account()
-print(f"可用资金: {account.available_cash}")
-
-# 创建订单
-order = Order(
- symbol='AAPL',
- side='buy',
- quantity=100,
- order_type='market'
-)
-
-# 提交订单
-order_id = client.submit_order(order)
-print(f"订单ID: {order_id}")
-
-# 查询订单状态
-status = client.get_order_status(order_id)
-print(f"订单状态: {status}")
-```
-
-## 支持的券商
-
-- **模拟交易** - 用于回测和策略验证
-- **Interactive Brokers** - 专业交易平台
-- **TD Ameritrade** - 美股交易
-- **富途证券** - 港美股交易
-- **华泰证券** - A股交易
-
-## 架构图
-
-```mermaid
-graph TD
- A[Strategy] --> B[BrokerClient]
- B --> C[BrokerServer]
- C --> D[OrderRouter]
- C --> E[RiskManager]
- D --> F[Exchange/Broker]
- E --> D
-
- G[Trade] --> H[Position]
- H --> I[Portfolio]
- B --> G
-```
-
-Brokers模块是QKA系统与外部交易系统的桥梁,确保策略能够安全、高效地执行交易。
diff --git a/docs/api/core.md b/docs/api/core.md
new file mode 100644
index 0000000..df669ad
--- /dev/null
+++ b/docs/api/core.md
@@ -0,0 +1,124 @@
+# 核心模块 API 参考
+
+QKA 的核心功能模块,包含数据管理、回测引擎、策略基类和虚拟经纪商。
+
+## qka.Data
+
+数据管理类,负责股票数据的获取、缓存和管理。
+
+::: qka.core.data.Data
+ options:
+ show_root_heading: false
+ show_source: true
+ members_order: source
+ heading_level: 3
+
+### 使用示例
+
+```python
+import qka
+
+# 创建数据对象
+data = qka.Data(
+ symbols=['000001.SZ', '600000.SH'],
+ period='1d',
+ adjust='qfq'
+)
+
+# 获取数据
+df = data.get()
+print(df.head())
+```
+
+## qka.Backtest
+
+回测引擎类,提供基于时间序列的回测功能。
+
+::: qka.core.backtest.Backtest
+ options:
+ show_root_heading: false
+ show_source: true
+ members_order: source
+ heading_level: 3
+
+### 使用示例
+
+```python
+# 运行回测
+strategy = MyStrategy()
+backtest = qka.Backtest(data, strategy)
+backtest.run()
+
+# 可视化结果
+backtest.plot("我的策略回测结果")
+```
+
+## qka.Strategy
+
+策略抽象基类,所有自定义策略都应该继承此类。
+
+::: qka.core.strategy.Strategy
+ options:
+ show_root_heading: false
+ show_source: true
+ members_order: source
+ heading_level: 3
+
+### 使用示例
+
+```python
+class MyStrategy(qka.Strategy):
+ def __init__(self):
+ super().__init__()
+ self.ma_short = 5
+ self.ma_long = 20
+
+ def on_bar(self, date, get):
+ close_prices = get('close')
+ # 策略逻辑...
+```
+
+## qka.Broker
+
+虚拟交易经纪商类,管理资金、持仓和交易记录。
+
+::: qka.core.broker.Broker
+ options:
+ show_root_heading: false
+ show_source: true
+ members_order: source
+ heading_level: 3
+
+### 使用示例
+
+```python
+# 在策略中使用
+class MyStrategy(qka.Strategy):
+ def on_bar(self, date, get):
+ close_prices = get('close')
+ for symbol in close_prices.index:
+ if self.should_buy(symbol, close_prices[symbol]):
+ self.broker.buy(symbol, close_prices[symbol], 100)
+```
+
+## 模块导入方式
+
+根据 [`qka/__init__.py`](../../qka/__init__.py) 的配置,所有核心模块都可以直接从 `qka` 包导入:
+
+```python
+import qka
+
+# 直接使用
+data = qka.Data(...)
+backtest = qka.Backtest(...)
+strategy = qka.Strategy(...) # 作为基类
+broker = qka.Broker(...)
+```
+
+## 相关链接
+
+- [用户指南 - 数据获取](../../user-guide/data.md)
+- [用户指南 - 回测分析](../../user-guide/backtest.md)
+- [快速开始 - 第一个策略](../../getting-started/first-strategy.md)
+- [交易模块 API](../brokers.md)
+- [工具模块 API](../utils.md)
\ No newline at end of file
diff --git a/docs/api/core/config.md b/docs/api/core/config.md
deleted file mode 100644
index b362537..0000000
--- a/docs/api/core/config.md
+++ /dev/null
@@ -1,200 +0,0 @@
-# Config API 参考
-
-::: qka.core.config
- options:
- show_root_heading: true
- show_source: true
- heading_level: 2
- members_order: source
- show_signature_annotations: true
- separate_signature: true
-
-## 配置示例
-
-### 基本用法
-
-```python
-from qka.core.config import Config
-
-# 创建配置实例
-config = Config()
-
-# 从文件加载配置
-config.load_from_file('config.yaml')
-
-# 获取配置值
-database_url = config.get('database.url', 'sqlite:///default.db')
-debug_mode = config.get('debug', False)
-
-# 设置配置值
-config.set('api.timeout', 30)
-config.set('logging.level', 'INFO')
-```
-
-### 环境变量配置
-
-```python
-import os
-
-# 设置环境变量
-os.environ['QKA_DEBUG'] = 'true'
-os.environ['QKA_DATABASE_URL'] = 'postgresql://localhost/qka'
-
-# 加载环境变量配置
-config = Config()
-config.load_from_env()
-
-# 访问配置
-debug = config.get('debug') # True
-db_url = config.get('database.url') # postgresql://localhost/qka
-```
-
-### 配置文件示例
-
-#### YAML格式 (config.yaml)
-
-```yaml
-# QKA量化系统配置文件
-
-# 数据库配置
-database:
- url: "sqlite:///qka.db"
- pool_size: 10
- echo: false
-
-# API配置
-api:
- host: "0.0.0.0"
- port: 8000
- timeout: 30
- rate_limit: 100
-
-# 日志配置
-logging:
- level: "INFO"
- format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
- file: "logs/qka.log"
- max_size: "10MB"
- backup_count: 5
-
-# 交易配置
-trading:
- commission: 0.001
- slippage: 0.0005
- initial_capital: 100000
-
-# 风险管理
-risk:
- max_position_size: 0.1
- max_drawdown: 0.2
- stop_loss: 0.05
-
-# 策略配置
-strategy:
- default_lookback: 252
- rebalance_frequency: "monthly"
-
-# 通知配置
-notifications:
- email:
- enabled: false
- smtp_server: "smtp.gmail.com"
- port: 587
- wechat:
- enabled: false
- webhook_url: ""
-```
-
-#### JSON格式 (config.json)
-
-```json
-{
- "database": {
- "url": "sqlite:///qka.db",
- "pool_size": 10,
- "echo": false
- },
- "api": {
- "host": "0.0.0.0",
- "port": 8000,
- "timeout": 30
- },
- "logging": {
- "level": "INFO",
- "file": "logs/qka.log"
- }
-}
-```
-
-### 配置验证
-
-```python
-from qka.core.config import Config
-
-config = Config()
-
-# 定义配置验证规则
-validation_rules = {
- 'database.url': {'required': True, 'type': str},
- 'api.port': {'required': True, 'type': int, 'min': 1, 'max': 65535},
- 'trading.commission': {'type': float, 'min': 0, 'max': 1},
- 'logging.level': {'type': str, 'choices': ['DEBUG', 'INFO', 'WARNING', 'ERROR']}
-}
-
-# 验证配置
-try:
- config.validate(validation_rules)
- print("配置验证通过")
-except ConfigError as e:
- print(f"配置验证失败: {e}")
-```
-
-### 动态配置更新
-
-```python
-# 监听配置文件变化
-config.watch_file('config.yaml', auto_reload=True)
-
-# 注册配置变更回调
-@config.on_change('database.url')
-def on_database_change(old_value, new_value):
- print(f"数据库配置从 {old_value} 更改为 {new_value}")
- # 重新初始化数据库连接
- reconnect_database(new_value)
-
-# 手动重新加载配置
-config.reload()
-```
-
-### 配置模板生成
-
-```python
-# 生成示例配置文件
-config.create_sample_config('sample_config.yaml')
-
-# 生成配置模板
-template = config.get_config_template()
-print(template)
-```
-
-## 最佳实践
-
-1. **配置文件管理**
- - 使用版本控制管理配置模板
- - 敏感信息使用环境变量
- - 不同环境使用不同配置文件
-
-2. **配置验证**
- - 应用启动时验证必需配置
- - 定义清晰的验证规则
- - 提供有意义的错误信息
-
-3. **配置更新**
- - 谨慎使用动态配置更新
- - 关键配置变更需要重启服务
- - 记录配置变更日志
-
-4. **安全考虑**
- - 敏感配置信息加密存储
- - 限制配置文件访问权限
- - 审计配置变更操作
diff --git a/docs/api/core/events.md b/docs/api/core/events.md
deleted file mode 100644
index 5f05ddc..0000000
--- a/docs/api/core/events.md
+++ /dev/null
@@ -1,253 +0,0 @@
-# Events API 参考
-
-::: qka.core.events
- options:
- show_root_heading: true
- show_source: true
- heading_level: 2
- members_order: source
- show_signature_annotations: true
- separate_signature: true
-
-## 事件系统使用指南
-
-### 基本概念
-
-事件系统采用发布-订阅模式,支持:
-- 事件发布和订阅
-- 异步事件处理
-- 事件过滤和转换
-- 事件统计和监控
-
-### 基本用法
-
-```python
-from qka.core.events import EventBus, Event
-
-# 创建事件总线
-bus = EventBus()
-
-# 定义事件处理器
-def handle_order(event):
- print(f"处理订单事件: {event}")
-
-# 订阅事件
-bus.subscribe('order_created', handle_order)
-
-# 发布事件
-event = Event('order_created', {'symbol': 'AAPL', 'quantity': 100})
-bus.publish(event)
-```
-
-### 预定义事件类型
-
-#### MarketDataEvent - 市场数据事件
-
-```python
-from qka.core.events import MarketDataEvent
-
-# 创建市场数据事件
-event = MarketDataEvent(
- symbol='AAPL',
- timestamp=datetime.now(),
- data={
- 'open': 150.0,
- 'high': 152.0,
- 'low': 149.0,
- 'close': 151.0,
- 'volume': 1000000
- }
-)
-
-# 订阅市场数据事件
-@bus.subscribe('market_data')
-def handle_market_data(event):
- symbol = event.symbol
- price = event.data['close']
- print(f"{symbol}: ${price}")
-```
-
-#### OrderEvent - 订单事件
-
-```python
-from qka.core.events import OrderEvent
-
-# 创建订单事件
-order_event = OrderEvent(
- order_id='ORD_001',
- symbol='AAPL',
- side='buy',
- quantity=100,
- price=150.0,
- order_type='limit',
- status='pending'
-)
-
-# 订阅订单事件
-@bus.subscribe('order')
-def handle_order(event):
- print(f"订单 {event.order_id}: {event.status}")
-```
-
-#### TradeEvent - 交易事件
-
-```python
-from qka.core.events import TradeEvent
-
-# 创建交易事件
-trade_event = TradeEvent(
- trade_id='TRD_001',
- order_id='ORD_001',
- symbol='AAPL',
- side='buy',
- quantity=100,
- price=150.5,
- commission=0.15,
- timestamp=datetime.now()
-)
-
-# 订阅交易事件
-@bus.subscribe('trade')
-def handle_trade(event):
- print(f"交易完成: {event.symbol} {event.side} {event.quantity}@{event.price}")
-```
-
-### 高级功能
-
-#### 异步事件处理
-
-```python
-import asyncio
-from qka.core.events import EventBus
-
-# 创建支持异步的事件总线
-bus = EventBus(async_mode=True)
-
-# 异步事件处理器
-async def async_handler(event):
- await asyncio.sleep(1) # 模拟异步操作
- print(f"异步处理事件: {event}")
-
-# 订阅异步处理器
-bus.subscribe('async_event', async_handler)
-
-# 发布事件(异步处理)
-await bus.publish_async(Event('async_event', {'data': 'test'}))
-```
-
-#### 事件过滤
-
-```python
-# 带条件的事件订阅
-def price_filter(event):
- return event.data.get('price', 0) > 100
-
-bus.subscribe('market_data', handle_expensive_stocks, filter_func=price_filter)
-
-# 仅处理价格大于100的股票数据
-event = MarketDataEvent('AAPL', data={'price': 150})
-bus.publish(event) # 会被处理
-
-event = MarketDataEvent('PENNY', data={'price': 5})
-bus.publish(event) # 不会被处理
-```
-
-#### 事件转换
-
-```python
-# 事件转换器
-def price_transformer(event):
- # 将价格转换为人民币
- if 'price' in event.data:
- event.data['price_cny'] = event.data['price'] * 7.0
- return event
-
-bus.subscribe('market_data', handle_cny_price, transformer=price_transformer)
-```
-
-#### 批量事件处理
-
-```python
-# 批量事件处理器
-@bus.subscribe_batch('market_data', batch_size=10, timeout=5)
-def handle_batch(events):
- prices = [e.data['price'] for e in events]
- avg_price = sum(prices) / len(prices)
- print(f"批量处理 {len(events)} 条数据,平均价格: {avg_price}")
-
-# 发布多个事件
-for i in range(20):
- event = MarketDataEvent(f'STOCK_{i}', data={'price': 100 + i})
- bus.publish(event)
-```
-
-### 事件统计和监控
-
-```python
-# 获取事件统计
-stats = bus.get_statistics()
-print(f"总事件数: {stats['total_events']}")
-print(f"订阅者数: {stats['total_subscribers']}")
-print(f"事件类型分布: {stats['event_types']}")
-
-# 监控事件处理性能
-@bus.subscribe('performance_monitor')
-def monitor_handler(event):
- processing_time = event.processing_time
- if processing_time > 1.0: # 超过1秒
- print(f"事件处理较慢: {processing_time:.2f}s")
-```
-
-### 错误处理
-
-```python
-# 错误处理器
-def error_handler(event, exception):
- print(f"事件处理失败: {event}, 错误: {exception}")
- # 记录错误日志或发送告警
-
-bus.set_error_handler(error_handler)
-
-# 带重试的事件处理
-@bus.subscribe('critical_event', retry_count=3, retry_delay=1)
-def critical_handler(event):
- if random.random() < 0.5:
- raise Exception("模拟处理失败")
- print(f"关键事件处理成功: {event}")
-```
-
-### 事件持久化
-
-```python
-# 启用事件持久化
-bus.enable_persistence('events.db')
-
-# 重放历史事件
-bus.replay_events(
- event_type='market_data',
- start_time=datetime(2024, 1, 1),
- end_time=datetime(2024, 1, 31)
-)
-```
-
-## 最佳实践
-
-1. **事件设计**
- - 事件名称要清晰、一致
- - 事件数据结构要稳定
- - 避免事件过于频繁
-
-2. **性能优化**
- - 异步处理耗时操作
- - 合理使用批量处理
- - 监控事件处理性能
-
-3. **错误处理**
- - 处理器要有错误处理逻辑
- - 关键事件要有重试机制
- - 记录事件处理日志
-
-4. **测试**
- - 模拟事件进行单元测试
- - 测试异常情况处理
- - 性能测试和压力测试
diff --git a/docs/api/core/index.md b/docs/api/core/index.md
deleted file mode 100644
index 2441756..0000000
--- a/docs/api/core/index.md
+++ /dev/null
@@ -1,98 +0,0 @@
-# Core 模块
-
-QKA系统的核心功能模块,包含配置管理、事件系统、回测引擎等关键组件。
-
-## 模块列表
-
-### [config.py](config.md)
-配置管理系统,支持多种配置源和动态配置更新。
-
-**主要类:**
-- `Config` - 主配置管理类
-- `ConfigError` - 配置相关异常
-
-**核心功能:**
-- 文件配置加载(YAML、JSON、TOML)
-- 环境变量配置
-- 代码配置
-- 配置验证和模板生成
-
-### [events.py](events.md)
-事件驱动框架,提供发布-订阅模式的事件处理机制。
-
-**主要类:**
-- `Event` - 基础事件类
-- `EventBus` - 事件总线
-- `MarketDataEvent` - 市场数据事件
-- `OrderEvent` - 订单事件
-- `TradeEvent` - 交易事件
-
-**核心功能:**
-- 事件发布和订阅
-- 异步事件处理
-- 事件统计和监控
-- 内置交易相关事件
-
-### [backtest.py](backtest.md)
-回测引擎,提供策略回测的核心逻辑。
-
-**主要功能:**
-- 历史数据回测
-- 策略执行模拟
-- 性能指标计算
-- 结果分析和报告
-
-### [data.py](data.md)
-数据处理模块,负责市场数据的获取和处理。
-
-**主要功能:**
-- 数据源接入
-- 数据清洗和预处理
-- 数据缓存和存储
-- 数据格式转换
-
-### [plot.py](plot.md)
-绘图工具模块,提供回测结果和数据的可视化功能。
-
-**主要功能:**
-- 回测结果可视化
-- 技术指标图表
-- 交易信号展示
-- 性能分析图表
-
-## 使用示例
-
-```python
-from qka.core import Config, EventBus
-from qka.core.events import MarketDataEvent
-
-# 初始化配置
-config = Config()
-config.load_from_file('config.yaml')
-
-# 创建事件总线
-bus = EventBus()
-
-# 注册事件处理器
-@bus.subscribe('market_data')
-def handle_market_data(event):
- print(f"收到市场数据: {event.data}")
-
-# 发布事件
-event = MarketDataEvent(symbol='AAPL', price=150.0, volume=1000)
-bus.publish(event)
-```
-
-## 模块依赖关系
-
-```mermaid
-graph TD
- A[config.py] --> D[backtest.py]
- B[events.py] --> D
- C[data.py] --> D
- D --> E[plot.py]
- A --> B
- A --> C
-```
-
-Core模块是整个QKA系统的基础,其他模块都依赖于这些核心组件。
diff --git a/docs/api/index.md b/docs/api/index.md
deleted file mode 100644
index e432986..0000000
--- a/docs/api/index.md
+++ /dev/null
@@ -1,73 +0,0 @@
-# API 参考
-
-QKA量化回测系统的完整API参考文档。
-
-## 模块概览
-
-### 核心模块
-
-- [**Core**](core/index.md) - 核心功能模块
- - [配置管理](core/config.md) - 系统配置管理
- - [事件系统](core/events.md) - 事件驱动框架
- - [回测引擎](core/backtest.md) - 回测核心逻辑
- - [数据处理](core/data.md) - 数据获取和处理
- - [绘图工具](core/plot.md) - 结果可视化
-
-### 工具模块
-
-- [**Utils**](utils/index.md) - 工具类模块
- - [日志系统](utils/logger.md) - 增强日志功能
- - [通用工具](utils/tools.md) - 常用工具类
- - [动画工具](utils/anis.md) - 动画显示工具
- - [通用函数](utils/util.md) - 通用辅助函数
-
-### 交易模块
-
-- [**Brokers**](brokers/index.md) - 交易接口模块
- - [交易客户端](brokers/client.md) - 交易客户端接口
- - [交易服务器](brokers/server.md) - 交易服务器实现
- - [交易执行](brokers/trade.md) - 交易执行逻辑
-
-### MCP模块
-
-- [**MCP**](mcp/index.md) - Model Context Protocol模块
- - [API接口](mcp/api.md) - MCP API定义
- - [服务器实现](mcp/server.md) - MCP服务器
-
-## 快速导航
-
-- [配置系统 API](core/config.md) - 管理系统配置
-- [事件系统 API](core/events.md) - 事件驱动编程
-- [日志系统 API](utils/logger.md) - 结构化日志记录
-- [工具类 API](utils/tools.md) - 通用工具函数
-
-## 使用示例
-
-```python
-from qka.core import Config, EventBus
-from qka.utils import Logger, cache, timeit
-
-# 配置管理
-config = Config()
-config.load_from_file('config.yaml')
-
-# 事件系统
-bus = EventBus()
-bus.subscribe('market_data', handler)
-
-# 日志记录
-logger = Logger()
-logger.info("系统启动")
-
-# 工具使用
-@cache(ttl=300)
-@timeit
-def expensive_function():
- pass
-```
-
-## 版本信息
-
-当前文档对应QKA系统版本:`1.0.0`
-
-API文档会随代码更新自动同步,确保文档的准确性和时效性。
diff --git a/docs/api/mcp/index.md b/docs/api/mcp/index.md
deleted file mode 100644
index 5c4a2e1..0000000
--- a/docs/api/mcp/index.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# MCP 模块
-
-QKA系统的Model Context Protocol模块,提供与AI模型的标准化接口。
-
-## 模块列表
-
-### [api.py](api.md)
-MCP API定义,提供标准的模型上下文协议接口。
-
-**主要类:**
-- `MCPServer` - MCP服务器
-- `MCPClient` - MCP客户端
-- `ContextManager` - 上下文管理器
-
-**核心功能:**
-- 模型接口标准化
-- 上下文管理
-- 会话管理
-- 数据交换
-
-### [server.py](server.md)
-MCP服务器实现,处理模型请求和响应。
-
-**主要类:**
-- `ModelServer` - 模型服务器
-- `RequestHandler` - 请求处理器
-- `ResponseFormatter` - 响应格式化器
-
-**核心功能:**
-- 请求路由
-- 模型调用
-- 结果处理
-- 错误处理
-
-## 使用示例
-
-```python
-from qka.mcp import MCPServer, MCPClient
-
-# 启动MCP服务器
-server = MCPServer(port=8080)
-server.start()
-
-# 创建MCP客户端
-client = MCPClient(server_url='http://localhost:8080')
-
-# 发送模型请求
-response = client.request({
- 'model': 'strategy_advisor',
- 'context': {
- 'portfolio': portfolio_data,
- 'market_data': market_data
- },
- 'query': '分析当前投资组合风险'
-})
-
-print(response['advice'])
-```
-
-## MCP协议特性
-
-- **标准化接口** - 统一的模型调用方式
-- **上下文感知** - 智能的上下文管理
-- **异步处理** - 支持异步模型调用
-- **可扩展性** - 易于添加新的模型
-
-## 架构图
-
-```mermaid
-graph TD
- A[QKA Strategy] --> B[MCP Client]
- B --> C[MCP Server]
- C --> D[Model Router]
- D --> E[AI Model 1]
- D --> F[AI Model 2]
- D --> G[AI Model N]
-
- H[Context Manager] --> C
- I[Request Handler] --> C
- J[Response Formatter] --> C
-```
-
-MCP模块为QKA系统提供了与AI模型交互的标准化方式,支持策略智能化和决策辅助。
diff --git a/docs/api/utils.md b/docs/api/utils.md
new file mode 100644
index 0000000..b7cfd05
--- /dev/null
+++ b/docs/api/utils.md
@@ -0,0 +1,97 @@
+# 工具模块 API 参考
+
+QKA 的工具模块,提供日志系统、颜色输出和各种实用工具函数。
+
+## qka.utils.logger
+
+日志系统模块,提供结构化的日志记录功能。
+
+::: qka.utils.logger
+ options:
+ show_root_heading: false
+ show_source: true
+ members_order: source
+ heading_level: 3
+
+### 主要功能
+
+#### create_logger 函数
+创建增强的日志记录器,支持控制台和文件输出。
+
+#### StructuredLogger 类
+结构化日志记录器,支持附加额外字段。
+
+#### WeChatHandler 类
+微信消息处理器,支持通过企业微信机器人发送日志。
+
+### 使用示例
+
+```python
+from qka.utils.logger import create_logger
+
+# 创建日志记录器
+logger = create_logger(
+ name='my_strategy',
+ level='DEBUG',
+ console_output=True,
+ file_output=True,
+ log_dir='my_logs'
+)
+
+# 记录日志
+logger.info("策略开始运行")
+logger.error("交易失败", symbol='000001.SZ', price=10.5)
+```
+
+## qka.utils.util
+
+通用工具函数模块。
+
+::: qka.utils.util
+ options:
+ show_root_heading: false
+ show_source: true
+ members_order: source
+ heading_level: 3
+
+## qka.utils.anis
+
+ANSI 颜色代码工具,提供带颜色的控制台输出。
+
+::: qka.utils.anis
+ options:
+ show_root_heading: false
+ show_source: true
+ members_order: source
+ heading_level: 3
+
+### 使用示例
+
+```python
+from qka.utils.anis import RED, GREEN, BLUE, RESET
+
+print(f"{RED}错误信息{RESET}")
+print(f"{GREEN}成功信息{RESET}")
+print(f"{BLUE}提示信息{RESET}")
+```
+
+## 模块导入方式
+
+工具模块需要从子模块导入:
+
+```python
+# 日志系统
+from qka.utils.logger import create_logger, StructuredLogger
+
+# 工具函数
+from qka.utils.util import timestamp_to_datetime_string
+
+# 颜色输出
+from qka.utils.anis import RED, GREEN, BLUE, RESET
+```
+
+## 相关链接
+
+- [核心模块 API](core.md)
+- [交易模块 API](brokers.md)
+- [用户指南 - 日志系统](../../user-guide/logging.md)
\ No newline at end of file
diff --git a/docs/api/utils/index.md b/docs/api/utils/index.md
deleted file mode 100644
index e9e6286..0000000
--- a/docs/api/utils/index.md
+++ /dev/null
@@ -1,97 +0,0 @@
-# Utils 模块
-
-QKA系统的工具类模块,提供日志、缓存、计时、格式化等通用功能。
-
-## 模块列表
-
-### [logger.py](logger.md)
-增强日志系统,支持彩色输出、结构化日志、文件轮转等功能。
-
-**主要类:**
-- `Logger` - 增强日志记录器
-- `ColorFormatter` - 彩色日志格式化器
-- `StructuredLogger` - 结构化日志记录器
-
-**核心功能:**
-- 彩色控制台输出
-- 结构化日志记录
-- 文件轮转和压缩
-- 微信通知集成
-- 性能监控日志
-
-### [tools.py](tools.md)
-通用工具类,包含缓存、计时器、装饰器等实用功能。
-
-**主要功能:**
-- `@cache` - 函数结果缓存
-- `@timeit` - 函数执行计时
-- `@retry` - 函数重试机制
-- `FileHelper` - 文件操作工具
-- `FormatHelper` - 格式化工具
-- `ValidationHelper` - 数据验证工具
-
-### [anis.py](anis.md)
-动画显示工具,提供进度条和动画效果。
-
-**主要功能:**
-- 进度条显示
-- 动画效果
-- 状态指示器
-
-### [util.py](util.md)
-通用辅助函数集合。
-
-**主要功能:**
-- 数据处理函数
-- 字符串操作
-- 数学计算工具
-
-## 使用示例
-
-```python
-from qka.utils import Logger, cache, timeit, FileHelper
-
-# 日志记录
-logger = Logger()
-logger.info("系统启动", extra={'module': 'main'})
-
-# 缓存装饰器
-@cache(ttl=300)
-def get_market_data(symbol):
- # 模拟耗时操作
- return fetch_data(symbol)
-
-# 计时装饰器
-@timeit
-def expensive_calculation():
- # 耗时计算
- pass
-
-# 文件操作
-helper = FileHelper()
-helper.ensure_dir('logs')
-helper.safe_write('config.json', data)
-```
-
-## 工具类关系图
-
-```mermaid
-graph TD
- A[logger.py] --> E[日志系统]
- B[tools.py] --> F[缓存工具]
- B --> G[计时工具]
- B --> H[文件工具]
- B --> I[验证工具]
- C[anis.py] --> J[动画工具]
- D[util.py] --> K[通用函数]
-
- E --> L[应用模块]
- F --> L
- G --> L
- H --> L
- I --> L
- J --> L
- K --> L
-```
-
-Utils模块为整个QKA系统提供基础工具支持,提高开发效率和代码质量。
diff --git a/docs/api/utils/logger.md b/docs/api/utils/logger.md
deleted file mode 100644
index d317371..0000000
--- a/docs/api/utils/logger.md
+++ /dev/null
@@ -1,317 +0,0 @@
-# Logger API 参考
-
-::: qka.utils.logger
- options:
- show_root_heading: true
- show_source: true
- heading_level: 2
- members_order: source
- show_signature_annotations: true
- separate_signature: true
-
-## 日志系统使用指南
-
-### 基本用法
-
-```python
-from qka.utils.logger import Logger
-
-# 创建日志实例
-logger = Logger(name='my_app')
-
-# 基本日志记录
-logger.debug("调试信息")
-logger.info("普通信息")
-logger.warning("警告信息")
-logger.error("错误信息")
-logger.critical("严重错误")
-```
-
-### 彩色日志输出
-
-```python
-from qka.utils.logger import Logger, ColorFormatter
-
-# 启用彩色输出
-logger = Logger(name='colorful_app', enable_color=True)
-
-# 日志会以不同颜色显示
-logger.info("这是蓝色的信息日志")
-logger.warning("这是黄色的警告日志")
-logger.error("这是红色的错误日志")
-```
-
-### 结构化日志
-
-```python
-from qka.utils.logger import StructuredLogger
-
-# 创建结构化日志记录器
-logger = StructuredLogger(name='structured_app')
-
-# 记录结构化日志
-logger.info("用户登录", extra={
- 'user_id': 12345,
- 'username': 'john_doe',
- 'ip_address': '192.168.1.100',
- 'user_agent': 'Mozilla/5.0...'
-})
-
-logger.error("数据库连接失败", extra={
- 'database': 'mysql',
- 'host': 'localhost',
- 'port': 3306,
- 'error_code': 2003
-})
-```
-
-### 文件日志配置
-
-```python
-# 配置文件日志
-logger = Logger(
- name='file_app',
- log_file='logs/app.log',
- max_size='10MB',
- backup_count=5,
- compression=True
-)
-
-# 日志会自动轮转和压缩
-for i in range(10000):
- logger.info(f"日志消息 {i}")
-```
-
-### 微信通知集成
-
-```python
-# 配置微信通知
-logger = Logger(
- name='notify_app',
- wechat_webhook='https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY'
-)
-
-# 发送重要通知到微信
-logger.critical("系统出现严重错误", notify_wechat=True)
-logger.error("数据库连接失败", notify_wechat=True)
-```
-
-### 性能监控日志
-
-```python
-import time
-from qka.utils.logger import Logger
-
-logger = Logger(name='perf_app')
-
-# 记录函数执行时间
-@logger.log_performance
-def slow_function():
- time.sleep(2)
- return "完成"
-
-# 记录代码块执行时间
-with logger.timer("数据处理"):
- # 数据处理代码
- process_data()
-```
-
-### 日志过滤和格式化
-
-```python
-import logging
-from qka.utils.logger import Logger
-
-# 自定义日志过滤器
-class SensitiveFilter(logging.Filter):
- def filter(self, record):
- # 过滤敏感信息
- if hasattr(record, 'msg'):
- record.msg = record.msg.replace('password=', 'password=***')
- return True
-
-# 应用过滤器
-logger = Logger(name='secure_app')
-logger.logger.addFilter(SensitiveFilter())
-
-# 自定义格式化器
-formatter = logging.Formatter(
- '%(asctime)s | %(name)s | %(levelname)s | %(message)s',
- datefmt='%Y-%m-%d %H:%M:%S'
-)
-logger.set_formatter(formatter)
-```
-
-### 上下文日志
-
-```python
-from contextvars import ContextVar
-from qka.utils.logger import Logger
-
-# 定义上下文变量
-request_id = ContextVar('request_id', default='unknown')
-
-# 自定义格式化器
-class ContextFormatter(logging.Formatter):
- def format(self, record):
- record.request_id = request_id.get()
- return super().format(record)
-
-# 配置日志
-logger = Logger(name='context_app')
-formatter = ContextFormatter(
- '%(asctime)s [%(request_id)s] %(name)s - %(levelname)s - %(message)s'
-)
-logger.set_formatter(formatter)
-
-# 使用上下文
-request_id.set('req_123456')
-logger.info("处理请求") # 日志中会包含 request_id
-```
-
-### 异步日志
-
-```python
-import asyncio
-from qka.utils.logger import Logger
-
-# 异步日志处理
-logger = Logger(name='async_app', async_mode=True)
-
-async def async_operation():
- logger.info("开始异步操作")
- await asyncio.sleep(1)
- logger.info("异步操作完成")
-
-# 运行异步代码
-asyncio.run(async_operation())
-```
-
-### 日志分析和监控
-
-```python
-# 日志统计
-stats = logger.get_statistics()
-print(f"总日志条数: {stats['total_logs']}")
-print(f"错误日志数: {stats['error_count']}")
-print(f"警告日志数: {stats['warning_count']}")
-
-# 设置日志阈值告警
-logger.set_error_threshold(100) # 错误数超过100时告警
-logger.set_warning_threshold(500) # 警告数超过500时告警
-
-# 日志采样(高频日志场景)
-logger.set_sampling_rate(0.1) # 只记录10%的日志
-```
-
-### 多进程日志
-
-```python
-import multiprocessing
-from qka.utils.logger import Logger
-
-def worker_process(worker_id):
- # 每个进程创建独立的日志实例
- logger = Logger(
- name=f'worker_{worker_id}',
- log_file=f'logs/worker_{worker_id}.log'
- )
-
- for i in range(100):
- logger.info(f"工作进程 {worker_id} 处理任务 {i}")
-
-# 启动多个工作进程
-processes = []
-for i in range(4):
- p = multiprocessing.Process(target=worker_process, args=(i,))
- processes.append(p)
- p.start()
-
-for p in processes:
- p.join()
-```
-
-## 配置示例
-
-### 日志配置文件
-
-```yaml
-# logging.yaml
-version: 1
-disable_existing_loggers: false
-
-formatters:
- standard:
- format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
- datefmt: '%Y-%m-%d %H:%M:%S'
-
- detailed:
- format: '%(asctime)s [%(levelname)s] %(name)s [%(filename)s:%(lineno)d] %(message)s'
- datefmt: '%Y-%m-%d %H:%M:%S'
-
-handlers:
- console:
- class: logging.StreamHandler
- level: INFO
- formatter: standard
- stream: ext://sys.stdout
-
- file:
- class: logging.handlers.RotatingFileHandler
- level: DEBUG
- formatter: detailed
- filename: logs/app.log
- maxBytes: 10485760 # 10MB
- backupCount: 5
- encoding: utf8
-
-loggers:
- qka:
- level: DEBUG
- handlers: [console, file]
- propagate: false
-
-root:
- level: WARNING
- handlers: [console]
-```
-
-### 加载配置文件
-
-```python
-import logging.config
-import yaml
-
-# 加载日志配置
-with open('logging.yaml', 'r') as f:
- config = yaml.safe_load(f.read())
- logging.config.dictConfig(config)
-
-# 使用配置的日志器
-logger = logging.getLogger('qka.strategy')
-logger.info("策略启动")
-```
-
-## 最佳实践
-
-1. **日志级别使用**
- - DEBUG: 详细的调试信息
- - INFO: 一般信息记录
- - WARNING: 警告但不影响运行
- - ERROR: 错误信息,影响功能
- - CRITICAL: 严重错误,可能导致程序终止
-
-2. **结构化日志**
- - 使用统一的日志格式
- - 包含足够的上下文信息
- - 便于日志分析和查询
-
-3. **性能考虑**
- - 避免在热点路径记录大量日志
- - 使用异步日志处理
- - 合理设置日志级别
-
-4. **安全注意**
- - 不要记录敏感信息
- - 使用日志过滤器清理敏感数据
- - 控制日志文件访问权限
diff --git a/docs/api/utils/tools.md b/docs/api/utils/tools.md
deleted file mode 100644
index c199b96..0000000
--- a/docs/api/utils/tools.md
+++ /dev/null
@@ -1,468 +0,0 @@
-# Tools API 参考
-
-::: qka.utils.tools
- options:
- show_root_heading: true
- show_source: true
- heading_level: 2
- members_order: source
- show_signature_annotations: true
- separate_signature: true
-
-## 工具类使用指南
-
-### 缓存装饰器
-
-#### 基本缓存
-
-```python
-from qka.utils.tools import cache
-
-# 简单缓存(内存)
-@cache()
-def expensive_function(x, y):
- # 模拟耗时计算
- import time
- time.sleep(2)
- return x + y
-
-# 第一次调用需要2秒
-result1 = expensive_function(1, 2) # 耗时:2秒
-
-# 第二次调用直接返回缓存结果
-result2 = expensive_function(1, 2) # 耗时:几乎为0
-```
-
-#### 带TTL的缓存
-
-```python
-# 缓存有效期为5分钟
-@cache(ttl=300)
-def get_stock_price(symbol):
- # 模拟API调用
- return fetch_price_from_api(symbol)
-
-# 5分钟内重复调用返回缓存结果
-# 5分钟后会重新调用API
-price = get_stock_price('AAPL')
-```
-
-#### 文件缓存
-
-```python
-# 使用文件缓存(持久化)
-@cache(cache_type='file', cache_dir='cache')
-def process_large_dataset(file_path):
- # 处理大型数据集
- return expensive_data_processing(file_path)
-
-# 结果会保存到文件,程序重启后仍然有效
-result = process_large_dataset('data/large_file.csv')
-```
-
-#### Redis缓存
-
-```python
-# 使用Redis缓存(分布式)
-@cache(cache_type='redis', redis_url='redis://localhost:6379/0')
-def get_user_profile(user_id):
- return fetch_user_from_database(user_id)
-
-# 多个进程/服务器可以共享缓存
-profile = get_user_profile(12345)
-```
-
-### 计时装饰器
-
-#### 函数计时
-
-```python
-from qka.utils.tools import timeit
-
-# 简单计时
-@timeit
-def data_processing():
- # 数据处理逻辑
- pass
-
-# 执行后会打印执行时间
-data_processing() # 输出: data_processing 执行时间: 1.23秒
-```
-
-#### 详细计时信息
-
-```python
-# 详细计时信息
-@timeit(detailed=True)
-def complex_calculation(n):
- result = 0
- for i in range(n):
- result += i * i
- return result
-
-# 输出更详细的时间信息
-result = complex_calculation(1000000)
-# 输出: complex_calculation(n=1000000) 执行时间: 0.15秒, 内存使用: +2.3MB
-```
-
-#### 性能监控
-
-```python
-# 性能监控和统计
-@timeit(monitor=True, threshold=1.0)
-def api_call(endpoint):
- # API调用
- return make_request(endpoint)
-
-# 如果执行时间超过阈值,会记录警告
-# 同时收集性能统计数据
-api_call('/api/data')
-
-# 获取性能统计
-stats = timeit.get_statistics()
-print(f"平均执行时间: {stats['avg_time']}")
-print(f"最大执行时间: {stats['max_time']}")
-```
-
-### 重试装饰器
-
-#### 基本重试
-
-```python
-from qka.utils.tools import retry
-
-# 最多重试3次
-@retry(max_attempts=3)
-def unstable_api_call():
- # 可能失败的API调用
- response = requests.get('https://api.example.com/data')
- response.raise_for_status()
- return response.json()
-
-# 如果失败会自动重试
-data = unstable_api_call()
-```
-
-#### 指定异常类型和重试间隔
-
-```python
-import requests
-
-# 只对特定异常重试,指定重试间隔
-@retry(
- max_attempts=5,
- exceptions=(requests.RequestException, ConnectionError),
- delay=1.0,
- backoff=2.0
-)
-def robust_api_call():
- return requests.get('https://api.example.com/data').json()
-
-# 重试间隔:1秒、2秒、4秒、8秒
-data = robust_api_call()
-```
-
-#### 自定义重试条件
-
-```python
-# 自定义重试条件
-def should_retry(exception):
- if isinstance(exception, requests.HTTPError):
- return exception.response.status_code >= 500
- return True
-
-@retry(max_attempts=3, should_retry=should_retry)
-def smart_api_call():
- response = requests.get('https://api.example.com/data')
- response.raise_for_status()
- return response.json()
-```
-
-### 文件操作工具
-
-#### 基本文件操作
-
-```python
-from qka.utils.tools import FileHelper
-
-helper = FileHelper()
-
-# 确保目录存在
-helper.ensure_dir('logs')
-helper.ensure_dir('data/processed')
-
-# 安全写入文件(原子操作)
-data = {'key': 'value'}
-helper.safe_write('config.json', data)
-
-# 安全读取文件
-config = helper.safe_read('config.json')
-
-# 备份文件
-helper.backup_file('important.txt')
-```
-
-#### 文件监控
-
-```python
-# 监控文件变化
-def on_file_change(file_path):
- print(f"文件 {file_path} 已更改")
-
-helper.watch_file('config.json', on_file_change)
-
-# 监控目录变化
-def on_dir_change(event_type, file_path):
- print(f"目录事件: {event_type} - {file_path}")
-
-helper.watch_directory('data', on_dir_change)
-```
-
-#### 文件压缩和解压
-
-```python
-# 压缩文件
-helper.compress_file('large_file.txt', 'compressed.gz')
-
-# 压缩目录
-helper.compress_directory('logs', 'logs_backup.tar.gz')
-
-# 解压文件
-helper.extract_file('backup.tar.gz', 'restore_dir')
-```
-
-### 格式化工具
-
-#### 数据格式化
-
-```python
-from qka.utils.tools import FormatHelper
-
-formatter = FormatHelper()
-
-# 格式化数字
-formatted = formatter.format_number(1234567.89)
-print(formatted) # 1,234,567.89
-
-# 格式化百分比
-percentage = formatter.format_percentage(0.1234)
-print(percentage) # 12.34%
-
-# 格式化文件大小
-size = formatter.format_size(1024*1024*1.5)
-print(size) # 1.5 MB
-
-# 格式化时间段
-duration = formatter.format_duration(3661)
-print(duration) # 1小时1分1秒
-```
-
-#### 货币格式化
-
-```python
-# 格式化货币
-price = formatter.format_currency(1234.56, currency='USD')
-print(price) # $1,234.56
-
-price_cny = formatter.format_currency(8888.88, currency='CNY')
-print(price_cny) # ¥8,888.88
-```
-
-#### 日期时间格式化
-
-```python
-from datetime import datetime
-
-now = datetime.now()
-
-# 不同格式的日期时间
-print(formatter.format_datetime(now, 'full')) # 2024年1月15日 星期一 14:30:25
-print(formatter.format_datetime(now, 'date')) # 2024-01-15
-print(formatter.format_datetime(now, 'time')) # 14:30:25
-print(formatter.format_datetime(now, 'relative')) # 刚刚
-```
-
-### 数据验证工具
-
-#### 基本验证
-
-```python
-from qka.utils.tools import ValidationHelper
-
-validator = ValidationHelper()
-
-# 验证邮箱
-is_valid = validator.validate_email('user@example.com')
-print(is_valid) # True
-
-# 验证手机号
-is_valid = validator.validate_phone('13812345678')
-print(is_valid) # True
-
-# 验证身份证号
-is_valid = validator.validate_id_card('110101199001011234')
-print(is_valid) # False (示例号码)
-```
-
-#### 数据结构验证
-
-```python
-# 验证字典结构
-schema = {
- 'name': {'type': str, 'required': True},
- 'age': {'type': int, 'min': 0, 'max': 150},
- 'email': {'type': str, 'validator': validator.validate_email}
-}
-
-data = {
- 'name': 'John Doe',
- 'age': 30,
- 'email': 'john@example.com'
-}
-
-is_valid, errors = validator.validate_dict(data, schema)
-if not is_valid:
- print("验证失败:", errors)
-```
-
-#### 自定义验证器
-
-```python
-# 自定义验证函数
-def validate_stock_symbol(symbol):
- return isinstance(symbol, str) and symbol.isupper() and len(symbol) <= 6
-
-# 注册自定义验证器
-validator.register_validator('stock_symbol', validate_stock_symbol)
-
-# 使用自定义验证器
-is_valid = validator.validate('AAPL', 'stock_symbol')
-print(is_valid) # True
-```
-
-### 配置管理工具
-
-#### 环境配置
-
-```python
-from qka.utils.tools import ConfigHelper
-
-config = ConfigHelper()
-
-# 获取环境变量(带默认值)
-debug_mode = config.get_env('DEBUG', default=False, cast=bool)
-api_timeout = config.get_env('API_TIMEOUT', default=30, cast=int)
-
-# 检查必需的环境变量
-required_vars = ['DATABASE_URL', 'SECRET_KEY']
-missing = config.check_required_env(required_vars)
-if missing:
- raise ValueError(f"缺少必需的环境变量: {missing}")
-```
-
-#### 配置合并
-
-```python
-# 合并多个配置源
-default_config = {'host': 'localhost', 'port': 8000, 'debug': False}
-user_config = {'port': 9000, 'debug': True}
-env_config = config.from_env_prefix('APP_')
-
-final_config = config.merge_configs(default_config, user_config, env_config)
-print(final_config) # {'host': 'localhost', 'port': 9000, 'debug': True}
-```
-
-## 组合使用示例
-
-### 完整的数据处理流水线
-
-```python
-from qka.utils.tools import cache, timeit, retry, FileHelper, FormatHelper
-
-# 组合多个装饰器
-@cache(ttl=3600) # 缓存1小时
-@timeit(detailed=True) # 详细计时
-@retry(max_attempts=3) # 最多重试3次
-def process_market_data(symbol, date):
- """处理市场数据的完整流水线"""
-
- # 下载数据
- raw_data = download_data(symbol, date)
-
- # 数据清洗
- cleaned_data = clean_data(raw_data)
-
- # 数据分析
- analysis_result = analyze_data(cleaned_data)
-
- # 保存结果
- helper = FileHelper()
- formatter = FormatHelper()
-
- output_file = f"analysis_{symbol}_{formatter.format_date(date)}.json"
- helper.safe_write(output_file, analysis_result)
-
- return analysis_result
-
-# 使用
-result = process_market_data('AAPL', '2024-01-15')
-```
-
-### 批量数据处理
-
-```python
-import concurrent.futures
-from qka.utils.tools import timeit, cache
-
-@cache(cache_type='redis')
-def get_stock_data(symbol):
- return fetch_stock_data(symbol)
-
-@timeit
-def process_portfolio(symbols):
- """并行处理投资组合数据"""
-
- with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
- # 并行获取数据
- future_to_symbol = {
- executor.submit(get_stock_data, symbol): symbol
- for symbol in symbols
- }
-
- results = {}
- for future in concurrent.futures.as_completed(future_to_symbol):
- symbol = future_to_symbol[future]
- try:
- data = future.result()
- results[symbol] = data
- except Exception as exc:
- print(f'{symbol} 处理失败: {exc}')
-
- return results
-
-# 处理大型投资组合
-portfolio = ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA'] * 20
-results = process_portfolio(portfolio)
-```
-
-## 最佳实践
-
-1. **缓存策略**
- - 选择合适的缓存类型和TTL
- - 注意缓存一致性问题
- - 监控缓存命中率
-
-2. **性能监控**
- - 对关键函数使用计时装饰器
- - 设置合理的性能阈值
- - 定期分析性能数据
-
-3. **错误处理**
- - 合理设置重试策略
- - 记录重试和失败信息
- - 区分可重试和不可重试的错误
-
-4. **文件操作**
- - 使用原子操作确保数据一致性
- - 定期备份重要文件
- - 监控磁盘空间使用
diff --git a/docs/enhanced_features_phase1.md b/docs/enhanced_features_phase1.md
deleted file mode 100644
index a8b57e0..0000000
--- a/docs/enhanced_features_phase1.md
+++ /dev/null
@@ -1,472 +0,0 @@
-# QKA 增强功能文档 - 阶段1
-
-## 概述
-
-QKA 阶段1增强功能主要包括四个核心模块:
-- 📋 **配置管理系统** - 统一的配置管理
-- 📡 **事件驱动框架** - 发布-订阅模式的事件系统
-- 📝 **增强日志系统** - 结构化和彩色日志
-- 🛠️ **基础工具类** - 通用工具函数和装饰器
-
----
-
-## 📋 配置管理系统
-
-### 快速开始
-
-```python
-import qka
-from qka.core.config import load_config, create_sample_config
-
-# 创建示例配置文件
-create_sample_config('my_config.json')
-
-# 加载配置
-config = load_config('my_config.json')
-
-# 使用配置
-print(f"初始资金: {qka.config.backtest.initial_cash:,}")
-print(f"数据源: {qka.config.data.default_source}")
-```
-
-### 配置结构
-
-#### BacktestConfig - 回测配置
-```python
-config.backtest.initial_cash = 1_000_000 # 初始资金
-config.backtest.commission_rate = 0.0003 # 手续费率
-config.backtest.slippage = 0.001 # 滑点率
-config.backtest.min_trade_amount = 100 # 最小交易股数
-config.backtest.max_position_ratio = 0.3 # 单只股票最大仓位比例
-config.backtest.benchmark = '000300.SH' # 基准指数
-```
-
-#### DataConfig - 数据配置
-```python
-config.data.default_source = 'akshare' # 默认数据源
-config.data.cache_enabled = True # 是否启用缓存
-config.data.cache_dir = './data_cache' # 缓存目录
-config.data.cache_expire_days = 7 # 缓存过期天数
-config.data.quality_check = True # 是否进行数据质量检查
-config.data.auto_download = True # 是否自动下载缺失数据
-```
-
-#### TradingConfig - 交易配置
-```python
-config.trading.server_host = '0.0.0.0' # 服务器地址
-config.trading.server_port = 8000 # 服务器端口
-config.trading.token_auto_generate = True # 自动生成token
-config.trading.order_timeout = 30 # 订单超时时间(秒)
-config.trading.max_retry_times = 3 # 最大重试次数
-config.trading.heartbeat_interval = 30 # 心跳间隔(秒)
-```
-
-### 环境变量支持
-
-```bash
-# 设置环境变量
-export QKA_INITIAL_CASH=2000000
-export QKA_DATA_SOURCE=qmt
-export QKA_SERVER_PORT=9000
-```
-
-### 配置文件示例
-
-```json
-{
- "backtest": {
- "initial_cash": 1000000,
- "commission_rate": 0.0003,
- "slippage": 0.001
- },
- "data": {
- "default_source": "akshare",
- "cache_enabled": true,
- "cache_dir": "./data_cache"
- },
- "trading": {
- "server_host": "0.0.0.0",
- "server_port": 8000
- }
-}
-```
-
----
-
-## 📡 事件驱动框架
-
-### 快速开始
-
-```python
-from qka.core.events import EventType, event_handler, emit_event, start_event_engine
-
-# 启动事件引擎
-start_event_engine()
-
-# 定义事件处理器
-@event_handler(EventType.DATA_LOADED)
-def on_data_loaded(event):
- print(f"数据加载完成: {event.data}")
-
-# 发送事件
-emit_event(EventType.DATA_LOADED, {"symbol": "000001.SZ", "count": 1000})
-```
-
-### 事件类型
-
-#### 数据相关事件
-- `DATA_LOADED` - 数据加载完成
-- `DATA_ERROR` - 数据加载错误
-
-#### 回测相关事件
-- `BACKTEST_START` - 回测开始
-- `BACKTEST_END` - 回测结束
-- `BACKTEST_ERROR` - 回测错误
-
-#### 交易相关事件
-- `ORDER_CREATED` - 订单创建
-- `ORDER_FILLED` - 订单成交
-- `ORDER_CANCELLED` - 订单取消
-- `ORDER_ERROR` - 订单错误
-
-#### 策略相关事件
-- `STRATEGY_START` - 策略开始
-- `STRATEGY_END` - 策略结束
-- `SIGNAL_GENERATED` - 信号生成
-
-### 自定义事件处理器
-
-```python
-from qka.core.events import EventHandler, Event
-
-class MyEventHandler(EventHandler):
- def handle(self, event: Event):
- if event.event_type == EventType.ORDER_FILLED:
- print(f"处理订单成交事件: {event.data}")
-
- def can_handle(self, event: Event) -> bool:
- return event.event_type == EventType.ORDER_FILLED
-
-# 注册处理器
-handler = MyEventHandler()
-event_engine.subscribe(EventType.ORDER_FILLED, handler)
-```
-
-### 事件统计
-
-```python
-# 获取事件统计信息
-stats = event_engine.get_statistics()
-print(f"事件计数: {stats['event_count']}")
-print(f"错误计数: {stats['error_count']}")
-print(f"队列大小: {stats['queue_size']}")
-```
-
----
-
-## 📝 增强日志系统
-
-### 快速开始
-
-```python
-from qka.utils.logger import create_logger, get_structured_logger
-
-# 创建彩色日志记录器
-logger = create_logger('my_app', colored_console=True)
-
-logger.debug("这是调试信息")
-logger.info("这是普通信息")
-logger.warning("这是警告信息")
-logger.error("这是错误信息")
-```
-
-### 结构化日志
-
-```python
-# 创建结构化日志记录器
-struct_logger = get_structured_logger('my_app')
-
-# 记录结构化日志
-struct_logger.info("用户登录",
- user_id=12345,
- ip="192.168.1.100",
- action="login")
-
-struct_logger.error("交易失败",
- symbol="000001.SZ",
- reason="余额不足",
- amount=10000)
-```
-
-### 日志配置选项
-
-```python
-logger = create_logger(
- name='my_app', # 日志记录器名称
- level='INFO', # 日志级别
- console_output=True, # 是否输出到控制台
- file_output=True, # 是否输出到文件
- log_dir='logs', # 日志文件目录
- max_file_size='10MB', # 最大文件大小
- backup_count=10, # 备份文件数量
- json_format=False, # 是否使用JSON格式
- colored_console=True # 控制台是否使用颜色
-)
-```
-
-### 微信通知
-
-```python
-from qka.utils.logger import add_wechat_handler
-
-# 添加微信通知处理器
-webhook_url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
-add_wechat_handler(logger, webhook_url, level='ERROR')
-
-# 现在ERROR级别的日志会发送到微信
-logger.error("这条错误信息会发送到微信群")
-```
-
----
-
-## 🛠️ 基础工具类
-
-### 缓存工具
-
-```python
-from qka.utils.tools import Cache
-
-# 创建缓存
-cache = Cache(max_size=1000, ttl=3600) # 最大1000条,1小时过期
-
-# 使用缓存
-cache.set('key1', 'value1')
-value = cache.get('key1')
-print(f"缓存大小: {cache.size()}")
-```
-
-### 计时器工具
-
-```python
-from qka.utils.tools import Timer, timer
-
-# 使用上下文管理器
-with Timer() as t:
- # 一些耗时操作
- time.sleep(1)
-print(f"耗时: {t.elapsed():.3f}秒")
-
-# 使用装饰器
-@timer
-def slow_function():
- time.sleep(1)
- return "完成"
-
-result = slow_function() # 自动打印执行时间
-```
-
-### 重试装饰器
-
-```python
-from qka.utils.tools import retry
-
-@retry(max_attempts=3, delay=1.0, backoff=2.0)
-def unreliable_function():
- # 可能失败的函数
- import random
- if random.random() < 0.7:
- raise Exception("随机失败")
- return "成功"
-
-result = unreliable_function() # 自动重试
-```
-
-### 记忆化装饰器
-
-```python
-from qka.utils.tools import memoize
-
-@memoize(ttl=300) # 缓存5分钟
-def expensive_calculation(x, y):
- time.sleep(1) # 模拟耗时计算
- return x * y
-
-result1 = expensive_calculation(10, 20) # 耗时1秒
-result2 = expensive_calculation(10, 20) # 从缓存返回,瞬间完成
-```
-
-### 文件工具
-
-```python
-from qka.utils.tools import FileUtils
-
-# JSON文件操作
-data = {"key": "value"}
-FileUtils.save_json(data, "data.json")
-loaded_data = FileUtils.load_json("data.json")
-
-# Pickle文件操作
-FileUtils.save_pickle(data, "data.pkl")
-loaded_data = FileUtils.load_pickle("data.pkl")
-
-# 文件信息
-size = FileUtils.get_file_size("data.json")
-mtime = FileUtils.get_file_mtime("data.json")
-```
-
-### 格式化工具
-
-```python
-from qka.utils.tools import format_number, format_percentage, format_currency
-
-print(format_number(1234567.89)) # 1,234,567.89
-print(format_percentage(0.1234)) # 12.34%
-print(format_currency(123456.78)) # ¥123,456.78
-```
-
-### 验证工具
-
-```python
-from qka.utils.tools import ValidationUtils
-
-# 验证股票代码
-is_valid = ValidationUtils.is_valid_symbol("000001.SZ") # True
-is_valid = ValidationUtils.is_valid_symbol("AAPL") # False
-
-# 验证正数
-is_positive = ValidationUtils.is_positive_number(100) # True
-is_positive = ValidationUtils.is_positive_number(-10) # False
-
-# 验证日期范围
-is_valid_range = ValidationUtils.is_valid_date_range("2023-01-01", "2023-12-31") # True
-```
-
----
-
-## 🚀 集成使用示例
-
-### 增强的策略类
-
-```python
-from qka.core.backtest import Strategy
-from qka.core.events import EventType, emit_event
-from qka.utils.logger import create_logger
-from qka.utils.tools import timer
-
-class EnhancedStrategy(Strategy):
- def __init__(self):
- super().__init__()
- self.logger = create_logger('strategy')
-
- def on_start(self, broker):
- self.logger.info(f"策略启动: {self.name}")
- emit_event(EventType.STRATEGY_START, {"strategy": self.name})
-
- @timer
- def on_bar(self, data, broker, current_date):
- # 策略逻辑
- for symbol, df in data.items():
- if len(df) >= 20:
- current_price = df['close'].iloc[-1]
- ma20 = df['close'].rolling(20).mean().iloc[-1]
-
- if current_price > ma20:
- emit_event(EventType.SIGNAL_GENERATED, {
- "symbol": symbol,
- "signal": "BUY",
- "price": current_price
- })
- broker.buy(symbol, 0.3, current_price)
-
- def on_end(self, broker):
- self.logger.info(f"策略结束: {self.name}")
- emit_event(EventType.STRATEGY_END, {"strategy": self.name})
-```
-
-### 完整使用流程
-
-```python
-import qka
-from qka.core.config import load_config
-from qka.core.events import start_event_engine, stop_event_engine
-
-# 1. 加载配置
-config = load_config('my_config.json')
-
-# 2. 启动事件系统
-start_event_engine()
-
-# 3. 获取数据
-data_obj = qka.data(config.data.default_source, stocks=['000001', '000002'])
-
-# 4. 运行回测
-result = qka.backtest(
- data=data_obj,
- strategy=EnhancedStrategy(),
- start_time='2023-01-01',
- end_time='2023-12-31'
-)
-
-# 5. 查看结果
-print(f"总收益率: {result['total_return']:.2%}")
-
-# 6. 清理
-stop_event_engine()
-```
-
----
-
-## 📚 API 参考
-
-### 配置管理 API
-
-| 函数/类 | 说明 |
-|---------|------|
-| `Config()` | 配置管理器类 |
-| `load_config(file_path)` | 加载配置文件 |
-| `create_sample_config(file_path)` | 创建示例配置 |
-| `config.get(section, key, default)` | 获取配置值 |
-| `config.set(section, key, value)` | 设置配置值 |
-
-### 事件系统 API
-
-| 函数/类 | 说明 |
-|---------|------|
-| `start_event_engine()` | 启动事件引擎 |
-| `stop_event_engine()` | 停止事件引擎 |
-| `emit_event(event_type, data)` | 发送事件 |
-| `@event_handler(event_type)` | 事件处理器装饰器 |
-| `event_engine.get_statistics()` | 获取事件统计 |
-
-### 日志系统 API
-
-| 函数/类 | 说明 |
-|---------|------|
-| `create_logger(name, **options)` | 创建日志记录器 |
-| `get_structured_logger(name)` | 创建结构化日志记录器 |
-| `add_wechat_handler(logger, webhook_url)` | 添加微信通知 |
-
-### 工具类 API
-
-| 函数/类 | 说明 |
-|---------|------|
-| `Cache(max_size, ttl)` | 内存缓存类 |
-| `Timer()` | 计时器类 |
-| `@timer` | 计时装饰器 |
-| `@retry(max_attempts, delay)` | 重试装饰器 |
-| `@memoize(ttl)` | 记忆化装饰器 |
-| `FileUtils` | 文件操作工具类 |
-| `ValidationUtils` | 验证工具类 |
-
----
-
-## 🔄 下一阶段预告
-
-**阶段2:数据层增强**
-- 数据缓存机制
-- 数据质量检查和清洗
-- 增量数据更新
-- 多频率数据支持
-- 数据订阅管理器
-
-敬请期待! 🎉
diff --git a/docs/examples/index.md b/docs/examples/index.md
deleted file mode 100644
index 62b1169..0000000
--- a/docs/examples/index.md
+++ /dev/null
@@ -1,143 +0,0 @@
-# 示例和教程
-
-QKA量化回测系统的实用示例和完整教程。
-
-## 快速入门示例
-
-### [基础示例](basic/index.md)
-- [第一个策略](basic/first-strategy.md) - 创建你的第一个交易策略
-- [数据获取](basic/data-fetching.md) - 学习如何获取和处理市场数据
-- [简单回测](basic/simple-backtest.md) - 运行基本的策略回测
-
-### [进阶示例](advanced/index.md)
-- [事件驱动策略](advanced/event-driven.md) - 使用事件系统的高级策略
-- [多资产策略](advanced/multi-asset.md) - 跨资产类别的投资策略
-- [风险管理](advanced/risk-management.md) - 集成风险控制的策略
-
-### [完整案例](complete/index.md)
-- [动量策略](complete/momentum-strategy.md) - 完整的动量交易策略
-- [均值回归策略](complete/mean-reversion.md) - 均值回归策略实现
-- [配对交易](complete/pairs-trading.md) - 统计套利策略
-
-## 实际应用
-
-### [实盘交易](live-trading/index.md)
-- [环境配置](live-trading/setup.md) - 实盘交易环境搭建
-- [风险控制](live-trading/risk-control.md) - 实盘风险管理
-- [监控告警](live-trading/monitoring.md) - 交易监控和告警
-
-### [性能优化](optimization/index.md)
-- [策略优化](optimization/strategy-optimization.md) - 策略参数优化
-- [性能调优](optimization/performance-tuning.md) - 系统性能优化
-- [并行计算](optimization/parallel-computing.md) - 使用并行计算加速回测
-
-### [集成案例](integration/index.md)
-- [数据源集成](integration/data-sources.md) - 集成多种数据源
-- [交易接口](integration/broker-apis.md) - 连接不同的交易平台
-- [外部工具](integration/external-tools.md) - 与其他工具的集成
-
-## 代码片段
-
-### 常用模式
-
-```python
-# 策略模板
-from qka.core import Strategy, EventBus
-from qka.utils import Logger
-
-class MyStrategy(Strategy):
- def __init__(self):
- super().__init__()
- self.logger = Logger()
-
- def on_market_data(self, event):
- # 处理市场数据
- pass
-
- def on_signal(self, signal):
- # 处理交易信号
- pass
-```
-
-### 工具使用
-
-```python
-# 配置管理
-from qka.core import Config
-
-config = Config()
-config.load_from_file('config.yaml')
-
-# 日志记录
-from qka.utils import Logger
-
-logger = Logger()
-logger.info("策略启动")
-
-# 缓存装饰器
-from qka.utils.tools import cache
-
-@cache(ttl=300)
-def expensive_calculation():
- return result
-```
-
-## 学习路径
-
-### 初学者路径
-1. [安装和配置](../getting-started/installation.md)
-2. [基础概念](../getting-started/concepts.md)
-3. [第一个策略](../getting-started/first-strategy.md)
-4. [基础示例](basic/index.md)
-
-### 进阶路径
-1. [进阶示例](advanced/index.md)
-2. [系统架构](../user-guide/architecture.md)
-3. [性能优化](optimization/index.md)
-4. [完整案例](complete/index.md)
-
-### 专家路径
-1. [源码分析](../development/source-analysis.md)
-2. [扩展开发](../development/extensions.md)
-3. [集成案例](integration/index.md)
-4. [贡献指南](../development/contributing.md)
-
-## 常见问题
-
-### 策略开发
-- **Q: 如何处理数据缺失?**
- A: 使用数据验证和填充机制,参考[数据处理示例](basic/data-processing.md)
-
-- **Q: 如何优化策略性能?**
- A: 查看[性能优化指南](optimization/performance-tuning.md)
-
-### 回测分析
-- **Q: 如何设置回测参数?**
- A: 参考[回测配置示例](basic/backtest-config.md)
-
-- **Q: 如何分析回测结果?**
- A: 查看[结果分析教程](basic/result-analysis.md)
-
-### 实盘交易
-- **Q: 如何配置交易接口?**
- A: 参考[交易接口配置](live-trading/broker-setup.md)
-
-- **Q: 如何监控策略运行?**
- A: 查看[监控配置指南](live-trading/monitoring.md)
-
-## 贡献示例
-
-我们欢迎社区贡献更多示例:
-
-1. Fork 项目仓库
-2. 在 `examples/` 目录下添加示例
-3. 在 `docs/examples/` 下添加对应文档
-4. 提交 Pull Request
-
-### 示例规范
-- 代码要有详细注释
-- 包含完整的运行说明
-- 提供示例数据
-- 说明预期结果
-
-更多信息请查看[贡献指南](../development/contributing.md)。
diff --git a/docs/getting-started/concepts.md b/docs/getting-started/concepts.md
index b3ee887..38a59d6 100644
--- a/docs/getting-started/concepts.md
+++ b/docs/getting-started/concepts.md
@@ -1,349 +1,199 @@
-# 基础概念
-
-在开始使用 QKA 之前,了解一些基础概念将帮助您更好地理解和使用这个框架。
-
-## 核心概念
-
-### 策略 (Strategy)
-
-策略是量化交易的核心,定义了买卖股票的逻辑规则。
-
-```python
-from qka.core.backtest import Strategy
-
-class MyStrategy(Strategy):
- def on_data(self, data):
- # 在这里实现您的交易逻辑
- pass
-```
-
-**关键特点**:
-- 策略继承自 `Strategy` 基类
-- 通过重写回调方法实现交易逻辑
-- 支持参数化配置
-
-### 回测引擎 (Backtest Engine)
-
-回测引擎模拟历史交易环境,验证策略的有效性。
-
-```python
-from qka.core.backtest import BacktestEngine
-
-engine = BacktestEngine(
- initial_cash=1000000, # 初始资金
- start_date='2023-01-01', # 开始日期
- end_date='2023-12-31', # 结束日期
- commission_rate=0.0003 # 手续费率
-)
-```
-
-**主要功能**:
-- 模拟真实的交易环境
-- 计算手续费和滑点
-- 生成详细的交易记录
-- 计算各种性能指标
-
-### 数据源 (Data Source)
-
-数据源提供股票的历史和实时价格数据。
-
-```python
-from qka.core.data import get_stock_data
-
-# 获取股票数据
-data = get_stock_data('000001.SZ', start='2023-01-01', end='2023-12-31')
-```
-
-**支持的数据源**:
-- **AkShare**: 免费的A股数据接口
-- **Tushare**: 专业的金融数据接口
-- **QMT**: 迅投QMT交易软件数据
-- **Wind**: 万得金融数据库
-
-### 交易客户端 (Trading Client)
-
-交易客户端连接券商接口,执行实际的买卖操作。
-
-```python
-from qka.brokers import QMTClient
-
-client = TradingClient()
-client.connect() # 连接券商
-
-# 下单买入
-order = client.place_order(
- symbol='000001.SZ',
- side='BUY',
- volume=100,
- price=15.50
-)
-```
-
-## 数据结构
-
-### 股票代码格式
-
-QKA 使用标准的股票代码格式:
-
-| 交易所 | 代码格式 | 示例 | 说明 |
-|--------|----------|------|------|
-| 深交所 | XXXXXX.SZ | 000001.SZ | 平安银行 |
-| 上交所 | XXXXXX.SH | 600000.SH | 浦发银行 |
-| 科创板 | 688XXX.SH | 688001.SH | 华兴源创 |
-| 创业板 | 300XXX.SZ | 300001.SZ | 特锐德 |
-
-### 价格数据格式
-
-标准的 OHLCV 格式:
-
-```python
-# 数据示例
-{
- 'open': 15.20, # 开盘价
- 'high': 15.80, # 最高价
- 'low': 15.10, # 最低价
- 'close': 15.50, # 收盘价
- 'volume': 1000000, # 成交量
- 'amount': 15500000 # 成交额
-}
-```
-
-### 订单状态
-
-| 状态 | 说明 |
-|------|------|
-| `PENDING` | 待提交 |
-| `SUBMITTED` | 已提交 |
-| `FILLED` | 已成交 |
-| `PARTIAL_FILLED` | 部分成交 |
-| `CANCELLED` | 已撤销 |
-| `REJECTED` | 已拒绝 |
-
-## 交易流程
-
-### 1. 策略开发流程
-
-```mermaid
-graph TD
- A[策略想法] --> B[编写策略代码]
- B --> C[历史数据回测]
- C --> D{回测结果满意?}
- D -->|否| E[优化策略参数]
- E --> C
- D -->|是| F[模拟交易验证]
- F --> G[实盘小资金测试]
- G --> H[正式实盘交易]
-```
-
-### 2. 回测流程
-
-```mermaid
-graph LR
- A[准备数据] --> B[配置回测引擎]
- B --> C[加载策略]
- C --> D[运行回测]
- D --> E[分析结果]
- E --> F[生成报告]
-```
-
-### 3. 实盘交易流程
-
-```mermaid
-graph TD
- A[连接券商] --> B[订阅实时数据]
- B --> C[策略计算信号]
- C --> D[风险检查]
- D --> E[提交订单]
- E --> F[监控执行]
- F --> G[记录交易]
-```
-
-## 性能指标
-
-### 收益率指标
-
-- **总收益率**: 投资期间的总收益百分比
-- **年化收益率**: 年化后的收益率
-- **基准收益率**: 相对于基准指数的收益率
-
-```python
-total_return = (final_value - initial_value) / initial_value
-annual_return = (1 + total_return) ** (365 / trading_days) - 1
-```
-
-### 风险指标
-
-- **波动率**: 收益率的标准差,衡量收益的不确定性
-- **最大回撤**: 从峰值到谷值的最大跌幅
-- **VaR**: 在一定置信水平下的潜在损失
-
-```python
-volatility = returns.std() * np.sqrt(252) # 年化波动率
-max_drawdown = (peak_value - valley_value) / peak_value
-```
-
-### 风险调整收益指标
-
-- **夏普比率**: 超额收益与波动率的比值
-- **索提诺比率**: 超额收益与下行风险的比值
-- **卡尔马比率**: 年化收益率与最大回撤的比值
-
-```python
-sharpe_ratio = (annual_return - risk_free_rate) / volatility
-sortino_ratio = (annual_return - risk_free_rate) / downside_deviation
-calmar_ratio = annual_return / max_drawdown
-```
-
-## 风险管理
-
-### 仓位管理
-
-控制单个股票和总体的仓位大小:
-
-```python
-# 单股最大仓位不超过10%
-max_position_ratio = 0.1
-position_value = volume * price
-max_volume = (total_value * max_position_ratio) / price
-
-# 总仓位不超过90%
-total_position_ratio = total_position_value / total_value
-if total_position_ratio > 0.9:
- # 减仓操作
- pass
-```
-
-### 止损止盈
-
-设置合理的止损止盈点:
-
-```python
-def check_stop_loss_take_profit(position, current_price):
- cost_price = position.avg_price
- return_rate = (current_price - cost_price) / cost_price
-
- # 止损:亏损超过5%
- if return_rate <= -0.05:
- return 'STOP_LOSS'
-
- # 止盈:盈利超过15%
- elif return_rate >= 0.15:
- return 'TAKE_PROFIT'
-
- return 'HOLD'
-```
-
-### 风险分散
-
-- **行业分散**: 不要集中投资单一行业
-- **时间分散**: 分批建仓,避免一次性投入
-- **策略分散**: 使用多种不同类型的策略
-
-## 常用交易策略类型
-
-### 趋势跟踪策略
-
-基于价格趋势进行交易:
-
-- **移动平均线策略**: 基于不同周期均线的交叉
-- **突破策略**: 基于价格突破重要阻力或支撑
-- **动量策略**: 基于价格动量指标
-
-### 均值回归策略
-
-基于价格会回归均值的假设:
-
-- **布林带策略**: 价格触及上下轨时交易
-- **RSI策略**: 基于相对强弱指标的超买超卖
-- **配对交易**: 利用相关股票的价格差异
-
-### 套利策略
-
-利用价格差异获得无风险收益:
-
-- **统计套利**: 基于统计关系的套利
-- **事件驱动**: 基于公司事件的套利
-- **跨市场套利**: 利用不同市场的价差
-
-## 开发工具和环境
-
-### 推荐开发环境
-
-- **IDE**: VS Code、PyCharm、Jupyter Notebook
-- **Python版本**: 3.8 或更高
-- **依赖管理**: uv、pip、conda
-
-### 版本控制
-
-```bash
-# 初始化Git仓库
-git init
-git add .
-git commit -m "初始化量化策略项目"
-
-# 创建分支
-git checkout -b feature/new-strategy
-```
-
-### 项目结构
-
-推荐的项目目录结构:
-
-```
-my_quant_project/
-├── strategies/ # 策略代码
-│ ├── __init__.py
-│ ├── ma_strategy.py
-│ └── bollinger_strategy.py
-├── data/ # 数据文件
-│ ├── stocks/
-│ └── index/
-├── backtest/ # 回测结果
-│ ├── reports/
-│ └── logs/
-├── config/ # 配置文件
-│ ├── development.json
-│ └── production.json
-├── tests/ # 测试代码
-│ └── test_strategies.py
-├── requirements.txt # 依赖列表
-└── README.md # 项目说明
-```
-
-## 学习路径
-
-### 新手入门
-
-1. **理解基本概念** ← 您在这里
-2. **完成第一个策略** → [第一个策略](first-strategy.md)
-3. **学习数据获取** → [数据获取](../user-guide/data.md)
-4. **掌握回测分析** → [回测分析](../user-guide/backtest.md)
-
-### 进阶学习
-
-5. **策略优化技巧** → [策略开发](../user-guide/strategy.md)
-6. **风险管理实践** → [风险管理](../examples/risk-management.md)
-7. **实盘交易部署** → [实盘交易](../user-guide/trading.md)
-
-### 高级应用
-
-8. **多因子策略** → [多因子策略](../examples/multi-factor.md)
-9. **机器学习集成** → [高级示例](../examples/indicators.md)
-10. **系统架构设计** → [架构设计](../development/architecture.md)
-
-## 常见术语
-
-| 术语 | 英文 | 说明 |
-|------|------|------|
-| 多头 | Long | 买入并持有股票的仓位 |
-| 空头 | Short | 卖出股票的仓位(A股不支持做空) |
-| 开仓 | Open Position | 建立新的交易仓位 |
-| 平仓 | Close Position | 了结现有的交易仓位 |
-| 滑点 | Slippage | 实际成交价与预期价格的差异 |
-| 回撤 | Drawdown | 从峰值到谷值的损失 |
-| 基准 | Benchmark | 用于比较策略表现的指数 |
-| 因子 | Factor | 影响股票收益的特征变量 |
-| 阿尔法 | Alpha | 策略相对于基准的超额收益 |
-| 贝塔 | Beta | 策略相对于市场的敏感度 |
-
-现在您已经了解了 QKA 的基础概念,可以开始 [创建您的第一个策略](first-strategy.md) 了!
+# 基础概念
+
+了解 QKA 的核心概念和架构设计,帮助你更好地使用这个量化交易框架。
+
+## 核心架构
+
+QKA 采用模块化设计,主要包含以下几个核心模块:
+
+```
+qka/
+├── core/ # 核心功能模块
+│ ├── data.py # 数据管理
+│ ├── backtest.py # 回测引擎
+│ ├── strategy.py # 策略基类
+│ └── broker.py # 虚拟经纪商
+├── brokers/ # 交易接口
+│ ├── client.py # 交易客户端
+│ ├── server.py # 交易服务器
+│ └── trade.py # 交易执行
+├── mcp/ # MCP 协议支持
+│ ├── api.py # MCP API
+│ └── server.py # MCP 服务器
+└── utils/ # 工具模块
+ ├── logger.py # 日志系统
+ └── util.py # 通用工具
+```
+
+## 数据流
+
+QKA 的数据处理流程如下:
+
+1. **数据获取**: 通过 `qka.Data` 类从数据源获取股票数据
+2. **策略处理**: 在 `on_bar` 方法中处理每个时间点的数据
+3. **交易执行**: 通过 `broker` 执行买卖操作
+4. **状态记录**: 自动记录资金、持仓和交易历史
+5. **结果分析**: 通过回测结果进行策略评估
+
+## 核心概念详解
+
+### 1. 数据维度
+
+QKA 的数据模型基于四个维度:
+
+- **标的维度**: 股票代码列表,如 `['000001.SZ', '600000.SH']`
+- **周期维度**: 数据频率,如 `'1d'`(日线)、`'1m'`(分钟线)
+- **因子维度**: 技术指标和特征,如移动平均、RSI 等
+- **数据源维度**: 数据来源,如 `'akshare'`、`'qmt'`
+
+### 2. 策略开发
+
+所有策略都必须继承 `qka.Strategy` 基类:
+
+```python
+class MyStrategy(qka.Strategy):
+ def __init__(self):
+ super().__init__()
+ # 初始化策略参数
+
+ def on_bar(self, date, get):
+ """
+ date: 当前时间戳
+ get: 获取因子数据的函数,格式为 get(factor_name) -> pd.Series
+ """
+ # 策略逻辑
+ pass
+```
+
+### 3. 回测引擎
+
+回测引擎负责:
+
+- 按时间顺序遍历数据
+- 在每个时间点调用策略的 `on_bar` 方法
+- 记录交易状态和资金变化
+- 提供可视化分析
+
+### 4. 经纪商接口
+
+`qka.Broker` 类提供虚拟交易功能:
+
+- 资金管理
+- 持仓跟踪
+- 交易执行
+- 交易记录
+
+## 关键特性
+
+### 并发数据下载
+
+QKA 使用多线程并发下载数据,显著提高数据获取效率:
+
+```python
+data = qka.Data(
+ symbols=['000001.SZ', '600000.SH', ...], # 多只股票
+ pool_size=10 # 并发线程数
+)
+```
+
+### 数据缓存
+
+自动缓存下载的数据到本地,避免重复下载:
+
+```python
+# 数据会自动缓存到 datadir/ 目录
+# 下次使用时直接从缓存读取
+```
+
+### 统一数据格式
+
+无论数据来源如何,都统一为标准的 DataFrame 格式:
+
+```python
+# 列名格式: {symbol}_{column}
+# 例如: 000001.SZ_close, 600000.SH_volume
+```
+
+## 设计原则
+
+### 1. 简洁性
+
+提供简单直观的 API,降低量化交易的学习门槛:
+
+```python
+# 三行代码完成基本回测
+data = qka.Data(symbols=['000001.SZ'])
+strategy = MyStrategy()
+backtest = qka.Backtest(data, strategy)
+backtest.run()
+```
+
+### 2. 扩展性
+
+模块化设计,易于扩展新功能:
+
+- 可以轻松添加新的数据源
+- 支持自定义因子计算
+- 可以扩展新的交易接口
+
+### 3. 实用性
+
+专注于 A 股市场的实际需求:
+
+- 支持 A 股特有的交易规则
+- 集成常用的 A 股数据源
+- 提供实盘交易接口
+
+## 使用模式
+
+### 回测模式
+
+用于策略开发和验证:
+
+```python
+# 1. 准备数据
+data = qka.Data(symbols=stock_list)
+
+# 2. 开发策略
+class MyStrategy(qka.Strategy):
+ def on_bar(self, date, get):
+ # 策略逻辑
+ pass
+
+# 3. 运行回测
+backtest = qka.Backtest(data, MyStrategy())
+backtest.run()
+
+# 4. 分析结果
+backtest.plot()
+```
+
+### 实盘模式
+
+用于实盘交易:
+
+```python
+# 1. 启动交易服务器
+from qka.brokers.server import QMTServer
+server = QMTServer(account_id, qmt_path)
+server.start()
+
+# 2. 使用交易客户端
+from qka.brokers.client import QMTClient
+client = QMTClient(token=token)
+client.api("order_stock", ...)
+```
+
+## 最佳实践
+
+1. **数据预处理**: 在策略开发前确保数据质量
+2. **参数优化**: 使用网格搜索等方法优化策略参数
+3. **风险控制**: 在策略中加入止损和仓位控制
+4. **回测验证**: 使用不同时间段的数据验证策略稳定性
+5. **实盘测试**: 从小资金开始实盘测试
+
+## 下一步
+
+- 查看 [用户指南](../user-guide/data.md) 学习详细功能用法
+- 参考 [API 文档](../api/core/data.md) 了解完整接口说明
+- 学习 [示例教程](../examples/basic/first-strategy.md) 获取实用代码示例
\ No newline at end of file
diff --git a/docs/getting-started/first-strategy.md b/docs/getting-started/first-strategy.md
index e38002b..fd95dec 100644
--- a/docs/getting-started/first-strategy.md
+++ b/docs/getting-started/first-strategy.md
@@ -1,335 +1,176 @@
-# 第一个策略
-
-本教程将指导您创建和运行您的第一个量化交易策略。
-
-## 策略概述
-
-我们将创建一个简单的均线策略:
-- 当短期均线上穿长期均线时买入(金叉)
-- 当短期均线下穿长期均线时卖出(死叉)
-
-## 创建策略文件
-
-创建一个新文件 `my_first_strategy.py`:
-
-```python
-"""
-我的第一个量化策略
-简单的双均线策略
-"""
-
-import qka
-from qka.core.backtest import Strategy
-from qka.core.data import get_stock_data
-
-
-class MovingAverageStrategy(Strategy):
- """双均线策略"""
-
- def __init__(self, short_window=20, long_window=50):
- super().__init__()
- self.short_window = short_window
- self.long_window = long_window
- self.name = f"双均线策略({short_window}/{long_window})"
-
- # 存储均线数据
- self.short_ma = {}
- self.long_ma = {}
- self.last_signal = {}
-
- def on_init(self):
- """策略初始化"""
- self.log("策略初始化开始")
-
- # 订阅股票数据
- self.subscribe('000001.SZ') # 平安银行
-
- self.log("策略初始化完成")
-
- def calculate_moving_average(self, prices, window):
- """计算移动平均线"""
- if len(prices) < window:
- return None
- return sum(prices[-window:]) / window
-
- def on_data(self, data):
- """处理数据更新"""
- for symbol in data.index:
- # 获取历史价格
- prices = self.get_price_history(symbol, self.long_window + 10)
-
- if len(prices) < self.long_window:
- continue
-
- # 计算短期和长期均线
- short_ma = self.calculate_moving_average(prices, self.short_window)
- long_ma = self.calculate_moving_average(prices, self.long_window)
-
- if short_ma is None or long_ma is None:
- continue
-
- # 获取之前的均线值
- prev_short = self.short_ma.get(symbol, 0)
- prev_long = self.long_ma.get(symbol, 0)
-
- # 当前持仓
- position = self.get_position(symbol)
- current_price = data.loc[symbol, 'close']
-
- # 交易信号判断
- if short_ma > long_ma and prev_short <= prev_long:
- # 金叉 - 买入信号
- if not position:
- volume = self.calculate_position_size(symbol, current_price)
- if volume > 0:
- self.buy(symbol, volume)
- self.log(f"{symbol} 金叉买入,价格: {current_price:.2f}, 数量: {volume}")
- self.last_signal[symbol] = 'BUY'
-
- elif short_ma < long_ma and prev_short >= prev_long:
- # 死叉 - 卖出信号
- if position and position.volume > 0:
- self.sell(symbol, position.volume)
- self.log(f"{symbol} 死叉卖出,价格: {current_price:.2f}, 数量: {position.volume}")
- self.last_signal[symbol] = 'SELL'
-
- # 保存当前均线值
- self.short_ma[symbol] = short_ma
- self.long_ma[symbol] = long_ma
-
- def calculate_position_size(self, symbol, price):
- """计算买入数量"""
- # 使用可用资金的10%买入
- available_cash = self.get_available_cash()
- target_value = available_cash * 0.1
- volume = int(target_value / price / 100) * 100 # 整手买入
- return volume
-
- def on_order(self, order):
- """订单状态变化回调"""
- self.log(f"订单更新: {order.symbol} {order.side} {order.volume}股 @ {order.price:.2f} - {order.status}")
-
- def on_trade(self, trade):
- """成交回调"""
- self.log(f"成交确认: {trade.symbol} {trade.side} {trade.volume}股 @ {trade.price:.2f}")
-
-
-if __name__ == "__main__":
- # 运行策略
- print("开始运行双均线策略...")
-
- # 1. 加载配置
- qka.config.backtest.initial_cash = 1000000 # 100万初始资金
- qka.config.backtest.commission_rate = 0.0003 # 万三手续费
-
- # 2. 创建回测引擎
- from qka.core.backtest import BacktestEngine
-
- engine = BacktestEngine(
- initial_cash=qka.config.backtest.initial_cash,
- start_date='2024-01-01',
- end_date='2024-06-30',
- commission_rate=qka.config.backtest.commission_rate
- )
-
- # 3. 获取数据
- print("正在获取数据...")
- data = get_stock_data('000001.SZ', start='2024-01-01', end='2024-06-30')
- engine.add_data(data)
-
- # 4. 创建并运行策略
- strategy = MovingAverageStrategy(short_window=20, long_window=50)
-
- print("开始回测...")
- result = engine.run(strategy)
-
- # 5. 显示结果
- print("\n" + "="*50)
- print("回测结果")
- print("="*50)
- print(f"策略名称: {strategy.name}")
- print(f"回测期间: 2024-01-01 至 2024-06-30")
- print(f"初始资金: ¥{qka.config.backtest.initial_cash:,.2f}")
- print(f"最终资金: ¥{result.final_value:,.2f}")
- print(f"总收益率: {result.total_return:.2%}")
- print(f"年化收益率: {result.annual_return:.2%}")
- print(f"最大回撤: {result.max_drawdown:.2%}")
- print(f"夏普比率: {result.sharpe_ratio:.2f}")
- print(f"交易次数: {result.trade_count}")
- print(f"胜率: {result.win_rate:.2%}")
-
- # 6. 绘制收益曲线(如果有matplotlib)
- try:
- from qka.core.plot import plot_returns
- plot_returns(result.returns, title="双均线策略收益曲线")
- print("\n收益曲线图已显示")
- except ImportError:
- print("\n提示: 安装 matplotlib 可以查看收益曲线图")
- print("命令: pip install matplotlib")
-
- print("\n策略运行完成!")
-```
-
-## 运行策略
-
-### 命令行运行
-
-```bash
-# 确保已安装 QKA
-pip install qka
-
-# 运行策略
-python my_first_strategy.py
-```
-
-### 预期输出
-
-```
-开始运行双均线策略...
-正在获取数据...
-开始回测...
-
-==================================================
-回测结果
-==================================================
-策略名称: 双均线策略(20/50)
-回测期间: 2024-01-01 至 2024-06-30
-初始资金: ¥1,000,000.00
-最终资金: ¥1,050,000.00
-总收益率: 5.00%
-年化收益率: 10.25%
-最大回撤: -3.20%
-夏普比率: 1.15
-交易次数: 8
-胜率: 62.50%
-
-收益曲线图已显示
-策略运行完成!
-```
-
-## 理解代码
-
-### 策略类结构
-
-```python
-class MovingAverageStrategy(Strategy):
- def __init__(self):
- # 初始化参数
-
- def on_init(self):
- # 策略启动时执行一次
-
- def on_data(self, data):
- # 每次数据更新时执行
-
- def on_order(self, order):
- # 订单状态变化时执行
-
- def on_trade(self, trade):
- # 成交时执行
-```
-
-### 关键方法说明
-
-| 方法 | 作用 | 调用时机 |
-|------|------|----------|
-| `on_init()` | 策略初始化 | 策略开始时 |
-| `on_data()` | 处理数据 | 每个交易日 |
-| `buy()` | 买入股票 | 产生买入信号时 |
-| `sell()` | 卖出股票 | 产生卖出信号时 |
-| `get_position()` | 获取持仓 | 需要查询持仓时 |
-| `log()` | 记录日志 | 任何时候 |
-
-## 策略优化
-
-### 参数调优
-
-```python
-# 测试不同参数组合
-strategies = []
-for short in [10, 15, 20]:
- for long in [30, 40, 50]:
- if short < long:
- strategy = MovingAverageStrategy(short, long)
- result = engine.run(strategy)
- strategies.append((short, long, result.sharpe_ratio))
-
-# 找出最优参数
-best_params = max(strategies, key=lambda x: x[2])
-print(f"最优参数: 短线={best_params[0]}, 长线={best_params[1]}")
-```
-
-### 添加止损止盈
-
-```python
-def on_data(self, data):
- # ...原有逻辑...
-
- # 检查止损止盈
- for symbol in self.positions:
- position = self.get_position(symbol)
- if position and position.volume > 0:
- current_price = data.loc[symbol, 'close']
- cost_price = position.avg_price
-
- # 计算收益率
- return_rate = (current_price - cost_price) / cost_price
-
- # 止损(-5%)
- if return_rate <= -0.05:
- self.sell(symbol, position.volume)
- self.log(f"{symbol} 触发止损")
-
- # 止盈(+10%)
- elif return_rate >= 0.10:
- self.sell(symbol, position.volume)
- self.log(f"{symbol} 触发止盈")
-```
-
-## 下一步
-
-现在您已经创建了第一个策略,可以:
-
-1. **学习更多策略**:查看 [示例教程](../examples/simple-strategy.md)
-2. **优化策略**:了解 [参数优化](../user-guide/backtest.md#参数优化)
-3. **风险管理**:学习 [风险控制](../examples/risk-management.md)
-4. **实盘交易**:准备 [实盘部署](../user-guide/trading.md)
-
-## 常见问题
-
-### Q: 如何添加更多股票?
-
-```python
-def on_init(self):
- # 添加多只股票
- stocks = ['000001.SZ', '000002.SZ', '600000.SH']
- for stock in stocks:
- self.subscribe(stock)
-```
-
-### Q: 如何修改买入金额?
-
-```python
-def calculate_position_size(self, symbol, price):
- # 固定金额买入(比如每次10000元)
- target_value = 10000
- volume = int(target_value / price / 100) * 100
- return volume
-```
-
-### Q: 如何保存回测结果?
-
-```python
-# 保存结果到文件
-import json
-results = {
- 'total_return': result.total_return,
- 'sharpe_ratio': result.sharpe_ratio,
- 'max_drawdown': result.max_drawdown
-}
-
-with open('backtest_results.json', 'w') as f:
- json.dump(results, f, indent=2)
-```
-
-恭喜!您已经创建并运行了第一个量化交易策略。
+# 第一个策略
+
+本指南将带你创建第一个简单的量化策略,包括数据获取、策略开发和回测分析。
+
+## 策略目标
+
+创建一个简单的移动平均策略:
+- 当短期均线上穿长期均线时买入
+- 当短期均线下穿长期均线时卖出
+
+## 步骤1:数据获取
+
+首先,我们需要获取股票数据:
+
+```python
+import qka
+
+# 创建数据对象
+data = qka.Data(
+ symbols=['000001.SZ', '600000.SH'], # 股票代码列表
+ period='1d', # 日线数据
+ adjust='qfq' # 前复权
+)
+
+# 获取数据
+df = data.get()
+print(f"数据形状: {df.shape}")
+print(df.head())
+```
+
+## 步骤2:创建策略
+
+继承 `qka.Strategy` 类并实现 `on_bar` 方法:
+
+```python
+class MovingAverageStrategy(qka.Strategy):
+ def __init__(self):
+ super().__init__()
+ self.ma_short = 5 # 短期均线周期
+ self.ma_long = 20 # 长期均线周期
+ self.positions = {} # 持仓记录
+
+ def on_bar(self, date, get):
+ """
+ 每个bar的处理逻辑
+
+ Args:
+ date: 当前时间戳
+ get: 获取因子数据的函数
+ """
+ # 获取当前价格数据
+ close_prices = get('close')
+
+ # 遍历所有股票
+ for symbol in close_prices.index:
+ # 获取该股票的历史数据
+ symbol_close = get('close')[symbol]
+
+ # 计算移动平均
+ if len(symbol_close) >= self.ma_long:
+ ma_short = symbol_close[-self.ma_short:].mean()
+ ma_long = symbol_close[-self.ma_long:].mean()
+
+ current_price = symbol_close.iloc[-1]
+
+ # 交易逻辑
+ if ma_short > ma_long and symbol not in self.positions:
+ # 短期均线上穿长期均线,买入
+ size = int(self.broker.cash * 0.1 / current_price) # 使用10%资金
+ if size > 0:
+ self.broker.buy(symbol, current_price, size)
+ self.positions[symbol] = True
+
+ elif ma_short < ma_long and symbol in self.positions:
+ # 短期均线下穿长期均线,卖出
+ position = self.broker.positions.get(symbol)
+ if position:
+ self.broker.sell(symbol, current_price, position['size'])
+ del self.positions[symbol]
+```
+
+## 步骤3:运行回测
+
+创建策略实例并运行回测:
+
+```python
+# 创建策略实例
+strategy = MovingAverageStrategy()
+
+# 创建回测引擎
+backtest = qka.Backtest(data, strategy)
+
+# 运行回测
+print("开始回测...")
+backtest.run()
+print("回测完成!")
+
+# 查看回测结果
+print(f"最终资金: {strategy.broker.cash:.2f}")
+print(f"持仓情况: {strategy.broker.positions}")
+```
+
+## 步骤4:可视化结果
+
+使用内置的可视化功能查看回测结果:
+
+```python
+# 绘制收益曲线
+fig = backtest.plot("移动平均策略回测结果")
+
+# 查看详细交易记录
+trades_df = strategy.broker.trades
+print("交易记录:")
+print(trades_df.tail())
+
+# 计算收益率
+initial_cash = 100000
+final_total = trades_df['total'].iloc[-1]
+total_return = (final_total - initial_cash) / initial_cash * 100
+print(f"总收益率: {total_return:.2f}%")
+```
+
+## 完整代码示例
+
+```python
+import qka
+
+class MovingAverageStrategy(qka.Strategy):
+ def __init__(self):
+ super().__init__()
+ self.ma_short = 5
+ self.ma_long = 20
+ self.positions = {}
+
+ def on_bar(self, date, get):
+ close_prices = get('close')
+
+ for symbol in close_prices.index:
+ symbol_close = get('close')[symbol]
+
+ if len(symbol_close) >= self.ma_long:
+ ma_short = symbol_close[-self.ma_short:].mean()
+ ma_long = symbol_close[-self.ma_long:].mean()
+ current_price = symbol_close.iloc[-1]
+
+ if ma_short > ma_long and symbol not in self.positions:
+ size = int(self.broker.cash * 0.1 / current_price)
+ if size > 0:
+ self.broker.buy(symbol, current_price, size)
+ self.positions[symbol] = True
+ elif ma_short < ma_long and symbol in self.positions:
+ position = self.broker.positions.get(symbol)
+ if position:
+ self.broker.sell(symbol, current_price, position['size'])
+ del self.positions[symbol]
+
+# 执行策略
+data = qka.Data(symbols=['000001.SZ', '600000.SH'], period='1d')
+strategy = MovingAverageStrategy()
+backtest = qka.Backtest(data, strategy)
+backtest.run()
+backtest.plot()
+```
+
+## 策略优化建议
+
+1. **参数调优**: 尝试不同的均线周期组合
+2. **风险控制**: 添加止损和仓位控制
+3. **多因子**: 结合其他技术指标
+4. **数据验证**: 使用更长时间段的数据进行验证
+
+## 下一步
+
+- 学习 [基础概念](concepts.md) 深入了解 QKA 架构
+- 查看 [用户指南](../user-guide/data.md) 学习更多高级功能
+- 参考 [API 文档](../api/core/data.md) 了解完整接口说明
\ No newline at end of file
diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md
index c7f4103..5892e7b 100644
--- a/docs/getting-started/installation.md
+++ b/docs/getting-started/installation.md
@@ -1,214 +1,99 @@
-# 安装指南
-
-## 系统要求
-
-!!! info "环境要求"
- - Python 3.8 或更高版本
- - Windows 10/11 (推荐用于QMT集成)
- - macOS / Linux (支持基础功能)
-
-## 安装方式
-
-### 使用 pip 安装
-
-```bash
-pip install qka
-```
-
-### 使用 uv 安装 (推荐)
-
-```bash
-# 安装 uv (如果尚未安装)
-curl -LsSf https://astral.sh/uv/install.sh | sh
-
-# 创建新项目
-uv init my-quant-project
-cd my-quant-project
-
-# 添加 qka 依赖
-uv add qka
-```
-
-### 从源码安装
-
-```bash
-git clone https://github.com/your-username/qka.git
-cd qka
-uv sync
-uv pip install -e .
-```
-
-## 验证安装
-
-创建一个测试文件 `test_install.py`:
-
-```python
-import qka
-from qka.core.config import config
-
-print(f"QKA 版本: {qka.__version__}")
-print(f"配置加载成功: {config.backtest.initial_cash:,}")
-print("✅ QKA 安装成功!")
-```
-
-运行测试:
-
-```bash
-python test_install.py
-```
-
-预期输出:
-```
-QKA 版本: 0.2.0
-配置加载成功: 1,000,000
-✅ QKA 安装成功!
-```
-
-## 可选依赖
-
-### QMT 集成
-
-如果需要使用QMT进行实盘交易,需要安装:
-
-1. **迅投QMT客户端** - [官方下载](https://www.xtquant.com/)
-2. **xtquant 库**:
- ```bash
- pip install xtquant
- ```
-
-### 数据源
-
-根据使用的数据源安装对应依赖:
-
-=== "Akshare"
- ```bash
- pip install akshare
- ```
-
-=== "Tushare"
- ```bash
- pip install tushare
- ```
-
-=== "Wind"
- ```bash
- pip install WindPy
- ```
-
-### 可视化增强
-
-```bash
-# 交互式图表
-pip install plotly
-
-# Jupyter支持
-pip install jupyter notebook
-
-# 额外图表库
-pip install matplotlib seaborn
-```
-
-## 开发环境设置
-
-如果您计划贡献代码或深度定制,建议设置开发环境:
-
-### 1. 克隆仓库
-
-```bash
-git clone https://github.com/your-username/qka.git
-cd qka
-```
-
-### 2. 安装开发依赖
-
-```bash
-uv sync --all-extras
-```
-
-### 3. 安装预提交钩子
-
-```bash
-pre-commit install
-```
-
-### 4. 运行测试
-
-```bash
-# 运行全部测试
-pytest
-
-# 运行特定测试
-pytest tests/test_config.py
-
-# 生成覆盖率报告
-pytest --cov=qka --cov-report=html
-```
-
-### 5. 构建文档
-
-```bash
-# 启动文档服务器
-mkdocs serve
-
-# 构建静态文档
-mkdocs build
-```
-
-## 故障排除
-
-### 常见问题
-
-!!! warning "ImportError: No module named 'qka'"
-
- **原因**: QKA 未正确安装
-
- **解决**:
- ```bash
- pip install --upgrade qka
- # 或
- uv add qka
- ```
-
-!!! warning "xtquant 相关错误"
-
- **原因**: QMT客户端未安装或路径配置错误
-
- **解决**:
- 1. 确保已安装QMT客户端
- 2. 检查QMT路径配置
- 3. 参考 [QMT配置指南](../user-guide/trading.md#qmt-配置)
-
-!!! warning "数据获取失败"
-
- **原因**: 网络问题或数据源配置错误
-
- **解决**:
- 1. 检查网络连接
- 2. 确认数据源API密钥配置
- 3. 参考 [数据配置指南](../user-guide/data.md#数据源配置)
-
-### 获取帮助
-
-如果遇到问题,可以通过以下方式获取帮助:
-
-1. **查看文档** - 本文档包含了详细的使用说明
-2. **搜索Issues** - [GitHub Issues](https://github.com/your-username/qka/issues)
-3. **提交问题** - 如果没有找到解决方案,请提交新的Issue
-4. **社区讨论** - [GitHub Discussions](https://github.com/your-username/qka/discussions)
-
-### 版本兼容性
-
-| QKA 版本 | Python 版本 | 主要变化 |
-|----------|-------------|----------|
-| 0.2.x | 3.8+ | 配置管理、事件系统 |
-| 0.1.x | 3.8+ | 基础功能 |
-
----
-
-## 下一步
-
-安装完成后,建议阅读:
-
-- [第一个策略](first-strategy.md) - 创建您的第一个量化策略
-- [基础概念](concepts.md) - 了解QKA的核心概念
-- [用户指南](../user-guide/data.md) - 深入学习各个功能模块
+# 安装指南
+
+## 系统要求
+
+- Python 3.10 或更高版本
+- Windows 系统(推荐 Windows 10/11)
+- 支持 QMT 交易(可选,用于实盘交易)
+
+## 安装方法
+
+### 从 PyPI 安装(推荐)
+
+```bash
+pip install qka
+```
+
+### 从源码安装
+
+如果你想使用最新的开发版本,可以从 GitHub 源码安装:
+
+```bash
+git clone https://github.com/zsrl/qka.git
+cd qka
+pip install -e .
+```
+
+### 安装开发依赖
+
+如果你想要构建文档或运行测试,可以安装开发依赖:
+
+```bash
+pip install qka[dev]
+```
+
+## 依赖说明
+
+QKA 依赖于以下主要包:
+
+- **akshare**: 数据获取
+- **fastapi**: Web 服务器框架
+- **plotly**: 数据可视化
+- **pandas**: 数据处理
+- **dask**: 并行计算
+- **xtquant**: QMT Python 接口
+
+完整的依赖列表请参考 [pyproject.toml](../pyproject.toml)。
+
+## 验证安装
+
+安装完成后,可以通过以下方式验证安装是否成功:
+
+```python
+import qka
+
+print(f"QKA 版本: {qka.__version__}")
+
+# 检查核心模块是否可用
+try:
+ from qka import Data, Backtest, Strategy
+ print("核心模块导入成功")
+except ImportError as e:
+ print(f"导入失败: {e}")
+```
+
+## 常见问题
+
+### Q: 安装过程中出现依赖冲突怎么办?
+
+A: 建议使用虚拟环境来避免依赖冲突:
+
+```bash
+# 创建虚拟环境
+python -m venv qka_env
+
+# 激活虚拟环境(Windows)
+qka_env\Scripts\activate
+
+# 安装 QKA
+pip install qka
+```
+
+### Q: 如何更新到最新版本?
+
+A: 使用 pip 更新:
+
+```bash
+pip install --upgrade qka
+```
+
+### Q: 安装 xtquant 失败怎么办?
+
+A: xtquant 是 QMT 的 Python 接口,如果你不需要实盘交易功能,可以跳过这个依赖。如果需要,请确保已安装 QMT 并正确配置环境。
+
+## 下一步
+
+安装完成后,建议继续阅读:
+
+- [第一个策略](first-strategy.md) - 学习如何创建你的第一个量化策略
+- [基础概念](concepts.md) - 了解 QKA 的核心概念和架构
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
index f2fb520..62fc86e 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,182 +1,67 @@
-# QKA - 快量化
-
-
-
-**Quick Quantitative Assistant**
-
-一个简洁易用、可实操A股的量化交易框架
-
-[](https://badge.fury.io/py/qka)
-[](https://www.python.org/downloads/)
-[](LICENSE)
-
-[快速开始](getting-started/installation.md){ .md-button .md-button--primary }
-[GitHub](https://github.com/zsrl/qka){ .md-button }
-
-
-
----
-
-## ✨ 特性
-
-!!! tip "核心特性"
-
- - 🚀 **极简API** - 3行代码完成回测
- - 📊 **多数据源** - 支持QMT、Akshare等数据源
- - 🔄 **事件驱动** - 现代化的事件系统架构
- - 📈 **实盘对接** - 直接对接QMT进行A股实盘交易
- - 🛠️ **工具丰富** - 内置缓存、日志、配置管理等工具
- - 📖 **文档完善** - 详细的文档和示例
-
-## 🚀 快速体验
-
-### 安装
-
-```bash
-pip install qka
-```
-
-### 3分钟上手
-
-=== "获取数据"
-
- ```python
- import qka
-
- # 获取股票数据
- data_obj = qka.data('akshare', stocks=['000001', '000002'])
- hist_data = data_obj.get(start_time='2023-01-01', end_time='2023-12-31')
- ```
-
-=== "定义策略"
-
- ```python
- from qka.core.backtest import Strategy
-
- class MyStrategy(Strategy):
- def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- if len(df) >= 20:
- price = df['close'].iloc[-1]
- ma20 = df['close'].rolling(20).mean().iloc[-1]
-
- if price > ma20 and broker.get_position(symbol) == 0:
- broker.buy(symbol, 0.3, price) # 买入30%资金
- elif price < ma20 and broker.get_position(symbol) > 0:
- broker.sell(symbol, 1.0, price) # 全部卖出
- ```
-
-=== "运行回测"
-
- ```python
- # 运行回测
- result = qka.backtest(
- data=data_obj,
- strategy=MyStrategy(),
- start_time='2023-01-01',
- end_time='2023-12-31'
- )
-
- # 查看结果
- print(f"总收益率: {result['total_return']:.2%}")
- print(f"年化收益率: {result['annual_return']:.2%}")
- print(f"最大回撤: {result['max_drawdown']:.2%}")
- ```
-
-## 📋 功能模块
-
-
-
-- 📊 **数据管理**
-
- ---
-
- 支持多种数据源,自动缓存,数据质量检查
-
- [→ 了解更多](user-guide/data.md)
-
-- 🧠 **策略开发**
-
- ---
-
- 简洁的策略框架,丰富的技术指标,事件驱动
-
- [→ 了解更多](user-guide/strategy.md)
-
-- 📈 **回测分析**
-
- ---
-
- 高效的回测引擎,详细的绩效分析,可视化图表
-
- [→ 了解更多](user-guide/backtest.md)
-
-- 🚀 **实盘交易**
-
- ---
-
- 直接对接QMT,支持A股实盘交易,风险控制
-
- [→ 了解更多](user-guide/trading.md)
-
-
-
-## 🏗️ 架构优势
-
-```mermaid
-graph TB
- A[策略层] --> B[事件系统]
- B --> C[数据层]
- B --> D[回测引擎]
- B --> E[交易接口]
-
- C --> F[QMT数据]
- C --> G[Akshare数据]
-
- E --> H[模拟交易]
- E --> I[实盘交易]
-
- J[配置管理] --> A
- J --> C
- J --> D
- J --> E
-
- K[日志系统] --> A
- K --> C
- K --> D
- K --> E
-```
-
-## 📊 使用场景
-
-!!! example "典型应用"
-
- - **量化策略研究** - 快速验证交易想法
- - **A股程序化交易** - 实盘自动化交易
- - **金融数据分析** - 多源数据整合分析
- - **风险管理** - 投资组合监控和风控
- - **教学研究** - 量化金融教学和研究
-
-## 🎯 版本规划
-
-| 版本 | 状态 | 主要功能 |
-|------|------|----------|
-| v0.1.x | ✅ 已发布 | 基础回测、数据接口、QMT交易 |
-| v0.2.x | 🚧 开发中 | 配置管理、事件系统、增强日志 |
-| v0.3.x | 📋 规划中 | 数据缓存、质量检查、多频率 |
-| v0.4.x | 📋 规划中 | 策略优化、风险管理、指标库 |
-| v1.0.x | 📋 规划中 | 稳定版本、完整文档、生态 |
-
-## 🐛 问题反馈
-
-- [GitHub Issues](https://github.com/zsrl/qka/issues) - 报告bug或提出功能建议
-
----
-
-
-
-**开始您的量化之旅** 🚀
-
-[立即开始](getting-started/installation.md){ .md-button .md-button--primary }
-
-
+# QKA - 快捷量化助手
+
+欢迎使用 QKA(Quick Quantitative Assistant)文档!
+
+## 简介
+
+QKA 是一个简洁易用、功能完整的A股量化交易框架,支持数据获取、策略回测、实盘交易等全流程量化交易功能。
+
+## 主要特性
+
+- 🚀 **简洁易用**: 统一的API设计,降低量化交易门槛
+- 📊 **数据丰富**: 支持Akshare数据源,提供多周期、多因子数据
+- 🔄 **高效回测**: 基于时间序列的回测引擎,支持多股票横截面处理
+- 💰 **实盘交易**: 集成QMT交易接口,支持实盘交易
+- 📈 **可视化**: 内置Plotly图表,提供交互式回测结果展示
+- 🔧 **模块化**: 高度模块化设计,易于扩展和维护
+
+## 快速开始
+
+### 安装
+
+```bash
+pip install qka
+```
+
+### 基本用法
+
+```python
+import qka
+
+# 数据获取
+data = qka.Data(symbols=['000001.SZ', '600000.SH'], period='1d')
+df = data.get()
+
+# 策略开发
+class MyStrategy(qka.Strategy):
+ def on_bar(self, date, get):
+ close_prices = get('close')
+ # 你的策略逻辑
+
+# 回测分析
+strategy = MyStrategy()
+backtest = qka.Backtest(data, strategy)
+backtest.run()
+backtest.plot()
+```
+
+## 文档结构
+
+- **快速开始**: 安装和基础使用指南
+- **用户指南**: 详细的功能使用说明
+- **API参考**: 完整的API文档
+- **示例教程**: 实用的代码示例
+
+## 获取帮助
+
+- 查看 [GitHub Issues](https://github.com/zsrl/qka/issues) 获取技术支持
+- 阅读 [用户指南](user-guide/data.md) 了解详细用法
+- 参考 [API文档](api/core/data.md) 查看完整接口说明
+
+## 许可证
+
+本项目采用 MIT 许可证 - 查看 [LICENSE](https://github.com/zsrl/qka/blob/main/LICENSE) 文件了解详情。
+
+---
+
+**注意**: 量化交易存在风险,请在充分了解风险的情况下使用本框架。
\ No newline at end of file
diff --git a/docs/user-guide/backtest.md b/docs/user-guide/backtest.md
index 7984a8b..0237c71 100644
--- a/docs/user-guide/backtest.md
+++ b/docs/user-guide/backtest.md
@@ -1,465 +1,342 @@
-# 回测分析
-
-QKA 提供了简洁易用的回测功能,帮助您快速验证交易策略的有效性。
-
-## 快速开始
-
-### 三步完成回测
-
-QKA 回测非常简单,只需三步:
-
-```python
-import qka
-
-# 第1步:获取数据
-data_obj = qka.data(stocks=['000001', '000002']) # 默认使用akshare数据源
-
-# 第2步:定义策略
-class SimpleStrategy(qka.Strategy):
- def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- if len(df) >= 20:
- price = df['close'].iloc[-1]
- ma20 = df['close'].rolling(20).mean().iloc[-1]
-
- if price > ma20: # 突破均线买入
- broker.buy(symbol, 0.5, price)
- elif price < ma20: # 跌破均线卖出
- broker.sell(symbol, 1.0, price)
-
-# 第3步:运行回测并查看结果
-result = qka.backtest(data_obj, SimpleStrategy(), start_time='2023-01-01', end_time='2023-12-31')
-
-print(f"总收益率: {result['total_return']:.2%}")
-print(f"年化收益率: {result['annual_return']:.2%}")
-print(f"夏普比率: {result['sharpe_ratio']:.2f}")
-```
-
-> **数据源说明**: 默认使用akshare数据源。如需使用其他数据源,可以调用 `set_source('qmt')` 或在 `data()` 函数中指定 `source` 参数。
-
-## 策略开发
-
-### 策略基类
-
-所有策略都需要继承 `qka.Strategy` 基类:
-
-```python
-import qka
-
-class MyStrategy(qka.Strategy):
- def on_bar(self, data, broker, current_date):
- """
- 每个交易日调用的策略逻辑
-
- Args:
- data: 历史数据字典 {股票代码: DataFrame}
- broker: 交易接口
- current_date: 当前日期
- """
- # 在这里实现你的策略逻辑
- pass
-
- def on_start(self, broker):
- """回测开始时调用"""
- print(f"策略 {self.name} 开始运行")
-
- def on_end(self, broker):
- """回测结束时调用"""
- print(f"策略 {self.name} 运行结束")
-```
-
-### 策略示例
-
-#### 移动平均策略
-
-```python
-class MovingAverageStrategy(qka.Strategy):
- def __init__(self, short_window=5, long_window=20):
- super().__init__()
- self.short_window = short_window
- self.long_window = long_window
-
- def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- if len(df) < self.long_window:
- continue
-
- # 计算短期和长期移动平均
- short_ma = df['close'].rolling(self.short_window).mean().iloc[-1]
- long_ma = df['close'].rolling(self.long_window).mean().iloc[-1]
- current_price = df['close'].iloc[-1]
-
- # 金叉买入,死叉卖出
- if short_ma > long_ma and broker.get_position(symbol) == 0:
- broker.buy(symbol, 0.3, current_price) # 用30%资金买入
- elif short_ma < long_ma and broker.get_position(symbol) > 0:
- broker.sell(symbol, 1.0, current_price) # 全部卖出
-```
-
-#### 布林带策略
-
-```python
-class BollingerBandStrategy(qka.Strategy):
- def __init__(self, window=20, num_std=2):
- super().__init__()
- self.window = window
- self.num_std = num_std
-
- def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- if len(df) < self.window:
- continue
-
- # 计算布林带
- close_prices = df['close']
- rolling_mean = close_prices.rolling(self.window).mean().iloc[-1]
- rolling_std = close_prices.rolling(self.window).std().iloc[-1]
-
- upper_band = rolling_mean + (rolling_std * self.num_std)
- lower_band = rolling_mean - (rolling_std * self.num_std)
- current_price = close_prices.iloc[-1]
-
- # 价格突破下轨买入,突破上轨卖出
- if current_price < lower_band and broker.get_position(symbol) == 0:
- broker.buy(symbol, 0.4, current_price)
- elif current_price > upper_band and broker.get_position(symbol) > 0:
- broker.sell(symbol, 1.0, current_price)
-```
-
-## 交易接口
-
-### Broker 类
-
-`Broker` 类提供了所有交易相关的功能:
-
-```python
-# 获取当前持仓
-position = broker.get_position('000001') # 返回持仓股数
-
-# 获取可用现金
-cash = broker.get_cash()
-
-# 获取所有持仓
-positions = broker.get_positions() # 返回 {股票代码: 持仓数量}
-
-# 计算总资产
-prices = {'000001': 10.5, '000002': 8.3}
-total_value = broker.get_total_value(prices)
-```
-
-### 买入操作
-
-```python
-# 按比例买入(推荐)
-broker.buy('000001', 0.3, price) # 用30%的资金买入
-
-# 按股数买入
-broker.buy('000001', 1000, price) # 买入1000股(自动调整为整手)
-
-# 买入条件检查
-if broker.get_cash() > 10000: # 现金充足
- if broker.get_position('000001') == 0: # 没有持仓
- broker.buy('000001', 0.2, current_price)
-```
-
-### 卖出操作
-
-```python
-# 按比例卖出
-broker.sell('000001', 0.5, price) # 卖出50%的持仓
-broker.sell('000001', 1.0, price) # 全部卖出
-
-# 按股数卖出
-broker.sell('000001', 500, price) # 卖出500股
-
-# 卖出条件检查
-if broker.get_position('000001') > 0: # 有持仓
- broker.sell('000001', 1.0, current_price) # 全部卖出
-```
-
-## 回测配置
-
-### 基本配置
-
-```python
-import qka
-
-# 自定义 Broker 配置
-custom_broker = qka.Broker(
- initial_cash=500000, # 初始资金50万
- commission_rate=0.0003 # 手续费率0.03%
-)
-
-# 使用自定义配置运行回测
-result = qka.backtest(
- data=data_obj,
- strategy=MyStrategy(),
- broker=custom_broker,
- start_time='2023-01-01',
- end_time='2023-12-31'
-)
-```
-
-### 数据获取
-
-```python
-import qka
-
-# 使用默认数据源(akshare)
-data_obj = qka.data(stocks=['000001'])
-
-# 多只股票
-data_obj = qka.data(stocks=['000001', '000002', '600000'])
-
-# 设置全局数据源
-qka.set_source('qmt')
-data_obj = qka.data(stocks=['000001.SZ', '600000.SH']) # QMT格式股票代码
-
-# 临时指定数据源
-data_obj = qka.data(stocks=['000001'], source='akshare')
-```
-
-## 回测结果分析
-
-### 基本指标
-
-回测结果包含以下关键指标:
-
-```python
-# 基本收益指标
-print(f"初始资金: {result['initial_capital']:,.0f}")
-print(f"最终资产: {result['final_value']:,.0f}")
-print(f"总收益率: {result['total_return']:.2%}")
-print(f"年化收益率: {result['annual_return']:.2%}")
-
-# 风险指标
-print(f"收益波动率: {result['volatility']:.2%}")
-print(f"夏普比率: {result['sharpe_ratio']:.2f}")
-print(f"最大回撤: {result['max_drawdown']:.2%}")
-
-# 交易指标
-print(f"总交易次数: {result['total_trades']}")
-print(f"总手续费: {result['total_commission']:,.2f}")
-print(f"胜率: {result['win_rate']:.2%}")
-print(f"交易天数: {result['trading_days']}")
-```
-
-### 详细数据
-
-```python
-# 每日净值数据
-daily_values = result['daily_values']
-for record in daily_values[:5]: # 显示前5天
- print(f"日期: {record['date']}, 总资产: {record['total_value']:,.2f}")
-
-# 交易记录
-trades = result['trades']
-for trade in trades[:5]: # 显示前5笔交易
- print(f"{trade['date']}: {trade['action']} {trade['symbol']} "
- f"{trade['shares']}股 @{trade['price']}")
-
-# 最终持仓
-positions = result['positions']
-print(f"最终持仓: {positions}")
-```
-
-## 结果可视化
-
-```python
-import qka
-
-# 绘制回测结果图表
-qka.plot(result)
-```
-
-## 策略开发技巧
-
-### 数据处理
-
-```python
-def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- # 检查数据长度
- if len(df) < 20:
- continue
-
- # 获取最新价格
- current_price = df['close'].iloc[-1]
-
- # 计算技术指标
- sma_20 = df['close'].rolling(20).mean().iloc[-1]
- rsi = self.calculate_rsi(df['close'], 14)
-
- # 处理缺失值
- if pd.isna(sma_20) or pd.isna(rsi):
- continue
-
- # 策略逻辑
- if rsi < 30 and current_price > sma_20:
- broker.buy(symbol, 0.2, current_price)
-```
-
-### 风险控制
-
-```python
-def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- current_price = df['close'].iloc[-1]
- position = broker.get_position(symbol)
-
- # 止损逻辑
- if position > 0:
- avg_cost = broker.avg_costs.get(symbol, current_price)
- if current_price < avg_cost * 0.95: # 5%止损
- broker.sell(symbol, 1.0, current_price)
- continue
-
- # 仓位控制
- total_value = broker.get_total_value({symbol: current_price})
- position_value = position * current_price
- position_ratio = position_value / total_value
-
- if position_ratio > 0.3: # 单只股票最大30%仓位
- continue
-
- # 买入逻辑
- # ...
-```
-
-### 多股票策略
-
-```python
-class MultiStockStrategy(qka.Strategy):
- def on_bar(self, data, broker, current_date):
- # 收集所有股票的信号
- signals = {}
- for symbol, df in data.items():
- if len(df) >= 20:
- signal = self.calculate_signal(df)
- signals[symbol] = signal
-
- # 按信号强度排序
- sorted_signals = sorted(signals.items(),
- key=lambda x: x[1], reverse=True)
-
- # 只选择前3只股票
- selected_stocks = sorted_signals[:3]
-
- # 平均分配资金
- for symbol, signal in selected_stocks:
- if signal > 0.5 and broker.get_position(symbol) == 0:
- broker.buy(symbol, 0.3, data[symbol]['close'].iloc[-1])
-```
-
-## 最佳实践
-
-### 1. 数据质量检查
-
-```python
-def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- # 检查价格合理性
- current_price = df['close'].iloc[-1]
- if current_price <= 0 or pd.isna(current_price):
- continue
-
- # 检查成交量
- volume = df['volume'].iloc[-1]
- if volume <= 0:
- continue
-
- # 策略逻辑
- # ...
-```
-
-### 2. 参数化策略
-
-```python
-class ParameterizedStrategy(qka.Strategy):
- def __init__(self, ma_period=20, position_size=0.3, stop_loss=0.05):
- super().__init__()
- self.ma_period = ma_period
- self.position_size = position_size
- self.stop_loss = stop_loss
-
- def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- if len(df) < self.ma_period:
- continue
-
- current_price = df['close'].iloc[-1]
- ma = df['close'].rolling(self.ma_period).mean().iloc[-1]
-
- # 使用参数化的逻辑
- if current_price > ma:
- broker.buy(symbol, self.position_size, current_price)
-```
-
-### 3. 策略状态管理
-
-```python
-class StatefulStrategy(qka.Strategy):
- def __init__(self):
- super().__init__()
- self.last_signal = {}
- self.entry_prices = {}
-
- def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- # 保存策略状态
- current_signal = self.calculate_signal(df)
- last_signal = self.last_signal.get(symbol, 0)
-
- # 信号变化时才交易
- if current_signal != last_signal:
- if current_signal > 0:
- price = df['close'].iloc[-1]
- broker.buy(symbol, 0.3, price)
- self.entry_prices[symbol] = price
- else:
- broker.sell(symbol, 1.0, df['close'].iloc[-1])
- self.entry_prices.pop(symbol, None)
-
- self.last_signal[symbol] = current_signal
-```
-
-## 常见问题
-
-### Q: 如何处理停牌股票?
-
-```python
-def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- # 检查是否停牌
- if current_date not in df.index:
- continue # 跳过停牌股票
-
- current_price = df.loc[current_date, 'close']
- if current_price == 0:
- continue # 价格为0可能是停牌
-```
-
-### Q: 如何避免未来函数?
-
-```python
-def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- # 只使用当前日期之前的数据
- historical_data = df.loc[:current_date]
-
- # 计算指标时确保不使用未来数据
- sma = historical_data['close'].rolling(20).mean().iloc[-1]
-```
-
-### Q: 如何处理数据缺失?
-
-```python
-def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- # 检查关键数据是否缺失
- if df[['open', 'high', 'low', 'close', 'volume']].iloc[-1].isna().any():
- continue
-
- # 使用前向填充处理缺失值
- df_filled = df.fillna(method='ffill')
-```
+# 回测分析
+
+QKA 提供完整的回测功能,支持策略验证、性能分析和结果可视化。
+
+## 基本用法
+
+### 创建回测
+
+```python
+import qka
+
+# 1. 准备数据
+data = qka.Data(symbols=['000001.SZ', '600000.SH'])
+
+# 2. 创建策略
+class MyStrategy(qka.Strategy):
+ def on_bar(self, date, get):
+ close_prices = get('close')
+ # 策略逻辑...
+
+# 3. 运行回测
+strategy = MyStrategy()
+backtest = qka.Backtest(data, strategy)
+backtest.run()
+```
+
+### 查看回测结果
+
+```python
+# 查看最终状态
+print(f"最终资金: {strategy.broker.cash:.2f}")
+print(f"持仓情况: {strategy.broker.positions}")
+
+# 查看交易记录
+trades_df = strategy.broker.trades
+print("交易记录:")
+print(trades_df.tail())
+```
+
+## 可视化分析
+
+### 收益曲线
+
+```python
+# 绘制收益曲线
+fig = backtest.plot("我的策略回测结果")
+
+# 自定义图表标题
+fig = backtest.plot("自定义标题")
+```
+
+### 详细分析
+
+```python
+# 计算关键指标
+trades_df = strategy.broker.trades
+
+# 总收益率
+initial_cash = 100000
+final_total = trades_df['total'].iloc[-1]
+total_return = (final_total - initial_cash) / initial_cash * 100
+
+# 最大回撤
+peak = trades_df['total'].expanding().max()
+drawdown = (trades_df['total'] - peak) / peak * 100
+max_drawdown = drawdown.min()
+
+print(f"总收益率: {total_return:.2f}%")
+print(f"最大回撤: {max_drawdown:.2f}%")
+print(f"夏普比率: {calculate_sharpe(trades_df):.2f}")
+```
+
+## 策略开发指南
+
+### 策略结构
+
+所有策略必须继承 `qka.Strategy` 并实现 `on_bar` 方法:
+
+```python
+class MyStrategy(qka.Strategy):
+ def __init__(self):
+ super().__init__()
+ # 初始化策略参数
+ self.param1 = value1
+ self.param2 = value2
+
+ def on_bar(self, date, get):
+ """
+ date: 当前时间戳
+ get: 获取因子数据的函数
+ """
+ # 获取数据
+ close_prices = get('close')
+ volumes = get('volume')
+
+ # 策略逻辑
+ for symbol in close_prices.index:
+ current_price = close_prices[symbol]
+ current_volume = volumes[symbol]
+
+ # 交易决策
+ if self.should_buy(symbol, current_price, current_volume):
+ self.buy(symbol, current_price)
+ elif self.should_sell(symbol, current_price, current_volume):
+ self.sell(symbol, current_price)
+
+ def should_buy(self, symbol, price, volume):
+ # 买入条件
+ return True # 替换为实际条件
+
+ def should_sell(self, symbol, price, volume):
+ # 卖出条件
+ return True # 替换为实际条件
+
+ def buy(self, symbol, price):
+ # 买入逻辑
+ size = self.calculate_position_size(price)
+ self.broker.buy(symbol, price, size)
+
+ def sell(self, symbol, price):
+ # 卖出逻辑
+ position = self.broker.positions.get(symbol)
+ if position:
+ self.broker.sell(symbol, price, position['size'])
+```
+
+### 数据访问
+
+在 `on_bar` 方法中,使用 `get` 函数访问数据:
+
+```python
+def on_bar(self, date, get):
+ # 获取收盘价(所有股票)
+ close_prices = get('close')
+
+ # 获取成交量
+ volumes = get('volume')
+
+ # 获取开盘价
+ open_prices = get('open')
+
+ # 获取自定义因子(如果定义了)
+ ma5_values = get('ma5') # 假设在数据中定义了ma5因子
+```
+
+## 风险控制
+
+### 仓位管理
+
+```python
+class RiskManagedStrategy(qka.Strategy):
+ def __init__(self):
+ super().__init__()
+ self.max_position_ratio = 0.1 # 单只股票最大仓位比例
+ self.max_total_position = 0.8 # 总仓位上限
+
+ def calculate_position_size(self, symbol, price):
+ # 计算合理的买入数量
+ available_cash = self.broker.cash
+ total_assets = self.broker.get('total')
+
+ # 单只股票仓位限制
+ max_position_value = total_assets * self.max_position_ratio
+ max_shares = int(max_position_value / price)
+
+ # 总仓位限制
+ current_position_value = sum(
+ pos['size'] * pos['avg_price']
+ for pos in self.broker.positions.values()
+ )
+ available_for_new = total_assets * self.max_total_position - current_position_value
+ max_shares_by_total = int(available_for_new / price)
+
+ return min(max_shares, max_shares_by_total, int(available_cash / price))
+```
+
+### 止损策略
+
+```python
+class StopLossStrategy(qka.Strategy):
+ def __init__(self):
+ super().__init__()
+ self.stop_loss_rate = 0.05 # 5%止损
+ self.entry_prices = {} # 记录买入价格
+
+ def on_bar(self, date, get):
+ close_prices = get('close')
+
+ # 检查止损
+ for symbol, position in self.broker.positions.items():
+ if symbol in self.entry_prices:
+ entry_price = self.entry_prices[symbol]
+ current_price = close_prices[symbol]
+ loss_rate = (current_price - entry_price) / entry_price
+
+ if loss_rate <= -self.stop_loss_rate:
+ # 触发止损
+ self.broker.sell(symbol, current_price, position['size'])
+ del self.entry_prices[symbol]
+
+ # 正常的买入逻辑
+ for symbol in close_prices.index:
+ if self.should_buy(symbol, close_prices[symbol]):
+ size = self.calculate_position_size(symbol, close_prices[symbol])
+ if self.broker.buy(symbol, close_prices[symbol], size):
+ self.entry_prices[symbol] = close_prices[symbol]
+```
+
+## 性能优化
+
+### 避免重复计算
+
+```python
+class OptimizedStrategy(qka.Strategy):
+ def __init__(self):
+ super().__init__()
+ self.cache = {} # 缓存计算结果
+
+ def on_bar(self, date, get):
+ # 缓存数据访问
+ close_prices = get('close')
+
+ for symbol in close_prices.index:
+ # 避免重复获取相同数据
+ if symbol not in self.cache:
+ self.cache[symbol] = self.calculate_indicators(symbol, get)
+
+ indicators = self.cache[symbol]
+
+ # 使用缓存的数据进行决策
+ if self.should_trade(symbol, indicators):
+ # 交易逻辑...
+ pass
+```
+
+### 批量处理
+
+```python
+class BatchStrategy(qka.Strategy):
+ def on_bar(self, date, get):
+ # 一次性获取所有需要的数据
+ close_prices = get('close')
+ volumes = get('volume')
+ ma5_values = get('ma5')
+ ma20_values = get('ma20')
+
+ # 批量计算交易信号
+ buy_signals = self.calculate_buy_signals(close_prices, volumes, ma5_values, ma20_values)
+ sell_signals = self.calculate_sell_signals(close_prices, volumes, ma5_values, ma20_values)
+
+ # 批量执行交易
+ for symbol, should_buy in buy_signals.items():
+ if should_buy:
+ self.buy(symbol, close_prices[symbol])
+
+ for symbol, should_sell in sell_signals.items():
+ if should_sell:
+ self.sell(symbol, close_prices[symbol])
+```
+
+## 高级功能
+
+### 多时间框架
+
+```python
+class MultiTimeframeStrategy(qka.Strategy):
+ def __init__(self):
+ super().__init__()
+ # 加载不同时间框架的数据
+ self.daily_data = qka.Data(symbols=['000001.SZ'], period='1d')
+ self.hourly_data = qka.Data(symbols=['000001.SZ'], period='1h')
+
+ def on_bar(self, date, get):
+ # 日线级别判断趋势
+ daily_trend = self.analyze_daily_trend()
+
+ # 小时线级别寻找入场点
+ if daily_trend == 'up':
+ hourly_signal = self.analyze_hourly_signal()
+ if hourly_signal == 'buy':
+ # 执行买入
+ pass
+```
+
+### 参数优化
+
+```python
+# 简单的参数网格搜索
+def optimize_strategy():
+ best_params = None
+ best_return = -float('inf')
+
+ for ma_short in [5, 10, 20]:
+ for ma_long in [20, 30, 50]:
+ # 使用不同参数运行回测
+ data = qka.Data(symbols=['000001.SZ'])
+ strategy = MovingAverageStrategy(ma_short, ma_long)
+ backtest = qka.Backtest(data, strategy)
+ backtest.run()
+
+ # 计算收益率
+ final_total = strategy.broker.get('total')
+ total_return = (final_total - 100000) / 100000
+
+ if total_return > best_return:
+ best_return = total_return
+ best_params = (ma_short, ma_long)
+
+ return best_params, best_return
+```
+
+## 常见问题
+
+### Q: 回测速度很慢怎么办?
+
+A: 可以尝试:
+- 减少股票数量
+- 使用更短的时间段
+- 优化策略代码,避免重复计算
+- 使用更简单的因子
+
+### Q: 如何验证策略的稳定性?
+
+A: 建议:
+- 使用不同时间段的数据进行回测
+- 进行参数敏感性分析
+- 使用交叉验证
+- 考虑交易成本和滑点
+
+### Q: 回测结果和实盘差异很大?
+
+A: 可能原因:
+- 未来函数(使用了未来数据)
+- 未考虑交易成本和滑点
+- 数据质量问题
+- 市场环境变化
+
+## 下一步
+
+- 学习 [实盘交易](trading.md) 了解如何将策略用于实盘
+- 查看 [API 文档](../api/core/backtest.md) 了解完整的回测接口
+- 参考 [示例教程](../examples/basic/simple-backtest.md) 获取更多代码示例
\ No newline at end of file
diff --git a/docs/user-guide/config.md b/docs/user-guide/config.md
deleted file mode 100644
index ec2350c..0000000
--- a/docs/user-guide/config.md
+++ /dev/null
@@ -1,322 +0,0 @@
-# 配置管理
-
-QKA 提供了强大而灵活的配置管理系统,支持多种配置方式和模块化配置。
-
-## 快速开始
-
-### 创建配置文件
-
-```python
-from qka.core.config import create_sample_config
-
-# 创建示例配置文件
-create_sample_config('my_config.json')
-```
-
-### 加载配置
-
-```python
-import qka
-from qka.core.config import load_config
-
-# 加载自定义配置
-config = load_config('my_config.json')
-
-# 使用全局配置
-print(f"初始资金: {qka.config.backtest.initial_cash:,}")
-print(f"数据源: {qka.config.data.default_source}")
-```
-
-## 配置结构
-
-### 回测配置 (BacktestConfig)
-
-```python
-# 访问回测配置
-config.backtest.initial_cash = 2_000_000 # 初始资金
-config.backtest.commission_rate = 0.0003 # 手续费率
-config.backtest.slippage = 0.001 # 滑点率
-config.backtest.min_trade_amount = 100 # 最小交易股数
-config.backtest.max_position_ratio = 0.3 # 单只股票最大仓位比例
-config.backtest.benchmark = '000300.SH' # 基准指数
-```
-
-### 数据配置 (DataConfig)
-
-```python
-# 访问数据配置
-config.data.default_source = 'akshare' # 默认数据源
-config.data.cache_enabled = True # 是否启用缓存
-config.data.cache_dir = './data_cache' # 缓存目录
-config.data.cache_expire_days = 7 # 缓存过期天数
-config.data.quality_check = True # 数据质量检查
-config.data.auto_download = True # 自动下载缺失数据
-```
-
-### 交易配置 (TradingConfig)
-
-```python
-# 访问交易配置
-config.trading.server_host = '0.0.0.0' # 服务器地址
-config.trading.server_port = 8000 # 服务器端口
-config.trading.token_auto_generate = True # 自动生成token
-config.trading.order_timeout = 30 # 订单超时时间(秒)
-config.trading.max_retry_times = 3 # 最大重试次数
-config.trading.heartbeat_interval = 30 # 心跳间隔(秒)
-```
-
-### 日志配置 (LogConfig)
-
-```python
-# 访问日志配置
-config.log.level = 'INFO' # 日志级别
-config.log.console_output = True # 控制台输出
-config.log.file_output = True # 文件输出
-config.log.log_dir = './logs' # 日志目录
-config.log.max_file_size = '10MB' # 最大文件大小
-config.log.backup_count = 10 # 备份文件数量
-```
-
-### 绘图配置 (PlotConfig)
-
-```python
-# 访问绘图配置
-config.plot.theme = 'plotly_white' # 图表主题
-config.plot.figure_height = 600 # 图表高度
-config.plot.figure_width = 1000 # 图表宽度
-config.plot.color_scheme = 'default' # 色彩方案
-config.plot.show_grid = True # 显示网格
-config.plot.auto_open = True # 自动打开图表
-```
-
-## 配置方式
-
-### 1. 配置文件
-
-创建 JSON 格式的配置文件:
-
-```json
-{
- "backtest": {
- "initial_cash": 2000000,
- "commission_rate": 0.0002,
- "benchmark": "000300.SH"
- },
- "data": {
- "default_source": "qmt",
- "cache_enabled": true,
- "cache_dir": "./cache"
- },
- "trading": {
- "server_port": 9000,
- "order_timeout": 60
- }
-}
-```
-
-加载配置:
-
-```python
-from qka.core.config import load_config
-
-config = load_config('production.json')
-```
-
-### 2. 环境变量
-
-支持通过环境变量覆盖配置:
-
-```bash
-# 设置环境变量
-export QKA_INITIAL_CASH=5000000
-export QKA_DATA_SOURCE=qmt
-export QKA_SERVER_PORT=9000
-export QKA_COMMISSION_RATE=0.0002
-export QKA_CACHE_DIR=/tmp/qka_cache
-```
-
-环境变量会自动覆盖配置文件中的值。
-
-### 3. 代码配置
-
-直接在代码中修改配置:
-
-```python
-import qka
-
-# 修改全局配置
-qka.config.backtest.initial_cash = 3_000_000
-qka.config.data.default_source = 'tushare'
-qka.config.trading.server_port = 8080
-
-# 或者创建新的配置实例
-from qka.core.config import Config
-
-custom_config = Config()
-custom_config.backtest.initial_cash = 5_000_000
-```
-
-## 高级用法
-
-### 配置继承
-
-```python
-from qka.core.config import Config
-
-# 基础配置
-base_config = Config('base.json')
-
-# 继承并修改
-prod_config = Config()
-prod_config.__dict__.update(base_config.__dict__)
-prod_config.backtest.initial_cash = 10_000_000
-prod_config.save_to_file('production.json')
-```
-
-### 动态配置更新
-
-```python
-# 运行时修改配置
-def update_config_for_market_hours():
- if is_market_open():
- qka.config.data.auto_download = True
- qka.config.trading.heartbeat_interval = 10
- else:
- qka.config.data.auto_download = False
- qka.config.trading.heartbeat_interval = 60
-```
-
-### 配置验证
-
-```python
-def validate_config(config):
- """验证配置的有效性"""
- assert config.backtest.initial_cash > 0, "初始资金必须大于0"
- assert config.backtest.commission_rate >= 0, "手续费率不能为负数"
- assert config.trading.server_port > 1024, "端口号必须大于1024"
-
- print("✅ 配置验证通过")
-
-# 使用验证
-validate_config(qka.config)
-```
-
-## 最佳实践
-
-### 1. 环境分离
-
-为不同环境创建不同的配置文件:
-
-```
-config/
-├── development.json # 开发环境
-├── testing.json # 测试环境
-├── staging.json # 预发布环境
-└── production.json # 生产环境
-```
-
-```python
-import os
-from qka.core.config import load_config
-
-# 根据环境变量选择配置
-env = os.getenv('QKA_ENV', 'development')
-config = load_config(f'config/{env}.json')
-```
-
-### 2. 敏感信息处理
-
-敏感信息(如API密钥)建议通过环境变量配置:
-
-```bash
-# .env 文件
-QKA_API_KEY=your_secret_api_key
-QKA_DATABASE_URL=postgresql://user:pass@localhost/db
-```
-
-```python
-import os
-from dotenv import load_dotenv
-
-# 加载 .env 文件
-load_dotenv()
-
-# 在配置中使用
-api_key = os.getenv('QKA_API_KEY')
-```
-
-### 3. 配置备份
-
-```python
-from qka.core.config import Config
-from datetime import datetime
-
-def backup_config():
- """备份当前配置"""
- timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
- backup_file = f'config_backup_{timestamp}.json'
- qka.config.save_to_file(backup_file)
- print(f"配置已备份到: {backup_file}")
-
-# 定期备份
-backup_config()
-```
-
-## 配置示例
-
-### 开发环境配置
-
-```json
-{
- "backtest": {
- "initial_cash": 1000000,
- "commission_rate": 0.0003
- },
- "data": {
- "default_source": "akshare",
- "cache_enabled": true,
- "cache_dir": "./dev_cache"
- },
- "log": {
- "level": "DEBUG",
- "console_output": true
- }
-}
-```
-
-### 生产环境配置
-
-```json
-{
- "backtest": {
- "initial_cash": 10000000,
- "commission_rate": 0.0002
- },
- "data": {
- "default_source": "qmt",
- "cache_enabled": true,
- "cache_dir": "/var/cache/qka"
- },
- "log": {
- "level": "INFO",
- "file_output": true,
- "log_dir": "/var/log/qka"
- },
- "trading": {
- "server_host": "0.0.0.0",
- "server_port": 8000
- }
-}
-```
-
-## API 参考
-
-配置管理的详细API参考请查看 [Config API文档](../api/core/config.md)。
-
-### 主要类和函数
-
-- **Config** - 主配置管理类
-- **load_config** - 加载配置函数
-- **create_sample_config** - 创建示例配置函数
-
-更多详细信息和使用示例请参考API文档页面。
diff --git a/docs/user-guide/data.md b/docs/user-guide/data.md
index 050e850..3b7d850 100644
--- a/docs/user-guide/data.md
+++ b/docs/user-guide/data.md
@@ -1,283 +1,243 @@
-# 数据获取
-
-QKA 提供了统一的数据获取接口,目前支持QMT和Akshare两种数据源。
-
-## 支持的数据源
-
-- **QMT** - 迅投QMT数据源,支持历史数据和实时数据
-- **Akshare** - 开源财经数据接口,支持历史数据(默认数据源)
-
-## 快速开始
-
-### 设置默认数据源
-
-```python
-import qka
-
-# 查看可用的数据源
-print(qka.get_available_sources()) # ['qmt', 'akshare']
-
-# 设置默认数据源(推荐在程序开始时设置)
-qka.set_source('akshare') # 或 'qmt'
-
-# 查看当前默认数据源
-print(qka.get_source()) # akshare
-```
-
-### 简化的数据获取
-
-设置默认数据源后,创建数据对象更加简洁:
-
-```python
-import qka
-
-# 设置默认数据源
-qka.set_source('akshare')
-
-# 创建数据对象(自动使用默认数据源)
-data_obj = qka.data(stocks=['000001', '600000'])
-
-# 获取历史数据
-hist_data = data_obj.get(
- start_time='2023-01-01',
- end_time='2023-12-31'
-)
-```
-
-## 基本用法
-
-### 使用QMT数据源
-
-```python
-import qka
-
-# 方式1:设置为默认数据源
-qka.set_source('qmt')
-data_obj = qka.data(stocks=['000001.SZ', '600000.SH'])
-
-# 方式2:临时指定数据源
-data_obj = qka.data(stocks=['000001.SZ', '600000.SH'], source='qmt')
-
-# 获取历史数据
-hist_data = data_obj.get(
- period='1d',
- start_time='2023-01-01',
- end_time='2023-12-31'
-)
-
-# 订阅实时数据(需要QMT环境)
-def on_data(code, item):
- print(f"{code}: 价格={item['lastPrice']}")
-
-data_obj.subscribe(on_data)
-```
-
-### 使用Akshare数据源
-
-```python
-import qka
-
-# 方式1:使用默认数据源(akshare为默认)
-data_obj = qka.data(stocks=['000001', '600000'])
-
-# 方式2:显式指定数据源
-data_obj = qka.data(stocks=['000001', '600000'], source='akshare')
-
-# 获取历史数据
-hist_data = data_obj.get(
- start_time='2023-01-01',
- end_time='2023-12-31'
-)
-
-# 注意:Akshare不支持实时数据订阅
-```
-
-### 板块数据获取
-
-```python
-import qka
-
-# 使用QMT获取板块股票
-qka.set_source('qmt')
-data_obj = qka.data(sector='沪深A股主板')
-
-# 使用Akshare获取沪深A股(限制前100只)
-qka.set_source('akshare')
-data_obj = qka.data(sector='沪深A股')
-
-# 获取板块内所有股票的历史数据
-hist_data = data_obj.get(start_time='2023-01-01')
-```
-
-## 扩展数据源
-
-QKA支持注册自定义数据源:
-
-```python
-import qka
-from qka.core.data.base import DataSource
-
-# 自定义数据源示例
-class TushareData(DataSource):
- def get_historical_data(self, period='1d', start_time='', end_time=''):
- # 实现tushare数据获取逻辑
- pass
-
- def subscribe_realtime(self, callback):
- # 实现实时数据订阅逻辑
- pass
-
-# 注册新数据源
-qka.register_data_source('tushare', TushareData)
-
-# 使用新数据源
-qka.set_source('tushare')
-data_obj = qka.data(stocks=['000001'])
-```
-
-## 数据格式
-
-QKA统一了不同数据源的数据格式,返回标准的pandas DataFrame:
-
-```python
-# 查看数据结构
-print(hist_data.keys()) # 获取股票列表
-print(hist_data['000001'].head()) # 查看具体股票数据
-
-# 标准数据列
-# open: 开盘价
-# high: 最高价
-# low: 最低价
-# close: 收盘价
-# volume: 成交量
-# amount: 成交额(Akshare提供)
-```
-
-## 数据源差异
-
-### QMT数据源特点
-- ✅ 支持历史数据和实时数据
-- ✅ 数据质量高,延迟低
-- ✅ 支持多种周期(日线、分钟线等)
-- ❗ 需要安装QMT软件环境
-
-### Akshare数据源特点
-- ✅ 免费开源,无需授权
-- ✅ 支持前复权数据调整
-- ✅ 安装简单,依赖较少
-- ❌ 不支持实时数据订阅
-- ❗ 仅支持日线数据
-
-## 股票代码格式
-
-不同数据源的股票代码格式:
-
-| 数据源 | 格式示例 | 说明 |
-|--------|----------|------|
-| QMT | `000001.SZ` | 带交易所后缀 |
-| QMT | `600000.SH` | 沪市股票 |
-| Akshare | `000001` | 不带后缀 |
-| Akshare | `600000` | 6位数字代码 |
-
-## 常用数据字段
-
-基础数据字段(所有数据源共有):
-
-| 字段名 | 描述 | 类型 |
-|--------|------|------|
-| open | 开盘价 | float |
-| high | 最高价 | float |
-| low | 最低价 | float |
-| close | 收盘价 | float |
-| volume | 成交量 | int |
-
-Akshare额外提供的字段:
-
-| 字段名 | 描述 | 类型 |
-|--------|------|------|
-| amount | 成交额 | float |
-
-## 错误处理
-
-```python
-try:
- # 使用新的API方式
- qka.set_source('qmt')
- data_obj = qka.data(stocks=['000001.SZ'])
- hist_data = data_obj.get(start_time='2023-01-01')
-except ImportError as e:
- print(f"数据源依赖缺失: {e}")
-except Exception as e:
- print(f"数据获取失败: {e}")
-```
-
-## 注意事项
-
-1. **默认数据源设置**:建议在程序开始时设置默认数据源,避免重复指定
-2. **QMT环境依赖**:使用QMT数据源需要安装QMT软件和xtquant库
-3. **Akshare限制**:仅支持日线数据,不支持实时数据订阅
-4. **股票代码格式**:QMT需要带交易所后缀,Akshare使用6位数字代码
-5. **数据获取频率**:避免过于频繁的API调用
-6. **数据源扩展**:可以通过`register_data_source()`注册自定义数据源
-
-## API参考
-
-### 配置函数
-
-- `qka.set_source(source)` - 设置默认数据源
-- `qka.get_source()` - 获取当前默认数据源
-- `qka.get_available_sources()` - 获取所有可用数据源
-- `qka.register_data_source(name, class)` - 注册新数据源
-
-### 工厂函数
-
-- `qka.data(stocks=None, sector=None, source=None)` - 创建数据对象
-
-### Data对象方法
-
-- `data_obj.get(period='1d', start_time='', end_time='')` - 获取历史数据
-- `data_obj.subscribe(callback)` - 订阅实时数据
-- `data_obj.stocks` - 获取股票列表
-
-## 完整示例
-
-### 基础使用流程
-
-```python
-import qka
-
-# 1. 设置默认数据源
-qka.set_source('akshare')
-
-# 2. 创建数据对象
-data_obj = qka.data(stocks=['000001', '600000'])
-
-# 3. 获取历史数据
-hist_data = data_obj.get(start_time='2023-01-01', end_time='2023-12-31')
-
-# 4. 查看数据
-for stock_code, df in hist_data.items():
- print(f"\n{stock_code} 数据概览:")
- print(df.head())
- print(f"数据行数: {len(df)}")
-```
-
-### 混合使用多个数据源
-
-```python
-import qka
-
-# 设置默认数据源为akshare
-qka.set_source('akshare')
-
-# 大部分使用默认数据源
-data_ak = qka.data(stocks=['000001', '600000'])
-hist_data_ak = data_ak.get(start_time='2023-01-01')
-
-# 临时使用QMT获取实时数据
-data_qmt = qka.data(stocks=['000001.SZ'], source='qmt')
-def on_realtime_data(code, item):
- print(f"实时数据 - {code}: {item['lastPrice']}")
-
-data_qmt.subscribe(on_realtime_data)
-```
+# 数据获取
+
+QKA 提供统一的数据获取接口,支持多种数据源和灵活的数据处理。
+
+## 基本用法
+
+### 创建数据对象
+
+```python
+import qka
+
+# 最简单的数据获取
+data = qka.Data(symbols=['000001.SZ', '600000.SH'])
+df = data.get()
+```
+
+### 参数说明
+
+```python
+data = qka.Data(
+ symbols=['000001.SZ', '600000.SH'], # 股票代码列表
+ period='1d', # 数据周期
+ adjust='qfq', # 复权方式
+ source='akshare', # 数据源
+ pool_size=10, # 并发线程数
+ datadir='./mydata' # 缓存目录
+)
+```
+
+## 数据周期
+
+支持多种数据周期:
+
+```python
+# 日线数据
+daily_data = qka.Data(symbols=['000001.SZ'], period='1d')
+
+# 分钟线数据(如果数据源支持)
+minute_data = qka.Data(symbols=['000001.SZ'], period='1m')
+
+# 周线数据
+weekly_data = qka.Data(symbols=['000001.SZ'], period='1w')
+```
+
+## 复权方式
+
+支持三种复权方式:
+
+```python
+# 前复权(推荐)
+qfq_data = qka.Data(symbols=['000001.SZ'], adjust='qfq')
+
+# 后复权
+hfq_data = qka.Data(symbols=['000001.SZ'], adjust='hfq')
+
+# 不复权
+bfq_data = qka.Data(symbols=['000001.SZ'], adjust='bfq')
+```
+
+## 数据源配置
+
+### Akshare 数据源
+
+Akshare 是默认的数据源,提供丰富的 A 股数据:
+
+```python
+data = qka.Data(
+ symbols=['000001.SZ', '600000.SH'],
+ source='akshare'
+)
+```
+
+### 自定义数据源
+
+你可以扩展 Data 类来支持其他数据源:
+
+```python
+class MyData(qka.Data):
+ def _get_from_custom_source(self, symbol: str):
+ # 实现自定义数据获取逻辑
+ pass
+```
+
+## 因子计算
+
+### 内置因子
+
+数据获取时自动包含基础因子:
+
+- `open`: 开盘价
+- `high`: 最高价
+- `low`: 最低价
+- `close`: 收盘价
+- `volume`: 成交量
+- `amount`: 成交额
+
+### 自定义因子
+
+可以通过 `factor` 参数添加自定义因子:
+
+```python
+def add_technical_indicators(df):
+ """添加技术指标"""
+ # 移动平均
+ df['ma5'] = df['close'].rolling(5).mean()
+ df['ma20'] = df['close'].rolling(20).mean()
+
+ # 相对强弱指标 (RSI)
+ delta = df['close'].diff()
+ gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
+ loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
+ rs = gain / loss
+ df['rsi'] = 100 - (100 / (1 + rs))
+
+ return df
+
+data = qka.Data(
+ symbols=['000001.SZ'],
+ factor=add_technical_indicators
+)
+```
+
+## 并发下载
+
+使用多线程并发下载提高效率:
+
+```python
+# 设置并发线程数
+data = qka.Data(
+ symbols=large_stock_list, # 大量股票
+ pool_size=20 # 增加并发数
+)
+```
+
+## 数据缓存
+
+### 自动缓存
+
+数据会自动缓存到本地,避免重复下载:
+
+```python
+# 第一次下载数据
+data1 = qka.Data(symbols=['000001.SZ'])
+df1 = data1.get() # 下载并缓存
+
+# 第二次使用相同参数,直接从缓存读取
+data2 = qka.Data(symbols=['000001.SZ'])
+df2 = data2.get() # 从缓存读取
+```
+
+### 自定义缓存目录
+
+```python
+from pathlib import Path
+
+data = qka.Data(
+ symbols=['000001.SZ'],
+ datadir=Path('/path/to/cache') # 自定义缓存目录
+)
+```
+
+## 数据格式
+
+### 返回数据格式
+
+`data.get()` 返回 Dask DataFrame,每只股票的列名格式为 `{symbol}_{column}`:
+
+```python
+df = data.get()
+print(df.columns)
+# 输出: ['000001.SZ_open', '000001.SZ_high', '000001.SZ_low',
+# '000001.SZ_close', '000001.SZ_volume', '000001.SZ_amount',
+# '600000.SH_open', ...]
+```
+
+### 数据访问
+
+```python
+# 获取特定股票的数据
+stock_000001 = df[['000001.SZ_open', '000001.SZ_close']]
+
+# 获取特定因子的所有股票数据
+all_close = df[[col for col in df.columns if col.endswith('_close')]]
+```
+
+## 高级用法
+
+### 批量处理大量股票
+
+```python
+# 获取A股所有股票列表(需要akshare)
+import akshare as ak
+stock_list = ak.stock_info_a_code_name()['code'].tolist()
+
+# 分批处理
+batch_size = 100
+for i in range(0, len(stock_list), batch_size):
+ batch = stock_list[i:i+batch_size]
+ data = qka.Data(symbols=batch, pool_size=10)
+ df_batch = data.get()
+ # 处理这批数据...
+```
+
+### 数据更新
+
+```python
+# 强制更新缓存(重新下载)
+import shutil
+shutil.rmtree('datadir') # 删除缓存目录
+
+# 或者指定新的缓存目录
+data = qka.Data(symbols=['000001.SZ'], datadir='./new_cache')
+```
+
+## 性能优化建议
+
+1. **合理设置并发数**: 根据网络情况和系统资源调整 `pool_size`
+2. **使用缓存**: 充分利用数据缓存避免重复下载
+3. **分批处理**: 对于大量股票,分批处理避免内存不足
+4. **选择合适的周期**: 根据策略需求选择合适的数据周期
+
+## 常见问题
+
+### Q: 数据下载失败怎么办?
+
+A: 检查网络连接,确认股票代码格式正确,可以尝试:
+- 减少并发数
+- 更换数据源
+- 检查股票代码是否有效
+
+### Q: 如何获取实时数据?
+
+A: 目前主要支持历史数据,实时数据可以通过 QMT 接口获取。
+
+### Q: 数据包含哪些时间段?
+
+A: 默认包含该股票的所有可用历史数据。
+
+## 下一步
+
+- 学习 [回测分析](backtest.md) 了解如何使用数据进行策略回测
+- 查看 [API 文档](../api/core/data.md) 了解完整的数据接口
+- 参考 [示例教程](../examples/basic/data-fetching.md) 获取更多代码示例
\ No newline at end of file
diff --git a/docs/user-guide/events.md b/docs/user-guide/events.md
deleted file mode 100644
index 14d9997..0000000
--- a/docs/user-guide/events.md
+++ /dev/null
@@ -1,414 +0,0 @@
-# 事件系统
-
-QKA 采用事件驱动架构,通过发布-订阅模式实现模块间的松耦合通信。事件系统让您可以监听和响应系统中发生的各种事件。
-
-## 为什么使用事件系统?
-
-!!! tip "事件系统的优势"
- - 🔗 **松耦合** - 模块间无需直接依赖
- - 📡 **实时响应** - 立即响应系统事件
- - 🔧 **易扩展** - 轻松添加新的事件处理逻辑
- - 📊 **可监控** - 完整的事件历史和统计
-
-## 快速开始
-
-### 启动事件系统
-
-```python
-from qka.core.events import start_event_engine, stop_event_engine
-
-# 启动事件引擎
-start_event_engine()
-
-# 程序结束时停止
-stop_event_engine()
-```
-
-### 监听事件
-
-使用装饰器方式监听事件:
-
-```python
-from qka.core.events import EventType, event_handler
-
-@event_handler(EventType.DATA_LOADED)
-def on_data_loaded(event):
- print(f"数据加载完成: {event.data}")
-
-@event_handler(EventType.ORDER_FILLED)
-def on_order_filled(event):
- print(f"订单成交: {event.data}")
-```
-
-### 发送事件
-
-```python
-from qka.core.events import emit_event
-
-# 发送数据加载事件
-emit_event(EventType.DATA_LOADED, {
- "symbol": "000001.SZ",
- "rows": 1000,
- "timespan": "2023-01-01 to 2023-12-31"
-})
-
-# 发送订单成交事件
-emit_event(EventType.ORDER_FILLED, {
- "order_id": "12345",
- "symbol": "000001.SZ",
- "price": 10.50,
- "quantity": 1000
-})
-```
-
-## 事件类型详解
-
-### 数据相关事件
-
-#### DATA_LOADED - 数据加载完成
-当数据成功加载时触发。
-
-```python
-@event_handler(EventType.DATA_LOADED)
-def on_data_loaded(event):
- data = event.data
- print(f"加载了 {data['symbol']} 的 {data['rows']} 条数据")
-```
-
-**事件数据示例**:
-```python
-{
- "symbol": "000001.SZ",
- "rows": 1000,
- "timespan": "2023-01-01 to 2023-12-31",
- "source": "akshare"
-}
-```
-
-#### DATA_ERROR - 数据加载错误
-当数据加载失败时触发。
-
-```python
-@event_handler(EventType.DATA_ERROR)
-def on_data_error(event):
- error = event.data
- print(f"数据加载失败: {error['message']}")
-```
-
-### 交易相关事件
-
-#### ORDER_CREATED - 订单创建
-当新订单被创建时触发。
-
-```python
-@event_handler(EventType.ORDER_CREATED)
-def on_order_created(event):
- order = event.data
- print(f"创建订单: {order['action']} {order['symbol']} @ {order['price']}")
-```
-
-#### ORDER_FILLED - 订单成交
-当订单成交时触发。
-
-```python
-@event_handler(EventType.ORDER_FILLED)
-def on_order_filled(event):
- trade = event.data
- print(f"订单成交: {trade['symbol']} 成交价 {trade['price']}")
-```
-
-#### ORDER_CANCELLED - 订单取消
-当订单被取消时触发。
-
-```python
-@event_handler(EventType.ORDER_CANCELLED)
-def on_order_cancelled(event):
- order = event.data
- print(f"订单取消: {order['order_id']}")
-```
-
-### 策略相关事件
-
-#### STRATEGY_START - 策略开始
-当策略开始运行时触发。
-
-```python
-@event_handler(EventType.STRATEGY_START)
-def on_strategy_start(event):
- strategy = event.data
- print(f"策略 {strategy['name']} 开始运行")
-```
-
-#### SIGNAL_GENERATED - 信号生成
-当策略生成交易信号时触发。
-
-```python
-@event_handler(EventType.SIGNAL_GENERATED)
-def on_signal_generated(event):
- signal = event.data
- print(f"信号: {signal['action']} {signal['symbol']}")
-
- # 可以在这里添加信号过滤、风险检查等逻辑
- if signal['strength'] > 0.8:
- print("强信号,建议关注!")
-```
-
-## 高级用法
-
-### 自定义事件处理器
-
-创建自定义的事件处理器类:
-
-```python
-from qka.core.events import EventHandler, Event
-
-class TradingEventHandler(EventHandler):
- def __init__(self):
- self.order_count = 0
- self.total_volume = 0
-
- def handle(self, event: Event):
- if event.event_type == EventType.ORDER_FILLED:
- self.order_count += 1
- self.total_volume += event.data.get('quantity', 0)
- print(f"总订单数: {self.order_count}, 总成交量: {self.total_volume}")
-
- def can_handle(self, event: Event) -> bool:
- return event.event_type == EventType.ORDER_FILLED
-
-# 注册处理器
-from qka.core.events import event_engine
-
-handler = TradingEventHandler()
-event_engine.subscribe(EventType.ORDER_FILLED, handler)
-```
-
-### 事件过滤
-
-只处理特定条件的事件:
-
-```python
-@event_handler(EventType.SIGNAL_GENERATED)
-def handle_strong_signals(event):
- signal = event.data
-
- # 只处理强信号
- if signal.get('strength', 0) > 0.8:
- print(f"收到强信号: {signal}")
- # 执行相应操作
-```
-
-### 异步事件处理
-
-```python
-from qka.core.events import AsyncEventHandler
-import asyncio
-
-class AsyncOrderHandler(AsyncEventHandler):
- async def handle_async(self, event: Event):
- if event.event_type == EventType.ORDER_FILLED:
- # 异步处理订单
- await self.update_portfolio(event.data)
- await self.send_notification(event.data)
-
- async def update_portfolio(self, order_data):
- # 模拟异步数据库操作
- await asyncio.sleep(0.1)
- print(f"组合更新完成: {order_data}")
-
- async def send_notification(self, order_data):
- # 模拟异步通知发送
- await asyncio.sleep(0.1)
- print(f"通知已发送: {order_data}")
-```
-
-## 事件统计和监控
-
-### 查看事件统计
-
-```python
-from qka.core.events import event_engine
-
-# 获取统计信息
-stats = event_engine.get_statistics()
-
-print(f"事件计数: {stats['event_count']}")
-print(f"错误计数: {stats['error_count']}")
-print(f"队列大小: {stats['queue_size']}")
-print(f"处理器数量: {stats['handler_count']}")
-print(f"运行状态: {stats['is_running']}")
-```
-
-### 查看事件历史
-
-```python
-# 获取所有事件历史
-all_events = event_engine.get_event_history(limit=100)
-
-# 获取特定类型的事件历史
-order_events = event_engine.get_event_history(
- event_type=EventType.ORDER_FILLED,
- limit=50
-)
-
-for event in order_events:
- print(f"{event.timestamp}: {event.data}")
-```
-
-## 在策略中使用事件
-
-### 事件驱动的策略
-
-```python
-from qka.core.backtest import Strategy
-from qka.core.events import EventType, emit_event
-
-class EventDrivenStrategy(Strategy):
- def on_start(self, broker):
- # 策略开始时发送事件
- emit_event(EventType.STRATEGY_START, {
- "strategy": self.name,
- "initial_cash": broker.initial_cash
- })
-
- def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- if len(df) >= 20:
- current_price = df['close'].iloc[-1]
- ma20 = df['close'].rolling(20).mean().iloc[-1]
-
- # 生成信号事件
- if current_price > ma20:
- emit_event(EventType.SIGNAL_GENERATED, {
- "symbol": symbol,
- "action": "BUY",
- "price": current_price,
- "strength": 0.8,
- "reason": "价格突破20日均线"
- })
-
- # 执行买入
- if broker.buy(symbol, 0.3, current_price):
- emit_event(EventType.ORDER_FILLED, {
- "symbol": symbol,
- "action": "BUY",
- "price": current_price,
- "quantity": broker.get_position(symbol)
- })
-```
-
-### 事件监听器
-
-```python
-# 策略性能监控
-@event_handler(EventType.ORDER_FILLED)
-def monitor_strategy_performance(event):
- order = event.data
-
- # 记录交易日志
- with open('trades.log', 'a') as f:
- f.write(f"{event.timestamp}: {order}\n")
-
- # 计算收益
- if order['action'] == 'SELL':
- # 计算这笔交易的盈亏
- pass
-
-# 风险监控
-@event_handler(EventType.SIGNAL_GENERATED)
-def risk_monitor(event):
- signal = event.data
-
- # 检查是否有过度交易
- if signal['strength'] < 0.5:
- print(f"⚠️ 弱信号警告: {signal}")
-
- # 检查仓位集中度
- # ...
-```
-
-## 最佳实践
-
-### 1. 事件命名
-
-为自定义事件使用清晰的命名:
-
-```python
-# 好的命名
-EventType.PORTFOLIO_REBALANCED
-EventType.RISK_LIMIT_EXCEEDED
-EventType.MARKET_DATA_UPDATED
-
-# 避免的命名
-EventType.EVENT1
-EventType.SOMETHING_HAPPENED
-```
-
-### 2. 事件数据结构
-
-保持事件数据结构的一致性:
-
-```python
-# 推荐的事件数据结构
-{
- "timestamp": "2023-12-01T10:30:00",
- "symbol": "000001.SZ",
- "action": "BUY",
- "price": 10.50,
- "quantity": 1000,
- "metadata": {
- "strategy": "MA_CROSS",
- "signal_strength": 0.85
- }
-}
-```
-
-### 3. 错误处理
-
-在事件处理器中添加适当的错误处理:
-
-```python
-@event_handler(EventType.ORDER_FILLED)
-def safe_order_handler(event):
- try:
- # 处理订单逻辑
- process_order(event.data)
- except Exception as e:
- print(f"处理订单事件时出错: {e}")
- # 发送错误事件
- emit_event(EventType.ORDER_ERROR, {
- "original_event": event.to_dict(),
- "error": str(e)
- })
-```
-
-### 4. 性能考虑
-
-避免在事件处理器中执行耗时操作:
-
-```python
-# ❌ 避免在事件处理器中执行耗时操作
-@event_handler(EventType.DATA_LOADED)
-def slow_handler(event):
- time.sleep(5) # 这会阻塞事件队列
-
-# ✅ 使用异步处理或后台任务
-@event_handler(EventType.DATA_LOADED)
-def fast_handler(event):
- # 快速处理或提交到后台队列
- background_queue.put(event.data)
-```
-
-## API 参考
-
-事件系统的详细API参考请查看 [Events API文档](../api/core/events.md)。
-
-### 主要类和函数
-
-- **EventBus** - 事件总线
-- **Event** - 基础事件类
-- **MarketDataEvent** - 市场数据事件
-- **OrderEvent** - 订单事件
-- **TradeEvent** - 交易事件
-
-更多详细信息和使用示例请参考API文档页面。
diff --git a/docs/user-guide/logging.md b/docs/user-guide/logging.md
deleted file mode 100644
index 9feffac..0000000
--- a/docs/user-guide/logging.md
+++ /dev/null
@@ -1,522 +0,0 @@
-# 日志系统
-
-QKA 提供了强大而灵活的日志系统,支持彩色输出、结构化日志、文件轮转和远程通知等功能。
-
-## 为什么需要好的日志系统?
-
-!!! tip "日志系统的重要性"
- - 🐛 **问题诊断** - 快速定位和解决问题
- - 📊 **性能监控** - 监控系统运行状态
- - 🔍 **行为追踪** - 记录用户操作和系统行为
- - 📈 **数据分析** - 提供业务分析数据
- - ⚠️ **告警通知** - 及时发现系统异常
-
-## 快速开始
-
-### 基础日志记录
-
-```python
-from qka.utils.logger import create_logger
-
-# 创建日志记录器
-logger = create_logger('my_app')
-
-# 记录不同级别的日志
-logger.debug("调试信息:变量值为 x=10")
-logger.info("程序正常运行")
-logger.warning("这是一个警告")
-logger.error("发生错误")
-logger.critical("严重错误,程序可能无法继续")
-```
-
-### 彩色日志输出
-
-```python
-# 启用彩色控制台输出
-logger = create_logger('my_app', colored_console=True)
-
-logger.debug("调试信息") # 青色
-logger.info("普通信息") # 绿色
-logger.warning("警告信息") # 黄色
-logger.error("错误信息") # 红色
-logger.critical("严重错误") # 紫色
-```
-
-## 日志配置
-
-### 基本配置
-
-```python
-from qka.utils.logger import create_logger
-
-logger = create_logger(
- name='my_app', # 日志记录器名称
- level='INFO', # 日志级别: DEBUG, INFO, WARNING, ERROR, CRITICAL
- console_output=True, # 是否输出到控制台
- file_output=True, # 是否输出到文件
- log_dir='logs', # 日志文件目录
- max_file_size='10MB', # 最大文件大小
- backup_count=10, # 备份文件数量
- json_format=False, # 是否使用JSON格式
- colored_console=True # 控制台是否使用颜色
-)
-```
-
-### 使用配置文件
-
-```python
-import qka
-from qka.utils.logger import setup_logging_from_config
-
-# 使用全局配置
-logger = create_logger(
- level=qka.config.log.level,
- log_dir=qka.config.log.log_dir,
- max_file_size=qka.config.log.max_file_size,
- backup_count=qka.config.log.backup_count
-)
-```
-
-## 结构化日志
-
-### 基础结构化日志
-
-```python
-from qka.utils.logger import get_structured_logger
-
-# 创建结构化日志记录器
-struct_logger = get_structured_logger('my_app')
-
-# 记录带有额外字段的日志
-struct_logger.info("用户登录",
- user_id=12345,
- ip="192.168.1.100",
- action="login",
- success=True)
-
-struct_logger.error("交易失败",
- symbol="000001.SZ",
- reason="余额不足",
- amount=10000,
- user_id=12345)
-```
-
-### 交易日志示例
-
-```python
-# 记录订单信息
-struct_logger.info("订单创建",
- order_id="ORD001",
- symbol="000001.SZ",
- side="BUY",
- quantity=1000,
- price=10.50,
- strategy="MA_CROSS")
-
-# 记录成交信息
-struct_logger.info("订单成交",
- order_id="ORD001",
- fill_price=10.48,
- fill_quantity=1000,
- commission=3.14,
- timestamp="2023-12-01T10:30:00")
-
-# 记录策略信号
-struct_logger.info("信号生成",
- strategy="MA_CROSS",
- symbol="000001.SZ",
- signal="BUY",
- strength=0.85,
- indicators={
- "ma5": 10.45,
- "ma20": 10.30,
- "volume": 1500000
- })
-```
-
-## 文件日志管理
-
-### 自动文件轮转
-
-QKA 支持自动文件轮转,防止日志文件过大:
-
-```python
-logger = create_logger(
- 'my_app',
- max_file_size='50MB', # 单个文件最大50MB
- backup_count=20 # 保留20个备份文件
-)
-```
-
-文件结构示例:
-```
-logs/
-├── 2023-12-01.log # 当前日志文件
-├── 2023-12-01.log.1 # 备份文件1
-├── 2023-12-01.log.2 # 备份文件2
-└── ...
-```
-
-### JSON格式日志
-
-适合后续分析和处理:
-
-```python
-logger = create_logger('my_app', json_format=True)
-
-logger.info("这将以JSON格式记录", extra_field="value")
-```
-
-JSON输出示例:
-```json
-{
- "timestamp": "2023-12-01T10:30:00.123456",
- "level": "INFO",
- "logger": "my_app",
- "message": "这将以JSON格式记录",
- "module": "main",
- "function": "main",
- "line": 15,
- "extra_field": "value"
-}
-```
-
-## 远程通知
-
-### 微信群通知
-
-为重要错误添加微信群通知:
-
-```python
-from qka.utils.logger import add_wechat_handler
-
-# 添加微信通知(只通知ERROR级别及以上)
-webhook_url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
-add_wechat_handler(logger, webhook_url, level='ERROR')
-
-# 现在ERROR和CRITICAL级别的日志会发送到微信群
-logger.error("这条错误信息会发送到微信群")
-logger.critical("这条严重错误也会发送到微信群")
-logger.warning("这条警告不会发送到微信群")
-```
-
-### 自定义通知处理器
-
-```python
-import requests
-from qka.utils.logger import logger
-
-class SlackHandler(logging.Handler):
- def __init__(self, webhook_url):
- super().__init__()
- self.webhook_url = webhook_url
-
- def emit(self, record):
- message = self.format(record)
- payload = {"text": message}
- try:
- requests.post(self.webhook_url, json=payload)
- except Exception as e:
- print(f"发送Slack消息失败: {e}")
-
-# 添加Slack通知
-slack_handler = SlackHandler("YOUR_SLACK_WEBHOOK_URL")
-slack_handler.setLevel(logging.ERROR)
-logger.addHandler(slack_handler)
-```
-
-## 在策略中使用日志
-
-### 策略日志记录
-
-```python
-from qka.core.backtest import Strategy
-from qka.utils.logger import create_logger
-
-class LoggedStrategy(Strategy):
- def __init__(self):
- super().__init__()
- # 为策略创建专用日志记录器
- self.logger = create_logger(f'strategy_{self.name}', colored_console=True)
-
- def on_start(self, broker):
- self.logger.info(f"策略启动",
- strategy=self.name,
- initial_cash=broker.initial_cash,
- commission_rate=broker.commission_rate)
-
- def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- if len(df) >= 20:
- current_price = df['close'].iloc[-1]
- ma20 = df['close'].rolling(20).mean().iloc[-1]
-
- if current_price > ma20 and broker.get_position(symbol) == 0:
- self.logger.info(f"买入信号",
- symbol=symbol,
- price=current_price,
- ma20=ma20,
- signal_strength=(current_price - ma20) / ma20)
-
- if broker.buy(symbol, 0.3, current_price):
- self.logger.info(f"买入成功",
- symbol=symbol,
- price=current_price,
- quantity=broker.get_position(symbol),
- cash_remaining=broker.get_cash())
- else:
- self.logger.warning(f"买入失败",
- symbol=symbol,
- price=current_price,
- reason="资金不足或其他原因")
-
- elif current_price < ma20 and broker.get_position(symbol) > 0:
- self.logger.info(f"卖出信号",
- symbol=symbol,
- price=current_price,
- ma20=ma20,
- position=broker.get_position(symbol))
-
- if broker.sell(symbol, 1.0, current_price):
- self.logger.info(f"卖出成功",
- symbol=symbol,
- price=current_price,
- cash_after=broker.get_cash())
-
- def on_end(self, broker):
- final_value = broker.get_total_value({})
- self.logger.info(f"策略结束",
- strategy=self.name,
- final_value=final_value,
- return_rate=(final_value - broker.initial_cash) / broker.initial_cash,
- total_trades=len(broker.trades))
-```
-
-### 交易日志分析
-
-```python
-import json
-from datetime import datetime
-
-def analyze_trading_logs(log_file):
- """分析交易日志文件"""
- trades = []
-
- with open(log_file, 'r', encoding='utf-8') as f:
- for line in f:
- if '买入成功' in line or '卖出成功' in line:
- # 解析日志行(如果是JSON格式)
- try:
- log_data = json.loads(line)
- trades.append(log_data)
- except:
- # 普通格式的解析
- pass
-
- # 分析交易数据
- print(f"总交易次数: {len(trades)}")
- return trades
-
-# 使用示例
-trades = analyze_trading_logs('logs/strategy_MA_CROSS.log')
-```
-
-## 性能监控日志
-
-### 函数执行时间记录
-
-```python
-from qka.utils.tools import timer
-from qka.utils.logger import create_logger
-
-logger = create_logger('performance')
-
-@timer
-def slow_function():
- """这个装饰器会自动记录执行时间"""
- import time
- time.sleep(1)
- return "完成"
-
-# 手动记录性能
-import time
-
-def manual_timing_example():
- start_time = time.time()
-
- # 执行一些操作
- result = complex_calculation()
-
- end_time = time.time()
- logger.info("计算完成",
- function="complex_calculation",
- execution_time=end_time - start_time,
- result_size=len(result))
-```
-
-### 内存使用监控
-
-```python
-import psutil
-import os
-
-def log_memory_usage():
- process = psutil.Process(os.getpid())
- memory_info = process.memory_info()
-
- logger.info("内存使用情况",
- rss_mb=memory_info.rss / 1024 / 1024, # 物理内存
- vms_mb=memory_info.vms / 1024 / 1024, # 虚拟内存
- cpu_percent=process.cpu_percent())
-
-# 定期记录内存使用
-import threading
-import time
-
-def memory_monitor():
- while True:
- log_memory_usage()
- time.sleep(60) # 每分钟记录一次
-
-# 启动内存监控线程
-monitor_thread = threading.Thread(target=memory_monitor, daemon=True)
-monitor_thread.start()
-```
-
-## 日志最佳实践
-
-### 1. 日志级别使用
-
-```python
-# DEBUG - 详细的诊断信息,仅在诊断问题时使用
-logger.debug(f"计算中间结果: ma5={ma5}, ma20={ma20}")
-
-# INFO - 一般信息,记录程序正常运行状态
-logger.info("策略开始运行", strategy="MA_CROSS")
-
-# WARNING - 警告信息,程序可以继续运行但需要注意
-logger.warning("数据缺失", symbol="000001.SZ", missing_days=3)
-
-# ERROR - 错误信息,功能无法正常执行但程序可以继续
-logger.error("订单下单失败", symbol="000001.SZ", reason="余额不足")
-
-# CRITICAL - 严重错误,程序可能无法继续运行
-logger.critical("数据库连接失败", error="连接超时")
-```
-
-### 2. 敏感信息处理
-
-```python
-# ❌ 不要记录敏感信息
-logger.info("用户登录", password="123456", api_key="secret_key")
-
-# ✅ 正确的做法
-logger.info("用户登录",
- user_id="12345",
- ip="192.168.1.100",
- # 密码和API密钥不记录
- login_method="password")
-```
-
-### 3. 结构化信息
-
-```python
-# ❌ 字符串拼接,难以解析
-logger.info(f"用户{user_id}在{timestamp}买入{symbol}数量{quantity}")
-
-# ✅ 结构化记录,便于后续分析
-logger.info("用户下单",
- user_id=user_id,
- timestamp=timestamp,
- action="BUY",
- symbol=symbol,
- quantity=quantity)
-```
-
-### 4. 异常记录
-
-```python
-try:
- result = risky_operation()
-except Exception as e:
- # 记录完整的异常信息
- logger.error("操作失败",
- operation="risky_operation",
- error_type=type(e).__name__,
- error_message=str(e),
- exc_info=True) # 包含完整的堆栈跟踪
-```
-
-## 日志分析工具
-
-### 实时日志监控
-
-```python
-import subprocess
-import re
-
-def tail_logs(log_file, pattern=None):
- """实时监控日志文件"""
- process = subprocess.Popen(['tail', '-f', log_file],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- universal_newlines=True)
-
- try:
- for line in iter(process.stdout.readline, ''):
- if pattern is None or re.search(pattern, line):
- print(line.strip())
- except KeyboardInterrupt:
- process.terminate()
-
-# 使用示例
-# tail_logs('logs/2023-12-01.log', 'ERROR') # 只显示错误日志
-```
-
-### 日志统计
-
-```python
-import re
-from collections import defaultdict
-
-def analyze_log_file(log_file):
- """分析日志文件统计信息"""
- level_counts = defaultdict(int)
- error_types = defaultdict(int)
-
- with open(log_file, 'r', encoding='utf-8') as f:
- for line in f:
- # 统计日志级别
- if match := re.search(r'\[(DEBUG|INFO|WARNING|ERROR|CRITICAL)\]', line):
- level_counts[match.group(1)] += 1
-
- # 统计错误类型
- if 'ERROR' in line and '失败' in line:
- if '下单失败' in line:
- error_types['下单失败'] += 1
- elif '数据获取失败' in line:
- error_types['数据获取失败'] += 1
-
- print("日志级别统计:")
- for level, count in level_counts.items():
- print(f" {level}: {count}")
-
- print("\n错误类型统计:")
- for error_type, count in error_types.items():
- print(f" {error_type}: {count}")
-
-# 使用示例
-analyze_log_file('logs/2023-12-01.log')
-```
-
-## API 参考
-
-日志系统的详细API参考请查看 [Logger API文档](../api/utils/logger.md)。
-
-### 主要类和函数
-
-- **Logger** - 增强日志记录器
-- **ColorFormatter** - 彩色日志格式化器
-- **StructuredLogger** - 结构化日志记录器
-
-更多详细信息和使用示例请参考API文档页面。
diff --git a/docs/user-guide/strategy.md b/docs/user-guide/strategy.md
deleted file mode 100644
index b8c3c74..0000000
--- a/docs/user-guide/strategy.md
+++ /dev/null
@@ -1,340 +0,0 @@
-# 策略开发
-
-QKA 提供了灵活的策略开发框架,支持多种交易策略模式。
-
-## 策略基类
-
-所有策略都需要继承 `Strategy` 基类:
-
-```python
-from qka.core.backtest import Strategy
-
-class MyStrategy(Strategy):
- def __init__(self):
- super().__init__()
- self.name = "我的策略"
- self.description = "策略描述"
-
- def on_init(self):
- """策略初始化"""
- self.log("策略初始化完成")
-
- def on_data(self, data):
- """数据更新时调用"""
- # 策略逻辑
- pass
-
- def on_order(self, order):
- """订单状态变化时调用"""
- self.log(f"订单状态: {order.status}")
-
- def on_trade(self, trade):
- """成交时调用"""
- self.log(f"成交: {trade.symbol} {trade.volume}股")
-```
-
-## 简单策略示例
-
-### 均线策略
-
-```python
-import pandas as pd
-from qka.core.backtest import Strategy
-
-class MovingAverageStrategy(Strategy):
- def __init__(self, short_window=20, long_window=50):
- super().__init__()
- self.short_window = short_window
- self.long_window = long_window
- self.name = f"MA策略({short_window}/{long_window})"
-
- def on_init(self):
- # 订阅数据
- self.subscribe('000001.SZ')
-
- # 初始化指标
- self.short_ma = {}
- self.long_ma = {}
-
- def on_data(self, data):
- for symbol in data.index:
- # 计算移动平均线
- prices = self.get_price_history(symbol, self.long_window)
- if len(prices) < self.long_window:
- continue
-
- short_ma = prices[-self.short_window:].mean()
- long_ma = prices.mean()
-
- prev_short = self.short_ma.get(symbol, 0)
- prev_long = self.long_ma.get(symbol, 0)
-
- # 金叉买入
- if short_ma > long_ma and prev_short <= prev_long:
- if not self.get_position(symbol):
- self.buy(symbol, 100)
- self.log(f"{symbol} 金叉买入")
-
- # 死叉卖出
- elif short_ma < long_ma and prev_short >= prev_long:
- if self.get_position(symbol):
- self.sell(symbol, self.get_position(symbol).volume)
- self.log(f"{symbol} 死叉卖出")
-
- self.short_ma[symbol] = short_ma
- self.long_ma[symbol] = long_ma
-```
-
-### 布林带策略
-
-```python
-class BollingerBandStrategy(Strategy):
- def __init__(self, window=20, num_std=2):
- super().__init__()
- self.window = window
- self.num_std = num_std
- self.name = f"布林带策略({window}, {num_std})"
-
- def calculate_bollinger_bands(self, prices):
- """计算布林带"""
- rolling_mean = prices.rolling(window=self.window).mean()
- rolling_std = prices.rolling(window=self.window).std()
-
- upper_band = rolling_mean + (rolling_std * self.num_std)
- lower_band = rolling_mean - (rolling_std * self.num_std)
-
- return upper_band, rolling_mean, lower_band
-
- def on_data(self, data):
- for symbol in data.index:
- prices = self.get_price_history(symbol, self.window + 10)
- if len(prices) < self.window:
- continue
-
- upper, middle, lower = self.calculate_bollinger_bands(prices)
- current_price = data.loc[symbol, 'close']
-
- position = self.get_position(symbol)
-
- # 价格触及下轨买入
- if current_price <= lower.iloc[-1] and not position:
- self.buy(symbol, 100)
- self.log(f"{symbol} 触及下轨买入")
-
- # 价格触及上轨卖出
- elif current_price >= upper.iloc[-1] and position:
- self.sell(symbol, position.volume)
- self.log(f"{symbol} 触及上轨卖出")
-```
-
-## 高级策略特性
-
-### 多股票策略
-
-```python
-class MultiStockStrategy(Strategy):
- def __init__(self):
- super().__init__()
- self.stock_pool = ['000001.SZ', '000002.SZ', '600000.SH']
- self.max_positions = 3
-
- def on_init(self):
- # 订阅股票池
- for symbol in self.stock_pool:
- self.subscribe(symbol)
-
- def select_stocks(self, data):
- """股票选择逻辑"""
- scores = {}
- for symbol in self.stock_pool:
- # 计算股票评分
- score = self.calculate_score(symbol, data)
- scores[symbol] = score
-
- # 返回评分最高的股票
- return sorted(scores.items(), key=lambda x: x[1], reverse=True)[:self.max_positions]
-
- def calculate_score(self, symbol, data):
- """计算股票评分"""
- # 实现评分逻辑
- return 0.5
-```
-
-### 动态调仓策略
-
-```python
-class RebalanceStrategy(Strategy):
- def __init__(self):
- super().__init__()
- self.rebalance_frequency = 'monthly' # 调仓频率
- self.target_weights = {
- '000001.SZ': 0.4,
- '000002.SZ': 0.3,
- '600000.SH': 0.3
- }
-
- def should_rebalance(self):
- """判断是否需要调仓"""
- # 实现调仓条件判断
- return True
-
- def rebalance(self):
- """执行调仓"""
- total_value = self.get_total_value()
-
- for symbol, target_weight in self.target_weights.items():
- target_value = total_value * target_weight
- current_value = self.get_position_value(symbol)
-
- if abs(target_value - current_value) > 1000: # 阈值
- if target_value > current_value:
- # 买入
- amount = target_value - current_value
- self.buy_value(symbol, amount)
- else:
- # 卖出
- amount = current_value - target_value
- self.sell_value(symbol, amount)
-```
-
-## 策略参数优化
-
-### 参数扫描
-
-```python
-from qka.core.backtest import ParameterOptimizer
-
-# 定义参数范围
-param_ranges = {
- 'short_window': range(5, 21, 5),
- 'long_window': range(20, 61, 10)
-}
-
-# 创建优化器
-optimizer = ParameterOptimizer(MovingAverageStrategy, param_ranges)
-
-# 执行优化
-best_params = optimizer.optimize(
- objective='sharpe_ratio', # 优化目标
- data_range=('2023-01-01', '2023-12-31')
-)
-
-print(f"最优参数: {best_params}")
-```
-
-### 遗传算法优化
-
-```python
-from qka.core.backtest import GeneticOptimizer
-
-optimizer = GeneticOptimizer(
- strategy_class=MovingAverageStrategy,
- param_ranges=param_ranges,
- population_size=50,
- generations=100
-)
-
-best_params = optimizer.evolve()
-```
-
-## 风险管理
-
-### 止损止盈
-
-```python
-class RiskManagedStrategy(Strategy):
- def __init__(self):
- super().__init__()
- self.stop_loss_ratio = 0.05 # 5% 止损
- self.take_profit_ratio = 0.10 # 10% 止盈
-
- def check_risk_management(self, symbol):
- """检查风险管理条件"""
- position = self.get_position(symbol)
- if not position:
- return
-
- current_price = self.get_current_price(symbol)
- cost_price = position.avg_price
-
- # 计算收益率
- return_rate = (current_price - cost_price) / cost_price
-
- # 止损
- if return_rate <= -self.stop_loss_ratio:
- self.sell(symbol, position.volume)
- self.log(f"{symbol} 触发止损")
-
- # 止盈
- elif return_rate >= self.take_profit_ratio:
- self.sell(symbol, position.volume)
- self.log(f"{symbol} 触发止盈")
-```
-
-### 仓位管理
-
-```python
-def calculate_position_size(self, symbol, signal_strength):
- """计算仓位大小"""
- available_cash = self.get_available_cash()
- risk_per_trade = available_cash * 0.02 # 每次交易风险2%
-
- stop_loss_distance = self.calculate_stop_loss_distance(symbol)
- position_size = risk_per_trade / stop_loss_distance
-
- # 调整仓位大小基于信号强度
- position_size *= signal_strength
-
- return min(position_size, available_cash * 0.1) # 最大10%仓位
-```
-
-## 策略评估
-
-### 性能指标
-
-```python
-# 在策略中记录关键指标
-def on_trade(self, trade):
- super().on_trade(trade)
-
- # 记录自定义指标
- self.record('trade_count', self.get_trade_count())
- self.record('win_rate', self.calculate_win_rate())
- self.record('max_drawdown', self.calculate_max_drawdown())
-```
-
-### 策略诊断
-
-```python
-from qka.core.backtest import StrategyAnalyzer
-
-analyzer = StrategyAnalyzer()
-
-# 分析策略表现
-analysis = analyzer.analyze_strategy(strategy_result)
-
-print(f"年化收益率: {analysis.annual_return:.2%}")
-print(f"夏普比率: {analysis.sharpe_ratio:.2f}")
-print(f"最大回撤: {analysis.max_drawdown:.2%}")
-```
-
-## 最佳实践
-
-1. **清晰的逻辑结构**:将策略逻辑分解为独立的方法
-2. **参数化设计**:将关键参数设为可配置
-3. **充分的日志记录**:记录关键决策点和执行过程
-4. **风险控制**:始终包含风险管理逻辑
-5. **性能监控**:定期评估策略表现
-6. **版本控制**:保存策略的不同版本
-
-## API 参考
-
-策略开发的详细API参考请查看 [Strategy API文档](../api/core/backtest.md)。
-
-### 主要类和接口
-
-- **Strategy** - 策略基类
-- **BacktestEngine** - 回测引擎
-- **Portfolio** - 投资组合管理
-
-更多详细信息和示例请参考API文档页面。
diff --git a/docs/user-guide/trading.md b/docs/user-guide/trading.md
index 482f195..533fe1d 100644
--- a/docs/user-guide/trading.md
+++ b/docs/user-guide/trading.md
@@ -1,512 +1,272 @@
-# 实盘交易
-
-QKA 提供了完整的实盘交易解决方案,支持多种券商接口和交易模式。
-
-## 交易环境配置
-
-### 券商配置
-
-在配置文件中设置券商信息:
-
-```json
-{
- "trading": {
- "broker": "华泰证券",
- "account": "your_account",
- "server_host": "localhost",
- "server_port": 8888,
- "timeout": 30,
- "auto_login": true,
- "credentials": {
- "username": "your_username",
- "password": "your_password",
- "communication_password": "your_comm_password"
- }
- }
-}
-```
-
-### 安全设置
-
-```python
-import os
-from qka.core.config import config
-
-# 使用环境变量存储敏感信息
-os.environ['QKA_BROKER_USERNAME'] = 'your_username'
-os.environ['QKA_BROKER_PASSWORD'] = 'your_password'
-
-# 配置会自动读取环境变量
-config.trading.credentials.username = os.getenv('QKA_BROKER_USERNAME')
-```
-
-## 交易客户端
-
-### 创建交易客户端
-
-```python
-from qka.brokers import QMTClient
-from qka.brokers.trade import Order, Trade, Position
-
-# 创建交易客户端
-client = QMTClient(base_url="http://localhost:8000", token="your_token")
-
-# 连接到券商
-try:
- client.connect()
- print("连接成功")
-except Exception as e:
- print(f"连接失败: {e}")
-```
-
-### 账户信息查询
-
-```python
-# 查询账户资金
-account_info = client.get_account_info()
-print(f"总资产: {account_info.total_value:,.2f}")
-print(f"可用资金: {account_info.available_cash:,.2f}")
-print(f"市值: {account_info.market_value:,.2f}")
-
-# 查询持仓
-positions = client.get_positions()
-for position in positions:
- print(f"{position.symbol}: {position.volume}股, 成本: {position.cost:.2f}")
-
-# 查询委托
-orders = client.get_orders()
-for order in orders:
- print(f"{order.symbol}: {order.status} {order.volume}股 @ {order.price:.2f}")
-```
-
-## 下单交易
-
-### 基本下单
-
-```python
-from qka.brokers.trade import OrderType, OrderSide
-
-# 市价买入
-buy_order = client.place_order(
- symbol='000001.SZ',
- side=OrderSide.BUY,
- order_type=OrderType.MARKET,
- volume=100
-)
-
-print(f"买单ID: {buy_order.order_id}")
-
-# 限价卖出
-sell_order = client.place_order(
- symbol='000001.SZ',
- side=OrderSide.SELL,
- order_type=OrderType.LIMIT,
- volume=100,
- price=15.50
-)
-
-print(f"卖单ID: {sell_order.order_id}")
-```
-
-### 高级订单类型
-
-```python
-# 止损单
-stop_loss_order = client.place_order(
- symbol='000001.SZ',
- side=OrderSide.SELL,
- order_type=OrderType.STOP_LOSS,
- volume=100,
- stop_price=14.50
-)
-
-# 止盈单
-take_profit_order = client.place_order(
- symbol='000001.SZ',
- side=OrderSide.SELL,
- order_type=OrderType.TAKE_PROFIT,
- volume=100,
- stop_price=16.50
-)
-
-# 条件单
-conditional_order = client.place_conditional_order(
- symbol='000001.SZ',
- condition='price >= 16.0',
- action='buy',
- volume=200
-)
-```
-
-### 批量下单
-
-```python
-# 批量下单
-orders = [
- {
- 'symbol': '000001.SZ',
- 'side': OrderSide.BUY,
- 'volume': 100,
- 'price': 15.00
- },
- {
- 'symbol': '000002.SZ',
- 'side': OrderSide.BUY,
- 'volume': 200,
- 'price': 12.50
- }
-]
-
-batch_results = client.place_batch_orders(orders)
-for result in batch_results:
- if result.success:
- print(f"订单 {result.order_id} 提交成功")
- else:
- print(f"订单提交失败: {result.error}")
-```
-
-## 实盘策略运行
-
-### 策略实盘化
-
-```python
-from qka.core.backtest import Strategy
-from qka.brokers.live import LiveEngine
-
-class LiveTradingStrategy(Strategy):
- def __init__(self):
- super().__init__()
- self.name = "实盘交易策略"
- self.client = TradingClient()
-
- def on_init(self):
- """策略初始化"""
- # 连接交易客户端
- self.client.connect()
-
- # 订阅实时数据
- self.subscribe_realtime('000001.SZ')
-
- # 初始化风险控制
- self.setup_risk_management()
-
- def on_data(self, data):
- """实时数据处理"""
- for symbol in data.index:
- # 获取当前持仓
- position = self.client.get_position(symbol)
- current_price = data.loc[symbol, 'last_price']
-
- # 策略逻辑
- signal = self.generate_signal(symbol, data)
-
- if signal == 'BUY' and not position:
- self.execute_buy(symbol, current_price)
- elif signal == 'SELL' and position:
- self.execute_sell(symbol, position.volume, current_price)
-
- def execute_buy(self, symbol, price):
- """执行买入"""
- # 计算仓位大小
- volume = self.calculate_position_size(symbol, price)
-
- # 风险检查
- if self.check_risk_limits(symbol, volume, price):
- order = self.client.place_order(
- symbol=symbol,
- side=OrderSide.BUY,
- order_type=OrderType.LIMIT,
- volume=volume,
- price=price * 1.001 # 稍微高于市价确保成交
- )
- self.log(f"买入订单已提交: {order.order_id}")
- else:
- self.log(f"风险控制: 跳过买入 {symbol}")
-
- def execute_sell(self, symbol, volume, price):
- """执行卖出"""
- order = self.client.place_order(
- symbol=symbol,
- side=OrderSide.SELL,
- order_type=OrderType.LIMIT,
- volume=volume,
- price=price * 0.999 # 稍微低于市价确保成交
- )
- self.log(f"卖出订单已提交: {order.order_id}")
-```
-
-### 启动实盘引擎
-
-```python
-# 创建实盘引擎
-live_engine = LiveEngine()
-
-# 配置实盘引擎
-live_engine.configure(
- strategy=LiveTradingStrategy(),
- data_frequency='1min', # 分钟级数据
- order_timeout=30, # 订单超时时间
- max_retry=3 # 最大重试次数
-)
-
-# 启动实盘交易
-live_engine.start()
-
-# 策略将在后台运行,处理实时数据和交易
-```
-
-## 风险管理
-
-### 实盘风险控制
-
-```python
-class RiskManager:
- def __init__(self, client):
- self.client = client
- self.max_position_ratio = 0.1 # 单股最大仓位10%
- self.max_daily_loss = 0.05 # 日最大亏损5%
- self.max_drawdown = 0.15 # 最大回撤15%
-
- def check_position_limit(self, symbol, volume, price):
- """检查仓位限制"""
- account_info = self.client.get_account_info()
- position_value = volume * price
- position_ratio = position_value / account_info.total_value
-
- return position_ratio <= self.max_position_ratio
-
- def check_daily_loss_limit(self):
- """检查日损失限制"""
- today_pnl = self.client.get_today_pnl()
- account_info = self.client.get_account_info()
- loss_ratio = abs(today_pnl) / account_info.total_value
-
- return loss_ratio <= self.max_daily_loss
-
- def emergency_stop(self):
- """紧急止损"""
- # 撤销所有未成交订单
- pending_orders = self.client.get_pending_orders()
- for order in pending_orders:
- self.client.cancel_order(order.order_id)
-
- # 平仓所有持仓
- positions = self.client.get_positions()
- for position in positions:
- self.client.place_order(
- symbol=position.symbol,
- side=OrderSide.SELL,
- order_type=OrderType.MARKET,
- volume=position.volume
- )
-
- self.log("执行紧急止损")
-```
-
-### 实时监控
-
-```python
-from qka.brokers.monitor import TradingMonitor
-
-monitor = TradingMonitor(client)
-
-# 设置监控规则
-monitor.add_rule(
- name='日亏损监控',
- condition=lambda: monitor.get_daily_pnl_ratio() < -0.05,
- action=monitor.send_alert
-)
-
-monitor.add_rule(
- name='仓位监控',
- condition=lambda: monitor.get_max_position_ratio() > 0.15,
- action=monitor.reduce_positions
-)
-
-# 启动监控
-monitor.start()
-```
-
-## 数据同步
-
-### 实时行情订阅
-
-```python
-from qka.brokers.data import RealtimeDataFeed
-
-# 创建实时数据源
-data_feed = RealtimeDataFeed()
-
-# 订阅股票行情
-symbols = ['000001.SZ', '000002.SZ', '600000.SH']
-data_feed.subscribe(symbols)
-
-# 设置数据回调
-def on_tick_data(tick):
- print(f"{tick.symbol}: {tick.last_price} ({tick.timestamp})")
-
-data_feed.set_tick_callback(on_tick_data)
-
-# 启动数据接收
-data_feed.start()
-```
-
-### 数据存储
-
-```python
-from qka.core.data import DataStorage
-
-storage = DataStorage()
-
-# 存储实时数据
-def save_tick_data(tick):
- storage.save_tick(
- symbol=tick.symbol,
- timestamp=tick.timestamp,
- price=tick.last_price,
- volume=tick.volume,
- bid=tick.bid,
- ask=tick.ask
- )
-
-data_feed.set_tick_callback(save_tick_data)
-```
-
-## 交易记录与分析
-
-### 交易日志
-
-```python
-from qka.utils.logger import get_structured_logger
-
-trade_logger = get_structured_logger('trading')
-
-def log_trade(order):
- trade_logger.info('trade_executed', {
- 'order_id': order.order_id,
- 'symbol': order.symbol,
- 'side': order.side,
- 'volume': order.volume,
- 'price': order.executed_price,
- 'timestamp': order.executed_time,
- 'commission': order.commission
- })
-```
-
-### 实盘表现分析
-
-```python
-from qka.core.backtest import LivePerformanceAnalyzer
-
-analyzer = LivePerformanceAnalyzer(client)
-
-# 生成日报
-daily_report = analyzer.generate_daily_report()
-print(f"今日收益: {daily_report.daily_return:.2%}")
-print(f"今日交易次数: {daily_report.trade_count}")
-
-# 生成周报
-weekly_report = analyzer.generate_weekly_report()
-print(f"本周收益: {weekly_report.weekly_return:.2%}")
-print(f"本周胜率: {weekly_report.win_rate:.2%}")
-```
-
-## 模拟交易
-
-### 模拟环境
-
-```python
-from qka.brokers.simulator import SimulatorClient
-
-# 创建模拟交易客户端
-sim_client = SimulatorClient(
- initial_cash=1000000,
- commission_rate=0.0003
-)
-
-# 使用模拟客户端进行测试
-strategy = LiveTradingStrategy()
-strategy.client = sim_client
-
-# 在模拟环境中运行策略
-sim_engine = LiveEngine()
-sim_engine.configure(
- strategy=strategy,
- client=sim_client,
- mode='simulation'
-)
-
-sim_engine.start()
-```
-
-## 异常处理
-
-### 连接异常
-
-```python
-def handle_connection_error():
- """处理连接异常"""
- max_retry = 3
- retry_count = 0
-
- while retry_count < max_retry:
- try:
- client.reconnect()
- print("重连成功")
- break
- except Exception as e:
- retry_count += 1
- print(f"重连失败 ({retry_count}/{max_retry}): {e}")
- time.sleep(5)
-
- if retry_count >= max_retry:
- print("连接失败,停止交易")
- live_engine.stop()
-```
-
-### 订单异常
-
-```python
-def handle_order_error(order, error):
- """处理订单异常"""
- if '资金不足' in str(error):
- print("资金不足,调整仓位大小")
- # 重新计算仓位
- elif '涨跌停' in str(error):
- print("股票涨跌停,取消订单")
- # 取消相关订单
- else:
- print(f"订单异常: {error}")
- # 记录错误日志
-```
-
-## 最佳实践
-
-1. **充分测试**:在模拟环境中充分测试策略
-2. **风险控制**:设置多层风险控制机制
-3. **实时监控**:建立完善的监控和告警系统
-4. **异常处理**:考虑各种异常情况的处理
-5. **数据备份**:定期备份交易数据和日志
-6. **版本控制**:对策略代码进行版本管理
-7. **渐进上线**:从小资金开始,逐步增加投入
-
-## 注意事项
-
-- **合规要求**:确保符合监管要求
-- **系统稳定性**:确保网络和系统稳定
-- **数据延迟**:考虑数据传输延迟的影响
-- **交易时间**:注意交易时间段的限制
-- **资金安全**:妥善保管账户信息
-
-## API 参考
-
-交易模块的详细API参考请查看 [API文档](../api/brokers/index.md)。
-
-### 主要类和函数
-
-- **QMTClient** - 交易客户端接口
-- **Order** - 订单对象
-- **Trade** - 交易记录
-- **Position** - 持仓信息
-
-更多详细信息请参考对应的API文档页面。
+# 实盘交易
+
+QKA 提供完整的实盘交易功能,支持通过 QMT 接口进行 A 股实盘交易。
+
+## 交易架构
+
+QKA 的实盘交易采用客户端-服务器架构:
+
+```
+策略代码 → QMTClient → QMTServer → QMT交易接口 → 券商系统
+```
+
+## 准备工作
+
+### 1. 安装 QMT
+
+确保已安装 QMT 并正确配置:
+- 下载并安装 QMT
+- 获取有效的账户 ID
+- 配置交易权限
+
+### 2. 启动交易服务器
+
+```python
+from qka.brokers.server import QMTServer
+
+# 创建交易服务器
+server = QMTServer(
+ account_id="YOUR_ACCOUNT_ID", # 你的账户ID
+ mini_qmt_path="YOUR_QMT_PATH", # QMT安装路径
+ host="0.0.0.0", # 服务器地址
+ port=8000 # 服务器端口
+)
+
+# 启动服务器
+server.start() # 会打印token供客户端使用
+```
+
+### 3. 使用交易客户端
+
+```python
+from qka.brokers.client import QMTClient
+
+# 创建交易客户端
+client = QMTClient(
+ base_url="http://localhost:8000", # 服务器地址
+ token="服务器打印的token" # 访问令牌
+)
+```
+
+## 交易操作
+
+### 查询账户信息
+
+```python
+# 查询股票资产
+assets = client.api("query_stock_asset")
+print(assets)
+
+# 查询资金信息
+capital = client.api("query_account_status")
+print(capital)
+
+# 查询持仓
+positions = client.api("query_stock_positions")
+print(positions)
+```
+
+### 下单交易
+
+```python
+from xtquant import xtconstant
+
+# 买入股票
+result = client.api(
+ "order_stock",
+ stock_code='600000.SH', # 股票代码
+ order_type=xtconstant.STOCK_BUY, # 买入
+ order_volume=1000, # 数量
+ price_type=xtconstant.FIX_PRICE, # 限价单
+ price=10.5 # 价格
+)
+
+# 卖出股票
+result = client.api(
+ "order_stock",
+ stock_code='600000.SH',
+ order_type=xtconstant.STOCK_SELL, # 卖出
+ order_volume=500,
+ price_type=xtconstant.FIX_PRICE,
+ price=11.0
+)
+```
+
+### 订单管理
+
+```python
+# 查询委托
+orders = client.api("query_stock_orders")
+print(orders)
+
+# 查询成交
+trades = client.api("query_stock_trades")
+print(trades)
+
+# 撤单
+cancel_result = client.api(
+ "cancel_order_stock",
+ order_id="订单ID"
+)
+```
+
+## 策略实盘化
+
+### 回测转实盘
+
+将回测策略转换为实盘策略:
+
+```python
+class RealTimeStrategy:
+ def __init__(self, client):
+ self.client = client
+ self.positions = {}
+
+ def run(self):
+ """运行实盘策略"""
+ while True:
+ # 获取实时数据
+ data = self.get_realtime_data()
+
+ # 执行策略逻辑
+ signals = self.generate_signals(data)
+
+ # 执行交易
+ self.execute_trades(signals)
+
+ # 等待下一轮
+ time.sleep(60) # 每分钟执行一次
+
+ def get_realtime_data(self):
+ """获取实时数据"""
+ # 可以通过其他数据源获取实时数据
+ pass
+
+ def generate_signals(self, data):
+ """生成交易信号"""
+ # 策略逻辑
+ pass
+
+ def execute_trades(self, signals):
+ """执行交易"""
+ for symbol, signal in signals.items():
+ if signal == 'buy':
+ self.buy(symbol)
+ elif signal == 'sell':
+ self.sell(symbol)
+
+ def buy(self, symbol):
+ """买入操作"""
+ # 获取当前价格
+ # 计算买入数量
+ # 执行买入
+ pass
+
+ def sell(self, symbol):
+ """卖出操作"""
+ # 执行卖出
+ pass
+```
+
+## 风险控制
+
+### 仓位管理
+
+```python
+class RiskManagedTrader:
+ def __init__(self, client, max_position_ratio=0.1):
+ self.client = client
+ self.max_position_ratio = max_position_ratio
+
+ def calculate_position_size(self, symbol, price):
+ """计算合理的买入数量"""
+ # 查询总资产
+ assets = self.client.api("query_stock_asset")
+ total_assets = assets['总资产']
+
+ # 单股票仓位限制
+ max_position_value = total_assets * self.max_position_ratio
+ max_shares = int(max_position_value / price)
+
+ return max_shares
+```
+
+### 交易频率控制
+
+```python
+import time
+
+class RateLimitedTrader:
+ def __init__(self, client, max_trades_per_minute=5):
+ self.client = client
+ self.max_trades_per_minute = max_trades_per_minute
+ self.trade_times = []
+
+ def can_trade(self):
+ """检查是否可以交易"""
+ current_time = time.time()
+ # 移除1分钟前的交易记录
+ self.trade_times = [t for t in self.trade_times
+ if current_time - t < 60]
+
+ return len(self.trade_times) < self.max_trades_per_minute
+
+ def record_trade(self):
+ """记录交易时间"""
+ self.trade_times.append(time.time())
+```
+
+## 监控和日志
+
+### 交易监控
+
+```python
+class TradingMonitor:
+ def __init__(self, client):
+ self.client = client
+
+ def monitor_positions(self):
+ """监控持仓"""
+ positions = self.client.api("query_stock_positions")
+ for position in positions:
+ print(f"持仓: {position['证券代码']} {position['当前数量']}股")
+
+ def monitor_orders(self):
+ """监控委托"""
+ orders = self.client.api("query_stock_orders")
+ for order in orders:
+ print(f"委托: {order['证券代码']} {order['委托状态']}")
+```
+
+### 错误处理
+
+```python
+try:
+ result = client.api("order_stock", ...)
+ if not result.get('success'):
+ print(f"交易失败: {result.get('detail')}")
+except Exception as e:
+ print(f"API调用失败: {e}")
+ # 重试逻辑或报警
+```
+
+## 最佳实践
+
+1. **小资金测试**: 先用小资金测试策略
+2. **风险控制**: 设置严格的仓位和止损限制
+3. **监控报警**: 设置交易异常报警
+4. **日志记录**: 详细记录所有交易操作
+5. **备份策略**: 准备手动干预方案
+
+## 注意事项
+
+1. **交易时间**: 只在交易时间段内运行策略
+2. **网络稳定性**: 确保网络连接稳定
+3. **系统维护**: 定期检查系统状态
+4. **合规性**: 遵守相关交易规则
+
+## 相关链接
+
+- [API参考 - 交易模块](../api/brokers.md)
+- [快速开始 - 第一个策略](../getting-started/first-strategy.md)
+- [用户指南 - 回测分析](backtest.md)
\ No newline at end of file
diff --git a/examples/basic_test.py b/examples/basic_test.py
deleted file mode 100644
index 8de21c4..0000000
--- a/examples/basic_test.py
+++ /dev/null
@@ -1,135 +0,0 @@
-"""
-QKA 基础功能测试
-测试配置管理、事件系统和日志系统是否正常工作
-"""
-
-def test_config_system():
- """测试配置管理系统"""
- print("=" * 30)
- print("测试配置管理系统")
- print("=" * 30)
-
- try:
- from qka.core.config import config, create_sample_config
-
- # 创建示例配置
- create_sample_config("test_config.json")
- print("✅ 配置文件创建成功")
-
- # 测试配置访问
- print(f"初始资金: {config.backtest.initial_cash:,}")
- print(f"数据源: {config.data.default_source}")
- print("✅ 配置系统正常")
-
- except Exception as e:
- print(f"❌ 配置系统错误: {e}")
- import traceback
- traceback.print_exc()
-
-
-def test_event_system():
- """测试事件系统"""
- print("\n" + "=" * 30)
- print("测试事件系统")
- print("=" * 30)
-
- try:
- from qka.core.events import EventType, event_handler, emit_event, start_event_engine, stop_event_engine
- import time
-
- # 定义事件处理器
- @event_handler(EventType.DATA_LOADED)
- def on_data_loaded(event):
- print(f"📊 收到数据加载事件: {event.data}")
-
- # 启动事件引擎
- start_event_engine()
- print("✅ 事件引擎启动成功")
-
- # 发送测试事件
- emit_event(EventType.DATA_LOADED, {"test": "data"})
- time.sleep(0.5) # 等待事件处理
-
- # 停止事件引擎
- stop_event_engine()
- print("✅ 事件系统正常")
-
- except Exception as e:
- print(f"❌ 事件系统错误: {e}")
- import traceback
- traceback.print_exc()
-
-
-def test_logging_system():
- """测试日志系统"""
- print("\n" + "=" * 30)
- print("测试日志系统")
- print("=" * 30)
-
- try:
- from qka.utils.logger import create_logger
-
- # 创建日志记录器
- logger = create_logger('test', colored_console=True)
-
- logger.info("日志系统测试 - 信息")
- logger.warning("日志系统测试 - 警告")
- logger.error("日志系统测试 - 错误")
-
- print("✅ 日志系统正常")
-
- except Exception as e:
- print(f"❌ 日志系统错误: {e}")
- import traceback
- traceback.print_exc()
-
-
-def test_tools():
- """测试工具类"""
- print("\n" + "=" * 30)
- print("测试工具类")
- print("=" * 30)
-
- try:
- from qka.utils.tools import Cache, Timer, format_number
- import time
-
- # 测试缓存
- cache = Cache(max_size=10, ttl=60)
- cache.set('test_key', 'test_value')
- value = cache.get('test_key')
- print(f"缓存测试: {value}")
-
- # 测试计时器
- with Timer() as t:
- time.sleep(0.01)
- print(f"计时器测试: {t.elapsed():.4f}秒")
-
- # 测试格式化
- formatted = format_number(123456.789)
- print(f"格式化测试: {formatted}")
-
- print("✅ 工具类正常")
-
- except Exception as e:
- print(f"❌ 工具类错误: {e}")
- import traceback
- traceback.print_exc()
-
-
-def main():
- """主测试函数"""
- print("🧪 QKA 基础功能测试开始\n")
-
- test_config_system()
- test_event_system()
- test_logging_system()
- test_tools()
-
- print("\n" + "=" * 30)
- print("🎉 测试完成")
- print("=" * 30)
-
-
-if __name__ == "__main__":
- main()
diff --git a/examples/enhanced_features_demo.py b/examples/enhanced_features_demo.py
deleted file mode 100644
index 9556c29..0000000
--- a/examples/enhanced_features_demo.py
+++ /dev/null
@@ -1,261 +0,0 @@
-"""
-QKA 增强功能演示
-展示配置管理、事件系统、日志系统等新功能
-"""
-
-import time
-import qka
-from qka.core.config import config, load_config, create_sample_config
-from qka.core.events import EventType, event_handler, emit_event, start_event_engine, stop_event_engine
-from qka.core.backtest import Strategy
-from qka.utils.logger import create_logger, get_structured_logger
-from qka.utils.tools import timer, retry
-
-
-def demo_config_system():
- """演示配置管理系统"""
- print("=" * 50)
- print("🔧 配置管理系统演示")
- print("=" * 50)
-
- # 创建示例配置文件
- create_sample_config("demo_config.json")
-
- # 加载配置
- cfg = load_config("demo_config.json")
-
- print(f"初始资金: {qka.config.backtest.initial_cash:,}")
- print(f"手续费率: {qka.config.backtest.commission_rate}")
- print(f"数据源: {qka.config.data.default_source}")
- print(f"缓存目录: {qka.config.data.cache_dir}")
- print(f"服务器端口: {qka.config.trading.server_port}")
-
- # 修改配置
- qka.config.backtest.initial_cash = 2_000_000
- print(f"修改后初始资金: {qka.config.backtest.initial_cash:,}")
-
-
-def demo_event_system():
- """演示事件驱动系统"""
- print("\n" + "=" * 50)
- print("📡 事件驱动系统演示")
- print("=" * 50)
-
- # 定义事件处理器
- @event_handler(EventType.DATA_LOADED)
- def on_data_loaded(event):
- print(f"📊 数据加载完成: {event.data}")
-
- @event_handler(EventType.ORDER_FILLED)
- def on_order_filled(event):
- print(f"✅ 订单成交: {event.data}")
-
- @event_handler(EventType.SIGNAL_GENERATED)
- def on_signal_generated(event):
- print(f"🎯 信号生成: {event.data}")
-
- # 启动事件引擎
- start_event_engine()
-
- # 发送测试事件
- emit_event(EventType.DATA_LOADED, {"symbol": "000001.SZ", "rows": 1000})
- emit_event(EventType.ORDER_FILLED, {"order_id": "123", "symbol": "000001.SZ", "price": 10.5})
- emit_event(EventType.SIGNAL_GENERATED, {"symbol": "000002.SZ", "signal": "BUY", "strength": 0.8})
-
- # 等待事件处理
- time.sleep(0.5)
-
- # 查看事件统计
- stats = qka.event_engine.get_statistics()
- print(f"\n📈 事件统计:")
- for event_type, count in stats['event_count'].items():
- print(f" {event_type}: {count}次")
-
-
-def demo_logging_system():
- """演示增强日志系统"""
- print("\n" + "=" * 50)
- print("📝 增强日志系统演示")
- print("=" * 50)
-
- # 创建彩色日志记录器
- logger = create_logger('demo', colored_console=True, level='DEBUG')
-
- logger.debug("这是调试信息")
- logger.info("这是普通信息")
- logger.warning("这是警告信息")
- logger.error("这是错误信息")
-
- # 结构化日志
- struct_logger = get_structured_logger('demo_struct')
- struct_logger.info("用户登录", user_id=12345, ip="192.168.1.100", action="login")
- struct_logger.error("交易失败", symbol="000001.SZ", reason="余额不足", amount=10000)
-
- print("📁 日志文件已保存到 logs 目录")
-
-
-class EnhancedStrategy(Strategy):
- """增强的策略类,集成事件系统"""
-
- def __init__(self):
- super().__init__()
- self.logger = create_logger('strategy', colored_console=True)
-
- def on_start(self, broker):
- """策略启动时的事件处理"""
- self.logger.info(f"策略 {self.name} 启动")
- emit_event(EventType.STRATEGY_START, {
- "strategy": self.name,
- "initial_cash": broker.initial_cash
- })
-
- def on_bar(self, data, broker, current_date):
- """策略核心逻辑"""
- for symbol, df in data.items():
- if len(df) < 20:
- continue
-
- current_price = df['close'].iloc[-1]
- ma20 = df['close'].rolling(20).mean().iloc[-1]
-
- # 生成交易信号
- if current_price > ma20 and broker.get_position(symbol) == 0:
- # 发送买入信号事件
- emit_event(EventType.SIGNAL_GENERATED, {
- "symbol": symbol,
- "signal": "BUY",
- "price": current_price,
- "reason": "价格突破20日均线"
- })
-
- # 执行买入
- if broker.buy(symbol, 0.3, current_price):
- self.logger.info(f"买入 {symbol} @ {current_price:.2f}")
- emit_event(EventType.ORDER_FILLED, {
- "symbol": symbol,
- "action": "BUY",
- "price": current_price,
- "amount": broker.get_position(symbol)
- })
-
- elif current_price < ma20 and broker.get_position(symbol) > 0:
- # 发送卖出信号事件
- emit_event(EventType.SIGNAL_GENERATED, {
- "symbol": symbol,
- "signal": "SELL",
- "price": current_price,
- "reason": "价格跌破20日均线"
- })
-
- # 执行卖出
- if broker.sell(symbol, 1.0, current_price):
- self.logger.info(f"卖出 {symbol} @ {current_price:.2f}")
- emit_event(EventType.ORDER_FILLED, {
- "symbol": symbol,
- "action": "SELL",
- "price": current_price,
- "amount": 0
- })
-
- def on_end(self, broker):
- """策略结束时的事件处理"""
- self.logger.info(f"策略 {self.name} 结束")
- emit_event(EventType.STRATEGY_END, {
- "strategy": self.name,
- "final_value": broker.get_total_value({})
- })
-
-
-@timer
-def demo_enhanced_backtest():
- """演示增强回测功能"""
- print("\n" + "=" * 50)
- print("🚀 增强回测演示")
- print("=" * 50)
-
- # 使用配置系统的参数
- print(f"使用配置: 初始资金 {qka.config.backtest.initial_cash:,}, 手续费 {qka.config.backtest.commission_rate}")
-
- # 获取数据
- data_obj = qka.data(qka.config.data.default_source, stocks=['000001', '000002'])
-
- # 运行回测
- result = qka.backtest(
- data=data_obj,
- strategy=EnhancedStrategy(),
- start_time='2023-06-01',
- end_time='2023-08-31'
- )
-
- # 输出结果
- print(f"\n📊 回测结果:")
- print(f"总收益率: {result['total_return']:.2%}")
- print(f"年化收益率: {result['annual_return']:.2%}")
- print(f"最大回撤: {result['max_drawdown']:.2%}")
- print(f"夏普比率: {result['sharpe_ratio']:.2f}")
- print(f"交易次数: {result['total_trades']}")
-
-
-@retry(max_attempts=3, delay=1.0)
-def demo_tools():
- """演示工具函数"""
- print("\n" + "=" * 50)
- print("🛠️ 工具函数演示")
- print("=" * 50)
-
- from qka.utils.tools import format_number, format_percentage, format_currency
- from qka.utils.tools import Timer, Cache
-
- # 格式化工具
- print(f"数字格式化: {format_number(1234567.89)}")
- print(f"百分比格式化: {format_percentage(0.1567)}")
- print(f"货币格式化: {format_currency(123456.78)}")
-
- # 计时器
- with Timer() as t:
- time.sleep(0.1)
- print(f"计时器测试: {t.elapsed():.3f}秒")
-
- # 缓存
- cache = Cache(max_size=100, ttl=60)
- cache.set('test_key', 'test_value')
- print(f"缓存测试: {cache.get('test_key')}")
-
- print("✅ 重试装饰器测试成功")
-
-
-def main():
- """主演示函数"""
- print("🎉 QKA 增强功能演示")
-
- try:
- # 演示各个功能模块
- demo_config_system()
- demo_event_system()
- demo_logging_system()
- demo_tools()
- demo_enhanced_backtest()
-
- print("\n" + "=" * 50)
- print("✨ 所有功能演示完成")
- print("=" * 50)
-
- # 查看最终事件统计
- final_stats = qka.event_engine.get_statistics()
- print(f"\n📊 最终事件统计:")
- for event_type, count in final_stats['event_count'].items():
- print(f" {event_type}: {count}次")
-
- except Exception as e:
- print(f"❌ 演示过程中出现错误: {e}")
- import traceback
- traceback.print_exc()
-
- finally:
- # 停止事件引擎
- stop_event_engine()
- print("\n🔚 事件引擎已关闭")
-
-
-if __name__ == "__main__":
- main()
diff --git a/examples/simple_backtest_demo.py b/examples/simple_backtest_demo.py
deleted file mode 100644
index 0080e23..0000000
--- a/examples/simple_backtest_demo.py
+++ /dev/null
@@ -1,44 +0,0 @@
-"""
-QKA 简化回测API演示 - 极简版本
-只需3步:获取数据 -> 定义策略 -> 运行回测
-"""
-
-import qka
-
-# 第1步:定义策略
-class SimpleStrategy(qka.Strategy):
- def on_bar(self, data, broker, current_date):
- for symbol, df in data.items():
- if len(df) < 20: # 需要足够的历史数据
- continue
-
- current_price = df['close'].iloc[-1]
- ma20 = df['close'].rolling(20).mean().iloc[-1]
-
- # 简单策略:价格突破20日均线买入,跌破卖出
- if current_price > ma20 and broker.get_position(symbol) == 0:
- broker.buy(symbol, 0.5, current_price) # 用50%资金买入
-
- elif current_price < ma20 and broker.get_position(symbol) > 0:
- broker.sell(symbol, 1.0, current_price) # 全部卖出
-
-# 第2步:获取数据并运行回测
-if __name__ == "__main__":
- # 获取数据
- data_obj = qka.data(stocks=['000001', '000002']) # 使用默认数据源
-
- # 运行回测
- result = qka.backtest(
- data=data_obj,
- strategy=SimpleStrategy(),
- start_time='2023-01-01',
- end_time='2023-12-31'
- )
-
- qka.plot(result)
-
- # 第3步:查看结果
- print(f"总收益率: {result['total_return']:.2%}")
- print(f"年化收益率: {result['annual_return']:.2%}")
- print(f"最大回撤: {result['max_drawdown']:.2%}")
- print(f"夏普比率: {result['sharpe_ratio']:.2f}")
diff --git a/examples/simple_demo.py b/examples/simple_demo.py
deleted file mode 100644
index 42b727b..0000000
--- a/examples/simple_demo.py
+++ /dev/null
@@ -1,111 +0,0 @@
-"""
-QKA 简化功能演示
-演示阶段1的核心增强功能
-"""
-
-print("🎉 QKA 增强功能演示")
-print("=" * 50)
-
-# 1. 配置管理系统演示
-print("\n📋 配置管理系统")
-print("-" * 30)
-
-from qka.core.config import config, create_sample_config
-
-# 创建示例配置
-create_sample_config("demo_config.json")
-print("✅ 配置文件创建成功")
-
-# 显示当前配置
-print(f"初始资金: {config.backtest.initial_cash:,}")
-print(f"手续费率: {config.backtest.commission_rate}")
-print(f"数据源: {config.data.default_source}")
-print(f"服务器端口: {config.trading.server_port}")
-
-# 2. 事件系统演示
-print("\n📡 事件驱动系统")
-print("-" * 30)
-
-from qka.core.events import EventType, event_handler, emit_event, start_event_engine, stop_event_engine
-import time
-
-# 定义事件处理器
-@event_handler(EventType.DATA_LOADED)
-def on_data_loaded(event):
- print(f"📊 数据加载事件: {event.data}")
-
-@event_handler(EventType.SIGNAL_GENERATED)
-def on_signal_generated(event):
- print(f"🎯 信号生成事件: {event.data}")
-
-# 启动事件引擎
-start_event_engine()
-print("✅ 事件引擎启动成功")
-
-# 发送测试事件
-emit_event(EventType.DATA_LOADED, {"symbol": "000001.SZ", "rows": 1000})
-emit_event(EventType.SIGNAL_GENERATED, {"symbol": "000002.SZ", "signal": "BUY"})
-
-# 等待事件处理
-time.sleep(1)
-
-# 3. 日志系统演示
-print("\n📝 日志系统")
-print("-" * 30)
-
-from qka.utils.logger import create_logger
-
-logger = create_logger('demo', colored_console=True)
-logger.info("这是一条信息日志")
-logger.warning("这是一条警告日志")
-logger.error("这是一条错误日志")
-
-print("✅ 彩色日志显示正常")
-
-# 4. 工具类演示
-print("\n🛠️ 工具类")
-print("-" * 30)
-
-from qka.utils.tools import Cache, Timer, format_number, format_percentage
-
-# 缓存测试
-cache = Cache(max_size=10, ttl=60)
-cache.set('test', 'value')
-print(f"缓存测试: {cache.get('test')}")
-
-# 计时器测试
-with Timer() as t:
- time.sleep(0.01)
-print(f"计时器测试: {t.elapsed():.4f}秒")
-
-# 格式化测试
-print(f"数字格式化: {format_number(123456.789)}")
-print(f"百分比格式化: {format_percentage(0.1234)}")
-
-# 获取统计信息
-from qka.core.events import event_engine
-stats = event_engine.get_statistics()
-print(f"\n📊 事件统计:")
-for event_type, count in stats['event_count'].items():
- print(f" {event_type}: {count}次")
-
-# 停止事件引擎
-stop_event_engine()
-
-print("\n" + "=" * 50)
-print("✨ 演示完成!阶段1功能正常运行")
-print("=" * 50)
-
-print("""
-🎯 阶段1完成的功能:
- ✅ 配置管理系统 - 统一的配置管理
- ✅ 事件驱动框架 - 发布-订阅模式
- ✅ 增强日志系统 - 彩色和结构化日志
- ✅ 基础工具类 - 缓存、计时器、格式化等
-
-🔄 下一步: 阶段2 - 数据层增强
- 📊 数据缓存机制
- 🔍 数据质量检查
- 📈 多频率数据支持
- 🔄 增量数据更新
-""")
diff --git a/mkdocs.yml b/mkdocs.yml
index e1792c7..0988ca1 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -126,47 +126,10 @@ nav:
- 数据获取: user-guide/data.md
- 回测分析: user-guide/backtest.md
- 实盘交易: user-guide/trading.md
- - 配置管理: user-guide/config.md
- - 事件系统: user-guide/events.md
- - 日志系统: user-guide/logging.md
- - 参考资料:
- - A股市场证券代码命名规则: A股市场证券代码命名规则.md
- API参考:
- - API概览: api/index.md
- - Core模块:
- - 模块概览: api/core/index.md
- - 配置管理: api/core/config.md
- - 事件系统: api/core/events.md
- - 回测引擎: api/core/backtest.md
- - 数据处理: api/core/data.md
- - 绘图工具: api/core/plot.md
- - Utils模块:
- - 模块概览: api/utils/index.md
- - 日志系统: api/utils/logger.md
- - 通用工具: api/utils/tools.md
- - 动画工具: api/utils/anis.md
- - 通用函数: api/utils/util.md
- - Brokers模块:
- - 模块概览: api/brokers/index.md
- - 交易客户端: api/brokers/client.md
- - 交易服务器: api/brokers/server.md
- - 交易执行: api/brokers/trade.md
- - MCP模块:
- - 模块概览: api/mcp/index.md
- - API接口: api/mcp/api.md
- - 服务器实现: api/mcp/server.md
+ - 核心模块: api/core.md
+ - 交易模块: api/brokers.md
+ - 工具模块: api/utils.md
- 示例教程:
- - 示例概览: examples/index.md
- - 基础示例:
- - 第一个策略: examples/basic/first-strategy.md
- - 数据获取: examples/basic/data-fetching.md
- - 简单回测: examples/basic/simple-backtest.md
- - 进阶示例:
- - 事件驱动策略: examples/advanced/event-driven.md
- - 多资产策略: examples/advanced/multi-asset.md
- - 风险管理: examples/advanced/risk-management.md
- - 完整案例:
- - 动量策略: examples/complete/momentum-strategy.md
- - 均值回归策略: examples/complete/mean-reversion.md
- - 配对交易: examples/complete/pairs-trading.md
+ - 基础示例: examples/basic.md
- 更新日志: changelog.md
diff --git a/pyproject.toml b/pyproject.toml
index 6b31665..fe41db5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -27,6 +27,10 @@ dependencies = [
"uvicorn>=0.34.3",
"xtquant>=241014.1.2",
"ipykernel>=6.29.5",
+ "pyarrow>=21.0.0",
+ "tqdm>=4.67.1",
+ "dask[complete]>=2025.7.0",
+ "ta>=0.11.0",
]
[project.optional-dependencies]
diff --git a/qka/__init__.py b/qka/__init__.py
index 8fd61da..d186d5e 100644
--- a/qka/__init__.py
+++ b/qka/__init__.py
@@ -12,11 +12,9 @@
__version__ = "0.1.0" # fallback version
# 核心功能直接导入
-from qka.core.data import data, set_source, get_source, register_data_source, get_available_sources
-from qka.core.backtest import backtest, Strategy, Broker
-from qka.core.config import config, load_config
-from qka.core.events import event_engine, emit_event
-from qka.core.plot import plot
+from qka.core.data import Data
+from qka.core.backtest import Backtest
+from qka.core.strategy import Strategy
# 子模块导入
from qka import core, utils, mcp
@@ -28,13 +26,7 @@
__all__ = [
# 核心功能
- 'data', 'backtest', 'Strategy', 'Broker', 'plot',
- # 配置
- 'config', 'load_config',
- # 数据源管理
- 'set_source', 'get_source', 'register_data_source', 'get_available_sources',
- # 事件系统
- 'event_engine', 'emit_event',
+ 'Data', 'Backtest', 'Strategy',
# 子模块
'core', 'utils', 'mcp'
]
\ No newline at end of file
diff --git a/qka/brokers/client.py b/qka/brokers/client.py
index c9ad480..bca9bbf 100644
--- a/qka/brokers/client.py
+++ b/qka/brokers/client.py
@@ -1,13 +1,36 @@
+"""
+QKA交易客户端模块
+
+提供QMT交易服务器的客户端接口,支持远程调用交易功能。
+"""
+
import requests
-from typing import Any, Dict
+from typing import Any, Dict, Optional
from qka.utils.logger import logger
class QMTClient:
- def __init__(self, base_url: str = "http://localhost:8000", token: str = None):
- """初始化交易客户端
+ """
+ QMT交易客户端类
+
+ 提供与QMT交易服务器的通信接口,支持各种交易操作。
+
+ Attributes:
+ base_url (str): API服务器地址
+ session (requests.Session): HTTP会话对象
+ token (str): 访问令牌
+ headers (Dict): HTTP请求头
+ """
+
+ def __init__(self, base_url: str = "http://localhost:8000", token: Optional[str] = None):
+ """
+ 初始化交易客户端
+
Args:
- base_url: API服务器地址,默认为本地8000端口
- token: 访问令牌,必须与服务器的token一致
+ base_url (str): API服务器地址,默认为本地8000端口
+ token (str): 访问令牌,必须与服务器的token一致
+
+ Raises:
+ ValueError: 如果未提供token
"""
self.base_url = base_url.rstrip('/')
self.session = requests.Session()
@@ -17,12 +40,18 @@ def __init__(self, base_url: str = "http://localhost:8000", token: str = None):
self.headers = {"X-Token": self.token}
def api(self, method_name: str, **params) -> Any:
- """通用调用接口方法
+ """
+ 通用调用接口方法
+
Args:
- method_name: 要调用的接口名称
+ method_name (str): 要调用的接口名称
**params: 接口参数,作为关键字参数传入
+
Returns:
- 接口返回的数据
+ Any: 接口返回的数据
+
+ Raises:
+ Exception: API调用失败时抛出异常
"""
try:
response = self.session.post(
diff --git a/qka/brokers/server.py b/qka/brokers/server.py
index 242cf11..0377034 100644
--- a/qka/brokers/server.py
+++ b/qka/brokers/server.py
@@ -1,21 +1,45 @@
+"""
+QKA交易服务器模块
+
+提供基于FastAPI的QMT交易服务器,将QMT交易接口封装为RESTful API。
+"""
+
from fastapi import FastAPI, HTTPException, Header, Depends
from pydantic import BaseModel
import inspect
-from typing import Any, Dict
+from typing import Any, Dict, Optional
from qka.brokers.trade import create_trader
import uvicorn
import uuid
import hashlib
class QMTServer:
- def __init__(self, account_id: str, mini_qmt_path: str, host: str = "0.0.0.0", port: int = 8000, token: str = None):
- """初始化交易服务器
+ """
+ QMT交易服务器类
+
+ 将QMT交易接口封装为RESTful API,支持远程调用交易功能。
+
+ Attributes:
+ account_id (str): 账户ID
+ mini_qmt_path (str): miniQMT安装路径
+ host (str): 服务器地址
+ port (int): 服务器端口
+ app (FastAPI): FastAPI应用实例
+ trader: QMT交易对象
+ account: 账户对象
+ token (str): 访问令牌
+ """
+
+ def __init__(self, account_id: str, mini_qmt_path: str, host: str = "0.0.0.0", port: int = 8000, token: Optional[str] = None):
+ """
+ 初始化交易服务器
+
Args:
- account_id: 账户ID
- mini_qmt_path: miniQMT路径
- host: 服务器地址,默认0.0.0.0
- port: 服务器端口,默认8000
- token: 可选的自定义token
+ account_id (str): 账户ID
+ mini_qmt_path (str): miniQMT路径
+ host (str): 服务器地址,默认0.0.0.0
+ port (int): 服务器端口,默认8000
+ token (Optional[str]): 可选的自定义token
"""
self.account_id = account_id
self.mini_qmt_path = mini_qmt_path
@@ -28,7 +52,12 @@ def __init__(self, account_id: str, mini_qmt_path: str, host: str = "0.0.0.0", p
print(f"\n授权Token: {self.token}\n") # 打印token供客户端使用
def generate_token(self) -> str:
- """生成基于机器码的固定token"""
+ """
+ 生成基于机器码的固定token
+
+ Returns:
+ str: 生成的token字符串
+ """
# 获取机器码(例如MAC地址)
mac = uuid.getnode()
# 将机器码转换为字符串
@@ -38,7 +67,18 @@ def generate_token(self) -> str:
return token
async def verify_token(self, x_token: str = Header(...)):
- """验证token的依赖函数"""
+ """
+ 验证token的依赖函数
+
+ Args:
+ x_token (str): 请求头中的token
+
+ Returns:
+ str: 验证通过的token
+
+ Raises:
+ HTTPException: token无效时抛出401错误
+ """
if x_token != self.token:
raise HTTPException(status_code=401, detail="无效的Token")
return x_token
@@ -47,8 +87,16 @@ def init_trader(self):
"""初始化交易对象"""
self.trader, self.account = create_trader(self.account_id, self.mini_qmt_path)
- def convert_to_dict(self, obj):
- """将结果转换为可序列化的字典"""
+ def convert_to_dict(self, obj) -> Dict[str, Any]:
+ """
+ 将结果转换为可序列化的字典
+
+ Args:
+ obj: 任意对象
+
+ Returns:
+ Dict[str, Any]: 可序列化的字典
+ """
# 如果是基本类型,直接返回
if isinstance(obj, (int, float, str, bool)):
return obj
@@ -62,15 +110,21 @@ def convert_to_dict(self, obj):
elif hasattr(obj, '__dir__'):
attrs = obj.__dir__()
# 过滤掉内部属性和方法
- public_attrs = {attr: getattr(obj, attr)
- for attr in attrs
+ public_attrs = {attr: getattr(obj, attr)
+ for attr in attrs
if not attr.startswith('_') and not callable(getattr(obj, attr))}
return public_attrs
# 其他类型直接返回
return str(obj) # 将无法处理的类型转换为字符串
def convert_method_to_endpoint(self, method_name: str, method):
- """将 XtQuantTrader 方法转换为 FastAPI 端点"""
+ """
+ 将 XtQuantTrader 方法转换为 FastAPI 端点
+
+ Args:
+ method_name (str): 方法名称
+ method: 方法对象
+ """
sig = inspect.signature(method)
param_names = list(sig.parameters.keys())
@@ -103,7 +157,7 @@ async def endpoint(request: RequestModel, token: str = Depends(self.verify_token
def setup_routes(self):
"""设置所有路由"""
trader_methods = inspect.getmembers(
- self.trader.__class__,
+ self.trader.__class__,
predicate=lambda x: inspect.isfunction(x) or inspect.ismethod(x)
)
@@ -120,7 +174,16 @@ def start(self):
self.setup_routes()
uvicorn.run(self.app, host=self.host, port=self.port)
-def qmt_server(account_id: str, mini_qmt_path: str, host: str = "0.0.0.0", port: int = 8000, token: str = None):
- """快速创建并启动服务器的便捷函数"""
+def qmt_server(account_id: str, mini_qmt_path: str, host: str = "0.0.0.0", port: int = 8000, token: Optional[str] = None):
+ """
+ 快速创建并启动服务器的便捷函数
+
+ Args:
+ account_id (str): 账户ID
+ mini_qmt_path (str): miniQMT路径
+ host (str): 服务器地址,默认0.0.0.0
+ port (int): 服务器端口,默认8000
+ token (Optional[str]): 可选的自定义token
+ """
server = QMTServer(account_id, mini_qmt_path, host, port, token)
server.start()
\ No newline at end of file
diff --git a/qka/core/__init__.py b/qka/core/__init__.py
index 9027379..05a3676 100644
--- a/qka/core/__init__.py
+++ b/qka/core/__init__.py
@@ -3,15 +3,17 @@
包含核心功能:数据处理、回测引擎、配置管理、事件系统等
"""
-from .data import data
-from .backtest import backtest, Strategy
-from .config import config, load_config
-from .events import EventType, event_engine, emit_event, start_event_engine, stop_event_engine
-from .plot import plot
+
+# 数据相关
+from .data import Data
+# 回测相关
+from .backtest import Backtest
+from .strategy import Strategy
+from .broker import Broker
__all__ = [
- 'data', 'backtest', 'Strategy',
- 'config', 'load_config',
- 'EventType', 'event_engine', 'emit_event', 'start_event_engine', 'stop_event_engine',
- 'plot'
+ # 数据相关
+ 'Data',
+ # 回测相关
+ 'Backtest', 'Strategy', 'Broker',
]
diff --git a/qka/core/backtest.py b/qka/core/backtest.py
index e3c8cb6..3948722 100644
--- a/qka/core/backtest.py
+++ b/qka/core/backtest.py
@@ -1,329 +1,117 @@
+"""
+QKA回测引擎模块
-import pandas as pd
-import numpy as np
-from datetime import datetime, timedelta
-from typing import Dict, List, Optional, Any
-from abc import ABC, abstractmethod
-import warnings
-warnings.filterwarnings('ignore')
+提供基于时间序列的回测功能,支持多股票横截面数据处理,包含完整的交易记录和可视化功能。
+"""
-from qka.core.data.base import Data
+import plotly.graph_objects as go
-class Strategy(ABC):
- """策略基类"""
+class Backtest:
+ """
+ QKA回测引擎类
+
+ 提供基于时间序列的回测功能,支持多股票横截面数据处理。
- def __init__(self):
- self.name = self.__class__.__name__
+ Attributes:
+ data (Data): 数据对象实例
+ strategy (Strategy): 策略对象实例
+ """
- @abstractmethod
- def on_bar(self, data: Dict[str, pd.DataFrame], broker, current_date: datetime):
+ def __init__(self, data, strategy):
"""
- 每个交易日调用的策略逻辑
+ 初始化回测引擎
Args:
- data: 历史数据 {股票代码: DataFrame}
- broker: 交易接口
- current_date: 当前日期
+ data (Data): Data类的实例,包含股票数据
+ strategy (Strategy): 策略对象,必须包含on_bar方法
"""
- pass
-
- def on_start(self, broker):
- """回测开始时调用"""
- pass
+ self.data = data
+ self.strategy = strategy
- def on_end(self, broker):
- """回测结束时调用"""
- pass
-
-class Broker:
- """简化的交易接口"""
-
- def __init__(self, initial_cash: float = 1000000, commission_rate: float = 0.0003):
- self.initial_cash = initial_cash
- self.cash = initial_cash
- self.commission_rate = commission_rate
- self.positions = {} # {股票代码: 数量}
- self.avg_costs = {} # {股票代码: 平均成本}
- self.trades = [] # 交易记录
- self.daily_values = [] # 每日净值
-
- def buy(self, symbol: str, amount: float, price: Optional[float] = None) -> bool:
+ def run(self):
"""
- 买入股票
+ 执行回测
- Args:
- symbol: 股票代码
- amount: 金额或数量,如果 < 1 则视为金额比例,否则视为股数
- price: 价格,为None时使用当前价格
+ 遍历所有时间点,在每个时间点调用策略的on_bar方法进行交易决策,
+ 并记录交易后的状态。
"""
- if amount <= 0:
- return False
-
- if amount < 1: # 按比例买入
- buy_amount = self.cash * amount
- shares = int(buy_amount / price / 100) * 100 # 按手买入
- else: # 按股数买入
- shares = int(amount / 100) * 100 # 按手买入
- buy_amount = shares * price
-
- commission = buy_amount * self.commission_rate
- total_cost = buy_amount + commission
-
- if self.cash >= total_cost and shares >= 100:
- # 更新持仓
- old_shares = self.positions.get(symbol, 0)
- old_cost = self.avg_costs.get(symbol, 0.0)
-
- new_shares = old_shares + shares
- new_avg_cost = ((old_shares * old_cost) + buy_amount) / new_shares
+ # 获取所有股票数据(dask DataFrame)
+ df = self.data.get()
+
+ for date, row in df.iterrows():
+ def get(factor):
+ """
+ 获取指定因子的数据
+
+ Args:
+ factor (str): 因子名称,如 'close', 'volume' 等
+
+ Returns:
+ pd.Series: 该因子在所有股票上的值
+ """
+ s = row[row.index.str.endswith(factor)]
+ s.index = s.index.str.replace(f'_{factor}$', '', regex=True)
+ return s
- self.positions[symbol] = new_shares
- self.avg_costs[symbol] = new_avg_cost
- self.cash -= total_cost
- # 记录交易
- self.trades.append({
- 'date': getattr(self, 'current_date', datetime.now()),
- 'symbol': symbol,
- 'action': 'buy',
- 'shares': shares,
- 'price': price,
- 'amount': buy_amount,
- 'commission': commission
- })
+ # 先调用策略的on_bar(可能包含交易操作)
+ self.strategy.on_bar(date, get)
- return True
- return False
+ # 再调用broker的on_bar记录状态(包含交易后的状态)
+ self.strategy.broker.on_bar(date, get)
- def sell(self, symbol: str, amount: float = 1.0, price: Optional[float] = None) -> bool:
+ def plot(self, title="回测收益曲线"):
"""
- 卖出股票
+ 绘制回测收益曲线图
Args:
- symbol: 股票代码
- amount: 比例或数量,如果 <= 1 则视为比例,否则视为股数
- price: 价格,为None时使用当前价格
- """
- current_shares = self.positions.get(symbol, 0)
- if current_shares == 0:
- return False
-
- if amount <= 1: # 按比例卖出
- sell_shares = int(current_shares * amount)
- else: # 按股数卖出
- sell_shares = min(int(amount / 100) * 100, current_shares)
+ title (str): 图表标题,默认为"回测收益曲线"
- if sell_shares <= 0:
- return False
-
- sell_amount = sell_shares * price
- commission = sell_amount * self.commission_rate
- net_proceeds = sell_amount - commission
+ Returns:
+ plotly.graph_objects.Figure: 交互式图表对象,如果无数据则返回None
+ """
- # 更新持仓
- self.positions[symbol] = current_shares - sell_shares
- if self.positions[symbol] == 0:
- del self.positions[symbol]
- if symbol in self.avg_costs:
- del self.avg_costs[symbol]
-
- self.cash += net_proceeds
- # 记录交易
- self.trades.append({
- 'date': getattr(self, 'current_date', datetime.now()),
- 'symbol': symbol,
- 'action': 'sell',
- 'shares': sell_shares,
- 'price': price,
- 'amount': sell_amount,
- 'commission': commission
- })
+ # 获取交易数据
+ trades_df = self.strategy.broker.trades
- return True
-
- def get_position(self, symbol: str) -> int:
- """获取持仓数量"""
- return self.positions.get(symbol, 0)
-
- def get_cash(self) -> float:
- """获取可用现金"""
- return self.cash
-
- def get_total_value(self, prices: Dict[str, float]) -> float:
- """计算总资产"""
- stock_value = sum(shares * prices.get(symbol, 0)
- for symbol, shares in self.positions.items())
- return self.cash + stock_value
-
- def get_positions(self) -> Dict[str, int]:
- """获取所有持仓"""
- return self.positions.copy()
-
-def backtest(data: Data, strategy: Strategy, broker: Optional[Broker] = None,
- start_time: str = '', end_time: str = '') -> Dict[str, Any]:
- """
- 简化的回测函数
-
- Args:
- data: 数据对象
- strategy: 策略对象
- broker: 交易接口,为None时使用默认设置
- start_time: 开始时间 'YYYY-MM-DD'
- end_time: 结束时间 'YYYY-MM-DD'
-
- Returns:
- 回测结果字典
- """
- # 获取历史数据
- historical_data = data.get(period='1d', start_time=start_time, end_time=end_time)
-
- if not historical_data:
- raise ValueError("未获取到有效数据")
-
- # 初始化broker
- if broker is None:
- broker = Broker()
-
- # 获取所有交易日期
- all_dates = set()
- for symbol, df in historical_data.items():
- if isinstance(df, pd.DataFrame) and not df.empty:
- dates = df.index
- if start_time:
- start_dt = pd.to_datetime(start_time)
- dates = dates[dates >= start_dt]
- if end_time:
- end_dt = pd.to_datetime(end_time)
- dates = dates[dates <= end_dt]
- all_dates.update(dates)
-
- trading_days = sorted(list(all_dates))
-
- if not trading_days:
- raise ValueError("没有找到有效的交易日期")
-
- # 策略初始化
- strategy.on_start(broker)
-
- # 逐日回测
- for current_date in trading_days:
- broker.current_date = current_date
+ # 检查是否有数据
+ if trades_df.empty or 'total' not in trades_df.columns:
+ print("错误:没有可用的回测数据或缺少total列")
+ return None
- # 准备当日数据(截止到当前日期的历史数据)
- current_data = {}
- current_prices = {}
+ # 提取总资产数据
+ total_assets = trades_df['total']
- for symbol, df in historical_data.items():
- if current_date in df.index:
- # 获取截止到当前日期的所有历史数据
- historical_slice = df.loc[:current_date].copy()
- current_data[symbol] = historical_slice
- current_prices[symbol] = df.loc[current_date, 'close']
+ # 创建交互式图表
+ fig = go.Figure()
- # 执行策略
- if current_data:
- try:
- strategy.on_bar(current_data, broker, current_date)
- except Exception as e:
- print(f"策略执行错误 {current_date}: {e}")
- continue
+ fig.add_trace(go.Scatter(
+ x=total_assets.index,
+ y=total_assets.values,
+ mode='lines',
+ name='总资产',
+ line=dict(color='#2E86AB', width=3),
+ hovertemplate='日期: %{x}
总资产: ¥%{y:,.2f}'
+ ))
- # 记录当日资产状况
- total_value = broker.get_total_value(current_prices)
- broker.daily_values.append({
- 'date': current_date,
- 'cash': broker.cash,
- 'total_value': total_value,
- 'positions': broker.get_positions().copy(),
- 'prices': current_prices.copy()
- })
-
- # 策略结束
- strategy.on_end(broker)
-
- # 计算回测结果
- return _calculate_performance(broker)
-
-def _calculate_performance(broker: Broker) -> Dict[str, Any]:
- """计算回测绩效指标"""
-
- if not broker.daily_values:
- return {
- 'error': '没有有效的回测数据'
- }
-
- # 提取数据
- dates = [record['date'] for record in broker.daily_values]
- values = [record['total_value'] for record in broker.daily_values]
-
- # 基本统计
- initial_value = broker.initial_cash
- final_value = values[-1] if values else initial_value
- total_return = (final_value - initial_value) / initial_value
-
- # 计算年化收益率
- days = len(values)
- if days > 0:
- annual_return = (final_value / initial_value) ** (252 / days) - 1
- else:
- annual_return = 0
-
- # 计算波动率和夏普比率
- returns = pd.Series(values).pct_change().dropna()
- if len(returns) > 1:
- volatility = returns.std() * np.sqrt(252)
- sharpe_ratio = annual_return / volatility if volatility > 0 else 0
- else:
- volatility = 0
- sharpe_ratio = 0
-
- # 计算最大回撤
- peak = pd.Series(values).expanding().max()
- drawdown = (pd.Series(values) - peak) / peak
- max_drawdown = drawdown.min()
- # 交易统计
- trades = broker.trades
- total_trades = len(trades)
- total_commission = sum(trade['commission'] for trade in trades)
-
- # 简化的胜率计算
- profitable_trades = 0
- buy_trades = [t for t in trades if t['action'] == 'buy']
- sell_trades = [t for t in trades if t['action'] == 'sell']
-
- if total_trades > 0 and sell_trades:
- for sell_trade in sell_trades:
- symbol = sell_trade['symbol']
- sell_date = sell_trade['date']
-
- # 查找最近的买入记录
- recent_buy = None
- for buy_trade in reversed(buy_trades):
- if (buy_trade['symbol'] == symbol and
- buy_trade['date'] <= sell_date):
- recent_buy = buy_trade
- break
-
- if recent_buy:
- profit = (sell_trade['price'] - recent_buy['price']) * sell_trade['shares']
- profit -= (sell_trade['commission'] + recent_buy['commission'])
- if profit > 0:
- profitable_trades += 1
-
- win_rate = profitable_trades / len(sell_trades) if sell_trades else 0
-
- return {
- 'initial_capital': initial_value,
- 'final_value': final_value,
- 'total_return': total_return,
- 'annual_return': annual_return,
- 'volatility': volatility,
- 'sharpe_ratio': sharpe_ratio,
- 'max_drawdown': max_drawdown,
- 'total_trades': total_trades,
- 'total_commission': total_commission,
- 'win_rate': win_rate,
- 'trading_days': days,
- 'daily_values': broker.daily_values,
- 'trades': trades,
- 'positions': broker.get_positions()
- }
\ No newline at end of file
+ # 更新布局
+ fig.update_layout(
+ title=dict(
+ text=title,
+ x=0.5,
+ font=dict(size=16)
+ ),
+ xaxis_title="日期",
+ yaxis_title="总资产 (¥)",
+ height=600,
+ showlegend=True,
+ template='plotly_white',
+ hovermode='x unified'
+ )
+
+ # 添加网格线
+ fig.update_xaxes(showgrid=True, gridwidth=1, gridcolor='LightGrey')
+
+ # 显示图表
+ fig.show()
+
+ return fig
\ No newline at end of file
diff --git a/qka/core/broker.py b/qka/core/broker.py
new file mode 100644
index 0000000..861ae07
--- /dev/null
+++ b/qka/core/broker.py
@@ -0,0 +1,215 @@
+"""
+QKA经纪商模块
+
+提供虚拟交易经纪商功能,管理资金、持仓和交易记录,支持回测环境下的交易操作。
+"""
+
+import pandas as pd
+from typing import Dict, List, Any, Optional
+
+class Broker:
+ """
+ 虚拟交易经纪商类
+
+ 管理资金、持仓和交易记录,提供买入卖出操作接口。
+
+ Attributes:
+ cash (float): 可用现金
+ positions (Dict): 持仓记录,格式: {symbol: {'size': 数量, 'avg_price': 平均成本}}
+ trade_history (List): 交易历史记录
+ timestamp: 当前时间戳
+ trades (pd.DataFrame): 交易记录DataFrame
+ """
+
+ def __init__(self, initial_cash=100000.0):
+ """
+ 初始化Broker类
+
+ Args:
+ initial_cash (float): 初始资金,默认10万元
+ """
+ self.cash = initial_cash # 可用现金
+ self.positions = {} # 持仓记录,格式: {symbol: {'size': 数量, 'avg_price': 平均成本}}
+ self.trade_history = [] # 交易历史记录
+ self.timestamp = None # 当前时间戳
+
+ # 交易记录
+ self.trades = pd.DataFrame(columns=[
+ 'cash', 'value', 'total',
+ 'positions', 'trades'
+ ])
+
+ def on_bar(self, date, get):
+ """
+ 处理每个bar的数据,记录状态
+
+ Args:
+ date: 当前时间戳
+ get: 获取因子数据的函数,格式为 get(factor_name) -> pd.Series
+ """
+ self.timestamp = date
+
+ # 获取当前市场价格
+ close_prices = get('close')
+ market_prices = close_prices.to_dict() if hasattr(close_prices, 'to_dict') else {}
+
+ # 记录状态到trades DataFrame
+ if self.timestamp is None:
+ return
+
+ # 获取当日交易记录
+ daily_trades = []
+ for trade in self.trade_history:
+ if trade['timestamp'] == self.timestamp:
+ daily_trades.append(trade)
+
+ # 计算持仓市值
+ position_value = 0.0
+ for symbol, position in self.positions.items():
+ if market_prices and symbol in market_prices:
+ # 使用市场价格计算市值
+ position_value += position['size'] * market_prices[symbol]
+ else:
+ # 使用平均成本估算市值
+ position_value += position['size'] * position['avg_price']
+
+ # 计算总资产
+ total_assets = self.cash + position_value
+
+ # 记录状态
+ state_data = {
+ 'cash': self.cash,
+ 'value': position_value,
+ 'total': total_assets,
+ 'positions': self.positions.copy(),
+ 'trades': daily_trades.copy()
+ }
+
+ # 添加到trades
+ self.trades.loc[self.timestamp] = state_data
+
+ def buy(self, symbol: str, price: float, size: int) -> bool:
+ """
+ 买入操作
+
+ Args:
+ symbol (str): 交易标的代码
+ price (float): 买入价格
+ size (int): 买入数量
+
+ Returns:
+ bool: 交易是否成功
+ """
+ # 计算买入所需金额
+ required_cash = price * size
+
+ # 检查资金是否足够
+ if self.cash < required_cash:
+ print(f"资金不足!需要 {required_cash:.2f},当前可用 {self.cash:.2f}")
+ return False
+
+ # 执行买入操作
+ self.cash -= required_cash
+
+ # 更新持仓
+ if symbol in self.positions:
+ # 已有持仓,计算新的平均成本
+ old_position = self.positions[symbol]
+ old_size = old_position['size']
+ old_avg_price = old_position['avg_price']
+ old_total_value = old_size * old_avg_price
+ new_total_value = old_total_value + required_cash
+ new_size = old_size + size
+ new_avg_price = new_total_value / new_size
+
+ self.positions[symbol] = {
+ 'size': new_size,
+ 'avg_price': new_avg_price
+ }
+ else:
+ # 新建持仓
+ self.positions[symbol] = {
+ 'size': size,
+ 'avg_price': price
+ }
+
+ # 记录交易历史
+ self.trade_history.append({
+ 'action': 'buy',
+ 'symbol': symbol,
+ 'price': price,
+ 'size': size,
+ 'timestamp': self.timestamp
+ })
+
+ print(f"买入成功: {symbol} {size}股 @ {price:.2f},花费 {required_cash:.2f}")
+ return True
+
+ def sell(self, symbol: str, price: float, size: int) -> bool:
+ """
+ 卖出操作
+
+ Args:
+ symbol (str): 交易标的代码
+ price (float): 卖出价格
+ size (int): 卖出数量
+
+ Returns:
+ bool: 交易是否成功
+ """
+ # 检查是否有足够的持仓
+ if symbol not in self.positions:
+ print(f"没有 {symbol} 的持仓!")
+ return False
+
+ position = self.positions[symbol]
+ if position['size'] < size:
+ print(f"持仓不足!当前持有 {position['size']},尝试卖出 {size}")
+ return False
+
+ # 计算卖出所得金额
+ sale_proceeds = price * size
+
+ # 执行卖出操作
+ self.cash += sale_proceeds
+
+ # 更新持仓
+ if position['size'] == size:
+ # 全部卖出,删除持仓记录
+ del self.positions[symbol]
+ else:
+ # 部分卖出,更新持仓数量
+ self.positions[symbol]['size'] -= size
+
+ # 记录交易历史
+ self.trade_history.append({
+ 'action': 'sell',
+ 'symbol': symbol,
+ 'price': price,
+ 'size': size,
+ 'timestamp': self.timestamp
+ })
+
+ print(f"卖出成功: {symbol} {size}股 @ {price:.2f},获得 {sale_proceeds:.2f}")
+ return True
+
+ def get(self, factor: str, timestamp=None) -> Any:
+ """
+ 从trades DataFrame中获取数据
+
+ Args:
+ factor (str): 列名,可选 'cash', 'value', 'total', 'positions', 'trades'
+ timestamp: 时间戳,如果为None则使用当前时间戳
+
+ Returns:
+ Any: 对应列的数据,如果不存在则返回None
+ """
+ if timestamp is None:
+ timestamp = self.timestamp
+
+ if timestamp is None or timestamp not in self.trades.index:
+ return None
+
+ return self.trades.at[timestamp, factor]
+
+
diff --git a/qka/core/config.py b/qka/core/config.py
deleted file mode 100644
index 719ff2d..0000000
--- a/qka/core/config.py
+++ /dev/null
@@ -1,230 +0,0 @@
-"""
-QKA 配置管理系统
-提供统一的配置管理,支持环境变量、配置文件和代码配置
-"""
-
-import os
-import json
-from typing import Any, Dict, Optional
-from pathlib import Path
-from dataclasses import dataclass, asdict
-
-
-@dataclass
-class BacktestConfig:
- """回测配置"""
- initial_cash: float = 1_000_000 # 初始资金
- commission_rate: float = 0.0003 # 手续费率
- slippage: float = 0.001 # 滑点率
- min_trade_amount: int = 100 # 最小交易股数
- max_position_ratio: float = 0.3 # 单只股票最大仓位比例
- benchmark: str = '000300.SH' # 基准指数
-
-
-@dataclass
-class DataConfig:
- """数据配置"""
- default_source: str = 'akshare' # 默认数据源
- cache_enabled: bool = True # 是否启用缓存
- cache_dir: str = './data_cache' # 缓存目录
- cache_expire_days: int = 7 # 缓存过期天数
- quality_check: bool = True # 是否进行数据质量检查
- auto_download: bool = True # 是否自动下载缺失数据
-
-
-@dataclass
-class TradingConfig:
- """交易配置"""
- server_host: str = '0.0.0.0'
- server_port: int = 8000
- token_auto_generate: bool = True
- order_timeout: int = 30 # 订单超时时间(秒)
- max_retry_times: int = 3 # 最大重试次数
- heartbeat_interval: int = 30 # 心跳间隔(秒)
-
-
-@dataclass
-class LogConfig:
- """日志配置"""
- level: str = 'INFO'
- console_output: bool = True
- file_output: bool = True
- log_dir: str = './logs'
- max_file_size: str = '10MB'
- backup_count: int = 10
- format: str = '[%(levelname)s][%(asctime)s][%(name)s] %(message)s'
-
-
-@dataclass
-class PlotConfig:
- """绘图配置"""
- theme: str = 'plotly_white'
- figure_height: int = 600
- figure_width: int = 1000
- color_scheme: str = 'default' # default, dark, colorful
- show_grid: bool = True
- auto_open: bool = True
-
-
-class Config:
- """QKA 配置管理器"""
-
- def __init__(self, config_file: Optional[str] = None):
- """
- 初始化配置管理器
-
- Args:
- config_file: 配置文件路径,为None时使用默认配置
- """
- # 默认配置
- self.backtest = BacktestConfig()
- self.data = DataConfig()
- self.trading = TradingConfig()
- self.log = LogConfig()
- self.plot = PlotConfig()
-
- # 加载配置文件
- if config_file and os.path.exists(config_file):
- self.load_from_file(config_file)
-
- # 加载环境变量配置
- self.load_from_env()
-
- def load_from_file(self, config_file: str):
- """从配置文件加载配置"""
- try:
- with open(config_file, 'r', encoding='utf-8') as f:
- config_data = json.load(f)
-
- # 更新各个配置段
- if 'backtest' in config_data:
- self._update_config(self.backtest, config_data['backtest'])
- if 'data' in config_data:
- self._update_config(self.data, config_data['data'])
- if 'trading' in config_data:
- self._update_config(self.trading, config_data['trading'])
- if 'log' in config_data:
- self._update_config(self.log, config_data['log'])
- if 'plot' in config_data:
- self._update_config(self.plot, config_data['plot'])
-
- except Exception as e:
- print(f"加载配置文件失败: {e}")
-
- def load_from_env(self):
- """从环境变量加载配置"""
- # 回测配置
- if os.getenv('QKA_INITIAL_CASH'):
- self.backtest.initial_cash = float(os.getenv('QKA_INITIAL_CASH'))
- if os.getenv('QKA_COMMISSION_RATE'):
- self.backtest.commission_rate = float(os.getenv('QKA_COMMISSION_RATE'))
-
- # 数据配置
- if os.getenv('QKA_DATA_SOURCE'):
- self.data.default_source = os.getenv('QKA_DATA_SOURCE')
- if os.getenv('QKA_CACHE_DIR'):
- self.data.cache_dir = os.getenv('QKA_CACHE_DIR')
- # 交易配置
- if os.getenv('QKA_SERVER_PORT'):
- self.trading.server_port = int(os.getenv('QKA_SERVER_PORT'))
-
- def _update_config(self, config_obj, config_dict: Dict[str, Any]):
- """更新配置对象"""
- for key, value in config_dict.items():
- if hasattr(config_obj, key):
- setattr(config_obj, key, value)
-
- def save_to_file(self, config_file: str):
- """保存配置到文件"""
- config_data = {
- 'backtest': asdict(self.backtest),
- 'data': asdict(self.data),
- 'trading': asdict(self.trading),
- 'log': asdict(self.log),
- 'plot': asdict(self.plot)
- }
-
- # 确保目录存在(只有当目录路径不为空时)
- dir_path = os.path.dirname(config_file)
- if dir_path:
- os.makedirs(dir_path, exist_ok=True)
-
- with open(config_file, 'w', encoding='utf-8') as f:
- json.dump(config_data, f, indent=2, ensure_ascii=False)
-
- def to_dict(self) -> Dict[str, Any]:
- """转换为字典格式"""
- return {
- 'backtest': asdict(self.backtest),
- 'data': asdict(self.data),
- 'trading': asdict(self.trading),
- 'log': asdict(self.log),
- 'plot': asdict(self.plot)
- }
-
- def get(self, section: str, key: str, default: Any = None) -> Any:
- """获取配置值"""
- section_obj = getattr(self, section, None)
- if section_obj:
- return getattr(section_obj, key, default)
- return default
-
- def set(self, section: str, key: str, value: Any):
- """设置配置值"""
- section_obj = getattr(self, section, None)
- if section_obj:
- setattr(section_obj, key, value)
-
-
-# 全局配置实例
-config = Config()
-
-
-def load_config(config_file: Optional[str] = None) -> Config:
- """
- 加载配置文件
-
- Args:
- config_file: 配置文件路径
-
- Returns:
- Config对象
-
- Examples:
- # 使用默认配置
- config = load_config()
-
- # 从文件加载配置
- config = load_config('config.json')
-
- # 访问配置
- print(config.backtest.initial_cash)
- print(config.data.default_source)
- """
- global config
- config = Config(config_file)
- return config
-
-
-def create_sample_config(file_path: str = 'qka_config.json'):
- """
- 创建示例配置文件
-
- Args:
- file_path: 配置文件路径
- """
- sample_config = Config()
- sample_config.save_to_file(file_path)
- print(f"示例配置文件已创建: {file_path}")
-
-
-if __name__ == '__main__':
- # 创建示例配置文件
- create_sample_config()
-
- # 测试配置加载
- cfg = load_config('qka_config.json')
- print("配置加载完成:")
- print(f"初始资金: {cfg.backtest.initial_cash:,}")
- print(f"数据源: {cfg.data.default_source}")
- print(f"服务器端口: {cfg.trading.server_port}")
diff --git a/qka/core/data.py b/qka/core/data.py
new file mode 100644
index 0000000..55a5be1
--- /dev/null
+++ b/qka/core/data.py
@@ -0,0 +1,180 @@
+"""
+QKA数据模块
+
+提供统一的数据获取、缓存和管理功能,支持多数据源、多周期、多因子的数据获取。
+"""
+
+from pathlib import Path
+from tqdm import tqdm
+from concurrent.futures import ThreadPoolExecutor, as_completed
+import pandas as pd
+import pyarrow as pa
+import pyarrow.parquet as pq
+import akshare as ak
+import dask.dataframe as dd
+from typing import List, Dict, Optional, Callable
+from qka.utils.logger import logger
+
+class Data():
+ """
+ 数据管理类
+
+ 负责股票数据的获取、缓存和管理,支持多数据源、并发下载和自定义因子计算。
+
+ Attributes:
+ symbols (List[str]): 股票代码列表
+ period (str): 数据周期,如 '1d'、'1m' 等
+ adjust (str): 复权方式,如 'qfq'、'hfq'、'bfq'
+ factor (Callable): 因子计算函数
+ source (str): 数据源,如 'akshare'、'qmt'
+ pool_size (int): 并发下载线程数
+ datadir (Path): 数据缓存目录
+ target_dir (Path): 目标存储目录
+ """
+
+ def __init__(
+ self,
+ symbols: Optional[List[str]] = None,
+ period: str = '1d',
+ adjust: str = 'qfq',
+ factor: Callable[[pd.DataFrame], pd.DataFrame] = lambda df: df,
+ source: str = 'akshare',
+ pool_size: int = 10,
+ datadir: Optional[Path] = None
+ ):
+ """
+ 初始化数据对象
+
+ Args:
+ symbols: [维度1] 标的,如 ['000001.SZ', '600000.SH']
+ period: [维度2] 周期,如 '1m', '5m', '1d' 等
+ factor: [维度3] 因子字典,key为因子名,value为因子函数
+ source: [维度4] 数据来源 ('qmt', 'akshare')
+ pool_size: 并发池大小
+ datadir: 缓存根目录,默认为项目根目录下的 datadir
+ """
+ self.symbols = symbols or []
+ self.period = period
+ self.adjust = adjust
+ self.factor = factor
+ self.source = source
+ self.pool_size = pool_size
+
+ # 初始化缓存目录
+ if datadir is None:
+ # 默认使用当前工作目录下的 datadir
+ self.datadir = Path.cwd() / "datadir"
+ else:
+ self.datadir = Path(datadir)
+
+ self.datadir.mkdir(parents=True, exist_ok=True)
+
+ self.target_dir = self.datadir / self.source / self.period / (self.adjust or "bfq")
+ self.target_dir.mkdir(parents=True, exist_ok=True)
+
+ def _download(self, symbol: str) -> Path:
+ """
+ 下载单个股票的数据
+
+ Args:
+ symbol (str): 股票代码
+
+ Returns:
+ Path: 数据文件路径
+ """
+ path = self.target_dir / f"{symbol}.parquet"
+
+ if path.exists():
+ return path
+
+ if self.source == 'akshare':
+ df = self._get_from_akshare(symbol)
+ else:
+ df = pd.DataFrame()
+
+ if len(df) == 0:
+ return path
+
+ table = pa.Table.from_pandas(df)
+ pq.write_table(table, path)
+
+ return path
+
+ def get(self) -> dd.DataFrame:
+ """
+ 获取历史数据
+
+ 并发下载所有股票数据,应用因子计算,并返回合并后的Dask DataFrame。
+
+ Returns:
+ dd.DataFrame: 合并后的股票数据,每只股票的列名格式为 {symbol}_{column}
+ """
+ # 准备缓存目录
+
+ with ThreadPoolExecutor(max_workers=self.pool_size) as executor:
+ # 提交下载任务
+ futures = {
+ executor.submit(self._download, symbol): symbol
+ for symbol in self.symbols
+ }
+
+ # 添加tqdm进度条
+ with tqdm(total=len(self.symbols), desc="下载数据") as pbar:
+ for future in as_completed(futures):
+ symbol = futures[future]
+ pbar.update(1)
+ pbar.set_postfix_str(f"当前: {symbol}")
+
+ dfs = []
+ for symbol in self.symbols:
+ df = dd.read_parquet(str(self.target_dir / f"{symbol}.parquet"))
+ df = self.factor(df)
+ column_mapping = {col: f'{symbol}_{col}' for col in df.columns}
+ dfs.append(df.rename(columns=column_mapping))
+
+ df = dd.concat(dfs, axis=1, join='outer')
+
+ return df
+
+ def _get_from_akshare(self, symbol: str) -> pd.DataFrame:
+ """
+ 从 akshare 获取单个股票的数据。
+
+ Args:
+ symbol (str): 股票代码,支持带后缀如 000001.SZ 或不带后缀的 000001
+
+ Returns:
+ pd.DataFrame: 股票数据,以 date 为索引,包含 open, high, low, close, volume, amount 列
+ """
+ column_mapping = {
+ "日期": "date",
+ "开盘": "open",
+ "收盘": "close",
+ "最高": "high",
+ "最低": "low",
+ "成交量": "volume",
+ "成交额": "amount",
+ }
+
+ # 下载数据
+ df = ak.stock_zh_a_hist(symbol=symbol, period='daily', adjust=self.adjust)
+
+ # 数据标准化处理
+ # 1. 标准化列名
+ df = df.rename(columns=column_mapping)
+ if "date" in df.columns:
+ df["date"] = pd.to_datetime(df["date"])
+
+ # 2. 确保数值列为数值类型
+ numeric_cols = [c for c in ("open", "high", "low", "close", "volume", "amount") if c in df.columns]
+ for col in numeric_cols:
+ df[col] = pd.to_numeric(df[col], errors="coerce")
+
+ # 3. 只保留需要的列
+ mapped_columns = list(column_mapping.values())
+ available_columns = [col for col in mapped_columns if col in df.columns]
+ df = df[available_columns]
+
+ df = df.set_index('date')
+ # 设置索引
+ return df
diff --git a/qka/core/data/__init__.py b/qka/core/data/__init__.py
deleted file mode 100644
index df7695b..0000000
--- a/qka/core/data/__init__.py
+++ /dev/null
@@ -1,38 +0,0 @@
-"""
-QKA数据模块
-
-提供统一的数据源接口,支持多种数据源:
-- QMT: 专业量化交易数据源
-- Akshare: 开源金融数据接口
-
-使用方式:
- import qka
-
- # 设置默认数据源
- qka.set_source('qmt')
-
- # 创建数据对象
- data_obj = qka.data(stocks=['000001.SZ', '600000.SH'])
-
- # 获取历史数据
- hist_data = data_obj.get('1d', '2024-01-01', '2024-12-31')
-"""
-
-# 从base模块导入所有公共接口
-from .base import (
- set_source,
- get_source,
- data,
- Data,
- register_data_source,
- get_available_sources
-)
-
-# 公开的API - 这些是qka包级别要暴露的
-__all__ = [
- 'set_source',
- 'get_source',
- 'data',
- 'register_data_source',
- 'get_available_sources'
-]
diff --git a/qka/core/data/akshare.py b/qka/core/data/akshare.py
deleted file mode 100644
index 78ba8e7..0000000
--- a/qka/core/data/akshare.py
+++ /dev/null
@@ -1,106 +0,0 @@
-from datetime import datetime, timedelta
-from typing import List, Dict
-import pandas as pd
-from qka.utils.logger import logger
-from .base import DataSource
-
-class AkshareData(DataSource):
- """Akshare数据源"""
-
- def __init__(self, stocks: List[str] = None, sector: str = None):
- super().__init__(stocks, sector)
- try:
- import akshare as ak
- self.ak = ak
- except ImportError:
- logger.error("无法导入akshare,请安装: pip install akshare")
- raise
-
- if sector is not None:
- self.stocks = self._get_stocks_by_sector(sector)
-
- def _get_stocks_by_sector(self, sector: str) -> List[str]:
- """根据板块获取股票列表"""
- try:
- if sector == "沪深A股":
- # 获取沪深A股列表
- stock_info = self.ak.stock_info_a_code_name()
- return stock_info['code'].tolist()[:100] # 限制数量避免过多
- else:
- logger.warning(f"暂不支持板块: {sector}")
- return []
- except Exception as e:
- logger.error(f"获取板块股票失败: {e}")
- return []
-
- def get_historical_data(self, period: str = '1d', start_time: str = '', end_time: str = '') -> Dict[str, pd.DataFrame]:
- """获取Akshare历史数据"""
- if not self.stocks:
- logger.warning("未指定股票列表")
- return {}
-
- result = {}
-
- # 处理日期格式
- if start_time:
- start_date = start_time.replace('-', '') if '-' in start_time else start_time
- else:
- start_date = (datetime.now() - timedelta(days=365)).strftime('%Y%m%d')
-
- if end_time:
- end_date = end_time.replace('-', '') if '-' in end_time else end_time
- else:
- end_date = datetime.now().strftime('%Y%m%d')
-
- for stock in self.stocks:
- try:
- # 转换股票代码格式
- if '.' in stock:
- code = stock.split('.')[0]
- else:
- code = stock
-
- # 获取股票历史数据
- df = self.ak.stock_zh_a_hist(
- symbol=code,
- period='daily',
- start_date=start_date,
- end_date=end_date,
- adjust="qfq" # 前复权
- )
-
- if df is not None and not df.empty:
- # 重命名列以匹配标准格式
- column_mapping = {
- '日期': 'date',
- '开盘': 'open',
- '收盘': 'close',
- '最高': 'high',
- '最低': 'low',
- '成交量': 'volume',
- '成交额': 'amount'
- }
-
- df = df.rename(columns=column_mapping)
- df['date'] = pd.to_datetime(df['date'])
- df = df.set_index('date')
-
- # 确保数值类型
- numeric_cols = ['open', 'high', 'low', 'close', 'volume']
- for col in numeric_cols:
- if col in df.columns:
- df[col] = pd.to_numeric(df[col], errors='coerce')
-
- result[stock] = df
- logger.debug(f"成功获取 {stock} 数据,共 {len(df)} 条记录")
-
- except Exception as e:
- logger.error(f"获取 {stock} 数据失败: {e}")
- continue
-
- return self.normalize_data(result)
-
- def subscribe_realtime(self, callback):
- """Akshare暂不支持实时数据订阅"""
- logger.warning("Akshare数据源暂不支持实时数据订阅")
- raise NotImplementedError("Akshare数据源暂不支持实时数据订阅")
diff --git a/qka/core/data/base.py b/qka/core/data/base.py
deleted file mode 100644
index 59ac878..0000000
--- a/qka/core/data/base.py
+++ /dev/null
@@ -1,219 +0,0 @@
-"""
-QKA数据模块基础功能
-
-包含数据源管理、配置、工厂函数等核心功能
-"""
-
-from abc import ABC, abstractmethod
-import pandas as pd
-from typing import List, Dict
-from qka.utils.logger import logger
-
-# ============================================================================
-# 1. 全局配置
-# ============================================================================
-
-# 全局默认数据源配置
-_DEFAULT_DATA_SOURCE = 'akshare'
-
-def set_source(source: str) -> None:
- """
- 设置全局默认数据源
-
- Args:
- source: 数据源类型 ('qmt', 'akshare')
-
- Examples:
- import qka
-
- # 设置默认使用QMT数据源
- qka.set_source('qmt')
-
- # 之后创建数据对象就不需要指定source了
- data_obj = qka.data(stocks=['000001.SZ', '600000.SH'])
- """
- global _DEFAULT_DATA_SOURCE
-
- if source.lower() not in DATA_SOURCE_MAPPING:
- available_sources = ', '.join(DATA_SOURCE_MAPPING.keys())
- raise ValueError(f"不支持的数据源类型: {source},支持的数据源: {available_sources}")
-
- _DEFAULT_DATA_SOURCE = source.lower()
- logger.info(f"已设置默认数据源为: {source}")
-
-def get_source() -> str:
- """
- 获取当前默认数据源
-
- Returns:
- 当前默认数据源名称
- """
- return _DEFAULT_DATA_SOURCE
-
-# ============================================================================
-# 2. 数据源注册机制
-# ============================================================================
-
-# 数据源映射字典(稍后会被初始化)
-DATA_SOURCE_MAPPING = {}
-
-def get_available_sources():
- """获取所有可用的数据源名称"""
- return list(DATA_SOURCE_MAPPING.keys())
-
-def register_data_source(name: str, data_source_class):
- """
- 注册新的数据源
-
- Args:
- name: 数据源名称
- data_source_class: 数据源类(必须继承DataSource)
-
- Examples:
- # 注册新的数据源
- register_data_source('tushare', TushareData)
- """
- if not issubclass(data_source_class, DataSource):
- raise TypeError(f"数据源类 {data_source_class} 必须继承 DataSource")
-
- DATA_SOURCE_MAPPING[name.lower()] = data_source_class
- logger.info(f"已注册数据源: {name}")
-
-# ============================================================================
-# 3. 基础抽象类
-# ============================================================================
-
-class DataSource(ABC):
- """数据源基类"""
-
- def __init__(self, stocks: List[str] = None, sector: str = None):
- self.stocks = stocks or []
- self.sector = sector
-
- @abstractmethod
- def get_historical_data(self, period: str = '1d', start_time: str = '', end_time: str = '') -> Dict[str, pd.DataFrame]:
- """获取历史数据"""
- pass
-
- @abstractmethod
- def subscribe_realtime(self, callback):
- """订阅实时数据"""
- pass
-
- def normalize_data(self, data: Dict) -> Dict[str, pd.DataFrame]:
- """标准化数据格式为统一的DataFrame格式"""
- normalized = {}
- for symbol, df in data.items():
- if isinstance(df, pd.DataFrame):
- # 确保包含必要的列
- required_cols = ['open', 'high', 'low', 'close', 'volume']
- if all(col in df.columns for col in required_cols):
- # 确保索引是datetime类型
- if not isinstance(df.index, pd.DatetimeIndex):
- if 'time' in df.columns:
- df = df.set_index('time')
- df.index = pd.to_datetime(df.index)
- normalized[symbol] = df
- else:
- logger.warning(f"股票 {symbol} 缺少必要的数据列")
- return normalized
-
-# ============================================================================
-# 4. 统一数据接口
-# ============================================================================
-
-class Data:
- """统一数据接口"""
-
- def __init__(self, source: str = 'akshare', stocks: List[str] = None, sector: str = None):
- """
- 初始化数据对象
-
- Args:
- source: 数据源类型 ('qmt', 'akshare')
- stocks: 股票代码列表
- sector: 板块名称
- """
- self.source_type = source
-
- if source.lower() not in DATA_SOURCE_MAPPING:
- available_sources = ', '.join(DATA_SOURCE_MAPPING.keys())
- raise ValueError(f"不支持的数据源类型: {source},支持的数据源: {available_sources}")
-
- # 动态创建数据源实例
- data_source_class = DATA_SOURCE_MAPPING[source.lower()]
- self.data_source = data_source_class(stocks, sector)
-
- def get(self, period: str = '1d', start_time: str = '', end_time: str = '') -> Dict[str, pd.DataFrame]:
- """获取历史数据"""
- return self.data_source.get_historical_data(period, start_time, end_time)
-
- def subscribe(self, callback):
- """订阅实时数据"""
- return self.data_source.subscribe_realtime(callback)
-
- @property
- def stocks(self) -> List[str]:
- """获取股票列表"""
- return self.data_source.stocks
-
-# ============================================================================
-# 5. 工厂函数
-# ============================================================================
-
-def data(stocks=None, sector=None, source=None):
- """
- 创建数据对象的工厂函数
-
- Args:
- stocks: 股票代码列表
- sector: 板块名称
- source: 数据源类型 ('qmt', 'akshare'),可选参数,如果不指定则使用全局默认数据源
-
- Returns:
- Data对象
-
- Examples:
- import qka
-
- # 设置默认数据源
- qka.set_source('qmt')
-
- # 使用默认数据源创建数据对象
- data_obj = qka.data(stocks=['000001.SZ', '600000.SH'])
-
- # 临时指定其他数据源
- data_ak = qka.data(stocks=['000001', '600000'], source='akshare')
-
- # 获取板块数据
- data_sector = qka.data(sector='沪深A股')
-
- # 获取历史数据
- hist_data = data_obj.get('1d', '2024-01-01', '2024-12-31')
- """
- # 如果没有指定source,使用全局默认数据源
- if source is None:
- source = _DEFAULT_DATA_SOURCE
-
- return Data(source, stocks, sector)
-
-# ============================================================================
-# 6. 初始化数据源映射
-# ============================================================================
-
-def _initialize_data_sources():
- """初始化内置数据源"""
- try:
- from .qmt import QMTData
- register_data_source('qmt', QMTData)
- except ImportError:
- pass # QMT可能未安装
-
- try:
- from .akshare import AkshareData
- register_data_source('akshare', AkshareData)
- except ImportError:
- pass # Akshare可能未安装
-
-# 自动初始化内置数据源
-_initialize_data_sources()
diff --git a/qka/core/data/qmt.py b/qka/core/data/qmt.py
deleted file mode 100644
index c00d63e..0000000
--- a/qka/core/data/qmt.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import time
-from datetime import datetime
-from typing import List, Dict
-import pandas as pd
-from qka.utils.logger import logger
-from .base import DataSource
-
-class QMTData(DataSource):
- """QMT数据源"""
-
- def __init__(self, stocks: List[str] = None, sector: str = None):
- super().__init__(stocks, sector)
- try:
- from xtquant import xtdata
- self.xtdata = xtdata
- if sector is not None:
- self.stocks = xtdata.get_stock_list_in_sector(sector)
- except ImportError:
- logger.error("无法导入xtquant,请检查QMT是否正确安装")
- raise
-
- def get_historical_data(self, period: str = '1d', start_time: str = '', end_time: str = '') -> Dict[str, pd.DataFrame]:
- """获取QMT历史数据"""
- if not self.stocks:
- logger.warning("未指定股票列表")
- return {}
-
- # 下载数据
- for stock in self.stocks:
- self.xtdata.download_history_data(
- stock_code=stock,
- period=period,
- start_time=start_time,
- end_time=end_time,
- incrementally=True
- )
-
- # 获取本地数据
- res = self.xtdata.get_local_data(
- stock_list=self.stocks,
- period=period,
- start_time=start_time,
- end_time=end_time
- )
-
- return self.normalize_data(res)
-
- def subscribe_realtime(self, callback):
- """订阅QMT实时数据"""
- delays = []
-
- def task(res):
- for code, item in res.items():
- rate = (item['lastPrice'] - item['lastClose']) / item['lastClose']
- timetag = datetime.fromtimestamp(item['time'] / 1000)
- current_time = datetime.fromtimestamp(time.time())
- delay_seconds = (current_time - timetag).total_seconds()
- if delay_seconds < 1000:
- if delay_seconds > 3:
- logger.warning(f'{code} 延迟 {delay_seconds}')
- callback(code, item)
-
- self.xtdata.subscribe_whole_quote(code_list=self.stocks, callback=task)
- self.xtdata.run()
diff --git a/qka/core/events.py b/qka/core/events.py
deleted file mode 100644
index ed211a2..0000000
--- a/qka/core/events.py
+++ /dev/null
@@ -1,365 +0,0 @@
-"""
-QKA 事件驱动框架
-提供发布-订阅模式的事件系统,支持异步和同步事件处理
-"""
-
-import asyncio
-from abc import ABC, abstractmethod
-from collections import defaultdict
-from datetime import datetime
-from enum import Enum
-from typing import Any, Callable, Dict, List, Optional, Union
-from dataclasses import dataclass, asdict
-import threading
-import queue
-import traceback
-from qka.utils.logger import logger
-
-
-class EventType(Enum):
- """事件类型枚举"""
- # 数据相关事件
- DATA_LOADED = "data_loaded"
- DATA_ERROR = "data_error"
-
- # 回测相关事件
- BACKTEST_START = "backtest_start"
- BACKTEST_END = "backtest_end"
- BACKTEST_ERROR = "backtest_error"
-
- # 交易相关事件
- ORDER_CREATED = "order_created"
- ORDER_FILLED = "order_filled"
- ORDER_CANCELLED = "order_cancelled"
- ORDER_ERROR = "order_error"
-
- # 策略相关事件
- STRATEGY_START = "strategy_start"
- STRATEGY_END = "strategy_end"
- STRATEGY_ERROR = "strategy_error"
- SIGNAL_GENERATED = "signal_generated"
-
- # 风险管理事件
- RISK_CHECK = "risk_check"
- RISK_ALERT = "risk_alert"
-
- # 系统事件
- SYSTEM_START = "system_start"
- SYSTEM_SHUTDOWN = "system_shutdown"
- HEARTBEAT = "heartbeat"
-
-
-@dataclass
-class Event:
- """事件基类"""
- event_type: EventType
- data: Any = None
- timestamp: datetime = None
- source: str = None
- event_id: str = None
-
- def __post_init__(self):
- if self.timestamp is None:
- self.timestamp = datetime.now()
- if self.event_id is None:
- self.event_id = f"{self.event_type.value}_{self.timestamp.strftime('%Y%m%d_%H%M%S_%f')}"
-
- def to_dict(self) -> Dict[str, Any]:
- """转换为字典"""
- result = asdict(self)
- result['event_type'] = self.event_type.value
- result['timestamp'] = self.timestamp.isoformat()
- return result
-
-
-@dataclass
-class DataEvent(Event):
- """数据事件"""
- symbol: str = None
- period: str = None
- count: int = None
-
-
-@dataclass
-class OrderEvent(Event):
- """订单事件"""
- order_id: str = None
- symbol: str = None
- action: str = None # buy/sell
- quantity: int = None
- price: float = None
- order_type: str = None
-
-
-@dataclass
-class SignalEvent(Event):
- """信号事件"""
- symbol: str = None
- signal_type: str = None # buy/sell/hold
- strength: float = None # 信号强度 0-1
- reason: str = None
-
-
-class EventHandler(ABC):
- """事件处理器基类"""
-
- @abstractmethod
- def handle(self, event: Event) -> Optional[Any]:
- """处理事件"""
- pass
-
- def can_handle(self, event: Event) -> bool:
- """判断是否可以处理该事件"""
- return True
-
-
-class AsyncEventHandler(EventHandler):
- """异步事件处理器基类"""
-
- @abstractmethod
- async def handle_async(self, event: Event) -> Optional[Any]:
- """异步处理事件"""
- pass
-
- def handle(self, event: Event) -> Optional[Any]:
- """同步接口,内部调用异步方法"""
- return asyncio.run(self.handle_async(event))
-
-
-class EventEngine:
- """事件引擎"""
-
- def __init__(self, max_queue_size: int = 10000):
- """
- 初始化事件引擎
-
- Args:
- max_queue_size: 事件队列最大大小
- """
- self._handlers: Dict[EventType, List[Union[EventHandler, Callable]]] = defaultdict(list)
- self._event_queue = queue.Queue(maxsize=max_queue_size)
- self._running = False
- self._worker_thread = None
- self._event_history: List[Event] = []
- self._max_history_size = 1000
-
- # 统计信息
- self._event_count = defaultdict(int)
- self._error_count = 0
-
- def subscribe(self, event_type: EventType, handler: Union[EventHandler, Callable]):
- """
- 订阅事件
-
- Args:
- event_type: 事件类型
- handler: 事件处理器或回调函数
- """
- self._handlers[event_type].append(handler)
- logger.debug(f"事件订阅: {event_type.value} -> {handler}")
-
- def unsubscribe(self, event_type: EventType, handler: Union[EventHandler, Callable]):
- """取消订阅"""
- if handler in self._handlers[event_type]:
- self._handlers[event_type].remove(handler)
- logger.debug(f"取消事件订阅: {event_type.value} -> {handler}")
-
- def emit(self, event: Event, sync: bool = False):
- """
- 发送事件
-
- Args:
- event: 事件对象
- sync: 是否同步处理
- """
- if sync:
- self._process_event(event)
- else:
- try:
- self._event_queue.put_nowait(event)
- except queue.Full:
- logger.error(f"事件队列已满,丢弃事件: {event.event_type.value}")
-
- def emit_simple(self, event_type: EventType, data: Any = None, source: str = None, sync: bool = False):
- """
- 发送简单事件
-
- Args:
- event_type: 事件类型
- data: 事件数据
- source: 事件源
- sync: 是否同步处理
- """
- event = Event(event_type=event_type, data=data, source=source)
- self.emit(event, sync)
-
- def start(self):
- """启动事件引擎"""
- if self._running:
- logger.warning("事件引擎已经在运行")
- return
-
- self._running = True
- self._worker_thread = threading.Thread(target=self._run, daemon=True)
- self._worker_thread.start()
-
- logger.info("事件引擎已启动")
- self.emit_simple(EventType.SYSTEM_START, {"timestamp": datetime.now()})
-
- def stop(self):
- """停止事件引擎"""
- if not self._running:
- return
-
- self.emit_simple(EventType.SYSTEM_SHUTDOWN, {"timestamp": datetime.now()})
- self._running = False
-
- if self._worker_thread:
- self._worker_thread.join(timeout=5)
-
- logger.info("事件引擎已停止")
-
- def _run(self):
- """事件处理主循环"""
- while self._running:
- try:
- # 带超时的获取事件,避免阻塞
- event = self._event_queue.get(timeout=1)
- self._process_event(event)
- self._event_queue.task_done()
- except queue.Empty:
- continue
- except Exception as e:
- logger.error(f"事件处理异常: {e}\n{traceback.format_exc()}")
- self._error_count += 1
-
- def _process_event(self, event: Event):
- """处理单个事件"""
- try:
- # 记录事件历史
- self._add_to_history(event)
- self._event_count[event.event_type] += 1
-
- # 获取处理器列表
- handlers = self._handlers.get(event.event_type, [])
-
- if not handlers:
- logger.debug(f"没有找到事件处理器: {event.event_type.value}")
- return
-
- # 执行处理器
- for handler in handlers:
- try:
- if isinstance(handler, EventHandler):
- if handler.can_handle(event):
- handler.handle(event)
- elif callable(handler):
- handler(event)
- except Exception as e:
- logger.error(f"事件处理器执行失败: {handler}, 事件: {event.event_type.value}, 错误: {e}")
- self._error_count += 1
-
- except Exception as e:
- logger.error(f"事件处理异常: {e}\n{traceback.format_exc()}")
- self._error_count += 1
-
- def _add_to_history(self, event: Event):
- """添加到事件历史"""
- self._event_history.append(event)
-
- # 保持历史记录大小限制
- if len(self._event_history) > self._max_history_size:
- self._event_history = self._event_history[-self._max_history_size:]
-
- def get_statistics(self) -> Dict[str, Any]:
- """获取统计信息"""
- return {
- "event_count": dict(self._event_count),
- "error_count": self._error_count,
- "queue_size": self._event_queue.qsize(),
- "handler_count": {
- event_type.value: len(handlers)
- for event_type, handlers in self._handlers.items()
- },
- "is_running": self._running
- }
-
- def get_event_history(self, event_type: Optional[EventType] = None, limit: int = 100) -> List[Event]:
- """
- 获取事件历史
-
- Args:
- event_type: 筛选事件类型
- limit: 限制返回数量
- """
- history = self._event_history
-
- if event_type:
- history = [e for e in history if e.event_type == event_type]
-
- return history[-limit:]
-
-
-# 全局事件引擎实例
-event_engine = EventEngine()
-
-
-# 便捷的装饰器函数
-def event_handler(event_type: EventType):
- """
- 事件处理器装饰器
-
- Examples:
- @event_handler(EventType.ORDER_FILLED)
- def on_order_filled(event):
- print(f"订单成交: {event.data}")
- """
- def decorator(func):
- event_engine.subscribe(event_type, func)
- return func
- return decorator
-
-
-# 便捷函数
-def emit_event(event_type: EventType, data: Any = None, source: str = None, sync: bool = False):
- """发送事件的便捷函数"""
- event_engine.emit_simple(event_type, data, source, sync)
-
-
-def start_event_engine():
- """启动事件引擎"""
- event_engine.start()
-
-
-def stop_event_engine():
- """停止事件引擎"""
- event_engine.stop()
-
-
-if __name__ == '__main__':
- # 测试事件系统
-
- @event_handler(EventType.DATA_LOADED)
- def on_data_loaded(event):
- print(f"数据加载完成: {event.data}")
-
- @event_handler(EventType.ORDER_FILLED)
- def on_order_filled(event):
- print(f"订单成交: {event.data}")
-
- # 启动事件引擎
- start_event_engine()
-
- # 发送测试事件
- emit_event(EventType.DATA_LOADED, {"symbol": "000001", "count": 1000})
- emit_event(EventType.ORDER_FILLED, {"order_id": "123", "price": 10.5})
-
- # 等待处理完成
- import time
- time.sleep(1)
-
- # 查看统计信息
- print("事件统计:", event_engine.get_statistics())
-
- # 停止事件引擎
- stop_event_engine()
diff --git a/qka/core/plot.py b/qka/core/plot.py
deleted file mode 100644
index 78009a9..0000000
--- a/qka/core/plot.py
+++ /dev/null
@@ -1,218 +0,0 @@
-import pandas as pd
-import plotly.graph_objects as go
-from plotly.subplots import make_subplots
-from typing import Dict, Any
-import numpy as np
-
-def plot(result: Dict[str, Any], title: str = "回测结果"):
- """
- 绘制回测结果图表
-
- Args:
- result: backtest()函数返回的结果字典
- title: 图表标题
-
- Examples:
- import qka
-
- result = qka.backtest(data, strategy)
- qka.plot(result)
- """
-
- if 'daily_values' not in result or not result['daily_values']:
- print("错误:回测结果中没有日收益数据")
- return
-
- # 提取数据
- daily_data = result['daily_values']
- dates = [record['date'] for record in daily_data]
- values = [record['total_value'] for record in daily_data]
-
- # 计算累计收益率和其他指标
- initial_value = result['initial_capital']
- returns = [(v - initial_value) / initial_value * 100 for v in values]
-
- # 计算每日收益率
- daily_returns = []
- for i in range(1, len(values)):
- daily_return = (values[i] - values[i-1]) / values[i-1] * 100
- daily_returns.append(daily_return)
-
- # 计算回撤
- peak_values = pd.Series(values).expanding().max()
- drawdowns = [(v - peak) / peak * 100 for v, peak in zip(values, peak_values)]
-
- # 定义颜色函数
- def get_color_style(value):
- """根据值的正负返回颜色样式"""
- if value < 0:
- return "color: red;"
- else:
- return "color: green;"
-
- # 创建子图
- fig = make_subplots(
- rows=3, cols=2,
- subplot_titles=(
- '累计收益率曲线', '回撤分析',
- '资产价值变化', '每日收益率分布',
- '滚动夏普比率', '月度收益'
- ),
- specs=[
- [{"colspan": 2}, None],
- [{"secondary_y": False}, {"type": "histogram"}],
- [{"secondary_y": False}, {"secondary_y": False}]
- ],
- vertical_spacing=0.12,
- horizontal_spacing=0.1
- )
-
- # 1. 累计收益率曲线 (主图)
- fig.add_trace(
- go.Scatter(
- x=dates,
- y=returns,
- mode='lines',
- name='累计收益率',
- line=dict(color='#2E86AB', width=3),
- hovertemplate='日期: %{x}
收益率: %{y:.2f}%'
- ),
- row=1, col=1
- )
-
- # 添加零轴线
- fig.add_hline(y=0, line_dash="dash", line_color="gray", opacity=0.5, row=1, col=1)
-
- # 2. 回撤分析
- fig.add_trace(
- go.Scatter(
- x=dates,
- y=drawdowns,
- mode='lines',
- name='回撤',
- line=dict(color='#A23B72', width=2),
- fill='tonexty',
- fillcolor='rgba(162, 59, 114, 0.2)',
- hovertemplate='日期: %{x}
回撤: %{y:.2f}%'
- ),
- row=2, col=1
- )
-
- # 3. 资产价值变化
- fig.add_trace(
- go.Scatter(
- x=dates,
- y=values,
- mode='lines',
- name='总资产',
- line=dict(color='#F18F01', width=2),
- hovertemplate='日期: %{x}
资产: ¥%{y:,.0f}'
- ),
- row=2, col=2
- )
-
- # 4. 每日收益率分布
- if daily_returns:
- fig.add_trace(
- go.Histogram(
- x=daily_returns,
- name='每日收益率',
- nbinsx=30,
- marker_color='#C73E1D',
- opacity=0.7,
- hovertemplate='收益率: %{x:.2f}%
频次: %{y}'
- ),
- row=3, col=1
- )
-
- # 5. 滚动夏普比率 (30日)
- if len(daily_returns) > 30:
- rolling_sharpe = []
- for i in range(30, len(daily_returns)):
- window_returns = daily_returns[i-30:i]
- if len(window_returns) > 0:
- mean_return = np.mean(window_returns)
- std_return = np.std(window_returns)
- sharpe = (mean_return * 252) / (std_return * np.sqrt(252)) if std_return > 0 else 0
- rolling_sharpe.append(sharpe)
-
- if rolling_sharpe:
- fig.add_trace(
- go.Scatter(
- x=dates[30:30+len(rolling_sharpe)],
- y=rolling_sharpe,
- mode='lines',
- name='30日滚动夏普',
- line=dict(color='#3F88C5', width=2),
- hovertemplate='日期: %{x}
夏普比率: %{y:.2f}'
- ),
- row=3, col=2
- )
-
- # 更新布局
- fig.update_layout(
- title=dict(
- text=f"{title}
总收益: {result['total_return']:.2%} | 年化收益: {result['annual_return']:.2%} | 夏普比率: {result['sharpe_ratio']:.2f} | 最大回撤: {result['max_drawdown']:.2%}",
- x=0.5,
- font=dict(size=16)
- ),
- height=800,
- showlegend=True,
- template='plotly_white',
- margin=dict(t=120, b=60, l=60, r=60)
- )
-
- # 更新子图标题
- fig.update_xaxes(title_text="日期", row=1, col=1)
- fig.update_yaxes(title_text="累计收益率 (%)", row=1, col=1)
-
- fig.update_xaxes(title_text="日期", row=2, col=1)
- fig.update_yaxes(title_text="回撤 (%)", row=2, col=1)
-
- fig.update_xaxes(title_text="日期", row=2, col=2)
- fig.update_yaxes(title_text="资产价值 (¥)", row=2, col=2)
-
- fig.update_xaxes(title_text="每日收益率 (%)", row=3, col=1)
- fig.update_yaxes(title_text="频次", row=3, col=1)
-
- fig.update_xaxes(title_text="日期", row=3, col=2)
- fig.update_yaxes(title_text="夏普比率", row=3, col=2)
-
- # 显示图表
- fig.show()
-
- # 打印关键指标
- print(f"\n📊 回测结果摘要")
- print(f"{'='*50}")
- print(f"📈 收益指标:")
- print(f" 总收益率: {result['total_return']:.2%}")
- print(f" 年化收益率: {result['annual_return']:.2%}")
- print(f" 基准收益率: {result.get('benchmark_return', 'N/A')}")
- print(f"")
- print(f"⚠️ 风险指标:")
- print(f" 波动率: {result['volatility']:.2%}")
- print(f" 夏普比率: {result['sharpe_ratio']:.2f}")
- print(f" 最大回撤: {result['max_drawdown']:.2%}")
- print(f"")
- print(f"📊 交易指标:")
- print(f" 胜率: {result['win_rate']:.2%}")
- print(f" 总交易次数: {result['total_trades']}")
- print(f" 交易成本: ¥{result['total_commission']:,.2f}")
- print(f" 交易天数: {result['trading_days']}")
-
- # 计算额外统计信息
- if daily_returns:
- print(f"")
- print(f"📋 统计信息:")
- print(f" 平均日收益: {np.mean(daily_returns):.3f}%")
- print(f" 收益标准差: {np.std(daily_returns):.3f}%")
- print(f" 最大单日收益: {max(daily_returns):.2f}%")
- print(f" 最大单日亏损: {min(daily_returns):.2f}%")
-
- # 计算胜负比
- positive_days = len([r for r in daily_returns if r > 0])
- total_days = len(daily_returns)
- if total_days > 0:
- print(f" 盈利天数占比: {positive_days/total_days:.2%}")
-
- print(f"{'='*50}")
diff --git a/qka/core/strategy.py b/qka/core/strategy.py
new file mode 100644
index 0000000..a08a1bd
--- /dev/null
+++ b/qka/core/strategy.py
@@ -0,0 +1,33 @@
+"""
+QKA策略模块
+
+提供策略开发的抽象基类,定义策略开发的标准接口和事件处理机制。
+"""
+
+from abc import ABC, abstractmethod
+from qka.core.broker import Broker
+
+class Strategy(ABC):
+ """
+ 策略抽象基类
+
+ 所有自定义策略都应该继承此类,并实现on_bar方法。
+
+ Attributes:
+ broker (Broker): 交易经纪商实例,用于执行交易操作
+ """
+
+ def __init__(self):
+ """初始化策略"""
+ self.broker = Broker()
+
+ @abstractmethod
+ def on_bar(self, date, get):
+ """
+ 每个bar的处理逻辑,必须由子类实现
+
+ Args:
+ date: 当前时间戳
+ get: 获取因子数据的函数,格式为 get(factor_name) -> pd.Series
+ """
+ pass
\ No newline at end of file
diff --git a/qka/utils/__init__.py b/qka/utils/__init__.py
index 0dc7439..ef61e08 100644
--- a/qka/utils/__init__.py
+++ b/qka/utils/__init__.py
@@ -4,16 +4,11 @@
"""
from .logger import logger, create_logger, get_structured_logger
-from .tools import Cache, Timer, timer, retry, memoize, FileUtils, DateUtils, MathUtils, ValidationUtils
-from .tools import format_number, format_percentage, format_currency
from .anis import RED, GREEN, YELLOW, BLUE, RESET
from .util import timestamp_to_datetime_string, parse_order_type, convert_to_current_date
__all__ = [
'logger', 'create_logger', 'get_structured_logger',
- 'Cache', 'Timer', 'timer', 'retry', 'memoize',
- 'FileUtils', 'DateUtils', 'MathUtils', 'ValidationUtils',
- 'format_number', 'format_percentage', 'format_currency',
'RED', 'GREEN', 'YELLOW', 'BLUE', 'RESET',
'timestamp_to_datetime_string', 'parse_order_type', 'convert_to_current_date'
]
diff --git a/qka/utils/tools.py b/qka/utils/tools.py
deleted file mode 100644
index c63c3e8..0000000
--- a/qka/utils/tools.py
+++ /dev/null
@@ -1,397 +0,0 @@
-"""
-QKA 基础工具类
-提供通用的工具函数和类
-"""
-
-import time
-import hashlib
-import threading
-from datetime import datetime, timedelta
-from typing import Any, Dict, List, Optional, Union, Callable
-from functools import wraps
-import inspect
-from pathlib import Path
-import pickle
-import json
-
-
-class Singleton(type):
- """单例模式元类"""
- _instances = {}
- _lock = threading.Lock()
-
- def __call__(cls, *args, **kwargs):
- if cls not in cls._instances:
- with cls._lock:
- if cls not in cls._instances:
- cls._instances[cls] = super().__call__(*args, **kwargs)
- return cls._instances[cls]
-
-
-class Cache:
- """简单的内存缓存"""
-
- def __init__(self, max_size: int = 1000, ttl: int = 3600):
- """
- 初始化缓存
-
- Args:
- max_size: 最大缓存条目数
- ttl: 过期时间(秒)
- """
- self.max_size = max_size
- self.ttl = ttl
- self._cache = {}
- self._access_times = {}
- self._lock = threading.RLock()
-
- def get(self, key: str) -> Optional[Any]:
- """获取缓存值"""
- with self._lock:
- if key not in self._cache:
- return None
-
- # 检查是否过期
- if time.time() - self._access_times[key] > self.ttl:
- self._remove(key)
- return None
-
- # 更新访问时间
- self._access_times[key] = time.time()
- return self._cache[key]
-
- def set(self, key: str, value: Any):
- """设置缓存值"""
- with self._lock:
- # 如果缓存已满,移除最老的条目
- if len(self._cache) >= self.max_size and key not in self._cache:
- oldest_key = min(self._access_times.keys(),
- key=lambda k: self._access_times[k])
- self._remove(oldest_key)
-
- self._cache[key] = value
- self._access_times[key] = time.time()
-
- def _remove(self, key: str):
- """移除缓存条目"""
- self._cache.pop(key, None)
- self._access_times.pop(key, None)
-
- def clear(self):
- """清空缓存"""
- with self._lock:
- self._cache.clear()
- self._access_times.clear()
-
- def size(self) -> int:
- """获取缓存大小"""
- return len(self._cache)
-
-
-class Timer:
- """计时器工具"""
-
- def __init__(self):
- self.start_time = None
- self.end_time = None
-
- def start(self):
- """开始计时"""
- self.start_time = time.time()
-
- def stop(self):
- """停止计时"""
- self.end_time = time.time()
-
- def elapsed(self) -> float:
- """获取已耗时间(秒)"""
- if self.start_time is None:
- return 0
-
- end = self.end_time if self.end_time else time.time()
- return end - self.start_time
-
- def __enter__(self):
- self.start()
- return self
-
- def __exit__(self, *args):
- self.stop()
-
-
-def timer(func: Callable) -> Callable:
- """计时装饰器"""
- @wraps(func)
- def wrapper(*args, **kwargs):
- start_time = time.time()
- result = func(*args, **kwargs)
- end_time = time.time()
-
- func_name = f"{func.__module__}.{func.__name__}"
- print(f"⏱️ {func_name} 执行时间: {end_time - start_time:.4f}秒")
-
- return result
- return wrapper
-
-
-def retry(max_attempts: int = 3, delay: float = 1.0, backoff: float = 2.0):
- """重试装饰器"""
- def decorator(func: Callable) -> Callable:
- @wraps(func)
- def wrapper(*args, **kwargs):
- attempts = 0
- current_delay = delay
-
- while attempts < max_attempts:
- try:
- return func(*args, **kwargs)
- except Exception as e:
- attempts += 1
- if attempts >= max_attempts:
- raise e
-
- print(f"🔄 {func.__name__} 第{attempts}次尝试失败: {e}, {current_delay}秒后重试")
- time.sleep(current_delay)
- current_delay *= backoff
-
- return None
- return wrapper
- return decorator
-
-
-def memoize(ttl: Optional[int] = None):
- """记忆化装饰器"""
- def decorator(func: Callable) -> Callable:
- cache = {}
- cache_times = {}
-
- @wraps(func)
- def wrapper(*args, **kwargs):
- # 创建缓存键
- key = _create_cache_key(func, args, kwargs)
-
- # 检查缓存
- if key in cache:
- if ttl is None or (time.time() - cache_times[key]) < ttl:
- return cache[key]
- else:
- # 过期,移除缓存
- del cache[key]
- del cache_times[key]
-
- # 执行函数并缓存结果
- result = func(*args, **kwargs)
- cache[key] = result
- cache_times[key] = time.time()
-
- return result
-
- # 添加清除缓存的方法
- wrapper.clear_cache = lambda: cache.clear() or cache_times.clear()
-
- return wrapper
- return decorator
-
-
-def _create_cache_key(func: Callable, args: tuple, kwargs: dict) -> str:
- """创建缓存键"""
- key_parts = [func.__name__]
-
- # 添加位置参数
- for arg in args:
- if hasattr(arg, '__dict__'):
- key_parts.append(str(hash(str(sorted(arg.__dict__.items())))))
- else:
- key_parts.append(str(hash(str(arg))))
-
- # 添加关键字参数
- for k, v in sorted(kwargs.items()):
- key_parts.append(f"{k}={hash(str(v))}")
-
- key_string = "|".join(key_parts)
- return hashlib.md5(key_string.encode()).hexdigest()
-
-
-class FileUtils:
- """文件操作工具类"""
-
- @staticmethod
- def ensure_dir(path: Union[str, Path]):
- """确保目录存在"""
- Path(path).mkdir(parents=True, exist_ok=True)
-
- @staticmethod
- def save_json(data: Any, file_path: Union[str, Path], indent: int = 2):
- """保存JSON文件"""
- FileUtils.ensure_dir(Path(file_path).parent)
- with open(file_path, 'w', encoding='utf-8') as f:
- json.dump(data, f, indent=indent, ensure_ascii=False, default=str)
-
- @staticmethod
- def load_json(file_path: Union[str, Path]) -> Any:
- """加载JSON文件"""
- with open(file_path, 'r', encoding='utf-8') as f:
- return json.load(f)
-
- @staticmethod
- def save_pickle(data: Any, file_path: Union[str, Path]):
- """保存pickle文件"""
- FileUtils.ensure_dir(Path(file_path).parent)
- with open(file_path, 'wb') as f:
- pickle.dump(data, f)
-
- @staticmethod
- def load_pickle(file_path: Union[str, Path]) -> Any:
- """加载pickle文件"""
- with open(file_path, 'rb') as f:
- return pickle.load(f)
-
- @staticmethod
- def get_file_size(file_path: Union[str, Path]) -> int:
- """获取文件大小(字节)"""
- return Path(file_path).stat().st_size
-
- @staticmethod
- def get_file_mtime(file_path: Union[str, Path]) -> datetime:
- """获取文件修改时间"""
- return datetime.fromtimestamp(Path(file_path).stat().st_mtime)
-
-
-class DateUtils:
- """日期时间工具类"""
-
- @staticmethod
- def is_trading_day(date: datetime) -> bool:
- """判断是否为交易日(简单实现,只排除周末)"""
- return date.weekday() < 5
-
- @staticmethod
- def get_trading_days(start_date: datetime, end_date: datetime) -> List[datetime]:
- """获取指定期间的交易日列表"""
- days = []
- current = start_date
-
- while current <= end_date:
- if DateUtils.is_trading_day(current):
- days.append(current)
- current += timedelta(days=1)
-
- return days
-
- @staticmethod
- def format_datetime(dt: datetime, format_str: str = '%Y-%m-%d %H:%M:%S') -> str:
- """格式化日期时间"""
- return dt.strftime(format_str)
-
- @staticmethod
- def parse_datetime(date_str: str, format_str: str = '%Y-%m-%d') -> datetime:
- """解析日期时间字符串"""
- return datetime.strptime(date_str, format_str)
-
- @staticmethod
- def get_date_range(days: int, end_date: Optional[datetime] = None) -> tuple:
- """获取日期范围"""
- if end_date is None:
- end_date = datetime.now()
- start_date = end_date - timedelta(days=days)
- return start_date, end_date
-
-
-class MathUtils:
- """数学工具类"""
-
- @staticmethod
- def safe_divide(a: float, b: float, default: float = 0) -> float:
- """安全除法,避免除零错误"""
- return a / b if b != 0 else default
-
- @staticmethod
- def clamp(value: float, min_val: float, max_val: float) -> float:
- """将值限制在指定范围内"""
- return max(min_val, min(value, max_val))
-
- @staticmethod
- def percent_change(old_value: float, new_value: float) -> float:
- """计算百分比变化"""
- if old_value == 0:
- return 0
- return (new_value - old_value) / old_value * 100
-
-
-class ValidationUtils:
- """验证工具类"""
-
- @staticmethod
- def is_valid_symbol(symbol: str) -> bool:
- """验证股票代码格式"""
- import re
- # 简单的A股股票代码验证
- pattern = r'^(000|002|300|600|688)\d{3}\.(SZ|SH)$'
- return bool(re.match(pattern, symbol))
-
- @staticmethod
- def is_positive_number(value: Any) -> bool:
- """验证是否为正数"""
- try:
- return float(value) > 0
- except (ValueError, TypeError):
- return False
-
- @staticmethod
- def is_valid_date_range(start_date: str, end_date: str) -> bool:
- """验证日期范围是否有效"""
- try:
- start = datetime.strptime(start_date, '%Y-%m-%d')
- end = datetime.strptime(end_date, '%Y-%m-%d')
- return start <= end
- except ValueError:
- return False
-
-
-def format_number(num: float, precision: int = 2, use_separator: bool = True) -> str:
- """格式化数字显示"""
- if use_separator:
- return f"{num:,.{precision}f}"
- else:
- return f"{num:.{precision}f}"
-
-
-def format_percentage(ratio: float, precision: int = 2) -> str:
- """格式化百分比显示"""
- return f"{ratio * 100:.{precision}f}%"
-
-
-def format_currency(amount: float, currency: str = '¥', precision: int = 2) -> str:
- """格式化货币显示"""
- return f"{currency}{amount:,.{precision}f}"
-
-
-if __name__ == '__main__':
- # 测试缓存
- cache = Cache(max_size=3, ttl=2)
- cache.set('key1', 'value1')
- cache.set('key2', 'value2')
- print(f"缓存大小: {cache.size()}")
- print(f"key1: {cache.get('key1')}")
-
- # 测试计时器
- with Timer() as t:
- time.sleep(0.1)
- print(f"计时: {t.elapsed():.3f}秒")
-
- # 测试装饰器
- @timer
- @retry(max_attempts=2)
- def test_func():
- print("测试函数执行")
- return "success"
-
- result = test_func()
- print(f"结果: {result}")
-
- # 测试工具函数
- print(f"格式化数字: {format_number(123456.789)}")
- print(f"格式化百分比: {format_percentage(0.1234)}")
- print(f"格式化货币: {format_currency(123456.78)}")
-
- print("工具类测试完成")
diff --git "a/\345\267\245\344\275\234\350\277\233\345\272\246\350\256\260\345\275\225.md" "b/\345\267\245\344\275\234\350\277\233\345\272\246\350\256\260\345\275\225.md"
deleted file mode 100644
index 9b17df0..0000000
--- "a/\345\267\245\344\275\234\350\277\233\345\272\246\350\256\260\345\275\225.md"
+++ /dev/null
@@ -1,217 +0,0 @@
-# QKA量化回测系统 - 第一阶段工作进度记录
-
-**工作日期:** 2025年6月19日
-**任务阶段:** 第一阶段 - 基础设施建设和文档体系搭建
-**整体进度:** 第一阶段完成度约85%,整个项目计划的第一阶段基本完成
-
-## 整体项目规划回顾
-
-### 🎯 第一阶段:基础设施建设(当前阶段,85%完成)
-- ✅ 配置管理系统
-- ✅ 事件驱动框架
-- ✅ 增强日志系统
-- ✅ 基础工具类
-- ✅ 文档体系搭建
-
-### 🚀 后续阶段(待规划)
-- **第二阶段:** 数据层增强
-- **第三阶段:** 策略引擎优化
-- **第四阶段:** 执行引擎升级
-- **第五阶段:** 风险管理强化
-- **第六阶段:** 系统集成
-
-## 已完成工作
-
-### 1. 核心基础设施完善 ✅
-- **配置管理系统** (`qka/core/config.py`) - 支持文件、环境变量、代码多种配置方式
-- **事件驱动框架** (`qka/core/events.py`) - 支持多类型事件、发布-订阅、异步处理、事件统计
-- **增强日志系统** (`qka/utils/logger.py`) - 支持彩色输出、结构化日志、文件轮转、微信通知
-- **通用工具类** (`qka/utils/tools.py`) - 包括缓存、计时器、装饰器、文件/格式化/验证工具等
-
-### 2. Bug修复和代码质量 ✅
-- 修复了`create_sample_config`目录创建bug和相关缩进问题
-- 添加/修复了各模块的`__init__.py`文件,保证模块可正确导入
-- 清理了冗余示例,仅保留核心演示文件
-
-### 3. 现代化文档站搭建 ✅
-- **MkDocs配置** (`mkdocs.yml`) - 使用Material主题,配置了API自动生成插件
-- **文档结构设计** - 建立了清晰的文档导航和层次结构
-- **API自动生成配置** - 集成mkdocstrings,支持从源码自动生成API文档
-
-### 4. 用户指南文档完善 ✅
-- `docs/index.md` - 项目首页
-- `docs/getting-started/` 目录:
- - `installation.md` - 安装指南
- - `first-strategy.md` - 第一个策略教程
- - `concepts.md` - 基础概念
-- `docs/user-guide/` 目录:
- - `config.md` - 配置管理指南
- - `events.md` - 事件系统指南
- - `logging.md` - 日志系统指南
- - `data.md` - 数据获取指南
- - `strategy.md` - 策略开发指南
- - `backtest.md` - 回测分析指南
- - `trading.md` - 实盘交易指南
-
-### 5. API参考文档建设 ✅
-- `docs/api/index.md` - API概览页面
-- `docs/api/core/` 目录:
- - `index.md` - Core模块概览
- - `config.md` - 配置管理API
- - `events.md` - 事件系统API
-- `docs/api/utils/` 目录:
- - `index.md` - Utils模块概览
- - `logger.md` - 日志系统API
- - `tools.md` - 通用工具API
-- `docs/api/brokers/index.md` - 交易模块概览
-- `docs/api/mcp/index.md` - MCP模块概览
-
-### 6. 示例和开发指南框架 ✅
-- `docs/examples/index.md` - 示例教程概览
-- `docs/development/index.md` - 开发指南概览
-
-### 7. 模块结构修复 ✅
-- 为`qka/brokers/`目录添加了`__init__.py`文件
-- 为`qka/mcp/`目录添加了`__init__.py`文件
-- 在相关模块文件中添加了基础类定义:
- - `qka/brokers/trade.py` - 添加了Order、Trade、Position等类
- - `qka/mcp/api.py` - 添加了MCPServer、MCPClient、ContextManager等类
- - `qka/mcp/server.py` - 添加了ModelServer类
-
-## 遇到的问题和解决状态
-
-### 1. YAML语法错误 ✅ 已解决
-- **问题:** `mkdocs.yml`文件存在YAML语法错误(缺少换行符)
-- **解决:** 修复了第132行和第156行的语法错误
-
-### 2. 模块导入错误 ✅ 已解决
-- **问题:** 缺少`__init__.py`文件导致模块无法导入
-- **解决:** 为所有模块目录添加了正确的`__init__.py`文件
-
-### 3. API文档引用问题 ✅ 已解决
-- **问题:** 用户指南中引用了不存在的函数和类
-- **解决:** 将直接的API引用改为指向专门的API文档页面的链接
-
-## 待完成工作
-
-### 1. 文档内容补充 🔄
-- **API参考文档细化:**
- - `docs/api/core/backtest.md` - 回测引擎API
- - `docs/api/core/data.md` - 数据处理API
- - `docs/api/core/plot.md` - 绘图工具API
- - `docs/api/utils/anis.md` - 动画工具API
- - `docs/api/utils/util.md` - 通用函数API
- - `docs/api/brokers/client.md` - 交易客户端API
- - `docs/api/brokers/server.md` - 交易服务器API
- - `docs/api/brokers/trade.md` - 交易执行API
- - `docs/api/mcp/api.md` - MCP API接口
- - `docs/api/mcp/server.md` - MCP服务器API
-
-- **示例教程补充:**
- - `docs/examples/basic/` - 基础示例
- - `docs/examples/advanced/` - 进阶示例
- - `docs/examples/complete/` - 完整案例
-
-- **开发指南补充:**
- - `docs/development/architecture.md` - 架构设计
- - `docs/development/development-setup.md` - 开发环境
- - `docs/development/coding-standards.md` - 编码规范
- - `docs/development/api-design.md` - API设计
- - `docs/development/testing.md` - 测试指南
- - `docs/development/deployment.md` - 部署指南
- - `docs/development/contributing.md` - 贡献指南
-
-### 2. 功能实现完善 🔄
-- **模块功能补充:**
- - 完善brokers模块的实际功能实现
- - 完善mcp模块的实际功能实现
- - 添加更多实用的工具函数
- - 完善事件系统的具体事件类型
-
-### 3. 文档站测试和部署 ⏳
-- **测试验证:**
- - 验证MkDocs能正常启动(已修复语法错误,但可能还需要进一步测试)
- - 验证所有链接和导航正常工作
- - 验证API文档自动生成功能
- - 测试文档的响应式布局
-
-- **部署配置:**
- - 配置GitHub Pages或其他文档托管平台
- - 设置自动构建和部署流程
-
-## 当前文件状态
-
-### 核心代码文件
-```
-qka/
-├── core/
-│ ├── __init__.py ✅
-│ ├── config.py ✅ (完整实现)
-│ ├── events.py ✅ (完整实现)
-│ ├── backtest.py ⚠️ (原有文件,待增强)
-│ ├── data.py ⚠️ (原有文件,待增强)
-│ └── plot.py ⚠️ (原有文件,待增强)
-├── utils/
-│ ├── __init__.py ✅
-│ ├── logger.py ✅ (完整实现)
-│ ├── tools.py ✅ (完整实现)
-│ ├── anis.py ⚠️ (原有文件)
-│ └── util.py ⚠️ (原有文件)
-├── brokers/
-│ ├── __init__.py ✅ (新增)
-│ ├── client.py ⚠️ (部分实现)
-│ ├── server.py ⚠️ (原有文件)
-│ └── trade.py ✅ (增强实现)
-├── mcp/
-│ ├── __init__.py ✅ (新增)
-│ ├── api.py ✅ (新增完整实现)
-│ └── server.py ✅ (增强实现)
-└── examples/
- ├── simple_demo.py ✅
- └── simple_backtest_demo.py ✅
-```
-
-### 文档文件
-```
-docs/
-├── index.md ✅
-├── mkdocs.yml ✅ (已修复语法错误)
-├── getting-started/ ✅ (完整)
-├── user-guide/ ✅ (完整,已修复API引用)
-├── api/ ✅ (结构完成,部分内容待补充)
-├── examples/ 🔄 (结构完成,内容待补充)
-└── development/ 🔄 (结构完成,内容待补充)
-```
-
-## 继续工作的建议
-
-### 完成第一阶段的剩余工作:
-1. **验证文档站:** 运行`uv run mkdocs serve`确认无错误
-2. **补充API文档:** 完善各模块的具体API文档内容
-3. **添加基础示例:** 创建第一阶段功能的使用示例
-4. **第一阶段总结:** 完成第一阶段的验收和总结
-
-### 后续阶段规划:
-- **第二阶段启动前:** 需要详细规划数据层增强的具体任务
-- **重点关注:** 多数据源集成、数据质量检查、高性能缓存等
-- **时间规划:** 建议每个阶段预留充足的开发和测试时间
-
-### 重要提醒:
-我们目前专注于**第一阶段的收尾工作**,不要急于进入第二阶段。第一阶段的基础设施必须稳固,才能支撑后续阶段的开发。
-```bash
-# 启动文档服务器
-uv run mkdocs serve
-
-# 构建文档
-uv run mkdocs build
-
-# 部署到GitHub Pages
-uv run mkdocs gh-deploy
-```
-
-### 重要文件位置:
-- **主配置:** `mkdocs.yml`
-- **文档源码:** `docs/` 目录
-- **项目源码:** `qka/` 目录
-
-这个记录文件已保存,您可以随时根据这个进度继续工作。整体框架已经搭建完成,剩下的主要是内容补充和功能完善。