SRS: UC_6.1.3 — TRIM_TO_COMPLIANCE
| BA in Charge | Date Created | Version | Document References |
|---|---|---|---|
| Trang Nguyen | 2026-09-06 | v1.6 | RFQ_ Stack Trading Prop Tech V7.pdf; CHR-101 (T-30s Active Failsafe, Futures+Forex); CHR-100 (TRIM_TO_COMPLIANCE algorithm upgrade, Futures — Check 1 + Check 2); QnA_init_docs.md A-22, A-23 |
UC_6.1.3 — TRIM_TO_COMPLIANCE
1. Overview
| Field | Content |
|---|---|
| ID | UC_6.1.3 |
| Use Case | TRIM_TO_COMPLIANCE (upgraded algorithm — ES-Equivalent + Risk Weight sort for Futures, notional sort for Forex, T-30s Active Failsafe backstop) |
| Description | An automated position-trim algorithm that brings a trader's exposure/notional back down to a computedTarget_Limit (or, for Futures Check 2, directly evaluates its own margin compliance) — its purpose is to proactively de-risk the position, protecting firm capital without resorting to an immediate hard liquidation. Two independent dispatch sources call this UC: (1) UC_6.1.2 (Flow 24 — Overnight Margin & Swap Monitor), at T-2min: for Futures, dispatched unconditionally once UC_6.1.2's Gate 1 (Universal Drawdown Safety Gate) passes — this UC itself then runs Check 1 (25% ES-Equivalent cap) then Check 2 (CME Overnight Margin, the former Required Margin audit UC_6.1.2 used to compute) and decides whether any trim is needed; for Forex, dispatched only when UC_6.1.2's own 25% notional-cap sweep finds a shortfall on either MT5 or TraderEvolution — both platforms dispatch unconditionally once a shortfall is found, with no native leverage-reduction/Stop-Out check first (CHR-102); (2) UC_6.2.1 (Flow 23 — News Event Manager), at T-1min around a high-impact news event, when its own Gate 2 (asset-specific size cap) finds the trader over the Table A/B-based ceiling — this always runs Check 1 only (no CME-margin Check 2). Both dispatch sources run the same TRIM_TO_COMPLIANCE algorithm documented in this UC. This UC also owns the T-30s Active Failsafe — an independent backstop (Rithmic/MT5/TraderEvolution alike) that hard-flattens the position directly to the gateway if the trim loop has not resolved the breach 30 seconds before Official_Close_UTC (BR_6.1.3.6) — regardless of whether the loop is still running, stalled, or already finished. ⚠️ Overnight-margin-only: this failsafe backstops a Flow 24-dispatched loop only; a Flow 23 (news-event) loop has no T-30s failsafe of its own — see BR_6.1.3.6. |
| Zapier Flow | Flow 24 — Overnight Margin & Swap Monitor (T-2min dispatch, overnight rollover)and Flow 23 — News Event Manager (T-1min dispatch, news-event window) (Sev-1 alert payloads only — see BR_6.1.3.5) |
| Zapier Table | —(consumes Target_Limit passed by UC_6.1.2; the Forex branch's Target_Limit restates Table A Max_Forex_Notional + Table C News_Hold_Cap_Percent/Forex_Overnight_Cap_Percent for completeness, mirroring UC_6.1.2's own dispatch-time computation, not a separate live read; Futures' Appendix C weights are Backend master data, not a Zapier table — see BR_6.1.3.1/BR_6.1.3.3) |
| 3rd Party | — |
No wireframe — backend execution loop with no UI screen of its own. UC_4.8.1 (SIM) / UC_4.12.2 (LIVE) Position Monitor (Live Grid) already displays the resulting position changes; no new UI is needed (per WBS mapping_design note for this UC).
2. Trigger
Three independent triggers — two separate Zapier flows can dispatch the same TRIM_TO_COMPLIANCE algorithm, plus the universal failsafe:
-
T-120s Primary Loop dispatch — Flow 24 (Overnight Margin & Swap Monitor), from UC_6.1.2's Gate 1. Called at T-2min, once UC_6.1.2's Gate 1 (Universal Drawdown Safety Gate, BR_6.1.2.2) has passed. ⚠️ Architecture change — dispatch is now unconditional, per asset class, not conditioned on a pre-found shortfall:
- Futures: UC_6.1.2 dispatches to this UC every time Gate 1 passes, for the asset class currently at its own T-2min — it runs the full two-check sequence — Check 1 (25% ES-Equivalent Contract Cap, BR_6.1.3.1) then Check 2 (CME Overnight Margin Check, new BR_6.1.3.9) — and decides for itself whether any trim is actually needed; a fully-compliant account simply passes both checks with no order ever dispatched.
- Forex: unchanged — UC_6.1.2 still runs its own 25% notional exposure sweep (
BR_6.1.2.5) and only dispatches to this UC, with a pre-computedTarget_Limit, when that sweep finds a shortfall on either MT5 or TraderEvolution (CHR-102).
This is the overnight rollover trigger — the loop has up to 120 seconds (T-2min → T-30sec) to resolve before the Active Failsafe below intervenes.
-
T-1min Gate 2 dispatch — Flow 23 (News Event Manager), from UC_6.2.1's asset-specific size cap. Called at T-1min relative to a high-impact news event (not the overnight close), once UC_6.2.1's own Gate 1 (the Universal Drawdown check, BR_6.2.1.4) has passed and its Gate 2 (the asset-specific size cap, BR_6.2.1.5) finds the trader over cap — Forex
Current_Notional > Max_Forex_Notional × cap_percent, or FuturesOpen_Contracts > Floor(Max_Contracts × cap_percent). This is a news-event trigger, structurally identical in shape to trigger 1's Forex path (same two-gate pattern: a universal check first, then an asset-specific size-cap check that dispatchesTRIM_TO_COMPLIANCEwith a computedTarget_Limit) but running on a completely different clock (minutes around a scheduled news release, not the overnight close) and against a different base cap (Flow 23'sMax_Forex_Notional/Max_Contractsceiling vs. Flow 24's equity-based ceiling for Forex — see BR_6.1.3.3's note on the two distinctTarget_Limitformulas). ⚠️ For Futures, a Flow 23 dispatch runs Check 1 only — Flow 23 has no CME Overnight Margin concept, so Check 2 never runs for a news-event-triggered loop, regardless of asset class. ⚠️ No T-30s Active Failsafe backstops a Flow 23 loop — see trigger 3 below; a Flow 23 trim loop that does not resolve beforeNews_Event_Timeruns with no independent hard-liquidation backstop. -
T-30s Active Failsafe (Flow 24 / overnight margin only) — self-triggered by this UC's own middleware clock exactly 30 seconds before
Official_Close_UTC(the market close/open/rollover boundary), for every Futures/Forex asset class with an open Flow 24-dispatched Primary Loop — this is not dispatched by UC_6.1.2; it runs independently as a backstop, per CHR-101. ⚠️ Overnight margin enforcement only — this failsafe does not cover a Flow 23 (news event) loop (confirmed — see BR_6.1.3.6):News_Event_Timeis not a valid failsafe anchor, since the client confirmed this backstop exists specifically to protect firm capital through the overnight rollover window, not the news-event window. A Flow 23 Primary Loop that is still non-compliant whenNews_Event_Timearrives simply exits — see Exc-4.
3. Pre-conditions
| ID | Condition |
|---|---|
| P-1 | EitherUC_6.1.2 (Flow 24, T-2min) or UC_6.2.1 (Flow 23, T-1min) has dispatched into this UC (Primary Loop trigger), or the middleware's own clock has reached Official_Close_UTC − 30sec (BR_6.1.3.6) for an asset class with an unresolved margin/exposure breach on an open Flow 24 Primary Loop (Active Failsafe trigger — this condition never fires for a Flow 23 loop, which has no T-30s failsafe of its own). For a Flow 24 Futures dispatch, no Target_Limit is required at dispatch time — this UC computes Check 1's Target_Limit itself and Check 2 has no Target_Limit input at all. For a Forex dispatch (either flow) or a Flow 23 Futures dispatch, a valid pre-computed Target_Limit is required, as today. |
| P-2 | For Futures: Risk Weight data is available for every open position's symbol — if missing for any symbol, the sort step cannot proceed safely (seeExceptional Flow Exc-1). For Check 2 (Flow 24 only): CME_Instrument_Details holds the current-day CME overnight margin rate for every open Futures symbol (UC_6.1.1 Step B), and Table B's Futures_Capital for the trader's current level is readable (for Total_Equity). |
| P-3 | The gateway's execution-report event stream (Rithmic / MT5 / TraderEvolution) is reachable so the event listener can receive fill confirmations. |
4. Post-conditions
Primary Loop — resolved within T-120s window
Open_Contracts(Futures) orCurrent_Notional(Forex) is at or belowTarget_Limit; the loop exits normally. The T-30s Active Failsafe finds the asset class already compliant and takes no action.
Futures, Flow 24 dispatch — Check 1 compliant, Check 2 then runs
- Once Check 1 (25% ES-Equivalent cap) reports compliant, Check 2 (CME Overnight Margin Check) begins immediately against the same closing-now asset class. If Check 2 is also already compliant with no trim needed, the loop ends here with zero orders dispatched this cycle. See BR_6.1.3.9.
Primary Loop — single REJECTED fill (race-condition check)
- The loop does not halt or alert on a single reject. The middleware refreshes the portfolio and re-checks compliance; if compliant, the loop stops silently with no alert, otherwise it retries with a recalculated
Order_Qty. See Exceptional Flow Exc-2 and BR_6.1.3.5.
Primary Loop — REJECTED fill twice in a row on a still-non-compliant position
- The loop aborts and executes
FLATTEN_ALLfor thatuser_id. The Trim/Flatten Failure Alert fires only if thatFLATTEN_ALLalso fails to bring the account into compliance. See Exceptional Flow Exc-2 and BR_6.1.3.4/BR_6.1.3.5.
Primary Loop — 2000ms fill-confirmation timeout
- The loop aborts and a
FLATTEN_ALL(hard liquidation) is dispatched immediately for thatuser_id. See Exceptional Flow Exc-3.
Primary Loop — 2000ms Re-Check snapshot-query timeout
- The loop aborts and a
FLATTEN_ALL(hard liquidation) is dispatched immediately for thatuser_id, on the assumption the broker connection is compromised. See Exceptional Flow Exc-5 and BR_6.1.3.7.
T-30s Active Failsafe — breach still present
- The middleware dispatches
FLATTEN_ALLdirectly to the gateway, bypassing the trim loop. Since both the trim process and thisFLATTEN_ALLfailsafe have now failed to bring the account into compliance, the Trim/Flatten Failure Alert ([SEV-1] TRIM / FLATTEN FAILURE ALERT, withuser_id/account_id/Broker name/Remaining Open Positions/Gateway Error) is pushed to Slack#risk-ops. See BR_6.1.3.4.
Missing Risk Weight / CME margin-rate data (Futures, either check)
- No sort/trim is attempted;
FLATTEN_ALLis dispatched immediately and the Trim/Flatten Failure Alert fired. See BR_6.1.3.2 (applies to both Check 1 and Check 2 per BR_6.1.3.9).
5. Basic Flow
Futures runs an upgraded trim algorithm per CHR-100 (Basic Flow A below); Forex keeps the RFQ V7 baseline algorithm, detailed further per user instruction (Basic Flow B below) . Each branch states its own event-driven execution/listener pattern in full, and both are backstopped by the same independent, universal T-30s Active Failsafe (step 8 below), a separate CR — CHR-101.
A. Futures — two sequential checks (Check 1: ES-Equivalent cap, Check 2: CME Overnight Margin)
Architecture: a Flow 24 (overnight) dispatch now runs Check 1 (steps 1-9 below) first; once Check 1's loop is fully compliant, it immediately runs Check 2 (new steps below, after step 9) against the same closing-now asset class. A Flow 23 (news event) dispatch runs Check 1 only — it never enters Check 2, since Flow 23 has no CME Overnight Margin concept. Check 1's algorithm (ES-Equivalent conversion, Risk Weight sort, raw-contract conversion) is unchanged from the existing CHR-100 upgrade — only its position in the overall sequence, and the fact that Flow 24 now dispatches here unconditionally rather than only after UC_6.1.2 finds a shortfall, has changed. Check 2 is new content, formerly computed inside UC_6.1.2's own Basic Flow step 5, now owned here since this UC runs the pass/fail evaluation and any resulting trim loop together.
Appendix C — Futures Relative Risk Helper Table (base unit 1.0 ES), used throughout Check 1 below:
| Symbol(s) | Contract Type | ES_Equivalent_Weight |
|---|---|---|
ES, NQ, YM, RTY | E-Mini Indices | 1 |
MES, MNQ, MYM, M2K | Micro Indices | 0.1 |
CL, NG, RB, HO | Standard Energy | 2 |
MCL | Micro Crude | 0.2 |
QG | E-Mini Natural Gas | 0.5 |
GC, HG, PL | Gold, Copper, Platinum | 1 |
MGC | Micro Gold | 0.1 |
SI, PA | Silver, Palladium | 2 |
SIL | Micro Silver | 0.4 |
ZN, ZB, ZF, ZT, UB, TN | Treasuries | 1 |
BTC | Bitcoin | 10 |
MBT | Micro Bitcoin | 0.2 |
ETH | Ethereum | 2 |
MET | Micro Ether | 0.1 |
⚠️ Appendix C is a Backend master-data table, not a Zapier config. Unlike Table A/B/C (the shared cap-percent/level-limit config read live by Zapier flows), the Appendix C symbol → ES_Equivalent_Weight mapping does not need to be configurable inside Zapier — it is managed as static master data on the Backend (e.g. a Futures_Risk_Weight_Table reference table), since these are standard exchange-contract-spec ratios that change only when CME lists/delists a contract, not something Risk Ops needs to tune per level/per trader.
Check 1 — 25% ES-Equivalent Contract Cap
Worked example used throughout Check 1 below: an Associate Trader's Table B row lists a raw
Max_Contracts = 8 Micros(Appendix B — see step 2 for the ES-Equivalent conversion this raw value requires, which yieldsMax_Contracts_ES_Equiv = 0.8 ES-Equivalent) andCap_Percent = 25%(Table C) — for a Flow 24 dispatch this is Flow 24's own cap-percent variable; for a Flow 23 dispatch this isNews_Hold_Cap_Percent, both the same0.25shared config value (BR_6.1.2.5). Overnight, the trader is holding40 MES(Micro E-mini S&P, weight0.1) and10 MCL(Micro Crude, weight0.2) — enough to breach the overnight cap and trigger this trim. AssumeCME_Overnight_Margin_Per_Contract= $50/contract forMES, $40/contract forMCL.
-
Calculate Total Portfolio Exposure. Convert every open Futures position into its ES-Equivalent value (using the Appendix C weight above) and sum them:
Total_Portfolio_ES_Equiv = Σ (Raw_Contract_Count_symbol × ES_Equivalent_Weight_symbol)Raw_Contract_Count_symbol— the number of open contracts the user holds in that symbol.ES_Equivalent_Weight_symbol— the symbol's weight from Appendix C, expressing how many ES-units one contract of that symbol is worth relative to the1.0 ESbase unit.Total_Portfolio_ES_Equiv— the user's entire open Futures book's exposure, with every symbol normalized into one common comparable unit (ES-equivalents), so positions in completely different instruments (e.g.MESmicro index vs.BTCbitcoin future) can be summed and compared directly.- Example:
(40 MES × 0.1) + (10 MCL × 0.2) = 4.0 + 2.0 = 6.0 ES-Equivalent.
-
Calculate the Target Limit. ⚠️
Max_Contracts_ES_Equivis not read directly from Table B — it must first be converted to ES-Equivalent units per Appendix B's own conversion logic, the same way step 1 converts the trader's raw open positions:Max_Contracts_ES_Equiv = Max_Contracts × ES_Equivalent_Weight Target_Limit = Floor(Max_Contracts_ES_Equiv × Cap_Percent)Max_Contracts— the user's level/title-based Futures contract ceiling as stored raw in Table B (Zapier config, Appendix B — Futures Configuration Matrix), e.g. an Associate Trader's8 Microsrow. This raw value is a count of a representative contract type (MicrosorMinis) — it is not already expressed in ES-Equivalent units, despite the Table B column itself being namedMax_Contracts_ES_Equiv.ES_Equivalent_Weight— the conversion weight for that representative contract type, per Appendix B's own governing note ("Currency: USD. Contracts normalized to E-Mini S&P 500 (ES) Margin. Logic: 1 ES ≡ 10 Micros (MES). 1 CL (Crude) ≡ 2 ES.") — the same ratios Appendix C already defines per symbol (used in step 1):0.1for aMicros-labeled Table B row (Micro Index weight),1for aMinis-labeled row (E-mini Index weight). This is the identical Appendix C lookup step 1 performs against the trader's open positions, applied here instead to Table B's own raw ceiling.Max_Contracts_ES_Equiv = Max_Contracts × ES_Equivalent_Weight— the user's level-based ceiling, now correctly expressed in the same ES-Equivalent unitTotal_Portfolio_ES_Equiv(step 1) uses, so the two are comparable in step 3 and subtractable in step 4. Table B's rawMax_Contractsvalue must never be substituted directly into theTarget_Limitformula without this conversion — doing so would compare an unconverted Micros/Minis count against a true ES-Equivalent total, understating how restrictive the cap actually is for a Micro-tier account.Cap_Percent(also referred to asNotional_Cap_Percent) — the shared cap-percent config value (Table C — the same0.25-type variable reused across Futures margin, Forex exposure, and News Events, per BR_6.1.2.5): Flow 24's own cap-percent variable for an overnight dispatch, orNews_Hold_Cap_Percentfor a Flow 23 dispatch — both are0.25by default, the same shared config, not two independently-set constants.Target_Limit = Floor(...)— the ES-Equivalent compliance ceiling, rounded down to the nearest whole ES-Equivalent unit so the limit is never rounded up past what the cap-percent actually allows.- Example: Associate Trader's
Max_Contracts = 8 Micros(Table B) ×ES_Equivalent_Weight = 0.1(Micro Index, Appendix B/C) →Max_Contracts_ES_Equiv = 8 × 0.1 = 0.8 ES-Equivalent.Target_Limit = Floor(0.8 × 0.25) = Floor(0.2) = 0 ES-Equivalent— matching UC_6.2.1BR_6.2.1.5's own worked example for this exact account tier, which this UC'sTarget_Limitmust stay consistent with since both UCs read the same Table B row.
-
Evaluate Compliance. Immediately after
Target_Limitis known — before calculating any overage, and before sorting or selecting anything to trim — check whether the book is already within the cap:IF Total_Portfolio_ES_Equiv ≤ Target_Limit => Check 1 is complete IF Total_Portfolio_ES_Equiv > Target_Limit => proceed to next step- This gate matters because, under the current architecture, UC_6.1.2 dispatches to Check 1 unconditionally every time its Gate 1 passes (BR_6.1.3.1) — not only when a shortfall is already known. A dispatched account may already be compliant on arrival, in which case Check 1 must exit immediately with zero orders dispatched, rather than computing an overage and running steps 5-7 (sort/select/size) against it.
- If compliant (
Total_Portfolio_ES_Equiv ≤ Target_Limit): Check 1 is complete with no trim this cycle. For a Flow 23 dispatch, the loop ends here entirely. For a Flow 24 dispatch, the engine proceeds straight to Check 2 below, against the same closing-now asset class (same branching rule as step 8's post-loop handoff). - If non-compliant (
Total_Portfolio_ES_Equiv > Target_Limit): proceed to step 4 (Calculate the Overage) to size the trim. - Example (continuing the worked example above):
Total_Portfolio_ES_Equiv = 6.0,Target_Limit = 0 ES-Equivalent→6.0 > 0→ non-compliant, proceed to step 4. (Had the trader instead been fully flat — zero open Futures positions,Total_Portfolio_ES_Equiv = 0—0 ≤ 0would still pass as compliant; at this Associate-Trader tierTarget_Limitfloors all the way to0, so any open Futures position at all breaches the cap — an intentionally restrictive ceiling for the newest/smallest account tier, and noOverage_ES_Equivwould ever need to be computed in that all-flat case.)
-
Calculate the Overage. Only reached once step 3 has found the book non-compliant:
Overage_ES_Equiv = Total_Portfolio_ES_Equiv − Target_LimitOverage_ES_Equiv— the amount of ES-Equivalent exposure that must still be trimmed to bring the book back into compliance; both terms are expressed in ES-Equivalent units (step 1's Appendix C conversion) so they can be subtracted directly.- Example:
Overage_ES_Equiv = 6.0 − 0 = 6.0 ES-Equivalentstill needs to be trimmed — the account's entire open Futures exposure, sinceTarget_Limitis0at this tier.
-
Sort by Risk Weight. Order the open positions from largest to smallest by each position's calculated Risk Weight:
Risk_Weight = Raw_Contract_Count × CME_Overnight_Margin_Per_ContractRaw_Contract_Count— the number of open contracts the user holds in that symbol.CME_Overnight_Margin_Per_Contract— the current trading day's CME overnight margin rate per contract for that symbol (CME_Instrument_Details, committed by UC_6.1.1 Step B).Risk_Weight— each position's relative capital risk, in dollar margin terms (distinct from step 1'sES_Equivalent_Weight, which is a unit-conversion ratio, not a dollar figure); sorting by this (rather than by raw contract size, the pre-upgrade baseline behavior) can produce materially different trim selection — a small-contract-count but high-risk-weight position may be trimmed before a larger-contract-count but lower-risk-weight one.- If Risk Weight/margin data is missing for any symbol in the book, the system does not attempt to sort or trim on incomplete data — trimming on a partial picture risks mis-selecting which position is actually the largest exposure. Instead it dispatches
FLATTEN_ALLfor the affected book immediately and fires a Sev-1 alert to Slack#risk-ops(see Exceptional Flow Exc-1). - Example:
MES: Risk_Weight = 40 × $50 = $2,000.MCL: Risk_Weight = 10 × $40 = $400. Sorted largest→smallest:MES ($2,000), thenMCL ($400)—MESis selected as the position to trim first, even though neither its raw contract count (40) nor its ES-Equivalent weight (0.1) alone would obviously signal "largest."
-
Convert Overage to Target Raw Contracts. Select the single largest open position from the Risk-Weight-sorted list (step 5) — in the example,
MES. Identify its specific conversion ratio to ES from Appendix C (MES→ES_Equivalent_Weight = 0.1, so1 ES = 10 MES→Conversion_Ratio = 10), then:Required_Trim_Raw_Contracts = Ceiling(Overage_ES_Equiv × Conversion_Ratio)Overage_ES_Equiv— the remaining ES-Equivalent amount to trim, from step 4.Conversion_Ratio— the selected position's symbol-specific ES-to-raw-contract ratio, i.e.1 ÷ ES_Equivalent_Weightfrom Appendix C (e.g.MESweight0.1→ ratio10;BTCweight10→ ratio0.1) — the inverse of step 1's weight, since step 1 converts raw contracts → ES while this step converts ES → raw contracts.Required_Trim_Raw_Contracts = Ceiling(...)— the ES-Equivalent overage converted into that symbol's actual raw contract units, rounded up so the trim order never undershoots the required overage.- Example:
Required_Trim_Raw_Contracts = Ceiling(6.0 × 10) = Ceiling(60) = 60 MES contracts— more than the trader's entire40-contractMESposition; step 7 below caps this at what is actually held.
-
Determine Trim Quantity.
Order_Qty = MIN(Required_Trim_Raw_Contracts, Position_Contract_Size)Required_Trim_Raw_Contracts— from step 6.Position_Contract_Size— the selected position's own actual open raw contract size.Order_Qty = MIN(...)— whichever is smaller, so a single close order never attempts to close more contracts than the position actually holds.- Example:
Position_Contract_Size (MES) = 40(the trader's entireMESposition).Order_Qty = MIN(60, 40) = 40— the trim order closes the entireMESposition, even though60was required; a single order can never close more than the position actually holds. After this fills,Total_Portfolio_ES_Equivrecalculates to(0 MES × 0.1) + (10 MCL × 0.2) = 2.0 ES-Equivalent— still aboveTarget_Limit = 0, so (unlike a less restrictive tier) the loop does not stop here: step 9's Re-Check sends it back to step 1 for a second iteration against the remaining10 MCL.
-
Execute & Listen. Send a partial-close
Market_Close_Orderfor the exactOrder_Qty— Order TypeMarket, Time in ForceIOCon Rithmic (BR_6.1.3.8) — and monitor the gateway socket for theExecutionReport:IF Status == "FILLED"→ proceed immediately to Re-Check (step 9), with zero artificial delay.IF Status == "REJECTED"→ see the race-condition handling rule in BR_6.1.3.5: do not alert on a single reject — refresh the portfolio and re-check compliance first; only escalate toFLATTEN_ALL+ Sev-1 alert after two consecutive rejects across the trim loop that is still non-compliant.- FAILSAFE (2000ms) — if no fill is confirmed within 2000ms of submission, abort the loop and execute
FLATTEN_ALL.
Same event-driven pattern as Forex's own step 7 below, minus the
PARTIAL_FILLEDbranch (Futures reports are treated as a single atomic fill/reject/timeout, not partial fills). See the shared Execution Listener & Failsafe Rules in BR_6.1.3.5 for the full REJECTED-handling detail — it applies identically here and to Check 2 and the Forex loop below. -
Re-Check & T-30 Failsafe. Recalculate
Total_Portfolio_ES_Equivfrom scratch — the middleware must query the fresh portfolio state from the broker each iteration, not reuse a stale snapshot, to ensure absolute accuracy for the next iteration.- ⚠️ FAILSAFE (2000ms Re-Check snapshot timeout, client-confirmed — BR_6.1.3.7): this snapshot query itself carries a hard 2000ms timeout, separate from step 8's fill-confirmation timeout. If the middleware cannot retrieve the updated position snapshot from the broker within 2000ms, it assumes the connection is compromised, aborts the trim loop immediately, and dispatches
FLATTEN_ALL— it does not retry the query or fall back to a stale snapshot. - If the snapshot returns in time and
Total_Portfolio_ES_Equiv ≤ Target_Limit, Check 1 is complete. If it is still over the limit, loop back to step 1. - Example (continuing the worked example above) — a full second iteration: after closing
40 MES, the Re-Check snapshot showsTotal_Portfolio_ES_Equiv = 2.0 ES-Equivalent(only10 MCLremain) — still> Target_Limit = 0— so the loop goes back to step 1 for a second iteration: step 1 recomputesTotal_Portfolio_ES_Equiv = 2.0(MCLonly,10 × 0.2); step 2'sTarget_Limitis unchanged at0(an account-level config value, not re-derived per iteration); step 3 finds2.0 > 0, still non-compliant; step 4 computesOverage_ES_Equiv = 2.0 − 0 = 2.0; step 5 sorts —MCLis now the only (and therefore largest) remaining position; step 6 converts (MCLweight0.2→Conversion_Ratio = 5)Required_Trim_Raw_Contracts = Ceiling(2.0 × 5) = 10 MCL contracts; step 7'sOrder_Qty = MIN(10, 10) = 10— closes the entire remainingMCLposition too. This second Re-Check findsTotal_Portfolio_ES_Equiv = 0 ≤ Target_Limit = 0— Check 1 is now complete, having flattened the account's entire Futures book (40 MES+10 MCL) across 2 iterations — the expected outcome at this Associate-Trader tier, whereTarget_Limitfloors to0. - For a Flow 24 dispatch only: independently of this re-check, if the system clock hits exactly
Official_Close_UTC − 30secand the portfolio is still over the limit, the T-30s Active Failsafe (shared step 8 below) instantly aborts this loop and dispatchesFLATTEN_ALL, regardless of which iteration the loop is on. ⚠️ For a Flow 23 dispatch, no such failsafe exists (BR_6.1.3.6) — if the loop has not resolved byNews_Event_Time, it simply keeps iterating (or exits unresolved per Exc-4); nothing independently aborts it atNews_Event_Time − 30sec. - Once Check 1 is complete: for a Flow 23 dispatch, the loop ends here — there is no Check 2. For a Flow 24 dispatch, the engine immediately proceeds to Check 2 below, against the same closing-now asset class.
- ⚠️ FAILSAFE (2000ms Re-Check snapshot timeout, client-confirmed — BR_6.1.3.7): this snapshot query itself carries a hard 2000ms timeout, separate from step 8's fill-confirmation timeout. If the middleware cannot retrieve the updated position snapshot from the broker within 2000ms, it assumes the connection is compromised, aborts the trim loop immediately, and dispatches
Check 2 — CME Overnight Margin Check (Flow 24 only)
⚠️ Content moved here from UC_6.1.2's former Basic Flow step 5. The formulas, scoping rules, and worked example below are unchanged in substance from what UC_6.1.2 used to compute inline at T-2min — only the owning document has changed, since this UC now runs the pass/fail evaluation and any resulting trim loop together, immediately after Check 1 resolves.
Core Definitions for Futures Overnight Margin:
-
Total_Equity = Futures_Capital + PnL—Futures_Capitalis sourced from Table B for the trader's current level;PnL = Current Account Equity - Initial balance. -
Margin_Already_Encumbered_By_Other_Closed_Asset_Classes— the sum of(Open_Contracts × CME_Overnight_Margin_Rate)for all open positions belonging to Futures asset classes that are already in aClosedorHaltedstate. Calculated as its own sub-procedure, run once per cycle beforeAvailable_Equitycan be computed:- Snapshot Positions — fetch the trader's complete array of open positions from Rithmic.
- Identify Closed Markets — query the
CME_Instrument_Detailstable (managed by the Dynamic Timekeeper, UC_6.1.1) to identify which asset classes have already passed theirOfficial_Close_UTCand are currently in a'Closed'or'Halted'state. - Filter — filter the trader's open positions (from step 1) down to only the symbols belonging to those already-closed asset classes (from step 2).
- Calculate Encumbered Margin — for those filtered positions, calculate their required overnight margin using the CME overnight margin rates stored in
CME_Instrument_Details. - Sum — the sum of that calculation across all filtered positions is the
Margin_Already_Encumbered_By_Other_Closed_Asset_Classesvalue.
-
Available_Equity = Total_Equity − Margin_Already_Encumbered_By_Other_Closed_Asset_Classes— what remains of total equity after subtracting margin already committed elsewhere; this is the figure Check 2 comparesRequired_Marginagainst. -
Required_Margin— the sum of(Open_Contracts × CME_Overnight_Margin_Rate)fromCME_Instrument_Details, for the open positions in the currently closing asset class (the same "closing-now group" scoping Check 1 and this definition both use — see the group-scoping note below).
🔧 Scope — only the asset class currently at its own T-2min, not every open position. A trader's open Futures book can span multiple asset classes/symbol groups simultaneously, and each one runs its own per-asset-class timeline thread (UC_6.1.1), so each reaches T-2min at its own wall-clock moment, not all together. The trader's open positions fall into one of three groups relative to the moment Check 2 runs for a given asset class:
- Already-closed group — asset class(es) whose own
Official_Close_UTCalready passed earlier this cycle. No freshRequired_Marginis calculated for these here; they only re-enter this calculation asMargin_Already_Encumbered_By_Other_Closed_Asset_Classesabove. - Closing-now group — the one specific asset class whose T-2min has just fired (and whose Check 1 loop has just completed). This is the only group this invocation of Check 2 computes
Required_Margin/Available_Equity/Pass-Fail for. - Not-yet-closing group — asset class(es) whose
Official_Close_UTCis still hours away and has not reached its own T-2min yet. Excluded entirely from this cycle — not charged aRequired_Margin, not folded intoMargin_Already_Encumbered_By_Other_Closed_Asset_Classes. They get their own independent Check 1 → Check 2 run once their own T-2min arrives.
-
Evaluate Compliance. Compute
Required_Marginfor the remaining open positions in the closing asset class (the same positions Check 1 just finished trimming, if it trimmed anything) and compare againstAvailable_Equity:Required_Margin = SUM(Open_Contracts × CME_Overnight_Margin_Rate) IF Required_Margin ≤ Available_Equity: Check 2 is complete, the loop stops. IF Required_Margin > Available_Equity: proceed to step 2.- If multiple symbols are open within the closing asset class,
Required_Marginis the sum of each symbol's ownOpen_Contracts × CME_Overnight_Margin_Rate— the same multi-symbol aggregation rule Check 1'sTotal_Portfolio_ES_Equivuses, just expressed in margin-dollar terms instead of ES-Equivalent units.
- If multiple symbols are open within the closing asset class,
-
Calculate Margin Overage.
Margin_Overage = Required_Margin − Available_Equity- The dollar amount of margin shortfall that must still be trimmed to bring the closing asset class back into compliance.
-
Select Largest Position. Sort the remaining open positions in the closing asset class from largest to smallest by the same Risk Weight key Check 1 uses:
Risk_Weight = Raw_Contract_Count × CME_Overnight_Margin_RateSelect the largest. (The missing-risk-data failsafe in BR_6.1.3.2 applies identically here — Check 2 does not sort/trim on incomplete margin-rate data.)
-
Convert Margin Overage to Raw Contracts. Divide the dollar
Margin_Overageby the selected symbol's ownCME_Overnight_Margin_Rate:Required_Trim_Raw_Contracts = Ceiling(Margin_Overage / CME_Overnight_Margin_Rate)- Unlike Check 1's ES-Equivalent conversion ratio, Check 2 converts directly from a dollar overage to raw contracts, since
CME_Overnight_Margin_Rateis already a per-contract dollar figure — no Appendix C lookup is involved in this conversion.
- Unlike Check 1's ES-Equivalent conversion ratio, Check 2 converts directly from a dollar overage to raw contracts, since
-
Determine Order Quantity.
Order_Qty = MIN(Required_Trim_Raw_Contracts, Position_Contract_Size)- Same MIN-of-two-quantities pattern as Check 1 step 7 — a single close order never attempts to close more contracts than the position actually holds.
-
Execute & Re-Check. Submit a
Market_Close_OrderforOrder_Qty— same order attributes as Check 1 (BR_6.1.3.8:Market,IOCon Rithmic) — await the gatewayExecutionReportfill confirmation (sameFILLED/REJECTED-race-condition/2000ms-timeout listener pattern as Check 1 step 8, BR_6.1.3.5), refresh the portfolio state and recomputeAvailable_Equity(same 2000ms Re-Check snapshot timeout as Check 1 step 9, BR_6.1.3.7), and repeat from step 1 untilRequired_Margin ≤ Available_Equity. The same T-30s Active Failsafe (shared step 8 below) races this loop independently, exactly as it races Check 1.
Worked example, continuing the Check 1 example above: in that specific scenario (Associate Trader,
Target_Limit = 0), Check 1's 2 iterations already closed the account's entire open Futures book (40 MES+10 MCL) to bring it flat. Check 2 therefore runs against zero remaining open positions in the closing asset class:Required_Margin = SUM(...) = $0(an empty sum over no open positions), trivially≤ Available_Equity— Check 2 passes immediately with no further trim, and the loop stops with a total of 2 orders dispatched this cycle (theMESandMCLcloses from Check 1's own 2 iterations).An independent example where Check 2 actually trims (illustrative — a different, higher-tier account where Check 1's own loop leaves positions open, not a continuation of the Associate Trader scenario above): suppose Check 1's loop completes leaving
10 MCLopen in the closing asset class, the trader's current level hasFutures_Capital = $1,250(Table B) andPnL = $0→Total_Equity = $1,250. No other asset class is already closed this cycle, soMargin_Already_Encumbered_By_Other_Closed_Asset_Classes = $0→Available_Equity = $1,250.Required_Margin = 10 MCL × $40/contract = $400. Since$400 ≤ $1,250, Check 2 passes immediately — no further trim needed.A shortfall variant of that same independent example (illustrative): if instead
Futures_Capital = $300→Total_Equity = $300→Available_Equity = $300, thenRequired_Margin ($400) > Available_Equity ($300)→Margin_Overage = $400 − $300 = $100. Sorted by Risk Weight,MCL(10 × $40 = $400) is the only — and therefore largest — remaining position.Required_Trim_Raw_Contracts = Ceiling($100 / $40) = Ceiling(2.5) = 3 MCL contracts.Order_Qty = MIN(3, 10) = 3. After closing 3MCLcontracts, the remaining 7MCLrequire7 × $40 = $280 ≤ $300— Check 2 completes on this single iteration.
B. Forex — notional sort, largest-position proportional trim
Worked example used throughout steps 1-7 below: a trader has
Max_Forex_Notional = $200,000(Table A) andNotional_Cap_Percent = 25%(Table C). They hold one openEURUSDposition:Lot_Size = 1.0lot,Contract_Size_Per_Lot = 100,000(standard lot, EUR-denominated),Current_Price = 1.10(USD per EUR) — large enough to breach the cap and trigger this trim.
-
Snapshot. Fetch all open Forex positions for the
user_id. Example: one open position,EURUSD,Lot_Size = 1.0. -
Calculate the Overage.
Target_Limit = Allowed_Notional = Max_Forex_Notional × Notional_Cap_Percent Overage_USD = Current_Notional − Target_LimitMax_Forex_Notional— the account's level/title-based maximum Forex notional ceiling, from Table A.Notional_Cap_Percent— the shared cap-percent config value in Table C: specifically theNews_Hold_Cap_Percentfield when dispatched by Flow 23 (News Events, UC_6.2.1's Gate 2) or theForex_Overnight_Cap_Percentfield when dispatched by Flow 24 (Overnight Margin & Swap Monitor, UC_6.1.2's Gate 2) — both are the same25%-type variable reused across Futures margin, Forex exposure, and News Events, per BR_6.1.2.5.Target_Limit(=Allowed_Notional) — the dollar ceiling on total open Forex notional the account may carry; this is the Flow 23 version of the formula (Table AMax_Forex_Notional× Table C cap-percent) — see BR_6.1.3.3 for how this differs from, and coexists with, Flow 24's ownTarget_Limitformula (Total_Account_Equity × Forex_Overnight_Cap_Percent, BR_6.1.2.5) — this UC's trim loop is formula-agnostic: it simply consumes whicheverTarget_Limitthe dispatching flow passed in.Current_Notional— the account's total open Forex notional exposure (sum of every open position'sPosition_Notional_Value, step 4 below) at check time.Overage_USD— the dollar amount of notional exposure that must still be trimmed to reach compliance.- Example:
Target_Limit = $200,000 × 0.25 = $50,000. TheEURUSDposition'sPosition_Notional_Value = 1.0 × 100,000 × 1.10 = $110,000(quote-currency-is-USD case, step 4) — this is alsoCurrent_Notionalsince it's the only open position.Overage_USD = $110,000 − $50,000 = $60,000.
-
Sort positions by notional value, largest to smallest (
Position_Notional_Value, computed per-position via step 4's formula). Example: only one position,EURUSDat$110,000— trivially the largest. -
Calculate the Trim Quantity for the largest position.
Trim_Lots = (Overage_USD / Largest_Position_Notional_USD) × Largest_Position_LotsOverage_USD— the remaining amount to trim, from step 2.Largest_Position_Notional_USD— the dollar notional value of the single largest position selected in step 3 (Position_Notional_Value, below).Largest_Position_Lots— that same position's current open lot size.Trim_Lots— the proportional number of lots to close:Overage_USDexpressed as a fraction of the position's total notional, applied to its lot size, so closingTrim_Lotsremoves exactlyOverage_USDworth of notional (assuming price doesn't move) rather than closing the position outright when only a partial trim is needed.
Position_Notional_Valueitself depends on which currency leg of the pair is USD:IF Quote_Currency == USD (e.g. EURUSD): Position_Notional_Value = Lot_Size × Contract_Size_Per_Lot × Current_Price IF Base_Currency == USD (e.g. USDJPY): Position_Notional_Value = Lot_Size × Contract_Size_Per_Lot IF neither leg is USD (cross pair, e.g. EURGBP): Position_Notional_Value = Lot_Size × Contract_Size_Per_Lot × FX_Conversion_Rate(Base_Currency → USD)Lot_Size— the number of lots open in that position.Contract_Size_Per_Lot— the standard contract size for one lot (typically 100,000 units of the base currency for a standard lot).Current_Price— the pair's current market price (quote currency per 1 unit of base currency).- ⚠️ Live price source (client-confirmed):
Current_Priceand everyFX_Conversion_Rateused in this formula must come from the real-time live market price on the existing gateway data stream (MT5 Gateway API / TraderEvolution Admin API) — never a cached, delayed, or end-of-day rate. The notional figure is only accurate at the instant it's calculated if the price feeding it is live. - Quote-currency-is-USD case (e.g.
EURUSD): the position is already denominated in EUR; multiplying byCurrent_Price(USD per EUR) converts it directly to USD. Example:1.0 × 100,000 × 1.10 = $110,000(as used in step 2 above). - Base-currency-is-USD case (e.g.
USDJPY):Lot_Size × Contract_Size_Per_Lotis already a USD amount (the base currency itself is USD) —Current_Priceis not needed for the notional figure itself. Example (illustrative, different position):0.5 lots USDJPY → 0.5 × 100,000 = $50,000, regardless of the USD/JPY rate. - Cross-pair case, simplified— e.g.
EURGBP, neither leg is USD: convert the base currency directly to USD viaFX_Conversion_Rate(Base_Currency → USD)— there is no need to first value the position in the quote currency and then convert that quote-currency amount to USD; that two-step detour is mathematically unnecessary and costs extra compute. Example:0.3 lots EURGBP— the base currency is EUR, so take the100,000-unit EUR base size and multiply by the liveEURUSDrate directly:0.3 × 100,000 × 1.10 (live EURUSD) = $33,000. (This replaces the earlier, more expensive formula that first computed the GBP quote-currency value viaCurrent_Price (EURGBP)and then applied a secondGBP → USDconversion on top of it.) - Continuing the worked example:
Trim_Lots = ($60,000 / $110,000) × 1.0 = 0.5455 lots.
-
Determine Final Order Quantity.
Order_Qty = MIN(Trim_Lots, Largest_Position_Lots)Trim_Lots— from step 4.Largest_Position_Lots— the selected position's own current open lot size.Order_Qty = MIN(...)— whichever is smaller, so the trim order never attempts to close more lots than the position actually holds (this caps the proportional calculation at a full close whenOverage_USDmeets or exceeds the position's own notional value).- ⚠️ Rounding (Critical): round
Order_QtyUP to the nearest step size (typically a micro-lot,0.01) before sending theMarket_Close_Order— rounding down would leave a residual sliver of notional still overTarget_Limit, forcing an unnecessary extra loop iteration. - Example:
Order_Qty = MIN(0.5455, 1.0) = 0.5455, rounded up to the nearest0.01→0.55 lots. This closes0.55 × 100,000 × 1.10 = $60,500of notional — slightly more than the$60,000overage (by design, since rounding always goes up), leaving the account at$110,000 − $60,500 = $49,500, just under the$50,000Target_Limit.
-
Execute. Send the partial-close
Market_Close_Orderfor the exactOrder_Qtycalculated in step 5 (0.55 lotsin the example) — Order TypeMarket, Time in ForceIOCon TraderEvolution,Today/blank on MT5 (BR_6.1.3.8) — and capture theOrder_ID. -
Event Listener — fill confirmation. Monitor the gateway socket for the
ExecutionReportassociated withOrder_ID:IF Status == "FILLED"→ proceed immediately to the Re-Check phase (step 8), with zero artificial delay.IF Status == "REJECTED"→ see the race-condition handling rule in BR_6.1.3.5: do not alert on a single reject — refresh the portfolio and re-check compliance first; only escalate toFLATTEN_ALL+ Sev-1 alert after two consecutive rejects across the trim loop that is still non-compliant.IF Status == "PARTIAL_FILLED"→ the algorithm continues waiting for the finalFILLEDconfirmation on the remaining quantity. The absolute 2000ms failsafe timer does not pause or reset just because a partial fill arrived — it began at order submission and keeps counting. If the remaining quantity does not reach a finalFILLEDstatus before that 2000ms window expires, the loop instantly aborts and executesFLATTEN_ALL.- FAILSAFE (2000ms Timeout) — if the exchange fails to confirm a (final) fill within 2000ms of order submission, abort the trim loop and immediately execute
FLATTEN_ALL(hard liquidation) to protect firm capital.
-
Re-Check & T-30 Failsafe. Recalculate
Current_Notionalfrom scratch — the middleware must query the fresh portfolio state from the broker, not reuse a stale snapshot.- ⚠️ FAILSAFE (2000ms Re-Check snapshot timeout, client-confirmed — BR_6.1.3.7): this snapshot query itself carries a hard 2000ms timeout, separate from step 7's fill-confirmation timeout. If the middleware cannot retrieve the updated position snapshot from the broker within 2000ms, it assumes the connection is compromised, aborts the trim loop immediately, and dispatches
FLATTEN_ALL— it does not retry the query or fall back to a stale snapshot. - If the snapshot returns in time and
Current_Notional ≤ Target_Limit, stop the loop. If it is still over the limit, loop back to step 1. - For a Flow 24 dispatch only: independently of this re-check, if the system clock hits exactly
Official_Close_UTC − 30secand the portfolio is still over the limit, the T-30s Active Failsafe (shared step 8 below) instantly aborts the loop and dispatchesFLATTEN_ALL. ⚠️ For a Flow 23 dispatch, no such failsafe exists (BR_6.1.3.6) — see the Flow 24-only note above. Example: the0.55 lotclose fills, bringingCurrent_Notionalto$49,500— below the$50,000Target_Limit— so the loop stops here; no second iteration needed.
- ⚠️ FAILSAFE (2000ms Re-Check snapshot timeout, client-confirmed — BR_6.1.3.7): this snapshot query itself carries a hard 2000ms timeout, separate from step 7's fill-confirmation timeout. If the middleware cannot retrieve the updated position snapshot from the broker within 2000ms, it assumes the connection is compromised, aborts the trim loop immediately, and dispatches
Shared step — T-30s Active Failsafe (applies after both A and B, Flow 24 / overnight margin enforcement only)
8. T-30s Active Failsafe (independent of either branch's steps above, universal across Rithmic/MT5/TraderEvolution — but scoped to a Flow 24-dispatched loop only, BR_6.1.3.6). At exactly Official_Close_UTC − 30sec — regardless of whether the Primary Loop above is still running, has stalled, or has already exited — the middleware independently re-verifies whether the position is still within Target_Limit:
- If compliant → no action; this is the expected outcome when the trim loop resolved in time.
- If still non-compliant → the middleware bypasses the trim loop entirely and dispatches
FLATTEN_ALLdirectly to the gateway (hard liquidation, no further trim attempt). This is the case where both the trim process and theFLATTEN_ALLfailsafe have failed to bring the account into compliance — the middleware fires the Trim / Flatten Failure Alert, a Severity 1 alert to Slack#risk-ops(BR_6.1.3.4 — field template below). This mechanism is universal across Rithmic (Futures), MT5, and TraderEvolution (Forex), and across both Futures checks (Check 1, Check 2) — the same Node.js middleware logic runs identically regardless of platform or which check was in progress; no platform-specific native failsafe is configured or relied upon.
⚠️ This step does not run for a Flow 23 (news event) loop. A Flow 23-dispatched Primary Loop has no News_Event_Time − 30sec equivalent of this mechanism — see BR_6.1.3.6 and Exc-4 for what happens instead if a Flow 23 loop has not resolved by News_Event_Time.
[SEV-1] TRIM / FLATTEN FAILURE ALERT
User ID: {user_id}
Account ID: {account_id}
Broker name: {MT5/TE/Rithmic}
Remaining Open Positions: {quantity}
Gateway Error: {gateway_error_reason}user_id— the trader whose account the trim/flatten attempt was run against.account_id— the specific trading account ID (distinct fromuser_id— a trader may hold more than one account/level).Broker name— which gateway the failed attempt went through:MT5,TE(TraderEvolution), orRithmic.Remaining Open Positions— the quantity still open on the account at the moment this alert fires (contracts for Futures, lots for Forex) — i.e. the breach the trim loop and theFLATTEN_ALLfailsafe both failed to clear.Gateway Error— the specific rejection/error reason returned by the broker gateway on the last attempted close order (e.g. theExecutionReportreject reason, a connectivity error, or an API-level error code), so Risk Ops has a concrete starting point for investigation rather than a generic "failed" notice.
See BR_6.1.3.4 for the full field-by-field rule and its relationship to the REJECTED-handling alert in BR_6.1.3.5.
6. Alternative Flows
-
Alt-1 — Primary Loop resolves compliance well within the T-120s → T-30s window.
- Context: the first trim order fills immediately and brings exposure at/below
Target_Limitin one iteration. - Futures Check 1 (and, for a Flow 24 dispatch, Check 2) / Forex step 8 exit normally. For a Flow 24 dispatch, the T-30s Active Failsafe finds the position already compliant at its check and takes no action — this is the expected common case. For a Flow 23 dispatch, there is no T-30s check to begin with (BR_6.1.3.6) — the loop's own normal exit is the only resolution.
- Context: the first trim order fills immediately and brings exposure at/below
-
Alt-2 — Multiple re-check iterations needed before compliance.
- Context: the first trim order is insufficient to cover the full overage (e.g. the largest position alone doesn't close the gap).
- The loop repeats Check 1's steps 1-9 (Futures) / Check 2's steps 1-6 / 1-8 (Forex), selecting the next largest position each time, until that check's limit is satisfied — or, for a Flow 24 dispatch, the T-30s Active Failsafe intervenes first. For a Flow 23 dispatch, no failsafe intervenes — the loop keeps iterating until compliant or exits unresolved at
News_Event_Time(BR_6.1.3.6, Exc-4).
-
Alt-3 — Futures, Flow 24: Check 1 trims, then Check 2 also needs to trim.
- Context: the account's overnight book breaches both the 25% ES-Equivalent cap and, even after Check 1's trim, the CME Overnight Margin requirement against
Available_Equity. - Check 1 runs to completion first (its own full sort/execute/re-check cycle); only once Check 1 reports compliant does Check 2 begin its own independent sort/execute/re-check cycle on the Check-1-reduced position. The two checks never interleave order-by-order — Check 2 never dispatches a close order before Check 1 has fully resolved.
- Context: the account's overnight book breaches both the 25% ES-Equivalent cap and, even after Check 1's trim, the CME Overnight Margin requirement against
7. Exceptional Flows
-
Exc-1 — Risk Weight/margin data missing for a symbol in the Futures book (Step A.3).
- The system does not attempt to sort or partially trim while risk data is incomplete — doing so on incomplete data could mis-rank which position is actually the largest risk exposure. Instead, it dispatches a global
FLATTEN_ALLfor the affected book immediately and fires a Sev-1 alert to Slack#risk-ops. See BR_6.1.3.2.
- The system does not attempt to sort or partially trim while risk data is incomplete — doing so on incomplete data could mis-rank which position is actually the largest risk exposure. Instead, it dispatches a global
-
Exc-2 — Gateway REJECTED an execution report for a dispatched close order (race-condition handling, BR_6.1.3.5).
- ⚠️ Not an instant halt-and-alert. A single REJECTED fill can happen naturally — the trader's position may have already closed or reduced milliseconds earlier via a resting stop/limit order or a manual close — so a lone reject does not itself page Operations. Instead: the middleware immediately refreshes the portfolio state from the broker and re-checks compliance. If the account now passes, the loop stops normally with no alert. If it is still over the limit, the middleware re-runs the calculation on the fresh snapshot and retries; only if a position rejects a close order twice in a row while still non-compliant does the loop abort to
FLATTEN_ALLand fire the Trim/Flatten Failure Alert. The position remains as-is between the first reject and the second (or the eventualFLATTEN_ALL) unless the T-30s Active Failsafe forcibly flattens it first.
- ⚠️ Not an instant halt-and-alert. A single REJECTED fill can happen naturally — the trader's position may have already closed or reduced milliseconds earlier via a resting stop/limit order or a manual close — so a lone reject does not itself page Operations. Instead: the middleware immediately refreshes the portfolio state from the broker and re-checks compliance. If the account now passes, the loop stops normally with no alert. If it is still over the limit, the middleware re-runs the calculation on the fresh snapshot and retries; only if a position rejects a close order twice in a row while still non-compliant does the loop abort to
-
Exc-3 — 2000ms fill-confirmation timeout on a dispatched close order.
- The loop aborts immediately and dispatches
FLATTEN_ALL(hard liquidation) for theuser_id, rather than waiting longer or retrying the partial close. No hardcoded sleep is used to implement this timeout — it is an event-driven timer on the execution-report listener itself.
- The loop aborts immediately and dispatches
-
Exc-4 — T-30s Active Failsafe fires (Flow 24 loop only), and the account is still non-compliant after
FLATTEN_ALL(Primary Loop did not resolve the breach in time, for any reason — the two-strikes REJECTED escalation, repeated timeouts, gateway latency, or the loop simply running out of time).- The middleware bypasses the trim loop entirely and dispatches
FLATTEN_ALLdirectly to the gateway. This is the condition under which the Trim / Flatten Failure Alert fires — a Severity 1 alert to Slack#risk-opswith the fulluser_id/account_id/Broker name/Remaining Open Positions/Gateway Error template. See BR_6.1.3.4. ⚠️ Because this failsafe now lives inside the same Node.js middleware that runs the Primary Loop (rather than an independent Rithmic R|Admin hard failsafe), if the middleware process itself crashes or hangs at T-30s, no independent backstop exists — client-accepted risk, see BR_6.1.2.7. ⚠️ This exception applies only to a Flow 24-dispatched loop — see Exc-4a below for the equivalent Flow 23 scenario, which has noFLATTEN_ALLfailsafe to fire in the first place.
- The middleware bypasses the trim loop entirely and dispatches
-
Exc-4a — Flow 23 (news event) loop still non-compliant at
News_Event_Time, with no T-30s Active Failsafe to intervene.- Per BR_6.1.3.6, the T-30s Active Failsafe is scoped to Flow 24 (overnight margin) only — a Flow 23 Primary Loop has no equivalent
News_Event_Time − 30secbackstop. If a Flow 23 loop has not resolved the breach byNews_Event_Time, the trim loop simply continues iterating on its own event-driven pace (same REJECTED two-strikes handling as any other Check 1 iteration, BR_6.1.3.5) — no middleware-sideFLATTEN_ALLis auto-dispatched, and no Trim/Flatten Failure Alert fires on this account for this reason alone. This is a client-confirmed, accepted gap for the news-event case — see BR_6.1.3.6 for the rationale.
- Per BR_6.1.3.6, the T-30s Active Failsafe is scoped to Flow 24 (overnight margin) only — a Flow 23 Primary Loop has no equivalent
-
Exc-5 — 2000ms Re-Check snapshot-query timeout (Futures step 7 / Forex step 8).
- The middleware's query for the fresh post-trim portfolio snapshot does not return within 2000ms. Per client-stated priority (never prioritize avoiding over-trimming over protecting firm capital — BR_6.1.2.10), the middleware treats this the same as a compromised connection: it does not retry the query or continue the loop on a stale/assumed snapshot. The loop aborts immediately and dispatches
FLATTEN_ALL(hard liquidation) for theuser_id. See BR_6.1.3.7. - ⚠️ Adrian-confirmed requirement, not a BA assumption: "Apply a hard 2000ms timeout to the Re-Check API snapshot query. If the middleware cannot retrieve the updated position snapshot within that window, assume the connection is compromised. Abort the trim loop immediately and fire the FLATTEN_ALL command." This exact 2000ms value, the no-retry/no-stale-snapshot rule, and the immediate
FLATTEN_ALLoutcome are all client-stated verbatim — none of the three is a BA-chosen default or an inferred behavior. See BR_6.1.3.7 for the full rule.
- The middleware's query for the fresh post-trim portfolio snapshot does not return within 2000ms. Per client-stated priority (never prioritize avoiding over-trimming over protecting firm capital — BR_6.1.2.10), the middleware treats this the same as a compromised connection: it does not retry the query or continue the loop on a stale/assumed snapshot. The loop aborts immediately and dispatches
8. Business Rules
BR_6.1.3.1: Futures trim algorithm, Check 1 — ES-Equivalent exposure + Risk Weight sort
The algorithm (ES-Equivalent conversion, Max_Contracts-to-Max_Contracts_ES_Equiv Appendix B conversion, Target Limit, Evaluate Compliance gate, Overage, Risk Weight sort, raw-contract conversion, Order_Qty, re-check loop) and Appendix C are fully specified in Basic Flow A, Check 1, steps 1-9. This BR adds no rule beyond them; it is kept as the traceability anchor for the CR source below. This is Check 1 only — it runs for both a Flow 24 dispatch (followed by Check 2, BR_6.1.3.9) and a Flow 23 dispatch (which stops after Check 1). The Max_Contracts_ES_Equiv conversion must stay consistent with UC_6.2.1 BR_6.2.1.5, which reads the same Table B/Appendix B column for its own Gate 2 size cap.
(Source: CHR-100 — Futures only — supersedes the raw contract-size sort in RFQ_ Stack Trading Prop Tech V7.pdf §"TRIM TO COMPLIANCE", lines 1899-1928; per-symbol ES-Equivalent ratios per Appendix C — Futures Relative Risk Helper Table (user-supplied image, 2026-10-09 session), confirmed Backend master data, not Zapier config; user-provided algorithm detail 2026-09-17/18 + 2026-10-09 sessions)
BR_6.1.3.2: Missing risk data → failsafe, never a best-effort sort
Behavior is defined in Basic Flow A step 3 and Exc-1. Rationale only: incomplete risk data is treated as a resolution failure, not a degraded-but-acceptable case.
(Source: CHR-100 — Futures only)
BR_6.1.3.3: Forex trim algorithm — BE-driven; two valid Target_Limit bases (client-confirmed)
The Forex algorithm (notional formulas, proportional Trim_Lots, round-up, PARTIAL_FILLED, live-price requirement) is fully specified in Basic Flow B, steps 1-8. Rules not stated there:
- Forex trim is 100% BE-algorithm-driven: no native MT5/TraderEvolution mechanism is involved (client-confirmed 2026-10-10).
- The Forex branch is not a Change Request: it is materially unchanged from the RFQ V7 baseline; no ES-Equivalent conversion or Risk Weight re-sort applies.
- Two
Target_Limitbases are both valid, not a conflict. Flow 23 uses a per-level fixed-cap basis (how much the trader may hold at all, by level); Flow 24 uses a live-equity basis (how much current capital can support holding overnight). They serve two different enforcement contexts. - The trim loop is formula-agnostic: it does not compute either
Target_Limit; the dispatching flow (UC_6.2.1 or UC_6.1.2) computes it and passes it in.
(Source: RFQ_ Stack Trading Prop Tech V7.pdf §"TRIM TO COMPLIANCE", lines 1899-1928 — algorithm unchanged in substance, not a CR; Trim_Lots/per-currency-case Position_Notional_Value formulas and PARTIAL_FILLED handling per user-supplied algorithm detail, 2026-10-09 session; cross-pair formula simplified (Base_Currency → USD direct conversion) and live-price-source requirement, client-confirmed 2026-10-11; shared execution/failsafe pattern per CHR-101; Target_Limit dual-formula treatment per BR_6.1.2.5 (Flow 24) and UC_6.2.1 BR_6.2.1.5 (Flow 23) — client-confirmed 2026-10-10)
BR_6.1.3.4: T-30s Node.js Active Failsafe — Flow 24 (overnight margin) only, replaces Native Broker Failsafe; Trim/Flatten Failure Alert template
The mechanism (re-verify compliance, bypass the trim loop, FLATTEN_ALL) is defined in Basic Flow shared step 8 and Exc-4. Rules not stated there:
- Scope — Flow 24 (overnight margin enforcement) only. This failsafe anchors exclusively to
Official_Close_UTC − 30sec(BR_6.1.3.6) and never fires for a Flow 23 (news event) loop — a Flow 23 loop that is still non-compliant atNews_Event_Timehas no equivalent backstop (see Exc-4a). This is a deliberate, client-confirmed scope restriction, not an oversight. - It fully replaces the old Rithmic-only R|Admin "Time-Based Auto-Flatten" hard failsafe described in RFQ V7, which is deprecated. R|Admin must not be configured with that parameter (see BR_6.1.2.7).
- The client accepted the tradeoff of running the failsafe in the same middleware process as the Primary Loop, in exchange for removing the R|Admin manual-configuration burden and DST/holiday sync risk (former A-22) — under R|Admin's native hard failsafe, DST/holiday calendar shifts had to be re-synced manually on the broker side every year; the Node.js failsafe removes that manual burden because its
Official_Close_UTCanchor is already DST-resolved before this UC ever reads it (Ref: BR_6.1.3.6). DST resolution itself is not performed by this UC — Futures'Official_Close_UTCis resolved source-native by the CME Reference Data API, per UC_4.1.3 BR_4.1.3.5.
Trim / Flatten Failure Alert — field template (client-supplied, user instruction 2026-11-05). This is the Severity 1 Slack #risk-ops alert that fires only when both the trim process and the FLATTEN_ALL failsafe fail to bring the account into compliance — i.e. the T-30s Active Failsafe's own FLATTEN_ALL dispatch does not resolve the breach either (see Basic Flow shared step 8):
[SEV-1] TRIM / FLATTEN FAILURE ALERT
User ID: {user_id}
Account ID: {account_id}
Broker name: {MT5/TE/Rithmic}
Remaining Open Positions: {quantity}
Gateway Error: {gateway_error_reason}| Field | Meaning |
|---|---|
user_id | The trader whose account the trim/flatten attempt was run against. |
account_id | The specific trading account ID — distinct from user_id, since a trader may hold more than one account/level. |
Broker name | Which gateway the failed attempt went through: MT5, TE (TraderEvolution), or Rithmic. |
Remaining Open Positions | The quantity still open on the account at the moment this alert fires — contracts for Futures, lots for Forex — i.e. the exposure neither the trim loop nor FLATTEN_ALL managed to clear. |
Gateway Error | The specific rejection/error reason returned by the broker gateway on the last attempted close order (ExecutionReport reject reason, a connectivity error, or an API-level error code) — giving Risk Ops a concrete starting point rather than a generic "failed" notice. |
This is a single alert format — it applies identically regardless of platform (Rithmic/MT5/TraderEvolution) or which Futures check was in progress (Check 1, BR_6.1.3.1; Check 2, BR_6.1.3.9) when the failure occurred. ⚠️ Dispatch source — Flow 24 only. Since this alert fires exclusively off the T-30s Active Failsafe's own FLATTEN_ALL dispatch, and that failsafe is scoped to Flow 24 (see the Scope bullet above), this alert never fires for a Flow 23-dispatched loop — a Flow 23 loop that remains non-compliant at News_Event_Time exits per Exc-4a with no Sev-1 alert of this kind. It supersedes the prior, less specific "Account ID + Platform" wording this UC previously used for the same T-30s Active Failsafe alert — the content described (account identity, outstanding exposure, gateway error) is the same information, now in an explicit field template rather than prose.
(Source: CHR-101 — supersedes RFQ_ Stack Trading Prop Tech V7.pdf §"Native Broker Failsafe Configuration", lines 1795-1817; QnA_init_docs.md A-22, A-23; Trim/Flatten Failure Alert field template — user instruction (BA session), 2026-11-05)
BR_6.1.3.5: Event-driven execution — no hardcoded sleep timers; REJECTED race-condition handling (two-strikes rule)
The execution-report handling (FILLED / REJECTED / PARTIAL_FILLED / 2000ms timeout) is defined in Basic Flow A Check 1 step 8, Check 2 step 6, Basic Flow B step 7, Exc-2 and Exc-3. Rules not stated there:
- Hardcoded
sleeptimers are forbidden anywhere in the trim loop (both branches, both Futures checks); all waiting is event-driven. - The 2000ms per-order failsafe is distinct from the T-30s Active Failsafe (BR_6.1.3.4): the former protects each individual order dispatch, the latter protects the overall window up to the deadline.
- Rationale for the
PARTIAL_FILLEDrule: it stops a slow trickle of partial fills from indefinitely extending the time the position sits non-compliant.
⚠️ REJECTED handling — race-condition check, not an instant halt (user instruction, BA session, 2026-11-05; corrects the prior "instantly halt + alert on any reject" behavior). A REJECTED close order is treated as a possible natural race condition, not an automatic failure:
| Case | Behavior |
|---|---|
FILLED | Proceed immediately to the Re-Check step, with zero artificial delay. |
REJECTED (first occurrence) | A reject can occur naturally if the trader's position already closed or reduced milliseconds earlier via a resting stop/limit order or a manual close. Do not alert Operations on a single order reject. Instead, immediately refresh the portfolio state from the broker and re-check compliance: if the portfolio now passes, stop the loop normally with no alert; if it is still over the limit, re-run the calculation on the fresh snapshot and submit a new close order for the (possibly recalculated) Order_Qty. |
REJECTED (second consecutive occurrence on a position still non-compliant) | Abort the trim loop and execute FLATTEN_ALL. The Trim/Flatten Failure Alert (BR_6.1.3.4) fires only if that FLATTEN_ALL itself also fails to bring the account into compliance — not merely because two rejects occurred. |
| 2000ms fill timeout | If an order does not reach full FILLED status within 2000ms of submission, abort the trim loop and execute FLATTEN_ALL (unchanged from the existing rule above). |
| T-30s cutoff | If the system clock reaches T-30 seconds before the loop's relevant deadline and the portfolio has not yet passed its check(s), abort the trim loop and execute FLATTEN_ALL — see BR_6.1.3.4/BR_6.1.3.6 (unchanged). |
This two-strikes rule applies identically to both Futures checks (Check 1, Check 2) and to the Forex loop — it is not specific to one branch. It supersedes the prior wording in this UC ("REJECTED → instantly halt the loop + alert"), which did not distinguish a benign race-condition reject from a genuine, unresolvable rejection.
(Source: RFQ_ Stack Trading Prop Tech V7.pdf §"TRIM TO COMPLIANCE" — "Definition: TRIM_TO_COMPLIANCE Algorithm", lines 1899-1928 — event-driven listener pattern and 2000ms timeout unchanged from baseline; PARTIAL_FILLED handling per user-supplied algorithm detail, 2026-10-09 session; REJECTED race-condition/two-strikes rule — user instruction (BA session), 2026-11-05, "Execution Listener & Failsafe Rules (Applies to Both Loops)"; not part of CHR-100 or CHR-101)
BR_6.1.3.6: T-30s Active Failsafe — scoped to Flow 24 (overnight margin enforcement) only, not Flow 23
[CR] The T-30s Active Failsafe applies only to a Flow 24-dispatched (overnight margin/rollover) trim loop. It anchors to Official_Close_UTC − 30sec (§2 Trigger item 3), the same market close/open/rollover boundary Flow 24's own T milestones derive from. It does not run for a Flow 23 (news event) trim loop — there is no News_Event_Time − 30sec failsafe equivalent, and none is dispatched for a news-event-triggered breach.
- This supersedes the prior "anchor-agnostic, universal across both dispatch sources" design (2026-10-11), under which the failsafe ran for both Flow 24 and Flow 23, anchored to
Official_Close_UTCorNews_Event_Timerespectively. The mechanism is now Flow-24-specific by design, not merely differently-anchored per flow. News_Event_Timeremains the timestamp Flow 23's own T-30/T-10/T-1/T+1 broadcast sequence (BR_6.2.1.3) is built around — that broadcast cadence is unaffected by this BR; only the T-30s Active Failsafe's own existence for a Flow 23 loop is removed.- Consequence for Flow 23: a Flow 23-dispatched trim loop that has not resolved the breach by
News_Event_Timehas no independent hard-liquidation backstop — see Exc-4a. This is a known, client-confirmed scope restriction for the news-event case, not an unresolved gap. - Every other T-30s Active Failsafe rule in this UC (the shared step 8 mechanism, BR_6.1.3.4's Trim/Flatten Failure Alert, Exc-4) is written assuming this Flow-24-only scope.
(Source: user request, 2026-11-06 — "cơ chế T-30s active failsafe chỉ được áp dụng với overnight margin enforcement, không áp dụng cho flow 23"; supersedes the 2026-10-11 "anchor-agnostic, both dispatch sources" design recorded in this same BR)
BR_6.1.3.7: Hard 2000ms timeout on the Re-Check portfolio-snapshot query (client-confirmed)
The timeout, the abort-and-FLATTEN_ALL behavior and the no-retry / no-stale-snapshot rule are defined in Basic Flow A Check 1 step 9, Check 2 step 6, Basic Flow B step 8 and Exc-5. Rules not stated there:
- It is a separate timer from the fill-confirmation timeout of BR_6.1.3.5: same 2000ms duration, but two independent timers on two different calls.
- It applies identically to the Futures (both Check 1 and Check 2) and Forex branches, and to a loop dispatched by either Flow 24 or Flow 23.
(Source: user instruction 2026-10-26 — client-stated risk acceptance and priority rule, relayed from UC_6.1.2 BR_6.1.2.10: "We never prioritize avoiding over-trimming over protecting firm capital... Apply a hard 2000ms timeout to the Re-Check API snapshot query. If the middleware cannot retrieve the updated position snapshot within that window, assume the connection is compromised. Abort the trim loop immediately and fire the FLATTEN_ALL command.")
BR_6.1.3.8: Close-order attributes — Order Type, Time in Force, matching policy
Every partial-close order this UC dispatches (Basic Flow A, Check 1 step 8; Check 2 step 6; Basic Flow B step 6), on any branch or check, is sent with a fixed set of order attributes — never a Limit order, and never a resting/GTC-style time-in-force that could leave a stale order sitting on the book past this loop's deadline:
-
Order Type:
Market— on every platform (Rithmic, MT5, TraderEvolution). A trim order's purpose is to de-risk the position within the loop's hard time budget (2000ms fill-confirmation failsafe, BR_6.1.3.5); a Limit order could sit unfilled indefinitely and would defeat that budget. -
Time in Force (TIF) — platform-specific:
Platform TIF Rithmic (Futures) IOC(Immediate or Cancel)TraderEvolution (Forex) IOC(Immediate or Cancel)MT5 (Forex) Today, or left blank — MT5 does not require a TIF value for a Market orderIOCfills whatever quantity is immediately available at the market and cancels the remainder outright, rather than letting any unfilled remainder rest on the book — consistent with this loop's event-driven fill-or-timeout pattern (BR_6.1.3.5): a resting remainder would be indistinguishable from a slow fill and could stall the 2000ms failsafe's intent. MT5 has no equivalent explicit IOC flag on its Market order type;Today/blank is simply MT5's own non-requirement for this field on a Market order, not a deliberately different fill behavior from the other two platforms. -
Matching/execution policy:
IOC(Immediate or Cancel) — the exchange/platform-side matching policy applied to the order, same intent as the TIF setting above: execute immediately against available liquidity, cancel any unfilled balance, never queue.
This rule applies identically regardless of which branch (Futures Basic Flow A — Check 1 or Check 2 — or Forex Basic Flow B) or which dispatch source (Flow 24 or Flow 23, §2 Trigger) is driving the loop — the order attributes are a property of how a close order is sent, not of which Target_Limit/sort algorithm computed its quantity.
(Source: user instruction, 2026-10-27 — "Order type khi đặt để cắt lệnh là Market. TIF: TE/Rithmic chọn IOC, MT5 chọn Today hoặc trống (MT5 đang không require). Quy tắc khớp lệnh (Policy): chọn loại IOC.")
BR_6.1.3.9: Futures trim algorithm, Check 2 — CME Overnight Margin Check (Flow 24 only, moved from UC_6.1.2)
The algorithm (Total_Equity/Margin_Already_Encumbered_By_Other_Closed_Asset_Classes/Available_Equity/Required_Margin core definitions, the three-group asset-class scoping, the sort/convert/execute/re-check loop, and the worked example) is fully specified in Basic Flow A, Check 2. This BR adds the rules not stated there:
- Sequencing. Check 2 only runs for a Flow 24 dispatch, and only once Check 1 (BR_6.1.3.1) has fully resolved for the same closing-now asset class. A Flow 23 dispatch never reaches Check 2 — Flow 23 has no CME Overnight Margin concept, so its loop stops after Check 1.
- Relocated content, same formula.
Required_Margin = MAX(CME_Overnight_Margin, 25% × Notional)compared againstAvailable_Equity, and theMargin_Already_Encumbered_By_Other_Closed_Asset_Classes5-step sub-procedure, are unchanged in substance from what UC_6.1.2 used to compute inline at T-2min (its formerBR_6.1.2.4/Basic Flow step 5) — only the owning document has changed. UC_6.1.2 now dispatches to this UC unconditionally once its own Gate 1 (Universal Drawdown Safety Gate) passes, rather than computing this check itself and only dispatching on a pre-found shortfall. - Shared failsafe/listener rules. Check 2's execution listener (
FILLED/REJECTED-race-condition/2000ms fill timeout) follows the exact same rule as Check 1 (BR_6.1.3.5); its Re-Check snapshot query carries the same independent 2000ms timeout (BR_6.1.3.7); its close orders use the same order attributes (BR_6.1.3.8); and it is backstopped by the same T-30s Active Failsafe (BR_6.1.3.4) as Check 1 and the Forex loop — there is no Check-2-specific variant of any of these mechanisms. - Missing margin-rate data. The missing-risk-data failsafe (BR_6.1.3.2) applies identically to Check 2 — if
CME_Overnight_Margin_Ratedata is missing for any symbol in the remaining book, Check 2 does not sort/trim on incomplete data; it dispatchesFLATTEN_ALLfor the affected book and fires the Trim/Flatten Failure Alert path.
(Source: RFQ_ Stack Trading Prop Tech V7.pdf §Risk Enforcement Endpoints — "Futures Asset-Specific Margin Enforcement", lines 1733-1767 — original formula source, previously cited under UC_6.1.2 BR_6.1.2.4; QnA_init_docs.md A-24 (Required Margin's single-canonical-definition decision, now pointing here); content relocated from UC_6.1.2 to this UC, and the Check 1 → Check 2 sequencing confirmed, per user instruction (BA session), 2026-11-05)
9. Update History
| Date | Version | Section | Change From | Change To | Source |
|---|---|---|---|---|---|
| 2026-09-06 | v1 | All (new) | UC_6.1.3 not yet written; RFQ V7 baseline algorithm (raw contract-size/notional sort, no independent active backstop, Native Broker Failsafe as sole T-30sec layer) | Initial SRS for UC_6.1.3, implementing the CR-20260906-001 upgrade: ES-Equivalent + Risk Weight sort for Futures, notional sort retained for Forex, universal T-30s Node.js Active Failsafe replacing Native Broker Failsafe | RFQ_ Stack Trading Prop Tech V7.pdf lines 1899-1928; CR-20260906-001; QnA_init_docs.md A-22, A-23 |
| 2026-09-06 | v1 | Whole document | Published together with UC_6.1.1/UC_6.1.2 in one combined file (UC_6.1.1-6.1.3_v1.md) | Split into 3 separate per-UC files per BA instruction; this file now contains UC_6.1.3 only; all cross-UC anchors rewritten to cross-file links | User instruction 2026-09-06 —"Hãy tách các UC_6.1.1, UC_6.1.2 và UC_6.1.3 ra thành 3 file UC riêng, không gộp vào 1 file." |
| 2026-09-09 | v1 | Overview (Description, 3rd Party), all CR citations, §9-10 removed | Description was a long technical paragraph; single combinedCR-20260906-001 citation throughout (incl. next to unchanged Forex logic); 3rd Party listed Rithmic / MT5-TraderEvolution / Slack; NFRs (old §9) and Acceptance Criteria (old §10) sections present | Description rewritten concisely (purpose + which UC/cases dispatch it); CR split intoCHR-101 (T-30s Active Failsafe, universal) and CHR-100 (TRIM_TO_COMPLIANCE Futures algorithm) — CHR tag scoped to Futures-sequence content only, since Forex notional sort (BR_6.1.3.3) is unchanged RFQ V7 baseline, not a CR; 3rd Party field cleared; NFRs and Acceptance Criteria sections removed; Update History renumbered to §9 | User instruction 2026-09-09 |
| 2026-09-15 | v1 | Blockquote (H2 heading), Overview (Description), §2 Trigger item 1 | Dispatch case 2 was worded as "a Forex TraderEvolution shortfall with no native leverage reduction available" — implying MT5 Forex never reached this UC, only dispatching when TraderEvolution's native group leverage reduction was unavailable | Reworded to "a Forex shortfall on either MT5 or TraderEvolution" — both platforms now dispatch unconditionally perUC_6.1.2's rewritten BR_6.1.2.5; no algorithm change here — BR_6.1.3.3 (Forex notional sort) and BR_6.1.3.4 (T-30s Active Failsafe) already describe the correct universal mechanism and are unaffected, only the dispatch condition upstream changed | CHR-102 — client-confirmed change, relayed by user (BA session) 2026-09-15 |
| 2026-09-17 | v1 | §5 Basic Flow (Futures steps 2-3, Forex steps 1 and 4, shared step 8) | Formula steps (Overage, Order_Qty) and the missing-data/failsafe steps stated the formula or behavior and then pointed to §8 (See [BR_6.1.3.2]/[BR_6.1.3.4]) for what each variable means or what the rule actually does | Each formula step now defines its own variables inline, directly beneath the formula; the Risk Weight sort step and the T-30s Active Failsafe step now state their full behavior in place, with noSee [BR_x] pointer. §8 Business Rules is unchanged and remains the authoritative, source-cited definition of each rule | User instruction 2026-09-17 —"update lại tài liệu thành từng step chi tiết, nếu step có công thức thì mô tả ý nghĩa từng thành phần ngay dưới, không mô tả theo phần refer tới business rule nữa" |
| 2026-09-18 | v1 | §5 Basic Flow A (Futures, full rewrite, steps 1-7), §5 Basic Flow B (Forex, step 1 + pending note), §8BR_6.1.3.1, BR_6.1.3.3 | Futures flow described ES-Equivalent + Risk Weight sort at a conceptual level without the actualTarget_Limit/Total_Portfolio_ES_Equiv/Risk_Weight/Required_Trim_Raw_Contracts formulas or the Appendix B (Table B) conversion-ratio mapping; Forex flow's Target_Limit was referenced only as "passed in by UC_6.1.2," with no formula restated and no note on its pending status | Futures Basic Flow A rewritten step-by-step with full formulas:Total_Portfolio_ES_Equiv (sum of per-symbol Appendix B/Table B ES-Equivalent conversions), Target_Limit = Floor(Max_Contracts_ES_Equiv × Notional_Cap_Percent), Overage_ES_Equiv, Risk_Weight = Raw_Contract_Count × CME_Overnight_Margin_Per_Contract (sort key), Required_Trim_Raw_Contracts = Ceiling(Overage_ES_Equiv × Conversion_Ratio), Order_Qty = MIN(Required_Trim_Raw_Contracts, Position_Contract_Size); re-check loop now explicit about querying fresh broker state each iteration and the T-30 Active Failsafe racing it independently. Forex Basic Flow B's Target_Limit = Allowed_Notional = Total_Account_Equity × Table_C_Cap_Percent formula restated inline (mirroring BR_6.1.2.5), and a ⚠️ PENDING note added: the entire Forex branch may be superseded by native MT5/TraderEvolution exchange-side integration, pending client confirmation — not yet a CR. BR_6.1.3.1 and BR_6.1.3.3 updated to match | User instruction 2026-09-18 —"update basic flow của Future với công thức Target_Limit/ES-Equivalent exposure theo symbol và quy đổi về 1 giá trị ES" + "basic flow Forex ghi rõ cách tính Target_Limit và note flow đang pending do có thể tích hợp sàn (MT5, TE), chờ khách confirm" |
| 2026-10-09 | v1 | §5 Basic Flow A (step 1 Appendix C mapping, step 3-4 Risk Weight/Conversion_Ratio clarified), §5 Basic Flow B (full rewrite, steps 1-8:Max_Forex_Notional/Table A/C fields, Trim_Lots proportional formula, 3-case Position_Notional_Value, rounding, PARTIAL_FILLED), §5 shared pattern (deduplicated — each branch now states its own listener in full), §8 BR_6.1.3.1 (Appendix C replaces placeholder Appendix B/Table B reference + Backend-master-data note), BR_6.1.3.3 (full rewrite matching new Basic Flow B), BR_6.1.3.5 (PARTIAL_FILLED sub-rule added) | Futures step 1 cited a generic "Appendix B — Futures Configuration Matrix (Table B)" ES-conversion ratio with no actual symbol table; Forex Basic Flow B was a short 7-step outline (Target_Limit = Total_Account_Equity × Table_C_Cap_Percent, single Order_Qty = MIN(Overage, Position_Notional_Value)) with no per-currency-case notional formula, no proportional-trim sizing, no rounding rule, and no PARTIAL_FILLED handling; the "Shared execution/failsafe pattern" section fully restated steps 6-7 a second time after each branch already had its own | Futures step 1/3/4 now reference the actualAppendix C — Futures Relative Risk Helper Table (base unit 1.0 ES) with the full symbol → ES_Equivalent_Weight list (E-mini Indices=1, Micro Indices=0.1, Standard Energy=2, Micro Crude=0.2, E-mini Nat Gas=0.5, Gold/Copper/Platinum=1, Micro Gold=0.1, Silver/Palladium=2, Micro Silver=0.4, Treasuries=1, Bitcoin=10, Micro Bitcoin=0.2, Ethereum=2, Micro Ether=0.1), and a note that Appendix C is Backend master data, not Zapier config. Forex Basic Flow B rewritten to 8 explicit steps: Target_Limit = Max_Forex_Notional (Table A) × Notional_Cap_Percent (Table C — News_Hold_Cap_Percent/Flow 23 or Forex_Overnight_Cap_Percent/Flow 24), Trim_Lots = (Overage_USD / Largest_Position_Notional_USD) × Largest_Position_Lots (proportional sizing against the largest position, not a flat MIN), the 3-case Position_Notional_Value formula (quote=USD / base=USD / cross-pair with FX conversion), mandatory round-UP-to-step-size before dispatch, and explicit PARTIAL_FILLED handling (keep waiting for final FILLED, 2000ms timer does not pause/reset). Shared-pattern section trimmed to only the T-30s Active Failsafe, since steps 6-7/6-8 are now fully inlined per branch. BR_6.1.3.1, BR_6.1.3.3, BR_6.1.3.5 updated to match | User instruction 2026-10-09 — pasted Futures/Forex algorithm detail + Appendix C image ("Appendix C: Futures Relative Risk Helper Table") —"update lại mô tả của UC này với logic thuật toán của Future và Forex... đối với từng công thức hãy có chú thích giải thích ý nghĩa của từng thành phần"; "quy đổi... sử dụng dữ liệu quy đổi được định nghĩa ở phụ lục C Zapier... Tỷ lệ này không cần config ở Zapier có thể quản lý ở master file data ở BE" |
| 2026-10-10 | v1 | Overview (Description, Zapier Flow), §2 Trigger (full rewrite — 3 triggers), §3 P-1, §5 Basic Flow A (Appendix C → table + worked example), §5 Basic Flow B (PENDING removed, BE-confirmed note, worked example), §8BR_6.1.3.1 (Table B/Appendix C disambiguated), BR_6.1.3.3 (PENDING removed, BE-confirmed note, GAP reframed as 2 valid formulas) | §2 Trigger only listed 2 sources (Flow 24 T-120s dispatch + T-30s failsafe) — Flow 23's own T-1min Gate 2 dispatch into this same algorithm was missing entirely. Appendix C was an inline bullet list. Neither branch had a worked numeric example. Forex branch carried a ⚠️ PENDING note suggesting native MT5/TE integration might replace the BE algorithm.BR_6.1.3.3 flagged the Flow 23 vs. Flow 24 Target_Limit formula difference as an unresolved ⚠️ GAP | §2 Trigger rewritten to 3 explicit triggers: (1) Flow 24 T-2min/T-120s dispatch from UC_6.1.2's Gate 2, (2)new Flow 23 T-1min dispatch from UC_6.2.1's own Gate 2 (BR_6.2.1.5) — same TRIM_TO_COMPLIANCE algorithm, different clock/base-cap, (3) T-30s Active Failsafe, flagged as confirmed-anchored to Flow 24's Official_Close_UTC only (Flow 23 backstop coverage not yet confirmed). Appendix C converted to a Markdown table. Added a full worked numeric example threaded through every step of Basic Flow A (40 MES + 10 MCL, Target_Limit=2 ES-Equiv, Overage=4.0, Risk_Weight sort picks MES, closes entire 40-contract MES position) and Basic Flow B (EURUSD, Max_Forex_Notional=$200k, Target_Limit=$50k, Overage=$60k, Trim_Lots=0.5455→0.55, final notional $49,500). Forex PENDING note replaced with ✅ Confirmed: client confirmed (2026-10-10) Forex trim is 100% BE-algorithm-driven, no native MT5/TraderEvolution mechanism. The Flow 23/Flow 24 Target_Limit discrepancy reframed from an open GAP into two deliberately distinct, valid formulas (per-level fixed-cap for Flow 23 vs. per-trade live-equity for Flow 24) — this UC's loop is formula-agnostic | User instruction 2026-10-10 — trigger ở T-120/T-1 Flow 23 Gate 2; chuyển Appendix C sang bảng; thêm ví dụ thực tế theo từng step; Forex do BE xử lý, không phải sàn; 2 công thức Target_Limit khác nhau không phải gap |
| 2026-10-11 | v1 | §2 Trigger item 3, §3 P-1, §5 (Futures step 7, Forex step 8, shared step 8), §8BR_6.1.3.4, BR_6.1.3.6 (full rewrite) | BR_6.1.3.6 and all T-30s Active Failsafe mentions were keyed only to Official_Close_UTC, with an open ⚠️ GAP on whether/how the failsafe covers a Flow 23-dispatched loop (which has no Official_Close_UTC nearby) | Confirmed: the T-30s Active Failsafe mechanism is universal, but itsanchor timestamp is per-dispatch-source — Official_Close_UTC (market close/open/rollover boundary) for a Flow 24 loop, News_Event_Time (the news event's own scheduled time) for a Flow 23 loop. BR_6.1.3.6 rewritten from an open GAP into this confirmed two-anchor rule; BR_6.1.3.4 and every other T-30s reference in §2/§3/§5 updated to say "30 seconds before the relevant deadline" with the two anchors spelled out, rather than hardcoding Official_Close_UTC | User instruction 2026-10-11 —"ở mốc T-30s thì đối với cơ chế overnight margin thì các mốc thời gian T sẽ dựa vào thời gian đóng/mở cửa hoặc rollover để xác định thì ở flow 23 sẽ dựa vào mốc thời gian tin tức đó diễn ra" |
| 2026-10-11 | v1 | §5 Basic Flow B step 4 (cross-pair formula + live-price note), §8BR_6.1.3.3 (cross-pair formula + live-price note) | Cross-pairPosition_Notional_Value formula was Lot_Size × Contract_Size_Per_Lot × Current_Price × FX_Conversion_Rate(Quote_Currency → USD) — a two-step conversion (value in quote currency, then quote-currency-to-USD). No explicit requirement that Current_Price/FX_Conversion_Rate be a live/real-time rate | Client confirmed: (1)Current_Price and every FX_Conversion_Rate must come from the real-time live market price on the existing gateway data stream (MT5 Gateway API / TraderEvolution Admin API), never cached/delayed — added as an explicit ⚠️ note on both the step and the BR; (2) the cross-pair formula simplifies to Lot_Size × Contract_Size_Per_Lot × FX_Conversion_Rate(Base_Currency → USD) — convert the base currency straight to USD, skipping the redundant quote-currency intermediate step. Worked example updated (EURGBP, base=EUR, direct EURUSD conversion: 0.3 × 100,000 × 1.10 = $33,000, replacing the old two-step $32,766 example) | User instruction 2026-10-11 —"You must use the real-time live market price from your existing gateway data stream to calculate notional exposure... you can simplify the cross-pair logic... You do not need to calculate the value in the quote currency and then convert it to USD. You can simply convert the base currency directly to USD" |
| 2026-10-26 | v1 | §4 Post-conditions (new "2000ms Re-Check snapshot-query timeout" entry); §5 Basic Flow (Futures step 7, Forex step 8 — snapshot-query failsafe added); §6 Exceptional Flows (new Exc-5); §8 (newBR_6.1.3.7) | The Re-Check step's portfolio-snapshot query (Futures step 7, Forex step 8) had no timeout of its own — only the preceding order-execution fill-confirmation leg (step 6/7) carried the existing 2000ms failsafe (BR_6.1.3.5). An unresponsive snapshot query had no documented failure handling | Per client-stated risk acceptance and priority rule (relayed viaUC_6.1.2 BR_6.1.2.11): added a new, separate hard 2000ms timeout on the Re-Check snapshot query itself. If the middleware cannot retrieve the fresh position snapshot within 2000ms, it assumes the connection is compromised, aborts the trim loop without retry or stale-snapshot fallback, and dispatches FLATTEN_ALL — implementing the client's rule that the system never prioritizes avoiding over-trimming over protecting firm capital. New BR_6.1.3.7 documents the mechanism in full and distinguishes it from BR_6.1.3.5's fill-confirmation timeout (same 2000ms duration, two independent timers on two different calls). New Exc-5 and a §4 post-condition entry added; Futures step 7 and Forex step 8 updated in place | User instruction 2026-10-26 — client quote: "We never prioritize avoiding over-trimming over protecting firm capital... Apply a hard 2000ms timeout to the Re-Check API snapshot query. If the middleware cannot retrieve the updated position snapshot within that window, assume the connection is compromised. Abort the trim loop immediately and fire the FLATTEN_ALL command." |
| 2026-10-26 | v1 | §6 Exc-5, §8 BR_6.1.3.7 (body + source line), §9 Update History (2 rows) — all 4 BR_6.1.2.12 cross-references updated to BR_6.1.2.11 | UC_6.1.2 renumbered its §8 Business Rules (.10→.9, .11→.10, .12→.11, .13→.12) to close a numbering gap, shifting the client risk-acceptance/priority-rule BR this UC cross-references from BR_6.1.2.12 to BR_6.1.2.11 | Updated all 4 occurrences in this file that referenced BR_6.1.2.12 by exact anchor — Exc-5's priority citation, BR_6.1.3.7's body text and source line, and both Update History rows mentioning it — to BR_6.1.2.11, keeping this UC's cross-references in sync with UC_6.1.2's renumbering | User instruction 2026-10-26 (to UC_6.1.2) — "Đánh lại số thứ tự cho đúng của business rule, nếu cần sửa lại tham chiếu thì hãy sửa lại cả phần đó" — propagated here since this UC held 4 exact-anchor references to the renumbered rule |
| 2026-10-20 | v1 | §8 Business Rules (BR_6.1.3.1-6.1.3.7) | Each BR restated the formulas, thresholds and behavior already written in Basic Flow A/B, §2 Trigger and §7 Exceptional Flows (e.g. ES-Equivalent/Appendix C list in BR_6.1.3.1, Forex formulas and PARTIAL_FILLED in BR_6.1.3.3/.5, FLATTEN_ALL behavior in BR_6.1.3.2/.4/.7) | Duplicated descriptions removed; each BR now points to the Basic Flow step / Exc that defines the behavior and keeps only rules not stated there (BE-driven + two Target_Limit bases, R | Admin deprecation + risk acceptance, no-sleep rule, anchor-agnostic rule, independent timers). BR IDs and source citations unchanged so external references stay valid |
| 2026-10-26 | v1 | §6 Exc-5 body, §8 BR_6.1.3.7 source line — both BR_6.1.2.11 cross-references updated to BR_6.1.2.10 | UC_6.1.2 removed its BR_6.1.2.8 (T-60/30/10 timing-split BR, deemed unnecessary) and renumbered its §8 down one slot each, shifting the client risk-acceptance/priority-rule BR this UC cross-references from BR_6.1.2.11 to BR_6.1.2.10 | Updated both occurrences in this file that referenced the old BR_6.1.2.11 by exact anchor — Exc-5's priority citation and BR_6.1.3.7's source line — to BR_6.1.2.10, keeping this UC's cross-references in sync with UC_6.1.2's renumbering | User instruction 2026-10-26 (to UC_6.1.2) — "Hãy update lại bỏ BR_6.1.2.8... Sau đó đánh lại số thứ tự cho đúng" — propagated here since this UC held 2 exact-anchor references to the renumbered rule |
| 2026-10-27 | v1 | §5 Basic Flow A step 6, Basic Flow B step 6 (order-attribute note added); §8 (new BR_6.1.3.8) | Neither branch's close-order dispatch step stated the order's Order Type, Time in Force, or matching/execution policy — only Order_Qty and the Market_Close_Order label were specified | Added new BR_6.1.3.8: every trim close order uses Order Type Market on all platforms; Time in Force is platform-specific — IOC on Rithmic (Futures) and TraderEvolution (Forex), Today/blank on MT5 (not required there); matching/execution policy is IOC. Basic Flow A step 6 and Basic Flow B step 6 updated in place with a short inline reference to the new BR | User instruction 2026-10-27 — "Order type khi đặt để cắt lệnh là Market. TIF: TE/Rithmic chọn IOC, MT5 chọn Today hoặc trống (MT5 đang không require). Quy tắc khớp lệnh (Policy): chọn loại IOC." |
| 2026-10-27 | v1 | §7 Exceptional Flows (Exc-5 — Adrian-confirmed note added) | Exc-5 described the 2000ms Re-Check snapshot-query timeout and FLATTEN_ALL fallback as BA-documented behavior, with the client-stated source only cited generically as "user instruction, 2026-10-26" rather than attributed directly | Added an explicit Adrian-confirmed quote directly under Exc-5: "Apply a hard 2000ms timeout to the Re-Check API snapshot query. If the middleware cannot retrieve the updated position snapshot within that window, assume the connection is compromised. Abort the trim loop immediately and fire the FLATTEN_ALL command." — making clear the 2000ms value, the no-retry/no-stale-snapshot rule, and the FLATTEN_ALL outcome are all client-stated verbatim, not a BA-chosen default or inferred behavior | User instruction 2026-10-27 — emphasize Adrian-confirmed requirement in the risk/exceptional-flow section |
| 2026-11-05 | v1.1 | §2 Trigger (item 1 rewritten); §3 P-1/P-2; §4 Post-conditions (new Check-2 entry, REJECTED entries split); §5 Basic Flow A (restructured into Check 1 / Check 2, new Check 2 section with Core Definitions + 6 steps + worked example; Check 1 steps 6-7 REJECTED handling rewritten; Forex step 7 REJECTED handling rewritten; shared step 8 alert template added); §6 Alt-1/Alt-2 updated, new Alt-3; §7 Exc-2/Exc-4 rewritten; §8 BR_6.1.3.1 (renamed, scoped to Check 1), BR_6.1.3.4 (Trim/Flatten Failure Alert template added), BR_6.1.3.5 (REJECTED two-strikes rule added), BR_6.1.3.7 (Check 2 cross-ref added), new BR_6.1.3.9 (Check 2) | (1) Architecture change, confirmed with user: Flow 24's Futures dispatch into this UC used to happen only after UC_6.1.2's own Gate 2 found a Required Margin shortfall, with a pre-computed Target_Limit; this UC's Futures algorithm (Basic Flow A) only ran the ES-Equivalent/Risk-Weight trim loop against that single Target_Limit — there was no CME Overnight Margin calculation inside this UC at all. (2) REJECTED handling said "instantly halt the loop + alert" on any single reject, with no race-condition check and no distinction between a benign reject (position already closed/reduced via a resting order) and a genuine failure. (3) The Sev-1 alert (#ops-risk/#risk-ops) was described only in prose ("Account ID + Platform" + a fixed investigation-required sentence), with no explicit field template | (1) UC_6.1.2's Futures role now ends at Gate 1 (Universal Drawdown Safety Gate) — it dispatches to this UC unconditionally once Gate 1 passes, no shortfall pre-check. This UC now runs a sequential two-check engine for Futures: Check 1 (25% ES-Equivalent Contract Cap — the existing CHR-100 algorithm, steps 1-7, unchanged in substance, now explicitly named/scoped as Check 1) runs first; once compliant, Check 2 (CME Overnight Margin Check, new — Required_Margin/Available_Equity/Margin_Already_Encumbered_By_Other_Closed_Asset_Classes, the exact calculation moved from UC_6.1.2's former Basic Flow step 5, now with its own 6-step sort/execute/re-check loop and worked example) runs immediately after, for a Flow 24 dispatch only — a Flow 23 (news event) dispatch stops after Check 1, since Flow 23 has no CME margin concept. New BR_6.1.3.9 documents Check 2 in full; BR_6.1.3.1 renamed/scoped to Check 1 only. Forex is explicitly confirmed unchanged — no Check 1/Check 2 split, since CME Overnight Margin is Futures-only. (2) Rewrote the REJECTED branch into a two-strikes rule: a single reject triggers a silent refresh-and-re-check (no alert) — only a second consecutive reject on a still-non-compliant position escalates to FLATTEN_ALL. Applied identically to Check 1, Check 2, and the Forex loop (BR_6.1.3.5 rewritten; Exc-2 rewritten; Post-conditions split into "single REJECTED" vs. "REJECTED twice in a row" entries). (3) Added the literal field template ([SEV-1] TRIM / FLATTEN FAILURE ALERT with User ID/Account ID/Broker name/Remaining Open Positions/Gateway Error) to BR_6.1.3.4, the shared T-30s Active Failsafe step, and Exc-4 — explicitly firing only when both the trim process and the FLATTEN_ALL failsafe fail to bring the account into compliance (not on every T-30s failsafe trigger as the prior wording implied). UC_6.1.2 updated in the same session to retire its Futures margin calculation and dispatch unconditionally; CHR-100's own CR_summary.md updated to reflect the Check 1/Check 2 split and the REJECTED rule correction. | User instruction (BA session), 2026-11-05 — pasted Slack alert field template, "Execution Listener & Failsafe Rules (Applies to Both Loops)" text, and a detailed 5-part Futures algorithm description ("Core Definitions for Futures Overnight Margin," "Sequential Execution Order," "Check 1 Loop," "Check 2 Loop," "Execution Listener"); architecture confirmed via clarifying questions (Check 1/Check 2 split, UC_6.1.2's narrowed role, unconditional dispatch, Forex unchanged) before implementation |
| 2026-11-06 | v1.2 | §8 BR_6.1.3.4 (DST/holiday sync risk bullet expanded) | The bullet mentioned "removing the R|Admin manual-configuration burden and DST/holiday sync risk (former A-22)" as a historical tradeoff note, without stating which mechanism actually resolves DST for the anchor timestamps (Official_Close_UTC/News_Event_Time) this UC's own T-30s failsafe reads — readable as if DST risk were simply accepted/ignored rather than resolved elsewhere | Expanded the bullet to state explicitly that the Node.js failsafe's anchor timestamps are already DST-resolved before this UC reads them — Futures' Official_Close_UTC resolved source-native by the CME Reference Data API, Forex's Rollover_UTC (via UC_6.1.2) resolved by a timezone-aware library targeting America/New_York — both per UC_4.1.3 BR_4.1.3.5. This UC performs no DST calculation of its own | User request, 2026-11-06 — "mô tả và update thông tin về khung giờ rollover đang áp dụng sẽ có xử lý DST trong UC_6.1.2 và UC_6.1.3"; DST mechanism itself already existed in BR_4.1.3.5 (client-supplied, 2026-08-19) — this update only adds the missing cross-reference from UC_6.1.3, it does not change the underlying DST mechanism |
| 2026-11-06 | v1.3 | §5 Basic Flow A, Check 1 (new step 3 "Evaluate Compliance," steps 3-7 renumbered to 4-8); §8 BR_6.1.3.1 (steps 1-7 → 1-8); §6 Alt-2 (step count updated); §8 BR_6.1.3.5/BR_6.1.3.7/BR_6.1.3.8 (step-number cross-references updated) | Check 1 computed Target_Limit/Overage_ES_Equiv (steps 1-2) and then went straight into sort/select/size (old step 3, Sort by Risk Weight) with no explicit compliance check in between — the only place Total_Portfolio_ES_Equiv ≤ Target_Limit was actually evaluated was inside step 7's Re-Check (i.e. only after a trim order had already been sent). Under the current architecture, where UC_6.1.2 dispatches to Check 1 unconditionally every time Gate 1 passes (not only on a pre-found shortfall), this left no documented early-exit for an account that is already compliant on arrival | Added new step 3 — Evaluate Compliance, immediately after step 2 (Calculate the Overage) and before step 4 (Sort by Risk Weight, renumbered from old step 3): IF Total_Portfolio_ES_Equiv ≤ Target_Limit => Check 1 is complete (zero orders dispatched, same Flow 23/Flow 24 branching as the post-loop handoff) IF Total_Portfolio_ES_Equiv > Target_Limit => proceed to next step (sort/select/size as before). Old steps 3-7 (Sort by Risk Weight, Convert Overage to Target Raw Contracts, Determine Trim Quantity, Execute & Listen, Re-Check & T-30 Failsafe) renumbered to steps 4-8; every in-file cross-reference to a Check 1 step number (BR_6.1.3.1's "steps 1-7" anchor, Alt-2's step-count note, and the step-number mentions inside BR_6.1.3.5/BR_6.1.3.7/BR_6.1.3.8/Check 2's own cross-references to Check 1) updated to match the new 1-8 numbering | User request, 2026-11-06 — "Hãy update mô tả cho tôi ở check 1, sau step tính toán Target limit và total portfolio exposure sẽ có step sau: Evaluate Compliance: If Total_Portfolio_ES_Equiv <= Target_Limit, Check 1 is complete. If Total_Portfolio_ES_Equiv > Target_Limit, proceed to next step." |
| 2026-11-06 | v1.4 | Overview (Description); §2 Trigger (items 2-3); §3 P-1; §5 Basic Flow A Check 1 step 8, Basic Flow B step 8, shared step 8 (T-30s Active Failsafe); §6 Alt-1/Alt-2; §7 (new Exc-4a, Exc-4 scoped); §8 BR_6.1.3.4/BR_6.1.3.6 (rewritten) | The T-30s Active Failsafe was documented as a universal, anchor-agnostic backstop running for both dispatch sources — Official_Close_UTC − 30sec for a Flow 24 (overnight margin) loop, News_Event_Time − 30sec for a Flow 23 (news event) loop (confirmed as a deliberate two-anchor design, 2026-10-11). This implied a Flow 23 trim loop that fails to resolve by News_Event_Time always gets hard-flattened by the same middleware mechanism as a Flow 24 loop | [CR] Scope restriction, client-confirmed: the T-30s Active Failsafe now applies only to a Flow 24-dispatched (overnight margin) loop — anchored exclusively to Official_Close_UTC − 30sec. It no longer runs for a Flow 23 (news event) loop at all; there is no News_Event_Time − 30sec failsafe equivalent. BR_6.1.3.6 rewritten from the "anchor-agnostic, both dispatch sources" design to this Flow-24-only scope. BR_6.1.3.4 and the shared step 8 mechanism updated to state the Flow-24-only scope explicitly, including the Trim/Flatten Failure Alert (which now never fires for a Flow 23 loop, since it fires only off this failsafe's own FLATTEN_ALL). New Exc-4a documents the resulting Flow 23 behavior: a non-compliant loop at News_Event_Time simply keeps iterating (or exits unresolved) with no auto-FLATTEN_ALL and no Sev-1 alert — a client-confirmed, accepted gap for the news-event case, not an unresolved design question. §2 Trigger items 2-3, §3 P-1, Alt-1/Alt-2, and Check 1/Basic Flow B's own step 8 Re-Check bullets all updated to state the Flow 24-only condition explicitly rather than describing the failsafe as running identically for both flows | User request, 2026-11-06 — "cơ chế T-30s active failsafe chỉ được áp dụng với overnight margin enforcement, không áp dụng cho flow 23" |
| 2026-11-06 | v1.5 | §5 Basic Flow A, Check 1 (old step 2 "Calculate the Overage" split into new step 2 "Calculate the Target Limit" + new step 4 "Calculate the Overage," with Evaluate Compliance staying step 3 in between; old steps 4-8 renumbered to 5-9); §8 BR_6.1.3.1 (steps 1-8 → 1-9); §6 Alt-2 (step count updated); §8 BR_6.1.3.5/BR_6.1.3.7/BR_6.1.3.8 (step-number cross-references updated); worked-example header (steps 1-6 → 1-7) | Step 2 computed both Target_Limit and Overage_ES_Equiv in one step, with Evaluate Compliance (step 3) running only after both had already been calculated — so Overage_ES_Equiv was always computed even for an already-compliant account that would exit at step 3 without ever using it | Split step 2 into two: step 2 — Calculate the Target Limit (Target_Limit = Floor(Max_Contracts_ES_Equiv × Cap_Percent) only) runs first; Evaluate Compliance stays step 3 and now runs immediately after Target_Limit is known, before any overage is calculated; Calculate the Overage (Overage_ES_Equiv = Total_Portfolio_ES_Equiv − Target_Limit) becomes a new step 4, reached only once step 3 finds the book non-compliant — so an already-compliant account exits at step 3 without Overage_ES_Equiv ever being computed. Old steps 4-8 (Sort by Risk Weight, Convert Overage to Target Raw Contracts, Determine Trim Quantity, Execute & Listen, Re-Check) shift down one slot each to steps 5-9; every in-file cross-reference to a Check 1 step number updated to match the new 1-9 numbering | User request, 2026-11-06 — "hãy update mô tả tách cho tôi step tính toán target limit và overage riêng, bước evaluate sẽ thực hiện ngay sau bước tính toán target limit chứ không phải ở sau bước tính toán overage" |
| 2026-11-06 | v1.6 | §5 Basic Flow A, Check 1 step 2 (new Max_Contracts-to-Max_Contracts_ES_Equiv conversion formula + description); worked-example header and the numeric examples in steps 1, 3, 4, 6, 7, 9 (rewritten for the corrected 0.8/Target_Limit = 0 values, including a new full second-iteration walkthrough in step 9); Check 2's own "continuing the Check 1 example" worked example (rewritten — Check 1 now leaves 0 positions open in that scenario, plus a new independent example to still illustrate Check 2 actually trimming); §8 BR_6.1.3.1 (conversion added to the summary list + cross-ref to BR_6.2.1.5) | Step 2's Target_Limit formula read Max_Contracts_ES_Equiv directly from Table B as if it were already in ES-Equivalent units (worked example used Max_Contracts_ES_Equiv = 8 for an Associate Trader's 8 Micros row) — but Table B/Appendix B's raw Max_Contracts value is a count of a representative contract type (Micros/Minis), not already ES-Equivalent, and UC_6.2.1 BR_6.2.1.5 — which reads this exact same Table B column — already correctly converts the same 8 Micros row to 0.8 ES-Equivalent. This UC's uncorrected = 8 value was inconsistent with its own sibling UC reading identical source data | [CR] Added the missing conversion step: Max_Contracts_ES_Equiv = Max_Contracts (raw Table B) × ES_Equivalent_Weight (Appendix B/C conversion — 0.1 for a Micros row, 1 for a Minis row, per Table B's own "1 ES ≡ 10 Micros" governing note), feeding into the existing Target_Limit = Floor(Max_Contracts_ES_Equiv × Cap_Percent) formula. Corrected the worked example throughout Check 1 to Max_Contracts_ES_Equiv = 8 × 0.1 = 0.8 → Target_Limit = Floor(0.8 × 0.25) = 0, now matching BR_6.2.1.5's own worked example for the same account tier. Cascaded this correction through every downstream numeric example: Overage becomes 6.0 (not 4.0), the MES close now leaves the account still non-compliant (2.0 > 0), requiring — and for the first time in this doc, concretely walking through — a genuine second iteration that closes the remaining 10 MCL too, flattening the account's entire Futures book. Check 2's own worked example updated to match (Check 1 now leaves nothing open in this specific scenario, so Check 2 trivially passes against $0 Required_Margin); added a separate, clearly-labeled independent example (unchanged from the prior numbers) to still demonstrate Check 2 actually computing and executing a trim | User request, 2026-11-06 — "ở step tính toán target limit của future phải được quy đổi sang đơn vị là ES theo phụ lục B"; user confirmed updating both the formula and the full worked example (not just the formula) when asked how to resolve the resulting inconsistency with BR_6.2.1.5 |