[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 *
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)
\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():
@ -438,7 +439,7 @@ TAPIERROR_SUBSCRIBEQUOTE_CONTRACT_MAY_NOT_EXIST: int
TAPIERROR_QUOTEFRONT_UNKNOWN_PROTOCOL: int
def CreateITapTradeAPI(appInfo: ITapTrade.TapAPIApplicationInfo)->Tuple[ITapTrade.ITapTradeAPI,int]:
return "retv","iResult"
def FreeITapTradeAPI(apiObj: ITapTrade.ITapTradeAPI)->Any:
def FreeITapTradeAPI(apiObj: ITapTrade.ITapTradeAPI)->None:
...
def GetITapTradeAPIVersion()->str:
...
@ -450,7 +451,7 @@ def GetITapErrorDescribe(errorCode: int)->str:
...
def CreateTapQuoteAPI(appInfo: TapAPIApplicationInfo)->Tuple[ITapQuoteAPI,int]:
return "retv","iResult"
def FreeTapQuoteAPI(apiObj: ITapQuoteAPI)->Any:
def FreeTapQuoteAPI(apiObj: ITapQuoteAPI)->None:
...
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);
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("function_name", &autocxxpy::async_dispatch_exception::function_name);

View File

@ -3,11 +3,14 @@
#include <tuple>
#include <type_traits>
#include <optional>
#include <iostream>
#include "brigand.hpp"
#include "./brigand.hpp"
#include "utils/functional.hpp"
#include "dispatcher.hpp"
#include "./utils/functional.hpp"
#include "./dispatcher.hpp"
#include "./config/config.hpp"
#include "./wrappers/string_array.hpp"
namespace autocxxpy
{
@ -28,7 +31,7 @@ namespace autocxxpy
template<>
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);
default_callback_wrapper<method>::call(instance, 1);
@ -83,7 +86,9 @@ namespace autocxxpy
{}
pybind11::object instance;
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();
}
@ -97,9 +102,25 @@ namespace autocxxpy
inline static void handle_excepiton(const async_dispatch_exception&e)
{
if (custom_handler)
{
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;
}
}
inline static void set_handler(const handler_type& handler)

View File

