Skip to content

Commit

Permalink
Merge branch 'main' into feature/trade_4
Browse files Browse the repository at this point in the history
# Conflicts:
#	build.gradle.kts
#	src/commonMain/kotlin/exchange.dydx.abacus/validator/AccountInputValidator.kt
#	src/commonMain/kotlin/exchange.dydx.abacus/validator/TradeInputValidator.kt
#	v4_abacus.podspec
  • Loading branch information
ruixhuang committed Aug 22, 2024
2 parents 270b53b + f3bc02f commit 1469a14
Show file tree
Hide file tree
Showing 12 changed files with 383 additions and 71 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ allprojects {
}

group = "exchange.dydx.abacus"
version = "1.8.95"
version = "1.8.97"

repositories {
google()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ internal class TradeInputCalculator(
val account = parser.asNativeMap(state["account"])

val crossMarginSubaccount = parser.asNativeMap(parser.value(account, "subaccounts.$subaccountNumber"))
val subaccount = parser.asMap(parser.value(account, "groupedSubaccounts.$subaccountNumber"))
val groupedSubaccount = parser.asMap(parser.value(account, "groupedSubaccounts.$subaccountNumber"))
?: crossMarginSubaccount

val user = parser.asNativeMap(state["user"]) ?: mapOf()
Expand All @@ -75,6 +75,12 @@ internal class TradeInputCalculator(
)

val marginMode = parser.asString(parser.value(trade, "marginMode"))?.let { MarginMode.invoke(it) }
val subaccount = if (marginMode == MarginMode.Cross) {
crossMarginSubaccount
} else {
// TODO: incorrect for isolated trades; fix CT-1092
groupedSubaccount
}

val marketId = parser.asString(trade?.get("marketId"))
val type = parser.asString(trade?.get("type"))
Expand All @@ -90,11 +96,7 @@ internal class TradeInputCalculator(
calculateMarketOrderTrade(
trade,
market,
if (marginMode == MarginMode.Isolated) {
subaccount
} else {
crossMarginSubaccount
}, // TODO: incorrect for isolated trades; fix CT-1092
subaccount,
user,
isBuying,
input,
Expand Down Expand Up @@ -854,22 +856,11 @@ internal class TradeInputCalculator(
feeTiers: List<Any>?,
type: String,
): Map<String, Any> {
val marketId = parser.asString(market?.get("id"))
val position = if (marketId != null) {
parser.asNativeMap(
parser.value(
subaccount,
"openPositions.$marketId",
),
)
} else {
null
}
var modified = trade.mutable()
val fields = requiredFields(account, subaccount, trade, market)
modified.safeSet("fields", fields)
modified.safeSet("options", calculatedOptionsFromFields(fields, trade, position, market))
modified = defaultOptions(account, subaccount, modified, position, market)
modified.safeSet("options", calculatedOptionsFromFields(fields, trade, market, subaccount))
modified = defaultOptions(account, subaccount, modified, market)
modified.safeSet(
"summary",
summaryForType(trade, subaccount, user, market, rewardsParams, feeTiers, type),
Expand Down Expand Up @@ -1148,8 +1139,8 @@ internal class TradeInputCalculator(
private fun calculatedOptionsFromFields(
fields: List<Any>?,
trade: Map<String, Any>,
position: Map<String, Any>?,
market: Map<String, Any>?,
subaccount: Map<String, Any>?,
): Map<String, Any>? {
fields?.let { fields ->
val options = mutableMapOf<String, Any>(
Expand Down Expand Up @@ -1217,7 +1208,7 @@ internal class TradeInputCalculator(
}
}
if (parser.asBool(options["needsLeverage"]) == true) {
options.safeSet("maxLeverage", maxLeverageFromPosition(position, market))
options.safeSet("maxLeverage", maxLeverage(subaccount, market))
} else {
options.safeSet("maxLeverage", null)
}
Expand All @@ -1241,20 +1232,6 @@ internal class TradeInputCalculator(
return null
}

private fun maxLeverageFromPosition(
position: Map<String, Any>?,
market: Map<String, Any>?,
): Double? {
if (position != null) {
return parser.asDouble(parser.value(position, "maxLeverage.current"))
} else {
val initialMarginFraction =
parser.asDouble(parser.value(market, "configs.effectiveInitialMarginFraction"))
?: return null
return 1.0 / initialMarginFraction
}
}

private fun reduceOnlyPromptFromTrade(
trade: Map<String, Any>,
): String? {
Expand All @@ -1280,18 +1257,16 @@ internal class TradeInputCalculator(
account: Map<String, Any>?,
subaccount: Map<String, Any>?,
trade: Map<String, Any>,
position: Map<String, Any>?,
market: Map<String, Any>?,
): Map<String, Any>? {
val fields = requiredFields(account, subaccount, trade, market)
return calculatedOptionsFromFields(fields, trade, position, market)
return calculatedOptionsFromFields(fields, trade, market, subaccount)
}

private fun defaultOptions(
account: Map<String, Any>?,
subaccount: Map<String, Any>?,
trade: Map<String, Any>,
position: Map<String, Any>?,
market: Map<String, Any>?,
): MutableMap<String, Any> {
val modified = trade.toMutableMap()
Expand All @@ -1300,7 +1275,6 @@ internal class TradeInputCalculator(
account,
subaccount,
trade,
position,
market,
)?.get("timeInForceOptions"),
)
Expand All @@ -1314,7 +1288,6 @@ internal class TradeInputCalculator(
account,
subaccount,
trade,
position,
market,
)?.get("goodTilUnitOptions"),
)
Expand All @@ -1329,7 +1302,6 @@ internal class TradeInputCalculator(
account,
subaccount,
trade,
position,
market,
)?.get("executionOptions"),
)
Expand All @@ -1343,7 +1315,6 @@ internal class TradeInputCalculator(
account,
subaccount,
trade,
position,
market,
)?.get("marginModeOptions"),
)
Expand All @@ -1357,7 +1328,6 @@ internal class TradeInputCalculator(
account,
subaccount,
trade,
position,
market,
)?.get("needsGoodUntil"),
) == true
Expand Down Expand Up @@ -1718,7 +1688,25 @@ internal class TradeInputCalculator(
"openPositions.$marketId",
),
)
return maxLeverageFromPosition(position, market)

val initialMarginFraction =
parser.asDouble(parser.value(market, "configs.effectiveInitialMarginFraction"))
?: return null
val maxMarketLeverage = if (initialMarginFraction <= Numeric.double.ZERO) {
return null
} else {
Numeric.double.ONE / initialMarginFraction
}

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

return if (equity != null && equity > Numeric.double.ZERO) {
(freeCollateral + positionNotionalTotal / maxMarketLeverage) * maxMarketLeverage / equity
} else {
maxMarketLeverage
}
}

private fun slippage(price: Double?, oraclePrice: Double?, side: String?): Double? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import exchange.dydx.abacus.state.internalstate.InternalSubaccountState
import exchange.dydx.abacus.state.internalstate.InternalTradeInputOptions
import exchange.dydx.abacus.state.internalstate.InternalTradeInputState
import exchange.dydx.abacus.state.internalstate.safeCreate
import exchange.dydx.abacus.utils.Numeric
import kollections.iListOf

internal class TradeInputOptionsCalculator(
Expand Down Expand Up @@ -63,6 +64,7 @@ internal class TradeInputOptionsCalculator(
return calculatedOptionsFromFields(
fields = fields,
trade = trade,
subaccount = subaccount,
position = position,
market = market,
)
Expand Down Expand Up @@ -166,6 +168,7 @@ internal class TradeInputOptionsCalculator(
private fun calculatedOptionsFromFields(
fields: List<Any>?,
trade: InternalTradeInputState,
subaccount: InternalSubaccountState?,
position: InternalPerpetualPosition?,
market: InternalMarketState?,
): InternalTradeInputOptions {
Expand Down Expand Up @@ -209,7 +212,7 @@ internal class TradeInputOptionsCalculator(
}

if (options.needsLeverage) {
options.maxLeverage = maxLeverageFromPosition(position, market)
options.maxLeverage = maxLeverage(subaccount, market, position)
} else {
options.maxLeverage = null
}
Expand Down Expand Up @@ -342,17 +345,32 @@ internal class TradeInputOptionsCalculator(
}
}

private fun maxLeverageFromPosition(
position: InternalPerpetualPosition?,
private fun maxLeverage(
subaccount: InternalSubaccountState?,
market: InternalMarketState?,
position: InternalPerpetualPosition?,
): Double? {
if (position != null) {
return position.calculated[CalculationPeriod.current]?.maxLeverage
if (subaccount == null || market == null) {
return null
}

val initialMarginFraction =
market.perpetualMarket?.configs?.effectiveInitialMarginFraction ?: return null

val maxMarketLeverage = if (initialMarginFraction <= Numeric.double.ZERO) {
return null
} else {
Numeric.double.ONE / initialMarginFraction
}

val equity = subaccount.calculated[CalculationPeriod.current]?.equity
val freeCollateral = subaccount.calculated[CalculationPeriod.current]?.freeCollateral ?: Numeric.double.ZERO
val positionNotionalTotal = position?.calculated?.get(CalculationPeriod.current)?.notionalTotal ?: Numeric.double.ZERO

return if (equity != null && equity > Numeric.double.ZERO) {
(freeCollateral + positionNotionalTotal / maxMarketLeverage) * maxMarketLeverage / equity
} else {
val initialMarginFraction =
market?.perpetualMarket?.configs?.effectiveInitialMarginFraction
?: return null
return 1.0 / initialMarginFraction
maxMarketLeverage
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package exchange.dydx.abacus.processor.router.skip

import exchange.dydx.abacus.processor.base.BaseProcessor
import exchange.dydx.abacus.protocols.ParserProtocol
import exchange.dydx.abacus.state.manager.StatsigConfig
import exchange.dydx.abacus.utils.SLIPPAGE_PERCENT
import exchange.dydx.abacus.utils.safeSet
import exchange.dydx.abacus.utils.toJson
import exchange.dydx.abacus.utils.toJsonArray
import kotlin.math.pow

Expand Down Expand Up @@ -108,6 +110,17 @@ internal class SkipRouteProcessor(internal val parser: ParserProtocol) {
val payloadProcessor = SkipRoutePayloadProcessor(parser)
modified.safeSet("requestPayload", payloadProcessor.received(null, payload))
}

if (modified.get("warning") == null && bridgeFees > StatsigConfig.dc_max_safe_bridge_fees) {
val fromAmountUSD = parser.asString(parser.value(payload, "route.usd_amount_in"))
modified.safeSet(
"warning",
mapOf(
"type" to "BAD_PRICE_WARNING",
"message" to "Difference in USD value of route input and output is large ($bridgeFees). Input USD Value: $fromAmountUSD Output USD value: $toAmountUSD",
).toJson(),
)
}
return modified
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ class V4Environment(
data object StatsigConfig {
var useSkip: Boolean = false
var ff_enable_evm_swaps: Boolean = false
var dc_max_safe_bridge_fees: Float = Float.POSITIVE_INFINITY
}

@JsExport
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class V4StateManagerConfigs(
"screen":"/v4/screen",
"complianceScreen":"/v4/compliance/screen",
"complianceGeoblock":"/v4/compliance/geoblock",
"complianceGeoblockKeplr":"/v4/compliance/geoblock-keplr",
"height":"/v4/height"
},
"private":{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ fun TradingStateMachine.closePosition(
val currentPositionLeverage = parser.asDouble(parser.value(position, "leverage.current"))?.abs()
trade["targetLeverage"] = if (currentPositionLeverage != null && currentPositionLeverage > 0) currentPositionLeverage else 1.0

// default full close
trade.safeSet("size.percent", 1.0)
trade.safeSet("size.input", "size.percent")

changes = StateChanges(
iListOf(Changes.subaccount, Changes.input),
null,
Expand Down Expand Up @@ -157,6 +161,9 @@ private fun TradingStateMachine.initiateClosePosition(
trade["type"] = "MARKET"
trade["side"] = "BUY"
trade["marketId"] = marketId ?: "ETH-USD"
// default full close
trade.safeSet("size.percent", 1.0)
trade.safeSet("size.input", "size.percent")

val calculator = TradeInputCalculator(parser, TradeCalculation.closePosition)
val params = mutableMapOf<String, Any>()
Expand All @@ -167,7 +174,7 @@ private fun TradingStateMachine.initiateClosePosition(
params.safeSet("rewardsParams", rewardsParams)
params.safeSet("configs", configs)

val modified = calculator.calculate(params, subaccountNumber, null)
val modified = calculator.calculate(params, subaccountNumber, "size.percent")

return parser.asMap(modified["trade"])?.mutable() ?: trade
}
Loading

0 comments on commit 1469a14

Please sign in to comment.