Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
3e92169
add period ops class
bxdd Mar 9, 2021
fead243
black format
bxdd Mar 9, 2021
61720c2
add pit data read
bxdd Mar 10, 2021
a0959a9
fix bug in period ops
bxdd Mar 10, 2021
bd46d14
update ops runnable
bxdd Mar 10, 2021
9f1cc64
update PIT test example
bxdd Mar 10, 2021
63e4895
black format
bxdd Mar 10, 2021
88b7926
update PIT test
bxdd Mar 10, 2021
a2dae5c
update tets_PIT
bxdd Mar 12, 2021
99db80d
update code format
bxdd Mar 12, 2021
c4bbe6b
add check_feature_exist
bxdd Mar 12, 2021
20bcf25
black format
bxdd Mar 12, 2021
6e23ff7
optimize the PIT Algorithm
bxdd Mar 12, 2021
88a0d3d
fix bug
bxdd Mar 12, 2021
f52462a
update example
bxdd Mar 12, 2021
b794e65
update test_PIT name
bxdd Mar 17, 2021
255ed0b
Merge https://github.com/microsoft/qlib
bxdd Apr 7, 2021
9df1fbd
add pit collector
bxdd Apr 7, 2021
71d5640
black format
bxdd Apr 7, 2021
ebe277b
fix bugs
bxdd Apr 8, 2021
655ff51
fix try
bxdd Apr 8, 2021
f6ca4d2
fix bug & add dump_pit.py
bxdd Apr 9, 2021
566a8f9
Successfully run and understand PIT
you-n-g Mar 4, 2022
63b5ed4
Merge remote-tracking branch 'origin/main' into PIT
you-n-g Mar 4, 2022
4997389
Add some docs and remove a bug
you-n-g Mar 4, 2022
561be64
Merge remote-tracking branch 'origin/main' into PIT
you-n-g Mar 8, 2022
6811a07
Merge remote-tracking branch 'origin/main' into PIT
you-n-g Mar 8, 2022
cf77cd0
mv crypto collector
you-n-g Mar 8, 2022
79422a1
black format
you-n-g Mar 8, 2022
48ea2c5
Run succesfully after merging master
you-n-g Mar 8, 2022
9c67303
Pass test and fix code
you-n-g Mar 10, 2022
69cf2ab
remove useless PIT code
you-n-g Mar 10, 2022
de8d6cb
fix PYlint
you-n-g Mar 10, 2022
2671dc2
Rename
you-n-g Mar 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
add period ops class
  • Loading branch information
bxdd committed Mar 9, 2021
commit 3e92169f859a06b26683be24178c42dfb21efaae
3 changes: 3 additions & 0 deletions qlib/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ def set_conf_from_C(self, config_c):
"region": REG_CN,
## Custom Operator
"custom_ops": [],
"custom_period_ops": [],
},
}

Expand Down Expand Up @@ -297,11 +298,13 @@ def set(self, default_conf="client", **kwargs):
def register(self):
from .utils import init_instance_by_config
from .data.ops import register_all_ops
from .data.ops_period import register_all_period_ops
from .data.data import register_all_wrappers
from .workflow import R, QlibRecorder
from .workflow.utils import experiment_exit_handler

register_all_ops(self)
register_all_period_ops(self)
register_all_wrappers(self)
# set up QlibRecorder
exp_manager = init_instance_by_config(self["exp_manager"])
Expand Down
206 changes: 206 additions & 0 deletions qlib/data/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import pandas as pd



class Expression(abc.ABC):
"""Expression base class"""

