some refactoring

This commit is contained in:
etreschenkov 2026-04-10 18:26:04 +03:00
parent c16bf5ea3b
commit 3e2c1cf629
10 changed files with 966 additions and 612 deletions

View file

@ -1,10 +1,5 @@
package ru.spcex.clearing.dflt.management.listener;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.Collection;
import java.util.Optional;
import org.apache.kafka.clients.consumer.Consumer;
@ -14,83 +9,41 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.company.ClearingMemberCategory;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanyRoleSet;
import ru.clearing.classes.statics.data.misc.Listing;
import ru.clearing.classes.statics.data.misc.Market;
import ru.clearing.classes.statics.data.misc.OrderCurrency;
import ru.clearing.classes.statics.data.misc.OvernightSettings;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.classes.statics.data.scheduler.ClearingCalendar;
import ru.clearing.classes.statics.data.security.CurrencyPairSecurity;
import ru.clearing.classes.statics.data.security.Rates;
import ru.clearing.classes.statics.data.security.RiskParameter;
import ru.clearing.platform.dictionary.CurrencyPairDictionary;
import ru.spcex.clearing.dflt.management.config.settings.DefaultManagementSettings;
import ru.spcex.clearing.dflt.management.service.OrderCurrencyService;
import ru.spcex.clearing.dflt.management.service.ImdgQueryService;
import ru.spcex.clearing.dflt.management.service.SpotOvernightOrderService;
import ru.spcex.clearing.dflt.management.service.SwapOvernightOrderService;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.misc.OvernightSettingsNewRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.platform.enumeration.CompanyRole;
import ru.spcex.platform.enumeration.DayStatus;
import ru.spcex.platform.enumeration.MarketType;
import ru.spcex.platform.enumeration.OvernightType;
import ru.spcex.platform.enumeration.Side;
import ru.spcex.platform.enumeration.Task;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
import ru.spcex.platform.utils.enumeration.IEnumKey;
@Service
public class TaskListener extends QueueConsumer implements InitializingBean {
protected final Logger log = LoggerFactory.getLogger(getClass());
private final OrderCurrencyService orderCurrencyService;
private final ImdgProvider imdgProvider;
private final ImdgQueryService imdgQueryService;
private final Imdg<Registry> registryImdg;
private final Imdg<ClearingMemberCategory> categoryImdg;
private final Imdg<OvernightSettings> overnightSettingsImdg;
private final Imdg<CompanyRoleSet> companyRoleSetImdg;
private final Imdg<Company> companyImdg;
private final Imdg<TradingClearingRegistry> tradingClearingRegistryImdg;
private final Imdg<CurrencyPairDictionary> currencyPairDictionaryImdg;
private final Imdg<CurrencyPairSecurity> currencyPairSecurityImdg;
private final Imdg<Listing> listingImdg;
private final Imdg<Market> marketImdg;
private final Imdg<RiskParameter> riskParameterImdg;
private final Imdg<Rates> ratesImdg;
private final Imdg<ClearingCalendar> clearingCalendarImdg;
private final DefaultManagementSettings settings;
private final SwapOvernightOrderService swapOvernightOrderService;
private final SpotOvernightOrderService spotOvernightOrderService;
@Autowired
public TaskListener(Consumer<String, Object> kafkaQueue,
Producer<String, Object> kafkaProducer,
ImdgQueryService imdgQueryService,
ImdgProvider imdgProvider,
UserRoleVerification userRoleVerification,
OrderCurrencyService orderCurrencyService,
DefaultManagementSettings settings) {
SwapOvernightOrderService swapOvernightOrderService,
SpotOvernightOrderService spotOvernightOrderService) {
super(kafkaQueue, kafkaProducer);
this.imdgProvider = imdgProvider;
this.imdgQueryService = imdgQueryService;
this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
this.overnightSettingsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_OvernightSettings, OvernightSettings.class);
this.categoryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class);
this.companyRoleSetImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CompanyRoleSet, CompanyRoleSet.class);
this.companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
this.tradingClearingRegistryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
this.currencyPairDictionaryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairDictionary, CurrencyPairDictionary.class);
this.currencyPairSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairSecurity, CurrencyPairSecurity.class);
this.listingImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
this.marketImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Market, Market.class);
this.riskParameterImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_RiskParameter, RiskParameter.class);
this.ratesImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Rates, Rates.class);
this.clearingCalendarImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingCalendar, ClearingCalendar.class);
this.orderCurrencyService = orderCurrencyService;
this.settings = settings;
this.swapOvernightOrderService = swapOvernightOrderService;
this.spotOvernightOrderService = spotOvernightOrderService;
}
@Override
@ -104,7 +57,7 @@ public class TaskListener extends QueueConsumer implements InitializingBean {
private void createOrder(BaseRequest<OvernightSettingsNewRequest> newReq) {
log.info("CROR createOrder started, request={}", newReq);
Collection<Long> registryIds = orderCurrencyService.getCurrencyRegistry();
Collection<Long> registryIds = imdgQueryService.getCurrencyRegistry();
if (registryIds == null || registryIds.isEmpty()) {
log.info("No registries found for CROR processing");
return;
@ -119,13 +72,12 @@ public class TaskListener extends QueueConsumer implements InitializingBean {
}
OvernightType overnightType = resolveOvernightType(registry);
log.info("Processing registry id={}, companyId={}, overnightType={}",
registry.getId(), registry.getCompanyId(), overnightType);
switch (overnightType) {
case SWAP -> createSwapOrders(registry);
case SPOT -> createSpotOrders(registry);
case SWAP -> swapOvernightOrderService.process(registry);
case SPOT -> spotOvernightOrderService.process(registry);
default ->
log.warn("Unsupported overnightType={} for registry id={}", overnightType, registry.getId());
}
@ -139,558 +91,10 @@ public class TaskListener extends QueueConsumer implements InitializingBean {
private OvernightType resolveOvernightType(Registry registry) {
Optional<OvernightSettings> settingsOpt =
orderCurrencyService.findOvernightSettingsByCompany(registry.getCompanyId());
imdgQueryService.findOvernightSettingsByCompany(registry.getCompanyId());
return settingsOpt
.map(settings -> IEnumKey.getEnumByKey(OvernightType.class, settings.getOvernightType()))
.orElse(OvernightType.SWAP);
}
private void createSpotOrders(Registry registry) {
}
private void createSwapOrders(Registry registry) {
OrderCurrency primaryTransferOrder = new OrderCurrency();
OrderCurrency counterTransferOrder = new OrderCurrency();
OrderCurrency primaryBalancingOrder = new OrderCurrency();
OrderCurrency counterBalancingOrder = new OrderCurrency();
ImdgPredicateBuilder predicateBuilder = categoryImdg.predicateBuilder();
ClearingMemberCategory category = categoryImdg.getFirstObjectByPredicate(
predicateBuilder.equals("companyId", registry.getCompanyId())
);
String orderCategory = category.getClearingMemberCategory().equals("P") ? "PL" : "UK";
Side primaryTransferSide = Side.SELL;
Side counterTransferSide = Side.BUY;
Side primaryBalancingSide = Side.BUY;
Side counterBalancingSide = Side.SELL;
if (registry.getSecuritySymbol().equals("RUB")) {
primaryTransferSide = primaryTransferSide.revers();
counterTransferSide = counterTransferSide.revers();
primaryBalancingSide = primaryBalancingSide.revers();
counterBalancingSide = counterBalancingSide.revers();
}
Market market = marketImdg.getSingleObjectByPredicate(predicateBuilder.equals("marketType", MarketType.SCSW));
Listing listing;
RiskParameter riskParameter;
if (registry.getSecuritySymbol().equals("RUB")) {
listing = findListingForRub(registry, market.getCode());
riskParameter = findRiskParameterForRub();
} else {
listing = findListingForOtherCurrency(registry, market.getCode());
riskParameter = findRiskParameterForOtherCurrency(registry);
}
if (orderCategory.equals("PL")) {
fillPrimaryTransferP(primaryTransferOrder, registry);
fillCounterTransferP(counterTransferOrder, registry);
fillPrimaryBalancingP(primaryBalancingOrder, registry);
fillCounterBalancingP(counterBalancingOrder, registry);
} else if (orderCategory.equals("UK")) {
fillPrimaryTransferUK(primaryTransferOrder, registry);
fillCounterTransferUK(counterTransferOrder, registry);
fillPrimaryBalancingUK(primaryBalancingOrder, registry);
fillCounterBalancingUK(counterBalancingOrder, registry);
}
fillSwapOrder(primaryTransferOrder, registry, listing, market, riskParameter, primaryTransferSide, "overnight");
fillSwapOrder(counterTransferOrder, registry, listing, market, riskParameter, counterTransferSide, "overnight");
fillSwapOrder(primaryBalancingOrder, registry, listing, market, riskParameter, primaryBalancingSide, "balance");
fillSwapOrder(counterBalancingOrder, registry, listing, market, riskParameter, counterBalancingSide, "balance");
}
private void fillPrimaryTransferUK(OrderCurrency orderCurrency, Registry registry) {
ImdgPredicateBuilder predicateBuilder = categoryImdg.predicateBuilder();
CompanyRoleSet companyRoleSet = companyRoleSetImdg.getSingleObjectByPredicate(
predicateBuilder.equals("companyRole", CompanyRole.CLCC)
);
Company company = companyImdg.getSingleObjectByID(companyRoleSet.getCompanyId());
orderCurrency.setAccount(registry.getTradingClearingRegistry());
orderCurrency.setTradingClearingRegistryId(registry.getTradingClearingRegistryId());
orderCurrency.setCompanyId(registry.getCompanyId());
orderCurrency.setTradingCode(registry.getTradingCode());
orderCurrency.setCounterPartyId(companyRoleSet.getCompanyId());
orderCurrency.setCounterTradingCode(company.getTradingCode());
orderCurrency.setType("CMOV");
}
private void fillCounterTransferUK(OrderCurrency orderCurrency, Registry registry) {
ImdgPredicateBuilder predicateBuilder = categoryImdg.predicateBuilder();
CompanyRoleSet companyRoleSet = companyRoleSetImdg.getSingleObjectByPredicate(
predicateBuilder.equals("companyRole", CompanyRole.CLCC)
);
Company company = companyImdg.getSingleObjectByID(companyRoleSet.getCompanyId());
TradingClearingRegistry tradingClearingRegistry = tradingClearingRegistryImdg.getFirstObjectByPredicate(
predicateBuilder.equals("companyId", company.getId())
);
orderCurrency.setAccount(tradingClearingRegistry.getCode());
orderCurrency.setTradingClearingRegistryId(tradingClearingRegistry.getId());
orderCurrency.setCompanyId(company.getId());
orderCurrency.setTradingCode(company.getTradingCode());
orderCurrency.setCounterPartyId(registry.getCompanyId());
orderCurrency.setCounterTradingCode(registry.getTradingCode());
orderCurrency.setType("CMOV");
}
private void fillPrimaryBalancingUK(OrderCurrency orderCurrency, Registry registry) {
ImdgPredicateBuilder predicateBuilder = categoryImdg.predicateBuilder();
ClearingMemberCategory category = categoryImdg.getFirstObjectByPredicate(
predicateBuilder.equals("clearingMemberCategory", "P")
);
TradingClearingRegistry tradingClearingRegistry = tradingClearingRegistryImdg.getFirstObjectByPredicate(
predicateBuilder.equals("companyId", category.getCompanyId())
);
Company company = companyImdg.getSingleObjectByID(category.getCompanyId());
CompanyRoleSet clccCompanyRole = companyRoleSetImdg.getSingleObjectByPredicate(
predicateBuilder.equals("companyRole", CompanyRole.CLCC)
);
Company clssCompany = companyImdg.getSingleObjectByID(category.getCompanyId());
orderCurrency.setAccount(tradingClearingRegistry.getCode());
orderCurrency.setTradingClearingRegistryId(tradingClearingRegistry.getId());
orderCurrency.setCompanyId(company.getId());
orderCurrency.setTradingCode(company.getTradingCode());
orderCurrency.setCounterPartyId(clccCompanyRole.getCompanyId());
orderCurrency.setCounterTradingCode(clssCompany.getTradingCode());
orderCurrency.setType("CMBL");
}
private void fillCounterBalancingUK(OrderCurrency orderCurrency, Registry registry) {
ImdgPredicateBuilder predicateBuilder = categoryImdg.predicateBuilder();
CompanyRoleSet companyRoleSet = companyRoleSetImdg.getSingleObjectByPredicate(
predicateBuilder.equals("companyRole", CompanyRole.CLCC)
);
Company company = companyImdg.getSingleObjectByID(companyRoleSet.getCompanyId());
TradingClearingRegistry tradingClearingRegistry = tradingClearingRegistryImdg.getFirstObjectByPredicate(
predicateBuilder.equals("companyId", company.getId())
);
ClearingMemberCategory categoryP = categoryImdg.getFirstObjectByPredicate(
predicateBuilder.equals("clearingMemberCategory", "P")
);
Company companyP = companyImdg.getSingleObjectByID(categoryP.getCompanyId());
orderCurrency.setAccount(tradingClearingRegistry.getCode());
orderCurrency.setTradingClearingRegistryId(tradingClearingRegistry.getId());
orderCurrency.setCompanyId(company.getId());
orderCurrency.setTradingCode(company.getTradingCode());
orderCurrency.setCounterPartyId(categoryP.getCompanyId());
orderCurrency.setCounterTradingCode(companyP.getTradingCode());
orderCurrency.setType("CMBL");
}
private void fillPrimaryTransferP(OrderCurrency orderCurrency, Registry registry) {
ImdgPredicateBuilder predicateBuilder = categoryImdg.predicateBuilder();
CompanyRoleSet companyRoleSet = companyRoleSetImdg.getSingleObjectByPredicate(
predicateBuilder.equals("companyRole", CompanyRole.CLCC)
);
Company company = companyImdg.getSingleObjectByID(companyRoleSet.getCompanyId());
orderCurrency.setAccount(registry.getTradingClearingRegistry());
orderCurrency.setTradingClearingRegistryId(registry.getTradingClearingRegistryId());
orderCurrency.setCompanyId(registry.getCompanyId());
orderCurrency.setTradingCode(registry.getTradingCode());
orderCurrency.setCounterPartyId(companyRoleSet.getCompanyId());
orderCurrency.setCounterTradingCode(company.getTradingCode());
orderCurrency.setType("PLOV");
}
private void fillCounterTransferP(OrderCurrency orderCurrency, Registry registry) {
ImdgPredicateBuilder predicateBuilder = categoryImdg.predicateBuilder();
CompanyRoleSet companyRoleSet = companyRoleSetImdg.getSingleObjectByPredicate(
predicateBuilder.equals("companyRole", CompanyRole.CLCC)
);
Company company = companyImdg.getSingleObjectByID(companyRoleSet.getCompanyId());
TradingClearingRegistry tradingClearingRegistry = tradingClearingRegistryImdg.getFirstObjectByPredicate(
predicateBuilder.equals("companyId", company.getId())
);
orderCurrency.setAccount(tradingClearingRegistry.getCode());
orderCurrency.setTradingClearingRegistryId(tradingClearingRegistry.getId());
orderCurrency.setCompanyId(company.getId());
orderCurrency.setTradingCode(company.getTradingCode());
orderCurrency.setCounterPartyId(registry.getCompanyId());
orderCurrency.setCounterTradingCode(registry.getTradingCode());
orderCurrency.setType("PLOV");
}
private void fillPrimaryBalancingP(OrderCurrency orderCurrency, Registry registry) {
ImdgPredicateBuilder predicateBuilder = categoryImdg.predicateBuilder();
CompanyRoleSet companyRoleSet = companyRoleSetImdg.getSingleObjectByPredicate(
predicateBuilder.equals("companyRole", CompanyRole.RGCM)
);
Company company = companyImdg.getSingleObjectByID(companyRoleSet.getCompanyId());
TradingClearingRegistry tradingClearingRegistry = tradingClearingRegistryImdg.getFirstObjectByPredicate(
predicateBuilder.equals("companyId", company.getId())
);
CompanyRoleSet clccCompanyRole = companyRoleSetImdg.getSingleObjectByPredicate(
predicateBuilder.equals("companyRole", CompanyRole.CLCC)
);
Company clssCompany = companyImdg.getSingleObjectByID(clccCompanyRole.getCompanyId());
orderCurrency.setAccount(tradingClearingRegistry.getCode());
orderCurrency.setTradingClearingRegistryId(tradingClearingRegistry.getId());
orderCurrency.setCompanyId(company.getId());
orderCurrency.setTradingCode(company.getTradingCode());
orderCurrency.setCounterPartyId(clccCompanyRole.getCompanyId());
orderCurrency.setCounterTradingCode(clssCompany.getTradingCode());
orderCurrency.setType("PLBL");
}
private void fillCounterBalancingP(OrderCurrency orderCurrency, Registry registry) {
ImdgPredicateBuilder predicateBuilder = categoryImdg.predicateBuilder();
CompanyRoleSet companyRoleSet = companyRoleSetImdg.getSingleObjectByPredicate(
predicateBuilder.equals("companyRole", CompanyRole.CLCC)
);
Company company = companyImdg.getSingleObjectByID(companyRoleSet.getCompanyId());
TradingClearingRegistry tradingClearingRegistry = tradingClearingRegistryImdg.getFirstObjectByPredicate(
predicateBuilder.equals("companyId", company.getId())
);
CompanyRoleSet rgcmCompanyRole = companyRoleSetImdg.getSingleObjectByPredicate(
predicateBuilder.equals("companyRole", CompanyRole.RGCM)
);
Company rgcmCompany = companyImdg.getSingleObjectByID(rgcmCompanyRole.getCompanyId());
orderCurrency.setAccount(tradingClearingRegistry.getCode());
orderCurrency.setTradingClearingRegistryId(tradingClearingRegistry.getId());
orderCurrency.setCompanyId(company.getId());
orderCurrency.setTradingCode(company.getTradingCode());
orderCurrency.setCounterPartyId(rgcmCompanyRole.getCompanyId());
orderCurrency.setCounterTradingCode(rgcmCompany.getTradingCode());
orderCurrency.setType("PLBL");
}
private void fillSwapOrder(OrderCurrency orderCurrency,
Registry registry,
Listing listing,
Market market,
RiskParameter riskParameter,
Side side,
String comment) {
CurrencyPairSecurity currencyPairSecurity = currencyPairSecurityImdg.getSingleObjectByID(listing.getSecurityId());
CurrencyPairDictionary currencyPairDictionary = currencyPairDictionaryImdg
.getSingleObjectByID(currencyPairSecurity.getCurrencyPairId());
BigDecimal s = defineTransferRate(currencyPairDictionary.getId(), registry.getSecuritySymbol());
BigDecimal n = numberOfDaysOfTransfer();
CalculationResultHolder resultHolder = calculationSwapSums(registry, listing.getLotSize().intValue(), s, n);
BigDecimal quantityLot = resultHolder.getSum3().abs();
BigDecimal price = swapPriceCalc(currencyPairDictionary.getBaseCurrency(), s, n);
orderCurrency.setOvernightType("SWAP");
orderCurrency.setMarket(market.getCode());
orderCurrency.setListingId(listing.getId());
orderCurrency.setSecuritySymbol(listing.getSymbolCode());
orderCurrency.setSecurityId(listing.getSecurityId());
orderCurrency.setLotSize(listing.getLotSize());
orderCurrency.setRate(riskParameter.getQuoteValue());
orderCurrency.setSide(side.getKey());
orderCurrency.setSettleCode("T1");
orderCurrency.setStatus("CRET");
orderCurrency.setComment(comment);
orderCurrency.setRegistryId(registry.getId());
orderCurrency.setPrice(price);
orderCurrency.setQuantityLot(quantityLot);
}
private Listing findListingForRub(Registry registry, String market) {
ImdgPredicateBuilder predicateBuilder = currencyPairDictionaryImdg.predicateBuilder();
CurrencyPairDictionary currencyPairDictionary = currencyPairDictionaryImdg.getFirstObjectByPredicate(
predicateBuilder.and(
predicateBuilder.equals("baseCurrency", "CNY"),
predicateBuilder.equals("quoteCurrency", registry.getSecuritySymbol())
));
Collection<Long> securitiesIds = currencyPairSecurityImdg.getCollectionIdsByPredicate(
predicateBuilder.equals("currencyPairId", currencyPairDictionary.getId())
);
Listing listing = listingImdg.getSingleObjectByPredicate(
predicateBuilder.and(
predicateBuilder.in("securityId", securitiesIds.toArray(new Long[0])),
predicateBuilder.equals("market", market)
)
);
return listing;
}
private Listing findListingForOtherCurrency(Registry registry, String market) {
ImdgPredicateBuilder predicateBuilder = currencyPairDictionaryImdg.predicateBuilder();
CurrencyPairDictionary currencyPairDictionary = currencyPairDictionaryImdg.getFirstObjectByPredicate(
predicateBuilder.and(
predicateBuilder.equals("baseCurrency", registry.getSecuritySymbol()),
predicateBuilder.equals("quoteCurrency", "RUB")
));
Collection<Long> securitiesIds = currencyPairSecurityImdg.getCollectionIdsByPredicate(
predicateBuilder.equals("currencyPairId", currencyPairDictionary.getId())
);
Listing listing = listingImdg.getSingleObjectByPredicate(
predicateBuilder.and(
predicateBuilder.in("securityId", securitiesIds.toArray(new Long[0])),
predicateBuilder.equals("market", market)
)
);
return listing;
}
private RiskParameter findRiskParameterForRub() {
ImdgPredicateBuilder predicateBuilder = currencyPairDictionaryImdg.predicateBuilder();
CurrencyPairDictionary currencyPairDictionary = currencyPairDictionaryImdg.getFirstObjectByPredicate(
predicateBuilder.and(
predicateBuilder.equals("baseCurrency", "CNY")
));
return riskParameterImdg.getSingleObjectByPredicate(
predicateBuilder.and(
predicateBuilder.equals("currencyPairId", currencyPairDictionary.getId()),
predicateBuilder.equals("settlementType", "T0")
)
);
}
private RiskParameter findRiskParameterForOtherCurrency(Registry registry) {
ImdgPredicateBuilder predicateBuilder = currencyPairDictionaryImdg.predicateBuilder();
CurrencyPairDictionary currencyPairDictionary = currencyPairDictionaryImdg.getFirstObjectByPredicate(
predicateBuilder.and(
predicateBuilder.equals("baseCurrency", registry.getSecuritySymbol())
));
return riskParameterImdg.getSingleObjectByPredicate(
predicateBuilder.and(
predicateBuilder.equals("currencyPairId", currencyPairDictionary.getId()),
predicateBuilder.equals("settlementType", "T0")
)
);
}
private static final MathContext MC = new MathContext(20, RoundingMode.HALF_UP);
//registry.securitySymbol != 'RUB'
private CalculationResultHolder calculationSwapSums(Registry registry, Integer lotSize, BigDecimal s, BigDecimal n) {
BigDecimal planPosition = registry.getBalance();
BigDecimal sum1 = planPosition.abs();
Registry amtRubRegistry = findAmtRegistry(registry, "RUB");
BigDecimal planPositionRub = amtRubRegistry.getBalance();
Rates rates = findRates(registry.getSecuritySymbol());
BigDecimal ratesValue = rates.getValue();
BigDecimal sum2 = planPositionRub.divide(ratesValue, lotSize, RoundingMode.HALF_DOWN);
BigDecimal ceilSum1 = sum1.setScale(0, RoundingMode.CEILING);
BigDecimal sum3 = ceilSum1.min(sum2);
BigDecimal sum4 = sum3
.multiply(ratesValue, MC)
.negate();
BigDecimal sum5 = sum3.negate();
BigDecimal daysInYear = BigDecimal.valueOf(365);
// (S / 365) * n
BigDecimal carryPart = s.divide(daysInYear, MC).multiply(n, MC);
// 1 + S / 365 * n
BigDecimal multiplier = BigDecimal.ONE.add(carryPart, MC);
BigDecimal sum6 = sum3
.multiply(ratesValue, MC)
.multiply(multiplier, MC);
return new CalculationResultHolder(sum1, sum2, sum3, sum4, sum5, sum6);
}
//registry.securitySymbol == 'RUB'
private CalculationResultHolder calculationSwapRubSums(Registry registry, Integer lotSize, BigDecimal s, BigDecimal n) {
BigDecimal planPosition = registry.getBalance();
Rates cnyRates = findRates(registry.getSecuritySymbol());
BigDecimal ratesValue = cnyRates.getValue();
BigDecimal sum1 = planPosition.divide(ratesValue, MC);
Registry amtRubRegistry = findAmtRegistry(registry, "CNY");
BigDecimal planPositionCny = amtRubRegistry.getBalance();
BigDecimal sum2 = planPositionCny.divide(ratesValue, lotSize, RoundingMode.HALF_DOWN);
BigDecimal ceilSum1 = sum1.setScale(0, RoundingMode.CEILING);
BigDecimal sum3 = ceilSum1.min(sum2).negate();
BigDecimal sum4 = sum3
.multiply(ratesValue, MC)
.negate();
BigDecimal sum5 = sum3.negate();
BigDecimal daysInYear = BigDecimal.valueOf(365);
// (S / 365) * n
BigDecimal carryPart = s.divide(daysInYear, MC).multiply(n, MC);
// 1 + S / 365 * n
BigDecimal multiplier = BigDecimal.ONE.add(carryPart, MC);
BigDecimal sum6 = sum3
.multiply(ratesValue, MC)
.multiply(multiplier, MC);
return new CalculationResultHolder(sum1, sum2, sum3, sum4, sum5, sum6);
}
private Registry findAmtRegistry(Registry registry, String securitySymbol) {
ImdgPredicateBuilder predicateBuilder = registryImdg.predicateBuilder();
return registryImdg.getSingleObjectByPredicate(
predicateBuilder.and(
predicateBuilder.regex("registryCode", "^PM.*T"),
predicateBuilder.equals("securitySymbol", securitySymbol),
predicateBuilder.equals("tradingClearingRegistryId", registry.getId()),
predicateBuilder.equals("companyId", registry.getCompanyId())
)
);
}
private Rates findRates(String securitySymbol) {
ImdgPredicateBuilder predicateBuilder = registryImdg.predicateBuilder();
return ratesImdg.getSingleObjectByPredicate(
predicateBuilder.and(
predicateBuilder.equals("currency", securitySymbol),
predicateBuilder.equals("valueDate", LocalDate.now()),
predicateBuilder.equals("workflowStatus", WorkflowStatus.Active.getKey())
)
);
}
private Rates findCnyRates(Registry registry) {
ImdgPredicateBuilder predicateBuilder = registryImdg.predicateBuilder();
return ratesImdg.getSingleObjectByPredicate(
predicateBuilder.and(
predicateBuilder.equals("currency", "CNY"),
predicateBuilder.equals("valueDate", LocalDate.now()),
predicateBuilder.equals("workflowStatus", WorkflowStatus.Active.getKey())
)
);
}
private BigDecimal swapPriceCalc(String baseCurrency, BigDecimal s, BigDecimal n) {
LocalDate now = LocalDate.now();
ImdgPredicateBuilder predicateBuilder = ratesImdg.predicateBuilder();
BigDecimal daysInYear = BigDecimal.valueOf(365);
Rates rates = ratesImdg.getSingleObjectByPredicate(
predicateBuilder.and(
predicateBuilder.equals("currency", baseCurrency),
predicateBuilder.equals("valueDate", now),
predicateBuilder.equals("workflowStatus", WorkflowStatus.Active.getKey())
)
);
BigDecimal rateValue = rates.getValue();
return rateValue.multiply(s, MC).multiply(n, MC).divide(daysInYear, MC);
}
private BigDecimal defineTransferRate(Long currencyPairDictionaryId, String securitySymbol) {
ImdgPredicateBuilder predicateBuilder = riskParameterImdg.predicateBuilder();
String securitySymbolCondition = securitySymbol.equals("RUB") ? "CNY" : securitySymbol;
RiskParameter riskParameter = riskParameterImdg.getSingleObjectByPredicate(
predicateBuilder.and(
predicateBuilder.equals("settlementType", "T0"),
predicateBuilder.equals("currencyPairId", currencyPairDictionaryId),
predicateBuilder.equals("baseCurrency", securitySymbolCondition)
)
);
return riskParameter.getQuoteValue();
}
private BigDecimal numberOfDaysOfTransfer() {
LocalDate nextWorkingDay = findNextWorkingDate();
return BigDecimal.valueOf(nextWorkingDay.compareTo(LocalDate.now()));
}
public static BigDecimal ceilMath(BigDecimal value, BigDecimal significance) {
if (significance == null || significance.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("significance must be > 0");
}
if (value == null) {
throw new IllegalArgumentException("value must not be null");
}
BigDecimal divided = value.divide(significance, 0, RoundingMode.CEILING);
return divided.multiply(significance);
}
private LocalDate findNextWorkingDate() {
LocalDate checkingDate = LocalDate.now().plusDays(1);
ImdgPredicateBuilder predicateBuilder = clearingCalendarImdg.predicateBuilder();
while (true) {
ClearingCalendar clearingCalendar = clearingCalendarImdg.getFirstObjectByPredicate(
predicateBuilder.equals("clearingDate", checkingDate)
);
DayOfWeek dayOfWeek = checkingDate.getDayOfWeek();
if (isWeekday(dayOfWeek)) {
if (clearingCalendar != null && DayStatus.Workday.equalsByKey(clearingCalendar.getDayStatus())) {
return checkingDate;
}
checkingDate = checkingDate.plusDays(1);
} else {
if (clearingCalendar != null && DayStatus.DayOff.equalsByKey(clearingCalendar.getDayStatus())) {
checkingDate = checkingDate.plusDays(1);
continue;
}
return checkingDate;
}
}
}
private boolean isWeekday(DayOfWeek dayOfWeek) {
return dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
}
public static class CalculationResultHolder {
private BigDecimal sum1;
private BigDecimal sum2;
private BigDecimal sum3;
private BigDecimal sum4;
private BigDecimal sum5;
private BigDecimal sum6;
public CalculationResultHolder(BigDecimal sum1,
BigDecimal sum2,
BigDecimal sum3,
BigDecimal sum4,
BigDecimal sum5,
BigDecimal sum6) {
this.sum1 = sum1;
this.sum2 = sum2;
this.sum3 = sum3;
this.sum4 = sum4;
this.sum5 = sum5;
this.sum6 = sum6;
}
public BigDecimal getSum1() {
return sum1;
}
public BigDecimal getSum2() {
return sum2;
}
public BigDecimal getSum3() {
return sum3;
}
public BigDecimal getSum4() {
return sum4;
}
public BigDecimal getSum5() {
return sum5;
}
public BigDecimal getSum6() {
return sum6;
}
}
}

View file

@ -0,0 +1,13 @@
package ru.spcex.clearing.dflt.management.model;
import java.math.BigDecimal;
public record CalculationResult(
BigDecimal sum1,
BigDecimal sum2,
BigDecimal sum3,
BigDecimal sum4,
BigDecimal sum5,
BigDecimal sum6
) {
}

View file

@ -0,0 +1,8 @@
package ru.spcex.clearing.dflt.management.model;
public record CounterpartyInfo(
Long companyId,
String tradingCode,
Long registryId,
String registryCode
) {}

View file

@ -0,0 +1,119 @@
package ru.spcex.clearing.dflt.management.model;
import ru.clearing.classes.statics.data.misc.Listing;
import ru.clearing.classes.statics.data.misc.Market;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.security.RiskParameter;
public class SwapContext {
private final Registry registry;
private final String orderCategory;
private final Market market;
private final Listing listing;
private final RiskParameter riskParameter;
private final CounterpartyInfo categoryP;
private final CounterpartyInfo clcc;
private final CounterpartyInfo rgcm;
private SwapContext(Builder builder) {
this.registry = builder.registry;
this.orderCategory = builder.orderCategory;
this.market = builder.market;
this.listing = builder.listing;
this.riskParameter = builder.riskParameter;
this.categoryP = builder.categoryP;
this.clcc = builder.clcc;
this.rgcm = builder.rgcm;
}
public Registry getRegistry() {
return registry;
}
public String getOrderCategory() {
return orderCategory;
}
public Market getMarket() {
return market;
}
public Listing getListing() {
return listing;
}
public RiskParameter getRiskParameter() {
return riskParameter;
}
public CounterpartyInfo getCategoryP() {
return categoryP;
}
public CounterpartyInfo getClcc() {
return clcc;
}
public CounterpartyInfo getRgcm() {
return rgcm;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Registry registry;
private String orderCategory;
private Market market;
private Listing listing;
private RiskParameter riskParameter;
private CounterpartyInfo categoryP;
private CounterpartyInfo clcc;
private CounterpartyInfo rgcm;
public Builder registry(Registry registry) {
this.registry = registry;
return this;
}
public Builder orderCategory(String orderCategory) {
this.orderCategory = orderCategory;
return this;
}
public Builder market(Market market) {
this.market = market;
return this;
}
public Builder listing(Listing listing) {
this.listing = listing;
return this;
}
public Builder riskParameter(RiskParameter riskParameter) {
this.riskParameter = riskParameter;
return this;
}
public Builder categoryP(CounterpartyInfo categoryP) {
this.categoryP = categoryP;
return this;
}
public Builder clcc(CounterpartyInfo clcc) {
this.clcc = clcc;
return this;
}
public Builder rgcm(CounterpartyInfo rgcm) {
this.rgcm = rgcm;
return this;
}
public SwapContext build() {
return new SwapContext(this);
}
}
}

View file

@ -0,0 +1,261 @@
package ru.spcex.clearing.dflt.management.service;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
import java.util.Optional;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.company.ClearingMemberCategory;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanyRoleSet;
import ru.clearing.classes.statics.data.misc.Listing;
import ru.clearing.classes.statics.data.misc.Market;
import ru.clearing.classes.statics.data.misc.OvernightSettings;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
import ru.clearing.classes.statics.data.security.CurrencyPairSecurity;
import ru.clearing.classes.statics.data.security.Rates;
import ru.clearing.classes.statics.data.security.RiskParameter;
import ru.clearing.platform.dictionary.CurrencyPairDictionary;
import ru.spcex.clearing.dflt.management.model.CounterpartyInfo;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.CompanyRole;
import ru.spcex.platform.enumeration.MarketType;
import ru.spcex.platform.enumeration.RegistryStatus;
import ru.spcex.platform.enumeration.WorkflowStatus;
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;
@Service
public class ImdgQueryService {
private final Imdg<ClearingMemberCategory> categoryImdg;
private final Imdg<CompanyRoleSet> companyRoleSetImdg;
private final Imdg<Company> companyImdg;
private final Imdg<TradingClearingRegistry> tradingClearingRegistryImdg;
private final Imdg<CurrencyPairDictionary> currencyPairDictionaryImdg;
private final Imdg<CurrencyPairSecurity> currencyPairSecurityImdg;
private final Imdg<Listing> listingImdg;
private final Imdg<Market> marketImdg;
private final Imdg<RiskParameter> riskParameterImdg;
private final Imdg<Rates> ratesImdg;
private final Imdg<Registry> registryImdg;
private final Imdg<OvernightSettings> overnightSettingsImdg;
public ImdgQueryService(ImdgProvider imdgProvider) {
this.categoryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class);
this.companyRoleSetImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CompanyRoleSet, CompanyRoleSet.class);
this.companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
this.tradingClearingRegistryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
this.currencyPairDictionaryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairDictionary, CurrencyPairDictionary.class);
this.currencyPairSecurityImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CurrencyPairSecurity, CurrencyPairSecurity.class);
this.listingImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Listing, Listing.class);
this.marketImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Market, Market.class);
this.riskParameterImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_RiskParameter, RiskParameter.class);
this.ratesImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Rates, Rates.class);
this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
this.overnightSettingsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_OvernightSettings, OvernightSettings.class);
}
public Collection<Long> getCurrencyRegistry() {
ImdgPredicateBuilder builder = registryImdg.predicateBuilder();
ImdgPredicate registryPredicate = builder.and(
builder.regex("registryCode", "^PM.*T"),
builder.not(builder.equals("registryStatus", RegistryStatus.OK.getKey()))
);
return registryImdg.getCollectionIdsByPredicate(registryPredicate);
}
public Optional<OvernightSettings> findOvernightSettingsByCompany(Long companyId) {
ImdgPredicateBuilder builder = overnightSettingsImdg.predicateBuilder();
ImdgPredicate predicate = builder.and(
builder.equals("market", ru.spcex.platform.enumeration.Market.curr),
builder.equals("companyId", companyId)
);
OvernightSettings overnightSettings = overnightSettingsImdg.getFirstObjectByPredicate(predicate);
return Optional.ofNullable(overnightSettings);
}
public String resolveOrderCategory(Long companyId) {
ImdgPredicateBuilder pb = categoryImdg.predicateBuilder();
ClearingMemberCategory category = categoryImdg.getFirstObjectByPredicate(
pb.equals("companyId", companyId)
);
return "P".equals(category.getClearingMemberCategory()) ? "PL" : "UK";
}
public CounterpartyInfo getCompanyByRole(CompanyRole role) {
ImdgPredicateBuilder pb = companyRoleSetImdg.predicateBuilder();
CompanyRoleSet roleSet = companyRoleSetImdg.getSingleObjectByPredicate(
pb.equals("companyRole", role)
);
Company company = companyImdg.getSingleObjectByID(roleSet.getCompanyId());
TradingClearingRegistry registry = tradingClearingRegistryImdg.getFirstObjectByPredicate(
pb.equals("companyId", company.getId())
);
return new CounterpartyInfo(
company.getId(),
company.getTradingCode(),
registry != null ? registry.getId() : null,
registry != null ? registry.getCode() : null
);
}
public CounterpartyInfo getCompanyByClearingCategory(String clearingCategory) {
ImdgPredicateBuilder pb = categoryImdg.predicateBuilder();
ClearingMemberCategory category = categoryImdg.getFirstObjectByPredicate(
pb.equals("clearingMemberCategory", clearingCategory)
);
Company company = companyImdg.getSingleObjectByID(category.getCompanyId());
TradingClearingRegistry registry = tradingClearingRegistryImdg.getFirstObjectByPredicate(
pb.equals("companyId", company.getId())
);
return new CounterpartyInfo(
company.getId(),
company.getTradingCode(),
registry != null ? registry.getId() : null,
registry != null ? registry.getCode() : null
);
}
public Market getSwapMarket() {
ImdgPredicateBuilder pb = marketImdg.predicateBuilder();
return marketImdg.getSingleObjectByPredicate(pb.equals("marketType", MarketType.SCSW));
}
public Listing findSwapListing(Registry registry, String marketCode) {
return "RUB".equals(registry.getSecuritySymbol())
? findListingForRub(registry, marketCode)
: findListingForOtherCurrency(registry, marketCode);
}
public RiskParameter findRiskParameter(Registry registry) {
return "RUB".equals(registry.getSecuritySymbol())
? findRiskParameterForRub()
: findRiskParameterForOtherCurrency(registry);
}
public Rates getRate(String currency, LocalDate valueDate) {
ImdgPredicateBuilder pb = ratesImdg.predicateBuilder();
return ratesImdg.getSingleObjectByPredicate(
pb.and(
pb.equals("currency", currency),
pb.equals("valueDate", valueDate),
pb.equals("workflowStatus", WorkflowStatus.Active.getKey())
)
);
}
public BigDecimal defineTransferRate(Long currencyPairDictionaryId, String securitySymbol) {
ImdgPredicateBuilder pb = riskParameterImdg.predicateBuilder();
String baseCurrency = "RUB".equals(securitySymbol) ? "CNY" : securitySymbol;
RiskParameter riskParameter = riskParameterImdg.getSingleObjectByPredicate(
pb.and(
pb.equals("settlementType", "T0"),
pb.equals("currencyPairId", currencyPairDictionaryId),
pb.equals("baseCurrency", baseCurrency)
)
);
return riskParameter.getQuoteValue();
}
public CurrencyPairDictionary getCurrencyPairDictionaryByListing(Listing listing) {
CurrencyPairSecurity security = currencyPairSecurityImdg.getSingleObjectByID(listing.getSecurityId());
return currencyPairDictionaryImdg.getSingleObjectByID(security.getCurrencyPairId());
}
private Listing findListingForRub(Registry registry, String marketCode) {
ImdgPredicateBuilder pb = currencyPairDictionaryImdg.predicateBuilder();
CurrencyPairDictionary pair = currencyPairDictionaryImdg.getFirstObjectByPredicate(
pb.and(
pb.equals("baseCurrency", "CNY"),
pb.equals("quoteCurrency", registry.getSecuritySymbol())
)
);
Collection<Long> securityIds = currencyPairSecurityImdg.getCollectionIdsByPredicate(
pb.equals("currencyPairId", pair.getId())
);
return listingImdg.getSingleObjectByPredicate(
pb.and(
pb.in("securityId", securityIds.toArray(new Long[0])),
pb.equals("market", marketCode)
)
);
}
private Listing findListingForOtherCurrency(Registry registry, String marketCode) {
ImdgPredicateBuilder pb = currencyPairDictionaryImdg.predicateBuilder();
CurrencyPairDictionary pair = currencyPairDictionaryImdg.getFirstObjectByPredicate(
pb.and(
pb.equals("baseCurrency", registry.getSecuritySymbol()),
pb.equals("quoteCurrency", "RUB")
)
);
Collection<Long> securityIds = currencyPairSecurityImdg.getCollectionIdsByPredicate(
pb.equals("currencyPairId", pair.getId())
);
return listingImdg.getSingleObjectByPredicate(
pb.and(
pb.in("securityId", securityIds.toArray(new Long[0])),
pb.equals("market", marketCode)
)
);
}
private RiskParameter findRiskParameterForRub() {
ImdgPredicateBuilder pb = currencyPairDictionaryImdg.predicateBuilder();
CurrencyPairDictionary pair = currencyPairDictionaryImdg.getFirstObjectByPredicate(
pb.equals("baseCurrency", "CNY")
);
return riskParameterImdg.getSingleObjectByPredicate(
pb.and(
pb.equals("currencyPairId", pair.getId()),
pb.equals("settlementType", "T0")
)
);
}
private RiskParameter findRiskParameterForOtherCurrency(Registry registry) {
ImdgPredicateBuilder pb = currencyPairDictionaryImdg.predicateBuilder();
CurrencyPairDictionary pair = currencyPairDictionaryImdg.getFirstObjectByPredicate(
pb.equals("baseCurrency", registry.getSecuritySymbol())
);
return riskParameterImdg.getSingleObjectByPredicate(
pb.and(
pb.equals("currencyPairId", pair.getId()),
pb.equals("settlementType", "T0")
)
);
}
public Registry getRegistryById(Long id) {
return registryImdg.getSingleObjectByID(id);
}
public Registry findAmtRegistry(Registry registry, String securitySymbol) {
ImdgPredicateBuilder pb = registryImdg.predicateBuilder();
return registryImdg.getSingleObjectByPredicate(
pb.and(
pb.regex("registryCode", "^PM.*T"),
pb.equals("securitySymbol", securitySymbol),
pb.equals("tradingClearingRegistryId", registry.getId()),
pb.equals("companyId", registry.getCompanyId())
)
);
}
}

