# HyroTrader Backtester

This document describes the dedicated HyroTrader prop-firm backtester added in:

- `src/research/hyro-backtest.ts`
- npm script: `npm run hyro:backtest`

It exists because an ordinary strategy backtest is not enough for a prop-firm account. Hyro-style rules are path-dependent: an account can fail intraday even when the final trade would have recovered, and an account can touch the profit target but still be ineligible because of minimum trading days or profit-distribution constraints.

The backtester therefore simulates the validated BTC strategy under Hyro-specific challenge and funded-account constraints.

---

## Executive summary

Initial smoke tests support the current working view:

> The current 3%-risk BTC strategy is a poor fit for HyroTrader challenge rules, especially Standard/Trailing daily drawdown. Swing/Fixed drawdown improves survival, but the 6% max-loss barrier still kills most attempts before the strategy has enough time to realise its statistical edge.

Important first finding:

- At `RISK_PCT=3%`, one full stop is roughly `-3%`.
- Hyro max overall loss is `6%`.
- Therefore, **two full stopped trades can fail the account**.
- The BTC strategy has positive expectancy over months, but it does not have the high win rate needed to avoid repeated stops inside a 6% loss envelope.

A second important finding:

- At `3%` risk, some trades can require **>10x account notional** because structural L3 stop distance can be tight.
- Hyro funded accounts reportedly impose a **2x notional cap** and **25% margin cap**.
- These funded-stage caps likely force lower risk or explicit notional clipping, even if the challenge phase allows larger notional.

---

## Why this backtester was needed

The canonical validation backtest in `src/research/full-validation.ts` answers questions like:

- Does the signal have positive expectancy?
- What is monthly IR?
- What is normal strategy drawdown under compounding?
- What is the stop rate?
- How stable is the signal across years?

The Hyro question is different. It asks:

- Does the account pass before it fails?
- Does it breach intraday floating drawdown?
- Does it hit max loss before the edge has enough trades to play out?
- Does it satisfy minimum trading days?
- Does it satisfy the profit distribution rule?
- Would it violate funded-account exposure caps?

This is a **barrier / first-passage** problem, not a simple monthly P&L problem.

---

## Hyro rules currently modeled

The implementation models the rules we extracted from HyroTrader pages during research. Final live use should re-confirm the current terms in Hyro's dashboard before purchasing or trading a challenge.

### Challenge account rules

Modeled:

1. **One-Step challenge**
   - Default profit target: `10%`
   - Default daily drawdown: `4%`
   - Default max overall loss: `6%`
   - Default minimum trading days: `10`

2. **Two-Step Phase 1**
   - Default profit target: `8%`
   - Default daily drawdown: `5%`
   - Default max overall loss: `6%`
   - Default minimum trading days: `10`

3. **Two-Step Phase 2**
   - Default profit target: `5%`
   - Default daily drawdown: `5%`
   - Default max overall loss: `6%`
   - Default minimum trading days: `10`

4. **Profit distribution rule**
   - During challenge phases, no single positive trading day may contribute more than `40%` of total positive profit.
   - Loss days do not offset the positive-profit denominator.
   - The backtester checks this when pass eligibility is evaluated.

5. **Stop-loss obligation**
   - The trading system is assumed compliant because the live runner arms exchange-managed SL via Bybit TP/SL logic after fill.
   - The research backtester does not simulate operational API timing failures; it assumes the strategy has an SL in place.

6. **Risk per trade**
   - Hyro's rule is stated as max risk per position relative to initial account balance.
   - Backtester default: `riskBase='initial'`.
   - Other risk bases are implemented in code for future experiments:
     - `initial`
     - `equity`
     - `min-initial-equity`

### Daily drawdown modes

The backtester supports both Hyro drawdown styles:

#### Standard / trailing daily drawdown

Daily drawdown is measured from the highest intraday equity point.

Formula:

```text
Daily DD = Day peak equity - Current/trough equity
```

This includes floating/unrealised P&L.

This is harsh for the BTC strategy because a profitable open trade can raise the daily peak, and a later pullback can breach the daily drawdown limit even if the trade eventually exits profitably.

#### Swing / fixed daily drawdown

Daily drawdown is measured from the day's starting equity.

Formula:

```text
Daily DD = Day starting equity - Current/trough equity
```

This also includes floating/unrealised P&L.

This is much more compatible with the BTC strategy because intraday profits do not tighten the drawdown boundary.

### Overall max loss

The backtester checks max overall loss using floating equity.

Formula:

```text
Overall DD = Initial balance - Current/trough equity
```

