[Add] 捕获xtp回调函数内部发生的错误

[Mod] 使用autocxxpy0.2.1来封装xtp
This commit is contained in:
nanoric 2019-04-25 07:02:41 -04:00
parent 72dd05dcb5
commit a2b55dda02
10 changed files with 413 additions and 198 deletions

Binary file not shown.

View File

@ -7,19 +7,34 @@ if typing.TYPE_CHECKING:
from .vnxtp import *
def set_async_callback_exception_handler(handler: Callable[[AsyncDispatchException], None]):
"""
set a customize exception handler for async callback in this module(pyd)
\a handler should return True if it handles that exception,
If the return value of \a handler is not True, exception will be re-thrown.
"""
...
class AsyncDispatchException:
what: str
instance: object
function_name: str
from . import vnxtp_XTP as XTP
class XTPRspInfoStruct():
error_id: int
error_msg: Sequence[int]
error_msg: str
class XTPSpecificTickerStruct():
exchange_id: XTP_EXCHANGE_TYPE
ticker: Sequence[int]
ticker: str
class XTPMarketDataStockExData():
@ -71,7 +86,7 @@ class XTPMarketDataStruct():
exchange_id: XTP_EXCHANGE_TYPE
ticker: Sequence[int]
ticker: str
last_price: float
pre_close_price: float
open_price: float
@ -95,7 +110,7 @@ class XTPMarketDataStruct():
bid_qty: Sequence[int]
ask_qty: Sequence[int]
trades_count: int
ticker_status: Sequence[int]
ticker_status: str
stk: XTPMarketDataStockExData
opt: XTPMarketDataOptionExData
data_type: XTP_MARKETDATA_TYPE
@ -106,8 +121,8 @@ class XTPQuoteStaticInfo():
exchange_id: XTP_EXCHANGE_TYPE
ticker: Sequence[int]
ticker_name: Sequence[int]
ticker: str
ticker_name: str
ticker_type: XTP_TICKER_TYPE
pre_close_price: float
upper_limit_price: float
@ -121,7 +136,7 @@ class OrderBookStruct():
exchange_id: XTP_EXCHANGE_TYPE
ticker: Sequence[int]
ticker: str
last_price: float
qty: int
turnover: float
@ -161,7 +176,7 @@ class XTPTickByTickStruct():
exchange_id: XTP_EXCHANGE_TYPE
ticker: Sequence[int]
ticker: str
seq: int
data_time: int
type: XTP_TBT_TYPE
@ -173,7 +188,7 @@ class XTPTickerPriceInfo():
exchange_id: XTP_EXCHANGE_TYPE
ticker: Sequence[int]
ticker: str
last_price: float
@ -182,7 +197,7 @@ class XTPOrderInsertInfo():
order_xtp_id: int
order_client_id: int
ticker: Sequence[int]
ticker: str
market: XTP_MARKET_TYPE
price: float
stop_price: float
@ -210,7 +225,7 @@ class XTPOrderInfo():
order_client_id: int
order_cancel_client_id: int
order_cancel_xtp_id: int
ticker: Sequence[int]
ticker: str
market: XTP_MARKET_TYPE
price: float
quantity: int
@ -227,7 +242,7 @@ class XTPOrderInfo():
update_time: int
cancel_time: int
trade_amount: float
order_local_id: Sequence[int]
order_local_id: str
order_status: XTP_ORDER_STATUS_TYPE
order_submit_status: XTP_ORDER_SUBMIT_STATUS_TYPE
order_type: int
@ -238,16 +253,16 @@ class XTPTradeReport():
order_xtp_id: int
order_client_id: int
ticker: Sequence[int]
ticker: str
market: XTP_MARKET_TYPE
local_order_id: int
exec_id: Sequence[int]
exec_id: str
price: float
quantity: int
trade_time: int
trade_amount: float
report_index: int
order_exch_id: Sequence[int]
order_exch_id: str
trade_type: int
u32: int
side: int
@ -255,13 +270,13 @@ class XTPTradeReport():
reserved1: int
reserved2: int
business_type: XTP_BUSINESS_TYPE
branch_pbu: Sequence[int]
branch_pbu: str
class XTPQueryOrderReq():
ticker: Sequence[int]
ticker: str
begin_time: int
end_time: int
@ -270,13 +285,13 @@ class XTPQueryReportByExecIdReq():
order_xtp_id: int
exec_id: Sequence[int]
exec_id: str
class XTPQueryTraderReq():
ticker: Sequence[int]
ticker: str
begin_time: int
end_time: int
@ -311,8 +326,8 @@ class XTPQueryAssetRsp():
class XTPQueryStkPositionRsp():
ticker: Sequence[int]
ticker_name: Sequence[int]
ticker: str
ticker_name: str
market: XTP_MARKET_TYPE
total_qty: int
sellable_qty: int
@ -350,17 +365,17 @@ class XTPQueryStructuredFundInfoReq():
exchange_id: XTP_EXCHANGE_TYPE
sf_ticker: Sequence[int]
sf_ticker: str
class XTPStructuredFundInfo():
exchange_id: XTP_EXCHANGE_TYPE
sf_ticker: Sequence[int]
sf_ticker_name: Sequence[int]
ticker: Sequence[int]
ticker_name: Sequence[int]
sf_ticker: str
sf_ticker_name: str
ticker: str
ticker_name: str
split_merge_status: XTP_SPLIT_MERGE_STATUS
ratio: int
min_split_qty: int
@ -372,15 +387,15 @@ class XTPQueryETFBaseReq():
market: XTP_MARKET_TYPE
ticker: Sequence[int]
ticker: str
class XTPQueryETFBaseRsp():
market: XTP_MARKET_TYPE
etf: Sequence[int]
subscribe_redemption_ticker: Sequence[int]
etf: str
subscribe_redemption_ticker: str
unit: int
subscribe_status: int
redemption_status: int
@ -395,16 +410,16 @@ class XTPQueryETFComponentReq():
market: XTP_MARKET_TYPE
ticker: Sequence[int]
ticker: str
class XTPQueryETFComponentRsp():
market: XTP_MARKET_TYPE
ticker: Sequence[int]
component_ticker: Sequence[int]
component_name: Sequence[int]
ticker: str
component_ticker: str
component_name: str
quantity: int
component_market: XTP_MARKET_TYPE
replace_type: ETF_REPLACE_TYPE
@ -416,8 +431,8 @@ class XTPQueryIPOTickerRsp():
market: XTP_MARKET_TYPE
ticker: Sequence[int]
ticker_name: Sequence[int]
ticker: str
ticker_name: str
price: float
unit: int
qty_upper_limit: int
@ -434,17 +449,17 @@ class XTPQueryOptionAuctionInfoReq():
market: XTP_MARKET_TYPE
ticker: Sequence[int]
ticker: str
class XTPQueryOptionAuctionInfoRsp():
ticker: Sequence[int]
ticker: str
security_id_source: XTP_MARKET_TYPE
symbol: Sequence[int]
contract_id: Sequence[int]
underlying_security_id: Sequence[int]
symbol: str
contract_id: str
underlying_security_id: str
underlying_security_id_source: XTP_MARKET_TYPE
list_date: int
last_trade_date: int
@ -483,8 +498,8 @@ class XTPFundTransferReq():
serial_id: int
fund_account: Sequence[int]
password: Sequence[int]
fund_account: str
password: str
amount: float
transfer_type: XTP_FUND_TRANSFER_TYPE
@ -610,7 +625,7 @@ class XTP_POSITION_DIRECTION_TYPE(Enum):
class XTP_MARKETDATA_TYPE(Enum):
XTP_MARKETDATA_ACTUAL: XTP_MARKETDATA_TYPE
XTP_MARKETDATA_OPTION: XTP_MARKETDATA_TYPE
XTPVersionType = Sequence[int]
XTPVersionType = str
XTP_LOG_LEVEL = XTP_LOG_LEVEL
XTP_PROTOCOL_TYPE = XTP_PROTOCOL_TYPE
XTP_EXCHANGE_TYPE = XTP_EXCHANGE_TYPE

