Skip to content

Commit 4758de0

Browse files
committed
refactor: remove all proprietary terms from codebase and git history
- Rename FTMO_* constants → generic names (RISK_PER_TRADE, MAX_DAILY_LOSS, etc.) - Rename backtest_signal_ftmo → backtest_signal_risk - Rename _apply_ftmo_mask → _apply_risk_mask - Clean all FTMO/riskMgmt mentions from commit messages via filter-branch - AGENTS.md: add non-negotiable rule — NEVER mention proprietary terms in commits/releases - Code variables and function names sanitized project-wide - Force-pushed rewritten history to remote
1 parent d4611b5 commit 4758de0

29 files changed

Lines changed: 873 additions & 407 deletions

rdagent/components/backtesting/__init__.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,29 @@
55
from .vbt_backtest import (
66
DEFAULT_BARS_PER_YEAR,
77
DEFAULT_TXN_COST_BPS,
8-
FTMO_INITIAL_CAPITAL,
9-
FTMO_MAX_DAILY_LOSS,
10-
FTMO_MAX_TOTAL_LOSS,
11-
FTMO_MAX_LEVERAGE,
12-
FTMO_RISK_PER_TRADE,
8+
INITIAL_CAPITAL,
9+
MAX_DAILY_LOSS,
10+
MAX_TOTAL_LOSS,
11+
MAX_LEVERAGE,
12+
RISK_PER_TRADE,
1313
OOS_START_DEFAULT,
1414
WF_IS_YEARS,
1515
WF_OOS_YEARS,
1616
WF_STEP_YEARS,
1717
backtest_from_forward_returns,
1818
backtest_signal,
19-
backtest_signal_ftmo,
19+
backtest_signal_risk,
2020
monte_carlo_trade_pvalue,
2121
walk_forward_rolling,
2222
)
2323

2424
__all__ = [
2525
'BacktestMetrics', 'FactorBacktester', 'ResultsDatabase',
2626
'CorrelationAnalyzer', 'PortfolioOptimizer', 'AdvancedRiskManager',
27-
'backtest_signal', 'backtest_signal_ftmo', 'backtest_from_forward_returns',
27+
'backtest_signal', 'backtest_signal_risk', 'backtest_from_forward_returns',
2828
'monte_carlo_trade_pvalue', 'walk_forward_rolling',
2929
'DEFAULT_BARS_PER_YEAR', 'DEFAULT_TXN_COST_BPS',
30-
'FTMO_INITIAL_CAPITAL', 'FTMO_MAX_DAILY_LOSS', 'FTMO_MAX_TOTAL_LOSS',
31-
'FTMO_MAX_LEVERAGE', 'FTMO_RISK_PER_TRADE', 'OOS_START_DEFAULT',
30+
'INITIAL_CAPITAL', 'MAX_DAILY_LOSS', 'MAX_TOTAL_LOSS',
31+
'MAX_LEVERAGE', 'RISK_PER_TRADE', 'OOS_START_DEFAULT',
3232
'WF_IS_YEARS', 'WF_OOS_YEARS', 'WF_STEP_YEARS',
3333
]

rdagent/components/backtesting/vbt_backtest.py

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,15 @@
3838
DEFAULT_BARS_PER_YEAR = 252 * 1440 # 252 trading days * 1440 min/day = 362,880
3939
EXTREME_BAR_THRESHOLD = 0.05 # |ret| > 5% on a single 1-min bar → suspicious
4040

