[Mod] complete test of QuoteApi

This commit is contained in:
vn.py 2019-06-07 17:33:19 +08:00
parent 260e270c22
commit 18b4162f4f
5 changed files with 378 additions and 218 deletions

View File

@ -1,31 +1,31 @@
from vnpy.event import EventEngine
from vnpy.trader.engine import MainEngine
from vnpy.trader.ui import MainWindow, create_qapp
from vnpy.gateway.bitmex import BitmexGateway
from vnpy.gateway.futu import FutuGateway
from vnpy.gateway.ib import IbGateway
from vnpy.gateway.ctp import CtpGateway
# from vnpy.gateway.ctptest import CtptestGateway
from vnpy.gateway.femas import FemasGateway
from vnpy.gateway.tiger import TigerGateway
from vnpy.gateway.oes import OesGateway
from vnpy.gateway.okex import OkexGateway
from vnpy.gateway.huobi import HuobiGateway
from vnpy.gateway.bitfinex import BitfinexGateway
from vnpy.gateway.onetoken import OnetokenGateway
from vnpy.gateway.okexf import OkexfGateway
from vnpy.gateway.xtp import XtpGateway
from vnpy.gateway.hbdm import HbdmGateway
# from vnpy.gateway.bitmex import BitmexGateway
# from vnpy.gateway.futu import FutuGateway
# from vnpy.gateway.ib import IbGateway
# from vnpy.gateway.ctp import CtpGateway
# # from vnpy.gateway.ctptest import CtptestGateway
# from vnpy.gateway.femas import FemasGateway
# from vnpy.gateway.tiger import TigerGateway
# from vnpy.gateway.oes import OesGateway
# from vnpy.gateway.okex import OkexGateway
# from vnpy.gateway.huobi import HuobiGateway
# from vnpy.gateway.bitfinex import BitfinexGateway
# from vnpy.gateway.onetoken import OnetokenGateway
# from vnpy.gateway.okexf import OkexfGateway
# from vnpy.gateway.xtp import XtpGateway
# from vnpy.gateway.hbdm import HbdmGateway
from vnpy.gateway.tap import TapGateway
from vnpy.app.cta_strategy import CtaStrategyApp
from vnpy.app.csv_loader import CsvLoaderApp
from vnpy.app.algo_trading import AlgoTradingApp
from vnpy.app.cta_backtester import CtaBacktesterApp
from vnpy.app.data_recorder import DataRecorderApp
from vnpy.app.risk_manager import RiskManagerApp
# from vnpy.app.cta_strategy import CtaStrategyApp
# from vnpy.app.csv_loader import CsvLoaderApp
# from vnpy.app.algo_trading import AlgoTradingApp
# from vnpy.app.cta_backtester import CtaBacktesterApp
# from vnpy.app.data_recorder import DataRecorderApp
# from vnpy.app.risk_manager import RiskManagerApp
def main():
@ -35,28 +35,29 @@ def main():
event_engine = EventEngine()
main_engine = MainEngine(event_engine)
main_engine.add_gateway(XtpGateway)
main_engine.add_gateway(CtpGateway)
# main_engine.add_gateway(CtptestGateway)
main_engine.add_gateway(FemasGateway)
main_engine.add_gateway(IbGateway)
main_engine.add_gateway(FutuGateway)
main_engine.add_gateway(BitmexGateway)
main_engine.add_gateway(TigerGateway)
main_engine.add_gateway(OesGateway)
main_engine.add_gateway(OkexGateway)
main_engine.add_gateway(HuobiGateway)
main_engine.add_gateway(BitfinexGateway)
main_engine.add_gateway(OnetokenGateway)
main_engine.add_gateway(OkexfGateway)
main_engine.add_gateway(HbdmGateway)
# main_engine.add_gateway(XtpGateway)
# main_engine.add_gateway(CtpGateway)
# # main_engine.add_gateway(CtptestGateway)
# main_engine.add_gateway(FemasGateway)
# main_engine.add_gateway(IbGateway)
# main_engine.add_gateway(FutuGateway)
# main_engine.add_gateway(BitmexGateway)
# main_engine.add_gateway(TigerGateway)
# main_engine.add_gateway(OesGateway)
# main_engine.add_gateway(OkexGateway)
# main_engine.add_gateway(HuobiGateway)
# main_engine.add_gateway(BitfinexGateway)
# main_engine.add_gateway(OnetokenGateway)
# main_engine.add_gateway(OkexfGateway)
# main_engine.add_gateway(HbdmGateway)
main_engine.add_gateway(TapGateway)
main_engine.add_app(CtaStrategyApp)
main_engine.add_app(CtaBacktesterApp)
main_engine.add_app(CsvLoaderApp)
main_engine.add_app(AlgoTradingApp)
main_engine.add_app(DataRecorderApp)
main_engine.add_app(RiskManagerApp)
# main_engine.add_app(CtaStrategyApp)
# main_engine.add_app(CtaBacktesterApp)
# main_engine.add_app(CsvLoaderApp)
# main_engine.add_app(AlgoTradingApp)
# main_engine.add_app(DataRecorderApp)
# main_engine.add_app(RiskManagerApp)
main_window = MainWindow(main_engine, event_engine)
main_window.showMaximized()

