Composite Strategies
Composite strategies combine multiple legs with designated risk partners to achieve enhanced capital efficiency. When legs are partnered, the protocol recognizes that their combined risk profile may be less than the sum of individual risks, resulting in reduced collateral requirements.
Risk Partners Overviewβ
Each leg in a Panoptic position can designate another leg as its "risk partner" via the riskPartner field in the TokenId. When two legs reference each other as partners and meet specific criteria, they're treated as a composite strategy rather than independent positions.
if (tokenId.riskPartner(index) == index) {
// No partner - compute as standalone leg
return _getRequiredCollateralSingleLegNoPartner(...);
} else {
// Has partner - check for composite strategy
return _getRequiredCollateralSingleLegPartner(...);
}
Strategy Classification Matrixβ
Composite strategies are classified by the attributes of the two partnered legs:
| Width A | Width B | isLong A | isLong B | TokenType Match | Strategy |
|---|---|---|---|---|---|
| > 0 | > 0 | 0 | 0 | Different | Strangle |
| > 0 | > 0 | 0/1 | 1/0 | Different | Synthetic Stock |
| > 0 | > 0 | 0/1 | 1/0 | Same | Spread |
| > 0 | 0 | - | 1 | Same | Credit-Option Composite |
| > 0 | 0 | - | 0 | Same | Loan-Option Composite |
| 0 | 0 | 0 | 1 | Different | Delayed Swap |
Stranglesβ
A strangle consists of two short options with different token types (one call, one put).
Identificationβ
if (_tokenType != tokenTypeP) { // Different token types
if (_isLong == 0 && isLongP == 0) { // Both short
return _computeStrangle(...);
}
}
Collateral Efficiencyβ
Strangles receive 50% capital efficiency because only one side can be in-the-money at any given time:
function _computeStrangle(...) internal view returns (uint256 strangleRequired) {
// Negative utilization signals strangle treatment
poolUtilization = -(poolUtilization == 0 ? int16(1) : poolUtilization);
return _getRequiredCollateralSingleLegNoPartner(
tokenId,
index,
positionSize,
atTick,
poolUtilization // Negative triggers 50% discount in _sellCollateralRatio
);
}
How the Discount Worksβ
In _sellCollateralRatio:
if (utilization < 0) {
min_sell_ratio /= 2; // 50% of normal base ratio
utilization = -utilization;
}
Exampleβ
| Component | Standalone Requirement | Strangle Requirement |
|---|---|---|
| Short Put (20% base) | 20% of notional | 10% of notional |
| Short Call (20% base) | 20% of notional | 10% of notional |
| Total | 40% | 20% |
Synthetic Stockβ
A synthetic stock combines a long option of one type with a short option of the opposite type.
Identificationβ
if (_tokenType != tokenTypeP) { // Different token types
if (_isLong != isLongP) { // One long, one short
// Synthetic stock
}
}
Collateral Requirementβ
The requirement is the maximum of the two legs' individual requirements:
return index < partnerIndex
? Math.max(
_getRequiredCollateralSingleLegNoPartner(tokenId, index, positionSize, atTick, poolUtilization),
_getRequiredCollateralSingleLegNoPartner(tokenId, partnerIndex, positionSize, atTick, poolUtilization)
)
: 0; // Only compute once
Rationaleβ
A synthetic stock (long call + short put, or long put + short call) behaves like holding the underlying asset:
- If price rises: call profits, put loses
- If price falls: put profits, call loses
The positions offset each other, so only one needs full collateral.
Spreadsβ
A spread combines a long and short option of the same type (both calls or both puts) at different strikes.
Identificationβ
if (_tokenType == tokenTypeP) { // Same token type
if (_isLong != isLongP) { // One long, one short
return _computeSpread(...);
}
}
Types of Spreadsβ
| Spread Type | Long Strike | Short Strike |
|---|---|---|
| Bull Call | Lower | Higher |
| Bear Call | Higher | Lower |
| Bull Put | Lower | Higher |
| Bear Put | Higher | Lower |
Collateral Calculationβ
The spread requirement is the minimum of:
- The sum of individual leg requirements (split requirement)
- The defined maximum loss of the spread
function _computeSpread(...) internal view returns (uint256 spreadRequirement) {
spreadRequirement = 1; // Minimum floor
// Option 1: Sum of individual requirements
uint256 splitRequirement = _getRequiredCollateralSingleLegNoPartner(index) +
_getRequiredCollateralSingleLegNoPartner(partnerIndex);
// Option 2: Maximum loss calculation
// ... (detailed below)
spreadRequirement = Math.min(splitRequirement, spreadRequirement);
}
Calendar Spread Adjustmentβ
For spreads with different widths (calendar spreads), an additional adjustment accounts for time value differences:
int24 deltaWidth = _tokenId.width(index) - _tokenId.width(partnerIndex);
if (deltaWidth < 0) deltaWidth = -deltaWidth;
// Add width-based adjustment
spreadRequirement += (amountsMoved * uint256(deltaWidth * tickSpacing)) / 80000;
Maximum Loss Calculationβ
Case 1: Asset != TokenTypeβ
When the position's asset differs from its token type, the max loss is simply the difference in notional values:
if (tokenId.asset(index) != tokenType) {
spreadRequirement += |moved0 - moved0Partner|; // or moved1 for token1
}
Case 2: Asset == TokenTypeβ
When asset equals token type, the calculation accounts for the ratio of notional to contracts:
spreadRequirement += |notional - notionalP| Γ contracts / max(notional, notionalP)
Exampleβ
| Component | Standalone | Spread |
|---|---|---|
| Short 100 Call | 200 USDC | - |
| Long 105 Call | 100 USDC | - |
| Total | 300 USDC | 50 USDC (max loss) |
Credit-Option Compositesβ
These strategies pair an option with a credit position of the same token type.
Strategies Includedβ
| Option Type | Result |
|---|---|
| Long option + Credit | Prepaid Long Option |
| Short option + Credit | Cash-Secured Option |
Identificationβ
if (_width != widthP) { // One option, one credit/loan
if (_tokenType == tokenTypeP) { // Same asset
if (isLongP == 1) { // Partner is credit
return _width ? _computeCreditOptionComposite(...) : 0;
}
}
}
Collateral Calculationβ
function _computeCreditOptionComposite(
TokenId tokenId,
uint128 positionSize,
uint256 index,
int24 atTick
) internal view returns (uint256) {
// Assume 100% utilization for conservative requirement
uint256 _required = _getRequiredCollateralSingleLegNoPartner(
tokenId,
index,
positionSize,
atTick,
MAX_UTILIZATION // 10000
);
return _required;
}
Key Featuresβ
Uses MAX_UTILIZATION: This means:
- Short options require 100% collateralization (cash-secured)
- Long options get enhanced capital efficiency (5% vs 10%)
Credit automatically offsets: The credit amount is added to balance, naturally offsetting the requirement
Prepaid Long Option Exampleβ
A prepaid long option "pre-pays" for the option cost:
| Component | Effect |
|---|---|
| Credit (100 USDC) | +100 USDC to balance |
| Long Call (5% requirement at max util) | 50 USDC requirement |
| Net Effect | +50 USDC excess collateral |
Cash-Secured Option Exampleβ
| Component | Effect |
|---|---|
| Credit (1000 USDC) | +1000 USDC to balance |
| Short Put (100% at max util) | 1000 USDC requirement |
| Net Effect | Fully cash-secured |
Loan-Option Compositesβ
These strategies pair an option with a loan position of the same token type.
Strategies Includedβ
| Option Type | Result |
|---|---|
| Long option + Loan | Option-Protected Loan |
| Short option + Loan | Upfront Short Option |
Identificationβ
if (_width != widthP) { // One option, one credit/loan
if (_tokenType == tokenTypeP) { // Same asset
if (isLongP == 0) { // Partner is loan
return _width ? _computeLoanOptionComposite(...) : 0;
}
}
}
Collateral Calculationβ
function _computeLoanOptionComposite(...) internal view returns (uint256) {
uint256 _required = _getRequiredCollateralSingleLegNoPartner(index, ...);
uint256 requiredPartner = _getRequiredCollateralSingleLegNoPartner(partnerIndex, ...);
if (tokenId.isLong(index) == 0) {
// Short option + Loan: sum of both
return _required + requiredPartner;
} else {
// Long option + Loan: max of both
return Math.max(_required, requiredPartner);
}
}
Upfront Short Optionβ
The short option premium is received as a loan upfront:
| Component | Requirement |
|---|---|
| Loan (100 USDC) | 120 USDC (100% + 20% SCR) |
| Short Put | 200 USDC |
| Total | 320 USDC (sum) |
Option-Protected Loanβ
The long option provides downside protection for the borrowed amount:
| Component | Requirement |
|---|---|
| Loan (1000 USDC) | 1200 USDC |
| Long Put (protection) | 100 USDC |
| Total | 1200 USDC (max, not sum) |
The put provides protection, so only the larger requirement applies.
Delayed Swapsβ
A delayed swap pairs a credit in one token with a loan in another, effectively creating a token exchange with delayed settlement.
Identificationβ
if (_width == 0 && widthP == 0) { // Both are credits/loans
if (_tokenType != tokenTypeP) { // Different tokens
if (_isLong != isLongP) { // One credit, one loan
return _isLong == 0 ? _computeDelayedSwap(...) : 0;
}
}
}
Collateral Calculationβ
function _computeDelayedSwap(...) internal view returns (uint256) {
// Loan amount + standard collateral ratio
uint256 loanAmount = ...;
uint256 required = Math.mulDivRoundingUp(
loanAmount,
SELLER_COLLATERAL_RATIO + DECIMALS,
DECIMALS
);
// Credit amount converted to loan token
uint256 creditAmount = ...;
uint256 convertedCredit = PanopticMath.convert0to1(...) or convert1to0(...);
// Requirement is max of loan requirement or converted credit
return required > convertedCredit ? required : convertedCredit;
}
Exampleβ
Swapping ETH for USDC with delayed settlement:
| Component | Token | Amount |
|---|---|---|
| Credit | ETH | 1 ETH |
| Loan | USDC | 2000 USDC |
If ETH = 2000 USDC:
- Loan requirement: 2000 Γ 1.2 = 2400 USDC
- Credit value: 1 ETH = 2000 USDC
- Final requirement: max(2400, 2000) = 2400 USDC
Strategy Summaryβ
| Strategy | Capital Efficiency | Key Benefit |
|---|---|---|
| Strangle | 50% discount | Only one side can be ITM |
| Synthetic Stock | Max of two legs | Positions offset |
| Spread | Max loss capped | Defined risk |
| Prepaid Long | 5% at max util | Pre-paid premium |
| Cash-Secured | 100% | Fully collateralized |
| Option-Protected Loan | Max of two | Protection from option |
| Upfront Short | Sum of both | Upfront premium receipt |
| Delayed Swap | Max of converted | Token exchange |
Important Notesβ
- Partner Validation: Legs must have matching
assetandoptionRatioto be valid partners - Single Computation: When legs are partnered, requirement is computed once (for the lower index leg)
- Fallback: If partnered legs don't match any composite pattern, they're computed as individual positions
- Option Ratios Must Match: Partners must have equal option ratios to receive composite treatment