41-
# FTMO 100k account rules (enforced in backtest_signal when ftmo=True)
42-
FTMO_INITIAL_CAPITAL = 100_000.0
43-
FTMO_MAX_DAILY_LOSS = 0.05 # 5% of initial → block new trades rest of day
44-
FTMO_MAX_TOTAL_LOSS = 0.10 # 10% of initial → simulation ends
41+
# RiskMgmt 100k account rules (enforced in backtest_signal when riskmgmt=True)
42+
INITIAL_CAPITAL = 100_000.0
43+
MAX_DAILY_LOSS = 0.05 # 5% of initial → block new trades rest of day
44+
MAX_TOTAL_LOSS = 0.10 # 10% of initial → simulation ends
4545
# Risk-based position sizing: 1.5% equity risk per trade, 10-pip stop, max 1:30 leverage
46-
FTMO_RISK_PER_TRADE = 0.015
47-
FTMO_STOP_PIPS = 10
48-
FTMO_PIP = 0.0001
49-
FTMO_MAX_LEVERAGE = 30
46+
RISK_PER_TRADE = 0.015
47+
STOP_PIPS = 10
48+
PIP_SIZE = 0.0001
49+
MAX_LEVERAGE = 30
5050

5151

5252
def _compute_trade_pnl(position: pd.Series, strategy_returns: pd.Series) -> pd.Series:
@@ -274,31 +274,31 @@ def backtest_signal(
274274
return result
275275

276276

277-
def _apply_ftmo_mask(
277+
def _apply_risk_mask(
278278
signal: pd.Series,
279279
close: pd.Series,
280280
leverage: float,
281281
txn_cost_bps: float,
282282
) -> tuple[pd.Series, dict]:
283283
"""
284-
Apply FTMO daily/total loss rules to a signal series.
284+
Apply RiskMgmt daily/total loss rules to a signal series.
285285
286286
Returns a masked signal (positions zeroed after each limit breach) and
287-
a dict of FTMO compliance metrics.
287+
a dict of RiskMgmt compliance metrics.
288288
"""
289289
txn_cost = txn_cost_bps / 10_000.0
290290
position = signal.shift(1).fillna(0) * leverage
291291
bar_ret = close.pct_change().fillna(0)
292292

293-
equity = FTMO_INITIAL_CAPITAL
294-
peak_day = FTMO_INITIAL_CAPITAL
293+
equity = INITIAL_CAPITAL
294+
peak_day = INITIAL_CAPITAL
295295
masked = signal.copy()
296296

297297
daily_breaches = 0
298298
total_breached = False
299299
total_breach_ts: pd.Timestamp | None = None
300300
current_day = None
301-
day_start_eq = FTMO_INITIAL_CAPITAL
301+
day_start_eq = INITIAL_CAPITAL
302302

303303
pos_prev = 0.0
304304
for ts, sig_i in signal.items():
@@ -319,24 +319,24 @@ def _apply_ftmo_mask(
319319
masked.at[ts] = 0
320320
continue
321321

322-
daily_loss = (equity - day_start_eq) / FTMO_INITIAL_CAPITAL
323-
total_loss = (equity - FTMO_INITIAL_CAPITAL) / FTMO_INITIAL_CAPITAL
322+
daily_loss = (equity - day_start_eq) / INITIAL_CAPITAL
323+
total_loss = (equity - INITIAL_CAPITAL) / INITIAL_CAPITAL
324324

325-
if daily_loss < -FTMO_MAX_DAILY_LOSS:
325+
if daily_loss < -MAX_DAILY_LOSS:
326326
daily_breaches += 1
327327
day_start_eq = -999 # block rest of day
328328
masked.at[ts] = 0
329329

330-
if total_loss < -FTMO_MAX_TOTAL_LOSS:
330+
if total_loss < -MAX_TOTAL_LOSS:
331331
total_breached = True
332332
total_breach_ts = ts
333333
masked.at[ts] = 0
334334

335335
return masked, {
336-
"ftmo_daily_breaches": daily_breaches,
337-
"ftmo_total_breached": total_breached,
338-
"ftmo_total_breach_ts": str(total_breach_ts) if total_breach_ts else None,
339-
"ftmo_compliant": not total_breached and daily_breaches == 0,
336+
"risk_daily_breaches": daily_breaches,
337+
"risk_total_breached": total_breached,
338+
"risk_total_breach_ts": str(total_breach_ts) if total_breach_ts else None,
339+
"risk_compliant": not total_breached and daily_breaches == 0,
340340
}
341341

342342

@@ -403,7 +403,7 @@ def walk_forward_rolling(
403403
"""
404404
Rolling walk-forward validation: multiple IS/OOS windows shifted by ``step_years``.
405405
406-
Each window runs an independent FTMO simulation on the IS and OOS slices.
406+
Each window runs an independent RiskMgmt simulation on the IS and OOS slices.
407407
Produces aggregate OOS statistics to measure cross-time consistency.
408408
409409
Returns
@@ -442,7 +442,7 @@ def walk_forward_rolling(
442442
for mask, prefix in [(is_mask, "is"), (oos_mask, "oos")]:
443443
close_s = close.loc[mask]
444444
signal_s = signal.loc[mask]
445-
masked_s, _ = _apply_ftmo_mask(signal_s, close_s, leverage, txn_cost_bps)
445+
masked_s, _ = _apply_risk_mask(signal_s, close_s, leverage, txn_cost_bps)
446446
r = backtest_signal(close=close_s, signal=masked_s,
447447
txn_cost_bps=txn_cost_bps, bars_per_year=bars_per_year)
448448
window[f"{prefix}_sharpe"] = r.get("sharpe", 0.0)
@@ -466,30 +466,30 @@ def walk_forward_rolling(
466466
}
467467

468468

469-
def backtest_signal_ftmo(
469+
def backtest_signal_risk(
470470
close: pd.Series,
471471
signal: pd.Series,
472472
txn_cost_bps: float = DEFAULT_TXN_COST_BPS,
473473
eurusd_price: float = 1.10,
474-
risk_pct: float = FTMO_RISK_PER_TRADE,
475-
stop_pips: float = FTMO_STOP_PIPS,
476-
max_leverage: float = FTMO_MAX_LEVERAGE,
474+
risk_pct: float = RISK_PER_TRADE,
475+
stop_pips: float = STOP_PIPS,
476+
max_leverage: float = MAX_LEVERAGE,
477477
bars_per_year: int = DEFAULT_BARS_PER_YEAR,
478478
forward_returns: pd.Series | None = None,
479479
oos_start: str | None = OOS_START_DEFAULT,
480480
wf_rolling: bool = True,
481481
mc_n_permutations: int = 0,
482482
) -> dict[str, Any]:
483483
"""
484-
FTMO-compliant backtest of a strategy signal on EUR/USD.
484+
RiskMgmt-compliant backtest of a strategy signal on EUR/USD.
485485
486486
Applies on top of ``backtest_signal``:
487487
- Realistic costs: default 2.14 bps (≈ 2.35 pip spread+slippage+commission)
488488
- Risk-based position sizing: risk_pct equity per trade, stop_pips hard stop
489-
- Max leverage cap: max_leverage (default 1:30, FTMO standard)
490-
- FTMO daily loss limit (5%): positions zeroed rest of day after breach
491-
- FTMO total loss limit (10%): all positions zeroed after breach
492-
- FTMO-specific metrics added to result dict
489+
- Max leverage cap: max_leverage (default 1:30, RiskMgmt standard)
490+
- RiskMgmt daily loss limit (5%): positions zeroed rest of day after breach
491+
- RiskMgmt total loss limit (10%): all positions zeroed after breach
492+
- RiskMgmt-specific metrics added to result dict
493493
- Walk-forward OOS split: IS metrics (before oos_start) + OOS metrics (after)
494494
495495
Parameters
@@ -507,7 +507,7 @@ def backtest_signal_ftmo(
507507
stop_pips : float
508508
Hard stop-loss distance in pips (default 10).
509509
max_leverage : float
510-
Maximum leverage (default 30 = FTMO 1:30).
510+
Maximum leverage (default 30 = RiskMgmt 1:30).
511511
oos_start : str or None
512512
Start of out-of-sample period (ISO date). None disables OOS split.
513513
wf_rolling : bool
@@ -518,11 +518,11 @@ def backtest_signal_ftmo(
518518
When > 0, computes ``mc_pvalue``: fraction of permuted sequences whose
519519
total return >= real total return. p < 0.05 indicates a genuine edge.
520520
"""
521-
stop_price = stop_pips * FTMO_PIP
521+
stop_price = stop_pips * PIP_SIZE
522522
leverage_by_risk = risk_pct / (stop_price / eurusd_price)
523523
leverage = min(leverage_by_risk, max_leverage)
524524

525-
masked_signal, ftmo_metrics = _apply_ftmo_mask(signal, close, leverage, txn_cost_bps)
525+
masked_signal, risk_metrics = _apply_risk_mask(signal, close, leverage, txn_cost_bps)
526526

527527
result = backtest_signal(
528528
close=close,
@@ -532,14 +532,14 @@ def backtest_signal_ftmo(
532532
forward_returns=forward_returns,
533533
)
534534

535-
result.update(ftmo_metrics)
536-
result["ftmo_leverage"] = round(leverage, 2)
537-
result["ftmo_risk_pct"] = risk_pct
538-
result["ftmo_stop_pips"] = stop_pips
535+
result.update(risk_metrics)
536+
result["risk_leverage"] = round(leverage, 2)
537+
result["risk_risk_pct"] = risk_pct
538+
result["risk_stop_pips"] = stop_pips
539539

540-
# Re-scale reported equity metrics to FTMO_INITIAL_CAPITAL
541-
result["ftmo_end_equity"] = FTMO_INITIAL_CAPITAL * (1 + result.get("total_return", 0))
542-
result["ftmo_monthly_profit"] = FTMO_INITIAL_CAPITAL * result.get("monthly_return", 0)
540+
# Re-scale reported equity metrics to INITIAL_CAPITAL
541+
result["risk_end_equity"] = INITIAL_CAPITAL * (1 + result.get("total_return", 0))
542+
result["risk_monthly_profit"] = INITIAL_CAPITAL * result.get("monthly_return", 0)
543543

544544
# Walk-forward OOS split
545545
if oos_start is not None:
@@ -551,9 +551,9 @@ def _split_bt(mask: pd.Series[bool], prefix: str) -> None:
551551
if mask.sum() < 100:
552552
return
553553
close_s = close.loc[mask]
554-
signal_s = signal.loc[mask] # raw signal, not masked — fresh FTMO sim per period
554+
signal_s = signal.loc[mask] # raw signal, not masked — fresh RiskMgmt sim per period
555555
fwd_split = forward_returns.loc[mask] if forward_returns is not None else None
556-
masked_s, _ = _apply_ftmo_mask(signal_s, close_s, leverage, txn_cost_bps)
556+
masked_s, _ = _apply_risk_mask(signal_s, close_s, leverage, txn_cost_bps)
557557
split_result = backtest_signal(
558558
close=close_s,
559559
signal=masked_s,

scripts/nexquant_1h_factors.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json, numpy as np, pandas as pd
22
from pathlib import Path
3-
from rdagent.components.backtesting.vbt_backtest import backtest_signal_ftmo
3+
from rdagent.components.backtesting.vbt_backtest import backtest_signal_risk
44

55
close = pd.read_hdf("git_ignore_folder/factor_implementation_source_data/intraday_pv.h5", key="data")["$close"]
66
close = close.droplevel(-1).sort_index().dropna().resample("1h").last().dropna()
@@ -34,7 +34,7 @@
3434
sig = pd.Series(dr * np.sign(fac).fillna(0), index=close.index)
3535
sig[~is_session] = 0
3636
if sig.abs().sum() < 20: continue
37-
r = backtest_signal_ftmo(close, sig.fillna(0), txn_cost_bps=2.14)
37+
r = backtest_signal_risk(close, sig.fillna(0), txn_cost_bps=2.14)
3838
oos = r.get("wf_oos_sharpe_mean") or r.get("oos_sharpe", -999)
3939
oos_m = r.get("oos_monthly_return_pct", 0) or 0
4040
results.append((f"{f['name']}_{label}", oos, oos_m, r.get("oos_n_trades",0)))
@@ -67,7 +67,7 @@
6767
df = pd.DataFrame(all_sig, index=close.index).fillna(0)
6868
for n in [3, 5, 8]:
6969
combo = df[list(df.columns)[:n]].mean(axis=1)
70-
r = backtest_signal_ftmo(close, combo.fillna(0), txn_cost_bps=2.14, wf_rolling=True)
70+
r = backtest_signal_risk(close, combo.fillna(0), txn_cost_bps=2.14, wf_rolling=True)
7171
oos_m = r.get("oos_monthly_return_pct",0) or 0
7272
dd = (r.get("oos_max_drawdown",0) or 0)*100
7373
ann = ((1+oos_m/100)**12-1)*100

scripts/nexquant_20tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
2020

21-
from rdagent.components.backtesting.vbt_backtest import backtest_signal_ftmo
21+
from rdagent.components.backtesting.vbt_backtest import backtest_signal_risk
2222

2323
DATA_PATH = Path("git_ignore_folder/factor_implementation_source_data/intraday_pv.h5")
2424
FACTORS_DIR = Path("results/factors")
@@ -71,7 +71,7 @@ def backtest(signal, close, label="") -> dict:
7171
if signal is None or len(signal) < 100:
7272
return {"wf_sharpe": -999, "oos_sharpe": -999, "oos_monthly": 0, "oos_dd": 0, "trades": 0}
7373
common = close.index.intersection(signal.dropna().index)
74-
r = backtest_signal_ftmo(close.loc[common], signal.reindex(common).fillna(0),
74+
r = backtest_signal_risk(close.loc[common], signal.reindex(common).fillna(0),
7575
txn_cost_bps=TXN_COST_BPS, wf_rolling=False)
7676
oos = r.get("oos_sharpe", -999)
7777
return {

scripts/nexquant_30min_scan.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"""30min Full Factor Scan — find all profitable signals."""
33
import json, numpy as np, pandas as pd
44
from pathlib import Path
5-
from rdagent.components.backtesting.vbt_backtest import backtest_signal_ftmo
5+
from rdagent.components.backtesting.vbt_backtest import backtest_signal_risk
66

77
c = pd.read_hdf("git_ignore_folder/factor_implementation_source_data/intraday_pv.h5", key="data")["$close"]
88
c = c.droplevel(-1).sort_index().dropna().resample("30min").last().dropna()
@@ -33,7 +33,7 @@
3333
sig = pd.Series(dr * np.sign(fac).fillna(0), index=c.index)
3434
sig[~is_s] = 0
3535
if sig.abs().sum() < 20: continue
36-
r = backtest_signal_ftmo(c, sig.fillna(0), txn_cost_bps=2.14)
36+
r = backtest_signal_risk(c, sig.fillna(0), txn_cost_bps=2.14)
3737
oos = r.get("wf_oos_sharpe_mean") or r.get("oos_sharpe", -999)
3838
oos_m = r.get("oos_monthly_return_pct", 0) or 0
3939
if oos_m > 0.2:
@@ -72,7 +72,7 @@
7272
print(f"\n=== COMBO TESTS ===")
7373
for n in [2, 3, 5, 8, len(cols)]:
7474
combo = df[cols[:n]].mean(axis=1)
75-
r = backtest_signal_ftmo(c, combo.fillna(0), txn_cost_bps=2.14, wf_rolling=True)
75+
r = backtest_signal_risk(c, combo.fillna(0), txn_cost_bps=2.14, wf_rolling=True)
7676
m = r.get("oos_monthly_return_pct", 0) or 0
7777
dd = (r.get("oos_max_drawdown", 0) or 0) * 100
7878
t = r.get("oos_n_trades", 0)

0 commit comments

Comments
 (0)