diff --git a/src/dist/cfg/log4j2.xml b/src/dist/cfg/log4j2.xml index 226fec133..41c5c9222 100644 --- a/src/dist/cfg/log4j2.xml +++ b/src/dist/cfg/log4j2.xml @@ -466,6 +466,11 @@ # Multi Limit Order + + + + diff --git a/src/main/kotlin/com/lykke/matching/engine/config/spring/InputQueueListenerConfig.kt b/src/main/kotlin/com/lykke/matching/engine/config/spring/InputQueueListenerConfig.kt index 2bd64a62a..0e5e53402 100644 --- a/src/main/kotlin/com/lykke/matching/engine/config/spring/InputQueueListenerConfig.kt +++ b/src/main/kotlin/com/lykke/matching/engine/config/spring/InputQueueListenerConfig.kt @@ -5,6 +5,7 @@ import com.lykke.matching.engine.incoming.preprocessor.impl.CashInOutPreprocesso import com.lykke.matching.engine.incoming.preprocessor.impl.CashTransferPreprocessor import com.lykke.matching.engine.incoming.preprocessor.impl.LimitOrderCancelOperationPreprocessor import com.lykke.matching.engine.incoming.preprocessor.impl.LimitOrderMassCancelOperationPreprocessor +import com.lykke.matching.engine.incoming.preprocessor.impl.MultilimitOrderPreprocessor import com.lykke.matching.engine.incoming.preprocessor.impl.SingleLimitOrderPreprocessor import com.lykke.matching.engine.messages.MessageWrapper import com.lykke.utils.logging.ThrottlingLogger @@ -38,6 +39,17 @@ open class InputQueueListenerConfig { "CashInOutInputQueueListener") } + @Bean + open fun multilimitOrderListener(multilimitOrderInputQueue: BlockingQueue, + multilimitOrderPreprocessor: MultilimitOrderPreprocessor, + @Qualifier("multiLimitOrderPreProcessingLogger") + logger: ThrottlingLogger): InputQueueListener { + return InputQueueListener(multilimitOrderInputQueue, + multilimitOrderPreprocessor, + logger, + "MultilimitOrderListener") + } + @Bean open fun limitOrderCancelInputQueueListener(limitOrderCancelInputQueue: BlockingQueue, limitOrderCancelOperationPreprocessor: LimitOrderCancelOperationPreprocessor, diff --git a/src/main/kotlin/com/lykke/matching/engine/config/spring/LoggerConfig.kt b/src/main/kotlin/com/lykke/matching/engine/config/spring/LoggerConfig.kt index 1ba35d650..98fd22dab 100644 --- a/src/main/kotlin/com/lykke/matching/engine/config/spring/LoggerConfig.kt +++ b/src/main/kotlin/com/lykke/matching/engine/config/spring/LoggerConfig.kt @@ -34,6 +34,11 @@ open class LoggerConfig { return LoggerFactory.getLogger("AppStarter") } + @Bean + open fun multiLimitOrderPreProcessingLogger(): ThrottlingLogger { + return ThrottlingLogger.getLogger("MultiLimitOrderPreProcessing") + } + @Bean open fun singleLimitOrderPreProcessingLogger(): ThrottlingLogger { return ThrottlingLogger.getLogger("SingleLimitOrderPreProcessing") diff --git a/src/main/kotlin/com/lykke/matching/engine/config/spring/QueueConfig.kt b/src/main/kotlin/com/lykke/matching/engine/config/spring/QueueConfig.kt index 3d46124a5..b129b6cdb 100644 --- a/src/main/kotlin/com/lykke/matching/engine/config/spring/QueueConfig.kt +++ b/src/main/kotlin/com/lykke/matching/engine/config/spring/QueueConfig.kt @@ -97,6 +97,12 @@ open class QueueConfig { return LinkedBlockingQueue() } + @Bean + @InputQueue + open fun multilimitOrderInputQueue(): BlockingQueue { + return LinkedBlockingQueue() + } + @Bean @InputQueue open fun cashInOutInputQueue(): BlockingQueue { diff --git a/src/main/kotlin/com/lykke/matching/engine/daos/LimitOrder.kt b/src/main/kotlin/com/lykke/matching/engine/daos/LimitOrder.kt index 331e7ada3..c586d0556 100644 --- a/src/main/kotlin/com/lykke/matching/engine/daos/LimitOrder.kt +++ b/src/main/kotlin/com/lykke/matching/engine/daos/LimitOrder.kt @@ -4,6 +4,7 @@ import com.lykke.matching.engine.daos.fee.v2.NewLimitOrderFeeInstruction import com.lykke.matching.engine.daos.order.OrderTimeInForce import com.lykke.matching.engine.daos.order.LimitOrderType import com.lykke.matching.engine.daos.v2.LimitOrderFeeInstruction +import com.lykke.matching.engine.utils.NumberUtils import org.nustaq.serialization.annotations.Version import java.io.Serializable import java.math.BigDecimal @@ -104,4 +105,35 @@ class LimitOrder(id: String, fun isExpired(date: Date): Boolean { return hasExpiryTime() && !expiryTime!!.after(date) } + + override fun toString(): String { + return "id: $externalId" + + if(previousExternalId != null) ", previousExternalId: $previousExternalId" else "" + + if(parentOrderExternalId != null) ", parentOrderExternalId: $previousExternalId" else "" + + if(childOrderExternalId != null) ", childOrderExternalId: $childOrderExternalId" else "" + + + ", type: $type" + + ", client: $clientId" + + ", assetPair: $assetPairId" + + ", status: $status" + + + ", volume: ${NumberUtils.roundForPrint(volume)}" + + (if (reservedLimitVolume != null) ", reservedLimitVolume: $reservedLimitVolume" else "") + + ", remainingVolume: $remainingVolume" + + ", price: ${NumberUtils.roundForPrint(price)}" + + (if (lowerLimitPrice != null) ", lowerLimitPrice: ${NumberUtils.roundForPrint(lowerLimitPrice)}" else "") + + (if (lowerPrice != null) ", lowerPrice: ${NumberUtils.roundForPrint(lowerPrice)}" else "") + + (if (upperLimitPrice != null) ", upperLimitPrice: ${NumberUtils.roundForPrint(upperLimitPrice)}" else "") + + (if (upperPrice != null) ", upperPrice: ${NumberUtils.roundForPrint(upperPrice)}" else "") + + + ", createdAt: $createdAt" + + (if (statusDate != null) ", statusDate: $statusDate" else "") + + (if (registered != null) ", registered: $registered" else "") + + (if (lastMatchTime != null) ", lastMatchTime: $lastMatchTime" else "") + + + ", fee: $fee" + + ", fees: $fees" + + (if (timeInForce != null) ", timeInForce: $timeInForce" else "") + + (if (expiryTime != null) ", expiryTime: $expiryTime" else "") + } } \ No newline at end of file diff --git a/src/main/kotlin/com/lykke/matching/engine/daos/context/LimitOrderMassCancelOperationContext.kt b/src/main/kotlin/com/lykke/matching/engine/daos/context/LimitOrderMassCancelOperationContext.kt index fbdc39d23..4d4340943 100644 --- a/src/main/kotlin/com/lykke/matching/engine/daos/context/LimitOrderMassCancelOperationContext.kt +++ b/src/main/kotlin/com/lykke/matching/engine/daos/context/LimitOrderMassCancelOperationContext.kt @@ -3,7 +3,7 @@ package com.lykke.matching.engine.daos.context import com.lykke.matching.engine.deduplication.ProcessedMessage import com.lykke.matching.engine.messages.MessageType -class LimitOrderMassCancelOperationContext(val uid: String, +data class LimitOrderMassCancelOperationContext(val uid: String, val messageId: String, val clientId: String?, val processedMessage: ProcessedMessage, diff --git a/src/main/kotlin/com/lykke/matching/engine/daos/context/MultilimitOrderContext.kt b/src/main/kotlin/com/lykke/matching/engine/daos/context/MultilimitOrderContext.kt new file mode 100644 index 000000000..49d21ff82 --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/daos/context/MultilimitOrderContext.kt @@ -0,0 +1,13 @@ +package com.lykke.matching.engine.daos.context + +import com.lykke.matching.engine.daos.Asset +import com.lykke.matching.engine.daos.AssetPair +import com.lykke.matching.engine.daos.MultiLimitOrder +import com.lykke.matching.engine.services.validators.MultilimitOrderValidationResult + +data class MultilimitOrderContext(val assetPair: AssetPair?, + val baseAsset: Asset?, + val quotingAsset: Asset?, + val isTrustedClient: Boolean, + val multiLimitOrder: MultiLimitOrder, + var multilimitOrderValidationResult: MultilimitOrderValidationResult? = null) diff --git a/src/main/kotlin/com/lykke/matching/engine/daos/context/SingleLimitOrderContext.kt b/src/main/kotlin/com/lykke/matching/engine/daos/context/SingleLimitOrderContext.kt index 52a1e683d..f0b534953 100644 --- a/src/main/kotlin/com/lykke/matching/engine/daos/context/SingleLimitOrderContext.kt +++ b/src/main/kotlin/com/lykke/matching/engine/daos/context/SingleLimitOrderContext.kt @@ -5,9 +5,8 @@ import com.lykke.matching.engine.daos.AssetPair import com.lykke.matching.engine.daos.LimitOrder import com.lykke.matching.engine.deduplication.ProcessedMessage import com.lykke.matching.engine.services.validators.impl.OrderValidationResult -import com.lykke.matching.engine.utils.NumberUtils -class SingleLimitOrderContext(val messageId: String, +data class SingleLimitOrderContext(val messageId: String, val limitOrder: LimitOrder, val isCancelOrders: Boolean, val assetPair: AssetPair?, @@ -30,25 +29,10 @@ class SingleLimitOrderContext(val messageId: String, builder.processedMessage) override fun toString(): String { - val order = this.limitOrder - - return "id: ${limitOrder.externalId}" + - ", messageId: $messageId" + - ", type: ${order.type}" + - ", client: ${order.clientId}" + + return ", messageId: $messageId" + ", isTrustedClient: $isTrustedClient" + - ", assetPair: ${order.assetPairId}" + - ", volume: ${NumberUtils.roundForPrint(order.volume)}" + - ", price: ${NumberUtils.roundForPrint(order.price)}" + - (if (order.lowerLimitPrice != null) ", lowerLimitPrice: ${NumberUtils.roundForPrint(order.lowerLimitPrice)}" else "") + - (if (order.lowerPrice != null) ", lowerPrice: ${NumberUtils.roundForPrint(order.lowerPrice)}" else "") + - (if (order.upperLimitPrice != null) ", upperLimitPrice: ${NumberUtils.roundForPrint(order.upperLimitPrice)}" else "") + - (if (order.upperPrice != null) ", upperPrice: ${NumberUtils.roundForPrint(order.upperPrice)}" else "") + ", cancel: $isCancelOrders" + - ", fee: ${order.fee}" + - ", fees: ${order.fees}" + - (if (order.timeInForce != null) ", timeInForce=${order.timeInForce}" else "") + - (if (order.expiryTime != null) ", expiryTime=${order.expiryTime}" else "") + ", limitOrder: $limitOrder" } class Builder { diff --git a/src/main/kotlin/com/lykke/matching/engine/incoming/MessageRouter.kt b/src/main/kotlin/com/lykke/matching/engine/incoming/MessageRouter.kt index e5b7708a1..cd637444c 100644 --- a/src/main/kotlin/com/lykke/matching/engine/incoming/MessageRouter.kt +++ b/src/main/kotlin/com/lykke/matching/engine/incoming/MessageRouter.kt @@ -12,6 +12,7 @@ class MessageRouter( private val cashTransferInputQueue: BlockingQueue, private val limitOrderCancelInputQueue: BlockingQueue, private val limitOrderMassCancelInputQueue: BlockingQueue, + private val multilimitOrderInputQueue: BlockingQueue, val preProcessedMessageQueue: BlockingQueue ) { fun process(wrapper: MessageWrapper) { @@ -21,6 +22,7 @@ class MessageRouter( MessageType.LIMIT_ORDER.type -> limitOrderInputQueue.put(wrapper) MessageType.LIMIT_ORDER_CANCEL.type -> limitOrderCancelInputQueue.put(wrapper) MessageType.LIMIT_ORDER_MASS_CANCEL.type -> limitOrderMassCancelInputQueue.put(wrapper) + MessageType.MULTI_LIMIT_ORDER.type -> multilimitOrderInputQueue.put(wrapper) else -> preProcessedMessageQueue.put(wrapper) } diff --git a/src/main/kotlin/com/lykke/matching/engine/incoming/listener/InputQueueListener.kt b/src/main/kotlin/com/lykke/matching/engine/incoming/listener/InputQueueListener.kt index 9e932ce53..118ba2ed0 100644 --- a/src/main/kotlin/com/lykke/matching/engine/incoming/listener/InputQueueListener.kt +++ b/src/main/kotlin/com/lykke/matching/engine/incoming/listener/InputQueueListener.kt @@ -6,6 +6,7 @@ import com.lykke.utils.logging.MetricsLogger import com.lykke.utils.logging.ThrottlingLogger import java.util.concurrent.BlockingQueue import javax.annotation.PostConstruct +import javax.annotation.PreDestroy class InputQueueListener(private val inputQueue: BlockingQueue, private val preProcessor: MessagePreprocessor, @@ -20,14 +21,34 @@ class InputQueueListener(private val inputQueue: BlockingQueue, @PostConstruct fun init() = start() + @PreDestroy + fun shutdown() { + this.interrupt() + } + override fun run() { while (true) { try { - preProcessor.preProcess(inputQueue.take()) + if(!process()) { + return + } } catch (e: Exception) { logger.error(ERROR_MESSAGE, e) METRICS_LOGGER.logError(ERROR_MESSAGE, e) } } } + + + private fun process(): Boolean { + try { + val messageWrapper = inputQueue.take() + preProcessor.preProcess(messageWrapper) + } catch(e: InterruptedException) { + this.interrupt() + return false + } + + return true + } } \ No newline at end of file diff --git a/src/main/kotlin/com/lykke/matching/engine/incoming/parsers/data/MultilimitOrderParsedData.kt b/src/main/kotlin/com/lykke/matching/engine/incoming/parsers/data/MultilimitOrderParsedData.kt new file mode 100644 index 000000000..126f19d99 --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/incoming/parsers/data/MultilimitOrderParsedData.kt @@ -0,0 +1,5 @@ +package com.lykke.matching.engine.incoming.parsers.data + +import com.lykke.matching.engine.messages.MessageWrapper + +class MultilimitOrderParsedData(messageWrapper: MessageWrapper, val inputAssetPairId: String) : ParsedData(messageWrapper) \ No newline at end of file diff --git a/src/main/kotlin/com/lykke/matching/engine/incoming/parsers/impl/MultilimitOrderContextParser.kt b/src/main/kotlin/com/lykke/matching/engine/incoming/parsers/impl/MultilimitOrderContextParser.kt new file mode 100644 index 000000000..ad5225189 --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/incoming/parsers/impl/MultilimitOrderContextParser.kt @@ -0,0 +1,173 @@ +package com.lykke.matching.engine.incoming.parsers.impl + +import com.lykke.matching.engine.daos.LimitOrder +import com.lykke.matching.engine.daos.MultiLimitOrder +import com.lykke.matching.engine.daos.context.MultilimitOrderContext +import com.lykke.matching.engine.daos.fee.v2.NewLimitOrderFeeInstruction +import com.lykke.matching.engine.daos.order.LimitOrderType +import com.lykke.matching.engine.daos.order.OrderTimeInForce +import com.lykke.matching.engine.daos.v2.LimitOrderFeeInstruction +import com.lykke.matching.engine.deduplication.ProcessedMessage +import com.lykke.matching.engine.fee.listOfLimitOrderFee +import com.lykke.matching.engine.holders.ApplicationSettingsHolder +import com.lykke.matching.engine.holders.AssetsHolder +import com.lykke.matching.engine.holders.AssetsPairsHolder +import com.lykke.matching.engine.holders.UUIDHolder +import com.lykke.matching.engine.incoming.parsers.ContextParser +import com.lykke.matching.engine.incoming.parsers.data.MultilimitOrderParsedData +import com.lykke.matching.engine.messages.MessageWrapper +import com.lykke.matching.engine.messages.ProtocolMessages +import com.lykke.matching.engine.order.OrderCancelMode +import com.lykke.matching.engine.order.OrderStatus +import com.lykke.utils.logging.ThrottlingLogger +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.stereotype.Component +import java.math.BigDecimal +import java.util.* + +@Component +class MultilimitOrderContextParser( + @Qualifier("multiLimitOrderPreProcessingLogger") + val logger: ThrottlingLogger, + val applicationSettingsHolder: ApplicationSettingsHolder, + val assertPairsHolder: AssetsPairsHolder, + val assetsHolder: AssetsHolder, + val uuid: UUIDHolder) : ContextParser { + override fun parse(messageWrapper: MessageWrapper): MultilimitOrderParsedData { + val message = parseMultiLimitOrder(messageWrapper.byteArray) + val trustedClient = applicationSettingsHolder.isTrustedClient(message.clientId) + messageWrapper.messageId = if (message.hasMessageId()) message.messageId else message.uid.toString() + messageWrapper.context = getContext(messageWrapper.messageId!!, trustedClient, message) + messageWrapper.timestamp = message.timestamp + messageWrapper.parsedMessage = message + messageWrapper.id = message.uid + messageWrapper.processedMessage = if (trustedClient) { + null + } else { + ProcessedMessage(messageWrapper.type, messageWrapper.timestamp!!, messageWrapper.messageId!!) + } + + return MultilimitOrderParsedData(messageWrapper, message.assetPairId) + } + + private fun parseMultiLimitOrder(array: ByteArray): ProtocolMessages.MultiLimitOrder { + return ProtocolMessages.MultiLimitOrder.parseFrom(array) + } + + private fun getContext(messageId: String, + trustedClient: Boolean, + message: ProtocolMessages.MultiLimitOrder): MultilimitOrderContext { + val assetPair = assertPairsHolder.getAssetPairAllowNulls(message.assetPairId) + val baseAsset = assetPair?.let { + assetsHolder.getAssetAllowNulls(it.baseAssetId) + } + + val quotingAsset = assetPair?.let { + assetsHolder.getAssetAllowNulls(it.quotingAssetId) + } + + return MultilimitOrderContext(assetPair, + baseAsset, + quotingAsset, + trustedClient, + readMultiLimitOrder(messageId, message, trustedClient)) + } + + private fun readMultiLimitOrder(messageId: String, + message: ProtocolMessages.MultiLimitOrder, + isTrustedClient: Boolean): MultiLimitOrder { + logger.debug("Got ${if (!isTrustedClient) "client " else ""}multi limit order id: ${message.uid}, " + + (if (messageId != message.uid) "messageId: $messageId, " else "") + + "client ${message.clientId}, " + + "assetPair: ${message.assetPairId}, " + + "ordersCount: ${message.ordersCount}, " + + (if (message.hasCancelAllPreviousLimitOrders()) "cancelPrevious: ${message.cancelAllPreviousLimitOrders}, " else "") + + (if (message.hasCancelMode()) "cancelMode: ${message.cancelMode}" else "")) + + val clientId = message.clientId + val messageUid = message.uid + val assetPairId = message.assetPairId + val cancelAllPreviousLimitOrders = message.cancelAllPreviousLimitOrders + val cancelMode = if (message.hasCancelMode()) OrderCancelMode.getByExternalId(message.cancelMode) else OrderCancelMode.NOT_EMPTY_SIDE + val now = Date() + var cancelBuySide = cancelMode == OrderCancelMode.BUY_SIDE || cancelMode == OrderCancelMode.BOTH_SIDES + var cancelSellSide = cancelMode == OrderCancelMode.SELL_SIDE || cancelMode == OrderCancelMode.BOTH_SIDES + + val buyReplacements = mutableMapOf() + val sellReplacements = mutableMapOf() + val orders = ArrayList() + message.ordersList.forEach { currentOrder -> + + val type = if (currentOrder.hasType()) LimitOrderType.getByExternalId(currentOrder.type) else LimitOrderType.LIMIT + val status = when (type) { + LimitOrderType.LIMIT -> OrderStatus.InOrderBook + LimitOrderType.STOP_LIMIT -> OrderStatus.Pending + } + val price = if (currentOrder.hasPrice()) BigDecimal.valueOf(currentOrder.price) else BigDecimal.ZERO + val lowerLimitPrice = if (currentOrder.hasLowerLimitPrice()) BigDecimal.valueOf(currentOrder.lowerLimitPrice) else null + val lowerPrice = if (currentOrder.hasLowerPrice()) BigDecimal.valueOf(currentOrder.lowerPrice) else null + val upperLimitPrice = if (currentOrder.hasUpperLimitPrice()) BigDecimal.valueOf(currentOrder.upperLimitPrice) else null + val upperPrice = if (currentOrder.hasUpperPrice()) BigDecimal.valueOf(currentOrder.upperPrice) else null + val feeInstruction = if (currentOrder.hasFee()) LimitOrderFeeInstruction.create(currentOrder.fee) else null + val feeInstructions = NewLimitOrderFeeInstruction.create(currentOrder.feesList) + val previousExternalId = if (currentOrder.hasOldUid()) currentOrder.oldUid else null + + val order = LimitOrder(uuid.getNextValue(), + currentOrder.uid, + message.assetPairId, + message.clientId, + BigDecimal.valueOf(currentOrder.volume), + price, + status.name, + now, + Date(message.timestamp), + now, + BigDecimal.valueOf(currentOrder.volume), + null, + fee = feeInstruction, + fees = listOfLimitOrderFee(feeInstruction, feeInstructions), + type = type, + lowerLimitPrice = lowerLimitPrice, + lowerPrice = lowerPrice, + upperLimitPrice = upperLimitPrice, + upperPrice = upperPrice, + previousExternalId = previousExternalId, + timeInForce = if (currentOrder.hasTimeInForce()) OrderTimeInForce.getByExternalId(currentOrder.timeInForce) else null, + expiryTime = if (currentOrder.hasExpiryTime()) Date(currentOrder.expiryTime) else null, + parentOrderExternalId = null, + childOrderExternalId = null + ) + + if (!isTrustedClient) { + logger.debug("Incoming limit order (message id: $messageId): $order") + } + + orders.add(order) + previousExternalId?.let { + (if (order.isBuySide()) buyReplacements else sellReplacements)[it] = order + } + + if (cancelAllPreviousLimitOrders && cancelMode == OrderCancelMode.NOT_EMPTY_SIDE) { + if (isBuyOrder(currentOrder)) { + cancelBuySide = true + } else { + cancelSellSide = true + } + } + } + + return MultiLimitOrder(messageUid, + clientId, + assetPairId, + orders, + cancelAllPreviousLimitOrders, + cancelBuySide, + cancelSellSide, + cancelMode, + buyReplacements, + sellReplacements) + } + + private fun isBuyOrder(currentOrder: ProtocolMessages.MultiLimitOrder.Order) = + currentOrder.volume > 0 +} \ No newline at end of file diff --git a/src/main/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/MultilimitOrderPreprocessor.kt b/src/main/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/MultilimitOrderPreprocessor.kt new file mode 100644 index 000000000..502ec5758 --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/MultilimitOrderPreprocessor.kt @@ -0,0 +1,118 @@ +package com.lykke.matching.engine.incoming.preprocessor.impl + +import com.lykke.matching.engine.daos.context.MultilimitOrderContext +import com.lykke.matching.engine.daos.order.LimitOrderType +import com.lykke.matching.engine.holders.MessageProcessingStatusHolder +import com.lykke.matching.engine.incoming.parsers.ContextParser +import com.lykke.matching.engine.incoming.parsers.data.MultilimitOrderParsedData +import com.lykke.matching.engine.incoming.preprocessor.AbstractMessagePreprocessor +import com.lykke.matching.engine.messages.MessageStatus +import com.lykke.matching.engine.messages.MessageWrapper +import com.lykke.matching.engine.messages.ProtocolMessages +import com.lykke.matching.engine.services.validators.MultilimitOrderValidationResult +import com.lykke.matching.engine.services.validators.common.OrderValidationUtils +import com.lykke.matching.engine.services.validators.impl.OrderValidationException +import com.lykke.matching.engine.services.validators.impl.OrderValidationResult +import com.lykke.matching.engine.services.validators.input.LimitOrderInputValidator +import com.lykke.matching.engine.services.validators.input.OrderInputValidator +import com.lykke.matching.engine.utils.order.MessageStatusUtils +import com.lykke.utils.logging.ThrottlingLogger +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.stereotype.Component +import java.util.* +import java.util.concurrent.BlockingQueue +import java.util.stream.Stream + +@Component +class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: MessageProcessingStatusHolder, + private val limitOrderInputValidator: LimitOrderInputValidator, + private val orderInputValidator: OrderInputValidator, + multilimitOrderContextParser: ContextParser, + preProcessedMessageQueue: BlockingQueue, + @Qualifier("multiLimitOrderPreProcessingLogger") + private val logger: ThrottlingLogger) : AbstractMessagePreprocessor(multilimitOrderContextParser, + messageProcessingStatusHolder, preProcessedMessageQueue, logger) { + override fun preProcessParsedData(parsedData: MultilimitOrderParsedData): Boolean { + val context = parsedData.messageWrapper.context as MultilimitOrderContext + if (messageProcessingStatusHolder.isTradeDisabled(context.assetPair)) { + writeResponse(parsedData.messageWrapper, + context.multiLimitOrder.assetPairId, + MessageStatus.MESSAGE_PROCESSING_DISABLED) + return false + } + + context.multilimitOrderValidationResult = getValidationResult(parsedData) + return processValidationResult(parsedData) + } + + fun writeResponse(messageWrapper: MessageWrapper, assetPairId: String, status: MessageStatus, message: String? = null) { + messageWrapper.writeMultiLimitOrderResponse(ProtocolMessages.MultiLimitOrderResponse.newBuilder() + .setStatus(status.type) + .setAssetPairId(assetPairId)) + } + + private fun processValidationResult(parsedData: MultilimitOrderParsedData): Boolean { + val context = parsedData.messageWrapper.context as MultilimitOrderContext + + val multilimitOrderValidationResult = context.multilimitOrderValidationResult + val fatallyInvalidValidationResult = Stream.concat(Stream.of(multilimitOrderValidationResult!!.globalValidationResult), + multilimitOrderValidationResult.inputValidationResultByOrderId?.values?.stream() + ?: Stream.empty()) + .filter { it.isFatalInvalid } + .findFirst() + + if (fatallyInvalidValidationResult.isPresent) { + logger.error("Fatal validation error occurred, ${fatallyInvalidValidationResult.get().message} " + + "Error details: $context") + writeResponse(parsedData.messageWrapper, + context.multiLimitOrder.assetPairId, + MessageStatusUtils.toMessageStatus(fatallyInvalidValidationResult.get().status!!), + fatallyInvalidValidationResult.get().message) + return false + } + + //if global non fatal validation occurs - all orders should has this validation error + if (!multilimitOrderValidationResult.globalValidationResult.isValid) { + val validationResultByOrderId = HashMap() + + context.multiLimitOrder.orders.forEach { + validationResultByOrderId[it.id] = multilimitOrderValidationResult.globalValidationResult + } + + context.multilimitOrderValidationResult = MultilimitOrderValidationResult(multilimitOrderValidationResult.globalValidationResult, validationResultByOrderId) + } + + return true + } + + private fun getValidationResult(parsedData: MultilimitOrderParsedData): MultilimitOrderValidationResult { + val context = parsedData.messageWrapper.context as MultilimitOrderContext + val orderValidationResultByOrderId = HashMap() + + try { + orderInputValidator.validateAsset(context.assetPair, parsedData.inputAssetPairId) + } catch (e: OrderValidationException) { + val fatalInvalid = OrderValidationUtils.isFatalInvalid(e) + return MultilimitOrderValidationResult(OrderValidationResult(false, fatalInvalid, e.message, e.orderStatus)) + } + + + for (order in context.multiLimitOrder.orders) { + try { + when (order.type) { + LimitOrderType.LIMIT -> limitOrderInputValidator.validateLimitOrder(context.isTrustedClient, + order, + context.assetPair, + null, + context.baseAsset) + LimitOrderType.STOP_LIMIT -> limitOrderInputValidator.validateStopOrder(order, context.assetPair, order.assetPairId, context.baseAsset) + } + } catch (e: OrderValidationException) { + val fatalInvalid = OrderValidationUtils.isFatalInvalid(e) + orderValidationResultByOrderId[order.id] = OrderValidationResult(false, fatalInvalid, e.message, e.orderStatus) + } + } + + return MultilimitOrderValidationResult(OrderValidationResult(true), orderValidationResultByOrderId) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/SingleLimitOrderPreprocessor.kt b/src/main/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/SingleLimitOrderPreprocessor.kt index f80a4f8ff..3eba926fd 100644 --- a/src/main/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/SingleLimitOrderPreprocessor.kt +++ b/src/main/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/SingleLimitOrderPreprocessor.kt @@ -8,7 +8,7 @@ import com.lykke.matching.engine.incoming.parsers.impl.SingleLimitOrderContextPa import com.lykke.matching.engine.incoming.preprocessor.AbstractMessagePreprocessor import com.lykke.matching.engine.messages.MessageStatus import com.lykke.matching.engine.messages.MessageWrapper -import com.lykke.matching.engine.order.OrderStatus +import com.lykke.matching.engine.services.validators.common.OrderValidationUtils import com.lykke.matching.engine.services.validators.impl.OrderValidationException import com.lykke.matching.engine.services.validators.impl.OrderValidationResult import com.lykke.matching.engine.services.validators.input.LimitOrderInputValidator @@ -64,13 +64,9 @@ class SingleLimitOrderPreprocessor(singleLimitOrderContextParser: SingleLimitOrd LimitOrderType.STOP_LIMIT -> limitOrderInputValidator.validateStopOrder(singleLimitOrderParsedData) } } catch (e: OrderValidationException) { - return OrderValidationResult(false, isFatalInvalid(e), e.message, e.orderStatus) + return OrderValidationResult(false, OrderValidationUtils.isFatalInvalid(e), e.message, e.orderStatus) } return OrderValidationResult(true) } - - private fun isFatalInvalid(validationException: OrderValidationException): Boolean { - return validationException.orderStatus == OrderStatus.UnknownAsset - } } \ No newline at end of file diff --git a/src/main/kotlin/com/lykke/matching/engine/order/process/LimitOrderProcessor.kt b/src/main/kotlin/com/lykke/matching/engine/order/process/LimitOrderProcessor.kt index 033edf862..2f2c522d6 100644 --- a/src/main/kotlin/com/lykke/matching/engine/order/process/LimitOrderProcessor.kt +++ b/src/main/kotlin/com/lykke/matching/engine/order/process/LimitOrderProcessor.kt @@ -16,14 +16,12 @@ import com.lykke.matching.engine.outgoing.messages.v2.enums.TradeRole import com.lykke.matching.engine.services.validators.business.LimitOrderBusinessValidator import com.lykke.matching.engine.services.validators.impl.OrderValidationException import com.lykke.matching.engine.services.validators.impl.OrderValidationResult -import com.lykke.matching.engine.services.validators.input.LimitOrderInputValidator import com.lykke.matching.engine.utils.NumberUtils import org.springframework.stereotype.Component import java.math.BigDecimal @Component -class LimitOrderProcessor(private val limitOrderInputValidator: LimitOrderInputValidator, - private val limitOrderBusinessValidator: LimitOrderBusinessValidator, +class LimitOrderProcessor(private val limitOrderBusinessValidator: LimitOrderBusinessValidator, private val applicationSettingsHolder: ApplicationSettingsHolder, private val matchingEngine: MatchingEngine, private val matchingResultHandlingHelper: MatchingResultHandlingHelper) : OrderProcessor { @@ -45,25 +43,7 @@ class LimitOrderProcessor(private val limitOrderInputValidator: LimitOrderInputV if (preProcessorValidationResult != null && !preProcessorValidationResult.isValid) { return preProcessorValidationResult } - // fixme: input validator will be moved from the business thread after multilimit order context release - val inputValidationResult = performInputValidation(orderContext) - return if (!inputValidationResult.isValid) inputValidationResult else performBusinessValidation(orderContext) - } - - private fun performInputValidation(orderContext: LimitOrderExecutionContext): OrderValidationResult { - val order = orderContext.order - val assetPair = orderContext.executionContext.assetPairsById[order.assetPairId] - val baseAsset = assetPair?.let { orderContext.executionContext.assetsById[assetPair.baseAssetId] } - try { - limitOrderInputValidator.validateLimitOrder(applicationSettingsHolder.isTrustedClient(order.clientId), - order, - assetPair, - order.assetPairId, - baseAsset) - } catch (e: OrderValidationException) { - return OrderValidationResult(false, false, e.message, e.orderStatus) - } - return OrderValidationResult(true) + return performBusinessValidation(orderContext) } private fun performBusinessValidation(orderContext: LimitOrderExecutionContext): OrderValidationResult { diff --git a/src/main/kotlin/com/lykke/matching/engine/order/process/StopLimitOrderProcessor.kt b/src/main/kotlin/com/lykke/matching/engine/order/process/StopLimitOrderProcessor.kt index 0b558cc54..4d97a4abd 100644 --- a/src/main/kotlin/com/lykke/matching/engine/order/process/StopLimitOrderProcessor.kt +++ b/src/main/kotlin/com/lykke/matching/engine/order/process/StopLimitOrderProcessor.kt @@ -13,14 +13,12 @@ import com.lykke.matching.engine.outgoing.messages.LimitOrderWithTrades import com.lykke.matching.engine.services.validators.business.StopOrderBusinessValidator import com.lykke.matching.engine.services.validators.impl.OrderValidationException import com.lykke.matching.engine.services.validators.impl.OrderValidationResult -import com.lykke.matching.engine.services.validators.input.LimitOrderInputValidator import com.lykke.matching.engine.utils.NumberUtils import org.springframework.stereotype.Component import java.math.BigDecimal @Component -class StopLimitOrderProcessor(private val limitOrderInputValidator: LimitOrderInputValidator, - private val stopOrderBusinessValidator: StopOrderBusinessValidator, +class StopLimitOrderProcessor(private val stopOrderBusinessValidator: StopOrderBusinessValidator, private val applicationSettingsHolder: ApplicationSettingsHolder, private val limitOrderProcessor: LimitOrderProcessor, private val uuidHolder: UUIDHolder) : OrderProcessor { @@ -41,18 +39,7 @@ class StopLimitOrderProcessor(private val limitOrderInputValidator: LimitOrderIn if (preProcessorValidationResult != null && !preProcessorValidationResult.isValid) { return preProcessorValidationResult } - // fixme: input validator will be moved from the business thread after multilimit order context release - val inputValidationResult = performInputValidation(orderContext) - return if (!inputValidationResult.isValid) inputValidationResult else performBusinessValidation(orderContext) - } - - private fun performInputValidation(orderContext: StopLimitOrderContext): OrderValidationResult { - try { - limitOrderInputValidator.validateStopOrder(orderContext) - } catch (e: OrderValidationException) { - return OrderValidationResult(false, false, e.message, e.orderStatus) - } - return OrderValidationResult(true) + return performBusinessValidation(orderContext) } private fun performBusinessValidation(orderContext: StopLimitOrderContext): OrderValidationResult { diff --git a/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt b/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt index c55dd908e..645241c5d 100644 --- a/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt +++ b/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt @@ -1,28 +1,13 @@ package com.lykke.matching.engine.services -import com.lykke.matching.engine.daos.fee.v2.NewLimitOrderFeeInstruction -import com.lykke.matching.engine.daos.AssetPair import com.lykke.matching.engine.daos.LimitOrder -import com.lykke.matching.engine.daos.MultiLimitOrder -import com.lykke.matching.engine.daos.order.OrderTimeInForce -import com.lykke.matching.engine.daos.order.LimitOrderType -import com.lykke.matching.engine.fee.listOfLimitOrderFee -import com.lykke.matching.engine.holders.AssetsHolder -import com.lykke.matching.engine.holders.AssetsPairsHolder +import com.lykke.matching.engine.daos.context.MultilimitOrderContext import com.lykke.matching.engine.holders.BalancesHolder import com.lykke.matching.engine.messages.MessageStatus import com.lykke.matching.engine.messages.MessageType import com.lykke.matching.engine.messages.MessageWrapper import com.lykke.matching.engine.messages.ProtocolMessages -import com.lykke.matching.engine.order.OrderCancelMode -import com.lykke.matching.engine.order.OrderStatus -import com.lykke.matching.engine.utils.NumberUtils import com.lykke.matching.engine.utils.order.MessageStatusUtils -import com.lykke.matching.engine.daos.v2.LimitOrderFeeInstruction -import com.lykke.matching.engine.deduplication.ProcessedMessage -import com.lykke.matching.engine.holders.MessageProcessingStatusHolder -import com.lykke.matching.engine.holders.ApplicationSettingsHolder -import com.lykke.matching.engine.holders.UUIDHolder import com.lykke.matching.engine.order.transaction.ExecutionContextFactory import com.lykke.matching.engine.order.process.GenericLimitOrdersProcessor import com.lykke.matching.engine.order.process.StopOrderBookProcessor @@ -31,7 +16,6 @@ import com.lykke.matching.engine.order.process.PreviousLimitOrdersProcessor import com.lykke.matching.engine.services.utils.MultiOrderFilter import org.slf4j.LoggerFactory import org.springframework.stereotype.Service -import java.math.BigDecimal import java.util.Date @Service @@ -40,50 +24,34 @@ class MultiLimitOrderService(private val executionContextFactory: ExecutionConte private val stopOrderBookProcessor: StopOrderBookProcessor, private val executionDataApplyService: ExecutionDataApplyService, private val previousLimitOrdersProcessor: PreviousLimitOrdersProcessor, - private val assetsHolder: AssetsHolder, - private val assetsPairsHolder: AssetsPairsHolder, - private val balancesHolder: BalancesHolder, - private val applicationSettingsHolder: ApplicationSettingsHolder, - private val messageProcessingStatusHolder: MessageProcessingStatusHolder, - private val uuidHolder: UUIDHolder) : AbstractService { + private val balancesHolder: BalancesHolder) : AbstractService { companion object { private val LOGGER = LoggerFactory.getLogger(MultiLimitOrderService::class.java.name) } override fun processMessage(messageWrapper: MessageWrapper) { - if (messageWrapper.parsedMessage == null) { - parseMessage(messageWrapper) - } processMultiOrder(messageWrapper) } private fun processMultiOrder(messageWrapper: MessageWrapper) { - val message = messageWrapper.parsedMessage!! as ProtocolMessages.MultiLimitOrder - val assetPair = assetsPairsHolder.getAssetPairAllowNulls(message.assetPairId) - if (assetPair == null) { - LOGGER.info("Unable to process message (${messageWrapper.messageId}): unknown asset pair ${message.assetPairId}") - writeResponse(messageWrapper, MessageStatus.UNKNOWN_ASSET) - return - } - - if (messageProcessingStatusHolder.isTradeDisabled(assetPair)) { - writeResponse(messageWrapper, MessageStatus.MESSAGE_PROCESSING_DISABLED) - return - } + val context = messageWrapper.context as MultilimitOrderContext - val isTrustedClient = applicationSettingsHolder.isTrustedClient(message.clientId) - - val multiLimitOrder = readMultiLimitOrder(messageWrapper.messageId!!, message, isTrustedClient, assetPair) val now = Date() + val ordersToProcess = getOrdersToProcess(context, now) + + val multiLimitOrder = context.multiLimitOrder val executionContext = executionContextFactory.create(messageWrapper.messageId!!, messageWrapper.id!!, MessageType.MULTI_LIMIT_ORDER, messageWrapper.processedMessage, - mapOf(Pair(assetPair.assetPairId, assetPair)), + mapOf(Pair(context.assetPair!!.assetPairId, context.assetPair)), now, - LOGGER) + LOGGER, + mapOf(Pair(context.baseAsset!!.assetId, context.baseAsset), + Pair(context.quotingAsset!!.assetId, context.quotingAsset)), + context.multilimitOrderValidationResult?.inputValidationResultByOrderId ?: emptyMap()) previousLimitOrdersProcessor.cancelAndReplaceOrders(multiLimitOrder.clientId, multiLimitOrder.assetPairId, @@ -94,7 +62,7 @@ class MultiLimitOrderService(private val executionContextFactory: ExecutionConte multiLimitOrder.sellReplacements, executionContext) - val processedOrders = genericLimitOrdersProcessor.processOrders(multiLimitOrder.orders, executionContext) + val processedOrders = genericLimitOrdersProcessor.processOrders(ordersToProcess, executionContext) stopOrderBookProcessor.checkAndExecuteStopLimitOrders(executionContext) val persisted = executionDataApplyService.persistAndSendEvents(messageWrapper, executionContext) @@ -129,152 +97,29 @@ class MultiLimitOrderService(private val executionContextFactory: ExecutionConte } - private fun readMultiLimitOrder(messageId: String, - message: ProtocolMessages.MultiLimitOrder, - isTrustedClient: Boolean, - assetPair: AssetPair): MultiLimitOrder { - LOGGER.debug("Got ${if (!isTrustedClient) "client " else ""}multi limit order id: ${message.uid}, " + - (if (messageId != message.uid) "messageId: $messageId, " else "") + - "client ${message.clientId}, " + - "assetPair: ${message.assetPairId}, " + - "ordersCount: ${message.ordersCount}, " + - (if (message.hasCancelAllPreviousLimitOrders()) "cancelPrevious: ${message.cancelAllPreviousLimitOrders}, " else "") + - (if (message.hasCancelMode()) "cancelMode: ${message.cancelMode}" else "")) - - val clientId = message.clientId - val messageUid = message.uid - val assetPairId = message.assetPairId - val cancelAllPreviousLimitOrders = message.cancelAllPreviousLimitOrders - val cancelMode = if (message.hasCancelMode()) OrderCancelMode.getByExternalId(message.cancelMode) else OrderCancelMode.NOT_EMPTY_SIDE - val now = Date() - var cancelBuySide = cancelMode == OrderCancelMode.BUY_SIDE || cancelMode == OrderCancelMode.BOTH_SIDES - var cancelSellSide = cancelMode == OrderCancelMode.SELL_SIDE || cancelMode == OrderCancelMode.BOTH_SIDES + fun getOrdersToProcess(context: MultilimitOrderContext, now: Date): List { + val multiLimitOrder = context.multiLimitOrder + val baseAssetAvailableBalance = balancesHolder.getAvailableBalance(multiLimitOrder.clientId, context.assetPair!!.baseAssetId) + val quotingAssetAvailableBalance = balancesHolder.getAvailableBalance(multiLimitOrder.clientId, context.assetPair.quotingAssetId) - val buyReplacements = mutableMapOf() - val sellReplacements = mutableMapOf() - - val baseAssetAvailableBalance = balancesHolder.getAvailableBalance(clientId, assetPair.baseAssetId) - val quotingAssetAvailableBalance = balancesHolder.getAvailableBalance(clientId, assetPair.quotingAssetId) - - val filter = MultiOrderFilter(isTrustedClient, + val filter = MultiOrderFilter(context.isTrustedClient, baseAssetAvailableBalance, quotingAssetAvailableBalance, - assetsHolder.getAsset(assetPair.quotingAssetId).accuracy, + context.quotingAsset!!.accuracy, now, - message.ordersList.size, + multiLimitOrder.orders.size, LOGGER) - message.ordersList.forEach { currentOrder -> - if (!isTrustedClient) { - LOGGER.debug("Incoming limit order (message id: $messageId): ${getIncomingOrderInfo(currentOrder)}") - } - val type = if (currentOrder.hasType()) LimitOrderType.getByExternalId(currentOrder.type) else LimitOrderType.LIMIT - val status = when(type) { - LimitOrderType.LIMIT -> OrderStatus.InOrderBook - LimitOrderType.STOP_LIMIT -> OrderStatus.Pending - } - val price = if (currentOrder.hasPrice()) BigDecimal.valueOf(currentOrder.price) else BigDecimal.ZERO - val lowerLimitPrice = if (currentOrder.hasLowerLimitPrice()) BigDecimal.valueOf(currentOrder.lowerLimitPrice) else null - val lowerPrice = if (currentOrder.hasLowerPrice()) BigDecimal.valueOf(currentOrder.lowerPrice) else null - val upperLimitPrice = if (currentOrder.hasUpperLimitPrice()) BigDecimal.valueOf(currentOrder.upperLimitPrice) else null - val upperPrice = if (currentOrder.hasUpperPrice()) BigDecimal.valueOf(currentOrder.upperPrice) else null - val feeInstruction = if (currentOrder.hasFee()) LimitOrderFeeInstruction.create(currentOrder.fee) else null - val feeInstructions = NewLimitOrderFeeInstruction.create(currentOrder.feesList) - val previousExternalId = if (currentOrder.hasOldUid()) currentOrder.oldUid else null - - val order = LimitOrder(uuidHolder.getNextValue(), - currentOrder.uid, - message.assetPairId, - message.clientId, - BigDecimal.valueOf(currentOrder.volume), - price, - status.name, - now, - Date(message.timestamp), - now, - BigDecimal.valueOf(currentOrder.volume), - null, - fee = feeInstruction, - fees = listOfLimitOrderFee(feeInstruction, feeInstructions), - type = type, - lowerLimitPrice = lowerLimitPrice, - lowerPrice = lowerPrice, - upperLimitPrice = upperLimitPrice, - upperPrice = upperPrice, - previousExternalId = previousExternalId, - timeInForce = if (currentOrder.hasTimeInForce()) OrderTimeInForce.getByExternalId(currentOrder.timeInForce) else null, - expiryTime = if (currentOrder.hasExpiryTime()) Date(currentOrder.expiryTime) else null, - parentOrderExternalId = null, - childOrderExternalId = null) - + for (order in multiLimitOrder.orders) { filter.checkAndAdd(order) - previousExternalId?.let { - (if (order.isBuySide()) buyReplacements else sellReplacements)[it] = order - } - - if (cancelAllPreviousLimitOrders && cancelMode == OrderCancelMode.NOT_EMPTY_SIDE) { - if (currentOrder.volume > 0) { - cancelBuySide = true - } else { - cancelSellSide = true - } - } } - return MultiLimitOrder(messageUid, - clientId, - assetPairId, - filter.getResult(), - cancelAllPreviousLimitOrders, - cancelBuySide, - cancelSellSide, - cancelMode, - buyReplacements, - sellReplacements) + return filter.getResult() } - private fun getIncomingOrderInfo(incomingOrder: ProtocolMessages.MultiLimitOrder.Order): String { - return "id: ${incomingOrder.uid}" + - (if (incomingOrder.hasType()) ", type: ${incomingOrder.type}" else "") + - ", volume: ${NumberUtils.roundForPrint(incomingOrder.volume)}" + - (if (incomingOrder.hasPrice()) ", price: ${NumberUtils.roundForPrint(incomingOrder.price)}" else "") + - (if (incomingOrder.hasLowerLimitPrice()) ", lowerLimitPrice: ${NumberUtils.roundForPrint(incomingOrder.lowerLimitPrice)}" else "") + - (if (incomingOrder.hasLowerPrice()) ", lowerPrice: ${NumberUtils.roundForPrint(incomingOrder.lowerPrice)}" else "") + - (if (incomingOrder.hasUpperLimitPrice()) ", upperLimitPrice: ${NumberUtils.roundForPrint(incomingOrder.upperLimitPrice)}" else "") + - (if (incomingOrder.hasUpperPrice()) ", upperPrice: ${NumberUtils.roundForPrint(incomingOrder.upperPrice)}" else "") + - (if (incomingOrder.hasOldUid()) ", oldUid: ${incomingOrder.oldUid}" else "") + - (if (incomingOrder.hasTimeInForce()) ", timeInForce: ${incomingOrder.timeInForce}" else "") + - (if (incomingOrder.hasExpiryTime()) ", expiryTime: ${incomingOrder.expiryTime}" else "") + - (if (incomingOrder.hasFee()) ", fee: ${getIncomingFeeInfo(incomingOrder.fee)}" else "") + - (if (incomingOrder.feesCount > 0) ", fees: ${incomingOrder.feesList.asSequence().map { getIncomingFeeInfo(incomingOrder.fee) }.joinToString(", ")}" else "") - } - - private fun getIncomingFeeInfo(incomingFee: ProtocolMessages.LimitOrderFee): String { - return "type: ${incomingFee.type}, " + - (if (incomingFee.hasMakerSize()) ", makerSize: ${NumberUtils.roundForPrint(incomingFee.makerSize)}" else "") + - (if (incomingFee.hasTakerSize()) ", takerSize: ${NumberUtils.roundForPrint(incomingFee.takerSize)}" else "") + - (if (incomingFee.hasSourceClientId()) ", sourceClientId: ${incomingFee.sourceClientId}" else "") + - (if (incomingFee.hasTargetClientId()) ", targetClientId: ${incomingFee.targetClientId}" else "") + - (if (incomingFee.hasMakerSizeType()) ", makerSizeType: ${incomingFee.makerSizeType}" else "") + - (if (incomingFee.hasTakerSizeType()) ", takerSizeType: ${incomingFee.takerSizeType}" else "") + - (if (incomingFee.hasMakerFeeModificator()) ", makerFeeModificator: ${NumberUtils.roundForPrint(incomingFee.makerFeeModificator)}" else "") + - (if (incomingFee.assetIdCount > 0) ", assetIds: ${incomingFee.assetIdList}}" else "") - } - - private fun parseMultiLimitOrder(array: ByteArray): ProtocolMessages.MultiLimitOrder { - return ProtocolMessages.MultiLimitOrder.parseFrom(array) - } override fun parseMessage(messageWrapper: MessageWrapper) { - val message = parseMultiLimitOrder(messageWrapper.byteArray) - messageWrapper.messageId = if (message.hasMessageId()) message.messageId else message.uid.toString() - messageWrapper.timestamp = message.timestamp - messageWrapper.parsedMessage = message - messageWrapper.id = message.uid - messageWrapper.processedMessage = if (applicationSettingsHolder.isTrustedClient(message.clientId)) - null - else - ProcessedMessage(messageWrapper.type, messageWrapper.timestamp!!, messageWrapper.messageId!!) + //nothing to do } fun writeResponse(messageWrapper: MessageWrapper, responseBuilder: ProtocolMessages.MultiLimitOrderResponse.Builder) { diff --git a/src/main/kotlin/com/lykke/matching/engine/services/validators/MultilimitOrderValidationResult.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/MultilimitOrderValidationResult.kt new file mode 100644 index 000000000..331c2613f --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/MultilimitOrderValidationResult.kt @@ -0,0 +1,6 @@ +package com.lykke.matching.engine.services.validators + +import com.lykke.matching.engine.services.validators.impl.OrderValidationResult + +data class MultilimitOrderValidationResult (val globalValidationResult: OrderValidationResult, + val inputValidationResultByOrderId: Map? = null) \ No newline at end of file diff --git a/src/main/kotlin/com/lykke/matching/engine/services/validators/business/OrderBusinessValidator.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/business/OrderBusinessValidator.kt new file mode 100644 index 000000000..04915e96b --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/business/OrderBusinessValidator.kt @@ -0,0 +1,10 @@ +package com.lykke.matching.engine.services.validators.business + +import com.lykke.matching.engine.daos.LimitOrder +import java.math.BigDecimal +import java.util.* + +interface OrderBusinessValidator { + fun validateBalance(availableBalance: BigDecimal, limitVolume: BigDecimal) + fun validateExpiration(order: LimitOrder, orderProcessingTime: Date) +} \ No newline at end of file diff --git a/src/main/kotlin/com/lykke/matching/engine/services/validators/business/impl/LimitOrderBusinessValidatorImpl.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/business/impl/LimitOrderBusinessValidatorImpl.kt index 79cec45d4..3c681200a 100644 --- a/src/main/kotlin/com/lykke/matching/engine/services/validators/business/impl/LimitOrderBusinessValidatorImpl.kt +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/business/impl/LimitOrderBusinessValidatorImpl.kt @@ -5,16 +5,15 @@ import com.lykke.matching.engine.holders.OrderBookMaxTotalSizeHolder import com.lykke.matching.engine.order.OrderStatus import com.lykke.matching.engine.services.AssetOrderBook import com.lykke.matching.engine.services.validators.business.LimitOrderBusinessValidator +import com.lykke.matching.engine.services.validators.business.OrderBusinessValidator import com.lykke.matching.engine.services.validators.common.OrderValidationUtils import com.lykke.matching.engine.services.validators.impl.OrderValidationException import org.springframework.stereotype.Component import java.math.BigDecimal import java.util.Date - @Component -class LimitOrderBusinessValidatorImpl(private val orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder) - : LimitOrderBusinessValidator { - +class LimitOrderBusinessValidatorImpl(private val orderBusinessValidatorImpl: OrderBusinessValidator, + private val orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder): LimitOrderBusinessValidator { override fun performValidation(isTrustedClient: Boolean, order: LimitOrder, availableBalance: BigDecimal, limitVolume: BigDecimal, @@ -24,12 +23,12 @@ class LimitOrderBusinessValidatorImpl(private val orderBookMaxTotalSizeHolder: O OrderValidationUtils.validateOrderBookTotalSize(currentOrderBookTotalSize, orderBookMaxTotalSizeHolder.get()) if (!isTrustedClient) { - OrderValidationUtils.validateBalance(availableBalance, limitVolume) + orderBusinessValidatorImpl.validateBalance(availableBalance, limitVolume) } validatePreviousOrderNotFound(order) validateNotEnoughFounds(order) - OrderValidationUtils.validateExpiration(order, date) + orderBusinessValidatorImpl.validateExpiration(order, date) } private fun validatePreviousOrderNotFound(order: LimitOrder) { diff --git a/src/main/kotlin/com/lykke/matching/engine/services/validators/business/impl/OrderBusinessValidatorImpl.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/business/impl/OrderBusinessValidatorImpl.kt new file mode 100644 index 000000000..4b086baa7 --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/business/impl/OrderBusinessValidatorImpl.kt @@ -0,0 +1,24 @@ +package com.lykke.matching.engine.services.validators.business.impl + +import com.lykke.matching.engine.daos.LimitOrder +import com.lykke.matching.engine.order.OrderStatus +import com.lykke.matching.engine.services.validators.business.OrderBusinessValidator +import com.lykke.matching.engine.services.validators.impl.OrderValidationException +import org.springframework.stereotype.Component +import java.math.BigDecimal +import java.util.* + +@Component +class OrderBusinessValidatorImpl: OrderBusinessValidator { + override fun validateBalance(availableBalance: BigDecimal, limitVolume: BigDecimal) { + if (availableBalance < limitVolume) { + throw OrderValidationException(OrderStatus.NotEnoughFunds, "not enough funds to reserve") + } + } + + override fun validateExpiration(order: LimitOrder, orderProcessingTime: Date) { + if (order.isExpired(orderProcessingTime)) { + throw OrderValidationException(OrderStatus.Cancelled, "expired") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lykke/matching/engine/services/validators/business/impl/StopOrderBusinessValidatorImpl.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/business/impl/StopOrderBusinessValidatorImpl.kt index 52f741110..6fe3db769 100644 --- a/src/main/kotlin/com/lykke/matching/engine/services/validators/business/impl/StopOrderBusinessValidatorImpl.kt +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/business/impl/StopOrderBusinessValidatorImpl.kt @@ -2,6 +2,7 @@ package com.lykke.matching.engine.services.validators.business.impl import com.lykke.matching.engine.daos.LimitOrder import com.lykke.matching.engine.holders.OrderBookMaxTotalSizeHolder +import com.lykke.matching.engine.services.validators.business.OrderBusinessValidator import com.lykke.matching.engine.services.validators.business.StopOrderBusinessValidator import com.lykke.matching.engine.services.validators.common.OrderValidationUtils import org.springframework.stereotype.Component @@ -9,7 +10,8 @@ import java.math.BigDecimal import java.util.Date @Component -class StopOrderBusinessValidatorImpl(private val orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder) +class StopOrderBusinessValidatorImpl(private val orderBusinessValidator: OrderBusinessValidator, + private val orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder) : StopOrderBusinessValidator { override fun performValidation(availableBalance: BigDecimal, limitVolume: BigDecimal, @@ -17,7 +19,7 @@ class StopOrderBusinessValidatorImpl(private val orderBookMaxTotalSizeHolder: Or orderProcessingTime: Date, currentOrderBookTotalSize: Int) { OrderValidationUtils.validateOrderBookTotalSize(currentOrderBookTotalSize, orderBookMaxTotalSizeHolder.get()) - OrderValidationUtils.validateBalance(availableBalance, limitVolume) - OrderValidationUtils.validateExpiration(order, orderProcessingTime) + orderBusinessValidator.validateBalance(availableBalance, limitVolume) + orderBusinessValidator.validateExpiration(order, orderProcessingTime) } } \ No newline at end of file diff --git a/src/main/kotlin/com/lykke/matching/engine/services/validators/common/OrderValidationUtils.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/common/OrderValidationUtils.kt index b76cae793..a2629bd67 100644 --- a/src/main/kotlin/com/lykke/matching/engine/services/validators/common/OrderValidationUtils.kt +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/common/OrderValidationUtils.kt @@ -1,35 +1,16 @@ package com.lykke.matching.engine.services.validators.common -import com.lykke.matching.engine.daos.AssetPair -import com.lykke.matching.engine.daos.LimitOrder -import com.lykke.matching.engine.daos.Order import com.lykke.matching.engine.order.OrderStatus import com.lykke.matching.engine.services.validators.impl.OrderValidationException import com.lykke.utils.logging.MetricsLogger -import java.math.BigDecimal -import java.util.Date class OrderValidationUtils { companion object { - private val METRICS_LOGGER = MetricsLogger.getLogger() - fun checkMinVolume(order: Order, assetPair: AssetPair): Boolean { - val volume = order.getAbsVolume() - val minVolume = if (order.isStraight()) assetPair.minVolume else assetPair.minInvertedVolume - return minVolume == null || volume >= minVolume - } - - fun validateBalance(availableBalance: BigDecimal, limitVolume: BigDecimal) { - if (availableBalance < limitVolume) { - throw OrderValidationException(OrderStatus.NotEnoughFunds, "not enough funds to reserve") - } - } - fun validateExpiration(order: LimitOrder, orderProcessingTime: Date) { - if (order.isExpired(orderProcessingTime)) { - throw OrderValidationException(OrderStatus.Cancelled, "expired") - } + fun isFatalInvalid(validationException: OrderValidationException): Boolean { + return validationException.orderStatus == OrderStatus.UnknownAsset } fun validateOrderBookTotalSize(currentOrderBookTotalSize: Int, orderBookMaxTotalSize: Int?) { diff --git a/src/main/kotlin/com/lykke/matching/engine/services/validators/impl/MarketOrderValidatorImpl.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/impl/MarketOrderValidatorImpl.kt index 9f030d0ce..ad44eb04b 100644 --- a/src/main/kotlin/com/lykke/matching/engine/services/validators/impl/MarketOrderValidatorImpl.kt +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/impl/MarketOrderValidatorImpl.kt @@ -10,7 +10,7 @@ import com.lykke.matching.engine.holders.AssetsHolder import com.lykke.matching.engine.holders.AssetsPairsHolder import com.lykke.matching.engine.order.OrderStatus import com.lykke.matching.engine.services.validators.MarketOrderValidator -import com.lykke.matching.engine.services.validators.common.OrderValidationUtils +import com.lykke.matching.engine.services.validators.input.OrderInputValidator import com.lykke.matching.engine.utils.NumberUtils import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired @@ -22,7 +22,8 @@ import java.util.concurrent.PriorityBlockingQueue class MarketOrderValidatorImpl @Autowired constructor(private val assetsPairsHolder: AssetsPairsHolder, private val assetsHolder: AssetsHolder, - private val applicationSettingsHolder: ApplicationSettingsHolder) : MarketOrderValidator { + private val applicationSettingsHolder: ApplicationSettingsHolder, + private val orderInputValidator: OrderInputValidator) : MarketOrderValidator { companion object { private val LOGGER = LoggerFactory.getLogger(MarketOrderValidatorImpl::class.java.name) @@ -61,7 +62,7 @@ class MarketOrderValidatorImpl throw OrderValidationException(OrderStatus.InvalidVolume, message) } - if (!OrderValidationUtils.checkMinVolume(order, assetsPairsHolder.getAssetPair(order.assetPairId))) { + if (!orderInputValidator.checkMinVolume(order, assetsPairsHolder.getAssetPair(order.assetPairId))) { LOGGER.info("Too small volume for $order") throw OrderValidationException(OrderStatus.TooSmallVolume) } diff --git a/src/main/kotlin/com/lykke/matching/engine/services/validators/impl/OrderValidationResult.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/impl/OrderValidationResult.kt index 048d3aa1f..3bc3fc3e3 100644 --- a/src/main/kotlin/com/lykke/matching/engine/services/validators/impl/OrderValidationResult.kt +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/impl/OrderValidationResult.kt @@ -2,7 +2,7 @@ package com.lykke.matching.engine.services.validators.impl import com.lykke.matching.engine.order.OrderStatus -class OrderValidationResult(val isValid: Boolean, +data class OrderValidationResult(val isValid: Boolean, val isFatalInvalid: Boolean = false, val message: String? = null, val status: OrderStatus? = null) diff --git a/src/main/kotlin/com/lykke/matching/engine/services/validators/input/LimitOrderInputValidator.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/LimitOrderInputValidator.kt index cc0746d50..98323a543 100644 --- a/src/main/kotlin/com/lykke/matching/engine/services/validators/input/LimitOrderInputValidator.kt +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/LimitOrderInputValidator.kt @@ -4,7 +4,6 @@ import com.lykke.matching.engine.daos.Asset import com.lykke.matching.engine.daos.AssetPair import com.lykke.matching.engine.daos.LimitOrder import com.lykke.matching.engine.incoming.parsers.data.SingleLimitOrderParsedData -import com.lykke.matching.engine.order.process.context.StopLimitOrderContext interface LimitOrderInputValidator { fun validateLimitOrder(singleLimitOrderParsedData: SingleLimitOrderParsedData) @@ -12,7 +11,10 @@ interface LimitOrderInputValidator { fun validateLimitOrder(isTrustedClient: Boolean, order: LimitOrder, assetPair: AssetPair?, - assetPairId: String, + assetPairId: String?, baseAsset: Asset?) - fun validateStopOrder(stopLimitOrderContext: StopLimitOrderContext) + fun validateStopOrder(limitOrder: LimitOrder, + assetPair: AssetPair?, + assetPairId: String, + baseAsset: Asset?) } \ No newline at end of file diff --git a/src/main/kotlin/com/lykke/matching/engine/services/validators/input/OrderInputValidator.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/OrderInputValidator.kt new file mode 100644 index 000000000..266ebb37e --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/OrderInputValidator.kt @@ -0,0 +1,9 @@ +package com.lykke.matching.engine.services.validators.input + +import com.lykke.matching.engine.daos.AssetPair +import com.lykke.matching.engine.daos.Order + +interface OrderInputValidator { + fun checkMinVolume(order: Order, assetPair: AssetPair): Boolean + fun validateAsset(assetPair: AssetPair?, assetPairId: String) +} \ No newline at end of file diff --git a/src/main/kotlin/com/lykke/matching/engine/services/validators/input/impl/LimitOrderInputValidatorImpl.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/impl/LimitOrderInputValidatorImpl.kt index 1809a23b8..dd4565285 100644 --- a/src/main/kotlin/com/lykke/matching/engine/services/validators/input/impl/LimitOrderInputValidatorImpl.kt +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/impl/LimitOrderInputValidatorImpl.kt @@ -8,16 +8,16 @@ import com.lykke.matching.engine.fee.checkFee import com.lykke.matching.engine.holders.ApplicationSettingsHolder import com.lykke.matching.engine.incoming.parsers.data.SingleLimitOrderParsedData import com.lykke.matching.engine.order.OrderStatus -import com.lykke.matching.engine.order.process.context.StopLimitOrderContext -import com.lykke.matching.engine.services.validators.common.OrderValidationUtils import com.lykke.matching.engine.services.validators.impl.OrderValidationException import com.lykke.matching.engine.services.validators.input.LimitOrderInputValidator +import com.lykke.matching.engine.services.validators.input.OrderInputValidator import com.lykke.matching.engine.utils.NumberUtils import org.springframework.stereotype.Component import java.math.BigDecimal @Component -class LimitOrderInputValidatorImpl(val applicationSettingsHolder: ApplicationSettingsHolder) : LimitOrderInputValidator { +class LimitOrderInputValidatorImpl(val applicationSettingsHolder: ApplicationSettingsHolder, + val orderInputValidator: OrderInputValidator) : LimitOrderInputValidator { override fun validateLimitOrder(singleLimitOrderParsedData: SingleLimitOrderParsedData) { val singleLimitContext = singleLimitOrderParsedData.messageWrapper.context as SingleLimitOrderContext @@ -31,13 +31,13 @@ class LimitOrderInputValidatorImpl(val applicationSettingsHolder: ApplicationSet override fun validateLimitOrder(isTrustedClient: Boolean, order: LimitOrder, assetPair: AssetPair?, - assetPairId: String, + assetPairId: String?, baseAsset: Asset?) { if (!isTrustedClient) { validateFee(order) } - validateAsset(assetPair, assetPairId) + assetPairId?.let { orderInputValidator.validateAsset(assetPair, assetPairId) } validatePrice(order) validateVolume(order, assetPair!!) validateMaxValue(order, assetPair) @@ -56,20 +56,11 @@ class LimitOrderInputValidatorImpl(val applicationSettingsHolder: ApplicationSet singleLimitContext.baseAsset) } - override fun validateStopOrder(stopLimitOrderContext: StopLimitOrderContext) { - val assetPair = stopLimitOrderContext.executionContext.assetPairsById[stopLimitOrderContext.order.assetPairId] - val baseAsset = assetPair?.let { stopLimitOrderContext.executionContext.assetsById[assetPair.baseAssetId] } - validateStopOrder(stopLimitOrderContext.order, - assetPair, - stopLimitOrderContext.order.assetPairId, - baseAsset) - } - - private fun validateStopOrder(limitOrder: LimitOrder, - assetPair: AssetPair?, - assetPairId: String, - baseAsset: Asset?) { - validateAsset(assetPair, assetPairId) + override fun validateStopOrder(limitOrder: LimitOrder, + assetPair: AssetPair?, + assetPairId: String, + baseAsset: Asset?) { + orderInputValidator.validateAsset(assetPair, assetPairId) validateFee(limitOrder) validateLimitPrices(limitOrder) validateVolume(limitOrder, assetPair!!) @@ -78,15 +69,6 @@ class LimitOrderInputValidatorImpl(val applicationSettingsHolder: ApplicationSet validateStopPricesAccuracy(limitOrder, assetPair) } - private fun validateAsset(assetPair: AssetPair?, assetPairId: String) { - if (assetPair == null) { - throw OrderValidationException(OrderStatus.UnknownAsset, "Unable to find asset pair $assetPairId") - } - - if (applicationSettingsHolder.isAssetDisabled(assetPair.baseAssetId) || applicationSettingsHolder.isAssetDisabled(assetPair.quotingAssetId)) { - throw OrderValidationException(OrderStatus.DisabledAsset, "disabled asset") - } - } private fun validateFee(order: LimitOrder) { if (order.fee != null && order.fees?.size ?: 0 > 1 || !checkFee(null, order.fees)) { @@ -133,12 +115,11 @@ class LimitOrderInputValidatorImpl(val applicationSettingsHolder: ApplicationSet } private fun validateVolume(limitOrder: LimitOrder, assetPair: AssetPair) { - if (NumberUtils.equalsIgnoreScale(BigDecimal.ZERO, limitOrder.volume)) { throw OrderValidationException(OrderStatus.InvalidVolume, "volume can not be equal to zero") } - if (!OrderValidationUtils.checkMinVolume(limitOrder, assetPair)) { + if (!orderInputValidator.checkMinVolume(limitOrder, assetPair)) { throw OrderValidationException(OrderStatus.TooSmallVolume, "volume is too small") } } diff --git a/src/main/kotlin/com/lykke/matching/engine/services/validators/input/impl/OrderInputValidatorImpl.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/impl/OrderInputValidatorImpl.kt new file mode 100644 index 000000000..508877cc9 --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/impl/OrderInputValidatorImpl.kt @@ -0,0 +1,30 @@ +package com.lykke.matching.engine.services.validators.input.impl + +import com.lykke.matching.engine.daos.AssetPair +import com.lykke.matching.engine.daos.Order +import com.lykke.matching.engine.holders.ApplicationSettingsHolder +import com.lykke.matching.engine.order.OrderStatus +import com.lykke.matching.engine.services.validators.impl.OrderValidationException +import com.lykke.matching.engine.services.validators.input.OrderInputValidator +import org.springframework.stereotype.Component + +@Component +class OrderInputValidatorImpl(val applicationSettingsHolder: ApplicationSettingsHolder): OrderInputValidator { + override fun validateAsset(assetPair: AssetPair?, assetPairId: String) { + if (assetPair == null) { + throw OrderValidationException(OrderStatus.UnknownAsset, "Unable to find asset pair $assetPairId") + } + + if (applicationSettingsHolder.isAssetDisabled(assetPair.baseAssetId) || applicationSettingsHolder.isAssetDisabled(assetPair.quotingAssetId)) { + throw OrderValidationException(OrderStatus.DisabledAsset, "disabled asset") + } + } + + override fun checkMinVolume(order: Order, assetPair: AssetPair): Boolean { + val volume = order.getAbsVolume() + val minVolume = if (order.isStraight()) assetPair.minVolume else assetPair.minInvertedVolume + return minVolume == null || volume >= minVolume + } + + +} \ No newline at end of file diff --git a/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt b/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt index a85765a26..4733f7cb8 100644 --- a/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt +++ b/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt @@ -21,6 +21,7 @@ import com.lykke.matching.engine.incoming.parsers.ContextParser import com.lykke.matching.engine.incoming.parsers.impl.* import com.lykke.matching.engine.incoming.preprocessor.impl.CashInOutPreprocessor import com.lykke.matching.engine.incoming.preprocessor.impl.CashTransferPreprocessor +import com.lykke.matching.engine.incoming.preprocessor.impl.MultilimitOrderPreprocessor import com.lykke.matching.engine.incoming.preprocessor.impl.SingleLimitOrderPreprocessor import com.lykke.matching.engine.matching.MatchingEngine import com.lykke.matching.engine.messages.MessageWrapper @@ -60,10 +61,12 @@ import com.lykke.matching.engine.services.validators.input.LimitOrderInputValida import com.lykke.matching.engine.services.validators.input.CashInOutOperationInputValidator import com.lykke.matching.engine.services.validators.input.CashTransferOperationInputValidator import com.lykke.matching.engine.services.validators.input.LimitOrderCancelOperationInputValidator +import com.lykke.matching.engine.services.validators.input.OrderInputValidator import com.lykke.matching.engine.services.validators.input.impl.CashInOutOperationInputValidatorImpl import com.lykke.matching.engine.services.validators.input.impl.CashTransferOperationInputValidatorImpl import com.lykke.matching.engine.services.validators.input.impl.LimitOrderInputValidatorImpl import com.lykke.matching.engine.services.validators.input.impl.LimitOrderCancelOperationInputValidatorImpl +import com.lykke.matching.engine.services.validators.input.impl.OrderInputValidatorImpl import com.lykke.matching.engine.services.validators.settings.SettingValidator import com.lykke.matching.engine.services.validators.settings.impl.DisabledFunctionalitySettingValidator import com.lykke.matching.engine.services.validators.settings.impl.MessageProcessingSwitchSettingValidator @@ -279,11 +282,22 @@ open class TestApplicationContext { outgoingEventProcessor) } + @Bean + fun orderInputValidator(applicationSettingsHolder: ApplicationSettingsHolder): OrderInputValidator { + return OrderInputValidatorImpl(applicationSettingsHolder) + } + + @Bean + fun orderBusinessValidator(): OrderBusinessValidator { + return OrderBusinessValidatorImpl() + } + @Bean open fun marketOrderValidator(assetsPairsHolder: AssetsPairsHolder, assetsHolder: AssetsHolder, - applicationSettingsHolder: ApplicationSettingsHolder): MarketOrderValidator { - return MarketOrderValidatorImpl(assetsPairsHolder, assetsHolder, applicationSettingsHolder) + applicationSettingsHolder: ApplicationSettingsHolder, + orderInputValidator: OrderInputValidator): MarketOrderValidator { + return MarketOrderValidatorImpl(assetsPairsHolder, assetsHolder, applicationSettingsHolder, orderInputValidator) } @Bean @@ -370,20 +384,13 @@ open class TestApplicationContext { assetsHolder: AssetsHolder, assetsPairsHolder: AssetsPairsHolder, balancesHolder: BalancesHolder, - applicationSettingsHolder: ApplicationSettingsHolder, - messageProcessingStatusHolder: MessageProcessingStatusHolder, - testUUIDHolder: TestUUIDHolder): MultiLimitOrderService { + applicationSettingsHolder: ApplicationSettingsHolder): MultiLimitOrderService { return MultiLimitOrderService(executionContextFactory, genericLimitOrdersProcessor, stopOrderBookProcessor, executionDataApplyService, previousLimitOrdersProcessor, - assetsHolder, - assetsPairsHolder, - balancesHolder, - applicationSettingsHolder, - messageProcessingStatusHolder, - testUUIDHolder) + balancesHolder) } @Bean @@ -569,11 +576,12 @@ open class TestApplicationContext { @Bean open fun messageBuilder(cashTransferContextParser: CashTransferContextParser, cashInOutContextParser: CashInOutContextParser, - singleLimitOrderContextParser: SingleLimitOrderContextParser, + singleLimitOrderPreprocessor: SingleLimitOrderPreprocessor, limitOrderCancelOperationContextParser: ContextParser, - limitOrderMassCancelOperationContextParser: ContextParser): MessageBuilder { - return MessageBuilder(singleLimitOrderContextParser, cashInOutContextParser, cashTransferContextParser, - limitOrderCancelOperationContextParser, limitOrderMassCancelOperationContextParser) + limitOrderMassCancelOperationContextParser: ContextParser, + multilimitOrderPreprocessor: MultilimitOrderPreprocessor): MessageBuilder { + return MessageBuilder(singleLimitOrderPreprocessor, cashInOutContextParser, cashTransferContextParser, + limitOrderCancelOperationContextParser, limitOrderMassCancelOperationContextParser, multilimitOrderPreprocessor) } @Bean @@ -614,23 +622,34 @@ open class TestApplicationContext { } @Bean - open fun limitOrderInputValidator(applicationSettingsHolder: ApplicationSettingsHolder): LimitOrderInputValidator { - return LimitOrderInputValidatorImpl(applicationSettingsHolder) + open fun multilimitOrderContextParser(applicationSettingsHolder: ApplicationSettingsHolder, + assetsPairsHolder: AssetsPairsHolder, + assetsHolder: AssetsHolder, + uuidHolder: UUIDHolder): MultilimitOrderContextParser { + return MultilimitOrderContextParser(ThrottlingLogger.getLogger("multilimitOrder"), applicationSettingsHolder, assetsPairsHolder, assetsHolder, uuidHolder) } @Bean - fun orderBookMaxTotalSizeHolder(): OrderBookMaxTotalSizeHolder { - return OrderBookMaxTotalSizeHolderImpl(null) + open fun limitOrderInputValidator(applicationSettingsHolder: ApplicationSettingsHolder, + orderInputValidator: OrderInputValidator): LimitOrderInputValidator { + return LimitOrderInputValidatorImpl(applicationSettingsHolder, orderInputValidator) + } + + @Bean + open fun limitOrderBusinessValidator(orderBusinessValidator: OrderBusinessValidator, + orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder): LimitOrderBusinessValidator { + return LimitOrderBusinessValidatorImpl(orderBusinessValidator, orderBookMaxTotalSizeHolder) } @Bean - open fun limitOrderBusinessValidator(orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder): LimitOrderBusinessValidator { - return LimitOrderBusinessValidatorImpl(orderBookMaxTotalSizeHolder) + fun orderBookMaxTotalSizeHolder(): OrderBookMaxTotalSizeHolder { + return OrderBookMaxTotalSizeHolderImpl(null) } @Bean - open fun stopOrderBusinessValidatorImpl(orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder): StopOrderBusinessValidatorImpl { - return StopOrderBusinessValidatorImpl(orderBookMaxTotalSizeHolder) + open fun stopOrderBusinessValidatorImpl(orderBusinessValidator: OrderBusinessValidator, + orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder): StopOrderBusinessValidatorImpl { + return StopOrderBusinessValidatorImpl(orderBusinessValidator, orderBookMaxTotalSizeHolder) } @Bean @@ -697,6 +716,21 @@ open class TestApplicationContext { ThrottlingLogger.getLogger("limitOrder")) } + @Bean + open fun multiltilimitOrderPreprocessor(messageProcessingStatusHolder: MessageProcessingStatusHolder, + limitOrderInputValidator: LimitOrderInputValidator, + multilimitOrderContextParser: MultilimitOrderContextParser, + preProcessedMessageQueue: BlockingQueue, + orderInputValidator: OrderInputValidator + ): MultilimitOrderPreprocessor { + return MultilimitOrderPreprocessor(messageProcessingStatusHolder, + limitOrderInputValidator, + orderInputValidator, + multilimitOrderContextParser, + preProcessedMessageQueue, + ThrottlingLogger.getLogger("multilimitOrder")) + } + @Bean open fun expiryOrdersQueue() = ExpiryOrdersQueue() @@ -712,6 +746,7 @@ open class TestApplicationContext { cashTransferInputQueue, limitOrderCancelInputQueue, limitOrderMassCancelInputQueue, + preProcessedMessageQueue, preProcessedMessageQueue) } diff --git a/src/test/kotlin/com/lykke/matching/engine/config/TestExecutionContext.kt b/src/test/kotlin/com/lykke/matching/engine/config/TestExecutionContext.kt index eb536db0f..33759b955 100644 --- a/src/test/kotlin/com/lykke/matching/engine/config/TestExecutionContext.kt +++ b/src/test/kotlin/com/lykke/matching/engine/config/TestExecutionContext.kt @@ -170,7 +170,7 @@ open class TestExecutionContext { applicationSettingsHolder: ApplicationSettingsHolder, matchingEngine: MatchingEngine, matchingResultHandlingHelper: MatchingResultHandlingHelper): LimitOrderProcessor { - return LimitOrderProcessor(limitOrderInputValidator, + return LimitOrderProcessor( limitOrderBusinessValidator, applicationSettingsHolder, matchingEngine, @@ -178,12 +178,11 @@ open class TestExecutionContext { } @Bean - open fun stopLimitOrdersProcessor(limitOrderInputValidator: LimitOrderInputValidator, - stopOrderBusinessValidator: StopOrderBusinessValidator, + open fun stopLimitOrdersProcessor(stopOrderBusinessValidator: StopOrderBusinessValidator, applicationSettingsHolder: ApplicationSettingsHolder, limitOrderProcessor: LimitOrderProcessor, uuidHolder: UUIDHolder): StopLimitOrderProcessor { - return StopLimitOrderProcessor(limitOrderInputValidator, + return StopLimitOrderProcessor( stopOrderBusinessValidator, applicationSettingsHolder, limitOrderProcessor, diff --git a/src/test/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/MultilimitOrerPreprocessorTest.kt b/src/test/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/MultilimitOrerPreprocessorTest.kt new file mode 100644 index 000000000..f57df24ae --- /dev/null +++ b/src/test/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/MultilimitOrerPreprocessorTest.kt @@ -0,0 +1,66 @@ +package com.lykke.matching.engine.incoming.preprocessor.impl + +import com.lykke.matching.engine.AbstractTest +import com.lykke.matching.engine.config.TestApplicationContext +import com.lykke.matching.engine.daos.IncomingLimitOrder +import com.lykke.matching.engine.daos.order.LimitOrderType +import com.lykke.matching.engine.messages.MessageStatus +import com.lykke.matching.engine.messages.MessageWrapper +import com.lykke.matching.engine.messages.ProtocolMessages +import com.lykke.matching.engine.socket.TestClientHandler +import com.lykke.matching.engine.utils.MessageBuilder +import org.junit.Test +import org.junit.runner.RunWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.annotation.DirtiesContext +import org.springframework.test.context.junit4.SpringRunner +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +@RunWith(SpringRunner::class) +@SpringBootTest(classes = [(TestApplicationContext::class)]) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +class MultilimitOrerPreprocessorTest: AbstractTest() { + + @Autowired + private lateinit var messageBuilder: MessageBuilder + + @Test + fun testLimitMultiOrderWithUnknownAssetPair() { + //preprocessing is performed during message building + val messageWrapper = messageBuilder.buildMultiLimitOrderWrapper(pair = "UnknownAsset", + clientId = "Client1", + orders = listOf(IncomingLimitOrder(100.0, 1.2), + IncomingLimitOrder(100.0, 1.3)), + cancel = false) + + assertResponse(messageWrapper) + } + + @Test + fun testStopMultiOrderWithUnknownAssetPair() { + //preprocessing is performed during message building + val messageWrapper = messageBuilder.buildMultiLimitOrderWrapper(pair = "UnknownAsset", + + clientId = "Client1", + orders = listOf(IncomingLimitOrder(100.0, 1.2, type = LimitOrderType.STOP_LIMIT), + IncomingLimitOrder(100.0, 1.3, type = LimitOrderType.STOP_LIMIT)), + cancel = false) + + assertResponse(messageWrapper) + } + + private fun assertResponse(messageWrapper: MessageWrapper) { + val clientHandler = messageWrapper.clientHandler!! as TestClientHandler + assertEquals(1, clientHandler.responses.size) + + val response = clientHandler.responses.single() + assertTrue(response is ProtocolMessages.MultiLimitOrderResponse) + response as ProtocolMessages.MultiLimitOrderResponse + assertEquals(MessageStatus.UNKNOWN_ASSET.type, response.status) + + assertEquals(0, clientsEventsQueue.size) + assertEquals(0, trustedClientsEventsQueue.size) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/SingleLimitOrderPreprocessorTest.kt b/src/test/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/SingleLimitOrderPreprocessorTest.kt index 9968730a0..26ae2f9a8 100644 --- a/src/test/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/SingleLimitOrderPreprocessorTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/SingleLimitOrderPreprocessorTest.kt @@ -4,6 +4,7 @@ import com.lykke.matching.engine.AbstractTest import com.lykke.matching.engine.config.TestApplicationContext import com.lykke.matching.engine.daos.order.LimitOrderType import com.lykke.matching.engine.messages.MessageStatus +import com.lykke.matching.engine.messages.MessageWrapper import com.lykke.matching.engine.messages.ProtocolMessages import com.lykke.matching.engine.socket.TestClientHandler import com.lykke.matching.engine.utils.MessageBuilder @@ -21,17 +22,18 @@ import kotlin.test.assertTrue @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) class SingleLimitOrderPreprocessorTest: AbstractTest() { - @Autowired - private lateinit var singleLimitOrderPreprocessor: SingleLimitOrderPreprocessor - @Autowired private lateinit var messageBuilder: MessageBuilder @Test fun testOrderWithUnknownAssetPair() { + //preprocessing is performed during message building val messageWrapper = messageBuilder.buildLimitOrderWrapper(MessageBuilder.buildLimitOrder(assetId = "UnknownAssetPair")) - singleLimitOrderPreprocessor.preProcess(messageWrapper) + assertResponse(messageWrapper) + } + + fun assertResponse(messageWrapper: MessageWrapper) { val clientHandler = messageWrapper.clientHandler!! as TestClientHandler assertEquals(1, clientHandler.responses.size) @@ -47,16 +49,7 @@ class SingleLimitOrderPreprocessorTest: AbstractTest() { fun testStopOrderWithUnknownAssetPair() { val messageWrapper = messageBuilder.buildLimitOrderWrapper(MessageBuilder.buildLimitOrder(assetId = "UnknownAssetPair", type = LimitOrderType.STOP_LIMIT, lowerPrice = 1.0, lowerLimitPrice = 1.0)) - singleLimitOrderPreprocessor.preProcess(messageWrapper) - - val clientHandler = messageWrapper.clientHandler!! as TestClientHandler - assertEquals(1, clientHandler.responses.size) - val response = clientHandler.responses.single() - assertTrue(response is ProtocolMessages.NewResponse) - response as ProtocolMessages.NewResponse - assertEquals(MessageStatus.UNKNOWN_ASSET.type, response.status) - - assertEquals(0, clientsEventsQueue.size) + assertResponse(messageWrapper) } } \ No newline at end of file diff --git a/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt b/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt index 9224e5fb7..2ac8eecc0 100644 --- a/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt @@ -25,7 +25,11 @@ import com.lykke.matching.engine.holders.StopOrdersDatabaseAccessorsHolder import com.lykke.matching.engine.holders.TestUUIDHolder import com.lykke.matching.engine.incoming.parsers.impl.LimitOrderCancelOperationContextParser import com.lykke.matching.engine.incoming.parsers.impl.LimitOrderMassCancelOperationContextParser +import com.lykke.matching.engine.incoming.parsers.impl.MultilimitOrderContextParser +import com.lykke.matching.engine.incoming.preprocessor.impl.MultilimitOrderPreprocessor +import com.lykke.matching.engine.incoming.preprocessor.impl.SingleLimitOrderPreprocessor import com.lykke.matching.engine.matching.MatchingEngine +import com.lykke.matching.engine.messages.MessageWrapper import com.lykke.matching.engine.notification.BalanceUpdateHandlerTest import com.lykke.matching.engine.order.ExecutionDataApplyService import com.lykke.matching.engine.order.ExecutionPersistenceService @@ -49,9 +53,11 @@ import com.lykke.matching.engine.outgoing.senders.impl.SpecializedEventSendersHo import com.lykke.matching.engine.outgoing.senders.impl.OutgoingEventProcessorImpl import com.lykke.matching.engine.services.* import com.lykke.matching.engine.services.validators.business.impl.LimitOrderBusinessValidatorImpl +import com.lykke.matching.engine.services.validators.business.impl.OrderBusinessValidatorImpl import com.lykke.matching.engine.services.validators.business.impl.StopOrderBusinessValidatorImpl import com.lykke.matching.engine.services.validators.impl.MarketOrderValidatorImpl import com.lykke.matching.engine.services.validators.input.impl.LimitOrderInputValidatorImpl +import com.lykke.matching.engine.services.validators.input.impl.OrderInputValidatorImpl import com.lykke.matching.engine.utils.MessageBuilder import com.lykke.utils.logging.ThrottlingLogger import org.mockito.Mockito @@ -179,7 +185,9 @@ abstract class AbstractPerformanceTest { feeProcessor = FeeProcessor(assetsHolder, assetsPairsHolder, genericLimitOrderService) val messageSequenceNumberHolder = MessageSequenceNumberHolder(TestMessageSequenceNumberDatabaseAccessor()) - val limitOrderInputValidator = LimitOrderInputValidatorImpl(applicationSettingsHolder) + val orderInputValidator = OrderInputValidatorImpl(applicationSettingsHolder) + val orderBusinessValidator = OrderBusinessValidatorImpl() + val limitOrderInputValidator = LimitOrderInputValidatorImpl(applicationSettingsHolder, orderInputValidator) singleLimitOrderContextParser = SingleLimitOrderContextParser(assetsPairsHolder, assetsHolder, applicationSettingsHolder, @@ -188,11 +196,16 @@ abstract class AbstractPerformanceTest { cashInOutContextParser = CashInOutContextParser(assetsHolder, uuidHolder) cashTransferContextParser = CashTransferContextParser(assetsHolder, uuidHolder) - messageBuilder = MessageBuilder(singleLimitOrderContextParser, + messageBuilder = MessageBuilder(SingleLimitOrderPreprocessor(singleLimitOrderContextParser, LinkedBlockingQueue(), messageProcessingStatusHolder, ThrottlingLogger.getLogger("test")), cashInOutContextParser, cashTransferContextParser, LimitOrderCancelOperationContextParser(), - LimitOrderMassCancelOperationContextParser()) + LimitOrderMassCancelOperationContextParser(), + MultilimitOrderPreprocessor(messageProcessingStatusHolder, limitOrderInputValidator, + orderInputValidator, + MultilimitOrderContextParser(ThrottlingLogger.getLogger("test"), + applicationSettingsHolder, assetsPairsHolder, assetsHolder, uuidHolder), + LinkedBlockingQueue(), ThrottlingLogger.getLogger("test"))) genericStopLimitOrderService = GenericStopLimitOrderService(stopOrdersDatabaseAccessorsHolder, expiryOrdersQueue) @@ -217,14 +230,14 @@ abstract class AbstractPerformanceTest { val matchingEngine = MatchingEngine(genericLimitOrderService, feeProcessor, uuidHolder) - val limitOrderProcessor = LimitOrderProcessor(limitOrderInputValidator, - LimitOrderBusinessValidatorImpl(OrderBookMaxTotalSizeHolderImpl(null)), + val limitOrderProcessor = LimitOrderProcessor( + LimitOrderBusinessValidatorImpl(orderBusinessValidator, OrderBookMaxTotalSizeHolderImpl(null)), applicationSettingsHolder, matchingEngine, matchingResultHandlingHelper) - val stopOrderProcessor = StopLimitOrderProcessor(limitOrderInputValidator, - StopOrderBusinessValidatorImpl(OrderBookMaxTotalSizeHolderImpl(null)), + val stopOrderProcessor = StopLimitOrderProcessor( + StopOrderBusinessValidatorImpl(orderBusinessValidator, OrderBookMaxTotalSizeHolderImpl(null)), applicationSettingsHolder, limitOrderProcessor, uuidHolder) @@ -246,14 +259,9 @@ abstract class AbstractPerformanceTest { stopOrderBookProcessor, executionDataApplyService, previousLimitOrdersProcessor, - assetsHolder, - assetsPairsHolder, - balancesHolder, - applicationSettingsHolder, - messageProcessingStatusHolder, - uuidHolder) + balancesHolder) - val marketOrderValidator = MarketOrderValidatorImpl(assetsPairsHolder, assetsHolder, applicationSettingsHolder) + val marketOrderValidator = MarketOrderValidatorImpl(assetsPairsHolder, assetsHolder, applicationSettingsHolder, orderInputValidator) marketOrderService = MarketOrderService(matchingEngine, executionContextFactory, stopOrderBookProcessor, diff --git a/src/test/kotlin/com/lykke/matching/engine/performance/MultiLimitOrderServicePerformanceTest.kt b/src/test/kotlin/com/lykke/matching/engine/performance/MultiLimitOrderServicePerformanceTest.kt index cb84d95b2..41c28d657 100644 --- a/src/test/kotlin/com/lykke/matching/engine/performance/MultiLimitOrderServicePerformanceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/performance/MultiLimitOrderServicePerformanceTest.kt @@ -5,7 +5,6 @@ import com.lykke.matching.engine.daos.AssetPair import com.lykke.matching.engine.daos.IncomingLimitOrder import com.lykke.matching.engine.daos.setting.AvailableSettingGroup import com.lykke.matching.engine.utils.MessageBuilder -import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderWrapper import com.lykke.matching.engine.utils.PrintUtils import org.junit.Ignore import org.junit.Test @@ -56,7 +55,7 @@ class MultiLimitOrderServicePerformanceTest: AbstractPerformanceTest() { initServices() counter.executeAction { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(0.1, 2.0), IncomingLimitOrder(0.1, 1.5), IncomingLimitOrder(0.09, 1.3), @@ -74,7 +73,7 @@ class MultiLimitOrderServicePerformanceTest: AbstractPerformanceTest() { initServices() counter.executeAction { multiLimitOrderService.processMessage( - buildMultiLimitOrderWrapper(pair = "EURUSD", + messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.2), IncomingLimitOrder(100.0, 1.3)), @@ -88,13 +87,13 @@ class MultiLimitOrderServicePerformanceTest: AbstractPerformanceTest() { counter.executeAction { multiLimitOrderService - .processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.2), + .processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.2), IncomingLimitOrder(100.0, 1.3)), cancel = false)) } counter.executeAction { multiLimitOrderService - .processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.4), + .processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.4), IncomingLimitOrder(100.0, 1.5)), cancel = false)) } @@ -107,15 +106,15 @@ class MultiLimitOrderServicePerformanceTest: AbstractPerformanceTest() { initServices() counter.executeAction { multiLimitOrderService - .processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + .processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.2), IncomingLimitOrder(100.0, 1.3)), cancel = false))} counter.executeAction { multiLimitOrderService - .processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + .processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.4), IncomingLimitOrder(100.0, 1.5)), cancel = false))} counter.executeAction { multiLimitOrderService - .processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + .processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 2.0), IncomingLimitOrder(100.0, 2.1)), cancel = true))} return counter.getAverageTime() @@ -125,13 +124,13 @@ class MultiLimitOrderServicePerformanceTest: AbstractPerformanceTest() { val counter = ActionTimeCounter() initServices() - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.3), + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.3), IncomingLimitOrder(100.0, 1.2)), cancel = false)) } singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(MessageBuilder.buildLimitOrder(clientId = "Client2", price = 1.25, volume = -150.0))) - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(10.0, 1.3), IncomingLimitOrder(100.0, 1.26), IncomingLimitOrder(100.0, 1.2)), cancel = true)) } @@ -143,14 +142,14 @@ class MultiLimitOrderServicePerformanceTest: AbstractPerformanceTest() { val counter = ActionTimeCounter() initServices() - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(-100.0, 1.2), + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(-100.0, 1.2), IncomingLimitOrder(-100.0, 1.3)), cancel = false)) } singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(MessageBuilder.buildLimitOrder(clientId = "Client2", price = 1.25, volume = 150.0))) - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(-10.0, 1.2), IncomingLimitOrder(-10.0, 1.24), IncomingLimitOrder(-10.0, 1.29), @@ -168,15 +167,15 @@ class MultiLimitOrderServicePerformanceTest: AbstractPerformanceTest() { testBalanceHolderWrapper.updateBalance("Client5", "TIME", 1000.0) testBalanceHolderWrapper.updateBalance("Client2", "TIME", 1000.0) - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "TIMEUSD", clientId = "Client5", orders = + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "TIMEUSD", clientId = "Client5", orders = listOf(IncomingLimitOrder(-100.0, 26.955076)), cancel = false)) } - counter.executeAction {multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "TIMEUSD", clientId = "Client5", orders = + counter.executeAction {multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "TIMEUSD", clientId = "Client5", orders = listOf(IncomingLimitOrder(0.69031943, 26.915076)), cancel = false))} singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(MessageBuilder.buildLimitOrder(assetId = "TIMEUSD", clientId = "Client2", price = 26.88023, volume = -26.0))) - counter.executeAction {multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "TIMEUSD", clientId = "Client5", + counter.executeAction {multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "TIMEUSD", clientId = "Client5", orders = listOf(IncomingLimitOrder(10.0, 26.915076), IncomingLimitOrder(10.0, 26.875076)), cancel = true))} return counter.getAverageTime() @@ -192,22 +191,22 @@ class MultiLimitOrderServicePerformanceTest: AbstractPerformanceTest() { singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(MessageBuilder.buildLimitOrder(assetId = "BTCEUR", clientId = "Client2", price = 3629.355, volume = 0.19259621))) - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = listOf(IncomingLimitOrder(-0.00574996, 3628.707)), cancel = true)) } - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = listOf(IncomingLimitOrder(-0.01431186, 3624.794), IncomingLimitOrder(-0.02956591, 3626.591)), cancel = true))} - counter.executeAction {multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = + counter.executeAction {multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = listOf(IncomingLimitOrder(-0.04996673, 3625.855)), cancel = true))} - counter.executeAction {multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", + counter.executeAction {multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = listOf(IncomingLimitOrder(-0.00628173, 3622.865), IncomingLimitOrder(-0.01280207, 3625.489), IncomingLimitOrder(-0.02201331, 3627.41), IncomingLimitOrder(-0.02628901, 3629.139)), cancel = true))} - counter.executeAction {multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = + counter.executeAction {multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = listOf(IncomingLimitOrder(-0.01708411, 3626.11)), cancel = true))} - counter.executeAction {multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = + counter.executeAction {multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = listOf(IncomingLimitOrder(-0.00959341, 3625.302)), cancel = true))} return counter.getAverageTime() @@ -228,12 +227,12 @@ class MultiLimitOrderServicePerformanceTest: AbstractPerformanceTest() { singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(MessageBuilder.buildLimitOrder(clientId = "Client2", assetId = "BTCCHF", uid = "1", price = 4384.15, volume = -0.26070853))) - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCCHF", clientId = "Client3", orders = + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCCHF", clientId = "Client3", orders = listOf(IncomingLimitOrder(0.00643271, 4390.84), IncomingLimitOrder(0.01359005, 4387.87), IncomingLimitOrder(0.02033985, 4384.811)), cancel = true)) } - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCCHF", clientId = "Client3", + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCCHF", clientId = "Client3", orders = listOf(IncomingLimitOrder(0.01691068, 4387.21)), cancel = true))} return counter.getAverageTime() @@ -252,7 +251,7 @@ class MultiLimitOrderServicePerformanceTest: AbstractPerformanceTest() { primaryOrdersDatabaseAccessor.addLimitOrder(MessageBuilder.buildLimitOrder(clientId = client, assetId = "BTCEUR", price = 4722.0, volume = 0.14825226)) initServices() - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = marketMaker, orders = + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = marketMaker, orders = listOf(IncomingLimitOrder(-0.4435, 4721.403)), cancel = true)) } return counter.getAverageTime() @@ -273,7 +272,7 @@ class MultiLimitOrderServicePerformanceTest: AbstractPerformanceTest() { initServices() - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(clientId = marketMaker, pair = "EURUSD", + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(clientId = marketMaker, pair = "EURUSD", orders = listOf(IncomingLimitOrder(-2.0, 1.1)), cancel = false)) } return counter.getAverageTime() @@ -282,10 +281,10 @@ class MultiLimitOrderServicePerformanceTest: AbstractPerformanceTest() { fun testCancelPreviousOrderWithSameUid(): Double { val counter = ActionTimeCounter() - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(-9.0, 0.4875, uid = "order1")), cancel = true)) } - counter.executeAction { multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", + counter.executeAction { multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(-10.0, 0.4880, uid = "order1")), cancel = true)) } return counter.getAverageTime() diff --git a/src/test/kotlin/com/lykke/matching/engine/services/ClientMultiLimitOrderTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/ClientMultiLimitOrderTest.kt index fd4f9db1f..53300b4f0 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/ClientMultiLimitOrderTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/ClientMultiLimitOrderTest.kt @@ -21,7 +21,6 @@ import com.lykke.matching.engine.outgoing.messages.v2.events.ExecutionEvent import com.lykke.matching.engine.utils.MessageBuilder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildLimitOrder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildLimitOrderFeeInstructions -import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderWrapper import com.lykke.matching.engine.utils.assertEquals import com.lykke.matching.engine.utils.getSetting import org.junit.Before @@ -79,22 +78,9 @@ class ClientMultiLimitOrderTest : AbstractTest() { initServices() } - @Test - fun testUnknownAssetPair() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("UnknownAssetPair", "Client1", - listOf(IncomingLimitOrder(-0.1, 10000.0), - IncomingLimitOrder(-0.1, 11000.0), - IncomingLimitOrder(0.1, 9000.0), - IncomingLimitOrder(0.1, 8000.0)))) - assertEquals(0, clientsEventsQueue.size) - assertEquals(0, trustedClientsEventsQueue.size) - assertOrderBookSize("UnknownAssetPair", false, 0) - assertOrderBookSize("UnknownAssetPair", true, 0) - } - @Test fun testAdd() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(-0.1, 10000.0, "1"), IncomingLimitOrder(-0.2, 10500.0, "2"), @@ -146,7 +132,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { @Test fun testAddOneSide() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(-0.1, 10000.0), IncomingLimitOrder(-0.2, 10500.0) @@ -192,7 +178,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { clearMessageQueues() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(-0.1, 10000.0), IncomingLimitOrder(-0.2, 10500.0), @@ -252,7 +238,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { clearMessageQueues() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(-0.1, 10000.0), IncomingLimitOrder(-0.2, 10500.0), @@ -289,7 +275,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { @Test fun testAddNotEnoughFundsOrder() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(-0.1, 10000.0, "1"), IncomingLimitOrder(-0.2, 10500.0, "2"), @@ -345,7 +331,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "TrustedClient", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "TrustedClient", listOf( IncomingLimitOrder(-0.3, 10800.0, "3"), IncomingLimitOrder(-0.4, 10900.0, "2"), IncomingLimitOrder(0.1, 9500.0, "6"), @@ -357,7 +343,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { fees = buildLimitOrderFeeInstructions(FeeType.CLIENT_FEE, makerSize = 0.05, targetClientId = "TargetClient", assetIds = listOf("BTC")) ))) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client2", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client2", listOf( IncomingLimitOrder(-0.1, 10000.0, "5"), IncomingLimitOrder(-0.5, 11000.0, "1"), IncomingLimitOrder(0.3, 9000.0, "8"), @@ -366,7 +352,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { clearMessageQueues() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(-0.1, 11500.0, "14"), IncomingLimitOrder(0.05, 11000.0, "12"), IncomingLimitOrder(0.2, 10800.0, "13"), @@ -442,7 +428,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { @Test fun testNegativeSpread() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(-0.1, 10000.0), IncomingLimitOrder(0.1, 10100.0) ))) @@ -468,7 +454,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(buildLimitOrder(clientId = "Client2", assetId = "BTCUSD", volume = -0.3, price = 9500.0))) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(0.1, 9000.0), IncomingLimitOrder(0.1, 8000.0), IncomingLimitOrder(0.1, 7000.0) @@ -476,7 +462,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { clearMessageQueues() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(0.1, 10000.0), IncomingLimitOrder(0.01, 9500.0), IncomingLimitOrder(0.1, 9000.0), @@ -500,7 +486,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { } private fun setOrder() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(-0.4, 9200.0), IncomingLimitOrder(-0.3, 9100.0), IncomingLimitOrder(-0.2, 9000.0), @@ -514,7 +500,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { fun testEmptyOrderWithCancelPreviousBothSides() { setOrder() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", orders = emptyList(), + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", orders = emptyList(), cancel = true, cancelMode = OrderCancelMode.BOTH_SIDES)) assertOrderBookSize("BTCUSD", true, 0) @@ -537,7 +523,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { fun testOneSideOrderWithCancelPreviousBothSides() { setOrder() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf(IncomingLimitOrder(-0.4, 9100.0, "1"), IncomingLimitOrder(-0.3, 9000.0, "2")), cancel = true, cancelMode = OrderCancelMode.BOTH_SIDES)) @@ -557,7 +543,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { fun testBothSidesOrderWithCancelPreviousOneSide() { setOrder() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf(IncomingLimitOrder(-0.01, 9100.0, "1"), IncomingLimitOrder(-0.009, 9000.0, "2"), IncomingLimitOrder(0.2, 7900.0, "3")), @@ -581,7 +567,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { testOrderBookWrapper.addLimitOrder(buildLimitOrder(uid = "ClientOrder", clientId = "Client2", assetId = "BTCUSD", volume = -0.1, price = 8000.0)) initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(-0.4, 9300.0, "Ask-ToReplace-2"), IncomingLimitOrder(-0.3, 9200.0, "Ask-ToReplace-1"), IncomingLimitOrder(-0.2, 9100.0, "Ask-ToCancel-2"), @@ -592,7 +578,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { ))) clearMessageQueues() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(-0.2, 9400.0, "NotFoundPrevious-1", oldUid = "NotExist-1"), IncomingLimitOrder(-0.2, 9300.0, "ask2", oldUid = "Ask-ToReplace-2"), IncomingLimitOrder(-0.3, 9200.0, "ask3", oldUid = "Ask-ToReplace-1"), @@ -682,7 +668,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { @Test fun testAddLimitOrderWithSameReserveSum() { //Do not send balance update if balances didn't change - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", "Client2", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client2", listOf( IncomingLimitOrder(100.0, 1.2, "1"), IncomingLimitOrder(100.0, 1.3, "2") ))) @@ -705,7 +691,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { assertEquals(1, event.balanceUpdates?.size) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", "Client2", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client2", listOf( IncomingLimitOrder(100.0, 1.2, "3", oldUid = "1"), IncomingLimitOrder(100.0, 1.3, "4", oldUid = "2") ))) @@ -732,7 +718,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { testOrderBookWrapper.addLimitOrder(buildLimitOrder(uid = "orderWithAnotherClient", assetId = "BTCUSD", clientId = "Client2", volume = 1.0, price = 1.0)) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCUSD", clientId = "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(oldUid = "orderWithAnotherPair", volume = 1.1, price = 1.0), IncomingLimitOrder(oldUid = "orderWithAnotherClient", volume = 1.1, price = 1.0)), cancel = false)) @@ -792,7 +778,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(clientId = "Client4", pair = "BTCUSD", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(clientId = "Client4", pair = "BTCUSD", orders = listOf(IncomingLimitOrder(volume = 2.0, price = -4.0, uid = "IncomingInvalidPrice"), IncomingLimitOrder(volume = 2.0, type = LimitOrderType.STOP_LIMIT, upperLimitPrice = 206.0, upperPrice = 210.0, uid = "Incoming-1", oldUid = "ToReplace"), IncomingLimitOrder(volume = 0.5, price = 220.0, uid = "Incoming-2")), cancel = true, cancelMode = OrderCancelMode.SELL_SIDE)) @@ -920,7 +906,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { testOrderBookWrapper.addLimitOrder(buildLimitOrder(clientId = "TrustedClient", assetId = "EURUSD", volume = -9.0, price = 1.1)) testOrderBookWrapper.addLimitOrder(buildLimitOrder(clientId = "Client1", assetId = "EURUSD", volume = -5.0, price = 1.2)) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", "Client2", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client2", listOf(IncomingLimitOrder(volume = 1.0, price = 1.4, uid = "matched1"), IncomingLimitOrder(volume = 3.0, price = 1.3, uid = "matched2"), IncomingLimitOrder(volume = 5.0, price = 1.2, uid = "rejectedAfterMatching", @@ -976,7 +962,7 @@ class ClientMultiLimitOrderTest : AbstractTest() { testOrderBookWrapper.addLimitOrder(buildLimitOrder(clientId = "Client1", assetId = "EURUSD", volume = -5.0, price = 1.2)) testOrderBookWrapper.addLimitOrder(buildLimitOrder(clientId = "Client1", assetId = "EURUSD", volume = -3.0, price = 1.4)) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", "Client2", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client2", listOf(IncomingLimitOrder(volume = 1.0, price = 1.4), IncomingLimitOrder(volume = 3.0, price = 1.3), IncomingLimitOrder(volume = 5.0, price = 1.2)))) diff --git a/src/test/kotlin/com/lykke/matching/engine/services/InvalidBalanceTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/InvalidBalanceTest.kt index e127745f5..28fd6df1b 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/InvalidBalanceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/InvalidBalanceTest.kt @@ -19,7 +19,6 @@ import com.lykke.matching.engine.utils.MessageBuilder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildLimitOrder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMarketOrder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMarketOrderWrapper -import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderWrapper import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -219,7 +218,7 @@ class InvalidBalanceTest : AbstractTest() { applicationSettingsCache.createOrUpdateSettingValue(AvailableSettingGroup.TRUSTED_CLIENTS, "Client1", "Client1", true) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("ETHUSD", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("ETHUSD", "Client1", listOf( IncomingLimitOrder(-0.1, 1000.0, "1"), IncomingLimitOrder(-0.05, 1010.0, "2"), IncomingLimitOrder(-0.1, 1100.0, "3") @@ -265,7 +264,7 @@ class InvalidBalanceTest : AbstractTest() { initServices() applicationSettingsCache.createOrUpdateSettingValue(AvailableSettingGroup.TRUSTED_CLIENTS, "Client1", "Client1", true) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("ETHUSD", "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("ETHUSD", "Client1", listOf(IncomingLimitOrder(-0.05, 1010.0, "1")))) testBalanceHolderWrapper.updateBalance("Client1", "ETH", 0.04) testSettingDatabaseAccessor.clear() diff --git a/src/test/kotlin/com/lykke/matching/engine/services/LimitOrderMassCancelServiceTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/LimitOrderMassCancelServiceTest.kt index c6e02012d..9d72f72f3 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/LimitOrderMassCancelServiceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/LimitOrderMassCancelServiceTest.kt @@ -18,7 +18,6 @@ import com.lykke.matching.engine.outgoing.messages.LimitOrdersReport import com.lykke.matching.engine.outgoing.messages.v2.events.ExecutionEvent import com.lykke.matching.engine.utils.MessageBuilder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildLimitOrder -import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderWrapper import com.lykke.matching.engine.utils.assertEquals import com.lykke.matching.engine.utils.getSetting import org.junit.Before @@ -95,14 +94,13 @@ class LimitOrderMassCancelServiceTest : AbstractTest() { lowerLimitPrice = 101.0, lowerPrice = 100.0))) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", "TrustedClient", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "TrustedClient", listOf( IncomingLimitOrder(-5.0, 1.3, "m1"), IncomingLimitOrder(5.0, 1.1, "m2") ))) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "TrustedClient", listOf( - IncomingLimitOrder(-1.0, 8500.0, "m3") - ))) + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "TrustedClient", listOf( + IncomingLimitOrder(-1.0, 8500.0, "m3")))) assertOrderBookSize("BTCUSD", false, 3) assertOrderBookSize("BTCUSD", true, 1) diff --git a/src/test/kotlin/com/lykke/matching/engine/services/MinRemainingVolumeTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/MinRemainingVolumeTest.kt index c421e9ab8..ccf833ff6 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/MinRemainingVolumeTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/MinRemainingVolumeTest.kt @@ -16,7 +16,6 @@ import com.lykke.matching.engine.utils.MessageBuilder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildLimitOrder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMarketOrder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMarketOrderWrapper -import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderWrapper import com.lykke.matching.engine.utils.getSetting import org.junit.Before import org.junit.Test @@ -165,7 +164,7 @@ class MinRemainingVolumeTest : AbstractTest() { testBalanceHolderWrapper.updateBalance("TrustedClient", "USD", 1800.0) initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "TrustedClient", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "TrustedClient", listOf( IncomingLimitOrder(0.11, 9000.0), IncomingLimitOrder(0.0891, 8900.0)))) @@ -193,7 +192,7 @@ class MinRemainingVolumeTest : AbstractTest() { singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(buildLimitOrder(clientId = "Client1", assetId = "BTCUSD", volume = 0.1, price = 6900.0))) clearMessageQueues() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "TrustedClient", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "TrustedClient", listOf( IncomingLimitOrder(-0.11, 6800.0, "order1"), IncomingLimitOrder(-0.0909, 6900.0, "order2")))) diff --git a/src/test/kotlin/com/lykke/matching/engine/services/MultiLimitOrderServiceTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/MultiLimitOrderServiceTest.kt index 6782f05b7..333cdef88 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/MultiLimitOrderServiceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/MultiLimitOrderServiceTest.kt @@ -17,7 +17,6 @@ import com.lykke.matching.engine.outgoing.messages.v2.events.ExecutionEvent import com.lykke.matching.engine.utils.MessageBuilder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildLimitOrder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderCancelWrapper -import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderWrapper import com.lykke.matching.engine.utils.NumberUtils import com.lykke.matching.engine.utils.assertEquals import com.lykke.matching.engine.utils.balance.ReservedVolumesRecalculator @@ -28,7 +27,6 @@ import org.junit.runner.RunWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.context.TestConfiguration -import org.springframework.context.ApplicationEventPublisher import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Primary import org.springframework.test.annotation.DirtiesContext @@ -43,7 +41,6 @@ import com.lykke.matching.engine.outgoing.messages.v2.enums.OrderStatus as Outgo @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) class MultiLimitOrderServiceTest: AbstractTest() { - @TestConfiguration open class Config { @Bean @@ -105,7 +102,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf( IncomingLimitOrder(0.1, 2.0), IncomingLimitOrder(0.1, 1.5), @@ -137,7 +134,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { @Test fun testAddLimitOrder() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.2), IncomingLimitOrder(100.0, 1.3)))) assertEquals(BigDecimal.valueOf(1000.0), testWalletDatabaseAccessor.getBalance("Client1", "USD")) @@ -164,7 +161,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { @Test fun testAdd2LimitOrder() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.2), IncomingLimitOrder(100.0, 1.3)))) assertEquals(BigDecimal.valueOf(1000.0), testWalletDatabaseAccessor.getBalance("Client1", "USD")) @@ -183,7 +180,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals("1.3", event.orders[1].price) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.4), IncomingLimitOrder(100.0, 1.5)), cancel = false)) @@ -202,7 +199,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { @Test fun testAddAndCancelLimitOrder() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.2), IncomingLimitOrder(100.0, 1.3)))) assertEquals(BigDecimal.valueOf(1000.0), testWalletDatabaseAccessor.getBalance("Client1", "USD")) @@ -221,7 +218,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals("1.2", event.orders[0].price) assertEquals("1.3", event.orders[1].price) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.4), IncomingLimitOrder(100.0, 1.5)), cancel = false)) @@ -238,7 +235,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals("1.4", event.orders[0].price) assertEquals("1.5", event.orders[1].price) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 2.0), IncomingLimitOrder(100.0, 2.1)), cancel = true)) assertEquals(1, testTrustedClientsLimitOrderListener.getCount()) @@ -265,7 +262,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { @Test fun testAddAndMatchLimitOrder() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(100.0, 1.3), IncomingLimitOrder(100.0, 1.2)))) assertEquals(1, testTrustedClientsLimitOrderListener.getCount()) @@ -296,7 +293,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals(BigDecimal.valueOf(50.0), testWalletDatabaseAccessor.getReservedBalance("Client2", "EUR")) assertOrderBookSize("EURUSD", true, 1) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(10.0, 1.3), IncomingLimitOrder(100.0, 1.26), IncomingLimitOrder(100.0, 1.2)), cancel = true)) @@ -338,7 +335,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { @Test fun testAddAndMatchLimitOrder2() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(-100.0, 1.2), IncomingLimitOrder(-100.0, 1.3)))) assertEquals(1, testTrustedClientsLimitOrderListener.getCount()) @@ -369,7 +366,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals(BigDecimal.valueOf(1100.0), testWalletDatabaseAccessor.getBalance("Client2", "EUR")) assertEquals(BigDecimal.valueOf(62.5), testWalletDatabaseAccessor.getReservedBalance("Client2", "USD")) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(-10.0, 1.2), IncomingLimitOrder(-10.0, 1.24), IncomingLimitOrder(-10.0, 1.29), @@ -421,9 +418,9 @@ class MultiLimitOrderServiceTest: AbstractTest() { initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "TIMEUSD", clientId = "Client5", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "TIMEUSD", clientId = "Client5", orders = listOf(IncomingLimitOrder(-100.0, 26.955076)))) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "TIMEUSD", clientId = "Client5", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "TIMEUSD", clientId = "Client5", orders = listOf(IncomingLimitOrder(0.69031943, 26.915076)))) assertEquals(2, testTrustedClientsLimitOrderListener.getCount()) @@ -468,7 +465,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals(BigDecimal.valueOf(999.30968057), testWalletDatabaseAccessor.getBalance("Client2", "TIME")) assertEquals(BigDecimal.valueOf(25.30968057), testWalletDatabaseAccessor.getReservedBalance("Client2", "TIME")) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "TIMEUSD", clientId = "Client5", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "TIMEUSD", clientId = "Client5", orders = listOf(IncomingLimitOrder(10.0, 26.915076), IncomingLimitOrder(10.0, 26.875076)), cancel = true)) assertEquals(0, testClientLimitOrderListener.getCount()) @@ -506,7 +503,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals(OutgoingOrderStatus.PLACED, event.orders[0].status) assertEquals("0.19259621", event.orders[0].remainingVolume) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = listOf(IncomingLimitOrder(-0.00574996, 3628.707)), cancel = true)) result = testClientLimitOrderListener.getQueue().poll() as LimitOrdersReport assertEquals(OrderStatus.Matched.name, result.orders[0].order.status) @@ -520,7 +517,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals(OutgoingOrderStatus.PARTIALLY_MATCHED, event.orders[1].status) assertEquals("0.18684625", event.orders[1].remainingVolume) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = listOf(IncomingLimitOrder(-0.01431186, 3624.794), IncomingLimitOrder(-0.02956591, 3626.591)), cancel = true)) result = testClientLimitOrderListener.getQueue().poll() as LimitOrdersReport @@ -537,7 +534,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals("0.14296848", event.orders[1].remainingVolume) assertEquals(OutgoingOrderStatus.MATCHED, event.orders[2].status) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = listOf(IncomingLimitOrder(-0.04996673, 3625.855)), cancel = true)) result = testClientLimitOrderListener.getQueue().poll() as LimitOrdersReport assertEquals(OrderStatus.Matched.name, result.orders[0].order.status) @@ -551,7 +548,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals(OutgoingOrderStatus.PARTIALLY_MATCHED, event.orders[1].status) assertEquals("0.09300175", event.orders[1].remainingVolume) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = listOf(IncomingLimitOrder(-0.00628173, 3622.865), IncomingLimitOrder(-0.01280207, 3625.489), IncomingLimitOrder(-0.02201331, 3627.41), @@ -574,7 +571,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals(OutgoingOrderStatus.MATCHED, event.orders[3].status) assertEquals(OutgoingOrderStatus.MATCHED, event.orders[4].status) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = listOf(IncomingLimitOrder(-0.01708411, 3626.11)), cancel = true)) result = testClientLimitOrderListener.getQueue().poll() as LimitOrdersReport assertEquals(OrderStatus.Matched.name, result.orders[0].order.status) @@ -588,7 +585,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals(OutgoingOrderStatus.PARTIALLY_MATCHED, event.orders[1].status) assertEquals("0.00853152", event.orders[1].remainingVolume) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = "Client5", orders = listOf(IncomingLimitOrder(-0.00959341, 3625.302)), cancel = true)) result = testClientLimitOrderListener.getQueue().poll() as LimitOrdersReport assertEquals(OrderStatus.Processing.name, result.orders[0].order.status) @@ -634,7 +631,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { var event = clientsEventsQueue.poll() as ExecutionEvent assertEquals(OutgoingOrderStatus.PLACED, event.orders[0].status) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCCHF", clientId = "Client3", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCCHF", clientId = "Client3", orders = listOf(IncomingLimitOrder(0.00643271, 4390.84), IncomingLimitOrder(0.01359005, 4387.87), IncomingLimitOrder(0.02033985, 4384.811)), cancel = true)) @@ -654,7 +651,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { assertEquals(OutgoingOrderStatus.MATCHED, event.orders[2].status) assertEquals(OutgoingOrderStatus.MATCHED, event.orders[3].status) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCCHF", clientId = "Client3", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCCHF", clientId = "Client3", orders = listOf(IncomingLimitOrder(0.01691068, 4387.21)), cancel = true)) result = testClientLimitOrderListener.getQueue().poll() as LimitOrdersReport assertEquals(OrderStatus.Matched.name, result.orders[0].order.status) @@ -692,7 +689,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { var event = clientsEventsQueue.poll() as ExecutionEvent assertEquals(OutgoingOrderStatus.PLACED, event.orders[0].status) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCCHF", clientId = "Client3", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCCHF", clientId = "Client3", orders = listOf(IncomingLimitOrder(0.00643271, 4390.84), IncomingLimitOrder(0.01359005, 4387.87), IncomingLimitOrder(0.02033985, 4384.811)), cancel = true)) @@ -726,7 +723,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { testOrderBookWrapper.addLimitOrder(buildLimitOrder(clientId = client, assetId = "BTCEUR", price = 4722.0, volume = 0.14825226)) initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = marketMaker, orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "BTCEUR", clientId = marketMaker, orders = listOf(IncomingLimitOrder(-0.4435, 4721.403)), cancel = true)) assertEquals(1, testClientLimitOrderListener.getCount()) @@ -756,7 +753,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(buildLimitOrder(clientId = client, assetId = "EURUSD", price = 1.2, volume = -50.0))) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper( pair = "EURUSD", clientId = marketMaker, orders = listOf( @@ -788,7 +785,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper( clientId = marketMaker, pair = "EURUSD", orders = listOf( IncomingLimitOrder(2.0, 1.20), @@ -844,7 +841,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(clientId = marketMaker, pair = "EURUSD", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(clientId = marketMaker, pair = "EURUSD", orders = listOf(IncomingLimitOrder(-2.0, 1.1)), cancel = false)) assertEquals(0, testOrderDatabaseAccessor.getOrders("EURUSD", true).size) @@ -882,12 +879,12 @@ class MultiLimitOrderServiceTest: AbstractTest() { @Test fun testCancelPreviousOrderWithSameUid() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(-9.0, 0.4875, uid = "orders")), cancel = true)) clearMessageQueues() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(pair = "EURUSD", clientId = "Client1", orders = listOf(IncomingLimitOrder(-10.0, 0.4880, uid = "order1")), cancel = true)) @@ -925,7 +922,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { testBalanceHolderWrapper.updateBalance("Client1", "EUR", 3000.0) initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCEUR", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCEUR", "Client1", listOf( IncomingLimitOrder(-0.4, 9200.0), IncomingLimitOrder(-0.3, 9100.0), IncomingLimitOrder(-0.2, 9000.0), @@ -939,7 +936,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { fun testEmptyOrderWithCancelPreviousBothSides() { setOrder() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCEUR", "Client1", orders = emptyList(), + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCEUR", "Client1", orders = emptyList(), cancel = true, cancelMode = OrderCancelMode.BOTH_SIDES)) assertOrderBookSize("BTCEUR", true, 0) @@ -960,7 +957,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { fun testOneSideOrderWithCancelPreviousBothSides() { setOrder() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCEUR", "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCEUR", "Client1", listOf(IncomingLimitOrder(-0.4, 9100.0, "1"), IncomingLimitOrder(-0.3, 9000.0, "2")), cancel = true, cancelMode = OrderCancelMode.BOTH_SIDES)) @@ -980,7 +977,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { fun testBothSidesOrderWithCancelPreviousOneSide() { setOrder() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCEUR", "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCEUR", "Client1", listOf(IncomingLimitOrder(-0.01, 9100.0, "1"), IncomingLimitOrder(-0.009, 9000.0, "2"), IncomingLimitOrder(0.2, 7900.0, "3")), @@ -1007,7 +1004,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { testOrderBookWrapper.addLimitOrder(buildLimitOrder(uid = "ClientOrder", clientId = "Client2", assetId = "BTCEUR", volume = -0.1, price = 8000.0)) initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCEUR", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCEUR", "Client1", listOf( IncomingLimitOrder(-0.4, 9300.0, "Ask-ToReplace-2"), IncomingLimitOrder(-0.3, 9200.0, "Ask-ToReplace-1"), IncomingLimitOrder(-0.2, 9100.0, "Ask-ToCancel-2"), @@ -1018,7 +1015,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { ))) clearMessageQueues() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCEUR", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCEUR", "Client1", listOf( IncomingLimitOrder(-0.2, 9400.0, "NotFoundPrevious-1", oldUid = "NotExist-1"), IncomingLimitOrder(-0.2, 9300.0, "ask2", oldUid = "Ask-ToReplace-2"), IncomingLimitOrder(-0.3, 9200.0, "ask3", oldUid = "Ask-ToReplace-1"), @@ -1097,13 +1094,13 @@ class MultiLimitOrderServiceTest: AbstractTest() { @Test fun testReplaceOrderWithNotEnoughFunds() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client1", listOf( IncomingLimitOrder(-100.0, 1.2, "0"), IncomingLimitOrder(-400.0, 1.3, "1"), IncomingLimitOrder(-400.0, 1.4, "2") ), cancel = false)) clearMessageQueues() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client1", listOf( IncomingLimitOrder(-700.0, 1.3, "3", oldUid = "1"), IncomingLimitOrder(-400.0, 1.5, "4", oldUid = "2") ), cancel = false)) @@ -1140,7 +1137,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client1", listOf(IncomingLimitOrder(10.0, 1.3, "1")))) @@ -1222,7 +1219,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { order10, order9) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client1", orders)) } @@ -1251,7 +1248,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { @Test fun testRejectRoundingOrdersWithNotEnoughFunds() { testBalanceHolderWrapper.updateBalance("Client1", "EUR", 50.02) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCEUR", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCEUR", "Client1", listOf(IncomingLimitOrder(0.005, 5003.0, "1"),//25.015 IncomingLimitOrder(0.005, 5001.0, "2")))) //25.005 @@ -1278,7 +1275,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(buildLimitOrder(assetId = "BTCUSD", price = 4999.0, volume = 0.01, clientId = "Client3"))) clearMessageQueues() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf( IncomingLimitOrder(-0.01000199, 4998.0, "order1"), IncomingLimitOrder(-0.01, 4999.0, "order2") ))) @@ -1322,7 +1319,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { maxValue = BigDecimal.valueOf(10000.0))) assetPairsCache.update() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf(IncomingLimitOrder(-1.1, 10000.0)))) + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf(IncomingLimitOrder(-1.1, 10000.0)))) assertOrderBookSize("BTCUSD", false, 0) } @@ -1334,7 +1331,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { maxVolume = BigDecimal.valueOf(1.0))) assetPairsCache.update() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf(IncomingLimitOrder(-1.1, 10000.0)))) + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client1", listOf(IncomingLimitOrder(-1.1, 10000.0)))) assertOrderBookSize("BTCUSD", false, 0) } @@ -1374,7 +1371,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { volume = -10.0, price = 10.0)) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(clientId = "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(clientId = "Client1", pair = "EURUSD", orders = listOf(IncomingLimitOrder(6.0, 11.0, uid = "Matched", timeInForce = OrderTimeInForce.IOC), IncomingLimitOrder(6.0, 10.0, uid = "PartiallyMatched", timeInForce = OrderTimeInForce.IOC), @@ -1408,7 +1405,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { volume = -10.0, price = 10.0)) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(clientId = "Client1", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(clientId = "Client1", pair = "EURUSD", orders = listOf(IncomingLimitOrder(6.0, 11.0, uid = "Matched", timeInForce = OrderTimeInForce.FOK), IncomingLimitOrder(6.0, 10.0, uid = "PartiallyMatched", timeInForce = OrderTimeInForce.FOK), diff --git a/src/test/kotlin/com/lykke/matching/engine/services/NegativePriceTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/NegativePriceTest.kt index 40747e8a1..6b9b07b51 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/NegativePriceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/NegativePriceTest.kt @@ -11,7 +11,6 @@ import com.lykke.matching.engine.order.OrderStatus import com.lykke.matching.engine.outgoing.messages.LimitOrdersReport import com.lykke.matching.engine.utils.MessageBuilder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildLimitOrder -import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderWrapper import com.lykke.matching.engine.utils.getSetting import org.junit.Before import org.junit.Test @@ -77,7 +76,7 @@ class NegativePriceTest : AbstractTest() { initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client", listOf( IncomingLimitOrder(1.0, 1.0, uid = "order1"), diff --git a/src/test/kotlin/com/lykke/matching/engine/services/OrderBookMaxSizeTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/OrderBookMaxSizeTest.kt index a1da0af2b..e0de769ba 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/OrderBookMaxSizeTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/OrderBookMaxSizeTest.kt @@ -18,7 +18,6 @@ import com.lykke.matching.engine.utils.MessageBuilder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildLimitOrder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMarketOrder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMarketOrderWrapper -import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderWrapper import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -140,7 +139,7 @@ class OrderBookMaxSizeTest : AbstractTest() { fun testMultiLimitOrder() { setMaxSizeOrderBook() - val messageWrapper = buildMultiLimitOrderWrapper( + val messageWrapper = messageBuilder.buildMultiLimitOrderWrapper( "EURUSD", "Client1", listOf(IncomingLimitOrder(-200.0, 3.0, "order1"), IncomingLimitOrder(-200.0, 3.1, uid = "order2"))) multiLimitOrderService.processMessage(messageWrapper) diff --git a/src/test/kotlin/com/lykke/matching/engine/services/PersistenceErrorTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/PersistenceErrorTest.kt index de74331d8..24f3b4e35 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/PersistenceErrorTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/PersistenceErrorTest.kt @@ -14,7 +14,6 @@ import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildLimitOrder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMarketOrder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMarketOrderWrapper import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderCancelWrapper -import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderWrapper import com.lykke.matching.engine.utils.getSetting import org.junit.After import org.junit.Before @@ -79,7 +78,7 @@ class PersistenceErrorTest : AbstractTest() { clientId = "Client1", assetId = "EURUSD", volume = 1.0, price = 2.0, uid = "order1" ))) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", "TrustedClient", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "TrustedClient", listOf(IncomingLimitOrder(-1.0, 3.0, "order2"), IncomingLimitOrder(-2.0, 3.1, "order3"), IncomingLimitOrder(-3.0, 3.2, "order4"), @@ -272,7 +271,7 @@ class PersistenceErrorTest : AbstractTest() { @Test fun testTrustedClientMultiLimitOrder() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper( "EURUSD", "TrustedClient", listOf(IncomingLimitOrder(-1.0, 3.1), IncomingLimitOrder(-2.0, 3.19), @@ -285,7 +284,7 @@ class PersistenceErrorTest : AbstractTest() { @Test fun testClientMultiLimitOrder() { - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper( "EURUSD", "Client3", listOf(IncomingLimitOrder(-1.0, 3.1), IncomingLimitOrder(-2.0, 3.19), @@ -293,7 +292,7 @@ class PersistenceErrorTest : AbstractTest() { assertMultiLimitOrderResult() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper( "EURUSD", "Client3", listOf(IncomingLimitOrder(-0.04, 5.1), IncomingLimitOrder(-2.0, 5.2), diff --git a/src/test/kotlin/com/lykke/matching/engine/services/StopLimitOrderTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/StopLimitOrderTest.kt index ebaecfc79..f3d59deaa 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/StopLimitOrderTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/StopLimitOrderTest.kt @@ -22,7 +22,6 @@ import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildLimitOrder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMarketOrder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMarketOrderWrapper import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderCancelWrapper -import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderWrapper import com.lykke.matching.engine.utils.assertEquals import com.lykke.matching.engine.utils.getSetting import org.junit.Before @@ -465,7 +464,7 @@ class StopLimitOrderTest : AbstractTest() { singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(buildLimitOrder(clientId = "Client2", assetId = "BTCUSD", volume = -0.2, price = 10000.0))) clearMessageQueues() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client3", listOf(IncomingLimitOrder(-0.1, 11000.0), IncomingLimitOrder(-0.05, 8500.0)))) @@ -555,7 +554,7 @@ class StopLimitOrderTest : AbstractTest() { type = LimitOrderType.STOP_LIMIT, upperLimitPrice = 10000.0, upperPrice = 10500.0 ))) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client2", listOf(IncomingLimitOrder(-0.1, 9000.0), IncomingLimitOrder(-0.2, 10000.0)))) @@ -650,11 +649,11 @@ class StopLimitOrderTest : AbstractTest() { testDictionariesDatabaseAccessor.addAssetPair(AssetPair("EURUSD", "EUR", "USD", 2)) initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", "Client2", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client2", listOf( IncomingLimitOrder(-0.00009, 10000.0), IncomingLimitOrder(-0.09, 11000.0)))) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", "Client2", listOf( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client2", listOf( IncomingLimitOrder(1.0, 1.1), IncomingLimitOrder(6.0, 1.0)))) @@ -774,7 +773,7 @@ class StopLimitOrderTest : AbstractTest() { assertEquals(BigDecimal.valueOf( 0.1), balancesHolder.getReservedBalance("Client1", "BTC")) assertEquals(BigDecimal.valueOf(1050.0), balancesHolder.getReservedBalance("Client3", "USD")) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCUSD", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "Client2", listOf(IncomingLimitOrder(-0.1, 10000.0), IncomingLimitOrder(0.1, 9000.0)))) diff --git a/src/test/kotlin/com/lykke/matching/engine/services/validator/OrderValidationUtilsTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/validator/OrderValidationUtilsTest.kt index 4890299b8..c15c5fb4f 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/validator/OrderValidationUtilsTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/validator/OrderValidationUtilsTest.kt @@ -1,82 +1,14 @@ package com.lykke.matching.engine.services.validator -import com.lykke.matching.engine.daos.AssetPair import com.lykke.matching.engine.order.OrderStatus import com.lykke.matching.engine.services.validators.common.OrderValidationUtils import com.lykke.matching.engine.services.validators.impl.OrderValidationException -import com.lykke.matching.engine.utils.MessageBuilder -import org.junit.Assert import org.junit.Test -import java.math.BigDecimal -import kotlin.test.assertFalse import kotlin.test.assertTrue class OrderValidationUtilsTest { - private companion object { - val MIN_VOLUME_ASSET_PAIR = AssetPair("EURUSD", "EUR", "USD", 5, - BigDecimal.valueOf(0.1), BigDecimal.valueOf(0.2)) - val BTC_USD_ASSET_PAIR = AssetPair("BTCUSD", "BTC", "USD", 8) - } - - @Test - fun testCheckVolume() { - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(assetId = "BTCUSD", volume = 1.0), BTC_USD_ASSET_PAIR) } - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(assetId = "BTCUSD", volume = 0.1), BTC_USD_ASSET_PAIR) } - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(assetId = "BTCUSD", volume = 0.00000001), BTC_USD_ASSET_PAIR) } - - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(volume = 1.0), MIN_VOLUME_ASSET_PAIR) } - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(volume = 0.1), MIN_VOLUME_ASSET_PAIR) } - assertFalse { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(volume = 0.09), MIN_VOLUME_ASSET_PAIR) } - - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(volume = -1.0), MIN_VOLUME_ASSET_PAIR) } - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(volume = -0.1), MIN_VOLUME_ASSET_PAIR) } - assertFalse { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(volume = -0.09), MIN_VOLUME_ASSET_PAIR) } - - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(price = 1.0, volume = 1.0), MIN_VOLUME_ASSET_PAIR) } - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(price = 1.0, volume = 0.1), MIN_VOLUME_ASSET_PAIR) } - assertFalse { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(price = 1.0, volume = 0.09), MIN_VOLUME_ASSET_PAIR) } - - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(price = 1.0, volume = -1.0), MIN_VOLUME_ASSET_PAIR) } - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(price = 1.0, volume = -0.1), MIN_VOLUME_ASSET_PAIR) } - assertFalse { OrderValidationUtils.checkMinVolume(MessageBuilder.buildLimitOrder(price = 1.0, volume = -0.09), MIN_VOLUME_ASSET_PAIR) } - - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(assetId = "BTCUSD", volume = 1.0), BTC_USD_ASSET_PAIR) } - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(assetId = "BTCUSD", volume = 0.1), BTC_USD_ASSET_PAIR) } - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(assetId = "BTCUSD", volume = 0.00000001), BTC_USD_ASSET_PAIR) } - - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(volume = 1.0), MIN_VOLUME_ASSET_PAIR) } - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(volume = 0.1), MIN_VOLUME_ASSET_PAIR) } - assertFalse { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(volume = 0.09), MIN_VOLUME_ASSET_PAIR) } - - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(volume = -1.0), MIN_VOLUME_ASSET_PAIR) } - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(volume = -0.1), MIN_VOLUME_ASSET_PAIR) } - assertFalse { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(volume = -0.09), MIN_VOLUME_ASSET_PAIR) } - - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(volume = 1.0, straight = false), MIN_VOLUME_ASSET_PAIR) } - assertFalse { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(volume = 0.1, straight = false), MIN_VOLUME_ASSET_PAIR) } - assertFalse { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(volume = 0.09, straight = false), MIN_VOLUME_ASSET_PAIR) } - - assertTrue { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(volume = -1.0, straight = false), MIN_VOLUME_ASSET_PAIR) } - assertFalse { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(volume = -0.1, straight = false), MIN_VOLUME_ASSET_PAIR) } - assertFalse { OrderValidationUtils.checkMinVolume(MessageBuilder.buildMarketOrder(volume = -0.09, straight = false), MIN_VOLUME_ASSET_PAIR) } - } - - - @Test(expected = OrderValidationException::class) - fun testInvalidBalance() { - try { - //when - OrderValidationUtils.validateBalance(BigDecimal.valueOf(10.0), BigDecimal.valueOf(11.0)) - } catch (e: OrderValidationException) { - //then - Assert.assertEquals(OrderStatus.NotEnoughFunds, e.orderStatus) - throw e - } - } - @Test - fun testValidBalance() { - //when - OrderValidationUtils.validateBalance(BigDecimal.valueOf(10.0), BigDecimal.valueOf(9.0)) + fun isFatalInvalid() { + assertTrue(OrderValidationUtils.isFatalInvalid(OrderValidationException(OrderStatus.UnknownAsset))) } } \ No newline at end of file diff --git a/src/test/kotlin/com/lykke/matching/engine/services/validator/business/LimitOrderBusinessValidatorTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/validator/business/LimitOrderBusinessValidatorTest.kt index 2c4f7d08a..264be42f6 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/validator/business/LimitOrderBusinessValidatorTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/validator/business/LimitOrderBusinessValidatorTest.kt @@ -8,7 +8,9 @@ import com.lykke.matching.engine.daos.v2.LimitOrderFeeInstruction import com.lykke.matching.engine.holders.OrderBookMaxTotalSizeHolderImpl import com.lykke.matching.engine.order.OrderStatus import com.lykke.matching.engine.services.AssetOrderBook +import com.lykke.matching.engine.services.validators.business.OrderBusinessValidator import com.lykke.matching.engine.services.validators.business.impl.LimitOrderBusinessValidatorImpl +import com.lykke.matching.engine.services.validators.business.impl.OrderBusinessValidatorImpl import com.lykke.matching.engine.services.validators.impl.OrderValidationException import org.junit.Assert.assertEquals import org.junit.Test @@ -24,7 +26,7 @@ class LimitOrderBusinessValidatorTest { @Test(expected = OrderValidationException::class) fun testPreviousOrderNotFount() { //given - val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl(OrderBookMaxTotalSizeHolderImpl(null)) + val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl(OrderBusinessValidatorImpl(), OrderBookMaxTotalSizeHolderImpl(null)) try { //when @@ -45,7 +47,7 @@ class LimitOrderBusinessValidatorTest { @Test(expected = OrderValidationException::class) fun testNotEnoughFounds() { //given - val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl(OrderBookMaxTotalSizeHolderImpl(null)) + val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl(OrderBusinessValidatorImpl(), OrderBookMaxTotalSizeHolderImpl(null)) try { //when @@ -66,7 +68,8 @@ class LimitOrderBusinessValidatorTest { @Test(expected = OrderValidationException::class) fun testOrderBookMaxTotalSize() { //given - val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl(OrderBookMaxTotalSizeHolderImpl(10)) + val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl(OrderBusinessValidatorImpl(), + OrderBookMaxTotalSizeHolderImpl(10)) try { //when @@ -87,7 +90,7 @@ class LimitOrderBusinessValidatorTest { @Test fun testValidOrder() { //given - val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl(OrderBookMaxTotalSizeHolderImpl(null)) + val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl(OrderBusinessValidatorImpl(), OrderBookMaxTotalSizeHolderImpl(null)) //when limitOrderBusinessValidatorImpl.performValidation(true, diff --git a/src/test/kotlin/com/lykke/matching/engine/services/validator/business/OrderBusinessValidatorTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/validator/business/OrderBusinessValidatorTest.kt new file mode 100644 index 000000000..d48d5794e --- /dev/null +++ b/src/test/kotlin/com/lykke/matching/engine/services/validator/business/OrderBusinessValidatorTest.kt @@ -0,0 +1,41 @@ +package com.lykke.matching.engine.services.validator.business + +import com.lykke.matching.engine.config.TestApplicationContext +import com.lykke.matching.engine.order.OrderStatus +import com.lykke.matching.engine.services.validators.business.OrderBusinessValidator +import com.lykke.matching.engine.services.validators.impl.OrderValidationException +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.annotation.DirtiesContext +import org.springframework.test.context.junit4.SpringRunner +import java.math.BigDecimal + +@RunWith(SpringRunner::class) +@SpringBootTest(classes = [(TestApplicationContext::class)]) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +class OrderBusinessValidatorTest { + + @Autowired + private lateinit var orderBusinessValidator: OrderBusinessValidator + + @Test(expected = OrderValidationException::class) + fun testInvalidBalance() { + try { + //when + orderBusinessValidator.validateBalance(BigDecimal.valueOf(10.0), BigDecimal.valueOf(11.0)) + } catch (e: OrderValidationException) { + //then + Assert.assertEquals(OrderStatus.NotEnoughFunds, e.orderStatus) + throw e + } + } + + @Test + fun testValidBalance() { + //when + orderBusinessValidator.validateBalance(BigDecimal.valueOf(10.0), BigDecimal.valueOf(9.0)) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/lykke/matching/engine/services/validator/input/LimitOrderInputValidatorTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/validator/input/LimitOrderInputValidatorTest.kt index 00ab48e06..103f8a31d 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/validator/input/LimitOrderInputValidatorTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/validator/input/LimitOrderInputValidatorTest.kt @@ -65,7 +65,6 @@ class LimitOrderInputValidatorTest { } } - @Before fun init() { testDictionariesDatabaseAccessor.addAssetPair(MIN_VOLUME_ASSET_PAIR) diff --git a/src/test/kotlin/com/lykke/matching/engine/services/validator/input/OrderInputValidatorTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/validator/input/OrderInputValidatorTest.kt new file mode 100644 index 000000000..a8cae7d59 --- /dev/null +++ b/src/test/kotlin/com/lykke/matching/engine/services/validator/input/OrderInputValidatorTest.kt @@ -0,0 +1,121 @@ +package com.lykke.matching.engine.services.validator.input + +import com.lykke.matching.engine.AbstractTest +import com.lykke.matching.engine.config.TestApplicationContext +import com.lykke.matching.engine.daos.AssetPair +import com.lykke.matching.engine.daos.setting.AvailableSettingGroup +import com.lykke.matching.engine.database.TestSettingsDatabaseAccessor +import com.lykke.matching.engine.holders.AssetsPairsHolder +import com.lykke.matching.engine.order.OrderStatus +import com.lykke.matching.engine.services.validators.impl.OrderValidationException +import com.lykke.matching.engine.services.validators.input.OrderInputValidator +import com.lykke.matching.engine.utils.MessageBuilder +import com.lykke.matching.engine.utils.getSetting +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Primary +import org.springframework.test.annotation.DirtiesContext +import org.springframework.test.context.junit4.SpringRunner +import java.math.BigDecimal +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +@RunWith(SpringRunner::class) +@SpringBootTest(classes = [(TestApplicationContext::class), (OrderInputValidatorTest.Config::class)]) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +class OrderInputValidatorTest: AbstractTest() { + private companion object { + val MIN_VOLUME_ASSET_PAIR = AssetPair("EURUSD", "EUR", "USD", 5, + BigDecimal.valueOf(0.1), BigDecimal.valueOf(0.2)) + val BTC_USD_ASSET_PAIR = AssetPair("BTCUSD", "BTC", "USD", 8) + } + + @TestConfiguration + open class Config { + + @Bean + @Primary + open fun testSettingsDatabaseAccessor(): TestSettingsDatabaseAccessor { + val testConfigDatabaseAccessor = TestSettingsDatabaseAccessor() + testConfigDatabaseAccessor.createOrUpdateSetting(AvailableSettingGroup.DISABLED_ASSETS, getSetting("JPY")) + return testConfigDatabaseAccessor + } + } + + @Autowired + private lateinit var orderInputValidator: OrderInputValidator + + @Autowired + private lateinit var assetPairHolder: AssetsPairsHolder + + @Before + fun init() { + testDictionariesDatabaseAccessor.addAssetPair(AssetPair("EURUSD", "EUR", "USD", 5)) + initServices() + } + + @Test + fun testCheckVolume() { + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(assetId = "BTCUSD", volume = 1.0), BTC_USD_ASSET_PAIR) } + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(assetId = "BTCUSD", volume = 0.1), BTC_USD_ASSET_PAIR) } + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(assetId = "BTCUSD", volume = 0.00000001), BTC_USD_ASSET_PAIR) } + + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(volume = 1.0), MIN_VOLUME_ASSET_PAIR) } + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(volume = 0.1), MIN_VOLUME_ASSET_PAIR) } + assertFalse { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(volume = 0.09), MIN_VOLUME_ASSET_PAIR) } + + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(volume = -1.0), MIN_VOLUME_ASSET_PAIR) } + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(volume = -0.1), MIN_VOLUME_ASSET_PAIR) } + assertFalse { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(volume = -0.09), MIN_VOLUME_ASSET_PAIR) } + + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(price = 1.0, volume = 1.0), MIN_VOLUME_ASSET_PAIR) } + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(price = 1.0, volume = 0.1), MIN_VOLUME_ASSET_PAIR) } + assertFalse { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(price = 1.0, volume = 0.09), MIN_VOLUME_ASSET_PAIR) } + + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(price = 1.0, volume = -1.0), MIN_VOLUME_ASSET_PAIR) } + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(price = 1.0, volume = -0.1), MIN_VOLUME_ASSET_PAIR) } + assertFalse { orderInputValidator.checkMinVolume(MessageBuilder.buildLimitOrder(price = 1.0, volume = -0.09), MIN_VOLUME_ASSET_PAIR) } + + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(assetId = "BTCUSD", volume = 1.0), BTC_USD_ASSET_PAIR) } + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(assetId = "BTCUSD", volume = 0.1), BTC_USD_ASSET_PAIR) } + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(assetId = "BTCUSD", volume = 0.00000001), BTC_USD_ASSET_PAIR) } + + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(volume = 1.0), MIN_VOLUME_ASSET_PAIR) } + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(volume = 0.1), MIN_VOLUME_ASSET_PAIR) } + assertFalse { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(volume = 0.09), MIN_VOLUME_ASSET_PAIR) } + + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(volume = -1.0), MIN_VOLUME_ASSET_PAIR) } + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(volume = -0.1), MIN_VOLUME_ASSET_PAIR) } + assertFalse { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(volume = -0.09), MIN_VOLUME_ASSET_PAIR) } + + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(volume = 1.0, straight = false), MIN_VOLUME_ASSET_PAIR) } + assertFalse { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(volume = 0.1, straight = false), MIN_VOLUME_ASSET_PAIR) } + assertFalse { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(volume = 0.09, straight = false), MIN_VOLUME_ASSET_PAIR) } + + assertTrue { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(volume = -1.0, straight = false), MIN_VOLUME_ASSET_PAIR) } + assertFalse { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(volume = -0.1, straight = false), MIN_VOLUME_ASSET_PAIR) } + assertFalse { orderInputValidator.checkMinVolume(MessageBuilder.buildMarketOrder(volume = -0.09, straight = false), MIN_VOLUME_ASSET_PAIR) } + } + + @Test(expected = Exception::class) + fun unknownAsset() { + try { + orderInputValidator.validateAsset(null, "Unknown") + } catch (e: OrderValidationException) { + assertEquals(OrderStatus.UnknownAsset, e.orderStatus) + } + + + try { + orderInputValidator.validateAsset(assetPairHolder.getAssetPair("JPYUSD"), "Unknown") + } catch (e: OrderValidationException) { + assertEquals(OrderStatus.DisabledAsset, e.orderStatus) + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/lykke/matching/engine/utils/MessageBuilder.kt b/src/test/kotlin/com/lykke/matching/engine/utils/MessageBuilder.kt index 56eefa4ff..87ac754d0 100644 --- a/src/test/kotlin/com/lykke/matching/engine/utils/MessageBuilder.kt +++ b/src/test/kotlin/com/lykke/matching/engine/utils/MessageBuilder.kt @@ -13,22 +13,23 @@ import com.lykke.matching.engine.incoming.parsers.data.LimitOrderMassCancelOpera import com.lykke.matching.engine.incoming.parsers.ContextParser import com.lykke.matching.engine.incoming.parsers.impl.CashInOutContextParser import com.lykke.matching.engine.incoming.parsers.impl.CashTransferContextParser -import com.lykke.matching.engine.incoming.parsers.impl.SingleLimitOrderContextParser +import com.lykke.matching.engine.incoming.preprocessor.impl.MultilimitOrderPreprocessor +import com.lykke.matching.engine.incoming.preprocessor.impl.SingleLimitOrderPreprocessor import com.lykke.matching.engine.messages.MessageType import com.lykke.matching.engine.messages.MessageWrapper import com.lykke.matching.engine.messages.ProtocolMessages import com.lykke.matching.engine.order.OrderCancelMode import com.lykke.matching.engine.order.OrderStatus -import com.lykke.matching.engine.services.validators.impl.OrderValidationResult import com.lykke.matching.engine.socket.TestClientHandler import java.math.BigDecimal import java.util.* -class MessageBuilder(private var singleLimitOrderContextParser: SingleLimitOrderContextParser, +class MessageBuilder(private var singleLimitOrderPreprocessor: SingleLimitOrderPreprocessor, private val cashInOutContextParser: CashInOutContextParser, private val cashTransferContextParser: CashTransferContextParser, private val limitOrderCancelOperationContextParser: ContextParser, - private val limitOrderMassCancelOperationContextParser: ContextParser) { + private val limitOrderMassCancelOperationContextParser: ContextParser, + private val multilimitOrderPreprocessor: MultilimitOrderPreprocessor) { companion object { fun buildLimitOrder(uid: String = UUID.randomUUID().toString(), assetId: String = "EURUSD", @@ -160,53 +161,6 @@ companion object { reservedVolume?.toBigDecimal(), fee = fee, fees = fees) - fun buildMultiLimitOrderWrapper(pair: String, - clientId: String, - orders: List, - cancel: Boolean = true, - cancelMode: OrderCancelMode? = null - ): MessageWrapper { - return MessageWrapper("Test", MessageType.MULTI_LIMIT_ORDER.type, buildMultiLimitOrder(pair, clientId, - orders, - cancel, - cancelMode).toByteArray(), TestClientHandler(), messageId = "test", id = "test") - } - - private fun buildMultiLimitOrder(assetPairId: String, - clientId: String, - orders: List, - cancel: Boolean, - cancelMode: OrderCancelMode?): ProtocolMessages.MultiLimitOrder { - val multiOrderBuilder = ProtocolMessages.MultiLimitOrder.newBuilder() - .setUid(UUID.randomUUID().toString()) - .setTimestamp(Date().time) - .setClientId(clientId) - .setAssetPairId(assetPairId) - .setCancelAllPreviousLimitOrders(cancel) - cancelMode?.let { multiOrderBuilder.cancelMode = it.externalId } - orders.forEach { order -> - val orderBuilder = ProtocolMessages.MultiLimitOrder.Order.newBuilder() - .setVolume(order.volume) - order.price?.let { orderBuilder.price = it } - order.feeInstruction?.let { orderBuilder.fee = buildLimitOrderFee(it) } - order.feeInstructions.forEach { orderBuilder.addFees(buildNewLimitOrderFee(it)) } - orderBuilder.uid = order.uid - order.oldUid?.let { orderBuilder.oldUid = order.oldUid } - order.timeInForce?.let { orderBuilder.timeInForce = it.externalId } - order.expiryTime?.let { orderBuilder.expiryTime = it.time } - order.type?.let { orderBuilder.type = it.externalId } - order.lowerLimitPrice?.let { orderBuilder.lowerLimitPrice = it } - order.lowerPrice?.let { orderBuilder.lowerPrice = it } - order.upperLimitPrice?.let { orderBuilder.upperLimitPrice = it } - order.upperPrice?.let { orderBuilder.upperPrice = it } - multiOrderBuilder.addOrders(orderBuilder.build()) - } - return multiOrderBuilder.build() - } - - - - fun buildMultiLimitOrderCancelWrapper(clientId: String, assetPairId: String, isBuy: Boolean): MessageWrapper = MessageWrapper("Test", MessageType.MULTI_LIMIT_ORDER_CANCEL.type, ProtocolMessages.MultiLimitOrderCancel.newBuilder() .setUid(UUID.randomUUID().toString()) .setTimestamp(Date().time) @@ -332,6 +286,74 @@ companion object { return limitOrderMassCancelOperationContextParser.parse(messageWrapper).messageWrapper } + private fun buildMultiLimitOrder(assetPairId: String, + clientId: String, + orders: List, + cancel: Boolean, + cancelMode: OrderCancelMode?): ProtocolMessages.MultiLimitOrder { + val multiOrderBuilder = ProtocolMessages.MultiLimitOrder.newBuilder() + .setUid(UUID.randomUUID().toString()) + .setTimestamp(Date().time) + .setClientId(clientId) + .setAssetPairId(assetPairId) + .setCancelAllPreviousLimitOrders(cancel) + cancelMode?.let { multiOrderBuilder.cancelMode = it.externalId } + orders.forEach { order -> + val orderBuilder = ProtocolMessages.MultiLimitOrder.Order.newBuilder() + .setVolume(order.volume) + order.price?.let { orderBuilder.price = it } + order.feeInstruction?.let { orderBuilder.fee = buildLimitOrderFee(it) } + order.feeInstructions.forEach { orderBuilder.addFees(buildNewLimitOrderFee(it)) } + orderBuilder.uid = order.uid + order.oldUid?.let { orderBuilder.oldUid = order.oldUid } + order.type?.let { orderBuilder.type = it.externalId } + order.lowerLimitPrice?.let { orderBuilder.lowerLimitPrice = it } + order.lowerPrice?.let { orderBuilder.lowerPrice = it } + order.timeInForce?.let { orderBuilder.timeInForce = it.externalId } + order.expiryTime?.let { orderBuilder.expiryTime = it.time } + order.upperLimitPrice?.let { orderBuilder.upperLimitPrice = it } + order.upperPrice?.let { orderBuilder.upperPrice = it } + multiOrderBuilder.addOrders(orderBuilder.build()) + } + return multiOrderBuilder.build() + } + + @Deprecated("Use buildMultiLimitOrderWrapper(5)") + fun buildMultiLimitOrderWrapper(pair: String, + clientId: String, + volumes: List, + ordersFee: List = emptyList(), + ordersFees: List> = emptyList(), + ordersUid: List = emptyList(), + cancel: Boolean = false, + cancelMode: OrderCancelMode? = null + ): MessageWrapper { + val orders = volumes.mapIndexed { i, volume -> + IncomingLimitOrder(volume.volume.toDouble(), + volume.price.toDouble(), + if (i < ordersUid.size) ordersUid[i] else UUID.randomUUID().toString(), + if (i < ordersFee.size) ordersFee[i] else null, + if (i < ordersFees.size) ordersFees[i] else emptyList(), + null) + } + return buildMultiLimitOrderWrapper(pair, clientId, orders, cancel, cancelMode) + } + + fun buildMultiLimitOrderWrapper(pair: String, + clientId: String, + orders: List, + cancel: Boolean = true, + cancelMode: OrderCancelMode? = null + ): MessageWrapper { + val messageWrapper = MessageWrapper("Test", MessageType.MULTI_LIMIT_ORDER.type, buildMultiLimitOrder(pair, clientId, + orders, + cancel, + cancelMode).toByteArray(), TestClientHandler(), messageId = "test", id = "test") + multilimitOrderPreprocessor.preProcess(messageWrapper) + return messageWrapper + } + + fun buildLimitOrderWrapper(order: LimitOrder, cancel: Boolean = false): MessageWrapper { val builder = ProtocolMessages.LimitOrder.newBuilder() @@ -357,12 +379,8 @@ companion object { order.upperPrice?.let { builder.setUpperPrice(it.toDouble()) } order.expiryTime?.let { builder.setExpiryTime(it.time) } order.timeInForce?.let { builder.setTimeInForce(it.externalId) } - val messageWrapper = singleLimitOrderContextParser - .parse(MessageWrapper("Test", MessageType.LIMIT_ORDER.type, builder.build().toByteArray(), TestClientHandler(), messageId = "test", id = "test")) - .messageWrapper - - val singleLimitContext = messageWrapper.context as SingleLimitOrderContext - singleLimitContext.validationResult = OrderValidationResult(true) + val messageWrapper = MessageWrapper("Test", MessageType.LIMIT_ORDER.type, builder.build().toByteArray(), TestClientHandler(), messageId = "test", id = "test") + singleLimitOrderPreprocessor.preProcess(messageWrapper) return messageWrapper } diff --git a/src/test/kotlin/com/lykke/matching/engine/utils/order/MinVolumeOrderCancellerTest.kt b/src/test/kotlin/com/lykke/matching/engine/utils/order/MinVolumeOrderCancellerTest.kt index 7cae40287..6247fd99d 100644 --- a/src/test/kotlin/com/lykke/matching/engine/utils/order/MinVolumeOrderCancellerTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/utils/order/MinVolumeOrderCancellerTest.kt @@ -11,7 +11,6 @@ import com.lykke.matching.engine.database.TestSettingsDatabaseAccessor import com.lykke.matching.engine.outgoing.messages.LimitOrdersReport import com.lykke.matching.engine.utils.MessageBuilder import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildLimitOrder -import com.lykke.matching.engine.utils.MessageBuilder.Companion.buildMultiLimitOrderWrapper import com.lykke.matching.engine.utils.balance.ReservedVolumesRecalculator import org.junit.Before import org.junit.Test @@ -100,7 +99,7 @@ class MinVolumeOrderCancellerTest : AbstractTest() { singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(buildLimitOrder(uid = "validVolume", clientId = "Client1", assetId = "BTCUSD", price = 10001.0, volume = 0.01))) singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(buildLimitOrder(clientId = "Client2", assetId = "BTCUSD", price = 10001.0, volume = 0.001))) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(clientId = "TrustedClient", pair = "BTCUSD", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(clientId = "TrustedClient", pair = "BTCUSD", orders = listOf(IncomingLimitOrder(0.00102, 10002.0), IncomingLimitOrder(-0.00001, 11000.0)))) singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(buildLimitOrder(clientId = "ClientForPartiallyMatching", assetId = "BTCUSD", price = 10002.0, volume = -0.001))) @@ -112,7 +111,7 @@ class MinVolumeOrderCancellerTest : AbstractTest() { singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(buildLimitOrder(uid = "order1", clientId = "Client2", assetId = "EURUSD", price = 1.3, volume = -4.09))) singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(buildLimitOrder(uid = "order2", clientId = "Client2", assetId = "EURUSD", price = 1.1, volume = 4.09))) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper(clientId = "TrustedClient", pair = "EURUSD", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper(clientId = "TrustedClient", pair = "EURUSD", orders = listOf(IncomingLimitOrder(30.0, 1.1), IncomingLimitOrder(-30.0, 1.4)))) singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(buildLimitOrder(clientId = "ClientForPartiallyMatching", assetId = "EURUSD", price = 1.2, volume = 6.0))) @@ -194,7 +193,7 @@ class MinVolumeOrderCancellerTest : AbstractTest() { @Test fun testCancelOrdersWithRemovedAssetPair() { singleLimitOrderService.processMessage(messageBuilder.buildLimitOrderWrapper(buildLimitOrder(uid = "order1", clientId = "Client1", assetId = "BTCEUR", price = 10000.0, volume = -1.0))) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("BTCEUR", "TrustedClient", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCEUR", "TrustedClient", listOf(IncomingLimitOrder(-1.0, price = 10000.0, uid = "order2")))) assertEquals(BigDecimal.ZERO, balancesHolder.getReservedBalance("TrustedClient", "BTC"))