From 7743172daf9c9b8ccb47a166190888f04a3aba93 Mon Sep 17 00:00:00 2001 From: mike-dydx <149746839+mike-dydx@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:46:29 -0400 Subject: [PATCH] combined hourly and daily data (#725) Co-authored-by: Mike --- build.gradle.kts | 2 +- .../functional/vault/Vault.kt | 8 ++-- .../processor/vault/VaultProcessor.kt | 2 +- .../state/model/TradingStateMachine+Vault.kt | 6 +-- .../state/v2/supervisor/VaultSupervisor.kt | 33 +++++++++++------ .../functional/vault/VaultTests.kt | 37 ++++++++++++++++--- .../TradingStateMachine+TestUtils.kt | 2 +- v4_abacus.podspec | 2 +- 8 files changed, 66 insertions(+), 26 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 0ef3d2b1a..fd0b0a58d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ allprojects { } group = "exchange.dydx.abacus" -version = "1.13.8" +version = "1.13.9" repositories { google() diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/functional/vault/Vault.kt b/src/commonMain/kotlin/exchange.dydx.abacus/functional/vault/Vault.kt index 185195353..b12b9f35b 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/functional/vault/Vault.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/functional/vault/Vault.kt @@ -94,13 +94,15 @@ object VaultCalculator { return parser.asTypedObject(apiResponse) } - fun calculateVaultSummary(historical: IndexerMegavaultHistoricalPnlResponse?): VaultDetails? { - if (historical?.megavaultPnl.isNullOrEmpty()) { + fun calculateVaultSummary(historicals: List?): VaultDetails? { + val combinedPnls = historicals?.flatMap { it.megavaultPnl?.toList() ?: emptyList() } // Convert Array to List + + if (combinedPnls.isNullOrEmpty()) { return null } val vaultOfVaultsPnl = - historical!!.megavaultPnl!!.sortedByDescending { parser.asDatetime(it.createdAt)?.toEpochMilliseconds() ?: 0 } + combinedPnls.sortedByDescending { parser.asDatetime(it.createdAt)?.toEpochMilliseconds() ?: 0 } val history = vaultOfVaultsPnl.mapNotNull { entry -> parser.asDatetime(entry.createdAt)?.toEpochMilliseconds()?.toDouble()?.let { createdAt -> diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/vault/VaultProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/vault/VaultProcessor.kt index d9ef98982..79a55536e 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/vault/VaultProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/vault/VaultProcessor.kt @@ -25,7 +25,7 @@ internal class VaultProcessor( fun processMegaVaultsHistoricalPnl( existing: InternalVaultState?, - payload: IndexerMegavaultHistoricalPnlResponse?, + payload: List?, ): InternalVaultState? { if (payload == null) { return existing diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine+Vault.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine+Vault.kt index 9b6847c0b..e4175ce0e 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine+Vault.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine+Vault.kt @@ -13,10 +13,10 @@ import indexer.models.chain.OnChainAccountVaultResponse import kollections.iListOf internal fun TradingStateMachine.onMegaVaultPnl( - payload: String + payloads: List ): StateChanges { - val pnlResponse = parser.asTypedObject(payload) - val newState = vaultProcessor.processMegaVaultsHistoricalPnl(internalState.vault, pnlResponse) + val responses = payloads.mapNotNull { parser.asTypedObject(it) } + val newState = vaultProcessor.processMegaVaultsHistoricalPnl(internalState.vault, responses) return updateVaultState(internalState, newState) } diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/v2/supervisor/VaultSupervisor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/v2/supervisor/VaultSupervisor.kt index 093686590..366509c85 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/v2/supervisor/VaultSupervisor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/v2/supervisor/VaultSupervisor.kt @@ -13,6 +13,10 @@ import exchange.dydx.abacus.utils.CoroutineTimer import exchange.dydx.abacus.utils.Logger import indexer.models.chain.OnChainAccountVaultResponse import indexer.models.chain.OnChainNumShares +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.launch internal class VaultSupervisor( stateMachine: TradingStateMachine, @@ -132,18 +136,25 @@ internal class VaultSupervisor( } private fun retrieveMegaVaultPnl() { - val url = helper.configs.publicApiUrl("vaultHistoricalPnl") - if (url != null) { - helper.get( - url = url, - params = mapOf("resolution" to "day"), - headers = null, - ) { _, response, httpCode, _ -> - if (helper.success(httpCode) && response != null) { - stateMachine.onMegaVaultPnl(response) - } else { + val scope = CoroutineScope(Dispatchers.Unconfined) + scope.launch { + val url = helper.configs.publicApiUrl("vaultHistoricalPnl") + if (url != null) { + val deferredDaily = async { helper.getAsync(url, params = mapOf("resolution" to "day"), headers = null) } + val deferredHourly = async { helper.getAsync(url, params = mapOf("resolution" to "hour"), headers = null) } + + val dailyResponse = deferredDaily.await() + val hourlyResponse = deferredHourly.await() + + if (dailyResponse.response != null || hourlyResponse.response != null) { + stateMachine.onMegaVaultPnl(listOfNotNull(dailyResponse.response, hourlyResponse.response)) + } else if (dailyResponse.error != null) { + Logger.e { + "Failed to retrieve day mega vault pnl: ${dailyResponse.error}" + } + } else if (hourlyResponse.error != null) { Logger.e { - "Failed to retrieve mega vault pnl: $httpCode, $response" + "Failed to retrieve hourly mega vault pnl: ${hourlyResponse.error}" } } } diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/functional/vault/VaultTests.kt b/src/commonTest/kotlin/exchange.dydx.abacus/functional/vault/VaultTests.kt index 1c85ce5c8..e375c8e9e 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/functional/vault/VaultTests.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/functional/vault/VaultTests.kt @@ -27,7 +27,7 @@ class VaultTests { @Test fun calculateVaultSummary_basic() { - val historicalPnl = IndexerMegavaultHistoricalPnlResponse( + val historicalPnl1 = IndexerMegavaultHistoricalPnlResponse( megavaultPnl = arrayOf( IndexerPnlTicksResponseObject( equity = "10000.0", @@ -44,7 +44,24 @@ class VaultTests { ), ) - val vaultDetails = calculateVaultSummary(historicalPnl) + val historicalPnl2 = IndexerMegavaultHistoricalPnlResponse( + megavaultPnl = arrayOf( + IndexerPnlTicksResponseObject( + equity = "10000.0", + totalPnl = "1000.0", + netTransfers = "0.0", + createdAt = Instant.fromEpochMilliseconds(1659465500000).toString(), + ), + IndexerPnlTicksResponseObject( + equity = "5000.0", + totalPnl = "500", + netTransfers = "0.0", + createdAt = Instant.fromEpochMilliseconds(1659379200001).toString(), + ), + ), + ) + + val vaultDetails = calculateVaultSummary(listOf(historicalPnl1, historicalPnl2)) val expectedVaultDetails = VaultDetails( totalValue = 10000.0, @@ -55,6 +72,16 @@ class VaultTests { equity = 10000.0, totalPnl = 1000.0, ), + VaultHistoryEntry( + date = 1659465500000.0, + equity = 10000.0, + totalPnl = 1000.0, + ), + VaultHistoryEntry( + date = 1659379200001.0, + equity = 5000.0, + totalPnl = 500.0, + ), VaultHistoryEntry( date = 1659379200000.0, equity = 5000.0, @@ -71,8 +98,8 @@ class VaultTests { val nullHistoricalPnl = IndexerMegavaultHistoricalPnlResponse(megavaultPnl = null) val emptyHistoricalPnl = IndexerMegavaultHistoricalPnlResponse(megavaultPnl = arrayOf()) - val nullVaultDetails = calculateVaultSummary(nullHistoricalPnl) - val emptyVaultDetails = calculateVaultSummary(emptyHistoricalPnl) + val nullVaultDetails = calculateVaultSummary(listOf(nullHistoricalPnl)) + val emptyVaultDetails = calculateVaultSummary(listOf(emptyHistoricalPnl)) assertEquals(null, nullVaultDetails) assertEquals(null, emptyVaultDetails) @@ -120,7 +147,7 @@ class VaultTests { ), ) - val vaultDetails = calculateVaultSummary(historicalPnl) + val vaultDetails = calculateVaultSummary(listOf(historicalPnl)) assertNotNull(vaultDetails) assertEquals(0.6403508771929824, vaultDetails.thirtyDayReturnPercent) diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/tests/extensions/TradingStateMachine+TestUtils.kt b/src/commonTest/kotlin/exchange.dydx.abacus/tests/extensions/TradingStateMachine+TestUtils.kt index 4f8bcbd9a..caeba4796 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/tests/extensions/TradingStateMachine+TestUtils.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/tests/extensions/TradingStateMachine+TestUtils.kt @@ -597,7 +597,7 @@ fun TradingStateMachine.rest( } "/v4/vault/v1/megavault/historicalPnl" -> { - changes = onMegaVaultPnl(payload) + changes = onMegaVaultPnl(listOf(payload)) } "/v4/vault/v1/megavault/positions" -> { diff --git a/v4_abacus.podspec b/v4_abacus.podspec index ffa0bdcb4..1ea87fda7 100644 --- a/v4_abacus.podspec +++ b/v4_abacus.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'v4_abacus' - spec.version = '1.13.8' + spec.version = '1.13.9' spec.homepage = 'https://github.com/dydxprotocol/v4-abacus' spec.source = { :http=> ''} spec.authors = ''