开始之前,强烈建议阅读下官方出的API接口说明,是个.chm文件,在上期技术官网可以找到,就在api接口下载页那里。P.S.simnow自22年7月8日起关闭一个月,上期技术官网也关闭了。。。
一.接口的使用方法
API&SPI行情接口分为两大块:CThostFtdcMdApi和CthostFtdcMdspi,前者提供了行情api的初始化,登录,订阅等功能;后者提供了行情相关的回调接口,用户需要继承该类并重载这些接口,以获取响应数据。
打开头文件的样子:
如何使用无论是行情接口还是接口,大部分功能都有对应的回调函数,例如API中的SubscribeMarketData,这个函数功能是订阅行情,如果要使用这个功能的话需要在程序调用之后重载它的回调函数OnRspSubMarketData,然后再重载OnRtnDepthMarketData,就可以收到深度行情了,重载OnRtnDepthMarketData时可以选择获得什么数据。所有的回调函数对应的功能都可以在API接口说明中找到。
二.接口代码
把行情接口的头文件和源文件准备好在项目中建好main.cpp,MdApi.cpp还有MdApi.h。
先在MdApi.h中把要重载的行情接口写好,参数在接口说明中可以找到。
//MdSpi.h
#pragma once
#include"../sdk/ThostFtdcMdApi.h"
#include <stdio.h>
#include <Windows.h>
//链接库
#pragma comment (lib, "thostmduserapi_se.lib")
#pragma comment (lib, "thosttraderapi_se.lib")
#pragma warning(disable : 4996)
using namespace std;
//MdApi继承了CThostFtdcMdSpi类,并且重载了OnRtnDepthMarketData等接口
class MdApi :public CThostFtdcMdSpi
{
public:
// 当客户端与交易后台建立起通信连接时(还未登录前),该方法被调用。在Init()之后,被重载的话就会调用他
void OnFrontConnected();
//在发送登录请求之后,还需要重载回调函数 OnRspUserLogin 接收登陆信息。
//注意如果登录的本机ip在当前交易日没有登录过交易系统,那么直接行情登录的话会报错,返回“不合法的登录”
void OnRspUserLogin(CThostFtdcRspUserLoginField* pRspUserLogin, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);
//订阅行情应答,调用SubscribeMarketData后,通过此接口返回。
void OnRspSubMarketData(CThostFtdcSpecificInstrumentField* pSpecificInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);
//订阅深度行情,包括最新价,昨持仓量等等
void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField* pDepthMarketData);
};
在main.cpp中创建CThostFtdcMdApi实例,并连接到simnow的服务器地址,simnow是上期技术的仿真平台。建议连接之前ping一下simnow的地址,有时候会关闭。最近一次是从2022年7月8日起,关闭一个月。
//main.cpp
#include <stdio.h>
#include <iostream>
#include <../sdk/ThostFtdcMdApi.h>
#include "MdApi.h"
using namespace std;
//链接库
#pragma comment(lib,"thostmduserapi_se.lib")
#pragma comment(lib,"thosttraderapi_se.lib")
CThostFtdcMdApi* m_MdApi;
//行情接口
void MDconnect()
{
m_MdApi = CThostFtdcMdApi::CreateFtdcMdApi();//通过CreateFtdcMdApi创建了一个API实例,将他赋值给m_MdApi
CThostFtdcMdSpi* MdSpi = new MdApi; //建立了一个Spi实例--->MdSpi 这里的MdApi在MdApi.h里创建的类
m_MdApi->RegisterSpi(MdSpi);//通过RegisterSpi将API(m_MdApi)和SPI(MdSpi)绑定
m_MdApi->RegisterFront("tcp://180.168.146.187:10211");//注册了前置地址以便与服务器连接。
m_MdApi->Init();//调用 Init() 函数开始正式初始化 api,也就是说前面的工作只是准备工作,到了这里 api 才真正开始工作。此时 api 会向之前注册的地址发起与 CTP 前置的连接
m_MdApi->Join();
}
int main(){
MDconnect();
system("pause");
}
最后在MdApi.cpp中进行重载
//MdApi.cpp
#include <iostream>
#include "MdApi.h"
using namespace std;
extern CThostFtdcMdApi* m_MdApi;//声明全局变量 m_MdApi,也就是在main,cpp中创建的 Api 实例
//登录代码直接写在了 OnFrontConnected 中,那么这也就意味着,一旦建立网络连接成功,调用 OnFrontConnected 之后便会进行登录操作
void MdApi::OnFrontConnected()
{
//如果这里没有输出,那么去检查RegisterFront的地址对不对,ping一下
cout << "网络链接链接成功" << endl;
//开始登录,如果是simnow账号,如果是第一次登录,需要修改密码(ReqUserPasswordUpdate)
CThostFtdcReqUserLoginField req; //创建了一个 CThostFtdcReqUserLoginField 类型的对象
memset(&req, 0, sizeof(req));//初始化登录数据
strcpy(req.BrokerID, ""); //simnow是9999
strcpy(req.UserID, ""); //去simnow注册个账号
strcpy(req.Password, "");
static int iRequestID = 0;
//调用登录,然后就要重载OnRspUserLogin来进行登录
int iResult = m_MdApi->ReqUserLogin(&req, iRequestID++);
if (!iResult)
cout << "发送登录请求成功" << endl;
else
cerr << "发送登录请求失败" << endl;
}
void MdApi::OnRspUserLogin(CThostFtdcRspUserLoginField* pRspUserLogin, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
bool bResult = pRspInfo && (pRspInfo->ErrorID != 0);
if (!bResult) {
cout << "账户登录成功" << endl;
cout << "交易日: " << pRspUserLogin->TradingDay << endl;
//开始订阅行情,注意别写错合约了,当然你也可以写外面
char* iInstrumentID[] = { "i2201" ,"cu2201" };
int iCount = sizeof(iInstrumentID) / sizeof(iInstrumentID[0]);
m_MdApi->SubscribeMarketData(iInstrumentID, iCount);//SubscribeMarketData(char **ppInstrument,int nCount)
}
else
cerr << "返回错误--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << endl;
}
void MdApi::OnRspSubMarketData(CThostFtdcSpecificInstrumentField* pSpecificInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
bool bResult = pRspInfo && (pRspInfo->ErrorID != 0);
if (!bResult) {
cout << "订阅行情成功" << endl;
cout << "合约代码: " << pSpecificInstrument->InstrumentID << endl;
}
else
cerr << "返回错误--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << endl;
}
void MdApi::OnRtnDepthMarketData(CThostFtdcDepthMarketDataField* pDepthMarketData)
{
//有很多数据,可以自己选择要接受那些
cout << "=====获得深度行情成功=====" << endl;
cout << "合约代码:" << pDepthMarketData->InstrumentID << endl;
cout << "最新价:" << pDepthMarketData->LastPrice << endl;
cout << "成交量:" << pDepthMarketData->Volume << endl;
}
写完这里就可以运行main.cpp了,但是应该没有输出,因为simnow自2022年7月8号起关闭一个月。只能过段时间再测试了
文章为作者独立观点,不代表 股票程序化软件自动交易接口观点