View File

@ -277,9 +277,14 @@ void generate_class_XTP_API_QuoteApi(pybind11::object & parent)
PyQuoteApi
> c(parent, "QuoteApi");
c.def_static("CreateQuoteApi",
autocxxpy::apply_function_transform<
autocxxpy::function_constant<
&XTP::API::QuoteApi::CreateQuoteApi
//,
//pybind11::call_guard<pybind11::gil_scoped_release>()
>,
brigand::list<
>
>::value,
pybind11::call_guard<pybind11::gil_scoped_release>()
);
c.def("Release",
autocxxpy::apply_function_transform<

View File

@ -1,6 +1,7 @@
#include <iostream>
#include <string>
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include <autocxxpy/autocxxpy.hpp>
#include "module.hpp"
@ -20,6 +21,12 @@ void additional_init(pybind11::module &m)
void init_dispatcher(pybind11::module &m)
{
m.def("set_async_callback_exception_handler", &autocxxpy::async_callback_exception_handler::set_handler);
pybind11::class_<autocxxpy::async_dispatch_exception> c(m, "AsyncDispatchException");
c.def_property("what", &autocxxpy::async_dispatch_exception::what, nullptr);
c.def_readonly("instance", &autocxxpy::async_dispatch_exception::instance);
c.def_readonly("function_name", &autocxxpy::async_dispatch_exception::function_name);
autocxxpy::dispatcher::instance().start();
}

View File

@ -2,6 +2,7 @@
#include <tuple>
#include <type_traits>
#include <optional>
#include "brigand.hpp"
@ -66,7 +67,7 @@ namespace autocxxpy
template <auto method>
constexpr callback_type callback_type_of_v = callback_type_of<method>::value;
#ifdef PYBIND11_OVERLOAD_NAME
#ifdef AUTOCXXPY_INCLUDED_PYBIND11
template <class ret_type>
struct pybind11_static_caster {
static pybind11::detail::overload_caster_t<ret_type> caster;
@ -75,18 +76,59 @@ namespace autocxxpy
template <class ret_type>
AUTOCXXPY_SELECT_ANY pybind11::detail::overload_caster_t<ret_type> pybind11_static_caster<ret_type>::caster;
struct async_dispatch_exception : public std::exception
{
async_dispatch_exception(const char *what, const pybind11::object &instance, std::string function_name)
: std::exception(what), instance(instance), function_name(function_name)
{}
pybind11::object instance;
std::string function_name;
inline const char* what() noexcept
{
return std::exception::what();
}
};
struct async_callback_exception_handler
{
using handler_type = std::function<void(const async_dispatch_exception&)>;
static handler_type custom_handler;
inline static void handle_excepiton(const async_dispatch_exception&e)
{
if (custom_handler)
{
custom_handler(e);
}
}
inline static void set_handler(const handler_type& handler)
{
custom_handler = handler;
}
};
AUTOCXXPY_SELECT_ANY async_callback_exception_handler::handler_type async_callback_exception_handler::custom_handler;
#endif
namespace arg_helper
{
//////////////////////////////////////////////////////////////////////////
// stores
//////////////////////////////////////////////////////////////////////////
// # todo: char8, char16, char32, wchar_t, etc...
// # todo: shall i copy only const type, treating non-const type as output pointer?
inline auto save(const char *val)
inline std::optional<std::string> save(const char* val)
{ // match const char *
if (nullptr == val) AUTOCXXPY_UNLIKELY
return std::nullopt; // maybe empty string is also a choice?
return std::string(val);
}
inline auto save(char *val)
inline std::optional<std::string> save(char* val)
{ // match char *
if (nullptr == val) AUTOCXXPY_UNLIKELY
return std::nullopt; // maybe empty string is also a choice?
return std::string(val);
}
template<size_t size>
@ -101,29 +143,41 @@ namespace autocxxpy
}
template <class T>
inline T &save(T *val)
inline std::optional<T> save(T * val)
{ // match pointer
if (nullptr == val) AUTOCXXPY_UNLIKELY
{
return std::nullopt;
}
return *val;
}
template <class T>
inline T &save(const T *val)
inline std::optional<T>& save(const T * val)
{ // match const pointer
if (nullptr == val) AUTOCXXPY_UNLIKELY
{
return std::nullopt;
}
return const_cast<T&>(*val);
}
template <class T>
inline T &save(const T &val)
inline T& save(const T & val)
{ // match everything else : just use original type
return const_cast<T&>(val);
}
//////////////////////////////////////////////////////////////////////////
// loads
//////////////////////////////////////////////////////////////////////////
template <class to_type>
struct loader
{ // match default(everyting besides pointer)
template <class src_type>
inline to_type operator ()(src_type &val)
inline to_type operator ()(src_type& val)
{
return val;
}
@ -132,57 +186,57 @@ namespace autocxxpy
template <size_t size>
struct loader<const string_array<size>>
{ // match const char []
using to_type = const char *;
inline to_type operator ()(const std::string &val)
using to_type = const char*;
inline to_type operator ()(const std::string& val)
{
return const_cast<char *>(val.data());
return const_cast<char*>(val.data());
}
};
template <size_t size>
struct loader<string_array<size>>
{ // match char []
using to_type = char *;
inline to_type operator ()(const std::string &val)
using to_type = char*;
inline to_type operator ()(const std::string& val)
{
return const_cast<char *>(val.data());
return const_cast<char*>(val.data());
}
};
template <>
struct loader<const char *>
struct loader<const char*>
{ // match const char *
using to_type = const char *;
inline to_type operator ()(const std::string &val)
using to_type = const char*;
inline to_type operator ()(const std::optional<std::string>& val)
{
return const_cast<char *>(val.data());
if (val) AUTOCXXPY_LIKELY
return const_cast<char*>(val->data());
return nullptr;
}
};
template <>
struct loader<char *>
struct loader<char*>
{ // match char *
using to_type = char *;
inline to_type operator ()(const std::string &val)
using to_type = char*;
inline to_type operator ()(const std::optional<std::string>& val)
{
return const_cast<char *>(val.data());
if (val) AUTOCXXPY_LIKELY
return const_cast<char*>(val->data());
return nullptr;
}
};
template <class to_type>
struct loader<to_type *>
struct loader<to_type*>
{ // match pointer
template <class src_type>
inline to_type *operator ()(src_type &val)
inline to_type* operator ()(const std::optional<src_type>& val)
{ // val to poiner
return const_cast<to_type *>(&val);
if (val) AUTOCXXPY_LIKELY
return const_cast<to_type*>(&(*val));
return nullptr;
}
//template <class src_type>
//inline to_type *operator ()(src_type *val)
//{ // pointer to pointer
// return val;
//}
};
};
@ -195,7 +249,7 @@ namespace autocxxpy
using class_type = class_of_member_method_t<method>;
public:
template <class ... arg_types>
inline static ret_type call(class_type *instance, const char *py_func_name, arg_types ... args)
inline static ret_type call(class_type* instance, const char* py_func_name, arg_types ... args)
{
if constexpr (callback_type_of_v<method> == callback_type::Direct)
{
@ -211,47 +265,70 @@ namespace autocxxpy
}
template <class ... arg_types>
inline static void async(class_type *instance, const char *py_func_name, arg_types ... args)
inline static void async(class_type* instance, const char* py_func_name, arg_types ... args)
{
return async_impl(instance, py_func_name, std::index_sequence_for<arg_types ...>{}, args ...);
}
template <class ... arg_types>
inline static ret_type sync(class_type *instance, const char * py_func_name, arg_types ... args)
inline static ret_type sync(class_type * instance, const char* py_func_name, arg_types ... args)
{
// if this code is under test environment, we don't need pybind11
// since header of pybind11 use #pragma once, no macros is defined, we use a public macro to check if pybind11 is included or not
#ifdef PYBIND11_OVERLOAD_NAME
pybind11::gil_scoped_acquire gil;
pybind11::function overload = pybind11::get_overload(static_cast<const class_type *>(instance), py_func_name);
if (overload) {
auto o = overload(args ...);
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value) {
auto & caster = pybind11_static_caster<ret_type>::caster;
return pybind11::detail::cast_ref<ret_type>(std::move(o), caster);
pybind11::function overload = pybind11::get_overload(static_cast<const class_type*>(instance), py_func_name);
if (overload) AUTOCXXPY_LIKELY{
try
{
auto result = overload(args ...);
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value)
{
auto& caster = pybind11_static_caster<ret_type>::caster;
return pybind11::detail::cast_ref<ret_type>(std::move(result), caster);
}
else
{
return pybind11::detail::cast_safe<ret_type>(std::move(result));
}
}
catch (const pybind11::error_already_set & e)
{
// todo: option to not to throw when sync is called directly
throw async_dispatch_exception(e.what(), pybind11::cast(instance), py_func_name);
}
else return pybind11::detail::cast_safe<ret_type>(std::move(o));
}
#endif
return (instance->*method)(args ...);
}
private:
template <class ... arg_types, size_t ... idx>
inline static void async_impl(class_type *instance, const char *py_func_name, std::index_sequence<idx ...>, arg_types ... args)
inline static void async_impl(class_type * instance, const char* py_func_name, std::index_sequence<idx ...>, arg_types ... args)
{
// wrap for ctp like function calls:
// all the pointer might be unavailable after this call, so copy its value into a tuple
auto arg_tuple = std::make_tuple(arg_helper::save(args) ...);
auto task = [instance, py_func_name, arg_tuple = std::move(arg_tuple)]()
{
// resolve all value:
// if it was originally a pointer, then use pointer type.
// if it was originally a value, just keep a reference to that value.
sync<arg_types ...>(
instance, py_func_name,
arg_helper::loader<brigand::at<brigand::list<arg_types ...>, brigand::integral_constant<int, idx> > >{}
(std::get<idx>(arg_tuple)) ...
);
#ifdef AUTOCXXPY_INCLUDED_PYBIND11
try
{
#endif
// resolve all value:
// if it was originally a pointer, then use pointer type.
// if it was originally a value, just keep a reference to that value.
sync<arg_types ...>(
instance, py_func_name,
arg_helper::loader<brigand::at<brigand::list<arg_types ...>, brigand::integral_constant<int, idx> > >{}
(std::get<idx>(arg_tuple)) ...
);
#ifdef AUTOCXXPY_INCLUDED_PYBIND11
}
catch (const async_dispatch_exception &e)
{
async_callback_exception_handler::handle_excepiton(e);
}
#endif
};
dispatcher::instance().add(std::move(task));
}

View File

@ -8,12 +8,30 @@
#ifndef AUTOCXXPY_UNUSED
#define AUTOCXXPY_UNUSED(x) (void)(x)
# define AUTOCXXPY_UNUSED(x) (void)(x)
#endif
#ifdef _MSC_VER
#define AUTOCXXPY_SELECT_ANY __declspec(selectany)
# define AUTOCXXPY_SELECT_ANY __declspec(selectany)
#else
#define AUTOCXXPY_SELECT_ANY __attribute__ ((selectany))
#endif
# define AUTOCXXPY_SELECT_ANY __attribute__ ((selectany))
#endif
#ifdef __has_cpp_attribute
# if __has_cpp_attribute(likely)
# define AUTOCXXPY_LIKELY [[likely]]
# endif
# if __has_cpp_attribute(unlikely)
# define AUTOCXXPY_UNLIKELY [[unlikely]]
# endif
#endif
#ifndef AUTOCXXPY_LIKELY
#define AUTOCXXPY_LIKELY
#endif
#ifndef AUTOCXXPY_UNLIKELY
#define AUTOCXXPY_UNLIKELY
#endif

View File

@ -119,6 +119,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
<DisableSpecificWarnings>4819</DisableSpecificWarnings>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -138,6 +139,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
<DisableSpecificWarnings>4819</DisableSpecificWarnings>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -160,6 +162,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
<DisableSpecificWarnings>4819</DisableSpecificWarnings>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -184,6 +187,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
<DisableSpecificWarnings>4819</DisableSpecificWarnings>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

View File

@ -7,5 +7,20 @@ if typing.TYPE_CHECKING:
from .vnxtp import *
def set_async_callback_exception_handler(handler: Callable[[Exception, object, str], bool]):
"""
set a customize exception handler for async callback in this module(pyd)
\a handler should return True if it handles that exception,
If the return value of \a handler is not True, exception will be re-thrown.
"""
...
class AsyncDispatchException:
what: str
instance: object
function_name: str
from . import vnxtp_XTP_API as API

View File

@ -7,6 +7,21 @@ if typing.TYPE_CHECKING:
from .vnxtp import *
def set_async_callback_exception_handler(handler: Callable[[Exception, object, str], bool]):
"""
set a customize exception handler for async callback in this module(pyd)
\a handler should return True if it handles that exception,
If the return value of \a handler is not True, exception will be re-thrown.
"""
...
class AsyncDispatchException:
what: str
instance: object
function_name: str
class TraderSpi():

View File

@ -1,3 +1,4 @@
import sys
from typing import Any, Sequence
from vnpy.api.xtp.vnxtp import (
@ -12,21 +13,21 @@ from vnpy.api.xtp.vnxtp import (
XTP_EXCHANGE_TYPE,
XTP_LOG_LEVEL,
XTP_PROTOCOL_TYPE,
XTP_TICKER_TYPE_STOCK,
XTP_TICKER_TYPE_INDEX,
XTP_TICKER_TYPE_FUND,
XTP_TICKER_TYPE_BOND,
XTP_TICKER_TYPE_OPTION,
XTP_PROTOCOL_TCP,
XTP_PROTOCOL_UDP
set_async_callback_exception_handler,
AsyncDispatchException,
XTP_TICKER_TYPE,
)
from vnpy.event import EventEngine
from vnpy.trader.constant import Exchange, Product
from vnpy.trader.gateway import BaseGateway
from vnpy.trader.object import (CancelRequest, OrderRequest, SubscribeRequest,
TickData, ContractData, OrderData, TradeData,
PositionData, AccountData)
from vnpy.trader.object import (
CancelRequest,
OrderRequest,
SubscribeRequest,
TickData,
ContractData,
)
from vnpy.trader.utility import get_folder_path
API = XTP.API
@ -38,19 +39,17 @@ EXCHANGE_XTP2VT = {
EXCHANGE_VT2XTP = {v: k for k, v in EXCHANGE_XTP2VT.items()}
PRODUCT_XTP2VT = {
XTP_TICKER_TYPE_STOCK: Product.EQUITY,
XTP_TICKER_TYPE_INDEX: Product.INDEX,
XTP_TICKER_TYPE_FUND: Product.FUND,
XTP_TICKER_TYPE_BOND: Product.BOND,
XTP_TICKER_TYPE_OPTION: Product.OPTION
XTP_TICKER_TYPE.XTP_TICKER_TYPE_STOCK: Product.EQUITY,
XTP_TICKER_TYPE.XTP_TICKER_TYPE_INDEX: Product.INDEX,
XTP_TICKER_TYPE.XTP_TICKER_TYPE_FUND: Product.FUND,
XTP_TICKER_TYPE.XTP_TICKER_TYPE_BOND: Product.BOND,
XTP_TICKER_TYPE.XTP_TICKER_TYPE_OPTION: Product.OPTION,
}
symbol_name_map = {}
class XtpGateway(BaseGateway):
default_setting = {
"账号": "",
"密码": "",
@ -59,7 +58,7 @@ class XtpGateway(BaseGateway):
"行情端口": 0,
"交易地址": "",
"交易端口": 0,
"行情协议": ["TCP", "UDP"]
"行情协议": ["TCP", "UDP"],
}
def __init__(self, event_engine: EventEngine):
@ -68,19 +67,23 @@ class XtpGateway(BaseGateway):
self.quote_api = XtpQuoteApi(self)
set_async_callback_exception_handler(self._async_callback_exception_handler)
pass
def connect(self, setting: dict):
""""""
userid = setting['账号']
password = setting['密码']
client_id = setting['客户号']
quote_ip = setting['行情地址']
quote_port = setting['行情端口']
trade_ip = setting['交易地址']
trade_port = setting['交易端口']
userid = setting["账号"]
password = setting["密码"]
client_id = int(setting["客户号"])
quote_ip = setting["行情地址"]
quote_port = int(setting["行情端口"])
trade_ip = setting["交易地址"]
trade_port = setting["交易端口"]
quote_protocol = setting["行情协议"]
self.quote_api.connect(userid, password, client_id,
quote_ip, quote_port, quote_protocol)
self.quote_api.connect(
userid, password, client_id, quote_ip, quote_port, quote_protocol
)
def close(self):
""""""
@ -102,11 +105,17 @@ class XtpGateway(BaseGateway):
def query_position(self):
pass
def _async_callback_exception_handler(self, e: AsyncDispatchException):
error_str = f"发生内部错误:\n" f"位置:{e.instance}.{e.function_name}" f"详细信息:{e.what}"
print(error_str, file=sys.stderr)
self.write_log(error_str) # write_error function?
class XtpQuoteApi(API.QuoteSpi):
def __init__(self, gateway: BaseGateway):
""""""
super(XtpQuoteApi, self).__init__()
self.gateway = gateway
self.gateway_name = gateway.gateway_name
@ -123,10 +132,10 @@ class XtpQuoteApi(API.QuoteSpi):
self,
userid: str,
password: str,
client_id: str,
client_id: int,
server_ip: str,
server_port: str,
quote_protocol: str
server_port: int,
quote_protocol: str,
):
""""""
if self.api:
@ -139,17 +148,15 @@ class XtpQuoteApi(API.QuoteSpi):
self.server_port = server_port
if quote_protocol == "CTP":
self.quote_protocol = XTP_PROTOCOL_TCP
self.quote_protocol = XTP_PROTOCOL_TYPE.XTP_PROTOCOL_TCP
else:
self.quote_protocol = XTP_PROTOCOL_UDP
self.quote_protocol = XTP_PROTOCOL_TYPE.XTP_PROTOCOL_UDP
# Create API object
path = str(get_folder_path(self.gateway_name.lower()))
self.api = API.QuoteApi.CreateQuoteApi(
self.client_id,
path,
XTP_LOG_LEVEL.XTP_LOG_LEVEL_TRACE
self.client_id, path, XTP_LOG_LEVEL.XTP_LOG_LEVEL_TRACE
)
self.api.RegisterSpi(self)
@ -161,7 +168,7 @@ class XtpQuoteApi(API.QuoteSpi):
self.server_port,
self.userid,
self.password,
self.quote_protocol
self.quote_protocol,
)
if not ret:
@ -180,11 +187,13 @@ class XtpQuoteApi(API.QuoteSpi):
def query_contract(self):
""""""
for exchange_id in EXCHANGE_XTP2VT.keys():
self.api.QueryAllTickers(exchange_id)
ret = self.api.QueryAllTickers(exchange_id)
if ret != 0:
self.gateway.write_log("订阅合约失败")
def check_error(self, func_name: str, error_info: XTPRspInfoStruct):
""""""
if error_info.error_id:
if error_info and error_info.error_id:
msg = f"{func_name}发生错误, 代码:{error_info.error_id},信息:{error_info.error_msg}"
self.gateway.write_log(msg)
return True
@ -199,21 +208,37 @@ class XtpQuoteApi(API.QuoteSpi):
""""""
self.check_error("行情接口", error_info)
def OnSubMarketData(self, ticker: XTPSpecificTickerStruct, error_info: XTPRspInfoStruct,
is_last: bool) -> Any:
def OnSubMarketData(
self,
ticker: XTPSpecificTickerStruct,
error_info: XTPRspInfoStruct,
is_last: bool,
) -> Any:
""""""
self.check_error("订阅行情", error_info)
return super().OnSubMarketData(ticker, error_info, is_last)
def OnUnSubMarketData(self, ticker: XTPSpecificTickerStruct, error_info: XTPRspInfoStruct,
is_last: bool) -> Any:
def OnUnSubMarketData(
self,
ticker: XTPSpecificTickerStruct,
error_info: XTPRspInfoStruct,
is_last: bool,
) -> Any:
""""""
pass
def OnDepthMarketData(self, market_data: XTPMarketDataStruct, bid1_qty: Sequence[int],
bid1_count: int, max_bid1_count: int, ask1_qty: Sequence[int],
ask1_count: int, max_ask1_count: int) -> Any:
def OnDepthMarketData(
self,
market_data: XTPMarketDataStruct,
bid1_qty: Sequence[int],
bid1_count: int,
max_bid1_count: int,
ask1_qty: Sequence[int],
ask1_count: int,
max_ask1_count: int,
) -> Any:
""""""
timestamp = market_data.date_time
timestamp = market_data.data_time
tick = TickData(
symbol=market_data.ticker,
@ -247,19 +272,27 @@ class XtpQuoteApi(API.QuoteSpi):
ask_volume_3=market_data.ask_qty[2],
ask_volume_4=market_data.ask_qty[3],
ask_volume_5=market_data.ask_qty[4],
gateway_name=self.gateway_name
gateway_name=self.gateway_name,
)
tick.name = symbol_name_map.get(tick.vt_symbol, tick.symbol)
self.gateway.on_tick(tick)
def OnSubOrderBook(self, ticker: XTPSpecificTickerStruct, error_info: XTPRspInfoStruct,
is_last: bool) -> Any:
def OnSubOrderBook(
self,
ticker: XTPSpecificTickerStruct,
error_info: XTPRspInfoStruct,
is_last: bool,
) -> Any:
""""""
pass
def OnUnSubOrderBook(self, ticker: XTPSpecificTickerStruct, error_info: XTPRspInfoStruct,
is_last: bool) -> Any:
def OnUnSubOrderBook(
self,
ticker: XTPSpecificTickerStruct,
error_info: XTPRspInfoStruct,
is_last: bool,
) -> Any:
""""""
pass
@ -267,13 +300,21 @@ class XtpQuoteApi(API.QuoteSpi):
""""""
pass
def OnSubTickByTick(self, ticker: XTPSpecificTickerStruct, error_info: XTPRspInfoStruct,
is_last: bool) -> Any:
def OnSubTickByTick(
self,
ticker: XTPSpecificTickerStruct,
error_info: XTPRspInfoStruct,
is_last: bool,
) -> Any:
""""""
pass
def OnUnSubTickByTick(self, ticker: XTPSpecificTickerStruct, error_info: XTPRspInfoStruct,
is_last: bool) -> Any:
def OnUnSubTickByTick(
self,
ticker: XTPSpecificTickerStruct,
error_info: XTPRspInfoStruct,
is_last: bool,
) -> Any:
""""""
pass
@ -281,88 +322,106 @@ class XtpQuoteApi(API.QuoteSpi):
""""""
pass
def OnSubscribeAllMarketData(self, exchange_id: XTP_EXCHANGE_TYPE,
error_info: XTPRspInfoStruct) -> Any:
def OnSubscribeAllMarketData(
self, exchange_id: XTP_EXCHANGE_TYPE, error_info: XTPRspInfoStruct
) -> Any:
""""""
pass
def OnUnSubscribeAllMarketData(self, exchange_id: XTP_EXCHANGE_TYPE,
error_info: XTPRspInfoStruct) -> Any:
def OnUnSubscribeAllMarketData(
self, exchange_id: XTP_EXCHANGE_TYPE, error_info: XTPRspInfoStruct
) -> Any:
""""""
pass
def OnSubscribeAllOrderBook(self, exchange_id: XTP_EXCHANGE_TYPE,
error_info: XTPRspInfoStruct) -> Any:
def OnSubscribeAllOrderBook(
self, exchange_id: XTP_EXCHANGE_TYPE, error_info: XTPRspInfoStruct
) -> Any:
""""""
pass
def OnUnSubscribeAllOrderBook(self, exchange_id: XTP_EXCHANGE_TYPE,
error_info: XTPRspInfoStruct) -> Any:
def OnUnSubscribeAllOrderBook(
self, exchange_id: XTP_EXCHANGE_TYPE, error_info: XTPRspInfoStruct
) -> Any:
""""""
pass
def OnSubscribeAllTickByTick(self, exchange_id: XTP_EXCHANGE_TYPE,
error_info: XTPRspInfoStruct) -> Any:
def OnSubscribeAllTickByTick(
self, exchange_id: XTP_EXCHANGE_TYPE, error_info: XTPRspInfoStruct
) -> Any:
""""""
pass
def OnUnSubscribeAllTickByTick(self, exchange_id: XTP_EXCHANGE_TYPE,
error_info: XTPRspInfoStruct) -> Any:
def OnUnSubscribeAllTickByTick(
self, exchange_id: XTP_EXCHANGE_TYPE, error_info: XTPRspInfoStruct
) -> Any:
""""""
pass
def OnQueryAllTickers(self, ticker_info: XTPQuoteStaticInfo, error_info: XTPRspInfoStruct,
is_last: bool) -> Any:
""""""
return
# if self.check_error("查询合约", error_info):
# return
def OnQueryAllTickers(
self,
ticker_info: XTPQuoteStaticInfo,
error_info: XTPRspInfoStruct,
is_last: bool,
) -> Any:
if self.check_error("查询合约", error_info):
return
# contract = ContractData(
# symbol=ticker_info.ticker,
# exchange=EXCHANGE_XTP2VT[ticker_info.exchange_id],
# name=ticker_info.ticker_name,
# product=PRODUCT_XTP2VT[ticker_info.ticker_type],
# size=1,
# pricetick=ticker_info.pricetick,
# min_volume=ticker_info.buy_qty_unit,
# gateway_name=self.gateway_name
# )
# self.gateway.on_contract(contract)
contract = ContractData(
symbol=ticker_info.ticker,
exchange=EXCHANGE_XTP2VT[ticker_info.exchange_id],
name=ticker_info.ticker_name,
product=PRODUCT_XTP2VT[ticker_info.ticker_type],
size=1,
pricetick=ticker_info.pricetick,
min_volume=ticker_info.buy_qty_unit,
gateway_name=self.gateway_name,
)
self.gateway.on_contract(contract)
# symbol_name_map[contract.vt_symbol] = contract.name
symbol_name_map[contract.vt_symbol] = contract.name
def OnQueryTickersPriceInfo(self, ticker_info: XTPTickerPriceInfo, error_info: XTPRspInfoStruct,
is_last: bool) -> Any:
def OnQueryTickersPriceInfo(
self,
ticker_info: XTPTickerPriceInfo,
error_info: XTPRspInfoStruct,
is_last: bool,
) -> Any:
""""""
pass
def OnSubscribeAllOptionMarketData(self, exchange_id: XTP_EXCHANGE_TYPE,
error_info: XTPRspInfoStruct) -> Any:
def OnSubscribeAllOptionMarketData(
self, exchange_id: XTP_EXCHANGE_TYPE, error_info: XTPRspInfoStruct
) -> Any:
""""""
pass
def OnUnSubscribeAllOptionMarketData(self, exchange_id: XTP_EXCHANGE_TYPE,
error_info: XTPRspInfoStruct) -> Any:
def OnUnSubscribeAllOptionMarketData(
self, exchange_id: XTP_EXCHANGE_TYPE, error_info: XTPRspInfoStruct
) -> Any:
""""""
pass
def OnSubscribeAllOptionOrderBook(self, exchange_id: XTP_EXCHANGE_TYPE,
error_info: XTPRspInfoStruct) -> Any:
def OnSubscribeAllOptionOrderBook(
self, exchange_id: XTP_EXCHANGE_TYPE, error_info: XTPRspInfoStruct
) -> Any:
""""""
pass
def OnUnSubscribeAllOptionOrderBook(self, exchange_id: XTP_EXCHANGE_TYPE,
error_info: XTPRspInfoStruct) -> Any:
def OnUnSubscribeAllOptionOrderBook(
self, exchange_id: XTP_EXCHANGE_TYPE, error_info: XTPRspInfoStruct
) -> Any:
""""""
pass
def OnSubscribeAllOptionTickByTick(self, exchange_id: XTP_EXCHANGE_TYPE,
error_info: XTPRspInfoStruct) -> Any:
def OnSubscribeAllOptionTickByTick(
self, exchange_id: XTP_EXCHANGE_TYPE, error_info: XTPRspInfoStruct
) -> Any:
""""""
pass
def OnUnSubscribeAllOptionTickByTick(self, exchange_id: XTP_EXCHANGE_TYPE,
error_info: XTPRspInfoStruct) -> Any:
def OnUnSubscribeAllOptionTickByTick(
self, exchange_id: XTP_EXCHANGE_TYPE, error_info: XTPRspInfoStruct
) -> Any:
""""""
pass