When to Use
Use this skill when developing, backtesting, or executing quantitative short-selling or market-neutral equity strategies. Short selling requires borrowing shares, and the borrow leg has two independent failure modes: the shares may not be there, and the fee may dwarf the alpha. General Collateral (GC) names lend at a few tens of basis points; specials run orders of magnitude higher, and the fee reprices daily on an open loan. This module gates the short on inventory, prices the borrow on the conventions the fee is actually charged under, and flags recall exposure.
When NOT to Use
- As a Regulation SHO locate. Rule 203(b)(1) requires the broker-dealer to have borrowed, arranged to borrow, or have reasonable grounds to believe it can borrow.
check_availability()compares a requested size against a reported inventory number — it creates nothing and it is not a locate record. Useus-reg-sho-short-sale-locate-requirementsfor the compliance gate. - As a guarantee the borrow survives the trade. US equity loans are open term. MSLA Sec. 6.1(a) lets either party terminate on notice, with the termination date no earlier than standard settlement. Availability today says nothing about availability on day 20.
- To price a borrow when the broker has quoted you a rate. The utilization ramp is a fallback for research on data where only utilization is observable. If you have a quoted rate, pass it as
observed_borrow_rate— no public source defines a functional mapping from utilization to fee, so the ramp is a guess and the quote is not. - For non-USD/EUR loans without changing
day_count_basis. The default 360 is the money-market convention for USD and EUR. GBP-denominated loans accrue ACT/365 fixed; leaving 360 in place overstates a sterling borrow by ~1.4%. - For dividend, corporate-action, or tax modelling. A short pays a manufactured dividend and may face substitute-payment tax treatment. That is a separate P&L line and is out of scope here.
Prerequisites
- A per-ticker borrow feed supplying
BorrowStatus(ticker, utilization_rate, available_shares)— utilization as on-loan quantity over lendable inventory in $[0, 1]$, availability as the shares your lender will actually offer. Neither field has a default; a fabricated inventory number is what makes an availability gate pass silently. - Where available, the desk's or broker's quoted annualized rate as
observed_borrow_rate. - For accurate accrual: the per-day settlement marks over the holding period (
calculate_borrow_cost_schedule), rather than a single entry price. - The correct
day_count_basisfor the loan currency (360 for USD/EUR, 365 for GBP).
Workflow
-
Availability Gate (fail-closed):
check_availability(ticker, shares)returns a reason code, not just a boolean. Decision point — an unregistered ticker is a rejection (NO_BORROW_STATUS), not a pass. The absence of borrow data is not evidence of a cheap, freely available borrow; treating it as one is how a backtest shorts a name no lender would have offered.- Decision point — inventory reported at 100% utilization is contradictory data, not a permissive signal. The module returns
FULLY_UTILIZEDand refuses rather than trusting whichever field is looser.
-
Rate Resolution:
resolve_rate()returns(rate, source). Anobserved_borrow_ratealways wins and reportsobserved.- Otherwise the heuristic applies: flat
gc_rateat or below the utilization threshold, then a linear ramp fromhtb_base_ratetomax_htb_rateup to 100% utilization. Checkrate_sourcebefore trusting a cost number —heuristic_htbmeans the rate was interpolated from supply pressure, not quoted. - The ramp steps discontinuously at the threshold (0.30% to 5.00% on the defaults). That is a modelling artifact, not a market phenomenon; do not build a signal on the jump.
-
Fee Accrual:
- Collateral base is the Margin Percentage times market value (MSLA Sec. 9; 102% is customary US practice, and IBKR rounds the margined per-share price up to the whole dollar).
- $\text{DailyFee} = \text{CollateralValue} \times \dfrac{\text{Rate}}{\text{DayCountBasis}}$, accrued from and including the open date to but excluding the cover date (MSLA Sec. 5.1). Calendar days — weekends accrue.
- Decision point — pick the right entry point.
calculate_borrow_cost(trade)prices the whole period at one rate and one price and is an approximation.calculate_borrow_cost_schedule(ticker, shares, daily_marks, daily_rates)accrues on each day's mark, which is what the fee is actually computed on. Feed prior-day settlement marks: accruing day $i$ on day $i$'s own close charges the position against a price it did not yet know.
-
Net Financing:
- The fee is the gross leg. Where short sale proceeds are rebated, set
short_proceeds_credit_rate;net_financing_cost_usdcan then be negative (positive carry). Default is no credit, which is conservative for cost but must not be reported as "the rebate is unavailable."
- The fee is the gross leg. Where short sale proceeds are rebated, set
-
Recall / Squeeze Triage:
assess_recall_risk()returnsLOW/ELEVATED/HIGHfrom utilization and offered inventory. These are review triggers, not calibrated probabilities.
Full procedure: see
references/workflows.md. Standards reference: seereferences/standards.md. Printable pre-flight checklist: seeassets/checklist.md.
Common Pitfalls
- Defaulting an unknown borrow to General Collateral. Pricing a ticker you have no borrow data for at 30bp is the single most effective way to make a short backtest look profitable. Missing data must raise, not fall back to the cheapest possible assumption.
- Fabricating an inventory default. An
available_sharesdefault (this module previously assumed 1,000,000) makes the availability gate approve every name nobody checked. Availability has no safe default. - Annualizing on 365. USD and EUR securities loans accrue ACT/360, and IBKR publishes the divisor as 360. Using 365 understates every borrow fee by about 1.4% — small per trade, systematic across a book.
- Accruing on the entry price. MSLA Sec. 5.1 computes the fee daily on that day's market value. A short that doubles against you costs roughly twice as much to carry on the way out, and a flat-entry-price model never sees it.
- Ignoring the 102% collateral markup. The fee is charged on collateral, not on bare notional; skipping the Margin Percentage understates cost by a further 2%.
- Treating today's rate as the term rate. Open loans reprice daily. Pricing a 30-day hold at the day-1 rate is an assumption about borrow supply 29 days out, not a cost estimate.
- Reading the utilization ramp as a market relationship. Utilization is on-loan over lendable inventory from custodial pools. It is a supply-pressure signal, not a fee curve, and it says nothing about what your prime broker will quote you.
- Confusing availability with a locate, or a locate with a term borrow. Neither survives a lender recall under MSLA Sec. 6.1(a), and a recall that cannot be replaced ends in a buy-in at the worst possible moment.
- Passing a signed short quantity.
sharesis an absolute size; a negative would flip the fee into a credit. The module rejects it.
Verification
- Instantiate
BorrowCostModeler(gc_rate=0.0025, htb_base_rate=0.05, max_htb_rate=0.30)— defaults ofday_count_basis=360,collateral_margin_pct=1.02,htb_utilization_threshold=0.80. - Availability:
BorrowStatus("AAPL", 0.10, 100_000)$\Rightarrow$can_short("AAPL", 1000) is True.BorrowStatus("MEME", 1.00, 0)$\Rightarrow$ reasonNO_INVENTORY.BorrowStatus("CNTR", 1.00, 5_000)$\Rightarrow$ reasonFULLY_UTILIZED. An unregistered ticker $\Rightarrow$ reasonNO_BORROW_STATUSandcan_short is False. - Rate:
BorrowStatus("GME", 0.90, 5_000)$\Rightarrow$ $0.05 + 0.5 \times (0.30 - 0.05) = 0.175$, sourceheuristic_htb. Utilization exactly $0.80$ $\Rightarrow$gc_rate. Utilization $1.00$ $\Rightarrow$max_htb_rate. Addingobserved_borrow_rate=0.87$\Rightarrow$ $0.87$, sourceobserved. An unregistered ticker $\Rightarrow$UnknownBorrowStatusError. - Cost:
ShortTrade("AAPL", 100, 150.0, 30)$\Rightarrow$ collateral $$15{,}300$, cost $$3.1875$ (the legacy 365-day bare-notional formula returned $$3.0822$).ShortTrade("GME", 100, 20.0, 10)$\Rightarrow$ $$9.9167$. - Schedule: 100 shares over marks $[10, 20, 30]$ at $10%$ $\Rightarrow$ $$1.70$, versus $$0.85$ for the flat-entry-price approximation over the same three days.
- Net financing:
short_proceeds_credit_rate=0.05on 100 shares at $$100$ for 36 days $\Rightarrow$ credit $$50.00$ against a $$3.06$ fee, i.e.net_financing_cost_usd$= -$46.94$. - Negative checks: utilization outside $[0,1]$,
NaNutilization or price, negativeavailable_shares, non-positiveshares, negativedays_held,max_htb_rate < htb_base_rate,htb_utilization_threshold = 1.0,collateral_margin_pct < 1.0, and adaily_rateslength mismatch must each raise. - Run
python -m unittest discover -s skills/short-selling-borrow-cost-and-availability-modeling/scriptsand confirm 100% pass rate.