[Add] XtpGateway support margin trading
This commit is contained in:
parent
9e5258b8df
commit
b56d0ce160
@ -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)
|
||||
|
@ -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]
|
||||
xtp_req.business_type = XTP_BUSINESS_TYPE.XTP_BUSINESS_TYPE_CASH
|
||||
|
||||
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()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user