Default threshold:

```text
6% of initial account balance
```

This is usually the binding constraint for the current strategy.

### Funded account rules

`--kind=funded` enables exposure checks:

- Max notional: `2x` initial account balance
- Max margin: `25%` initial account balance

The script currently reports violations rather than failing the funded simulation on them. This is deliberate: the immediate purpose is to audit whether the current risk profile is compatible. If we decide to develop a Hyro-funded execution profile, the next step is to turn these into hard pre-entry gates or notional caps.

---

## Strategy logic mirrored

The Hyro backtester duplicates the current validated BTC strategy logic from `src/research/full-validation.ts` so results can be compared directly.

Modeled strategy features:

- Composite score:
  - day-of-week weights
  - hour-of-day weights
  - BUYP / close-position pressure
  - US gap signal
  - RSI oversold signal
  - 24h reversion signal
- Entry thresholds:
  - long threshold: `10`
  - short threshold: `8`
- Confirmation:
  - `CONFIRM_BARS=4`
  - current bar plus prior 3 bars must remain above threshold in direction
- Momentum halts:
  - 72h halt: `600 bps`
  - 7d halt: `700 bps`
  - 14d halt: `800 bps`
- Entry level:
  - L1 composite liquidity level
  - round numbers
  - fractal swings
  - previous day high/low
  - session POC
- Entry wait:
  - wait up to `20` bars for level touch
- Stop architecture:
  - L2 soft stop: round numbers + PDH/PDL only
  - L3 hard stop: next round/PDH/PDL beyond L2
  - sizing uses L1→L3 distance
- Exit model:
  - soft stop on close
  - hard stop intrabar
  - FREEZE extension logic
  - no FLIP_EXIT
  - hard cap: `360` bars / `6h`
- Post-stop cooldown:
  - `30` bars / `30m`
- Fees:
  - default Bybit fee model: `2 bps` per side
  - entry fee booked immediately
  - exit fee booked on exit

---

## Important implementation choices

### Floating drawdown is included

Prop firms evaluate drawdown using equity, not only closed balance. The backtester therefore evaluates drawdown while positions are open.

For an open position:

```text
floating P&L = direction × (price - entryPrice) / entryPrice × notional
floating equity = realised equity + floating P&L
```

### Intrabar drawdown modes

The script supports three modes.

#### `--intrabar=ohlc-conservative` default

Uses 1-minute OHLC to estimate both favourable peak and adverse trough inside the bar.

For a long:

- favourable price: high
- adverse price: low

For a short:

- favourable price: low
- adverse price: high

This is conservative because it assumes both extremes are relevant for barrier checks during the same bar.

#### `--intrabar=adverse`

Uses bar close for peak update but adverse high/low for trough.

Useful if trailing peak from intrabar high/low feels too pessimistic, but adverse drawdown should still be detected.

#### `--intrabar=close`

Uses only bar closes for floating drawdown checks.

This is less conservative and can materially improve apparent pass rates. It is useful for sensitivity analysis, but likely underestimates prop-firm breach risk if Hyro monitors real-time equity.

### Stop cap default is total per day

Default:

```text
stopCap=1
default stopCapMode='total'
```

Meaning:

```text
one stop per UTC day total, not one long stop plus one short stop
```

This is stricter than the original runner's per-side stop cap and better matches prop-firm survival logic. If one stop is already a 3% loss, allowing a second same-day stop can threaten the 4–5% daily DD rule and the 6% max-loss rule.

### Risk uses initial balance by default

Default:

```text
riskBase='initial'
```

Reason: Hyro's max-risk rule is stated relative to initial account balance.

At `riskPct=0.03`, a full hard stop is intended to risk around 3% of initial balance.

### Challenge pass requires all gates

Touching the target is not enough. The script only returns `pass` if all are true:

```text
equity >= target equity
tradingDays >= minimum trading days
profit distribution rule passes
```

If the target is touched but the account is not eligible yet, the script tracks:

```text
targetTouchedButIneligible=true
```

---

## Commands

### Build

```bash
npm run build
```

### Default Hyro sweep

```bash
npm run hyro:backtest
```

Defaults:

```text
kind=one-step
account=100000
starts=monthly
maxDays=90
risks=0.005,0.01,0.015,0.02,0.025,0.03
intrabar=ohlc-conservative
profit distribution=on
```

### One-Step, $100k, 3% risk

```bash
npm run hyro:backtest -- \
  --kind=one-step \
  --account=100000 \
  --risks=0.03 \
  --starts=monthly \
  --max-days=90
```

