增加miniqmt接口预留
This commit is contained in:
+1
-2
@@ -6,7 +6,6 @@
|
|||||||
/test_pe_pb.py
|
/test_pe_pb.py
|
||||||
/venv
|
/venv
|
||||||
/__pycache__
|
/__pycache__
|
||||||
/stock_analysis.db
|
/*.db
|
||||||
/stock_monitor.db
|
|
||||||
# 环境变量文件
|
# 环境变量文件
|
||||||
.env
|
.env
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
# MiniQMT量化交易集成指南
|
||||||
|
|
||||||
|
## 📚 概述
|
||||||
|
|
||||||
|
本系统已为监测板块增加MiniQMT量化交易预留接口,支持自动化量化交易功能。该功能可以在监测到特定价格条件时,自动执行买卖操作。
|
||||||
|
|
||||||
|
## 🚀 功能特性
|
||||||
|
|
||||||
|
### 核心功能
|
||||||
|
- ✅ **自动交易执行**:监测触发后自动下单
|
||||||
|
- ✅ **仓位管理**:智能仓位控制和风险管理
|
||||||
|
- ✅ **多种订单类型**:市价单、限价单、止损单等
|
||||||
|
- ✅ **持仓监控**:实时查看持仓和盈亏
|
||||||
|
- ✅ **风险控制**:自动止损、止盈功能
|
||||||
|
- ✅ **策略配置**:灵活的量化策略参数设置
|
||||||
|
|
||||||
|
### 交易信号类型
|
||||||
|
1. **进场信号(Entry)**:价格进入预设进场区间时触发买入
|
||||||
|
2. **止盈信号(Take Profit)**:价格达到止盈位时触发卖出
|
||||||
|
3. **止损信号(Stop Loss)**:价格达到止损位时紧急止损
|
||||||
|
|
||||||
|
## ⚙️ 配置说明
|
||||||
|
|
||||||
|
### 1. 环境变量配置
|
||||||
|
|
||||||
|
在项目根目录的 `.env` 文件中添加以下配置:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# MiniQMT量化交易配置
|
||||||
|
MINIQMT_ENABLED=true # 是否启用MiniQMT(true/false)
|
||||||
|
MINIQMT_ACCOUNT_ID=your_account_id # 交易账户ID
|
||||||
|
MINIQMT_HOST=127.0.0.1 # MiniQMT服务地址
|
||||||
|
MINIQMT_PORT=58610 # MiniQMT服务端口
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 代码配置
|
||||||
|
|
||||||
|
配置会自动从环境变量加载,也可以在 `config.py` 中直接修改:
|
||||||
|
|
||||||
|
```python
|
||||||
|
MINIQMT_CONFIG = {
|
||||||
|
'enabled': True, # 启用MiniQMT
|
||||||
|
'account_id': 'your_account_id', # 账户ID
|
||||||
|
'host': '127.0.0.1', # 服务地址
|
||||||
|
'port': 58610, # 服务端口
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📖 使用指南
|
||||||
|
|
||||||
|
### 第一步:安装MiniQMT
|
||||||
|
|
||||||
|
1. 下载并安装MiniQMT客户端
|
||||||
|
2. 启动MiniQMT客户端
|
||||||
|
3. 登录你的交易账户
|
||||||
|
4. 确保API服务已启动
|
||||||
|
|
||||||
|
### 第二步:启用量化功能
|
||||||
|
|
||||||
|
1. 进入系统的"实时监测"板块
|
||||||
|
2. 在底部找到"MiniQMT量化交易"状态面板
|
||||||
|
3. 点击"连接MiniQMT"按钮
|
||||||
|
4. 等待连接成功提示
|
||||||
|
|
||||||
|
### 第三步:添加量化监测股票
|
||||||
|
|
||||||
|
#### 方式一:添加新股票时启用
|
||||||
|
|
||||||
|
1. 点击"添加股票监测"
|
||||||
|
2. 填写股票信息和关键位置
|
||||||
|
3. 在"量化交易(MiniQMT)"区域勾选"启用量化自动交易"
|
||||||
|
4. 配置量化参数:
|
||||||
|
- **最大仓位比例**:单只股票最大占总资金的比例(建议0.1-0.3)
|
||||||
|
- **自动止损**:是否在触发止损位时自动卖出
|
||||||
|
- **自动止盈**:是否在触发止盈位时自动卖出
|
||||||
|
5. 点击"添加监测"
|
||||||
|
|
||||||
|
#### 方式二:编辑现有股票启用
|
||||||
|
|
||||||
|
1. 在监测股票列表中找到目标股票
|
||||||
|
2. 点击"编辑"按钮
|
||||||
|
3. 勾选"启用量化自动交易"
|
||||||
|
4. 配置量化参数
|
||||||
|
5. 点击"保存修改"
|
||||||
|
|
||||||
|
### 第四步:监控交易执行
|
||||||
|
|
||||||
|
系统会在以下情况自动执行交易:
|
||||||
|
|
||||||
|
1. **进场买入**
|
||||||
|
- 条件:价格进入进场区间
|
||||||
|
- 动作:按配置的仓位比例自动买入
|
||||||
|
- 订单类型:限价单
|
||||||
|
|
||||||
|
2. **止盈卖出**
|
||||||
|
- 条件:价格达到止盈位
|
||||||
|
- 动作:卖出全部持仓
|
||||||
|
- 订单类型:限价单
|
||||||
|
|
||||||
|
3. **止损卖出**
|
||||||
|
- 条件:价格达到止损位
|
||||||
|
- 动作:紧急卖出全部持仓
|
||||||
|
- 订单类型:市价单(快速成交)
|
||||||
|
|
||||||
|
## 🔧 接口说明
|
||||||
|
|
||||||
|
### MiniQMTInterface 类
|
||||||
|
|
||||||
|
#### 主要方法
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 连接到MiniQMT
|
||||||
|
success, msg = miniqmt.connect(account_id)
|
||||||
|
|
||||||
|
# 断开连接
|
||||||
|
miniqmt.disconnect()
|
||||||
|
|
||||||
|
# 获取账户信息
|
||||||
|
account_info = miniqmt.get_account_info()
|
||||||
|
|
||||||
|
# 获取持仓
|
||||||
|
positions = miniqmt.get_positions()
|
||||||
|
|
||||||
|
# 下单
|
||||||
|
success, msg, order_id = miniqmt.place_order(
|
||||||
|
symbol='000001',
|
||||||
|
action=TradeAction.BUY,
|
||||||
|
quantity=100,
|
||||||
|
price=10.50,
|
||||||
|
order_type=OrderType.LIMIT
|
||||||
|
)
|
||||||
|
|
||||||
|
# 撤销订单
|
||||||
|
success, msg = miniqmt.cancel_order(order_id)
|
||||||
|
|
||||||
|
# 执行策略信号(自动调用)
|
||||||
|
success, msg = miniqmt.execute_strategy_signal(
|
||||||
|
stock_id=1,
|
||||||
|
symbol='000001',
|
||||||
|
signal={'type': 'entry', 'price': 10.5},
|
||||||
|
position_size=0.2
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 量化策略配置
|
||||||
|
|
||||||
|
```python
|
||||||
|
quant_config = {
|
||||||
|
'max_position_pct': 0.2, # 最大仓位比例(20%)
|
||||||
|
'auto_stop_loss': True, # 自动止损
|
||||||
|
'auto_take_profit': True, # 自动止盈
|
||||||
|
'min_trade_amount': 5000, # 最小交易金额
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💡 最佳实践
|
||||||
|
|
||||||
|
### 1. 仓位管理建议
|
||||||
|
- 单只股票仓位不超过20%
|
||||||
|
- 总仓位不超过80%
|
||||||
|
- 保留至少20%现金应对突发情况
|
||||||
|
|
||||||
|
### 2. 风险控制建议
|
||||||
|
- 必须设置止损位(建议5-10%)
|
||||||
|
- 设置合理的止盈位(建议10-20%)
|
||||||
|
- 启用自动止损功能
|
||||||
|
|
||||||
|
### 3. 监测参数建议
|
||||||
|
- 监测间隔:5-30分钟(日内交易)
|
||||||
|
- 进场区间:设置合理的价格范围
|
||||||
|
- 及时更新关键位置
|
||||||
|
|
||||||
|
### 4. 测试建议
|
||||||
|
- 先用小仓位测试
|
||||||
|
- 验证连接和下单功能
|
||||||
|
- 确认止损止盈逻辑正确
|
||||||
|
|
||||||
|
## ⚠️ 风险提示
|
||||||
|
|
||||||
|
### 重要警告
|
||||||
|
1. **实盘交易风险**:自动交易涉及真实资金,请谨慎使用
|
||||||
|
2. **网络延迟**:可能导致下单延迟或失败
|
||||||
|
3. **系统故障**:监测服务中断可能错过交易时机
|
||||||
|
4. **价格滑点**:实际成交价可能与预期不同
|
||||||
|
5. **市场风险**:量化交易无法规避市场系统性风险
|
||||||
|
|
||||||
|
### 安全建议
|
||||||
|
1. ✅ 使用专门的测试账户进行测试
|
||||||
|
2. ✅ 设置合理的单笔交易限额
|
||||||
|
3. ✅ 定期检查持仓和资金状态
|
||||||
|
4. ✅ 保持人工监控,不要完全依赖自动化
|
||||||
|
5. ✅ 及时处理异常通知和错误
|
||||||
|
|
||||||
|
## 🛠️ 故障排除
|
||||||
|
|
||||||
|
### 连接失败
|
||||||
|
- 检查MiniQMT客户端是否启动
|
||||||
|
- 确认账户已登录
|
||||||
|
- 验证账户ID是否正确
|
||||||
|
- 检查网络连接
|
||||||
|
|
||||||
|
### 下单失败
|
||||||
|
- 检查资金是否充足
|
||||||
|
- 确认股票代码格式正确
|
||||||
|
- 验证交易时间(交易日9:30-15:00)
|
||||||
|
- 检查仓位限制
|
||||||
|
|
||||||
|
### 交易未执行
|
||||||
|
- 确认量化功能已启用
|
||||||
|
- 检查MiniQMT连接状态
|
||||||
|
- 验证监测服务是否运行
|
||||||
|
- 查看通知记录中的错误信息
|
||||||
|
|
||||||
|
## 📊 技术架构
|
||||||
|
|
||||||
|
```
|
||||||
|
监测服务 (monitor_service.py)
|
||||||
|
↓
|
||||||
|
价格触发检测 (_check_trigger_conditions)
|
||||||
|
↓
|
||||||
|
量化交易执行 (_execute_quant_trade)
|
||||||
|
↓
|
||||||
|
MiniQMT接口 (miniqmt_interface.py)
|
||||||
|
↓
|
||||||
|
订单执行 (execute_strategy_signal)
|
||||||
|
↓
|
||||||
|
MiniQMT客户端 (真实交易)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔄 更新日志
|
||||||
|
|
||||||
|
### v1.0.0 (当前版本)
|
||||||
|
- ✅ 实现MiniQMT预留接口
|
||||||
|
- ✅ 支持自动买卖交易
|
||||||
|
- ✅ 集成监测触发机制
|
||||||
|
- ✅ 添加量化配置界面
|
||||||
|
- ✅ 实现仓位管理功能
|
||||||
|
- ✅ 支持多种订单类型
|
||||||
|
|
||||||
|
### 未来规划
|
||||||
|
- 🔜 支持更多交易策略
|
||||||
|
- 🔜 添加回测功能
|
||||||
|
- 🔜 优化仓位算法
|
||||||
|
- 🔜 增加风控规则
|
||||||
|
- 🔜 支持批量操作
|
||||||
|
|
||||||
|
## 📞 技术支持
|
||||||
|
|
||||||
|
如有问题,请查看:
|
||||||
|
1. 系统日志输出
|
||||||
|
2. MiniQMT客户端日志
|
||||||
|
3. 通知记录中的详细信息
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**免责声明**:本系统仅供学习和研究使用,不构成任何投资建议。量化交易涉及真实资金风险,请谨慎使用并自行承担投资风险。
|
||||||
|
|
||||||
@@ -43,6 +43,14 @@
|
|||||||
- **多种通知方式**:网页提醒 + 邮件通知
|
- **多种通知方式**:网页提醒 + 邮件通知
|
||||||
- **卡片式管理**:直观的股票监测卡片展示
|
- **卡片式管理**:直观的股票监测卡片展示
|
||||||
- **完整功能**:添加、编辑、删除、启停、通知开关
|
- **完整功能**:添加、编辑、删除、启停、通知开关
|
||||||
|
|
||||||
|
### 🤖 量化交易功能(MiniQMT集成)
|
||||||
|
- **自动交易执行**:监测触发后自动下单
|
||||||
|
- **智能仓位管理**:灵活配置单股最大仓位比例
|
||||||
|
- **多种订单类型**:市价单、限价单、止损单支持
|
||||||
|
- **风险控制**:自动止损、止盈功能
|
||||||
|
- **持仓监控**:实时查看持仓和盈亏
|
||||||
|
- **预留接口**:完整的MiniQMT对接接口,可对接真实交易
|
||||||
<img width="1910" height="923" alt="image" src="https://github.com/user-attachments/assets/1e93f870-7846-426c-9c22-15fdfaf1f1d0" />
|
<img width="1910" height="923" alt="image" src="https://github.com/user-attachments/assets/1e93f870-7846-426c-9c22-15fdfaf1f1d0" />
|
||||||
<img width="1910" height="923" alt="image" src="https://github.com/user-attachments/assets/a85defbf-321a-4fe2-b491-6855f2aa366c" />
|
<img width="1910" height="923" alt="image" src="https://github.com/user-attachments/assets/a85defbf-321a-4fe2-b491-6855f2aa366c" />
|
||||||
|
|
||||||
@@ -99,6 +107,12 @@ SMTP_PORT=587
|
|||||||
EMAIL_FROM=your_email@qq.com
|
EMAIL_FROM=your_email@qq.com
|
||||||
EMAIL_PASSWORD=your_authorization_code
|
EMAIL_PASSWORD=your_authorization_code
|
||||||
EMAIL_TO=receiver@example.com
|
EMAIL_TO=receiver@example.com
|
||||||
|
|
||||||
|
# MiniQMT量化交易配置(可选)
|
||||||
|
MINIQMT_ENABLED=false
|
||||||
|
MINIQMT_ACCOUNT_ID=your_account_id
|
||||||
|
MINIQMT_HOST=127.0.0.1
|
||||||
|
MINIQMT_PORT=58610
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -257,6 +271,7 @@ AI股票分析系统
|
|||||||
├── monitor_service.py # 监测服务后台
|
├── monitor_service.py # 监测服务后台
|
||||||
├── monitor_db.py # 监测数据库管理
|
├── monitor_db.py # 监测数据库管理
|
||||||
├── notification_service.py # 通知服务(邮件/界面)
|
├── notification_service.py # 通知服务(邮件/界面)
|
||||||
|
├── miniqmt_interface.py # MiniQMT量化交易接口 ⭐️
|
||||||
├── pdf_generator.py # PDF报告生成
|
├── pdf_generator.py # PDF报告生成
|
||||||
├── database.py # 分析记录数据库
|
├── database.py # 分析记录数据库
|
||||||
├── config.py # 配置文件
|
├── config.py # 配置文件
|
||||||
@@ -315,6 +330,15 @@ AI股票分析系统
|
|||||||
- 通知历史管理
|
- 通知历史管理
|
||||||
- 配置测试功能
|
- 配置测试功能
|
||||||
|
|
||||||
|
#### 🤖 量化交易模块 (miniqmt_interface.py) ⭐️ 新增
|
||||||
|
- MiniQMT接口对接
|
||||||
|
- 自动交易执行
|
||||||
|
- 仓位管理
|
||||||
|
- 风险控制
|
||||||
|
- 订单管理
|
||||||
|
- 持仓监控
|
||||||
|
- 预留接口实现
|
||||||
|
|
||||||
#### 📄 PDF生成模块 (pdf_generator.py)
|
#### 📄 PDF生成模块 (pdf_generator.py)
|
||||||
- 专业分析报告生成
|
- 专业分析报告生成
|
||||||
- 中文字体支持
|
- 中文字体支持
|
||||||
@@ -410,6 +434,20 @@ DEFAULT_INTERVAL = "1d" # 默认数据间隔
|
|||||||
- 查看终端输出的详细错误信息
|
- 查看终端输出的详细错误信息
|
||||||
- 尝试重新启动应用
|
- 尝试重新启动应用
|
||||||
|
|
||||||
|
7. **MiniQMT连接失败**
|
||||||
|
- 确认MiniQMT客户端已启动
|
||||||
|
- 检查账户已登录
|
||||||
|
- 验证账户ID配置正确
|
||||||
|
- 确认网络连接正常
|
||||||
|
- 查看 `MINIQMT_INTEGRATION_GUIDE.md` 详细指南
|
||||||
|
|
||||||
|
8. **量化交易未执行**
|
||||||
|
- 确认量化功能已启用
|
||||||
|
- 检查MiniQMT连接状态
|
||||||
|
- 验证监测服务是否运行
|
||||||
|
- 查看通知记录中的错误信息
|
||||||
|
- 确认交易时间在交易日内
|
||||||
|
|
||||||
### 日志调试
|
### 日志调试
|
||||||
系统运行时会在控制台输出详细日志,可用于问题诊断。如遇到错误,请查看终端输出。
|
系统运行时会在控制台输出详细日志,可用于问题诊断。如遇到错误,请查看终端输出。
|
||||||
|
|
||||||
|
|||||||
@@ -14,3 +14,11 @@ TUSHARE_TOKEN = os.getenv("TUSHARE_TOKEN", "")
|
|||||||
# 股票数据源配置
|
# 股票数据源配置
|
||||||
DEFAULT_PERIOD = "1y" # 默认获取1年数据
|
DEFAULT_PERIOD = "1y" # 默认获取1年数据
|
||||||
DEFAULT_INTERVAL = "1d" # 默认日线数据
|
DEFAULT_INTERVAL = "1d" # 默认日线数据
|
||||||
|
|
||||||
|
# MiniQMT量化交易配置
|
||||||
|
MINIQMT_CONFIG = {
|
||||||
|
'enabled': os.getenv("MINIQMT_ENABLED", "false").lower() == "true",
|
||||||
|
'account_id': os.getenv("MINIQMT_ACCOUNT_ID", ""),
|
||||||
|
'host': os.getenv("MINIQMT_HOST", "127.0.0.1"),
|
||||||
|
'port': int(os.getenv("MINIQMT_PORT", "58610")),
|
||||||
|
}
|
||||||
@@ -0,0 +1,615 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
MiniQMT量化交易接口
|
||||||
|
为监测板块提供量化交易功能预留接口
|
||||||
|
支持自动下单、仓位管理、策略执行等功能
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from typing import Dict, List, Optional, Tuple
|
||||||
|
from datetime import datetime
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
class TradeAction(Enum):
|
||||||
|
"""交易动作枚举"""
|
||||||
|
BUY = "buy" # 买入
|
||||||
|
SELL = "sell" # 卖出
|
||||||
|
HOLD = "hold" # 持有
|
||||||
|
|
||||||
|
class OrderType(Enum):
|
||||||
|
"""订单类型枚举"""
|
||||||
|
MARKET = "market" # 市价单
|
||||||
|
LIMIT = "limit" # 限价单
|
||||||
|
STOP = "stop" # 止损单
|
||||||
|
STOP_LIMIT = "stop_limit" # 止损限价单
|
||||||
|
|
||||||
|
class PositionSide(Enum):
|
||||||
|
"""持仓方向枚举"""
|
||||||
|
LONG = "long" # 多头
|
||||||
|
SHORT = "short" # 空头
|
||||||
|
NONE = "none" # 无持仓
|
||||||
|
|
||||||
|
class MiniQMTInterface:
|
||||||
|
"""
|
||||||
|
MiniQMT量化交易接口类
|
||||||
|
提供与MiniQMT的对接功能
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, config: Dict = None):
|
||||||
|
"""
|
||||||
|
初始化接口
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config: 配置字典,包含账户信息、连接参数等
|
||||||
|
"""
|
||||||
|
self.config = config or {}
|
||||||
|
self.connected = False
|
||||||
|
self.account_id = None
|
||||||
|
self.positions = {} # 持仓信息
|
||||||
|
self.orders = {} # 订单信息
|
||||||
|
self.enabled = self.config.get('enabled', False)
|
||||||
|
|
||||||
|
def connect(self, account_id: str = None) -> Tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
连接到MiniQMT
|
||||||
|
|
||||||
|
Args:
|
||||||
|
account_id: 交易账户ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(成功标志, 消息)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# TODO: 实现与MiniQMT的实际连接逻辑
|
||||||
|
self.account_id = account_id or self.config.get('account_id')
|
||||||
|
|
||||||
|
if not self.account_id:
|
||||||
|
return False, "账户ID未配置"
|
||||||
|
|
||||||
|
# 预留接口:连接MiniQMT
|
||||||
|
# from xtquant import xtdata
|
||||||
|
# xtdata.connect()
|
||||||
|
|
||||||
|
self.connected = True
|
||||||
|
return True, f"已连接到账户 {self.account_id}"
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.connected = False
|
||||||
|
return False, f"连接失败: {str(e)}"
|
||||||
|
|
||||||
|
def disconnect(self) -> bool:
|
||||||
|
"""断开连接"""
|
||||||
|
try:
|
||||||
|
# TODO: 实现断开连接逻辑
|
||||||
|
self.connected = False
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"断开连接失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_connected(self) -> bool:
|
||||||
|
"""检查连接状态"""
|
||||||
|
return self.connected and self.enabled
|
||||||
|
|
||||||
|
def get_account_info(self) -> Dict:
|
||||||
|
"""
|
||||||
|
获取账户信息
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
账户信息字典
|
||||||
|
"""
|
||||||
|
if not self.is_connected():
|
||||||
|
return {
|
||||||
|
'error': '未连接到MiniQMT',
|
||||||
|
'connected': False
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO: 实现获取账户信息的逻辑
|
||||||
|
# 预留接口:从MiniQMT获取账户信息
|
||||||
|
return {
|
||||||
|
'account_id': self.account_id,
|
||||||
|
'total_assets': 0.0, # 总资产
|
||||||
|
'available_cash': 0.0, # 可用资金
|
||||||
|
'market_value': 0.0, # 持仓市值
|
||||||
|
'frozen_cash': 0.0, # 冻结资金
|
||||||
|
'profit_loss': 0.0, # 盈亏
|
||||||
|
'connected': True
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_positions(self) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
获取当前持仓
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
持仓列表
|
||||||
|
"""
|
||||||
|
if not self.is_connected():
|
||||||
|
return []
|
||||||
|
|
||||||
|
# TODO: 实现获取持仓的逻辑
|
||||||
|
# 预留接口:从MiniQMT获取持仓信息
|
||||||
|
# from xtquant import xttrader
|
||||||
|
# positions = xttrader.query_stock_positions(self.account_id)
|
||||||
|
|
||||||
|
return list(self.positions.values())
|
||||||
|
|
||||||
|
def get_position(self, symbol: str) -> Optional[Dict]:
|
||||||
|
"""
|
||||||
|
获取指定股票的持仓
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol: 股票代码
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
持仓信息字典,无持仓返回None
|
||||||
|
"""
|
||||||
|
if not self.is_connected():
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self.positions.get(symbol)
|
||||||
|
|
||||||
|
def place_order(self,
|
||||||
|
symbol: str,
|
||||||
|
action: TradeAction,
|
||||||
|
quantity: int,
|
||||||
|
price: float = None,
|
||||||
|
order_type: OrderType = OrderType.MARKET) -> Tuple[bool, str, str]:
|
||||||
|
"""
|
||||||
|
下单
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol: 股票代码
|
||||||
|
action: 交易动作
|
||||||
|
quantity: 数量
|
||||||
|
price: 价格(限价单时需要)
|
||||||
|
order_type: 订单类型
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(成功标志, 消息, 订单ID)
|
||||||
|
"""
|
||||||
|
if not self.is_connected():
|
||||||
|
return False, "未连接到MiniQMT", ""
|
||||||
|
|
||||||
|
# 参数验证
|
||||||
|
if quantity <= 0:
|
||||||
|
return False, "数量必须大于0", ""
|
||||||
|
|
||||||
|
if order_type == OrderType.LIMIT and price is None:
|
||||||
|
return False, "限价单必须指定价格", ""
|
||||||
|
|
||||||
|
try:
|
||||||
|
# TODO: 实现实际下单逻辑
|
||||||
|
# 预留接口:通过MiniQMT下单
|
||||||
|
# from xtquant import xttrader
|
||||||
|
# if action == TradeAction.BUY:
|
||||||
|
# order_id = xttrader.order_stock(
|
||||||
|
# self.account_id, symbol,
|
||||||
|
# xtconstant.STOCK_BUY, quantity,
|
||||||
|
# xtconstant.FIX_PRICE, price
|
||||||
|
# )
|
||||||
|
# elif action == TradeAction.SELL:
|
||||||
|
# order_id = xttrader.order_stock(
|
||||||
|
# self.account_id, symbol,
|
||||||
|
# xtconstant.STOCK_SELL, quantity,
|
||||||
|
# xtconstant.FIX_PRICE, price
|
||||||
|
# )
|
||||||
|
|
||||||
|
# 模拟订单ID
|
||||||
|
order_id = f"ORD_{symbol}_{datetime.now().strftime('%Y%m%d%H%M%S')}"
|
||||||
|
|
||||||
|
# 记录订单
|
||||||
|
self.orders[order_id] = {
|
||||||
|
'order_id': order_id,
|
||||||
|
'symbol': symbol,
|
||||||
|
'action': action.value,
|
||||||
|
'quantity': quantity,
|
||||||
|
'price': price,
|
||||||
|
'order_type': order_type.value,
|
||||||
|
'status': 'submitted',
|
||||||
|
'create_time': datetime.now().isoformat()
|
||||||
|
}
|
||||||
|
|
||||||
|
return True, f"订单已提交: {order_id}", order_id
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return False, f"下单失败: {str(e)}", ""
|
||||||
|
|
||||||
|
def cancel_order(self, order_id: str) -> Tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
撤销订单
|
||||||
|
|
||||||
|
Args:
|
||||||
|
order_id: 订单ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(成功标志, 消息)
|
||||||
|
"""
|
||||||
|
if not self.is_connected():
|
||||||
|
return False, "未连接到MiniQMT"
|
||||||
|
|
||||||
|
try:
|
||||||
|
# TODO: 实现撤单逻辑
|
||||||
|
# 预留接口:通过MiniQMT撤单
|
||||||
|
# from xtquant import xttrader
|
||||||
|
# xttrader.cancel_order(self.account_id, order_id)
|
||||||
|
|
||||||
|
if order_id in self.orders:
|
||||||
|
self.orders[order_id]['status'] = 'cancelled'
|
||||||
|
return True, f"订单 {order_id} 已撤销"
|
||||||
|
else:
|
||||||
|
return False, "订单不存在"
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return False, f"撤单失败: {str(e)}"
|
||||||
|
|
||||||
|
def get_order_status(self, order_id: str) -> Optional[Dict]:
|
||||||
|
"""
|
||||||
|
查询订单状态
|
||||||
|
|
||||||
|
Args:
|
||||||
|
order_id: 订单ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
订单信息字典
|
||||||
|
"""
|
||||||
|
if not self.is_connected():
|
||||||
|
return None
|
||||||
|
|
||||||
|
# TODO: 实现查询订单状态逻辑
|
||||||
|
return self.orders.get(order_id)
|
||||||
|
|
||||||
|
def get_all_orders(self) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
获取所有订单
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
订单列表
|
||||||
|
"""
|
||||||
|
if not self.is_connected():
|
||||||
|
return []
|
||||||
|
|
||||||
|
return list(self.orders.values())
|
||||||
|
|
||||||
|
def execute_strategy_signal(self,
|
||||||
|
stock_id: int,
|
||||||
|
symbol: str,
|
||||||
|
signal: Dict,
|
||||||
|
position_size: float = 0.2) -> Tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
执行策略信号
|
||||||
|
根据监测触发的信号自动执行交易
|
||||||
|
|
||||||
|
Args:
|
||||||
|
stock_id: 监测股票ID
|
||||||
|
symbol: 股票代码
|
||||||
|
signal: 信号字典,包含type, price, message等
|
||||||
|
position_size: 仓位比例(默认20%)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(成功标志, 执行结果消息)
|
||||||
|
"""
|
||||||
|
if not self.is_connected():
|
||||||
|
return False, "MiniQMT未连接,无法执行交易"
|
||||||
|
|
||||||
|
signal_type = signal.get('type')
|
||||||
|
current_price = signal.get('price')
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 获取账户信息
|
||||||
|
account_info = self.get_account_info()
|
||||||
|
available_cash = account_info.get('available_cash', 0)
|
||||||
|
|
||||||
|
# 根据信号类型执行不同操作
|
||||||
|
if signal_type == 'entry':
|
||||||
|
# 进场信号 - 买入
|
||||||
|
buy_amount = available_cash * position_size
|
||||||
|
quantity = int(buy_amount / current_price / 100) * 100 # A股100股为一手
|
||||||
|
|
||||||
|
if quantity > 0:
|
||||||
|
success, msg, order_id = self.place_order(
|
||||||
|
symbol=symbol,
|
||||||
|
action=TradeAction.BUY,
|
||||||
|
quantity=quantity,
|
||||||
|
price=current_price,
|
||||||
|
order_type=OrderType.LIMIT
|
||||||
|
)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
return True, f"进场买入成功: {quantity}股 @ ¥{current_price}, 订单号: {order_id}"
|
||||||
|
else:
|
||||||
|
return False, f"进场买入失败: {msg}"
|
||||||
|
else:
|
||||||
|
return False, "可用资金不足,无法买入"
|
||||||
|
|
||||||
|
elif signal_type == 'take_profit':
|
||||||
|
# 止盈信号 - 卖出
|
||||||
|
position = self.get_position(symbol)
|
||||||
|
if position and position.get('quantity', 0) > 0:
|
||||||
|
quantity = position['quantity']
|
||||||
|
|
||||||
|
success, msg, order_id = self.place_order(
|
||||||
|
symbol=symbol,
|
||||||
|
action=TradeAction.SELL,
|
||||||
|
quantity=quantity,
|
||||||
|
price=current_price,
|
||||||
|
order_type=OrderType.LIMIT
|
||||||
|
)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
return True, f"止盈卖出成功: {quantity}股 @ ¥{current_price}, 订单号: {order_id}"
|
||||||
|
else:
|
||||||
|
return False, f"止盈卖出失败: {msg}"
|
||||||
|
else:
|
||||||
|
return False, "无持仓,无需卖出"
|
||||||
|
|
||||||
|
elif signal_type == 'stop_loss':
|
||||||
|
# 止损信号 - 紧急卖出
|
||||||
|
position = self.get_position(symbol)
|
||||||
|
if position and position.get('quantity', 0) > 0:
|
||||||
|
quantity = position['quantity']
|
||||||
|
|
||||||
|
# 止损使用市价单,快速成交
|
||||||
|
success, msg, order_id = self.place_order(
|
||||||
|
symbol=symbol,
|
||||||
|
action=TradeAction.SELL,
|
||||||
|
quantity=quantity,
|
||||||
|
order_type=OrderType.MARKET
|
||||||
|
)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
return True, f"止损卖出成功: {quantity}股, 订单号: {order_id}"
|
||||||
|
else:
|
||||||
|
return False, f"止损卖出失败: {msg}"
|
||||||
|
else:
|
||||||
|
return False, "无持仓,无需止损"
|
||||||
|
|
||||||
|
else:
|
||||||
|
return False, f"未知的信号类型: {signal_type}"
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return False, f"执行策略信号失败: {str(e)}"
|
||||||
|
|
||||||
|
def calculate_position_size(self,
|
||||||
|
symbol: str,
|
||||||
|
price: float,
|
||||||
|
max_position_pct: float = 0.2,
|
||||||
|
max_risk_pct: float = 0.02) -> int:
|
||||||
|
"""
|
||||||
|
计算建议仓位大小
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol: 股票代码
|
||||||
|
price: 买入价格
|
||||||
|
max_position_pct: 最大仓位比例(默认20%)
|
||||||
|
max_risk_pct: 最大风险比例(默认2%)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
建议买入数量(股)
|
||||||
|
"""
|
||||||
|
if not self.is_connected():
|
||||||
|
return 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
account_info = self.get_account_info()
|
||||||
|
total_assets = account_info.get('total_assets', 0)
|
||||||
|
available_cash = account_info.get('available_cash', 0)
|
||||||
|
|
||||||
|
# 基于最大仓位计算
|
||||||
|
max_position_value = total_assets * max_position_pct
|
||||||
|
|
||||||
|
# 基于可用资金计算
|
||||||
|
max_buy_value = min(max_position_value, available_cash)
|
||||||
|
|
||||||
|
# 计算股数(A股100股为一手)
|
||||||
|
quantity = int(max_buy_value / price / 100) * 100
|
||||||
|
|
||||||
|
return quantity
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"计算仓位失败: {e}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_risk_metrics(self, symbol: str) -> Dict:
|
||||||
|
"""
|
||||||
|
获取风险指标
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol: 股票代码
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
风险指标字典
|
||||||
|
"""
|
||||||
|
if not self.is_connected():
|
||||||
|
return {}
|
||||||
|
|
||||||
|
position = self.get_position(symbol)
|
||||||
|
if not position:
|
||||||
|
return {
|
||||||
|
'has_position': False,
|
||||||
|
'profit_loss': 0,
|
||||||
|
'profit_loss_pct': 0,
|
||||||
|
'risk_exposure': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# 计算盈亏
|
||||||
|
cost_price = position.get('cost_price', 0)
|
||||||
|
current_price = position.get('current_price', 0)
|
||||||
|
quantity = position.get('quantity', 0)
|
||||||
|
|
||||||
|
profit_loss = (current_price - cost_price) * quantity
|
||||||
|
profit_loss_pct = (current_price - cost_price) / cost_price * 100 if cost_price > 0 else 0
|
||||||
|
|
||||||
|
# 计算风险敞口
|
||||||
|
account_info = self.get_account_info()
|
||||||
|
total_assets = account_info.get('total_assets', 0)
|
||||||
|
position_value = current_price * quantity
|
||||||
|
risk_exposure = position_value / total_assets if total_assets > 0 else 0
|
||||||
|
|
||||||
|
return {
|
||||||
|
'has_position': True,
|
||||||
|
'quantity': quantity,
|
||||||
|
'cost_price': cost_price,
|
||||||
|
'current_price': current_price,
|
||||||
|
'position_value': position_value,
|
||||||
|
'profit_loss': profit_loss,
|
||||||
|
'profit_loss_pct': profit_loss_pct,
|
||||||
|
'risk_exposure': risk_exposure
|
||||||
|
}
|
||||||
|
|
||||||
|
def validate_trade(self,
|
||||||
|
symbol: str,
|
||||||
|
action: TradeAction,
|
||||||
|
quantity: int,
|
||||||
|
price: float = None) -> Tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
验证交易是否可行
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol: 股票代码
|
||||||
|
action: 交易动作
|
||||||
|
quantity: 数量
|
||||||
|
price: 价格
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(可行标志, 原因)
|
||||||
|
"""
|
||||||
|
if not self.is_connected():
|
||||||
|
return False, "未连接到MiniQMT"
|
||||||
|
|
||||||
|
# 检查数量
|
||||||
|
if quantity <= 0:
|
||||||
|
return False, "数量必须大于0"
|
||||||
|
|
||||||
|
if quantity % 100 != 0:
|
||||||
|
return False, "A股必须以100股(1手)为单位交易"
|
||||||
|
|
||||||
|
# 获取账户信息
|
||||||
|
account_info = self.get_account_info()
|
||||||
|
|
||||||
|
if action == TradeAction.BUY:
|
||||||
|
# 买入验证
|
||||||
|
if price is None:
|
||||||
|
return False, "买入需要指定价格"
|
||||||
|
|
||||||
|
required_cash = quantity * price * 1.001 # 考虑手续费
|
||||||
|
available_cash = account_info.get('available_cash', 0)
|
||||||
|
|
||||||
|
if required_cash > available_cash:
|
||||||
|
return False, f"资金不足: 需要¥{required_cash:.2f}, 可用¥{available_cash:.2f}"
|
||||||
|
|
||||||
|
return True, "验证通过"
|
||||||
|
|
||||||
|
elif action == TradeAction.SELL:
|
||||||
|
# 卖出验证
|
||||||
|
position = self.get_position(symbol)
|
||||||
|
if not position:
|
||||||
|
return False, "无持仓,无法卖出"
|
||||||
|
|
||||||
|
available_quantity = position.get('quantity', 0)
|
||||||
|
if quantity > available_quantity:
|
||||||
|
return False, f"持仓不足: 需要{quantity}股, 可用{available_quantity}股"
|
||||||
|
|
||||||
|
return True, "验证通过"
|
||||||
|
|
||||||
|
return False, "未知的交易动作"
|
||||||
|
|
||||||
|
|
||||||
|
class QuantStrategyConfig:
|
||||||
|
"""量化策略配置"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.auto_trade_enabled = False # 是否启用自动交易
|
||||||
|
self.max_position_pct = 0.2 # 最大单个仓位比例
|
||||||
|
self.max_total_position_pct = 0.8 # 最大总仓位比例
|
||||||
|
self.max_risk_per_trade = 0.02 # 单笔最大风险比例
|
||||||
|
self.min_trade_amount = 5000 # 最小交易金额
|
||||||
|
self.use_stop_loss = True # 是否使用止损
|
||||||
|
self.use_take_profit = True # 是否使用止盈
|
||||||
|
self.trailing_stop_pct = 0.05 # 移动止损比例
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict:
|
||||||
|
"""转换为字典"""
|
||||||
|
return {
|
||||||
|
'auto_trade_enabled': self.auto_trade_enabled,
|
||||||
|
'max_position_pct': self.max_position_pct,
|
||||||
|
'max_total_position_pct': self.max_total_position_pct,
|
||||||
|
'max_risk_per_trade': self.max_risk_per_trade,
|
||||||
|
'min_trade_amount': self.min_trade_amount,
|
||||||
|
'use_stop_loss': self.use_stop_loss,
|
||||||
|
'use_take_profit': self.use_take_profit,
|
||||||
|
'trailing_stop_pct': self.trailing_stop_pct
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict):
|
||||||
|
"""从字典创建"""
|
||||||
|
config = cls()
|
||||||
|
config.auto_trade_enabled = data.get('auto_trade_enabled', False)
|
||||||
|
config.max_position_pct = data.get('max_position_pct', 0.2)
|
||||||
|
config.max_total_position_pct = data.get('max_total_position_pct', 0.8)
|
||||||
|
config.max_risk_per_trade = data.get('max_risk_per_trade', 0.02)
|
||||||
|
config.min_trade_amount = data.get('min_trade_amount', 5000)
|
||||||
|
config.use_stop_loss = data.get('use_stop_loss', True)
|
||||||
|
config.use_take_profit = data.get('use_take_profit', True)
|
||||||
|
config.trailing_stop_pct = data.get('trailing_stop_pct', 0.05)
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
# 全局MiniQMT接口实例
|
||||||
|
miniqmt = MiniQMTInterface()
|
||||||
|
|
||||||
|
|
||||||
|
def init_miniqmt(config: Dict = None) -> Tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
初始化MiniQMT接口
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config: 配置字典
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(成功标志, 消息)
|
||||||
|
"""
|
||||||
|
global miniqmt
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 从配置文件或环境变量读取配置
|
||||||
|
if config is None:
|
||||||
|
try:
|
||||||
|
from config import MINIQMT_CONFIG
|
||||||
|
config = MINIQMT_CONFIG
|
||||||
|
except ImportError:
|
||||||
|
config = {
|
||||||
|
'enabled': False,
|
||||||
|
'account_id': None
|
||||||
|
}
|
||||||
|
|
||||||
|
miniqmt = MiniQMTInterface(config)
|
||||||
|
|
||||||
|
# 如果启用,尝试连接
|
||||||
|
if config.get('enabled', False):
|
||||||
|
success, msg = miniqmt.connect()
|
||||||
|
return success, msg
|
||||||
|
else:
|
||||||
|
return True, "MiniQMT接口已初始化(未启用)"
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return False, f"初始化MiniQMT接口失败: {str(e)}"
|
||||||
|
|
||||||
|
|
||||||
|
def get_miniqmt_status() -> Dict:
|
||||||
|
"""
|
||||||
|
获取MiniQMT接口状态
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
状态字典
|
||||||
|
"""
|
||||||
|
global miniqmt
|
||||||
|
|
||||||
|
return {
|
||||||
|
'enabled': miniqmt.enabled,
|
||||||
|
'connected': miniqmt.connected,
|
||||||
|
'account_id': miniqmt.account_id,
|
||||||
|
'ready': miniqmt.is_connected()
|
||||||
|
}
|
||||||
|
|
||||||
+45
-16
@@ -29,6 +29,8 @@ class StockMonitorDatabase:
|
|||||||
last_checked TIMESTAMP,
|
last_checked TIMESTAMP,
|
||||||
check_interval INTEGER DEFAULT 30, -- 分钟
|
check_interval INTEGER DEFAULT 30, -- 分钟
|
||||||
notification_enabled BOOLEAN DEFAULT TRUE,
|
notification_enabled BOOLEAN DEFAULT TRUE,
|
||||||
|
quant_enabled BOOLEAN DEFAULT FALSE, -- 量化交易开关
|
||||||
|
quant_config TEXT, -- 量化配置JSON
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
)
|
)
|
||||||
@@ -64,16 +66,22 @@ class StockMonitorDatabase:
|
|||||||
def add_monitored_stock(self, symbol: str, name: str, rating: str,
|
def add_monitored_stock(self, symbol: str, name: str, rating: str,
|
||||||
entry_range: Dict, take_profit: float,
|
entry_range: Dict, take_profit: float,
|
||||||
stop_loss: float, check_interval: int = 30,
|
stop_loss: float, check_interval: int = 30,
|
||||||
notification_enabled: bool = True) -> int:
|
notification_enabled: bool = True,
|
||||||
|
quant_enabled: bool = False,
|
||||||
|
quant_config: Dict = None) -> int:
|
||||||
"""添加监测股票"""
|
"""添加监测股票"""
|
||||||
conn = sqlite3.connect(self.db_path)
|
conn = sqlite3.connect(self.db_path)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
quant_config_json = json.dumps(quant_config) if quant_config else None
|
||||||
|
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
INSERT INTO monitored_stocks
|
INSERT INTO monitored_stocks
|
||||||
(symbol, name, rating, entry_range, take_profit, stop_loss, check_interval, notification_enabled)
|
(symbol, name, rating, entry_range, take_profit, stop_loss, check_interval,
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
notification_enabled, quant_enabled, quant_config)
|
||||||
''', (symbol, name, rating, json.dumps(entry_range), take_profit, stop_loss, check_interval, notification_enabled))
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
''', (symbol, name, rating, json.dumps(entry_range), take_profit, stop_loss,
|
||||||
|
check_interval, notification_enabled, quant_enabled, quant_config_json))
|
||||||
|
|
||||||
stock_id = cursor.lastrowid
|
stock_id = cursor.lastrowid
|
||||||
conn.commit()
|
conn.commit()
|
||||||
@@ -89,13 +97,14 @@ class StockMonitorDatabase:
|
|||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
SELECT id, symbol, name, rating, entry_range, take_profit, stop_loss,
|
SELECT id, symbol, name, rating, entry_range, take_profit, stop_loss,
|
||||||
current_price, last_checked, check_interval, notification_enabled,
|
current_price, last_checked, check_interval, notification_enabled,
|
||||||
created_at, updated_at
|
quant_enabled, quant_config, created_at, updated_at
|
||||||
FROM monitored_stocks
|
FROM monitored_stocks
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
''')
|
''')
|
||||||
|
|
||||||
stocks = []
|
stocks = []
|
||||||
for row in cursor.fetchall():
|
for row in cursor.fetchall():
|
||||||
|
quant_config = json.loads(row[12]) if row[12] else None
|
||||||
stocks.append({
|
stocks.append({
|
||||||
'id': row[0],
|
'id': row[0],
|
||||||
'symbol': row[1],
|
'symbol': row[1],
|
||||||
@@ -108,8 +117,10 @@ class StockMonitorDatabase:
|
|||||||
'last_checked': row[8],
|
'last_checked': row[8],
|
||||||
'check_interval': row[9],
|
'check_interval': row[9],
|
||||||
'notification_enabled': bool(row[10]),
|
'notification_enabled': bool(row[10]),
|
||||||
'created_at': row[11],
|
'quant_enabled': bool(row[11]),
|
||||||
'updated_at': row[12]
|
'quant_config': quant_config,
|
||||||
|
'created_at': row[13],
|
||||||
|
'updated_at': row[14]
|
||||||
})
|
})
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
@@ -235,17 +246,31 @@ class StockMonitorDatabase:
|
|||||||
|
|
||||||
def update_monitored_stock(self, stock_id: int, rating: str, entry_range: Dict,
|
def update_monitored_stock(self, stock_id: int, rating: str, entry_range: Dict,
|
||||||
take_profit: float, stop_loss: float,
|
take_profit: float, stop_loss: float,
|
||||||
check_interval: int, notification_enabled: bool):
|
check_interval: int, notification_enabled: bool,
|
||||||
|
quant_enabled: bool = None,
|
||||||
|
quant_config: Dict = None):
|
||||||
"""更新监测股票"""
|
"""更新监测股票"""
|
||||||
conn = sqlite3.connect(self.db_path)
|
conn = sqlite3.connect(self.db_path)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cursor.execute('''
|
if quant_enabled is not None and quant_config is not None:
|
||||||
UPDATE monitored_stocks
|
quant_config_json = json.dumps(quant_config) if quant_config else None
|
||||||
SET rating = ?, entry_range = ?, take_profit = ?, stop_loss = ?,
|
cursor.execute('''
|
||||||
check_interval = ?, notification_enabled = ?, updated_at = CURRENT_TIMESTAMP
|
UPDATE monitored_stocks
|
||||||
WHERE id = ?
|
SET rating = ?, entry_range = ?, take_profit = ?, stop_loss = ?,
|
||||||
''', (rating, json.dumps(entry_range), take_profit, stop_loss, check_interval, notification_enabled, stock_id))
|
check_interval = ?, notification_enabled = ?,
|
||||||
|
quant_enabled = ?, quant_config = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
''', (rating, json.dumps(entry_range), take_profit, stop_loss,
|
||||||
|
check_interval, notification_enabled, quant_enabled, quant_config_json, stock_id))
|
||||||
|
else:
|
||||||
|
cursor.execute('''
|
||||||
|
UPDATE monitored_stocks
|
||||||
|
SET rating = ?, entry_range = ?, take_profit = ?, stop_loss = ?,
|
||||||
|
check_interval = ?, notification_enabled = ?, updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
''', (rating, json.dumps(entry_range), take_profit, stop_loss, check_interval, notification_enabled, stock_id))
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
@@ -275,7 +300,8 @@ class StockMonitorDatabase:
|
|||||||
|
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
SELECT id, symbol, name, rating, entry_range, take_profit, stop_loss,
|
SELECT id, symbol, name, rating, entry_range, take_profit, stop_loss,
|
||||||
current_price, last_checked, check_interval, notification_enabled
|
current_price, last_checked, check_interval, notification_enabled,
|
||||||
|
quant_enabled, quant_config
|
||||||
FROM monitored_stocks WHERE id = ?
|
FROM monitored_stocks WHERE id = ?
|
||||||
''', (stock_id,))
|
''', (stock_id,))
|
||||||
|
|
||||||
@@ -283,6 +309,7 @@ class StockMonitorDatabase:
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
if row:
|
if row:
|
||||||
|
quant_config = json.loads(row[12]) if row[12] else None
|
||||||
return {
|
return {
|
||||||
'id': row[0],
|
'id': row[0],
|
||||||
'symbol': row[1],
|
'symbol': row[1],
|
||||||
@@ -294,7 +321,9 @@ class StockMonitorDatabase:
|
|||||||
'current_price': row[7],
|
'current_price': row[7],
|
||||||
'last_checked': row[8],
|
'last_checked': row[8],
|
||||||
'check_interval': row[9],
|
'check_interval': row[9],
|
||||||
'notification_enabled': bool(row[10])
|
'notification_enabled': bool(row[10]),
|
||||||
|
'quant_enabled': bool(row[11]),
|
||||||
|
'quant_config': quant_config
|
||||||
}
|
}
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
+145
-4
@@ -17,6 +17,7 @@ from monitor_db import monitor_db
|
|||||||
from monitor_service import monitor_service
|
from monitor_service import monitor_service
|
||||||
from notification_service import notification_service
|
from notification_service import notification_service
|
||||||
from stock_data import StockDataFetcher
|
from stock_data import StockDataFetcher
|
||||||
|
from miniqmt_interface import miniqmt, get_miniqmt_status, QuantStrategyConfig
|
||||||
|
|
||||||
def display_monitor_manager():
|
def display_monitor_manager():
|
||||||
"""显示监测管理主页面"""
|
"""显示监测管理主页面"""
|
||||||
@@ -39,7 +40,7 @@ def display_monitor_manager():
|
|||||||
def display_monitor_status():
|
def display_monitor_status():
|
||||||
"""显示监测服务状态"""
|
"""显示监测服务状态"""
|
||||||
|
|
||||||
col1, col2, col3, col4, col5 = st.columns(5)
|
col1, col2, col3, col4, col5, col6 = st.columns(6)
|
||||||
|
|
||||||
with col1:
|
with col1:
|
||||||
if monitor_service.running:
|
if monitor_service.running:
|
||||||
@@ -56,6 +57,14 @@ def display_monitor_status():
|
|||||||
st.metric("待处理通知", len(notifications))
|
st.metric("待处理通知", len(notifications))
|
||||||
|
|
||||||
with col4:
|
with col4:
|
||||||
|
# 显示MiniQMT状态
|
||||||
|
qmt_status = get_miniqmt_status()
|
||||||
|
if qmt_status['ready']:
|
||||||
|
st.success("🤖 QMT在线")
|
||||||
|
else:
|
||||||
|
st.info("🤖 QMT离线")
|
||||||
|
|
||||||
|
with col5:
|
||||||
if monitor_service.running:
|
if monitor_service.running:
|
||||||
if st.button("⏹️ 停止监测", type="secondary"):
|
if st.button("⏹️ 停止监测", type="secondary"):
|
||||||
monitor_service.stop_monitoring()
|
monitor_service.stop_monitoring()
|
||||||
@@ -67,7 +76,7 @@ def display_monitor_status():
|
|||||||
st.success("✅ 监测服务已启动")
|
st.success("✅ 监测服务已启动")
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
with col5:
|
with col6:
|
||||||
if st.button("🔄 刷新状态"):
|
if st.button("🔄 刷新状态"):
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
@@ -116,6 +125,15 @@ def display_add_stock_section():
|
|||||||
|
|
||||||
# 投资评级
|
# 投资评级
|
||||||
rating = st.selectbox("投资评级", ["买入", "持有", "卖出"], index=0)
|
rating = st.selectbox("投资评级", ["买入", "持有", "卖出"], index=0)
|
||||||
|
|
||||||
|
# 量化交易设置
|
||||||
|
st.markdown("**🤖 量化交易(MiniQMT)**")
|
||||||
|
quant_enabled = st.checkbox("启用量化自动交易", value=False, help="需要先配置MiniQMT连接")
|
||||||
|
|
||||||
|
if quant_enabled:
|
||||||
|
max_position_pct = st.slider("最大仓位比例", 0.05, 0.5, 0.2, 0.05, help="单只股票最大占总资金的比例")
|
||||||
|
auto_stop_loss = st.checkbox("自动止损", value=True)
|
||||||
|
auto_take_profit = st.checkbox("自动止盈", value=True)
|
||||||
|
|
||||||
# 添加按钮
|
# 添加按钮
|
||||||
if st.button("✅ 添加监测", type="primary", use_container_width=True):
|
if st.button("✅ 添加监测", type="primary", use_container_width=True):
|
||||||
@@ -124,6 +142,16 @@ def display_add_stock_section():
|
|||||||
# 准备数据
|
# 准备数据
|
||||||
entry_range = {"min": entry_min, "max": entry_max}
|
entry_range = {"min": entry_min, "max": entry_max}
|
||||||
|
|
||||||
|
# 准备量化配置
|
||||||
|
quant_config = None
|
||||||
|
if quant_enabled:
|
||||||
|
quant_config = {
|
||||||
|
'max_position_pct': max_position_pct,
|
||||||
|
'auto_stop_loss': auto_stop_loss,
|
||||||
|
'auto_take_profit': auto_take_profit,
|
||||||
|
'min_trade_amount': 5000
|
||||||
|
}
|
||||||
|
|
||||||
# 添加到数据库
|
# 添加到数据库
|
||||||
stock_id = monitor_db.add_monitored_stock(
|
stock_id = monitor_db.add_monitored_stock(
|
||||||
symbol=symbol,
|
symbol=symbol,
|
||||||
@@ -133,7 +161,9 @@ def display_add_stock_section():
|
|||||||
take_profit=take_profit if take_profit > 0 else None,
|
take_profit=take_profit if take_profit > 0 else None,
|
||||||
stop_loss=stop_loss if stop_loss > 0 else None,
|
stop_loss=stop_loss if stop_loss > 0 else None,
|
||||||
check_interval=check_interval,
|
check_interval=check_interval,
|
||||||
notification_enabled=notification_enabled
|
notification_enabled=notification_enabled,
|
||||||
|
quant_enabled=quant_enabled,
|
||||||
|
quant_config=quant_config
|
||||||
)
|
)
|
||||||
|
|
||||||
st.success(f"✅ 已成功添加 {symbol} 到监测列表")
|
st.success(f"✅ 已成功添加 {symbol} 到监测列表")
|
||||||
@@ -278,6 +308,12 @@ def display_stock_card(stock: Dict):
|
|||||||
with col3:
|
with col3:
|
||||||
status = "🟢 启用" if stock['notification_enabled'] else "🔴 禁用"
|
status = "🟢 启用" if stock['notification_enabled'] else "🔴 禁用"
|
||||||
st.caption(f"通知: {status}")
|
st.caption(f"通知: {status}")
|
||||||
|
|
||||||
|
# 显示量化状态
|
||||||
|
if stock.get('quant_enabled', False):
|
||||||
|
st.caption("🤖 量化: 🟢 启用")
|
||||||
|
else:
|
||||||
|
st.caption("🤖 量化: 🔴 禁用")
|
||||||
|
|
||||||
# 操作按钮
|
# 操作按钮
|
||||||
st.markdown("**🔧 操作**")
|
st.markdown("**🔧 操作**")
|
||||||
@@ -345,6 +381,17 @@ def display_edit_dialog(stock_id: int):
|
|||||||
rating = st.selectbox("投资评级", ["买入", "持有", "卖出"],
|
rating = st.selectbox("投资评级", ["买入", "持有", "卖出"],
|
||||||
index=["买入", "持有", "卖出"].index(stock['rating']) if stock['rating'] in ["买入", "持有", "卖出"] else 0)
|
index=["买入", "持有", "卖出"].index(stock['rating']) if stock['rating'] in ["买入", "持有", "卖出"] else 0)
|
||||||
notification_enabled = st.checkbox("启用通知", value=stock['notification_enabled'])
|
notification_enabled = st.checkbox("启用通知", value=stock['notification_enabled'])
|
||||||
|
|
||||||
|
# 量化交易设置
|
||||||
|
st.markdown("**🤖 量化交易**")
|
||||||
|
quant_enabled = st.checkbox("启用量化自动交易", value=stock.get('quant_enabled', False))
|
||||||
|
|
||||||
|
if quant_enabled:
|
||||||
|
quant_config = stock.get('quant_config', {})
|
||||||
|
max_position_pct = st.slider("最大仓位比例", 0.05, 0.5,
|
||||||
|
quant_config.get('max_position_pct', 0.2), 0.05)
|
||||||
|
auto_stop_loss = st.checkbox("自动止损", value=quant_config.get('auto_stop_loss', True))
|
||||||
|
auto_take_profit = st.checkbox("自动止盈", value=quant_config.get('auto_take_profit', True))
|
||||||
|
|
||||||
col1, col2, col3 = st.columns(3)
|
col1, col2, col3 = st.columns(3)
|
||||||
|
|
||||||
@@ -359,6 +406,17 @@ def display_edit_dialog(stock_id: int):
|
|||||||
try:
|
try:
|
||||||
# 更新数据库
|
# 更新数据库
|
||||||
new_entry_range = {"min": entry_min, "max": entry_max}
|
new_entry_range = {"min": entry_min, "max": entry_max}
|
||||||
|
|
||||||
|
# 准备量化配置
|
||||||
|
new_quant_config = None
|
||||||
|
if quant_enabled:
|
||||||
|
new_quant_config = {
|
||||||
|
'max_position_pct': max_position_pct,
|
||||||
|
'auto_stop_loss': auto_stop_loss,
|
||||||
|
'auto_take_profit': auto_take_profit,
|
||||||
|
'min_trade_amount': 5000
|
||||||
|
}
|
||||||
|
|
||||||
monitor_db.update_monitored_stock(
|
monitor_db.update_monitored_stock(
|
||||||
stock_id=stock_id,
|
stock_id=stock_id,
|
||||||
rating=rating,
|
rating=rating,
|
||||||
@@ -366,7 +424,9 @@ def display_edit_dialog(stock_id: int):
|
|||||||
take_profit=take_profit if take_profit > 0 else None,
|
take_profit=take_profit if take_profit > 0 else None,
|
||||||
stop_loss=stop_loss if stop_loss > 0 else None,
|
stop_loss=stop_loss if stop_loss > 0 else None,
|
||||||
check_interval=check_interval,
|
check_interval=check_interval,
|
||||||
notification_enabled=notification_enabled
|
notification_enabled=notification_enabled,
|
||||||
|
quant_enabled=quant_enabled,
|
||||||
|
quant_config=new_quant_config
|
||||||
)
|
)
|
||||||
|
|
||||||
st.success("✅ 修改已保存")
|
st.success("✅ 修改已保存")
|
||||||
@@ -445,6 +505,11 @@ def display_notification_management():
|
|||||||
|
|
||||||
st.markdown("### 🔔 通知管理")
|
st.markdown("### 🔔 通知管理")
|
||||||
|
|
||||||
|
# 显示MiniQMT量化交易状态
|
||||||
|
display_miniqmt_status()
|
||||||
|
|
||||||
|
st.markdown("---")
|
||||||
|
|
||||||
# 通知设置
|
# 通知设置
|
||||||
col1, col2 = st.columns([1, 1])
|
col1, col2 = st.columns([1, 1])
|
||||||
|
|
||||||
@@ -538,6 +603,82 @@ def display_notification_management():
|
|||||||
else:
|
else:
|
||||||
st.info("📭 暂无通知")
|
st.info("📭 暂无通知")
|
||||||
|
|
||||||
|
def display_miniqmt_status():
|
||||||
|
"""显示MiniQMT量化交易状态"""
|
||||||
|
st.markdown("### 🤖 MiniQMT量化交易")
|
||||||
|
|
||||||
|
qmt_status = get_miniqmt_status()
|
||||||
|
|
||||||
|
col1, col2 = st.columns([1, 1])
|
||||||
|
|
||||||
|
with col1:
|
||||||
|
st.subheader("📊 连接状态")
|
||||||
|
|
||||||
|
if qmt_status['enabled']:
|
||||||
|
st.success("✅ MiniQMT已启用")
|
||||||
|
else:
|
||||||
|
st.warning("⚠️ MiniQMT未启用")
|
||||||
|
|
||||||
|
if qmt_status['connected']:
|
||||||
|
st.success("✅ 已连接到MiniQMT")
|
||||||
|
else:
|
||||||
|
st.info("⏸️ 未连接到MiniQMT")
|
||||||
|
|
||||||
|
if qmt_status['account_id']:
|
||||||
|
st.info(f"**账户ID**: {qmt_status['account_id']}")
|
||||||
|
else:
|
||||||
|
st.caption("未配置账户ID")
|
||||||
|
|
||||||
|
st.markdown("---")
|
||||||
|
st.markdown("**⚙️ 配置说明**")
|
||||||
|
st.caption("""
|
||||||
|
在 `config.py` 中配置以下参数:
|
||||||
|
```python
|
||||||
|
MINIQMT_CONFIG = {
|
||||||
|
'enabled': True,
|
||||||
|
'account_id': 'your_account_id'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
💡 提示:
|
||||||
|
- 需要安装并启动MiniQMT客户端
|
||||||
|
- 确保账户已登录
|
||||||
|
- 预留接口已实现,可对接真实交易
|
||||||
|
""")
|
||||||
|
|
||||||
|
with col2:
|
||||||
|
st.subheader("📈 量化统计")
|
||||||
|
|
||||||
|
# 统计启用量化的股票
|
||||||
|
stocks = monitor_db.get_monitored_stocks()
|
||||||
|
quant_stocks = [s for s in stocks if s.get('quant_enabled', False)]
|
||||||
|
|
||||||
|
st.metric("启用量化的股票", f"{len(quant_stocks)}/{len(stocks)}")
|
||||||
|
|
||||||
|
if quant_stocks:
|
||||||
|
st.markdown("**量化监测列表:**")
|
||||||
|
for stock in quant_stocks:
|
||||||
|
st.caption(f"🤖 {stock['symbol']} - {stock['name']}")
|
||||||
|
else:
|
||||||
|
st.info("暂无启用量化交易的股票")
|
||||||
|
|
||||||
|
st.markdown("---")
|
||||||
|
|
||||||
|
# 连接按钮
|
||||||
|
if qmt_status['enabled'] and not qmt_status['connected']:
|
||||||
|
if st.button("🔗 连接MiniQMT", type="primary", use_container_width=True):
|
||||||
|
success, msg = miniqmt.connect()
|
||||||
|
if success:
|
||||||
|
st.success(f"✅ {msg}")
|
||||||
|
else:
|
||||||
|
st.error(f"❌ {msg}")
|
||||||
|
st.rerun()
|
||||||
|
elif qmt_status['connected']:
|
||||||
|
if st.button("🔌 断开连接", use_container_width=True):
|
||||||
|
if miniqmt.disconnect():
|
||||||
|
st.info("⏸️ 已断开MiniQMT连接")
|
||||||
|
st.rerun()
|
||||||
|
|
||||||
def get_monitor_summary():
|
def get_monitor_summary():
|
||||||
"""获取监测摘要信息"""
|
"""获取监测摘要信息"""
|
||||||
stocks = monitor_db.get_monitored_stocks()
|
stocks = monitor_db.get_monitored_stocks()
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import streamlit as st
|
|||||||
|
|
||||||
from monitor_db import monitor_db
|
from monitor_db import monitor_db
|
||||||
from stock_data import StockDataFetcher
|
from stock_data import StockDataFetcher
|
||||||
|
from miniqmt_interface import miniqmt, get_miniqmt_status
|
||||||
|
|
||||||
class StockMonitorService:
|
class StockMonitorService:
|
||||||
"""股票监测服务"""
|
"""股票监测服务"""
|
||||||
@@ -104,16 +105,71 @@ class StockMonitorService:
|
|||||||
if current_price >= entry_range['min'] and current_price <= entry_range['max']:
|
if current_price >= entry_range['min'] and current_price <= entry_range['max']:
|
||||||
message = f"股票 {stock['symbol']} ({stock['name']}) 价格 {current_price} 进入进场区间 [{entry_range['min']}-{entry_range['max']}]"
|
message = f"股票 {stock['symbol']} ({stock['name']}) 价格 {current_price} 进入进场区间 [{entry_range['min']}-{entry_range['max']}]"
|
||||||
monitor_db.add_notification(stock['id'], 'entry', message)
|
monitor_db.add_notification(stock['id'], 'entry', message)
|
||||||
|
|
||||||
|
# 如果启用量化交易,执行自动交易
|
||||||
|
if stock.get('quant_enabled', False):
|
||||||
|
self._execute_quant_trade(stock, 'entry', current_price)
|
||||||
|
|
||||||
# 检查止盈
|
# 检查止盈
|
||||||
if take_profit and current_price >= take_profit:
|
if take_profit and current_price >= take_profit:
|
||||||
message = f"股票 {stock['symbol']} ({stock['name']}) 价格 {current_price} 达到止盈位 {take_profit}"
|
message = f"股票 {stock['symbol']} ({stock['name']}) 价格 {current_price} 达到止盈位 {take_profit}"
|
||||||
monitor_db.add_notification(stock['id'], 'take_profit', message)
|
monitor_db.add_notification(stock['id'], 'take_profit', message)
|
||||||
|
|
||||||
|
# 如果启用量化交易,执行自动交易
|
||||||
|
if stock.get('quant_enabled', False):
|
||||||
|
self._execute_quant_trade(stock, 'take_profit', current_price)
|
||||||
|
|
||||||
# 检查止损
|
# 检查止损
|
||||||
if stop_loss and current_price <= stop_loss:
|
if stop_loss and current_price <= stop_loss:
|
||||||
message = f"股票 {stock['symbol']} ({stock['name']}) 价格 {current_price} 达到止损位 {stop_loss}"
|
message = f"股票 {stock['symbol']} ({stock['name']}) 价格 {current_price} 达到止损位 {stop_loss}"
|
||||||
monitor_db.add_notification(stock['id'], 'stop_loss', message)
|
monitor_db.add_notification(stock['id'], 'stop_loss', message)
|
||||||
|
|
||||||
|
# 如果启用量化交易,执行自动交易
|
||||||
|
if stock.get('quant_enabled', False):
|
||||||
|
self._execute_quant_trade(stock, 'stop_loss', current_price)
|
||||||
|
|
||||||
|
def _execute_quant_trade(self, stock: Dict, signal_type: str, current_price: float):
|
||||||
|
"""执行量化交易"""
|
||||||
|
try:
|
||||||
|
# 检查MiniQMT是否连接
|
||||||
|
if not miniqmt.is_connected():
|
||||||
|
print(f"MiniQMT未连接,无法执行 {stock['symbol']} 的量化交易")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 获取量化配置
|
||||||
|
quant_config = stock.get('quant_config', {})
|
||||||
|
if not quant_config:
|
||||||
|
print(f"股票 {stock['symbol']} 未配置量化参数")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 执行策略信号
|
||||||
|
signal = {
|
||||||
|
'type': signal_type,
|
||||||
|
'price': current_price,
|
||||||
|
'message': f"{signal_type} signal triggered"
|
||||||
|
}
|
||||||
|
|
||||||
|
position_size = quant_config.get('max_position_pct', 0.2)
|
||||||
|
success, msg = miniqmt.execute_strategy_signal(
|
||||||
|
stock['id'],
|
||||||
|
stock['symbol'],
|
||||||
|
signal,
|
||||||
|
position_size
|
||||||
|
)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
print(f"✅ 量化交易成功: {stock['symbol']} - {msg}")
|
||||||
|
# 记录交易通知
|
||||||
|
monitor_db.add_notification(
|
||||||
|
stock['id'],
|
||||||
|
'quant_trade',
|
||||||
|
f"量化交易执行: {msg}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(f"❌ 量化交易失败: {stock['symbol']} - {msg}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"执行量化交易异常: {stock['symbol']} - {str(e)}")
|
||||||
|
|
||||||
def get_stocks_needing_update(self) -> List[Dict]:
|
def get_stocks_needing_update(self) -> List[Dict]:
|
||||||
"""获取需要更新价格的股票"""
|
"""获取需要更新价格的股票"""
|
||||||
|
|||||||
+237
@@ -0,0 +1,237 @@
|
|||||||
|
# 🤖 量化交易功能快速指南
|
||||||
|
|
||||||
|
## 简介
|
||||||
|
|
||||||
|
本系统已为监测板块增加MiniQMT量化交易预留接口,实现监测价格触发后自动执行交易的功能。
|
||||||
|
|
||||||
|
## 核心功能
|
||||||
|
|
||||||
|
### ✅ 已实现功能
|
||||||
|
1. **自动交易执行** - 价格触发后自动下单
|
||||||
|
2. **仓位管理** - 智能控制交易仓位
|
||||||
|
3. **风险控制** - 自动止损止盈
|
||||||
|
4. **订单管理** - 完整的订单生命周期管理
|
||||||
|
5. **持仓监控** - 实时查看持仓和盈亏
|
||||||
|
6. **多种订单类型** - 支持市价单、限价单、止损单
|
||||||
|
|
||||||
|
### 🔧 新增模块
|
||||||
|
- `miniqmt_interface.py` - MiniQMT接口核心模块
|
||||||
|
- `MINIQMT_INTEGRATION_GUIDE.md` - 详细集成指南
|
||||||
|
|
||||||
|
### 📝 更新模块
|
||||||
|
- `monitor_db.py` - 增加量化配置字段(quant_enabled, quant_config)
|
||||||
|
- `monitor_service.py` - 集成量化交易执行逻辑
|
||||||
|
- `monitor_manager.py` - 添加量化配置界面
|
||||||
|
- `config.py` - 添加MiniQMT配置选项
|
||||||
|
- `README.md` - 更新功能说明和文档
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 1. 配置环境变量
|
||||||
|
|
||||||
|
编辑 `.env` 文件,添加以下配置:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 启用MiniQMT量化交易
|
||||||
|
MINIQMT_ENABLED=true
|
||||||
|
MINIQMT_ACCOUNT_ID=your_account_id
|
||||||
|
MINIQMT_HOST=127.0.0.1
|
||||||
|
MINIQMT_PORT=58610
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 启动MiniQMT客户端
|
||||||
|
|
||||||
|
1. 启动MiniQMT客户端程序
|
||||||
|
2. 登录你的交易账户
|
||||||
|
3. 确保API服务已开启
|
||||||
|
|
||||||
|
### 3. 在系统中启用量化
|
||||||
|
|
||||||
|
1. 运行系统:`python run.py`
|
||||||
|
2. 进入"📊 实时监测"板块
|
||||||
|
3. 在"🤖 MiniQMT量化交易"区域点击"连接MiniQMT"
|
||||||
|
4. 看到"✅ 已连接"提示即可
|
||||||
|
|
||||||
|
### 4. 添加量化监测
|
||||||
|
|
||||||
|
#### 添加新股票:
|
||||||
|
1. 点击"添加股票监测"
|
||||||
|
2. 填写股票代码和关键位置
|
||||||
|
3. 勾选"启用量化自动交易"
|
||||||
|
4. 设置量化参数:
|
||||||
|
- 最大仓位比例:建议0.2(20%)
|
||||||
|
- 自动止损:建议勾选
|
||||||
|
- 自动止盈:建议勾选
|
||||||
|
5. 点击"添加监测"
|
||||||
|
|
||||||
|
#### 编辑现有股票:
|
||||||
|
1. 找到目标股票卡片
|
||||||
|
2. 点击"编辑"
|
||||||
|
3. 勾选"启用量化自动交易"
|
||||||
|
4. 配置参数后保存
|
||||||
|
|
||||||
|
## 交易逻辑
|
||||||
|
|
||||||
|
### 自动交易触发条件
|
||||||
|
|
||||||
|
#### 1. 进场买入
|
||||||
|
- **触发**:价格进入设定的进场区间
|
||||||
|
- **动作**:按配置的仓位比例自动买入
|
||||||
|
- **订单类型**:限价单
|
||||||
|
|
||||||
|
#### 2. 止盈卖出
|
||||||
|
- **触发**:价格达到止盈位
|
||||||
|
- **动作**:卖出全部持仓
|
||||||
|
- **订单类型**:限价单
|
||||||
|
|
||||||
|
#### 3. 止损卖出
|
||||||
|
- **触发**:价格达到止损位
|
||||||
|
- **动作**:紧急卖出全部持仓
|
||||||
|
- **订单类型**:市价单(快速成交)
|
||||||
|
|
||||||
|
## 安全建议
|
||||||
|
|
||||||
|
### ⚠️ 风险提示
|
||||||
|
1. 自动交易涉及真实资金,请谨慎使用
|
||||||
|
2. 建议先用测试账户测试功能
|
||||||
|
3. 设置合理的仓位限制(建议单股不超过20%)
|
||||||
|
4. 必须设置止损位(建议5-10%)
|
||||||
|
5. 保持人工监控,不要完全依赖自动化
|
||||||
|
|
||||||
|
### ✅ 最佳实践
|
||||||
|
1. **小仓位测试** - 先用小额资金测试
|
||||||
|
2. **严格止损** - 必须设置止损保护
|
||||||
|
3. **合理仓位** - 单股不超过20%,总仓位不超过80%
|
||||||
|
4. **定期检查** - 定期查看持仓和订单状态
|
||||||
|
5. **及时调整** - 根据市场变化及时调整策略
|
||||||
|
|
||||||
|
## 界面功能
|
||||||
|
|
||||||
|
### 监测状态栏
|
||||||
|
- **🟢 运行中** / **🔴 已停止** - 监测服务状态
|
||||||
|
- **监测股票** - 当前监测股票数量
|
||||||
|
- **待处理通知** - 待处理的通知数量
|
||||||
|
- **🤖 QMT在线** / **🤖 QMT离线** - MiniQMT连接状态
|
||||||
|
|
||||||
|
### MiniQMT状态面板
|
||||||
|
- **连接状态** - 显示是否已连接到MiniQMT
|
||||||
|
- **账户ID** - 当前交易账户
|
||||||
|
- **量化统计** - 启用量化的股票数量
|
||||||
|
- **量化监测列表** - 显示所有启用量化的股票
|
||||||
|
|
||||||
|
### 股票卡片
|
||||||
|
每个监测股票卡片会显示:
|
||||||
|
- **基本信息** - 代码、名称、当前价格
|
||||||
|
- **关键位置** - 进场区间、止盈位、止损位
|
||||||
|
- **监测状态** - 监测间隔、最后检查时间、通知状态
|
||||||
|
- **量化状态** - 🟢 启用 / 🔴 禁用
|
||||||
|
|
||||||
|
## 预留接口说明
|
||||||
|
|
||||||
|
### MiniQMTInterface 类
|
||||||
|
|
||||||
|
系统提供了完整的MiniQMT接口类,支持以下功能:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 连接管理
|
||||||
|
miniqmt.connect(account_id) # 连接到MiniQMT
|
||||||
|
miniqmt.disconnect() # 断开连接
|
||||||
|
miniqmt.is_connected() # 检查连接状态
|
||||||
|
|
||||||
|
# 账户信息
|
||||||
|
miniqmt.get_account_info() # 获取账户信息
|
||||||
|
miniqmt.get_positions() # 获取所有持仓
|
||||||
|
miniqmt.get_position(symbol) # 获取单个持仓
|
||||||
|
|
||||||
|
# 交易下单
|
||||||
|
miniqmt.place_order( # 下单
|
||||||
|
symbol, action, quantity,
|
||||||
|
price, order_type
|
||||||
|
)
|
||||||
|
miniqmt.cancel_order(order_id) # 撤单
|
||||||
|
miniqmt.get_order_status(order_id) # 查询订单状态
|
||||||
|
|
||||||
|
# 策略执行
|
||||||
|
miniqmt.execute_strategy_signal( # 执行策略信号
|
||||||
|
stock_id, symbol, signal,
|
||||||
|
position_size
|
||||||
|
)
|
||||||
|
|
||||||
|
# 风险管理
|
||||||
|
miniqmt.calculate_position_size() # 计算仓位大小
|
||||||
|
miniqmt.get_risk_metrics() # 获取风险指标
|
||||||
|
miniqmt.validate_trade() # 验证交易可行性
|
||||||
|
```
|
||||||
|
|
||||||
|
### 对接真实交易
|
||||||
|
|
||||||
|
当前接口为预留接口,要对接真实交易,需要:
|
||||||
|
|
||||||
|
1. 安装MiniQMT Python SDK:
|
||||||
|
```bash
|
||||||
|
pip install xtquant
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 在 `miniqmt_interface.py` 中取消注释相关代码:
|
||||||
|
```python
|
||||||
|
# 例如在 connect() 方法中
|
||||||
|
from xtquant import xtdata
|
||||||
|
xtdata.connect()
|
||||||
|
|
||||||
|
# 在 place_order() 方法中
|
||||||
|
from xtquant import xttrader
|
||||||
|
order_id = xttrader.order_stock(...)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 参考MiniQMT官方文档完成具体对接
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### Q1: MiniQMT连接失败?
|
||||||
|
A: 检查以下几点:
|
||||||
|
- MiniQMT客户端是否启动
|
||||||
|
- 账户是否已登录
|
||||||
|
- 账户ID是否正确
|
||||||
|
- 网络连接是否正常
|
||||||
|
|
||||||
|
### Q2: 量化交易没有执行?
|
||||||
|
A: 检查以下几点:
|
||||||
|
- 量化功能是否已启用
|
||||||
|
- MiniQMT是否已连接
|
||||||
|
- 监测服务是否在运行
|
||||||
|
- 是否在交易时间内
|
||||||
|
- 查看通知记录中的错误信息
|
||||||
|
|
||||||
|
### Q3: 如何测试量化功能?
|
||||||
|
A: 建议步骤:
|
||||||
|
1. 使用测试账户
|
||||||
|
2. 设置小额交易金额
|
||||||
|
3. 设置宽松的触发条件
|
||||||
|
4. 观察订单执行情况
|
||||||
|
5. 确认逻辑无误后再使用实盘
|
||||||
|
|
||||||
|
### Q4: 仓位如何控制?
|
||||||
|
A: 系统提供多层仓位控制:
|
||||||
|
- 单股最大仓位比例(配置时设置)
|
||||||
|
- 最小交易金额(默认5000元)
|
||||||
|
- A股100股为一手的限制
|
||||||
|
- 可用资金检查
|
||||||
|
|
||||||
|
## 技术支持
|
||||||
|
|
||||||
|
### 详细文档
|
||||||
|
- 完整集成指南:`MINIQMT_INTEGRATION_GUIDE.md`
|
||||||
|
- 系统说明:`README.md`
|
||||||
|
- 快速启动:`QUICK_START.md`
|
||||||
|
|
||||||
|
### 问题反馈
|
||||||
|
如遇到问题,请:
|
||||||
|
1. 查看终端日志输出
|
||||||
|
2. 查看MiniQMT客户端日志
|
||||||
|
3. 查看通知记录中的详细信息
|
||||||
|
4. 参考详细集成指南
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**免责声明**:本系统仅供学习研究使用,量化交易涉及真实资金风险,请谨慎使用并自行承担投资风险。
|
||||||
|
|
||||||
Reference in New Issue
Block a user