[Add] query_history function for BinanceGateway

This commit is contained in:
vn.py 2019-07-16 14:43:20 +08:00
parent 28b9ce6d8d
commit 4d36b5198b
3 changed files with 114 additions and 13 deletions

View File

@ -4,11 +4,11 @@ from vnpy.event import EventEngine
from vnpy.trader.engine import MainEngine from vnpy.trader.engine import MainEngine
from vnpy.trader.ui import MainWindow, create_qapp from vnpy.trader.ui import MainWindow, create_qapp
# from vnpy.gateway.binance import BinanceGateway from vnpy.gateway.binance import BinanceGateway
# from vnpy.gateway.bitmex import BitmexGateway # from vnpy.gateway.bitmex import BitmexGateway
# from vnpy.gateway.futu import FutuGateway # from vnpy.gateway.futu import FutuGateway
# from vnpy.gateway.ib import IbGateway # from vnpy.gateway.ib import IbGateway
from vnpy.gateway.ctp import CtpGateway # from vnpy.gateway.ctp import CtpGateway
# from vnpy.gateway.ctptest import CtptestGateway # from vnpy.gateway.ctptest import CtptestGateway
# from vnpy.gateway.femas import FemasGateway # from vnpy.gateway.femas import FemasGateway
# from vnpy.gateway.tiger import TigerGateway # from vnpy.gateway.tiger import TigerGateway
@ -42,8 +42,8 @@ def main():
main_engine = MainEngine(event_engine) main_engine = MainEngine(event_engine)
# main_engine.add_gateway(BinanceGateway) main_engine.add_gateway(BinanceGateway)
main_engine.add_gateway(CtpGateway) # main_engine.add_gateway(CtpGateway)
# main_engine.add_gateway(CtptestGateway) # main_engine.add_gateway(CtptestGateway)
# main_engine.add_gateway(FemasGateway) # main_engine.add_gateway(FemasGateway)
# main_engine.add_gateway(IbGateway) # main_engine.add_gateway(IbGateway)

View File

