Back to Wondertrader

Swordfish-OES API {#mainpage}

src/API/oesApi0.17.5.8/include/oes_api/README.md

0.9.922.5 KB
Original Source

Swordfish-OES API {#mainpage}

箭鱼快速订单系统API使用说明


Quick Start

1.1 示例代码

  • 参见 samples/oes_sample_c 目录下的样例文件
    • 配置文件样例 <oes_client_sample.conf>
    • 现货代码样例 <01_oes_client_stock_sample.c>
    • 期权代码样例 <02_oes_client_option_sample.c>
    • 异步接口样例 <03_oes_async_api_sample.c>
    • 现货查询样例 <04_oes_stk_query_sample.c>
    • 期权查询样例 <05_oes_opt_query_sample.c>
    • 信用异步代码样例 <08_oes_async_client_credit_sample.c>
    • 信用异步查询样例 <10_oes_async_crd_query_sample.c>
    • 用于样例代码编译的 <Makefile.sample>

01_oes_client_stock_sample.c 摘录如下:

{.c}

/**
 * 发送委托请求
 *
 * 提示:
 * - 可以通过 OesApi_GetClEnvId() 方法获得到当前通道所使用的客户端环境号(clEnvId), 如:
 *   <code>int8 clEnvId = OesApi_GetClEnvId(pOrdChannel);</code>
 *
 * @param   pOrdChannel     委托通道的会话信息
 * @param   mktId           市场代码 (必填) @see eOesMarketIdT
 * @param   pSecurityId     股票代码 (必填)
 * @param   pInvAcctId      股东账户代码 (可不填)
 * @param   ordType         委托类型 (必填) @see eOesOrdTypeT, eOesOrdTypeShT, eOesOrdTypeSzT
 * @param   bsType          买卖类型 (必填) @see eOesBuySellTypeT
 * @param   ordQty          委托数量 (必填, 单位为股/张)
 * @param   ordPrice        委托价格 (必填, 单位精确到元后四位,即1元 = 10000)
 * @return  大于等于0,成功;小于0,失败(错误号)
 */
static inline int32
_OesStkSample_SendOrderReq(OesApiSessionInfoT *pOrdChannel,
        uint8 mktId, const char *pSecurityId, const char *pInvAcctId,
        uint8 ordType, uint8 bsType, int32 ordQty, int32 ordPrice) {
    OesOrdReqT          ordReq = {NULLOBJ_OES_ORD_REQ};

    SLOG_ASSERT2(pOrdChannel
            && mktId > 0 && mktId < __OES_MKT_ID_MAX
            && pSecurityId && ordType < __OES_ORD_TYPE_FOK_MAX
            && bsType > 0 && bsType < __OES_BS_TYPE_MAX_TRADING
            && ordQty > 0 && ordPrice >= 0,
            "pOrdChannel[%p], mktId[%hhu], pSecurityId[%s], " \
            "ordType[%hhu], bsType[%hhu], ordQty[%d], ordPrice[%d]",
            pOrdChannel, mktId, pSecurityId ? pSecurityId : "NULL",
            ordType, bsType, ordQty, ordPrice);

    ordReq.clSeqNo = (int32) ++pOrdChannel->lastOutMsgSeq;
    ordReq.mktId = mktId;
    ordReq.ordType = ordType;
    ordReq.bsType = bsType;

    strncpy(ordReq.securityId, pSecurityId, sizeof(ordReq.securityId) - 1);
    if (pInvAcctId) {
        /* 股东账户可不填 */
        strncpy(ordReq.invAcctId, pInvAcctId, sizeof(ordReq.invAcctId) - 1);
    }

    ordReq.ordQty = ordQty;
    ordReq.ordPrice = ordPrice;

    return OesApi_SendOrderReq(pOrdChannel, &ordReq);
}


/**
 * 发送撤单请求
 *
 * @param   pOrdChannel     委托通道的会话信息
 * @param   mktId           被撤委托的市场代码 (必填) @see eOesMarketIdT
 * @param   pSecurityId     被撤委托的股票代码 (选填, 若不为空则校验待撤订单是否匹配)
 * @param   pInvAcctId      被撤委托的股东账户代码 (选填, 若不为空则校验待撤订单是否匹配)
 * @param   origClSeqNo     被撤委托的流水号 (若使用 origClOrdId, 则不必填充该字段)
 * @param   origClEnvId     被撤委托的客户端环境号 (小于等于0, 则使用当前会话的 clEnvId)
 * @param   origClOrdId     被撤委托的客户订单编号 (若使用 origClSeqNo, 则不必填充该字段)
 * @return  大于等于0,成功;小于0,失败(错误号)
 */
static inline int32
_OesStkSample_SendOrderCancelReq(OesApiSessionInfoT *pOrdChannel,
        uint8 mktId, const char *pSecurityId, const char *pInvAcctId,
        int32 origClSeqNo, int8 origClEnvId, int64 origClOrdId) {
    OesOrdCancelReqT    cancelReq = {NULLOBJ_OES_ORD_CANCEL_REQ};

    SLOG_ASSERT2(pOrdChannel && mktId > 0 && mktId < __OES_MKT_ID_MAX,
            "pOrdChannel[%p], mktId[%hhu]", pOrdChannel, mktId);

    cancelReq.clSeqNo = (int32) ++pOrdChannel->lastOutMsgSeq;
    cancelReq.mktId = mktId;

    if (pSecurityId) {
        /* 撤单时被撤委托的股票代码可不填 */
        strncpy(cancelReq.securityId, pSecurityId, sizeof(cancelReq.securityId) - 1);
    }

    if (pInvAcctId) {
        /* 撤单时被撤委托的股东账户可不填 */
        strncpy(cancelReq.invAcctId, pInvAcctId, sizeof(cancelReq.invAcctId) - 1);
    }

    cancelReq.origClSeqNo = origClSeqNo;
    cancelReq.origClEnvId = origClEnvId;
    cancelReq.origClOrdId = origClOrdId;

    return OesApi_SendOrderCancelReq(pOrdChannel, &cancelReq);
}


/**
 * 对执行报告消息进行处理的回调函数
 *
 * @param   pRptChannel     回报通道的会话信息
 * @param   pMsgHead        消息头
 * @param   pMsgItem        消息体数据
 * @param   pCallbackParams 外部传入的参数
 * @return  大于等于0,成功;小于0,失败(错误号)
 */
static inline int32
_OesStkSample_HandleReportMsg(OesApiSessionInfoT *pRptChannel,
        SMsgHeadT *pMsgHead, void *pMsgItem, void *pCallbackParams) {
    OesRspMsgBodyT      *pRspMsg = (OesRspMsgBodyT *) pMsgItem;
    OesRptMsgT          *pRptMsg = &pRspMsg->rptMsg;

    assert(pRptChannel && pMsgHead && pRspMsg);

    switch (pMsgHead->msgId) {
    case OESMSG_RPT_ORDER_INSERT:               /* OES委托已生成 (已通过风控检查) */
        printf(">>> Recv OrdInsertRsp: {clSeqNo: %d, clOrdId: %lld}\n",
                pRptMsg->rptBody.ordInsertRsp.clSeqNo,
                pRptMsg->rptBody.ordInsertRsp.clOrdId);
        break;

    case OESMSG_RPT_BUSINESS_REJECT:            /* OES业务拒绝 (未通过风控检查等) */
        printf(">>> Recv OrdRejectRsp: {clSeqNo: %d, ordRejReason: %d}\n",
                pRptMsg->rptBody.ordRejectRsp.clSeqNo,
                pRptMsg->rptHead.ordRejReason);
        break;

    case OESMSG_RPT_ORDER_REPORT:               /* 交易所委托回报 (包括交易所委托拒绝、委托确认和撤单完成通知) */
        printf(">>> Recv OrdCnfm: {clSeqNo: %d, clOrdId: %lld}\n",
                pRptMsg->rptBody.ordCnfm.clSeqNo,
                pRptMsg->rptBody.ordCnfm.clOrdId);
        break;

    case OESMSG_RPT_REPORT_SYNCHRONIZATION:     /* 回报同步响应 */
    case ...:
         ...
    }

    return 0;
}


/**
 * 回报采集处理 (可以做为线程的主函数运行)
 *
 * @param   pRptChannel     回报通道的会话信息
 * @return  TRUE 处理成功; FALSE 处理失败
 */
void*
OesStkSample_ReportThreadMain(OesApiClientEnvT *pClientEnv) {
    static const int32  THE_TIMEOUT_MS = 1000;

    OesApiSessionInfoT  *pRptChannel = &pClientEnv->rptChannel;
    int32               ret = 0;

    while (1) {
        /* 等待回报消息到达, 并通过回调函数对消息进行处理 */
        ret = OesApi_WaitReportMsg(pRptChannel, THE_TIMEOUT_MS,
                _OesApiSample_HandleReportMsg, NULL);
        if (__spk_unlikely(ret < 0)) {
            if (__spk_likely(SPK_IS_NEG_ETIMEDOUT(ret))) {
                /* 执行超时检查 (检查会话是否已超时) */
                if (__spk_likely(_OesApiSample_OnTimeout(pClientEnv) == 0)) {
                    continue;
                }

                /* 会话已超时 */
                goto ON_ERROR;
            }

            if (SPK_IS_NEG_EPIPE(ret)) {
                /* 连接已断开 */
            }
            goto ON_ERROR;
        }
    }

    return (void *) TRUE;

ON_ERROR:
    return (void *) FALSE;
}

1.2 示例代码的编译和运行

  1. 进入样例代码目录

    • cd oes_libs-xxx/samples/oes_sample_c
  2. 编译代码

    • make -f Makefile.sample
  3. 修改配置文件,确认服务地址、用户名等正确

    • vi oes_client_sample.conf
  4. 运行样例程序

    • ./01_oes_client_stock_sample
    • ./02_oes_client_option_sample
    • ./03_oes_async_api_sample
    • ./04_oes_stk_query_sample
    • ./05_oes_opt_query_sample
    • ./08_oes_async_client_credit_sample
    • ./10_oes_async_crd_query_sample

版本升级指引及修改历史

  • 版本升级指引参见 <@ref update_guide>
  • 版本修改历史参见 <@ref changelog>

常见问题

  • 价格和金额单位

    • OES中的所有价格均为int32类型的整型数值,单位精确到元后四位,即: 1元=10000
    • OES中的所有金额均为int64类型的整型数值,单位精确到元后四位,即: 1元=10000
  • 份额单位

    • OES中的所有委托数量、成交数量等份额单位均为int32int64类型的整型数值,不带小数位
    • OES中债券交易的份额单位是 <b>'张'</b>,股票交易份额单位是 <b>'股'</b>
  • 报价单位不在合法区间?

    • OES中的所有价格均为int32类型的整型数值,单位精确到元后四位,即: 1元=10000
  • 怎么分辨出查询返回的最后一条记录?

OesApi_QueryOrder是同步函数,它返回了代表查询到的所有委托信息回调完成,在Action_OnQryOrdItem 回调函数中没有想过最后一条的标识,返回值>=0代表查询到的记录数量。

  • 如何查看OrdRejectRsp的拒绝原因?

用OesApi_GetErrorMsg(rptHead.ordRejReason)去获取相关错误信息,消息头中的status、detailStatus 主要返回通信层的错误。

  • clEnvId 作用?
    • clEnvId 是客户端环境号,用于区分不同客户端实例上报的委托。即可以为每个客户端实例分配不同的 clEnvId,这样这些客户端实例就可以各自维护自己的 clSeqNo 而不会相互干扰
    • 不同客户端实例可以使用同一 clEnvId 登录服务端。此时这些使用了同一 clEnvId 的客户端实例共享同一个 clSeqNo 序列
    • clEnvId 客户端的取值范围是 [0~99] ([100~127] 为保留区间,客户端应避免使用)
    • 可以通过 OesApi_GetClEnvId() 接口获得本客户端实例绑定的 clEnvId
    • 服务端维护的委托信息中,会记录发送此委托的源客户端实例所绑定的 clEnvId。委托回报消息(OesOrdCnfmT.clEnvId) 和 委托查询应答(OesOrdItemT.clEnvId) 会携带此信息
    • 配置文件相关设置请参考 oes_client_sample.conf 中 [oes_client].clEnvId 参数的设置

OES错误码表

错误码错误说明
1001报文格式错误
1002当前主机不是主节点
1003主存库操作失败
1004因状态等基础数据不匹配,无法更新数据
1005协议版本不兼容
1006数据不存在
1007非服务开放时间
1008非法的定位游标
1009非法的客户端登录用户名称
1010非法的证券代码
1011非法的客户代码
1012非法的客户端类型
1013客户端已被禁用
1014客户端密码不正确
1015客户端重复登录
1016客户端连接数量过多
1017客户端未经授权操作他人账户
1018数据超出修改范围
1019非法的应用系统名称
1020请求条件有冲突
1021非法的客户端IP/MAC地址格式
1022尚不支持或尚未开通此业务
1023非法的客户端环境号
1024交易所拒绝
1025主柜拒绝
1026流量超出限制范围
1027禁止使用API登录
1028非法的私募基金产品代码
1029密码未改变
1030非法的来源分类
1031非法的加密类型
1032非法的客户端设备序列号
1033无可用节点
1034密码强度不足
1035非法的产品类型
1036未通过黑白名单检查
1037集群编号不匹配
1038无此操作权限
1039非法的指令类型
1040数据已存在
1041需要再次尝试
1042非法的委托方式
1101登录柜台失败
1102上报至柜台失败
1103从柜台获取状态失败
1201非法的证券账户代码
1202非法的资金账户代码
1203非法的出入金方向
1204非法的市场代码
1205非法的证券类别
1206非法的买卖类型
1207非法的币种
1208非法的委托类型
1209无效的账户状态
1210未找到委托信息
1211未找到持仓信息
1212未找到出入金流水
1213流水号重复
1214当前时段不能报价
1215没有操作权限
1216可用/可取资金余额不足
1217可用持仓不足
1218委托数量不在合法区间内
1219非数量单位的整数倍
1220非法的PBU代码
1221价格不在合法区间内
1222非价格单位的整数倍
1223无涨停价市价委托失败
1224当前时段不支持市价委托
1225无效的订单状态
1226撤单信息与原始委托不符
1227重复撤单
1228未通过限仓检查
1229未通过限购检查
1230超过了ETF最大现金替代比例
1232证券禁止交易或已收盘
1233合约限制开仓
1234当日累计申购或赎回数量超过限额
1235当日累计净申购或净赎回数量超过限额
1236找不到前收盘价
1237超过报撤比限制
1238委托请求过于频繁
1239非法的出入金转账金额
1240重复的认购委托
1241认购委托份数超过认购额度
1243禁止同时做多笔出入金
1244非法的新股配号、中签记录类型
1245限制股东账户进行买交易
1246限制股东账户进行卖交易
1247限制股东账户进行逆回购交易
1248限制股东账户进行新股认购交易
1249不支持市价委托或账户无市价委托的交易权限
1250股东账户没有交易创业板核准制证券的权限
1251股东账户没有交易分级基金的权限
1252股东账户没有债券合格投资者的权限
1253客户风险评级低于交易证券需求的风险等级
1254股东账户没有交易风险警示证券的权限
1255股东账户没有交易退市整理证券的权限
1256股东账户没有交易单市场ETF的权限
1257股东账户没有交易跨市场ETF的权限
1258股东账户没有交易货币ETF的权限
1259股东账户没有交易跨境ETF的权限
1260仅允许合格投资者投资该证券
1261仅允许合格机构投资者投资该证券
1262出入金执行异常,待人工干预
1263交易日不在证券的发行期内
1264该ETF禁止申购
1265该ETF禁止赎回
1266限制股东账户进行撤指定
1267限制股东账户进行转托管
1268机构客户/主柜业务不支持银行转帐
1269禁止私募基金产品交易此证券
1270禁止客户交易此证券
1271股东账户没有交易存托凭证的权限
1272股东账户没有交易创新企业股票的权限
1273非法的出入金转账类型
1274股东账户没有交易沪伦通存托凭证的权限
1275股东账户没有交易科创板的权限
1276限制交易上交所新债券平台
1277营业部委托流水号超出有效范围
1278结算单未确认
1279结算单重复确认
1280有未成交的卖出委托时禁止买入
1281有未成交的买入委托时禁止卖出
1282客户当日交易总量超出限制
1283委托数量超出报备的单笔委托数量限制
1284投资者未进行程序化交易报备
1285股东账户没有交易债券ETF的权限
1286股东账户没有交易黄金ETF的权限
1287股东账户没有交易商品期货ETF的权限
1288股东账户没有交易创业板注册制证券的权限
1289股东账户没有交易可转换公司债券的权限
1290股东账户没有交易基础设施基金的权限
1291限制入金
1292限制出金
1293无可用现货系统节点
1294无可用对端系统节点
1295对端限制入金
1296对端限制出金
1297禁止ETF申购
1298禁止ETF赎回
1299股东账户没有交易公司债/企业债的权限
1331非法的持仓类型
1332合约限制开仓
1333客户权利仓持仓限额不足
1334客户总持仓限额不足
1335客户单日买入开仓限额不足
1336客户买入额度不足 (限购)
1337券商总持仓限额不足
1338券商总保证金额度不足
1339非法的标的锁定指令类型
1340禁止买入开仓
1341禁止卖出平仓
1342禁止卖出开仓
1343禁止买入平仓
1344禁止备兑开仓
1345禁止备兑平仓
1346禁止标的锁定
1347禁止标的解锁
1348禁止期权行权
1349非行权日
1401保证金可用余额不足
1402可用还款资金不足
1403客户可用两融总额度不足
1404券商可用两融总额度不足
1405客户可用融资额度不足
1406券商可用融资额度不足
1407客户可用融券额度不足
1408券商可用融券额度不足
1409可用融资头寸不足
1410可用融券头寸不足
1411无可用融资头寸
1412无可用融券头寸
1413非法的头寸性质
1414单笔委托融资金额超上限
1415单笔委托融券规模超上限
1416禁止担保品转入
1417禁止担保品转出
1418禁止融资买入
1419禁止卖券还款
1420禁止直接还款
1421禁止融券卖出
1422禁止买券还券
1423禁止直接还券
1424禁止董监高或大股东的融资融券交易
1425禁止提交限售股份为担保物
1426禁止个人投资者提交解除限售存量股份为担保物
1427禁止大小非开展该证券的融资融券交易
1428禁止其他股东角色开展该证券的融资融券交易
1429无效的担保品状态
1430非担保证券
1431非融资标的证券
1432非融券标的证券
1433非融资负债
1434非融券负债
1435非法的融资融券负债类型
1436非法的融资融券归还模式
1437非法的担保证券划转指令类型
1438无可归还的负债
1439不能归还当日开仓的合约
1440不能归还已了结的合约
1441指定合约的负债证券非委托归还的证券
1442还券数量超过融券合约待归还数量
1443未找到融资融券合约信息
1444未通过维保比检查
1445申报价格不得低于最近成交价
1446信用合同不存在或者状态异常
1447信用客户处于监管黑名单
1448券商深圳市场融资融券专用交易单元未配置
1449不能偿还非临近到期日负债
1450可转出资产不足
15xx未通过集中度检查