Skip to content

Commit

Permalink
needs to be cleaned up
Browse files Browse the repository at this point in the history
  • Loading branch information
moo-onthelawn committed Sep 19, 2024
1 parent 9399502 commit 348797d
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import exchange.dydx.abacus.utils.safeSet
import kollections.JsExport
import kotlinx.serialization.Serializable
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow

Expand Down Expand Up @@ -490,7 +491,7 @@ internal class TradeInputCalculator(
}
val freeCollateral = parser.asDouble(parser.value(subaccount, "freeCollateral.current")) ?: Numeric.double.ZERO

val tradeSide = OrderSide.invoke(parser.asString(trade["side"]))
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 Down Expand Up @@ -582,6 +583,7 @@ internal class TradeInputCalculator(
stepSize,
oraclePrice,
isReduceOnly,
tradeSide,
)
}

Expand All @@ -591,13 +593,38 @@ internal class TradeInputCalculator(
return null
}

private fun isolatedPnlImpact(marginMode: MarginMode, size: Double, entryPrice: Double, oraclePrice: Double?, isReduceOnly: Boolean): Double {
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

// 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)

return when (marginMode) {
MarginMode.Cross -> Numeric.double.ZERO
MarginMode.Isolated -> if (isReduceOnly) Numeric.double.ZERO else (entryPrice - (oraclePrice ?: entryPrice)).abs() * size
MarginMode.Isolated -> if (isReduceOnly) {
Numeric.double.ZERO
} else {
val diff = when (tradeSide) {
OrderSide.Buy -> entryPrice - (oraclePrice ?: entryPrice)
OrderSide.Sell -> (oraclePrice ?: entryPrice) - entryPrice
}
val res = (diff * desiredBalance * tradeLeverage) / (entryPrice + diff * tradeLeverage)
max(res, Numeric.double.ZERO)
}
}
}

