refactor(paper_trading): move multi_swarm_core/paper_trading → strategy_crypto/backend

- git mv executor.py, portfolio.py, persistence.py al backend strategy_crypto
- Cancellato src/multi_swarm_core/multi_swarm_core/paper_trading/
- Patch import: from ..backtest/protocol → from multi_swarm_core.backtest/protocol
- persistence.py:
  * usa schema locale strategy_crypto.backend.schema (no piu' core)
  * docstring aggiornata: DB dedicato state/strategy_crypto.db isolato dal core
  * PaperRepository.init_schema() crea le tabelle paper_trading_*
- backend/__init__.py: re-export pubblico (PaperExecutor, Portfolio, PaperRepository, ...)
- config.py:
  * NEW: ga_db_path (alias DB_PATH legacy + GA_DB_PATH preferito)
  * NEW: strategy_crypto_db_path (STRATEGY_CRYPTO_DB_PATH)
  * db_path conserva come property proxy di ga_db_path per backcompat
- Test: import in venv workspace OK; load_settings() resolve entrambi i path

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-05-15 17:54:31 +00:00
parent 08f1585ab2
commit b02be64831
6 changed files with 58 additions and 8 deletions
@@ -6,7 +6,7 @@ in the project root. Required secrets are validated at instantiation time.
from pathlib import Path from pathlib import Path
from pydantic import Field, SecretStr from pydantic import AliasChoices, Field, SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic_settings import BaseSettings, SettingsConfigDict
@@ -35,7 +35,24 @@ class Settings(BaseSettings):
run_name: str = "phase1-spike-001" run_name: str = "phase1-spike-001"
data_dir: Path = Field(default=Path("./data")) data_dir: Path = Field(default=Path("./data"))
series_dir: Path = Field(default=Path("./series")) series_dir: Path = Field(default=Path("./series"))
db_path: Path = Field(default=Path("./runs.db"))
# GA core DB (tabelle universali: runs, generations, genomes, evaluations, ...)
# Alias DB_PATH legacy mantenuto per backcompat (deprecato, rimuovere nei prossimi cicli).
ga_db_path: Path = Field(
default=Path("./state/runs.db"),
validation_alias=AliasChoices("GA_DB_PATH", "DB_PATH"),
)
# DB per la strategia crypto (tabelle paper_trading_*, isolato dal core)
strategy_crypto_db_path: Path = Field(
default=Path("./state/strategy_crypto.db"),
validation_alias="STRATEGY_CRYPTO_DB_PATH",
)
@property
def db_path(self) -> Path:
"""Backcompat alias: legge ga_db_path. Deprecato — usare ga_db_path."""
return self.ga_db_path
def load_settings() -> Settings: def load_settings() -> Settings:
@@ -0,0 +1,23 @@
"""Backend paper-trading per la strategia crypto.
Espone le classi principali per import ergonomici in scripts/runner:
from strategy_crypto.backend import PaperExecutor, Portfolio, PaperRepository
Per i tipi interni (TickResult, OpenPosition, Trade) importare dal sotto-modulo.
"""
from .executor import PaperExecutor, TickResult
from .persistence import PaperRepository
from .portfolio import OpenPosition, Portfolio
from .schema import PAPER_SCHEMA_SQL, init_schema
__all__ = [
"PAPER_SCHEMA_SQL",
"OpenPosition",
"PaperExecutor",
"PaperRepository",
"Portfolio",
"TickResult",
"init_schema",
]
@@ -20,9 +20,10 @@ from pathlib import Path
import pandas as pd # type: ignore[import-untyped] import pandas as pd # type: ignore[import-untyped]
from ..backtest.orders import Side, Trade from multi_swarm_core.backtest.orders import Side, Trade
from ..protocol.compiler import compile_strategy from multi_swarm_core.protocol.compiler import compile_strategy
from ..protocol.parser import parse_strategy from multi_swarm_core.protocol.parser import parse_strategy
from .portfolio import OpenPosition, Portfolio from .portfolio import OpenPosition, Portfolio
@@ -1,5 +1,9 @@
"""Persistenza paper-trading: usa lo stesso ``runs.db`` con tabelle dedicate """Persistenza paper-trading: scrive su un DB dedicato (state/strategy_crypto.db)
``paper_trading_*`` (vedi :mod:`multi_swarm_core.persistence.schema`). con le tabelle ``paper_trading_*`` definite localmente in :mod:`.schema`.
Il DB e' isolato dal ``runs.db`` del core GA: nessun naming conflict con
future strategie (state/strategy_<asset>.db), nessuna contention di lock
fra writer GA e writer paper.
""" """
from __future__ import annotations from __future__ import annotations
@@ -13,12 +17,17 @@ from typing import Any
from .executor import TickResult from .executor import TickResult
from .portfolio import Portfolio from .portfolio import Portfolio
from .schema import init_schema as _init_paper_schema
class PaperRepository: class PaperRepository:
def __init__(self, db_path: Path | str): def __init__(self, db_path: Path | str):
self.db_path = Path(db_path) self.db_path = Path(db_path)
def init_schema(self) -> None:
"""Crea (se mancanti) le tabelle paper_trading_* su ``self.db_path``."""
_init_paper_schema(self.db_path)
def _conn(self) -> sqlite3.Connection: def _conn(self) -> sqlite3.Connection:
conn = sqlite3.connect(self.db_path, isolation_level=None) conn = sqlite3.connect(self.db_path, isolation_level=None)
conn.row_factory = sqlite3.Row conn.row_factory = sqlite3.Row
@@ -17,7 +17,7 @@ from __future__ import annotations
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime from datetime import datetime
from ..backtest.orders import Side, Trade from multi_swarm_core.backtest.orders import Side, Trade
@dataclass(frozen=True) @dataclass(frozen=True)