CTP JAVA API(JCTP)编译(利用Swig封装C++动态库)windows版

12 篇文章 1 订阅
10 篇文章 6 订阅

前言:
目前上期技术CTP系统提供的API版本是C++版本,而很多客户采用Java开发,就产生了一些问题。SWIG是一个能将C/C++接口转换为其他语言的工具,目前可以支持Python,Java,R等语言。
本文主要介绍Windows 32位平台(64位平台请使用对应的软件和API)下利用Swig工具将CTP C++接口API转换为Java可调用的接口。原创不易,欢迎点赞。

0. 欢迎交流

github: https://github.com/nicai0609/JAVA-CTPAPI


1. 准备工作

  • 从CTP官网上下载CTP API点击下载。32位的API文件包清单如下:

error.dtd
error.xml
ThostFtdcMdApi.h
ThostFtdcTraderApi.h
ThostFtdcUserApiDataType.h
ThostFtdcUserApiStruct.h
thostmduserapi.dll
thostmduserapi.lib
thosttraderapi.dll
thosttraderapi.lib

  • 安装Swig软件,本文中所用的Swig是swigwin-2.0.11版本,点击下载
  • 安装JDK,注意要安装32位版本,将环境变量配置好。本文所用的是1.8.0_111版本,点击下载
  • 安装libiconv库。这个库主要适用于字节编码转换,因为CTP的结算单信息是GB2312编码,而Java采用UTF-8编码,如果不进行字节转换,得到的结算单信息中的中文将会是乱码。 本文采用的libiconv版本是自己下载的源码编译的静态库,可至群内直接下载源码自己编译,也可以到我的github libiconv下载编译好的。本文一开始采用的是第三方库libiconv转换,下面也以libiconv为例继续。C++11库中已有字节编码转换方式,采用这种方式可以不用libiconv库,下面和libiconv相关的都可以略去,见《Swig转换C++接口中文乱码解决方案》
  • 安装Eclipse,注意,也需要下载32位版本。主要用与Java demo的测试,点击下载
  • 安装vs2013,主要用于生成包装dll。

2. 通过Swig得到jar包

在刚刚下载得到的API文件夹20180109_tradeapi_windows内,新建文件thosttraderapi.i,内容如下

%module(directors="1") thosttradeapi 
%{ 
#include "ThostFtdcTraderApi.h"
#include "iconv.h"
%}

%typemap(out) char[ANY], char[] {
    if ($1) {
        iconv_t cd = iconv_open("utf-8", "gb2312");
        if (cd != reinterpret_cast<iconv_t>(-1)) {
            char buf[4096] = {};
            char **in = &$1;
            char *out = buf;
            size_t inlen = strlen($1), outlen = 4096;

            if (iconv(cd, in, &inlen, &out, &outlen) != static_cast<size_t>(-1))
                $result = JCALL1(NewStringUTF, jenv, (const char *)buf);
            iconv_close(cd);
        }
    }
}

%feature("director") CThostFtdcTraderSpi; 
%ignore THOST_FTDC_VTC_BankBankToFuture;
%ignore THOST_FTDC_VTC_BankFutureToBank;
%ignore THOST_FTDC_VTC_FutureBankToFuture;
%ignore THOST_FTDC_VTC_FutureFutureToBank;
%ignore THOST_FTDC_FTC_BankLaunchBankToBroker;
%ignore THOST_FTDC_FTC_BrokerLaunchBankToBroker;
%ignore THOST_FTDC_FTC_BankLaunchBrokerToBank;
%ignore THOST_FTDC_FTC_BrokerLaunchBrokerToBank;  
%feature("director") CThostFtdcTraderSpi; 
%include "ThostFtdcUserApiDataType.h"
%include "ThostFtdcUserApiStruct.h" 
%include "ThostFtdcTraderApi.h"  

这是一个接口文件,用于告诉swig为哪些类和方法创建接口。***.i文件的具体解释参考这篇文章《用Swig封装C/C++》。然后在当前目录内建立文件夹srcwraptradeapi32ctp,在ctp文件夹内建立文件夹thosttraderapi。文件夹结构图如下:

20180109_tradeapi_windows

│─── ctp ─── thosttraderapi

│─── tradeapi32

│─── src

│─── wrap

│ ThostFtdcMdApi.h
│ ThostFtdcTraderApi.h
│ ThostFtdcUserApiDataType.h
│ …

打开windows cmd工具,cd到当前目录\20180109_tradeapi_windows下。 在cmd中运行命令

