feat(research): comando CLI research-trigger + flag force

- option_chain_research_cycle: parametro force=True bypassa il gate
  enabled, per testare la raccolta prima di accendere il cron.
- CLI `option-chain research-trigger`: esegue UNA volta il collector
  full-chain (source='research', book_depth popolato), come il gemello
  `trigger` per il collettore live.

Verificato: 324 quote ETH su 7 scadenze (DTE 1..80), book_depth su tutte.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-09 08:40:11 +00:00
parent 8a1fb823dc
commit 097e764f6a
2 changed files with 70 additions and 2 deletions
+64
View File
@@ -1204,6 +1204,70 @@ def option_chain_trigger(
)
@option_chain.command(name="research-trigger")
@click.option(
"--strategy",
"strategy_path",
type=click.Path(exists=True, dir_okay=False, path_type=Path),
default=_DEFAULT_STRATEGY_PATH,
show_default=True,
)
@click.option(
"--db",
"db_path",
type=click.Path(dir_okay=False, path_type=Path),
default=_DEFAULT_DB_PATH,
show_default=True,
)
@click.option(
"--audit",
"audit_path",
type=click.Path(dir_okay=False, path_type=Path),
default=_DEFAULT_AUDIT_PATH,
show_default=True,
)
@click.option(
"--token",
type=str,
default=None,
help="MCP bearer token (override su CERBERO_BITE_MCP_TOKEN).",
)
@click.option("--asset", default="ETH", show_default=True)
def option_chain_research_trigger(
strategy_path: Path,
db_path: Path,
audit_path: Path,
token: str | None,
asset: str,
) -> None:
"""Esegue UNA volta il collector research full-chain (source='research').
Cattura tutte le scadenze ed entrambe le ali con book_depth_top3
popolato. ``force=True``: gira anche se ``research_collector.enabled``
è false, utile per testare prima di accendere il cron orario.
"""
from cerbero_bite.runtime.dependencies import build_runtime # noqa: PLC0415
from cerbero_bite.runtime.option_chain_research_cycle import ( # noqa: PLC0415
collect_option_chain_research,
)
cfg = load_strategy(strategy_path).config
ctx = build_runtime(
cfg=cfg,
endpoints=load_endpoints(),
token=load_token(value=token),
db_path=db_path,
audit_path=audit_path,
bot_tag=load_bot_tag(),
)
n = asyncio.run(collect_option_chain_research(ctx, asset=asset, force=True))
console.print(
f"[green]Persisted {n} research quote(s) for {asset}[/green]"
if n > 0
else "[yellow]No quotes persisted (chain empty or fetch failed)[/yellow]"
)
@option_chain.command(name="analyze")
@click.option(
"--strategy",
@@ -70,12 +70,16 @@ async def collect_option_chain_research(
asset: str = "ETH",
now: datetime | None = None,
batch_size: int = DEFAULT_BATCH_SIZE,
force: bool = False,
) -> int:
"""Collect + persist un singolo snapshot full-chain ``research`` per
``asset``. Ritorna il numero di quote persistiti (0 su fallimento
best-effort o se il collettore è disabilitato)."""
best-effort o se il collettore è disabilitato).
``force=True`` bypassa il gate ``enabled`` (usato dal trigger CLI per
testare la raccolta prima di accendere il cron schedulato)."""
rc = getattr(ctx.cfg, "research_collector", None)
if rc is None or not rc.enabled:
if rc is None or (not rc.enabled and not force):
return 0
when = (now or datetime.now(UTC)).astimezone(UTC)