@ -7,11 +7,12 @@ if typing.TYPE_CHECKING:
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)
\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():

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 (
CreateTapQuoteAPI,
GetITapTradeAPIVersion,
GetTapQuoteAPIVersion,
ITapQuoteAPINotify,
TapAPIApplicationInfo,
TapAPIContract,
TapAPIQuotLoginRspInfo,
TapAPIQuoteCommodityInfo,
TapAPIQuoteContractInfo,
TapAPIQuoteWhole,
TAPIERROR_SUCCEED,
TapAPIQuoteLoginAuth,
ITapQuoteAPI,
APIYNFLAG_NO,
FreeTapQuoteAPI,
)
from vnpy.api.itap.vnitap import (APIYNFLAG_NO, AsyncDispatchException, CreateTapQuoteAPI,
FreeTapQuoteAPI, ITapQuoteAPI, ITapQuoteAPINotify,
TAPIERROR_SUCCEED, TAPI_CALLPUT_FLAG_NONE,
TAPI_COMMODITY_TYPE_FUTURES, TAPI_COMMODITY_TYPE_INDEX,
TAPI_COMMODITY_TYPE_OPTION, TAPI_COMMODITY_TYPE_SPOT,
TAPI_COMMODITY_TYPE_STOCK, TapAPIApplicationInfo, TapAPIContract,
TapAPIQuotLoginRspInfo, TapAPIQuoteCommodityInfo,
TapAPIQuoteContractInfo, TapAPIQuoteLoginAuth, TapAPIQuoteWhole,
set_async_callback_exception_handler)
from vnpy.api.itap.error_codes import error_map
from vnpy.event import EventEngine
from vnpy.trader.constant import Exchange, Product
from vnpy.trader.gateway import BaseGateway
from vnpy.trader.object import (
CancelRequest,
HistoryRequest,
ContractData,
OrderRequest,
SubscribeRequest,
)
from vnpy.api.itap.error_codes import error_map
TickData)
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:
@ -36,15 +59,37 @@ def error_to_str(err_code: int) -> str:
return f"Unknown error({err_code})"
@dataclass()
class ContractExtraInfo:
"""
缓存一些ITAP API不直接提供的信息而且仅仅保存这些信息Symbol之类的作为键就不保存在这里面了
"""
name: str
commodity_type: int
commodity_no: str
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:
if TAPIERROR_SUCCEED == errorCode:
print("[+] login succeed!")
else:
print(f"[-] login failed! {error_to_str(errorCode)}")
if self.gateway.if_error_write_log(errorCode, "OnRspQryCommodity"):
self.gateway.write_log("行情服务器登录失败")
return
self.gateway.write_log("行情服务器登录成功")
def OnAPIReady(self) -> Any:
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:
print(f"OnDisconnect : {error_to_str(reasonCode)}")
@ -56,25 +101,96 @@ class QuoteNotify(ITapQuoteAPINotify):
isLast: int,
info: TapAPIQuoteCommodityInfo,
) -> 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(
self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteContractInfo
) -> 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(
self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteWhole
) -> Any:
print("OnRspSubscribeQuote")
if self.gateway.if_error_write_log(errorCode, "OnRspSubscribeQuote"):
return
def OnRspUnSubscribeQuote(
self, sessionID: int, errorCode: int, isLast: int, info: TapAPIContract
) -> Any:
print("OnRspUnSubscribeQuote")
if self.gateway.if_error_write_log(errorCode, "OnRspUnSubscribeQuote"):
return
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):
@ -85,11 +201,16 @@ class ITapGateway(BaseGateway):
"quote_username": "",
"quote_password": "",
}
exchanges = list(EXCHANGE_VT2ITAP.keys())
def __init__(self, event_engine: EventEngine):
super().__init__(event_engine, "ITAP")
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):
auth_code = setting["auth_code"]
@ -97,24 +218,25 @@ class ITapGateway(BaseGateway):
quote_port = setting["quote_port"]
quote_username = setting["quote_username"]
quote_password = setting["quote_password"]
print("quote version:", GetTapQuoteAPIVersion())
print("trade version:", GetITapTradeAPIVersion())
# print("quote version:", GetTapQuoteAPIVersion())
# print("trade version:", GetITapTradeAPIVersion())
ai = TapAPIApplicationInfo()
ai.AuthCode = auth_code
# iResult是输出参数Python中只能用返回值作为输出。
# 具体输出了哪些,看pyi的注释
# 具体输出了哪些,可以看pyi的注释
api, iResult = CreateTapQuoteAPI(ai)
if api is None:
error_code = iResult # 看API文档的注释iResult就是错误代码
print(f"CreateTapQuoteAPI error: {error_to_str(error_code)}")
return # todo: error report
self.if_error_write_log(iResult, "CreateTapQuoteAPI")
return
assert self.api is None
self.api = api
api.SetAPINotify(self.quote_notify)
error_code: int = api.SetHostAddress(quote_host, quote_port)
if TAPIERROR_SUCCEED != error_code:
print(f"SetHostAddress error: {error_to_str(error_code)}")
if self.if_error_write_log(error_code, "SetHostAddress"):
return
# login
@ -124,10 +246,8 @@ class ITapGateway(BaseGateway):
la.ISDDA = APIYNFLAG_NO
la.ISModifyPassword = APIYNFLAG_NO
error_code: int = api.Login(la) # async
if TAPIERROR_SUCCEED != error_code:
print(f"Login error: {error_to_str(error_code)}")
if self.if_error_write_log(error_code, "api.Login"):
return
self.api = api
def close(self):
self.api.SetAPINotify(None)
@ -137,7 +257,17 @@ class ITapGateway(BaseGateway):
pass
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:
pass
@ -150,3 +280,22 @@ class ITapGateway(BaseGateway):
def query_position(self):
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