View file

@ -0,0 +1,76 @@
package ru.spcex.clearing.dflt.management.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.misc.Listing;
import ru.clearing.classes.statics.data.misc.Market;
import ru.clearing.classes.statics.data.misc.OrderCurrency;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.security.RiskParameter;
import ru.spcex.clearing.dflt.management.model.CounterpartyInfo;
import ru.spcex.clearing.dflt.management.model.SwapContext;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.CompanyRole;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
@Service
public class SpotOvernightOrderService {
private final Logger log = LoggerFactory.getLogger(getClass());
private final ImdgQueryService imdgQueryService;
private final Imdg<OrderCurrency> orderCurrencyImdg;
private final SwapOrderTemplateBuilder templateBuilder;
private final SwapCalculationService swapCalculationService;
public SpotOvernightOrderService(ImdgProvider imdgProvider,
ImdgQueryService imdgQueryService,
SwapOrderTemplateBuilder templateBuilder,
SwapCalculationService swapCalculationService) {
this.imdgQueryService = imdgQueryService;
this.orderCurrencyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_OrderCurrency, OrderCurrency.class);
this.templateBuilder = templateBuilder;
this.swapCalculationService = swapCalculationService;
}
public void process(Registry registry) {
String orderCategory = imdgQueryService.resolveOrderCategory(registry.getCompanyId());
Market market = imdgQueryService.getSwapMarket();
Listing listing = imdgQueryService.findSwapListing(registry, market.getCode());
RiskParameter riskParameter = imdgQueryService.findRiskParameter(registry);
CounterpartyInfo categoryP = imdgQueryService.getCompanyByClearingCategory("P");
CounterpartyInfo clcc = imdgQueryService.getCompanyByRole(CompanyRole.CLCC);
CounterpartyInfo rgcm = imdgQueryService.getCompanyByRole(CompanyRole.RGCM);
SwapContext context = SwapContext.builder()
.registry(registry)
.orderCategory(orderCategory)
.market(market)
.listing(listing)
.riskParameter(riskParameter)
.categoryP(categoryP)
.clcc(clcc)
.rgcm(rgcm)
.build();
// OrderCurrency primaryTransfer = templateBuilder.buildPrimaryTransfer(context);
// OrderCurrency counterTransfer = templateBuilder.buildCounterTransfer(context);
// OrderCurrency primaryBalancing = templateBuilder.buildPrimaryBalancing(context);
// OrderCurrency counterBalancing = templateBuilder.buildCounterBalancing(context);
//
// swapCalculationService.calcAndEnrich(primaryTransfer, context);
// swapCalculationService.calcAndEnrich(counterTransfer, context);
// swapCalculationService.calcAndEnrich(primaryBalancing, context);
// swapCalculationService.calcAndEnrich(counterBalancing, context);
//
// orderCurrencyImdg.insert(primaryTransfer);
// orderCurrencyImdg.insert(counterTransfer);
// orderCurrencyImdg.insert(primaryBalancing);
// orderCurrencyImdg.insert(counterBalancing);
log.info("Spot orders created for registryId={}", registry.getId());
}
}

