[Add] XtpGateway support margin trading

This commit is contained in:
vn.py 2019-05-21 14:26:55 +08:00
parent 9e5258b8df
commit b56d0ce160
2 changed files with 91 additions and 21 deletions

View File

@ -35,20 +35,20 @@ def main():
main_engine = MainEngine(event_engine)
main_engine.add_gateway(XtpGateway)
main_engine.add_gateway(CtpGateway)
# 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(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_app(CtaStrategyApp)
main_engine.add_app(CtaBacktesterApp)

View File

@ -17,6 +17,7 @@ from vnpy.api.xtp.vnxtp import (
XTPOrderInfo,
XTPTradeReport,
XTPOrderCancelInfo,
XTPCrdDebtInfo,
XTPQueryStkPositionRsp,
XTPQueryAssetRsp,
XTPStructuredFundInfo,
@ -32,6 +33,11 @@ from vnpy.api.xtp.vnxtp import (
XTP_TE_RESUME_TYPE,
XTP_SIDE_BUY,
XTP_SIDE_SELL,
XTP_SIDE_MARGIN_TRADE,
XTP_SIDE_SHORT_SELL,
XTP_SIDE_REPAY_MARGIN,
XTP_SIDE_REPAY_STOCK,
XTP_ACCOUNT_TYPE,
XTP_BUSINESS_TYPE,
XTP_TICKER_TYPE,
XTP_MARKET_TYPE,
@ -40,7 +46,7 @@ from vnpy.api.xtp.vnxtp import (
)
from vnpy.event import EventEngine
from vnpy.trader.event import EVENT_TIMER
from vnpy.trader.constant import Exchange, Product, Direction, OrderType, Status
from vnpy.trader.constant import Exchange, Product, Direction, OrderType, Status, Offset
from vnpy.trader.gateway import BaseGateway
from vnpy.trader.object import (CancelRequest, OrderRequest, SubscribeRequest,
TickData, ContractData, OrderData, TradeData,
@ -71,9 +77,17 @@ PRODUCT_XTP2VT = {
XTP_TICKER_TYPE.XTP_TICKER_TYPE_OPTION: Product.OPTION
}
# DIRECTION_VT2XTP = {
# Direction.LONG: XTP_SIDE_BUY,
# Direction.SHORT: XTP_SIDE_SELL
# }
DIRECTION_VT2XTP = {
Direction.LONG: XTP_SIDE_BUY,
Direction.SHORT: XTP_SIDE_SELL
(Direction.LONG, Offset.OPEN): XTP_SIDE_MARGIN_TRADE,
(Direction.SHORT, Offset.CLOSE): XTP_SIDE_REPAY_MARGIN,
(Direction.SHORT, Offset.OPEN): XTP_SIDE_SHORT_SELL,
(Direction.LONG, Offset.CLOSE): XTP_SIDE_REPAY_STOCK,
(Direction.SHORT, Offset.NONE): XTP_SIDE_BUY,
(Direction.LONG, Offset.NONE): XTP_SIDE_SELL,
}
DIRECTION_XTP2VT = {v: k for k, v in DIRECTION_VT2XTP.items()}
@ -95,6 +109,7 @@ STATUS_XTP2VT = {
symbol_name_map = {}
symbol_exchange_map = {}
class XtpGateway(BaseGateway):
@ -428,6 +443,9 @@ class XtpQuoteApi(API.QuoteSpi):
symbol_name_map[contract.vt_symbol] = contract.name
if contract.product != Product.INDEX:
symbol_exchange_map[contract.symbol] = contract.exchange
if is_last:
self.gateway.write_log(f"{contract.exchange.value}合约信息查询成功")
@ -487,6 +505,13 @@ class XtpTraderApi(API.TraderSpi):
self.session_id = 0
self.reqid = 0
# Whether current account supports margin or option
self.margin_trading = False
self.option_trading = False
#
self.short_positions = {}
def connect(
self,
userid: str,
@ -564,9 +589,13 @@ class XtpTraderApi(API.TraderSpi):
xtp_req.market = MARKET_VT2XTP[req.exchange]
xtp_req.price = req.price
xtp_req.quantity = int(req.volume)
xtp_req.side = DIRECTION_VT2XTP[req.direction]
xtp_req.side = DIRECTION_VT2XTP.get((req.direction, req.offset), "")
xtp_req.price_type = ORDERTYPE_VT2XTP[req.type]
if req.offset == Offset.NONE:
xtp_req.business_type = XTP_BUSINESS_TYPE.XTP_BUSINESS_TYPE_CASH
else:
xtp_req.business_type = XTP_BUSINESS_TYPE.XTP_BUSINESS_TYPE_MARGIN
orderid = self.api.InsertOrder(xtp_req, self.session_id)
@ -595,6 +624,10 @@ class XtpTraderApi(API.TraderSpi):
self.reqid += 1
self.api.QueryPosition("", self.session_id, self.reqid)
if self.margin_trading:
self.reqid += 1
self.api.QueryCreditDebtInfo(self.session_id, self.reqid)
def check_error(self, func_name: str, error_info: XTPRspInfoStruct):
""""""
if error_info and error_info.error_id:
@ -617,12 +650,15 @@ class XtpTraderApi(API.TraderSpi):
""""""
self.check_error("委托下单", error_info)
direction, offset = DIRECTION_XTP2VT[ order_info.side]
order = OrderData(
symbol=order_info.ticker,
exchange=MARKET_XTP2VT[order_info.market],
orderid=str(order_info.order_xtp_id),
type=ORDERTYPE_XTP2VT[order_info.price_type],
direction=DIRECTION_XTP2VT[order_info.side],
direction=direction,
offset=offset,
price=order_info.price,
volume=order_info.quantity,
traded=order_info.qty_traded,
@ -635,12 +671,15 @@ class XtpTraderApi(API.TraderSpi):
def OnTradeEvent(self, trade_info: XTPTradeReport, session_id: int) -> Any:
""""""
direction, offset = DIRECTION_XTP2VT[trade_info.side]
trade = TradeData(
symbol=trade_info.ticker,
exchange=MARKET_XTP2VT[trade_info.market],
orderid=str(trade_info.order_xtp_id),
tradeid=str(trade_info.exec_id),
direction=DIRECTION_XTP2VT[trade_info.side],
direction=direction,
offset=offset,
price=trade_info.price,
volume=trade_info.quantity,
time=trade_info.trade_time,
@ -682,7 +721,7 @@ class XtpTraderApi(API.TraderSpi):
position = PositionData(
symbol=xtp_position.ticker,
exchange=MARKET_XTP2VT[xtp_position.market],
direction=Direction.NET,
direction=Direction.LONG,
volume=xtp_position.total_qty,
frozen=xtp_position.locked_position,
price=xtp_position.avg_price,
@ -703,6 +742,11 @@ class XtpTraderApi(API.TraderSpi):
)
self.gateway.on_account(account)
if asset.account_type == XTP_ACCOUNT_TYPE.XTP_ACCOUNT_CREDIT:
self.margin_trading = True
elif asset.account_type == XTP_ACCOUNT_TYPE.XTP_ACCOUNT_DERIVE:
self.option_trading = True
def OnQueryStructuredFund(self, fund_info: XTPStructuredFundInfo, error_info: XTPRspInfoStruct,
is_last: bool, session_id: int) -> Any:
""""""
@ -741,3 +785,29 @@ class XtpTraderApi(API.TraderSpi):
is_last: bool, session_id: int) -> Any:
""""""
pass
def OnQueryCreditDebtInfo(self, debt_info: XTPCrdDebtInfo, error_info: XTPRspInfoStruct,
request_id: int, is_last: bool, session_id: int) -> Any:
""""""
if debt_info.debt_type == 1:
symbol = debt_info.ticker
exchange = MARKET_XTP2VT[debt_info.market]
position = self.short_positions.get(symbol, None)
if not position:
position = PositionData(
symbol=symbol,
exchange=exchange,
direction=Direction.SHORT,
gateway_name=self.gateway_name
)
self.short_positions[symbol] = position
position.volume += debt_info.remain_qty
if is_last:
for position in self.short_positions.values():
self.gateway.on_position(position)
self.short_positions.clear()