Merge pull request #1650 from vnpy/gateway_exchange

Gateway exchange
This commit is contained in:
vn.py 2019-04-30 14:31:37 +08:00 committed by GitHub
commit 4ec6ca2af7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 70 additions and 15 deletions

View File

@ -219,7 +219,7 @@ class PositionHolding:
elif order.offset == Offset.CLOSE: elif order.offset == Offset.CLOSE:
self.long_td_frozen += frozen self.long_td_frozen += frozen
if self.long_td_frozen > self.short_td: if self.long_td_frozen > self.long_td:
self.long_yd_frozen += (self.long_td_frozen self.long_yd_frozen += (self.long_td_frozen
- self.long_td) - self.long_td)
self.long_td_frozen = self.long_td self.long_td_frozen = self.long_td

View File

@ -72,6 +72,8 @@ class BitfinexGateway(BaseGateway):
"proxy_port": 1080, "proxy_port": 1080,
} }
exchanges = [Exchange.BITFINEX]
def __init__(self, event_engine): def __init__(self, event_engine):
"""Constructor""" """Constructor"""
super(BitfinexGateway, self).__init__(event_engine, "BITFINEX") super(BitfinexGateway, self).__init__(event_engine, "BITFINEX")

View File

@ -75,6 +75,8 @@ class BitmexGateway(BaseGateway):
"代理端口": "", "代理端口": "",
} }
exchanges = [Exchange.BITMEX]
def __init__(self, event_engine): def __init__(self, event_engine):
"""Constructor""" """Constructor"""
super(BitmexGateway, self).__init__(event_engine, "BITMEX") super(BitmexGateway, self).__init__(event_engine, "BITMEX")

View File

@ -134,6 +134,8 @@ class CtpGateway(BaseGateway):
"授权编码": "" "授权编码": ""
} }
exchanges = list(EXCHANGE_CTP2VT.values())
def __init__(self, event_engine): def __init__(self, event_engine):
"""Constructor""" """Constructor"""
super(CtpGateway, self).__init__(event_engine, "CTP") super(CtpGateway, self).__init__(event_engine, "CTP")

View File

@ -87,12 +87,6 @@ OFFSET_VT2FEMAS = {
} }
OFFSET_FEMAS2VT = {v: k for k, v in OFFSET_VT2FEMAS.items()} OFFSET_FEMAS2VT = {v: k for k, v in OFFSET_VT2FEMAS.items()}
# PRODUCT_CTP2VT = {
# THOST_FTDC_PC_Futures: Product.FUTURES,
# THOST_FTDC_PC_Options: Product.OPTION,
# THOST_FTDC_PC_Combination: Product.SPREAD
# }
DIRECTION_FEMAS2VT = {v: k for k, v in DIRECTION_VT2FEMAS.items()} DIRECTION_FEMAS2VT = {v: k for k, v in DIRECTION_VT2FEMAS.items()}
DIRECTION_FEMAS2VT[USTP_FTDC_PD_Long] = Direction.LONG DIRECTION_FEMAS2VT[USTP_FTDC_PD_Long] = Direction.LONG
DIRECTION_FEMAS2VT[USTP_FTDC_PD_Short] = Direction.SHORT DIRECTION_FEMAS2VT[USTP_FTDC_PD_Short] = Direction.SHORT
@ -128,6 +122,8 @@ class FemasGateway(BaseGateway):
"md_address": "", "md_address": "",
} }
exchanges = list(EXCHANGE_FEMAS2VT.values())
def __init__(self, event_engine): def __init__(self, event_engine):
"""Constructor""" """Constructor"""
super(FemasGateway, self).__init__(event_engine, "FEMAS") super(FemasGateway, self).__init__(event_engine, "FEMAS")

View File

@ -86,6 +86,8 @@ class FutuGateway(BaseGateway):
"环境": [TrdEnv.REAL, TrdEnv.SIMULATE], "环境": [TrdEnv.REAL, TrdEnv.SIMULATE],
} }
exchanges = list(EXCHANGE_FUTU2VT.values())
def __init__(self, event_engine): def __init__(self, event_engine):
"""Constructor""" """Constructor"""
super(FutuGateway, self).__init__(event_engine, "FUTU") super(FutuGateway, self).__init__(event_engine, "FUTU")

View File

@ -77,6 +77,8 @@ class HuobiGateway(BaseGateway):
"代理端口": "", "代理端口": "",
} }
exchanges = [Exchange.HUOBI]
def __init__(self, event_engine): def __init__(self, event_engine):
"""Constructor""" """Constructor"""
super(HuobiGateway, self).__init__(event_engine, "HUOBI") super(HuobiGateway, self).__init__(event_engine, "HUOBI")

