diff --git a/qlib/data/storage/file_storage.py b/qlib/data/storage/file_storage.py index e2bc5c3679a..91ba3101913 100644 --- a/qlib/data/storage/file_storage.py +++ b/qlib/data/storage/file_storage.py @@ -230,10 +230,10 @@ def _write_instrument(self, data: Dict[InstKT, InstVT] = None) -> None: res.append(_df) df = pd.concat(res, sort=False) + # persist in the column order _read_instrument expects: symbol, start, end df.loc[:, [self.SYMBOL_FIELD_NAME, self.INSTRUMENT_START_FIELD, self.INSTRUMENT_END_FIELD]].to_csv( - self.uri, header=False, sep=self.INSTRUMENT_SEP, index=False + self.uri, header=False, sep=self.INSTRUMENT_SEP, index=False, encoding="utf-8" ) - df.to_csv(self.uri, sep="\t", encoding="utf-8", header=False, index=False) def clear(self) -> None: self._write_instrument(data={}) diff --git a/tests/storage_tests/test_storage.py b/tests/storage_tests/test_storage.py index 92fed34ecda..bae1bf6f37a 100644 --- a/tests/storage_tests/test_storage.py +++ b/tests/storage_tests/test_storage.py @@ -4,8 +4,12 @@ from pathlib import Path from collections.abc import Iterable +import tempfile +import unittest import numpy as np +import pandas as pd +import qlib from qlib.tests import TestAutoData from qlib.data.storage.file_storage import ( @@ -168,3 +172,29 @@ def test_feature_storage(self): print(feature[:].empty) with self.assertRaises(ValueError): print(feature.data.empty) + + +class TestInstrumentStorageRoundTrip(unittest.TestCase): + """_write_instrument must persist the column order _read_instrument parses.""" + + def test_write_then_read(self): + with tempfile.TemporaryDirectory() as tmp: + provider_uri = str(Path(tmp) / "cn_data") + (Path(tmp) / "cn_data" / "instruments").mkdir(parents=True) + calendars_dir = Path(tmp) / "cn_data" / "calendars" + calendars_dir.mkdir(parents=True) + # bootstrap day-calendar data so the storage uri validation accepts the provider + np.savetxt( + calendars_dir / "day.txt", + pd.bdate_range("2024-01-02", periods=5), + fmt="%s", + encoding="utf-8", + ) + qlib.init(provider_uri=provider_uri, region="cn") + + inst = InstrumentStorage(market="roundtrip", freq="day", provider_uri=provider_uri) + spans = [(pd.Timestamp("2024-01-02"), pd.Timestamp("2024-01-31"))] + inst["SH600000"] = spans + + self.assertEqual(inst["SH600000"], spans) + self.assertEqual(inst.data, {"SH600000": spans})