Expand All @@ -613,6 +640,7 @@ internal class TradeInputCalculator(
stepSize: Double,
oraclePrice: Double?,
isReduceOnly: Boolean,
side: 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 Down Expand Up @@ -655,25 +683,29 @@ 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
filled = (balanceTotal + entryBalanceSize + isolatedPnlImpact(marginMode, entrySize, entryPrice, oraclePrice, isReduceOnly)) >= desiredBalance
val pnlImpact = isolatedPnlImpact2(marginMode, side, desiredBalance, tradeLeverage, entryPrice, oraclePrice, isReduceOnly)
filled = (balanceTotal + entryBalanceSize + pnlImpact) >= desiredBalance

var matchedSize = entrySize
var matchedUsdcSize = entryUsdcSize
var matchedBalance = matchedUsdcSize / tradeLeverage + isolatedPnlImpact(marginMode, matchedSize, entryPrice, oraclePrice, isReduceOnly)
var matchedBalance = matchedUsdcSize / tradeLeverage

if (filled) {
matchedBalance = desiredBalance - balanceTotal - isolatedPnlImpact(marginMode, (desiredBalance - balanceTotal) * tradeLeverage / entryPrice, entryPrice, oraclePrice, isReduceOnly)
matchedBalance = desiredBalance - balanceTotal - pnlImpact
matchedUsdcSize = matchedBalance * tradeLeverage
matchedSize = matchedUsdcSize / entryPrice
// Round the size to appropriate step size for market and recalculate
matchedSize =
Rounder.quickRound(
matchedSize,
stepSize,
)
matchedUsdcSize = matchedSize * entryPrice
matchedBalance = matchedUsdcSize / tradeLeverage + isolatedPnlImpact(marginMode, matchedSize, entryPrice, oraclePrice, isReduceOnly)
matchedBalance = matchedUsdcSize / tradeLeverage + pnlImpact
}
sizeTotal += matchedSize
usdcSizeTotal += matchedUsdcSize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import exchange.dydx.abacus.utils.MAX_FREE_ISOLATED_COLLATERAL_BUFFER_PERCENT
import exchange.dydx.abacus.utils.Numeric
import exchange.dydx.abacus.utils.Rounder
import kollections.toIList
import kotlin.math.max
import kotlin.math.min

internal class TradeInputMarketOrderCalculator() {
Expand Down Expand Up @@ -105,7 +106,7 @@ internal class TradeInputMarketOrderCalculator() {
user: InternalUserState?,
input: String?,
): TradeInputMarketOrder? {
val tradeSide = trade.side
val tradeSide = trade.side ?: return null
val tradeSize = trade.size
val freeCollateral = subaccount?.calculated?.get(CalculationPeriod.current)?.freeCollateral

Expand Down Expand Up @@ -195,6 +196,7 @@ internal class TradeInputMarketOrderCalculator() {
stepSize = stepSize,
oraclePrice = oraclePrice,
isReduceOnly = isReduceOnly,
tradeSide = tradeSide,
)
}

Expand All @@ -215,12 +217,29 @@ internal class TradeInputMarketOrderCalculator() {
}
}

private fun isolatedPnlImpact(marginMode: MarginMode, size: Double, entryPrice: Double, oraclePrice: Double?, isReduceOnly: Boolean): Double {
private fun isolatedPnlImpact(
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
// TODO CT-1192: refactor to call into MarginCalculator.getShouldTransferInCollateralDeprecated and MarginCalculator.getTransferAmountFromTargetLeverage
return when (marginMode) {
MarginMode.Cross -> Numeric.double.ZERO
MarginMode.Isolated -> if (isReduceOnly) Numeric.double.ZERO else (entryPrice - (oraclePrice ?: entryPrice)).abs() * size
MarginMode.Isolated -> if (isReduceOnly) {
Numeric.double.ZERO
} else {
val diff = when (tradeSide) {
OrderSide.Buy -> entryPrice - (oraclePrice ?: entryPrice)
OrderSide.Sell -> (oraclePrice ?: entryPrice) - entryPrice
}
val res = (diff * desiredBalance * tradeLeverage) / (entryPrice + diff * tradeLeverage)
max(res, Numeric.double.ZERO)
}
}
}

Expand All @@ -236,6 +255,7 @@ internal class TradeInputMarketOrderCalculator() {
stepSize: Double,
oraclePrice: Double?,
isReduceOnly: Boolean,
tradeSide: OrderSide,
): TradeInputMarketOrder? {
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 Down Expand Up @@ -276,23 +296,33 @@ internal class TradeInputMarketOrderCalculator() {
if (entryPrice > Numeric.double.ZERO) {
val entryUsdcSize = entrySize * entryPrice
val entryBalanceSize = entryUsdcSize / tradeLeverage
filled = (balanceTotal + entryBalanceSize + isolatedPnlImpact(marginMode = marginMode, size = entrySize, entryPrice = entryPrice, oraclePrice = oraclePrice, isReduceOnly = isReduceOnly)) >= desiredBalance
val pnlImpact = isolatedPnlImpact(
marginMode = marginMode,
tradeSide = tradeSide,
desiredBalance = desiredBalance,
tradeLeverage = tradeLeverage,
entryPrice = entryPrice,
oraclePrice = oraclePrice,
isReduceOnly = isReduceOnly,
)
filled = (balanceTotal + entryBalanceSize + pnlImpact) >= desiredBalance

var matchedSize = entrySize
var matchedUsdcSize = entryUsdcSize
var matchedBalance = matchedUsdcSize / tradeLeverage + isolatedPnlImpact(marginMode = marginMode, size = matchedSize, entryPrice = entryPrice, oraclePrice = oraclePrice, isReduceOnly = isReduceOnly)
var matchedBalance = matchedUsdcSize / tradeLeverage

if (filled) {
matchedBalance = desiredBalance - balanceTotal + isolatedPnlImpact(marginMode = marginMode, size = (desiredBalance - balanceTotal) * tradeLeverage / entryPrice, entryPrice = entryPrice, oraclePrice = oraclePrice, isReduceOnly = isReduceOnly)
matchedBalance = desiredBalance - balanceTotal - pnlImpact
matchedUsdcSize = matchedBalance * tradeLeverage
matchedSize = matchedUsdcSize / entryPrice
// Round the size to appropriate step size for market and recalculate
matchedSize =
Rounder.quickRound(
matchedSize,
stepSize,
)
matchedUsdcSize = matchedSize * entryPrice
matchedBalance = matchedUsdcSize / tradeLeverage + isolatedPnlImpact(marginMode = marginMode, size = matchedSize, entryPrice = entryPrice, oraclePrice = oraclePrice, isReduceOnly = isReduceOnly)
matchedBalance = matchedUsdcSize / tradeLeverage + pnlImpact
}
sizeTotal += matchedSize
usdcSizeTotal += matchedUsdcSize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal const val SLIPPAGE_PERCENT = "1"
internal const val MAX_FREE_CROSS_COLLATERAL_BUFFER_PERCENT = 0.95

// Isolated Margin Constants
internal const val MAX_FREE_ISOLATED_COLLATERAL_BUFFER_PERCENT = 0.93
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 348797d

Please sign in to comment.