mirror of
https://github.com/microsoft/qlib.git
synced 2026-07-15 08:46:56 +08:00
Fix FileStorage
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) Microsoft Corporation.
|
# Copyright (c) Microsoft Corporation.
|
||||||
# Licensed under the MIT License.
|
# Licensed under the MIT License.
|
||||||
|
|
||||||
from .storage import CalendarStorage, InstrumentStorage, FeatureStorage
|
from .storage import CalendarStorage, InstrumentStorage, FeatureStorage
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
# Copyright (c) Microsoft Corporation.
|
# Copyright (c) Microsoft Corporation.
|
||||||
# Licensed under the MIT License.
|
# Licensed under the MIT License.
|
||||||
|
|
||||||
|
import struct
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Iterator, Iterable, Type, List, Tuple, Text, Union
|
from typing import Iterator, Iterable, Type, List, Tuple, Text, Union
|
||||||
|
|
||||||
from data.storage.storage import FeatureVT
|
from .storage import FeatureVT
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from qlib.data.storage import CalendarStorage, InstrumentStorage, FeatureStorage
|
from . import CalendarStorage, InstrumentStorage, FeatureStorage
|
||||||
|
|
||||||
|
|
||||||
CalVT = Type[pd.Timestamp]
|
CalVT = Type[pd.Timestamp]
|
||||||
@@ -70,9 +71,9 @@ class FileFeatureStorage(FeatureStorage):
|
|||||||
|
|
||||||
if isinstance(i, int):
|
if isinstance(i, int):
|
||||||
if ref_start_index > i:
|
if ref_start_index > i:
|
||||||
raise IndexError(f"{i}")
|
raise IndexError(f"{i}: start index is {ref_start_index}")
|
||||||
fp.seek(4 * (i - ref_start_index) + 4)
|
fp.seek(4 * (i - ref_start_index) + 4)
|
||||||
return i, float(fp.read(4))
|
return i, struct.unpack("f", fp.read(4))
|
||||||
elif isinstance(i, slice):
|
elif isinstance(i, slice):
|
||||||
start_index = i.start
|
start_index = i.start
|
||||||
end_index = i.stop - 1
|
end_index = i.stop - 1
|
||||||
@@ -83,9 +84,18 @@ class FileFeatureStorage(FeatureStorage):
|
|||||||
# read n bytes
|
# read n bytes
|
||||||
count = end_index - si + 1
|
count = end_index - si + 1
|
||||||
data = np.frombuffer(fp.read(4 * count), dtype="<f")
|
data = np.frombuffer(fp.read(4 * count), dtype="<f")
|
||||||
return zip(range(si, si + len(data)), data)
|
return list(zip(range(si, si + len(data)), data))
|
||||||
else:
|
else:
|
||||||
raise TypeError(f"type(i) = {type(i)}")
|
raise TypeError(f"type(i) = {type(i)}")
|
||||||
|
|
||||||
def __len__(self) -> int:
|
def __len__(self) -> int:
|
||||||
return Path(self._uri).stat().st_size // 4 - 1
|
return Path(self._uri).stat().st_size // 4 - 1
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
with open(self._uri, "rb") as fp:
|
||||||
|
ref_start_index = int(np.frombuffer(fp.read(4), dtype="<f")[0])
|
||||||
|
fp.seek(4)
|
||||||
|
# read n bytes
|
||||||
|
data = np.frombuffer(fp.read(), dtype="<f")
|
||||||
|
for v in zip(range(ref_start_index, ref_start_index + len(data)), data):
|
||||||
|
yield v
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Copyright (c) Microsoft Corporation.
|
# Copyright (c) Microsoft Corporation.
|
||||||
# Licensed under the MIT License.
|
# Licensed under the MIT License.
|
||||||
from abc import abstractmethod
|
|
||||||
from collections.abc import MutableSequence, MutableMapping, Sequence
|
from collections.abc import MutableSequence, MutableMapping, Sequence
|
||||||
from typing import Iterable, overload, TypeVar, Tuple, List, Text, Iterator
|
from typing import Iterable, overload, TypeVar, Tuple, List, Text, Iterator
|
||||||
|
|
||||||
|
|||||||
@@ -1,54 +1,50 @@
|
|||||||
# Copyright (c) Microsoft Corporation.
|
# Copyright (c) Microsoft Corporation.
|
||||||
# Licensed under the MIT License.
|
# Licensed under the MIT License.
|
||||||
|
|
||||||
|
|
||||||
|
import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from importlib.util import spec_from_file_location, module_from_spec
|
from collections.abc import Iterable
|
||||||
|
|
||||||
import pandas as pd
|
import pytest
|
||||||
|
import numpy as np
|
||||||
|
from qlib.tests.data import GetData
|
||||||
|
|
||||||
|
from qlib.data.storage.file_storage import (
|
||||||
|
FileCalendarStorage as CalendarStorage,
|
||||||
|
FileInstrumentStorage as InstrumentStorage,
|
||||||
|
FileFeatureStorage as FeatureStorage,
|
||||||
|
)
|
||||||
|
|
||||||
|
DATA_DIR = Path(__file__).parent.joinpath("test_get_data")
|
||||||
|
QLIB_DIR = DATA_DIR.joinpath("qlib")
|
||||||
|
QLIB_DIR.mkdir(exist_ok=True, parents=True)
|
||||||
|
|
||||||
|
|
||||||
# TODO: set STORAGE_NAME
|
|
||||||
STORAGE_NAME = ""
|
|
||||||
STORAGE_FILE_PATH = Path("")
|
|
||||||
# TODO: set value
|
# TODO: set value
|
||||||
CALENDAR_URI = ""
|
CALENDAR_URI = QLIB_DIR.joinpath("calendars").joinpath("day.txt")
|
||||||
INSTRUMENT_URI = ""
|
INSTRUMENT_URI = QLIB_DIR.joinpath("instruments").joinpath("csi300.txt")
|
||||||
FEATURE_URI = ""
|
FEATURE_URI = QLIB_DIR.joinpath("features").joinpath("SH600004").joinpath("close.day.bin")
|
||||||
|
|
||||||
|
|
||||||
def get_module(module_path: Path):
|
class TestStorage:
|
||||||
module_spec = spec_from_file_location("", module_path)
|
@classmethod
|
||||||
module = module_from_spec(module_spec)
|
def setup_class(cls):
|
||||||
module_spec.loader.exec_module(module)
|
GetData().qlib_data(name="qlib_data_simple", target_dir=QLIB_DIR, region="cn", interval="1d", delete_old=False)
|
||||||
return module
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def teardown_class(cls):
|
||||||
|
shutil.rmtree(str(DATA_DIR.resolve()))
|
||||||
|
|
||||||
STORAGE_MODULE = get_module(STORAGE_FILE_PATH)
|
|
||||||
|
|
||||||
|
|
||||||
CalendarStorage = getattr(STORAGE_MODULE, f"{STORAGE_NAME.title()}CalendarStorage")
|
|
||||||
InstrumentStorage = getattr(STORAGE_MODULE, f"{STORAGE_NAME.title()}InstrumentStorage")
|
|
||||||
FeatureStorage = getattr(STORAGE_MODULE, f"{STORAGE_NAME.title()}FeatureStorage")
|
|
||||||
|
|
||||||
|
|
||||||
class TestCalendarStorage:
|
|
||||||
def test_calendar_storage(self):
|
def test_calendar_storage(self):
|
||||||
# calendar value: pd.date_range(start="2005-01-01", stop="2005-03-01", freq="1D")
|
|
||||||
start_date = "2005-01-01"
|
|
||||||
end_date = "2005-03-01"
|
|
||||||
values = pd.date_range(start_date, end_date, freq="1D")
|
|
||||||
|
|
||||||
calendar = CalendarStorage(uri=CALENDAR_URI)
|
calendar = CalendarStorage(uri=CALENDAR_URI)
|
||||||
# test `__iter__`
|
assert isinstance(calendar, Iterable), f"{calendar.__class__.__name__} is not Iterable"
|
||||||
for _s, _t in zip(calendar, values):
|
assert isinstance(calendar[:], Iterable), f"{calendar.__class__.__name__}.__getitem__(s: slice) is not Iterable"
|
||||||
assert pd.Timestamp(_s) == pd.Timestamp(_t), f"{calendar.__name__}.__iter__ error"
|
|
||||||
|
|
||||||
# test `__getitem__(self, s: slice)`
|
print(f"calendar[1: 5]: {calendar[1:5]}")
|
||||||
for _s, _t in zip(calendar[1:3], values[1:3]):
|
print(f"calendar[0]: {calendar[0]}")
|
||||||
assert pd.Timestamp(_s) == pd.Timestamp(_t), f"{calendar.__name__}.__getitem__(s: slice) error"
|
print(f"calendar[-1]: {calendar[-1]}")
|
||||||
|
|
||||||
# test `__getitem__(self, i)`
|
|
||||||
assert pd.Timestamp(calendar[0]) == pd.Timestamp(values[0]), f"{calendar.__name__}.__getitem__(i: int) error"
|
|
||||||
|
|
||||||
def test_instrument_storage(self):
|
def test_instrument_storage(self):
|
||||||
"""
|
"""
|
||||||
@@ -83,24 +79,21 @@ class TestCalendarStorage:
|
|||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
base_instrument = {
|
|
||||||
"SH600000": [("2005-01-01", "2005-01-31"), ("2005-02-15", "2005-03-01")],
|
|
||||||
"SH600001": [("2005-01-01", "2005-03-01")],
|
|
||||||
"SH600002": [("2005-01-01", "2005-02-14")],
|
|
||||||
"SH600003": [("2005-02-01", "2005-03-01")],
|
|
||||||
}
|
|
||||||
instrument = InstrumentStorage(uri=INSTRUMENT_URI)
|
instrument = InstrumentStorage(uri=INSTRUMENT_URI)
|
||||||
|
|
||||||
# test `keys`
|
assert isinstance(instrument, Iterable), f"{instrument.__class__.__name__} is not Iterable"
|
||||||
assert sorted(instrument.keys()) == sorted(base_instrument.keys()), f"{instrument.__name__}.keys error"
|
|
||||||
# test `__getitem__`
|
for inst, spans in instrument.items():
|
||||||
assert instrument["SH600000"] == base_instrument["SH600000"], f"{instrument.__name__}.__getitem__ error"
|
assert isinstance(inst, str) and isinstance(
|
||||||
# test `get`
|
spans, Iterable
|
||||||
assert instrument.get("SH600001") == base_instrument.get("SH600001"), f"{instrument.__name__}.get error"
|
), f"{instrument.__class__.__name__} value is not Iterable"
|
||||||
# test `items`
|
for s_e in spans:
|
||||||
for _item in instrument.items():
|
assert (
|
||||||
assert base_instrument[_item[0]] == _item[1]
|
isinstance(s_e, tuple) and len(s_e) == 2
|
||||||
assert len(instrument.items()) == len(instrument) == len(base_instrument), f"{instrument.__name__}.items error"
|
), f"{instrument.__class__.__name__}.__getitem__(k) TypeError"
|
||||||
|
|
||||||
|
print(f"instrument['SH600000']: {instrument['SH600000']}")
|
||||||
|
|
||||||
def test_feature_storage(self):
|
def test_feature_storage(self):
|
||||||
"""
|
"""
|
||||||
@@ -156,19 +149,18 @@ class TestCalendarStorage:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# FeatureStorage(SH600003, close)
|
|
||||||
feature = FeatureStorage(uri=FEATURE_URI)
|
feature = FeatureStorage(uri=FEATURE_URI)
|
||||||
# 2005-02-01 and 2005-03-01
|
|
||||||
assert feature[31] == 1 and feature[59] == 4, f"{feature.__name__}.__getitem__(i: int) error"
|
|
||||||
|
|
||||||
# 2005-02-01, 2005-02-02, 2005-02-03
|
assert isinstance(feature, Iterable), f"{feature.__class__.__name__} is not Iterable"
|
||||||
# close_items: [(31, 1), ..., (33, <value>)]
|
with pytest.raises(IndexError):
|
||||||
close_items = feature[31:34]
|
print(feature[0])
|
||||||
|
assert len(feature[815:818]) == 3, f"{feature.__class__.__name__}.__getitem__(s: slice) error"
|
||||||
|
print(f"feature[815: 818]: {feature[815: 818]}")
|
||||||
|
|
||||||
# 2005-02-01, ..., 2005-03-01
|
for _item in feature:
|
||||||
# feature: [(31, 1), ..., (59, 4)]
|
assert (
|
||||||
print(feature)
|
isinstance(_item, tuple) and len(_item) == 2
|
||||||
|
), f"{feature.__class__.__name__}.__iter__ item type error"
|
||||||
assert (
|
assert isinstance(_item[0], int) and isinstance(
|
||||||
len(feature) == len(feature[:]) == len(feature[31:60]) == 29
|
_item[1], (float, np.float, np.float32)
|
||||||
), f"{feature.__name__}.items/__getitem__(s: slice) error"
|
), f"{feature.__class__.__name__}.__iter__ value type error"
|
||||||
|
|||||||
Reference in New Issue
Block a user