ctp java_上期CTP 封装JAVA API window Swig

本文档详细介绍了如何利用Swig工具将CTP C++ API转换为Java接口,以便Java程序员可以使用。首先,从官方站点下载CTP API并解压,接着安装Swig并配置环境变量。然后,创建两个.i文件(thosttraderapi.i 和 thostmduserapi.i),并在various.i文件中定义类型转换。通过Swig执行命令生成Java接口和对应的cpp文件,接着使用Visual Studio创建DLL项目,将生成的cpp和h文件以及原始API文件添加到项目中。完成编译后,将生成的dll库放在Java JDK的bin目录下,最后编写测试类并实现行情和交易接口,以获取期货合约'rb1710'的价格信息。
摘要由CSDN通过智能技术生成

1 首先在http://www.sfit.com.cn/5_2_DocumentDown.htm 下载CTP  后得到下面这些文件

1064509a26a4b4ecdb1eebc522ca145f.png

2 我们选用32位版本20160606_tradeapi_windows 解压后得到

511cf5af426e253736fd26252e6d009f.png

这其中包括两大部分thostmduserapi和thosttraderapi  其中这个mdxxx的api是管行情获取的,比方说你想得到期货"rb1710"当前价格 bid ask ....就用行情的api,在开盘状态下一秒返回俩tick. 如果想参与交易  就用thosttraderapi相关的. 剩下的.h文件里主要定义了客户端接口使用的业务数据结构,数据类型,接口等等,可以打开里面看看,注释还是很全面的,而且是中文.

然后我们安装Swig 这个自行去sf搜索安装即可,安装好后加入环境变量,这个工具帮我们把C++接口转为JAVA接口.

然后我们找一个32位的JDK安装好,也加入path中.这个如果是java程序员应该是人手一个了.

这些都做完后我们cd到\20160606_tradeapi_windows目录中 新建俩.i后缀的文件 thosttraderapi.i  thostmduserapi.i  然后在建立一个various.i 这个用来定义一些类型转换的代码. 这些.i的文件是供Swig使用的,具体可以参考Swig教程. 如果不熟悉也不影响下一步. 具体代码如下

thosttraderapi.i

%module(directors="1") thosttradeapi

%include "various.i"

%apply char **STRING_ARRAY { char *ppInstrumentID[] }

%{

#include "ThostFtdcTraderApi.h"

%}

%feature("director") CThostFtdcTraderSpi;

%include "ThostFtdcUserApiDataType.h"

%include "ThostFtdcUserApiStruct.h"

%include "ThostFtdcTraderApi.h"

thostmduserapi.i

%module(directors="1") thostmdapi

%include "various.i"

%apply char **STRING_ARRAY { char *ppInstrumentID[] }

%{

#include "ThostFtdcMdApi.h"

%}

%feature("director") CThostFtdcMdSpi;

%include "ThostFtdcUserApiDataType.h"

%include "ThostFtdcUserApiStruct.h"

%include "ThostFtdcMdApi.h"

various.i

/* -----------------------------------------------------------------------------

* See the LICENSE file for information on copyright, usage and redistribution

* of SWIG, and the README file for authors - http://www.swig.org/release.html.

*

* various.i

*

* SWIG Typemap library for Java.

* Various useful typemaps.

* ----------------------------------------------------------------------------- */

/*

* char **STRING_ARRAY typemaps.

* These typemaps are for C String arrays which are NULL terminated.

* char *values[] = { "one", "two", "three", NULL }; // note NULL

* char ** is mapped to a Java String[].

*

* Example usage wrapping:

* %apply char **STRING_ARRAY { char **input };

* char ** foo(char **input);

*

* Java usage:

* String numbers[] = { "one", "two", "three" };

* String[] ret = modulename.foo( numbers };

*/

%typemap(jni) char **STRING_ARRAY "jobjectArray"

%typemap(jtype) char **STRING_ARRAY "String[]"

%typemap(jstype) char **STRING_ARRAY "String[]"

%typemap(in) char **STRING_ARRAY (jint size) {

int i = 0;

size = JCALL1(GetArrayLength, jenv, $input);

#ifdef __cplusplus

$1 = new char*[size+1];

#else

$1 = (char **)calloc(size+1, sizeof(char *));

#endif

for (i = 0; i

jstring j_string = (jstring)JCALL2(GetObjectArrayElement, jenv, $input, i);

const char *c_string = JCALL2(GetStringUTFChars, jenv, j_string, 0);

#ifdef __cplusplus

$1[i] = new char [strlen(c_string)+1];

#else

$1[i] = (char *)calloc(strlen(c_string)+1, sizeof(const char *));

#endif

strcpy($1[i], c_string);

JCALL2(ReleaseStringUTFChars, jenv, j_string, c_string);

JCALL1(DeleteLocalRef, jenv, j_string);

}

$1[i] = 0;

}

