A complete toolkit to manage and control trading activity on Prop Trading accounts in MetaTrader 5.
Everything is driven from one single Expert Advisor. There is no server, no login, and no license — it works 100% offline on your own machine/VPS.
- What's Included
- Features at a Glance
- Download
- Quick Start
- The HCPropsController EA
- Feature: Prop-Firm Guardian
- Feature: Copy Trading (Master / Slave)
- Feature: News Filter
- Feature: Information Panel
- Feature: Crash-Safe State Persistence
- Verifying the calendar works on your broker
- Tool: StrategyQuant EA Patcher
- How Synchronization Works (Technical)
- Frequently Asked Questions
- Important Notes
- Troubleshooting / Support
| File | Type | Purpose |
|---|---|---|
HCPropsController.mq5 |
Expert Advisor | The core EA: Master/Slave copy trading + prop-firm risk guardian + news filter, all in one. |
HCProps_*.mqh (6 files) |
EA modules | Source modules included by HCPropsController.mq5 (util, guardian, news, master, slave, panel). Keep them in the same folder as the .mq5 when compiling; the compiled .ex5 is self-contained. |
Patch-SQX-GV-Disable.ps1 + Run-Patcher.bat |
Windows tool | Patches EAs exported from StrategyQuant (SQX) so they obey HCPropsController's limits. |
patch-gv-disable.py |
Cross-platform tool | Same patcher as above, for Linux / macOS / any system with Python 3. |
Everything is controlled from a single EA. The news filter is built into
HCPropsController(it is not a separate EA). No backend, login, orWebRequestis required — the EA runs entirely offline.
- Prop-firm risk guardian (every mode) — daily and total profit/loss limits (checked every 200 ms), max parallel trades, max trades per day, consecutive win/loss streak limits, trading-hours window, and a forced close time, enforced independently on every account — including standalone accounts via
Mode = NONE(guardian only, no shared files). When a limit is hit it closes positions, deletes pending orders, and disables trading. WithPropagateSlaveClose, a Slave breach also closes the originals on the Master and locks the Master: new orders are only accepted while every account has trading enabled. Survived a prop-firm account reset?HistoryFromDatemakes the EA ignore all older history and re-baseline from the reset moment. - Dead-Slave detection — every Slave publishes a heartbeat; with
ExpectedSlavesset, the Master blocks new entries the moment a Slave terminal goes silent, so nothing trades unhedged. A per-account trade log (TradePairLog) records every closed position for hedge-leakage reconciliation. - Copy trading — replicate one MASTER account onto any number of SLAVE accounts on the same machine, with auto lot scaling by point value, lot multiplier, symbol mapping, inverse mode, distance-based SL/TP (measured from each account's own fill price), and Slave→Master close propagation (a Slave-side SL/TP/manual close flattens the Master and every other Slave within ~half a second).
- News filter — pause or close trading around economic news using MT5's native economic calendar (fully offline).
- Live information panel — an on-chart dashboard showing status, limits, counters, schedules, and connection state.
- Crash-safe — risk state is persisted in MT5 Global Variables and survives EA restarts and VPS reboots.
- SQX integration — a patcher that makes StrategyQuant EAs stop trading whenever HCPropsController blocks trading.
Go to the Releases section and download the latest version. Unzip the archive into your working folder.
Note on the compiled
.ex5files: if you edit any.mq5source, recompile it in MetaEditor (F7) so your changes take effect. The shipped.ex5reflects the source as released.
- Copy
HCPropsController.mq5and theHCProps_*.mqhmodules into your MT5MQL5/Experts/folder and compile (or just use the provided.ex5, which is self-contained). - Attach the EA to a chart on your MASTER account, choose your risk limits, and you're protected.
- (Optional) Attach the same EA in SLAVE mode on other accounts/terminals to copy trades.
- (Optional, for StrategyQuant users) Patch your SQX EAs so they pause when a limit is hit.
- (Optional) Turn on the news filter — the EA logs
NEWS: N news scheduledand warns loudly if your broker doesn't serve the calendar.
- Copy
HCPropsController.mq5and theHCProps_*.mqhmodules into theMQL5/Experts/folder of your MetaTrader 5 (same folder; or deploy only the compiled.ex5). - Restart MetaTrader 5 or refresh the Navigator (F5), then compile the EA in MetaEditor (F7).
- Drag the EA onto a chart.
- In Tools → Options → Expert Advisors, allow algorithmic trading. (No
WebRequestwhitelist is needed — the EA never makes network requests.)
Meant to run together with another EA that places the orders. HCPropsController monitors the account, enforces the risk limits (when PropFirmMode is on), runs the news filter, gates the order-placing EA through the HCPropsControllerDisableTrading global variable, and writes a shared file describing its open positions so Slaves can copy them.
Meant to run alone on its account: HCPropsController itself replicates the Master's positions. Since v2.20 it enforces the same guardian limits on its own account (configure them per account — each prop firm has its own rules). The only difference from the Master is who places the orders.
With PropagateSlaveClose = true the whole system behaves as one unit: a Slave-side close (SL/TP/manual/breach) closes the original on the Master and every other Slave, and a Slave whose trading is disabled (any lock) disables trading on the Master too — new orders are only accepted while every account has trading enabled.
Runs the full guardian and the news filter on one account without any copy trading: no shared files are created in Common\Files at all (no sync file, no status file, no trade log). Use it when you only want HCPropsController to restrict trading and close trades on a standalone account — for example a prop account you trade with one EA and no hedge. Everything in Prop-Firm Guardian applies; the copy-trading and propagation parameters are ignored.
| Parameter | Variable | Default | Description |
|---|---|---|---|
| Operation mode | Mode |
Master (executes trades) |
MASTER = guardian + replicate to Slaves; SLAVE = guardian + replicate from a Master; NONE = guardian only on this account, no shared files / no replication. |
| Enable limits guardian | PropFirmMode |
true |
true = enforce all risk limits on this account (works in every mode since v2.20). false = pure relay/copy, no intervention in your trading. |
| Force initial balance | ForceInitialBalance |
0 |
0 = auto-detect the initial balance from deposits. >0 = use this fixed value as the initial balance (basis for total/% limits). |
| Ignore history before | HistoryFromDate |
0 |
For prop-firm account resets (balance restored, trade history kept): set it to any moment after the last pre-reset trade and the EA ignores everything older — the initial balance becomes the balance as of that time, and the daily baseline and trade/streak counters only see newer deals. The firm's balance-correction deal counts as baseline (not P/L), so it doesn't matter whether your timestamp falls before or after it. 0 = full history. |
| Reset counters and locks on init | ResetCountersOnInit |
false |
true + reinitialize the EA = resets counters, daily initial equity, and clears the sticky daily and total locks (both the persisted and the in-memory state). Use it when starting a fresh account/challenge, or to manually lift a latched lock. Remember to set it back to false afterwards. A lock re-latches immediately if its limit is still enabled and the equity still breaches it. |
| Parameter | Variable | Default | Description |
|---|---|---|---|
| File name | FileName |
master_00001.csv |
Shared file name that links a Master to its Slave(s). The Slave must use the same value. For a second independent setup, bump the number (master_00002.csv, …) on both sides. |
| Custom path | CustomFilePath |
"" |
Custom path inside Common\Files (optional). |
| Symbols | Symbols |
"" |
(MASTER) Comma-separated symbols to replicate (empty = all). E.g. EURUSD,US30. Warning: an excluded symbol's positions are NOT hedged — the Master logs a warning per excluded position. |
| Parameter | Variable | Default | Description |
|---|---|---|---|
| Fresh Slave heartbeats required | ExpectedSlaves |
0 |
Set this to your number of Slaves. The Master blocks new entries while fewer than this many Slaves have a fresh heartbeat — the only protection against a silently crashed Slave terminal leaving new trades unhedged. 0 = off. |
| Heartbeat timeout (seconds) | SlaveHeartbeatTimeoutSec |
15 |
A Slave heartbeat older than this is considered stale. |
| Parameter | Variable | Default | Description |
|---|---|---|---|
| Trade pair log | TradePairLog |
true |
Each account appends every closed position to <syncfile>.trades.<login>.csv. Join Master + Slave files on masterTicket to measure hedge leakage per pair. |
| Parameter | Variable | Default | Description |
|---|---|---|---|
| Daily profit limit (%) | DailyProfitLimitPercent |
4.6 |
Daily profit cap. 0 = disabled. |
| Daily loss limit (%) | DailyLossLimitPercent |
4.6 |
Daily loss cap. 0 = disabled. |
| Total profit limit (%) | TotalProfitLimitPercent |
8.1 |
Total profit cap. 0 = disabled. |
| Total loss limit (%) | TotalLossLimitPercent |
8.1 |
Total loss cap. 0 = disabled. |
Set any limit to
0to disable it. See Prop-Firm Guardian for how the limits are calculated.
| Parameter | Variable | Default | Description |
|---|---|---|---|
| Parallel trades limit | MaxParallelTrades |
1 |
Max positions open at the same time. 0 = no limit. |
| Trades per day limit | MaxTradesPerDay |
1 |
Max trades opened per day. 0 = no limit. |
| Consecutive losses per day limit | MaxConsecLossesPerDay |
0 |
Max consecutive losing trades. 0 = no limit. |
| Consecutive wins per day limit | MaxConsecWinsPerDay |
0 |
Max consecutive winning trades. 0 = no limit. |
| Parameter | Variable | Default | Description |
|---|---|---|---|
| Daily reset hour | DailyResetHour |
0 |
Hour of the daily reset (0–23). 0 = midnight. |
| Daily reset minute | DailyResetMinute |
0 |
Minute of the daily reset (0–59). |
At the reset time, counters, daily initial equity, and the daily equity lock are reset/recalculated.
| Parameter | Variable | Default | Description |
|---|---|---|---|
| Limit new entries to the specified hours | LimitTradingHours |
true |
Enable the trading-hours window. |
| Trading start hour / minute | TradingStartHour / TradingStartMinute |
6 / 0 |
Window start (e.g. 06:00). |
| Trading end hour / minute | TradingEndHour / TradingEndMinute |
20 / 0 |
Window end (e.g. 20:00). Windows that cross midnight are supported. |
Outside the window, new entries are blocked and pending orders are removed; open positions are not force-closed by this rule.
| Parameter | Variable | Default | Description |
|---|---|---|---|
| Force close at the specified time | ForceExitEnabled |
true |
Enable a daily forced close. |
| Forced close hour / minute | TradingExitHour / TradingExitMinute |
22 / 0 |
At this time, all positions are closed and pending orders deleted. |
See the dedicated News Filter section for full details.
| Parameter | Variable | Default | Description |
|---|---|---|---|
| News handling mode | NewsMode |
OPERATE |
OPERATE / PAUSE_OPEN / CLOSE_ALL. |
| Protection before and after (seconds) | NewsDuration |
120 |
Half-window in seconds around each event. |
| Currencies to watch | NewsCurrencies |
"" |
E.g. EUR,USD,GBP. Empty = derive from the chart symbol. |
| Minimum impact to consider | NewsMinImpact |
HIGH |
LOW / MODERATE / HIGH. |
Operation mode = Master (executes trades)
Enable limits guardian = true
Daily profit limit (%) = 4.6
Daily loss limit (%) = 4.6
Total profit limit (%) = 8.1
Total loss limit (%) = 8.1
Parallel trades limit = 1
Trades per day limit = 1
Daily reset hour / minute = 0 / 0
Limit new entries to hours = true
Trading start = 06:00
Trading end = 20:00
Force close at time = true
Forced close = 22:00
| Parameter | Variable | Description |
|---|---|---|
| Operation mode | Mode |
Select Slave (replicates trades). |
A Slave links to its Master purely through the FileName in the === SYNC FILE === group — set it to the same value the Master uses (default master_00001.csv). No server/account configuration is needed.
| Parameter | Variable | Default | Description |
|---|---|---|---|
| Symbol mapping | SymbolMapping |
"" |
Format MASTER:SLAVE;MASTER2:SLAVE2. E.g. EURUSD:EURUSD.pro;US30:US30Cash. Empty = same names. |
| Copy mode | CopyMode |
NORMAL |
NORMAL also replicates SL/TP modifications; INCOGNITO sets SL/TP only at open and ignores later changes. |
| Invert Master trades (and SL/TP) | InverseMode |
true |
true = trade the opposite direction (BUY→SELL) and mirror SL/TP around the entry. false = copy in the same direction. |
| Lot multiplier | RiskMultiplier |
1.0 |
Slave lot = Master lot × multiplier, applied after auto lot scaling. Keep 1.0 unless you deliberately want a smaller/larger hedge. |
| Auto lot scaling | AutoLotScaling |
true |
Equalizes money per point when contract sizes differ between brokers (e.g. an index worth $20/pt on the Slave vs $10/pt on the Master copies at half the lots automatically). Uses the point value the Master writes into the sync file. |
| Allowed slippage (points) | Slippage |
10 |
Permitted deviation in points. |
| Magic Number | MagicNumber |
987654 |
Magic of the Slave's orders. Must be unique per Slave within the same terminal. The EA only manages positions carrying this magic. |
| Slave closes/locks propagate | PropagateSlaveClose |
true |
Two effects, set the same value on the Master and all Slaves. Closes: a mirrored position closed on the Slave by its own SL/TP, a manual close, a stop out, or a guardian breach immediately closes the original on the Master — which in turn flattens every other Slave. Locks: while any Slave has trading disabled (any guardian lock), the Master disables trading too, so new orders are only accepted when every account is enabled. |
The guardian groups (equity limits, trading limits, daily reset, trading hours, forced close, news) apply to the SLAVE as well — configure them with this account's prop-firm rules. The old
SlaveTotalProfitLimitPercentwas removed in v2.20: useTotalProfitLimitPercentwithPropFirmMode = trueinstead.
Operation mode = Slave (replicates trades)
File name = master_00001.csv (must match the Master)
Symbol mapping = "EURUSD:EURUSD.pro;US30:US30Cash"
Copy mode = NORMAL
Invert Master trades = true
Lot multiplier = 1.0
Auto lot scaling = true
Allowed slippage = 10
Magic Number = 987654
Slave close closes Master = true
Linking Master ↔ Slave: they are paired solely by
FileName. Leave the default (master_00001.csv) on one Master and its Slave(s) and they connect with no further setup. For a second, independent Master/Slave group on the same machine, set both of its EAs tomaster_00002.csv, and so on.
Active in both modes when PropFirmMode = true (each account enforces its own configured limits). The guardian continuously monitors the account and enforces every configured limit. Equity limits (daily/total) are checked every 200 ms so a fast spike cannot run a full second past a limit; count/streak limits update on every trade event; hours/news on a 1 s cadence. "Trades per day" counts distinct positions (partial fills are one trade; on a Slave, a re-replicated Master ticket is still one trade).
Remember the EA reacts after a threshold is touched and market-closes with slippage — always configure the limits with a safety buffer inside the firm's hard rules (e.g. 4.6% for a 5% rule).
On a Slave, two extra things happen when PropagateSlaveClose = true:
- A breach that closes positions (equity limits, streaks,
CLOSE_ALLnews, forced close) first asks the Master to close the mirrored originals, so the Master and every other Slave flatten with it. - While the Slave has any lock active, it publishes a lock file that makes the Master disable trading too (
SLAVE LOCKon the Master's panel). The Master deletes its pending orders and blocks new entries until every account is enabled again. A locked Slave also refuses to replicate new positions; if one slips through the race window, it requests the Master to close it.
| Limit | Action when hit | Re-enables when |
|---|---|---|
| Total profit/loss (equity) | Closes all positions + deletes pending orders + disables trading. Sticky — stays locked even if equity recovers. | Only by setting ResetCountersOnInit = true and reinitializing. |
| Daily profit/loss (equity) | Closes all positions + deletes pending orders + disables trading. Sticky for the rest of the day. | At the next daily reset. |
| Max trades per day | Blocks new entries + deletes pending orders. Open positions are kept. | At the next daily reset. |
| Max parallel trades | Blocks new entries + deletes pending orders. If the open count exceeds the limit, closes the newest position(s) down to the limit (a position count merely equal to the limit is kept, to avoid open/close churn). | When position count drops below the limit. |
| Consecutive wins / losses | Closes all positions + deletes pending orders + disables trading. | At the next daily reset. |
| Outside trading hours | Blocks new entries + deletes pending orders. | Inside the trading window. |
| Forced close time | Closes all positions + deletes pending orders. | — (one-shot at the configured time). |
"Disabling trading" sets the MT5 Global Variable HCPropsControllerDisableTrading to 1.0. Any EA that checks this variable — such as SQX EAs processed by the patcher — will stop opening new positions while it is set.
- Initial balance (
AccountDepositsAndWithdrawals) = sum of deposits/withdrawals/credits/charges detected from account history (orForceInitialBalanceif you set it). WithHistoryFromDateset (prop-firm account reset), it is instead the balance as of that moment, and every history-based counter ignores older deals. - Daily initial equity = account equity at the daily reset time (or at
HistoryFromDate, if the reset happened mid-day).
Total limits (percent of initial balance):
Total upper = InitialBalance × (1 + TotalProfitLimitPercent / 100)
Total lower = InitialBalance × (1 − TotalLossLimitPercent / 100)
Daily limits use the more conservative of daily equity vs. initial balance as the basis (basis = min(DailyInitialEquity, InitialBalance)):
Daily upper = DailyInitialEquity + basis × DailyProfitLimitPercent / 100
Daily lower = DailyInitialEquity − basis × DailyLossLimitPercent / 100
Using the smaller basis prevents the daily allowance from drifting larger than your account can support after a gain.
One MASTER account broadcasts its open positions to any number of SLAVE accounts running on the same machine/VPS (communication is via a shared file — see How Synchronization Works).
-
Per-ticket mapping. Each Master position is mapped to a Slave position via the order comment
HC<masterTicket>plus the Slave'sMagicNumber, with a GlobalVariable backup per position (HCProps_Map_<slaveTicket>) so the mapping survives brokers that strip/overwrite comments and EA restarts. The Slave only ever manages positions carrying its own magic. -
Lot sizing.
SlaveLot = NormalizeVolume(MasterLot × pointValueRatio × RiskMultiplier), clamped to the symbol's min/max/step. WithAutoLotScaling = truethe point-value ratio (Master$/point ÷ Slave $ /point, from the value the Master writes per line) equalizes money-per-point across brokers with different contract sizes;RiskMultiplieris a pure preference on top. Broker clamps are warned in both directions: down = "hedge coverage reduced", up to the minimum lot = "OVERSIZED hedge".AutoLotScalingassumes both accounts share the same account currency (the Master writes its currency into the file; the Slave warns loudly on mismatch). It is not proportional to balance. -
Slave-close propagation. With
PropagateSlaveClose = true(default), a mirrored position that closes on the Slave by its own SL/TP, a manual close, a stop out, or the Slave profit lock is propagated back: the Slave writes a close request file, the Master closes the original ticket (checked every 200 ms), the sync file updates, and every other Slave flattens. Sync-driven closes (the Master closed first) are never propagated back, so there are no loops. While a request is pending the Slave will not reopen that ticket; if the Master doesn't process it within 120 s (offline, or propagation disabled there) the Slave resumes plain mirroring. -
Distance-based SL/TP. The Slave doesn't copy the Master's absolute SL/TP prices — it copies the distance from the Master's entry and applies it to its own actual fill price. So if the Master enters at 1.04500 with a stop 0.01000 away (1.05500) and the Slave fills at 1.04700 (slippage / different quotes), the Slave's stop is set at 1.05700 — the same distance, preserving the intended risk.
CopyMode = NORMALkeeps re-applying this when the Master moves its SL/TP;INCOGNITOsets it only at open. -
Inverse trading.
InverseMode = true(the default) flips BUY↔SELL and mirrors SL/TP around the entry — the Master's TP distance becomes the Slave's SL, and vice versa. -
Symbol mapping. Use
SymbolMapping(MAST:SLAV;MAST2:SLAV2) when broker symbol names differ. - Volume reduction tracking. If the Master partially closes a position, the Slave reduces its volume to match (reduction only).
-
Per-Slave guardian. The Slave runs the full prop-firm guardian on its own account (see Prop-Firm Guardian); breaches close the Master's originals and lock the Master via
PropagateSlaveClose.
Account type: requires hedging accounts — SLAVE mode refuses to initialize on a netting account (per-ticket mapping would break); MASTER mode warns. The common case is one position per symbol per account.
News interaction: the news filter can run on any account. On the Master, pauses/closes replicate to the Slaves automatically. On a Slave (with
PropagateSlaveClose), a news lock disables the Master too, andCLOSE_ALLcloses the originals everywhere.
Available in both modes. The EA can pause or close trading around economic news using MetaTrader 5's native economic calendar — no email, API, or WebRequest required. It reads the calendar that MetaQuotes already delivers to the terminal. (On a Slave, the Slave broker must serve the calendar too — the EA warns in the log and panel if it doesn't.)
OPERATE— do nothing (filter off).PAUSE_OPEN(recommended) — block new entries and cancel pending orders; keep open positions.CLOSE_ALL— close ALL positions + cancel pending orders + block new entries.
NewsDuration— seconds of protection before and after each event. E.g.120→ protection from 2 min before to 2 min after (a 4-minute window).NewsCurrencies— uppercase, no spaces:EUR,USD,GBP. If left empty, the EA uses the base + profit currency of the chart symbol.NewsMinImpact—LOW/MODERATE/HIGH(default HIGH, high-impact events only).
- The EA queries the calendar on start and refreshes it once per hour.
- It filters events by the chosen currencies and minimum impact.
- When the clock enters the window
[event − NewsDuration, event + NewsDuration], it applies theNewsModeaction. - On leaving the window, it re-enables trading automatically.
The panel shows NEWS ACTIVE: <event> (ends in Xm) in red during protection. The rest of the time it shows News: watching (N) (orange when N is 0 — the broker is probably not serving the calendar) plus the next two events that will pause trading, each as > 14:30 USD CPI m/m (blocks in 1h05m) — orange when the block starts within 30 minutes.
The news filter reads only MT5's native economic calendar — no network requests, no external feeds. Because calendar access from MQL5 is per-broker, check the log/panel after enabling it — see Verifying the calendar works on your broker.
The EA draws an on-chart dashboard with everything important. It only redraws the labels that changed, to avoid flicker.
Both modes show (when PropFirmMode = true): mode (guardian on / sync- or copy-only), the sync file in use, trading status (ENABLED/DISABLED), active locks, initial balance, day-start equity, live equity with daily/total %, configured daily/total limits with color bands, trades today / parallel / win & loss streaks vs. their caps, the trading-hours window, news status with the next two events that will pause trading (and a countdown while a news block is active), the next daily reset, and the forced-close time.
SLAVE adds: invert/multiplier/auto-lots/copy-mode summary and the connection status (CONNECTED / WAITING FOR MASTER).
MASTER adds: a red SLAVE LOCK: <login> (<reason>) line whenever a Slave's lock is currently disabling the Master, and a Slaves alive: N / M required line (green when all expected heartbeats are present, red + (BLOCKING) when a Slave is down).
Color coding (graded by how close you are to a limit):
| Color | Meaning |
|---|---|
| 🟢 Green | OK — below 50% of the limit |
| 🟡 Yellow | Caution — 50–75% of the limit |
| 🟠 Orange | Danger — 75–100% of the limit |
| 🔴 Red | Limit reached / trading blocked |
Connection and status labels also use green for the good state (trading enabled, Master connected, inside trading hours) and red/orange for the bad state.
When PropFirmMode = true, the guardian persists its state in MT5 Global Variables so it survives EA reinitialization, terminal restarts, and VPS reboots:
| Global Variable | Holds |
|---|---|
HCPropsController_InitBalance |
Detected initial balance |
HCPropsController_InitEquityDaily |
Day-start equity |
HCPropsController_NextReset |
Next daily reset timestamp |
HCPropsController_TotalLocked |
Sticky total-lock flag |
HCPropsController_DailyLocked |
Daily equity-lock flag |
HCPropsControllerDisableTrading |
Shared "stop trading" signal (read by patched SQX EAs) |
On startup the EA restores these values. If a daily reset time was missed while the EA was off, it performs the reset immediately. Set ResetCountersOnInit = true to wipe this state and start fresh.
The economic calendar is delivered by MetaQuotes, not your broker, but some brokers/builds restrict access to it from MQL5. The EA verifies it for you — no separate tool needed:
- EA log: with
NewsModeother thanOPERATE, the EA printsNEWS: N news scheduledon start and hourly. If the calendar returns zero events it logs a loudNEWS: WARNING ... ZERO events ... the news filter is effectively INACTIVE!— if you see that on days with obvious news (NFP, CPI, FOMC), the broker is not serving the calendar. - Panel: the dashboard shows
News: watching (N)plus the next upcoming events that will pause trading; ifNstays0, same conclusion. - Interface cross-check: in MT5, View → Toolbox → Calendar. If events are listed there, the terminal has calendar data.
Requirement: the terminal must be connected to a trading server (the calendar syncs from there). In the Strategy Tester the calendar may be limited on older builds.
If your broker doesn't serve the calendar: the news filter cannot work on that terminal (the EA intentionally has no external-feed fallback, to stay fully offline). Options: run the EA on a terminal/broker whose build does serve the MQL5 calendar, or leave NewsMode = OPERATE to disable the news filter while still using the copy-trading and prop-firm features.
If you export Expert Advisors from StrategyQuant (SQX), patch them so they obey HCPropsController's limits. The patcher injects, at the very start of sqHandleTradingOptions(), this check:
// Check global variable to disable trading
if(GlobalVariableGet("HCPropsControllerDisableTrading") == 1.0) return false;While HCPropsController holds that Global Variable at 1.0 (because a risk limit was hit or a news window is active), the patched EA will not open new positions — instead of immediately re-opening what HCPropsController just closed.
A .backup copy of each file is created before it is modified. The patcher is idempotent: files that are already patched, or that have no sqHandleTradingOptions(), are left unchanged. After patching, recompile the resulting .mq5 in MetaEditor and use those instead of the originals.
- Keep
Run-Patcher.batandPatch-SQX-GV-Disable.ps1in the same folder. - Double-click
Run-Patcher.bat. - Choose an option:
- Option 1 — process all
.mq5files in a folder (recursive). - Option 2 — process a single file.
- Option 1 — process all
- Follow the on-screen instructions.
Other ways to run it (Windows):
- Drag & drop a
.mq5file or a folder ontoPatch-SQX-GV-Disable.ps1. - From PowerShell:
.\Patch-SQX-GV-Disable.ps1 -Path "C:\Path\To\Your\Folder" .\Patch-SQX-GV-Disable.ps1 -Path "C:\Path\To\Your\File.mq5"
When it finishes you get a summary of patched, skipped (already patched / no SQX function), and errors.
patch-gv-disable.py injects exactly the same line of code as the Windows patcher. It needs only Python 3 (no external dependencies), and the result is identical — use whichever you prefer.
# Option A — IN-PLACE: patch one file or every .mq5 in a folder (recursive).
# A .backup copy is made before each file is modified.
python3 patch-gv-disable.py /path/to/MQL5/Experts
python3 patch-gv-disable.py /path/to/MyEA.mq5
# Option B — MIRROR: copy SRC into DST, patching along the way.
# Originals in SRC are never touched; DST becomes a full mirror.
python3 patch-gv-disable.py /path/to/MQL5 /path/to/MQL5_PatchedThe exit code is 1 if any file errored, 0 otherwise.
- First patch your SQX-exported EAs with the patcher.
- Then install and configure HCPropsController.
- Finally run your patched EAs alongside HCPropsController.
- Transport: a CSV file in
Common\Files\HCPropsController\on the same machine, named byFileName(or a full path viaCustomFilePath). The Master writes it and its Slave(s) read it — they're linked by using the sameFileName. Run multiple independent groups on one machine by giving each its own file name (master_00001.csv,master_00002.csv, …). - CSV format v2 — a
SEQheader, one line per Master ticket (9 comma-separated fields), and anENDfooter:whereSEQ,<n> ticket,symbol,type,volume,openPrice,sl,tp,openTime,pointValuePerLot END,<n>type:0= BUY,1= SELL;volume= the Master's real lots;openPrice/sl/tp= prices;pointValuePerLot= account-currency value of a 1.0 price move per lot (used byAutoLotScaling). TheopenPriceis what lets the Slave compute SL/TP as a distance from the Master's entry. TheSEQ/ENDpair (a write counter, monotonic across restarts) lets the Slave skip unchanged files and discard torn reads — a file caught mid-write has no matchingENDand is simply re-read 200 ms later. The old 1-second modification-time check (which could miss two writes within the same second) is gone. - Master writes only when something changes (a content hash covering ticket, symbol, type, volume, SL, TP is compared each tick, and on every trade transaction). It also force-syncs immediately when a position opens or changes.
- Slave reads the header every 200 ms (full re-parse only when
SEQchanged) and reconciles its positions against the cached targets every tick, so failed opens and failed SL/TP modifications are retried automatically:- closes Slave positions the Master no longer has,
- reopens a position whose direction changed,
- reduces volume to match a Master partial close,
- sets/updates SL/TP as a distance from the Master's entry applied to the Slave's own fill price (re-applied each tick in
NORMALmode; inINCOGNITOset at open and re-tried only while the position has no levels at all), - opens any Master position it does not have yet (tagged with
HC<masterTicket>; failed opens retry every ~1.5 s).
- Slave status files (Slave → Master): each Slave maintains
<syncfile>.slave.<login>, rewritten every second (and immediately on changes):The Master reads allHB,<timestamp> ← heartbeat (machine-local clock, shared by both terminals) LOCK,<0|1>,<active lock flags> ← this Slave's guardian state CLOSE,<masterTicket>,<reason> ← 0..n pending close requests END,<timestamp> ← torn-read marker<syncfile>.slave.*every 200 ms and: executes the CLOSE requests (idempotent and retried — a request line stays in the file until the ticket disappears from the sync file, which is the natural ack, so a temporarily failed close is retried instead of lost); treats anyLOCK,1as "block new entries"; and counts fresh heartbeats. Torn reads keep the previous cached state for that Slave. - Dead-Slave detection (
ExpectedSlaves): setExpectedSlaveson the Master to the number of Slaves that must be alive. If fewer than that many status files have a heartbeat younger thanSlaveHeartbeatTimeoutSec, the Master blocks new entries (SlaveDownlock, redSlaves aliveline on the panel) — a crashed/hung Slave terminal can no longer leave new Master trades unhedged. Removing a Slave EA from its chart deletes its status file; withExpectedSlavesstill counting it, the Master stays blocked until you adjust the input (intended: removing a hedge leg should be a deliberate, two-step act). - Trade log: with
TradePairLog = trueevery account appends one line per closed position to<syncfile>.trades.<login>.csv(time, M/S, masterTicket, position, symbol, side, volume, close price, profit, swap, commission, close reason). Join the Master's and a Slave's file onmasterTicketto measure the per-pair hedge leakage directly. - Disconnect detection: the Master deletes its sync file on shutdown; the Slave then shows
WAITING FOR MASTER. Close requests persist in the Slave status files while the Master is offline and are processed when it returns. - Duplicate-Master protection: a per-
FileNamechart mutex refuses a second Master in the same terminal, and a foreignSEQin the sync file (another terminal writing it) is detected and logged loudly.
Upgrading from v2.00: the file format changed — update the EA on the Master and every Slave at the same time (an old Slave cannot parse a v2 file and vice versa). If you had set
RiskMultiplierto compensate for a contract-size difference (e.g.0.5because the Slave's index contract is worth twice as much per point), set it back to1.0:AutoLotScalingnow handles that per symbol, and a leftover manual multiplier would halve every other symbol's hedge.Upgrading to v2.20: the guardian inputs (equity/trading limits, hours, forced close, news) are now active on Slaves and load with their defaults the first time the new build attaches. Review every Slave's inputs after updating: either configure that account's actual prop-firm rules, or set
PropFirmMode = falseon the Slave to keep the old copy-only behavior.SlaveTotalProfitLimitPercentwas removed — useTotalProfitLimitPercentinstead.Upgrading to v2.30: the v2.20
.close.<login>/.lock.<login>side files are replaced by the.slave.<login>status file (leftovers are cleaned automatically on init). SLAVE mode now requires a hedging account (init fails on netting). Recommended: setExpectedSlaveson the Master to your actual number of Slaves — it is the only protection against a silently dead Slave terminal.
Q: Can I use the EA without patching my SQX EAs? A: Yes, but your EAs won't stop automatically when a limit is reached — only HCPropsController's own actions (closing positions, deleting pendings) apply.
Q: What happens when I hit a limit?
A: For equity limits and forced close, the EA closes all positions, deletes pending orders, and disables trading until the appropriate reset (daily, or ResetCountersOnInit for the sticky total lock). For count/streak/hours limits, it blocks new entries and removes pending orders but keeps open positions.
Q: Can I connect multiple SLAVE accounts to one MASTER?
A: Yes — as many Slaves as you want, all reading the same Master file. Give each Slave a unique MagicNumber within the same terminal.
Q: Does the Slave copy the exact same volume?
A: With AutoLotScaling = true it copies the volume that gives the same money-per-point as the Master (so a Slave broker whose contract is worth 2× per point trades half the lots), times RiskMultiplier (1.0 = same), normalized to the Slave symbol's lot step. If the broker's lot limits clamp the result, a "hedge coverage reduced" warning is logged.
Q: What happens when the Slave's own SL/TP is hit before the Master's?
A: With PropagateSlaveClose = true (default), the Slave asks the Master to close the original position immediately (the Master polls every 200 ms), and every other Slave flattens as soon as the sync file updates. With false, the Slave keeps mirroring the file and would reopen the position on the next change.
Q: Can I use the EA on a single account, without copy trading?
A: Yes — set Mode = NONE. The full guardian (equity/count/streak/hours/forced close) and the news filter run on that account, gating your order-placing EA through the usual HCPropsControllerDisableTrading global variable, and no shared files are created (no sync file, no status file, no trade log).
Q: My prop firm "reset" my account (balance back to the original, history kept). What do I do?
A: Set HistoryFromDate to any moment after your last pre-reset trade (the exact timestamp of the firm's balance-correction deal doesn't matter — corrections count as baseline, not P/L) and reinitialize with ResetCountersOnInit = true once (then back to false). The EA then treats the account as if it started at that moment: the initial balance is the reset amount, and old trades no longer count toward the daily baseline or the trade/streak counters. The log prints the computed baseline: HistoryFromDate: initial balance = ... — verify it matches the reset amount.
Q: What happens if a Slave terminal crashes or hangs?
A: Its heartbeat in <syncfile>.slave.<login> goes stale. With ExpectedSlaves set on the Master, the Master blocks new entries within ~SlaveHeartbeatTimeoutSec seconds and shows a red Slaves alive line — no new trade can be opened unhedged. Existing positions are still protected by the broker-side SL/TP that both legs always carry. When the Slave comes back, its heartbeat resumes and the Master unblocks automatically.
Q: What happens when a Slave hits one of its own limits?
A: The Slave's guardian acts on its own account exactly like on the Master (close positions for equity/streak breaches, block entries for count/hours breaches). With PropagateSlaveClose = true it also closes the originals on the Master (for closing breaches) and keeps the Master's trading disabled until the Slave's lock clears — so no account ever trades while another is locked.
Q: Does the news filter work without internet / a server?
A: It uses MT5's native calendar (no backend, login, or network requests). If your broker doesn't serve the calendar, the EA logs a loud NEWS: WARNING ... ZERO events and the panel shows News: watching (0) — in that case leave NewsMode = OPERATE; the rest of the EA still works.
Q: What does "0 = no limit" mean?
A: Setting 0 on any limit disables that limit entirely.
Q: How does a Slave know which Master to follow?
A: Purely by FileName — set the Slave's FileName to the same value as its Master (default master_00001.csv). No server name or account number is involved.
- Works with MetaTrader 5 only.
- The Windows patcher requires PowerShell; on Linux/macOS use the Python patcher.
- Risk limits are computed from the account's detected initial balance (or
ForceInitialBalance). - The EA's internal timer runs every 200 ms (sync, close requests, equity limits, heartbeats); count/hours/news checks and the panel update every second.
- Copy trading requires the Master and Slave terminals to share the same
Common\Files(i.e. run on the same machine/VPS). - After editing any
.mq5, recompile it in MetaEditor (F7).
If you run into issues:
- Check the Experts and Journal tabs in MetaTrader 5 for messages.
- Verify all parameters are set correctly (especially the Master/Slave linking — both must use the same
FileName). - Make sure files are in the correct folders and the EAs are compiled.
- For news, check the Experts log for
NEWS: N news scheduled(aZERO eventswarning means the broker doesn't serve the calendar).
Version: 2.0