View file

@ -0,0 +1,110 @@
package ru.spcex.clearing.dflt.management.service;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.misc.Listing;
import ru.clearing.classes.statics.data.misc.OrderCurrency;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.security.Rates;
import ru.clearing.platform.dictionary.CurrencyPairDictionary;
import ru.spcex.clearing.dflt.management.model.CalculationResult;
import ru.spcex.clearing.dflt.management.model.SwapContext;
@Service
public class SwapCalculationService {
private static final MathContext MC = new MathContext(20, RoundingMode.HALF_UP);
private final ImdgQueryService imdgQueryService;
private final TransferDateService transferDateService;
public SwapCalculationService(ImdgQueryService imdgQueryService,
TransferDateService transferDateService) {
this.imdgQueryService = imdgQueryService;
this.transferDateService = transferDateService;
}
public void calcAndEnrich(OrderCurrency order,
SwapContext context) {
Registry registry = context.getRegistry();
Listing listing = context.getListing();
CurrencyPairDictionary pair = imdgQueryService.getCurrencyPairDictionaryByListing(listing);
BigDecimal s = imdgQueryService.defineTransferRate(pair.getId(), registry.getSecuritySymbol());
BigDecimal n = transferDateService.numberOfDaysOfTransfer();
CalculationResult result = isRub(registry)
? calculationSwapRubSums(registry, listing.getLotSize().intValue(), s, n)
: calculationSwapSums(registry, listing.getLotSize().intValue(), s, n);
BigDecimal quantityLot = result.sum3().abs();
BigDecimal price = swapPriceCalc(pair.getBaseCurrency(), s, n);
order.setPrice(price);
order.setQuantityLot(quantityLot);
}
private CalculationResult calculationSwapSums(Registry registry, Integer lotSize, BigDecimal s, BigDecimal n) {
BigDecimal planPosition = registry.getBalance();
BigDecimal sum1 = planPosition.abs();
Registry rubRegistry = imdgQueryService.findAmtRegistry(registry, "RUB");
BigDecimal planPositionRub = rubRegistry.getBalance();
Rates rates = imdgQueryService.getRate(registry.getSecuritySymbol(), LocalDate.now());
BigDecimal rateValue = rates.getValue();
BigDecimal sum2 = planPositionRub.divide(rateValue, lotSize, RoundingMode.HALF_DOWN);
BigDecimal sum3 = sum1.setScale(0, RoundingMode.CEILING).min(sum2);
BigDecimal sum4 = sum3.multiply(rateValue, MC).negate();
BigDecimal sum5 = sum3.negate();
BigDecimal multiplier = BigDecimal.ONE.add(
s.divide(BigDecimal.valueOf(365), MC).multiply(n, MC),
MC
);
BigDecimal sum6 = sum3.multiply(rateValue, MC).multiply(multiplier, MC);
return new CalculationResult(sum1, sum2, sum3, sum4, sum5, sum6);
}
private CalculationResult calculationSwapRubSums(Registry registry, Integer lotSize, BigDecimal s, BigDecimal n) {
BigDecimal planPosition = registry.getBalance();
Rates cnyRate = imdgQueryService.getRate(registry.getSecuritySymbol(), LocalDate.now());
BigDecimal rateValue = cnyRate.getValue();
BigDecimal sum1 = planPosition.divide(rateValue, MC);
Registry cnyRegistry = imdgQueryService.findAmtRegistry(registry, "CNY");
BigDecimal planPositionCny = cnyRegistry.getBalance();
BigDecimal sum2 = planPositionCny.divide(rateValue, lotSize, RoundingMode.HALF_DOWN);
BigDecimal sum3 = sum1.setScale(0, RoundingMode.CEILING).min(sum2).negate();
BigDecimal sum4 = sum3.multiply(rateValue, MC).negate();
BigDecimal sum5 = sum3.negate();
BigDecimal multiplier = BigDecimal.ONE.add(
s.divide(BigDecimal.valueOf(365), MC).multiply(n, MC),
MC
);
BigDecimal sum6 = sum3.multiply(rateValue, MC).multiply(multiplier, MC);
return new CalculationResult(sum1, sum2, sum3, sum4, sum5, sum6);
}
private BigDecimal swapPriceCalc(String baseCurrency, BigDecimal s, BigDecimal n) {
Rates rate = imdgQueryService.getRate(baseCurrency, LocalDate.now());
return rate.getValue()
.multiply(s, MC)
.multiply(n, MC)
.divide(BigDecimal.valueOf(365), MC);
}
private boolean isRub(Registry registry) {
return "RUB".equals(registry.getSecuritySymbol());
}
}

