1
0
mirror of https://github.com/microsoft/qlib.git synced 2026-07-18 18:04:31 +08:00

add CSI500 data collector

This commit is contained in:
BigTreei
2020-12-26 16:51:52 +08:00
committed by Linlang Lv (iSoftStone)
parent ec8969a3ae
commit 74cc21fc2c
4 changed files with 146 additions and 92 deletions

View File

@@ -1,4 +1,4 @@
# CSI300/CSI100 History Companies Collection
# CSI300/CSI100/CSI500 History Companies Collection
## Requirements
@@ -15,7 +15,7 @@ python collector.py --index_name CSI300 --qlib_dir ~/.qlib/qlib_data/cn_data --m
# parse new companies
python collector.py --index_name CSI300 --qlib_dir ~/.qlib/qlib_data/cn_data --method save_new_companies
# index_name support: CSI300, CSI100
# index_name support: CSI300, CSI100, CSI500
# help
python collector.py --help
```

View File

@@ -5,6 +5,7 @@ import re
import abc
import sys
import importlib
from tqdm import tqdm
from io import BytesIO
from typing import List, Iterable
from pathlib import Path
@@ -12,6 +13,8 @@ from pathlib import Path
import fire
import requests
import pandas as pd
import baostock as bs
from lxml import etree
from loguru import logger
CUR_DIR = Path(__file__).resolve().parent
@@ -44,6 +47,7 @@ def retry_request(url: str, method: str = "get", exclude_status: List = None):
class CSIIndex(IndexBase):
@property
def calendar_list(self) -> List[pd.Timestamp]:
"""get history trading date
@@ -314,6 +318,7 @@ class CSIIndex(IndexBase):
class CSI300(CSIIndex):
@property
def index_code(self):
return "000300"
@@ -324,10 +329,11 @@ class CSI300(CSIIndex):
@property
def html_table_index(self):
return 1
return 0
class CSI100(CSIIndex):
@property
def index_code(self):
return "000903"
@@ -338,16 +344,54 @@ class CSI100(CSIIndex):
@property
def html_table_index(self):
return 2
return 1
class CSI500(CSIIndex):
@property
def index_code(self):
return "000905"
@property
def bench_start_date(self) -> pd.Timestamp:
return pd.Timestamp("2007-01-15")
@property
def html_table_index(self):
return 0
def get_changes(self):
return self.get_changes_with_history_companies(self.get_history_companies())
def get_history_companies(self):
"""
Data sourcehttp://baostock.com/baostock/index.php/%E4%B8%AD%E8%AF%81500%E6%88%90%E5%88%86%E8%82%A1
Avoid a large number of parallel data acquisition,
such as 1000 times of concurrent data acquisition, because IP will be blocked
Returns
-------
"""
lg = bs.login()
today = pd.datetime.now()
date_range = pd.DataFrame(pd.date_range(start="2007-01-15", end=today, freq="7D"))[0].dt.date
ret_list = []
col = ["date", "symbol", "code_name"]
for date in tqdm(date_range, desc="Download CSI500"):
rs = bs.query_zz500_stocks(date=str(date))
zz500_stocks = []
while (rs.error_code == "0") & rs.next():
zz500_stocks.append(rs.get_row_data())
result = pd.DataFrame(zz500_stocks, columns=col)
result["symbol"] = result["symbol"].apply(lambda x: x.replace(".", "").upper())
ret_list.append(result[["date", "symbol"]])
bs.logout()
return pd.concat(ret_list, sort=False)
def get_instruments(
qlib_dir: str,
index_name: str,
method: str = "parse_instruments",
freq: str = "day",
request_retry: int = 5,
retry_sleep: int = 3,
qlib_dir: str, index_name: str, method: str = "parse_instruments", request_retry: int = 5, retry_sleep: int = 3
):
"""

View File

@@ -1,5 +1,8 @@
baostock
logure
fire
requests
pandas
lxml
loguru
tqdm

View File

@@ -28,15 +28,14 @@ SZSE_CALENDAR_URL = "http://www.szse.cn/api/report/exchange/onepersistenthour/mo
CALENDAR_BENCH_URL_MAP = {
"CSI300": CALENDAR_URL_BASE.format(market=1, bench_code="000300"),
"CSI500": CALENDAR_URL_BASE.format(market=1, bench_code="000905"),
"CSI100": CALENDAR_URL_BASE.format(market=1, bench_code="000903"),
# NOTE: Use the time series of SH600000 as the sequence of all stocks
"ALL": CALENDAR_URL_BASE.format(market=1, bench_code="000905"),
# NOTE: Use the time series of ^GSPC(SP500) as the sequence of all stocks
"US_ALL": "^GSPC",
"IN_ALL": "^NSEI",
}
_BENCH_CALENDAR_LIST = None
_ALL_CALENDAR_LIST = None
_HS_SYMBOLS = None
@@ -234,13 +233,16 @@ def get_us_stock_symbols(qlib_data_path: [str, Path] = None) -> list:
resp = requests.get(url)
if resp.status_code != 200:
raise ValueError("request error")
try:
_symbols = [_v["f12"].replace("_", "-P") for _v in resp.json()["data"]["diff"].values()]
except Exception as e:
logger.warning(f"request error: {e}")
raise
if len(_symbols) < 8000:
raise ValueError("request error")
return _symbols
@deco_retry
@@ -273,6 +275,7 @@ def get_us_stock_symbols(qlib_data_path: [str, Path] = None) -> list:
resp = requests.post(url, json=_parms)
if resp.status_code != 200:
raise ValueError("request error")
try:
_symbols = [_v["symbolTicker"].replace("-", "-P") for _v in resp.json()]
except Exception as e:
@@ -449,7 +452,9 @@ def symbol_prefix_to_sufix(symbol: str, capital: bool = True) -> str:
def deco_retry(retry: int = 5, retry_sleep: int = 3):
def deco_func(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
_retry = 5 if callable(retry) else retry
@@ -458,10 +463,12 @@ def deco_retry(retry: int = 5, retry_sleep: int = 3):
try:
_result = func(*args, **kwargs)
break
except Exception as e:
logger.warning(f"{func.__name__}: {_i} :{e}")
if _i == _retry:
raise
time.sleep(retry_sleep)
return _result