%typemap(freearg) char **STRING_ARRAY {

int i;

for (i=0; i

#ifdef __cplusplus

delete[] $1[i];

delete[] $1;

#else

free($1[i]);

free($1);

#endif

}

%typemap(out) char **STRING_ARRAY {

int i;

int len=0;

jstring temp_string;

const jclass clazz = JCALL1(FindClass, jenv, "java/lang/String");

while ($1[len]) len++;

jresult = JCALL3(NewObjectArray, jenv, len, clazz, NULL);

/* exception checking omitted */

for (i=0; i

temp_string = JCALL1(NewStringUTF, jenv, *result++);

JCALL3(SetObjectArrayElement, jenv, jresult, i, temp_string);

JCALL1(DeleteLocalRef, jenv, temp_string);

}

}

%typemap(javain) char **STRING_ARRAY "$javainput"

%typemap(javaout) char **STRING_ARRAY {

return $jnicall;

}

/*

* char **STRING_OUT typemaps.

* These are typemaps for returning strings when using a C char ** parameter type.

* The returned string appears in the 1st element of the passed in Java String array.

*

* Example usage wrapping:

* void foo(char **string_out);

*

* Java usage:

* String stringOutArray[] = { "" };

* modulename.foo(stringOutArray);

* System.out.println( stringOutArray[0] );

*/

%typemap(jni) char **STRING_OUT "jobjectArray"

%typemap(jtype) char **STRING_OUT "String[]"

%typemap(jstype) char **STRING_OUT "String[]"

%typemap(javain) char **STRING_OUT "$javainput"

%typemap(in) char **STRING_OUT($*1_ltype temp) {

if (!$input) {

SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");

return $null;

}

if (JCALL1(GetArrayLength, jenv, $input) == 0) {

SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");

return $null;

}

$1 = &temp;

}

%typemap(argout) char **STRING_OUT {

jstring jnewstring = NULL;

if($1) {

jnewstring = JCALL1(NewStringUTF, jenv, *$1);

}

JCALL3(SetObjectArrayElement, jenv, $input, 0, jnewstring);

}

/*

* char *BYTE typemaps.

* These are input typemaps for mapping a Java byte[] array to a C char array.

* Note that as a Java array is used and thus passeed by reference, the C routine

* can return data to Java via the parameter.

*

* Example usage wrapping:

* void foo(char *array);

*

* Java usage:

* byte b[] = new byte[20];

* modulename.foo(b);

*/

%typemap(jni) char *BYTE "jbyteArray"

%typemap(jtype) char *BYTE "byte[]"

%typemap(jstype) char *BYTE "byte[]"

%typemap(in) char *BYTE {

$1 = (char *) JCALL2(GetByteArrayElements, jenv, $input, 0);

}

%typemap(argout) char *BYTE {

JCALL3(ReleaseByteArrayElements, jenv, $input, (jbyte *) $1, 0);

}

%typemap(javain) char *BYTE "$javainput"

/* Prevent default freearg typemap from being used */

%typemap(freearg) char *BYTE ""

通过观察我们可以发现thostmduserapi里包含的是md的操作所用到的文件 thosttraderapi里包含的是trader操作所需要的文件

建好后我们用Swig去处理一下 以md的为例 执行如下命令

cd .一堆路径.\20160606_tradeapi_windows

swig.exe -c++ -java -package test.thostmduserapi -outdir srcmd -o thostmduserapi_wrap.cpp thostmduserapi.i

其中-java生成java接口 -package是指定包位置 这个大家根据情况自己来即可,-outdir是指定输出cpp代码位置, 这个也自己指定好即可

执行完成后得到了我们刚才命令里-o指定的文件 如下

thostmduserapi_wrap.h

thostmduserapi_wrap.cpp

可以理解成这俩文件是根据thostmduserapi翻译过来的 ,其中cpp文件大概5M左右

同时我们在srcmd目录下得到了一堆.java文件  这些文件对应的就是刚才那些api里的.h文件里的接口和po类等等.

我们做完这一步后 JAVA程序猿即可将这些java类拷贝自己项目里待用了,为了最终通过JNI调用,我们还需要得到thostmduserapi_wrap.dll动态库  这个是根据刚才生成的thosttraderapi_wrap.cpp  和thosttraderapi_wrap.h 还有刚才下载的那些api中md部分生成的,我们可以用下面这个工具来生成dll

0ad8e45232d995a2010b532a9a5a3f42.png\

对于JAVA程序猿 可能压根没用过VS 不过我们也不需要你会C++ 只要会简单的安装VS基本可以搞定了

假设我们安装好了 然后启动VS

Ctrl+Shift+N新建项目->win32项目->名称叫"thostmduserapi_wrap"   然后我们选dll项目 如果

0a2616fbe872665cb7864b2bd45f4455.png

建好后我们把刚才的文件添加到项目中 需要添加的文件如图  添加方法是源文件那右键选添加->现有项

4c2dde06bfb073a2bd312dc3b49cf973.png 基本就是刚才生成的cpp和h 加上之前api里的md相关的文件和头文件

添加好后的项目如图

cafd8878a366c84f491ffe97223c180b.png

然后将你安装jdk目录\Java\jdk1.8.0_111\include下的jni.h和win32文件夹下的jni_md.h, jawt_md.h一共三个文件拷贝到安装vs的include目录底下\Microsoft Visual Studio 12.0\VC\include。这是因为thosttraderapi_wrap.cpp文件中包含了,这是用于生成Java可调用接口的库文件。

然后我们按F7 生成解决方案 可以看到一堆报错的 我们把报错的那些方法都注释掉如图

8183e3d91fb050ffbebe306c1b6e1739.png

就是上面这些 都注释掉 然后重新编译  运气好的话可以得到编译成功 然后在Debug目录可以找到

485a13a99d2ceeed891a38ba87fdfa24.png

取里面的thostmduserapi_wrap.dll 放在刚才32位jdk的bin下方便调用 同时thostmduserapi.dll也放入该目录下,最终目的是确保java中loadLibrary时候可以读取到

------------------------------------------------------------------------------------

相同的操作 请在thosttraderapi也做一遍后得到thosttraderapi_wrap.dll

------------------------------------------------------------------------------------

最终我们jdk里可能有一堆dll

332f5145f1febc0bc85408d6d439884c.png

--------------------------------------------------------------------------------------

以上操作ok后基本就成功了  下面我们写几个测试类 真正获取一下'rb1710'的价位

public class Test {

static{

System.loadLibrary("thosttraderapi");

System.loadLibrary("thosttraderapi_wrap");

System.loadLibrary("thostmduserapi");

System.loadLibrary("thostmduserapi_wrap");

}

final static String ctp1_MdAddress = "tcp://180.168.146.187:10010";

public static void main(String[] args) {

String pszFlowPath = "C:\\out";

CThostFtdcMdApi mdApi = CThostFtdcMdApi.CreateFtdcMdApi(pszFlowPath,true);

MdSpiImpl mdSpi = new MdSpiImpl(mdApi);

mdApi.RegisterSpi(mdSpi);

mdApi.RegisterFront(ctp1_MdAddress);

mdApi.Init();

mdApi.Join();

return;

}

}

/**

* Created by

*/

public class MdSpiImpl extends CThostFtdcMdSpi {

final static String m_BrokerId = "9999";

final static String m_UserId = "123456";

final static String m_InvestorId = "123456";

final static String m_PassWord = "123456";

private static final String LINE_SEPARATOR = System.getProperty("line.separator");

MdSpiImpl(CThostFtdcMdApi mdApi)

{

m_mdapi = mdApi;

}

private CThostFtdcMdApi m_mdapi;

@Override

public void OnFrontConnected() {

/*

客户端到行情前置的无身份验证连接建立之后,这个函数会被调用,用于说明连接已经建立。连接建立之后,才能请求登录

*/

super.OnFrontConnected();

System.out.println("On Front Connected");

test.thostmduserapi.CThostFtdcReqUserLoginField field = new test.thostmduserapi.CThostFtdcReqUserLoginField();

field.setBrokerID(m_BrokerId);

field.setUserID(m_UserId);

field.setPassword(m_PassWord);

field.setUserProductInfo("JAVA_API");

m_mdapi.ReqUserLogin(field, 0);

System.out.println("Send login ok");

//连接成功后获取下这俩的价格信息

String[] ppInstrumentID = new String[2];

ppInstrumentID[0] = "rb1710";

ppInstrumentID[1] = "hc1710";

int i = m_mdapi.SubscribeMarketData(ppInstrumentID,2);

System.out.println(i);

}

@Override

public void OnFrontDisconnected(int nReason) {

/*

如果客户端到行情前置的无身份验证连接建立失败,这个函数被调用。其中的参数说明连接失败的原因

*/

super.OnFrontDisconnected(nReason);

System.out.println("连接失败!!!" + nReason);

}

/*

交易系统对客户端的请求登录消息作出的响应

*/

@Override

public void OnRspUserLogin(CThostFtdcRspUserLoginField pRspUserLogin, CThostFtdcRspInfoField pRspInfo, int nRequestID, boolean bIsLast) {

//super.OnRspUserLogin(pRspUserLogin, pRspInfo, nRequestID, bIsLast);

if (pRspInfo != null && pRspInfo.getErrorID() != 0)

{

System.out.printf("Login ErrorID[%d] ErrMsg[%s]\n", pRspInfo.getErrorID(), pRspInfo.getErrorMsg());

return;

}

System.out.println("Login success!!!");

System.out.println("BrokerID:" + pRspUserLogin.getBrokerID());

System.out.println("CZCETime:"+pRspUserLogin.getCZCETime());

System.out.println("MaxOrderRef:"+pRspUserLogin.getMaxOrderRef());

System.out.println("UserID:"+pRspUserLogin.getUserID());

System.out.println("FrontID:"+pRspUserLogin.getFrontID());

System.out.println("SessionID:"+pRspUserLogin.getSessionID());

System.out.println("SystemName:" + pRspUserLogin.getSystemName());

}

/**

* 交易核心认为客户端请求订阅行情的消息不合法时通过这个函数返回错误信息。订阅请求合法时,也会调用,返回错误代码为 0

* @param pSpecificInstrument

* @param pRspInfo

* @param nRequestID

* @param bIsLast

*/

@Override

public void OnRspSubMarketData(CThostFtdcSpecificInstrumentField pSpecificInstrument, CThostFtdcRspInfoField pRspInfo, int nRequestID, boolean bIsLast) {

System.out.println("OnRspSubMarketData");

super.OnRspSubMarketData(pSpecificInstrument, pRspInfo, nRequestID, bIsLast);

}

/**

* 交易核心认为客户端请求退订行情的消息不合法时通过这个函数返回错误信息

* @param pSpecificInstrument

* @param pRspInfo

* @param nRequestID

* @param bIsLast

*/

@Override

public void OnRspUnSubMarketData(CThostFtdcSpecificInstrumentField pSpecificInstrument, CThostFtdcRspInfoField pRspInfo, int nRequestID, boolean bIsLast) {

System.out.println("OnRspUnSubMarketData");

super.OnRspUnSubMarketData(pSpecificInstrument, pRspInfo, nRequestID, bIsLast);

}

/**

* 通过这个函数返回行情信息。频率是每秒两次

* @param pDepthMarketData

*/

@Override

public void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField pDepthMarketData) {

System.out.println("%"+pDepthMarketData.getInstrumentID()+"AskPrice1:"+pDepthMarketData.getAskPrice1()+"&&&&&&BidPrice1:"+pDepthMarketData.getBidPrice1());

}

/**

* 如果交易系统无法识别客户端发送的请求消息,就通过这个函数返回错误信息

* @param pRspInfo

* @param nRequestID

* @param bIsLast

*/

@Override

public void OnRspError(CThostFtdcRspInfoField pRspInfo, int nRequestID, boolean bIsLast) {

System.out.println("OnRspError");

super.OnRspError(pRspInfo, nRequestID, bIsLast);

}

/**

* 如果超过一定时间在客户端和系统之间没有任何消息交换发生,这个函数会发送心跳用来说明客户端到系统服务器之间的连接是活跃的。

目前此接口已经不再起效

* @param nTimeLapse

*/

@Override

public void OnHeartBeatWarning(int nTimeLapse) {

System.out.println("OnHeartBeatWarning");

super.OnHeartBeatWarning(nTimeLapse);

}

}

上面是一个Test类  和 MdSpi的实现类 具体可以参考上期所给的api文档 虽然是C++的 但对着java代码看也基本是相通的.

正常运行后每秒在控制端打印4行记录 如图

78250cbe8050177aac2d70cb6764c8ba.png

---------------------------------------------------------------------------------------

下面说说测试帐号的获取方式和行情地址等

我们去http://www.simnow.com.cn/   申请一个帐号后得到如下信息

13718b60703aedb53c2fab6207882e4d.png

investorId和userId相同 密码就是你注册的密码  地址在http://www.simnow.com.cn/product.action中可以找到 如下

BrokerID统一为:9999

第一套:

标准CTP:

第一组:Trade Front:180.168.146.187:10000,Market Front:180.168.146.187:10010;【电信】

第二组:Trade Front:180.168.146.187:10001,Market Front:180.168.146.187:10011;【电信】

第三组:Trade Front:218.202.237.33 :10002,Market Front:218.202.237.33 :10012;【移动】

交易阶段(服务时间):与实际生产环境保持一致

我们行情spi就选Market Front中的地址即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值