swig.exe -c++ -java -package ctp.thosttraderapi -outdir src -o thosttraderapi_wrap.cpp thosttraderapi.i

这运行可能要持续1分钟,中间会报一次warning 514:...警告,在程序员眼里警告直接忽略:)。等到运行完成后,可以看到当前目录下生成了

thosttraderapi_wrap.h
thosttraderapi_wrap.cpp

这两个文件是用于包装原来C++接口的文件,下面要用。打开src文件夹,可以看到这时在里面生成了一系列方法的java文件,如下:

CThostFtdcAccountregisterField.java
CThostFtdcAuthenticationInfoField.java
… … …
thosttradeapiJNI.java

cmdcdsrc文件夹底下,运行命令

javac *.java

运行结束之后可以看到生成了等量的class文件,将所有的class文件拷贝到\ctp\thosttraderapi\文件夹中,cmdcd20180109_tradeapi_windows目录下,运行命令

jar cf thosttraderapi.jar ctp

这样我们就在当前文件夹下得到了jar包thosttraderapi.jar

3. 通过C++得到java可调用的dll动态库

接下来在wrap文件夹中,建立一个C++工程,工程为Win32控制台应用程序,工程名为thosttraderapi_wrap,点下一步,工程的应用程序类型选DLL,附加选项选空项目。另外建好项目后,在工程属性-c/c+±代码生成-运行库中选多线程(/MT)。步骤图如下:
1)

2)
3)

完成之后,将如下文件拷贝到\wrap\thosttraderapi_wrap文件夹下:

ThostFtdcTraderApi.h
ThostFtdcUserApiDataType.h
ThostFtdcUserApiStruct.h
thosttraderapi.lib
thosttraderapi_wrap.cpp
thosttraderapi_wrap.h
libiconv.lib
iconv.h

c++工程中添加现有项,将这些文件全部添加到工程中去。下面还要做几步:

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

这所有完成之后,C++工程中文件应该如下:

然后选择release版编译。我们按F7编译,在\wrap\thosttraderapi_wrap\Release目录底下可见thosttraderapi_wrap.dll动态库文件,说明编译成功,这样CTP Java API就编译成功了。编译中如果出现error LNK2005: abort 已经在 LIBCMT.lib(abort.obj) 中定义...等错误,可以右击工程 - 属性 ”配置属性 - 链接器 - 命令行” 添加: /NODEFAULTLIB:"libcmt.lib"解决。

4. Java Demo

打开Eclipse,新建traderapidemo工程。

  • 在工程中新建lib文件夹,将刚刚的thosttraderapi.jar包拷贝到该文件夹底下,刷新工程,在工程中jar包上右击选择BuildPath/Add to Build Path将jar包导入到工程。
  • 将如下动态库文件

thosttraderapi.dll
thosttraderapi_wrap.dll

拷贝到你电脑环境变量path路径底下,如果自己不清楚,可以在Java中用如下代码获得

System.out.println(System.getProperty("java.library.path"));

我直接拷贝到了\Java\jdk1.8.0_111底下。
完整的tradeapidemo代码如下:

import ctp.thosttraderapi.*;

class TraderSpiImpl extends CThostFtdcTraderSpi{	
	final static String m_BrokerId = "9999";
	final static String m_UserId = "070624";
	final static String m_InvestorId = "070624";
	final static String m_PassWord = "passwd"; 
	final static String m_TradingDay = "20181122";
	final static String m_AccountId = "070624";
	final static String m_CurrencyId = "CNY";
	TraderSpiImpl(CThostFtdcTraderApi traderapi)
	{
		m_traderapi =  traderapi;
	}
	
	@Override
	public void OnFrontConnected(){
		System.out.println("On Front Connected");
		CThostFtdcReqUserLoginField field = new CThostFtdcReqUserLoginField();
		field.setBrokerID(m_BrokerId);
		field.setUserID(m_UserId);
		field.setPassword(m_PassWord);
		field.setUserProductInfo("JAVA_API");
		m_traderapi.ReqUserLogin(field,0);
		System.out.println("Send login ok");
	}
	
	@Override
	public void OnRspUserLogin(CThostFtdcRspUserLoginField pRspUserLogin, CThostFtdcRspInfoField pRspInfo, int nRequestID, boolean 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!!!");
		CThostFtdcQryTradingAccountField qryTradingAccount = new CThostFtdcQryTradingAccountField();
		qryTradingAccount.setBrokerID(m_BrokerId);
		qryTradingAccount.setCurrencyID(m_CurrencyId);;
		qryTradingAccount.setInvestorID(m_InvestorId);
		m_traderapi.ReqQryTradingAccount(qryTradingAccount, 1);
				
	}
	
