回测基本一致
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
"""Declared search space — every tunable parameter in one place (doc 05 §2).
|
||||
|
||||
A search space is a mapping ``name -> (low, high, step)`` plus a set of
|
||||
integer parameter names. The optimizer turns each entry into an Optuna
|
||||
``suggest_float`` / ``suggest_int``. Nothing tunable should be hidden in the
|
||||
strategy body.
|
||||
|
||||
Rules (doc 05 §2):
|
||||
|
||||
- Ranges encode priors, not hope — bracket where the answer plausibly is.
|
||||
- Step matters — too fine explodes the space, too coarse misses optima.
|
||||
- What is NOT in the space is a decision — list exclusions explicitly.
|
||||
- Timeframe is usually fixed per iteration (searching timeframes overfits).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TypedDict
|
||||
|
||||
|
||||
class Range(TypedDict):
|
||||
"""One parameter range: ``low`` to ``high`` in steps of ``step``."""
|
||||
|
||||
low: float
|
||||
high: float
|
||||
step: float
|
||||
|
||||
|
||||
# name -> (low, high, step)
|
||||
SearchSpace = dict[str, tuple[float, float, float]]
|
||||
|
||||
|
||||
def suggest_params(
|
||||
trial,
|
||||
space: SearchSpace,
|
||||
int_params: set[str] | None = None,
|
||||
) -> dict[str, float | int]:
|
||||
"""Sample every parameter in ``space`` from an Optuna trial.
|
||||
|
||||
Integer params (listed in ``int_params``) use ``suggest_int``; floats use
|
||||
``suggest_float`` with ``step``. Returns a plain ``dict`` of sampled
|
||||
values keyed by parameter name.
|
||||
"""
|
||||
int_params = int_params or set()
|
||||
sampled: dict[str, float | int] = {}
|
||||
for name, (low, high, step) in space.items():
|
||||
if name in int_params:
|
||||
lo = int(round(low))
|
||||
hi = int(round(high))
|
||||
st = max(int(round(step)), 1)
|
||||
sampled[name] = trial.suggest_int(name, lo, hi, step=st)
|
||||
else:
|
||||
sampled[name] = trial.suggest_float(name, low, high, step=step)
|
||||
return sampled
|
||||
|
||||
|
||||
def validate_space(space: SearchSpace, int_params: set[str] | None = None) -> list[str]:
|
||||
"""Return a list of problems with the space (empty = OK).
|
||||
|
||||
Catches: reversed ranges, zero/negative steps, int params with non-integer
|
||||
bounds, duplicate names. Run this once before launching a study so a
|
||||
malformed space doesn't waste a background run.
|
||||
"""
|
||||
int_params = int_params or set()
|
||||
problems: list[str] = []
|
||||
for name, (low, high, step) in space.items():
|
||||
if high < low:
|
||||
problems.append(f"{name}: high < low ({low} > {high})")
|
||||
if step <= 0:
|
||||
problems.append(f"{name}: step <= 0 ({step})")
|
||||
if name in int_params:
|
||||
if int(low) != low or int(high) != high:
|
||||
problems.append(f"{name}: int param with non-integer bound ({low}, {high})")
|
||||
return problems
|
||||
Reference in New Issue
Block a user