QxLab · Internal Documentation · Shared for Review

Position Manager — A to Z

How the system manages risk, exits, and portfolio-level decisions across 9 live EAs on a $100k FundedNext Stellar Lite demo account. Written 2026-05-22 for external review.

PM health: checking…
Trades since reset:
Active rules: 19 + Phase 2a + P2
Reset date: 2026-05-12
→ Live scorecard ↗

1. What the PM is

The Position Manager (PM) is a Python process that runs continuously alongside MT5 on the same machine. It does not open positions — that's the EA's (Expert Advisor's) job. The PM's role is everything that happens after entry: stop-loss adjustments, partial profit- taking, breakeven moves, drawdown kill switches, portfolio-level exposure caps, news-event blackouts, and friday flatten.

The architectural decision to split entry (in MQL5 .ex5 EAs) from management (in Python PM) was deliberate: it lets us iterate on risk rules without rewriting every EA, and it gives us a single point of truth for portfolio-level decisions that no individual EA can see.

The PM has evolved through 20 sequential rule versions (V1 → V20), each added in response to a specific live-trading incident. Most rules fire on every tick check (~once per minute). Some rules are cap-style (block new entries), some are action-style (close positions, adjust SL), and a few are alert-only (Telegram warning, no automated action).

2. Architecture overview

The system has three layers communicating via files:

  EAs (.mq5 binaries)            ← place new entries, manage trailing
   │
   │  attach to charts in MT5 Terminal
   ▼
  MT5 Terminal (IC Markets demo) ← maintains positions, executes orders
   │
   │  Python MetaTrader5 module reads positions + history
   ▼
  Position Manager (Python)      ← evaluates rules every minute,
   │                               adjusts SL/TP, closes positions
   │
   │  writes disabled_magics.txt + pm_heartbeat.txt
   ▼
  pm_guard.mqh (shared include)  ← read by every EA before placing orders
                                   so disabled magics never even fire
      

The PM reads MT5 state via the official MetaTrader5 Python API (positions, history, account info) and writes back via the same API (modify SL/TP, close position). It also writes plain-text "state" files into MQL5/Common/Files/ that the EAs read on each tick — that's how the EAs know which magics are blocked.

3. The tick loop (~once per minute)

Every tick, in order:

  1. Publish disabled_magics.txt, disabled_pairs.txt, and pm_heartbeat.txt to MQL5/Common/Files/
  2. Pull current positions from MT5 + account balance/equity
  3. Check V7 ACCOUNT KILL SWITCH (if floating DD breach → flatten all)
  4. Check ACCOUNT_DAILY_DD_KILL at -2% (flatten + freeze entries)
  5. For each open position, apply per-trade management (V1, V12, V12.1, V15, V19)
  6. Check portfolio-level caps + alerts (V2, V11, V13, V14)
  7. Track exec costs (V18) + regime tags (V17) for downstream analysis
  8. Sleep 60s and repeat

The PM is intentionally conservative: it never opens positions, only manages them. If the PM crashes, the EAs continue running but with stop-losses already in place at entry — meaning each open position has a defined max loss. Phase 2a adds a heartbeat so the EAs detect a dead PM and switch to fail-safe behavior (use last cached state).

4. The 20 rules (V1–V20)

Rules are tagged ACTION if they close/adjust positions, CAP if they block new entries, or ALERT if they only emit Telegram warnings without changing trade state.

Account-level guards

V7 Account kill switch
ACTION

If floating drawdown breaches the configured account DD limit (currently -2.5% daily / -8% total), flatten every position immediately and freeze new entries until the next day. Hard stop, no recovery within session.

V9 Daily profit lock at +1.5%
ACTION

Once the account hits +1.5% daily PnL, close all winning positions and stop opening new ones for the day. Locks the win, prevents giveback. Underwater positions are explicitly skipped (bug fixed 2026-05-21).

V10 Friday flat at 19:00 UTC
ACTION

Close everything before the weekend gap. Standard prop-firm convention. Combined with V19 for gradient unwinding earlier in the week.

V11 Total positions cap (8)
CAP

Hard limit of 8 simultaneous open positions across all EAs. If exceeded (race condition), the most recently opened are auto-closed back down to 8.

V19 Friday gradient
ACTION

Wed 16:00 UTC tightens stops; Thu 8:00 UTC takes partial 50%; Fri 19:00 UTC full flat (V10). Smooths the Friday close instead of one abrupt event.

V20 Trail-don't-TP
ACTION

After V12 partial+BE fires at +0.5R and price crosses +1.0R, strip the EA's take-profit and chandelier-trail the runner half at 1.0×initial_risk behind the running peak (long) / trough (short). Plugs the "capped winner" leak where positions reached ~+1R peak but exited at only +0.47R historically (56% capture ratio). Per-magic allowlist for staged rollout — initially enabled on 8 magics including FibChandelier H1, FibStructRetrace M15, and all 3 Multimind GOLDs.

Per-trade management

V1 R-harvest table
ACTION

Progressive partial + SL ratchet: at +1R close 50% + SL to entry; at +1.5R SL to +0.5R; at +2R SL to +1R; etc. Standard "scale out + trail" framework.

V9.3 Portfolio R-harvest at +5R
ACTION

Once total realized R across all open winners hits +5R, partial 50% of every winner and move SL to BE. Account-level lock-in, complementary to V9.

V12 Aggressive partial+BE at +0.5R
ACTION

More aggressive variant of V1. At +0.5R, close 50% + move SL to entry. Captures more frequent wins; the remaining 50% can run to V1's higher levels.

V12.1 Per-position -1.0% kill
ACTION

If a single position's unrealized PnL drops below -1.0% of account, close it. Catches oversized SL-distance trades before they damage the account.

V13 Dynamic risk by DD/streak
CAP

Risk multiplier on new entries: 1.00x normal, 0.75x at -1% DD, 0.50x at -2%, 0.25x at -3%. Smaller bets when the account is bleeding, full size when recovered.

Portfolio alerts (alert-only — does NOT block trades)

V2 Correlation cap
ALERT

Telegram warning when more than N positions are open in the same currency family and direction. Observation only, no auto-action. Pending upgrade to active sizing (round-2 council unanimous recommendation).

V14 Macro view exposure cap + active sizing (P2)
ACTION

Aggregates positions by macro thesis (USD-long, JPY-short, etc.). Originally alert-only — upgraded 2026-05-22 to active sizing (P2): new entries are scaled down based on existing stacked exposure (1.0× solo / 0.6× one correlated / 0.4× two / 0.25× three+). Published to size_overrides.txt via the same atomic-write mechanism as the disabled-magic firewall.

Entry-time filters (block new entries)

V8 Consecutive entry cap
CAP

Max 2 entries per (magic, symbol) per 240-minute window. Prevents revenge-trading by any single EA.

V15 Vol-regime trim
CAP

When H1 ATR ≥ 90th percentile (extreme volatility), cut new position sizes by 50%. Defensive sizing during chaos.

V16 Tiered news blackout
CAP

Tier-1 events (NFP, FOMC, CPI): 60-min entry blackout + flatten existing positions at -0.5R. Tier-2 (PMI, retail sales): 30-min blackout + flatten at +0.3R.

V17 Regime classifier (read-only)
ALERT

Tags every entry with the prevailing regime: trending (ADX ≥ 25 + ATR ≥ p90) vs ranging. Currently used for post-hoc analysis only. Pending upgrade to size by regime.

V18 Exec cost tracker (read-only)
ALERT

Logs every entry's bid/ask spread + execution slippage to exec_breadcrumbs.jsonl. Used to detect when execution costs are eating the edge.

Hard-disable systems

DISABLED_MAGICS Hard close any disabled magic
ACTION

A maintained set of magic numbers (currently 5) that should never be allowed to hold positions. If any of those fires, PM closes immediately. Combined with the EA-level firewall (see §5), the EAs now know not to even fire.

DISABLED_PAIRS Hard close (magic, symbol) bleeders
ACTION

Even within a "good" magic, some pair combinations bleed consistently. Set of (magic, symbol) tuples auto-closed on entry.

COLD_STREAK Auto-pause after 4 consecutive losses
CAP

If a (magic, symbol) hits 4 closing losses in a row, pause that combination for 240 minutes. Prevents the EA from grinding into a hole.

5. Disabled-magic firewall (Phase 2 + 2a — shipped 2026-05-22)

Of the most recent 72 trades, 32 were closed by the DISABLED_MAGICS rule (44% of all activity). Each cost ~1.5 pips of spread. The EAs were dumb — they kept firing trades that PM immediately closed, paying spread tax on each round trip with zero edge captured.

The fix moves the gate upstream: the PM publishes the kill list to a file the EAs read before placing orders. EAs literally don't fire if their magic is disabled.

Phase 2a hardening addresses four failure modes the multi-model review identified:

The whole system fails CLOSED on validation errors (better to halt than to trade rogue) and fails OPEN on first-ever boot (no info to act on) — a defensible compromise.

6. Live performance data

Real numbers from the lab since the 2026-05-12 account reset:

Total trades
Net P&L (USD)
Disabled magics
PM heartbeat age

Exit breakdown — which rule closed each trade

RuleTrades% of total

Per-magic performance

MagicTradesWin rateNet P&L

7. How decisions get made

Most rule additions (V13 onward) come from a structured AI council process. The PM's full state — rules, recent stats, known incidents — is briefed to six different LLMs simultaneously, each given a distinct risk-management persona (Renaissance quant, DE Shaw risk manager, Druckenmiller macro, ICT microstructure, etc.). Each model independently reviews the same data and proposes their highest- leverage next change.

When 4 of 6 models surface the same failure mode independently, it's signal not noise. That's how the disabled-magic firewall in §5 got picked as the next ship — four models from four different vendors all flagged it as #1 priority without seeing each other's answers.

After shipping, the council is re-run with the new state ("we just fixed X, what's next?"). The round-2 review of the firewall is what identified the four failure modes Phase 2a addresses. This is iterative: ship → review → ship → review.

8. Open questions for reviewers

If you have an opinion on any of these, we'd love to hear it.

  1. Active correlation sizing. Currently V14 alerts but doesn't act. SHIPPED 2026-05-22. V14 now scales down new entries based on existing stacked exposure (0.6× one correlated / 0.4× two / 0.25× three+). Did we miss a better tier curve? Are there macro views we haven't mapped that we should add?
  2. Per-EA daily DD limit. Should each EA get its own -1% daily DD, separate from the account-wide -2%? Three of six models said yes (Kimi, DeepSeek), the others said wait for clean post-firewall data first. Where do you stand?
  3. Streak-based asymmetric sizing. Should risk per trade GROW when a magic is on a winning streak (controlled aggression) the way V13 already SHRINKS it on losing streaks? Worried about pro-cyclical risk-on after a hot streak right into the mean reversion.
  4. Adaptive trail tightening. Currently V12 partials at +0.5R only. Should we tighten the trail progressively at +1R, +2R, +3R? The council vetoed this in round 1 as over-engineered — but did they miss something?
  5. Regime-conditional entries. V17 currently classifies regime but only TAGS trades. Should we go further and SKIP entries in unfavorable regimes (e.g., low-ADX-low-ATR chop)? At what cost in lost opportunities?
  6. The 30-second cache window. Phase 2a's only known weak point. For an H1 strategy this is 0.5% of a bar's time. Is the file-read overhead of going to 5-second checks worth the reduced exposure? Or accept it as acceptable noise?