	@Override
	public void OnRspQryTradingAccount(CThostFtdcTradingAccountField pTradingAccount, CThostFtdcRspInfoField pRspInfo, int nRequestID, boolean bIsLast) 
	{
		if (pRspInfo != null && pRspInfo.getErrorID() != 0)
		{
			System.out.printf("OnRspQryTradingAccount ErrorID[%d] ErrMsg[%s]\n", pRspInfo.getErrorID(), pRspInfo.getErrorMsg());

			return;
		}
		
		if (pTradingAccount != null)
		{
			System.out.printf("Balance[%f]Available[%f]WithdrawQuota[%f]Credit[%f]\n",
				pTradingAccount.getBalance(), pTradingAccount.getAvailable(), pTradingAccount.getWithdrawQuota(),
				pTradingAccount.getCredit());
		}
		else
		{
			System.out.printf("NULL obj\n");
		}
	}	
	
	private CThostFtdcTraderApi m_traderapi;
}

public class tradeapidemo{

	static{
		System.loadLibrary("thosttraderapi");
		System.loadLibrary("thosttraderapi_wrap");
	}
	final static String ctp1_TradeAddress = "tcp://180.168.146.187:10000";
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		CThostFtdcTraderApi traderApi = CThostFtdcTraderApi.CreateFtdcTraderApi();
		TraderSpiImpl pTraderSpi = new TraderSpiImpl(traderApi);
		traderApi.RegisterSpi(pTraderSpi);
		traderApi.RegisterFront(ctp1_TradeAddress);
		traderApi.SubscribePublicTopic(THOST_TE_RESUME_TYPE.THOST_TERT_RESTART);
		traderApi.SubscribePrivateTopic(THOST_TE_RESUME_TYPE.THOST_TERT_RESTART);
		traderApi.Init();
		traderApi.Join();
		return;
	}
}

行情mdapidemo如下

import ctp.thostmduserapi.*;

class mdspiImpl extends CThostFtdcMdSpi{
	final static String m_BrokerId = "9999";
	final static String m_UserId = "070624";
	final static String m_InvestorId = "070624";
	final static String m_PassWord = "passwd"; 
	final static String m_TradingDay = "20181122";
	final static String m_AccountId = "070624";
	final static String m_CurrencyId = "CNY";
	mdspiImpl(CThostFtdcMdApi mdapi)
	{
		m_mdapi =  mdapi;
	}
	
	public void OnFrontConnected(){
		System.out.println("On Front Connected");
		CThostFtdcReqUserLoginField field = new CThostFtdcReqUserLoginField();
		field.setBrokerID(m_BrokerId);
		field.setUserID(m_UserId);
		field.setPassword(m_PassWord);
		m_mdapi.ReqUserLogin(field, 0);
		
	}
	
	public void OnRspUserLogin(CThostFtdcRspUserLoginField pRspUserLogin, CThostFtdcRspInfoField pRspInfo, int nRequestID, boolean bIsLast) {
		if (pRspUserLogin != null) {
			System.out.printf("Brokerid[%s]\n",pRspUserLogin.getBrokerID());			
		}
		
		String[] instruementid = new String[1];
		instruementid[0]="rb1906";		
		m_mdapi.SubscribeMarketData(instruementid,1);
	}
	
	public void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField pDepthMarketData) {
		if (pDepthMarketData != null)
		{
			System.out.printf("AskPrice1[%f]BidPrice1[%f]\n",
				pDepthMarketData.getAskPrice1(),pDepthMarketData.getBidPrice1());
		}
		else
		{
			System.out.printf("NULL obj\n");
		}
	}	
	private CThostFtdcMdApi m_mdapi;
}

public class MdapiDemo {
	static{
		System.loadLibrary("thostmduserapi");
		System.loadLibrary("thostmduserapi_wrap");
	}
	final static String ctp1_MdAddress = "tcp://180.168.146.187:10031";
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		CThostFtdcMdApi mdApi = CThostFtdcMdApi.CreateFtdcMdApi();
		mdspiImpl pMdspiImpl = new mdspiImpl(mdApi);
		mdApi.RegisterSpi(pMdspiImpl);
		mdApi.RegisterFront(ctp1_MdAddress);
		mdApi.Init();
		mdApi.Join();		
		return;
	}
}

本人所编译的CTP0606版本的交易、行情Java API点击下载。声明:仅是个人爱好编译,对此API引起的您的任何损失不负责任。