Expand Down Expand Up @@ -224,3 +225,208 @@ class ExpressionOps(Expression):
"""

pass


class PExpression(abc.ABC):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MetaClass

"""PExpression base class"""

def __str__(self):
return type(self).__name__

def __repr__(self):
return str(self)

def __gt__(self, other):
from .ops import PGt

return PGt(self, other)

def __ge__(self, other):
from .ops import PGe

return PGe(self, other)

def __lt__(self, other):
from .ops import PLt

return PLt(self, other)

def __le__(self, other):
from .ops import PLe

return PLe(self, other)

def __eq__(self, other):
from .ops import PEq

return PEq(self, other)

def __ne__(self, other):
from .ops import PNe

return PNe(self, other)

def __add__(self, other):
from .ops import PAdd

return PAdd(self, other)

def __radd__(self, other):
from .ops import PAdd

return PAdd(other, self)

def __sub__(self, other):
from .ops import PSub

return PSub(self, other)

def __rsub__(self, other):
from .ops import PSub

return PSub(other, self)

def __mul__(self, other):
from .ops import PMul

return PMul(self, other)

def __rmul__(self, other):
from .ops import PMul

return PMul(self, other)

def __div__(self, other):
from .ops import PDiv

return PDiv(self, other)

def __rdiv__(self, other):
from .ops import PDiv

return PDiv(other, self)

def __truediv__(self, other):
from .ops import PDiv

return PDiv(self, other)

def __rtruediv__(self, other):
from .ops import PDiv

return PDiv(other, self)

def __pow__(self, other):
from .ops import PPower

return PPower(self, other)

def __and__(self, other):
from .ops import PAnd

return PAnd(self, other)

def __rand__(self, other):
from .ops import PAnd

return PAnd(other, self)

def __or__(self, other):
from .ops import POr

return POr(self, other)

def __ror__(self, other):
from .ops import POr

return POr(other, self)


@abc.abstractmethod
def load_period_data(self, instrument, start_offset, end_offset, cur_index):
raise NotImplementedError("This function must be implemented in your newly defined feature")

@abc.abstractmethod
def get_period_offset(self, cur_index):
raise NotImplementedError("This function must be implemented in your newly defined feature")

def load(self, instrument, start_index, end_index, freq):
from .cache import H

# cache
args = str(self), instrument, start_index, end_index, freq
if args in H["f"]:
return H["f"][args]
if start_index is None or end_index is None or start_index > end_index:
raise ValueError("Invalid index range: {} {}".format(start_index, end_index))

resample_series = pd.Series(index=pd.RangeIndex(start_index, end_index + 1), dtype='float32', name=str(self))
for cur_index in range(start_index, end_index + 1):
start_offset, end_offset = self.get_period_offset(cur_index)
resample_data[cur_index] = self.load_period_data(instrument, start_offset, end_offset, cur_index).iloc[-1]

H["f"][args] = resample_series
return resample_data

def get_longest_back_rolling(self):
return 0

def get_extended_window_size(self):
return 0, 0


class PFeature(PExpression):

def __init__(self, name=None):
if name:
self._name = name.lower()
else:
self._name = type(self).__name__.lower()

def __str__(self):
return "$" + self._name

def load_period_data(self, instrument, start_offset, end_offset, cur_index):
### Zhou Code
return pd.Series([1,2,3])

def get_period_offset(self, cur_index):
return 0


class PExpressionOps(PExpression):
"""Operator Expression

This kind of feature will use operator for feature
construction on the fly.
"""

pass

class OpsWrapper:
"""Ops Wrapper"""

def __init__(self):
self._ops = {}

def reset(self):
self._ops = {}

def register(self, ops_list):
for operator in ops_list:
if not issubclass(operator, ExpressionOps) and not issubclass(operator, PExpressionOps):
raise TypeError("operator must be subclass of ExpressionOps or PExpressionOps, not {}".format(operator))

if operator.__name__ in self._ops:
get_module_logger(self.__class__.__name__).warning(
"The custom operator [{}] will override the qlib default definition".format(operator.__name__)
)
self._ops[operator.__name__] = operator

def __getattr__(self, key):
if key not in self._ops:
raise AttributeError("The operator [{0}] is not registered".format(key))
return self._ops[key]


Operators = OpsWrapper()
4 changes: 1 addition & 3 deletions qlib/data/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@
)

from ..log import get_module_logger
from .base import Feature

from .ops import Operators
from .base import Feature, PFeature, Operators


class QlibCacheException(RuntimeError):
Expand Down
4 changes: 1 addition & 3 deletions qlib/data/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@

from .cache import H
from ..config import C
from .ops import Operators
from ..log import get_module_logger
from ..utils import parse_field, read_bin, hash_args, normalize_cache_fields, code_to_fname
from .base import Feature
from .base import Feature, PFeature, Operators
from .cache import DiskDatasetCache, DiskExpressionCache
from ..utils import Wrapper, init_instance_by_config, register_wrapper, get_module_by_module_path

Expand Down Expand Up @@ -480,7 +479,6 @@ def expression_calculator(inst, start_time, end_time, freq, column_names, spans=
_calendar = Cal.calendar(freq=freq)
data.index = _calendar[data.index.values.astype(int)]
data.index.names = ["datetime"]

if spans is None:
return data
else:
Expand Down
34 changes: 2 additions & 32 deletions qlib/data/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ class NpElemOperator(ElemOperator):
"""

def __init__(self, feature, func):
self.feature = feature
self.func = func
super(NpElemOperator, self).__init__(feature)

Expand Down Expand Up @@ -289,8 +288,6 @@ class NpPairOperator(PairOperator):
"""

def __init__(self, feature_left, feature_right, func):
self.feature_left = feature_left
self.feature_right = feature_right
self.func = func
super(NpPairOperator, self).__init__(feature_left, feature_right)

Expand Down Expand Up @@ -1489,39 +1486,12 @@ def __init__(self, feature_left, feature_right, N):
]


class OpsWrapper:
"""Ops Wrapper"""

def __init__(self):
self._ops = {}

def reset(self):
self._ops = {}

def register(self, ops_list):
for operator in ops_list:
if not issubclass(operator, ExpressionOps):
raise TypeError("operator must be subclass of ExpressionOps, not {}".format(operator))

if operator.__name__ in self._ops:
get_module_logger(self.__class__.__name__).warning(
"The custom operator [{}] will override the qlib default definition".format(operator.__name__)
)
self._ops[operator.__name__] = operator

def __getattr__(self, key):
if key not in self._ops:
raise AttributeError("The operator [{0}] is not registered".format(key))
return self._ops[key]


Operators = OpsWrapper()


def register_all_ops(C):
"""register all operator"""
logger = get_module_logger("ops")

from .base import Operators

Operators.reset()
Operators.register(OpsList)

Expand Down
Loading