Repository Public
1"""Describe a strategy version without running it: `python -m spq.describe --strategy <dir>` prints2{"sha256": "<hex of strategy.py>", "meta": {...}} after the same loading checks as the signal runner3(META validation, static purity check). Non-zero exit and a reason on stderr on any problem.45Contract versions. Without `--contract` (= 1) the output is exactly the one above and a perpetual-futures strategy6(META["kind"] = "perp", contract 2: signed, leveraged weights) is REFUSED with exit 4: a caller that only knows the7spot contract must not be offered a strategy whose weights it would misread. With `--contract 2` every strategy is8described and the output gains "contract" (1 or 2) and "kind" ("spot" or "perp").910A universe-generic strategy reports "universe": ["*"] in meta (with "min_symbols" / "max_symbols" when it sets them),11"generic": true, and the bounds in force as "min_symbols" / "max_symbols" at the top level; the output always has "generic"."""12from __future__ import annotations1314import argparse15import json16import sys1718from .strategy import StrategyError, load_strategy, sha256_file, symbol_bounds192021def main(argv=None) -> int:22 p = argparse.ArgumentParser(prog="python -m spq.describe")23 p.add_argument("--strategy", required=True)24 p.add_argument("--contract", type=int, choices=(1, 2), default=1,25 help="highest strategy contract the caller understands (2 = perpetual futures)")26 a = p.parse_args(argv)27 try:28 s = load_strategy(a.strategy)29 if s.kind == "perp" and a.contract < 2:30 raise StrategyError("perpetual-futures strategy (contract 2): not available to a contract-1 caller; "31 "pass --contract 2 if signed, leveraged weights are understood")32 out = {"sha256": sha256_file(f"{a.strategy}/strategy.py"), "meta": s.meta, "generic": s.generic}33 if s.generic:34 out["min_symbols"], out["max_symbols"] = symbol_bounds(s.meta)35 if a.contract >= 2:36 out.update({"contract": 2 if s.kind == "perp" else 1, "kind": s.kind})37 except BaseException as e: # noqa: BLE00138 print(f"spq.describe: {type(e).__name__}: {e}", file=sys.stderr)39 return 440 print(json.dumps(out))41 return 0424344if __name__ == "__main__":45 sys.exit(main())46