Sentinel-Witness / automatedLimits.js
LAWLESS1987
Add files via upload
3f9464a
Raw History Blame Contribute Delete
2.1 kB
/**
* automatedLimits.js
*
* Pure logic behind AutomatedSetupModal.jsx, pulled out of the component
* for the same reason gridMath.js and strategyGuide.js already live here
* rather than inside a .jsx file: this project's test runner only
* executes plain .js under src/lib/__tests__/ (no JSX transform in that
* path, by design -- see package.json's "test" script), so logic left
* inline in a component is logic that never gets a regression test.
* That gap is exactly how Dashboard.jsx's dead dashboard-tier button
* shipped unnoticed -- see tierNavigation.js for the other half of that
* fix.
*
* isValidLimit() intentionally mirrors tradeGate.js's own enableAutomated()
* check (finite, > 0, nothing stricter) rather than inventing a separate
* rule -- if this ever drifted from the gate's actual check, the UI could
* either block something the gate would allow, or (worse) look valid
* here and still throw at the gate. Kept identical on purpose.
*/
export function isValidLimit(raw) {
if (typeof raw !== "string" || raw.trim() === "") return false;
const n = Number(raw);
return Number.isFinite(n) && n > 0;
}
/** Worst-case, not expected-case: what it would mean if every single
* trade, every day, hit the per-trade cap. Returns null rather than NaN
* or 0 when inputs aren't both valid yet, so a caller can't accidentally
* render "$0" and have it read as a real answer. */
export function computeMaxDailyExposure(maxPerTradeUsd, maxDailyTradesCount) {
if (!isValidLimit(String(maxPerTradeUsd)) || !isValidLimit(String(maxDailyTradesCount))) return null;
return Number(maxPerTradeUsd) * Number(maxDailyTradesCount);
}
/** null when there's no balance to relate the exposure to yet (still
* loading, or a zero/missing USD balance) -- distinguished from 0 for
* the same "don't render a fake-looking real number" reason as above. */
export function computeExposurePctOfBalance(maxDailyExposure, usdBalance) {
if (maxDailyExposure === null || !Number.isFinite(usdBalance) || usdBalance <= 0) return null;
return (maxDailyExposure / usdBalance) * 100;
}