Browse AI-generated trading strategies shared by the community. Fork, learn, and build on each other's work.
| Score▼ | Strategy | Author | Win Rate▼ | Return▼ | PF▼ | MDD▼ | Trades▼ | Actions | ||
|---|---|---|---|---|---|---|---|---|---|---|
|
🥇
|
USD/JPY BB Squeeze Breakout (GBM)
Maximize risk-adjusted return (Sharpe). GradientBoostingClassifier chosen for strong performance on tabular financial data with moderate fea…
|
V
@vol_drifter
|
USDJPY | 15min | 60.7%66.7% | +1.15%+67.50% | 1.062.98 | 3.13%3.13% | 20154 |
|
# ╔══════════════════════════════════════════════════════════════╗
# ║ STRATEGY REQUEST LOG ║
# ╚══════════════════════════════════════════════════════════════╝
# Generated : 2026-05-06 02:57:20
# Model : Gradient Boosting
# Feature Eng. : BB (20,2.0), ATR 14 + Auto-add features: ON
# Signal / Entry : Enter when model confidence > threshold; exit on opposite signal or SL/TP
# Optimization : Maximize risk-adjusted return
# Risk Mgmt : Stop loss 0.5%, Take profit 1.0%
# Risk Filter : —
# ══════════════════════════════════════════════════════════════
# ============================================================
# Bollinger Bands Squeeze Breakout Strategy — USD/JPY 15-min
# ============================================================
# SECTION 0 — IMPORTS & CONSTANTS
import numpy as np
import pandas as pd
DATA_PATH = "/root/Desktop/QuantifyMe/data/ohlc/USDJPY_15min.parquet"
START_DATE = "2025-04-24"
END_DATE = "2026-04-24"
VALIDATION_DATE = ""
TRAIN_SPLIT = 0.7
# SECTION 1 — FEATURE ENGINEERING
def feature_engineering(df, close, open_, high, low):
# ── Bollinger Bands (20, 2) ──────────────────────────────────────────────
bb_period = 20
bb_std = 2.0
bb_mid = close.rolling(bb_period).mean()
bb_sigma = close.rolling(bb_period).std(ddof=0)
bb_upper = bb_mid + bb_std * bb_sigma
bb_lower = bb_mid - bb_std * bb_sigma
df["bb_mid"] = bb_mid
df["bb_upper"] = bb_upper
df["bb_lower"] = bb_lower
# Band width and %B — required features
df["bb_width"] = (bb_upper - bb_lower) / bb_mid
df["bb_pct"] = (close - bb_lower) / (bb_upper - bb_lower)
# ── ATR 14 & NATR ────────────────────────────────────────────────────────
atr_period = 14
prev_close = close.shift(1)
tr = pd.concat([
high - low,
(high - prev_close).abs(),
(low - prev_close).abs()
], axis=1).max(axis=1)
atr = tr.ewm(span=atr_period, min_periods=atr_period, adjust=False).mean()
natr = atr / close
df["atr"] = atr
df["natr"] = natr
# ── Squeeze detection ────────────────────────────────────────────────────
# Keltner Channel (EMA20 ± 1.5 × ATR) for squeeze comparison
kc_mid = close.ewm(span=20, adjust=False).mean()
kc_upper = kc_mid + 1.5 * atr
kc_lower = kc_mid - 1.5 * atr
df["squeeze"] = np.where(
(bb_upper < kc_upper) & (bb_lower > kc_lower), 1.0, 0.0
)
# Rolling squeeze count (bars in squeeze over last 10 bars)
df["squeeze_count"] = (
df["squeeze"].rolling(10).sum()
)
# Band-width z-score (how compressed is the width vs recent history)
bw_mean = df["bb_width"].rolling(50).mean()
bw_std = df["bb_width"].rolling(50).std(ddof=0)
df["bb_width_zscore"] = (df["bb_width"] - bw_mean) / (bw_std + 1e-10)
# ── Breakout momentum ────────────────────────────────────────────────────
# Price distance from bands, normalised by ATR
df["dist_upper"] = (close - bb_upper) / (atr + 1e-10)
df["dist_lower"] = (close - bb_lower) / (atr + 1e-10)
df["dist_mid"] = (close - bb_mid) / (atr + 1e-10)
# ── Rate of change ────────────────────────────────────────────────────────
for n in [1, 4, 8, 16]:
df[f"roc_{n}"] = close.pct_change(n)
# ── RSI 14 ───────────────────────────────────────────────────────────────
delta = close.diff()
gain = delta.clip(lower=0)
loss = (-delta).clip(lower=0)
avg_g = gain.ewm(span=14, min_periods=14, adjust=False).mean()
avg_l = loss.ewm(span=14, min_periods=14, adjust=False).mean()
rs = avg_g / (avg_l + 1e-10)
df["rsi_14"] = 100.0 - 100.0 / (1.0 + rs)
# RSI normalised to [-1, 1]
df["rsi_norm"] = (df["rsi_14"] - 50.0) / 50.0
# ── Momentum / trend context ──────────────────────────────────────────────
ema_9 = close.ewm(span=9, adjust=False).mean()
ema_21 = close.ewm(span=21, adjust=False).mean()
ema_50 = close.ewm(span=50, adjust=False).mean()
df["ema_9_21_diff"] = (ema_9 - ema_21) / (atr + 1e-10)
df["ema_21_50_diff"] = (ema_21 - ema_50) / (atr + 1e-10)
# Price position relative to EMAs
df["close_vs_ema9"] = (close - ema_9) / (atr + 1e-10)
df["close_vs_ema50"] = (close - ema_50) / (atr + 1e-10)
# ── Volume-proxy: ATR velocity ────────────────────────────────────────────
df["atr_roc"] = atr.pct_change(4)
# ── MACD-style oscillator ─────────────────────────────────────────────────
macd_line = close.ewm(span=12, adjust=False).mean() - close.ewm(span=26, adjust=False).mean()
macd_signal = macd_line.ewm(span=9, adjust=False).mean()
df["macd_hist"] = (macd_line - macd_signal) / (atr + 1e-10)
# ── Stochastic %K (14) ────────────────────────────────────────────────────
low_14 = low.rolling(14).min()
high_14 = high.rolling(14).max()
df["stoch_k"] = (close - low_14) / (high_14 - low_14 + 1e-10)
# ── Candle body / wick features ───────────────────────────────────────────
body = (close - open_).abs()
candle_range = (high - low).replace(0, np.nan)
df["body_ratio"] = body / candle_range
df["upper_wick"] = (high - pd.concat([close, open_], axis=1).max(axis=1)) / (candle_range + 1e-10)
df["lower_wick"] = (pd.concat([close, open_], axis=1).min(axis=1) - low) / (candle_range + 1e-10)
df["bull_candle"] = np.where(close > open_, 1.0, 0.0)
# ── Lagged bb_pct and bb_width ────────────────────────────────────────────
for lag in [1, 2, 4]:
df[f"bb_pct_lag{lag}"] = df["bb_pct"].shift(lag)
df[f"bb_width_lag{lag}"] = df["bb_width"].shift(lag)
# ── Band width momentum (is it expanding?) ────────────────────────────────
df["bb_width_chg1"] = df["bb_width"].diff(1)
df["bb_width_chg4"] = df["bb_width"].diff(4)
# ── Hour / session features ───────────────────────────────────────────────
df["hour_sin"] = np.sin(2 * np.pi * df.index.hour / 24)
df["hour_cos"] = np.cos(2 * np.pi * df.index.hour / 24)
df["dow_sin"] = np.sin(2 * np.pi * df.index.dayofweek / 5)
df["dow_cos"] = np.cos(2 * np.pi * df.index.dayofweek / 5)
# ── Fill NaN from warm-up ─────────────────────────────────────────────────
df = df.bfill().ffill()
return df
# SECTION 2 — STRATEGY CONFIG
def strategy_config():
return {
"title": "USD/JPY BB Squeeze Breakout (GBM)",
"model_type": "GradientBoostingClassifier",
"model_params": {
"n_estimators": 400,
"max_depth": 4,
"learning_rate": 0.04,
"subsample": 0.75,
"min_samples_leaf": 20,
"max_features": "sqrt",
"validation_fraction": 0.1,
"n_iter_no_change": 30,
"tol": 1e-4,
"random_state": 42,
},
"signal_threshold": 0.55,
"direction": "both",
"stop_loss": 0.005,
"take_profit": 0.010,
"cooldown": 0,
"max_positions": 1,
"on_opposite": "reverse",
"session_filter": [6, 20],
"min_atr": 0.0003,
"trend_filter": None,
"target_horizon": 4,
"objective": (
"Maximize risk-adjusted return (Sharpe). "
"GradientBoostingClassifier chosen for strong performance on tabular "
"financial data with moderate feature counts. Deeper ensemble (400 "
"estimators, depth 4) with early stopping captures non-linear BB "
"squeeze patterns. Subsample=0.75 and sqrt features reduce overfitting. "
"SL 0.5% / TP 1.0% gives 1:2 R:R ratio. Session filter 06-20 UTC covers "
"London + NY sessions where USD/JPY liquidity is highest."
),
"notes": (
"Core signal: BB squeeze (narrow band width inside Keltner Channel) "
"followed by band expansion. Features include band width z-score, "
"breakout direction (dist_upper/lower), RSI, MACD histogram, "
"stochastic %K, EMA spreads, candle structure, and lagged BB features. "
"NATR used as min_atr filter to avoid low-volatility noise trades. "
"Horizon=4 bars (1 hour on 15-min data) aligns with typical "
"post-squeeze expansion duration."
),
}
|
||||||||||
|
🥈
|
USD/JPY BB Mean-Reversion + ATR Gradient Boost
Maximise Sharpe ratio via a Gradient Boosting classifier trained on Bollinger Band position (bb_pct), normalised bandwidth (bb_width), ATR/N…
|
R
@ratio_witch
|
USDJPY | 15min | 60.2%60.8% | +4.28%+28.20% | 1.231.59 | 2.32%2.32% | 16651 |
|
# ╔══════════════════════════════════════════════════════════════╗
# ║ STRATEGY REQUEST LOG ║
# ╚══════════════════════════════════════════════════════════════╝
# Generated : 2026-05-06 02:01:39
# Model : Gradient Boosting
# Feature Eng. : BB (20,2.0), ATR 14 + Auto-add features: ON
# Signal / Entry : Enter when model confidence > threshold; exit on opposite signal or SL/TP
# Optimization : Maximize risk-adjusted return
# Risk Mgmt : Stop loss 0.5%, Take profit 1.0%
# Risk Filter : —
# ══════════════════════════════════════════════════════════════
# ============================================================
# SECTION 0 — IMPORTS & CONSTANTS
import numpy as np
import pandas as pd
DATA_PATH = "/root/Desktop/QuantifyMe/data/ohlc/USDJPY_15min.parquet"
START_DATE = "2025-04-24"
END_DATE = "2026-04-24"
VALIDATION_DATE = ""
TRAIN_SPLIT = 0.7
# SECTION 1 — FEATURE ENGINEERING
def feature_engineering(df, close, open_, high, low):
# ── Bollinger Bands (period=20, std_dev=2.0) ──────────────────────────────
bb_period = 20
bb_std = 2.0
bb_mid = close.rolling(bb_period).mean()
bb_sigma = close.rolling(bb_period).std(ddof=0)
bb_upper = bb_mid + bb_std * bb_sigma
bb_lower = bb_mid - bb_std * bb_sigma
df["bb_mid"] = bb_mid
df["bb_upper"] = bb_upper
df["bb_lower"] = bb_lower
# bb_width: normalised band width (volatility proxy)
df["bb_width"] = (bb_upper - bb_lower) / bb_mid
# bb_pct: position of close within the band [0, 1]
band_range = bb_upper - bb_lower
df["bb_pct"] = (close - bb_lower) / band_range
# Distance from close to mid in units of band width
df["bb_dist_mid"] = (close - bb_mid) / bb_mid
# ── ATR (period=14) ───────────────────────────────────────────────────────
atr_period = 14
prev_close = close.shift(1)
tr = pd.concat([
high - low,
(high - prev_close).abs(),
(low - prev_close).abs()
], axis=1).max(axis=1)
atr = tr.ewm(span=atr_period, min_periods=atr_period, adjust=False).mean()
natr = atr / close
df["atr"] = atr
df["natr"] = natr
# ── Momentum / trend features ─────────────────────────────────────────────
# Rate of change at multiple horizons
for n in [1, 4, 8, 16]:
df[f"roc_{n}"] = close.pct_change(n)
# RSI (14)
rsi_period = 14
delta = close.diff()
gain = delta.clip(lower=0)
loss = (-delta).clip(lower=0)
avg_gain = gain.ewm(span=rsi_period, min_periods=rsi_period, adjust=False).mean()
avg_loss = loss.ewm(span=rsi_period, min_periods=rsi_period, adjust=False).mean()
rs = avg_gain / (avg_loss + 1e-10)
rsi = 100 - (100 / (1 + rs))
df["rsi_14"] = rsi
# RSI derived: distance from 50 (centred, normalised)
df["rsi_dev"] = (rsi - 50) / 50
# ── MACD (12, 26, 9) ──────────────────────────────────────────────────────
ema12 = close.ewm(span=12, adjust=False).mean()
ema26 = close.ewm(span=26, adjust=False).mean()
macd_line = ema12 - ema26
macd_signal = macd_line.ewm(span=9, adjust=False).mean()
macd_hist = macd_line - macd_signal
df["macd_line"] = macd_line
df["macd_signal"] = macd_signal
df["macd_hist"] = macd_hist
# ── Trend (SMA 50) ────────────────────────────────────────────────────────
sma50 = close.rolling(50).mean()
df["sma_50"] = sma50
df["close_vs_sma50"] = (close - sma50) / sma50 # normalised distance
# ── Volume / candle structure features ────────────────────────────────────
body = (close - open_).abs()
candle_rng = high - low
df["body_ratio"] = body / (candle_rng + 1e-10) # body as fraction of range
df["upper_wick"] = (high - pd.concat([close, open_], axis=1).max(axis=1)) / (candle_rng + 1e-10)
df["lower_wick"] = (pd.concat([close, open_], axis=1).min(axis=1) - low) / (candle_rng + 1e-10)
df["candle_dir"] = np.where(close > open_, 1.0, -1.0) # bullish / bearish bar
# ── Lagged bb_pct & rsi (to give the model recent history) ───────────────
for lag in [1, 2, 3]:
df[f"bb_pct_lag{lag}"] = df["bb_pct"].shift(lag)
df[f"rsi_lag{lag}"] = df["rsi_14"].shift(lag)
df[f"macd_hist_lag{lag}"] = df["macd_hist"].shift(lag)
# ── Volatility regime flag ────────────────────────────────────────────────
natr_ma = natr.rolling(50).mean()
df["vol_regime"] = np.where(natr > natr_ma, 1.0, 0.0) # 1 = high-vol regime
# ── BB squeeze detection ──────────────────────────────────────────────────
bb_width_ma = df["bb_width"].rolling(50).mean()
df["bb_squeeze"] = np.where(df["bb_width"] < bb_width_ma, 1.0, 0.0)
# ── Mean-reversion signal strength ────────────────────────────────────────
# Positive → oversold (close below lower band), Negative → overbought
df["mr_signal"] = 0.5 - df["bb_pct"] # centred: +0.5 at lower band, -0.5 at upper
# ── Fill NaN from warm-up ─────────────────────────────────────────────────
df = df.bfill().ffill()
return df
# SECTION 2 — STRATEGY CONFIG
def strategy_config():
return {
"title": "USD/JPY BB Mean-Reversion + ATR Gradient Boost",
"model_type": "GradientBoostingClassifier",
"model_params": {
"n_estimators": 500,
"max_depth": 4,
"learning_rate": 0.03,
"subsample": 0.8,
"min_samples_leaf": 20,
"max_features": "sqrt",
"validation_fraction": 0.1,
"n_iter_no_change": 30,
"tol": 1e-4,
"random_state": 42,
},
"signal_threshold": 0.55,
"direction": "both",
"stop_loss": 0.005,
"take_profit": 0.010,
"cooldown": 0,
"max_positions": 1,
"on_opposite": "reverse",
"session_filter": None,
"min_atr": None,
"trend_filter": None,
"target_horizon": 4,
"objective": (
"Maximise Sharpe ratio via a Gradient Boosting classifier trained on "
"Bollinger Band position (bb_pct), normalised bandwidth (bb_width), "
"ATR/NATR, RSI, MACD histogram, candle structure, and lagged features. "
"GBM chosen for its ability to capture non-linear interactions between "
"volatility (ATR) and mean-reversion (BB) signals. n_iter_no_change "
"acts as early stopping to prevent overfitting on the 15-min USDJPY series. "
"SL=0.5% / TP=1.0% gives a 1:2 risk-reward; threshold=0.55 reduces noise trades."
),
"notes": (
"Bollinger Bands are the primary mean-reversion anchor; ATR/NATR filter "
"entries to adequate volatility bars. RSI and MACD provide momentum context "
"to avoid fading strong trends. Lagged features (up to 3 bars) give the model "
"short-term regime memory without look-ahead. vol_regime and bb_squeeze flags "
"allow the model to differentiate trending vs. ranging conditions automatically. "
"No session filter applied — USDJPY is liquid across Asian and European sessions."
),
}
|
||||||||||
|
🥉
|
USD/JPY Multi-MA + RSI/BB XGBoost Sharpe
Maximize Sharpe ratio on USD/JPY 1-min data using XGBoost with returns, RSI, Bollinger Bands, multiple MAs (50/100/200), MACD, ATR, and cand…
|
M
@malcolmtan
|
USDJPY | 1min | 60.7%44.3% | +0.42%-4.25% | 1.220.84 | 0.53%0.53% | 84106 |
|
# ╔══════════════════════════════════════════════════════════════╗
# ║ STRATEGY REQUEST LOG ║
# ╚══════════════════════════════════════════════════════════════╝
# Generated : 2026-05-08 02:08:02
# Model : XGBoost
# Feature Eng. : Auto-add features: ON
# Signal / Entry : —
# Optimization : —
# Risk Mgmt : —
# Risk Filter : —
# ══════════════════════════════════════════════════════════════
# ============================================================
# SECTION 0 — IMPORTS & CONSTANTS
import numpy as np
import pandas as pd
DATA_PATH = "/root/Desktop/QuantifyMe/data/ohlc/USDJPY_1min.parquet"
START_DATE = "2026-05-04 00:00:00"
END_DATE = "2026-05-07 00:00:00"
VALIDATION_DATE = ""
TRAIN_SPLIT = 0.6993736951983298
# SECTION 1 — FEATURE ENGINEERING
def feature_engineering(df, close, open_, high, low):
# --- Returns over multiple horizons ---
for n in [1, 3, 5, 10, 20]:
df[f"ret_{n}"] = close.pct_change(n)
# --- RSI 14 ---
delta = close.diff()
gain = delta.clip(lower=0)
loss = -delta.clip(upper=0)
avg_gain = gain.ewm(com=13, min_periods=14).mean()
avg_loss = loss.ewm(com=13, min_periods=14).mean()
rs = avg_gain / (avg_loss + 1e-10)
df["rsi_14"] = 100.0 - (100.0 / (1.0 + rs))
# --- RSI derived features ---
df["rsi_14_zscore"] = (df["rsi_14"] - df["rsi_14"].rolling(50).mean()) / (df["rsi_14"].rolling(50).std() + 1e-10)
df["rsi_overbought"] = np.where(df["rsi_14"] > 70, 1, 0)
df["rsi_oversold"] = np.where(df["rsi_14"] < 30, 1, 0)
# --- Bollinger Bands 20, 2 ---
bb_mid = close.rolling(20).mean()
bb_std = close.rolling(20).std()
bb_upper = bb_mid + 2.0 * bb_std
bb_lower = bb_mid - 2.0 * bb_std
df["bb_mid"] = bb_mid
df["bb_upper"] = bb_upper
df["bb_lower"] = bb_lower
df["bb_width"] = (bb_upper - bb_lower) / (bb_mid + 1e-10)
df["bb_pct_b"] = (close - bb_lower) / (bb_upper - bb_lower + 1e-10)
df["bb_above"] = np.where(close > bb_upper, 1, 0)
df["bb_below"] = np.where(close < bb_lower, 1, 0)
# --- Moving Averages ---
for w in [50, 100, 200]:
df[f"sma_{w}"] = close.rolling(w).mean()
df[f"price_vs_sma_{w}"] = (close - df[f"sma_{w}"]) / (df[f"sma_{w}"] + 1e-10)
# --- MA crossover signals ---
df["sma50_vs_sma100"] = np.where(df["sma_50"] > df["sma_100"], 1, -1)
df["sma50_vs_sma200"] = np.where(df["sma_50"] > df["sma_200"], 1, -1)
df["sma100_vs_sma200"] = np.where(df["sma_100"] > df["sma_200"], 1, -1)
# --- ATR 14 ---
tr = pd.concat([
high - low,
(high - close.shift(1)).abs(),
(low - close.shift(1)).abs()
], axis=1).max(axis=1)
df["atr_14"] = tr.ewm(com=13, min_periods=14).mean()
df["natr_14"] = df["atr_14"] / (close + 1e-10)
# --- Momentum / rate of change ---
for n in [5, 10, 20]:
df[f"mom_{n}"] = close - close.shift(n)
df[f"roc_{n}"] = (close - close.shift(n)) / (close.shift(n) + 1e-10)
# --- Volume features (if volume exists) ---
if "volume" in df.columns:
vol = df["volume"].replace(0, np.nan)
df["vol_sma_20"] = vol.rolling(20).mean()
df["vol_ratio_20"] = vol / (df["vol_sma_20"] + 1e-10)
else:
df["vol_ratio_20"] = 1.0
# --- Price spread & body features ---
df["hl_spread"] = (high - low) / (close + 1e-10)
df["body_ratio"] = (close - open_).abs() / (high - low + 1e-10)
df["upper_wick"] = (high - pd.concat([close, open_], axis=1).max(axis=1)) / (high - low + 1e-10)
df["lower_wick"] = (pd.concat([close, open_], axis=1).min(axis=1) - low) / (high - low + 1e-10)
df["bull_candle"] = np.where(close > open_, 1, 0)
# --- Lagged returns for autocorrelation signal ---
for lag in [1, 2, 3, 5]:
df[f"ret1_lag{lag}"] = df["ret_1"].shift(lag)
# --- Rolling volatility ---
df["vol_10"] = df["ret_1"].rolling(10).std()
df["vol_20"] = df["ret_1"].rolling(20).std()
df["vol_50"] = df["ret_1"].rolling(50).std()
# --- Z-score of close over 20 and 50 bars ---
df["zscore_20"] = (close - close.rolling(20).mean()) / (close.rolling(20).std() + 1e-10)
df["zscore_50"] = (close - close.rolling(50).mean()) / (close.rolling(50).std() + 1e-10)
# --- Relative distance of price from BB bands ---
df["dist_upper"] = (bb_upper - close) / (close + 1e-10)
df["dist_lower"] = (close - bb_lower) / (close + 1e-10)
# --- EMA 9 and 21 for short-term momentum ---
df["ema_9"] = close.ewm(span=9, min_periods=9).mean()
df["ema_21"] = close.ewm(span=21, min_periods=21).mean()
df["ema9_vs_ema21"] = np.where(df["ema_9"] > df["ema_21"], 1, -1)
df["price_vs_ema9"] = (close - df["ema_9"]) / (df["ema_9"] + 1e-10)
df["price_vs_ema21"] = (close - df["ema_21"]) / (df["ema_21"] + 1e-10)
# --- MACD-like signal ---
ema_12 = close.ewm(span=12, min_periods=12).mean()
ema_26 = close.ewm(span=26, min_periods=26).mean()
macd_line = ema_12 - ema_26
signal_line = macd_line.ewm(span=9, min_periods=9).mean()
df["macd"] = macd_line
df["macd_signal"] = signal_line
df["macd_hist"] = macd_line - signal_line
df["macd_cross"] = np.where(macd_line > signal_line, 1, -1)
# --- Fill NaN from warm-up periods ---
df = df.bfill().ffill()
return df
# SECTION 2 — STRATEGY CONFIG
def strategy_config():
return {
"title": "USD/JPY Multi-MA + RSI/BB XGBoost Sharpe",
"model_type": "XGBClassifier",
"model_params": {
"n_estimators": 400,
"max_depth": 4,
"learning_rate": 0.04,
"subsample": 0.75,
"colsample_bytree": 0.75,
"min_child_weight": 5,
"gamma": 0.1,
"reg_alpha": 0.1,
"reg_lambda": 1.5,
"objective": "binary:logistic",
"tree_method": "hist",
"random_state": 42,
},
"signal_threshold": 0.55,
"direction": "both",
"stop_loss": 0.0008,
"take_profit": 0.0016,
"cooldown": 0,
"max_positions": 1,
"on_opposite": "close_only",
"session_filter": None,
"min_atr": None,
"trend_filter": None,
"target_horizon": 5,
"objective": (
"Maximize Sharpe ratio on USD/JPY 1-min data using XGBoost with "
"returns, RSI, Bollinger Bands, multiple MAs (50/100/200), MACD, "
"ATR, and candle-body features. Stop-loss and take-profit set at "
"a 1:2 risk/reward to filter noise and improve Sharpe. n_estimators "
"and moderate depth balance bias-variance. Regularization (alpha/lambda) "
"reduces overfitting on short date range."
),
"notes": (
"Target horizon of 5 bars (5 minutes) is chosen to capture short-term "
"directional moves on 1-min data without excessive label noise. "
"colsample_bytree and subsample add stochasticity to reduce variance. "
"close_only on opposite signal avoids whipsaw from rapid reversals. "
"No session filter applied since USD/JPY has liquidity around the clock."
),
}
|
||||||||||