不同券商接口千差万别?深入Qt交易系统的接口抽象层,构建可扩展的券商适配架构
一、券商接口概述
国内券商接口种类繁多,各有特点:
| 接口类型 | 代表厂商 | 特点 | 适用场景 |
|---|---|---|---|
| CTP | 上期技术 | 期货标准接口 | 期货交易 |
| XTP | 中泰证券 | 高性能股票接口 | 股票交易 |
| KGS | 国金证券 | 快速行情 | 高频交易 |
| LTS | 华鑫证券 | 嵌入式接口 | 私募产品 |
| FIX | 国际标准 | 通用协议 | 海外市场 |
1.1 接口抽象目标
- 统一API:屏蔽不同券商的接口差异
- 可扩展:支持快速接入新券商
- 可测试:提供Mock实现便于测试
- 高性能:减少抽象层开销
二、接口抽象设计
2.1 核心接口定义
cpp
// ITradeApi.h - 交易接口基类
class ITradeApi : public QObject
{
Q_OBJECT
public:
virtual ~ITradeApi() = default;
// 连接管理
virtual bool connect(const QString &address, int port) = 0;
virtual void disconnect() = 0;
virtual bool isConnected() const = 0;
// 登录认证
virtual bool login(const QString &username, const QString &password) = 0;
virtual void logout() = 0;
// 账户查询
virtual QFuture<AccountInfo> queryAccount() = 0;
virtual QFuture<QList<Position>> queryPositions() = 0;
virtual QFuture<QList<Order>> queryOrders() = 0;
virtual QFuture<QList<Trade>> queryTrades() = 0;
// 交易操作
virtual QString insertOrder(const OrderRequest &request) = 0;
virtual bool cancelOrder(const QString &orderId) = 0;
// 行情订阅
virtual bool subscribeMarketData(const QStringList &symbols) = 0;
virtual bool unsubscribeMarketData(const QStringList &symbols) = 0;
signals:
void connected();
void disconnected();
void loginResult(bool success, const QString &message);
void orderUpdated(const Order &order);
void tradeReceived(const Trade &trade);
void positionUpdated(const Position &position);
void marketDataReceived(const MarketData &data);
void errorOccurred(int errorCode, const QString &errorMessage);
};
2.2 数据结构定义
cpp
// TradeTypes.h
struct AccountInfo
{
QString accountId; // 账户ID
double totalAssets; // 总资产
double availableCash; // 可用资金
double marketValue; // 持仓市值
double frozenCash; // 冻结资金
double margin; // 保证金
};
struct Position
{
QString symbol; // 证券代码
QString exchange; // 交易所
int64_t totalQty; // 总持仓
int64_t availableQty; // 可用持仓
double avgPrice; // 成本价
double marketPrice; // 市价
double profitLoss; // 浮动盈亏
};
struct Order
{
QString orderId; // 订单ID
QString symbol; // 证券代码
QString exchange; // 交易所
QString direction; // 买卖方向 Buy/Sell
QString offset; // 开平 Open/Close
double price; // 委托价格
int64_t quantity; // 委托数量
int64_t filledQty; // 成交数量
QString status; // 订单状态
QDateTime createTime; // 创建时间
QDateTime updateTime; // 更新时间
};
struct Trade
{
QString tradeId; // 成交ID
QString orderId; // 订单ID
QString symbol; // 证券代码
QString exchange; // 交易所
QString direction; // 买卖方向
double price; // 成交价格
int64_t quantity; // 成交数量
QDateTime tradeTime; // 成交时间
};
struct MarketData
{
QString symbol; // 证券代码
QString exchange; // 交易所
double lastPrice; // 最新价
double openPrice; // 开盘价
double highPrice; // 最高价
double lowPrice; // 最低价
int64_t volume; // 成交量
double turnover; // 成交额
double bidPrice[5]; // 买价
int64_t bidVolume[5]; // 买量
double askPrice[5]; // 卖价
int64_t askVolume[5]; // 卖量
};
struct OrderRequest
{
QString symbol; // 证券代码
QString exchange; // 交易所
QString direction; // 买卖方向
QString offset; // 开平
double price; // 委托价格
int64_t quantity; // 委托数量
QString orderType; // 订单类型 Limit/Market
};
三、CTP接口适配实现
3.1 CTP适配器类
cpp
// CtpTradeApi.h
class CtpTradeApi : public ITradeApi
{
Q_OBJECT
public:
explicit CtpTradeApi(QObject *parent = nullptr);
~CtpTradeApi() override;
// ITradeApi接口实现
bool connect(const QString &address, int port) override;
void disconnect() override;
bool isConnected() const override;
bool login(const QString &username, const QString &password) override;
void logout() override;
QString insertOrder(const OrderRequest &request) override;
bool cancelOrder(const QString &orderId) override;
QFuture<AccountInfo> queryAccount() override;
QFuture<QList<Position>> queryPositions() override;
bool subscribeMarketData(const QStringList &symbols) override;
private slots:
void onFrontConnected();
void onFrontDisconnected(int reason);
void onRspUserLogin(int errorId, const QString &errorMsg);
void onRspOrderInsert(const QString &orderId, int errorId, const QString &errorMsg);
void onRtnOrder(const CThostFtdcOrderField *pOrder);
void onRtnTrade(const CThostFtdcTradeField *pTrade);
void onRtnDepthMarketData(const CThostFtdcDepthMarketDataField *pData);
private:
Order convertFromCtp(const CThostFtdcOrderField *pOrder);
Trade convertFromCtp(const CThostFtdcTradeField *pTrade);
MarketData convertFromCtp(const CThostFtdcDepthMarketDataField *pData);
CThostFtdcMdApi *m_mdApi = nullptr; // 行情API
CThostFtdcTraderApi *m_tradeApi = nullptr; // 交易API
QString m_brokerId;
QString m_investorId;
int m_requestId = 0;
QPromise<AccountInfo> *m_accountPromise = nullptr;
QPromise<QList<Position>> *m_positionPromise = nullptr;
};
3.2 CTP回调处理
cpp
// CtpTradeApi.cpp
void CtpTradeApi::onRtnOrder(const CThostFtdcOrderField *pOrder)
{
if (!pOrder) return;
Order order = convertFromCtp(pOrder);
emit orderUpdated(order);
}
void CtpTradeApi::onRtnTrade(const CThostFtdcTradeField *pTrade)
{
if (!pTrade) return;
Trade trade = convertFromCtp(pTrade);
emit tradeReceived(trade);
}
Order CtpTradeApi::convertFromCtp(const CThostFtdcOrderField *pOrder)
{
Order order;
order.orderId = pOrder->OrderRef;
order.symbol = pOrder->InstrumentID;
order.exchange = pOrder->ExchangeID;
order.direction = (pOrder->Direction == THOST_FTDC_D_Buy) ? "Buy" : "Sell";
order.offset = (pOrder->CombOffsetFlag[0] == THOST_FTDC_OF_Open) ? "Open" : "Close";
order.price = pOrder->LimitPrice;
order.quantity = pOrder->VolumeTotalOriginal;
order.filledQty = pOrder->VolumeTraded;
// 状态转换
switch (pOrder->OrderStatus) {
case THOST_FTDC_OST_AllTraded:
order.status = "Filled"; break;
case THOST_FTDC_OST_PartTradedQueueing:
order.status = "Partial"; break;
case THOST_FTDC_OST_NoTradeQueueing:
order.status = "Pending"; break;
case THOST_FTDC_OST_Canceled:
order.status = "Canceled"; break;
default:
order.status = "Unknown";
}
order.createTime = QDateTime::fromString(pOrder->InsertDate, "yyyyMMdd");
return order;
}
四、接口工厂模式
4.1 工厂类设计
cpp
// TradeApiFactory.h
class TradeApiFactory
{
public:
enum ApiType {
CTP, // 期货CTP
XTP, // 中泰XTP
KGS, // 国金KGS
Mock // 测试用Mock
};
static ITradeApi* create(ApiType type, QObject *parent = nullptr)
{
switch (type) {
case CTP:
return new CtpTradeApi(parent);
case XTP:
return new XtpTradeApi(parent);
case KGS:
return new KgsTradeApi(parent);
case Mock:
return new MockTradeApi(parent);
default:
return nullptr;
}
}
static QStringList supportedApis()
{
return {"CTP", "XTP", "KGS", "Mock"};
}
};
4.2 配置化创建
cpp
// 从配置文件读取券商类型
ITradeApi* createTradeApiFromConfig()
{
QSettings settings("config.ini", QSettings::IniFormat);
QString apiType = settings.value("Trade/ApiType").toString();
ITradeApi *api = nullptr;
if (apiType == "CTP") {
api = TradeApiFactory::create(TradeApiFactory::CTP);
api->connect(settings.value("CTP/TradeFront").toString(),
settings.value("CTP/TradePort").toInt());
} else if (apiType == "XTP") {
api = TradeApiFactory::create(TradeApiFactory::XTP);
// XTP初始化...
}
return api;
}
五、Mock实现
5.1 测试用Mock类
cpp
// MockTradeApi.h
class MockTradeApi : public ITradeApi
{
Q_OBJECT
public:
explicit MockTradeApi(QObject *parent = nullptr);
bool connect(const QString &address, int port) override;
bool login(const QString &username, const QString &password) override;
QString insertOrder(const OrderRequest &request) override;
bool cancelOrder(const QString &orderId) override;
QFuture<AccountInfo> queryAccount() override;
QFuture<QList<Position>> queryPositions() override;
// Mock特有方法
void simulateOrderFill(const QString &orderId, double price, int64_t qty);
void simulateMarketData(const QString &symbol, double price);
private:
bool m_connected = false;
bool m_loggedIn = false;
QMap<QString, Order> m_orders;
QMap<QString, Position> m_positions;
AccountInfo m_account;
};
// 实现
QString MockTradeApi::insertOrder(const OrderRequest &request)
{
QString orderId = QUuid::createUuid().toString(QUuid::WithoutBraces);
Order order;
order.orderId = orderId;
order.symbol = request.symbol;
order.exchange = request.exchange;
order.direction = request.direction;
order.offset = request.offset;
order.price = request.price;
order.quantity = request.quantity;
order.filledQty = 0;
order.status = "Pending";
order.createTime = QDateTime::currentDateTime();
m_orders[orderId] = order;
// 模拟订单更新
QTimer::singleShot(100, [this, orderId]() {
Order &ord = m_orders[orderId];
ord.status = "Partial";
ord.filledQty = ord.quantity / 2;
emit orderUpdated(ord);
});
return orderId;
}
六、统一管理类
6.1 TradeManager封装
cpp
// TradeManager.h
class TradeManager : public QObject
{
Q_OBJECT
public:
static TradeManager* instance();
void init(ITradeApi *api);
void cleanup();
// 便捷接口
QString buy(const QString &symbol, double price, int64_t qty);
QString sell(const QString &symbol, double price, int64_t qty);
bool cancelOrder(const QString &orderId);
void queryAll();
void subscribe(const QStringList &symbols);
signals:
void accountUpdated(const AccountInfo &account);
void positionUpdated(const Position &position);
void orderUpdated(const Order &order);
void tradeReceived(const Trade &trade);
void marketDataReceived(const MarketData &data);
private:
TradeManager();
ITradeApi *m_api = nullptr;
AccountInfo m_account;
QMap<QString, Position> m_positions;
QMap<QString, Order> m_orders;
};
QString TradeManager::buy(const QString &symbol, double price, int64_t qty)
{
OrderRequest request;
request.symbol = symbol;
request.direction = "Buy";
request.offset = "Open";
request.price = price;
request.quantity = qty;
request.orderType = "Limit";
return m_api->insertOrder(request);
}
七、总结
券商接口封装核心要点:
- 抽象接口:ITradeApi定义统一操作
- 数据结构:标准化Account/Position/Order/Trade
- 适配器模式:CTP/XTP/KGS各自实现适配
- 工厂模式:配置化创建具体实现
- Mock测试:提供模拟环境便于开发测试
《注:若有发现问题欢迎大家提出来纠正》
以上仅为技术分享参考,不构成投资建议