[Add] download bar data from gateway in CtaBacktester
This commit is contained in:
parent
e1c824307e
commit
8c707435e8
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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(
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user