Neuro-Structural Trading Engine — NSTE (Part I): How to Build a Prop-Firm-Safe Multi-Account System
Introduction
If you trade cryptocurrency CFDs on proprietary firm accounts, you already know the three ways the market can end your day before it starts: a single volatile candle blows through your ATR-based stop and wipes out your daily loss limit, your script switches between accounts and silently kills open positions, or a choppy sideways market grinds your edge to nothing with dozens of small losses. This article solves all three problems.
This is the first article in a 19-part series documenting Neuro-Structural Trading Engine, a multi-account algorithmic trading system designed to trade cryptocurrency CFDs (BTCUSD, ETHUSD) across multiple prop firm accounts simultaneously. The system combines LSTM neural networks, compression-based regime detection, and biology-inspired adaptive algorithms into a unified trading framework.
This article is for algorithmic traders who need a reliable foundation for running automated strategies across multiple prop firm accounts without breaching drawdown rules. By the end, you will have a working process architecture, a fixed-dollar risk formula, a noise filter that keeps you out of bad markets, and a complete Expert Advisor skeleton you can compile and test in Strategy Tester today.
The system was built with three non-negotiable principles:
Principle 1: Stop Loss is Sacred
Every trade risks a fixed dollar amount ($1.00). Not a percentage of price. Not an ATR multiplier. A hard dollar value. The lot size adjusts to make the SL distance equal exactly $1.00 of risk.
Formula:
lot = MAX_LOSS_DOLLARS / (sl_distance_points * tick_value)
This prevents the catastrophic $500+ losses that ATR-based stops can produce in volatile crypto markets. When Bitcoin moves $2,000 in minutes, an ATR-based stop can blow through your entire daily loss limit in a single trade. A fixed dollar stop ensures that regardless of how volatile the market becomes, you never lose more than your predetermined amount.
Principle 2: One Script Per Account
The MetaTrader 5 Python API (MetaTrader 5 package) is a singleton. Calling mt5.login() to switch accounts kills all open trades on the current terminal. Each prop firm account runs its own dedicated Python process that connects to its own MetaTrader 5 terminal instance. This architectural decision was born from a painful lesson: attempting to manage multiple prop firm accounts from a single script led to trades being silently closed when the script switched between accounts.
Principle 3: Centralized Config, Decentralized Execution
All trading parameters live in MASTER_CONFIG.json . Every script imports values through config_loader.py . No hardcoded trading values exist in any execution script. This prevents accidental changes to risk parameters. When you are running live money across six different prop firm accounts, the last thing you want is a stray edit changing your risk from $1.00 to $10.00 per trade.
The One-Script-Per-Account Architecture
Each "BRAIN" script runs an independent process connected to its own MetaTrader 5 terminal:
// --- Architecture Diagram: One-Script-Per-Account ---
+-------------------+ +-------------------+ +-------------------+
| BRAIN_Account_A | | BRAIN_Account_B | | BRAIN_Account_C |
| Process 1 | | Process 2 | | Process 3 |
+--------+----------+ +--------+----------+ +--------+----------+
| | |
v v v
+-------------------+ +-------------------+ +-------------------+
| MT5 Terminal 1 | | MT5 Terminal 2 | | MT5 Terminal 3 |
+-------------------+ +-------------------+ +-------------------+
Each BRAIN script runs a 60-second loop:
- Fetch 100 bars of 1-minute data from the MetaTrader 5 terminal
- Calculate 8 technical features (RSI, MACD, Bollinger Bands, etc.)
- Check market regime via compression ratio analysis
- Get LSTM prediction (BUY/SELL/HOLD) with confidence score
- Execute trade if signal passes all filters and confidence threshold
- Manage open positions (partial close at 50% TP, rolling stop loss)
- Sleep 60 seconds, repeat the entire cycle
The following diagram illustrates the complete architecture:

