[Mod] complete test of gateio gateway
This commit is contained in:
parent
4336ccf065
commit
8f7ddd985a
@ -8,9 +8,8 @@ import sys
|
|||||||
import time
|
import time
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from threading import Lock
|
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
from typing import List
|
from typing import List, Dict
|
||||||
|
|
||||||
from vnpy.api.rest import Request, RestClient
|
from vnpy.api.rest import Request, RestClient
|
||||||
from vnpy.api.websocket import WebsocketClient
|
from vnpy.api.websocket import WebsocketClient
|
||||||
@ -31,11 +30,6 @@ REST_HOST = "https://api.gateio.ws"
|
|||||||
TESTNET_WEBSOCKET_HOST = "wss://fx-ws-testnet.gateio.ws/v4/ws"
|
TESTNET_WEBSOCKET_HOST = "wss://fx-ws-testnet.gateio.ws/v4/ws"
|
||||||
WEBSOCKET_HOST = "wss://fx-ws.gateio.ws/v4/ws"
|
WEBSOCKET_HOST = "wss://fx-ws.gateio.ws/v4/ws"
|
||||||
|
|
||||||
STATUS_GATEIO2VT = {
|
|
||||||
"open": Status.NOTTRADED,
|
|
||||||
"finished": Status.ALLTRADED,
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERVAL_VT2GATEIO = {
|
INTERVAL_VT2GATEIO = {
|
||||||
Interval.MINUTE: "1m",
|
Interval.MINUTE: "1m",
|
||||||
Interval.HOUR: "1h",
|
Interval.HOUR: "1h",
|
||||||
@ -72,7 +66,7 @@ class GateiosGateway(BaseGateway):
|
|||||||
self.ws_api = GateiosWebsocketApi(self)
|
self.ws_api = GateiosWebsocketApi(self)
|
||||||
self.rest_api = GateiosRestApi(self)
|
self.rest_api = GateiosRestApi(self)
|
||||||
|
|
||||||
def connect(self, setting: dict):
|
def connect(self, setting: Dict):
|
||||||
""""""
|
""""""
|
||||||
key = setting["API Key"]
|
key = setting["API Key"]
|
||||||
secret = setting["Secret Key"]
|
secret = setting["Secret Key"]
|
||||||
@ -99,7 +93,7 @@ class GateiosGateway(BaseGateway):
|
|||||||
|
|
||||||
def cancel_order(self, req: CancelRequest):
|
def cancel_order(self, req: CancelRequest):
|
||||||
""""""
|
""""""
|
||||||
self.order_manager.cancel_order(req)
|
self.rest_api.cancel_order(req)
|
||||||
|
|
||||||
def query_account(self):
|
def query_account(self):
|
||||||
""""""
|
""""""
|
||||||
@ -320,12 +314,15 @@ class GateiosRestApi(RestClient):
|
|||||||
on_failed=self.on_send_order_failed
|
on_failed=self.on_send_order_failed
|
||||||
)
|
)
|
||||||
|
|
||||||
self.gateway.on_order(order)
|
self.order_manager.on_order(order)
|
||||||
return order.vt_orderid
|
return order.vt_orderid
|
||||||
|
|
||||||
def cancel_order(self, req: CancelRequest):
|
def cancel_order(self, req: CancelRequest):
|
||||||
""""""
|
""""""
|
||||||
sys_orderid = self.order_manager.get_sys_orderid(req.orderid)
|
sys_orderid = self.order_manager.get_sys_orderid(req.orderid)
|
||||||
|
if not sys_orderid:
|
||||||
|
self.write_log("撤单失败,找不到对应系统委托号{}".format(req.orderid))
|
||||||
|
return
|
||||||
|
|
||||||
self.add_request(
|
self.add_request(
|
||||||
method="DELETE",
|
method="DELETE",
|
||||||
@ -367,7 +364,7 @@ class GateiosRestApi(RestClient):
|
|||||||
def on_query_order(self, data, request):
|
def on_query_order(self, data, request):
|
||||||
""""""
|
""""""
|
||||||
for d in data:
|
for d in data:
|
||||||
local_orderid = self.new_local_orderid()
|
local_orderid = self.order_manager.new_local_orderid()
|
||||||
sys_orderid = str(d["id"])
|
sys_orderid = str(d["id"])
|
||||||
|
|
||||||
self.order_manager.update_orderid_map(
|
self.order_manager.update_orderid_map(
|
||||||
@ -375,12 +372,15 @@ class GateiosRestApi(RestClient):
|
|||||||
sys_orderid=sys_orderid
|
sys_orderid=sys_orderid
|
||||||
)
|
)
|
||||||
|
|
||||||
volume = d["size"]
|
if d["size"] > 0:
|
||||||
if volume > 0:
|
|
||||||
direction = Direction.LONG
|
direction = Direction.LONG
|
||||||
else:
|
else:
|
||||||
direction = Direction.SHORT
|
direction = Direction.SHORT
|
||||||
|
|
||||||
|
volume = abs(d["size"])
|
||||||
|
traded = abs(d["size"] - d["left"])
|
||||||
|
status = get_order_status(d["status"], volume, traded)
|
||||||
|
|
||||||
dt = datetime.fromtimestamp(d["create_time"])
|
dt = datetime.fromtimestamp(d["create_time"])
|
||||||
|
|
||||||
order = OrderData(
|
order = OrderData(
|
||||||
@ -391,7 +391,7 @@ class GateiosRestApi(RestClient):
|
|||||||
volume=abs(volume),
|
volume=abs(volume),
|
||||||
type=OrderType.LIMIT,
|
type=OrderType.LIMIT,
|
||||||
direction=direction,
|
direction=direction,
|
||||||
status=STATUS_GATEIO2VT[d["status"]],
|
status=status,
|
||||||
time=dt.strftime("%H:%M:%S"),
|
time=dt.strftime("%H:%M:%S"),
|
||||||
gateway_name=self.gateway_name,
|
gateway_name=self.gateway_name,
|
||||||
)
|
)
|
||||||
@ -434,16 +434,7 @@ class GateiosRestApi(RestClient):
|
|||||||
def on_send_order(self, data, request):
|
def on_send_order(self, data, request):
|
||||||
""""""
|
""""""
|
||||||
order = request.extra
|
order = request.extra
|
||||||
order.status = STATUS_GATEIO2VT[data["status"]]
|
sys_orderid = str(data["id"])
|
||||||
|
|
||||||
if order.status == Status.ALLTRADED:
|
|
||||||
order.traded = order.volume
|
|
||||||
|
|
||||||
dt = datetime.fromtimestamp(data["create_time"])
|
|
||||||
order.time = dt.strftime("%H:%M:%S")
|
|
||||||
|
|
||||||
sys_orderid = data["id"]
|
|
||||||
self.order_manager.on_order(order)
|
|
||||||
self.order_manager.update_orderid_map(order.orderid, sys_orderid)
|
self.order_manager.update_orderid_map(order.orderid, sys_orderid)
|
||||||
|
|
||||||
def on_send_order_failed(self, status_code: str, request: Request):
|
def on_send_order_failed(self, status_code: str, request: Request):
|
||||||
@ -473,17 +464,10 @@ class GateiosRestApi(RestClient):
|
|||||||
|
|
||||||
def on_cancel_order(self, data, request):
|
def on_cancel_order(self, data, request):
|
||||||
""""""
|
""""""
|
||||||
cancel_request = request.extra
|
|
||||||
local_orderid = cancel_request.orderid
|
|
||||||
order = self.order_manager.get_order_with_local_orderid(local_orderid)
|
|
||||||
|
|
||||||
if data["status"] == "error":
|
if data["status"] == "error":
|
||||||
error_code = data["err_code"]
|
error_code = data["err_code"]
|
||||||
error_msg = data["err_msg"]
|
error_msg = data["err_msg"]
|
||||||
self.gateway.write_log(f"撤单失败,错误代码:{error_code},信息:{error_msg}")
|
self.gateway.write_log(f"撤单失败,错误代码:{error_code},信息:{error_msg}")
|
||||||
else:
|
|
||||||
order.status = Status.CANCELLED
|
|
||||||
self.order_manager.on_order(order)
|
|
||||||
|
|
||||||
def on_cancel_order_failed(self, status_code: str, request: Request):
|
def on_cancel_order_failed(self, status_code: str, request: Request):
|
||||||
"""
|
"""
|
||||||
@ -540,19 +524,16 @@ class GateiosWebsocketApi(WebsocketClient):
|
|||||||
self.gateway.write_log("Websocket API连接成功")
|
self.gateway.write_log("Websocket API连接成功")
|
||||||
|
|
||||||
for symbol in self.symbols:
|
for symbol in self.symbols:
|
||||||
update_order = self.generate_req(
|
for channel in [
|
||||||
channel="futures.orders",
|
"futures.orders",
|
||||||
event="subscribe",
|
"futures.usertrades"
|
||||||
pay_load=[self.account_id, symbol]
|
]:
|
||||||
)
|
req = self.generate_req(
|
||||||
self.send_packet(update_order)
|
channel=channel,
|
||||||
|
event="subscribe",
|
||||||
update_position = self.generate_req(
|
pay_load=[self.account_id, symbol]
|
||||||
channel="futures.position_closes",
|
)
|
||||||
event="subscribe",
|
self.send_packet(req)
|
||||||
pay_load=[self.account_id, symbol]
|
|
||||||
)
|
|
||||||
self.send_packet(update_position)
|
|
||||||
|
|
||||||
def subscribe(self, req: SubscribeRequest):
|
def subscribe(self, req: SubscribeRequest):
|
||||||
"""
|
"""
|
||||||
@ -585,7 +566,7 @@ class GateiosWebsocketApi(WebsocketClient):
|
|||||||
""""""
|
""""""
|
||||||
self.gateway.write_log("Websocket API连接断开")
|
self.gateway.write_log("Websocket API连接断开")
|
||||||
|
|
||||||
def on_packet(self, packet: dict):
|
def on_packet(self, packet: Dict):
|
||||||
""""""
|
""""""
|
||||||
timestamp = packet["time"]
|
timestamp = packet["time"]
|
||||||
channel = packet["channel"]
|
channel = packet["channel"]
|
||||||
@ -597,17 +578,14 @@ class GateiosWebsocketApi(WebsocketClient):
|
|||||||
self.gateway.write_log("Websocket API报错:%s" % error)
|
self.gateway.write_log("Websocket API报错:%s" % error)
|
||||||
return
|
return
|
||||||
|
|
||||||
print(packet)
|
if channel == "futures.tickers" and event == "update":
|
||||||
|
self.on_tick(result, timestamp)
|
||||||
if channel == "futures.tickers":
|
elif channel == "futures.order_book" and event == "all":
|
||||||
if event == "update":
|
self.on_depth(result, timestamp)
|
||||||
self.on_tick(result, timestamp)
|
elif channel == "futures.orders" and event == "update":
|
||||||
elif channel == "futures.order_book":
|
self.on_order(result, timestamp)
|
||||||
if event == "all":
|
elif channel == "futures.usertrades" and event == "update":
|
||||||
self.on_depth(result, timestamp)
|
self.on_trade(result, timestamp)
|
||||||
elif channel == "futures.orders":
|
|
||||||
if event == "update":
|
|
||||||
self.on_order(result, timestamp)
|
|
||||||
|
|
||||||
def on_error(self, exception_type: type, exception_value: Exception, tb):
|
def on_error(self, exception_type: type, exception_value: Exception, tb):
|
||||||
""""""
|
""""""
|
||||||
@ -617,10 +595,11 @@ class GateiosWebsocketApi(WebsocketClient):
|
|||||||
sys.stderr.write(self.exception_detail(
|
sys.stderr.write(self.exception_detail(
|
||||||
exception_type, exception_value, tb))
|
exception_type, exception_value, tb))
|
||||||
|
|
||||||
def generate_req(self, channel: str, event: str, pay_load: list):
|
def generate_req(self, channel: str, event: str, pay_load: List):
|
||||||
""""""
|
""""""
|
||||||
expires = int(time.time())
|
expires = int(time.time())
|
||||||
signature = generate_websocket_sign(self.secret, channel, event, expires)
|
signature = generate_websocket_sign(
|
||||||
|
self.secret, channel, event, expires)
|
||||||
|
|
||||||
req = {
|
req = {
|
||||||
"time": expires,
|
"time": expires,
|
||||||
@ -636,7 +615,7 @@ class GateiosWebsocketApi(WebsocketClient):
|
|||||||
|
|
||||||
return req
|
return req
|
||||||
|
|
||||||
def on_tick(self, l: list, t: int):
|
def on_tick(self, l: List, t: int):
|
||||||
""""""
|
""""""
|
||||||
d = l[0]
|
d = l[0]
|
||||||
symbol = d["contract"]
|
symbol = d["contract"]
|
||||||
@ -645,10 +624,11 @@ class GateiosWebsocketApi(WebsocketClient):
|
|||||||
return
|
return
|
||||||
|
|
||||||
tick.last_price = float(d["last"])
|
tick.last_price = float(d["last"])
|
||||||
|
tick.volume = int(d["volume_24h"])
|
||||||
tick.datetime = datetime.fromtimestamp(t)
|
tick.datetime = datetime.fromtimestamp(t)
|
||||||
self.gateway.on_tick(copy(tick))
|
self.gateway.on_tick(copy(tick))
|
||||||
|
|
||||||
def on_depth(self, d: dict, t: int):
|
def on_depth(self, d: Dict, t: int):
|
||||||
""""""
|
""""""
|
||||||
symbol = d["contract"]
|
symbol = d["contract"]
|
||||||
tick = self.ticks.get(symbol, None)
|
tick = self.ticks.get(symbol, None)
|
||||||
@ -671,18 +651,21 @@ class GateiosWebsocketApi(WebsocketClient):
|
|||||||
|
|
||||||
self.gateway.on_tick(copy(tick))
|
self.gateway.on_tick(copy(tick))
|
||||||
|
|
||||||
def on_order(self, l: list, t: int):
|
def on_order(self, l: List, t: int):
|
||||||
""""""
|
""""""
|
||||||
d = l[0]
|
d = l[0]
|
||||||
|
|
||||||
local_orderid = str(d["text"])[2:]
|
local_orderid = str(d["text"])[2:]
|
||||||
|
|
||||||
volume = d["size"]
|
if d["size"] > 0:
|
||||||
if volume > 0:
|
|
||||||
direction = Direction.LONG
|
direction = Direction.LONG
|
||||||
else:
|
else:
|
||||||
direction = Direction.SHORT
|
direction = Direction.SHORT
|
||||||
|
|
||||||
|
volume = abs(d["size"])
|
||||||
|
traded = abs(d["size"] - d["left"])
|
||||||
|
status = get_order_status(d["status"], volume, traded)
|
||||||
|
|
||||||
order = OrderData(
|
order = OrderData(
|
||||||
orderid=local_orderid,
|
orderid=local_orderid,
|
||||||
symbol=d["contract"],
|
symbol=d["contract"],
|
||||||
@ -691,29 +674,34 @@ class GateiosWebsocketApi(WebsocketClient):
|
|||||||
volume=abs(volume),
|
volume=abs(volume),
|
||||||
type=OrderType.LIMIT,
|
type=OrderType.LIMIT,
|
||||||
direction=direction,
|
direction=direction,
|
||||||
status=STATUS_GATEIO2VT[d["status"]],
|
status=status,
|
||||||
time=datetime.fromtimestamp(t).strftime("%H:%M:%S"),
|
time=datetime.fromtimestamp(t).strftime("%H:%M:%S"),
|
||||||
gateway_name=self.gateway_name,
|
gateway_name=self.gateway_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.order_manager.on_order(copy(order))
|
self.order_manager.on_order(order)
|
||||||
|
|
||||||
# Update trade
|
def on_trade(self, l: List, t: int):
|
||||||
if order.status == Status.ALLTRADED:
|
""""""
|
||||||
self.trade_count += 1
|
d = l[0]
|
||||||
|
|
||||||
trade = TradeData(
|
sys_orderid = d["order_id"]
|
||||||
symbol=order.symbol,
|
order = self.order_manager.get_order_with_sys_orderid(sys_orderid)
|
||||||
exchange=order.exchange,
|
if not order:
|
||||||
orderid=order.orderid,
|
return
|
||||||
tradeid=str(self.trade_count).rjust(8, "0"),
|
|
||||||
direction=order.direction,
|
trade = TradeData(
|
||||||
price=float(d["fill_price"]),
|
symbol=order.symbol,
|
||||||
volume=order.volume,
|
exchange=order.exchange,
|
||||||
time=order.time,
|
orderid=order.orderid,
|
||||||
gateway_name=self.gateway_name,
|
tradeid=d["id"],
|
||||||
)
|
direction=order.direction,
|
||||||
self.gateway.on_trade(trade)
|
price=float(d["price"]),
|
||||||
|
volume=abs(d["size"]),
|
||||||
|
time=datetime.fromtimestamp(d["create_time"]).strftime("%H:%M:%S"),
|
||||||
|
gateway_name=self.gateway_name,
|
||||||
|
)
|
||||||
|
self.gateway.on_trade(trade)
|
||||||
|
|
||||||
|
|
||||||
def generate_sign(key, secret, method, path, get_params=None, get_data=None):
|
def generate_sign(key, secret, method, path, get_params=None, get_data=None):
|
||||||
@ -768,3 +756,17 @@ def generate_websocket_sign(secret, channel, event, time):
|
|||||||
).hexdigest()
|
).hexdigest()
|
||||||
|
|
||||||
return signature
|
return signature
|
||||||
|
|
||||||
|
|
||||||
|
def get_order_status(status: str, volume: int, traded: int):
|
||||||
|
""""""
|
||||||
|
if status == "open":
|
||||||
|
if traded:
|
||||||
|
return Status.PARTTRADED
|
||||||
|
else:
|
||||||
|
return Status.NOTTRADED
|
||||||
|
else:
|
||||||
|
if traded == volume:
|
||||||
|
return Status.ALLTRADED
|
||||||
|
else:
|
||||||
|
return Status.CANCELLED
|
||||||
|
Loading…
Reference in New Issue
Block a user