http://jira.mfd.msk:8088/browse/CLS-591
This commit is contained in:
parent
e8cba0467a
commit
c86f1e907a
7 changed files with 125 additions and 52 deletions
|
|
@ -15,6 +15,7 @@ public class ClearingServiceSettings {
|
||||||
private KafkaConsumerSettings kafkaConsumer;
|
private KafkaConsumerSettings kafkaConsumer;
|
||||||
private KafkaProducerSettings kafkaProducer;
|
private KafkaProducerSettings kafkaProducer;
|
||||||
private SessionStageSettings sessionStage;
|
private SessionStageSettings sessionStage;
|
||||||
|
private TradeSettings trade = new TradeSettings();
|
||||||
|
|
||||||
public HazelcastClientParams getHazelcast() {
|
public HazelcastClientParams getHazelcast() {
|
||||||
return hazelcast;
|
return hazelcast;
|
||||||
|
|
@ -47,4 +48,12 @@ public class ClearingServiceSettings {
|
||||||
public void setSessionStage(SessionStageSettings sessionStage) {
|
public void setSessionStage(SessionStageSettings sessionStage) {
|
||||||
this.sessionStage = sessionStage;
|
this.sessionStage = sessionStage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TradeSettings getTrade() {
|
||||||
|
return trade;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTrade(TradeSettings trade) {
|
||||||
|
this.trade = trade;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -11,29 +11,35 @@ import org.springframework.stereotype.Component;
|
||||||
import ru.clearing.classes.statics.data.account.ClientCode;
|
import ru.clearing.classes.statics.data.account.ClientCode;
|
||||||
import ru.clearing.classes.statics.data.company.Company;
|
import ru.clearing.classes.statics.data.company.Company;
|
||||||
import ru.clearing.classes.statics.data.execution.ExecutionFond;
|
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.Listing;
|
||||||
import ru.clearing.classes.statics.data.misc.STrades;
|
import ru.clearing.classes.statics.data.misc.STrades;
|
||||||
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
|
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
|
||||||
import ru.clearing.classes.statics.data.security.Security;
|
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.ClearingError;
|
||||||
import ru.spcex.clearing.error.ClearingException;
|
import ru.spcex.clearing.error.ClearingException;
|
||||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
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.Consts;
|
||||||
import ru.spcex.clearing.platform.messaging.domain.cud.registry.DealRegisterNewRequest;
|
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.domain.cud.registry.ExecutionType;
|
||||||
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
||||||
import ru.spcex.clearing.service.validation.ValidationStored;
|
import ru.spcex.clearing.service.validation.ValidationStored;
|
||||||
import ru.spcex.platform.enumeration.CurrencyCode;
|
import ru.spcex.platform.enumeration.*;
|
||||||
import ru.spcex.platform.enumeration.Section;
|
|
||||||
import ru.spcex.platform.enumeration.Side;
|
|
||||||
import ru.spcex.platform.imdg.api.Imdg;
|
import ru.spcex.platform.imdg.api.Imdg;
|
||||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
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.imdg.api.predicate.ImdgPredicateBuilder;
|
||||||
import ru.spcex.platform.utils.enumeration.*;
|
import ru.spcex.platform.utils.enumeration.*;
|
||||||
import ru.spcex.platform.utils.log.ExceptionUtils;
|
import ru.spcex.platform.utils.log.ExceptionUtils;
|
||||||
import ru.spcex.platform.utils.time.TimeUtil;
|
import ru.spcex.platform.utils.time.TimeUtil;
|
||||||
import ru.spcex.platform.utils.validation.IValidator;
|
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.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
@ -41,6 +47,8 @@ import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static ru.spcex.platform.utils.number.BigDecimalUtil.safeBD;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
public class ExecutionFondComponent {
|
public class ExecutionFondComponent {
|
||||||
|
|
@ -50,6 +58,7 @@ public class ExecutionFondComponent {
|
||||||
private final Imdg<ExecutionFond> executionFondImdg;
|
private final Imdg<ExecutionFond> executionFondImdg;
|
||||||
private final Imdg<Listing> listingImdg;
|
private final Imdg<Listing> listingImdg;
|
||||||
private final Imdg<ClientCode> clientCodeImdg;
|
private final Imdg<ClientCode> clientCodeImdg;
|
||||||
|
private final Imdg<FixedIncomeCashFlow> fixedIncomeCashFlowImdg;
|
||||||
private final Imdg<ru.clearing.classes.statics.data.misc.Market> marketImdg;
|
private final Imdg<ru.clearing.classes.statics.data.misc.Market> marketImdg;
|
||||||
|
|
||||||
//fixme ждать ТЗ
|
//fixme ждать ТЗ
|
||||||
|
|
@ -58,19 +67,27 @@ public class ExecutionFondComponent {
|
||||||
private final IMessageResolver msgResolver = new SimpleMessageResolver();
|
private final IMessageResolver msgResolver = new SimpleMessageResolver();
|
||||||
private final Function<STrades, IValidator> stradesValidator;
|
private final Function<STrades, IValidator> stradesValidator;
|
||||||
private final KafkaSender kafkaSender;
|
private final KafkaSender kafkaSender;
|
||||||
|
private final NotificationSender notifications;
|
||||||
|
private final boolean valuation;
|
||||||
|
private static MathContext prec2 = new MathContext(2, RoundingMode.HALF_UP);
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ExecutionFondComponent(ImdgProvider imdgProvider, Producer<String, Object> kafka,
|
public ExecutionFondComponent(ImdgProvider imdgProvider,
|
||||||
|
ClearingServiceSettings settings,
|
||||||
|
Producer<String, Object> kafka,
|
||||||
@Qualifier("sTradesValidatorFond") Function<STrades, IValidator> stradesValidator,
|
@Qualifier("sTradesValidatorFond") Function<STrades, IValidator> stradesValidator,
|
||||||
@Qualifier("kafkaSenderWithoutRequestInfo") KafkaSender kafkaSender) {
|
@Qualifier("kafkaSenderWithoutRequestInfo") KafkaSender kafkaSender, NotificationSender notifications) {
|
||||||
this.sTradeImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_STrades, STrades.class);
|
this.sTradeImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_STrades, STrades.class);
|
||||||
this.executionFondImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ExecutionFond, ExecutionFond.class);
|
this.executionFondImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ExecutionFond, ExecutionFond.class);
|
||||||
this.listingImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
|
this.listingImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
|
||||||
this.clientCodeImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClientCode, ClientCode.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.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.stradesValidator = stradesValidator;
|
||||||
this.kafkaSender = kafkaSender;
|
this.kafkaSender = kafkaSender;
|
||||||
|
this.notifications = notifications;
|
||||||
|
|
||||||
resetTradingDay();
|
resetTradingDay();
|
||||||
}
|
}
|
||||||
|
|
@ -165,6 +182,7 @@ public class ExecutionFondComponent {
|
||||||
protected ExecutionFond createExecutionFond(STrades sTrades,
|
protected ExecutionFond createExecutionFond(STrades sTrades,
|
||||||
IValidator validator) throws ClearingException {
|
IValidator validator) throws ClearingException {
|
||||||
Security security = validator.getStored(ValidationStored.STradesSecurity);
|
Security security = validator.getStored(ValidationStored.STradesSecurity);
|
||||||
|
// Listing listing = listingImdg.getFirstObjectByFieldValues(Map.of("securityId", security.getId()));
|
||||||
Company company = validator.getStored(ValidationStored.STradesCompany);
|
Company company = validator.getStored(ValidationStored.STradesCompany);
|
||||||
Company counterCompany = validator.getStored(ValidationStored.STradesCounterCompany);
|
Company counterCompany = validator.getStored(ValidationStored.STradesCounterCompany);
|
||||||
TradingClearingRegistry rgstr = validator.getStored(ValidationStored.STradesTradingClearingRegistry);
|
TradingClearingRegistry rgstr = validator.getStored(ValidationStored.STradesTradingClearingRegistry);
|
||||||
|
|
@ -212,7 +230,64 @@ public class ExecutionFondComponent {
|
||||||
eFond.setSecurityId(security.getId());
|
eFond.setSecurityId(security.getId());
|
||||||
eFond.setInterestAmount(sTrades.getAccruedint());
|
eFond.setInterestAmount(sTrades.getAccruedint());
|
||||||
eFond.setExchangeOrderId(sTrades.getOrderNum());
|
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());
|
eFond.setCounterPartyId(counterCompany.getId());
|
||||||
{
|
{
|
||||||
ImdgPredicateBuilder strPb = sTradeImdg.predicateBuilder();
|
ImdgPredicateBuilder strPb = sTradeImdg.predicateBuilder();
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,10 @@ import ru.spcex.platform.utils.enumeration.IMessageResolver;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
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.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
|
@ -269,15 +272,23 @@ public class FinishingSession implements ISessionStage {
|
||||||
|
|
||||||
protected Collection<ExecutionFond> findExecutionFondBySessionId(Set<Long> exchangeIds) {
|
protected Collection<ExecutionFond> findExecutionFondBySessionId(Set<Long> exchangeIds) {
|
||||||
ImdgPredicateBuilder pb = executionFondImdg.predicateBuilder();
|
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<ExecutionFond> result = executionFondImdg.getCollectionObjectsByPredicate(prdct);
|
Collection<ExecutionFond> result = executionFondImdg.getCollectionObjectsByPredicate(prdct);
|
||||||
log.trace("found {} ExecutionFond from first day", result.size());
|
log.trace("found {} ExecutionFond from first day", result.size());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Collection<ExecutionDeposit> findExecutionDepositBySessionId(Long sessionId) {
|
protected Collection<ExecutionDeposit> findExecutionDepositBySessionId(Long sessionId) {
|
||||||
Collection<ExecutionDeposit> result = executionDepositImdg.getCollectionObjectsByFieldValues(Map.of("sessionId", sessionId));
|
ImdgPredicateBuilder pb = executionDepositImdg.predicateBuilder();
|
||||||
log.trace("found {} ExecutionDeposit by sessionId={}", result.size(), sessionId);
|
ImdgPredicate prdct = pb.and(
|
||||||
|
pb.equals("sessionId", sessionId),
|
||||||
|
pb.equals("firstLegSettlementDate", LocalDate.now())
|
||||||
|
);
|
||||||
|
Collection<ExecutionDeposit> result = executionDepositImdg.getCollectionObjectsByPredicate(prdct);
|
||||||
|
log.trace("found {} ExecutionDeposit by {}", result.size(), prdct);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,4 +107,9 @@ public class ImdgPredicateBuilderHazelcast implements ImdgPredicateBuilder {
|
||||||
public ImdgPredicate alwaysTrue() {
|
public ImdgPredicate alwaysTrue() {
|
||||||
return new ImdgPredicateHazelcast(Predicates.alwaysTrue());
|
return new ImdgPredicateHazelcast(Predicates.alwaysTrue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImdgPredicate alwaysFalse() {
|
||||||
|
return new ImdgPredicateHazelcast(Predicates.alwaysFalse());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,4 +21,5 @@ public interface ImdgPredicateBuilder {
|
||||||
ImdgPredicate regex(String key, String regex);
|
ImdgPredicate regex(String key, String regex);
|
||||||
|
|
||||||
ImdgPredicate alwaysTrue();
|
ImdgPredicate alwaysTrue();
|
||||||
|
ImdgPredicate alwaysFalse();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue