From 57c496bb863142991b01beae9f8ec995d60b3747 Mon Sep 17 00:00:00 2001 From: papchenko Date: Fri, 4 Jan 2019 18:03:10 +0200 Subject: [PATCH 01/14] LWDEV-8274 add multilimit order context --- .../engine/config/spring/LoggerConfig.kt | 5 + .../daos/context/MultilimitOrderContext.kt | 14 ++ .../parsers/data/MultilimitOrderParsedData.kt | 5 + .../impl/MultilimitOrderContextParser.kt | 190 +++++++++++++++++ .../impl/MultilimitOrderPreprocessor.kt | 76 +++++++ .../order/process/LimitOrderProcessor.kt | 24 +-- .../order/process/StopLimitOrderProcessor.kt | 17 +- .../engine/services/MultiLimitOrderService.kt | 191 ++---------------- .../input/LimitOrderInputValidator.kt | 6 +- .../impl/LimitOrderInputValidatorImpl.kt | 11 +- .../engine/config/TestApplicationContext.kt | 39 +++- .../engine/config/TestExecutionContext.kt | 10 +- .../impl/SingleLimitOrderPreprocessorTest.kt | 5 +- .../performance/AbstractPerformanceTest.kt | 21 +- .../MultiLimitOrderServicePerformanceTest.kt | 53 +++-- .../services/ClientMultiLimitOrderTest.kt | 60 +++--- .../engine/services/InvalidBalanceTest.kt | 5 +- .../LimitOrderMassCancelServiceTest.kt | 5 +- .../engine/services/MinRemainingVolumeTest.kt | 5 +- .../services/MultiLimitOrderServiceTest.kt | 87 ++++---- .../engine/services/NegativePriceTest.kt | 3 +- .../engine/services/PersistenceErrorTest.kt | 9 +- .../engine/services/StopLimitOrderTest.kt | 11 +- .../matching/engine/utils/MessageBuilder.kt | 150 +++++++------- .../order/MinVolumeOrderCancellerTest.kt | 7 +- 25 files changed, 550 insertions(+), 459 deletions(-) create mode 100644 src/main/kotlin/com/lykke/matching/engine/daos/context/MultilimitOrderContext.kt create mode 100644 src/main/kotlin/com/lykke/matching/engine/incoming/parsers/data/MultilimitOrderParsedData.kt create mode 100644 src/main/kotlin/com/lykke/matching/engine/incoming/parsers/impl/MultilimitOrderContextParser.kt create mode 100644 src/main/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/MultilimitOrderPreprocessor.kt 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 856a45a39..bfae610e9 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 @@ -21,6 +21,11 @@ open class LoggerConfig { return Logger.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/daos/context/MultilimitOrderContext.kt b/src/main/kotlin/com/lykke/matching/engine/daos/context/MultilimitOrderContext.kt new file mode 100644 index 000000000..d7d29275f --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/daos/context/MultilimitOrderContext.kt @@ -0,0 +1,14 @@ +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.impl.OrderValidationResult + +class MultilimitOrderContext(val assetPair: AssetPair?, + val baseAsset: Asset?, + val quotingAsset: Asset?, + val clientId: String, + val isTrustedClient: Boolean, + val multiLimitOrder: MultiLimitOrder, + var inputValidationResultByOrderId: Map? = null) \ 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..ba0ed198e --- /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) : 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..8d84ab177 --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/incoming/parsers/impl/MultilimitOrderContextParser.kt @@ -0,0 +1,190 @@ +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.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.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.matching.engine.utils.NumberUtils +import com.lykke.utils.logging.ThrottlingLogger +import org.springframework.stereotype.Component +import java.math.BigDecimal +import java.util.* + +@Component +class MultilimitOrderContextParser(val logger: ThrottlingLogger, + val applicationSettingsHolder: ApplicationSettingsHolder, + val assertPairsHolder: AssetsPairsHolder, + val assetsHolder: AssetsHolder) : 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) + } + + 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, + message.clientId, + 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 -> + 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(UUID.randomUUID().toString(), + 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 + ) + + orders.add(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, + orders, + cancelAllPreviousLimitOrders, + cancelBuySide, + cancelSellSide, + cancelMode, + buyReplacements, + sellReplacements) + } + + 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 "") + } +} \ 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..d10f5252d --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/MultilimitOrderPreprocessor.kt @@ -0,0 +1,76 @@ +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.order.OrderStatus +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.order.MessageStatusUtils +import com.lykke.utils.logging.ThrottlingLogger +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.stereotype.Component +import java.util.concurrent.BlockingQueue + +@Component +class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: MessageProcessingStatusHolder, + private val limitOrderInputValidator: LimitOrderInputValidator, + multilimitOrderContextParser: ContextParser, + private val 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, MessageStatus.MESSAGE_PROCESSING_DISABLED) + return false + } + + val validationResult = getValidationResult(context) + val fatallyInvalidValidationResult = validationResult.values.find { it.isFatalInvalid } + if (fatallyInvalidValidationResult != null) { + logger.error("Fatal validation error occurred, ${fatallyInvalidValidationResult.message} " + + "Error details: $context") + writeResponse(parsedData.messageWrapper, MessageStatusUtils.toMessageStatus(fatallyInvalidValidationResult.status!!), fatallyInvalidValidationResult.message) + return false + } + + context.inputValidationResultByOrderId = validationResult + return true + } + + private fun getValidationResult(context: MultilimitOrderContext): Map { + val orderValidationResultByOrderId = HashMap() + for (order in context.multiLimitOrder.orders) { + try { + when (order.type) { + LimitOrderType.LIMIT -> limitOrderInputValidator.validateLimitOrder(context.isTrustedClient, + order, + context.assetPair, + order.assetPairId, + context.baseAsset) + LimitOrderType.STOP_LIMIT -> limitOrderInputValidator.validateStopOrder(order, context.assetPair, order.assetPairId, context.baseAsset) + } + } catch (e: OrderValidationException) { + val fatalInvalid = isFatalInvalid(e) + orderValidationResultByOrderId.put(order.id, OrderValidationResult(false, fatalInvalid, e.message, e.orderStatus)) + if (fatalInvalid) { + return orderValidationResultByOrderId + } + } + } + + return orderValidationResultByOrderId + } + + 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 45fe8fd5d..596e65195 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 @@ -15,14 +15,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 { @@ -44,25 +42,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 a082a8888..1dbb5bdc2 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 @@ -11,14 +11,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) : OrderProcessor { @@ -38,18 +36,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 6407934b7..657c73f8d 100644 --- a/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt +++ b/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt @@ -1,26 +1,14 @@ 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.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.order.transaction.ExecutionContextFactory import com.lykke.matching.engine.order.process.GenericLimitOrdersProcessor import com.lykke.matching.engine.order.process.StopOrderBookProcessor @@ -29,9 +17,7 @@ import com.lykke.matching.engine.order.process.PreviousLimitOrdersProcessor import com.lykke.matching.engine.services.utils.MultiOrderFilter import org.apache.log4j.Logger import org.springframework.stereotype.Service -import java.math.BigDecimal import java.util.Date -import java.util.UUID @Service class MultiLimitOrderService(private val executionContextFactory: ExecutionContextFactory, @@ -39,11 +25,7 @@ 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) : AbstractService { + private val balancesHolder: BalancesHolder) : AbstractService { companion object { private val LOGGER = Logger.getLogger(MultiLimitOrderService::class.java.name) @@ -57,31 +39,23 @@ class MultiLimitOrderService(private val executionContextFactory: ExecutionConte } 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, context.assetPair!!, 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.inputValidationResultByOrderId ?: emptyMap()) previousLimitOrdersProcessor.cancelAndReplaceOrders(multiLimitOrder.clientId, multiLimitOrder.assetPairId, @@ -92,7 +66,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) @@ -126,151 +100,28 @@ class MultiLimitOrderService(private val executionContextFactory: ExecutionConte messageWrapper.writeMultiLimitOrderResponse(responseBuilder) } - 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 - - val buyReplacements = mutableMapOf() - val sellReplacements = mutableMapOf() - - val baseAssetAvailableBalance = balancesHolder.getAvailableBalance(clientId, assetPair.baseAssetId) - val quotingAssetAvailableBalance = balancesHolder.getAvailableBalance(clientId, assetPair.quotingAssetId) + fun getOrdersToProcess(context: MultilimitOrderContext, assetPair: AssetPair, now: Date): List { + val baseAssetAvailableBalance = balancesHolder.getAvailableBalance(context.clientId, context.assetPair!!.baseAssetId) + val quotingAssetAvailableBalance = balancesHolder.getAvailableBalance(context.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, + context.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(UUID.randomUUID().toString(), - 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 - ) - + for (order in context.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 } override fun writeResponse(messageWrapper: MessageWrapper, status: MessageStatus) { 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..8cb9fe53f 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) @@ -14,5 +13,8 @@ interface LimitOrderInputValidator { assetPair: AssetPair?, 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/impl/LimitOrderInputValidatorImpl.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/impl/LimitOrderInputValidatorImpl.kt index 1809a23b8..df62fa4bc 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 @@ -56,16 +56,7 @@ 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, + override fun validateStopOrder(limitOrder: LimitOrder, assetPair: AssetPair?, assetPairId: String, baseAsset: Asset?) { 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 1987d7a97..71257ad96 100644 --- a/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt +++ b/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt @@ -20,6 +20,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 @@ -342,18 +343,13 @@ open class TestApplicationContext { assetsHolder: AssetsHolder, assetsPairsHolder: AssetsPairsHolder, balancesHolder: BalancesHolder, - applicationSettingsHolder: ApplicationSettingsHolder, - messageProcessingStatusHolder: MessageProcessingStatusHolder): MultiLimitOrderService { + applicationSettingsHolder: ApplicationSettingsHolder): MultiLimitOrderService { return MultiLimitOrderService(executionContextFactory, genericLimitOrdersProcessor, stopOrderBookProcessor, executionDataApplyService, previousLimitOrdersProcessor, - assetsHolder, - assetsPairsHolder, - balancesHolder, - applicationSettingsHolder, - messageProcessingStatusHolder) + balancesHolder) } @Bean @@ -547,11 +543,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 @@ -587,6 +584,13 @@ open class TestApplicationContext { ThrottlingLogger.getLogger("limitOrder")) } + @Bean + open fun multilimitOrderContextParser(applicationSettingsHolder: ApplicationSettingsHolder, + assetsPairsHolder: AssetsPairsHolder, + assetsHolder: AssetsHolder): MultilimitOrderContextParser { + return MultilimitOrderContextParser(ThrottlingLogger.getLogger("multilimitOrder"), applicationSettingsHolder, assetsPairsHolder, assetsHolder) + } + @Bean open fun limitOrderInputValidator(applicationSettingsHolder: ApplicationSettingsHolder): LimitOrderInputValidator { return LimitOrderInputValidatorImpl(applicationSettingsHolder) @@ -668,4 +672,17 @@ open class TestApplicationContext { messageProcessingStatusHolder, ThrottlingLogger.getLogger("limitOrder")) } + + @Bean + open fun multiltilimitOrderPreprocessor(messageProcessingStatusHolder: MessageProcessingStatusHolder, + limitOrderInputValidator: LimitOrderInputValidator, + multilimitOrderContextParser: MultilimitOrderContextParser, + preProcessedMessageQueue: BlockingQueue + ): MultilimitOrderPreprocessor { + return MultilimitOrderPreprocessor(messageProcessingStatusHolder, + limitOrderInputValidator, + multilimitOrderContextParser, + preProcessedMessageQueue, + ThrottlingLogger.getLogger("multilimitOrder")) + } } \ No newline at end of file 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 b3575eafe..a54be44cb 100644 --- a/src/test/kotlin/com/lykke/matching/engine/config/TestExecutionContext.kt +++ b/src/test/kotlin/com/lykke/matching/engine/config/TestExecutionContext.kt @@ -100,7 +100,7 @@ open class TestExecutionContext { applicationSettingsHolder: ApplicationSettingsHolder, matchingEngine: MatchingEngine, matchingResultHandlingHelper: MatchingResultHandlingHelper): LimitOrderProcessor { - return LimitOrderProcessor(limitOrderInputValidator, + return LimitOrderProcessor( limitOrderBusinessValidator, applicationSettingsHolder, matchingEngine, @@ -108,11 +108,10 @@ open class TestExecutionContext { } @Bean - open fun stopLimitOrdersProcessor(limitOrderInputValidator: LimitOrderInputValidator, - stopOrderBusinessValidator: StopOrderBusinessValidator, + open fun stopLimitOrdersProcessor(stopOrderBusinessValidator: StopOrderBusinessValidator, applicationSettingsHolder: ApplicationSettingsHolder, limitOrderProcessor: LimitOrderProcessor): StopLimitOrderProcessor { - return StopLimitOrderProcessor(limitOrderInputValidator, + return StopLimitOrderProcessor( stopOrderBusinessValidator, applicationSettingsHolder, limitOrderProcessor) @@ -130,7 +129,8 @@ open class TestExecutionContext { return StopOrderBookProcessor(limitOrderProcessor, applicationSettingsHolder) } - @Bean fun matchingResultHandlingHelper(applicationSettingsHolder: ApplicationSettingsHolder): MatchingResultHandlingHelper { + @Bean + fun matchingResultHandlingHelper(applicationSettingsHolder: ApplicationSettingsHolder): MatchingResultHandlingHelper { return MatchingResultHandlingHelper(applicationSettingsHolder) } 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 d12666118..4404edfed 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 @@ -23,13 +23,11 @@ class SingleLimitOrderPreprocessorTest: AbstractTest() { @Autowired private lateinit var messageBuilder: MessageBuilder - @Autowired - private lateinit var singleLimitOrderPreprocessor: SingleLimitOrderPreprocessor @Test fun testOrderWithUnknownAssetPair() { + //preprocessing is performed during message building val messageWrapper = messageBuilder.buildLimitOrderWrapper(MessageBuilder.buildLimitOrder(assetId = "UnknownAssetPair")) - singleLimitOrderPreprocessor.preProcess(messageWrapper) val clientHandler = messageWrapper.clientHandler!! as TestClientHandler assertEquals(1, clientHandler.responses.size) @@ -46,7 +44,6 @@ 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) 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 345b6a27d..e9b4ed97c 100644 --- a/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt @@ -22,7 +22,11 @@ import com.lykke.matching.engine.holders.OrdersDatabaseAccessorsHolder import com.lykke.matching.engine.holders.StopOrdersDatabaseAccessorsHolder 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.ExecutionEventSender @@ -169,11 +173,14 @@ abstract class AbstractPerformanceTest { cashInOutContextParser = CashInOutContextParser(assetsHolder) cashTransferContextParser = CashTransferContextParser(assetsHolder) - messageBuilder = MessageBuilder(singleLimitOrderContextParser, + messageBuilder = MessageBuilder(SingleLimitOrderPreprocessor(singleLimitOrderContextParser, LinkedBlockingQueue(), messageProcessingStatusHolder, ThrottlingLogger.getLogger("test")), cashInOutContextParser, cashTransferContextParser, LimitOrderCancelOperationContextParser(), - LimitOrderMassCancelOperationContextParser()) + LimitOrderMassCancelOperationContextParser(), + MultilimitOrderPreprocessor(messageProcessingStatusHolder, limitOrderInputValidator, MultilimitOrderContextParser(ThrottlingLogger.getLogger("test"), + applicationSettingsHolder, assetsPairsHolder, assetsHolder), + LinkedBlockingQueue(), ThrottlingLogger.getLogger("test"))) genericStopLimitOrderService = GenericStopLimitOrderService(stopOrdersDatabaseAccessorsHolder) @@ -200,13 +207,13 @@ abstract class AbstractPerformanceTest { val matchingEngine = MatchingEngine(genericLimitOrderService, feeProcessor) - val limitOrderProcessor = LimitOrderProcessor(limitOrderInputValidator, + val limitOrderProcessor = LimitOrderProcessor( LimitOrderBusinessValidatorImpl(), applicationSettingsHolder, matchingEngine, matchingResultHandlingHelper) - val stopOrderProcessor = StopLimitOrderProcessor(limitOrderInputValidator, + val stopOrderProcessor = StopLimitOrderProcessor( StopOrderBusinessValidatorImpl(), applicationSettingsHolder, limitOrderProcessor) @@ -238,11 +245,7 @@ abstract class AbstractPerformanceTest { stopOrderBookProcessor, executionDataApplyService, previousLimitOrdersProcessor, - assetsHolder, - assetsPairsHolder, - balancesHolder, - applicationSettingsHolder, - messageProcessingStatusHolder) + balancesHolder) val marketOrderValidator = MarketOrderValidatorImpl(assetsPairsHolder, assetsHolder, applicationSettingsHolder) marketOrderService = MarketOrderService(matchingEngine, 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 1cfd873e4..d17e8ec52 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)) @@ -895,7 +881,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", @@ -951,7 +937,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 29ce632b8..14d7f52c1 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,12 +94,12 @@ 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( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "TrustedClient", listOf( IncomingLimitOrder(-1.0, 8500.0) ))) 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 935fcae5e..305d520da 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/MultiLimitOrderServiceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/MultiLimitOrderServiceTest.kt @@ -16,7 +16,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 @@ -104,7 +103,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), @@ -136,7 +135,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")) @@ -163,7 +162,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")) @@ -182,7 +181,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)) @@ -201,7 +200,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")) @@ -220,7 +219,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)) @@ -237,7 +236,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()) @@ -264,7 +263,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()) @@ -295,7 +294,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)) @@ -337,7 +336,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()) @@ -368,7 +367,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), @@ -420,9 +419,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()) @@ -467,7 +466,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()) @@ -505,7 +504,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) @@ -519,7 +518,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 @@ -536,7 +535,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) @@ -550,7 +549,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), @@ -573,7 +572,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) @@ -587,7 +586,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) @@ -633,7 +632,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)) @@ -653,7 +652,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) @@ -691,7 +690,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)) @@ -725,7 +724,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()) @@ -755,7 +754,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( @@ -787,7 +786,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper( + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper( clientId = marketMaker, pair = "EURUSD", orders = listOf( IncomingLimitOrder(2.0, 1.20), @@ -843,7 +842,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) @@ -881,12 +880,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)) @@ -924,7 +923,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), @@ -938,7 +937,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) @@ -959,7 +958,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)) @@ -979,7 +978,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")), @@ -1006,7 +1005,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"), @@ -1017,7 +1016,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"), @@ -1096,13 +1095,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)) @@ -1139,7 +1138,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client1", listOf(IncomingLimitOrder(10.0, 1.3, "1")))) @@ -1221,7 +1220,7 @@ class MultiLimitOrderServiceTest: AbstractTest() { order10, order9) - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client1", orders)) } @@ -1250,7 +1249,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 @@ -1277,7 +1276,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") ))) @@ -1321,7 +1320,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) } @@ -1333,7 +1332,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) } 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 8f76594ce..93c733af4 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 @@ -81,7 +80,7 @@ class NegativePriceTest : AbstractTest() { initServices() - multiLimitOrderService.processMessage(buildMultiLimitOrderWrapper("EURUSD", + multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("EURUSD", "Client", listOf( VolumePrice(BigDecimal.valueOf(1.0), BigDecimal.valueOf(1.0)), 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 c5220b567..c78a7c730 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/StopLimitOrderTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/StopLimitOrderTest.kt @@ -19,7 +19,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 @@ -430,7 +429,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)))) @@ -511,7 +510,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)))) @@ -586,11 +585,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)))) @@ -710,7 +709,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/utils/MessageBuilder.kt b/src/test/kotlin/com/lykke/matching/engine/utils/MessageBuilder.kt index 0fe462465..92b9027ef 100644 --- a/src/test/kotlin/com/lykke/matching/engine/utils/MessageBuilder.kt +++ b/src/test/kotlin/com/lykke/matching/engine/utils/MessageBuilder.kt @@ -12,22 +12,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", @@ -152,73 +153,6 @@ companion object { reservedVolume?.toBigDecimal(), fee = fee, fees = fees) - - @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 { - return MessageWrapper("Test", MessageType.MULTI_LIMIT_ORDER.type, buildMultiLimitOrder(pair, clientId, - orders, - cancel, - cancelMode).toByteArray(), null, 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.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) @@ -342,6 +276,72 @@ 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.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(), null, messageId = "test", id = "test") + multilimitOrderPreprocessor.preProcess(messageWrapper) + return messageWrapper + } + + fun buildLimitOrderWrapper(order: LimitOrder, cancel: Boolean = false): MessageWrapper { val builder = ProtocolMessages.LimitOrder.newBuilder() @@ -365,12 +365,8 @@ companion object { order.lowerPrice?.let { builder.setLowerPrice(it.toDouble()) } order.upperLimitPrice?.let { builder.setUpperLimitPrice(it.toDouble()) } order.upperPrice?.let { builder.setUpperPrice(it.toDouble()) } - 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")) From c214df8b962dce4a565473ff59fb6711c27eccef Mon Sep 17 00:00:00 2001 From: papchenko Date: Fri, 4 Jan 2019 18:55:11 +0200 Subject: [PATCH 02/14] LWDEV-8274 route messages to multilimit order preprocessor --- .../engine/config/spring/InputQueueListenerConfig.kt | 12 ++++++++++++ .../matching/engine/config/spring/QueueConfig.kt | 6 ++++++ .../lykke/matching/engine/incoming/MessageRouter.kt | 2 ++ .../parsers/impl/MultilimitOrderContextParser.kt | 11 +++++++---- .../preprocessor/impl/MultilimitOrderPreprocessor.kt | 2 +- 5 files changed, 28 insertions(+), 5 deletions(-) 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/QueueConfig.kt b/src/main/kotlin/com/lykke/matching/engine/config/spring/QueueConfig.kt index 97a1ad03a..65795d750 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 @@ -89,6 +89,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/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/parsers/impl/MultilimitOrderContextParser.kt b/src/main/kotlin/com/lykke/matching/engine/incoming/parsers/impl/MultilimitOrderContextParser.kt index 8d84ab177..012d1ab83 100644 --- 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 @@ -19,15 +19,18 @@ import com.lykke.matching.engine.order.OrderCancelMode import com.lykke.matching.engine.order.OrderStatus import com.lykke.matching.engine.utils.NumberUtils 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(val logger: ThrottlingLogger, - val applicationSettingsHolder: ApplicationSettingsHolder, - val assertPairsHolder: AssetsPairsHolder, - val assetsHolder: AssetsHolder) : ContextParser { +class MultilimitOrderContextParser( + @Qualifier("multiLimitOrderPreProcessingLogger") + val logger: ThrottlingLogger, + val applicationSettingsHolder: ApplicationSettingsHolder, + val assertPairsHolder: AssetsPairsHolder, + val assetsHolder: AssetsHolder) : ContextParser { override fun parse(messageWrapper: MessageWrapper): MultilimitOrderParsedData { val message = parseMultiLimitOrder(messageWrapper.byteArray) val trustedClient = applicationSettingsHolder.isTrustedClient(message.clientId) 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 index d10f5252d..fa051144c 100644 --- 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 @@ -22,7 +22,7 @@ import java.util.concurrent.BlockingQueue class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: MessageProcessingStatusHolder, private val limitOrderInputValidator: LimitOrderInputValidator, multilimitOrderContextParser: ContextParser, - private val preProcessedMessageQueue: BlockingQueue, + preProcessedMessageQueue: BlockingQueue, @Qualifier("multiLimitOrderPreProcessingLogger") private val logger: ThrottlingLogger) : AbstractMessagePreprocessor(multilimitOrderContextParser, messageProcessingStatusHolder, preProcessedMessageQueue, logger) { From 83e25e0d8ed72167cc9b05000630fd29b258f73c Mon Sep 17 00:00:00 2001 From: papchenko Date: Mon, 7 Jan 2019 17:47:54 +0200 Subject: [PATCH 03/14] LWDEV-8274 fixes --- src/dist/cfg/log4j.properties | 2 ++ .../preprocessor/impl/MultilimitOrderPreprocessor.kt | 8 +++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dist/cfg/log4j.properties b/src/dist/cfg/log4j.properties index 8b76ac6a8..e6844c8ff 100644 --- a/src/dist/cfg/log4j.properties +++ b/src/dist/cfg/log4j.properties @@ -117,6 +117,8 @@ log4j.logger.com.lykke.matching.engine.services.MultiLimitOrderService=debug,mul log4j.additivity.com.lykke.matching.engine.services.MultiLimitOrderService=false log4j.logger.com.lykke.matching.engine.services.validators.impl.MultiLimitOrderValidatorImpl=debug,multiLimit log4j.additivity.com.lykke.matching.engine.services.validators.impl.MultiLimitOrderValidatorImpl=false +log4j.logger.MultiLimitOrderPreProcessing=debug,multiLimit +log4j.additivity.MultiLimitOrderPreProcessing=false log4j.appender.multiLimit=org.apache.log4j.DailyRollingFileAppender log4j.appender.multiLimit.File=../log/multiLimitOrder.log log4j.appender.multiLimit.layout=org.apache.log4j.PatternLayout 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 index fa051144c..949bbd3c9 100644 --- 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 @@ -34,6 +34,8 @@ class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: Mes } val validationResult = getValidationResult(context) + context.inputValidationResultByOrderId = validationResult + val fatallyInvalidValidationResult = validationResult.values.find { it.isFatalInvalid } if (fatallyInvalidValidationResult != null) { logger.error("Fatal validation error occurred, ${fatallyInvalidValidationResult.message} " + @@ -42,7 +44,6 @@ class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: Mes return false } - context.inputValidationResultByOrderId = validationResult return true } @@ -60,10 +61,7 @@ class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: Mes } } catch (e: OrderValidationException) { val fatalInvalid = isFatalInvalid(e) - orderValidationResultByOrderId.put(order.id, OrderValidationResult(false, fatalInvalid, e.message, e.orderStatus)) - if (fatalInvalid) { - return orderValidationResultByOrderId - } + orderValidationResultByOrderId[order.id] = OrderValidationResult(false, fatalInvalid, e.message, e.orderStatus) } } From fffb22847250fb7c801bc3a2cfc21d3d396d087c Mon Sep 17 00:00:00 2001 From: papchenko Date: Mon, 14 Jan 2019 14:56:46 +0200 Subject: [PATCH 04/14] LWDEV-8274 fix tests --- .../parsers/impl/MultilimitOrderContextParser.kt | 9 ++++++--- .../matching/engine/config/TestApplicationContext.kt | 1 + .../engine/services/MultiLimitOrderServiceTest.kt | 6 ++---- .../com/lykke/matching/engine/utils/MessageBuilder.kt | 2 ++ 4 files changed, 11 insertions(+), 7 deletions(-) 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 index 012d1ab83..74fe4fd2d 100644 --- 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 @@ -5,6 +5,7 @@ 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 @@ -132,9 +133,11 @@ class MultilimitOrderContextParser( 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 + 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 ) orders.add(order) 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 d0b1f03aa..3394114c9 100644 --- a/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt +++ b/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt @@ -690,6 +690,7 @@ open class TestApplicationContext { cashTransferInputQueue, limitOrderCancelInputQueue, limitOrderMassCancelInputQueue, + preProcessedMessageQueue, preProcessedMessageQueue) } } \ No newline at end of file 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 c79b1221d..333cdef88 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/MultiLimitOrderServiceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/MultiLimitOrderServiceTest.kt @@ -27,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 @@ -42,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 @@ -1373,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), @@ -1407,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/utils/MessageBuilder.kt b/src/test/kotlin/com/lykke/matching/engine/utils/MessageBuilder.kt index 8bf0d2f11..6e9b3e184 100644 --- a/src/test/kotlin/com/lykke/matching/engine/utils/MessageBuilder.kt +++ b/src/test/kotlin/com/lykke/matching/engine/utils/MessageBuilder.kt @@ -374,6 +374,8 @@ companion object { order.lowerPrice?.let { builder.setLowerPrice(it.toDouble()) } order.upperLimitPrice?.let { builder.setUpperLimitPrice(it.toDouble()) } order.upperPrice?.let { builder.setUpperPrice(it.toDouble()) } + order.expiryTime?.let { builder.setExpiryTime(it.time) } + order.timeInForce?.let { builder.setTimeInForce(it.externalId) } val messageWrapper = MessageWrapper("Test", MessageType.LIMIT_ORDER.type, builder.build().toByteArray(), TestClientHandler(), messageId = "test", id = "test") singleLimitOrderPreprocessor.preProcess(messageWrapper) From 3a86f9142a35d141f16b115ed9302f0ac8070110 Mon Sep 17 00:00:00 2001 From: papchenko Date: Mon, 8 Apr 2019 13:37:33 +0300 Subject: [PATCH 05/14] LWDEV-9478 merge fixes --- src/dist/cfg/log4j2.xml | 5 +++++ .../parsers/impl/MultilimitOrderContextParser.kt | 6 ++++-- .../matching/engine/config/TestApplicationContext.kt | 11 +++++++---- .../matching/engine/config/TestExecutionContext.kt | 3 ++- .../engine/performance/AbstractPerformanceTest.kt | 7 +------ 5 files changed, 19 insertions(+), 13 deletions(-) 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/incoming/parsers/impl/MultilimitOrderContextParser.kt b/src/main/kotlin/com/lykke/matching/engine/incoming/parsers/impl/MultilimitOrderContextParser.kt index 74fe4fd2d..c47e83360 100644 --- 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 @@ -12,6 +12,7 @@ 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 @@ -31,7 +32,8 @@ class MultilimitOrderContextParser( val logger: ThrottlingLogger, val applicationSettingsHolder: ApplicationSettingsHolder, val assertPairsHolder: AssetsPairsHolder, - val assetsHolder: AssetsHolder) : ContextParser { + val assetsHolder: AssetsHolder, + val uuid: UUIDHolder) : ContextParser { override fun parse(messageWrapper: MessageWrapper): MultilimitOrderParsedData { val message = parseMultiLimitOrder(messageWrapper.byteArray) val trustedClient = applicationSettingsHolder.isTrustedClient(message.clientId) @@ -114,7 +116,7 @@ class MultilimitOrderContextParser( val feeInstructions = NewLimitOrderFeeInstruction.create(currentOrder.feesList) val previousExternalId = if (currentOrder.hasOldUid()) currentOrder.oldUid else null - val order = LimitOrder(UUID.randomUUID().toString(), + val order = LimitOrder(uuid.getNextValue(), currentOrder.uid, message.assetPairId, message.clientId, 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 7f13c731d..aa077ce7d 100644 --- a/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt +++ b/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt @@ -352,13 +352,15 @@ open class TestApplicationContext { assetsHolder: AssetsHolder, assetsPairsHolder: AssetsPairsHolder, balancesHolder: BalancesHolder, - applicationSettingsHolder: ApplicationSettingsHolder): MultiLimitOrderService { + applicationSettingsHolder: ApplicationSettingsHolder, + uuidHolder: TestUUIDHolder): MultiLimitOrderService { return MultiLimitOrderService(executionContextFactory, genericLimitOrdersProcessor, stopOrderBookProcessor, executionDataApplyService, previousLimitOrdersProcessor, - balancesHolder) + balancesHolder, + uuidHolder) } @Bean @@ -591,8 +593,9 @@ open class TestApplicationContext { @Bean open fun multilimitOrderContextParser(applicationSettingsHolder: ApplicationSettingsHolder, assetsPairsHolder: AssetsPairsHolder, - assetsHolder: AssetsHolder): MultilimitOrderContextParser { - return MultilimitOrderContextParser(ThrottlingLogger.getLogger("multilimitOrder"), applicationSettingsHolder, assetsPairsHolder, assetsHolder) + assetsHolder: AssetsHolder, + uuidHolder: UUIDHolder): MultilimitOrderContextParser { + return MultilimitOrderContextParser(ThrottlingLogger.getLogger("multilimitOrder"), applicationSettingsHolder, assetsPairsHolder, assetsHolder, uuidHolder) } @Bean 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 9a317aaa0..3db1ce1ec 100644 --- a/src/test/kotlin/com/lykke/matching/engine/config/TestExecutionContext.kt +++ b/src/test/kotlin/com/lykke/matching/engine/config/TestExecutionContext.kt @@ -115,7 +115,8 @@ open class TestExecutionContext { @Bean open fun stopLimitOrdersProcessor(stopOrderBusinessValidator: StopOrderBusinessValidator, applicationSettingsHolder: ApplicationSettingsHolder, - limitOrderProcessor: LimitOrderProcessor): StopLimitOrderProcessor { + limitOrderProcessor: LimitOrderProcessor, + uuidHolder: UUIDHolder): StopLimitOrderProcessor { return StopLimitOrderProcessor( stopOrderBusinessValidator, applicationSettingsHolder, 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 7e48de5a6..b96210f9b 100644 --- a/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt @@ -189,7 +189,7 @@ abstract class AbstractPerformanceTest { LimitOrderCancelOperationContextParser(), LimitOrderMassCancelOperationContextParser(), MultilimitOrderPreprocessor(messageProcessingStatusHolder, limitOrderInputValidator, MultilimitOrderContextParser(ThrottlingLogger.getLogger("test"), - applicationSettingsHolder, assetsPairsHolder, assetsHolder), + applicationSettingsHolder, assetsPairsHolder, assetsHolder, uuidHolder), LinkedBlockingQueue(), ThrottlingLogger.getLogger("test"))) genericStopLimitOrderService = GenericStopLimitOrderService(stopOrdersDatabaseAccessorsHolder, expiryOrdersQueue) @@ -246,12 +246,7 @@ abstract class AbstractPerformanceTest { stopOrderBookProcessor, executionDataApplyService, previousLimitOrdersProcessor, - assetsHolder, - balancesHolder, - assetsPairsHolder, balancesHolder, - applicationSettingsHolder, - messageProcessingStatusHolder, uuidHolder) val marketOrderValidator = MarketOrderValidatorImpl(assetsPairsHolder, assetsHolder, applicationSettingsHolder) From 99abe7b92e1c457ffcd0f38f9455d9a8c12bd1fd Mon Sep 17 00:00:00 2001 From: papchenko Date: Fri, 12 Apr 2019 09:31:54 +0300 Subject: [PATCH 06/14] LWDEV-8274 refactoring --- .../incoming/listener/InputQueueListener.kt | 23 ++++++++++++++++++- .../impl/MultilimitOrderContextParser.kt | 5 +++- 2 files changed, 26 insertions(+), 2 deletions(-) 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/impl/MultilimitOrderContextParser.kt b/src/main/kotlin/com/lykke/matching/engine/incoming/parsers/impl/MultilimitOrderContextParser.kt index c47e83360..12ad1a818 100644 --- 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 @@ -148,7 +148,7 @@ class MultilimitOrderContextParser( } if (cancelAllPreviousLimitOrders && cancelMode == OrderCancelMode.NOT_EMPTY_SIDE) { - if (currentOrder.volume > 0) { + if (isBuyOrder(currentOrder)) { cancelBuySide = true } else { cancelSellSide = true @@ -168,6 +168,9 @@ class MultilimitOrderContextParser( sellReplacements) } + fun isBuyOrder(currentOrder: ProtocolMessages.MultiLimitOrder.Order) = + currentOrder.volume > 0 + private fun getIncomingOrderInfo(incomingOrder: ProtocolMessages.MultiLimitOrder.Order): String { return "id: ${incomingOrder.uid}" + (if (incomingOrder.hasType()) ", type: ${incomingOrder.type}" else "") + From 3b9401304fede233976a24a2d634cf010e079faf Mon Sep 17 00:00:00 2001 From: papchenko Date: Mon, 15 Apr 2019 09:50:20 +0300 Subject: [PATCH 07/14] LWDEV-8274 fixes --- .../daos/context/MultilimitOrderContext.kt | 1 - .../impl/MultilimitOrderContextParser.kt | 7 +- .../impl/MultilimitOrderPreprocessor.kt | 23 ++++--- .../impl/SingleLimitOrderPreprocessor.kt | 8 +-- .../engine/services/MultiLimitOrderService.kt | 20 +++--- .../validators/common/OrderValidationUtils.kt | 4 ++ .../engine/config/TestApplicationContext.kt | 6 +- .../impl/MultilimitOrerPreprocessorTest.kt | 66 +++++++++++++++++++ .../impl/SingleLimitOrderPreprocessorTest.kt | 15 ++--- .../performance/AbstractPerformanceTest.kt | 3 +- .../matching/engine/utils/MessageBuilder.kt | 2 +- 11 files changed, 109 insertions(+), 46 deletions(-) create mode 100644 src/test/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/MultilimitOrerPreprocessorTest.kt 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 index d7d29275f..2fb562553 100644 --- a/src/main/kotlin/com/lykke/matching/engine/daos/context/MultilimitOrderContext.kt +++ b/src/main/kotlin/com/lykke/matching/engine/daos/context/MultilimitOrderContext.kt @@ -8,7 +8,6 @@ import com.lykke.matching.engine.services.validators.impl.OrderValidationResult class MultilimitOrderContext(val assetPair: AssetPair?, val baseAsset: Asset?, val quotingAsset: Asset?, - val clientId: String, val isTrustedClient: Boolean, val multiLimitOrder: MultiLimitOrder, var inputValidationResultByOrderId: Map? = null) \ 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 index 12ad1a818..fe917fc79 100644 --- 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 @@ -70,7 +70,6 @@ class MultilimitOrderContextParser( return MultilimitOrderContext(assetPair, baseAsset, quotingAsset, - message.clientId, trustedClient, readMultiLimitOrder(messageId, message, trustedClient)) } @@ -168,7 +167,7 @@ class MultilimitOrderContextParser( sellReplacements) } - fun isBuyOrder(currentOrder: ProtocolMessages.MultiLimitOrder.Order) = + private fun isBuyOrder(currentOrder: ProtocolMessages.MultiLimitOrder.Order) = currentOrder.volume > 0 private fun getIncomingOrderInfo(incomingOrder: ProtocolMessages.MultiLimitOrder.Order): String { @@ -181,8 +180,8 @@ class MultilimitOrderContextParser( (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.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 "") } 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 index 949bbd3c9..5797fb061 100644 --- 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 @@ -8,7 +8,8 @@ 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.order.OrderStatus +import com.lykke.matching.engine.messages.ProtocolMessages +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 @@ -29,7 +30,9 @@ class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: Mes override fun preProcessParsedData(parsedData: MultilimitOrderParsedData): Boolean { val context = parsedData.messageWrapper.context as MultilimitOrderContext if (messageProcessingStatusHolder.isTradeDisabled(context.assetPair)) { - writeResponse(parsedData.messageWrapper, MessageStatus.MESSAGE_PROCESSING_DISABLED) + writeResponse(parsedData.messageWrapper, + context.multiLimitOrder.assetPairId, + MessageStatus.MESSAGE_PROCESSING_DISABLED) return false } @@ -40,13 +43,21 @@ class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: Mes if (fatallyInvalidValidationResult != null) { logger.error("Fatal validation error occurred, ${fatallyInvalidValidationResult.message} " + "Error details: $context") - writeResponse(parsedData.messageWrapper, MessageStatusUtils.toMessageStatus(fatallyInvalidValidationResult.status!!), fatallyInvalidValidationResult.message) + writeResponse(parsedData.messageWrapper, + context.multiLimitOrder.assetPairId, + MessageStatusUtils.toMessageStatus(fatallyInvalidValidationResult.status!!), + fatallyInvalidValidationResult.message) return false } return true } + fun writeResponse(messageWrapper: MessageWrapper, assetPairId: String, status: MessageStatus, message: String? = null) { + messageWrapper.writeMultiLimitOrderResponse(ProtocolMessages.MultiLimitOrderResponse.newBuilder() + .setStatus(status.type).setAssetPairId(assetPairId)) + } + private fun getValidationResult(context: MultilimitOrderContext): Map { val orderValidationResultByOrderId = HashMap() for (order in context.multiLimitOrder.orders) { @@ -60,15 +71,11 @@ class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: Mes LimitOrderType.STOP_LIMIT -> limitOrderInputValidator.validateStopOrder(order, context.assetPair, order.assetPairId, context.baseAsset) } } catch (e: OrderValidationException) { - val fatalInvalid = isFatalInvalid(e) + val fatalInvalid = OrderValidationUtils.isFatalInvalid(e) orderValidationResultByOrderId[order.id] = OrderValidationResult(false, fatalInvalid, e.message, e.orderStatus) } } return orderValidationResultByOrderId } - - 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/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/services/MultiLimitOrderService.kt b/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt index 28d1f8b8d..c4bd6243a 100644 --- a/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt +++ b/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt @@ -1,10 +1,8 @@ package com.lykke.matching.engine.services -import com.lykke.matching.engine.daos.AssetPair import com.lykke.matching.engine.daos.LimitOrder import com.lykke.matching.engine.daos.context.MultilimitOrderContext import com.lykke.matching.engine.holders.BalancesHolder -import com.lykke.matching.engine.holders.UUIDHolder import com.lykke.matching.engine.messages.MessageStatus import com.lykke.matching.engine.messages.MessageType import com.lykke.matching.engine.messages.MessageWrapper @@ -26,8 +24,7 @@ class MultiLimitOrderService(private val executionContextFactory: ExecutionConte private val stopOrderBookProcessor: StopOrderBookProcessor, private val executionDataApplyService: ExecutionDataApplyService, private val previousLimitOrdersProcessor: PreviousLimitOrdersProcessor, - private val balancesHolder: BalancesHolder, - private val uuidHolder: UUIDHolder) : AbstractService { + private val balancesHolder: BalancesHolder) : AbstractService { companion object { private val LOGGER = LoggerFactory.getLogger(MultiLimitOrderService::class.java.name) @@ -44,7 +41,7 @@ class MultiLimitOrderService(private val executionContextFactory: ExecutionConte val context = messageWrapper.context as MultilimitOrderContext val now = Date() - val ordersToProcess = getOrdersToProcess(context, context.assetPair!!, now) + val ordersToProcess = getOrdersToProcess(context, now) val multiLimitOrder = context.multiLimitOrder @@ -52,7 +49,7 @@ class MultiLimitOrderService(private val executionContextFactory: ExecutionConte messageWrapper.id!!, MessageType.MULTI_LIMIT_ORDER, messageWrapper.processedMessage, - mapOf(Pair(context.assetPair.assetPairId, context.assetPair)), + mapOf(Pair(context.assetPair!!.assetPairId, context.assetPair)), now, LOGGER, mapOf(Pair(context.baseAsset!!.assetId, context.baseAsset), @@ -103,19 +100,20 @@ class MultiLimitOrderService(private val executionContextFactory: ExecutionConte } - fun getOrdersToProcess(context: MultilimitOrderContext, assetPair: AssetPair, now: Date): List { - val baseAssetAvailableBalance = balancesHolder.getAvailableBalance(context.clientId, context.assetPair!!.baseAssetId) - val quotingAssetAvailableBalance = balancesHolder.getAvailableBalance(context.clientId, assetPair.quotingAssetId) + 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 filter = MultiOrderFilter(context.isTrustedClient, baseAssetAvailableBalance, quotingAssetAvailableBalance, context.quotingAsset!!.accuracy, now, - context.multiLimitOrder.orders.size, + multiLimitOrder.orders.size, LOGGER) - for (order in context.multiLimitOrder.orders) { + for (order in multiLimitOrder.orders) { filter.checkAndAdd(order) } 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 e6e5ee3cc..955ea3b60 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 @@ -27,5 +27,9 @@ class OrderValidationUtils { throw OrderValidationException(OrderStatus.Cancelled, "expired") } } + + fun isFatalInvalid(validationException: OrderValidationException): Boolean { + return validationException.orderStatus == OrderStatus.UnknownAsset + } } } \ 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 aa077ce7d..7c7f77831 100644 --- a/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt +++ b/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt @@ -352,15 +352,13 @@ open class TestApplicationContext { assetsHolder: AssetsHolder, assetsPairsHolder: AssetsPairsHolder, balancesHolder: BalancesHolder, - applicationSettingsHolder: ApplicationSettingsHolder, - uuidHolder: TestUUIDHolder): MultiLimitOrderService { + applicationSettingsHolder: ApplicationSettingsHolder): MultiLimitOrderService { return MultiLimitOrderService(executionContextFactory, genericLimitOrdersProcessor, stopOrderBookProcessor, executionDataApplyService, previousLimitOrdersProcessor, - balancesHolder, - uuidHolder) + balancesHolder) } @Bean 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 4404edfed..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 @@ -29,6 +30,10 @@ class SingleLimitOrderPreprocessorTest: AbstractTest() { //preprocessing is performed during message building val messageWrapper = messageBuilder.buildLimitOrderWrapper(MessageBuilder.buildLimitOrder(assetId = "UnknownAssetPair")) + assertResponse(messageWrapper) + } + + fun assertResponse(messageWrapper: MessageWrapper) { val clientHandler = messageWrapper.clientHandler!! as TestClientHandler assertEquals(1, clientHandler.responses.size) @@ -45,14 +50,6 @@ class SingleLimitOrderPreprocessorTest: AbstractTest() { val messageWrapper = messageBuilder.buildLimitOrderWrapper(MessageBuilder.buildLimitOrder(assetId = "UnknownAssetPair", type = LimitOrderType.STOP_LIMIT, lowerPrice = 1.0, lowerLimitPrice = 1.0)) - 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 b96210f9b..305680d4f 100644 --- a/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt @@ -246,8 +246,7 @@ abstract class AbstractPerformanceTest { stopOrderBookProcessor, executionDataApplyService, previousLimitOrdersProcessor, - balancesHolder, - uuidHolder) + balancesHolder) val marketOrderValidator = MarketOrderValidatorImpl(assetsPairsHolder, assetsHolder, applicationSettingsHolder) marketOrderService = MarketOrderService(matchingEngine, 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 6e9b3e184..3a966ea31 100644 --- a/src/test/kotlin/com/lykke/matching/engine/utils/MessageBuilder.kt +++ b/src/test/kotlin/com/lykke/matching/engine/utils/MessageBuilder.kt @@ -345,7 +345,7 @@ companion object { val messageWrapper = MessageWrapper("Test", MessageType.MULTI_LIMIT_ORDER.type, buildMultiLimitOrder(pair, clientId, orders, cancel, - cancelMode).toByteArray(), null, messageId = "test", id = "test") + cancelMode).toByteArray(), TestClientHandler(), messageId = "test", id = "test") multilimitOrderPreprocessor.preProcess(messageWrapper) return messageWrapper } From e27c82e3fa67c1b3770212082cdf359785ba45e4 Mon Sep 17 00:00:00 2001 From: papchenko Date: Mon, 15 Apr 2019 10:13:26 +0300 Subject: [PATCH 08/14] LWDEV-8274 context is not displayed properly on log messages --- .../engine/daos/context/LimitOrderMassCancelOperationContext.kt | 2 +- .../matching/engine/daos/context/MultilimitOrderContext.kt | 2 +- .../matching/engine/daos/context/SingleLimitOrderContext.kt | 2 +- .../engine/services/validators/impl/OrderValidationResult.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) 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 fcb14d0ed..bf5ed6602 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 index 2fb562553..891c482c8 100644 --- a/src/main/kotlin/com/lykke/matching/engine/daos/context/MultilimitOrderContext.kt +++ b/src/main/kotlin/com/lykke/matching/engine/daos/context/MultilimitOrderContext.kt @@ -5,7 +5,7 @@ import com.lykke.matching.engine.daos.AssetPair import com.lykke.matching.engine.daos.MultiLimitOrder import com.lykke.matching.engine.services.validators.impl.OrderValidationResult -class MultilimitOrderContext(val assetPair: AssetPair?, +data class MultilimitOrderContext(val assetPair: AssetPair?, val baseAsset: Asset?, val quotingAsset: Asset?, val isTrustedClient: Boolean, 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..aaa4be4dc 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 @@ -7,7 +7,7 @@ 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?, 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) From 81451b4f0efe46755e13863149aa182445695486 Mon Sep 17 00:00:00 2001 From: papchenko Date: Mon, 15 Apr 2019 12:36:32 +0300 Subject: [PATCH 09/14] LWDEV-8274 add limit order to string --- .../lykke/matching/engine/daos/LimitOrder.kt | 32 ++++++++++++++++ .../daos/context/SingleLimitOrderContext.kt | 20 +--------- .../impl/MultilimitOrderContextParser.kt | 37 +++---------------- 3 files changed, 39 insertions(+), 50 deletions(-) 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..77e2dad70 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: $previousExternalId" 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/SingleLimitOrderContext.kt b/src/main/kotlin/com/lykke/matching/engine/daos/context/SingleLimitOrderContext.kt index aaa4be4dc..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,7 +5,6 @@ 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 data class SingleLimitOrderContext(val messageId: String, val limitOrder: LimitOrder, @@ -30,25 +29,10 @@ data 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/parsers/impl/MultilimitOrderContextParser.kt b/src/main/kotlin/com/lykke/matching/engine/incoming/parsers/impl/MultilimitOrderContextParser.kt index fe917fc79..2745adbe1 100644 --- 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 @@ -19,7 +19,6 @@ 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.utils.logging.ThrottlingLogger import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component @@ -98,9 +97,7 @@ class MultilimitOrderContextParser( val sellReplacements = mutableMapOf() val orders = ArrayList() 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 @@ -141,6 +138,10 @@ class MultilimitOrderContextParser( 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 @@ -169,32 +170,4 @@ class MultilimitOrderContextParser( private fun isBuyOrder(currentOrder: ProtocolMessages.MultiLimitOrder.Order) = currentOrder.volume > 0 - - 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 "") - } } \ No newline at end of file From f27019236387ee390ed3e778f8d5865eb130bba9 Mon Sep 17 00:00:00 2001 From: papchenko Date: Mon, 15 Apr 2019 16:22:23 +0300 Subject: [PATCH 10/14] LWDEV-8274 perform asset validation only once for order --- .../daos/context/MultilimitOrderContext.kt | 12 +-- .../parsers/data/MultilimitOrderParsedData.kt | 2 +- .../impl/MultilimitOrderContextParser.kt | 2 +- .../impl/MultilimitOrderPreprocessor.kt | 43 +++++--- .../engine/services/MultiLimitOrderService.kt | 2 +- .../MultilimitOrderValidationResult.kt | 6 ++ .../input/LimitOrderInputValidator.kt | 2 +- .../validators/input/OrderInputValidator.kt | 27 +++++ .../impl/LimitOrderInputValidatorImpl.kt | 11 +-- .../input/impl/OrderInputValidatorImpl.kt | 98 +++++++++++++++++++ .../engine/config/TestApplicationContext.kt | 13 ++- .../performance/AbstractPerformanceTest.kt | 6 +- 12 files changed, 194 insertions(+), 30 deletions(-) create mode 100644 src/main/kotlin/com/lykke/matching/engine/services/validators/MultilimitOrderValidationResult.kt create mode 100644 src/main/kotlin/com/lykke/matching/engine/services/validators/input/OrderInputValidator.kt create mode 100644 src/main/kotlin/com/lykke/matching/engine/services/validators/input/impl/OrderInputValidatorImpl.kt 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 index 891c482c8..49d21ff82 100644 --- a/src/main/kotlin/com/lykke/matching/engine/daos/context/MultilimitOrderContext.kt +++ b/src/main/kotlin/com/lykke/matching/engine/daos/context/MultilimitOrderContext.kt @@ -3,11 +3,11 @@ 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.impl.OrderValidationResult +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 inputValidationResultByOrderId: Map? = null) \ No newline at end of file + 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/incoming/parsers/data/MultilimitOrderParsedData.kt b/src/main/kotlin/com/lykke/matching/engine/incoming/parsers/data/MultilimitOrderParsedData.kt index ba0ed198e..126f19d99 100644 --- 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 @@ -2,4 +2,4 @@ package com.lykke.matching.engine.incoming.parsers.data import com.lykke.matching.engine.messages.MessageWrapper -class MultilimitOrderParsedData(messageWrapper: MessageWrapper) : ParsedData(messageWrapper) \ No newline at end of file +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 index 2745adbe1..ad5225189 100644 --- 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 @@ -47,7 +47,7 @@ class MultilimitOrderContextParser( ProcessedMessage(messageWrapper.type, messageWrapper.timestamp!!, messageWrapper.messageId!!) } - return MultilimitOrderParsedData(messageWrapper) + return MultilimitOrderParsedData(messageWrapper, message.assetPairId) } private fun parseMultiLimitOrder(array: ByteArray): ProtocolMessages.MultiLimitOrder { 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 index 5797fb061..64aec7840 100644 --- 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 @@ -9,19 +9,24 @@ import com.lykke.matching.engine.incoming.preprocessor.AbstractMessagePreprocess 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") @@ -36,17 +41,21 @@ class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: Mes return false } - val validationResult = getValidationResult(context) - context.inputValidationResultByOrderId = validationResult + context.multilimitOrderValidationResult = getValidationResult(parsedData) - val fatallyInvalidValidationResult = validationResult.values.find { it.isFatalInvalid } - if (fatallyInvalidValidationResult != null) { - logger.error("Fatal validation error occurred, ${fatallyInvalidValidationResult.message} " + + 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.status!!), - fatallyInvalidValidationResult.message) + MessageStatusUtils.toMessageStatus(fatallyInvalidValidationResult.get().status!!), + fatallyInvalidValidationResult.get().message) return false } @@ -55,18 +64,30 @@ class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: Mes fun writeResponse(messageWrapper: MessageWrapper, assetPairId: String, status: MessageStatus, message: String? = null) { messageWrapper.writeMultiLimitOrderResponse(ProtocolMessages.MultiLimitOrderResponse.newBuilder() - .setStatus(status.type).setAssetPairId(assetPairId)) + .setStatus(status.type) + .setAssetPairId(assetPairId)) } - private fun getValidationResult(context: MultilimitOrderContext): Map { + 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, - order.assetPairId, + null, context.baseAsset) LimitOrderType.STOP_LIMIT -> limitOrderInputValidator.validateStopOrder(order, context.assetPair, order.assetPairId, context.baseAsset) } @@ -76,6 +97,6 @@ class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: Mes } } - return orderValidationResultByOrderId + return MultilimitOrderValidationResult(OrderValidationResult(true), orderValidationResultByOrderId) } } \ No newline at end of file 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 c4bd6243a..39c58bf96 100644 --- a/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt +++ b/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt @@ -54,7 +54,7 @@ class MultiLimitOrderService(private val executionContextFactory: ExecutionConte LOGGER, mapOf(Pair(context.baseAsset!!.assetId, context.baseAsset), Pair(context.quotingAsset!!.assetId, context.quotingAsset)), - context.inputValidationResultByOrderId ?: emptyMap()) + context.multilimitOrderValidationResult?.inputValidationResultByOrderId ?: emptyMap()) previousLimitOrdersProcessor.cancelAndReplaceOrders(multiLimitOrder.clientId, multiLimitOrder.assetPairId, 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/input/LimitOrderInputValidator.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/LimitOrderInputValidator.kt index 8cb9fe53f..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 @@ -11,7 +11,7 @@ interface LimitOrderInputValidator { fun validateLimitOrder(isTrustedClient: Boolean, order: LimitOrder, assetPair: AssetPair?, - assetPairId: String, + assetPairId: String?, baseAsset: Asset?) fun validateStopOrder(limitOrder: LimitOrder, assetPair: AssetPair?, 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..2535289a5 --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/OrderInputValidator.kt @@ -0,0 +1,27 @@ +package com.lykke.matching.engine.services.validators.input + +import com.lykke.matching.engine.daos.Asset +import com.lykke.matching.engine.daos.AssetPair +import com.lykke.matching.engine.daos.LimitOrder + +interface OrderInputValidator { + fun validateAsset(assetPair: AssetPair?, assetPairId: String) + + fun validateFee(order: LimitOrder) + + fun validatePrice(limitOrder: LimitOrder) + + fun validateLimitPrices(order: LimitOrder) + + fun validateValue(order: LimitOrder, assetPair: AssetPair) + + fun validateMaxValue(limitOrder: LimitOrder, assetPair: AssetPair) + + fun validateStopOrderMaxValue(limitOrder: LimitOrder, assetPair: AssetPair) + + fun validateVolume(limitOrder: LimitOrder, assetPair: AssetPair) + + fun validateVolumeAccuracy(limitOrder: LimitOrder, baseAsset: Asset) + + fun validatePriceAccuracy(limitOrder: LimitOrder, assetPair: AssetPair) +} \ 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 df62fa4bc..9a06cec09 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,7 +8,6 @@ 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 @@ -31,13 +30,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 { validateAsset(assetPair, assetPairId) } validatePrice(order) validateVolume(order, assetPair!!) validateMaxValue(order, assetPair) @@ -57,9 +56,9 @@ class LimitOrderInputValidatorImpl(val applicationSettingsHolder: ApplicationSet } override fun validateStopOrder(limitOrder: LimitOrder, - assetPair: AssetPair?, - assetPairId: String, - baseAsset: Asset?) { + assetPair: AssetPair?, + assetPairId: String, + baseAsset: Asset?) { validateAsset(assetPair, assetPairId) validateFee(limitOrder) validateLimitPrices(limitOrder) 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..d0c940568 --- /dev/null +++ b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/impl/OrderInputValidatorImpl.kt @@ -0,0 +1,98 @@ +package com.lykke.matching.engine.services.validators.input.impl + +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.fee.checkFee +import com.lykke.matching.engine.holders.ApplicationSettingsHolder +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.input.OrderInputValidator +import com.lykke.matching.engine.utils.NumberUtils +import org.springframework.stereotype.Component +import java.math.BigDecimal + +@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 validateFee(order: LimitOrder) { + if (order.fee != null && order.fees?.size ?: 0 > 1 || !checkFee(null, order.fees)) { + throw OrderValidationException(OrderStatus.InvalidFee, "has invalid fee") + } + } + + override fun validatePrice(limitOrder: LimitOrder) { + if (limitOrder.price <= BigDecimal.ZERO) { + throw OrderValidationException(OrderStatus.InvalidPrice, "price is invalid") + } + } + + override fun validateLimitPrices(order: LimitOrder) { + if ((order.lowerLimitPrice == null && order.lowerPrice == null && order.upperLimitPrice == null && order.upperPrice == null) || + ((order.lowerLimitPrice == null).xor(order.lowerPrice == null)) || + ((order.upperLimitPrice == null).xor(order.upperPrice == null)) || + (order.lowerLimitPrice != null && (order.lowerLimitPrice <= BigDecimal.ZERO || order.lowerPrice!! <= BigDecimal.ZERO)) || + (order.upperLimitPrice != null && (order.upperLimitPrice <= BigDecimal.ZERO || order.upperPrice!! <= BigDecimal.ZERO)) || + (order.lowerLimitPrice != null && order.upperLimitPrice != null && order.lowerLimitPrice >= order.upperLimitPrice)) { + throw OrderValidationException(OrderStatus.InvalidPrice, "limit prices are invalid") + } + } + + override fun validateValue(order: LimitOrder, assetPair: AssetPair) { + if (assetPair.maxValue != null && order.getAbsVolume() * order.price > assetPair.maxValue) { + throw OrderValidationException(OrderStatus.InvalidValue, "value is too large") + } + } + + override fun validateMaxValue(limitOrder: LimitOrder, assetPair: AssetPair) { + if (assetPair.maxVolume != null && limitOrder.getAbsVolume() > assetPair.maxVolume) { + throw OrderValidationException(OrderStatus.InvalidVolume, "volume is too large") + } + } + + override fun validateStopOrderMaxValue(limitOrder: LimitOrder, assetPair: AssetPair) { + validateMaxValue(limitOrder, assetPair) + + if (assetPair.maxValue != null && (limitOrder.lowerLimitPrice != null && limitOrder.getAbsVolume() * limitOrder.lowerPrice!! > assetPair.maxValue + || limitOrder.upperLimitPrice != null && limitOrder.getAbsVolume() * limitOrder.upperPrice!! > assetPair.maxValue)) { + throw OrderValidationException(OrderStatus.InvalidValue, "value is too large") + } + } + + override 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)) { + throw OrderValidationException(OrderStatus.TooSmallVolume, "volume is too small") + } + } + + override fun validateVolumeAccuracy(limitOrder: LimitOrder, baseAsset: Asset) { + val baseAssetAccuracy = baseAsset.accuracy + + val volumeAccuracyValid = NumberUtils.isScaleSmallerOrEqual(limitOrder.volume, baseAssetAccuracy) + if (!volumeAccuracyValid) { + throw OrderValidationException(OrderStatus.InvalidVolumeAccuracy, "volume accuracy is invalid") + } + } + + override fun validatePriceAccuracy(limitOrder: LimitOrder, assetPair: AssetPair) { + val priceAccuracyValid = NumberUtils.isScaleSmallerOrEqual(limitOrder.price, assetPair.accuracy) + if (!priceAccuracyValid) { + throw OrderValidationException(OrderStatus.InvalidPriceAccuracy, "price accuracy is invalid") + } + } +} \ 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 7c7f77831..3cf4e8382 100644 --- a/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt +++ b/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt @@ -57,10 +57,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 @@ -264,6 +266,11 @@ open class TestApplicationContext { cashInOutOperationBusinessValidator, messageSequenceNumberHolder, messageSender) } + @Bean + fun orderValidator(applicationSettingsHolder: ApplicationSettingsHolder): OrderInputValidator { + return OrderInputValidatorImpl(applicationSettingsHolder) + } + @Bean open fun marketOrderValidator(assetsPairsHolder: AssetsPairsHolder, assetsHolder: AssetsHolder, @@ -680,10 +687,12 @@ open class TestApplicationContext { open fun multiltilimitOrderPreprocessor(messageProcessingStatusHolder: MessageProcessingStatusHolder, limitOrderInputValidator: LimitOrderInputValidator, multilimitOrderContextParser: MultilimitOrderContextParser, - preProcessedMessageQueue: BlockingQueue - ): MultilimitOrderPreprocessor { + preProcessedMessageQueue: BlockingQueue, + orderInputValidator: OrderInputValidator + ): MultilimitOrderPreprocessor { return MultilimitOrderPreprocessor(messageProcessingStatusHolder, limitOrderInputValidator, + orderInputValidator, multilimitOrderContextParser, preProcessedMessageQueue, ThrottlingLogger.getLogger("multilimitOrder")) 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 305680d4f..81d52440c 100644 --- a/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt @@ -53,6 +53,7 @@ import com.lykke.matching.engine.services.validators.business.impl.LimitOrderBus 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 @@ -175,6 +176,7 @@ abstract class AbstractPerformanceTest { val messageSequenceNumberHolder = MessageSequenceNumberHolder(TestMessageSequenceNumberDatabaseAccessor()) val notificationSender = MessageSender(rabbitEventsQueue, rabbitTrustedClientsEventsQueue) val limitOrderInputValidator = LimitOrderInputValidatorImpl(applicationSettingsHolder) + val orderInputValidator = OrderInputValidatorImpl(applicationSettingsHolder) singleLimitOrderContextParser = SingleLimitOrderContextParser(assetsPairsHolder, assetsHolder, applicationSettingsHolder, @@ -188,7 +190,9 @@ abstract class AbstractPerformanceTest { cashTransferContextParser, LimitOrderCancelOperationContextParser(), LimitOrderMassCancelOperationContextParser(), - MultilimitOrderPreprocessor(messageProcessingStatusHolder, limitOrderInputValidator, MultilimitOrderContextParser(ThrottlingLogger.getLogger("test"), + MultilimitOrderPreprocessor(messageProcessingStatusHolder, limitOrderInputValidator, + orderInputValidator, + MultilimitOrderContextParser(ThrottlingLogger.getLogger("test"), applicationSettingsHolder, assetsPairsHolder, assetsHolder, uuidHolder), LinkedBlockingQueue(), ThrottlingLogger.getLogger("test"))) From 33c59744e33221d3ca84b4b11f3bba114305abca Mon Sep 17 00:00:00 2001 From: papchenko Date: Mon, 15 Apr 2019 18:06:22 +0300 Subject: [PATCH 11/14] LWDEV-8274 extract business order validator --- .../engine/services/MultiLimitOrderService.kt | 3 - .../business/OrderBusinessValidator.kt | 10 ++ .../impl/LimitOrderBusinessValidatorImpl.kt | 8 +- .../impl/OrderBusinessValidatorImpl.kt | 24 ++++ .../impl/StopOrderBusinessValidatorImpl.kt | 8 +- .../validators/common/OrderValidationUtils.kt | 23 ---- .../impl/MarketOrderValidatorImpl.kt | 7 +- .../validators/input/OrderInputValidator.kt | 22 +--- .../impl/LimitOrderInputValidatorImpl.kt | 21 +-- .../input/impl/OrderInputValidatorImpl.kt | 78 +---------- .../engine/config/TestApplicationContext.kt | 25 ++-- .../performance/AbstractPerformanceTest.kt | 10 +- .../validator/OrderValidationUtilsTest.kt | 72 +---------- .../LimitOrderBusinessValidatorTest.kt | 7 +- .../business/OrderBusinessValidatorTest.kt | 41 ++++++ .../input/LimitOrderInputValidatorTest.kt | 1 - .../input/OrderInputValidatorTest.kt | 121 ++++++++++++++++++ 17 files changed, 249 insertions(+), 232 deletions(-) create mode 100644 src/main/kotlin/com/lykke/matching/engine/services/validators/business/OrderBusinessValidator.kt create mode 100644 src/main/kotlin/com/lykke/matching/engine/services/validators/business/impl/OrderBusinessValidatorImpl.kt create mode 100644 src/test/kotlin/com/lykke/matching/engine/services/validator/business/OrderBusinessValidatorTest.kt create mode 100644 src/test/kotlin/com/lykke/matching/engine/services/validator/input/OrderInputValidatorTest.kt 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 39c58bf96..645241c5d 100644 --- a/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt +++ b/src/main/kotlin/com/lykke/matching/engine/services/MultiLimitOrderService.kt @@ -31,9 +31,6 @@ class MultiLimitOrderService(private val executionContextFactory: ExecutionConte } override fun processMessage(messageWrapper: MessageWrapper) { - if (messageWrapper.parsedMessage == null) { - parseMessage(messageWrapper) - } processMultiOrder(messageWrapper) } 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 bbb120896..834eeac8f 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 @@ -4,14 +4,14 @@ import com.lykke.matching.engine.daos.LimitOrder 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.common.OrderValidationUtils +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.Date @Component -class LimitOrderBusinessValidatorImpl: LimitOrderBusinessValidator { +class LimitOrderBusinessValidatorImpl(private val orderBusinessValidatorImpl: OrderBusinessValidator): LimitOrderBusinessValidator { override fun performValidation(isTrustedClient: Boolean, order: LimitOrder, availableBalance: BigDecimal, limitVolume: BigDecimal, @@ -19,12 +19,12 @@ class LimitOrderBusinessValidatorImpl: LimitOrderBusinessValidator { date: Date) { 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 e3443c2e0..a0924c20c 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 @@ -1,19 +1,19 @@ package com.lykke.matching.engine.services.validators.business.impl import com.lykke.matching.engine.daos.LimitOrder +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 import java.math.BigDecimal import java.util.* @Component -class StopOrderBusinessValidatorImpl: StopOrderBusinessValidator { +class StopOrderBusinessValidatorImpl(private val orderBusinessValidator: OrderBusinessValidator): StopOrderBusinessValidator { override fun performValidation(availableBalance: BigDecimal, limitVolume: BigDecimal, order: LimitOrder, orderProcessingTime: Date) { - 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 955ea3b60..91438e68c 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,33 +1,10 @@ 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 java.math.BigDecimal -import java.util.Date class OrderValidationUtils { companion object { - 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 } 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/input/OrderInputValidator.kt b/src/main/kotlin/com/lykke/matching/engine/services/validators/input/OrderInputValidator.kt index 2535289a5..266ebb37e 100644 --- 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 @@ -1,27 +1,9 @@ package com.lykke.matching.engine.services.validators.input -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.daos.Order interface OrderInputValidator { + fun checkMinVolume(order: Order, assetPair: AssetPair): Boolean fun validateAsset(assetPair: AssetPair?, assetPairId: String) - - fun validateFee(order: LimitOrder) - - fun validatePrice(limitOrder: LimitOrder) - - fun validateLimitPrices(order: LimitOrder) - - fun validateValue(order: LimitOrder, assetPair: AssetPair) - - fun validateMaxValue(limitOrder: LimitOrder, assetPair: AssetPair) - - fun validateStopOrderMaxValue(limitOrder: LimitOrder, assetPair: AssetPair) - - fun validateVolume(limitOrder: LimitOrder, assetPair: AssetPair) - - fun validateVolumeAccuracy(limitOrder: LimitOrder, baseAsset: Asset) - - fun validatePriceAccuracy(limitOrder: LimitOrder, assetPair: AssetPair) } \ 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 9a06cec09..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,15 +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.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 @@ -36,7 +37,7 @@ class LimitOrderInputValidatorImpl(val applicationSettingsHolder: ApplicationSet validateFee(order) } - assetPairId?.let { validateAsset(assetPair, assetPairId) } + assetPairId?.let { orderInputValidator.validateAsset(assetPair, assetPairId) } validatePrice(order) validateVolume(order, assetPair!!) validateMaxValue(order, assetPair) @@ -59,7 +60,7 @@ class LimitOrderInputValidatorImpl(val applicationSettingsHolder: ApplicationSet assetPair: AssetPair?, assetPairId: String, baseAsset: Asset?) { - validateAsset(assetPair, assetPairId) + orderInputValidator.validateAsset(assetPair, assetPairId) validateFee(limitOrder) validateLimitPrices(limitOrder) validateVolume(limitOrder, assetPair!!) @@ -68,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)) { @@ -123,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 index d0c940568..508877cc9 100644 --- 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 @@ -1,17 +1,12 @@ package com.lykke.matching.engine.services.validators.input.impl -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.fee.checkFee +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.common.OrderValidationUtils import com.lykke.matching.engine.services.validators.impl.OrderValidationException 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 OrderInputValidatorImpl(val applicationSettingsHolder: ApplicationSettingsHolder): OrderInputValidator { @@ -25,74 +20,11 @@ class OrderInputValidatorImpl(val applicationSettingsHolder: ApplicationSettings } } - override fun validateFee(order: LimitOrder) { - if (order.fee != null && order.fees?.size ?: 0 > 1 || !checkFee(null, order.fees)) { - throw OrderValidationException(OrderStatus.InvalidFee, "has invalid fee") - } - } - - override fun validatePrice(limitOrder: LimitOrder) { - if (limitOrder.price <= BigDecimal.ZERO) { - throw OrderValidationException(OrderStatus.InvalidPrice, "price is invalid") - } - } - - override fun validateLimitPrices(order: LimitOrder) { - if ((order.lowerLimitPrice == null && order.lowerPrice == null && order.upperLimitPrice == null && order.upperPrice == null) || - ((order.lowerLimitPrice == null).xor(order.lowerPrice == null)) || - ((order.upperLimitPrice == null).xor(order.upperPrice == null)) || - (order.lowerLimitPrice != null && (order.lowerLimitPrice <= BigDecimal.ZERO || order.lowerPrice!! <= BigDecimal.ZERO)) || - (order.upperLimitPrice != null && (order.upperLimitPrice <= BigDecimal.ZERO || order.upperPrice!! <= BigDecimal.ZERO)) || - (order.lowerLimitPrice != null && order.upperLimitPrice != null && order.lowerLimitPrice >= order.upperLimitPrice)) { - throw OrderValidationException(OrderStatus.InvalidPrice, "limit prices are invalid") - } - } - - override fun validateValue(order: LimitOrder, assetPair: AssetPair) { - if (assetPair.maxValue != null && order.getAbsVolume() * order.price > assetPair.maxValue) { - throw OrderValidationException(OrderStatus.InvalidValue, "value is too large") - } - } - - override fun validateMaxValue(limitOrder: LimitOrder, assetPair: AssetPair) { - if (assetPair.maxVolume != null && limitOrder.getAbsVolume() > assetPair.maxVolume) { - throw OrderValidationException(OrderStatus.InvalidVolume, "volume is too large") - } - } - - override fun validateStopOrderMaxValue(limitOrder: LimitOrder, assetPair: AssetPair) { - validateMaxValue(limitOrder, assetPair) - - if (assetPair.maxValue != null && (limitOrder.lowerLimitPrice != null && limitOrder.getAbsVolume() * limitOrder.lowerPrice!! > assetPair.maxValue - || limitOrder.upperLimitPrice != null && limitOrder.getAbsVolume() * limitOrder.upperPrice!! > assetPair.maxValue)) { - throw OrderValidationException(OrderStatus.InvalidValue, "value is too large") - } - } - - override 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)) { - throw OrderValidationException(OrderStatus.TooSmallVolume, "volume is too small") - } + 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 } - override fun validateVolumeAccuracy(limitOrder: LimitOrder, baseAsset: Asset) { - val baseAssetAccuracy = baseAsset.accuracy - val volumeAccuracyValid = NumberUtils.isScaleSmallerOrEqual(limitOrder.volume, baseAssetAccuracy) - if (!volumeAccuracyValid) { - throw OrderValidationException(OrderStatus.InvalidVolumeAccuracy, "volume accuracy is invalid") - } - } - - override fun validatePriceAccuracy(limitOrder: LimitOrder, assetPair: AssetPair) { - val priceAccuracyValid = NumberUtils.isScaleSmallerOrEqual(limitOrder.price, assetPair.accuracy) - if (!priceAccuracyValid) { - throw OrderValidationException(OrderStatus.InvalidPriceAccuracy, "price accuracy is invalid") - } - } } \ 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 3cf4e8382..58ece38e7 100644 --- a/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt +++ b/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt @@ -267,15 +267,21 @@ open class TestApplicationContext { } @Bean - fun orderValidator(applicationSettingsHolder: ApplicationSettingsHolder): OrderInputValidator { + 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 @@ -604,19 +610,20 @@ open class TestApplicationContext { } @Bean - open fun limitOrderInputValidator(applicationSettingsHolder: ApplicationSettingsHolder): LimitOrderInputValidator { - return LimitOrderInputValidatorImpl(applicationSettingsHolder) + open fun limitOrderInputValidator(applicationSettingsHolder: ApplicationSettingsHolder, + orderInputValidator: OrderInputValidator): LimitOrderInputValidator { + return LimitOrderInputValidatorImpl(applicationSettingsHolder, orderInputValidator) } @Bean - open fun limitOrderBusinessValidator(): LimitOrderBusinessValidator { - return LimitOrderBusinessValidatorImpl() + open fun limitOrderBusinessValidator(orderBusinessValidator: OrderBusinessValidator): LimitOrderBusinessValidator { + return LimitOrderBusinessValidatorImpl(orderBusinessValidator) } @Bean - open fun stopOrderBusinessValidatorImpl(): StopOrderBusinessValidatorImpl { - return StopOrderBusinessValidatorImpl() + open fun stopOrderBusinessValidatorImpl(orderBusinessValidator: OrderBusinessValidator): StopOrderBusinessValidatorImpl { + return StopOrderBusinessValidatorImpl(orderBusinessValidator) } @Bean 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 81d52440c..855feb667 100644 --- a/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/performance/AbstractPerformanceTest.kt @@ -50,6 +50,7 @@ import com.lykke.matching.engine.outgoing.messages.v2.events.Event import com.lykke.matching.engine.outgoing.messages.v2.events.ExecutionEvent 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 @@ -175,8 +176,9 @@ abstract class AbstractPerformanceTest { val messageSequenceNumberHolder = MessageSequenceNumberHolder(TestMessageSequenceNumberDatabaseAccessor()) val notificationSender = MessageSender(rabbitEventsQueue, rabbitTrustedClientsEventsQueue) - val limitOrderInputValidator = LimitOrderInputValidatorImpl(applicationSettingsHolder) val orderInputValidator = OrderInputValidatorImpl(applicationSettingsHolder) + val orderBusinessValidator = OrderBusinessValidatorImpl() + val limitOrderInputValidator = LimitOrderInputValidatorImpl(applicationSettingsHolder, orderInputValidator) singleLimitOrderContextParser = SingleLimitOrderContextParser(assetsPairsHolder, assetsHolder, applicationSettingsHolder, @@ -222,13 +224,13 @@ abstract class AbstractPerformanceTest { val matchingEngine = MatchingEngine(genericLimitOrderService, feeProcessor, uuidHolder) val limitOrderProcessor = LimitOrderProcessor( - LimitOrderBusinessValidatorImpl(), + LimitOrderBusinessValidatorImpl(orderBusinessValidator), applicationSettingsHolder, matchingEngine, matchingResultHandlingHelper) val stopOrderProcessor = StopLimitOrderProcessor( - StopOrderBusinessValidatorImpl(), + StopOrderBusinessValidatorImpl(orderBusinessValidator), applicationSettingsHolder, limitOrderProcessor, uuidHolder) @@ -252,7 +254,7 @@ abstract class AbstractPerformanceTest { previousLimitOrdersProcessor, 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/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 20c8e76de..bf5452b65 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,6 +8,7 @@ import com.lykke.matching.engine.daos.v2.LimitOrderFeeInstruction import com.lykke.matching.engine.order.OrderStatus import com.lykke.matching.engine.services.AssetOrderBook 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 @@ -23,7 +24,7 @@ class LimitOrderBusinessValidatorTest { @Test(expected = OrderValidationException::class) fun testPreviousOrderNotFount() { //given - val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl() + val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl(OrderBusinessValidatorImpl()) try { //when @@ -43,7 +44,7 @@ class LimitOrderBusinessValidatorTest { @Test(expected = OrderValidationException::class) fun testNotEnoughFounds() { //given - val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl() + val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl(OrderBusinessValidatorImpl()) try { //when @@ -63,7 +64,7 @@ class LimitOrderBusinessValidatorTest { @Test fun testValidOrder() { //given - val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl() + val limitOrderBusinessValidatorImpl = LimitOrderBusinessValidatorImpl(OrderBusinessValidatorImpl()) //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 From 590ecf728f82a3038fb620205ac9492fb65601e9 Mon Sep 17 00:00:00 2001 From: papchenko Date: Tue, 16 Apr 2019 09:52:27 +0300 Subject: [PATCH 12/14] LWDEV-8274 refactoring --- .../lykke/matching/engine/daos/LimitOrder.kt | 6 ++-- .../impl/MultilimitOrderPreprocessor.kt | 36 +++++++++++++------ 2 files changed, 29 insertions(+), 13 deletions(-) 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 77e2dad70..c586d0556 100644 --- a/src/main/kotlin/com/lykke/matching/engine/daos/LimitOrder.kt +++ b/src/main/kotlin/com/lykke/matching/engine/daos/LimitOrder.kt @@ -110,7 +110,7 @@ class LimitOrder(id: String, return "id: $externalId" + if(previousExternalId != null) ", previousExternalId: $previousExternalId" else "" + if(parentOrderExternalId != null) ", parentOrderExternalId: $previousExternalId" else "" + - if(childOrderExternalId != null) ", childOrderExternalId: $previousExternalId" else "" + + if(childOrderExternalId != null) ", childOrderExternalId: $childOrderExternalId" else "" + ", type: $type" + ", client: $clientId" + @@ -133,7 +133,7 @@ class LimitOrder(id: String, ", fee: $fee" + ", fees: $fees" + - (if (timeInForce != null) ", timeInForce=$timeInForce" else "") + - (if (expiryTime != null) ", expiryTime=$expiryTime" else "") + (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/incoming/preprocessor/impl/MultilimitOrderPreprocessor.kt b/src/main/kotlin/com/lykke/matching/engine/incoming/preprocessor/impl/MultilimitOrderPreprocessor.kt index 64aec7840..502ec5758 100644 --- 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 @@ -41,11 +41,23 @@ class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: Mes return false } - context.multilimitOrderValidationResult = getValidationResult(parsedData) + 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()) + multilimitOrderValidationResult.inputValidationResultByOrderId?.values?.stream() + ?: Stream.empty()) .filter { it.isFatalInvalid } .findFirst() @@ -59,13 +71,18 @@ class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: Mes return false } - return true - } + //if global non fatal validation occurs - all orders should has this validation error + if (!multilimitOrderValidationResult.globalValidationResult.isValid) { + val validationResultByOrderId = HashMap() - fun writeResponse(messageWrapper: MessageWrapper, assetPairId: String, status: MessageStatus, message: String? = null) { - messageWrapper.writeMultiLimitOrderResponse(ProtocolMessages.MultiLimitOrderResponse.newBuilder() - .setStatus(status.type) - .setAssetPairId(assetPairId)) + context.multiLimitOrder.orders.forEach { + validationResultByOrderId[it.id] = multilimitOrderValidationResult.globalValidationResult + } + + context.multilimitOrderValidationResult = MultilimitOrderValidationResult(multilimitOrderValidationResult.globalValidationResult, validationResultByOrderId) + } + + return true } private fun getValidationResult(parsedData: MultilimitOrderParsedData): MultilimitOrderValidationResult { @@ -74,8 +91,7 @@ class MultilimitOrderPreprocessor(private val messageProcessingStatusHolder: Mes try { orderInputValidator.validateAsset(context.assetPair, parsedData.inputAssetPairId) - } - catch(e: OrderValidationException) { + } catch (e: OrderValidationException) { val fatalInvalid = OrderValidationUtils.isFatalInvalid(e) return MultilimitOrderValidationResult(OrderValidationResult(false, fatalInvalid, e.message, e.orderStatus)) } From ca219a2c66a9238e8463731d9f548672dc183d0b Mon Sep 17 00:00:00 2001 From: papchenko Date: Wed, 24 Apr 2019 10:48:48 +0300 Subject: [PATCH 13/14] LWDEV-8274 merge fixes --- .../matching/engine/services/LimitOrderMassCancelServiceTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 61e1e84e1..9d72f72f3 100644 --- a/src/test/kotlin/com/lykke/matching/engine/services/LimitOrderMassCancelServiceTest.kt +++ b/src/test/kotlin/com/lykke/matching/engine/services/LimitOrderMassCancelServiceTest.kt @@ -100,7 +100,7 @@ class LimitOrderMassCancelServiceTest : AbstractTest() { ))) multiLimitOrderService.processMessage(messageBuilder.buildMultiLimitOrderWrapper("BTCUSD", "TrustedClient", listOf( - IncomingLimitOrder(-1.0, 8500.0), "m3"))) + IncomingLimitOrder(-1.0, 8500.0, "m3")))) assertOrderBookSize("BTCUSD", false, 3) assertOrderBookSize("BTCUSD", true, 1) From 13582bb42176bf369ca3716c5b44b1f38d814c87 Mon Sep 17 00:00:00 2001 From: papchenko Date: Fri, 26 Apr 2019 17:57:50 +0300 Subject: [PATCH 14/14] LWDEV-8274 merge fixes --- .../business/impl/LimitOrderBusinessValidatorImpl.kt | 2 +- .../business/impl/StopOrderBusinessValidatorImpl.kt | 4 ++-- .../matching/engine/config/TestApplicationContext.kt | 10 ++++++---- .../matching/engine/services/OrderBookMaxSizeTest.kt | 3 +-- .../business/LimitOrderBusinessValidatorTest.kt | 4 +++- 5 files changed, 13 insertions(+), 10 deletions(-) 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 b821837fa..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 @@ -6,11 +6,11 @@ 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 orderBusinessValidatorImpl: OrderBusinessValidator, private val orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder): LimitOrderBusinessValidator { 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 714fff4ad..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 @@ -10,8 +10,8 @@ import java.math.BigDecimal import java.util.Date @Component -class StopOrderBusinessValidatorImpl(private val orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder, - private val orderBusinessValidator: OrderBusinessValidator) +class StopOrderBusinessValidatorImpl(private val orderBusinessValidator: OrderBusinessValidator, + private val orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder) : StopOrderBusinessValidator { override fun performValidation(availableBalance: BigDecimal, limitVolume: BigDecimal, 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 0c82247a1..4733f7cb8 100644 --- a/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt +++ b/src/test/kotlin/com/lykke/matching/engine/config/TestApplicationContext.kt @@ -636,8 +636,9 @@ open class TestApplicationContext { } @Bean - open fun limitOrderBusinessValidator(orderBusinessValidator: OrderBusinessValidator): LimitOrderBusinessValidator { - return LimitOrderBusinessValidatorImpl(orderBusinessValidator) + open fun limitOrderBusinessValidator(orderBusinessValidator: OrderBusinessValidator, + orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder): LimitOrderBusinessValidator { + return LimitOrderBusinessValidatorImpl(orderBusinessValidator, orderBookMaxTotalSizeHolder) } @Bean @@ -646,8 +647,9 @@ open class TestApplicationContext { } @Bean - open fun stopOrderBusinessValidatorImpl(orderBusinessValidator: OrderBusinessValidator): StopOrderBusinessValidatorImpl { - return StopOrderBusinessValidatorImpl(orderBusinessValidator) + open fun stopOrderBusinessValidatorImpl(orderBusinessValidator: OrderBusinessValidator, + orderBookMaxTotalSizeHolder: OrderBookMaxTotalSizeHolder): StopOrderBusinessValidatorImpl { + return StopOrderBusinessValidatorImpl(orderBusinessValidator, orderBookMaxTotalSizeHolder) } @Bean 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/validator/business/LimitOrderBusinessValidatorTest.kt b/src/test/kotlin/com/lykke/matching/engine/services/validator/business/LimitOrderBusinessValidatorTest.kt index 86c321773..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,6 +8,7 @@ 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 @@ -67,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