You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
5.2 KiB
187 lines
5.2 KiB
from datetime import datetime, timedelta
|
|
from typing import List
|
|
|
|
from rqdatac import init as rqdata_init
|
|
from rqdatac.services.basic import all_instruments as rqdata_all_instruments
|
|
from rqdatac.services.get_price import get_price as rqdata_get_price
|
|
|
|
from source.common.config import SETTINGS
|
|
from source.common.datastruct import BarData, HistoryRequest
|
|
from source.common.constant import Exchange, Interval
|
|
|
|
|
|
INTERVAL_VT2RQ = {
|
|
Interval.MINUTE: "1m",
|
|
Interval.HOUR: "60m",
|
|
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:
|
|
"""
|
|
Client for querying history data from RQData.
|
|
"""
|
|
|
|
def __init__(self):
|
|
""""""
|
|
self.username = SETTINGS["rqdata.username"]
|
|
self.password = SETTINGS["rqdata.password"]
|
|
|
|
self.inited = False
|
|
self.symbols = set()
|
|
|
|
def init(self):
|
|
""""""
|
|
if self.inited:
|
|
return True
|
|
|
|
if not self.username or not self.password:
|
|
return False
|
|
|
|
rqdata_init(self.username, self.password,
|
|
('rqdatad-pro.ricequant.com', 16011))
|
|
|
|
try:
|
|
df = rqdata_all_instruments(date=datetime.now())
|
|
for ix, row in df.iterrows():
|
|
self.symbols.add(row['order_book_id'])
|
|
except RuntimeError:
|
|
return False
|
|
|
|
self.inited = True
|
|
return True
|
|
|
|
def to_rq_symbol(self, symbol: str, exchange: Exchange):
|
|
"""
|
|
CZCE product of RQData has symbol like "TA1905" while
|
|
vt symbol is "TA905.CZCE" so need to add "1" in symbol.
|
|
"""
|
|
if exchange in [Exchange.SSE, Exchange.SZSE]:
|
|
if exchange == Exchange.SSE:
|
|
rq_symbol = f"{symbol}.XSHG"
|
|
else:
|
|
rq_symbol = f"{symbol}.XSHE"
|
|
else:
|
|
if exchange is not Exchange.CZCE:
|
|
return symbol.upper()
|
|
|
|
for count, word in enumerate(symbol):
|
|
if word.isdigit():
|
|
break
|
|
|
|
# noinspection PyUnboundLocalVariable
|
|
product = symbol[:count]
|
|
year = symbol[count]
|
|
month = symbol[count + 1:]
|
|
|
|
if year == "9":
|
|
year = "1" + year
|
|
else:
|
|
year = "2" + year
|
|
|
|
rq_symbol = f"{product}{year}{month}".upper()
|
|
|
|
return rq_symbol
|
|
|
|
def query_bar(
|
|
self,
|
|
symbol: str,
|
|
exchange: Exchange,
|
|
interval: Interval,
|
|
start: datetime,
|
|
end: datetime
|
|
):
|
|
"""
|
|
Query bar data from RQData.
|
|
"""
|
|
rq_symbol = self.to_rq_symbol(symbol, exchange)
|
|
if rq_symbol not in self.symbols:
|
|
return None
|
|
|
|
end += timedelta(1) # For querying night trading period data
|
|
|
|
df = rqdata_get_price(
|
|
rq_symbol,
|
|
frequency=interval.value,
|
|
fields=["open", "high", "low", "close", "volume","open_interest"],
|
|
start_date=start,
|
|
end_date=end
|
|
)
|
|
|
|
data: List[BarData] = []
|
|
for ix, row in df.iterrows():
|
|
bar = BarData(
|
|
symbol=symbol,
|
|
exchange=exchange,
|
|
interval=interval,
|
|
datetime=row.name.to_pydatetime(),
|
|
open_price=row["open"],
|
|
high_price=row["high"],
|
|
low_price=row["low"],
|
|
close_price=row["close"],
|
|
volume=row["volume"],
|
|
open_interest=row["open_interest"],
|
|
gateway_name="RQ"
|
|
)
|
|
data.append(bar)
|
|
|
|
return data
|
|
|
|
def query_history(self, req: HistoryRequest):
|
|
"""
|
|
Query history bar data from RQData.
|
|
"""
|
|
symbol = req.symbol
|
|
exchange = req.exchange
|
|
interval = req.interval
|
|
start = req.start
|
|
end = req.end
|
|
|
|
rq_symbol = self.to_rq_symbol(symbol, exchange)
|
|
if rq_symbol not in self.symbols:
|
|
return None
|
|
rq_interval = INTERVAL_VT2RQ.get(interval)
|
|
if not rq_interval:
|
|
return None
|
|
|
|
# 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(
|
|
rq_symbol,
|
|
frequency=rq_interval,
|
|
fields=["open", "high", "low", "close", "volume","open_interest"],
|
|
start_date=start,
|
|
end_date=end
|
|
)
|
|
|
|
data: List[BarData] = []
|
|
for ix, row in df.iterrows():
|
|
bar = BarData(
|
|
symbol=symbol,
|
|
exchange=exchange,
|
|
interval=interval,
|
|
datetime=row.name.to_pydatetime() - adjustment,
|
|
open_price=row["open"],
|
|
high_price=row["high"],
|
|
low_price=row["low"],
|
|
close_price=row["close"],
|
|
volume=row["volume"],
|
|
open_interest=row["open_interest"],
|
|
gateway_name="RQ"
|
|
)
|
|
data.append(bar)
|
|
|
|
return data
|
|
|
|
|
|
rqdata_client = RqdataClient()
|
|
|