Figure 1. Three independent BRAIN processes each connect to a dedicated MetaTrader 5 terminal instance for complete process isolation
This architecture scales horizontally. Adding a new prop firm account means adding one new BRAIN script and one new MetaTrader 5 terminal instance. No existing processes are affected.
LSTM Neural Network
The core prediction engine uses a stacked LSTM (Long Short-Term Memory) architecture. LSTMs are a type of recurrent neural network specifically designed to learn long-term dependencies in sequential data, making them well-suited for time series prediction in financial markets.
Architecture specifications:
- Input: 8 features x 30 time steps = 240 inputs per prediction
- LSTM Layer 1: 128 hidden units with tanh activation
- LSTM Layer 2: 128 hidden units with tanh activation
- Dropout: 40% between layers to prevent overfitting
- Output: 3 classes (BUY, SELL, HOLD) via Softmax probability distribution
The model is trained offline using walk-forward methodology and exported as .pth files (PyTorch). During live trading, inference runs on CPU because DirectML (AMD GPU) does not support LSTM backward pass through its kernel. Forward pass inference on CPU takes less than 10ms per prediction, which is more than adequate for our 60-second trading loop.
Training uses a 6-component fitness function that balances multiple objectives:
- Win rate (Bayesian posterior with Beta(10,10) prior to handle small samples)
- Profit factor (average win / average loss, must exceed 1.5)
- Sharpe ratio (risk-adjusted return, annualized)
- Max drawdown penalty (exponential penalty as drawdown approaches limits)
- Trade count (minimum 30 observations required for statistical significance)
- Consistency score across walk-forward windows (penalizes overfitting to one period)
The Bayesian prior of Beta(10,10) is crucial. Without it, a model that takes 2 trades and wins both would show a 100% win rate. The Beta prior pulls the posterior toward 50%, requiring substantial evidence before the win rate estimate moves significantly away from the baseline.
Compression-Based Regime Detection
The core insight behind the regime detection system is elegant in its simplicity:
Structured data compresses well. Random data compresses poorly.
If price action has a detectable pattern (trending, mean-reverting, or otherwise structured), the data will compress to a smaller size because the compression algorithm can find repeating patterns. If price action is random noise (choppy, directionless market), compression achieves very little because there are no patterns to exploit.
The algorithm implementation is straightforward:
- Take the last 100 closing prices from the 1-minute chart
- Convert to bytes using Python's struct.pack
- Compress with zlib at maximum compression level 9
- Calculate: ratio = len(original_bytes) / len(compressed_bytes)
The compression ratio tells us how much structure exists in the current price action:
// --- Regime Classification Thresholds --- ratio >= 3.5 -> CLEAN regime -> Market is structured, TRADE ratio >= 2.5 -> VOLATILE regime -> Moderate structure, HOLD ratio < 2.5 -> CHOPPY regime -> Random noise, HOLD
The three regime zones and their trading implications:

Figure 2. Compression-Based Regime Detection. The three regime zones (CLEAN, VOLATILE, CHOPPY) determined by compression ratio thresholds. Only CLEAN regime permits trading
Only trades during CLEAN regime. This single filter eliminates a massive percentage of losing trades that occur in choppy conditions. In backtesting, the compression filter alone improved the system's win rate by approximately 12 percentage points compared to trading in all regimes.
The beauty of this approach is that it is completely model-agnostic. It does not care about indicators, patterns, or any specific market theory. It simply measures whether the current price data contains exploitable structure, regardless of what form that structure takes.
Fixed Dollar Risk Management
The risk management system is designed around a single immutable rule: no trade can lose more than $1.00. Everything else flows from this constraint.
Per-Trade Risk Parameters:
- Maximum loss: $1.00 per trade (absolute ceiling)
- Initial SL: $0.60 (starting stop loss distance in dollars)
- Rolling SL: Divides stop distance by 1.5x as price moves favorably
- Final SL: $1.00 (maximum stop distance after all rolling adjustments)
- TP = 3x SL distance (risk:reward ratio of 1:3)
The two-stage profit extraction mechanism in action:

