Perp: Borrowing Module
Borrowing fees and groups in the Sai Perp (perpetual futures) contract.
The Borrowing Module is a crucial part of the perpetual futures trading system. Its primary responsibilities include:
Calculating and accumulating borrowing fees for leveraged positions.
Tracking open interest (OI) for trading pairs and borrowing groups.
Enforcing exposure limits to ensure trading activity remains within defined thresholds.
This document explains how the borrowing process works—from how borrowing groups are structured to the logic that updates them. It also covers the lifecycle of borrowing fees, from when a trade is opened until it is closed or liquidated.
Key Components
Data Structures
BorrowingData
Purpose: Stores fee rates and the accumulated fees for both pairs and groups.
Fields:
fee_per_block
: Base fee rate per block.acc_fee_long
: Accumulated fee for long positions.acc_fee_short
: Accumulated fee for short positions.acc_last_updated_block
: Block number of the most recent fee update.fee_exponent
: Adjusts sensitivity for fee calculation based on open interest imbalances.
BorrowingPairGroup
Purpose: Captures the historical group associations for borrowing pairs.
Fields:
group_index
: Identifier for the borrowing group.block
: Block number at which the group association was set.initial_acc_fee_long
: Initial accumulated fee for long positions.initial_acc_fee_short
: Initial accumulated fee for short positions.prev_group_acc_fee_long
: Previous group's accumulated fee for long positions.prev_group_acc_fee_short
: Previous group's accumulated fee for short positions.pair_acc_fee_long
: Accumulated fee for the pair's long positions at the time of group change.pair_acc_fee_short
: Accumulated fee for the pair's short positions at the time of group change.
OpenInterest
Purpose: Tracks open interest (total position sizes) for both pairs and groups.
Fields:
long
: Total open interest for long positions.short
: Total open interest for short positions.max
: Maximum allowable open interest.
BorrowingInitialAccFees
Purpose: Records initial accumulated fees for a trade at the moment it opens.
Fields:
acc_pair_fee
: Pair's accumulated fee when the trade opened.acc_group_fee
: Group's accumulated fee when the trade opened.block
: Block number when the trade was opened.
Storage Maps
PAIRS
: StoresBorrowingData
for each trading pair.PAIR_GROUPS
: Stores a list ofBorrowingPairGroup
records for each pair (capturing historical group changes).PAIR_OIS
: StoresOpenInterest
for each pair.GROUPS
: StoresBorrowingData
for each borrowing group.GROUP_OIS
: StoresOpenInterest
for each borrowing group.INITIAL_ACC_FEES
: StoresBorrowingInitialAccFees
for each trade.
Borrowing Groups
What is a Borrowing Group?
A Borrowing Group is a set of trading pairs that share common borrowing parameters. It simplifies fee management and exposure control by allowing:
Collective fee adjustments: Update borrowing fees for multiple pairs simultaneously.
Shared exposure limits: Manage cumulative open interest across all pairs in the group.
Role of Borrowing Groups
Fee Adjustments: Updates borrowing fees in response to market conditions—affecting all pairs in the group at once.
Exposure Control: Aggregates open interest to ensure the group's overall risk remains within acceptable limits.
Historical Fee Tracking: Logs when pairs change groups so that fee calculations remain accurate for open trades.
How Borrowing Groups Are Updated
Setting Borrowing Group Parameters
Use set_borrowing_group_params
to create or update a borrowing group's parameters:
Key Parameters:
fee_per_block
: Base borrowing fee rate per block.fee_exponent
: Exponent to scale fees based on open interest imbalances.max_oi
: Maximum allowable open interest for the group.current_block
: Current block number (for fee updates).
Process:
Validation: Ensures
fee_exponent
is within allowed bounds (1% to 300%).Update Accumulated Fees: Calls
set_group_pending_acc_fees
to synchronize the group's fees up tocurrent_block
.Store New Data: Updates the group's parameters in
GROUPS
.Adjust Open Interest Limit: Sets
max_oi
inGROUP_OIS
.
Changing a Pair's Borrowing Group
When calling set_borrowing_pair_params
to place a pair in a new borrowing group:
Key Parameters:
group_index
: The new group index to assign to the pair.
Process:
Fee Synchronization: Updates fees for both the old and new groups via
set_group_pending_acc_fees
.Open Interest Update: Removes the pair's open interest from the old group and adds it to the new group using
update_group_oi
.Record Group Change: Appends a new
BorrowingPairGroup
entry toPAIR_GROUPS
, capturing relevant fee data and the block number.Update Pair Data: Adjusts any pair-specific borrowing parameters in
PAIRS
.
Updating Open Interest
Open interest is recalculated whenever trades open or close:
Key Functions:
update_pair_oi
: Updates pair-level open interest inPAIR_OIS
.update_group_oi
: Updates group-level open interest inGROUP_OIS
.
Process:
Opening a Trade: Increases the
long
orshort
OI depending on the trade's direction.Closing a Trade: Decreases the
long
orshort
OI accordingly.
Logic Behind Updates
Accumulating Borrowing Fees
Borrowing fees grow over time, affected by OI imbalances:
Fee Formula:
delta = fee_per_block * (current_block - acc_last_updated_block) * (net_oi / max_oi) ^ fee_exponent
fee_per_block
: Base fee rate per block.current_block - acc_last_updated_block
: Blocks elapsed since the last fee update.net_oi
: Absolute difference betweenlong
andshort
OI.max_oi
: Maximum allowed open interest (for the pair or group).fee_exponent
: Exponent that increases fees exponentially with larger OI imbalances.
Side-Specific Fee Accumulation:
Fees accrue only on the side (long or short) that has the larger open interest, incentivizing a more balanced market.
Handling Trades
Opening a Trade
When a new trade is opened:
Function:
handle_trade_borrowing
Fee Synchronization: Calls
set_pair_pending_acc_fees
andset_group_pending_acc_fees
to update fees.Open Interest: Updates pair and group OI via
update_pair_oi
andupdate_group_oi
.Initial Fee Recording: Invokes
reset_trade_borrowing_fees
to log the accumulated fees at the time the trade opens.
Closing a Trade
When an existing trade closes:
Function:
handle_trade_borrowing
Fee Synchronization: Updates fees up to the current block.
Open Interest: Reduces the pair and group OI (long or short) accordingly.
Borrowing Fee Calculation:
Function:
get_trade_borrowing_fees
Computes the difference between the fees at closure vs. the
INITIAL_ACC_FEES
from trade open.Accounts for any group changes that happened during the trade.
Adjusting for Group Changes
If a pair moves to a new group while a trade is open:
Challenge: The position's borrowing fees must reflect fees from both the old group and the new group.
Solution:
Use
get_borrowing_pair_group_acc_fees_deltas
to determine the fee delta across group transitions.Sum the larger of (pair delta, group delta) for each period to get total fees.
Calculating Liquidation Price with Fees
To calculate liquidation prices, including borrowing fees:
Function:
get_trade_liquidation_price_with_fees
Includes:
Closing fees (e.g., close fee, trigger order fee)
Borrowing fees from
get_trade_borrowing_fees
Purpose: Computes the final liquidation price after deducting all fees.
Process Flow Summary
A high-level look at how trades interact with the Borrowing Module:
Trade Opening
User Action: Opens a new trade.
System:
Uses
handle_trade_borrowing
to sync fees and update OI.Stores initial accrued fees in
INITIAL_ACC_FEES
.
During Trade
System:
Continues to accumulate fees over time (not updated in storage unless an event triggers an update, like another trade).
Trade Closing
User Action: Closes an existing trade.
System:
Calls
handle_trade_borrowing
to update fees and OI.Uses
get_trade_borrowing_fees
to compute the total borrowing fees.Finalizes the trade, deducting any closing fees and borrowing fees.
Parameter Updates
Admin Action: Updates group or pair parameters.
System:
Syncs fees up to the current block.
Updates open interest if a pair's group changes.
Detailed Function Explanations
handle_trade_borrowing
handle_trade_borrowing
Purpose: Coordinates the borrowing logic whenever a trade opens or closes.
Workflow:
Pending Fees Update: Invokes
set_pair_pending_acc_fees
andset_group_pending_acc_fees
.Open Interest Update: Adjusts OI via
update_pair_oi
andupdate_group_oi
.Reset Initial Fees (for new trades): Stores current fees in
INITIAL_ACC_FEES
.
get_trade_borrowing_fees
get_trade_borrowing_fees
Purpose: Calculates total borrowing fees for a trade upon closure.
Workflow:
Load Initial Fees: Retrieves
INITIAL_ACC_FEES
for the trade.Compute Current Fees: Uses
get_direction_borrowing_pair_pending_acc_fees
andget_direction_borrowing_group_pending_acc_fees
.Group Transition Handling: Applies
get_borrowing_pair_group_acc_fees_deltas
for fee periods affected by group changes.Final Fee Calculation:
(Current Acc Fees - Initial Acc Fees) * (Trade Collateral * Leverage)
.
get_borrowing_pending_acc_fees
get_borrowing_pending_acc_fees
Purpose: Calculates the additional fees that accumulated between the last update and the current block.
Workflow:
Identify OI Imbalance: Determines whether long or short positions exceed the other.
Calculate Fee Delta: Uses the fee formula to calculate newly accrued fees.
Add Fee Delta: Applies the calculated delta to either
acc_fee_long
oracc_fee_short
.
reset_trade_borrowing_fees
reset_trade_borrowing_fees
Purpose: Logs the borrow-related fees at the moment a trade is opened.
Workflow:
Saves the current
BorrowingData
for both pair and group intoINITIAL_ACC_FEES
, including the current block number.
Example Scenario
Consider a pair that transitions from Group A to Group B while a trade is open:
Block 100
Trade Opened:
Trader opens a long position on Pair X.
Pair X is in Group A.
Accumulated Fees: 2% for the pair, 1% for the group.
Initial fees are recorded in
INITIAL_ACC_FEES
.
Block 150
Group Change:
Pair X is moved from Group A to Group B.
System updates all relevant fees for Group A up to Block 150, then assigns Pair X to Group B.
The group transition is recorded in
PAIR_GROUPS
.
Block 200
Trade Closed:
System updates fees for Pair X and Group B up to Block 200.
It calculates borrowing fees via
get_trade_borrowing_fees
:Considers the 2%/1% from Group A until Block 150.
Includes the new rates from Group B from Block 150 to 200.
Final settlement occurs, including close fees and borrowing fees.
Visualization of Logic Flow
graph TD
A[Open Trade] --> B[handle_trade_borrowing]
B --> C[Set Pending Accumulated Fees for Pair and Group]
B --> D[Update Open Interest for Pair and Group]
B --> E[reset_trade_borrowing_fees]
E --> G[Store Initial Accumulated Fees]
subgraph Pair and Group Fees
C --> F[get_borrowing_pending_acc_fees]
end
subgraph Open Interest Updates
D --> H[update_pair_oi and update_group_oi]
end
Key Takeaways
The Borrowing Module is vital to mastering the perpetual futures platform. It ensures accurate fee accrual, consistent open interest tracking, and robust exposure management.
Borrowing Groups: Centralize exposure limits and streamline fee adjustments for multiple pairs.
Accumulated Fees: Updated based on time, OI imbalances, and fee parameters.
Open Interest: Tracked at both the pair and group level, essential for risk control.
Trade Lifecycle:
Opening a trade sets the initial fees.
Closing a trade calculates total borrowing fees and updates open interest.
By carefully managing how trades interact with pairs and borrowing groups, the module ensures fairness, clarity, and security for leveraged traders and the platform as a whole.
Last updated