From 6746ced7e42782651b07afea280a8eeac0568dca Mon Sep 17 00:00:00 2001 From: ialbert Date: Fri, 8 May 2026 12:00:05 +0300 Subject: [PATCH] http://jira.mfd.msk:8088/browse/CLS-1000 --- .../listener/OrderCurrencyListener.java | 16 +++++-- .../management/listener/TaskListener.java | 13 ++++- .../service/OrderCalculationService.java | 48 ++++++++++++++----- .../OrderCurrencyTriExportService.java | 16 +++++-- 4 files changed, 72 insertions(+), 21 deletions(-) diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java index 750e5278c..3ee0101f7 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java @@ -29,6 +29,7 @@ import ru.clearing.platform.dictionary.CurrencyPairDictionary; import ru.spcex.clearing.dflt.management.component.validation.OrderCurrencyValidationStored; import ru.spcex.clearing.dflt.management.config.ValidationConfig; import ru.spcex.clearing.dflt.management.service.ImdgQueryService; +import ru.spcex.clearing.dflt.management.service.TransferDateService; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; @@ -69,6 +70,7 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing private final ImdgQueryService imdgQueryService; private final IMessageResolver msgResolver; private final ValidationConfig validationConfig; + private final TransferDateService transferDateService; @Autowired public OrderCurrencyListener(Consumer kafkaQueue, @@ -86,11 +88,12 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing Function orderCurrencyUpdateStatusValidator, Function orderCompanyDeleteValidator, ImdgQueryService imdgQueryService, - IMessageResolver msgResolver, ValidationConfig validationConfig) { + IMessageResolver msgResolver, ValidationConfig validationConfig, TransferDateService transferDateService) { super(kafkaQueue, kafkaProducer); this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class); this.overnightSettingsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_OvernightSettings, OvernightSettings.class); - this.sOrdersImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SOrders, SOrders.class);; + this.sOrdersImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_SOrders, SOrders.class); + this.transferDateService = transferDateService; this.orderCurrencyUpdateValidator = orderCurrencyUpdateValidator; this.orderCurrencyUpdateStatusValidator = orderCurrencyUpdateStatusValidator; this.overnightTypeUpdateValidator = overnightTypeUpdateValidator; @@ -225,11 +228,16 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing Market market = imdgQueryService.getSpotMarket(); Listing listingT0 = imdgQueryService.findListing(rgs, market.getCode(), SettleCode.T0.getKey()); Listing listingT1 = imdgQueryService.findListing(rgs, market.getCode(), SettleCode.T1.getKey()); + LocalDate now = LocalDate.now(); //мб возвращать вместе с листингом? CurrencyPairDictionary currPairT0 = imdgQueryService.getCurrencyPairDictionaryBySecurityId(listingT0.getSecurityId()); - SCrossRate rateT0 = imdgQueryService.getSCrossRates(currPairT0.getBaseCurrency(), LocalDate.now()); + SCrossRate rateT0 = imdgQueryService.getSCrossRates(currPairT0.getBaseCurrency(), now); CurrencyPairDictionary currPairT1 = imdgQueryService.getCurrencyPairDictionaryBySecurityId(listingT1.getSecurityId()); - SCrossRate rateT1 = imdgQueryService.getSCrossRates(currPairT1.getBaseCurrency(), LocalDate.now()); + BigDecimal nextWorkDayDelta = transferDateService.numberOfDaysOfTransfer(); + SCrossRate rateT1 = imdgQueryService.getSCrossRates( + currPairT1.getBaseCurrency(), + now.plusDays(nextWorkDayDelta.longValue()) + ); var pair = new Pair<>(orderT0, orderT1); Pair.forEach(pair, o -> { diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/TaskListener.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/TaskListener.java index f6c00556b..2f217600e 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/TaskListener.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/TaskListener.java @@ -32,6 +32,7 @@ import ru.spcex.clearing.dflt.management.service.ImdgQueryService; import ru.spcex.clearing.dflt.management.service.OrderCurrencyTriExportService; import ru.spcex.clearing.dflt.management.service.SpotOvernightOrderService; import ru.spcex.clearing.dflt.management.service.SwapOvernightOrderService; +import ru.spcex.clearing.dflt.management.service.TransferDateService; import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.Consts; @@ -44,6 +45,7 @@ import ru.spcex.platform.enumeration.ObjectType; import ru.spcex.platform.enumeration.OrderStatus; import ru.spcex.platform.enumeration.OvernightType; import ru.spcex.platform.enumeration.Priority; +import ru.spcex.platform.enumeration.SettleCode; import ru.spcex.platform.enumeration.Task; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; @@ -64,6 +66,7 @@ public class TaskListener extends QueueConsumer implements InitializingBean { private final Path storagePath; private final SendOrdersTypes sendOrdersTypes; private final Charset winCharset = Charset.forName("windows-1251"); + private final TransferDateService transferDateService; @Autowired public TaskListener(Consumer kafkaQueue, @@ -74,7 +77,7 @@ public class TaskListener extends QueueConsumer implements InitializingBean { SpotOvernightOrderService spotOvernightOrderService, OrderCurrencyTriExportService orderCurrencyTriExportService, KafkaSender kafkaSender, - DefaultManagementSettings defaultManagementSettings) { + DefaultManagementSettings defaultManagementSettings, TransferDateService transferDateService) { super(kafkaQueue, kafkaProducer); this.imdgQueryService = imdgQueryService; this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class); @@ -85,6 +88,7 @@ public class TaskListener extends QueueConsumer implements InitializingBean { this.kafkaSender = kafkaSender; this.storagePath = Path.of(defaultManagementSettings.getFileStoragePath()); this.sendOrdersTypes = defaultManagementSettings.getSendOrdersType(); + this.transferDateService = transferDateService; } @Override @@ -182,7 +186,12 @@ public class TaskListener extends QueueConsumer implements InitializingBean { } String currency = isRubPmt ? CurrencyCode.CNY.getKey() : pmtRegistry.getSecuritySymbol(); - SCrossRate sCrossRate = imdgQueryService.getSCrossRates(currency, LocalDate.now()); + LocalDate rateDate = LocalDate.now(); + if (SettleCode.T1.equalsByKey(orderCurrency.getSettleCode())) { + BigDecimal workDayDelta = transferDateService.numberOfDaysOfTransfer(); + rateDate = rateDate.plusDays(workDayDelta.longValue()); + } + SCrossRate sCrossRate = imdgQueryService.getSCrossRates(currency, rateDate); BigDecimal val = orderCurrency.getQuantityLot() .multiply(orderCurrency.getLotSize()) diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java index 4066f2f0e..745d4392a 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCalculationService.java @@ -42,11 +42,16 @@ public class OrderCalculationService { BigDecimal n = transferDateService.numberOfDaysOfTransfer(); CalculationResult result = isRub(registry) - ? calculationRubSums(registry, listing.getLotSize().intValue(), s, n) - : calculationSums(registry, listing.getLotSize().intValue(), s, n); + ? calculationRubSums(registry, listing.getLotSize().intValue(), s, n, settleCode) + : calculationSums(registry, listing.getLotSize().intValue(), s, n, settleCode); BigDecimal quantityLot = result.sum3().abs(); - BigDecimal price = swapPriceCalc(pair.getBaseCurrency(), s, n, listing.getPrecision().intValue()); + BigDecimal price; + if (SettleCode.T1.equals(settleCode)) { + price = swapPriceCalcT1(pair.getBaseCurrency(), s, n, listing.getPrecision().intValue()); + } else { + price = swapPriceCalc(pair.getBaseCurrency(), s, n, listing.getPrecision().intValue()); + } return new FinalCalculationResult(price, s, quantityLot, result); } @@ -61,29 +66,35 @@ public class OrderCalculationService { BigDecimal n = transferDateService.numberOfDaysOfTransfer(); CalculationResult result = isRub(registry) - ? calculationRubSums(registry, listing.getLotSize().intValue(), s, n) - : calculationSums(registry, listing.getLotSize().intValue(), s, n); + ? calculationRubSums(registry, listing.getLotSize().intValue(), s, n, settleCode) + : calculationSums(registry, listing.getLotSize().intValue(), s, n, settleCode); - SCrossRate rates = imdgQueryService.getSCrossRates(pair.getBaseCurrency(), LocalDate.now()); + SCrossRate rates; BigDecimal quantityLot; BigDecimal price; if (SettleCode.T0 == settleCode) { + rates = imdgQueryService.getSCrossRates(pair.getBaseCurrency(), LocalDate.now()); quantityLot = result.sum3().abs(); price = rates.getUnitRate().setScale(listing.getPrecision().intValue(), RoundingMode.HALF_UP); } else { + rates = imdgQueryService.getSCrossRates(pair.getBaseCurrency(), LocalDate.now().plusDays(n.longValue())); quantityLot = result.sum5().abs(); - BigDecimal delta = swapPriceCalc(pair.getBaseCurrency(), s, n, listing.getPrecision().intValue()); + BigDecimal delta = swapPriceCalcT1(pair.getBaseCurrency(), s, n, listing.getPrecision().intValue()); price = rates.getUnitRate().add(delta).setScale(listing.getPrecision().intValue(), RoundingMode.HALF_UP);; } return new FinalCalculationResult(price, s, quantityLot, result); } - private CalculationResult calculationSums(Registry registry, Integer lotSize, BigDecimal s, BigDecimal n) { + private CalculationResult calculationSums(Registry registry, Integer lotSize, BigDecimal s, BigDecimal n, SettleCode settleCode) { BigDecimal planPosition = registry.getBalance(); BigDecimal sum1 = planPosition.abs(); - SCrossRate sCrossRates = imdgQueryService.getSCrossRates(registry.getSecuritySymbol(), LocalDate.now()); + LocalDate rateDate = LocalDate.now(); + if (settleCode.equals(SettleCode.T1)) { + rateDate = rateDate.plusDays(n.longValue()); + } + SCrossRate sCrossRates = imdgQueryService.getSCrossRates(registry.getSecuritySymbol(), rateDate); if (sCrossRates == null) { throw new IllegalStateException(String.format("Not fond rate by security symbol: %s", CurrencyCode.CNY.getKey())); } @@ -102,9 +113,13 @@ public class OrderCalculationService { return new CalculationResult(sum1, BigDecimal.ZERO, sum3, sum4, sum5, sum6); } - private CalculationResult calculationRubSums(Registry registry, Integer lotSize, BigDecimal s, BigDecimal n) { + private CalculationResult calculationRubSums(Registry registry, Integer lotSize, BigDecimal s, BigDecimal n, SettleCode settleCode) { BigDecimal planPosition = registry.getBalance(); - SCrossRate sCrossRates = imdgQueryService.getSCrossRates(CurrencyCode.CNY.getKey(), LocalDate.now()); + LocalDate rateDate = LocalDate.now(); + if (settleCode.equals(SettleCode.T1)) { + rateDate = rateDate.plusDays(n.longValue()); + } + SCrossRate sCrossRates = imdgQueryService.getSCrossRates(CurrencyCode.CNY.getKey(), rateDate); if (sCrossRates == null) { throw new IllegalStateException(String.format("Not fond rate by security symbol: %s", CurrencyCode.CNY.getKey())); } @@ -141,6 +156,17 @@ public class OrderCalculationService { .setScale(precision, RoundingMode.HALF_UP); } + private BigDecimal swapPriceCalcT1(String baseCurrency, BigDecimal s, BigDecimal n, int precision) { + long nextWorkDayDelta = n.longValue(); + Rates rate = imdgQueryService.getRate(baseCurrency, LocalDate.now().plusDays(nextWorkDayDelta)); + BigDecimal p = n.divide(BigDecimal.valueOf(365), MC); + log.info("Calculation swap price: {}*{}*{}", rate.getValue(), s, p); + return rate.getValue() + .multiply(s, MC) + .multiply(p, MC) + .setScale(precision, RoundingMode.HALF_UP); + } + private boolean isRub(Registry registry) { return "RUB".equals(registry.getSecuritySymbol()); } diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCurrencyTriExportService.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCurrencyTriExportService.java index 230b046c9..6ae642a7e 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCurrencyTriExportService.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/service/OrderCurrencyTriExportService.java @@ -19,6 +19,7 @@ import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; import ru.spcex.platform.enumeration.ObjectType; import ru.spcex.platform.enumeration.OvernightType; import ru.spcex.platform.enumeration.Priority; +import ru.spcex.platform.enumeration.SettleCode; import ru.spcex.platform.enumeration.Side; @Service @@ -26,12 +27,14 @@ public class OrderCurrencyTriExportService { private static final Logger log = LoggerFactory.getLogger(OrderCurrencyTriExportService.class); private final ImdgQueryService imdgQueryService; private final KafkaSender kafkaSender; + private final TransferDateService transferDateService; private static final String ACTION = "Ввод внебиржевой заявки"; public OrderCurrencyTriExportService(ImdgQueryService imdgQueryService, - KafkaSender kafkaSender) { + KafkaSender kafkaSender, TransferDateService transferDateService) { this.imdgQueryService = imdgQueryService; this.kafkaSender = kafkaSender; + this.transferDateService = transferDateService; } /** @@ -106,11 +109,16 @@ public class OrderCurrencyTriExportService { CurrencyPairDictionary currencyPairDictionary = imdgQueryService.getCurrencyPairDictionaryBySecurityId(orderCurrency.getSecurityId()); String baseCurrency = currencyPairDictionary.getBaseCurrency(); - LocalDate now = LocalDate.now(); - Rates rates = imdgQueryService.getRate(currencyPairDictionary.getBaseCurrency(), now); + LocalDate rateDate = LocalDate.now(); + + if (SettleCode.T1.equalsByKey(orderCurrency.getSettleCode())) { //всегда т.к. SWAP? + BigDecimal n = transferDateService.numberOfDaysOfTransfer(); + rateDate = rateDate.plusDays(n.longValue()); + } + Rates rates = imdgQueryService.getRate(currencyPairDictionary.getBaseCurrency(), rateDate); if (rates == null || rates.getValue() == null) { - log.warn("Не найден активный курс для валюты {} на дату {}", baseCurrency, now); + log.warn("Не найден активный курс для валюты {} на дату {}", baseCurrency, rateDate); return null; }