Figure 3. Two-Stage Profit Extraction. At 50% of TP distance, half the position closes and the stop moves to breakeven. The remaining half runs to full TP with zero risk
Dynamic Take Profit System: At 50% of the TP distance, the system closes half the position. After this partial close, the stop loss moves to breakeven (entry price). The result is guaranteed profit from the closed half, plus a "free runner" that can continue to accumulate gains with zero downside risk. This mechanism transforms every winning trade into a two-stage profit extraction process.
Prop Firm Safety Limits:
- Daily loss limit: 5% of account balance
- Maximum drawdown: 10% of account balance from peak equity
- Profit target: 10% of account balance
When any limit is approached within a safety margin, the BRAIN stops trading entirely for that account. This ensures we never breach a prop firm rule, which would result in account termination and loss of the funded capital.
Feature Engineering Pipeline
The LSTM receives 8 features calculated from raw 1-minute OHLCV data. Each feature was selected to capture a different aspect of market microstructure:
| Feature | Calculation | Purpose |
|---|---|---|
| RSI(14) | Relative Strength Index, 14-period | Overbought/Oversold detection |
| MACD | EMA(12) - EMA(26) | Trend direction and momentum |
| MACD Signal | EMA(9) of MACD line | Trend change confirmation |
| BB Upper | SMA(20) + 2*StdDev | Upper volatility boundary |
| BB Lower | SMA(20) - 2*StdDev | Lower volatility boundary |
| Momentum(10) | Close - Close[10] | Raw price momentum |
| ROC(10) | (Close-Close[10])/Close[10] | Percentage rate of change |
| ATR(14) | Average True Range, 14-period | Current volatility measurement |
Normalization uses Global Z-score: subtract the dataset mean and divide by standard deviation. This ensures all features are scale-invariant across instruments. Without normalization, ATR values for BTCUSD (which can be hundreds of dollars) would dominate features like RSI (which ranges 0-100).
MQL5 Implementation
The MQL5 side handles trade execution. The Python side handles intelligence (LSTM inference, regime detection, signal generation). Communication between the two is via JSON signal files written by Python and read by the MQL5 Expert Advisor running on the chart.
Below are the key implementation details of the Expert Advisor. The complete source code is attached to this article for download.
Input Parameters and Risk Settings
The EA begins with input parameters that mirror the MASTER_CONFIG.json settings. These allow the trader to adjust risk parameters directly from the MetaTrader 5 interface:
input group "=== Core Risk Settings ===" input double InpMaxLossDollars = 1.00; // Max Loss per Trade ($) input double InpInitialSL = 0.60; // Initial SL ($) input double InpTpMultiplier = 3.0; // TP = Nx SL Distance input double InpRollingSLMult = 1.5; // Rolling SL Divider input int InpDynamicTpPct = 50; // Dynamic TP Trigger (%) input bool InpUseDynamicTp = true; // Enable Dynamic TP input bool InpUseRollingSL = true; // Enable Rolling SL input double InpConfidenceThresh = 0.70; // Min Confidence to Trade input group "=== Drawdown Limits ===" input double InpDailyDDLimit = 4.5; // Daily DD Limit % input double InpMaxDDLimit = 9.0; // Max DD Limit %
Fixed Dollar Lot Size Calculation
The core risk formula calculates the exact lot size needed to risk exactly $1.00 at the given stop loss distance. This is the most critical function in the entire system:
// CalculateLotSize - determines exact lot size to risk InpMaxLossDollars // symbol - the trading instrument (e.g. "BTCUSD") // slDistPoints - stop loss distance in price points // returns - lot size clamped to broker min/max limits double CalculateLotSize(string symbol, double slDistPoints) { // Query broker for instrument specifications at runtime double tickVal = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); if(tickVal <= 0 || slDistPoints <= 0) return minLot; // (tickVal / tickSize) = dollar value per one point of price movement // So: slDistPoints * (tickVal / tickSize) = total dollar loss per lot // Dividing maxLoss by that gives the lot size for exact risk control // // Example: BTCUSD, SL = 50 points, tickVal = $0.01, tickSize = 0.01 // valuePerPoint = 0.01 / 0.01 = $1.00 per point per lot // dollarRisk = 50 * 1.00 = $50.00 per lot // lot = 1.00 / 50.00 = 0.02 lots -> risks exactly $1.00 double lot = InpMaxLossDollars / (slDistPoints * (tickVal / tickSize)); // Round DOWN to nearest lot step (never round up to avoid exceeding risk) lot = MathFloor(lot / lotStep) * lotStep; // Clamp to broker min/max volume limits if(lot < minLot) lot = minLot; if(lot > maxLot) lot = maxLot; return lot; }
This function queries the broker for tick value and tick size at runtime, ensuring correct lot sizing across any instrument. The MathFloor rounding ensures we never accidentally exceed our risk budget due to rounding up.
Drawdown Safety Check
Before every trading decision, the EA checks both daily drawdown and maximum drawdown against prop firm limits:
bool IsDrawdownSafe() { double equity = AccountInfoDouble(ACCOUNT_EQUITY); double balance = AccountInfoDouble(ACCOUNT_BALANCE); // Daily drawdown check double dailyDD = (g_dailyStartBalance - equity) / g_dailyStartBalance * 100.0; if(dailyDD >= InpDailyDDLimit) { Print("DAILY DD LIMIT REACHED: ", DoubleToString(dailyDD, 2), "%"); return false; } // Max drawdown check (from peak balance) if(balance > g_peakBalance) g_peakBalance = balance; double maxDD = (g_peakBalance - equity) / g_peakBalance * 100.0; if(maxDD >= InpMaxDDLimit) { Print("MAX DD LIMIT REACHED: ", DoubleToString(maxDD, 2), "%"); return false; } return true; }
The daily drawdown is calculated from the balance at the start of the trading day. The maximum drawdown tracks the high-water mark of the account balance. When either limit is reached, the function returns false and the EA ceases all trading activity until conditions improve.
Position Management: Partial Close and Rolling Stop Loss
The ManagePositions function implements the two-stage profit extraction system. It iterates through all open positions belonging to this EA (filtered by magic number) and applies dynamic take profit and rolling stop loss logic:
void ManagePositions() { for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket <= 0) continue; if(PositionGetInteger(POSITION_MAGIC) != InpMagic) continue; double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double curPrice = PositionGetDouble(POSITION_PRICE_CURRENT); double volume = PositionGetDouble(POSITION_VOLUME); long type = PositionGetInteger(POSITION_TYPE); // Calculate profit distance from entry double profitDist = 0; if(type == POSITION_TYPE_BUY) profitDist = curPrice - openPrice; else profitDist = openPrice - curPrice; double slDist = g_tracks[idx].initialSLDist; double tpDist = slDist * InpTpMultiplier; // Stage 1: Partial close at 50% of TP distance if(InpUseDynamicTp && !g_tracks[idx].partialClosed) { double trigger = tpDist * InpDynamicTpPct / 100.0; if(profitDist >= trigger) { // --- Simplified logic (full implementation in attached EA) --- // 1. Close half the position via OrderSend(TRADE_ACTION_DEAL) // 2. Move SL to breakeven (entry price) via OrderSend(TRADE_ACTION_SLTP) // 3. Set partialClosed = true to prevent repeat execution } } // Stage 2: Rolling SL tightens as price moves favorably if(InpUseRollingSL && profitDist > 0) { double newSLDist = slDist / InpRollingSLMult; // --- Simplified logic (full implementation in attached EA) --- // Calculate new SL price, only modify if tighter than current SL } } }
The partial close mechanism is particularly powerful for prop firm trading. By closing half the position at 50% of the take profit target and moving the stop to breakeven, every winning trade that reaches this threshold becomes a guaranteed profit. The remaining "free runner" can continue to the full TP target or beyond, with zero risk of giving back the gains.
Results and Performance Considerations
The foundation architecture has been running live across multiple prop firm accounts since January 2026. Key performance characteristics include:
- Risk per trade: Exactly $1.00, never exceeded
- Compression filter: Eliminates approximately 60-70% of potential trades, focusing only on structured market conditions
- Partial close rate: Approximately 40% of winning trades reach the 50% TP threshold for partial close
- Drawdown compliance: Zero prop firm rule violations across all accounts
- Architecture scalability: Successfully running 6+ accounts simultaneously with independent process isolation
The most important metric is the last one: zero rule violations. In prop firm trading, survival comes before profitability. A system that consistently avoids breaching drawdown limits will eventually pass challenges and maintain funded accounts, while a more profitable system that occasionally violates rules will lose everything.
Complete EA Skeleton
The following minimal skeleton shows how all the components discussed above connect within the standard MetaTrader 5 EA lifecycle. The complete implementation with full trade execution logic is provided in the attached .mq5 file.
//+------------------------------------------------------------------+ //| Article_01_EA.mq5 | //| Neuro-Structural Trading Engine - Foundation | //+------------------------------------------------------------------+ #property copyright "QuantumChildren Trading Systems" #property version "1.00" input double InpMaxLossDollars = 1.00; // Max Loss per Trade ($) input double InpInitialSL = 0.60; // Initial SL ($) input double InpTpMultiplier = 3.0; // TP = Nx SL Distance input double InpDailyDDLimit = 4.5; // Daily DD Limit % input double InpMaxDDLimit = 9.0; // Max DD Limit % input int InpMagic = 212001;// Magic Number double g_dailyStartBalance, g_peakBalance; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { g_dailyStartBalance = AccountInfoDouble(ACCOUNT_BALANCE); g_peakBalance = g_dailyStartBalance; Print("Foundation EA initialized. Balance: $", DoubleToString(g_dailyStartBalance, 2)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert tick function - main trading loop | //+------------------------------------------------------------------+ void OnTick() { // Step 1: Safety check - are we within prop firm drawdown limits? if(!IsDrawdownSafe()) return; // Step 2: Manage existing positions (partial close + rolling SL) ManagePositions(); // Step 3: Generate or read trading signal // (signal generation via indicators shown in attached EA) // Step 4: Calculate lot size for fixed dollar risk // double lots = CalculateLotSize(_Symbol, slDistance); // Step 5: Execute trade if signal passes all validation // (full execution logic in attached EA) } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Print("Foundation EA stopped. Reason: ", reason); }
Testing in Strategy Tester
To test the attached EA in the MetaTrader 5 Strategy Tester:
- Open MetaEditor (F4) and compile the attached Article_01_EA.mq5 file (F7).
- In MetaTrader 5, open the Strategy Tester panel (Ctrl+R).
- Select the compiled EA from the Expert Advisor dropdown.
- Set the symbol to BTCUSD and timeframe to M1 (1 Minute).
- Set the testing model to "Every tick based on real ticks" for maximum accuracy.
- Set the date range to at least one month of recent data.
- Set the initial deposit to match your prop firm account size (e.g., $100,000).
- Click "Start" to run the backtest.
Key parameters to verify in the Settings tab before running:
| Parameter | Default | Description |
|---|---|---|
| InpMaxLossDollars | 1.00 | Maximum dollar risk per trade |
| InpInitialSL | 0.60 | Starting stop loss distance in dollars |
| InpTpMultiplier | 3.0 | Take profit as multiple of SL distance |
| InpDailyDDLimit | 4.5 | Daily drawdown halt threshold (%) |
| InpMaxDDLimit | 9.0 | Maximum drawdown halt threshold (%) |
After the test completes, review the Results, Graph, and Report tabs. The equity curve should show controlled drawdowns consistent with the $1.00 fixed risk per trade.

Figure 4. Strategy Tester Report. Backtest results for BTCUSD M1 showing trade statistics, profit factor, and drawdown metrics

Figure 5. Equity Curve. The balance and equity lines during the backtest period, showing controlled drawdowns consistent with $1.00 fixed risk per trade
How to Use- Open the attached .mq5 file in MetaEditor and press F7 to compile.
- In MetaTrader 5, open Navigator (Ctrl+N), find the EA under Expert Advisors, and drag it onto a BTCUSD or XAUUSD M1 chart.
- In the EA properties dialog, configure the input parameters to match your account risk rules. At minimum, verify InpMaxLossDollars, InpDailyDDLimit, and InpMaxDDLimit.
- Click the AutoTrading button in the MetaTrader 5 toolbar to enable algorithmic trading.
- Start the Python signal engine in a separate terminal window so the EA can read signal files.
- Monitor the Experts tab at the bottom of MetaTrader 5 for trade execution logs and signal status messages.
Recommended timeframe: M1 (1 Minute). The EA reads signals generated at 60-second intervals by the Python backend.
What You Now Have
After reading this article, you have the following concrete artifacts ready to use:
- A process architecture diagram — one dedicated Python script and one dedicated MetaTrader 5 terminal per prop firm account, with no shared state between them.
- A fixed-dollar lot sizing function ( CalculateLotSize ) — paste this into any EA to guarantee that no single trade can lose more than your specified dollar amount, regardless of instrument volatility.
- A compression-based regime filter — three lines of logic that measure whether the current market has exploitable structure, eliminating 60-70% of losing trades in choppy conditions.
- A drawdown safety check ( IsDrawdownSafe ) — call this before every trade decision to ensure you never breach a prop firm daily or maximum drawdown limit.
- A two-stage profit extraction system — partial close at 50% of TP plus rolling stop loss, turning winning trades into guaranteed profit with a free runner.
- A complete EA skeleton — compile the attached .mq5 file in MetaEditor, attach it to a chart, and test it in Strategy Tester immediately.
Five parameters you should not change without understanding the consequences:
- InpMaxLossDollars — increasing this multiplies your worst-case loss per trade
- InpDailyDDLimit — setting this above your prop firm's actual daily limit will get your account terminated
- InpMaxDDLimit — same as above for maximum drawdown
- InpTpMultiplier — values below 2.0 destroy the risk:reward ratio that makes the system profitable
- InpDynamicTpPct — setting this too high means partial closes rarely trigger, removing the guaranteed-profit mechanism
Success criteria when testing in Strategy Tester: The backtest should show no single trade losing more than InpMaxLossDollars, daily drawdown never exceeding InpDailyDDLimit percent, and the equity curve should display controlled, shallow drawdowns rather than sharp vertical drops.
Conclusion
This foundation provides five core capabilities that every subsequent article in the series builds upon:
- Fixed dollar risk that prevents catastrophic losses regardless of market volatility
- Clean regime detection via compression ratio that avoids choppy, unprofitable markets
- LSTM neural network intelligence for directional prediction with confidence scoring
- Two-stage profit extraction through partial close and rolling stop loss
- Prop firm safety limits integrated into every decision cycle
The system runs across 6+ prop firm accounts simultaneously, each with its own dedicated process and MetaTrader 5 terminal. The centralized configuration ensures all accounts share the same risk parameters without any hardcoded values leaking into execution scripts.
In the next article, we introduce Jardine's Gate — the six-gate quantum filter that sits between signal generation and trade execution. This filter achieved a remarkable improvement in trade quality by requiring signals to pass through six independent validation gates before execution is permitted.
The complete Expert Advisor source code implementing everything discussed in this article is attached for download. It compiles directly in MetaEditor 5 and can be attached to any chart for testing in the Strategy Tester.
Warning: All rights to these materials are reserved by MetaQuotes Ltd. Copying or reprinting of these materials in whole or in part is prohibited.
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.
The MQL5 Standard Library Explorer (Part 10): Polynomial Regression Channel
MQL5 Trading Tools (Part 24): Depth-Perception Upgrades with 3D Curves, Pan Mode, and ViewCube Navigation
Neural Networks in Trading: Dual Clustering of Multivariate Time Series (Final Part)
Integrating MQL5 with Data Processing Packages (Part 8): Using Graph Neural Networks for Liquidity Zone Recognition
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use