View file

@ -0,0 +1,231 @@
package ru.spcex.clearing.dflt.management.service;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.misc.Listing;
import ru.clearing.classes.statics.data.misc.Market;
import ru.clearing.classes.statics.data.misc.OrderCurrency;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.security.RiskParameter;
import ru.spcex.clearing.dflt.management.model.CounterpartyInfo;
import ru.spcex.clearing.dflt.management.model.SwapContext;
import ru.spcex.platform.enumeration.Side;
@Service
public class SwapOrderTemplateBuilder {
private final ImdgQueryService imdgQueryService;
public SwapOrderTemplateBuilder(ImdgQueryService imdgQueryService) {
this.imdgQueryService = imdgQueryService;
}
public OrderCurrency buildPrimaryTransfer(SwapContext context) {
OrderCurrency orderCurrency;
switch (context.getOrderCategory()) {
case "PL" -> orderCurrency = buildPrimaryTransferPl(context);
case "UK" -> orderCurrency = buildPrimaryTransferUk(context);
default -> throw new IllegalArgumentException("Unsupported order category: " + context.getOrderCategory());
}
Side side = resolvePrimaryTransferSide(context.getRegistry());
enrichOrder(orderCurrency, context, side, "overnight");
return orderCurrency;
}
public OrderCurrency buildCounterTransfer(SwapContext context) {
OrderCurrency orderCurrency;
switch (context.getOrderCategory()) {
case "PL" -> orderCurrency = buildCounterTransferPl(context);
case "UK" -> orderCurrency = buildCounterTransferUk(context);
default -> throw new IllegalArgumentException("Unsupported order category: " + context.getOrderCategory());
};
Side side = resolveCounterTransferSide(context.getRegistry());
enrichOrder(orderCurrency, context, side, "overnight");
return orderCurrency;
}
public OrderCurrency buildPrimaryBalancing(SwapContext context) {
OrderCurrency orderCurrency;
switch (context.getOrderCategory()) {
case "PL" -> orderCurrency = buildPrimaryBalancingPl(context);
case "UK" -> orderCurrency = buildPrimaryBalancingUk(context);
default -> throw new IllegalArgumentException("Unsupported order category: " + context.getOrderCategory());
};
Side side = resolvePrimaryBalancingSide(context.getRegistry());
enrichOrder(orderCurrency, context, side, "balance");
return orderCurrency;
}
public OrderCurrency buildCounterBalancing(SwapContext context) {
OrderCurrency orderCurrency;
switch (context.getOrderCategory()) {
case "PL" -> orderCurrency = buildCounterBalancingPl(context);
case "UK" -> orderCurrency = buildCounterBalancingUk(context);
default -> throw new IllegalArgumentException("Unsupported order category: " + context.getOrderCategory());
};
Side side = resolveCounterBalancingSide(context.getRegistry());
enrichOrder(orderCurrency, context, side, "balance");
return orderCurrency;
}
private OrderCurrency buildPrimaryTransferUk(SwapContext context) {
CounterpartyInfo clcc = context.getClcc();
Registry registry = context.getRegistry();
OrderCurrency order = new OrderCurrency();
order.setAccount(registry.getTradingClearingRegistry());
order.setTradingClearingRegistryId(registry.getTradingClearingRegistryId());
order.setCompanyId(registry.getCompanyId());
order.setTradingCode(registry.getTradingCode());
order.setCounterPartyId(clcc.companyId());
order.setCounterTradingCode(clcc.tradingCode());
order.setType("CMOV");
return order;
}
private OrderCurrency buildCounterTransferUk(SwapContext context) {
CounterpartyInfo clcc = context.getClcc();
Registry registry = context.getRegistry();
OrderCurrency order = new OrderCurrency();
order.setAccount(clcc.registryCode());
order.setTradingClearingRegistryId(clcc.registryId());
order.setCompanyId(clcc.companyId());
order.setTradingCode(clcc.tradingCode());
order.setCounterPartyId(registry.getCompanyId());
order.setCounterTradingCode(registry.getTradingCode());
order.setType("CMOV");
return order;
}
private OrderCurrency buildPrimaryBalancingUk(SwapContext context) {
CounterpartyInfo categoryP = context.getCategoryP();
CounterpartyInfo clcc = context.getClcc();
OrderCurrency order = new OrderCurrency();
order.setAccount(categoryP.registryCode());
order.setTradingClearingRegistryId(categoryP.registryId());
order.setCompanyId(categoryP.companyId());
order.setTradingCode(categoryP.tradingCode());
order.setCounterPartyId(clcc.companyId());
order.setCounterTradingCode(clcc.tradingCode());
order.setType("CMBL");
return order;
}
private OrderCurrency buildCounterBalancingUk(SwapContext context) {
CounterpartyInfo categoryP = context.getCategoryP();
CounterpartyInfo clcc = context.getClcc();
OrderCurrency order = new OrderCurrency();
order.setAccount(clcc.registryCode());
order.setTradingClearingRegistryId(clcc.registryId());
order.setCompanyId(clcc.companyId());
order.setTradingCode(clcc.tradingCode());
order.setCounterPartyId(categoryP.companyId());
order.setCounterTradingCode(categoryP.tradingCode());
order.setType("CMBL");
return order;
}
private OrderCurrency buildPrimaryTransferPl(SwapContext context) {
CounterpartyInfo clcc = context.getClcc();
Registry registry = context.getRegistry();
OrderCurrency order = new OrderCurrency();
order.setAccount(registry.getTradingClearingRegistry());
order.setTradingClearingRegistryId(registry.getTradingClearingRegistryId());
order.setCompanyId(registry.getCompanyId());
order.setTradingCode(registry.getTradingCode());
order.setCounterPartyId(clcc.companyId());
order.setCounterTradingCode(clcc.tradingCode());
order.setType("PLOV");
return order;
}
private OrderCurrency buildCounterTransferPl(SwapContext context) {
CounterpartyInfo clcc = context.getClcc();
Registry registry = context.getRegistry();
OrderCurrency order = new OrderCurrency();
order.setAccount(clcc.registryCode());
order.setTradingClearingRegistryId(clcc.registryId());
order.setCompanyId(clcc.companyId());
order.setTradingCode(clcc.tradingCode());
order.setCounterPartyId(registry.getCompanyId());
order.setCounterTradingCode(registry.getTradingCode());
order.setType("PLOV");
return order;
}
private OrderCurrency buildPrimaryBalancingPl(SwapContext context) {
CounterpartyInfo rgcm = context.getRgcm();
CounterpartyInfo clcc = context.getClcc();
OrderCurrency order = new OrderCurrency();
order.setAccount(rgcm.registryCode());
order.setTradingClearingRegistryId(rgcm.registryId());
order.setCompanyId(rgcm.companyId());
order.setTradingCode(rgcm.tradingCode());
order.setCounterPartyId(clcc.companyId());
order.setCounterTradingCode(clcc.tradingCode());
order.setType("PLBL");
return order;
}
private OrderCurrency buildCounterBalancingPl(SwapContext context) {
CounterpartyInfo clcc = context.getClcc();
CounterpartyInfo rgcm = context.getRgcm();
OrderCurrency order = new OrderCurrency();
order.setAccount(clcc.registryCode());
order.setTradingClearingRegistryId(clcc.registryId());
order.setCompanyId(clcc.companyId());
order.setTradingCode(clcc.tradingCode());
order.setCounterPartyId(rgcm.companyId());
order.setCounterTradingCode(rgcm.tradingCode());
order.setType("PLBL");
return order;
}
public void enrichOrder(OrderCurrency order,
SwapContext context,
Side side,
String comment) {
Registry registry = context.getRegistry();
Listing listing = context.getListing();
Market market = context.getMarket();
RiskParameter riskParameter = context.getRiskParameter();
order.setOvernightType("SWAP");
order.setMarket(market.getCode());
order.setListingId(listing.getId());
order.setSecuritySymbol(listing.getSymbolCode());
order.setSecurityId(listing.getSecurityId());
order.setLotSize(listing.getLotSize());
order.setRate(riskParameter.getQuoteValue());
order.setSide(side.getKey());
order.setSettleCode("T1");
order.setStatus("CRET");
order.setComment(comment);
order.setRegistryId(registry.getId());
}
private Side resolvePrimaryTransferSide(Registry registry) {
return isRub(registry) ? Side.BUY : Side.SELL;
}
private Side resolveCounterTransferSide(Registry registry) {
return isRub(registry) ? Side.SELL : Side.BUY;
}
private Side resolvePrimaryBalancingSide(Registry registry) {
return isRub(registry) ? Side.SELL : Side.BUY;
}
private Side resolveCounterBalancingSide(Registry registry) {
return isRub(registry) ? Side.BUY : Side.SELL;
}
private boolean isRub(Registry registry) {
return "RUB".equals(registry.getSecuritySymbol());
}
}

