Skip to content

Commit

Permalink
add cancel orders with tx queue
Browse files Browse the repository at this point in the history
  • Loading branch information
aforaleka committed Aug 29, 2024
1 parent 2515890 commit bc416a0
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ interface AsyncAbacusStateManagerProtocol {
fun closePositionPayload(): HumanReadablePlaceOrderPayload?
fun triggerOrdersPayload(): HumanReadableTriggerOrdersPayload?
fun cancelOrderPayload(orderId: String): HumanReadableCancelOrderPayload?
fun cancelOrdersPayload(marketId: String?): HumanReadableCancelMultipleOrdersPayload?
fun depositPayload(): HumanReadableDepositPayload?
fun withdrawPayload(): HumanReadableWithdrawPayload?
fun subaccountTransferPayload(): HumanReadableSubaccountTransferPayload?
Expand All @@ -80,6 +81,7 @@ interface AsyncAbacusStateManagerProtocol {
// Commit changes with params
fun faucet(amount: Double, callback: TransactionCallback)
fun cancelOrder(orderId: String, callback: TransactionCallback)
fun cancelOrders(marketId: String?, callback: TransactionCallback)

// Bridge functions.
// If client is not using cancelOrder function, it should call orderCanceled function with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ data class HumanReadableCancelOrderPayload(
val goodTilBlockTime: Int?,
)

@JsExport
@Serializable
data class HumanReadableCancelMultipleOrdersPayload(
val marketId: String?,
val payloads: IList<HumanReadableCancelOrderPayload>,
)

@JsExport
@Serializable
data class HumanReadableTriggerOrdersPayload(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import exchange.dydx.abacus.state.manager.ConfigFile
import exchange.dydx.abacus.state.manager.GasToken
import exchange.dydx.abacus.state.manager.HistoricalPnlPeriod
import exchange.dydx.abacus.state.manager.HistoricalTradingRewardsPeriod
import exchange.dydx.abacus.state.manager.HumanReadableCancelMultipleOrdersPayload
import exchange.dydx.abacus.state.manager.HumanReadableCancelOrderPayload
import exchange.dydx.abacus.state.manager.HumanReadableDepositPayload
import exchange.dydx.abacus.state.manager.HumanReadablePlaceOrderPayload
Expand Down Expand Up @@ -503,6 +504,10 @@ class AsyncAbacusStateManagerV2(
return adaptor?.cancelOrderPayload(orderId)
}

override fun cancelOrdersPayload(marketId: String?): HumanReadableCancelMultipleOrdersPayload? {
return adaptor?.cancelOrdersPayload(marketId)
}

override fun triggerOrdersPayload(): HumanReadableTriggerOrdersPayload? {
return adaptor?.triggerOrdersPayload()
}
Expand Down Expand Up @@ -603,6 +608,15 @@ class AsyncAbacusStateManagerV2(
}
}

override fun cancelOrders(marketId: String?, callback: TransactionCallback) {
try {
adaptor?.cancelOrders(marketId, callback)
} catch (e: Exception) {
val error = V4TransactionErrors.error(null, e.toString())
callback(false, error, null)
}
}

override fun triggerCompliance(action: ComplianceAction, callback: TransactionCallback) {
try {
adaptor?.triggerCompliance(action, callback)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import exchange.dydx.abacus.state.manager.BlockAndTime
import exchange.dydx.abacus.state.manager.GasToken
import exchange.dydx.abacus.state.manager.HistoricalPnlPeriod
import exchange.dydx.abacus.state.manager.HistoricalTradingRewardsPeriod
import exchange.dydx.abacus.state.manager.HumanReadableCancelMultipleOrdersPayload
import exchange.dydx.abacus.state.manager.HumanReadableCancelOrderPayload
import exchange.dydx.abacus.state.manager.HumanReadableDepositPayload
import exchange.dydx.abacus.state.manager.HumanReadablePlaceOrderPayload
Expand Down Expand Up @@ -58,6 +59,8 @@ import exchange.dydx.abacus.state.v2.supervisor.adjustIsolatedMargin
import exchange.dydx.abacus.state.v2.supervisor.adjustIsolatedMarginPayload
import exchange.dydx.abacus.state.v2.supervisor.cancelOrder
import exchange.dydx.abacus.state.v2.supervisor.cancelOrderPayload
import exchange.dydx.abacus.state.v2.supervisor.cancelOrders
import exchange.dydx.abacus.state.v2.supervisor.cancelOrdersPayload
import exchange.dydx.abacus.state.v2.supervisor.closePosition
import exchange.dydx.abacus.state.v2.supervisor.closePositionPayload
import exchange.dydx.abacus.state.v2.supervisor.commitAdjustIsolatedMargin
Expand Down Expand Up @@ -538,6 +541,10 @@ internal class StateManagerAdaptorV2(
return accounts.cancelOrderPayload(orderId)
}

internal fun cancelOrdersPayload(marketId: String?): HumanReadableCancelMultipleOrdersPayload? {
return accounts.cancelOrdersPayload(marketId)
}

internal fun triggerOrdersPayload(): HumanReadableTriggerOrdersPayload? {
return accounts.triggerOrdersPayload(currentHeight)
}
Expand Down Expand Up @@ -596,6 +603,10 @@ internal class StateManagerAdaptorV2(
accounts.cancelOrder(orderId, callback)
}

internal fun cancelOrders(marketId: String?, callback: TransactionCallback) {
accounts.cancelOrders(marketId, callback)
}

internal fun orderCanceled(orderId: String) {
accounts.orderCanceled(orderId)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import exchange.dydx.abacus.state.changes.StateChanges
import exchange.dydx.abacus.state.manager.ApiData
import exchange.dydx.abacus.state.manager.BlockAndTime
import exchange.dydx.abacus.state.manager.HistoricalTradingRewardsPeriod
import exchange.dydx.abacus.state.manager.HumanReadableCancelMultipleOrdersPayload
import exchange.dydx.abacus.state.manager.HumanReadableCancelOrderPayload
import exchange.dydx.abacus.state.manager.HumanReadableDepositPayload
import exchange.dydx.abacus.state.manager.HumanReadablePlaceOrderPayload
Expand Down Expand Up @@ -1180,6 +1181,10 @@ internal fun AccountSupervisor.cancelOrderPayload(
return subaccount?.cancelOrderPayload(orderId)
}

internal fun AccountSupervisor.cancelOrdersPayload(marketId: String?): HumanReadableCancelMultipleOrdersPayload? {
return subaccount?.cancelOrdersPayload(marketId)
}

internal fun AccountSupervisor.depositPayload(): HumanReadableDepositPayload? {
return subaccount?.depositPayload()
}
Expand Down Expand Up @@ -1231,6 +1236,10 @@ internal fun AccountSupervisor.cancelOrder(orderId: String, callback: Transactio
subaccount?.cancelOrder(orderId = orderId, callback = callback)
}

internal fun AccountSupervisor.cancelOrders(marketId: String?, callback: TransactionCallback) {
subaccount?.cancelOrders(marketId, callback)
}

internal fun AccountSupervisor.orderCanceled(orderId: String) {
subaccount?.orderCanceled(orderId)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import exchange.dydx.abacus.state.manager.ApiData
import exchange.dydx.abacus.state.manager.BlockAndTime
import exchange.dydx.abacus.state.manager.HistoricalPnlPeriod
import exchange.dydx.abacus.state.manager.HistoricalTradingRewardsPeriod
import exchange.dydx.abacus.state.manager.HumanReadableCancelMultipleOrdersPayload
import exchange.dydx.abacus.state.manager.HumanReadableCancelOrderPayload
import exchange.dydx.abacus.state.manager.HumanReadableDepositPayload
import exchange.dydx.abacus.state.manager.HumanReadablePlaceOrderPayload
Expand Down Expand Up @@ -275,6 +276,10 @@ internal fun AccountsSupervisor.cancelOrderPayload(orderId: String): HumanReadab
return account?.cancelOrderPayload(orderId)
}

internal fun AccountsSupervisor.cancelOrdersPayload(marketId: String?): HumanReadableCancelMultipleOrdersPayload? {
return account?.cancelOrdersPayload(marketId)
}

internal fun AccountsSupervisor.depositPayload(): HumanReadableDepositPayload? {
return account?.depositPayload()
}
Expand Down Expand Up @@ -337,6 +342,10 @@ internal fun AccountsSupervisor.cancelOrder(orderId: String, callback: Transacti
account?.cancelOrder(orderId, callback)
}

internal fun AccountsSupervisor.cancelOrders(marketId: String?, callback: TransactionCallback) {
account?.cancelOrders(marketId, callback)
}

internal fun AccountsSupervisor.orderCanceled(orderId: String) {
account?.orderCanceled(orderId)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import exchange.dydx.abacus.state.changes.StateChanges
import exchange.dydx.abacus.state.manager.ApiData
import exchange.dydx.abacus.state.manager.BlockAndTime
import exchange.dydx.abacus.state.manager.FaucetRecord
import exchange.dydx.abacus.state.manager.HumanReadableCancelMultipleOrdersPayload
import exchange.dydx.abacus.state.manager.HumanReadableCancelOrderPayload
import exchange.dydx.abacus.state.manager.HumanReadableDepositPayload
import exchange.dydx.abacus.state.manager.HumanReadableFaucetPayload
Expand Down Expand Up @@ -328,6 +329,10 @@ internal class SubaccountSupervisor(
return payloadProvider.cancelOrderPayload(orderId)
}

internal fun cancelOrdersPayload(marketId: String?): HumanReadableCancelMultipleOrdersPayload {
return payloadProvider.cancelOrdersPayload(marketId)
}

fun trade(
data: String?,
type: TradeInputField?,
Expand Down Expand Up @@ -425,6 +430,10 @@ internal class SubaccountSupervisor(
return transactionSupervisor.cancelOrder(orderId, isOrphanedTriggerOrder, callback)
}

internal fun cancelOrders(marketId: String?, callback: TransactionCallback): HumanReadableCancelMultipleOrdersPayload {
return transactionSupervisor.cancelOrders(marketId, callback)
}

internal fun commitTriggerOrders(
currentHeight: Int?,
callback: TransactionCallback
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import exchange.dydx.abacus.output.input.OrderStatus
import exchange.dydx.abacus.output.input.OrderType
import exchange.dydx.abacus.output.input.TradeInputGoodUntil
import exchange.dydx.abacus.output.input.TriggerOrder
import exchange.dydx.abacus.state.manager.HumanReadableCancelMultipleOrdersPayload
import exchange.dydx.abacus.state.manager.HumanReadableCancelOrderPayload
import exchange.dydx.abacus.state.manager.HumanReadableDepositPayload
import exchange.dydx.abacus.state.manager.HumanReadablePlaceOrderPayload
Expand All @@ -22,8 +23,10 @@ import exchange.dydx.abacus.utils.LIMIT_CLOSE_ORDER_DEFAULT_DURATION_DAYS
import exchange.dydx.abacus.utils.MAX_SUBACCOUNT_NUMBER
import exchange.dydx.abacus.utils.NUM_PARENT_SUBACCOUNTS
import exchange.dydx.abacus.utils.SHORT_TERM_ORDER_DURATION
import kollections.iEmptyList
import kollections.iListOf
import kollections.iMutableListOf
import kollections.toIList
import kotlin.random.Random
import kotlin.time.Duration.Companion.seconds

Expand All @@ -35,6 +38,9 @@ internal interface SubaccountTransactionPayloadProviderProtocol {
@Throws(Exception::class)
fun cancelOrderPayload(orderId: String): HumanReadableCancelOrderPayload

@Throws(Exception::class)
fun cancelOrdersPayload(marketId: String?): HumanReadableCancelMultipleOrdersPayload

fun triggerOrdersPayload(currentHeight: Int?): HumanReadableTriggerOrdersPayload

@Throws(Exception::class)
Expand Down Expand Up @@ -169,6 +175,22 @@ internal class SubaccountTransactionPayloadProvider(
)
}

@Throws(Exception::class)
override fun cancelOrdersPayload(
marketId: String?,
): HumanReadableCancelMultipleOrdersPayload {
val subaccount = stateMachine.state?.subaccount(subaccountNumber) ?: throw Exception("subaccount is null")
val openOrders = subaccount.orders?.let { orders ->
orders.filter { ( marketId == null || it.marketId == marketId ) && it.status.isOpen }
} ?: iEmptyList()
val cancelPayloads = openOrders.map { cancelOrderPayload(it.id) }.sortedBy { payload -> payload.orderFlags }.toIList()

return HumanReadableCancelMultipleOrdersPayload(
marketId = marketId,
payloads = cancelPayloads
)
}

override fun transferPayloadForIsolatedMarginTrade(orderPayload: HumanReadablePlaceOrderPayload): HumanReadableSubaccountTransferPayload? {
val trade = stateMachine.state?.input?.trade ?: return null
val childSubaccountNumber = orderPayload.subaccountNumber
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import exchange.dydx.abacus.responses.ParsingErrorType
import exchange.dydx.abacus.responses.ParsingException
import exchange.dydx.abacus.state.manager.CancelOrderRecord
import exchange.dydx.abacus.state.manager.FaucetRecord
import exchange.dydx.abacus.state.manager.HumanReadableCancelMultipleOrdersPayload
import exchange.dydx.abacus.state.manager.HumanReadableCancelOrderPayload
import exchange.dydx.abacus.state.manager.HumanReadablePlaceOrderPayload
import exchange.dydx.abacus.state.manager.HumanReadableSubaccountTransferPayload
Expand All @@ -31,6 +32,7 @@ import exchange.dydx.abacus.utils.IMap
import exchange.dydx.abacus.utils.IMutableList
import exchange.dydx.abacus.utils.Logger
import exchange.dydx.abacus.utils.NUM_PARENT_SUBACCOUNTS
import exchange.dydx.abacus.utils.Numeric
import exchange.dydx.abacus.utils.ParsingHelper
import exchange.dydx.abacus.utils.SHORT_TERM_ORDER_FLAGS
import exchange.dydx.abacus.utils.iMapOf
Expand Down Expand Up @@ -147,6 +149,33 @@ internal class SubaccountTransactionSupervisor(
return submitCancelOrder(orderId, marketId, callback, payload, analyticsPayload, uiClickTimeMs)
}

internal fun cancelOrders(marketId: String?, callback: TransactionCallback): HumanReadableCancelMultipleOrdersPayload {
val payload = payloadProvider.cancelOrdersPayload(marketId)

payload.payloads.forEach { cancelPayload ->
val subaccount = stateMachine.state?.subaccount(subaccountNumber)
val existingOrder = subaccount?.orders?.firstOrNull { it.id == cancelPayload.orderId }
?: throw ParsingException(
ParsingErrorType.MissingRequiredData,
"no existing order to be cancelled for $cancelPayload.orderId",
)
val marketId = existingOrder.marketId
val cancelOrderAnalyticsPayload = analyticsUtils.cancelOrderAnalyticsPayload(
cancelPayload,
existingOrder
)
submitCancelOrder(
orderId = cancelPayload.orderId,
marketId = marketId,
callback = callback,
payload = cancelPayload,
analyticsPayload = cancelOrderAnalyticsPayload,
uiClickTimeMs = Numeric.double.ZERO, // TODO(@aforaleka) add back tracking
)
}
return payload
}

internal fun commitTriggerOrders(
currentHeight: Int?,
callback: TransactionCallback
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,50 @@ class V4TransactionTests : NetworkTests() {
assertTransactionQueueEmpty()
}

@Test
fun testCancelAllOrders() {
setStateMachineConnected(stateManager)
testWebSocket?.simulateReceived(mock.accountsChannel.v4_channel_data_with_orders)

var statefulCancelCalledCount = 0
val callback: TransactionCallback = { _, _, _ -> statefulCancelCalledCount++ }
val cancelPayloads = testChain!!.canceldOrderPayloads

subaccountSupervisor?.cancelOrders(null, callback)
// there are 2 short term orders and 4 stateful orders
// hence 2 stateful orders should be queued
assertEquals(3, cancelPayloads.size)
assertEquals(2, subaccountSupervisor?.transactionQueue?.size)
repeat(4) {
testChain?.simulateTransactionResponse(testChain!!.dummySuccess)
}

assertEquals(4, statefulCancelCalledCount)
assertEquals(5, cancelPayloads.size)
}

@Test
fun testCancelAllOrdersUnderMarket() {
setStateMachineConnected(stateManager)
testWebSocket?.simulateReceived(mock.accountsChannel.v4_channel_data_with_orders)

var statefulCancelCalledCount = 0
val callback: TransactionCallback = { _, _, _ -> statefulCancelCalledCount++ }
val cancelPayloads = testChain!!.canceldOrderPayloads

subaccountSupervisor?.cancelOrders("ETH-USD", callback)
// there are 1 short term order and 3 stateful orders in "ETH"
// hence 2 stateful orders should be queued
assertEquals(2, cancelPayloads.size)
assertEquals(2, subaccountSupervisor?.transactionQueue?.size)
repeat(3) {
testChain?.simulateTransactionResponse(testChain!!.dummySuccess)
}
assertTransactionQueueEmpty()
assertEquals(3, statefulCancelCalledCount)
assertEquals(4, cancelPayloads.size)
}

@Test
fun testCancelTriggerOrdersWithClosedOrFlippedPositions() {
setStateMachineConnected(stateManager)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1949,6 +1949,28 @@ internal class AccountsChannelMock {
"goodTilBlock": "8864635",
"ticker": "ETH-USD",
"clientMetadata": "1"
},
{
"id": "734617f4-29ba-50fe-878d-391ad4e4fbae",
"subaccountId": "e470a747-3aa0-543e-aafa-0bd27d568901",
"clientId": "1597910999",
"clobPairId": "0",
"side": "BUY",
"size": "0.1",
"totalFilled": "0",
"price": "42000",
"type": "LIMIT",
"status": "OPEN",
"timeInForce": "IOC",
"reduceOnly": true,
"orderFlags": "0",
"goodTilBlockTime": "2024-04-02T15:57:16.000Z",
"createdAtHeight": "8489771",
"clientMetadata": "0",
"updatedAt": "2024-03-15T06:37:01.731Z",
"updatedAtHeight": "8489771",
"postOnly": false,
"ticker": "BTC-USD"
}
],
"fills":[
Expand Down

0 comments on commit bc416a0

Please sign in to comment.