Skip to content

Commit

Permalink
enable balancePercent on isolated market orders (#643)
Browse files Browse the repository at this point in the history
  • Loading branch information
moo-onthelawn authored Sep 11, 2024
1 parent 660791b commit 4875794
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import exchange.dydx.abacus.calculator.SlippageConstants.TAKE_PROFIT_MARKET_ORDE
import exchange.dydx.abacus.calculator.SlippageConstants.TAKE_PROFIT_MARKET_ORDER_SLIPPAGE_BUFFER_MAJOR_MARKET
import exchange.dydx.abacus.output.input.MarginMode
import exchange.dydx.abacus.protocols.ParserProtocol
import exchange.dydx.abacus.utils.MAX_FREE_COLLATERAL_BUFFER_PERCENT
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.NUM_PARENT_SUBACCOUNTS
import exchange.dydx.abacus.utils.Numeric
import exchange.dydx.abacus.utils.QUANTUM_MULTIPLIER
Expand Down Expand Up @@ -478,6 +479,14 @@ internal class TradeInputCalculator(

if (tradeSize != null) {
val maxMarketLeverage = maxMarketLeverage(market)
val targetLeverage = parser.asDouble(trade["targetLeverage"])
val marginMode = MarginMode.invoke(parser.asString(trade["marginMode"])) ?: MarginMode.Cross
val tradeLeverage = if (marginMode == MarginMode.Isolated && targetLeverage != null && targetLeverage > Numeric.double.ZERO) {
targetLeverage
} else {
maxMarketLeverage
}

val freeCollateral = parser.asDouble(parser.value(subaccount, "freeCollateral.current")) ?: Numeric.double.ZERO

return when (input) {
Expand All @@ -486,7 +495,7 @@ internal class TradeInputCalculator(
calculateMarketOrderFromSize(
parser.asDouble(tradeSize["size"]),
freeCollateral,
maxMarketLeverage,
tradeLeverage,
orderbook,
)
}
Expand All @@ -499,7 +508,7 @@ internal class TradeInputCalculator(
calculateMarketOrderFromUsdcSize(
parser.asDouble(tradeSize["usdcSize"]),
freeCollateral,
maxMarketLeverage,
tradeLeverage,
orderbook,
stepSize,
)
Expand All @@ -512,7 +521,7 @@ internal class TradeInputCalculator(
leverage,
market,
freeCollateral,
maxMarketLeverage,
tradeLeverage,
subaccount,
user,
)
Expand All @@ -528,9 +537,9 @@ internal class TradeInputCalculator(

calculateMarketOrderFromBalancePercent(
balancePercent,
marginMode,
freeCollateral,
maxMarketLeverage,
subaccount,
tradeLeverage,
orderbook,
stepSize,
)
Expand All @@ -544,15 +553,19 @@ internal class TradeInputCalculator(

private fun calculateMarketOrderFromBalancePercent(
balancePercent: Double,
marginMode: MarginMode,
freeCollateral: Double,
maxMarketLeverage: Double,
subaccount: Map<String, Any>?,
tradeLeverage: Double,
orderbook: List<Map<String, Any>>?,
stepSize: Double,
): Map<String, Any>? {
val cappedPercent = min(balancePercent, MAX_FREE_COLLATERAL_BUFFER_PERCENT * balancePercent)
val buffer = when (marginMode) {
MarginMode.Cross -> MAX_FREE_CROSS_COLLATERAL_BUFFER_PERCENT
MarginMode.Isolated -> MAX_FREE_ISOLATED_COLLATERAL_BUFFER_PERCENT
}
val cappedPercent = min(balancePercent, buffer)
val desiredBalance = cappedPercent * freeCollateral
val usdcSize = desiredBalance * maxMarketLeverage
val usdcSize = desiredBalance * tradeLeverage

return if (usdcSize != Numeric.double.ZERO) {
if (orderbook != null) {
Expand All @@ -570,16 +583,16 @@ internal class TradeInputCalculator(

if (entryPrice != null && entryPrice > Numeric.double.ZERO && entrySize != null) {
val entryUsdcSize = entrySize * entryPrice
val entryBalanceSize = entryUsdcSize / maxMarketLeverage
val entryBalanceSize = entryUsdcSize / tradeLeverage
filled = (balanceTotal + entryBalanceSize >= desiredBalance)

var matchedSize = entrySize
var matchedUsdcSize = entryUsdcSize
var matchedBalance = matchedUsdcSize / maxMarketLeverage
var matchedBalance = matchedUsdcSize / tradeLeverage

if (filled) {
matchedBalance = desiredBalance - balanceTotal
matchedUsdcSize = matchedBalance * maxMarketLeverage
matchedUsdcSize = matchedBalance * tradeLeverage
matchedSize = matchedUsdcSize / entryPrice
matchedSize =
Rounder.quickRound(
Expand Down Expand Up @@ -636,7 +649,7 @@ internal class TradeInputCalculator(
leverage: Double,
market: Map<String, Any>?,
freeCollateral: Double,
maxMarketLeverage: Double,
tradeLeverage: Double,
subaccount: Map<String, Any>?,
user: Map<String, Any>,
): Map<String, Any>? {
Expand Down Expand Up @@ -683,7 +696,7 @@ internal class TradeInputCalculator(
leverage,
stepSize,
freeCollateral,
maxMarketLeverage,
tradeLeverage,
orderbook,
)
} else {
Expand All @@ -700,7 +713,7 @@ internal class TradeInputCalculator(
private fun calculateMarketOrderFromSize(
size: Double?,
freeCollateral: Double,
maxMarketLeverage: Double,
tradeLeverage: Double,
orderbook: List<Map<String, Any>>?,
): Map<String, Any>? {
return if (size != null && size != Numeric.double.ZERO) {
Expand Down Expand Up @@ -734,7 +747,7 @@ internal class TradeInputCalculator(
}
}
val balancePercentTotal = if (freeCollateral > Numeric.double.ZERO) {
(usdcSizeTotal / maxMarketLeverage) / freeCollateral
(usdcSizeTotal / tradeLeverage) / freeCollateral
} else {
Numeric.double.ZERO
}
Expand Down Expand Up @@ -789,7 +802,7 @@ internal class TradeInputCalculator(
private fun calculateMarketOrderFromUsdcSize(
usdcSize: Double?,
freeCollateral: Double,
maxMarketLeverage: Double,
tradeLeverage: Double,
orderbook: List<Map<String, Any>>?,
stepSize: Double,
): Map<String, Any>? {
Expand Down Expand Up @@ -840,7 +853,7 @@ internal class TradeInputCalculator(
}
}
val balancePercentTotal = if (freeCollateral > Numeric.double.ZERO) {
(usdcSizeTotal / maxMarketLeverage) / freeCollateral
(usdcSizeTotal / tradeLeverage) / freeCollateral
} else {
Numeric.double.ZERO
}
Expand Down Expand Up @@ -895,7 +908,7 @@ internal class TradeInputCalculator(
leverage: Double,
stepSize: Double,
freeCollateral: Double,
maxMarketLeverage: Double,
tradeLeverage: Double,
orderbook: List<Map<String, Any>>,
): Map<String, Any>? {
/*
Expand Down Expand Up @@ -1000,7 +1013,7 @@ internal class TradeInputCalculator(
}
}
val balancePercentTotal = if (freeCollateral > Numeric.double.ZERO) {
(usdcSizeTotal / maxMarketLeverage) / freeCollateral
(usdcSizeTotal / tradeLeverage) / freeCollateral
} else {
Numeric.double.ZERO
}
Expand Down Expand Up @@ -1066,7 +1079,7 @@ internal class TradeInputCalculator(
return when (MarginMode.invoke(marginMode)) {
MarginMode.Isolated -> listOf(
sizeField(),
// balancePercentField(), TODO: enable in CT-1180
balancePercentField(),
bracketsField(),
marginModeField(market, account, subaccount),
reduceOnlyField(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package exchange.dydx.abacus.calculator.v2.tradeinput

import abs
import exchange.dydx.abacus.calculator.CalculationPeriod
import exchange.dydx.abacus.output.input.MarginMode
import exchange.dydx.abacus.output.input.OrderSide
import exchange.dydx.abacus.output.input.OrderbookUsage
import exchange.dydx.abacus.output.input.TradeInputMarketOrder
Expand All @@ -15,7 +16,8 @@ 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_COLLATERAL_BUFFER_PERCENT
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.Numeric
import exchange.dydx.abacus.utils.Rounder
import kollections.toIList
Expand Down Expand Up @@ -108,14 +110,21 @@ internal class TradeInputMarketOrderCalculator() {

if (tradeSize != 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
val tradeLeverage = if (marginMode == MarginMode.Isolated && targetLeverage != null && targetLeverage > Numeric.double.ZERO) {
targetLeverage
} else {
maxMarketLeverage
}

return when (input) {
"size.size", "size.percent" -> {
val orderbook = getOrderbook(market = market, isBuying = trade.isBuying)
createMarketOrderFromSize(
size = tradeSize.size,
freeCollateral = freeCollateral,
maxMarketLeverage = maxMarketLeverage,
tradeLeverage = tradeLeverage,
orderbook = orderbook,
)
}
Expand All @@ -126,7 +135,7 @@ internal class TradeInputMarketOrderCalculator() {
createMarketOrderFromUsdcSize(
usdcSize = tradeSize.usdcSize,
freeCollateral = freeCollateral,
maxMarketLeverage = maxMarketLeverage,
tradeLeverage = tradeLeverage,
orderbook = orderbook,
stepSize = stepSize,
)
Expand All @@ -138,7 +147,7 @@ internal class TradeInputMarketOrderCalculator() {
leverage = leverage,
market = market,
freeCollateral = freeCollateral,
maxMarketLeverage = maxMarketLeverage,
tradeLeverage = tradeLeverage,
subaccount = subaccount,
user = user,
)
Expand All @@ -151,9 +160,9 @@ internal class TradeInputMarketOrderCalculator() {

createMarketOrderFromBalancePercent(
balancePercent = balancePercent,
marginMode = marginMode,
freeCollateral = freeCollateral,
maxMarketLeverage = maxMarketLeverage,
subaccount = subaccount,
tradeLeverage = tradeLeverage,
orderbook = orderbook,
stepSize = stepSize,
)
Expand All @@ -178,15 +187,19 @@ internal class TradeInputMarketOrderCalculator() {

private fun createMarketOrderFromBalancePercent(
balancePercent: Double,
marginMode: MarginMode,
freeCollateral: Double,
maxMarketLeverage: Double,
subaccount: InternalSubaccountState?,
tradeLeverage: Double,
orderbook: List<InternalOrderbookTick>?,
stepSize: Double,
): TradeInputMarketOrder? {
val cappedPercent = min(balancePercent, MAX_FREE_COLLATERAL_BUFFER_PERCENT * balancePercent)
val buffer = when (marginMode) {
MarginMode.Cross -> MAX_FREE_CROSS_COLLATERAL_BUFFER_PERCENT
MarginMode.Isolated -> MAX_FREE_ISOLATED_COLLATERAL_BUFFER_PERCENT
}
val cappedPercent = min(balancePercent, buffer)
val desiredBalance = cappedPercent * freeCollateral
val usdcSize = desiredBalance * maxMarketLeverage
val usdcSize = desiredBalance * tradeLeverage

return if (usdcSize != Numeric.double.ZERO) {
if (orderbook != null) {
Expand All @@ -203,16 +216,16 @@ internal class TradeInputMarketOrderCalculator() {

if (entryPrice > Numeric.double.ZERO) {
val entryUsdcSize = entrySize * entryPrice
val entryBalanceSize = entryUsdcSize / maxMarketLeverage
val entryBalanceSize = entryUsdcSize / tradeLeverage
filled = (balanceTotal + entryBalanceSize >= desiredBalance)

var matchedSize = entrySize
var matchedUsdcSize = entryUsdcSize
var matchedBalance = matchedUsdcSize / maxMarketLeverage
var matchedBalance = matchedUsdcSize / tradeLeverage

if (filled) {
matchedBalance = desiredBalance - balanceTotal
matchedUsdcSize = matchedBalance * maxMarketLeverage
matchedUsdcSize = matchedBalance * tradeLeverage
matchedSize = matchedUsdcSize / entryPrice
matchedSize =
Rounder.quickRound(
Expand Down Expand Up @@ -259,7 +272,7 @@ internal class TradeInputMarketOrderCalculator() {
private fun createMarketOrderFromSize(
size: Double?,
freeCollateral: Double,
maxMarketLeverage: Double,
tradeLeverage: Double,
orderbook: List<InternalOrderbookTick>?,
): TradeInputMarketOrder? {
return if (size != null && size != Numeric.double.ZERO) {
Expand Down Expand Up @@ -288,7 +301,7 @@ internal class TradeInputMarketOrderCalculator() {
break@orderbookLoop
}
}
val balancePercentTotal = (usdcSizeTotal / maxMarketLeverage) / freeCollateral
val balancePercentTotal = (usdcSizeTotal / tradeLeverage) / freeCollateral
createMarketOrderWith(
orderbook = marketOrderOrderBook,
size = sizeTotal,
Expand All @@ -315,7 +328,7 @@ internal class TradeInputMarketOrderCalculator() {
private fun createMarketOrderFromUsdcSize(
usdcSize: Double?,
freeCollateral: Double,
maxMarketLeverage: Double,
tradeLeverage: Double,
orderbook: List<InternalOrderbookTick>?,
stepSize: Double,
): TradeInputMarketOrder? {
Expand Down Expand Up @@ -359,7 +372,7 @@ internal class TradeInputMarketOrderCalculator() {
}
}
}
val balancePercentTotal = (usdcSizeTotal / maxMarketLeverage) / freeCollateral
val balancePercentTotal = (usdcSizeTotal / tradeLeverage) / freeCollateral
createMarketOrderWith(
orderbook = marketOrderOrderBook,
size = sizeTotal,
Expand Down Expand Up @@ -387,7 +400,7 @@ internal class TradeInputMarketOrderCalculator() {
leverage: Double,
market: InternalMarketState?,
freeCollateral: Double,
maxMarketLeverage: Double,
tradeLeverage: Double,
subaccount: InternalSubaccountState?,
user: InternalUserState?,
): TradeInputMarketOrder? {
Expand Down Expand Up @@ -425,7 +438,7 @@ internal class TradeInputMarketOrderCalculator() {
leverage = leverage,
stepSize = stepSize,
freeCollateral = freeCollateral,
maxMarketLeverage = maxMarketLeverage,
tradeLeverage = tradeLeverage,
orderbook = orderbook,
)
} else {
Expand All @@ -448,7 +461,7 @@ internal class TradeInputMarketOrderCalculator() {
leverage: Double,
stepSize: Double,
freeCollateral: Double,
maxMarketLeverage: Double,
tradeLeverage: Double,
orderbook: List<InternalOrderbookTick>,
): TradeInputMarketOrder? {
/*
Expand Down Expand Up @@ -545,7 +558,7 @@ internal class TradeInputMarketOrderCalculator() {
break@orderbookLoop
}
}
val balancePercentTotal = (usdcSizeTotal / maxMarketLeverage) / freeCollateral
val balancePercentTotal = (usdcSizeTotal / tradeLeverage) / freeCollateral
return createMarketOrderWith(
orderbook = marketOrderOrderBook,
size = sizeTotal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ internal class TradeInputOptionsCalculator(
return when (trade.marginMode) {
MarginMode.Isolated -> listOf(
sizeField(),
// balancePercentField(), TODO: enable in CT-1180
balancePercentField(),
bracketsField(),
marginModeField(market, account, subaccount),
reduceOnlyField(),
Expand Down
Loading

0 comments on commit 4875794

Please sign in to comment.