View File

@ -116,6 +116,8 @@ class IbGateway(BaseGateway):
"客户号": 1 "客户号": 1
} }
exchanges = list(EXCHANGE_VT2IB.keys())
def __init__(self, event_engine): def __init__(self, event_engine):
"""""" """"""
super(IbGateway, self).__init__(event_engine, "IB") super(IbGateway, self).__init__(event_engine, "IB")

View File

@ -12,7 +12,7 @@ from vnpy.trader.object import (CancelRequest, OrderRequest,
SubscribeRequest) SubscribeRequest)
from vnpy.trader.utility import get_file_path from vnpy.trader.utility import get_file_path
from .oes_md import OesMdApi from .oes_md import OesMdApi
from .oes_td import OesTdApi from .oes_td import OesTdApi, EXCHANGE_VT2OES
from .utils import config_template from .utils import config_template
@ -39,6 +39,8 @@ class OesGateway(BaseGateway):
"hdd_serial": "", "hdd_serial": "",
} }
exchanges = list(EXCHANGE_VT2OES.keys())
def __init__(self, event_engine): def __init__(self, event_engine):
"""Constructor""" """Constructor"""
super().__init__(event_engine, "OES") super().__init__(event_engine, "OES")
@ -55,7 +57,8 @@ class OesGateway(BaseGateway):
def connect(self, setting: dict): def connect(self, setting: dict):
"""""" """"""
if not setting['password'].startswith("md5:"): if not setting['password'].startswith("md5:"):
setting['password'] = "md5:" + hashlib.md5(setting['password'].encode()).hexdigest() setting['password'] = "md5:" + \
hashlib.md5(setting['password'].encode()).hexdigest()
username = setting['username'] username = setting['username']
password = setting['password'] password = setting['password']
@ -80,13 +83,15 @@ class OesGateway(BaseGateway):
self.md_api.tcp_server = setting['md_tcp_server'] self.md_api.tcp_server = setting['md_tcp_server']
self.md_api.qry_server = setting['md_qry_server'] self.md_api.qry_server = setting['md_qry_server']
Thread(target=self._connect_md_sync, args=(config_path, username, password)).start() Thread(target=self._connect_md_sync, args=(
config_path, username, password)).start()
self.td_api.ord_server = setting['td_ord_server'] self.td_api.ord_server = setting['td_ord_server']
self.td_api.rpt_server = setting['td_rpt_server'] self.td_api.rpt_server = setting['td_rpt_server']
self.td_api.qry_server = setting['td_qry_server'] self.td_api.qry_server = setting['td_qry_server']
self.td_api.hdd_serial = setting['hdd_serial'] self.td_api.hdd_serial = setting['hdd_serial']
Thread(target=self._connect_td_sync, args=(config_path, username, password)).start() Thread(target=self._connect_td_sync, args=(
config_path, username, password)).start()
def _connect_td_sync(self, config_path, username, password): def _connect_td_sync(self, config_path, username, password):
self.td_api.config_path = config_path self.td_api.config_path = config_path

View File

@ -78,6 +78,8 @@ class OkexGateway(BaseGateway):
"代理端口": "", "代理端口": "",
} }
exchanges = [Exchange.OKEX]
def __init__(self, event_engine): def __init__(self, event_engine):
"""Constructor""" """Constructor"""
super(OkexGateway, self).__init__(event_engine, "OKEX") super(OkexGateway, self).__init__(event_engine, "OKEX")

View File

@ -81,6 +81,8 @@ class OkexfGateway(BaseGateway):
"代理端口": "", "代理端口": "",
} }
exchanges = [Exchange.OKEX]
def __init__(self, event_engine): def __init__(self, event_engine):
"""Constructor""" """Constructor"""
super(OkexfGateway, self).__init__(event_engine, "OKEXF") super(OkexfGateway, self).__init__(event_engine, "OKEXF")

View File

@ -71,6 +71,8 @@ class OnetokenGateway(BaseGateway):
"代理端口": 1080, "代理端口": 1080,
} }
exchanges = list(EXCHANGE_VT2ONETOKEN.keys())
def __init__(self, event_engine): def __init__(self, event_engine):
"""Constructor""" """Constructor"""
super(OnetokenGateway, self).__init__(event_engine, "1TOKEN") super(OnetokenGateway, self).__init__(event_engine, "1TOKEN")

View File