各位注意一下,在上传的win32资源中,mdapi里的一个dll上传错了,只要将ctp官网中的“thostmduserapi.dll”替换掉“thosttraderapi.dll”就可以运行了。是我粗心上传错了,抱歉!

  • 23
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 128
    评论
JCTP 0.3.2 2013-2-27 增加:JCTPStructUtil工具类 修正:交易API部分函数出现空指针异常的问题 修正:行情API部分函数出现空指针异常的问题 变更:发布包中增加JCTP.jar *********************************************** JCTP 0.3.1 2013-2-26 修正:交易API部分函数出现空指针异常的问题 *********************************************** JCTP 0.3 2013-2-26 增加:完成对交易API封装 增加:格式化结构体方法注释为javadoc格式(暂未转成中文) 增加:优化结构体属性的调用方式,增加getter/setter方法,隐藏bridj框架代码 修正:解决Bridj框架中一处与CTP接口的兼容问题 修正:解决回调方法中结构体的属性值为中文时出现乱码的问题 变更:移动util包到jctp路径下 变更:发布本号格式更改,缩进1位 *********************************************** JCTP 0.0.2 2013-1-31 增加:JCTPLibraryUtil类,用于初始化CTP环境或卸载CTP环境 增加:JCTPMdApi类,将Bridj调用CTP的代码隐藏 增加:JCTPMdSpi类,将Bridj调用CTP的代码隐藏 增加:JCTPTraderApi类,将Bridj调用CTP的代码隐藏 增加:JCTPTraderSpi类,将Bridj调用CTP的代码隐藏 修正:Spi回调时报空指针,无法进入回调方法的问题 修正:无法调用带参数的CreateFtdc.....Api函数的问题 修正:只能在调试模式下进行回调的问题 变更:CTP动态链接库置入jar包 变更:将JCTP相关类独立出CTP调用包
### 回答1: 上期ctp_api_c源代码.rar是一个包含CTP (中国金融期货交易系统) API的源代码压缩文件。CTP API是为了与中国金融期货交易系统进行交互而开发的一套接口。它允许开发人员通过编程语言来实现与交易系统的通信和交易操作。 该源代码包含了使用C语言编写的CTP API的实现代码。C语言是一种广泛使用的编程语言,非常适合开发高性能的软件。通过研究和理解这份源代码,开发人员可以了解CTP API的具体实现细节,并在此基础上进行二次开发。 该源代码压缩文件通常包含以下内容: 1. CTP API的源代码文件:这些文件包含了CTP API的各个功能模块的具体实现代码,如行情查询、委托下单、成交查询等。开发人员可以通过阅读这些代码来了解CTP API的调用方式和相关参数。 2. 相关的头文件和函数库:这些文件包含了CTP API的函数声明和必要的宏定义等信息。开发人员可以在自己的项目中包含这些头文件并链接相关的函数库来使用CTP API的功能。 3. 示例代码:源代码压缩文件中可能还包含了一些示例代码,用于演示如何使用CTP API进行实际的交易操作。开发人员可以参考这些示例代码来快速上手并进行二次开发。 总而言之,上期ctp_api_c源代码.rar提供了一个基于C语言的CTP API实现的源代码,通过研究和使用该代码,开发人员可以在自己的软件项目中实现与中国金融期货交易系统的交互和交易操作。 ### 回答2: 上期ctp_api_c 源代码.rar 是一个压缩文件,里面包含了ctp_api_c的源代码。ctp_api_c是一个针对中国金融期货交易的API接口库,主要用于开发相关的交易软件。 在这个压缩文件中,我们可以找到所有关于ctp_api_c的源代码文件。这些源代码文件是以.c和.h为后缀的,分别表示源代码和头文件。 在解压缩后的文件夹中,我们可以看到一些主要的文件,如ctp_md.c,ctp_td.c等。这些文件对应着行情数据接口和交易接口的实现。除此之外,还有一些辅助文件,如ctp_common.c,ctp_utils.c等,用于提供一些共用的函数和工具。 通过阅读这些源代码文件,可以了解ctp_api_c的整体架构和各个功能模块的实现细节。其中,会包含一些关于行情订阅、交易下单、账户查询等相关的代码。 值得一提的是,ctp_api_c是基于C语言编写的,因此在阅读这些源代码时,需要对C语言有一定的了解。通过分析和理解这些代码,我们可以更好地理解ctp_api_c的使用方法和原理,并在此基础上进行二次开发,以满足特定的交易需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 128
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值