[Add] download bar data from gateway in CtaBacktester

This commit is contained in:
vn.py 2019-05-08 15:39:15 +08:00
parent e1c824307e
commit 8c707435e8
5 changed files with 108 additions and 14 deletions

View File

@ -258,7 +258,7 @@ class RestClient(object):
request.response = response request.response = response
status_code = response.status_code status_code = response.status_code
if status_code / 100 == 2: # 2xx都算成功尽管交易所都用200 if status_code // 100 == 2: # 2xx都算成功尽管交易所都用200
jsonBody = response.json() jsonBody = response.json()
request.callback(jsonBody, request) request.callback(jsonBody, request)
request.status = RequestStatus.success request.status = RequestStatus.success

View File

@ -9,6 +9,7 @@ from vnpy.event import Event, EventEngine
from vnpy.trader.engine import BaseEngine, MainEngine from vnpy.trader.engine import BaseEngine, MainEngine
from vnpy.trader.constant import Interval from vnpy.trader.constant import Interval
from vnpy.trader.utility import extract_vt_symbol from vnpy.trader.utility import extract_vt_symbol
from vnpy.trader.object import HistoryRequest
from vnpy.trader.rqdata import rqdata_client from vnpy.trader.rqdata import rqdata_client
from vnpy.trader.database import database_manager from vnpy.trader.database import database_manager
from vnpy.app.cta_strategy import ( from vnpy.app.cta_strategy import (
@ -337,10 +338,25 @@ class BacktesterEngine(BaseEngine):
""" """
self.write_log(f"{vt_symbol}-{interval}开始下载历史数据") self.write_log(f"{vt_symbol}-{interval}开始下载历史数据")
symbol, exchange = extract_vt_symbol(vt_symbol) contract = self.main_engine.get_contract(vt_symbol)
data = rqdata_client.query_bar(
symbol, exchange, Interval(interval), start, end # If history data provided in gateway, then query
) if contract and contract.history_data:
req = HistoryRequest(
symbol=contract.symbol,
exchange=contract.exchange,
interval=Interval(interval),
start=start,
end=end
)
data = self.main_engine.query_history(req, contract.gateway_name)
# Otherwise use RQData to query data
else:
symbol, exchange = extract_vt_symbol(vt_symbol)
data = rqdata_client.query_bar(
symbol, exchange, Interval(interval), start, end
)
if data: if data:
database_manager.save_bar_data(data) database_manager.save_bar_data(data)

View File

@ -56,14 +56,14 @@ class BacktesterManager(QtWidgets.QWidget):
self.class_combo = QtWidgets.QComboBox() self.class_combo = QtWidgets.QComboBox()
self.class_combo.addItems(self.class_names) self.class_combo.addItems(self.class_names)
self.symbol_line = QtWidgets.QLineEdit("IF88.CFFEX") self.symbol_line = QtWidgets.QLineEdit("XBTUSD.BITMEX")
self.interval_combo = QtWidgets.QComboBox() self.interval_combo = QtWidgets.QComboBox()
for inteval in Interval: for inteval in Interval:
self.interval_combo.addItem(inteval.value) self.interval_combo.addItem(inteval.value)
end_dt = datetime.now() end_dt = datetime.now()
start_dt = end_dt - timedelta(days=3 * 365) start_dt = end_dt - timedelta(days=30)# * 365)
self.start_date_edit = QtWidgets.QDateEdit( self.start_date_edit = QtWidgets.QDateEdit(
QtCore.QDate( QtCore.QDate(

View File

@ -7,7 +7,7 @@ import hmac
import sys import sys
import time import time
from copy import copy from copy import copy
from datetime import datetime from datetime import datetime, timedelta
from threading import Lock from threading import Lock
from urllib.parse import urlencode from urllib.parse import urlencode
@ -21,7 +21,8 @@ from vnpy.trader.constant import (
OrderType, OrderType,
Product, Product,
Status, Status,
Offset Offset,
Interval
) )
from vnpy.trader.gateway import BaseGateway from vnpy.trader.gateway import BaseGateway
from vnpy.trader.object import ( from vnpy.trader.object import (
@ -31,6 +32,7 @@ from vnpy.trader.object import (
PositionData, PositionData,
AccountData, AccountData,
ContractData, ContractData,
BarData,
OrderRequest, OrderRequest,
CancelRequest, CancelRequest,
SubscribeRequest, SubscribeRequest,
@ -61,6 +63,18 @@ ORDERTYPE_VT2BITMEX = {
} }
ORDERTYPE_BITMEX2VT = {v: k for k, v in ORDERTYPE_VT2BITMEX.items()} ORDERTYPE_BITMEX2VT = {v: k for k, v in ORDERTYPE_VT2BITMEX.items()}
INTERVAL_VT2BITMEX = {
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 BitmexGateway(BaseGateway): class BitmexGateway(BaseGateway):
""" """
@ -160,7 +174,7 @@ class BitmexRestApi(RestClient):
Generate BitMEX signature. Generate BitMEX signature.
""" """
# Sign # Sign
expires = int(time.time() + 5) expires = int(time.time() + 30)
if request.params: if request.params:
query = urlencode(request.params) query = urlencode(request.params)
@ -286,7 +300,72 @@ class BitmexRestApi(RestClient):
def query_history(self, req: HistoryRequest): def query_history(self, req: HistoryRequest):
"""""" """"""
pass history = []
count = 750
start_time = req.start.isoformat()
while True:
# Create query params
params = {
"binSize": INTERVAL_VT2BITMEX[req.interval],
"symbol": req.symbol,
"count": count,
"startTime": start_time
}
# Add end time if specified
if req.end:
params["endTime"] = req.end.isoformat()
# Get response from server
resp = self.request(
"GET",
"/trade/bucketed",
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()
for d in data:
dt = datetime.strptime(d["timestamp"], "%Y-%m-%dT%H:%M:%S.%fZ")
bar = BarData(
symbol=req.symbol,
exchange=req.exchange,
datetime=dt,
interval=req.interval,
volume=d["volume"],
open_price=d["open"],
high_price=d["high"],
low_price=d["low"],
close_price=d["close"],
gateway_name=self.gateway_name
)
history.append(bar)
begin = data[0]["timestamp"]
end = data[-1]["timestamp"]
msg = f"获取历史数据成功,{req.symbol} - {req.interval.value}{begin} - {end}"
self.gateway.write_log(msg)
# Break if total data count less than 750 (latest date collected)
if len(data) < 750:
break
# Update start time
start_time = bar.datetime + TIMEDELTA_MAP[req.interval]
return history
def on_send_order_failed(self, status_code: str, request: Request): def on_send_order_failed(self, status_code: str, request: Request):
""" """
@ -624,7 +703,7 @@ class BitmexWebsocketApi(WebsocketClient):
size=d["lotSize"], size=d["lotSize"],
stop_supported=True, stop_supported=True,
net_position=True, net_position=True,
bar_history=True, history_data=True,
gateway_name=self.gateway_name, gateway_name=self.gateway_name,
) )

View File

@ -236,8 +236,7 @@ class ContractData(BaseData):
min_volume: float = 1 # minimum trading volume of the contract min_volume: float = 1 # minimum trading volume of the contract
stop_supported: bool = False # whether server supports stop order stop_supported: bool = False # whether server supports stop order
net_position: bool = False # whether gateway uses net position volume net_position: bool = False # whether gateway uses net position volume
bar_history: bool = False # whether gateway provides bar history data history_data: bool = False # whether gateway provides bar history data
tick_history: bool = False # whether gateway provides tick history data
option_strike: float = 0 option_strike: float = 0
option_underlying: str = "" # vt_symbol of underlying contract option_underlying: str = "" # vt_symbol of underlying contract