Skip to content

Commit

Permalink
TRCL-3706 Static Typing: Fixing isolated margin position update (#741)
Browse files Browse the repository at this point in the history
  • Loading branch information
ruixhuang authored Nov 8, 2024
1 parent 338b6e6 commit 6aa4ecf
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 43 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.13.18"
version = "1.13.19"

repositories {
google()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ internal class SubaccountCalculatorV2(
val marginMode = position.marginMode
when (marginMode) {
MarginMode.Isolated -> {
val equity = subaccount.equity
val equity = subaccount.calculated[period]?.equity
calculated.marginValue = equity
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,13 @@ object VaultCalculator {
val assetPositionsMap = assetPosition?.let { mapOf((it.symbol ?: "") to it) }
val subaccount = subaccountCalculator.calculate(
subaccount = InternalSubaccountState(
equity = equity ?: 0.0,
assetPositions = assetPositionsMap,
openPositions = perpetualPosition?.let { mapOf((it.market ?: "") to it) },
subaccountNumber = 0,
calculated = mutableMapOf(
CalculationPeriod.current to
InternalSubaccountCalculated(
equity = equity ?: 0.0,
quoteBalance = subaccountCalculator.calculateQuoteBalance(
assetPositionsMap,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import exchange.dydx.abacus.output.TradeStatesWithDoubleValues
import exchange.dydx.abacus.processor.base.ComparisonOrder
import exchange.dydx.abacus.protocols.LocalizerProtocol
import exchange.dydx.abacus.protocols.ParserProtocol
import exchange.dydx.abacus.state.internalstate.InternalPerpetualPendingPosition
import exchange.dydx.abacus.state.internalstate.InternalPerpetualPosition
import exchange.dydx.abacus.state.internalstate.InternalSubaccountState
import exchange.dydx.abacus.utils.IList
Expand Down Expand Up @@ -242,11 +243,19 @@ data class Subaccount(
)
}

val pendingPositions = pendingPositions(
existing?.pendingPositions,
parser,
parser.asList(data?.get("pendingPositions")),
)
val pendingPositions = if (staticTyping) {
createPendingPositions(
existing = existing?.pendingPositions,
parser = parser,
pendingPositions = internalState?.pendingPositions,
)
} else {
pendingPositionsDeprecated(
existing?.pendingPositions,
parser,
parser.asList(data?.get("pendingPositions")),
)
}
val orders =
if (staticTyping) {
internalState?.orders?.toIList()
Expand Down Expand Up @@ -387,7 +396,32 @@ data class Subaccount(
)?.toIList()
}

private fun pendingPositions(
private fun createPendingPositions(
existing: IList<SubaccountPendingPosition>?,
parser: ParserProtocol,
pendingPositions: List<InternalPerpetualPendingPosition>?,
): IList<SubaccountPendingPosition>? {
val newEntries: MutableList<SubaccountPendingPosition> = mutableListOf()
for (position in pendingPositions ?: emptyList()) {
val pendingPosition = SubaccountPendingPosition.create(
existing = null,
parser = parser,
data = emptyMap(),
internalState = position,
)
if (pendingPosition != null) {
newEntries.add(pendingPosition)
}
}

return if (newEntries != existing) {
newEntries.toIList()
} else {
existing
}
}

private fun pendingPositionsDeprecated(
existing: IList<SubaccountPendingPosition>?,
parser: ParserProtocol,
data: List<*>?,
Expand All @@ -402,6 +436,7 @@ data class Subaccount(
obj as? SubaccountPendingPosition,
parser,
parser.asMap(itemData),
internalState = null,
)
}, true)?.toIList()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package exchange.dydx.abacus.output.account

import exchange.dydx.abacus.calculator.CalculationPeriod
import exchange.dydx.abacus.output.TradeStatesWithDoubleValues
import exchange.dydx.abacus.protocols.ParserProtocol
import exchange.dydx.abacus.state.internalstate.InternalPerpetualPendingPosition
import exchange.dydx.abacus.utils.Logger
import kollections.JsExport
import kotlinx.serialization.Serializable
Expand All @@ -23,32 +25,33 @@ data class SubaccountPendingPosition(
existing: SubaccountPendingPosition?,
parser: ParserProtocol,
data: Map<String, Any>?,
internalState: InternalPerpetualPendingPosition?,
): SubaccountPendingPosition? {
Logger.d { "creating Account Pending Position\n" }
data?.let {
val assetId = parser.asString(data["assetId"]) ?: return null
val displayId = parser.asString(data["displayId"]) ?: return null
val marketId = parser.asString(data["marketId"]) ?: return null
val firstOrderId = parser.asString(data["firstOrderId"]) ?: return null
val orderCount = parser.asInt(data["orderCount"]) ?: return null
val freeCollateral = TradeStatesWithDoubleValues.create(
null,
parser,
parser.asMap(data["freeCollateral"]),
if (internalState != null) {
Logger.d { "Account Pending Position from internal state\n" }
val assetId = internalState.assetId ?: return null
val displayId = internalState.displayId ?: return null
val marketId = internalState.marketId ?: return null
val firstOrderId = internalState.firstOrderId ?: return null
val orderCount = internalState.orderCount ?: return null
val freeCollateral = TradeStatesWithDoubleValues(
internalState.calculated[CalculationPeriod.current]?.freeCollateral,
internalState.calculated[CalculationPeriod.post]?.freeCollateral,
internalState.calculated[CalculationPeriod.settled]?.freeCollateral,
)
val quoteBalance = TradeStatesWithDoubleValues.create(
null,
parser,
parser.asMap(data["quoteBalance"]),
val quoteBalance = TradeStatesWithDoubleValues(
internalState.calculated[CalculationPeriod.current]?.quoteBalance,
internalState.calculated[CalculationPeriod.post]?.quoteBalance,
internalState.calculated[CalculationPeriod.settled]?.quoteBalance,
)
val equity = TradeStatesWithDoubleValues.create(
null,
parser,
parser.asMap(data["equity"]),
val equity = TradeStatesWithDoubleValues(
internalState.calculated[CalculationPeriod.current]?.equity,
internalState.calculated[CalculationPeriod.post]?.equity,
internalState.calculated[CalculationPeriod.settled]?.equity,
)

return if (existing?.assetId != assetId ||
existing?.displayId != displayId ||
existing.displayId != displayId ||
existing.marketId != marketId ||
existing.firstOrderId != firstOrderId ||
existing.orderCount != orderCount ||
Expand All @@ -69,9 +72,56 @@ data class SubaccountPendingPosition(
} else {
existing
}
} else {
Logger.d { "creating Account Pending Position\n" }
data?.let {
val assetId = parser.asString(data["assetId"]) ?: return null
val displayId = parser.asString(data["displayId"]) ?: return null
val marketId = parser.asString(data["marketId"]) ?: return null
val firstOrderId = parser.asString(data["firstOrderId"]) ?: return null
val orderCount = parser.asInt(data["orderCount"]) ?: return null
val freeCollateral = TradeStatesWithDoubleValues.create(
null,
parser,
parser.asMap(data["freeCollateral"]),
)
val quoteBalance = TradeStatesWithDoubleValues.create(
null,
parser,
parser.asMap(data["quoteBalance"]),
)
val equity = TradeStatesWithDoubleValues.create(
null,
parser,
parser.asMap(data["equity"]),
)

return if (existing?.assetId != assetId ||
existing?.displayId != displayId ||
existing.marketId != marketId ||
existing.firstOrderId != firstOrderId ||
existing.orderCount != orderCount ||
existing.freeCollateral !== freeCollateral ||
existing.quoteBalance !== quoteBalance ||
existing.equity !== equity
) {
SubaccountPendingPosition(
assetId = assetId,
displayId = displayId,
marketId = marketId,
firstOrderId = firstOrderId,
orderCount = orderCount,
freeCollateral = freeCollateral,
quoteBalance = quoteBalance,
equity = equity,
)
} else {
existing
}
}
Logger.d { "Account Pending Position not valid" }
return null
}
Logger.d { "Account Pending Position not valid" }
return null
}

private fun positionSide(size: TradeStatesWithDoubleValues): TradeStatesWithPositionSides {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ internal class TradeInputProcessor(

if (existingPosition != null) {
trade.marginMode =
if (subaccount?.equity != null) MarginMode.Isolated else MarginMode.Cross
if (subaccount?.calculated?.get(CalculationPeriod.current)?.equity != null) MarginMode.Isolated else MarginMode.Cross
val currentPositionLeverage =
existingPosition.calculated[CalculationPeriod.current]?.leverage?.abs()
val positionLeverage =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,9 @@ internal class MarketProcessor(
payload: List<String>,
period: IndexerSparklineTimePeriod,
): PerpetualMarket? {
cachedIndexerSparklines[marketId] = payload.mapNotNull { parser.asDouble(it) }.reversed()
when (period) {
IndexerSparklineTimePeriod.ONEDAY -> {
cachedIndexerSparklines[marketId] = payload.mapNotNull { parser.asDouble(it) }.reversed()
return createPerpetualMarket(marketId)
}
IndexerSparklineTimePeriod.SEVENDAYS -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ internal open class SubaccountProcessor(
)

val subaccountCalculated = state.calculated[CalculationPeriod.current] ?: InternalSubaccountCalculated()
state.calculated[CalculationPeriod.current] = subaccountCalculated
subaccountCalculated.quoteBalance = subaccountCalculator.calculateQuoteBalance(state.assetPositions)
state.calculated[CalculationPeriod.current] = subaccountCalculated

val fills = parser.asTypedList<IndexerFillResponseObject>(content["fills"])
state = processFills(
Expand Down Expand Up @@ -231,8 +231,11 @@ internal open class SubaccountProcessor(
existing.subaccountNumber = subaccountNumber
existing.address = payload.address

existing.equity = parser.asDouble(payload.equity)
existing.freeCollateral = parser.asDouble(payload.freeCollateral)
val calculated = existing.calculated[CalculationPeriod.current] ?: InternalSubaccountCalculated()
calculated.equity = parser.asDouble(payload.equity)
calculated.freeCollateral = parser.asDouble(payload.freeCollateral)
existing.calculated[CalculationPeriod.current] = calculated

existing.marginEnabled = payload.marginEnabled
existing.updatedAtHeight = payload.updatedAtHeight
existing.latestProcessedBlockHeight = payload.latestProcessedBlockHeight
Expand All @@ -251,8 +254,8 @@ internal open class SubaccountProcessor(
}

val subaccountCalculated = existing.calculated[CalculationPeriod.current] ?: InternalSubaccountCalculated()
existing.calculated[CalculationPeriod.current] = subaccountCalculated
subaccountCalculated.quoteBalance = subaccountCalculator.calculateQuoteBalance(existing.assetPositions)
existing.calculated[CalculationPeriod.current] = subaccountCalculated

return existing
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,6 @@ internal data class InternalSubaccountState(
var assetPositions: Map<String, InternalAssetPositionState>? = null,
var subaccountNumber: Int,
var address: String? = null,
var equity: Double? = null,
var freeCollateral: Double? = null,
var marginEnabled: Boolean? = null,
var updatedAtHeight: String? = null,
var latestProcessedBlockHeight: String? = null,
Expand All @@ -332,8 +330,6 @@ internal data class InternalSubaccountState(
assetPositions = assetPositions?.map { it.key to it.value.copy() }?.toMap(),
subaccountNumber = subaccountNumber,
address = address,
equity = equity,
freeCollateral = freeCollateral,
marginEnabled = marginEnabled,
updatedAtHeight = updatedAtHeight,
latestProcessedBlockHeight = latestProcessedBlockHeight,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package exchange.dydx.abacus.state.manager.notification.providers

import com.ionspin.kotlin.bignum.decimal.toBigDecimal
import exchange.dydx.abacus.output.Notification
import exchange.dydx.abacus.output.NotificationPriority
import exchange.dydx.abacus.output.NotificationType
Expand Down Expand Up @@ -52,7 +53,7 @@ class BlockRewardNotificationProvider(
token: String,
): Notification? {
val blockHeight = blockReward.createdAtHeight
val blockRewardAmount = blockReward.tradingReward
val blockRewardAmount = blockReward.tradingReward.toBigDecimal().toPlainString()
val params = iMapOf(
"BLOCK_REWARD_HEIGHT" to blockHeight,
"TOKEN_NAME" to token,
Expand Down
2 changes: 1 addition & 1 deletion v4_abacus.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = 'v4_abacus'
spec.version = '1.13.18'
spec.version = '1.13.19'
spec.homepage = 'https://github.com/dydxprotocol/v4-abacus'
spec.source = { :http=> ''}
spec.authors = ''
Expand Down

0 comments on commit 6aa4ecf

Please sign in to comment.