### Full risk sweep

```bash
npm run hyro:backtest -- \
  --kind=one-step \
  --account=100000 \
  --risks=0.005,0.01,0.015,0.02,0.025,0.03 \
  --starts=monthly \
  --max-days=90
```

### Close-only drawdown sensitivity

```bash
npm run hyro:backtest -- \
  --kind=one-step \
  --account=100000 \
  --risks=0.03 \
  --starts=monthly \
  --max-days=90 \
  --intrabar=close
```

### Weekly starts

```bash
npm run hyro:backtest -- \
  --starts=weekly \
  --risks=0.01,0.02,0.03
```

### Daily starts

Daily starts are slower but give a better estimate of arbitrary challenge start timing.

```bash
npm run hyro:backtest -- \
  --starts=daily \
  --risks=0.005,0.01,0.015,0.02,0.025,0.03
```

### Disable profit distribution rule

```bash
npm run hyro:backtest -- --no-pdr
```

Use this only for sensitivity analysis. The rule should remain enabled for realistic Hyro challenge evaluation.

### Two-Step Phase 1

```bash
npm run hyro:backtest -- \
  --kind=two-step-1 \
  --account=100000 \
  --risks=0.005,0.01,0.015,0.02,0.025,0.03
```

### Two-Step Phase 2

```bash
npm run hyro:backtest -- \
  --kind=two-step-2 \
  --account=100000 \
  --risks=0.005,0.01,0.015,0.02,0.025,0.03
```

### Funded exposure audit

```bash
npm run hyro:backtest -- \
  --kind=funded \
  --account=100000 \
  --risks=0.005,0.01,0.015,0.02,0.025,0.03
```

This reports max notional multiple and exposure violations against the funded rules.

---

## Output fields

Each summary block prints:

```text
runs
pass / fail / incomplete
avgDaysToPass
targetTouchedButIneligible
return avg / median / p10 / p90
avgTrades
avgMaxOverallDD
avgMaxDailyDD
reasons
exposure
```

### Status meanings

#### `pass`

The attempt reached target equity and all pass gates were satisfied:

- profit target
- minimum trading days
- profit distribution rule

#### `fail`

The account breached a hard rule:

- `daily_dd_trailing`
- `daily_dd_swing`
- `max_loss`
- `equity_depleted`

#### `incomplete`

The simulation reached `--max-days` or data end without pass/fail.

### Reason meanings

#### `target_min_days_pdr`

Successful pass: target reached and both minimum trading days and profit distribution rule were satisfied.

#### `daily_dd_trailing`

Standard trailing daily drawdown was breached.

This means:

```text
day peak equity - floating/trough equity > daily DD limit
```

#### `daily_dd_swing`

Swing/fixed daily drawdown was breached.

This means:

```text
day starting equity - floating/trough equity > daily DD limit
```

#### `max_loss`

Overall account loss exceeded the max-loss threshold.

This means:

```text
initial balance - floating/trough equity > 6% initial balance
```

#### `target_touched_but_ineligible_or_no_pass`

The account touched target equity but could not yet pass, usually because:

- fewer than 10 trading days had occurred, or
- profit distribution rule failed.

Then it later failed to complete a valid pass before max days/data end.

#### `max_days_or_data_end`

No pass or fail occurred before `--max-days` or the end of historical data.

### Exposure output

Example:

```text
exposure: maxNotional=11.13x initial
```

This means the largest trade required notional equal to `11.13 × initial account balance`.

For challenge accounts, the script currently reports this but does not fail the attempt. For funded accounts, this indicates whether a funded-stage 2x notional cap would be violated.

---

## Initial smoke-test results

Command:

```bash
npm run hyro:backtest -- \
  --risks=0.03 \
  --starts=monthly \
  --max-days=30 \
  --kind=one-step \
  --account=100000 \
  --intrabar=close
```

Result summary:

### One-Step, Standard/Trailing DD, 3% risk, close-only DD

```text
runs=49
pass=1 (2.0%)
fail=48 (98.0%)
incomplete=0
reasons: daily_dd_trailing=39, max_loss=9, target_min_days_pdr=1
```

Interpretation:

- Standard trailing DD is extremely hostile to this strategy.
- Even with close-only drawdown checks, almost all starts fail.
- Most failures are daily trailing DD, not max-loss.

### One-Step, Swing/Fixed DD, 3% risk, close-only DD

```text
runs=49
pass=10 (20.4%)
fail=36 (73.5%)
incomplete=3
reasons: max_loss=27, target_min_days_pdr=10, daily_dd_swing=9, target_touched_but_ineligible_or_no_pass=2, max_days_or_data_end=1
```

