vnpy/vn.api/vn.ksotp/vnksotpmd/vnksotpmd/vnksotpmd.cpp

870 lines
21 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// vnctpmd.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
#include "vnksotpmd.h"
///-------------------------------------------------------------------------------------
///从Python对象到C++类型转换用的函数
///-------------------------------------------------------------------------------------
void getInt(dict d, string key, int *value)
{
if (d.has_key(key)) //检查字典中是否存在该键值
{
object o = d[key]; //获取该键值
extract<int> x(o); //创建提取器
if (x.check()) //如果可以提取
{
*value = x(); //对目标整数指针赋值
}
}
};
void getDouble(dict d, string key, double *value)
{
if (d.has_key(key))
{
object o = d[key];
extract<double> x(o);
if (x.check())
{
*value = x();
}
}
};
void getChar(dict d, string key, char *value)
{
if (d.has_key(key))
{
object o = d[key];
extract<string> x(o);
if (x.check())
{
string s = x();
const char *buffer = s.c_str();
//对字符串指针赋值必须使用strcpy_s, vs2013使用strcpy编译通不过
//+1应该是因为C++字符串的结尾符号不是特别确定不加这个1会出错
strcpy_s(value, strlen(buffer) + 1, buffer);
}
}
};
///-------------------------------------------------------------------------------------
///C++的回调函数将数据保存到队列中
///-------------------------------------------------------------------------------------
void MdApi::OnFrontConnected()
{
Task task = Task();
task.task_name = ONFRONTCONNECTED;
this->task_queue.push(task);
};
void MdApi::OnFrontDisconnected(int nReason)
{
Task task = Task();
task.task_name = ONFRONTDISCONNECTED;
task.task_id = nReason;
this->task_queue.push(task);
};
void MdApi::OnRspUserLogin(CKSOTPRspUserLoginField *pRspUserLogin, CKSOTPRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
Task task = Task();
task.task_name = ONRSPUSERLOGIN;
if (pRspUserLogin)
{
task.task_data = *pRspUserLogin;
}
else
{
CKSOTPRspUserLoginField empty_data = CKSOTPRspUserLoginField();
memset(&empty_data, 0, sizeof(empty_data));
task.task_data = empty_data;
}
if (pRspInfo)
{
task.task_error = *pRspInfo;
}
else
{
CKSOTPRspInfoField empty_error = CKSOTPRspInfoField();
memset(&empty_error, 0, sizeof(empty_error));
task.task_error = empty_error;
}
task.task_id = nRequestID;
task.task_last = bIsLast;
this->task_queue.push(task);
};
void MdApi::OnRspUserLogout(CKSOTPUserLogoutField *pUserLogout, CKSOTPRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
Task task = Task();
task.task_name = ONRSPUSERLOGOUT;
if (pUserLogout)
{
task.task_data = *pUserLogout;
}
else
{
CKSOTPUserLogoutField empty_data = CKSOTPUserLogoutField();
memset(&empty_data, 0, sizeof(empty_data));
task.task_data = empty_data;
}
if (pRspInfo)
{
task.task_error = *pRspInfo;
}
else
{
CKSOTPRspInfoField empty_error = CKSOTPRspInfoField();
memset(&empty_error, 0, sizeof(empty_error));
task.task_error = empty_error;
}
task.task_id = nRequestID;
task.task_last = bIsLast;
this->task_queue.push(task);
};
void MdApi::OnRspError(CKSOTPRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
Task task = Task();
task.task_name = ONRSPERROR;
if (pRspInfo)
{
task.task_error = *pRspInfo;
}
else
{
CKSOTPRspInfoField empty_error = CKSOTPRspInfoField();
memset(&empty_error, 0, sizeof(empty_error));
task.task_error = empty_error;
}
task.task_id = nRequestID;
task.task_last = bIsLast;
this->task_queue.push(task);
};
void MdApi::OnRspSubMarketData(CKSOTPSpecificInstrumentField *pSpecificInstrument, CKSOTPRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
Task task = Task();
task.task_name = ONRSPSUBMARKETDATA;
if (pSpecificInstrument)
{
task.task_data = *pSpecificInstrument;
}
else
{
CKSOTPSpecificInstrumentField empty_data = CKSOTPSpecificInstrumentField();
memset(&empty_data, 0, sizeof(empty_data));
task.task_data = empty_data;
}
if (pRspInfo)
{
task.task_error = *pRspInfo;
}
else
{
CKSOTPRspInfoField empty_error = CKSOTPRspInfoField();
memset(&empty_error, 0, sizeof(empty_error));
task.task_error = empty_error;
}
task.task_id = nRequestID;
task.task_last = bIsLast;
this->task_queue.push(task);
};
void MdApi::OnRspUnSubMarketData(CKSOTPSpecificInstrumentField *pSpecificInstrument, CKSOTPRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
Task task = Task();
task.task_name = ONRSPUNSUBMARKETDATA;
if (pSpecificInstrument)
{
task.task_data = *pSpecificInstrument;
}
else
{
CKSOTPSpecificInstrumentField empty_data = CKSOTPSpecificInstrumentField();
memset(&empty_data, 0, sizeof(empty_data));
task.task_data = empty_data;
}
if (pRspInfo)
{
task.task_error = *pRspInfo;
}
else
{
CKSOTPRspInfoField empty_error = CKSOTPRspInfoField();
memset(&empty_error, 0, sizeof(empty_error));
task.task_error = empty_error;
}
task.task_id = nRequestID;
task.task_last = bIsLast;
this->task_queue.push(task);
};
void MdApi::OnRspSubForQuoteRsp(CKSOTPSpecificInstrumentField *pSpecificInstrument, CKSOTPRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
Task task = Task();
task.task_name = ONRSPSUBFORQUOTERSP;
if (pSpecificInstrument)
{
task.task_data = *pSpecificInstrument;
}
else
{
CKSOTPSpecificInstrumentField empty_data = CKSOTPSpecificInstrumentField();
memset(&empty_data, 0, sizeof(empty_data));
task.task_data = empty_data;
}
if (pRspInfo)
{
task.task_error = *pRspInfo;
}
else
{
CKSOTPRspInfoField empty_error = CKSOTPRspInfoField();
memset(&empty_error, 0, sizeof(empty_error));
task.task_error = empty_error;
}
task.task_id = nRequestID;
task.task_last = bIsLast;
this->task_queue.push(task);
};
void MdApi::OnRspUnSubForQuoteRsp(CKSOTPSpecificInstrumentField *pSpecificInstrument, CKSOTPRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
Task task = Task();
task.task_name = ONRSPUNSUBFORQUOTERSP;
if (pSpecificInstrument)
{
task.task_data = *pSpecificInstrument;
}
else
{
CKSOTPSpecificInstrumentField empty_data = CKSOTPSpecificInstrumentField();
memset(&empty_data, 0, sizeof(empty_data));
task.task_data = empty_data;
}
if (pRspInfo)
{
task.task_error = *pRspInfo;
}
else
{
CKSOTPRspInfoField empty_error = CKSOTPRspInfoField();
memset(&empty_error, 0, sizeof(empty_error));
task.task_error = empty_error;
}
task.task_id = nRequestID;
task.task_last = bIsLast;
this->task_queue.push(task);
};
void MdApi::OnRtnDepthMarketData(CKSOTPDepthMarketDataField *pDepthMarketData)
{
Task task = Task();
task.task_name = ONRTNDEPTHMARKETDATA;
if (pDepthMarketData)
{
task.task_data = *pDepthMarketData;
}
else
{
CKSOTPDepthMarketDataField empty_data = CKSOTPDepthMarketDataField();
memset(&empty_data, 0, sizeof(empty_data));
task.task_data = empty_data;
}
this->task_queue.push(task);
};
void MdApi::OnRtnForQuoteRsp(CKSOTPForQuoteRspField *pForQuoteRsp)
{
Task task = Task();
task.task_name = ONRTNFORQUOTERSP;
if (pForQuoteRsp)
{
task.task_data = *pForQuoteRsp;
}
else
{
CKSOTPForQuoteRspField empty_data = CKSOTPForQuoteRspField();
memset(&empty_data, 0, sizeof(empty_data));
task.task_data = empty_data;
}
this->task_queue.push(task);
};
///-------------------------------------------------------------------------------------
///工作线程从队列中取出数据转化为python对象后进行推送
///-------------------------------------------------------------------------------------
void MdApi::processTask()
{
while (1)
{
Task task = this->task_queue.wait_and_pop();
switch (task.task_name)
{
case ONFRONTCONNECTED:
{
this->processFrontConnected(task);
break;
}
case ONFRONTDISCONNECTED:
{
this->processFrontDisconnected(task);
break;
}
case ONRSPUSERLOGIN:
{
this->processRspUserLogin(task);
break;
}
case ONRSPUSERLOGOUT:
{
this->processRspUserLogout(task);
break;
}
case ONRSPERROR:
{
this->processRspError(task);
break;
}
case ONRSPSUBMARKETDATA:
{
this->processRspSubMarketData(task);
break;
}
case ONRSPUNSUBMARKETDATA:
{
this->processRspUnSubMarketData(task);
break;
}
case ONRSPSUBFORQUOTERSP:
{
this->processRspSubForQuoteRsp(task);
break;
}
case ONRSPUNSUBFORQUOTERSP:
{
this->processRspUnSubForQuoteRsp(task);
break;
}
case ONRTNDEPTHMARKETDATA:
{
this->processRtnDepthMarketData(task);
break;
}
case ONRTNFORQUOTERSP:
{
this->processRtnForQuoteRsp(task);
break;
}
};
}
};
void MdApi::processFrontConnected(Task task)
{
PyLock lock;
this->onFrontConnected();
};
void MdApi::processFrontDisconnected(Task task)
{
PyLock lock;
this->onFrontDisconnected(task.task_id);
};
void MdApi::processRspUserLogin(Task task)
{
PyLock lock;
CKSOTPRspUserLoginField task_data = any_cast<CKSOTPRspUserLoginField>(task.task_data);
dict data;
data["MaxOrderRef"] = task_data.MaxOrderRef;
data["UserID"] = task_data.UserID;
data["TradingDay"] = task_data.TradingDay;
data["SessionID"] = task_data.SessionID;
data["SystemName"] = task_data.SystemName;
data["FrontID"] = task_data.FrontID;
data["BrokerID"] = task_data.BrokerID;
data["LoginTime"] = task_data.LoginTime;
data["SSETime"] = task_data.SSETime;
CKSOTPRspInfoField task_error = any_cast<CKSOTPRspInfoField>(task.task_error);
dict error;
error["ErrorMsg"] = task_error.ErrorMsg;
error["ErrorID"] = task_error.ErrorID;
this->onRspUserLogin(data, error, task.task_id, task.task_last);
};
void MdApi::processRspUserLogout(Task task)
{
PyLock lock;
CKSOTPUserLogoutField task_data = any_cast<CKSOTPUserLogoutField>(task.task_data);
dict data;
data["UserID"] = task_data.UserID;
data["BrokerID"] = task_data.BrokerID;
CKSOTPRspInfoField task_error = any_cast<CKSOTPRspInfoField>(task.task_error);
dict error;
error["ErrorMsg"] = task_error.ErrorMsg;
error["ErrorID"] = task_error.ErrorID;
this->onRspUserLogout(data, error, task.task_id, task.task_last);
};
void MdApi::processRspError(Task task)
{
PyLock lock;
CKSOTPRspInfoField task_error = any_cast<CKSOTPRspInfoField>(task.task_error);
dict error;
error["ErrorMsg"] = task_error.ErrorMsg;
error["ErrorID"] = task_error.ErrorID;
this->onRspError(error, task.task_id, task.task_last);
};
void MdApi::processRspSubMarketData(Task task)
{
PyLock lock;
CKSOTPSpecificInstrumentField task_data = any_cast<CKSOTPSpecificInstrumentField>(task.task_data);
dict data;
data["InstrumentID"] = task_data.InstrumentID;
data["ExchangeID"] = task_data.ExchangeID;
CKSOTPRspInfoField task_error = any_cast<CKSOTPRspInfoField>(task.task_error);
dict error;
error["ErrorMsg"] = task_error.ErrorMsg;
error["ErrorID"] = task_error.ErrorID;
this->onRspSubMarketData(data, error, task.task_id, task.task_last);
};
void MdApi::processRspUnSubMarketData(Task task)
{
PyLock lock;
CKSOTPSpecificInstrumentField task_data = any_cast<CKSOTPSpecificInstrumentField>(task.task_data);
dict data;
data["InstrumentID"] = task_data.InstrumentID;
data["ExchangeID"] = task_data.ExchangeID;
CKSOTPRspInfoField task_error = any_cast<CKSOTPRspInfoField>(task.task_error);
dict error;
error["ErrorMsg"] = task_error.ErrorMsg;
error["ErrorID"] = task_error.ErrorID;
this->onRspUnSubMarketData(data, error, task.task_id, task.task_last);
};
void MdApi::processRspSubForQuoteRsp(Task task)
{
PyLock lock;
CKSOTPSpecificInstrumentField task_data = any_cast<CKSOTPSpecificInstrumentField>(task.task_data);
dict data;
data["InstrumentID"] = task_data.InstrumentID;
data["ExchangeID"] = task_data.ExchangeID;
CKSOTPRspInfoField task_error = any_cast<CKSOTPRspInfoField>(task.task_error);
dict error;
error["ErrorMsg"] = task_error.ErrorMsg;
error["ErrorID"] = task_error.ErrorID;
this->onRspSubForQuoteRsp(data, error, task.task_id, task.task_last);
};
void MdApi::processRspUnSubForQuoteRsp(Task task)
{
PyLock lock;
CKSOTPSpecificInstrumentField task_data = any_cast<CKSOTPSpecificInstrumentField>(task.task_data);
dict data;
data["InstrumentID"] = task_data.InstrumentID;
data["ExchangeID"] = task_data.ExchangeID;
CKSOTPRspInfoField task_error = any_cast<CKSOTPRspInfoField>(task.task_error);
dict error;
error["ErrorMsg"] = task_error.ErrorMsg;
error["ErrorID"] = task_error.ErrorID;
this->onRspUnSubForQuoteRsp(data, error, task.task_id, task.task_last);
};
void MdApi::processRtnDepthMarketData(Task task)
{
PyLock lock;
CKSOTPDepthMarketDataField task_data = any_cast<CKSOTPDepthMarketDataField>(task.task_data);
dict data;
data["HighestPrice"] = task_data.HighestPrice;
data["BidPrice5"] = task_data.BidPrice5;
data["BidPrice4"] = task_data.BidPrice4;
data["BidPrice1"] = task_data.BidPrice1;
data["BidPrice3"] = task_data.BidPrice3;
data["BidPrice2"] = task_data.BidPrice2;
data["LowerLimitPrice"] = task_data.LowerLimitPrice;
data["OpenPrice"] = task_data.OpenPrice;
data["AskPrice5"] = task_data.AskPrice5;
data["AskPrice4"] = task_data.AskPrice4;
data["AskPrice3"] = task_data.AskPrice3;
data["PreClosePrice"] = task_data.PreClosePrice;
data["AskPrice1"] = task_data.AskPrice1;
data["PreSettlementPrice"] = task_data.PreSettlementPrice;
data["AskVolume1"] = task_data.AskVolume1;
data["UpdateTime"] = task_data.UpdateTime;
data["UpdateMillisec"] = task_data.UpdateMillisec;
data["AveragePrice"] = task_data.AveragePrice;
data["BidVolume5"] = task_data.BidVolume5;
data["BidVolume4"] = task_data.BidVolume4;
data["BidVolume3"] = task_data.BidVolume3;
data["BidVolume2"] = task_data.BidVolume2;
data["PreOpenInterest"] = task_data.PreOpenInterest;
data["AskPrice2"] = task_data.AskPrice2;
data["Volume"] = task_data.Volume;
data["AskVolume3"] = task_data.AskVolume3;
data["AskVolume2"] = task_data.AskVolume2;
data["AskVolume5"] = task_data.AskVolume5;
data["AskVolume4"] = task_data.AskVolume4;
data["UpperLimitPrice"] = task_data.UpperLimitPrice;
data["BidVolume1"] = task_data.BidVolume1;
data["InstrumentID"] = task_data.InstrumentID;
data["ClosePrice"] = task_data.ClosePrice;
data["ExchangeID"] = task_data.ExchangeID;
data["TradingDay"] = task_data.TradingDay;
data["PreDelta"] = task_data.PreDelta;
data["OpenInterest"] = task_data.OpenInterest;
data["CurrDelta"] = task_data.CurrDelta;
data["Turnover"] = task_data.Turnover;
data["LastPrice"] = task_data.LastPrice;
data["SettlementPrice"] = task_data.SettlementPrice;
data["ExchangeInstID"] = task_data.ExchangeInstID;
data["LowestPrice"] = task_data.LowestPrice;
data["ActionDay"] = task_data.ActionDay;
this->onRtnDepthMarketData(data);
};
void MdApi::processRtnForQuoteRsp(Task task)
{
PyLock lock;
CKSOTPForQuoteRspField task_data = any_cast<CKSOTPForQuoteRspField>(task.task_data);
dict data;
data["InstrumentID"] = task_data.InstrumentID;
data["ActionDay"] = task_data.ActionDay;
data["ExchangeID"] = task_data.ExchangeID;
data["TradingDay"] = task_data.TradingDay;
data["ForQuoteSysID"] = task_data.ForQuoteSysID;
data["ForQuoteTime"] = task_data.ForQuoteTime;
this->onRtnForQuoteRsp(data);
};
///-------------------------------------------------------------------------------------
///主动函数
///-------------------------------------------------------------------------------------
void MdApi::createOTPMdApi(string pszFlowPath)
{
this->api = CKSOTPMdApi::CreateOTPMdApi(pszFlowPath.c_str());
this->api->RegisterSpi(this);
};
void MdApi::release()
{
this->api->Release();
};
void MdApi::init()
{
this->api->Init();
};
int MdApi::exit()
{
//该函数在原生API里没有用于安全退出API用原生的join似乎不太稳定
this->api->RegisterSpi(NULL);
this->api->Release();
this->api = NULL;
return 1;
};
string MdApi::getTradingDay()
{
string day = this->api->GetTradingDay();
return day;
};
void MdApi::registerFront(string pszFrontAddress)
{
this->api->RegisterFront((char*)pszFrontAddress.c_str());
};
int MdApi::subscribeMarketData(dict req)
{
//手写
CKSOTPSpecificInstrumentField myreq = CKSOTPSpecificInstrumentField();
getChar(req, "InstrumentID", myreq.InstrumentID);
getChar(req, "ExchangeID", myreq.ExchangeID);
CKSOTPSpecificInstrumentField* reqarray[1] = { &myreq };
int i = this->api->SubscribeMarketData(reqarray, 1);
return i;
};
int MdApi::unSubscribeMarketData(dict req)
{
//手写
CKSOTPSpecificInstrumentField myreq = CKSOTPSpecificInstrumentField();
getChar(req, "InstrumentID", myreq.InstrumentID);
getChar(req, "ExchangeID", myreq.ExchangeID);
CKSOTPSpecificInstrumentField* reqarray[1] = { &myreq };
int i = this->api->UnSubscribeMarketData(reqarray, 1);
return i;
};
int MdApi::subscribeForQuoteRsp(string instrumentID)
{
char* buffer = (char*)instrumentID.c_str();
char* myreq[1] = { buffer };
int i = this->api->SubscribeForQuoteRsp(myreq, 1);
return i;
};
int MdApi::unSubscribeForQuoteRsp(string instrumentID)
{
char* buffer = (char*)instrumentID.c_str();
char* myreq[1] = { buffer };;
int i = this->api->UnSubscribeForQuoteRsp(myreq, 1);
return i;
};
int MdApi::reqUserLogin(dict req, int nRequestID)
{
CKSOTPReqUserLoginField myreq = CKSOTPReqUserLoginField();
memset(&myreq, 0, sizeof(myreq));
getChar(req, "MacAddress", myreq.MacAddress);
getChar(req, "UserProductInfo", myreq.UserProductInfo);
getChar(req, "UserID", myreq.UserID);
getChar(req, "BrokerID", myreq.BrokerID);
getChar(req, "ClientIPAddress", myreq.ClientIPAddress);
getChar(req, "Password", myreq.Password);
int i = this->api->ReqUserLogin(&myreq, nRequestID);
return i;
};
int MdApi::reqUserLogout(dict req, int nRequestID)
{
CKSOTPUserLogoutField myreq = CKSOTPUserLogoutField();
memset(&myreq, 0, sizeof(myreq));
getChar(req, "UserID", myreq.UserID);
getChar(req, "BrokerID", myreq.BrokerID);
int i = this->api->ReqUserLogout(&myreq, nRequestID);
return i;
};
///-------------------------------------------------------------------------------------
///Boost.Python封装
///-------------------------------------------------------------------------------------
struct MdApiWrap : MdApi, wrapper < MdApi >
{
virtual void onFrontConnected()
{
//以下的try...catch...可以实现捕捉python环境中错误的功能防止C++直接出现原因未知的崩溃
try
{
this->get_override("onFrontConnected")();
}
catch (error_already_set const &)
{
PyErr_Print();
}
};
virtual void onFrontDisconnected(int i)
{
try
{
this->get_override("onFrontDisconnected")(i);
}
catch (error_already_set const &)
{
PyErr_Print();
}
};
virtual void onRspError(dict data, int id, bool last)
{
try
{
this->get_override("onRspError")(data, id, last);
}
catch (error_already_set const &)
{
PyErr_Print();
}
};
virtual void onRspUserLogin(dict data, dict error, int id, bool last)
{
try
{
this->get_override("onRspUserLogin")(data, error, id, last);
}
catch (error_already_set const &)
{
PyErr_Print();
}
};
virtual void onRspUserLogout(dict data, dict error, int id, bool last)
{
try
{
this->get_override("onRspUserLogout")(data, error, id, last);
}
catch (error_already_set const &)
{
PyErr_Print();
}
};
virtual void onRspSubMarketData(dict data, dict error, int id, bool last)
{
try
{
this->get_override("onRspSubMarketData")(data, error, id, last);
}
catch (error_already_set const &)
{
PyErr_Print();
}
};
virtual void onRspUnSubMarketData(dict data, dict error, int id, bool last)
{
try
{
this->get_override("onRspUnSubMarketData")(data, error, id, last);
}
catch (error_already_set const &)
{
PyErr_Print();
}
};
virtual void onRspSubForQuoteRsp(dict data, dict error, int id, bool last)
{
try
{
this->get_override("onRspSubForQuoteRsp")(data, error, id, last);
}
catch (error_already_set const &)
{
PyErr_Print();
}
};
virtual void onRspUnSubForQuoteRsp(dict data, dict error, int id, bool last)
{
try
{
this->get_override("onRspUnSubForQuoteRsp")(data, error, id, last);
}
catch (error_already_set const &)
{
PyErr_Print();
}
};
virtual void onRtnDepthMarketData(dict data)
{
try
{
this->get_override("onRtnDepthMarketData")(data);
}
catch (error_already_set const &)
{
PyErr_Print();
}
};
virtual void onRtnForQuoteRsp(dict data)
{
try
{
this->get_override("onRtnForQuoteRsp")(data);
}
catch (error_already_set const &)
{
PyErr_Print();
}
};
};
BOOST_PYTHON_MODULE(vnksotpmd)
{
PyEval_InitThreads(); //导入时运行保证先创建GIL
class_<MdApiWrap, boost::noncopyable>("MdApi")
.def("createOTPMdApi", &MdApiWrap::createOTPMdApi)
.def("release", &MdApiWrap::release)
.def("init", &MdApiWrap::init)
.def("exit", &MdApiWrap::exit)
.def("getTradingDay", &MdApiWrap::getTradingDay)
.def("registerFront", &MdApiWrap::registerFront)
.def("subscribeMarketData", &MdApiWrap::subscribeMarketData)
.def("unSubscribeMarketData", &MdApiWrap::unSubscribeMarketData)
.def("subscribeForQuoteRsp", &MdApiWrap::subscribeForQuoteRsp)
.def("unSubscribeForQuoteRsp", &MdApiWrap::unSubscribeForQuoteRsp)
.def("reqUserLogin", &MdApiWrap::reqUserLogin)
.def("reqUserLogout", &MdApiWrap::reqUserLogout)
.def("onFrontConnected", pure_virtual(&MdApiWrap::onFrontConnected))
.def("onFrontDisconnected", pure_virtual(&MdApiWrap::onFrontDisconnected))
.def("onRspError", pure_virtual(&MdApiWrap::onRspError))
.def("onRspUserLogin", pure_virtual(&MdApiWrap::onRspUserLogin))
.def("onRspUserLogout", pure_virtual(&MdApiWrap::onRspUserLogout))
.def("onRspSubMarketData", pure_virtual(&MdApiWrap::onRspSubMarketData))
.def("onRspUnSubMarketData", pure_virtual(&MdApiWrap::onRspUnSubMarketData))
.def("onRtnDepthMarketData", pure_virtual(&MdApiWrap::onRtnDepthMarketData))
.def("onRspSubForQuoteRsp", pure_virtual(&MdApiWrap::onRspSubForQuoteRsp))
.def("onRspUnSubForQuoteRsp", pure_virtual(&MdApiWrap::onRspUnSubForQuoteRsp))
.def("onRtnForQuoteRsp", pure_virtual(&MdApiWrap::onRtnForQuoteRsp))
;
};