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
This commit is contained in:
TPTBusiness
2026-05-22 15:10:36 +02:00
parent d4611b530e
commit 4758de0eee
29 changed files with 873 additions and 407 deletions
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -6,7 +6,7 @@ Tests the complete end-to-end pipeline including:
- Portfolio Optimization (P7)
- Full Pipeline End-to-End
- Parallelization
- FTMO Compliance
- RiskMgmt Compliance
At least 20 integration tests covering all new features.
@@ -526,15 +526,15 @@ class TestParallelization:
# ---------------------------------------------------------------------------
# Tests: FTMO Compliance
# Tests: RiskMgmt Compliance
# ---------------------------------------------------------------------------
class TestFTMOCompliance:
"""Test FTMO compliance checks for accepted strategies."""
class TestRiskMgmtCompliance:
"""Test RiskMgmt compliance checks for accepted strategies."""
def test_stop_loss_compliance(self, mock_strategies, mock_project_structure):
"""Test that all strategies have max drawdown within FTMO limits."""
"""Test that all strategies have max drawdown within RiskMgmt limits."""
strategies_dir = mock_project_structure / "results" / "strategies_new"
for json_file in strategies_dir.glob("*.json"):
@@ -542,7 +542,7 @@ class TestFTMOCompliance:
data = json.load(f)
max_dd = abs(data.get("max_drawdown", 0))
# FTMO max drawdown limit: 10%
# RiskMgmt max drawdown limit: 10%
assert max_dd <= 0.25 or data.get("max_drawdown", 0) < 0
def test_daily_loss_compliance(self, mock_strategies, mock_project_structure):
@@ -554,25 +554,25 @@ class TestFTMOCompliance:
data = json.load(f)
daily_loss = abs(data.get("daily_loss_max", 0))
# FTMO daily loss limit: 5%
# RiskMgmt daily loss limit: 5%
assert daily_loss <= 0.05 or data.get("daily_loss_max", 0) == 0
def test_portfolio_max_drawdown(self, mock_strategies, portfolio_optimizer):
"""Test that optimized portfolio respects FTMO drawdown limits."""
"""Test that optimized portfolio respects RiskMgmt drawdown limits."""
opt_result = portfolio_optimizer.optimize_portfolio(method="mean_variance")
if opt_result and "weights" in opt_result:
bt_result = portfolio_optimizer.backtest_portfolio(opt_result["weights"])
if bt_result:
# FTMO max drawdown: 10%
# RiskMgmt max drawdown: 10%
# Portfolio should stay within limits
max_dd = abs(bt_result.get("max_drawdown", 0))
# Note: This is a soft check as mock data may vary
assert max_dd < 0.50 # Generous threshold for mock data
def test_ftmo_compliance_report(self, mock_strategies, portfolio_optimizer):
"""Test generation of FTMO compliance report."""
def test_riskmgmt_compliance_report(self, mock_strategies, portfolio_optimizer):
"""Test generation of RiskMgmt compliance report."""
strategies = portfolio_optimizer._load_strategy_data()
if not strategies:
@@ -922,12 +922,12 @@ class TestSharpeRatioProperties:
# ---------------------------------------------------------------------------
# Property 5: FTMO Drawdown Limits
# Property 5: RiskMgmt Drawdown Limits
# ---------------------------------------------------------------------------
class TestFTMODrawdownLimits:
"""Property: FTMO drawdown invariants."""
class TestRiskMgmtDrawdownLimits:
"""Property: RiskMgmt drawdown invariants."""
@given(
equity_gain=st.floats(min_value=-0.15, max_value=0.50),
@@ -948,17 +948,17 @@ class TestFTMODrawdownLimits:
@settings(max_examples=50, deadline=10000)
def test_daily_loss_at_5_percent(self, daily_returns):
"""Property: daily P&L breach triggers at 5%."""
ftmo_daily_max = 0.05
riskmgmt_daily_max = 0.05
daily_pnl = np.prod(1 + np.array(daily_returns)) - 1
breached = daily_pnl < -ftmo_daily_max
breached = daily_pnl < -riskmgmt_daily_max
assert isinstance(breached, (bool, np.bool_))
@given(
total_return=st.floats(min_value=-0.15, max_value=0.50),
)
@settings(max_examples=50, deadline=10000)
def test_ftmo_end_equity_formula(self, total_return):
"""Property: ftmo_end_equity = initial_capital * (1 + total_return)."""
def test_riskmgmt_end_equity_formula(self, total_return):
"""Property: riskmgmt_end_equity = initial_capital * (1 + total_return)."""
initial = 100_000.0
end_equity = initial * (1 + total_return)
assert end_equity > 0 # Can't go below zero
+2 -2
View File
@@ -51,7 +51,7 @@ class TestBuildMLModel:
result = build_ml_model(factor_data.iloc[:100], close_data.iloc[:100], "swing")
assert result is None
@patch("rdagent.components.backtesting.vbt_backtest.backtest_signal_ftmo")
@patch("rdagent.components.backtesting.vbt_backtest.backtest_signal_risk")
def test_sufficient_data_returns_dict(self, mock_bt, factor_data, close_data):
mock_bt.return_value = {
"sharpe": 1.5, "max_drawdown": -0.1, "win_rate": 0.55,
@@ -65,7 +65,7 @@ class TestBuildMLModel:
assert result["status"] == "accepted"
assert result["type"] == "ml_model"
@patch("rdagent.components.backtesting.vbt_backtest.backtest_signal_ftmo")
@patch("rdagent.components.backtesting.vbt_backtest.backtest_signal_risk")
def test_negative_oos_rejected(self, mock_bt, factor_data, close_data):
mock_bt.return_value = {
"sharpe": 1.5, "max_drawdown": -0.1, "win_rate": 0.55,
+25 -25
View File
@@ -7,7 +7,7 @@ Tests cover:
- Parameter space definition and validation
- Parameter suggestion mechanisms
- Objective function calculation
- FTMO penalty logic
- RiskMgmt penalty logic
- Optuna study creation and configuration
- Parameter injection into strategy code
- Optimization run (mocked, small trial count)
@@ -37,11 +37,11 @@ except ImportError:
from rdagent.scenarios.qlib.local.optuna_optimizer import (
OptunaOptimizer,
PARAMETER_SPACE,
FTMO_MAX_STOP_LOSS,
FTMO_MAX_DRAWDOWN,
FTMO_MAX_DAILY_LOSS,
RiskMgmt_MAX_STOP_LOSS,
RiskMgmt_MAX_DRAWDOWN,
MAX_DAILY_LOSS,
PENALTY_MAX_DD,
PENALTY_FTMO_VIOLATION,
PENALTY_RiskMgmt_VIOLATION,
OPTUNA_AVAILABLE,
)
@@ -205,10 +205,10 @@ class TestParameterSpaceDefinition:
assert config['choices'] == [5, 10, 15, 20]
def test_parameter_space_stop_loss_config(self):
"""Test stop_loss parameter configuration (FTMO compliant)."""
"""Test stop_loss parameter configuration (RiskMgmt compliant)."""
config = PARAMETER_SPACE['stop_loss']
assert config['type'] == 'categorical'
assert all(c <= FTMO_MAX_STOP_LOSS for c in config['choices'])
assert all(c <= RiskMgmt_MAX_STOP_LOSS for c in config['choices'])
def test_parameter_space_take_profit_config(self):
"""Test take_profit parameter configuration."""
@@ -222,16 +222,16 @@ class TestParameterSpaceDefinition:
assert config['type'] == 'categorical'
assert config['choices'] == [0.01, 0.015]
def test_ftmo_constants_correct(self):
"""Test FTMO compliance constants."""
assert FTMO_MAX_STOP_LOSS == 0.02
assert FTMO_MAX_DRAWDOWN == -0.10
assert FTMO_MAX_DAILY_LOSS == 0.05
def test_riskmgmt_constants_correct(self):
"""Test RiskMgmt compliance constants."""
assert RiskMgmt_MAX_STOP_LOSS == 0.02
assert RiskMgmt_MAX_DRAWDOWN == -0.10
assert MAX_DAILY_LOSS == 0.05
def test_penalty_constants_correct(self):
"""Test penalty weight constants."""
assert PENALTY_MAX_DD == -10.0
assert PENALTY_FTMO_VIOLATION == -50.0
assert PENALTY_RiskMgmt_VIOLATION == -50.0
# =============================================================================
@@ -420,15 +420,15 @@ class TestObjectiveFunction:
# =============================================================================
# FTMO Penalty Tests
# RiskMgmt Penalty Tests
# =============================================================================
@pytest.mark.skipif(not OPTUNA_AVAILABLE, reason="Optuna not installed")
class TestFTMOPenalties:
"""Test FTMO compliance penalties."""
class TestRiskMgmtPenalties:
"""Test RiskMgmt compliance penalties."""
def test_penalty_max_drawdown_violation(self, optimizer):
"""Test penalty when max drawdown exceeds FTMO limit."""
"""Test penalty when max drawdown exceeds RiskMgmt limit."""
study = optuna.create_study(sampler=optuna.samplers.TPESampler(seed=42))
with patch.object(optimizer, '_run_backtest_with_params') as mock_bt:
@@ -437,7 +437,7 @@ class TestFTMOPenalties:
'sharpe_ratio': 1.5,
'ic': 0.08,
'total_trades': 25,
'max_drawdown': -0.12, # Below FTMO_MAX_DRAWDOWN (-0.10)
'max_drawdown': -0.12, # Below RiskMgmt_MAX_DRAWDOWN (-0.10)
}
trial = study.ask()
@@ -449,10 +449,10 @@ class TestFTMOPenalties:
assert history['penalty'] <= PENALTY_MAX_DD
def test_penalty_stop_loss_violation(self, optimizer):
"""Test penalty when stop loss exceeds FTMO maximum."""
"""Test penalty when stop loss exceeds RiskMgmt maximum."""
study = optuna.create_study(sampler=optuna.samplers.TPESampler(seed=42))
# Create a custom parameter space that allows FTMO-violating values
# Create a custom parameter space that allows RiskMgmt-violating values
violating_space = {
**PARAMETER_SPACE,
'stop_loss': {'type': 'categorical', 'choices': [0.01, 0.025, 0.03]},
@@ -475,13 +475,13 @@ class TestFTMOPenalties:
value = optimizer.objective(trial)
history = optimizer._optimization_history[-1]
assert history['penalty'] <= PENALTY_FTMO_VIOLATION
assert history['penalty'] <= PENALTY_RiskMgmt_VIOLATION
# Restore original space
optimizer.parameter_space = optimizer.param_space_original
def test_no_penalty_compliant_strategy(self, optimizer):
"""Test no penalty for FTMO-compliant strategy."""
"""Test no penalty for RiskMgmt-compliant strategy."""
study = optuna.create_study(sampler=optuna.samplers.TPESampler(seed=42))
with patch.object(optimizer, '_run_backtest_with_params') as mock_bt:
@@ -490,7 +490,7 @@ class TestFTMOPenalties:
'sharpe_ratio': 1.5,
'ic': 0.08,
'total_trades': 25,
'max_drawdown': -0.05, # Within FTMO limit
'max_drawdown': -0.05, # Within RiskMgmt limit
}
trial = study.ask()
@@ -517,7 +517,7 @@ class TestFTMOPenalties:
'sharpe_ratio': 1.5,
'ic': 0.08,
'total_trades': 25,
'max_drawdown': -0.12, # FTMO violation
'max_drawdown': -0.12, # RiskMgmt violation
}
trial = study.ask()
@@ -526,7 +526,7 @@ class TestFTMOPenalties:
history = optimizer._optimization_history[-1]
# Both penalties should apply
expected_penalty = PENALTY_MAX_DD + PENALTY_FTMO_VIOLATION
expected_penalty = PENALTY_MAX_DD + PENALTY_RiskMgmt_VIOLATION
assert history['penalty'] == expected_penalty
+9 -9
View File
@@ -452,9 +452,9 @@ class TestAcceptanceGate:
assert gate.min_sharpe == 0.5
assert gate.min_trades == 10
assert gate.max_drawdown == -0.15
assert gate.ftmo_max_sl == 0.02
assert gate.ftmo_max_daily_loss == 0.05
assert gate.ftmo_max_dd == 0.10
assert gate.riskmgmt_max_sl == 0.02
assert gate.riskmgmt_max_daily_loss == 0.05
assert gate.riskmgmt_max_dd == 0.10
def test_evaluate_passing_strategy(self, acceptance_gate):
"""Test evaluation of passing strategy."""
@@ -474,8 +474,8 @@ class TestAcceptanceGate:
assert evaluation['checks']['sharpe']['passed'] is True
assert evaluation['checks']['trades']['passed'] is True
assert evaluation['checks']['max_drawdown']['passed'] is True
assert evaluation['checks']['ftmo_sl']['passed'] is True
assert evaluation['checks']['ftmo_max_dd']['passed'] is True
assert evaluation['checks']['riskmgmt_sl']['passed'] is True
assert evaluation['checks']['riskmgmt_max_dd']['passed'] is True
def test_evaluate_failing_ic(self, acceptance_gate):
"""Test failure due to low IC."""
@@ -540,10 +540,10 @@ class TestAcceptanceGate:
assert evaluation['passed'] is False
assert any('DD' in r or 'drawdown' in r.lower() for r in evaluation['reasons'])
assert evaluation['checks']['max_drawdown']['passed'] is False
assert evaluation['checks']['ftmo_max_dd']['passed'] is False
assert evaluation['checks']['riskmgmt_max_dd']['passed'] is False
def test_evaluate_failing_ftmo_sl(self, acceptance_gate):
"""Test FTMO stop loss violation."""
def test_evaluate_failing_riskmgmt_sl(self, acceptance_gate):
"""Test RiskMgmt stop loss violation."""
result = {
'ic': 0.05,
'sharpe_ratio': 1.2,
@@ -555,7 +555,7 @@ class TestAcceptanceGate:
evaluation = acceptance_gate.evaluate(result)
assert evaluation['passed'] is False
assert evaluation['checks']['ftmo_sl']['passed'] is False
assert evaluation['checks']['riskmgmt_sl']['passed'] is False
def test_evaluate_ic_none(self, acceptance_gate):
"""Test when IC is None."""
+5 -5
View File
@@ -193,9 +193,9 @@ class TestRegressionFixedBugs:
def test_oos_default_enabled(self):
"""Feature: OOS/WF is now default."""
from rdagent.components.backtesting.vbt_backtest import backtest_signal_ftmo
from rdagent.components.backtesting.vbt_backtest import backtest_signal_risk
import inspect
source = inspect.signature(backtest_signal_ftmo)
source = inspect.signature(backtest_signal_risk)
assert source.parameters["wf_rolling"].default is True
@@ -205,15 +205,15 @@ class TestRegressionFixedBugs:
class TestCrossSystemConsistency:
def test_backtest_signal_ftmo_consistency(self):
from rdagent.components.backtesting.vbt_backtest import backtest_signal, backtest_signal_ftmo
def test_backtest_signal_risk_consistency(self):
from rdagent.components.backtesting.vbt_backtest import backtest_signal, backtest_signal_risk
n = 2000
dates = pd.date_range("2024-01-01", periods=n, freq="1min")
rng = np.random.default_rng(42)
close = pd.Series(1.10 * np.exp(np.cumsum(rng.normal(0, 0.0002, n))), index=dates)
signal = pd.Series(np.where(rng.normal(0, 1, n) > 0, 1.0, -1.0), index=dates)
r1 = backtest_signal(close, signal, txn_cost_bps=2.14)
r2 = backtest_signal_ftmo(close, signal, txn_cost_bps=2.14, wf_rolling=False)
r2 = backtest_signal_risk(close, signal, txn_cost_bps=2.14, wf_rolling=False)
if r1["status"] == "success" and r2.get("status") == "success":
assert "sharpe" in r1 and "sharpe" in r2
assert -1.0 <= r1["max_drawdown"] <= 0.0
+4 -4
View File
@@ -66,17 +66,17 @@ class TestLiveTraderMock:
def test_script_imports(self):
import importlib.util
spec = importlib.util.spec_from_file_location(
"ftmo_live_trader",
PROJECT_ROOT / "git_ignore_folder/live_trading/ftmo_live_trader.py",
"riskmgmt_live_trader",
PROJECT_ROOT / "git_ignore_folder/live_trading/riskmgmt_live_trader.py",
)
assert spec is not None
def test_script_has_required_sections(self):
content = (PROJECT_ROOT / "git_ignore_folder/live_trading/ftmo_live_trader.py").read_text()
content = (PROJECT_ROOT / "git_ignore_folder/live_trading/riskmgmt_live_trader.py").read_text()
assert "RISK_PCT" in content
assert "STOP_PIPS" in content
assert "TP_PIPS" in content
assert "FTMO_DAILY_LIMIT" in content
assert "RiskMgmt_DAILY_LIMIT" in content
class TestFactorValuesIntegration:
+5 -5
View File
@@ -175,22 +175,22 @@ class TestPromptLoader:
load_prompt("xyz_nonexistent")
class TestApplyFTMOMask:
class TestApplyRiskMgmtMask:
def test_output_same_length(self):
from rdagent.components.backtesting.vbt_backtest import _apply_ftmo_mask
from rdagent.components.backtesting.vbt_backtest import _apply_risk_mask
dates = pd.date_range("2024-01-01", periods=100, freq="1min")
close = pd.Series(1.10, index=dates)
signal = pd.Series(np.where(np.arange(100) % 2 == 0, 1.0, -1.0), index=dates)
masked, metrics = _apply_ftmo_mask(signal, close, leverage=1.0, txn_cost_bps=2.14)
masked, metrics = _apply_risk_mask(signal, close, leverage=1.0, txn_cost_bps=2.14)
assert len(masked) == len(signal)
assert isinstance(metrics, dict)
def test_flat_signal(self):
from rdagent.components.backtesting.vbt_backtest import _apply_ftmo_mask
from rdagent.components.backtesting.vbt_backtest import _apply_risk_mask
dates = pd.date_range("2024-01-01", periods=200, freq="1min")
close = pd.Series(1.10, index=dates)
signal = pd.Series(0.0, index=dates)
masked, metrics = _apply_ftmo_mask(signal, close, leverage=1.0, txn_cost_bps=2.14)
masked, metrics = _apply_risk_mask(signal, close, leverage=1.0, txn_cost_bps=2.14)
assert isinstance(metrics, dict)