This repository has been archived on 2026-10-22. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
anatoly c6671410dc research(5m): прогон 14 методов на 250 парах, сверка движка, издержки, графики
ЧТО: code/ (стенд и методы), results/ (сводки), charts/ (3 графика), reports/ (издержки, плацебо, по годам), docs/REJECTED.md.

ПОЧЕМУ: цель — найти кандидатов на 5м или доказать с цифрами их отсутствие.

КАК ПРОВЕРЕНО: движок сверен с прод-движком TON-бота 1:1; плацебо и рандом-контроль в отчёте; бутстрап по дням.
2026-09-29 02:46:08 +03:00

71 lines
3.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Сверка движка 5м-стенда с ПРОДОВЫМ движком TON-бота (обязательный шаг Ф1).
Делает ровно то, что требует цель: берёт 5м-данные, ресемплит в 30м, считает индикаторы
нашим стендом и прогоняет ОДНИ И ТЕ ЖЕ правила двумя движками:
* прод: app.trading.mean_reversion.run_mr_backtest (импорт из /opt/data/work/tonbot_src);
* стенд: tools/mr_engine.stand_mr_backtest (независимая машина состояний).
Расхождение PF больше 5% означает ошибку в машине состояний (не в правилах входа) — тогда
правится движок, а не цифры.
Результат: reports/stand_reconcile.json {pairs: {SYM: {prod_n, stand_n, prod_pf, stand_pf}}}
"""
from __future__ import annotations
import json
import os
import sys
import pandas as pd
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ROOT)
sys.path.insert(0, "/opt/data/work/tonbot_src")
from tools.mr_engine import (MRParamsStand, load_5m, prepare_frame, resample_30m, # noqa: E402
metrics as stand_metrics, stand_mr_backtest)
from app.trading.mean_reversion import MRParams, prepare_mr_frame, run_mr_backtest # noqa: E402
FEE_RT = 0.0011 # 0,055% тейкер × 2 ноги = 0,11% на круг
def main() -> int:
pairs = sys.argv[1:] or ["BTCUSDT", "ETHUSDT", "SOLUSDT", "XRPUSDT", "ZECUSDT"]
out = {}
for sym in pairs:
path = os.path.join(ROOT, "data", "5m", f"{sym}_5m.csv")
if not os.path.isfile(path):
print(f"{sym}: нет файла 5м — пропуск")
continue
df30 = resample_30m(load_5m(path))
frame = prepare_frame(df30)
prod_frame = prepare_mr_frame(frame.copy(), MRParams())
prod = run_mr_backtest(prod_frame, MRParams(), FEE_RT)
prod_m = prod["trades"]
stand = stand_mr_backtest(frame, MRParamsStand(), FEE_RT)
stand_m = stand["metrics"]
out[sym] = {"prod_n": int(prod_m["total_trades"]), "stand_n": int(stand_m["total_trades"]),
"prod_pf": round(float(prod_m["profit_factor"]), 4),
"stand_pf": round(float(stand_m["profit_factor"]), 4),
"prod_sum_pnl": round(float(prod_m.get("total_return", 0.0)), 4),
"stand_sum_pnl": round(float(stand_m["sum_pnl"]), 4),
"bars_30m": int(len(df30))}
print(f"{sym}: 30м баров {len(df30)}, прод n={out[sym]['prod_n']} PF={out[sym]['prod_pf']}, "
f"стенд n={out[sym]['stand_n']} PF={out[sym]['stand_pf']}")
os.makedirs(os.path.join(ROOT, "reports"), exist_ok=True)
with open(os.path.join(ROOT, "reports", "stand_reconcile.json"), "w") as fh:
json.dump({"pairs": out, "fee_rt": FEE_RT, "engine": "app.trading.mean_reversion.run_mr_backtest",
"stand": "tools/mr_engine.stand_mr_backtest", "source": "30м из ресемпла 5м данных"},
fh, ensure_ascii=False, indent=1)
print("записано reports/stand_reconcile.json, пар:", len(out))
return 0
if __name__ == "__main__":
sys.exit(main())