Interpretation:

- Swing DD is materially better than trailing DD.
- However, the 6% max-loss rule remains the dominant problem.
- The strategy can pass in favourable windows but is not robust enough to justify calling Hyro compatible.

### One-Step, Standard/Trailing DD, 3% risk, conservative OHLC DD

Command:

```bash
node dist/research/hyro-backtest.js \
  --risks=0.03 \
  --starts=monthly \
  --max-days=90 \
  --kind=one-step \
  --account=100000
```

Result summary from smoke run:

```text
runs=49
pass=0 (0.0%)
fail=49 (100.0%)
reasons: daily_dd_trailing=42, max_loss=7
```

Interpretation:

- Under conservative intrabar barrier checks, Standard/Trailing DD is effectively unusable.

### One-Step, Swing/Fixed DD, 3% risk, conservative OHLC DD

Same command, Swing section:

```text
runs=49
pass=11 (22.4%)
fail=38 (77.6%)
reasons: max_loss=23, daily_dd_swing=15, target_min_days_pdr=11
```

Interpretation:

- Swing remains far better than Standard.
- The pass rate is still too low for a serious prop-firm deployment plan.
- Conservative OHLC checks show daily swing DD can still fail when intrabar adverse movement exceeds the allowed daily threshold.

---

## Why the strategy struggles at Hyro

The validated BTC strategy is not a high-win-rate scalping strategy. It is a statistical, calendar/structural mean-reversion strategy with:

- positive expectancy across many trades,
- meaningful stop clusters during bad regimes,
- acceptable self-funded max drawdown,
- strong fee sensitivity,
- best deployment profile on 0% maker venues.

Hyro challenges are designed around tight barrier survival:

```text
Profit target: +10%
Max loss: -6%
Daily DD: -4% or -5%
```

At 3% risk:

```text
1 full stop ≈ -3%
2 full stops ≈ -6%
```

So the challenge becomes:

> Can the strategy reach +10% before suffering roughly two stopped trades?

That is not the natural shape of this edge.

The strategy's normal behaviour is closer to:

- take many trades,
- absorb stop clusters,
- let strong positive months dominate,
- rely on low maker fees and enough capital runway.

Hyro removes that runway.

---

## How to interpret risk sweeps

A lower risk setting improves survival but slows target acquisition.

For example:

### High risk: `3%`

Pros:

- Can reach 10% target quickly in favourable windows.
- Best chance of passing before time/friction if the first trades are strong.

Cons:

- Two full stops can fail the account.
- Daily DD can fail on adverse floating P&L.
- Funded-stage 2x notional cap likely violated.

### Medium risk: `1%` to `1.5%`

Pros:

- Can survive more stops.
- More compatible with max-loss and daily-DD barriers.

Cons:

- 10% target takes far longer.
- Profit distribution rule may become a bigger issue if one large day dominates.
- Still may violate funded notional cap if structural stops are very tight.

### Low risk: `0.5%`

Pros:

- Much safer barrier profile.
- More prop-firm compatible.

Cons:

- Target velocity may be too slow.
- Opportunity cost and challenge duration become important.
- May still be inferior to self-funded MEXC in expected value.

The right metric is not simple average return. The right metric is:

```text
P(pass before fail) × expected funded value - P(fail) × challenge fee - opportunity cost
```

---

## Known limitations

### 1. Rule source may change

Hyro terms can change. Before using this for real capital allocation, re-check:

- daily DD percentage by product,
- whether Swing upgrade is available for the selected platform,
- max loss rule,
- minimum trading days,
- profit distribution rule,
- funded exposure caps,
- Bybit API/TP-SL recognition rules,
- whether account review imposes additional discretionary constraints.

### 2. Intrabar path is unknowable from 1m OHLC

`ohlc-conservative` is deliberately harsh. It assumes the relevant favourable and adverse extrema can both matter inside the same minute.

This may overstate failures for trailing DD.

`close` mode likely understates failures.

The truth is between them unless tick/orderbook data is used.

### 3. No operational failure simulation

The backtester assumes:

- orders are placed correctly,
- stop-loss is armed in time,
- Bybit/Hyro recognises the TP/SL stop,
- no WebSocket/API outage,
- no partial-fill weirdness,
- no exchange maintenance issue.

Live prop-firm risk is worse than backtest risk.

### 4. Maker execution is simplified

