Add single-command GTL tuning matrix

This commit is contained in:
2026-07-13 13:13:18 +02:00
parent 0873176f64
commit 3999c5efc1
12 changed files with 1032 additions and 17 deletions
+24 -7
View File
@@ -93,6 +93,7 @@ def _zone_representative_levels(
entry_price: float,
*,
strength_mode: str = "sum",
tolerance: float = _SR_ZONE_TOLERANCE,
) -> list[Any]:
"""Collapse near-duplicate S/R levels into one representative per zone.
@@ -124,7 +125,7 @@ def _zone_representative_levels(
zones = cluster_sr_zones(
level_dicts,
entry_price,
tolerance=_SR_ZONE_TOLERANCE,
tolerance=tolerance,
strength_mode=strength_mode,
)
@@ -315,9 +316,16 @@ class TargetGenerator:
stop_loss: float,
sr_levels: list[SRLevel],
atr_value: float,
*,
max_targets: int | None = 5,
max_atr_multiple_override: float | None = None,
) -> list[dict[str, Any]]:
if atr_value <= 0:
return []
if max_targets is not None and max_targets < 1:
raise ValueError("max_targets must be positive or None")
if max_atr_multiple_override is not None and max_atr_multiple_override <= 0:
raise ValueError("max_atr_multiple_override must be positive or None")
risk = abs(entry_price - stop_loss)
if risk <= 0:
@@ -326,11 +334,12 @@ class TargetGenerator:
candidates: list[dict[str, Any]] = []
atr_pct = atr_value / entry_price if entry_price > 0 else 0.0
max_atr_multiple: float | None = None
if atr_pct > 0.05:
max_atr_multiple = 10.0
elif atr_pct < 0.02:
max_atr_multiple = 3.0
max_atr_multiple: float | None = max_atr_multiple_override
if max_atr_multiple is None:
if atr_pct > 0.05:
max_atr_multiple = 10.0
elif atr_pct < 0.02:
max_atr_multiple = 3.0
for level in sr_levels:
is_candidate = False
@@ -383,6 +392,12 @@ class TargetGenerator:
if not candidates:
return []
if max_targets is None:
candidates.sort(key=lambda row: row["distance_from_entry"])
for target in candidates:
target.pop("quality", None)
return candidates
# Select up to 5 targets that SPAN the distance range, instead of the
# top-5 by quality (which biases toward far, high-R:R levels and buries
# every nearby target). Guarantees the nearest level plus a
@@ -396,6 +411,8 @@ class TargetGenerator:
selected_ids: set[int] = set()
def _add(candidate: dict[str, Any] | None) -> None:
if len(selected) >= max_targets:
return
if candidate is not None and candidate["sr_level_id"] not in selected_ids:
selected.append(candidate)
selected_ids.add(candidate["sr_level_id"])
@@ -408,7 +425,7 @@ class TargetGenerator:
_add(max(bucket, key=lambda c: c["quality"]))
# Fill remaining slots with the next-best by quality
for candidate in sorted(candidates, key=lambda c: c["quality"], reverse=True):
if len(selected) >= 5:
if len(selected) >= max_targets:
break
_add(candidate)