3838DEFAULT_BARS_PER_YEAR = 252 * 1440 # 252 trading days * 1440 min/day = 362,880
3939EXTREME_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
5252def _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 ,
0 commit comments