java调用ctp
1. 利用SWIG将CTP封装成JAVA版本
1.1 参考文章
利用SWIG将CTP封装成JAVA版本
CTP JAVA API(JCTP)编译(利用Swig封装C++动态库)windows版
1.2 环境准备
所有软件都采用最新版本,除vs需要安装,其它只需要解压,jdk、maven和eclipse的配置参考第一章 Java21开发环境配置
swig
:swig-4.1.1.tar.gz,解压到D:\java\swigwin-4.1.1
ctp
:CTP v6.7.2,解压到任意目录,找到目录20230913_traderapi64_se_windows
vs
:Visual Studio 2022 Community,直接安装
1.3 创建JAVA工程
在eclipse里创建一个maven工程:try-ctp
把20230913_traderapi64_se_windows
复制到try-ctp
在20230913_traderapi64_se_windows
新建文件thostapi.i
%module(directors="1") thostapi
%include "various.i"
%apply char **STRING_ARRAY { char *ppInstrumentID[] }
%{
#include "ThostFtdcMdApi.h"
#include "ThostFtdcTraderApi.h"
#include <codecvt>
#include <locale>
#include <vector>
#include <string>
using namespace std;
#ifdef _MSC_VER
const static locale g_loc("zh-CN");
#else
const static locale g_loc("zh_CN.GB18030");
#endif
%}
%typemap(out) char[ANY], char[] {
const std::string &gb2312($1);
std::vector<wchar_t> wstr(gb2312.size());
wchar_t* wstrEnd = nullptr;
const char* gbEnd = nullptr;
mbstate_t state = {};
int res = use_facet<codecvt<wchar_t, char, mbstate_t> >
(g_loc).in(state,
gb2312.data(), gb2312.data() + gb2312.size(), gbEnd,
wstr.data(), wstr.data() + wstr.size(), wstrEnd);
if (codecvt_base::ok == res) {
wstring_convert<codecvt_utf8<wchar_t>> cutf8;
std::string result = cutf8.to_bytes(wstring(wstr.data(), wstrEnd));
$result=JCALL1(NewStringUTF,jenv,result.c_str());
} else {
std::string result;
$result=JCALL1(NewStringUTF,jenv,result.c_str());
}
}
%feature("director") CThostFtdcMdSpi;
%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;
%include "ThostFtdcUserApiDataType.h"
%include "ThostFtdcUserApiStruct.h"
%include "ThostFtdcMdApi.h"
%feature("director") CThostFtdcTraderSpi;
%include "ThostFtdcTraderApi.h"
从D:\java\swigwin-4.1.1\Lib\java
复制various.i
到20230913_traderapi64_se_windows
E:\eclipse-workspace\tryto\try-ctp\20230913_traderapi64_se_windows
文件清单如下:
error.dtd
error.xml
thostapi.i
ThostFtdcMdApi.h
ThostFtdcTraderApi.h
ThostFtdcUserApiDataType.h
ThostFtdcUserApiStruct.h
thostmduserapi_se.dll
thostmduserapi_se.lib
thosttraderapi_se.dll
thosttraderapi_se.lib
various.i
1.4 用swig生成代码
在命令行运行swig在20230913_traderapi64_se_windows
生成thostapi_wrap.cpp
和thostapi_wrap.h
,同时在E:\eclipse-workspace\tryto\try-ctp\src\main\java\fun\tryto\ctp
生成大量java文件
PS E:\eclipse-workspace\tryto\try-ctp\20230913_traderapi64_se_windows> D:\java\swigwin-4.1.1\swig.exe -c++ -java -package fun.tryto.ctp -outdir E:\eclipse-workspace\tryto\try-ctp\src\main\java\fun\tryto\ctp -o thostapi_wrap.cpp thostapi.i
ThostFtdcMdApi.h(30) : Warning 514: Director base class CThostFtdcMdSpi has no virtual destructor.
ThostFtdcTraderApi.h(30) : Warning 514: Director base class CThostFtdcTraderSpi has no virtual destructor.
PS E:\eclipse-workspace\tryto\try-ctp\20230913_traderapi64_se_windows>
1.5 用vs创建java可以调用的dll动态库
打开Visual Studio 2022,创建新项目
选择“控制台应用”,下一步,项目名称:thostapi_wrap,位置:E:\eclipse-workspace\tryto\try-ctp\,勾选将解决方案和项目放在同一目录中,点击“创建”
创建项目后,在项目上右键-属性,“常规-配置类型”,选择dll,“C/C+±代码生成-运行库”,选择多线程(/MT)
完成之后,将E:\eclipse-workspace\tryto\try-ctp\20230913_traderapi64_se_windows
里的文件拷贝到thostapi_wrap
文件夹下,清单如下:
thostapi_wrap.cpp
thostapi_wrap.h
ThostFtdcMdApi.h
ThostFtdcTraderApi.h
ThostFtdcUserApiDataType.h
ThostFtdcUserApiStruct.h
thostmduserapi_se.lib
thosttraderapi_se.lib
右键头文件,添加现有项,添加5个h文件
右键资源文件,添加现有项,添加两个lib文件
工具栏,选择release x64,ctrl+F5
,生成的代码位于E:\eclipse-workspace\tryto\try-ctp\thostapi_wrap\x64\Release
生成开始于 16:36...
1>------ 已启动生成: 项目: thostapi_wrap, 配置: Release x64 ------
1>thostapi_wrap.cpp
1> 正在创建库 E:\eclipse-workspace\tryto\try-ctp\thostapi_wrap\x64\Release\thostapi_wrap.lib 和对象 E:\eclipse-workspace\tryto\try-ctp\thostapi_wrap\x64\Release\thostapi_wrap.exp
1>正在生成代码
1>0 of 13441 functions ( 0.0%) were compiled, the rest were copied from previous compilation.
1> 0 functions were new in current compilation
1> 0 functions had inline decision re-evaluated but remain unchanged
1>已完成代码的生成
1>thostapi_wrap.vcxproj -> E:\eclipse-workspace\tryto\try-ctp\thostapi_wrap\x64\Release\thostapi_wrap.dll
========== 生成: 1 成功,0 失败,0 最新,0 已跳过 ==========
========== 生成 于 16:36 完成,耗时 05.836 秒 ==========
复制thostapi_wrap.dll到E:\eclipse-workspace\tryto\try-ctp\lib
从E:\eclipse-workspace\tryto\try-ctp\20230913_traderapi64_se_windows复制两个dll到E:\eclipse-workspace\tryto\try-ctp\lib
至此所有文件生成完毕。
2. 在java工程里编写测试案例
案例是用的是sinow模拟账户,运行TestAPI需要配置vm参数:-Djava.library.path=E:\eclipse-workspace\tryto\try-ctp\lib
直接运行会报错UnsatisfiedLinkError
public class TestAPI {
static {
System.loadLibrary("thostmduserapi_se");
System.loadLibrary("thosttraderapi_se");
System.loadLibrary("thostapi_wrap");
}
public static void main(String[] args) {
CThostFtdcTraderApi api = CThostFtdcTraderApi.CreateFtdcTraderApi();
TraderSpiImpl spi = new TraderSpiImpl(api);
api.RegisterSpi(spi);
api.RegisterFront("tcp://180.168.146.187:10130");
api.SubscribePublicTopic(THOST_TE_RESUME_TYPE.THOST_TERT_RESTART);
api.SubscribePrivateTopic(THOST_TE_RESUME_TYPE.THOST_TERT_RESTART);
api.Init();
api.Join();
api.Release();
return;
}
}
public class TraderSpiImpl extends CThostFtdcTraderSpi {
final static String m_BrokerId = "9999";
final static String m_UserId = "xxxxxxxxxxx";//手机号
final static String m_InvestorId = "xxxxxx";
final static String m_AccountId = "xxxxxxxxxxx";//手机号
final static String m_appID = "simnow_client_test";
final static String m_appCode = "0000000000000000";
final static String m_PassWord = "xxxxxxxx";
private List<String> ListExchanges = new ArrayList<String>();
private List<String> ListProducts = new ArrayList<String>();
private List<String> ListInstruments = new ArrayList<String>();
TraderSpiImpl(CThostFtdcTraderApi traderapi) {
m_traderapi = traderapi;
}
@Override
public void OnFrontConnected() {
Console.log("OnFrontConnected");
CThostFtdcReqAuthenticateField clientAuth = new CThostFtdcReqAuthenticateField();
clientAuth.setBrokerID(m_BrokerId);
clientAuth.setUserID(m_UserId);
clientAuth.setAppID(m_appID);
clientAuth.setAuthCode(m_appCode);
clientAuth.setUserProductInfo(m_appID);
int b = m_traderapi.ReqAuthenticate(clientAuth, 0);
Console.log("b:" + b);
Console.log("Send auth ok");
}
@Override
public void OnRspAuthenticate(CThostFtdcRspAuthenticateField field, CThostFtdcRspInfoField pRspInfo, int nRequestID, boolean bIsLast) {
Console.log("OnRspAuthenticate:{}:{}:{}", bIsLast, JSONUtil.toJsonStr(field), JSONUtil.toJsonStr(pRspInfo));
if (pRspInfo != null && pRspInfo.getErrorID() != 0) {
System.out.printf("Auth ErrorID[%d] ErrMsg[%s]\n", pRspInfo.getErrorID(), pRspInfo.getErrorMsg());
return;
}
Console.log("Auth success!!!");
CThostFtdcReqUserLoginField userLogin = new CThostFtdcReqUserLoginField();
userLogin.setBrokerID(m_BrokerId);
userLogin.setUserID(m_InvestorId);
userLogin.setPassword(m_PassWord);
userLogin.setUserProductInfo("JAVA_API");
int a = m_traderapi.ReqUserLogin(userLogin, 1);
Console.log("a:" + a);
Console.log("Send login ok");
}
@Override
public void OnRspUserLogin(CThostFtdcRspUserLoginField pRspUserLogin, CThostFtdcRspInfoField pRspInfo, int nRequestID, boolean bIsLast) {
Console.log("OnRspUserLogin:{}:{}:{}", bIsLast, JSONUtil.toJsonStr(pRspUserLogin), JSONUtil.toJsonStr(pRspInfo));
if (pRspInfo != null && pRspInfo.getErrorID() != 0) {
System.out.printf("Login ErrorID[%d] ErrMsg[%s]\n", pRspInfo.getErrorID(), pRspInfo.getErrorMsg());
return;
}
Console.log(pRspUserLogin);
Console.log("Login success!!!");
CThostFtdcQryExchangeField pQryExchange = new CThostFtdcQryExchangeField();
int b = m_traderapi.ReqQryExchange(pQryExchange, 1);
Console.log("b:" + b);
}
@Override
public void OnRspQryExchange(CThostFtdcExchangeField exchange, CThostFtdcRspInfoField pRspInfo, int nRequestID, boolean bIsLast) {
Console.log("OnRspQryExchange:{}:交易所代码={},交易所名称={}", bIsLast, exchange.getExchangeID(), exchange.getExchangeName());
ListExchanges.add(exchange.toString());
if (bIsLast) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
CThostFtdcQryProductField pQryProduct = new CThostFtdcQryProductField();
int c = m_traderapi.ReqQryProduct(pQryProduct, 2);
}
}
@Override
public void OnRspQryProduct(CThostFtdcProductField product, CThostFtdcRspInfoField pRspInfo, int nRequestID, boolean bIsLast) {
Console.log("OnRspQryProduct:{}:产品名称={},产品代码={},交易所代码={}", bIsLast, product.getProductName(), product.getProductID(), product.getExchangeID());
ListProducts.add(product.toString());
if (bIsLast) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
CThostFtdcQryInstrumentField pQryInstrument = new CThostFtdcQryInstrumentField();
int d = m_traderapi.ReqQryInstrument(pQryInstrument, nRequestID);
Console.log("d:" + d);
}
}
@Override
public void OnRspQryInstrument(CThostFtdcInstrumentField instrument, CThostFtdcRspInfoField pRspInfo, int nRequestID, boolean bIsLast) {
Console.log("OnRspQryInstrument:{}:合约名称={},合约代码={},产品代码={}", bIsLast, instrument.getInstrumentName(), instrument.getInstrumentID(), instrument.getProductID());
ListInstruments.add(instrument.toString());
}
private CThostFtdcTraderApi m_traderapi;
}