The strategy assumes maker economics, but the research simulator is not a full live chase-order simulator. It mirrors the canonical research path rather than every detail of order placement.

For prop-firm suitability, this is acceptable for first-pass barrier analysis, but not enough for execution certification.

### 5. Profit distribution rule timing

The script checks the 40% profit distribution rule when pass eligibility is evaluated. If Hyro evaluates the rule differently, results may change.

### 6. Funded exposure caps are reported, not enforced

For `--kind=funded`, the script reports notional/margin violations. It does not yet clip or skip trades.

Next implementation step, if needed:

- add `--enforce-exposure-caps`,
- cap notional at `2x initial`,
- recalculate risk actually deployed,
- compare funded P&L under capped risk.

### 7. Account review discretion is not modeled

Hyro reserves discretion for gambling/all-or-nothing behaviour. The backtester cannot model discretionary manual review.

High-risk profiles that technically pass may still be operationally risky.

---

## Recommended next experiments

Run these before making any real Hyro decision.

### 1. Full monthly sweep, conservative intrabar

```bash
npm run hyro:backtest -- \
  --kind=one-step \
  --account=100000 \
  --starts=monthly \
  --max-days=90 \
  --risks=0.005,0.01,0.015,0.02,0.025,0.03 \
  --intrabar=ohlc-conservative
```

Goal:

- identify whether any risk level has a credible pass/fail balance.

### 2. Daily-start sweep

```bash
npm run hyro:backtest -- \
  --kind=one-step \
  --account=100000 \
  --starts=daily \
  --max-days=90 \
  --risks=0.005,0.01,0.015,0.02,0.025,0.03 \
  --intrabar=ohlc-conservative
```

Goal:

- estimate arbitrary start-date pass probability rather than month-start luck.

### 3. Swing-only practical profile

Hyro should only be considered with Swing/Fixed daily drawdown.

The script currently prints both trailing and swing. For decision-making, focus on the Swing section.

### 4. Funded exposure cap audit

```bash
npm run hyro:backtest -- \
  --kind=funded \
  --account=100000 \
  --starts=monthly \
  --risks=0.005,0.01,0.015,0.02,0.025,0.03
```

Goal:

- determine the largest risk percentage that does not regularly violate `2x` notional.

### 5. Add exposure-enforced mode

Future code change:

```text
--enforce-exposure-caps
```

Expected behaviour:

- skip trades above cap, or
- cap notional to max allowed and accept lower effective risk.

This is required before claiming any funded-stage projection.

### 6. Add Hyro-specific risk controls

Potential strategy profile for testing only:

```text
riskPct = 0.5% to 1.0%
stopCap = 1 total/day
no new trade after any stop until next UTC day
daily profit lock at +2% or +3%
daily loss lock at -1% to -2%
Swing DD only
exposure cap enforced
```

This would be a separate prop-firm profile, not the current MEXC-optimised profile.

---

## Current decision status

Based on the initial backtester and smoke results:

### Do not run current 3% profile on Hyro Standard/Trailing DD

Reason:

- near-total failure rate in conservative and close-only tests.

### Do not assume current 3% profile is robust on Hyro Swing DD

Reason:

- materially better than trailing, but still high failure rate.
- max loss remains a severe barrier.
- funded-stage notional caps may be violated.

### Continue treating MEXC self-funded as the cleaner deployment target

Reason:

- strategy was validated for capital-runway + low-maker-fee deployment,
- MEXC has 0% maker fees,
- no 6% prop-firm account-failure barrier,
- no profit-distribution rule,
- no discretionary payout review.

### Hyro remains a possible research branch only

It may be worth testing a dedicated Hyro-safe profile, but that profile should be judged on pass-before-fail probability, not ordinary monthly return.

---

## Source files

- Backtester: `src/research/hyro-backtest.ts`
- Canonical validation reference: `src/research/full-validation.ts`
- Current development log: `docs/algo-dev-session2.md`
- Four-year research: `docs/4year-research.md`
- Strategy notes: `docs/strategy-session-notes.md`

---

## Repro checklist

From repo root:

```bash
npm run build
npm run hyro:backtest -- --risks=0.03 --starts=monthly --max-days=30 --kind=one-step --account=100000 --intrabar=close
npm run hyro:backtest -- --risks=0.03 --starts=monthly --max-days=90 --kind=one-step --account=100000 --intrabar=ohlc-conservative
```

Expected qualitative result:

- trailing DD: very poor / near-unusable,
- swing DD: better but still not robust,
- max-loss and daily-DD breaches dominate,
- funded exposure audit needed before any prop-firm live plan.