Binary file not shown.

0
vnpy/api/tap/__init__.py Normal file
View File

View File

@ -138,7 +138,7 @@ class CtpGateway(BaseGateway):
def __init__(self, event_engine):
"""Constructor"""
super(CtpGateway, self).__init__(event_engine, "CTP")
super().__init__(event_engine, "CTP")
self.td_api = CtpTdApi(self)
self.md_api = CtpMdApi(self)

View File

@ -3,7 +3,8 @@ from dataclasses import dataclass
from datetime import datetime
from typing import Any, Dict, Optional, Tuple
from vnpy.api.tap.vntap import (APIYNFLAG_NO, AsyncDispatchException, CreateTapQuoteAPI,
from vnpy.api.tap.vntap import (
APIYNFLAG_NO, AsyncDispatchException, CreateTapQuoteAPI,
FreeTapQuoteAPI, ITapQuoteAPI, ITapQuoteAPINotify,
TAPIERROR_SUCCEED, TAPI_CALLPUT_FLAG_NONE,
TAPI_COMMODITY_TYPE_FUTURES, TAPI_COMMODITY_TYPE_INDEX,
@ -11,9 +12,18 @@ from vnpy.api.tap.vntap import (APIYNFLAG_NO, AsyncDispatchException, CreateTapQ
TAPI_COMMODITY_TYPE_STOCK, TapAPIApplicationInfo, TapAPIContract,
TapAPIQuotLoginRspInfo, TapAPIQuoteCommodityInfo,
TapAPIQuoteContractInfo, TapAPIQuoteLoginAuth, TapAPIQuoteWhole,
set_async_callback_exception_handler)
set_async_callback_exception_handler,
CreateITapTradeAPI
)
from vnpy.api.tap.vntap.ITapTrade import (
ITapTradeAPINotify, ITapTradeAPI,
TapAPITradeLoginRspInfo,
TapAPIApplicationInfo as TapTradeAPIApplicationInfo,
TapAPITradeLoginAuth, TapAPIAccQryReq, TapAPIFundReq,
TapAPIAccountInfo, TapAPIFundData
)
from vnpy.api.tap.error_codes import error_map
from vnpy.event import EventEngine
from vnpy.trader.constant import Exchange, Product
from vnpy.trader.gateway import BaseGateway
@ -38,124 +48,212 @@ EXCHANGE_TAP2VT = {
'APEX': Exchange.APEX,
'NYMEX': Exchange.NYMEX,
'LME': Exchange.LME,
'COMEX': Exchange.COMEX, # verify: I added this exchange in vnpy, is this correct?
'COMEX': Exchange.COMEX,
'CBOT': Exchange.CBOT,
'HKEX': Exchange.HKFE, # verify: is this correct?,
'HKEX': Exchange.HKFE,
'CME': Exchange.CME,
}
EXCHANGE_VT2TAP = {v: k for k, v in EXCHANGE_TAP2VT.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")
commodity_infos = {}
extra_infos = {}
def error_to_str(err_code: int) -> str:
try:
return error_map[err_code]
except KeyError:
return f"Unknown error({err_code})"
@dataclass()
class ContractExtraInfo:
class TapGateway(BaseGateway):
"""
缓存一些ITAP API不直接提供的信息而且仅仅保存这些信息Symbol之类的作为键就不保存在这里面了
VN Trader gateway for Esunny 9.0.
"""
name: str
commodity_type: int
commodity_no: str
default_setting = {
"quote_username": "",
"quote_password": "",
"quote_host": "",
"quote_port": 0,
"trade_username": "",
"trade_password": "",
"trade_host": "",
"trade_port": 0,
"auth_code": ""
}
exchanges = list(EXCHANGE_VT2TAP.keys())
def __init__(self, event_engine: EventEngine):
""""""
super().__init__(event_engine, "TAP")
self.quote_api = QuoteApi(self)
self.trade_api = TradeApi(self)
set_async_callback_exception_handler(
self._async_callback_exception_handler)
def connect(self, setting: dict):
""""""
quote_username = setting["quote_username"]
quote_password = setting["quote_password"]
quote_host = setting["quote_host"]
quote_port = setting["quote_port"]
trade_username = setting["trade_username"]
trade_password = setting["trade_password"]
trade_host = setting["trade_host"]
trade_port = setting["trade_port"]
auth_code = setting["auth_code"]
self.trade_api.connect(
trade_username,
trade_password,
trade_host,
trade_port,
auth_code
)
self.quote_api.connect(
quote_username,
quote_password,
quote_host,
quote_port,
auth_code
)
def close(self):
""""""
self.trade_api.close()
self.quote_api.close()
def subscribe(self, req: SubscribeRequest):
""""""
self.quote_api.subscribe(req)
def send_order(self, req: OrderRequest) -> str:
""""""
return self.trade_api.send_order(req)
def cancel_order(self, req: CancelRequest):
""""""
self.trade_api.cancel_order(req)
def query_account(self):
""""""
self.trade_api.query_account()
def query_position(self):
""""""
self.trade_api.query_position()
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)
self.write_log(error_str)
return True
class QuoteNotify(ITapQuoteAPINotify):
class QuoteApi(ITapQuoteAPINotify):
""""""
def __init__(self, gateway: "TapGateway"):
def __init__(self, gateway: TapGateway):
""""""
super().__init__()
self.gateway = gateway
self.api = None
@property
def api(self) -> ITapQuoteAPI:
return self.gateway.api
def OnRspLogin(self, errorCode: int, info: TapAPIQuotLoginRspInfo) -> Any:
if self.gateway.if_error_write_log(errorCode, "OnRspQryCommodity"):
def OnRspLogin(self, errorCode: int, info: TapAPIQuotLoginRspInfo):
""""""
if errorCode != TAPIERROR_SUCCEED:
self.gateway.write_log("行情服务器登录失败")
return
else:
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 OnAPIReady(self):
""""""
self.api.QryCommodity()
def OnDisconnect(self, reasonCode: int) -> Any:
print(f"OnDisconnect : {error_to_str(reasonCode)}")
def OnDisconnect(self, reasonCode: int):
""""""
self.gateway.write_log(f"行情服务器连接断开,原因:{reasonCode}")
def OnRspQryCommodity(
self,
sessionID: int,
errorCode: int,
isLast: int,
isLast: str,
info: TapAPIQuoteCommodityInfo,
) -> Any:
if self.gateway.if_error_write_log(errorCode, "OnRspQryCommodity"):
):
""""""
if errorCode != TAPIERROR_SUCCEED:
self.gateway.write_log("查询交易品种信息失败")
return
error_code, session_id = self.api.QryContract(info.Commodity)
if self.gateway.if_error_write_log(error_code, "api.QryContract"):
return
commodity_info = CommodityInfo(
name=info.CommodityName,
size=info.ContractSize, # value is 0 in sim environment
pricetick=info.CommodityTickSize
)
commodity_infos[info.Commodity.CommodityNo] = commodity_info
self.api.QryContract(info.Commodity)
if isLast == "Y":
self.gateway.write_log("查询交易品种信息成功")
def OnRspQryContract(
self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteContractInfo
) -> Any:
if self.gateway.if_error_write_log(errorCode, "OnRspQryContract"):
self, sessionID: int, errorCode: int, isLast: str, info: TapAPIQuoteContractInfo
):
""""""
if errorCode != TAPIERROR_SUCCEED:
self.gateway.write_log("查询交易合约信息失败")
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_TAP2VT[info.Contract.Commodity.ExchangeNo]
name = info.ContractName
contract_data = ContractData(
gateway_name=self.gateway.gateway_name,
if not info:
return
commodity_info = commodity_infos[info.Contract.Commodity.CommodityNo]
symbol = info.Contract.Commodity.CommodityNo + info.Contract.ContractNo1
contract = ContractData(
symbol=symbol,
exchange=exchange,
name=name,
product=PRODUCT_TYPE_TAP2VT.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
# ...
exchange=EXCHANGE_TAP2VT[info.Contract.Commodity.ExchangeNo],
name=symbol,
product=Product.FUTURES,
size=commodity_info.size,
pricetick=commodity_info.pricetick,
gateway_name=self.gateway.gateway_name
)
contract_extra_info = ContractExtraInfo(
name=name,
self.gateway.on_contract(contract)
extra_info = ExtraInfo(
name=contract.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)
extra_infos[(contract.symbol, contract.exchange)] = extra_info
def OnRspSubscribeQuote(
self, sessionID: int, errorCode: int, isLast: int, info: TapAPIQuoteWhole
) -> Any:
print("OnRspSubscribeQuote")
if self.gateway.if_error_write_log(errorCode, "OnRspSubscribeQuote"):
return
self, sessionID: int, errorCode: int, isLast: str, info: TapAPIQuoteWhole
):
if errorCode != TAPIERROR_SUCCEED:
self.gateway.write_log("订阅行情失败")
else:
self.update_tick(info)
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):
""""""
self.update_tick(info)
def OnRtnQuote(self, info: TapAPIQuoteWhole) -> Any:
def update_tick(self, info: TapAPIQuoteWhole):
""""""
symbol = info.Contract.ContractNo1
exchange = EXCHANGE_TAP2VT[info.Contract.Commodity.ExchangeNo]
extra_info = self.gateway.contract_extra_infos[(symbol, exchange)]
extra_info = extra_infos.get((symbol, exchange), None)
if not extra_info:
return
tick = TickData(
gateway_name=self.gateway.gateway_name,
symbol=symbol,
exchange=exchange,
datetime=parse_datetime(info.DateTimeStamp),
@ -189,113 +287,174 @@ class QuoteNotify(ITapQuoteAPINotify):
ask_volume_3=info.QAskQty[2],
ask_volume_4=info.QAskQty[3],
ask_volume_5=info.QAskQty[4],
gateway_name=self.gateway.gateway_name,
)
self.gateway.on_tick(tick=tick)
self.gateway.on_tick(tick)
def connect(self, username: str, password: str, host: str, port: int, auth_code: str):
""""""
# Create API object
info = TapAPIApplicationInfo()
info.AuthCode = auth_code
class TapGateway(BaseGateway):
default_setting = {
"auth_code": "",
"quote_host": "123.15.58.21",
"quote_port": 7171,
"quote_username": "",
"quote_password": "",
}
exchanges = list(EXCHANGE_VT2TAP.keys())
def __init__(self, event_engine: EventEngine):
super().__init__(event_engine, "ITAP")
self.api: Optional[ITapQuoteAPI] = None
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"]
quote_host = setting["quote_host"]
quote_port = setting["quote_port"]
quote_username = setting["quote_username"]
quote_password = setting["quote_password"]
# print("quote version:", GetTapQuoteAPIVersion())
# print("trade version:", GetITapTradeAPIVersion())
ai = TapAPIApplicationInfo()
ai.AuthCode = auth_code
# iResult是输出参数Python中只能用返回值作为输出。
# 具体输出了哪些可以看pyi的注释
api, iResult = CreateTapQuoteAPI(ai)
if api is None:
self.if_error_write_log(iResult, "CreateTapQuoteAPI")
self.api, iResult = CreateTapQuoteAPI(info)
if not self.api:
self.gateway.write_log("行情API初始化失败")
return
assert self.api is None
self.api = api
# Set server address and port
self.api.SetAPINotify(self)
self.api.SetHostAddress(host, port)
api.SetAPINotify(self.quote_notify)
error_code: int = api.SetHostAddress(quote_host, quote_port)
if self.if_error_write_log(error_code, "SetHostAddress"):
return
# Start connection
login_auth = TapAPIQuoteLoginAuth()
login_auth.UserNo = username
login_auth.Password = password
login_auth.ISDDA = APIYNFLAG_NO
login_auth.ISModifyPassword = APIYNFLAG_NO
# login
la = TapAPIQuoteLoginAuth()
la.UserNo = quote_username
la.Password = quote_password
la.ISDDA = APIYNFLAG_NO
la.ISModifyPassword = APIYNFLAG_NO
error_code: int = api.Login(la) # async
if self.if_error_write_log(error_code, "api.Login"):
return
self.api.Login(login_auth)
def close(self):
""""""
self.api.SetAPINotify(None)
self.quote_notify = None
FreeTapQuoteAPI(self.api)
self.api = None
pass
def subscribe(self, req: SubscribeRequest):
contract = TapAPIContract()
extra_info = self.contract_extra_infos[(req.symbol, req.exchange)]
contract.Commodity.ExchangeNo = EXCHANGE_VT2TAP[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"):
""""""
extra_info = extra_infos.get((req.symbol, req.exchange), None)
if not extra_info:
self.gateway.write_log(
f"找不到匹配的合约:{req.symbol}{req.exchange.value}")
return
def send_order(self, req: OrderRequest) -> str:
tap_contract = TapAPIContract()
tap_contract.Commodity.ExchangeNo = EXCHANGE_VT2TAP[req.exchange]
tap_contract.Commodity.CommodityType = extra_info.commodity_type
tap_contract.Commodity.CommodityNo = extra_info.commodity_no
tap_contract.ContractNo1 = req.symbol
tap_contract.CallOrPutFlag1 = TAPI_CALLPUT_FLAG_NONE
tap_contract.CallOrPutFlag2 = TAPI_CALLPUT_FLAG_NONE
self.api.SubscribeQuote(tap_contract)
class TradeApi(ITapTradeAPINotify):
""""""
def __init__(self, gateway: TapGateway):
""""""
super().__init__()
self.gateway = gateway
self.api = None
def OnConnect(self):
""""""
self.gateway.write_log("交易服务器连接成功")
def OnRspLogin(self, errorCode: int, info: TapAPITradeLoginRspInfo):
""""""
if errorCode != TAPIERROR_SUCCEED:
error_msg = error_to_str(errorCode)
self.gateway.write_log(f"交易服务器登录失败:{error_msg}")
else:
self.gateway.write_log("交易服务器登录成功")
def OnRspQryAccount(
self,
sessionID: int,
errorCode: int,
isLast: str,
info: TapAPIFundData
):
req = TapAPIFundReq()
req.AccountNo = info.AccountNo
self.api.QryFund(req)
def OnRspQryFund(
self,
sessionID: int,
errorCode: int,
isLast: str,
info: TapAPIAccountInfo
):
self.update_account(info)
def update_account(self, info: TapAPIAccountInfo):
""""""
account = AccountData()
def connect(self, username: str, password: str, host: str, port: int, auth_code: str):
""""""
# Create API object
info = TapTradeAPIApplicationInfo()
info.AuthCode = auth_code
self.api, iResult = CreateITapTradeAPI(info)
if not self.api:
self.gateway.write_log("交易API初始化失败")
return
# Set server address and port
self.api.SetAPINotify(self)
self.api.SetHostAddress(host, port, False)
# Start connection
login_auth = TapAPITradeLoginAuth()
login_auth.UserNo = username
login_auth.Password = password
login_auth.ISModifyPassword = APIYNFLAG_NO
self.api.Login(login_auth)
def send_order(self, req: OrderRequest):
""""""
pass
def cancel_order(self, req: CancelRequest):
""""""
pass
def query_account(self):
pass
""""""
req = TapAPIAccQryReq()
self.api.QryAccount(req)
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
def parse_datetime(dt_str: str):
""""""
try:
dt = datetime.strptime(dt_str, "%Y-%m-%d %H:%M:%S.%f")
except ValueError:
dt = datetime(1970, 1, 1)
return dt
def error_to_str(err_code: int) -> str:
""""""
try:
return error_map[err_code]
except KeyError:
return f"Unknown error({err_code})"
@dataclass
class ExtraInfo:
""""""
name: str
commodity_type: int
commodity_no: str
@dataclass
class CommodityInfo:
""""""
name: str
size: int
pricetick: float