mirror of
https://github.com/artemium428/428-backtester.git
synced 2026-09-15 18:36:20 +00:00
Ship SampleStrategy and Integral workflow scripts without proprietary V15 logic, Pine, or run results. Co-authored-by: Cursor <cursoragent@cursor.com>
83 lines
2.4 KiB
Bash
Executable file
83 lines
2.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
# shellcheck disable=SC1091
|
|
source "$(dirname "$0")/_env.sh"
|
|
|
|
# Export best (or N-th) hyperopt epoch into strategy params JSON so backtesting
|
|
# picks them up: user_data/strategies/<Strategy>.json
|
|
STRATEGY="${STRATEGY:-SampleStrategy}"
|
|
EPOCH="${EPOCH:--1}"
|
|
OUT="${OUT:-user_data/strategies/${STRATEGY}.json}"
|
|
|
|
TMP="$(mktemp)"
|
|
trap 'rm -f "$TMP"' EXIT
|
|
|
|
freqtrade hyperopt-show \
|
|
--config user_data/config.json \
|
|
-n "${EPOCH}" \
|
|
--print-json \
|
|
--no-header >"$TMP"
|
|
|
|
PYTHON_BIN="${ROOT}/.venv/bin/python"
|
|
if [[ ! -x "${PYTHON_BIN}" ]]; then
|
|
PYTHON_BIN="$(command -v python3)"
|
|
fi
|
|
|
|
"${PYTHON_BIN}" - "$TMP" "$STRATEGY" "$OUT" <<'PY'
|
|
import json, sys
|
|
from pathlib import Path
|
|
|
|
src, strategy, out = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
raw = Path(src).read_text().strip()
|
|
# hyperopt-show may print log noise; keep the last JSON object
|
|
start = raw.rfind("{")
|
|
if start < 0:
|
|
raise SystemExit(f"No JSON found in hyperopt-show output:\n{raw[:500]}")
|
|
payload = json.loads(raw[start:])
|
|
|
|
KNOWN = ("buy", "sell", "roi", "stoploss", "trailing", "protection")
|
|
|
|
|
|
def expand_tp_combo(sell: dict) -> dict:
|
|
"""If sell has tp_rr_combo 'a,b,c', mirror into tp1_rr/tp2_rr/tp3_rr."""
|
|
combo = sell.get("tp_rr_combo")
|
|
if combo is None:
|
|
return sell
|
|
if isinstance(combo, (list, tuple)) and len(combo) == 3:
|
|
a, b, c = (float(x) for x in combo)
|
|
sell["tp_rr_combo"] = f"{a},{b},{c}"
|
|
elif isinstance(combo, str) and "," in combo:
|
|
a, b, c = (float(x) for x in combo.split(","))
|
|
else:
|
|
return sell
|
|
sell["tp1_rr"] = a
|
|
sell["tp2_rr"] = b
|
|
sell["tp3_rr"] = c
|
|
return sell
|
|
|
|
|
|
def as_params(obj: dict) -> dict:
|
|
if "params" in obj and isinstance(obj["params"], dict):
|
|
raw_params = obj["params"]
|
|
if any(k in raw_params for k in KNOWN):
|
|
params = {k: v for k, v in raw_params.items() if k in KNOWN}
|
|
else:
|
|
params = {"buy": raw_params} if raw_params else {}
|
|
elif any(k in obj for k in KNOWN):
|
|
params = {k: v for k, v in obj.items() if k in KNOWN}
|
|
else:
|
|
params = {"buy": obj} if obj else {}
|
|
if "sell" in params and isinstance(params["sell"], dict):
|
|
params["sell"] = expand_tp_combo(dict(params["sell"]))
|
|
return params
|
|
|
|
|
|
params = as_params(payload)
|
|
doc = {
|
|
"strategy_name": strategy,
|
|
"params": params,
|
|
}
|
|
Path(out).write_text(json.dumps(doc, indent=2) + "\n")
|
|
print(f"Wrote {out}")
|
|
print(json.dumps(params, indent=2))
|
|
PY
|