View file

@ -0,0 +1,76 @@
package ru.spcex.clearing.dflt.management.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.misc.Listing;
import ru.clearing.classes.statics.data.misc.Market;
import ru.clearing.classes.statics.data.misc.OrderCurrency;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.clearing.classes.statics.data.security.RiskParameter;
import ru.spcex.clearing.dflt.management.model.CounterpartyInfo;
import ru.spcex.clearing.dflt.management.model.SwapContext;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.CompanyRole;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
@Service
public class SwapOvernightOrderService {
private final Logger log = LoggerFactory.getLogger(getClass());
private final ImdgQueryService imdgQueryService;
private final Imdg<OrderCurrency> orderCurrencyImdg;
private final SwapOrderTemplateBuilder templateBuilder;
private final SwapCalculationService swapCalculationService;
public SwapOvernightOrderService(ImdgProvider imdgProvider,
ImdgQueryService imdgQueryService,
SwapOrderTemplateBuilder templateBuilder,
SwapCalculationService swapCalculationService) {
this.imdgQueryService = imdgQueryService;
this.orderCurrencyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_OrderCurrency, OrderCurrency.class);
this.templateBuilder = templateBuilder;
this.swapCalculationService = swapCalculationService;
}
public void process(Registry registry) {
String orderCategory = imdgQueryService.resolveOrderCategory(registry.getCompanyId());
Market market = imdgQueryService.getSwapMarket();
Listing listing = imdgQueryService.findSwapListing(registry, market.getCode());
RiskParameter riskParameter = imdgQueryService.findRiskParameter(registry);
CounterpartyInfo categoryP = imdgQueryService.getCompanyByClearingCategory("P");
CounterpartyInfo clcc = imdgQueryService.getCompanyByRole(CompanyRole.CLCC);
CounterpartyInfo rgcm = imdgQueryService.getCompanyByRole(CompanyRole.RGCM);
SwapContext context = SwapContext.builder()
.registry(registry)
.orderCategory(orderCategory)
.market(market)
.listing(listing)
.riskParameter(riskParameter)
.categoryP(categoryP)
.clcc(clcc)
.rgcm(rgcm)
.build();
OrderCurrency primaryTransfer = templateBuilder.buildPrimaryTransfer(context);
OrderCurrency counterTransfer = templateBuilder.buildCounterTransfer(context);
OrderCurrency primaryBalancing = templateBuilder.buildPrimaryBalancing(context);
OrderCurrency counterBalancing = templateBuilder.buildCounterBalancing(context);
swapCalculationService.calcAndEnrich(primaryTransfer, context);
swapCalculationService.calcAndEnrich(counterTransfer, context);
swapCalculationService.calcAndEnrich(primaryBalancing, context);
swapCalculationService.calcAndEnrich(counterBalancing, context);
orderCurrencyImdg.insert(primaryTransfer);
orderCurrencyImdg.insert(counterTransfer);
orderCurrencyImdg.insert(primaryBalancing);
orderCurrencyImdg.insert(counterBalancing);
log.info("Swap orders created for registryId={}", registry.getId());
}
}

