feat(protocol): dispatcher temporal features (hour) in compiler
This commit is contained in:
@@ -107,6 +107,13 @@ INDICATOR_FNS: dict[str, Any] = {
|
|||||||
"macd": _ind_macd,
|
"macd": _ind_macd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_TIME_FEATURE_FNS: dict[str, Callable[[pd.DatetimeIndex], pd.Series]] = {
|
||||||
|
"hour": lambda idx: pd.Series(idx.hour, index=idx, dtype="int64"),
|
||||||
|
"dow": lambda idx: pd.Series(idx.dayofweek, index=idx, dtype="int64"),
|
||||||
|
"is_weekend": lambda idx: pd.Series((idx.dayofweek >= 5).astype("int64"), index=idx),
|
||||||
|
"minute_of_hour": lambda idx: pd.Series(idx.minute, index=idx, dtype="int64"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _to_series(value: float, df: pd.DataFrame) -> pd.Series:
|
def _to_series(value: float, df: pd.DataFrame) -> pd.Series:
|
||||||
"""Broadcast a numeric literal across the DataFrame index."""
|
"""Broadcast a numeric literal across the DataFrame index."""
|
||||||
@@ -134,6 +141,8 @@ def _eval_bool_arg(node: Node, df: pd.DataFrame) -> pd.Series:
|
|||||||
|
|
||||||
def _eval_node(node: Node, df: pd.DataFrame) -> pd.Series:
|
def _eval_node(node: Node, df: pd.DataFrame) -> pd.Series:
|
||||||
if isinstance(node, FeatureNode):
|
if isinstance(node, FeatureNode):
|
||||||
|
if node.name in _TIME_FEATURE_FNS:
|
||||||
|
return _TIME_FEATURE_FNS[node.name](df.index)
|
||||||
return df[node.name]
|
return df[node.name]
|
||||||
|
|
||||||
if isinstance(node, IndicatorNode):
|
if isinstance(node, IndicatorNode):
|
||||||
|
|||||||
@@ -106,3 +106,27 @@ def test_compile_two_rules_priority(ohlcv: pd.DataFrame) -> None:
|
|||||||
signals = fn(ohlcv)
|
signals = fn(ohlcv)
|
||||||
last = signals.iloc[-1]
|
last = signals.iloc[-1]
|
||||||
assert last == Side.LONG # close finale e' 120, regola 1 matcha
|
assert last == Side.LONG # close finale e' 120, regola 1 matcha
|
||||||
|
|
||||||
|
|
||||||
|
def test_compile_hour_feature_returns_index_hour(ohlcv: pd.DataFrame) -> None:
|
||||||
|
src = json.dumps(
|
||||||
|
{
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"condition": {
|
||||||
|
"op": "gt",
|
||||||
|
"args": [
|
||||||
|
{"kind": "feature", "name": "hour"},
|
||||||
|
{"kind": "literal", "value": -1.0},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"action": "entry-long",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ast = parse_strategy(src)
|
||||||
|
fn = compile_strategy(ast)
|
||||||
|
signal = fn(ohlcv)
|
||||||
|
# All rows have hour >= 0 > -1, so all entry-long.
|
||||||
|
assert (signal == Side.LONG).all()
|
||||||
|
|||||||
Reference in New Issue
Block a user