mirror of
https://github.com/PyP-Quant/quant-trading-strategy-templates.git
synced 2026-08-17 20:48:06 +00:00
46 lines
2.1 KiB
Python
46 lines
2.1 KiB
Python
import numpy as np
|
|
import pandas as pd
|
|
from sklearn.ensemble import RandomForestClassifier
|
|
|
|
|
|
def _dataset(data, horizon=4, threshold=0.0012):
|
|
df = data.copy()
|
|
df.columns = [str(c).lower() for c in df.columns]
|
|
if "volume" not in df.columns:
|
|
df["volume"] = 1
|
|
for col in ["open", "high", "low", "close", "volume"]:
|
|
df[col] = pd.to_numeric(df[col], errors="coerce")
|
|
c = df["close"]
|
|
x = pd.DataFrame(index=df.index)
|
|
x["range_break"] = (c - df["high"].rolling(24).max().shift()) / c
|
|
x["range_floor"] = (c - df["low"].rolling(24).min().shift()) / c
|
|
x["ret4"] = c.pct_change(4)
|
|
x["ret12"] = c.pct_change(12)
|
|
x["vol"] = c.pct_change().rolling(20).std()
|
|
x = x.replace([np.inf, -np.inf], np.nan).dropna()
|
|
fwd = c.pct_change(horizon).shift(-horizon)
|
|
y = pd.Series(1, index=df.index)
|
|
y[fwd > threshold] = 2
|
|
y[fwd < -threshold] = 0
|
|
return x, y.reindex(x.index).fillna(1).astype(int)
|
|
|
|
|
|
def train(data, config):
|
|
p = config.get("parameters", {})
|
|
x, y = _dataset(data, int(p.get("horizon", 4)), float(p.get("threshold", 0.0012)))
|
|
clf = RandomForestClassifier(n_estimators=300, max_depth=7, class_weight="balanced_subsample", random_state=42)
|
|
clf.fit(x.values, y.values)
|
|
return {"model": clf, "features": list(x.columns)}, {"training_bars": int(len(x)), "feature_count": int(x.shape[1])}
|
|
|
|
|
|
def predict(model, market_data, config):
|
|
candles = market_data.get("candles", [])
|
|
if len(candles) < int(config.get("parameters", {}).get("lookback", 120)):
|
|
return {"signal": "HOLD", "confidence": 0, "metadata": {"reason": "not_enough_candles"}}
|
|
x, _ = _dataset(pd.DataFrame(candles, columns=["open", "high", "low", "close", "volume"]))
|
|
row = x.tail(1)[model["features"]]
|
|
prob = model["model"].predict_proba(row.values)[0]
|
|
k = int(np.argmax(prob))
|
|
conf = float(np.max(prob))
|
|
return {"signal": {0: "DOWN", 1: "HOLD", 2: "UP"}[k] if conf >= float(config.get("parameters", {}).get("min_confidence", 0.5)) else "HOLD", "confidence": round(conf, 4), "metadata": {"proba": [round(float(v), 4) for v in prob]}}
|