View file

@ -0,0 +1,56 @@
package ru.spcex.clearing.dflt.management.service;
import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.scheduler.ClearingCalendar;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.platform.enumeration.DayStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
@Service
public class TransferDateService {
private final Imdg<ClearingCalendar> clearingCalendarImdg;
public TransferDateService(ImdgProvider imdgProvider) {
this.clearingCalendarImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ClearingCalendar, ClearingCalendar.class);
}
public LocalDate findNextWorkingDate() {
LocalDate checkingDate = LocalDate.now().plusDays(1);
ImdgPredicateBuilder pb = clearingCalendarImdg.predicateBuilder();
while (true) {
ClearingCalendar calendarDay = clearingCalendarImdg.getFirstObjectByPredicate(
pb.equals("clearingDate", checkingDate)
);
if (isWeekday(checkingDate.getDayOfWeek())) {
// Будний день рабочий, если НЕТ явной записи DOFF
if (calendarDay == null || !DayStatus.DayOff.equalsByKey(calendarDay.getDayStatus())) {
return checkingDate;
}
} else {
// Выходной рабочий, только если ЕСТЬ явная запись BDAY
if (calendarDay != null && DayStatus.Workday.equalsByKey(calendarDay.getDayStatus())) {
return checkingDate;
}
}
checkingDate = checkingDate.plusDays(1);
}
}
public BigDecimal numberOfDaysOfTransfer() {
long days = ChronoUnit.DAYS.between(LocalDate.now(), findNextWorkingDate());
return BigDecimal.valueOf(days);
}
private boolean isWeekday(DayOfWeek dayOfWeek) {
return dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
}
}