Files
mt-data-mcp/research/config.py
T
gavindiazandClaude Code 1bcfe6e374 feat(research): complete the offline pipeline and add live-identical backtest
research/ now runs end-to-end (fetch -> features/labels -> walk-forward ->
train -> OOS evaluate -> save), and backtest_strategy() replays the same
signal(ctx) strategy over a historical frame with the same manage_position
hook the live loop calls, simulating SL/TP, trailing, partial closes and cost
per bar. --backtest wires it into the CLI.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-25 20:20:49 +08:00

61 lines
2.6 KiB
Python

"""Research pipeline configuration (environment-driven, like trading/)."""
from __future__ import annotations
import os
from dataclasses import dataclass, field
from pathlib import Path
def _env_float(name: str, default: float) -> float:
raw = os.environ.get(name)
return float(raw) if raw else default
def _env_int(name: str, default: int) -> int:
raw = os.environ.get(name)
return int(raw) if raw else default
@dataclass(frozen=True)
class ResearchConfig:
# --- process ------------------------------------------------------------
mtdata_cli: str = os.environ.get("MTDATA_CLI", "mtdata-cli")
cli_timeout_seconds: float = _env_float("RESEARCH_CLI_TIMEOUT", 60.0)
# --- data ---------------------------------------------------------------
data_dir: Path = Path(os.environ.get("RESEARCH_DATA_DIR", "research/data"))
storage_format: str = os.environ.get("RESEARCH_STORAGE_FORMAT", "parquet") # parquet | csv
symbols: tuple[str, ...] = field(
default_factory=lambda: tuple(
filter(None, os.environ.get("RESEARCH_SYMBOLS", "EURUSD,GBPUSD").split(","))
)
)
timeframe: str = os.environ.get("RESEARCH_TIMEFRAME", "H1")
lookback_bars: int = _env_int("RESEARCH_LOOKBACK_BARS", 3000)
indicators: tuple[str, ...] = field(
default_factory=lambda: tuple(
filter(None, os.environ.get("RESEARCH_INDICATORS", "rsi,atr,ema,bbands").split(","))
)
)
# --- labels --------------------------------------------------------------
label_tp_pct: float = _env_float("RESEARCH_LABEL_TP_PCT", 0.4) # 0.4%
label_sl_pct: float = _env_float("RESEARCH_LABEL_SL_PCT", 0.6) # 0.6%
label_horizon: int = _env_int("RESEARCH_LABEL_HORIZON", 12)
# --- walk-forward backtest ------------------------------------------------
wf_n_splits: int = _env_int("RESEARCH_WF_N_SPLITS", 5)
wf_min_train_bars: int = _env_int("RESEARCH_WF_MIN_TRAIN_BARS", 1000)
spread_bps: float = _env_float("RESEARCH_SPREAD_BPS", 1.0)
commission_bps_per_side: float = _env_float("RESEARCH_COMMISSION_BPS", 0.0)
slippage_bps: float = _env_float("RESEARCH_SLIPPAGE_BPS", 1.0)
# --- model ----------------------------------------------------------------
model_dir: Path = Path(os.environ.get("RESEARCH_MODEL_DIR", "research/models"))
model_kind: str = os.environ.get("RESEARCH_MODEL", "logistic") # logistic|rf|gboost|lightgbm
train_ratio: float = _env_float("RESEARCH_TRAIN_RATIO", 0.8) # chronological split
# --- reporting --------------------------------------------------------------
report_dir: Path = Path(os.environ.get("RESEARCH_REPORT_DIR", "research/reports"))