feat: signal abstraction layer + sizer + HS300 universe + PnL/IC reports
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
"""Map signal values to discrete position actions."""
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class PositionAction:
|
||||
"""A target action for a single stock on a single bar."""
|
||||
|
||||
action: str # "buy", "sell", or "hold"
|
||||
size_pct: float = 0.0 # target portfolio fraction for buys
|
||||
|
||||
|
||||
class ThresholdBuilder:
|
||||
"""Open on strong positive signal, close on strong negative signal."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
buy_threshold: float = 0.02,
|
||||
sell_threshold: float = -0.02,
|
||||
size_pct: float = 0.95,
|
||||
):
|
||||
self.buy_threshold = buy_threshold
|
||||
self.sell_threshold = sell_threshold
|
||||
self.size_pct = size_pct
|
||||
|
||||
def build(self, signal_value: float, in_position: bool) -> PositionAction:
|
||||
"""Decide what to do given the current signal and position state.
|
||||
|
||||
Args:
|
||||
signal_value: Latest signal value for the stock.
|
||||
in_position: Whether the portfolio currently holds the stock.
|
||||
|
||||
Returns:
|
||||
The action to take ("buy", "sell", or "hold").
|
||||
"""
|
||||
if not in_position and signal_value >= self.buy_threshold:
|
||||
return PositionAction("buy", self.size_pct)
|
||||
if in_position and signal_value <= self.sell_threshold:
|
||||
return PositionAction("sell", 0.0)
|
||||
return PositionAction("hold", 0.0)
|
||||
Reference in New Issue
Block a user