@ -315,8 +315,11 @@ class BacktesterManager(QtWidgets.QWidget):
"""""" """"""
vt_symbol = self.symbol_line.text() vt_symbol = self.symbol_line.text()
interval = self.interval_combo.currentText() interval = self.interval_combo.currentText()
start = self.start_date_edit.date().toPyDate() start_date = self.start_date_edit.date()
end = self.end_date_edit.date().toPyDate() end_date = self.end_date_edit.date()
start = datetime(start_date.year(), start_date.month(), start_date.day())
end = datetime(end_date.year(), end_date.month(), end_date.day())
self.backtester_engine.start_downloading( self.backtester_engine.start_downloading(
vt_symbol, vt_symbol,

View File

@ -7,7 +7,7 @@ import hashlib
import hmac import hmac
import time import time
from copy import copy from copy import copy
from datetime import datetime from datetime import datetime, timedelta
from enum import Enum from enum import Enum
from threading import Lock from threading import Lock
@ -18,7 +18,8 @@ from vnpy.trader.constant import (
Exchange, Exchange,
Product, Product,
Status, Status,
OrderType OrderType,
Interval
) )
from vnpy.trader.gateway import BaseGateway from vnpy.trader.gateway import BaseGateway
from vnpy.trader.object import ( from vnpy.trader.object import (
@ -27,9 +28,11 @@ from vnpy.trader.object import (
TradeData, TradeData,
AccountData, AccountData,
ContractData, ContractData,
BarData,
OrderRequest, OrderRequest,
CancelRequest, CancelRequest,
SubscribeRequest SubscribeRequest,
HistoryRequest
) )
from vnpy.trader.event import EVENT_TIMER from vnpy.trader.event import EVENT_TIMER
from vnpy.event import Event from vnpy.event import Event
@ -59,6 +62,18 @@ DIRECTION_VT2BINANCE = {
} }
DIRECTION_BINANCE2VT = {v: k for k, v in DIRECTION_VT2BINANCE.items()} DIRECTION_BINANCE2VT = {v: k for k, v in DIRECTION_VT2BINANCE.items()}
INTERVAL_VT2BINANCE = {
Interval.MINUTE: "1m",
Interval.HOUR: "1h",
Interval.DAILY: "1d",
}
TIMEDELTA_MAP = {
Interval.MINUTE: timedelta(minutes=1),
Interval.HOUR: timedelta(hours=1),
Interval.DAILY: timedelta(days=1),
}
class Security(Enum): class Security(Enum):
NONE = 0 NONE = 0
@ -126,6 +141,10 @@ class BinanceGateway(BaseGateway):
"""""" """"""
pass pass
def query_history(self, req: HistoryRequest):
""""""
return self.rest_api.query_history(req)
def close(self): def close(self):
"""""" """"""
self.rest_api.stop() self.rest_api.stop()
@ -167,14 +186,17 @@ class BinanceRestApi(RestClient):
""" """
Generate BINANCE signature. Generate BINANCE signature.
""" """
security = request.data["security"]
if security == Security.NONE:
request.data = None
return request
if request.params: if request.params:
path = request.path + "?" + urllib.parse.urlencode(request.params) path = request.path + "?" + urllib.parse.urlencode(request.params)
else: else:
request.params = dict() request.params = dict()
path = request.path path = request.path
security = request.data["security"]
if security == Security.SIGNED: if security == Security.SIGNED:
timestamp = int(time.time() * 1000) timestamp = int(time.time() * 1000)
@ -184,7 +206,6 @@ class BinanceRestApi(RestClient):
timestamp += abs(self.time_offset) timestamp += abs(self.time_offset)
request.params["timestamp"] = timestamp request.params["timestamp"] = timestamp
# request.params["recv_window"] = self.recv_window
query = urllib.parse.urlencode(sorted(request.params.items())) query = urllib.parse.urlencode(sorted(request.params.items()))
signature = hmac.new(self.secret, query.encode( signature = hmac.new(self.secret, query.encode(
@ -204,7 +225,7 @@ class BinanceRestApi(RestClient):
"X-MBX-APIKEY": self.key "X-MBX-APIKEY": self.key
} }
if security == Security.SIGNED or security == Security.API_KEY: if security in [Security.SIGNED, Security.API_KEY]:
request.headers = headers request.headers = headers
return request return request
@ -454,6 +475,7 @@ class BinanceRestApi(RestClient):
size=1, size=1,
min_volume=min_volume, min_volume=min_volume,
product=Product.SPOT, product=Product.SPOT,
history_data=True,
gateway_name=self.gateway_name, gateway_name=self.gateway_name,
) )
self.gateway.on_contract(contract) self.gateway.on_contract(contract)
@ -507,6 +529,82 @@ class BinanceRestApi(RestClient):
"""""" """"""
pass pass
def query_history(self, req: HistoryRequest):
""""""
history = []
limit = 1000
start_time = int(datetime.timestamp(req.start))
while True:
# Create query params
params = {
"symbol": req.symbol,
"interval": INTERVAL_VT2BINANCE[req.interval],
"limit": limit,
"startTime": start_time * 1000, # convert to millisecond
}
# Add end time if specified
if req.end:
end_time = int(datetime.timestamp(req.end))
params["endTime"] = end_time * 1000 # convert to millisecond
# Get response from server
resp = self.request(
"GET",
"/api/v1/klines",
data={"security": Security.NONE},
params=params
)
# Break if request failed with other status code
if resp.status_code // 100 != 2:
msg = f"获取历史数据失败,状态码:{resp.status_code},信息:{resp.text}"
self.gateway.write_log(msg)
break
else:
data = resp.json()
if not data:
msg = f"获取历史数据为空,开始时间:{start_time}"
self.gateway.write_log(msg)
break
buf = []
for l in data:
dt = datetime.fromtimestamp(l[0] / 1000) # convert to second
bar = BarData(
symbol=req.symbol,
exchange=req.exchange,
datetime=dt,
interval=req.interval,
volume=float(l[5]),
open_price=float(l[1]),
high_price=float(l[2]),
low_price=float(l[3]),
close_price=float(l[4]),
gateway_name=self.gateway_name
)
buf.append(bar)
history.extend(buf)
begin = buf[0].datetime
end = buf[-1].datetime
msg = f"获取历史数据成功,{req.symbol} - {req.interval.value}{begin} - {end}"
self.gateway.write_log(msg)
# Break if total data count less than limit (latest date collected)
if len(data) < limit:
break
# Update start time
start_dt = bar.datetime + TIMEDELTA_MAP[req.interval]
start_time = int(datetime.timestamp(start_dt))
return history
class BinanceTradeWebsocketApi(WebsocketClient): class BinanceTradeWebsocketApi(WebsocketClient):
"""""" """"""