diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/element/ClearingServiceSettings.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/element/ClearingServiceSettings.java index 7e9600c2f..bfa0bc150 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/element/ClearingServiceSettings.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/element/ClearingServiceSettings.java @@ -15,6 +15,7 @@ public class ClearingServiceSettings { private KafkaConsumerSettings kafkaConsumer; private KafkaProducerSettings kafkaProducer; private SessionStageSettings sessionStage; + private TradeSettings trade = new TradeSettings(); public HazelcastClientParams getHazelcast() { return hazelcast; @@ -47,4 +48,12 @@ public class ClearingServiceSettings { public void setSessionStage(SessionStageSettings sessionStage) { this.sessionStage = sessionStage; } + + public TradeSettings getTrade() { + return trade; + } + + public void setTrade(TradeSettings trade) { + this.trade = trade; + } } diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/element/TradeSettings.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/element/TradeSettings.java new file mode 100644 index 000000000..b178e3717 --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/element/TradeSettings.java @@ -0,0 +1,14 @@ +package ru.spcex.clearing.config.element; + + +public class TradeSettings { + private Boolean valuation = false; + + public Boolean getValuation() { + return valuation; + } + + public void setValuation(Boolean valuation) { + this.valuation = valuation; + } +} diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/builder/PaymentInstructionBuilderDepositReturn.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/builder/PaymentInstructionBuilderDepositReturn.java deleted file mode 100644 index 897e38acf..000000000 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/builder/PaymentInstructionBuilderDepositReturn.java +++ /dev/null @@ -1,42 +0,0 @@ -package ru.spcex.clearing.service.builder; - -import ru.clearing.classes.statics.data.payment.PaymentInstruction; -import ru.clearing.classes.statics.data.registry.Registry; -import ru.spcex.platform.imdg.api.ImdgProvider; - -import java.math.BigDecimal; - -public class PaymentInstructionBuilderDepositReturn { - - private ImdgProvider imdgProvider; - private Long sessionId; - private BigDecimal amount; - private Registry lm_tRgs; - - public static PaymentInstructionBuilderDepositReturn builder(ImdgProvider imdgProvider) { - return new PaymentInstructionBuilderDepositReturn(imdgProvider); - } - - private PaymentInstructionBuilderDepositReturn(ImdgProvider imdgProvider) { - this.imdgProvider = imdgProvider; - } - - public PaymentInstructionBuilderDepositReturn sessionId(Long sessionId) { - this.sessionId = sessionId; - return this; - } - - public PaymentInstructionBuilderDepositReturn amount(BigDecimal amount) { - this.amount = amount; - return this; - } - - public PaymentInstructionBuilderDepositReturn lm_tRgs(Registry rgs) { - this.lm_tRgs = rgs; - return this; - } - - public PaymentInstruction build() { - return null; - } -} diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/execution/ExecutionFondComponent.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/execution/ExecutionFondComponent.java index 2d3a87e5e..815bb4cc9 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/execution/ExecutionFondComponent.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/service/execution/ExecutionFondComponent.java @@ -11,29 +11,35 @@ import org.springframework.stereotype.Component; import ru.clearing.classes.statics.data.account.ClientCode; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.execution.ExecutionFond; +import ru.clearing.classes.statics.data.instrument.issue.FixedIncomeCashFlow; +import ru.clearing.classes.statics.data.instrument.issue.FixedIncomeSecurity; import ru.clearing.classes.statics.data.misc.Listing; import ru.clearing.classes.statics.data.misc.STrades; import ru.clearing.classes.statics.data.registry.TradingClearingRegistry; import ru.clearing.classes.statics.data.security.Security; +import ru.spcex.clearing.config.element.ClearingServiceSettings; import ru.spcex.clearing.error.ClearingError; import ru.spcex.clearing.error.ClearingException; import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.notification.NotificationSender; import ru.spcex.clearing.platform.messaging.domain.Consts; import ru.spcex.clearing.platform.messaging.domain.cud.registry.DealRegisterNewRequest; import ru.spcex.clearing.platform.messaging.domain.cud.registry.ExecutionType; import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; import ru.spcex.clearing.service.validation.ValidationStored; -import ru.spcex.platform.enumeration.CurrencyCode; -import ru.spcex.platform.enumeration.Section; -import ru.spcex.platform.enumeration.Side; +import ru.spcex.platform.enumeration.*; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicate; import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; import ru.spcex.platform.utils.enumeration.*; import ru.spcex.platform.utils.log.ExceptionUtils; import ru.spcex.platform.utils.time.TimeUtil; import ru.spcex.platform.utils.validation.IValidator; +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; import java.time.Instant; import java.time.LocalDate; import java.util.Collection; @@ -41,6 +47,8 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; +import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD; + @Component @EnableScheduling public class ExecutionFondComponent { @@ -50,6 +58,7 @@ public class ExecutionFondComponent { private final Imdg executionFondImdg; private final Imdg listingImdg; private final Imdg clientCodeImdg; + private final Imdg fixedIncomeCashFlowImdg; private final Imdg marketImdg; //fixme ждать ТЗ @@ -58,19 +67,27 @@ public class ExecutionFondComponent { private final IMessageResolver msgResolver = new SimpleMessageResolver(); private final Function stradesValidator; private final KafkaSender kafkaSender; + private final NotificationSender notifications; + private final boolean valuation; + private static MathContext prec2 = new MathContext(2, RoundingMode.HALF_UP); @Autowired - public ExecutionFondComponent(ImdgProvider imdgProvider, Producer kafka, + public ExecutionFondComponent(ImdgProvider imdgProvider, + ClearingServiceSettings settings, + Producer kafka, @Qualifier("sTradesValidatorFond") Function stradesValidator, - @Qualifier("kafkaSenderWithoutRequestInfo") KafkaSender kafkaSender) { + @Qualifier("kafkaSenderWithoutRequestInfo") KafkaSender kafkaSender, NotificationSender notifications) { this.sTradeImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_STrades, STrades.class); this.executionFondImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ExecutionFond, ExecutionFond.class); this.listingImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Listing, Listing.class); this.clientCodeImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClientCode, ClientCode.class); this.marketImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Market, ru.clearing.classes.statics.data.misc.Market.class); + this.fixedIncomeCashFlowImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_FixedIncomeCashFlow, FixedIncomeCashFlow.class); + this.valuation = settings.getTrade().getValuation(); //fixme this.stradesValidator = stradesValidator; this.kafkaSender = kafkaSender; + this.notifications = notifications; resetTradingDay(); } @@ -165,6 +182,7 @@ public class ExecutionFondComponent { protected ExecutionFond createExecutionFond(STrades sTrades, IValidator validator) throws ClearingException { Security security = validator.getStored(ValidationStored.STradesSecurity); +// Listing listing = listingImdg.getFirstObjectByFieldValues(Map.of("securityId", security.getId())); Company company = validator.getStored(ValidationStored.STradesCompany); Company counterCompany = validator.getStored(ValidationStored.STradesCounterCompany); TradingClearingRegistry rgstr = validator.getStored(ValidationStored.STradesTradingClearingRegistry); @@ -212,7 +230,64 @@ public class ExecutionFondComponent { eFond.setSecurityId(security.getId()); eFond.setInterestAmount(sTrades.getAccruedint()); eFond.setExchangeOrderId(sTrades.getOrderNum()); - eFond.setSettlementAmount(sTrades.getValue()); + if (valuation) { + BigDecimal lots = safeBD(sTrades.getQty());// eFond.getLots + BigDecimal price = safeBD(sTrades.getPrice());// eFond.setPrice + BigDecimal settlementAmount = BigDecimal.ZERO; + if (InstrumentType.BOND.equalsByKey(security.getInstrumentType())) { + FixedIncomeSecurity fixedIncome = (FixedIncomeSecurity) security; + BigDecimal nominalValue; + Listing listing = listingImdg.getFirstObjectBySQL("securityId = %d and market = '%s'".formatted(fixedIncome.getId(), sTrades.getClassCode())); + BigDecimal lotSize = listing != null ? safeBD(listing.getLotSize()) : BigDecimal.ZERO; + BigDecimal ncd = safeBD(sTrades.getAccruedint());// eFond.interestAmount + if (BondType.I.equalsByKey(fixedIncome.getBondType())) { + ImdgPredicateBuilder pb = fixedIncomeCashFlowImdg.predicateBuilder(); + ImdgPredicate prdct = pb.and( + pb.equals("securityId", fixedIncome.getId()), + sTrades.getSettleDate() != null ? + pb.equals("valueDate", sTrades.getSettleDate()) : pb.alwaysFalse() + //fixme в тз settlementDate + ); + FixedIncomeCashFlow cashFlow = fixedIncomeCashFlowImdg.getFirstObjectByPredicate(prdct); + if (cashFlow != null) { + nominalValue = safeBD(cashFlow.getNominalValue()); + } else { + nominalValue = BigDecimal.ZERO; + } + } else { + nominalValue = safeBD(fixedIncome.getNominalValue()); + } + { + lotSize.multiply(lots); + settlementAmount = lotSize.multiply(lots) + .multiply(nominalValue) + .multiply(price) + .divide(new BigDecimal(100), prec2) //first rounding + .add(ncd.setScale(2, RoundingMode.HALF_UP)); //second rounding + } + eFond.setSettlementAmount(settlementAmount); + //ОКРУГЛЕНИЕ( NV* quantity * price/100) + ОКРУГЛЕНИЕ (executionFond.interestAmount) для каждой сделки + } else if (InstrumentType.EQTY.equalsByKey(security.getInstrumentType())) { + settlementAmount = lots.multiply(price, prec2); + } + eFond.setSettlementAmount(settlementAmount); + if (settlementAmount.compareTo(safeBD(sTrades.getValue())) != 0) { + log.warn("sTrades.TradeNum={} sTrades.value({}) != eFond({})", + sTrades.getTradeNum(), + safeBD(sTrades.getValue()), + settlementAmount); + notifications.sendNotification( + ObjectType.vfrs, + "Для сделки %s объем сделки в ТС %s не совпадает с расчитанным в КС %s" + .formatted(sTrades.getTradeNum(), + safeBD(sTrades.getValue()).toString(), + settlementAmount.toString()), + Priority.HIGH + ); + } + } else { + eFond.setSettlementAmount(sTrades.getValue()); + } eFond.setCounterPartyId(counterCompany.getId()); { ImdgPredicateBuilder strPb = sTradeImdg.predicateBuilder(); diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/impl/FinishingSession.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/impl/FinishingSession.java index c34d454a3..aabb6ae71 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/impl/FinishingSession.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/session/stage/impl/FinishingSession.java @@ -34,7 +34,10 @@ import ru.spcex.platform.utils.enumeration.IMessageResolver; import java.time.Instant; import java.time.LocalDate; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -269,15 +272,23 @@ public class FinishingSession implements ISessionStage { protected Collection findExecutionFondBySessionId(Set exchangeIds) { ImdgPredicateBuilder pb = executionFondImdg.predicateBuilder(); - ImdgPredicate prdct = pb.in("exchangeExecutionId", exchangeIds.toArray(new Long[0])); + ImdgPredicate prdct = pb.and( + pb.in("exchangeExecutionId", exchangeIds.toArray(new Long[0])), + pb.not(pb.equals("settlementDate", LocalDate.now())) + ); Collection result = executionFondImdg.getCollectionObjectsByPredicate(prdct); log.trace("found {} ExecutionFond from first day", result.size()); return result; } protected Collection findExecutionDepositBySessionId(Long sessionId) { - Collection result = executionDepositImdg.getCollectionObjectsByFieldValues(Map.of("sessionId", sessionId)); - log.trace("found {} ExecutionDeposit by sessionId={}", result.size(), sessionId); + ImdgPredicateBuilder pb = executionDepositImdg.predicateBuilder(); + ImdgPredicate prdct = pb.and( + pb.equals("sessionId", sessionId), + pb.equals("firstLegSettlementDate", LocalDate.now()) + ); + Collection result = executionDepositImdg.getCollectionObjectsByPredicate(prdct); + log.trace("found {} ExecutionDeposit by {}", result.size(), prdct); return result; } diff --git a/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/predicate/ImdgPredicateBuilderHazelcast.java b/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/predicate/ImdgPredicateBuilderHazelcast.java index 0569de496..fef559a7f 100644 --- a/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/predicate/ImdgPredicateBuilderHazelcast.java +++ b/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/predicate/ImdgPredicateBuilderHazelcast.java @@ -107,4 +107,9 @@ public class ImdgPredicateBuilderHazelcast implements ImdgPredicateBuilder { public ImdgPredicate alwaysTrue() { return new ImdgPredicateHazelcast(Predicates.alwaysTrue()); } + + @Override + public ImdgPredicate alwaysFalse() { + return new ImdgPredicateHazelcast(Predicates.alwaysFalse()); + } } diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/predicate/ImdgPredicateBuilder.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/predicate/ImdgPredicateBuilder.java index 6cd12ad1c..bee080b38 100644 --- a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/predicate/ImdgPredicateBuilder.java +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/predicate/ImdgPredicateBuilder.java @@ -21,4 +21,5 @@ public interface ImdgPredicateBuilder { ImdgPredicate regex(String key, String regex); ImdgPredicate alwaysTrue(); + ImdgPredicate alwaysFalse(); }