[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:
parent
06b16cb0b3
commit
c580d3cb76
Binary file not shown.
@ -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:
|
||||||
...
|
...
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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():
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user