I already had a margin-call calculator for regular margin buying (the long side), so when someone asked for a short-selling version I figured it'd be a ten-minute job: take the existing ratio formula, flip a sign so the loss direction points up instead of down, done. It wasn't. Once I actually sat down to write the short-side math, I realized the "maintenance ratio" isn't a single universal equation at all — depending on which market's convention you're modeling, it's two structurally different formulas, and the code has to branch on which one applies before it can even ask "what price triggers a margin call."
Two regions, two different ratio formulas
The tool splits behavior on a locale check:
const isAsianMode = computed(() => {
return ["tw", "cn", "kr"].includes(locale.value);
});
That one boolean decides which of two completely different maintenance-ratio formulas gets used:
const now_maintenance_ratio = computed(() => {
if (!now_market_value.value) return 0;
let totalAsset =
old_market_value.value + self_provided.value + maintenance_margin.value;
let res = 0;
if (isAsianMode.value) {
// Asia: total collateral / current market value (call below 130%)
res = totalAsset / now_market_value.value;
} else {
// West: (total collateral - current market value) / current market value
// i.e. equity / liability
res = (totalAsset - now_market_value.value) / now_market_value.value;
}
return Math.floor(res * 100);
});
totalAsset is the same thing in both branches — proceeds from the short sale plus the initial margin you put up plus anything you've added since. What differs is the denominator relationship. The Asian-market version treats the ratio as "how much collateral do I have relative to what I owe," full stop, so it's always comfortably above 100% (the usual floor is 130%). The Western version subtracts the current market value first — it's computing account equity (what's left over after covering your short liability) as a fraction of the liability, which is why 25–40% is a normal maintenance floor there instead of 130%. Same underlying accounting, but they're not the same formula with a constant swapped — one has a subtraction the other doesn't.
That difference isn't cosmetic. It's why the component also switches default thresholds when you change language:
watch(
locale,
(newVal) => {
if (["tw", "cn", "kr"].includes(newVal)) {
maintenance_ratio.value = 130;
target_maintenance_ratio.value = 167;
} else {
maintenance_ratio.value = 30; // Western-style equity %
target_maintenance_ratio.value = 50;
}
},
{ immediate: true },
);
If you plugged a Taiwan-style 130% floor into the Western formula (or vice versa), the numbers would be nonsense — you'd either never trigger a call or trigger one immediately. The defaults aren't just localization polish; they exist because the underlying math actually changes shape.
Solving for the price, not just the ratio
The more useful number isn't "what's my ratio right now," it's "at what price do I get called." That means solving the ratio equation for price instead of evaluating it. For the Asian branch that's simple algebra:
Asset / Price = Ratio => Price = Asset / Ratio
For the Western branch, the subtraction means an extra step:
(Asset - Price) / Price = Ratio
Asset / Price - 1 = Ratio
Price = Asset / (1 + Ratio)
Both show up almost verbatim in the code, just divided by quantity to turn total asset value back into a per-share price:
const gg_price = computed(() => {
if (!sell_quantity.value) return 0;
let totalAsset =
old_market_value.value + self_provided.value + maintenance_margin.value;
let ratioDecimal = maintenance_ratio.value / 100;
let gg = 0;
if (isAsianMode.value) {
gg = totalAsset / ratioDecimal / sell_quantity.value;
} else {
gg = totalAsset / (1 + ratioDecimal) / sell_quantity.value;
}
return Math.ceil(gg * 100) / 100;
});
This is the actual mirror-image part, and it's a genuine inversion, not just a sign flip: in a long margin-call calculator the danger direction is the stock price falling (your collateral shrinks relative to your loan). Here now_market_value — the thing working against you — is now_price * sell_quantity, and it grows as price rises, because rising price means it costs more to buy back the shares you borrowed and sold. Same "collateral vs. liability" skeleton as the long-side tool, opposite trigger direction, and (for the Western branch) an extra subtraction that the long-side formula never needed.
Working out how much cash to inject to get back to a target ratio is the same algebra run in reverse — set the ratio equation equal to a target instead of the current value, then solve for the "add" term:
// Asian: (Asset + Add) / Price = Target => Add = Price * Target - Asset
needValue = now_market_value.value * targetDecimal - totalAsset;
// Western: ((Asset + Add) - Price) / Price = Target => Add = Price * (1 + Target) - Asset
needValue = now_market_value.value * (1 + targetDecimal) - totalAsset;
What this doesn't account for
The feature description says it outright: the calculation excludes fees and taxes. It also doesn't model the cost that's specific to shorting and doesn't exist on the long side at all — the daily stock-borrow fee you pay for as long as the position stays open. Every non-Asian language file mentions this in the intro copy as a caveat, but it's genuinely absent from the computation, not just undocumented; totalAsset never touches a daily accrual.
The other asymmetry is economic, not a code bug, but it's the reason the whole tool exists: a long position's maximum loss is capped (the stock can only fall to zero), while a short position's loss is theoretically unbounded, since price has no ceiling. The calculator will happily compute a "you get called at $X" number, but nothing in the math communicates that the position you're protecting has open-ended downside in a way a long position never does — that's on the person reading the result, not the formula.
One more small thing worth knowing if you go digging in the source yourself: the maintenance-ratio input has a locale-dependent minimum (:min="isAsianMode ? 100 : 0"), which quietly enforces that the Asian-mode floor can never be typed in below 100% — a sensible guard given that formula has no subtraction term to keep it in a sane range on its own.
I turned this into a small free tool if you want to plug in real numbers instead of tracing the algebra yourself: Short Selling Calculator. No sign-up, and if you're on the long side instead, there's a companion margin-call calculator linked from the same page.
Available in other languages
- 融券維持率計算機 — 繁體中文
- 融券维持率计算器 — 简体中文
- Short Selling Calculator — English
- 空売り維持率計算機 — 日本語
- 공매도 담보비율 계산기 — 한국어
- Calculateur Short Selling — Français
- Калькулятор Шорта — Русский
- Leerverkauf (Short) Rechner — Deutsch
- Kalkulator Short Selling — Bahasa Indonesia
- Calculadora de Venta en Corto — Español
- Máy Tính Bán Khống — Tiếng Việt
- เครื่องคำนวณ Short Sell — ไทย
- Kalkulator Short Selling — Polski
- Short Selling Hesaplayıcı — Türkçe
- Calcolatore Short Selling — Italiano
- Calculadora Short Selling — Português
- Short Selling Calculator — Nederlands
- Калькулятор Шорт — Українська
Top comments (0)