[Add] ITapGateway: Added support for Market subscription

[Mod] use newer autocxxpy: make error handing better and make its hint(generated pyi code) better.
This commit is contained in:
nanoric 2019-05-21 15:25:23 +08:00
parent 06b16cb0b3
commit c580d3cb76
6 changed files with 284 additions and 112 deletions

Binary file not shown.

View File

@ -7,11 +7,12 @@ if typing.TYPE_CHECKING:
from .vnitap import * from .vnitap import *
def set_async_callback_exception_handler(handler: Callable[[Exception, object, str], bool]): def set_async_callback_exception_handler(handler: Callable[[AsyncDispatchException], bool]):
""" """
set a customize exception handler for async callback in this module(pyd) set a customize exception handler for async callback in this module(pyd)
\a handler should return True if it handles that exception, \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.
:note: If the return value of \a handler is not True, exception will be re-thrown.
""" """
... ...
@ -179,21 +180,21 @@ class ITapQuoteAPINotify():
def OnRspLogin(self, errorCode: int, info: TapAPIQuotLoginRspInfo)->Any: def OnRspLogin(self, errorCode: int, info: TapAPIQuotLoginRspInfo)->None:
... ...
def OnAPIReady(self, )->Any: def OnAPIReady(self, )->None:
... ...
def OnDisconnect(self, reasonCode: int)->Any: def OnDisconnect(self, reasonCode: int)->None:
... ...
def OnRspQryCommodity(self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteCommodityInfo)->Any: def OnRspQryCommodity(self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteCommodityInfo)->None:
... ...
def OnRspQryContract(self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteContractInfo)->Any: def OnRspQryContract(self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteContractInfo)->None:
... ...
def OnRspSubscribeQuote(self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteWhole)->Any: def OnRspSubscribeQuote(self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteWhole)->None:
... ...
def OnRspUnSubscribeQuote(self, sessionID: int, errorCode: int, isLast: int, info: TapAPIContract)->Any: def OnRspUnSubscribeQuote(self, sessionID: int, errorCode: int, isLast: int, info: TapAPIContract)->None:
... ...
def OnRtnQuote(self, info: TapAPIQuoteWhole)->Any: def OnRtnQuote(self, info: TapAPIQuoteWhole)->None:
... ...
class ITapQuoteAPI(): class ITapQuoteAPI():
@ -438,7 +439,7 @@ TAPIERROR_SUBSCRIBEQUOTE_CONTRACT_MAY_NOT_EXIST: int
TAPIERROR_QUOTEFRONT_UNKNOWN_PROTOCOL: int TAPIERROR_QUOTEFRONT_UNKNOWN_PROTOCOL: int
def CreateITapTradeAPI(appInfo: ITapTrade.TapAPIApplicationInfo)->Tuple[ITapTrade.ITapTradeAPI,int]: def CreateITapTradeAPI(appInfo: ITapTrade.TapAPIApplicationInfo)->Tuple[ITapTrade.ITapTradeAPI,int]:
return "retv","iResult" return "retv","iResult"
def FreeITapTradeAPI(apiObj: ITapTrade.ITapTradeAPI)->Any: def FreeITapTradeAPI(apiObj: ITapTrade.ITapTradeAPI)->None:
... ...
def GetITapTradeAPIVersion()->str: def GetITapTradeAPIVersion()->str:
... ...
@ -450,7 +451,7 @@ def GetITapErrorDescribe(errorCode: int)->str:
... ...
def CreateTapQuoteAPI(appInfo: TapAPIApplicationInfo)->Tuple[ITapQuoteAPI,int]: def CreateTapQuoteAPI(appInfo: TapAPIApplicationInfo)->Tuple[ITapQuoteAPI,int]:
return "retv","iResult" return "retv","iResult"
def FreeTapQuoteAPI(apiObj: ITapQuoteAPI)->Any: def FreeTapQuoteAPI(apiObj: ITapQuoteAPI)->None:
... ...
def GetTapQuoteAPIVersion()->str: def GetTapQuoteAPIVersion()->str:
... ...

