2026-10-30 07:19:59 +07:00
//+------------------------------------------------------------------+
//| UQ_Risk.mqh |
//| Universal Quant EA - centralized account risk controller |
//| |
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
//| All three account-level thresholds are evaluated here, in the |
2026-10-30 07:19:59 +07:00
//| priority order required by the specification: |
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
//| 1. static-drawdown and equity-target permanent locks |
//| 2. daily-loss lock |
//| 3. baseline / persistent-state validity |
//| 4. persistence health (a risk event that cannot be saved must |
//| never be forgotten after a restart) |
2026-10-30 07:19:59 +07:00
//| A risk event always outranks a trading signal. |
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
//| |
//| A new risk cycle - and therefore a new B0 - is only ever |
//| created by an explicit owner authorization. A missing, empty, |
//| truncated, corrupt or foreign state file is never reinterpreted |
//| as a fresh installation. |
2026-10-30 07:19:59 +07:00
//+------------------------------------------------------------------+
# ifndef UQ_RISK_MQH
# define UQ_RISK_MQH
# include "UQ_Defs.mqh"
# include "UQ_State.mqh"
//+------------------------------------------------------------------+
//| Risk controller configuration |
//+------------------------------------------------------------------+
struct UQRiskConfig
{
2026-10-30 08:52:18 +07:00
ulong magic ; // portfolio magic: decides order/position ownership
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
string portfolio ; // EA portfolio identifier
double balanceOverride ; // explicit owner-declared B0
double dailyLimitPct ; // default 5.0
double staticLimitPct ; // default 8.0
double targetPct ; // default 10.0
ENUM_UQ_RESET_REQUEST resetRequest ; // owner reset request
string resetToken ; // confirmation string
2026-10-30 08:37:46 +07:00
double resetBaseline ; // explicit B0 of the new risk cycle
string resetNonce ; // unique nonce of this reset operation
bool resetPreconditionsOk ; // caller-verified flat account scope
string resetPreconditionDetail ; // reason when the scope is not clear
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
bool allowFirstInit ; // owner authorizes a new risk cycle
bool allowBackupRestore ; // owner authorizes backup recovery
2026-10-30 07:19:59 +07:00
} ;
2026-10-30 08:52:18 +07:00
//+------------------------------------------------------------------+
//| Aggregate exposure of the portfolio, in deposit-currency money. |
//| |
//| One authoritative calculation covers every form the exposure can |
//| take: |
//| * stop-loss risk of the EA's open positions; |
//| * stop-loss risk of the EA's pending orders; |
//| * money still reserved by an accepted entry that has not yet |
//| been reconciled with the broker state. |
//| |
//| An owned position or pending order without a protective stop, or |
//| one whose profit cannot be converted into the deposit currency, |
//| makes the exposure unbounded: the caller must then refuse new |
//| entries instead of assuming zero risk. |
//+------------------------------------------------------------------+
struct UQExposure
{
double positions ; // stop-loss risk of owned open positions
double pending ; // stop-loss risk of owned pending orders
double reserved ; // money held by an unreconciled entry order
int positionCount ;
int pendingCount ;
bool bounded ; // false when any part of the exposure is unknown
string detail ; // what could not be quantified
double Total ( void ) const { return ( positions + pending + reserved ) ; }
} ;
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
//+------------------------------------------------------------------+
//| Maximum length of the unbounded-exposure diagnostic text |
//+------------------------------------------------------------------+
# define UQ_EXPOSURE_DETAIL_MAX_CHARS 480
//+------------------------------------------------------------------+
//| Record one unquantifiable exposure item with a bounded reason |
//+------------------------------------------------------------------+
void UQExposureNote ( UQExposure & out , const string symbol , const ulong ticket ,
const string reason )
{
out . bounded = false ;
if ( StringLen ( out . detail ) > = UQ_EXPOSURE_DETAIL_MAX_CHARS )
return ;
out . detail + = StringFormat ( " %s#%s(%s) " ,
( StringLen ( symbol ) > 0 ? symbol : " ? " ) ,
IntegerToString ( ( long ) ticket ) ,
( StringLen ( reason ) > 0 ? reason : " unquantifiable " ) ) ;
}
//+------------------------------------------------------------------+
//| Short, display-safe form of an unbounded-exposure diagnostic |
//+------------------------------------------------------------------+
string UQExposureBrief ( const string detail , const int maxLen = 160 )
{
if ( StringLen ( detail ) < = maxLen )
return ( detail ) ;
return ( StringSubstr ( detail , 0 , maxLen ) + " ... " ) ;
}
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
//+------------------------------------------------------------------+
//| Broker evidence for one outstanding entry reservation. |
//| |
//| Correlation is deliberately narrow. A reservation is proven |
//| executed only when either its own order ticket is still an active |
//| order, or a deal whose DEAL_ORDER is that ticket can be found. |
//| Any other position or pending order carrying the same Magic Number |
//| is unrelated exposure, and its presence is never evidence that |
//| this request produced it. |
//+------------------------------------------------------------------+
struct UQReserveEvidence
{
bool connected ; // the broker can be queried
bool orderLive ; // the request is still an active order
ulong liveOrder ; // active order ticket
int dealCount ; // deals traceable to the reservation
int positionCount ; // owned positions carrying the traced identifier
int unrelatedCount ; // owned positions that are NOT this request
ulong dealTicket ; // first traced deal ticket
ulong positionId ; // position identifier traced from a deal
bool ambiguous ; // more than one candidate: never guess
bool noExposureProven ; // the order history proves nothing executed
string detail ; // bounded diagnostic
} ;
//+------------------------------------------------------------------+
//| Collect the broker evidence of one reservation. |
//| |
//| Every field is evidence, never an assumption: the order pool, the |
//| deal history keyed by DEAL_ORDER/DEAL_TICKET and |
//| POSITION_IDENTIFIER are the only accepted links. A missing link |
//| leaves the reservation unresolved instead of guessing. |
//+------------------------------------------------------------------+
void UQReserveCorrelate ( const ulong magic , UQRiskState & st , UQReserveEvidence & ev )
{
ev . connected = ( ( bool ) TerminalInfoInteger ( TERMINAL_CONNECTED ) | |
( bool ) MQLInfoInteger ( MQL_TESTER ) ) ;
ev . orderLive = false ;
ev . liveOrder = 0 ;
ev . dealCount = 0 ;
ev . positionCount = 0 ;
ev . unrelatedCount = 0 ;
ev . dealTicket = 0 ;
ev . positionId = 0 ;
ev . ambiguous = false ;
ev . noExposureProven = false ;
ev . detail = " " ;
if ( st . reserveState = = UQ_RESERVE_NONE )
return ;
const ulong orderTicket = st . reserveTicket ;
//--- 1. the request may still be an active pending order. The ticket must
//--- belong to this symbol and Magic Number, otherwise it is not ours.
if ( orderTicket > 0 & & OrderSelect ( orderTicket ) )
{
const string osym = OrderGetString ( ORDER_SYMBOL ) ;
const ulong omag = ( ulong ) OrderGetInteger ( ORDER_MAGIC ) ;
if ( osym = = st . reserveSymbol & & ( magic = = 0 | | omag = = magic ) )
{
ev . orderLive = true ;
ev . liveOrder = orderTicket ;
}
else
{
ev . ambiguous = true ;
ev . detail + = StringFormat ( " %s#%s(order identity mismatch) " ,
osym , IntegerToString ( ( long ) orderTicket ) ) ;
}
}
//--- 2. deals produced by that order ticket. HistorySelect is required
//--- before any deal can be read; the window is anchored on the request
//--- time so a restart does not have to scan the whole history.
const datetime to = UQServerNow ( ) ;
const datetime from = ( st . reserveTime > 0 ?
( datetime ) ( st . reserveTime - ( datetime ) UQ_HISTORY_LOOKBACK_SECONDS ) :
( datetime ) ( to - ( datetime ) ( 2 * UQ_HISTORY_LOOKBACK_SECONDS ) ) ) ;
if ( ev . connected & & to > 0 & & HistorySelect ( from , ( datetime ) ( to + 60 ) ) )
{
ulong foundPos = 0 ;
const int deals = HistoryDealsTotal ( ) ;
for ( int i = 0 ; i < deals ; i + + )
{
const ulong dt = HistoryDealGetTicket ( i ) ;
if ( dt = = 0 )
continue ;
if ( HistoryDealGetString ( dt , DEAL_SYMBOL ) ! = st . reserveSymbol )
continue ;
if ( magic ! = 0 & & ( ulong ) HistoryDealGetInteger ( dt , DEAL_MAGIC ) ! = magic )
continue ;
bool match = false ;
if ( orderTicket > 0 & &
( ulong ) HistoryDealGetInteger ( dt , DEAL_ORDER ) = = orderTicket )
match = true ;
else if ( st . reserveDeal > 0 & & dt = = st . reserveDeal )
match = true ;
if ( ! match )
continue ;
ev . dealCount + + ;
if ( ev . dealTicket = = 0 )
ev . dealTicket = dt ;
const ulong pid = ( ulong ) HistoryDealGetInteger ( dt , DEAL_POSITION_ID ) ;
if ( pid > 0 )
{
if ( foundPos = = 0 )
{
foundPos = pid ;
ev . positionId = pid ;
}
else if ( foundPos ! = pid )
{
ev . ambiguous = true ;
ev . detail + = " several position identifiers " ;
}
}
}
}
//--- 3. count the owned positions, separating the traced one from the
//--- unrelated ones. Only the traced identifier may convert a reservation.
const int total = PositionsTotal ( ) ;
for ( int i = 0 ; i < total ; i + + )
{
const ulong pt = PositionGetTicket ( i ) ;
if ( pt = = 0 )
continue ;
if ( magic ! = 0 & & ( ulong ) PositionGetInteger ( POSITION_MAGIC ) ! = magic )
continue ;
if ( ev . positionId > 0 & &
( ulong ) PositionGetInteger ( POSITION_IDENTIFIER ) = = ev . positionId )
ev . positionCount + + ;
else
ev . unrelatedCount + + ;
}
if ( ev . dealCount > 0 & & ev . positionId > 0 & & ev . positionCount = = 0 )
ev . detail + = " traced position already closed " ;
//--- 4. authoritative proof that nothing was executed: the order exists in
//--- history in a terminal state that carries no fill and it produced no
//--- deal at all. Anything less proves nothing.
if ( ev . connected & & ! ev . orderLive & & ev . dealCount = = 0 & & orderTicket > 0 )
{
if ( HistoryOrderSelect ( orderTicket ) )
{
const long state = ( long ) HistoryOrderGetInteger ( orderTicket , ORDER_STATE ) ;
const double volInit = HistoryOrderGetDouble ( orderTicket , ORDER_VOLUME_INITIAL ) ;
const double volCur = HistoryOrderGetDouble ( orderTicket , ORDER_VOLUME_CURRENT ) ;
//--- a terminal state alone is not enough: a cancelled order may have
//--- been filled in part, so the executed volume must also be zero
if ( ( state = = ORDER_STATE_REJECTED | | state = = ORDER_STATE_CANCELED | |
state = = ORDER_STATE_EXPIRED ) & & ! ( volInit - volCur > 0.0 ) )
ev . noExposureProven = true ;
}
}
}
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
//+------------------------------------------------------------------+
//| Validate the monetary result of a stop-loss calculation. |
//| |
//| A stop-loss distance is only allowed to produce an adverse loss. |
//| Zero or positive means the value cannot describe risk at all: a |
//| missing currency conversion, a stale quote or a malformed price |
//| all end here, and MathAbs() must never turn such a value into a |
//| plausible positive exposure. |
//+------------------------------------------------------------------+
bool UQAdverseRiskFromProfit ( const double p , double & risk , string & reason )
{
risk = 0.0 ;
reason = " " ;
if ( ! MathIsValidNumber ( p ) )
{
reason = " profit is not a finite number " ;
return ( false ) ;
}
if ( ! ( p < 0.0 ) )
{
reason = StringFormat ( " profit %s is not an adverse loss " , DoubleToString ( p , 2 ) ) ;
return ( false ) ;
}
risk = - p ;
if ( ! MathIsValidNumber ( risk ) | | ! ( risk > 0.0 ) )
{
reason = " monetary risk is not usable " ;
risk = 0.0 ;
return ( false ) ;
}
return ( true ) ;
}
//+------------------------------------------------------------------+
//| Verified stop-loss risk of one owned exposure item, expressed in |
//| the deposit currency. |
//| |
//| Every condition must hold before the monetary value may be used: |
//| * the direction is one OrderCalcProfit() understands; |
//| * the instrument is still described by the terminal; |
//| * the volume and the reference price are positive and finite; |
//| * a protective stop exists and sits on the adverse side of the |
//| reference price for the direction it belongs to; |
//| * OrderCalcProfit() succeeds; |
//| * its result is a finite number and a strictly adverse loss. |
//| |
//| A zero or positive result is NOT a risk of zero. It means the |
//| calculation cannot be trusted - a missing currency conversion, a |
//| stale quote or a malformed stop all end here - so the caller must|
//| report an unbounded exposure instead of inventing a plausible |
//| positive number with MathAbs(). |
//+------------------------------------------------------------------+
bool UQStopLossRisk ( const string symbol , const ulong ticket ,
const ENUM_ORDER_TYPE dir ,
const double volume , const double reference , const double stop ,
double & risk , string & reason )
{
risk = 0.0 ;
reason = " " ;
//--- 1. the direction must be one OrderCalcProfit() accepts
if ( dir ! = ORDER_TYPE_BUY & & dir ! = ORDER_TYPE_SELL )
{
reason = " no tradable direction " ;
return ( false ) ;
}
//--- 2. a valid symbol, still described by the terminal
if ( StringLen ( symbol ) < = 0 )
{
reason = " no symbol " ;
return ( false ) ;
}
if ( StringFind ( symbol , " = " ) > = 0 | | StringFind ( symbol , " | " ) > = 0 | |
StringFind ( symbol , " \r " ) > = 0 | | StringFind ( symbol , " \n " ) > = 0 )
{
reason = " invalid symbol name " ;
return ( false ) ;
}
if ( ! ( SymbolInfoDouble ( symbol , SYMBOL_POINT ) > 0.0 ) | |
! ( SymbolInfoDouble ( symbol , SYMBOL_TRADE_TICK_SIZE ) > 0.0 ) )
{
reason = " symbol is not priced by the terminal " ;
return ( false ) ;
}
//--- 3. a valid volume
if ( ! MathIsValidNumber ( volume ) | | ! ( volume > 0.0 ) )
{
reason = " invalid volume " ;
return ( false ) ;
}
//--- 4. a valid entry / reference price
if ( ! MathIsValidNumber ( reference ) | | ! ( reference > 0.0 ) )
{
reason = " invalid reference price " ;
return ( false ) ;
}
//--- 5. a valid protective stop on the correct side of the reference
if ( ! MathIsValidNumber ( stop ) | | ! ( stop > 0.0 ) )
{
reason = " no protective stop " ;
return ( false ) ;
}
if ( dir = = ORDER_TYPE_BUY & & ! ( stop < reference ) )
{
reason = " buy stop is not below the reference price " ;
return ( false ) ;
}
if ( dir = = ORDER_TYPE_SELL & & ! ( stop > reference ) )
{
reason = " sell stop is not above the reference price " ;
return ( false ) ;
}
//--- 6. the broker-side monetary calculation
double p = 0.0 ;
if ( ! OrderCalcProfit ( dir , symbol , volume , reference , stop , p ) )
{
reason = StringFormat ( " OrderCalcProfit failed (%d) " , GetLastError ( ) ) ;
return ( false ) ;
}
//--- 7..10. finite, strictly adverse and usable monetary exposure
return ( UQAdverseRiskFromProfit ( p , risk , reason ) ) ;
}
2026-10-30 08:52:18 +07:00
//+------------------------------------------------------------------+
//| Measure the exposure from the live broker pools and add the money |
//| that an accepted but unreconciled entry still reserves. |
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
//| |
//| Unquantifiable exposure is never represented as zero: the affected |
//| symbol and ticket are reported, bounded is cleared, and the caller |
//| refuses every new entry. |
2026-10-30 08:52:18 +07:00
//+------------------------------------------------------------------+
bool UQExposureFromPools ( const ulong magic , const double reservedMoney , UQExposure & out )
{
out . positions = 0.0 ;
out . pending = 0.0 ;
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
out . reserved = 0.0 ;
2026-10-30 08:52:18 +07:00
out . positionCount = 0 ;
out . pendingCount = 0 ;
out . bounded = true ;
out . detail = " " ;
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
//--- money still held by an unreconciled entry order
if ( MathIsValidNumber ( reservedMoney ) & & reservedMoney > 0.0 )
out . reserved = reservedMoney ;
else if ( ! MathIsValidNumber ( reservedMoney ) )
UQExposureNote ( out , " " , 0 , " reserved money is not a finite number " ) ;
2026-10-30 08:52:18 +07:00
const int total = PositionsTotal ( ) ;
for ( int i = 0 ; i < total ; i + + )
{
const ulong ticket = PositionGetTicket ( i ) ;
if ( ticket = = 0 )
continue ;
if ( ( ulong ) PositionGetInteger ( POSITION_MAGIC ) ! = magic )
continue ;
out . positionCount + + ;
const string sym = PositionGetString ( POSITION_SYMBOL ) ;
const double vol = PositionGetDouble ( POSITION_VOLUME ) ;
const double sl = PositionGetDouble ( POSITION_SL ) ;
const double cur = PositionGetDouble ( POSITION_PRICE_CURRENT ) ;
const double open = PositionGetDouble ( POSITION_PRICE_OPEN ) ;
const long ptype = PositionGetInteger ( POSITION_TYPE ) ;
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
if ( ptype ! = POSITION_TYPE_BUY & & ptype ! = POSITION_TYPE_SELL )
{
UQExposureNote ( out , sym , ticket , " position type is not BUY or SELL " ) ;
continue ;
}
//--- the entry price is part of the conservative reference: without it
//--- the worse-of rule cannot be applied and the risk is not quantifiable
if ( ! MathIsValidNumber ( open ) | | ! ( open > 0.0 ) | |
! MathIsValidNumber ( cur ) | | ! ( cur > 0.0 ) )
2026-10-30 08:52:18 +07:00
{
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
UQExposureNote ( out , sym , ticket , " position price is unavailable " ) ;
2026-10-30 08:52:18 +07:00
continue ;
}
const bool isBuy = ( ptype = = POSITION_TYPE_BUY ) ;
//--- Potential loss down to the stop, measured from the worse of the
//--- entry price and the current price: for a buy the higher price, for
//--- a sell the lower one. Measuring from the current price alone would
//--- let the bid/ask spread release aggregate budget the moment a
//--- position is opened, which would let the aggregate ceiling be
//--- exceeded. The risk only falls once the stop itself has been moved.
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
const double from = isBuy ? MathMax ( cur , open ) : MathMin ( cur , open ) ;
2026-10-30 08:52:18 +07:00
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
double risk = 0.0 ;
string reason = " " ;
if ( ! UQStopLossRisk ( sym , ticket , ( isBuy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL ) ,
vol , from , sl , risk , reason ) )
2026-10-30 08:52:18 +07:00
{
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
UQExposureNote ( out , sym , ticket , reason ) ;
2026-10-30 08:52:18 +07:00
continue ;
}
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
out . positions + = risk ;
2026-10-30 08:52:18 +07:00
}
const int orders = OrdersTotal ( ) ;
for ( int i = 0 ; i < orders ; i + + )
{
const ulong ticket = OrderGetTicket ( i ) ;
if ( ticket = = 0 )
continue ;
if ( ( ulong ) OrderGetInteger ( ORDER_MAGIC ) ! = magic )
continue ;
out . pendingCount + + ;
const string sym = OrderGetString ( ORDER_SYMBOL ) ;
const double vol = OrderGetDouble ( ORDER_VOLUME_CURRENT ) ;
const double price = OrderGetDouble ( ORDER_PRICE_OPEN ) ;
const double sl = OrderGetDouble ( ORDER_SL ) ;
const long otype = OrderGetInteger ( ORDER_TYPE ) ;
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
//--- OrderCalcProfit only accepts the plain buy/sell direction, so the
//--- pending type is mapped explicitly and an unknown type fails closed
ENUM_ORDER_TYPE dir = ORDER_TYPE_SELL ;
bool mapped = false ;
if ( otype = = ORDER_TYPE_BUY | | otype = = ORDER_TYPE_BUY_LIMIT | |
otype = = ORDER_TYPE_BUY_STOP | | otype = = ORDER_TYPE_BUY_STOP_LIMIT )
{
dir = ORDER_TYPE_BUY ;
mapped = true ;
}
else if ( otype = = ORDER_TYPE_SELL | | otype = = ORDER_TYPE_SELL_LIMIT | |
otype = = ORDER_TYPE_SELL_STOP | | otype = = ORDER_TYPE_SELL_STOP_LIMIT )
2026-10-30 08:52:18 +07:00
{
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
dir = ORDER_TYPE_SELL ;
mapped = true ;
}
if ( ! mapped )
{
UQExposureNote ( out , sym , ticket , " pending order type is not tradable " ) ;
2026-10-30 08:52:18 +07:00
continue ;
}
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
double risk = 0.0 ;
string reason = " " ;
if ( ! UQStopLossRisk ( sym , ticket , dir , vol , price , sl , risk , reason ) )
2026-10-30 08:52:18 +07:00
{
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
UQExposureNote ( out , sym , ticket , reason ) ;
2026-10-30 08:52:18 +07:00
continue ;
}
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
out . pending + = risk ;
2026-10-30 08:52:18 +07:00
}
return ( out . bounded ) ;
}
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
//+------------------------------------------------------------------+
//| Prove that account equity cannot have changed in a window |
//| |
//| A daily baseline may only be reconstructed when the equity path |
//| across the unobserved window is provably constant: no position |
//| and no pending order survives and no account deal was recorded. |
//| Without that proof the window is unmeasurable instead of assumed |
//| flat, so the caller fails closed. |
//+------------------------------------------------------------------+
bool UQAccountProvablyFlat ( const datetime from , const datetime to , string & detail )
{
detail = " " ;
if ( from < = 0 | | to < = from )
{
detail = " the unobserved window is not a usable interval " ;
return ( false ) ;
}
const int positions = PositionsTotal ( ) ;
if ( positions > 0 )
{
detail = StringFormat ( " %d position(s) are open, so equity was exposed during the window " , positions ) ;
return ( false ) ;
}
const int orders = OrdersTotal ( ) ;
if ( orders > 0 )
{
detail = StringFormat ( " %d pending order(s) exist, so an unobserved fill cannot be excluded " , orders ) ;
return ( false ) ;
}
if ( ! HistorySelect ( from , to ) )
{
detail = " the account deal history cannot be read, so no flat equity path can be proven " ;
return ( false ) ;
}
const int deals = HistoryDealsTotal ( ) ;
if ( deals > 0 )
{
detail = StringFormat ( " %d account deal(s) were recorded inside the window " , deals ) ;
return ( false ) ;
}
return ( true ) ;
}
2026-10-30 07:19:59 +07:00
//+------------------------------------------------------------------+
//| Centralized risk controller |
//+------------------------------------------------------------------+
class CUQRisk
{
private :
UQIdentity m_id ;
UQRiskState m_st ;
UQRiskConfig m_cfg ;
bool m_ready ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
bool m_healthy ;
2026-10-30 07:19:59 +07:00
bool m_freshInstall ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
bool m_migrated ;
bool m_restoredBackup ;
2026-10-30 08:37:46 +07:00
bool m_resetRejected ;
bool m_resetApplied ;
string m_cycleId ;
int m_cycleSequence ;
2026-10-30 07:19:59 +07:00
string m_lastError ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
string m_lastSaveError ;
datetime m_saveRetryAt ;
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
ulong m_reserveSeq ;
datetime m_reserveCheckAt ;
2026-10-30 07:19:59 +07:00
double m_equity ;
double m_b0 ;
double m_d0 ;
double m_dailyLossPct ;
double m_staticDdPct ;
double m_targetEquity ;
double m_dailyFloor ;
double m_staticFloor ;
datetime m_today ;
ENUM_UQ_BLOCK m_block ;
bool Save ( void ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
void ApplyBlock ( void ) ;
2026-10-30 08:52:18 +07:00
void ClearReservation ( void ) ;
2026-10-30 07:19:59 +07:00
bool ApplyResetRequest ( void ) ;
2026-10-30 08:37:46 +07:00
bool RejectReset ( const string why ) ;
2026-10-30 07:19:59 +07:00
bool EvaluateLocks ( void ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
bool EstablishBaselineFromState ( void ) ;
bool EstablishInitialBaseline ( void ) ;
2026-10-30 07:19:59 +07:00
bool EstablishDailyBaseline ( void ) ;
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
bool UpdateMonitoring ( const datetime now , const datetime today ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
bool LoadPersistentState ( void ) ;
2026-10-30 07:19:59 +07:00
public :
CUQRisk ( void ) ;
~ CUQRisk ( void ) ;
bool Init ( UQRiskConfig & cfg ) ;
void Evaluate ( void ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
bool IsReady ( void ) const { return ( m_ready ) ; }
bool Healthy ( void ) const { return ( m_healthy ) ; }
string LastError ( void ) const { return ( m_lastError ) ; }
string LastSaveError ( void ) const { return ( m_lastSaveError ) ; }
string IdentityKey ( void ) const { return ( m_id . key ) ; }
string Portfolio ( void ) const { return ( m_cfg . portfolio ) ; }
long Login ( void ) const { return ( m_id . login ) ; }
bool StateMigrated ( void ) const { return ( m_migrated ) ; }
bool StateFromBackup ( void ) const { return ( m_restoredBackup ) ; }
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
//--- persistence generation of the authoritative state and the recovery
//--- hold that a recovered state always starts behind
long StateRevision ( void ) const { return ( m_st . stateRevision ) ; }
bool RecoveryHold ( void ) const { return ( m_st . recoveryHold ) ; }
datetime RecoveryHoldTime ( void ) const { return ( m_st . recoveryHoldTime ) ; }
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
//--- daily monitoring continuity: the last verified heartbeat, the most
//--- recent unobserved interval and the hold that blocks entries while the
//--- daily baseline cannot be reconstructed
datetime LastMonitorTime ( void ) const { return ( m_st . monitorTime ) ; }
int MonitorGapSeconds ( void ) const { return ( m_st . monitorGapSeconds ) ; }
bool MonitorGapHold ( void ) const { return ( m_st . gapHold ) ; }
datetime MonitorGapHoldTime ( void ) const { return ( m_st . gapHoldTime ) ; }
bool DailyMonitored ( void ) const { return ( ! m_st . gapHold ) ; }
2026-10-30 08:37:46 +07:00
string CycleId ( void ) const { return ( m_cycleId ) ; }
int CycleSequence ( void ) const { return ( m_cycleSequence ) ; }
bool ResetApplied ( void ) const { return ( m_resetApplied ) ; }
bool ResetRejected ( void ) const { return ( m_resetRejected ) ; }
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
2026-10-30 10:20:54 +07:00
//--- permanent locks recorded by the most recent owner reset. Kind 3 means
//--- the closed cycle carried both permanent locks; the state schema
//--- preserves that value across restarts.
int PriorLockKind ( void ) const { return ( m_st . priorLockKind ) ; }
datetime PriorLockTime ( void ) const { return ( m_st . priorLockTime ) ; }
string PriorLockText ( void ) const { return ( UQPriorLockText ( m_st . priorLockKind ) ) ; }
2026-10-30 08:52:18 +07:00
//--- aggregate exposure, including unreconciled entry reservations
bool Exposure ( const ulong magic , UQExposure & out ) ;
//--- entry-risk reservation: taken before an order is submitted and
//--- released only after the broker state proves where the order went
bool ReserveEntryRisk ( const ulong magic , const string symbol ,
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
const int direction , const double volume ,
const double entry , const double stop ,
2026-10-30 08:52:18 +07:00
const double money , string & err ) ;
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
bool NoteSubmittedTickets ( const ulong orderTicket , const ulong dealTicket ) ;
2026-10-30 08:52:18 +07:00
void ReleaseReservation ( const string why ) ;
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
void MarkReservationUnresolved ( const string why , UQReserveEvidence & ev ) ;
2026-10-30 08:52:18 +07:00
void ReconcileReservation ( void ) ;
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
void ReconcileReservationDepth ( const bool forced ) ;
//--- a submission whose result cannot be established keeps its reserved
//--- risk: the caller has no proof that the request left no exposure
void MarkReservationUncertain ( const string why )
{
UQReserveEvidence ev ;
UQReserveCorrelate ( m_cfg . magic , m_st , ev ) ;
MarkReservationUnresolved ( why , ev ) ;
}
2026-10-30 08:52:18 +07:00
ENUM_UQ_RESERVE_STATE ReserveState ( void ) const { return ( m_st . reserveState ) ; }
double ReservedRisk ( void ) const { return ( m_st . reserveMoney ) ; }
ulong ReserveTicket ( void ) const { return ( m_st . reserveTicket ) ; }
string ReserveSymbol ( void ) const { return ( m_st . reserveSymbol ) ; }
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
string ReserveId ( void ) const { return ( m_st . reserveId ) ; }
ulong ReserveDeal ( void ) const { return ( m_st . reserveDeal ) ; }
ulong ReservePosition ( void ) const { return ( m_st . reservePosition ) ; }
2026-10-30 08:52:18 +07:00
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
double Baseline ( void ) const { return ( m_b0 ) ; }
double DailyStart ( void ) const { return ( m_d0 ) ; }
double Equity ( void ) const { return ( m_equity ) ; }
double DailyLossPct ( void ) const { return ( m_dailyLossPct ) ; }
double StaticDdPct ( void ) const { return ( m_staticDdPct ) ; }
double TargetEquity ( void ) const { return ( m_targetEquity ) ; }
double DailyFloor ( void ) const { return ( m_dailyFloor ) ; }
double StaticFloor ( void ) const { return ( m_staticFloor ) ; }
2026-10-30 07:19:59 +07:00
double DailyLimitPct ( void ) const { return ( m_cfg . dailyLimitPct ) ; }
double StaticLimitPct ( void ) const { return ( m_cfg . staticLimitPct ) ; }
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
double TargetPct ( void ) const { return ( m_cfg . targetPct ) ; }
datetime TradingDate ( void ) const { return ( m_today ) ; }
2026-10-30 07:19:59 +07:00
datetime DailyStartTime ( void ) const { return ( m_st . dailyStartTime ) ; }
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
bool StaticLock ( void ) const { return ( m_st . staticLock ) ; }
bool TargetLock ( void ) const { return ( m_st . targetLock ) ; }
bool DailyLock ( void ) const { return ( m_st . dailyLock ) ; }
2026-10-30 07:19:59 +07:00
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
ENUM_UQ_BLOCK Block ( void ) const { return ( m_block ) ; }
2026-10-30 07:19:59 +07:00
string BlockText ( void ) const { return ( UQBlockText ( m_block ) ) ; }
//--- a permanent lock or the daily lock demands immediate flattening
bool LiquidationRequired ( void ) const
{
return ( m_block = = UQ_BLOCK_STATIC | | m_block = = UQ_BLOCK_TARGET | | m_block = = UQ_BLOCK_DAILY ) ;
}
//--- new entries permitted only when nothing blocks them
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
bool CanOpenNew ( void ) const
{
return ( m_ready & & m_healthy & & m_block = = UQ_BLOCK_NONE ) ;
}
2026-10-30 07:19:59 +07:00
} ;
//+------------------------------------------------------------------+
CUQRisk : : CUQRisk ( void )
{
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
m_ready = false ;
m_healthy = false ;
m_freshInstall = false ;
m_migrated = false ;
m_restoredBackup = false ;
2026-10-30 08:37:46 +07:00
m_resetRejected = false ;
m_resetApplied = false ;
m_cycleId = " " ;
m_cycleSequence = 0 ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
m_lastError = " " ;
m_lastSaveError = " " ;
m_saveRetryAt = 0 ;
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
m_reserveSeq = 0 ;
m_reserveCheckAt = 0 ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
m_equity = 0.0 ;
m_b0 = 0.0 ;
m_d0 = 0.0 ;
m_dailyLossPct = 0.0 ;
m_staticDdPct = 0.0 ;
m_targetEquity = 0.0 ;
m_dailyFloor = 0.0 ;
m_staticFloor = 0.0 ;
m_today = 0 ;
m_block = UQ_BLOCK_BASELINE ;
2026-10-30 07:19:59 +07:00
UQStateReset ( m_st ) ;
}
//+------------------------------------------------------------------+
CUQRisk : : ~ CUQRisk ( void )
{
}
//+------------------------------------------------------------------+
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
//| Persist the current state. A failure degrades the controller to |
//| "unhealthy": every new entry is blocked until persistence works |
//| again, while the in-memory lock is preserved. |
2026-10-30 07:19:59 +07:00
//+------------------------------------------------------------------+
bool CUQRisk : : Save ( void )
{
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
if ( UQStateSave ( m_id , m_st ) )
2026-10-30 07:19:59 +07:00
{
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
m_healthy = true ;
m_lastSaveError = " " ;
m_saveRetryAt = 0 ;
return ( true ) ;
2026-10-30 07:19:59 +07:00
}
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
m_healthy = false ;
m_lastSaveError = " persistent risk state could not be written " ;
m_lastError = m_lastSaveError ;
m_saveRetryAt = UQServerNow ( ) + ( datetime ) UQ_STATE_RETRY_SECONDS ;
m_block = UQ_BLOCK_STATE ;
PrintFormat ( " [UQ] ERROR: %s. New entries are blocked and the in-memory lock is preserved. " ,
m_lastSaveError ) ;
return ( false ) ;
}
//+------------------------------------------------------------------+
//| Priority of the active block reason. Liquidation-triggering locks |
//| always outrank the persistence-health block. |
//+------------------------------------------------------------------+
void CUQRisk : : ApplyBlock ( void )
{
if ( m_st . staticLock )
m_block = UQ_BLOCK_STATIC ;
else if ( m_st . targetLock )
m_block = UQ_BLOCK_TARGET ;
else if ( m_st . dailyLock )
m_block = UQ_BLOCK_DAILY ;
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
else if ( m_st . gapHold )
m_block = UQ_BLOCK_GAP ;
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
else if ( m_st . recoveryHold )
m_block = UQ_BLOCK_RECOVERY ;
2026-10-30 08:37:46 +07:00
else if ( m_resetRejected )
m_block = UQ_BLOCK_RESET ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
else if ( ! m_st . baselineValid | | m_b0 < = 0.0 | | m_d0 < = 0.0 )
m_block = UQ_BLOCK_BASELINE ;
2026-10-30 08:52:18 +07:00
else if ( m_st . reserveState ! = UQ_RESERVE_NONE )
m_block = UQ_BLOCK_RESERVATION ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
else if ( ! m_healthy )
m_block = UQ_BLOCK_STATE ;
else
m_block = UQ_BLOCK_NONE ;
2026-10-30 07:19:59 +07:00
}
//+------------------------------------------------------------------+
2026-10-30 08:37:46 +07:00
//| Record a rejected owner reset. Rejection is fail closed: the lock |
//| stays active, the reason is reported and new entries are blocked. |
//+------------------------------------------------------------------+
bool CUQRisk : : RejectReset ( const string why )
{
m_resetRejected = true ;
m_resetApplied = false ;
m_lastError = " owner reset rejected: " + why ;
PrintFormat ( " [UQ] ERROR: OWNER RESET REJECTED - %s. The permanent lock stays active, the risk cycle is unchanged and new entries are blocked. " , why ) ;
return ( false ) ;
}
//+------------------------------------------------------------------+
//| Apply an explicit owner reset as a new risk cycle. |
//| |
//| A permanent lock is never cleared in place. A successful reset |
//| closes the current cycle and opens a new one with an explicitly |
//| authorized baseline, a new daily baseline, a new cycle identifier |
//| and a consumed nonce, and it is persisted before entries may be |
//| allowed again. |
//| |
//| The daily-loss lock is never affected: only a broker-server |
//| trading-day rollover clears it. |
//| |
//| A nonce that was consumed by an earlier cycle is not applied |
//| again. That is the restart case (the inputs still carry the old |
//| request), so it is reported and never treated as a new reset. |
2026-10-30 07:19:59 +07:00
//+------------------------------------------------------------------+
bool CUQRisk : : ApplyResetRequest ( void )
{
2026-10-30 08:37:46 +07:00
m_resetRejected = false ;
m_resetApplied = false ;
2026-10-30 07:19:59 +07:00
if ( m_cfg . resetRequest = = UQ_RESET_NONE )
return ( true ) ;
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
//--- a recovery acknowledgement is a distinct owner operation: it exists
//--- only while a persistence recovery hold is active, and it never clears
//--- a permanent lock that the recovered state carries
const bool isRecovery = ( m_cfg . resetRequest = = UQ_RESET_RECOVERY ) ;
if ( isRecovery & & ! m_st . recoveryHold )
return ( RejectReset ( " no persistence recovery hold is active, so there is nothing to acknowledge " ) ) ;
2026-10-30 08:37:46 +07:00
//--- 1. operational confirmation phrase (a safeguard, not a secret)
2026-10-30 07:19:59 +07:00
if ( m_cfg . resetToken ! = UQ_RESET_TOKEN )
2026-10-30 08:37:46 +07:00
return ( RejectReset ( " the confirmation phrase does not match the required value " ) ) ;
//--- 2. nonce syntax: unique per operation, never a secret
if ( ! UQResetNonceValid ( m_cfg . resetNonce ) )
return ( RejectReset ( StringFormat ( " the reset nonce must be %d..%d printable characters without '=' or '|' " ,
UQ_RESET_NONCE_MIN_LEN , UQ_RESET_NONCE_MAX_LEN ) ) ) ;
//--- 3. a nonce is consumed at most once
if ( UQResetNonceConsumed ( m_st . resetNonceHistory , m_cfg . resetNonce ) )
2026-10-30 07:19:59 +07:00
{
2026-10-30 08:37:46 +07:00
PrintFormat ( " [UQ] Owner reset nonce was already consumed by an earlier risk cycle (%s); it is not applied again. Remove the reset inputs. " ,
m_st . cycleId ) ;
return ( true ) ;
2026-10-30 07:19:59 +07:00
}
2026-10-30 08:37:46 +07:00
//--- 4. the new cycle needs a deliberate positive baseline
if ( ! ( m_cfg . resetBaseline > 0.0 ) )
return ( RejectReset ( " a new risk cycle requires an explicitly supplied positive baseline B0 " ) ) ;
//--- 5. the account scope must be verified clear of this EA's exposure
if ( ! m_cfg . resetPreconditionsOk )
return ( RejectReset ( StringLen ( m_cfg . resetPreconditionDetail ) > 0
? m_cfg . resetPreconditionDetail
: " the account scope is not verified flat " ) ) ;
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
//--- 6. the requested lock must actually be active. A recovery
//--- acknowledgement clears no lock, so it requires no active lock and
//--- any lock the recovered state carries keeps blocking entries.
const bool wantStatic = ( ! isRecovery & &
( m_cfg . resetRequest = = UQ_RESET_STATIC | |
m_cfg . resetRequest = = UQ_RESET_BOTH ) ) ;
const bool wantTarget = ( ! isRecovery & &
( m_cfg . resetRequest = = UQ_RESET_TARGET | |
m_cfg . resetRequest = = UQ_RESET_BOTH ) ) ;
if ( ! isRecovery & & ! ( wantStatic & & m_st . staticLock ) & & ! ( wantTarget & & m_st . targetLock ) )
2026-10-30 08:37:46 +07:00
return ( RejectReset ( " no matching permanent lock is active, so there is nothing to reset " ) ) ;
//--- 7. the new baseline must not re-arm the lock it is meant to clear
const double eq = AccountInfoDouble ( ACCOUNT_EQUITY ) ;
if ( ! ( eq > 0.0 ) )
return ( RejectReset ( " account equity is unavailable " ) ) ;
if ( wantStatic & & m_st . staticLock )
2026-10-30 07:19:59 +07:00
{
2026-10-30 08:37:46 +07:00
const double newFloor = m_cfg . resetBaseline * ( 1.0 - m_cfg . staticLimitPct / 100.0 ) ;
if ( eq < = newFloor )
return ( RejectReset ( StringFormat ( " baseline %.2f re-arms the static-drawdown lock immediately (floor %.2f, equity %.2f) " ,
m_cfg . resetBaseline , newFloor , eq ) ) ) ;
}
if ( wantTarget & & m_st . targetLock )
{
const double newTarget = m_cfg . resetBaseline * ( 1.0 + m_cfg . targetPct / 100.0 ) ;
if ( eq > = newTarget )
return ( RejectReset ( StringFormat ( " baseline %.2f re-arms the equity-target lock immediately (target %.2f, equity %.2f) " ,
m_cfg . resetBaseline , newTarget , eq ) ) ) ;
2026-10-30 07:19:59 +07:00
}
2026-10-30 08:37:46 +07:00
//--- 8. open the new cycle
const datetime now = UQServerNow ( ) ;
if ( now < = 0 )
return ( RejectReset ( " broker-server time is unavailable " ) ) ;
2026-10-30 07:19:59 +07:00
2026-10-30 08:37:46 +07:00
const string priorCycleId = m_st . cycleId ;
const double priorB0 = m_st . baselineBalance ;
2026-10-30 10:20:54 +07:00
//--- record EVERY permanent lock the closed cycle carried, never only the
//--- first one: both locks can be armed in the same cycle, and the recorded
//--- kind 3 keeps that fact verifiable after a restart
const int priorKind = UQPriorLockKindFromFlags ( m_st . staticLock , m_st . targetLock ) ;
2026-10-30 08:37:46 +07:00
datetime priorTime = 0 ;
2026-10-30 10:20:54 +07:00
if ( UQPriorLockHasStatic ( priorKind ) )
2026-10-30 08:37:46 +07:00
priorTime = ( m_st . staticLockTime > 0 ? m_st . staticLockTime : priorTime ) ;
2026-10-30 10:20:54 +07:00
if ( UQPriorLockHasTarget ( priorKind ) )
2026-10-30 08:37:46 +07:00
priorTime = ( priorTime > 0 & & m_st . targetLockTime > 0 )
? ( datetime ) MathMin ( ( double ) priorTime , ( double ) m_st . targetLockTime )
: m_st . targetLockTime ;
m_st . cycleSequence + + ;
m_st . cycleId = UQBuildCycleId ( m_st . cycleSequence , m_cfg . resetNonce ) ;
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
//--- the prior-cycle slot is defined as "the lock event that authorized the
//--- reset": without a prior permanent lock (a recovery acknowledgement of a
//--- clean cycle) it stays empty instead of recording an inconsistent
//--- reference, and the closed cycle is still reported in the log
const bool priorRecorded = ( priorKind ! = UQ_PRIOR_LOCK_NONE ) ;
m_st . priorBaselineBalance = ( priorRecorded ? priorB0 : 0.0 ) ;
m_st . priorCycleId = ( priorRecorded ? priorCycleId : " " ) ;
2026-10-30 08:37:46 +07:00
m_st . priorLockKind = priorKind ;
m_st . priorLockTime = priorTime ;
//--- only the requested permanent locks are cleared
if ( wantStatic & & m_st . staticLock )
2026-10-30 07:19:59 +07:00
{
2026-10-30 08:37:46 +07:00
m_st . staticLock = false ;
m_st . staticLockTime = 0 ;
}
if ( wantTarget & & m_st . targetLock )
{
m_st . targetLock = false ;
m_st . targetLockTime = 0 ;
2026-10-30 07:19:59 +07:00
}
2026-10-30 08:37:46 +07:00
//--- new cycle baselines
m_st . baselineBalance = m_cfg . resetBaseline ;
m_st . baselineValid = true ;
m_st . baselineTime = now ;
m_b0 = m_st . baselineBalance ;
m_st . dailyStartEquity = eq ;
m_st . dailyValid = true ;
m_st . dailyDate = UQDayStart ( now ) ;
m_st . dailyStartTime = now ;
m_d0 = m_st . dailyStartEquity ;
m_equity = eq ;
m_today = m_st . dailyDate ;
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
//--- the explicit owner authorization is what clears the recovery hold,
//--- and it also opens a new monitoring window: the gap hold is released
//--- expressly, never silently
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
m_st . recoveryHold = false ;
m_st . recoveryHoldTime = 0 ;
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
if ( m_st . gapHold )
PrintFormat ( " [UQ] MONITORING GAP HOLD released by the explicit owner risk cycle %s. " , m_st . cycleId ) ;
m_st . gapHold = false ;
m_st . gapHoldTime = 0 ;
m_st . monitorGapSeconds = 0 ;
m_st . monitorTime = now ;
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
2026-10-30 08:37:46 +07:00
m_st . resetSignature = " " ;
m_st . resetNonceHistory = UQResetNonceHistoryAppend ( m_st . resetNonceHistory , m_cfg . resetNonce ) ;
m_st . createdAt = now ;
m_st . updatedAt = now ;
m_cycleId = m_st . cycleId ;
m_cycleSequence = m_st . cycleSequence ;
m_dailyFloor = m_d0 * ( 1.0 - m_cfg . dailyLimitPct / 100.0 ) ;
m_staticFloor = m_b0 * ( 1.0 - m_cfg . staticLimitPct / 100.0 ) ;
m_targetEquity = m_b0 * ( 1.0 + m_cfg . targetPct / 100.0 ) ;
//--- the new cycle must be durable before entries may be allowed
if ( ! Save ( ) )
return ( RejectReset ( " the new risk cycle could not be persisted " ) ) ;
//--- the initialization marker follows the cycle creation timestamp
if ( ! UQStateMarkerSet ( m_id , m_st . createdAt ) )
2026-10-30 07:19:59 +07:00
{
2026-10-30 08:37:46 +07:00
PrintFormat ( " [UQ] ERROR: the initialization marker could not be updated for cycle %s; it is removed so the verified state can re-establish it. " ,
m_st . cycleId ) ;
GlobalVariableDel ( UQStateMarkerName ( m_id ) ) ;
if ( GlobalVariableCheck ( UQStateMarkerName ( m_id ) ) )
return ( RejectReset ( " the initialization marker could not be reconciled with the new cycle " ) ) ;
2026-10-30 07:19:59 +07:00
}
2026-10-30 08:37:46 +07:00
m_resetApplied = true ;
2026-10-30 10:20:54 +07:00
PrintFormat ( " [UQ] NEW RISK CYCLE %s (sequence %d) | previous cycle %s B0=%.2f priorLocks=%d (%s) at %s " ,
m_st . cycleId , m_st . cycleSequence , priorCycleId , priorB0 , priorKind ,
2026-10-30 08:37:46 +07:00
UQPriorLockText ( priorKind ) , TimeToString ( priorTime , TIME_DATE | TIME_SECONDS ) ) ;
2026-10-30 10:20:54 +07:00
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
if ( isRecovery )
PrintFormat ( " [UQ] RECOVERY ACKNOWLEDGED: the persistence recovery hold is cleared by explicit owner authorization; risk cycle %s is active and the recovered state was never treated as a fresh installation. " ,
m_st . cycleId ) ;
2026-10-30 10:20:54 +07:00
//--- a partial reset clears only the requested permanent lock: the other
//--- lock was not authorized to be cleared and keeps blocking entries
if ( m_st . staticLock | | m_st . targetLock )
PrintFormat ( " [UQ] RESIDUAL PERMANENT LOCK: %s is still active after the partial reset; new entries stay blocked and liquidation remains required. " ,
UQBlockText ( m_st . staticLock ? UQ_BLOCK_STATIC : UQ_BLOCK_TARGET ) ) ;
2026-10-30 08:37:46 +07:00
PrintFormat ( " [UQ] New cycle baselines: B0=%.2f D0=%.2f dailyFloor=%.2f staticFloor=%.2f target=%.2f. Remove the reset inputs now. " ,
m_b0 , m_d0 , m_dailyFloor , m_staticFloor , m_targetEquity ) ;
2026-10-30 07:19:59 +07:00
return ( true ) ;
}
//+------------------------------------------------------------------+
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
//| Restore the persisted fixed baseline B0. Never derives a value. |
2026-10-30 07:19:59 +07:00
//+------------------------------------------------------------------+
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
bool CUQRisk : : EstablishBaselineFromState ( void )
2026-10-30 07:19:59 +07:00
{
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
if ( ! m_st . baselineValid | | ! ( m_st . baselineBalance > 0.0 ) )
2026-10-30 07:19:59 +07:00
{
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
m_lastError = " persisted baseline B0 is missing or not positive " ;
return ( false ) ;
2026-10-30 07:19:59 +07:00
}
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
if ( m_cfg . balanceOverride > 0.0 & & MathAbs ( m_cfg . balanceOverride - m_st . baselineBalance ) > 0.005 )
PrintFormat ( " [UQ] WARNING: configured baseline override %.2f is ignored; persisted B0 %.2f is authoritative. " ,
m_cfg . balanceOverride , m_st . baselineBalance ) ;
m_b0 = m_st . baselineBalance ;
return ( true ) ;
}
2026-10-30 07:19:59 +07:00
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
//+------------------------------------------------------------------+
//| Create B0 for a new risk cycle. Requires an explicit owner- |
//| declared positive baseline: the current account balance is never |
//| used as an automatic substitute. |
//+------------------------------------------------------------------+
bool CUQRisk : : EstablishInitialBaseline ( void )
{
if ( ! ( m_cfg . balanceOverride > 0.0 ) )
2026-10-30 07:19:59 +07:00
{
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
m_lastError = " creating a risk cycle requires an explicit positive initial balance B0 " ;
2026-10-30 07:19:59 +07:00
return ( false ) ;
}
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
m_st . baselineBalance = m_cfg . balanceOverride ;
2026-10-30 07:19:59 +07:00
m_st . baselineValid = true ;
m_st . baselineTime = TimeCurrent ( ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
if ( m_st . baselineTime < = 0 )
m_st . baselineTime = UQServerNow ( ) ;
m_b0 = m_cfg . balanceOverride ;
2026-10-30 07:19:59 +07:00
2026-10-30 09:03:13 +07:00
//--- the first persisted cycle must carry its own identity: the state
//--- schema rejects a non-positive cycle sequence and an empty cycle
//--- identifier, so without this a fresh deployment could never persist
//--- its authorised baseline and could never start at all
m_st . cycleSequence = 1 ;
m_st . cycleId = UQBuildCycleId ( 1 , m_id . hash + " | " + IntegerToString ( ( long ) m_st . baselineTime ) ) ;
m_st . resetNonceHistory = " " ;
m_st . priorBaselineBalance = 0.0 ;
m_st . priorCycleId = " " ;
m_st . priorLockKind = 0 ;
m_st . priorLockTime = 0 ;
PrintFormat ( " [UQ] OWNER INITIALIZATION: new risk cycle %s baseline B0 = %.2f " ,
m_st . cycleId , m_b0 ) ;
2026-10-30 07:19:59 +07:00
return ( true ) ;
}
//+------------------------------------------------------------------+
//| Establish D0 for the current broker-server trading day |
//+------------------------------------------------------------------+
bool CUQRisk : : EstablishDailyBaseline ( void )
{
m_equity = AccountInfoDouble ( ACCOUNT_EQUITY ) ;
if ( ! ( m_equity > 0.0 ) )
{
m_lastError = " account equity is unavailable " ;
return ( false ) ;
}
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
const datetime now = UQServerNow ( ) ;
if ( now < = 0 )
2026-10-30 07:19:59 +07:00
{
m_lastError = " broker-server time is unavailable " ;
return ( false ) ;
}
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
//--- a cycle created by this initialization has no daily baseline yet. It
//--- is the only case in which D0 may be created here: a restored state is
//--- schema-validated, so a missing daily baseline would already have been
//--- refused instead of being replaced by the current equity.
if ( ! m_st . dailyValid | | ! ( m_st . dailyStartEquity > 0.0 ) | | m_st . dailyDate < = 0 )
2026-10-30 07:19:59 +07:00
{
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
if ( m_st . dailyValid | | ! m_st . baselineValid | | m_st . cycleSequence < 1 | | ! ( m_b0 > 0.0 ) )
{
m_lastError = " the persisted daily baseline D0 is missing or invalid " ;
return ( false ) ;
}
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
2026-10-30 07:19:59 +07:00
m_st . dailyStartEquity = m_equity ;
m_st . dailyValid = true ;
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
m_st . dailyDate = UQDayStart ( now ) ;
m_st . dailyStartTime = now ;
2026-10-30 07:19:59 +07:00
m_st . dailyLock = false ;
m_st . dailyLockTime = 0 ;
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
m_st . monitorTime = now ;
2026-10-30 07:19:59 +07:00
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
PrintFormat ( " [UQ] Monitoring starts with risk cycle %s: D0 = %.2f for broker-server day %s. Equity changes before this moment are not measured. " ,
m_st . cycleId , m_equity , TimeToString ( m_st . dailyDate , TIME_DATE ) ) ;
2026-10-30 07:19:59 +07:00
}
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
m_d0 = m_st . dailyStartEquity ;
m_today = m_st . dailyDate ;
//--- D0 is adopted from the state and never re-measured here. Whether the
//--- current broker-server day may replace it is decided by the monitoring
//--- pass, which either proves an observed boundary, proves a constant
//--- equity path, or holds entries.
if ( UQDayStart ( now ) ! = m_st . dailyDate )
PrintFormat ( " [UQ] The persisted daily baseline D0 = %.2f belongs to broker-server day %s. It is preserved until the monitoring pass establishes the current day %s. " ,
m_d0 , TimeToString ( m_st . dailyDate , TIME_DATE ) ,
TimeToString ( UQDayStart ( now ) , TIME_DATE ) ) ;
m_dailyLossPct = ( ( m_d0 - m_equity ) / m_d0 ) * 100.0 ;
if ( m_dailyLossPct < 0.0 )
m_dailyLossPct = 0.0 ;
2026-10-30 07:19:59 +07:00
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
m_dailyFloor = m_d0 * ( 1.0 - m_cfg . dailyLimitPct / 100.0 ) ;
m_staticFloor = m_b0 * ( 1.0 - m_cfg . staticLimitPct / 100.0 ) ;
2026-10-30 07:19:59 +07:00
m_targetEquity = m_b0 * ( 1.0 + m_cfg . targetPct / 100.0 ) ;
return ( true ) ;
}
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
//+------------------------------------------------------------------+
//| Establish and verify daily monitoring continuity. |
//| |
//| The heartbeat is persisted with the risk state, so a trading day |
//| is only adopted when its boundary was observed while the EA was |
//| executing, or when the equity path across that boundary is |
//| provably constant (no position, no pending order, no deal). In |
//| every other case the previous D0 is preserved and a monitoring- |
//| gap hold blocks new entries until the next observed day boundary. |
//| The unobserved interval is reported with its exact length and is |
//| never presented as a successfully monitored trading day. |
//+------------------------------------------------------------------+
bool CUQRisk : : UpdateMonitoring ( const datetime now , const datetime today )
{
bool changed = false ;
if ( now < = 0 | | today < = 0 )
return ( false ) ;
const datetime last = m_st . monitorTime ;
//--- the unobserved window starts at the last proven moment: the heartbeat
//--- when there is one, otherwise the moment the persisted state was last
//--- written. Without either, nothing about the interval is proven.
const datetime ref = ( last > 0 ? last : m_st . updatedAt ) ;
const long gap = ( ( ref > 0 & & now > ref ) ? ( long ) ( now - ref ) : 0 ) ;
const long maxGap = ( long ) UQ_MONITOR_GAP_MAX_SECONDS ;
const long shown = ( gap > maxGap ? maxGap : gap ) ;
//--- 1. a broker-server day can only move backwards when the server clock
//--- is inconsistent; the daily history is then unverifiable
if ( today < m_st . dailyDate )
{
if ( ! m_st . gapHold )
{
m_st . gapHold = true ;
m_st . gapHoldTime = now ;
changed = true ;
PrintFormat ( " [UQ] MONITORING GAP HOLD: broker-server day moved backwards (%s -> %s). The daily baseline D0 = %.2f is preserved and new entries stay blocked until an observed day boundary. " ,
TimeToString ( m_st . dailyDate , TIME_DATE ) , TimeToString ( today , TIME_DATE ) ,
m_st . dailyStartEquity ) ;
}
}
//--- 2. a new broker-server trading day
else if ( m_st . dailyDate ! = today )
{
//--- continuity requires a heartbeat that is recent enough to prove the
//--- EA was executing at the boundary. A state with no heartbeat (a
//--- schema migrated from the previous build) proves nothing, so it must
//--- be reconstructed or held instead of being trusted.
const bool continuous = ( last > 0 & & gap < = ( long ) UQ_MONITOR_GAP_SECONDS ) ;
string detail = " " ;
const bool flat = ( continuous ? true : UQAccountProvablyFlat ( ref , now , detail ) ) ;
if ( ! flat )
{
if ( ! m_st . gapHold )
{
m_st . gapHold = true ;
m_st . gapHoldTime = now ;
PrintFormat ( " [UQ] MONITORING GAP HOLD: the broker-server day boundary between %s and %s was never observed (%d s) and the equity path cannot be reconstructed (%s). D0 stays at %.2f from %s, new entries are blocked and the loss of the unobserved interval is not claimed as measured. Entries resume only at a day boundary observed while the EA is executing. " ,
( ref > 0 ? TimeToString ( ref , TIME_DATE | TIME_SECONDS ) : " an unknown moment " ) ,
TimeToString ( now , TIME_DATE | TIME_SECONDS ) , ( int ) gap , detail ,
m_st . dailyStartEquity , TimeToString ( m_st . dailyDate , TIME_DATE ) ) ;
}
else
PrintFormat ( " [UQ] MONITORING GAP HOLD stays active: the day boundary between %s and %s is still unverified. " ,
( ref > 0 ? TimeToString ( ref , TIME_DATE | TIME_SECONDS ) : " an unknown moment " ) ,
TimeToString ( now , TIME_DATE | TIME_SECONDS ) ) ;
m_st . dailyDate = today ;
m_today = today ;
if ( m_st . monitorGapSeconds ! = ( int ) shown )
m_st . monitorGapSeconds = ( int ) shown ;
changed = true ;
}
else
{
m_st . dailyStartEquity = m_equity ;
m_st . dailyDate = today ;
m_st . dailyValid = true ;
m_st . dailyStartTime = now ;
m_st . dailyLock = false ;
m_st . dailyLockTime = 0 ;
m_st . monitorGapSeconds = 0 ;
m_d0 = m_equity ;
m_dailyFloor = m_d0 * ( 1.0 - m_cfg . dailyLimitPct / 100.0 ) ;
m_today = today ;
changed = true ;
if ( m_st . gapHold )
{
m_st . gapHold = false ;
m_st . gapHoldTime = 0 ;
PrintFormat ( " [UQ] MONITORING GAP HOLD cleared: broker-server day %s began while the EA was executing, so D0 = %.2f is established from an observed boundary. " ,
TimeToString ( today , TIME_DATE ) , m_equity ) ;
}
if ( continuous )
PrintFormat ( " [UQ] New broker-server trading day %s: D0 = %.2f, daily loss lock cleared. Permanent locks are never cleared by a rollover. " ,
TimeToString ( today , TIME_DATE ) , m_equity ) ;
else
PrintFormat ( " [UQ] RECONSTRUCTED DAY: no position, no pending order and no deal existed between %s and %s (%s), so the equity path was constant and D0 = %.2f is exact for broker-server day %s. " ,
( ref > 0 ? TimeToString ( ref , TIME_DATE | TIME_SECONDS ) : " an unknown moment " ) ,
TimeToString ( now , TIME_DATE | TIME_SECONDS ) , detail ,
m_equity , TimeToString ( today , TIME_DATE ) ) ;
}
}
//--- 3. the same trading day is still monitored: D0 stands, so the daily
//--- loss of an unobserved interval is measured late, never skipped
else if ( gap > ( long ) UQ_MONITOR_GAP_SECONDS & & ! m_st . gapHold )
{
if ( m_st . monitorGapSeconds ! = ( int ) shown )
{
m_st . monitorGapSeconds = ( int ) shown ;
changed = true ;
PrintFormat ( " [UQ] WARNING: risk evaluation resumed after %d s without a monitoring pass. The daily baseline D0 = %.2f for broker-server day %s is preserved, so the equity change is still measured against it; during the gap no threshold was evaluated, so a breach could have gone unanswered for that interval. " ,
( int ) gap , m_st . dailyStartEquity , TimeToString ( today , TIME_DATE ) ) ;
}
}
//--- 4. heartbeat: refreshed on every pass and persisted at a bounded
//--- interval, so the state file is not rewritten on every tick
if ( m_st . monitorTime < = 0 | |
now > = m_st . monitorTime + ( datetime ) UQ_MONITOR_HEARTBEAT_SECONDS )
{
m_st . monitorTime = now ;
changed = true ;
}
return ( changed ) ;
}
2026-10-30 07:19:59 +07:00
//+------------------------------------------------------------------+
//| Re-evaluate the three thresholds. |
//| Returns true when persisted state was modified. |
//+------------------------------------------------------------------+
bool CUQRisk : : EvaluateLocks ( void )
{
bool changed = false ;
m_equity = AccountInfoDouble ( ACCOUNT_EQUITY ) ;
if ( ! ( m_equity > 0.0 ) )
{
m_block = UQ_BLOCK_BASELINE ;
return ( false ) ;
}
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
//--- Monitoring continuity is established before any threshold is trusted.
//--- A new broker-server day is adopted only when its boundary was observed
//--- while the EA was executing, or when the equity path across it can be
//--- proven constant. Otherwise the previous D0 is preserved and a hold
//--- blocks entries: an unmonitored interval is never reported as a
//--- monitored trading day and D0 is never silently re-measured.
const datetime now = UQServerNow ( ) ;
const datetime today = ( now > 0 ? UQDayStart ( now ) : 0 ) ;
if ( now < = 0 | | today < = 0 )
2026-10-30 07:19:59 +07:00
{
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
m_block = UQ_BLOCK_BASELINE ;
return ( changed ) ;
2026-10-30 07:19:59 +07:00
}
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
if ( UpdateMonitoring ( now , today ) )
changed = true ;
2026-10-30 07:19:59 +07:00
if ( ! ( m_b0 > 0.0 ) | | ! ( m_d0 > 0.0 ) | | ! m_st . baselineValid )
{
m_block = UQ_BLOCK_BASELINE ;
return ( changed ) ;
}
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
//--- the daily loss is always measured against the baseline the state
//--- carries. While a monitoring-gap hold is active that baseline is the
//--- preserved one, so a breach is still acted on instead of being skipped.
2026-10-30 07:19:59 +07:00
m_dailyLossPct = ( ( m_d0 - m_equity ) / m_d0 ) * 100.0 ;
if ( m_dailyLossPct < 0.0 )
m_dailyLossPct = 0.0 ;
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
2026-10-30 07:19:59 +07:00
m_staticDdPct = ( ( m_b0 - m_equity ) / m_b0 ) * 100.0 ;
//--- permanent static-drawdown lock
if ( ! m_st . staticLock & & m_staticDdPct > = m_cfg . staticLimitPct )
{
m_st . staticLock = true ;
m_st . staticLockTime = TimeCurrent ( ) ;
changed = true ;
PrintFormat ( " [UQ] PERMANENT LOCK: static drawdown %.3f%% >= %.2f%% (equity %.2f, B0 %.2f). " ,
m_staticDdPct , m_cfg . staticLimitPct , m_equity , m_b0 ) ;
}
//--- permanent equity-target lock
if ( ! m_st . targetLock & & m_equity > = m_targetEquity )
{
m_st . targetLock = true ;
m_st . targetLockTime = TimeCurrent ( ) ;
changed = true ;
PrintFormat ( " [UQ] PERMANENT LOCK: equity %.2f reached target %.2f (B0 %.2f + %.2f%%). " ,
m_equity , m_targetEquity , m_b0 , m_cfg . targetPct ) ;
}
//--- daily loss lock
if ( ! m_st . dailyLock & & m_dailyLossPct > = m_cfg . dailyLimitPct )
{
m_st . dailyLock = true ;
m_st . dailyLockTime = TimeCurrent ( ) ;
changed = true ;
PrintFormat ( " [UQ] LOCK: daily loss %.3f%% >= %.2f%% (equity %.2f, D0 %.2f). " ,
m_dailyLossPct , m_cfg . dailyLimitPct , m_equity , m_d0 ) ;
}
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
ApplyBlock ( ) ;
2026-10-30 07:19:59 +07:00
return ( changed ) ;
}
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
//+------------------------------------------------------------------+
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
//| Load the persistent state, order it against its backup by the |
//| generation each file carries, and reconcile the redundant |
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
//| initialization marker. Fails closed on every uncertain condition. |
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
//| |
//| A backup is evidence that this scope was already initialized, so a |
//| missing primary is never a fresh installation. A state that had to |
//| be recovered, that was adopted from a newer backup or that had to |
//| be ordered against a conflict is never entry-permitted: it starts |
//| behind a persisted recovery hold that only an explicit owner |
//| authorization can clear. |
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
//+------------------------------------------------------------------+
bool CUQRisk : : LoadPersistentState ( void )
{
const string primary = UQStateFileName ( m_id ) ;
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
const string backup = UQStateBackupFileName ( m_id ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
UQRiskState prim ;
UQRiskState back ;
string perr = " " ;
string berr = " " ;
long revPrimary = 0 ;
long revBackup = 0 ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
const ENUM_UQ_STATE_LOAD loadPrimary = UQStateLoadGenerational ( primary , m_id , prim , revPrimary , perr ) ;
const ENUM_UQ_STATE_LOAD loadBackup = UQStateLoadGenerational ( backup , m_id , back , revBackup , berr ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
const bool primaryUsable = ( loadPrimary = = UQ_LOAD_VALID | | loadPrimary = = UQ_LOAD_LEGACY ) ;
const bool backupUsable = ( loadBackup = = UQ_LOAD_VALID | | loadBackup = = UQ_LOAD_LEGACY ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
//--- A. nothing is stored for this scope at all: a new risk cycle requires
//--- an explicit owner authorization and is refused while a redundant
//--- marker proves that a previous initialization existed
if ( ! primaryUsable & & loadPrimary = = UQ_LOAD_ABSENT & & loadBackup = = UQ_LOAD_ABSENT )
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
{
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
datetime markerEvidence = 0 ;
if ( UQStateMarkerCheck ( m_id , 0 , markerEvidence ) ! = UQ_MARKER_ABSENT )
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
{
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
m_lastError = StringFormat ( " risk state and backup are missing but an initialization marker from %s exists; a new risk cycle is refused " ,
TimeToString ( markerEvidence , TIME_DATE | TIME_SECONDS ) ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
PrintFormat ( " [UQ] ERROR: %s " , m_lastError ) ;
return ( false ) ;
}
if ( ! m_cfg . allowFirstInit )
{
m_lastError = " no persistent risk state exists and a new risk cycle is not authorized " ;
PrintFormat ( " [UQ] ERROR: %s. Set the first-initialization authorization input only after confirming that this portfolio has never been initialized. " , m_lastError ) ;
return ( false ) ;
}
if ( ! ( m_cfg . balanceOverride > 0.0 ) )
{
m_lastError = " a new risk cycle requires an explicit positive initial balance B0 " ;
PrintFormat ( " [UQ] ERROR: %s. The current account balance is deliberately not used as a substitute. " , m_lastError ) ;
return ( false ) ;
}
if ( ! EstablishInitialBaseline ( ) )
return ( false ) ;
if ( ! EstablishDailyBaseline ( ) )
return ( false ) ;
EvaluateLocks ( ) ;
//--- persist before the cycle may be used, then prove it exists
if ( ! Save ( ) )
return ( false ) ;
if ( ! UQStateMarkerSet ( m_id , m_st . createdAt ) )
{
m_lastError = " initialization marker could not be persisted " ;
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
PrintFormat ( " [UQ] ERROR: %s " , m_lastError ) ;
return ( false ) ;
}
datetime markerCheck = 0 ;
if ( UQStateMarkerCheck ( m_id , m_st . createdAt , markerCheck ) ! = UQ_MARKER_MATCH )
{
m_lastError = " initialization marker could not be verified after it was written " ;
PrintFormat ( " [UQ] ERROR: %s " , m_lastError ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
return ( false ) ;
}
2026-10-30 08:37:46 +07:00
m_cycleId = m_st . cycleId ;
m_cycleSequence = m_st . cycleSequence ;
if ( m_cfg . resetRequest ! = UQ_RESET_NONE )
PrintFormat ( " [UQ] WARNING: the owner reset request is ignored because this scope holds no risk cycle yet; the new cycle is created by the initialization authorization instead. " ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
m_freshInstall = true ;
return ( true ) ;
}
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
//--- B. an existing but unusable primary is never replaced silently, and a
//--- backup is never restored without the owner authorization
if ( ! primaryUsable )
{
if ( ! backupUsable )
{
m_lastError = StringFormat ( " the persistent risk state is %s%s and the backup is %s%s; recovery is ambiguous and a new risk cycle is refused " ,
UQStateLoadText ( loadPrimary ) ,
( StringLen ( perr ) > 0 ? " ( " + perr + " ) " : " " ) ,
UQStateLoadText ( loadBackup ) ,
( StringLen ( berr ) > 0 ? " ( " + berr + " ) " : " " ) ) ;
PrintFormat ( " [UQ] ERROR: %s " , m_lastError ) ;
return ( false ) ;
}
if ( ! m_cfg . allowBackupRestore )
{
m_lastError = StringFormat ( " the persistent risk state is %s%s and restoring the verified backup is not authorized; a new risk cycle is refused " ,
UQStateLoadText ( loadPrimary ) ,
( StringLen ( perr ) > 0 ? " ( " + perr + " ) " : " " ) ) ;
PrintFormat ( " [UQ] ERROR: %s " , m_lastError ) ;
return ( false ) ;
}
}
//--- C. order the two verified files by the generation each one carries
string holdReason = " " ;
bool holdNeeded = false ;
if ( primaryUsable & & backupUsable )
{
if ( revPrimary > revBackup )
{
m_st = prim ;
PrintFormat ( " [UQ] Persistent state generation %I64d is newer than the backup generation %I64d; the primary is authoritative. " ,
revPrimary , revBackup ) ;
}
else if ( revPrimary = = revBackup )
{
if ( UQStateCanonicalBody ( prim ) ! = UQStateCanonicalBody ( back ) )
{
m_lastError = StringFormat ( " the primary and the backup disagree at generation %I64d; the latest lock state cannot be established and a new risk cycle is refused " ,
revPrimary ) ;
PrintFormat ( " [UQ] ERROR: %s " , m_lastError ) ;
return ( false ) ;
}
m_st = prim ;
}
else
{
if ( revBackup ! = revPrimary + 1 )
{
m_lastError = StringFormat ( " the backup generation %I64d is inconsistent with the primary generation %I64d; the state ordering cannot be established " ,
revBackup , revPrimary ) ;
PrintFormat ( " [UQ] ERROR: %s " , m_lastError ) ;
return ( false ) ;
}
//--- the interrupted commit is exactly the write-ahead window: the
//--- backup holds the newer verified generation, the primary the
//--- previous one. The newer verified generation wins, but never into
//--- an entry-permitted condition.
m_st = back ;
m_restoredBackup = true ;
holdNeeded = true ;
holdReason = StringFormat ( " the latest verified generation %I64d exists only in the backup because an interrupted commit left the primary at generation %I64d " ,
revBackup , revPrimary ) ;
}
}
else if ( primaryUsable )
{
m_st = prim ;
}
else
{
m_st = back ;
m_restoredBackup = true ;
holdNeeded = true ;
holdReason = ( loadPrimary = = UQ_LOAD_ABSENT
? StringFormat ( " the primary state file is missing while a verified backup at generation %I64d proves that this scope was already initialized " , revBackup )
: StringFormat ( " the primary state file is unusable and the verified backup at generation %I64d was restored " , revBackup ) ) ;
PrintFormat ( " [UQ] WARNING: risk state restored from the verified backup '%s' under explicit owner authorization. " ,
backup ) ;
}
//--- D. the redundant marker must agree with the state that was chosen
datetime markerTime = 0 ;
const ENUM_UQ_MARKER_STATE marker = UQStateMarkerCheck ( m_id , m_st . createdAt , markerTime ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
if ( marker = = UQ_MARKER_MISMATCH )
{
m_lastError = StringFormat ( " initialization marker (%s) disagrees with the persisted state (%s); refusing to start " ,
TimeToString ( markerTime , TIME_DATE | TIME_SECONDS ) ,
TimeToString ( m_st . createdAt , TIME_DATE | TIME_SECONDS ) ) ;
PrintFormat ( " [UQ] ERROR: %s " , m_lastError ) ;
return ( false ) ;
}
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
//--- E. a recovered or reordered state is never entry-permitted
if ( holdNeeded & & ! m_st . recoveryHold )
{
m_st . recoveryHold = true ;
m_st . recoveryHoldTime = UQServerNow ( ) ;
if ( m_st . recoveryHoldTime < = 0 )
m_st . recoveryHoldTime = TimeCurrent ( ) ;
PrintFormat ( " [UQ] RECOVERY HOLD: %s. New entries are blocked until the owner authorizes a recovery risk cycle. " ,
holdReason ) ;
}
if ( m_st . recoveryHold )
PrintFormat ( " [UQ] RECOVERY HOLD is active since %s. New entries stay blocked until the owner authorizes recovery with a fresh nonce. " ,
TimeToString ( m_st . recoveryHoldTime , TIME_DATE | TIME_SECONDS ) ) ;
if ( loadPrimary = = UQ_LOAD_LEGACY | | loadBackup = = UQ_LOAD_LEGACY )
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
{
m_migrated = true ;
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
PrintFormat ( " [UQ] A persisted state uses the previous published schema; it is migrated to schema %d after validation. " ,
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
UQ_STATE_FORMAT ) ;
}
if ( ! EstablishBaselineFromState ( ) )
return ( false ) ;
if ( ! EstablishDailyBaseline ( ) )
return ( false ) ;
2026-10-30 08:37:46 +07:00
//--- a rejected reset must not stop risk management: it blocks entries
ApplyResetRequest ( ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
EvaluateLocks ( ) ;
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
//--- rewriting migrates a legacy schema, mirrors the backup with the same
//--- verified generation and persists the recovery hold
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
if ( ! Save ( ) )
return ( false ) ;
2026-10-30 08:37:46 +07:00
m_cycleId = m_st . cycleId ;
m_cycleSequence = m_st . cycleSequence ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
if ( marker = = UQ_MARKER_ABSENT )
{
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
PrintFormat ( " [UQ] WARNING: the initialization marker was absent; it is re-established from the verified state file. " ) ;
if ( ! UQStateMarkerSet ( m_id , m_st . createdAt ) )
{
m_lastError = " the initialization marker could not be restored from the verified state " ;
PrintFormat ( " [UQ] ERROR: %s. The persistence scope is not healthy and new entries stay blocked. " , m_lastError ) ;
return ( false ) ;
}
datetime restored = 0 ;
if ( UQStateMarkerCheck ( m_id , m_st . createdAt , restored ) ! = UQ_MARKER_MATCH )
{
m_lastError = " the restored initialization marker could not be verified " ;
PrintFormat ( " [UQ] ERROR: %s. The persistence scope is not healthy and new entries stay blocked. " , m_lastError ) ;
return ( false ) ;
}
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
}
return ( true ) ;
}
2026-10-30 08:52:18 +07:00
//+------------------------------------------------------------------+
//| Aggregate exposure of this portfolio: verified broker exposure |
//| plus the entry money that is still reserved. |
//+------------------------------------------------------------------+
bool CUQRisk : : Exposure ( const ulong magic , UQExposure & out )
{
fix: fail closed on invalid aggregate exposure
UQExposureFromPools() no longer converts an unusable OrderCalcProfit() result into a plausible risk with MathAbs().
Every owned position and pending order is now validated: direction, instrument pricing, volume, entry/reference price, protective stop, stop side, OrderCalcProfit success, finiteness and a strictly adverse monetary result. A zero, positive, non-finite or inconsistent result marks the aggregate exposure unbounded, records the symbol, ticket and reason, and refuses new entries instead of counting the item as zero risk.
The conservative worse-of opening/current reference rule is unchanged, the aggregate formula (1.0% of live equity) is unchanged, and unquantifiable exposure is never represented as zero. The volume sizing and the reserved entry risk in UQ_Exec.mqh require the same adverse result, so a fabricated amount can never enter the reservation or the ceiling.
2026-10-30 10:33:44 +07:00
UQExposureFromPools ( magic , m_st . reserveMoney , out ) ;
//--- an entry reservation that carries no usable monetary amount cannot be
//--- quantified either: it must never disappear from the aggregate as if it
//--- had been zero risk, so the exposure stays unbounded and entries closed
if ( m_st . reserveState ! = UQ_RESERVE_NONE & & ! ( m_st . reserveMoney > 0.0 ) )
UQExposureNote ( out , m_st . reserveSymbol , m_st . reserveTicket ,
" reservation without a usable monetary risk " ) ;
return ( out . bounded ) ;
2026-10-30 08:52:18 +07:00
}
//+------------------------------------------------------------------+
//| Clear the reservation fields without persisting |
//+------------------------------------------------------------------+
void CUQRisk : : ClearReservation ( void )
{
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
m_st . reserveState = UQ_RESERVE_NONE ;
m_st . reserveMoney = 0.0 ;
m_st . reserveTicket = 0 ;
m_st . reserveSymbol = " " ;
m_st . reserveTime = 0 ;
m_st . reserveId = " " ;
m_st . reserveMagic = 0 ;
m_st . reserveScope = " " ;
m_st . reserveDirection = 0 ;
m_st . reserveVolume = 0.0 ;
m_st . reserveEntry = 0.0 ;
m_st . reserveStop = 0.0 ;
m_st . reserveDeal = 0 ;
m_st . reservePosition = 0 ;
m_reserveCheckAt = 0 ;
2026-10-30 08:52:18 +07:00
}
//+------------------------------------------------------------------+
//| Reserve the monetary risk of an entry BEFORE the order is sent. |
//| |
//| The reservation is persisted first: an entry whose risk cannot be |
//| written to disk must not be submitted at all, otherwise a restart |
//| would forget exposure that the account actually carries. |
//+------------------------------------------------------------------+
bool CUQRisk : : ReserveEntryRisk ( const ulong magic , const string symbol ,
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
const int direction , const double volume ,
const double entry , const double stop ,
2026-10-30 08:52:18 +07:00
const double money , string & err )
{
err = " " ;
if ( ! m_ready )
{
err = " the risk controller is not initialised " ;
return ( false ) ;
}
if ( ! m_healthy )
{
err = " risk-state persistence is unhealthy, so no entry risk can be reserved " ;
return ( false ) ;
}
if ( m_st . reserveState ! = UQ_RESERVE_NONE )
{
err = StringFormat ( " an earlier entry (%s, %.2f) is still unreconciled " ,
m_st . reserveSymbol , m_st . reserveMoney ) ;
return ( false ) ;
}
if ( ! ( money > 0.0 ) )
{
err = " the reserved entry risk is not positive " ;
return ( false ) ;
}
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
if ( ! UQReserveTextSafe ( symbol , UQ_RESERVE_SYMBOL_MAX_LEN ) )
2026-10-30 08:52:18 +07:00
{
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
err = " the entry symbol is empty, too long or carries a format character " ;
2026-10-30 08:52:18 +07:00
return ( false ) ;
}
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
if ( direction ! = 1 & & direction ! = -1 )
2026-10-30 08:52:18 +07:00
{
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
err = " the entry direction is not buy or sell " ;
return ( false ) ;
}
if ( ! ( volume > 0.0 ) | | ! ( entry > 0.0 ) | | ! ( stop > 0.0 ) )
{
err = " the entry request carries no usable volume, price and stop " ;
2026-10-30 08:52:18 +07:00
return ( false ) ;
}
const datetime now = UQServerNow ( ) ;
if ( now < = 0 )
{
err = " broker-server time is unavailable " ;
return ( false ) ;
}
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
m_reserveSeq + + ;
const string rid = UQBuildReserveId ( m_id . key , symbol , now , m_reserveSeq ) ;
if ( ! UQReserveTextSafe ( rid , UQ_RESERVE_ID_MAX_LEN ) )
{
err = " the entry reservation identifier could not be built " ;
return ( false ) ;
}
m_st . reserveState = UQ_RESERVE_SENT ;
m_st . reserveMoney = money ;
m_st . reserveTicket = 0 ;
m_st . reserveSymbol = symbol ;
m_st . reserveTime = now ;
m_st . reserveId = rid ;
m_st . reserveMagic = magic ;
m_st . reserveScope = ( StringLen ( m_cfg . portfolio ) < = UQ_RESERVE_SCOPE_MAX_LEN ?
m_cfg . portfolio : " " ) ;
m_st . reserveDirection = direction ;
m_st . reserveVolume = volume ;
m_st . reserveEntry = entry ;
m_st . reserveStop = stop ;
m_st . reserveDeal = 0 ;
m_st . reservePosition = 0 ;
m_reserveCheckAt = 0 ;
2026-10-30 08:52:18 +07:00
if ( ! Save ( ) )
{
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
//--- nothing was submitted yet: the reservation is withdrawn again,
//--- while the persistence-health block keeps further entries closed
2026-10-30 08:52:18 +07:00
ClearReservation ( ) ;
err = " the entry-risk reservation could not be persisted: " + m_lastSaveError ;
ApplyBlock ( ) ;
return ( false ) ;
}
ApplyBlock ( ) ;
return ( true ) ;
}
//+------------------------------------------------------------------+
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
//| Record the tickets returned by an accepted entry order |
//| |
//| The order ticket and the deal ticket are different identities and |
//| are stored separately. Neither is promoted to a position |
//| identifier here: that link only comes from a verified deal record. |
2026-10-30 08:52:18 +07:00
//+------------------------------------------------------------------+
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
bool CUQRisk : : NoteSubmittedTickets ( const ulong orderTicket , const ulong dealTicket )
2026-10-30 08:52:18 +07:00
{
if ( m_st . reserveState = = UQ_RESERVE_NONE )
return ( true ) ;
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
m_st . reserveTicket = orderTicket ;
m_st . reserveDeal = dealTicket ;
2026-10-30 08:52:18 +07:00
if ( ! Save ( ) )
{
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
m_lastError = " the submitted order and deal tickets could not be persisted " ;
2026-10-30 08:52:18 +07:00
ApplyBlock ( ) ;
return ( false ) ;
}
ApplyBlock ( ) ;
return ( true ) ;
}
//+------------------------------------------------------------------+
//| Release a reservation after verified evidence that it carries no |
//| exposure any more. The release is persisted; if that fails the |
//| controller stays unhealthy and entries stay blocked. |
//+------------------------------------------------------------------+
void CUQRisk : : ReleaseReservation ( const string why )
{
if ( m_st . reserveState = = UQ_RESERVE_NONE )
return ;
const string sym = m_st . reserveSymbol ;
const double money = m_st . reserveMoney ;
const ulong tick = m_st . reserveTicket ;
ClearReservation ( ) ;
if ( ! Save ( ) )
PrintFormat ( " [UQ] ERROR: the released reservation of %.2f %s could not be persisted; entries stay blocked. " , money , sym ) ;
ApplyBlock ( ) ;
PrintFormat ( " [UQ] Entry risk released: %s | money=%.2f symbol=%s ticket=%s " ,
why , money , sym , IntegerToString ( ( long ) tick ) ) ;
}
//+------------------------------------------------------------------+
//| Reconcile an accepted entry order with the live broker state. |
//| |
//| While the reconciliation window is open the reserved money keeps |
//| counting as exposure. After it, only a connected terminal may |
//| prove that nothing is exposed; otherwise the reservation becomes |
//| UNRESOLVED and new entries stay blocked. |
//+------------------------------------------------------------------+
void CUQRisk : : ReconcileReservation ( void )
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
{
ReconcileReservationDepth ( false ) ;
}
//+------------------------------------------------------------------+
//| Depth-limited reconciliation. 'forced' bypasses the throttle and |
//| is used by the transaction handler, so a fill converts the |
//| reservation as soon as the broker reports the deal. |
//+------------------------------------------------------------------+
void CUQRisk : : ReconcileReservationDepth ( const bool forced )
2026-10-30 08:52:18 +07:00
{
if ( m_st . reserveState = = UQ_RESERVE_NONE )
return ;
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
const datetime now = UQServerNow ( ) ;
//--- the correlation scans the deal history, so a repeated call inside the
//--- throttle window is skipped. The reserved money keeps counting while a
//--- check is skipped, so skipping can never free risk.
if ( ! forced & & m_reserveCheckAt > 0 & & now > 0 & &
now < m_reserveCheckAt + ( datetime ) ( UQ_RESERVE_RECONCILE_SECONDS / 4 ) )
return ;
m_reserveCheckAt = now ;
UQReserveEvidence ev ;
UQReserveCorrelate ( m_cfg . magic , m_st , ev ) ;
const ulong order = m_st . reserveTicket ;
const ulong deal = m_st . reserveDeal ;
const string sym = m_st . reserveSymbol ;
const string rid = m_st . reserveId ;
const double money = m_st . reserveMoney ;
2026-10-30 08:52:18 +07:00
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
//--- 1. more than one candidate: never guess, never release
if ( ev . ambiguous )
2026-10-30 08:52:18 +07:00
{
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
MarkReservationUnresolved ( " several broker records could belong to this request ( " + ev . detail + " ) " , ev ) ;
return ;
}
//--- 2. verified: an active order, or a deal traced to this request, is
//--- real exposure. The reserved money stops counting because the pools
//--- now measure the same exposure instead.
if ( ev . orderLive | | ev . dealCount > 0 )
{
const ulong verifiedOrder = ( ev . liveOrder > 0 ? ev . liveOrder : order ) ;
2026-10-30 08:52:18 +07:00
ClearReservation ( ) ;
if ( ! Save ( ) )
PrintFormat ( " [UQ] ERROR: the reconciled reservation could not be persisted; entries stay blocked. " ) ;
ApplyBlock ( ) ;
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
PrintFormat ( " [UQ] Entry risk converted: id=%s %s order=%s deal=%s position=%s. %d unrelated owned position(s) were not used as evidence. " ,
rid , sym , IntegerToString ( ( long ) verifiedOrder ) ,
IntegerToString ( ( long ) ev . dealTicket ) , IntegerToString ( ( long ) ev . positionId ) ,
ev . unrelatedCount ) ;
2026-10-30 08:52:18 +07:00
return ;
}
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
//--- 3. the order history proves that the request left no exposure
if ( ev . noExposureProven )
{
ReleaseReservation ( StringFormat ( " the order history proves that ticket=%s never executed " ,
IntegerToString ( ( long ) order ) ) ) ;
return ;
}
//--- 4. no evidence yet: the reservation keeps counting as exposure and no
//--- conclusion is drawn before the reconciliation window has elapsed
2026-10-30 08:52:18 +07:00
if ( now < = 0 | | m_st . reserveTime < = 0 | |
now < m_st . reserveTime + ( datetime ) UQ_RESERVE_RECONCILE_SECONDS )
return ;
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
//--- 5. the window elapsed without a verifiable answer
if ( ! ev . connected )
2026-10-30 08:52:18 +07:00
{
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
MarkReservationUnresolved ( " the terminal is disconnected, so the broker state cannot be verified " , ev ) ;
2026-10-30 08:52:18 +07:00
return ;
}
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
MarkReservationUnresolved ( StringFormat ( " no broker transaction matches id=%s order=%s deal=%s within %d seconds; the request may still have been executed " ,
rid , IntegerToString ( ( long ) order ) , IntegerToString ( ( long ) deal ) ,
UQ_RESERVE_RECONCILE_SECONDS ) , ev ) ;
}
//+------------------------------------------------------------------+
//| Persist an unverifiable reservation as UNRESOLVED. |
//| |
//| The money keeps counting as exposure and every new entry stays |
//| blocked. This is the case the reservation exists for: an answer |
//| that cannot be established is not a rejection. |
//+------------------------------------------------------------------+
void CUQRisk : : MarkReservationUnresolved ( const string why , UQReserveEvidence & ev )
{
if ( m_st . reserveState = = UQ_RESERVE_NONE )
return ;
const bool first = ( m_st . reserveState ! = UQ_RESERVE_UNRESOLVED ) ;
m_st . reserveState = UQ_RESERVE_UNRESOLVED ;
if ( ev . dealTicket > 0 & & m_st . reserveDeal = = 0 )
m_st . reserveDeal = ev . dealTicket ;
if ( ev . positionId > 0 & & m_st . reservePosition = = 0 )
m_st . reservePosition = ev . positionId ;
m_lastError = " entry reservation unresolved: " + why ;
//--- an already persisted UNRESOLVED reservation needs no rewrite; the
//--- block is re-applied so a persistence-health change still wins
if ( first & & ! Save ( ) )
2026-10-30 08:52:18 +07:00
{
ApplyBlock ( ) ;
return ;
}
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
ApplyBlock ( ) ;
2026-10-30 08:52:18 +07:00
fix: correlate outstanding entry risk reservations
A reservation could be released merely because an unrelated position or pending order existed under the same Magic Number, and an order ticket was treated as a position ticket. An entry whose submission result was lost also released its reserved risk.
- UQ_Defs: state schema 5 adds the reservation identity; ENUM_UQ_SUBMIT_RESULT and a retcode classifier that only accepts proven non-execution.
- UQ_State: reservation id, magic, scope, direction, volume, entry, stop, order/deal/position tickets are persisted, checksummed and strictly validated. A previous-schema reservation migrates to UNRESOLVED with its money preserved, never to NONE.
- UQ_Risk: UQReserveCorrelate links a reservation to the broker only through its own order ticket, a deal whose DEAL_ORDER is that ticket, or the traced POSITION_IDENTIFIER. Ambiguity, a disconnected terminal and a missing record all keep the money reserved as UNRESOLVED and block entries.
- UQ_Exec: UQSendMarket reports the submission outcome; the caller withdraws reserved risk only on a local preflight failure or a proven broker rejection.
- Universal_Quant_EA.mq5: deals and order transactions reconcile the reservation immediately; status and startup diagnostics expose the reservation identity.
2026-10-30 10:43:15 +07:00
if ( first )
PrintFormat ( " [UQ] ERROR: %s. %.2f %s stays reserved (id=%s order=%s) and new entries are blocked until the broker state can be verified. " ,
m_lastError , m_st . reserveMoney , m_st . reserveSymbol , m_st . reserveId ,
IntegerToString ( ( long ) m_st . reserveTicket ) ) ;
2026-10-30 08:52:18 +07:00
}
2026-10-30 07:19:59 +07:00
//+------------------------------------------------------------------+
//| Initialise the controller. Fails closed on any integrity problem. |
//+------------------------------------------------------------------+
bool CUQRisk ::Init ( UQRiskConfig & cfg )
{
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
m_ready = false ;
m_healthy = false ;
m_freshInstall = false ;
m_migrated = false ;
m_restoredBackup = false ;
2026-10-30 08:37:46 +07:00
m_resetRejected = false ;
m_resetApplied = false ;
m_cycleId = " " ;
m_cycleSequence = 0 ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
m_lastError = " " ;
m_lastSaveError = " " ;
m_saveRetryAt = 0 ;
m_equity = 0.0 ;
m_b0 = 0.0 ;
m_d0 = 0.0 ;
m_dailyLossPct = 0.0 ;
m_staticDdPct = 0.0 ;
m_targetEquity = 0.0 ;
m_dailyFloor = 0.0 ;
m_staticFloor = 0.0 ;
m_today = 0 ;
m_block = UQ_BLOCK_BASELINE ;
m_cfg = cfg ;
UQStateReset ( m_st ) ;
2026-10-30 07:19:59 +07:00
if ( ! ( cfg . dailyLimitPct > 0.0 & & cfg . dailyLimitPct < 100.0 ) )
{
m_lastError = " daily maximum loss percentage is outside (0, 100) " ;
return ( false ) ;
}
if ( ! ( cfg . staticLimitPct > 0.0 & & cfg . staticLimitPct < 100.0 ) )
{
m_lastError = " static maximum drawdown percentage is outside (0, 100) " ;
return ( false ) ;
}
if ( ! ( cfg . targetPct > 0.0 & & cfg . targetPct < = 1000.0 ) )
{
m_lastError = " equity growth target percentage is outside (0, 1000] " ;
return ( false ) ;
}
if ( cfg . balanceOverride < 0.0 )
{
m_lastError = " initial balance override must not be negative " ;
return ( false ) ;
}
2026-10-30 08:37:46 +07:00
if ( cfg . resetBaseline < 0.0 )
{
m_lastError = " the baseline of a new risk cycle must not be negative " ;
return ( false ) ;
}
2026-10-30 08:52:18 +07:00
if ( cfg . magic = = 0 )
{
m_lastError = " a positive Magic Number is required to account for the portfolio exposure " ;
return ( false ) ;
}
2026-10-30 08:37:46 +07:00
if ( cfg . resetRequest ! = UQ_RESET_NONE & &
cfg . resetRequest ! = UQ_RESET_STATIC & &
cfg . resetRequest ! = UQ_RESET_TARGET & &
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
cfg . resetRequest ! = UQ_RESET_BOTH & &
cfg . resetRequest ! = UQ_RESET_RECOVERY )
2026-10-30 08:37:46 +07:00
{
m_lastError = " unrecognized owner reset request " ;
return ( false ) ;
}
2026-10-30 07:19:59 +07:00
string err = " " ;
if ( ! UQBuildIdentity ( cfg . portfolio , m_id , err ) )
{
m_lastError = err ;
return ( false ) ;
}
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
if ( ! LoadPersistentState ( ) )
2026-10-30 07:19:59 +07:00
return ( false ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
if ( ! m_healthy )
{
m_lastError = " persistent risk state could not be written during initialization " ;
2026-10-30 07:19:59 +07:00
return ( false ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
}
2026-10-30 07:19:59 +07:00
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
//--- the block reason must reflect the fully reconciled state
ApplyBlock ( ) ;
2026-10-30 07:19:59 +07:00
m_ready = true ;
PrintFormat ( " [UQ] Risk scope '%s' | B0=%.2f D0=%.2f equity=%.2f target=%.2f dailyFloor=%.2f staticFloor=%.2f state=%s " ,
m_id . key , m_b0 , m_d0 , m_equity , m_targetEquity , m_dailyFloor , m_staticFloor ,
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
( m_freshInstall ? " new " : ( m_restoredBackup ? " restored-from-backup " : " restored " ) ) ) ;
PrintFormat ( " [UQ] Risk state: staticLock=%s targetLock=%s dailyLock=%s block=%s " ,
( m_st . staticLock ? " ON " : " off " ) , ( m_st . targetLock ? " ON " : " off " ) ,
( m_st . dailyLock ? " ON " : " off " ) , UQBlockText ( m_block ) ) ;
2026-10-30 07:19:59 +07:00
fix: recover the latest verified persistent state
The backup was built from the previous primary before the new primary was installed, so it could lag the newest successful update, and a missing primary was still treated as a candidate fresh installation. Neither an interrupted commit nor a stale mirror was detectable.
B1 state schema 6 (defines UQ_STATE_FORMAT=6, UQ_STATE_IDENTITY_FORMAT=5) adds a monotonic stateRevision plus recoveryHold/recoveryHoldTime. Formats 1..5 keep their own field block, so every published checksum still verifies over exactly the block that produced it, and a migration sets generation 1 without inventing a lock event.
B2 UQStateSave is write-ahead and generation-aware: the next generation is derived from what is proven on disk (primary and backup), the staged file is written and read back, the same verified bytes go to the backup and are read back, the primary is replaced and read back, and primary and backup are finally reconciled on generation and content. A newer verified state is never overwritten by an older instance; a failure at any step returns false, which blocks every new entry.
B3 LoadPersistentState orders primary and backup by generation: newer primary wins, equal generations must agree on content (otherwise fail closed), and a backup exactly one generation ahead is the interrupted-commit window and is adopted. Anything else is refused.
B4 a backup is evidence of a previous initialization, so a missing primary is never a fresh installation and never creates a replacement B0; a verified backup is restored only under explicit owner authorization.
B5 a recovered, reordered or superseded state always starts behind a persisted recovery hold (UQ_BLOCK_RECOVERY) that survives restart and only an explicit owner-authorized recovery risk cycle (UQ_RESET_RECOVERY, fresh nonce, explicit B0, flat scope) can clear. A recovery never clears a permanent lock the recovered state carries, and a cycle without a prior permanent lock records no prior-cycle reference instead of an inconsistent one.
B6 the initialization marker is written and then verified; a marker that cannot be persisted or verified fails the load closed.
B7 the status panel reports the persistence generation and an active recovery hold.
2026-10-30 11:09:43 +07:00
PrintFormat ( " [UQ] Persistence generation %I64d | recoveryHold=%s | primary=%s " ,
m_st . stateRevision ,
( m_st . recoveryHold
? " ACTIVE since " + TimeToString ( m_st . recoveryHoldTime , TIME_DATE | TIME_SECONDS )
: " none " ) ,
( m_restoredBackup ? " restored from backup " : " verified " ) ) ;
fix: enforce account scope and daily monitoring continuity
Schema 7 adds a persisted monitoring heartbeat, the last recorded gap and a gap hold, with deterministic migration from schema 6 that keeps every lock, cycle identity and reservation.
D0 is no longer invented on startup or on a rollover: a trading day is adopted only when its boundary was observed while the EA was executing, or when the equity path across it is provably constant (no position, no pending order, no account deal). Otherwise the previous D0 is preserved, a monitoring-gap hold blocks every new entry and the exact gap is reported; the hold survives restart and clears only at an observed day boundary or an explicit owner cycle. Static, target and daily thresholds keep their priority, so a breach is still locked and liquidated while a day is unverified.
Account scope is now counted and disclosed for owned and unmanaged positions and pending orders; unmanaged pending orders block entries under the external-exposure guard, and the EA states that the account-wide limits cannot be guaranteed while whole-account liquidation stays disabled.
2026-10-30 11:20:47 +07:00
PrintFormat ( " [UQ] Monitoring: last heartbeat %s | gap %d s | %s | D0 day %s " ,
( m_st . monitorTime > 0 ? TimeToString ( m_st . monitorTime , TIME_DATE | TIME_SECONDS ) : " none " ) ,
m_st . monitorGapSeconds ,
( m_st . gapHold
? " GAP HOLD since " + TimeToString ( m_st . gapHoldTime , TIME_DATE | TIME_SECONDS )
: " continuous " ) ,
TimeToString ( m_st . dailyDate , TIME_DATE ) ) ;
2026-10-30 08:37:46 +07:00
PrintFormat ( " [UQ] Risk cycle %s (sequence %d) | consumed reset nonces=%d%s " ,
m_st . cycleId , m_st . cycleSequence ,
UQResetNonceHistoryCount ( m_st . resetNonceHistory ) ,
( m_resetRejected ? " | RESET REQUEST REJECTED " : ( m_resetApplied ? " | RESET APPLIED " : " " ) ) ) ;
2026-10-30 10:20:54 +07:00
//--- the recorded prior lock history is displayed, never hidden: kind 3
//--- proves that both permanent locks were carried by the closed cycle
PrintFormat ( " [UQ] Prior permanent locks of the closed cycle: kind=%d (%s)%s " ,
m_st . priorLockKind , UQPriorLockText ( m_st . priorLockKind ) ,
( m_st . priorLockTime > 0
? " at " + TimeToString ( m_st . priorLockTime , TIME_DATE | TIME_SECONDS )
: " " ) ) ;
2026-10-30 08:37:46 +07:00
if ( m_resetRejected )
PrintFormat ( " [UQ] ERROR: an owner reset request was rejected; new entries stay blocked until the request is corrected or removed. Reason: %s " ,
m_lastError ) ;
2026-10-30 07:19:59 +07:00
return ( true ) ;
}
//+------------------------------------------------------------------+
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
//| Periodic evaluation. Persists when a threshold transitions and |
//| retries a previously failed persistence at a bounded interval. |
2026-10-30 07:19:59 +07:00
//+------------------------------------------------------------------+
void CUQRisk : : Evaluate ( void )
{
if ( ! m_ready )
return ;
2026-10-30 08:52:18 +07:00
//--- an accepted entry order must be reconciled before it can stop
//--- counting as reserved exposure
ReconcileReservation ( ) ;
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
const bool changed = EvaluateLocks ( ) ;
if ( changed )
2026-10-30 07:19:59 +07:00
{
fix: validate persistent risk-state integrity and fail closed on missing state
* UQ_State: checksummed schema v2 with strict typed parsing, duplicate/unknown-field rejection and semantic validation of every mandatory field; legacy v1 files are validated and migrated on load
* UQ_State: verified backup retention, staged-file verification before commit and post-commit re-verification
* UQ_State: redundant identity-scoped initialization marker reconciled against the persisted state
* UQ_Risk: a new risk cycle requires an explicit owner authorization and a deliberately declared positive B0; the current account balance is never used as a substitute
* UQ_Risk: missing, empty, corrupt, foreign, version-unsupported or schema-invalid state fails closed; backup recovery only under explicit owner authorization
* UQ_Risk: a failed state write degrades the controller to unhealthy, blocks all new entries, preserves the in-memory lock and retries at a bounded interval
* UQ_Risk: daily rollover keeps permanent locks and reports unmonitored intervals explicitly
* UQ_Defs: state schema constants, marker global-variable prefix and the STATE PERSISTENCE FAILED block reason
* Universal_Quant_EA: first-initialization and backup-restore authorization inputs, input validation and state-health status line
2026-10-30 08:07:18 +07:00
Save ( ) ;
ApplyBlock ( ) ;
return ;
}
if ( ! m_healthy )
{
const datetime now = UQServerNow ( ) ;
if ( m_saveRetryAt < = 0 | | now > = m_saveRetryAt )
{
PrintFormat ( " [UQ] Retrying persistence of the pending risk-state change. " ) ;
Save ( ) ;
ApplyBlock ( ) ;
}
2026-10-30 07:19:59 +07:00
}
}
# endif // UQ_RISK_MQH
//+------------------------------------------------------------------+