@ -96,6 +96,13 @@ class TigerGateway(BaseGateway):
"private_key": '', "private_key": '',
} }
exchanges = [
Exchange.SEHK,
Exchange.SMART,
Exchange.SSE,
Exchange.SZSE
]
def __init__(self, event_engine): def __init__(self, event_engine):
"""Constructor""" """Constructor"""
super(TigerGateway, self).__init__(event_engine, "TIGER") super(TigerGateway, self).__init__(event_engine, "TIGER")

View File

@ -111,6 +111,8 @@ class XtpGateway(BaseGateway):
"授权码": "" "授权码": ""
} }
exchanges = list(EXCHANGE_VT2XTP.keys())
def __init__(self, event_engine: EventEngine): def __init__(self, event_engine: EventEngine):
"""""" """"""
super().__init__(event_engine, "XTP") super().__init__(event_engine, "XTP")

View File

@ -43,6 +43,7 @@ class MainEngine:
self.gateways = {} self.gateways = {}
self.engines = {} self.engines = {}
self.apps = {} self.apps = {}
self.exchanges = []
self.init_engines() self.init_engines()
@ -60,6 +61,12 @@ class MainEngine:
""" """
gateway = gateway_class(self.event_engine) gateway = gateway_class(self.event_engine)
self.gateways[gateway.gateway_name] = gateway self.gateways[gateway.gateway_name] = gateway
# Add gateway supported exchanges into engine
for exchange in gateway.exchanges:
if exchange not in self.exchanges:
self.exchanges.append(exchange)
return gateway return gateway
def add_app(self, app_class: BaseApp): def add_app(self, app_class: BaseApp):
@ -127,6 +134,12 @@ class MainEngine:
""" """
return list(self.apps.values()) return list(self.apps.values())
def get_all_exchanges(self):
"""
Get all exchanges.
"""
return self.exchanges
def connect(self, setting: dict, gateway_name: str): def connect(self, setting: dict, gateway_name: str):
""" """
Start connection of a specific gateway. Start connection of a specific gateway.

View File

@ -72,6 +72,9 @@ class BaseGateway(ABC):
# Fields required in setting dict for connect function. # Fields required in setting dict for connect function.
default_setting = {} default_setting = {}
# Exchanges supported in the gateway.
exchanges = []
def __init__(self, event_engine: EventEngine, gateway_name: str): def __init__(self, event_engine: EventEngine, gateway_name: str):
"""""" """"""
self.event_engine = event_engine self.event_engine = event_engine

View File

@ -12,10 +12,16 @@ from .object import BarData
INTERVAL_VT2RQ = { INTERVAL_VT2RQ = {
Interval.MINUTE: "1m", Interval.MINUTE: "1m",
Interval.HOUR: "1h", Interval.HOUR: "60m",
Interval.DAILY: "1d", Interval.DAILY: "1d",
} }
INTERVAL_ADJUSTMENT_MAP = {
Interval.MINUTE: timedelta(minutes=1),
Interval.HOUR: timedelta(hours=1),
Interval.DAILY: timedelta() # no need to adjust for daily bar
}
class RqdataClient: class RqdataClient:
""" """
@ -102,7 +108,11 @@ class RqdataClient:
if not rq_interval: if not rq_interval:
return None return None
end += timedelta(1) # For querying night trading period data # For adjust timestamp from bar close point (RQData) to open point (VN Trader)
adjustment = INTERVAL_ADJUSTMENT_MAP[interval]
# For querying night trading period data
end += timedelta(1)
df = rqdata_get_price( df = rqdata_get_price(
rq_symbol, rq_symbol,
@ -118,7 +128,7 @@ class RqdataClient:
symbol=symbol, symbol=symbol,
exchange=exchange, exchange=exchange,
interval=interval, interval=interval,
datetime=row.name.to_pydatetime(), datetime=row.name.to_pydatetime() - adjustment,
open_price=row["open"], open_price=row["open"],
high_price=row["high"], high_price=row["high"],
low_price=row["low"], low_price=row["low"],

View File

@ -582,8 +582,9 @@ class TradingWidget(QtWidgets.QWidget):
self.setFixedWidth(300) self.setFixedWidth(300)
# Trading function area # Trading function area
exchanges = self.main_engine.get_all_exchanges()
self.exchange_combo = QtWidgets.QComboBox() self.exchange_combo = QtWidgets.QComboBox()
self.exchange_combo.addItems([exchange.value for exchange in Exchange]) self.exchange_combo.addItems([exchange.value for exchange in exchanges])
self.symbol_line = QtWidgets.QLineEdit() self.symbol_line = QtWidgets.QLineEdit()
self.symbol_line.returnPressed.connect(self.set_vt_symbol) self.symbol_line.returnPressed.connect(self.set_vt_symbol)