View File

@ -27,7 +27,7 @@ void init_dispatcher(pybind11::module &m)
m.def("set_async_callback_exception_handler", &autocxxpy::async_callback_exception_handler::set_handler); m.def("set_async_callback_exception_handler", &autocxxpy::async_callback_exception_handler::set_handler);
pybind11::class_<autocxxpy::async_dispatch_exception> c(m, "AsyncDispatchException"); pybind11::class_<autocxxpy::async_dispatch_exception> c(m, "AsyncDispatchException");
c.def_property("what", &autocxxpy::async_dispatch_exception::what, nullptr); c.def_property_readonly("what", &autocxxpy::async_dispatch_exception::what_mutable);
c.def_readonly("instance", &autocxxpy::async_dispatch_exception::instance); c.def_readonly("instance", &autocxxpy::async_dispatch_exception::instance);
c.def_readonly("function_name", &autocxxpy::async_dispatch_exception::function_name); c.def_readonly("function_name", &autocxxpy::async_dispatch_exception::function_name);

View File

@ -3,11 +3,14 @@
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <optional> #include <optional>
#include <iostream>
#include "brigand.hpp" #include "./brigand.hpp"
#include "utils/functional.hpp" #include "./utils/functional.hpp"
#include "dispatcher.hpp" #include "./dispatcher.hpp"
#include "./config/config.hpp"
#include "./wrappers/string_array.hpp"
namespace autocxxpy namespace autocxxpy
{ {
@ -28,7 +31,7 @@ namespace autocxxpy
template<> template<>
struct callback_wrapper<static_cast<int(A::*)(int)>(&A::func2)> struct callback_wrapper<static_cast<int(A::*)(int)>(&A::func2)>
{ {
inline static void call(A *instance, float) inline static void call(A *instance, const char *py_func_name, float)
{ {
constexpr auto method = static_cast<int(A::*)(int)>(&A::func2); constexpr auto method = static_cast<int(A::*)(int)>(&A::func2);
default_callback_wrapper<method>::call(instance, 1); default_callback_wrapper<method>::call(instance, 1);
@ -83,7 +86,9 @@ namespace autocxxpy
{} {}
pybind11::object instance; pybind11::object instance;
std::string function_name; std::string function_name;
inline const char* what() noexcept
// mutable version of what() for pybind11 to make it happy
inline const char* what_mutable() noexcept
{ {
return std::exception::what(); return std::exception::what();
} }
@ -98,7 +103,23 @@ namespace autocxxpy
{ {
if (custom_handler) if (custom_handler)
{ {
custom_handler(e); try
{
custom_handler(e);
}
catch (pybind11::error_already_set & e2)
{
std::cerr << "error while calling custom async callback exception handler:" << std::endl;
std::cerr << e2.what() << std::endl;
std::cerr << "while handling following exception:" << std::endl;
std::cerr << e.what() << std::endl;
}
}
else
{
std::cerr << e.what() << std::endl;
std::cerr << "custom async callback exception handler not set." << std::endl;
std::cerr << "Call set_async_callback_exception_handler() to set it. " << std::endl;
} }
} }

View File

@ -7,11 +7,12 @@ if typing.TYPE_CHECKING:
from .vnitap import * from .vnitap import *
def set_async_callback_exception_handler(handler: Callable[[Exception, object, str], bool]): def set_async_callback_exception_handler(handler: Callable[[AsyncDispatchException], bool]):
""" """
set a customize exception handler for async callback in this module(pyd) set a customize exception handler for async callback in this module(pyd)
\a handler should return True if it handles that exception, \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.
:note: If the return value of \a handler is not True, exception will be re-thrown.
""" """
... ...
@ -1129,105 +1130,105 @@ class ITapTradeAPINotify():
def OnConnect(self, )->Any: def OnConnect(self, )->None:
... ...
def OnRspLogin(self, errorCode: int, loginRspInfo: ITapTrade.TapAPITradeLoginRspInfo)->Any: def OnRspLogin(self, errorCode: int, loginRspInfo: ITapTrade.TapAPITradeLoginRspInfo)->None:
... ...
def OnRtnContactInfo(self, errorCode: int, isLast: int, ContactInfo: str)->Any: def OnRtnContactInfo(self, errorCode: int, isLast: int, ContactInfo: str)->None:
... ...
def OnRspRequestVertificateCode(self, sessionID: int, errorCode: int, rsp: ITapTrade.TapAPIRequestVertificateCodeRsp)->Any: def OnRspRequestVertificateCode(self, sessionID: int, errorCode: int, rsp: ITapTrade.TapAPIRequestVertificateCodeRsp)->None:
... ...
def OnExpriationDate(self, date: str, days: int)->Any: def OnExpriationDate(self, date: str, days: int)->None:
... ...
def OnAPIReady(self, errorCode: int)->Any: def OnAPIReady(self, errorCode: int)->None:
... ...
def OnDisconnect(self, reasonCode: int)->Any: def OnDisconnect(self, reasonCode: int)->None:
... ...
def OnRspChangePassword(self, sessionID: int, errorCode: int)->Any: def OnRspChangePassword(self, sessionID: int, errorCode: int)->None:
... ...
def OnRspAuthPassword(self, sessionID: int, errorCode: int)->Any: def OnRspAuthPassword(self, sessionID: int, errorCode: int)->None:
... ...
def OnRspQryTradingDate(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPITradingCalendarQryRsp)->Any: def OnRspQryTradingDate(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPITradingCalendarQryRsp)->None:
... ...
def OnRspSetReservedInfo(self, sessionID: int, errorCode: int, info: str)->Any: def OnRspSetReservedInfo(self, sessionID: int, errorCode: int, info: str)->None:
... ...
def OnRspQryAccount(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIAccountInfo)->Any: def OnRspQryAccount(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIAccountInfo)->None:
... ...
def OnRspQryFund(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIFundData)->Any: def OnRspQryFund(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIFundData)->None:
... ...
def OnRtnFund(self, info: ITapTrade.TapAPIFundData)->Any: def OnRtnFund(self, info: ITapTrade.TapAPIFundData)->None:
... ...
def OnRspQryExchange(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIExchangeInfo)->Any: def OnRspQryExchange(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIExchangeInfo)->None:
... ...
def OnRspQryCommodity(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPICommodityInfo)->Any: def OnRspQryCommodity(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPICommodityInfo)->None:
... ...
def OnRspQryContract(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPITradeContractInfo)->Any: def OnRspQryContract(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPITradeContractInfo)->None:
... ...
def OnRtnContract(self, info: ITapTrade.TapAPITradeContractInfo)->Any: def OnRtnContract(self, info: ITapTrade.TapAPITradeContractInfo)->None:
... ...
def OnRspOrderAction(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderActionRsp)->Any: def OnRspOrderAction(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderActionRsp)->None:
... ...
def OnRtnOrder(self, info: ITapTrade.TapAPIOrderInfoNotice)->Any: def OnRtnOrder(self, info: ITapTrade.TapAPIOrderInfoNotice)->None:
... ...
def OnRspQryOrder(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIOrderInfo)->Any: def OnRspQryOrder(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIOrderInfo)->None:
... ...
def OnRspQryOrderProcess(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIOrderInfo)->Any: def OnRspQryOrderProcess(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIOrderInfo)->None:
... ...
def OnRspQryFill(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIFillInfo)->Any: def OnRspQryFill(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIFillInfo)->None:
... ...
def OnRtnFill(self, info: ITapTrade.TapAPIFillInfo)->Any: def OnRtnFill(self, info: ITapTrade.TapAPIFillInfo)->None:
... ...
def OnRspQryPosition(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIPositionInfo)->Any: def OnRspQryPosition(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIPositionInfo)->None:
... ...
def OnRtnPosition(self, info: ITapTrade.TapAPIPositionInfo)->Any: def OnRtnPosition(self, info: ITapTrade.TapAPIPositionInfo)->None:
... ...
def OnRspQryPositionSummary(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIPositionSummary)->Any: def OnRspQryPositionSummary(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIPositionSummary)->None:
... ...
def OnRtnPositionSummary(self, info: ITapTrade.TapAPIPositionSummary)->Any: def OnRtnPositionSummary(self, info: ITapTrade.TapAPIPositionSummary)->None:
... ...
def OnRtnPositionProfit(self, info: ITapTrade.TapAPIPositionProfitNotice)->Any: def OnRtnPositionProfit(self, info: ITapTrade.TapAPIPositionProfitNotice)->None:
... ...
def OnRspQryCurrency(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPICurrencyInfo)->Any: def OnRspQryCurrency(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPICurrencyInfo)->None:
... ...
def OnRspQryTradeMessage(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPITradeMessage)->Any: def OnRspQryTradeMessage(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPITradeMessage)->None:
... ...
def OnRtnTradeMessage(self, info: ITapTrade.TapAPITradeMessage)->Any: def OnRtnTradeMessage(self, info: ITapTrade.TapAPITradeMessage)->None:
... ...
def OnRspQryHisOrder(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIHisOrderQryRsp)->Any: def OnRspQryHisOrder(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIHisOrderQryRsp)->None:
... ...
def OnRspQryHisOrderProcess(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIHisOrderQryRsp)->Any: def OnRspQryHisOrderProcess(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIHisOrderQryRsp)->None:
... ...
def OnRspQryHisMatch(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIHisMatchQryRsp)->Any: def OnRspQryHisMatch(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIHisMatchQryRsp)->None:
... ...
def OnRspQryHisPosition(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIHisPositionQryRsp)->Any: def OnRspQryHisPosition(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIHisPositionQryRsp)->None:
... ...
def OnRspQryHisDelivery(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIHisDeliveryQryRsp)->Any: def OnRspQryHisDelivery(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIHisDeliveryQryRsp)->None:
... ...
def OnRspQryAccountCashAdjust(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIAccountCashAdjustQryRsp)->Any: def OnRspQryAccountCashAdjust(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIAccountCashAdjustQryRsp)->None:
... ...
def OnRspQryBill(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIBillQryRsp)->Any: def OnRspQryBill(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIBillQryRsp)->None:
... ...
def OnRspQryAccountFeeRent(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIAccountFeeRentQryRsp)->Any: def OnRspQryAccountFeeRent(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIAccountFeeRentQryRsp)->None:
... ...
def OnRspQryAccountMarginRent(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIAccountMarginRentQryRsp)->Any: def OnRspQryAccountMarginRent(self, sessionID: int, errorCode: int, isLast: int, info: ITapTrade.TapAPIAccountMarginRentQryRsp)->None:
... ...
def OnRspHKMarketOrderInsert(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderMarketInsertRsp)->Any: def OnRspHKMarketOrderInsert(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderMarketInsertRsp)->None:
... ...
def OnRspHKMarketOrderDelete(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderMarketInsertRsp)->Any: def OnRspHKMarketOrderDelete(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderMarketInsertRsp)->None:
... ...
def OnHKMarketQuoteNotice(self, info: ITapTrade.TapAPIOrderQuoteMarketNotice)->Any: def OnHKMarketQuoteNotice(self, info: ITapTrade.TapAPIOrderQuoteMarketNotice)->None:
... ...
def OnRspOrderLocalRemove(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderLocalRemoveRsp)->Any: def OnRspOrderLocalRemove(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderLocalRemoveRsp)->None:
... ...
def OnRspOrderLocalInput(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderInfo)->Any: def OnRspOrderLocalInput(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderInfo)->None:
... ...
def OnRspOrderLocalModify(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderInfo)->Any: def OnRspOrderLocalModify(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderInfo)->None:
... ...
def OnRspOrderLocalTransfer(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderInfo)->Any: def OnRspOrderLocalTransfer(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIOrderInfo)->None:
... ...
def OnRspFillLocalInput(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIFillLocalInputReq)->Any: def OnRspFillLocalInput(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIFillLocalInputReq)->None:
... ...
def OnRspFillLocalRemove(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIFillLocalRemoveReq)->Any: def OnRspFillLocalRemove(self, sessionID: int, errorCode: int, info: ITapTrade.TapAPIFillLocalRemoveReq)->None:
... ...
class ITapTradeAPI(): class ITapTradeAPI():

View File

@ -1,32 +1,55 @@
from typing import Any, Sequence, Optional import sys
from dataclasses import dataclass
from datetime import datetime
from typing import Any, Dict, Optional, Tuple
from vnpy.api.itap.vnitap import ( from vnpy.api.itap.vnitap import (APIYNFLAG_NO, AsyncDispatchException, CreateTapQuoteAPI,
CreateTapQuoteAPI, FreeTapQuoteAPI, ITapQuoteAPI, ITapQuoteAPINotify,
GetITapTradeAPIVersion, TAPIERROR_SUCCEED, TAPI_CALLPUT_FLAG_NONE,
GetTapQuoteAPIVersion, TAPI_COMMODITY_TYPE_FUTURES, TAPI_COMMODITY_TYPE_INDEX,
ITapQuoteAPINotify, TAPI_COMMODITY_TYPE_OPTION, TAPI_COMMODITY_TYPE_SPOT,
TapAPIApplicationInfo, TAPI_COMMODITY_TYPE_STOCK, TapAPIApplicationInfo, TapAPIContract,
TapAPIContract, TapAPIQuotLoginRspInfo, TapAPIQuoteCommodityInfo,
TapAPIQuotLoginRspInfo, TapAPIQuoteContractInfo, TapAPIQuoteLoginAuth, TapAPIQuoteWhole,
TapAPIQuoteCommodityInfo, set_async_callback_exception_handler)
TapAPIQuoteContractInfo,
TapAPIQuoteWhole,
TAPIERROR_SUCCEED,
TapAPIQuoteLoginAuth,
ITapQuoteAPI,
APIYNFLAG_NO,
FreeTapQuoteAPI,
)
from vnpy.api.itap.error_codes import error_map
from vnpy.event import EventEngine from vnpy.event import EventEngine
from vnpy.trader.constant import Exchange, Product
from vnpy.trader.gateway import BaseGateway from vnpy.trader.gateway import BaseGateway
from vnpy.trader.object import ( from vnpy.trader.object import (
CancelRequest, CancelRequest,
HistoryRequest, ContractData,
OrderRequest, OrderRequest,
SubscribeRequest, SubscribeRequest,
) TickData)
from vnpy.api.itap.error_codes import error_map
PRODUCT_TYPE_ITAP2VT = {
TAPI_COMMODITY_TYPE_SPOT: Product.SPOT,
TAPI_COMMODITY_TYPE_FUTURES: Product.FUTURES,
TAPI_COMMODITY_TYPE_OPTION: Product.OPTION,
TAPI_COMMODITY_TYPE_INDEX: Product.INDEX,
TAPI_COMMODITY_TYPE_STOCK: Product.EQUITY,
}
EXCHANGE_ITAP2VT = {
'SGX': Exchange.SGX,
'INE': Exchange.INE,
'APEX': Exchange.APEX,
'NYMEX': Exchange.NYMEX,
'LME': Exchange.LME,
'COMEX': Exchange.COMEX, # verify: I added this exchange in vnpy, is this correct?
'CBOT': Exchange.CBOT,
'HKEX': Exchange.HKFE, # verify: is this correct?,
'CME': Exchange.CME,
}
EXCHANGE_VT2ITAP = {v: k for k, v in EXCHANGE_ITAP2VT.items()}
def parse_datetime(dt_str: str):
# todo: 我不知道这个时间所用的是哪种时间
# yyyy-MM-dd hh:nn:ss.xxx
return datetime.strptime(dt_str, "%Y-%m-%d %H:%M:%S.%f")
def error_to_str(err_code: int) -> str: def error_to_str(err_code: int) -> str:
@ -36,15 +59,37 @@ def error_to_str(err_code: int) -> str:
return f"Unknown error({err_code})" return f"Unknown error({err_code})"
@dataclass()
class ContractExtraInfo:
"""
缓存一些ITAP API不直接提供的信息而且仅仅保存这些信息Symbol之类的作为键就不保存在这里面了
"""
name: str
commodity_type: int
commodity_no: str
class QuoteNotify(ITapQuoteAPINotify): class QuoteNotify(ITapQuoteAPINotify):
def __init__(self, gateway: "ITapGateway"):
super().__init__()
self.gateway = gateway
@property
def api(self) -> ITapQuoteAPI:
return self.gateway.api
def OnRspLogin(self, errorCode: int, info: TapAPIQuotLoginRspInfo) -> Any: def OnRspLogin(self, errorCode: int, info: TapAPIQuotLoginRspInfo) -> Any:
if TAPIERROR_SUCCEED == errorCode: if self.gateway.if_error_write_log(errorCode, "OnRspQryCommodity"):
print("[+] login succeed!") self.gateway.write_log("行情服务器登录失败")
else: return
print(f"[-] login failed! {error_to_str(errorCode)}") self.gateway.write_log("行情服务器登录成功")
def OnAPIReady(self) -> Any: def OnAPIReady(self) -> Any:
print("OnApiReady") print("OnApiReady")
error_code, sessionId = self.api.QryCommodity()
if self.gateway.if_error_write_log(error_code, "api.QryCommodity"):
return
def OnDisconnect(self, reasonCode: int) -> Any: def OnDisconnect(self, reasonCode: int) -> Any:
print(f"OnDisconnect : {error_to_str(reasonCode)}") print(f"OnDisconnect : {error_to_str(reasonCode)}")
@ -56,25 +101,96 @@ class QuoteNotify(ITapQuoteAPINotify):
isLast: int, isLast: int,
info: TapAPIQuoteCommodityInfo, info: TapAPIQuoteCommodityInfo,
) -> Any: ) -> Any:
print(f"OnRspQryCommodity : {error_to_str(errorCode)}") if self.gateway.if_error_write_log(errorCode, "OnRspQryCommodity"):
return
error_code, session_id = self.api.QryContract(info.Commodity)
if self.gateway.if_error_write_log(error_code, "api.QryContract"):
return
def OnRspQryContract( def OnRspQryContract(
self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteContractInfo self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteContractInfo
) -> Any: ) -> Any:
print("OnRspQryContract") if self.gateway.if_error_write_log(errorCode, "OnRspQryContract"):
return
if info is not None: # isLast == True ==> info is None
symbol = info.Contract.ContractNo1 # what's the different between No1 and No2?
exchange = EXCHANGE_ITAP2VT[info.Contract.Commodity.ExchangeNo]
name = info.ContractName
contract_data = ContractData(
gateway_name=self.gateway.gateway_name,
symbol=symbol,
exchange=exchange,
name=name,
product=PRODUCT_TYPE_ITAP2VT.get(info.ContractType, Product.EQUITY),
size=1, # verify: no key for this
pricetick=1, # verify: no key for this
min_volume=1, # verify: no key for this
# ...
)
contract_extra_info = ContractExtraInfo(
name=name,
commodity_type=info.Contract.Commodity.CommodityType,
commodity_no=info.Contract.Commodity.CommodityNo,
)
self.gateway.contract_extra_infos[(symbol, exchange)] = contract_extra_info
self.gateway.on_contract(contract_data)
def OnRspSubscribeQuote( def OnRspSubscribeQuote(
self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteWhole self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteWhole
) -> Any: ) -> Any:
print("OnRspSubscribeQuote") print("OnRspSubscribeQuote")
if self.gateway.if_error_write_log(errorCode, "OnRspSubscribeQuote"):
return
def OnRspUnSubscribeQuote( def OnRspUnSubscribeQuote(
self, sessionID: int, errorCode: int, isLast: int, info: TapAPIContract self, sessionID: int, errorCode: int, isLast: int, info: TapAPIContract
) -> Any: ) -> Any:
print("OnRspUnSubscribeQuote") print("OnRspUnSubscribeQuote")
if self.gateway.if_error_write_log(errorCode, "OnRspUnSubscribeQuote"):
return
def OnRtnQuote(self, info: TapAPIQuoteWhole) -> Any: def OnRtnQuote(self, info: TapAPIQuoteWhole) -> Any:
print("OnRtnQuote") symbol = info.Contract.ContractNo1
exchange = EXCHANGE_ITAP2VT[info.Contract.Commodity.ExchangeNo]
extra_info = self.gateway.contract_extra_infos[(symbol, exchange)]
tick = TickData(
gateway_name=self.gateway.gateway_name,
symbol=symbol,
exchange=exchange,
datetime=parse_datetime(info.DateTimeStamp),
name=extra_info.name,
volume=info.QTotalQty,
last_price=info.QLastPrice,
last_volume=info.QLastQty,
limit_up=info.QLimitUpPrice,
limit_down=info.QLimitDownPrice,
open_price=info.QOpeningPrice,
high_price=info.QHighPrice,
low_price=info.QLowPrice,
pre_close=info.QPreClosingPrice,
bid_price_1=info.QBidPrice[0],
bid_price_2=info.QBidPrice[1],
bid_price_3=info.QBidPrice[3],
bid_price_4=info.QBidPrice[4],
bid_price_5=info.QBidPrice[5],
ask_price_1=info.QAskPrice[0],
ask_price_2=info.QAskPrice[1],
ask_price_3=info.QAskPrice[2],
ask_price_4=info.QAskPrice[3],
ask_price_5=info.QAskPrice[4],
bid_volume_1=info.QBidQty[0],
bid_volume_2=info.QBidQty[1],
bid_volume_3=info.QBidQty[2],
bid_volume_4=info.QBidQty[3],
bid_volume_5=info.QBidQty[4],
ask_volume_1=info.QAskQty[0],
ask_volume_2=info.QAskQty[1],
ask_volume_3=info.QAskQty[2],
ask_volume_4=info.QAskQty[3],
ask_volume_5=info.QAskQty[4],
)
self.gateway.on_tick(tick=tick)
class ITapGateway(BaseGateway): class ITapGateway(BaseGateway):
@ -85,11 +201,16 @@ class ITapGateway(BaseGateway):
"quote_username": "", "quote_username": "",
"quote_password": "", "quote_password": "",
} }
exchanges = list(EXCHANGE_VT2ITAP.keys())
def __init__(self, event_engine: EventEngine): def __init__(self, event_engine: EventEngine):
super().__init__(event_engine, "ITAP") super().__init__(event_engine, "ITAP")
self.api: Optional[ITapQuoteAPI] = None self.api: Optional[ITapQuoteAPI] = None
self.quote_notify = QuoteNotify() self.quote_notify = QuoteNotify(self)
# [symbol, exchange] : [CommodityType, CommodityNo]
self.contract_extra_infos: Dict[Tuple[str, Exchange], ContractExtraInfo] = {}
set_async_callback_exception_handler(self._async_callback_exception_handler)
def connect(self, setting: dict): def connect(self, setting: dict):
auth_code = setting["auth_code"] auth_code = setting["auth_code"]
@ -97,24 +218,25 @@ class ITapGateway(BaseGateway):
quote_port = setting["quote_port"] quote_port = setting["quote_port"]
quote_username = setting["quote_username"] quote_username = setting["quote_username"]
quote_password = setting["quote_password"] quote_password = setting["quote_password"]
print("quote version:", GetTapQuoteAPIVersion()) # print("quote version:", GetTapQuoteAPIVersion())
print("trade version:", GetITapTradeAPIVersion()) # print("trade version:", GetITapTradeAPIVersion())
ai = TapAPIApplicationInfo() ai = TapAPIApplicationInfo()
ai.AuthCode = auth_code ai.AuthCode = auth_code
# iResult是输出参数Python中只能用返回值作为输出。 # iResult是输出参数Python中只能用返回值作为输出。
# 具体输出了哪些,看pyi的注释 # 具体输出了哪些,可以看pyi的注释
api, iResult = CreateTapQuoteAPI(ai) api, iResult = CreateTapQuoteAPI(ai)
if api is None: if api is None:
error_code = iResult # 看API文档的注释iResult就是错误代码 self.if_error_write_log(iResult, "CreateTapQuoteAPI")
print(f"CreateTapQuoteAPI error: {error_to_str(error_code)}") return
return # todo: error report
assert self.api is None
self.api = api
api.SetAPINotify(self.quote_notify) api.SetAPINotify(self.quote_notify)
error_code: int = api.SetHostAddress(quote_host, quote_port) error_code: int = api.SetHostAddress(quote_host, quote_port)
if TAPIERROR_SUCCEED != error_code: if self.if_error_write_log(error_code, "SetHostAddress"):
print(f"SetHostAddress error: {error_to_str(error_code)}")
return return
# login # login
@ -124,10 +246,8 @@ class ITapGateway(BaseGateway):
la.ISDDA = APIYNFLAG_NO la.ISDDA = APIYNFLAG_NO
la.ISModifyPassword = APIYNFLAG_NO la.ISModifyPassword = APIYNFLAG_NO
error_code: int = api.Login(la) # async error_code: int = api.Login(la) # async
if TAPIERROR_SUCCEED != error_code: if self.if_error_write_log(error_code, "api.Login"):
print(f"Login error: {error_to_str(error_code)}")
return return
self.api = api
def close(self): def close(self):
self.api.SetAPINotify(None) self.api.SetAPINotify(None)
@ -137,7 +257,17 @@ class ITapGateway(BaseGateway):
pass pass
def subscribe(self, req: SubscribeRequest): def subscribe(self, req: SubscribeRequest):
pass contract = TapAPIContract()
extra_info = self.contract_extra_infos[(req.symbol, req.exchange)]
contract.Commodity.ExchangeNo = EXCHANGE_VT2ITAP[req.exchange]
contract.Commodity.CommodityType = extra_info.commodity_type
contract.Commodity.CommodityNo = extra_info.commodity_no
contract.ContractNo1 = req.symbol
contract.CallOrPutFlag1 = TAPI_CALLPUT_FLAG_NONE
contract.CallOrPutFlag2 = TAPI_CALLPUT_FLAG_NONE
error_code, session_id = self.api.SubscribeQuote(contract)
if self.if_error_write_log(error_code, "api.SubscribeQuote"):
return
def send_order(self, req: OrderRequest) -> str: def send_order(self, req: OrderRequest) -> str:
pass pass
@ -150,3 +280,22 @@ class ITapGateway(BaseGateway):
def query_position(self): def query_position(self):
pass pass
def _async_callback_exception_handler(self, e: AsyncDispatchException):
error_str = (f"发生内部错误,位置:\n{e.instance}.{e.function_name},详细信息:\n"
f"{e.what}\n"
)
print(error_str, file=sys.stderr, flush=True)
self.write_log(error_str)
return True
def if_error_write_log(self, error_code: int, function: str):
"""
检查返回值如果发生错误调用write_log报告该错误并返回True
:return: 若有错误发生返回True
"""
if TAPIERROR_SUCCEED != error_code:
error_msg = f"调用{function}时出错:\n{error_to_str(error_code)}"
self.write_log(error_msg)
print(error_msg, file=sys.stderr)
return True