Skip to content

Commit

Permalink
cleaned
Browse files Browse the repository at this point in the history
  • Loading branch information
moo-onthelawn committed Sep 19, 2024
1 parent 348797d commit 734dfc6
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import exchange.dydx.abacus.calculator.SlippageConstants.TAKE_PROFIT_MARKET_ORDE
import exchange.dydx.abacus.output.input.MarginMode
import exchange.dydx.abacus.output.input.OrderSide
import exchange.dydx.abacus.protocols.ParserProtocol
import exchange.dydx.abacus.utils.MAX_FREE_CROSS_COLLATERAL_BUFFER_PERCENT
import exchange.dydx.abacus.utils.MAX_FREE_ISOLATED_COLLATERAL_BUFFER_PERCENT
import exchange.dydx.abacus.utils.MAX_FREE_COLLATERAL_BUFFER_PERCENT
import exchange.dydx.abacus.utils.NUM_PARENT_SUBACCOUNTS
import exchange.dydx.abacus.utils.Numeric
import exchange.dydx.abacus.utils.QUANTUM_MULTIPLIER
Expand Down Expand Up @@ -479,8 +478,9 @@ internal class TradeInputCalculator(
): Map<String, Any>? {
val marketId = parser.asString(market?.get("id"))
val tradeSize = parser.asNativeMap(trade["size"])
val tradeSide = OrderSide.invoke(parser.asString(trade["side"]))

if (tradeSize != null && marketId != null) {
if (tradeSize != null && marketId != null && tradeSide != null) {
val maxMarketLeverage = maxMarketLeverage(market)
val targetLeverage = parser.asDouble(trade["targetLeverage"])
val marginMode = MarginMode.invoke(parser.asString(trade["marginMode"])) ?: MarginMode.Cross
Expand All @@ -491,7 +491,6 @@ internal class TradeInputCalculator(
}
val freeCollateral = parser.asDouble(parser.value(subaccount, "freeCollateral.current")) ?: Numeric.double.ZERO

val tradeSide = OrderSide.invoke(parser.asString(trade["side"])) ?: OrderSide.Buy
val position = parser.asNativeMap(parser.value(subaccount, "openPositions.$marketId"))
val positionNotionalSize = if (position != null) {
parser.asDouble(
Expand All @@ -513,7 +512,7 @@ internal class TradeInputCalculator(
} else {
Numeric.double.ZERO
}
val isTradeSameSide = tradeSide != null &&
val isTradeSameSide =
((tradeSide == OrderSide.Buy && positionSize >= Numeric.double.ZERO) || (tradeSide == OrderSide.Sell && positionSize <= Numeric.double.ZERO))

return when (input) {
Expand Down Expand Up @@ -593,25 +592,30 @@ internal class TradeInputCalculator(
return null
}

private fun isolatedPnlImpact2(marginMode: MarginMode, tradeSide: OrderSide, desiredBalance: Double, tradeLeverage: Double, entryPrice: Double, oraclePrice: Double?, isReduceOnly: Boolean): Double {
// Calculate the difference between the oracle price and the ask/bid price in order to determine immediate PnL impact that would affect collateral checks
// Should only apply to orders that are increasing in position size (not reduceOnly)
// In a cleaner world, this would call MarginCalculator.getShouldTransferInCollateralDeprecated and MarginCalculator.getTransferAmountFromTargetLeverage but because it will be deprecated soon anyways, just passing in the necessary variables

private fun isolatedPnlImpactForBalance(
marginMode: MarginMode,
tradeSide: OrderSide,
balance: Double,
tradeLeverage: Double,
entryPrice: Double,
oraclePrice: Double?,
isReduceOnly: Boolean
): Double {
// Calculates the pnl impact for an isolated order trade, given:
// - the difference between the oracle price and the ask/bid price
// - a total balance to be used for the trade, note this balance should also be used for the pnl impact
//
// This should only apply to orders that are increasing in position size (not reduceOnly).
// In a cleaner world, this would call MarginCalculator.getShouldTransferInCollateralDeprecated and MarginCalculator.getTransferAmountFromTargetLeverage but
// because it will be deprecated soon anyways, just passing in the necessary variables.

// Formula Derivation:
// pnlImpact = diff * size
// size = balance * leverage / price

// pnlImpact = diff * (desiredBalance-pnlImpact) * tradeLeverage / entryPrice
// pnlImpact = (diff * desiredBalance - diff * pnlImpact) * tradeLeverage / entryPrice
// pnlImpact = [diff * desiredBalance * tradeLeverage - diff * pnlImpact * tradeLeverage] / entryPrice
// pnlImpact * entryPrice = diff * desiredBalance * tradeLeverage - diff * pnlImpact * tradeLeverage
// pnlImpact * entryPrice + diff * pnlImpact * tradeLeverage = diff * desiredBalance * tradeLeverage
// pnlImpact [entryPrice + diff * tradeLeverage] = diff * desiredBalance * tradeLeverage
// pnlImpact = (diff * desiredBalance * tradeLeverage) / (entryPrice + diff * tradeLeverage)

// pnlImpact + (diff * pnlImpact * tradeLeverage) / entryPrice = desiredBalance * tradeLeverage
// pnlImpact * (1 + diff * tradeLeverage / entryPrice)= desiredBalance * tradeLeverage
// pnlImpact = desiredBalance * tradeLeverage * entryPrice / (1 + diff * tradeLeverage)
// size = balance * tradeLeverage / entryPrice
// pnlImpact = diff * (balance - pnlImpact) * tradeLeverage / entryPrice
// pnlImpact = (diff * balance - diff * pnlImpact) * tradeLeverage / entryPrice
// pnlImpact * (entryPrice + diff * tradeLeverage) = diff * balance * tradeLeverage
// pnlImpact = (diff * balance * tradeLeverage) / (entryPrice + diff * tradeLeverage)

return when (marginMode) {
MarginMode.Cross -> Numeric.double.ZERO
Expand All @@ -622,8 +626,8 @@ internal class TradeInputCalculator(
OrderSide.Buy -> entryPrice - (oraclePrice ?: entryPrice)
OrderSide.Sell -> (oraclePrice ?: entryPrice) - entryPrice
}
val res = (diff * desiredBalance * tradeLeverage) / (entryPrice + diff * tradeLeverage)
max(res, Numeric.double.ZERO)
val pnlImpact = (diff * balance * tradeLeverage) / (entryPrice + diff * tradeLeverage)
max(pnlImpact, Numeric.double.ZERO)
}
}
}
Expand All @@ -640,7 +644,7 @@ internal class TradeInputCalculator(
stepSize: Double,
oraclePrice: Double?,
isReduceOnly: Boolean,
side: OrderSide,
tradeSide: OrderSide,
): Map<String, Any>? {
if (marginMode == MarginMode.Isolated && !isTradeSameSide) {
// For isolated margin orders where the user is trading on the opposite side of their currentPosition, the balancePercent represents a percentage of their current position rather than freeCollateral
Expand All @@ -652,11 +656,7 @@ internal class TradeInputCalculator(
return null
}

val maxPercent = when (marginMode) {
MarginMode.Cross -> MAX_FREE_CROSS_COLLATERAL_BUFFER_PERCENT
MarginMode.Isolated -> MAX_FREE_ISOLATED_COLLATERAL_BUFFER_PERCENT
}
val cappedPercent = min(balancePercent, maxPercent)
val cappedPercent = min(balancePercent, MAX_FREE_COLLATERAL_BUFFER_PERCENT)

val existingBalance = existingPositionNotionalSize.abs() / tradeLeverage
val desiredBalance = when (marginMode) {
Expand All @@ -683,11 +683,9 @@ internal class TradeInputCalculator(
val entrySize = parser.asDouble(entry["size"])

if (entryPrice != null && entryPrice > Numeric.double.ZERO && entrySize != null) {
// balance = size * price / leverage
// balance * leverage / price = size
val entryUsdcSize = entrySize * entryPrice
val entryBalanceSize = entryUsdcSize / tradeLeverage
val pnlImpact = isolatedPnlImpact2(marginMode, side, desiredBalance, tradeLeverage, entryPrice, oraclePrice, isReduceOnly)
val pnlImpact = isolatedPnlImpactForBalance(marginMode, tradeSide, desiredBalance, tradeLeverage, entryPrice, oraclePrice, isReduceOnly)
filled = (balanceTotal + entryBalanceSize + pnlImpact) >= desiredBalance

var matchedSize = entrySize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import exchange.dydx.abacus.state.internalstate.InternalSubaccountState
import exchange.dydx.abacus.state.internalstate.InternalTradeInputState
import exchange.dydx.abacus.state.internalstate.InternalUserState
import exchange.dydx.abacus.state.internalstate.safeCreate
import exchange.dydx.abacus.utils.MAX_FREE_CROSS_COLLATERAL_BUFFER_PERCENT
import exchange.dydx.abacus.utils.MAX_FREE_ISOLATED_COLLATERAL_BUFFER_PERCENT
import exchange.dydx.abacus.utils.MAX_FREE_COLLATERAL_BUFFER_PERCENT
import exchange.dydx.abacus.utils.Numeric
import exchange.dydx.abacus.utils.Rounder
import kollections.toIList
Expand Down Expand Up @@ -106,11 +105,11 @@ internal class TradeInputMarketOrderCalculator() {
user: InternalUserState?,
input: String?,
): TradeInputMarketOrder? {
val tradeSide = trade.side ?: return null
val tradeSide = trade.side
val tradeSize = trade.size
val freeCollateral = subaccount?.calculated?.get(CalculationPeriod.current)?.freeCollateral

if (tradeSize != null && freeCollateral != null && freeCollateral > Numeric.double.ZERO) {
if (tradeSize != null && tradeSide != null && freeCollateral != null && freeCollateral > Numeric.double.ZERO) {
val maxMarketLeverage = market?.perpetualMarket?.configs?.maxMarketLeverage ?: Numeric.double.ONE
val targetLeverage = trade.targetLeverage
val marginMode = trade.marginMode ?: MarginMode.Cross
Expand All @@ -132,8 +131,7 @@ internal class TradeInputMarketOrderCalculator() {
} else {
Numeric.double.ZERO
}
val isTradeSameSide = tradeSide != null &&
((tradeSide == OrderSide.Buy && positionSize >= Numeric.double.ZERO) || (tradeSide == OrderSide.Sell && positionSize <= Numeric.double.ZERO))
val isTradeSameSide = ((tradeSide == OrderSide.Buy && positionSize >= Numeric.double.ZERO) || (tradeSide == OrderSide.Sell && positionSize <= Numeric.double.ZERO))

return when (input) {
"size.size", "size.percent" -> {
Expand Down Expand Up @@ -217,7 +215,7 @@ internal class TradeInputMarketOrderCalculator() {
}
}

private fun isolatedPnlImpact(
private fun isolatedPnlImpactForBalance(
marginMode: MarginMode,
tradeSide: OrderSide,
desiredBalance: Double,
Expand All @@ -226,8 +224,19 @@ internal class TradeInputMarketOrderCalculator() {
oraclePrice: Double?,
isReduceOnly: Boolean
): Double {
// Calculate the difference between the oracle price and the ask/bid price in order to determine immediate PnL impact that would affect collateral checks
// Calculates the pnl impact for an isolated order trade, given:
// - the difference between the oracle price and the ask/bid price
// - a total balance to be used for the trade, note this balance should also be used for the pnl impact
// TODO CT-1192: refactor to call into MarginCalculator.getShouldTransferInCollateralDeprecated and MarginCalculator.getTransferAmountFromTargetLeverage

// Formula Derivation:
// pnlImpact = diff * size
// size = balance * tradeLeverage / entryPrice
// pnlImpact = diff * (balance - pnlImpact) * tradeLeverage / entryPrice
// pnlImpact = (diff * balance - diff * pnlImpact) * tradeLeverage / entryPrice
// pnlImpact * (entryPrice + diff * tradeLeverage) = diff * balance * tradeLeverage
// pnlImpact = (diff * balance * tradeLeverage) / (entryPrice + diff * tradeLeverage)

return when (marginMode) {
MarginMode.Cross -> Numeric.double.ZERO
MarginMode.Isolated -> if (isReduceOnly) {
Expand Down Expand Up @@ -263,11 +272,7 @@ internal class TradeInputMarketOrderCalculator() {
return createMarketOrderFromSize(size = desiredSize, existingPositionNotionalSize = existingPositionNotionalSize, isTradeSameSide = isTradeSameSide, freeCollateral = freeCollateral, tradeLeverage = tradeLeverage, orderbook = orderbook)
}

val maxPercent = when (marginMode) {
MarginMode.Cross -> MAX_FREE_CROSS_COLLATERAL_BUFFER_PERCENT
MarginMode.Isolated -> MAX_FREE_ISOLATED_COLLATERAL_BUFFER_PERCENT
}
val cappedPercent = min(balancePercent, maxPercent)
val cappedPercent = min(balancePercent, MAX_FREE_COLLATERAL_BUFFER_PERCENT)

val existingBalance = existingPositionNotionalSize.abs() / tradeLeverage

Expand Down Expand Up @@ -296,7 +301,7 @@ internal class TradeInputMarketOrderCalculator() {
if (entryPrice > Numeric.double.ZERO) {
val entryUsdcSize = entrySize * entryPrice
val entryBalanceSize = entryUsdcSize / tradeLeverage
val pnlImpact = isolatedPnlImpact(
val pnlImpact = isolatedPnlImpactForBalance(
marginMode = marginMode,
tradeSide = tradeSide,
desiredBalance = desiredBalance,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ internal const val QUANTUM_MULTIPLIER = 1_000_000
internal const val SLIPPAGE_PERCENT = "1"

// Trade Constants
internal const val MAX_FREE_CROSS_COLLATERAL_BUFFER_PERCENT = 0.95
internal const val MAX_FREE_COLLATERAL_BUFFER_PERCENT = 0.95

// Isolated Margin Constants
internal const val MAX_FREE_ISOLATED_COLLATERAL_BUFFER_PERCENT = 0.95
internal const val MAX_LEVERAGE_BUFFER_PERCENT = 0.98
internal const val MARGIN_COLLATERALIZATION_CHECK_BUFFER = 0.01;

Expand Down

0 comments on commit 734dfc6

Please sign in to comment.