Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

analytics: add missing fields in place/cancel order events #301

Merged
merged 4 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ allprojects {
}

group = "exchange.dydx.abacus"
version = "1.6.40"
version = "1.6.41"

repositories {
google()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1162,37 +1162,53 @@ class V4StateManagerAdaptor(

override fun commitPlaceOrder(callback: TransactionCallback): HumanReadablePlaceOrderPayload {
val payload = placeOrderPayload()
val analyticsPayload = analyticsUtils.formatPlaceOrderPayload(payload)
val midMarketPrice = stateMachine.state?.marketOrderbook(payload.marketId)?.midPrice
val analyticsPayload = analyticsUtils.placeOrderAnalyticsPayload(payload, midMarketPrice)
return submitPlaceOrder(callback, payload, analyticsPayload)
}

override fun commitClosePosition(callback: TransactionCallback): HumanReadablePlaceOrderPayload {
val payload = closePositionPayload()
val analyticsPayload = analyticsUtils.formatPlaceOrderPayload(payload, true)
val midMarketPrice = stateMachine.state?.marketOrderbook(payload.marketId)?.midPrice
val analyticsPayload = analyticsUtils.placeOrderAnalyticsPayload(payload, midMarketPrice, true)
return submitPlaceOrder(callback, payload, analyticsPayload)
}

override fun cancelOrder(orderId: String, callback: TransactionCallback) {
val payload = cancelOrderPayload(orderId)
val analyticsPayload = analyticsUtils.formatCancelOrderPayload(payload)
val subaccount = stateMachine.state?.subaccount(subaccountNumber)
val existingOrder = subaccount?.orders?.firstOrNull { it.id == orderId }
val analyticsPayload = analyticsUtils.cancelOrderAnalyticsPayload(
payload,
existingOrder,
)

submitCancelOrder(orderId, callback, payload, analyticsPayload)
}

override fun commitTriggerOrders(callback: TransactionCallback): HumanReadableTriggerOrdersPayload {
val payloads = triggerOrdersPayload()

payloads.cancelOrderPayloads.forEach {
val analyticsPayload = analyticsUtils.formatCancelOrderPayload(it, true)
submitCancelOrder(it.orderId, callback, it, analyticsPayload, true)
payloads.cancelOrderPayloads.forEach { payload ->
val subaccount = stateMachine.state?.subaccount(subaccountNumber)
val existingOrder = subaccount?.orders?.firstOrNull { it.id == payload.orderId }
val analyticsPayload = analyticsUtils.cancelOrderAnalyticsPayload(
payload,
existingOrder,
true,
)
submitCancelOrder(payload.orderId, callback, payload, analyticsPayload, true)
}

payloads.placeOrderPayloads.forEach {
val analyticsPayload = analyticsUtils.formatPlaceOrderPayload(
it,
payloads.placeOrderPayloads.forEach { payload ->
val midMarketPrice = stateMachine.state?.marketOrderbook(payload.marketId)?.midPrice
val analyticsPayload = analyticsUtils.placeOrderAnalyticsPayload(
payload,
midMarketPrice,
isClosePosition = false,
fromSlTpDialog = true,
)
submitPlaceOrder(callback, it, analyticsPayload, true)
submitPlaceOrder(callback, payload, analyticsPayload, true)
}

if (payloads.cancelOrderPayloads.isEmpty() && payloads.placeOrderPayloads.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,8 @@ internal class SubaccountSupervisor(
callback: TransactionCallback
): HumanReadablePlaceOrderPayload {
val orderPayload = placeOrderPayload(currentHeight)
val analyticsPayload = analyticsUtils.formatPlaceOrderPayload(orderPayload, false)
val midMarketPrice = stateMachine.state?.marketOrderbook(orderPayload.marketId)?.midPrice
val analyticsPayload = analyticsUtils.placeOrderAnalyticsPayload(orderPayload, midMarketPrice, false)
val isIsolatedMarginOrder =
helper.parser.asInt(orderPayload.subaccountNumber) != subaccountNumber
val transferPayload =
Expand All @@ -751,14 +752,17 @@ internal class SubaccountSupervisor(
callback: TransactionCallback
): HumanReadablePlaceOrderPayload {
val payload = closePositionPayload(currentHeight)
val analyticsPayload = analyticsUtils.formatPlaceOrderPayload(payload, true)
val midMarketPrice = stateMachine.state?.marketOrderbook(payload.marketId)?.midPrice
val analyticsPayload = analyticsUtils.placeOrderAnalyticsPayload(payload, midMarketPrice, true)

return submitPlaceOrder(callback, payload, analyticsPayload)
}

internal fun cancelOrder(orderId: String, callback: TransactionCallback): HumanReadableCancelOrderPayload {
val payload = cancelOrderPayload(orderId)
val analyticsPayload = analyticsUtils.formatCancelOrderPayload(payload)
val subaccount = stateMachine.state?.subaccount(subaccountNumber)
val existingOrder = subaccount?.orders?.firstOrNull { it.id == orderId }
val analyticsPayload = analyticsUtils.cancelOrderAnalyticsPayload(payload, existingOrder)

return submitCancelOrder(orderId, callback, payload, analyticsPayload)
}
Expand All @@ -770,13 +774,17 @@ internal class SubaccountSupervisor(
val payloads = triggerOrdersPayload(currentHeight)

payloads.cancelOrderPayloads.forEach { payload ->
val analyticsPayload = analyticsUtils.formatCancelOrderPayload(payload, true)
val subaccount = stateMachine.state?.subaccount(subaccountNumber)
val existingOrder = subaccount?.orders?.firstOrNull { it.id == payload.orderId }
val analyticsPayload = analyticsUtils.cancelOrderAnalyticsPayload(payload, existingOrder, true)
submitCancelOrder(payload.orderId, callback, payload, analyticsPayload, true)
}

payloads.placeOrderPayloads.forEach { payload ->
val analyticsPayload = analyticsUtils.formatPlaceOrderPayload(
val midMarketPrice = stateMachine.state?.marketOrderbook(payload.marketId)?.midPrice
val analyticsPayload = analyticsUtils.placeOrderAnalyticsPayload(
payload,
midMarketPrice,
isClosePosition = false,
fromSlTpDialog = true,
)
Expand Down
72 changes: 69 additions & 3 deletions src/commonMain/kotlin/exchange.dydx.abacus/utils/AnalyticsUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,37 @@ package exchange.dydx.abacus.utils
import exchange.dydx.abacus.output.SubaccountOrder
import exchange.dydx.abacus.state.manager.HumanReadableCancelOrderPayload
import exchange.dydx.abacus.state.manager.HumanReadablePlaceOrderPayload
import kollections.toIMap

class AnalyticsUtils {
/**
* Format Place Order Payload and add additional details for `TradePlaceOrder` Analytic Events
* @param payload HumanReadablePlaceOrderPayload
* @param midMarketPrice Double?
* @param isClosePosition Boolean?
* @param fromSlTpDialog Boolean?
*/
fun placeOrderAnalyticsPayload(
payload: HumanReadablePlaceOrderPayload,
midMarketPrice: Double?,
isClosePosition: Boolean? = false,
fromSlTpDialog: Boolean? = false,
): IMap<String, Any>? {
return ParsingHelper.merge(
formatPlaceOrderPayload(payload, isClosePosition, fromSlTpDialog),
iMapOf(
"inferredTimeInForce" to calculateOrderTimeInForce(payload),
"midMarketPrice" to midMarketPrice,
) as IMap<String, Any>?,
)?.toIMap()
}

/**
* Format Place Order Payload for `TradePlaceOrder` Analytic Event
* @param payload HumanReadablePlaceOrderPayload
* @param isClosePosition Boolean
*/
fun formatPlaceOrderPayload(
private fun formatPlaceOrderPayload(
payload: HumanReadablePlaceOrderPayload,
isClosePosition: Boolean? = false,
fromSlTpDialog: Boolean? = false,
Expand All @@ -37,11 +60,54 @@ class AnalyticsUtils {
}

/**
* Format Cancel Order Payload for `TradeCancelOrder` Analytic Event
* Infer time in force from order params for analytics, mirroring v4-clients
* @param payload HumanReadablePlaceOrderPayload
*/
private fun calculateOrderTimeInForce(
payload: HumanReadablePlaceOrderPayload
): String? {
return when (payload.type) {
"MARKET" -> payload.timeInForce ?: "FOK"
"LIMIT" -> {
when (payload.timeInForce) {
"GTT" -> if (payload.postOnly == true) "POST_ONLY" else "GTT"
else -> payload.timeInForce
}
}

"STOP_LIMIT", "TAKE_PROFIT" -> {
when (payload.execution) {
"DEFAULT" -> "GTT"
else -> payload.execution
}
}

"STOP_MARKET", "TAKE_PROFIT_MARKET" -> payload.execution
else -> payload.timeInForce ?: payload.execution
}
}

/**
* Format Cancel Order Payload and add order details for `TradeCancelOrder` Analytic Events
* @param payload HumanReadableCancelOrderPayload
* @param existingOrder SubaccountOrder?
* @param fromSlTpDialog Boolean
*/
fun formatCancelOrderPayload(payload: HumanReadableCancelOrderPayload, fromSlTpDialog: Boolean? = false,): IMap<String, Any>? {
fun cancelOrderAnalyticsPayload(
payload: HumanReadableCancelOrderPayload,
existingOrder: SubaccountOrder?,
fromSlTpDialog: Boolean? = false,
): IMap<String, Any>? {
return ParsingHelper.merge(
formatCancelOrderPayload(payload, fromSlTpDialog),
if (existingOrder != null) formatOrder(existingOrder) else mapOf(),
)?.toIMap()
}

private fun formatCancelOrderPayload(
payload: HumanReadableCancelOrderPayload,
fromSlTpDialog: Boolean? = false,
): IMap<String, Any>? {
return iMapOf(
"fromSlTpDialog" to fromSlTpDialog,
"subaccountNumber" to payload.subaccountNumber,
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.6.40'
spec.version = '1.6.41'
spec.homepage = 'https://github.com/dydxprotocol/v4-abacus'
spec.source = { :http=> ''}
spec.authors = ''
Expand Down
Loading