edgekit

edgekit.challenge

Prop-firm challenge simulation. A prop challenge is a path problem, not an average-return problem, so the only honest answer is Monte-Carlo over resampled paths. Both entry points take daily_pnl_dollars (P&L after sizing, dollars per day) so the breach limits are absolute dollars.

What's inside. The ChallengeRules dataclass and three presets (FTMO_1STEP, CFT_2PHASE, BRIGHTFUNDED), plus two Monte-Carlo entry points: simulate (the pass rate) and days_to_pass (the distribution of days to clear all phases). Both use a block-bootstrap (not i.i.d.) so losing streaks stay intact and the breach probability is honest.

ChallengeRules (frozen dataclass)#

A prop-firm evaluation's hard constraints, all in account dollars.

ChallengeRules(account: float, phase_targets: list[float], daily_loss: float,
               max_loss: float, min_days: int = 4)
FieldTypeMeaning
accountfloatAccount size in dollars.
phase_targetslist[float]Profit target per phase in dollars ([10_000] = single phase; [8_000, 5_000] = two phases).
daily_lossfloatPositive daily-loss limit in dollars.
max_lossfloatPositive overall max-loss limit in dollars.
min_daysint (default 4)Minimum active days before a phase may be marked passed.

Presets#

All three are $100k accounts with dollar limits, encoding each firm's published rules.

Presetphase_targetsdaily_lossmax_lossmin_days
FTMO_1STEP[10_000]5_00010_0004
CFT_2PHASE[8_000, 5_000]5_00010_0004
BRIGHTFUNDED[8_000, 5_000]5_00010_0003
from edgekit import challenge
challenge.FTMO_1STEP     # ChallengeRules(account=100_000, phase_targets=[10_000], daily_loss=5_000, max_loss=10_000, min_days=4)
challenge.CFT_2PHASE     # two phases: [8_000, 5_000]
challenge.BRIGHTFUNDED   # two phases, min_days=3

# a custom rule set
rules = challenge.ChallengeRules(account=50_000, phase_targets=[4_000], daily_loss=2_500, max_loss=5_000)

simulate#

Block-bootstrap pass rate for a sized daily-P&L stream through the rules — the fraction of n Monte-Carlo paths that clear every phase without breaching the daily-loss or max-loss limits.

simulate(daily_pnl_dollars, rules: ChallengeRules, n: int = 12000,
         rng=None, block: int = 5, phase_days: int = 400) -> float
ParamTypeDefaultMeaning
daily_pnl_dollarspd.SeriesSized P&L per day, in dollars (breach limits are absolute).
rulesChallengeRulesThe evaluation's constraints (or a preset).
nint12000Number of Monte-Carlo paths.
rngGenerator | NoneNoneSeeded generator for reproducibility.
blockint5Block length for the bootstrap (keeps losing streaks intact).
phase_daysint400Max days allowed per phase before the path is abandoned.

Returns a float pass rate in [0, 1].

simulate.py
import numpy as np, pandas as pd
from edgekit import challenge

# sized daily P&L (dollars/day) — e.g. from sizing.size_to_dd(...)["sized"]
idx = pd.date_range("2020-01-01", periods=400, freq="D")
daily_pnl = pd.Series(np.random.default_rng(0).normal(700.0, 200.0, 400), index=idx)

rate = challenge.simulate(daily_pnl, challenge.FTMO_1STEP, n=12000)
print(f"pass rate = {rate:.1%}")

days_to_pass#

Distribution of days-to-pass (all phases) over the paths that pass — how long a successful attempt typically takes.

days_to_pass(daily_pnl_dollars, rules: ChallengeRules, n: int = 12000,
             rng=None, block: int = 5, phase_days: int = 400) -> dict

Returns a dict:

  • median — median days-to-pass (NaN if nothing passes).
  • p25, p75 — 25th / 75th percentile days.
  • mean — mean days-to-pass.
  • pass_rate — fraction of paths that passed.
  • n_pass — count of passing paths.
d = challenge.days_to_pass(daily_pnl, challenge.CFT_2PHASE)
print(d["median"], d["p25"], d["p75"], d["pass_rate"])
!Feed it the SIZED stream, not raw R
Both functions expect dollars-per-day after sizing, because the breach limits are absolute dollars. Passing a raw R-stream (or an unsized dollar stream) makes the daily-loss and max-loss checks meaningless. Size first with sizing.size_to_dd, then simulate.

See also#

  • edgekit.sizing — produce the sized dollar stream these functions consume.
  • edgekit.portfolio — build the combined book you then size and simulate.
  • edgekit.report — turn the pass rate into a Challenge / Live / Realistic report suite.