1
0
mirror of https://github.com/microsoft/qlib.git synced 2026-07-11 14:56:55 +08:00

Merge pull request #476 from bxdd/qlib_ops_config

Support using config to register custom operators
This commit is contained in:
you-n-g
2021-06-24 20:41:48 +08:00
committed by GitHub
2 changed files with 31 additions and 8 deletions

View File

@@ -195,7 +195,10 @@ MODE_CONF = {
"timeout": 100, "timeout": 100,
"logging_level": logging.INFO, "logging_level": logging.INFO,
"region": REG_CN, "region": REG_CN,
## Custom Operator # custom operator
# each element of custom_ops should be Type[ExpressionOps] or dict
# if element of custom_ops is Type[ExpressionOps], it represents the custom operator class
# if element of custom_ops is dict, it represents the config of custom operator and should include `class` and `module_path` keys.
"custom_ops": [], "custom_ops": [],
}, },
} }

View File

@@ -10,10 +10,12 @@ import abc
import numpy as np import numpy as np
import pandas as pd import pandas as pd
from typing import Union, List, Type
from scipy.stats import percentileofscore from scipy.stats import percentileofscore
from .base import Expression, ExpressionOps from .base import Expression, ExpressionOps
from ..log import get_module_logger from ..log import get_module_logger
from ..utils import get_cls_kwargs
try: try:
from ._libs.rolling import rolling_slope, rolling_rsquare, rolling_resi from ._libs.rolling import rolling_slope, rolling_rsquare, rolling_resi
@@ -1495,16 +1497,34 @@ class OpsWrapper:
def reset(self): def reset(self):
self._ops = {} self._ops = {}
def register(self, ops_list): def register(self, ops_list: List[Union[Type[ExpressionOps], dict]]):
for operator in ops_list: """register operator
if not issubclass(operator, ExpressionOps):
raise TypeError("operator must be subclass of ExpressionOps, not {}".format(operator))
if operator.__name__ in self._ops: Parameters
----------
ops_list : List[Union[Type[ExpressionOps], dict]]
- if type(ops_list) is List[Type[ExpressionOps]], each element of ops_list represents the operator class, which should be the subclass of `ExpressionOps`.
- if type(ops_list) is List[dict], each element of ops_list represents the config of operator, which has the following format:
{
"class": class_name,
"module_path": path,
}
Note: `class` should be the class name of operator, `module_path` should be a python module or path of file.
"""
for _operator in ops_list:
if isinstance(_operator, dict):
_ops_class, _ = get_cls_kwargs(_operator)
else:
_ops_class = _operator
if not issubclass(_ops_class, ExpressionOps):
raise TypeError("operator must be subclass of ExpressionOps, not {}".format(_ops_class))
if _ops_class.__name__ in self._ops:
get_module_logger(self.__class__.__name__).warning( get_module_logger(self.__class__.__name__).warning(
"The custom operator [{}] will override the qlib default definition".format(operator.__name__) "The custom operator [{}] will override the qlib default definition".format(_ops_class.__name__)
) )
self._ops[operator.__name__] = operator self._ops[_ops_class.__name__] = _ops_class
def __getattr__(self, key): def __getattr__(self, key):
if key not in self._ops: if key not in self._ops: