It was never in the enabled timeframes, so it held zero bars and produced no levels, but it still carried weight 8 in the scoring table and forced bucket_start to special-case a wall-clock ET anchor whose entire purpose was surviving DST transitions. That was the most intricate logic in session.py, maintained for a timeframe nobody used. Daily is now the only session-anchored bucket, which is a much easier rule to state and to keep correct. The DST parametrised tests go with it; the Sunday open and daily boundary cases remain. Manual-line tests move to 1h, so the weight assertions drop from 8 to 4. The plan document keeps its 4h examples — rewriting a dozen illustrative sentences would churn more than it clarifies — but the timeframe-roles section now records the removal so nothing reads as a spec to build. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
61 lines
1.3 KiB
Python
61 lines
1.3 KiB
Python
from dataclasses import asdict, dataclass
|
|
from enum import Enum
|
|
from typing import Any
|
|
|
|
|
|
class Timeframe(str, Enum):
|
|
M1 = "1m"
|
|
M2 = "2m"
|
|
M5 = "5m"
|
|
M15 = "15m"
|
|
M30 = "30m"
|
|
H1 = "1h"
|
|
D1 = "1d"
|
|
|
|
@property
|
|
def seconds(self) -> int:
|
|
seconds = {
|
|
self.M1: 60,
|
|
self.M2: 120,
|
|
self.M5: 300,
|
|
self.M15: 900,
|
|
self.M30: 1800,
|
|
self.H1: 3600,
|
|
}
|
|
if self is self.D1:
|
|
raise ValueError("1d is session-defined, not a fixed number of seconds")
|
|
return seconds[self]
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class Bar:
|
|
tf: Timeframe
|
|
t: int
|
|
o: float
|
|
h: float
|
|
l: float
|
|
c: float
|
|
v: int
|
|
closed: bool
|
|
symbol: str
|
|
source: str
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
value = asdict(self)
|
|
value["tf"] = self.tf.value
|
|
return value
|
|
|
|
@classmethod
|
|
def from_dict(cls, value: dict[str, Any]) -> "Bar":
|
|
return cls(
|
|
tf=Timeframe(value["tf"]),
|
|
t=int(value["t"]),
|
|
o=float(value["o"]),
|
|
h=float(value["h"]),
|
|
l=float(value["l"]),
|
|
c=float(value["c"]),
|
|
v=int(value.get("v") or 0),
|
|
closed=bool(value["closed"]),
|
|
symbol=str(value["symbol"]),
|
|
source=str(value["source"]),
|
|
)
|