zs_sec.py
"""
招商证券对接模块
基于 CTP/UFT/OpenCTP 封装专属对接层,简化配置参数
"""
import logging
from typing import Optional, Dict, Any
from ..constant import Exchange, OrderType, Direction, Offset
# 招商证券对接模块日志
logger = logging.getLogger("AIQuant.zs_sec")
logger.setLevel(logging.INFO)
class ZSSecConfig:
"""
招商证券接口配置类
"""
def __init__(
self,
server_address: str = "",
port: int = 0,
account: str = "",
password: str = "",
broker_code: str = ""
):
"""
初始化招商证券接口配置
Args:
server_address: 服务器地址
port: 端口号
account: 账号
password: 密码
broker_code: 经纪商代码
"""
self.server_address = server_address
self.port = port
self.account = account
self.password = password
self.broker_code = broker_code
@classmethod
def from_dict(cls, config: Dict[str, Any]) -> "ZSSecConfig":
"""
从字典创建配置对象
Args:
config: 配置字典
Returns:
招商证券接口配置对象
"""
return cls(
server_address=config.get("server_address", ""),
port=config.get("port", 0),
account=config.get("account", ""),
password=config.get("password", ""),
broker_code=config.get("broker_code", "")
)
def to_dict(self) -> Dict[str, Any]:
"""
转换为字典
Returns:
配置字典
"""
return {
"server_address": self.server_address,
"port": self.port,
"account": self.account,
"password": self.password,
"broker_code": self.broker_code
}
def validate(self) -> bool:
"""
验证配置是否有效
Returns:
配置是否有效的布尔值
"""
if not self.server_address:
logger.error("服务器地址不能为空")
return False
if self.port <= 0 or self.port > 65535:
logger.error("端口号必须在 1-65535 之间")
return False
if not self.account:
logger.error("账号不能为空")
return False
if not self.password:
logger.error("密码不能为空")
return False
if not self.broker_code:
logger.error("经纪商代码不能为空")
return False
return True
class ZSSecApi:
"""
招商证券交易接口
"""
def __init__(self, config: ZSSecConfig):
"""
初始化招商证券交易接口
Args:
config: 招商证券接口配置
"""
self.config = config
self.connected = False
self.login_success = False
def connect(self) -> bool:
"""
连接服务器
Returns:
连接是否成功的布尔值
"""
logger.info("正在连接招商证券接口服务器...")
logger.info(f"服务器地址: {self.config.server_address}:{self.config.port}")
logger.info(f"账号: {self.config.account}")
logger.info(f"经纪商代码: {self.config.broker_code}")
# 这里应该实现实际的连接逻辑
# 暂时返回模拟成功
self.connected = True
logger.info("招商证券接口连接成功")
return True
def login(self) -> bool:
"""
登录账户
Returns:
登录是否成功的布尔值
"""
if not self.connected:
logger.error("尚未连接服务器,无法登录")
return False
logger.info("正在登录招商证券账户...")
# 这里应该实现实际的登录逻辑
# 暂时返回模拟成功
self.login_success = True
logger.info("招商证券账户登录成功")
return True
def disconnect(self) -> bool:
"""
断开连接
Returns:
断开连接是否成功的布尔值
"""
logger.info("正在断开招商证券接口连接...")
self.connected = False
self.login_success = False
logger.info("招商证券接口连接已断开")
return True
def send_order(
self,
symbol: str,
exchange: Exchange,
price: float,
volume: int,
direction: Direction,
offset: Offset,
order_type: OrderType = OrderType.LIMIT
) -> Optional[str]:
"""
发送订单
Args:
symbol: 股票代码
exchange: 交易所
price: 价格
volume: 数量
direction: 方向
offset: 开平类型
order_type: 订单类型
Returns:
订单 ID(如果成功),否则 None
"""
if not self.connected or not self.login_success:
logger.error("尚未连接或登录,无法发送订单")
return None
logger.info(
f"发送订单: {symbol} - {direction.value}{offset.value} - "
f"{price:.2f} * {volume}")
# 这里应该实现实际的订单发送逻辑
# 暂时返回模拟订单 ID
return f"ZS{symbol}{exchange.value}{direction.value}{offset.value}"
def cancel_order(self, order_id: str) -> bool:
"""
撤销订单
Args:
order_id: 订单 ID
Returns:
撤销是否成功的布尔值
"""
if not self.connected or not self.login_success:
logger.error("尚未连接或登录,无法撤销订单")
return False
logger.info(f"撤销订单: {order_id}")
# 这里应该实现实际的订单撤销逻辑
# 暂时返回模拟成功
return True
def get_account(self) -> Optional[Dict[str, Any]]:
"""
获取账户信息
Returns:
账户信息字典(如果成功),否则 None
"""
if not self.connected or not self.login_success:
logger.error("尚未连接或登录,无法获取账户信息")
return None
# 这里应该实现实际的账户信息获取逻辑
# 暂时返回模拟数据
return {
"account": self.config.account,
"balance": 1000000.00,
"available": 800000.00,
"margin": 200000.00,
"profit": 50000.00
}
def get_positions(self) -> Optional[Dict[str, Any]]:
"""
获取持仓信息
Returns:
持仓信息字典(如果成功),否则 None
"""
if not self.connected or not self.login_success:
logger.error("尚未连接或登录,无法获取持仓信息")
return None
# 这里应该实现实际的持仓信息获取逻辑
# 暂时返回模拟数据
return {
"000001.SZ": {
"volume": 1000,
"direction": Direction.LONG,
"price": 12.50,
"pnl": 2500.00
}
}
# 错误码和常见问题
ZS_ERROR_CODES = {
1001: "服务器地址错误",
1002: "端口号错误",
1003: "账号或密码错误",
1004: "经纪商代码错误",
1005: "网络连接失败",
1006: "登录超时",
1007: "权限不足",
1008: "账户被锁定"
}
# 常见问题排查指引
ZS_TROUBLESHOOTING = {
"连接失败": [
"检查服务器地址和端口号是否正确",
"检查网络连接是否正常",
"确认防火墙是否允许访问该端口",
"联系招商证券客服确认服务器状态"
],
"登录失败": [
"检查账号和密码是否正确",
"确认是否开通了量化交易权限",
"检查经纪商代码是否正确",
"确认账户是否被锁定"
],
"订单发送失败": [
"检查股票代码和交易所是否有效",
"确认账户是否有足够的资金",
"检查交易时间是否在正常交易时段",
"确认是否有持仓限制"
]
}
# 默认配置
ZS_DEFAULT_CONFIG = ZSSecConfig(
server_address="",
port=0,
account="",
password="",
broker_code=""
)