diff --git a/pyproject.toml b/pyproject.toml index 6350d092c7..987e224730 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,2 @@ [build-system] -requires = ["setuptools", "numpy", "Cython"] +requires = ["setuptools", "numpy", "Cython"] \ No newline at end of file diff --git a/qlib/backtest/exchange.py b/qlib/backtest/exchange.py index 1ab0d07a75..a8a117f9e5 100644 --- a/qlib/backtest/exchange.py +++ b/qlib/backtest/exchange.py @@ -511,6 +511,9 @@ def get_deal_price( self.logger.warning(f"(stock_id:{stock_id}, trade_time:{(start_time, end_time)}, {pstr}): {deal_price}!!!") self.logger.warning(f"setting deal_price to close price") deal_price = self.get_close(stock_id, start_time, end_time, method) + # if stock is delisted, the deal_price(close) will be None,set to 0 + if deal_price is None or np.isnan(deal_price): + deal_price = 0.0 return deal_price def get_factor( diff --git a/qlib/contrib/strategy/cost_control.py b/qlib/contrib/strategy/cost_control.py index ff51f484f5..3a2bce84da 100644 --- a/qlib/contrib/strategy/cost_control.py +++ b/qlib/contrib/strategy/cost_control.py @@ -5,6 +5,7 @@ """ +import pandas as pd from .order_generator import OrderGenWInteract from .signal_strategy import WeightStrategyBase import copy @@ -13,16 +14,11 @@ class SoftTopkStrategy(WeightStrategyBase): def __init__( self, - model, - dataset, topk, order_generator_cls_or_obj=OrderGenWInteract, max_sold_weight=1.0, risk_degree=0.95, buy_method="first_fill", - trade_exchange=None, - level_infra=None, - common_infra=None, **kwargs, ): """ @@ -37,7 +33,8 @@ def __init__( average_fill: assign the weight to the stocks rank high averagely. """ super(SoftTopkStrategy, self).__init__( - model, dataset, order_generator_cls_or_obj, trade_exchange, level_infra, common_infra, **kwargs + order_generator_cls_or_obj=order_generator_cls_or_obj, + **kwargs, ) self.topk = topk self.max_sold_weight = max_sold_weight @@ -70,6 +67,8 @@ def generate_target_weight_position(self, score, current, trade_start_time, trad # TODO: # If the current stock list is more than topk(eg. The weights are modified # by risk control), the weight will not be handled correctly. + if isinstance(score, pd.DataFrame): + score = score.iloc[:, 0] buy_signal_stocks = set(score.sort_values(ascending=False).iloc[: self.topk].index) cur_stock_weight = current.get_stock_weight_dict(only_stock=True) diff --git a/qlib/contrib/strategy/signal_strategy.py b/qlib/contrib/strategy/signal_strategy.py index 9ba960eebd..09ed1cd280 100644 --- a/qlib/contrib/strategy/signal_strategy.py +++ b/qlib/contrib/strategy/signal_strategy.py @@ -333,7 +333,7 @@ def generate_target_weight_position(self, score, current, trade_start_time, trad Parameters ----------- - score : pd.Series + score : pd.DataFrame pred score for this trade date, index is stock_id, contain 'score' column. current : Position() current position. diff --git a/qlib/data/base.py b/qlib/data/base.py index 496ae38ee2..c1c71a3350 100644 --- a/qlib/data/base.py +++ b/qlib/data/base.py @@ -138,6 +138,12 @@ def __ror__(self, other): from .ops import Or # pylint: disable=C0415 return Or(other, self) + + def __pos__(self): + return self + + def __neg__(self): + return 0 - self def load(self, instrument, start_index, end_index, *args): """load feature diff --git a/qlib/data/pit.py b/qlib/data/pit.py index 33d5e0c5cc..673c3cb7b2 100644 --- a/qlib/data/pit.py +++ b/qlib/data/pit.py @@ -39,7 +39,7 @@ def _load_internal(self, instrument, start_index, end_index, freq): s = self._load_feature(instrument, -start_ws, 0, cur_time) resample_data[cur_index - start_index] = s.iloc[-1] if len(s) > 0 else np.nan except FileNotFoundError: - get_module_logger("base").warning(f"WARN: period data not found for {str(self)}") + get_module_logger("base").warning(f"WARN: period data not found for {instrument} {str(self)} ({freq})") return pd.Series(dtype="float32", name=str(self)) resample_series = pd.Series( diff --git a/qlib/data/storage/file_storage.py b/qlib/data/storage/file_storage.py index 8a100a2d19..67554a7d24 100644 --- a/qlib/data/storage/file_storage.py +++ b/qlib/data/storage/file_storage.py @@ -80,6 +80,7 @@ def __init__(self, freq: str, future: bool, provider_uri: dict = None, **kwargs) self._provider_uri = None if provider_uri is None else C.DataPathManager.format_provider_uri(provider_uri) self.enable_read_cache = True # TODO: make it configurable self.region = C["region"] + self.uri.parent.mkdir(parents=True, exist_ok=True) @property def file_name(self) -> str: @@ -90,7 +91,7 @@ def _freq_file(self) -> str: """the freq to read from file""" if not hasattr(self, "_freq_file_cache"): freq = Freq(self.freq) - if freq not in self.support_freq: + if self.support_freq and freq not in self.support_freq: # NOTE: uri # 1. If `uri` does not exist # - Get the `min_uri` of the closest `freq` under the same "directory" as the `uri` @@ -199,6 +200,7 @@ def __init__(self, market: str, freq: str, provider_uri: dict = None, **kwargs): super(FileInstrumentStorage, self).__init__(market, freq, **kwargs) self._provider_uri = None if provider_uri is None else C.DataPathManager.format_provider_uri(provider_uri) self.file_name = f"{market.lower()}.txt" + self.uri.parent.mkdir(parents=True, exist_ok=True) def _read_instrument(self) -> Dict[InstKT, InstVT]: if not self.uri.exists(): @@ -233,7 +235,6 @@ def _write_instrument(self, data: Dict[InstKT, InstVT] = None) -> None: 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 ) - df.to_csv(self.uri, sep="\t", encoding="utf-8", header=False, index=False) def clear(self) -> None: self._write_instrument(data={}) @@ -287,6 +288,7 @@ def __init__(self, instrument: str, field: str, freq: str, provider_uri: dict = super(FileFeatureStorage, self).__init__(instrument, field, freq, **kwargs) self._provider_uri = None if provider_uri is None else C.DataPathManager.format_provider_uri(provider_uri) self.file_name = f"{instrument.lower()}/{field.lower()}.{freq.lower()}.bin" + self.uri.parent.mkdir(parents=True, exist_ok=True) def clear(self): with self.uri.open("wb") as _: @@ -318,7 +320,7 @@ def write(self, data_array: Union[List, np.ndarray], index: int = None) -> None: # rewrite with self.uri.open("rb+") as fp: _old_data = np.fromfile(fp, dtype=" None: _new_df = pd.DataFrame(data_array, index=range(index, index + len(data_array)), columns=["new"]) _df = pd.concat([_old_df, _new_df], sort=False, axis=1) _df = _df.reindex(range(_df.index.min(), _df.index.max() + 1)) - _df["new"].fillna(_df["old"]).values.astype(" Union[int, None]: