Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
ialbert 2026-04-29 15:05:32 +03:00
commit 4e52ce01d8
18 changed files with 191 additions and 51 deletions

View file

@ -192,7 +192,7 @@ public class RegistryController extends AbstractQueueController {
@ApiOperation(value = "Вывод средств с регистра невыясненных активов") @ApiOperation(value = "Вывод средств с регистра невыясненных активов")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CudResponse.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)}) @ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CudResponse.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
@RequestMapping(value = "/withdrawalFunds", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(value = "/withdrawalFunds", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody @ResponseBody
public CudResponse dmauRegistryNew( public CudResponse dmauRegistryNew(
@ApiParam(value = "Параметры команды в JSON формате.", required = true) @ApiParam(value = "Параметры команды в JSON формате.", required = true)

View file

@ -12,9 +12,12 @@ public class RiskParameterNewAction implements IAction<RiskParameterNewRequest>
@ApiModelProperty(value = "Курс.", example = "1234") @ApiModelProperty(value = "Курс.", example = "1234")
@JsonProperty @JsonProperty
private BigDecimal value; private BigDecimal value;
@ApiModelProperty(value = "Ставка сопряженной валюты.", example = "1234") @ApiModelProperty(value = "Ставка переноса при нехватке рублей.", example = "1234")
@JsonProperty @JsonProperty
private BigDecimal quoteValue; private BigDecimal quoteValue;
@ApiModelProperty(value = "Ставка переноса при нехватке валюты.", example = "1234")
@JsonProperty
private BigDecimal penaltyValue;
@ApiModelProperty(value = "Код расчёта.", example = "1234") @ApiModelProperty(value = "Код расчёта.", example = "1234")
@JsonProperty @JsonProperty
private String settlementType; private String settlementType;
@ -30,6 +33,7 @@ public class RiskParameterNewAction implements IAction<RiskParameterNewRequest>
RiskParameterNewRequest request = new RiskParameterNewRequest(); RiskParameterNewRequest request = new RiskParameterNewRequest();
request.setValue(this.value); request.setValue(this.value);
request.setQuoteValue(this.quoteValue); request.setQuoteValue(this.quoteValue);
request.setPenaltyValue(this.penaltyValue);
request.setSettlementType(this.settlementType); request.setSettlementType(this.settlementType);
request.setCurrencyPairId(this.currencyPairId); request.setCurrencyPairId(this.currencyPairId);
request.setWorkflowStatus(this.workflowStatus); request.setWorkflowStatus(this.workflowStatus);
@ -73,4 +77,8 @@ public class RiskParameterNewAction implements IAction<RiskParameterNewRequest>
public void setWorkflowStatus(String workflowStatus) { public void setWorkflowStatus(String workflowStatus) {
this.workflowStatus = workflowStatus; this.workflowStatus = workflowStatus;
} }
public void setPenaltyValue(BigDecimal penaltyValue) {
this.penaltyValue = penaltyValue;
}
} }

View file

@ -15,9 +15,12 @@ public class RiskParameterUpdateAction implements IAction<RiskParameterUpdateReq
@ApiModelProperty(value = "Курс.", example = "1234") @ApiModelProperty(value = "Курс.", example = "1234")
@JsonProperty @JsonProperty
private BigDecimal value; private BigDecimal value;
@ApiModelProperty(value = "Ставка сопряженной валюты.", example = "1234") @ApiModelProperty(value = "Ставка переноса при нехватке рублей.", example = "1234")
@JsonProperty @JsonProperty
private BigDecimal quoteValue; private BigDecimal quoteValue;
@ApiModelProperty(value = "Ставка переноса при нехватке валюты.", example = "1234")
@JsonProperty
private BigDecimal penaltyValue;
@ApiModelProperty(value = "Статус.", example = "1234") @ApiModelProperty(value = "Статус.", example = "1234")
@JsonProperty @JsonProperty
private String workflowStatus; private String workflowStatus;
@ -28,6 +31,7 @@ public class RiskParameterUpdateAction implements IAction<RiskParameterUpdateReq
request.setId(this.id); request.setId(this.id);
request.setValue(this.value); request.setValue(this.value);
request.setQuoteValue(this.quoteValue); request.setQuoteValue(this.quoteValue);
request.setPenaltyValue(this.penaltyValue);
request.setWorkflowStatus(this.workflowStatus); request.setWorkflowStatus(this.workflowStatus);
return request; return request;
} }
@ -61,4 +65,12 @@ public class RiskParameterUpdateAction implements IAction<RiskParameterUpdateReq
public void setWorkflowStatus(String workflowStatus) { public void setWorkflowStatus(String workflowStatus) {
this.workflowStatus = workflowStatus; this.workflowStatus = workflowStatus;
} }
public void setQuoteValue(BigDecimal quoteValue) {
this.quoteValue = quoteValue;
}
public void setPenaltyValue(BigDecimal penaltyValue) {
this.penaltyValue = penaltyValue;
}
} }

View file

@ -1,6 +1,6 @@
{ {
"version": "3.23.295.164", "version": "3.23.295.167",
"enums": { "enums": {
@ -11089,9 +11089,13 @@
{"code": "value", {"code": "value",
"name": "Ставка","shortname": "Ставка","type": 10 "name": "Ставка","shortname": "Ставка","type": 10
} }
,
{"code": "penaltyValue",
"name": "Ставка переноса при нехватке валюты","shortname": "Ставка переноса при нехватке валюты","type": 10
}
, ,
{"code": "quoteValue", {"code": "quoteValue",
"name": "Ставка сопряженной валюты","shortname": "Ставка сопряженной валюты","type": 10 "name": "Ставка переноса при нехватке рублей","shortname": "Ставка переноса при нехватке рублей","type": 10
} }
, ,
{"code": "workflowStatus", {"code": "workflowStatus",
@ -11103,7 +11107,7 @@
"name": "Добавление параметров риска", "name": "Добавление параметров риска",
"confirmation": "value,quoteValue,settlementType,currencyPairId,workflowStatus", "confirmation": "value,penaltyValue,quoteValue,settlementType,currencyPairId,workflowStatus",
"class": "ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterNewAction", "class": "ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterNewAction",
@ -11119,9 +11123,13 @@
{"code": "value", {"code": "value",
"name": "Ставка","shortname": "Ставка","type": 10 "name": "Ставка","shortname": "Ставка","type": 10
} }
,
{"code": "penaltyValue",
"name": "Ставка переноса при нехватке валюты","shortname": "Ставка переноса при нехватке валюты","type": 10
}
, ,
{"code": "quoteValue", {"code": "quoteValue",
"name": "Ставка сопряженной валюты","shortname": "Ставка сопряженной валюты","type": 10 "name": "Ставка переноса при нехватке рублей","shortname": "Ставка переноса при нехватке рублей","type": 10
} }
, ,
{"code": "workflowStatus", {"code": "workflowStatus",
@ -11134,7 +11142,7 @@
"name": "Изменение параметров риска", "name": "Изменение параметров риска",
"confirmation": "value,quoteValue,workflowStatus", "confirmation": "value,penaltyValue,quoteValue,workflowStatus",
"class": "ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterUpdateAction", "class": "ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterUpdateAction",
@ -11146,9 +11154,13 @@
{"code": "value", {"code": "value",
"name": "Ставка","shortname": "Ставка","type": 10 "name": "Ставка","shortname": "Ставка","type": 10
} }
,
{"code": "penaltyValue",
"name": "Ставка переноса при нехватке валюты","shortname": "Ставка переноса при нехватке валюты","type": 10
}
, ,
{"code": "quoteValue", {"code": "quoteValue",
"name": "Ставка сопряженной валюты","shortname": "Ставка сопряженной валюты","type": 10 "name": "Ставка переноса при нехватке рублей","shortname": "Ставка переноса при нехватке рублей","type": 10
} }
, ,
{"code": "workflowStatus", {"code": "workflowStatus",
@ -11755,7 +11767,7 @@
} }
, ,
{"code": "quantityLot", {"code": "quantityLot",
"type": 3,"name": "Объем заявки в лотах","shortname": "Объем заявки в лотах","searchable": true,"sortable": true,"visible": false,"ignore": true "type": 3,"name": "Объем заявки в лотах","shortname": "Объем заявки в лотах","searchable": true,"sortable": true,"visible": false
} }
, ,
{"code": "rate", {"code": "rate",
@ -11763,7 +11775,7 @@
} }
, ,
{"code": "quantity", {"code": "quantity",
"type": 3,"name": "Объем заявки в штуках","shortname": "Объем заявки в шт.","searchable": true,"sortable": true,"visible": true "type": 3,"name": "Объем заявки в штуках","shortname": "Объем заявки в шт.","searchable": true,"sortable": true,"visible": true,"ignore": true
} }
, ,
{"code": "lotSize", {"code": "lotSize",

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!--?xml-stylesheet type="text/xsl" href="\..\corp-reports\src\data\meta\meta.server.xslt"?--> <!--?xml-stylesheet type="text/xsl" href="\..\corp-reports\src\data\meta\meta.server.xslt"?-->
<meta version="3.23.295.164"> <meta version="3.23.295.167">
<!-- _xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" _xsi:noNamespaceSchemaLocation="file:///E:/d/projects/meta/from/meta.xsd" --> <!-- _xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" _xsi:noNamespaceSchemaLocation="file:///E:/d/projects/meta/from/meta.xsd" -->
<!--Здесь словари--> <!--Здесь словари-->
<enums> <enums>
@ -2570,20 +2570,23 @@
<currencyPairId name="Идентификатор валютной пары" shortname="Валютная пара" type="1"/> <currencyPairId name="Идентификатор валютной пары" shortname="Валютная пара" type="1"/>
<settlementType name="Код расчета" shortname="Код расчета" type="2" length="4"/> <settlementType name="Код расчета" shortname="Код расчета" type="2" length="4"/>
<value name="Ставка" shortname="Ставка" type="10"/> <value name="Ставка" shortname="Ставка" type="10"/>
<quoteValue name="Ставка сопряженной валюты" shortname="Ставка сопряженной валюты" type="10"/> <penaltyValue name="Ставка переноса при нехватке валюты" shortname="Ставка переноса при нехватке валюты" type="10"/>
<quoteValue name="Ставка переноса при нехватке рублей" shortname="Ставка переноса при нехватке рублей" type="10"/>
<workflowStatus name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/> <workflowStatus name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/>
<actions> <actions>
<post name="Добавление параметров риска" confirmation="value,quoteValue,settlementType,currencyPairId,workflowStatus" class="ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterNewAction"> <post name="Добавление параметров риска" confirmation="value,penaltyValue,quoteValue,settlementType,currencyPairId,workflowStatus" class="ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterNewAction">
<currencyPairId name="Идентификатор валютной пары" shortname="Валютная пара" type="1" link="currencyPair" linkCode="code" linkKeyCode="id"/> <currencyPairId name="Идентификатор валютной пары" shortname="Валютная пара" type="1" link="currencyPair" linkCode="code" linkKeyCode="id"/>
<settlementType name="Код расчёта" shortname="Код расчёта" type="12" link="currencySettlementType" linkCode="code"/> <settlementType name="Код расчёта" shortname="Код расчёта" type="12" link="currencySettlementType" linkCode="code"/>
<value name="Ставка" shortname="Ставка" type="10"/> <value name="Ставка" shortname="Ставка" type="10"/>
<quoteValue name="Ставка сопряженной валюты" shortname="Ставка сопряженной валюты" type="10"/> <penaltyValue name="Ставка переноса при нехватке валюты" shortname="Ставка переноса при нехватке валюты" type="10"/>
<quoteValue name="Ставка переноса при нехватке рублей" shortname="Ставка переноса при нехватке рублей" type="10"/>
<workflowStatus name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/> <workflowStatus name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/>
</post> </post>
<put name="Изменение параметров риска" confirmation="value,quoteValue,workflowStatus" class="ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterUpdateAction"> <put name="Изменение параметров риска" confirmation="value,penaltyValue,quoteValue,workflowStatus" class="ru.spcex.clearing.backendapi.controller.request.cud.securities.RiskParameterUpdateAction">
<id type="1" name="Идентификатор записи" shortname="ID" link="riskParameter" linkCode="id" required="true"/> <id type="1" name="Идентификатор записи" shortname="ID" link="riskParameter" linkCode="id" required="true"/>
<value name="Ставка" shortname="Ставка" type="10"/> <value name="Ставка" shortname="Ставка" type="10"/>
<quoteValue name="Ставка сопряженной валюты" shortname="Ставка сопряженной валюты" type="10"/> <penaltyValue name="Ставка переноса при нехватке валюты" shortname="Ставка переноса при нехватке валюты" type="10"/>
<quoteValue name="Ставка переноса при нехватке рублей" shortname="Ставка переноса при нехватке рублей" type="10"/>
<workflowStatus name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/> <workflowStatus name="Статус" shortname="Статус" type="2" length="4" link="workflowStatus"/>
</put> </put>
</actions> </actions>
@ -2729,9 +2732,9 @@
<market type="12" name="Код режима торгов" shortname="Режим торгов" visible="true" searchable="true" sortable="true" link="market" linkCode="code"/> <market type="12" name="Код режима торгов" shortname="Режим торгов" visible="true" searchable="true" sortable="true" link="market" linkCode="code"/>
<status type="2" length="4" name="Статус заявки" shortname="Статус" link="orderStatus" searchable="true" sortable="true" visible="true"/> <status type="2" length="4" name="Статус заявки" shortname="Статус" link="orderStatus" searchable="true" sortable="true" visible="true"/>
<price type="10" name="Цена заявки" shortname="Цена" searchable="true" sortable="true" visible="true"/> <price type="10" name="Цена заявки" shortname="Цена" searchable="true" sortable="true" visible="true"/>
<quantityLot type="3" name="Объем заявки в лотах" shortname="Объем заявки в лотах" searchable="true" sortable="true" visible="false" ignore="true"/> <quantityLot type="3" name="Объем заявки в лотах" shortname="Объем заявки в лотах" searchable="true" sortable="true" visible="false"/>
<rate type="10" name="Ставка переноса" shortname="Ставка переноса" searchable="true" sortable="true" visible="false"/> <rate type="10" name="Ставка переноса" shortname="Ставка переноса" searchable="true" sortable="true" visible="false"/>
<quantity type="3" name="Объем заявки в штуках" shortname="Объем заявки в шт." searchable="true" sortable="true" visible="true"/> <quantity type="3" name="Объем заявки в штуках" shortname="Объем заявки в шт." searchable="true" sortable="true" visible="true" ignore="true"/>
<lotSize field="securityId" type="11" name="Размер лота" shortname="Лот" searchable="true" sortable="true" visible="false" linkKeyCode="securityId" linkCode="lotSize" link="listing" extends="listing"/> <lotSize field="securityId" type="11" name="Размер лота" shortname="Лот" searchable="true" sortable="true" visible="false" linkKeyCode="securityId" linkCode="lotSize" link="listing" extends="listing"/>
<side type="12" name="Направление заявки" shortname="Направление" searchable="true" sortable="true" visible="true" link="side"/> <side type="12" name="Направление заявки" shortname="Направление" searchable="true" sortable="true" visible="true" link="side"/>
<counterPartyId type="1" dbname="Идентификатор компании-партнера" name="Название УК контрагента" shortname="Контрагент" visible="false" searchable="true" sortable="true" link="company" linkCode="shortName"/> <counterPartyId type="1" dbname="Идентификатор компании-партнера" name="Название УК контрагента" shortname="Контрагент" visible="false" searchable="true" sortable="true" link="company" linkCode="shortName"/>

View file

@ -10,6 +10,7 @@ public class RiskParameter extends BusinessObject {
private Long currencyPairId; private Long currencyPairId;
private String workflowStatus; private String workflowStatus;
private BigDecimal quoteValue; private BigDecimal quoteValue;
private BigDecimal penaltyValue;
public BigDecimal getValue() { public BigDecimal getValue() {
return value; return value;
@ -58,4 +59,12 @@ public class RiskParameter extends BusinessObject {
public void setQuoteValue(BigDecimal quoteValue) { public void setQuoteValue(BigDecimal quoteValue) {
this.quoteValue = quoteValue; this.quoteValue = quoteValue;
} }
public BigDecimal getPenaltyValue() {
return penaltyValue;
}
public void setPenaltyValue(BigDecimal penaltyValue) {
this.penaltyValue = penaltyValue;
}
} }

View file

@ -5343,7 +5343,9 @@ CREATE TABLE RISK_PARAMETER
CURRENCY_PAIR_ID BIGINT, CURRENCY_PAIR_ID BIGINT,
CREATED_AT timestamp, CREATED_AT timestamp,
UPDATED_AT timestamp, UPDATED_AT timestamp,
WORKFLOW_STATUS VARCHAR(4) WORKFLOW_STATUS VARCHAR(4),
PENALTY_VALUE numeric(72,18),
QUOTE_VALUE numeric(72,18)
); );
COMMENT ON TABLE RISK_PARAMETER IS 'Риск-параметры'; COMMENT ON TABLE RISK_PARAMETER IS 'Риск-параметры';
COMMENT ON COLUMN RISK_PARAMETER.ID IS 'Идентификатор записи'; COMMENT ON COLUMN RISK_PARAMETER.ID IS 'Идентификатор записи';
@ -5354,6 +5356,8 @@ COMMENT ON COLUMN RISK_PARAMETER.CURRENCY_PAIR_ID IS 'Идентификатор
COMMENT ON COLUMN RISK_PARAMETER.CREATED_AT IS 'Время создания записи'; COMMENT ON COLUMN RISK_PARAMETER.CREATED_AT IS 'Время создания записи';
COMMENT ON COLUMN RISK_PARAMETER.UPDATED_AT IS 'Время изменения записи'; COMMENT ON COLUMN RISK_PARAMETER.UPDATED_AT IS 'Время изменения записи';
COMMENT ON COLUMN RISK_PARAMETER.WORKFLOW_STATUS IS 'Статус'; COMMENT ON COLUMN RISK_PARAMETER.WORKFLOW_STATUS IS 'Статус';
COMMENT ON COLUMN RISK_PARAMETER.QUOTE_VALUE IS 'Ставка переноса сопряженной валюты';
COMMENT ON COLUMN RISK_PARAMETER.PENALTY_VALUE IS 'Ставка переноса при нехватке базовой валюты';
GRANT ALL PRIVILEGES ON TABLE RISK_PARAMETER TO clearing; GRANT ALL PRIVILEGES ON TABLE RISK_PARAMETER TO clearing;
-- rates - Расчетные курсы -- rates - Расчетные курсы
@ -5579,7 +5583,8 @@ CREATE TABLE ORDER_CURRENCY
COMMENT VARCHAR(255), COMMENT VARCHAR(255),
INITIAL_ORDER_ID BIGINT, INITIAL_ORDER_ID BIGINT,
CREATED_AT TIMESTAMP, CREATED_AT TIMESTAMP,
UPDATED_AT TIMESTAMP UPDATED_AT TIMESTAMP,
REGISTRY_ID BIGINT
); );
COMMENT ON TABLE ORDER_CURRENCY IS 'Заявки для заключения сделок переноса на валютном рынке'; COMMENT ON TABLE ORDER_CURRENCY IS 'Заявки для заключения сделок переноса на валютном рынке';

View file

@ -3,6 +3,8 @@
ALTER TABLE RISK_PARAMETER ADD COLUMN IF NOT EXISTS QUOTE_VALUE NUMERIC(72, 18); ALTER TABLE RISK_PARAMETER ADD COLUMN IF NOT EXISTS QUOTE_VALUE NUMERIC(72, 18);
COMMENT ON COLUMN RISK_PARAMETER.QUOTE_VALUE IS 'Ставка переноса сопряженной валюты'; COMMENT ON COLUMN RISK_PARAMETER.QUOTE_VALUE IS 'Ставка переноса сопряженной валюты';
ALTER TABLE RISK_PARAMETER ADD COLUMN IF NOT EXISTS PENALTY_VALUE NUMERIC(72, 18);
COMMENT ON COLUMN RISK_PARAMETER.PENALTY_VALUE IS 'Ставка переноса при нехватке базовой валюты';
ALTER TABLE ORDER_CURRENCY ADD COLUMN IF NOT EXISTS REGISTRY_ID BIGINT; ALTER TABLE ORDER_CURRENCY ADD COLUMN IF NOT EXISTS REGISTRY_ID BIGINT;
COMMENT ON COLUMN ORDER_CURRENCY.REGISTRY_ID IS 'Идентификатор регистра'; COMMENT ON COLUMN ORDER_CURRENCY.REGISTRY_ID IS 'Идентификатор регистра';

View file

@ -217,7 +217,7 @@ public class ImdgQueryService {
pb.equals("currencyPairId", currencyPairDictionaryId) pb.equals("currencyPairId", currencyPairDictionaryId)
) )
); );
return isRub ? riskParameter.getValue() : riskParameter.getQuoteValue(); return isRub ? riskParameter.getQuoteValue() : riskParameter.getValue();
} }
public CurrencyPairDictionary getCurrencyPairDictionaryBySecurityId(Long securityId) { public CurrencyPairDictionary getCurrencyPairDictionaryBySecurityId(Long securityId) {

View file

@ -50,6 +50,7 @@ public class OrderCalculationService {
order.setPrice(price); order.setPrice(price);
order.setQuantityLot(quantityLot); order.setQuantityLot(quantityLot);
order.setRate(s);
} }
public void calcAndEnrichSpot(OrderCurrency order, public void calcAndEnrichSpot(OrderCurrency order,
@ -90,8 +91,12 @@ public class OrderCalculationService {
BigDecimal planPositionRub = rubRegistry.getBalance(); BigDecimal planPositionRub = rubRegistry.getBalance();
Rates rates = imdgQueryService.getRate(registry.getSecuritySymbol(), LocalDate.now()); Rates rates = imdgQueryService.getRate(registry.getSecuritySymbol(), LocalDate.now());
BigDecimal rateValue = rates.getValue();
SCrossRate sCrossRates = imdgQueryService.getSCrossRates(registry.getSecuritySymbol(), LocalDate.now());
if (sCrossRates == null) {
throw new IllegalStateException(String.format("Not fond rate by security symbol: %s", CurrencyCode.CNY.getKey()));
}
BigDecimal rateValue = sCrossRates.getUnitRate();
BigDecimal sum2 = planPositionRub.divide(rateValue, lotSize, RoundingMode.HALF_DOWN); BigDecimal sum2 = planPositionRub.divide(rateValue, lotSize, RoundingMode.HALF_DOWN);
BigDecimal sum3 = sum1.setScale(lotSize, RoundingMode.CEILING); BigDecimal sum3 = sum1.setScale(lotSize, RoundingMode.CEILING);
BigDecimal sum4 = sum3.multiply(rateValue, MC).negate(); BigDecimal sum4 = sum3.multiply(rateValue, MC).negate();
@ -117,10 +122,10 @@ public class OrderCalculationService {
BigDecimal sum1 = planPosition.divide(rateValue, MC); BigDecimal sum1 = planPosition.divide(rateValue, MC);
Registry cnyRegistry = imdgQueryService.findAmtRegistry(registry, "CNY"); Registry amtRegistry = imdgQueryService.findAmtRegistry(registry, "CNY");
BigDecimal planPositionCny = cnyRegistry.getBalance(); BigDecimal planPositionCny = amtRegistry.getBalance();
BigDecimal sum2 = planPositionCny.divide(rateValue, lotSize, RoundingMode.HALF_DOWN); BigDecimal sum2 = planPositionCny.setScale(lotSize, RoundingMode.HALF_DOWN);
BigDecimal sum3 = sum1.setScale(lotSize, RoundingMode.CEILING).min(sum2).negate(); BigDecimal sum3 = sum1.setScale(lotSize, RoundingMode.CEILING).min(sum2).negate();
BigDecimal sum4 = sum3.multiply(rateValue, MC).negate(); BigDecimal sum4 = sum3.multiply(rateValue, MC).negate();
BigDecimal sum5 = sum3.negate(); BigDecimal sum5 = sum3.negate();

View file

@ -3,32 +3,59 @@ package ru.spcex.clearing.dflt.management.service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.StringJoiner; import java.util.StringJoiner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.misc.OrderCurrency; import ru.clearing.classes.statics.data.misc.OrderCurrency;
import ru.clearing.classes.statics.data.security.Rates; import ru.clearing.classes.statics.data.security.Rates;
import ru.clearing.platform.dictionary.CurrencyPairDictionary; import ru.clearing.platform.dictionary.CurrencyPairDictionary;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.NotificationNewRequest;
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.platform.enumeration.ObjectType;
import ru.spcex.platform.enumeration.OvernightType; import ru.spcex.platform.enumeration.OvernightType;
import ru.spcex.platform.enumeration.Priority;
import ru.spcex.platform.enumeration.Side; import ru.spcex.platform.enumeration.Side;
@Service @Service
public class OrderCurrencyTriExportService { public class OrderCurrencyTriExportService {
private static final Logger log = LoggerFactory.getLogger(OrderCurrencyTriExportService.class);
private final ImdgQueryService imdgQueryService; private final ImdgQueryService imdgQueryService;
private final KafkaSender kafkaSender;
private static final String ACTION = "Ввод внебиржевой заявки"; private static final String ACTION = "Ввод внебиржевой заявки";
public OrderCurrencyTriExportService( public OrderCurrencyTriExportService(ImdgQueryService imdgQueryService,
ImdgQueryService imdgQueryService) { KafkaSender kafkaSender) {
this.imdgQueryService = imdgQueryService; this.imdgQueryService = imdgQueryService;
this.kafkaSender = kafkaSender;
} }
/** /**
* Возвращает содержимое tri-файла в виде строки. * Возвращает содержимое tri-файла в виде строки.
*/ */
public String exportToTri(Collection<OrderCurrency> orders) { public String exportToTri(Collection<OrderCurrency> orders) {
return orders.stream() boolean allSuccess = true;
.map(this::toTriLine) List<String> rows = new ArrayList<>();
for (OrderCurrency orderCurrency : orders) {
String baseCurrency = resolveBaseRate(orderCurrency);
if (OvernightType.SWAP.equalsByKey(orderCurrency.getOvernightType()) && baseCurrency == null) {
allSuccess = false;
}
rows.add(toTriLine(orderCurrency, baseCurrency));
}
if (!allSuccess) {
String comment = "При формировании файла с заявками не определен Базовый курс";
NotificationNewRequest newReq = new NotificationNewRequest();
newReq.setObjectType(ObjectType.rgst.getKey());
newReq.setPriority(Priority.HIGH.getKey());
newReq.setComment(comment);
kafkaSender.sendRequestToQueue(Consts.NOTIFICATION_NEW, newReq);
}
return rows.stream()
.reduce((a, b) -> a + System.lineSeparator() + b) .reduce((a, b) -> a + System.lineSeparator() + b)
.orElse(""); .orElse("");
} }
@ -40,7 +67,7 @@ public class OrderCurrencyTriExportService {
return exportToTri(orders).getBytes(StandardCharsets.UTF_8); return exportToTri(orders).getBytes(StandardCharsets.UTF_8);
} }
private String toTriLine(OrderCurrency orderCurrency) { private String toTriLine(OrderCurrency orderCurrency, String baseCurrency) {
StringJoiner joiner = new StringJoiner(";", "", ";"); StringJoiner joiner = new StringJoiner(";", "", ";");
joiner.add("TRANS_ID=" + nullSafe(orderCurrency.getId())); joiner.add("TRANS_ID=" + nullSafe(orderCurrency.getId()));
joiner.add("CLASSCODE=" + nullSafe(orderCurrency.getMarket())); joiner.add("CLASSCODE=" + nullSafe(orderCurrency.getMarket()));
@ -56,7 +83,7 @@ public class OrderCurrencyTriExportService {
joiner.add("Ссылка="); joiner.add("Ссылка=");
joiner.add("Код расчетов=" + nullSafe(orderCurrency.getSettleCode())); joiner.add("Код расчетов=" + nullSafe(orderCurrency.getSettleCode()));
joiner.add("На заявку №="); joiner.add("На заявку №=");
joiner.add("Базовый курс=" + resolveBaseRate(orderCurrency)); joiner.add("Базовый курс=" + nullSafe(baseCurrency));
return joiner.toString(); return joiner.toString();
} }
@ -68,22 +95,23 @@ public class OrderCurrencyTriExportService {
if (Side.SELL.equalsByKey(side)) { if (Side.SELL.equalsByKey(side)) {
return "Продажа"; return "Продажа";
} }
throw new IllegalArgumentException("Неизвестное значение side: " + side); log.warn("Неизвестное значение side: {}", side);
return "";
} }
private String resolveBaseRate(OrderCurrency orderCurrency) { public String resolveBaseRate(OrderCurrency orderCurrency) {
if (OvernightType.SPOT.equalsByKey(orderCurrency.getOvernightType())) { if (OvernightType.SPOT.equalsByKey(orderCurrency.getOvernightType())) {
return ""; return "";
} }
CurrencyPairDictionary currencyPairDictionary = imdgQueryService.getCurrencyPairDictionaryBySecurityId(orderCurrency.getSecurityId()); CurrencyPairDictionary currencyPairDictionary = imdgQueryService.getCurrencyPairDictionaryBySecurityId(orderCurrency.getSecurityId());
String baseCurrency = currencyPairDictionary.getBaseCurrency(); String baseCurrency = currencyPairDictionary.getBaseCurrency();
Rates rates = imdgQueryService.getRate(currencyPairDictionary.getBaseCurrency(), LocalDate.now()); LocalDate now = LocalDate.now();
Rates rates = imdgQueryService.getRate(currencyPairDictionary.getBaseCurrency(), now);
if (rates == null || rates.getValue() == null) { if (rates == null || rates.getValue() == null) {
throw new IllegalStateException( log.warn("Не найден активный курс для валюты {} на дату {}", baseCurrency, now);
"Не найден активный курс для валюты " + baseCurrency + " на дату " + LocalDate.now() return null;
);
} }
return formatDecimal(rates.getValue()); return formatDecimal(rates.getValue());

View file

@ -214,26 +214,26 @@ public class OrderTemplateBuilder {
order.setCreated(Instant.now()); order.setCreated(Instant.now());
} }
private Side resolvePrimaryTransferSide(Registry registry, SettleCode settleCode) { public Side resolvePrimaryTransferSide(Registry registry, SettleCode settleCode) {
Side side = T0 == settleCode ? Side.BUY : Side.SELL;
return isRub(registry) ? side : side.revers();
}
private Side resolveCounterTransferSide(Registry registry, SettleCode settleCode) {
Side side = T0 == settleCode ? Side.SELL : Side.BUY; Side side = T0 == settleCode ? Side.SELL : Side.BUY;
return isRub(registry) ? side : side.revers(); return isRub(registry) ? side : side.revers();
} }
private Side resolvePrimaryBalancingSide(Registry registry, SettleCode settleCode) { public Side resolveCounterTransferSide(Registry registry, SettleCode settleCode) {
Side side = T0 == settleCode ? Side.SELL : Side.BUY; Side side = T0 == settleCode ? Side.BUY : Side.SELL;
return isRub(registry) ? side : side.revers(); return isRub(registry) ? side : side.revers();
} }
private Side resolveCounterBalancingSide(Registry registry, SettleCode settleCode) { public Side resolvePrimaryBalancingSide(Registry registry, SettleCode settleCode) {
Side side = T0 == settleCode ? Side.BUY : Side.SELL; Side side = T0 == settleCode ? Side.BUY : Side.SELL;
return isRub(registry) ? side : side.revers(); return isRub(registry) ? side : side.revers();
} }
public Side resolveCounterBalancingSide(Registry registry, SettleCode settleCode) {
Side side = T0 == settleCode ? Side.SELL : Side.BUY;
return isRub(registry) ? side : side.revers();
}
private boolean isRub(Registry registry) { private boolean isRub(Registry registry) {
return "RUB".equals(registry.getSecuritySymbol()); return "RUB".equals(registry.getSecuritySymbol());
} }

View file

@ -0,0 +1,32 @@
package ru.spcex.clearing.dflt.service;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.spcex.clearing.dflt.management.service.OrderTemplateBuilder;
import ru.spcex.platform.enumeration.SettleCode;
import ru.spcex.platform.enumeration.Side;
public class OrderTemplateBuilderTest {
@Test
public void testSwapNotRubT1() {
OrderTemplateBuilder builder = new OrderTemplateBuilder(null);
Assertions.assertEquals(Side.SELL, builder.resolvePrimaryTransferSide(createNotRubRegistry(), SettleCode.T1));
Assertions.assertEquals(Side.BUY, builder.resolvePrimaryTransferSide(createRubRegistry(), SettleCode.T1));
Assertions.assertEquals(Side.BUY, builder.resolvePrimaryTransferSide(createNotRubRegistry(), SettleCode.T0));
Assertions.assertEquals(Side.SELL, builder.resolvePrimaryTransferSide(createNotRubRegistry(), SettleCode.T1));
}
public static Registry createNotRubRegistry() {
Registry registry = new Registry();
registry.setSecuritySymbol("CNY");
return registry;
}
public static Registry createRubRegistry() {
Registry registry = new Registry();
registry.setSecuritySymbol("RUB");
return registry;
}
}

View file

@ -194,13 +194,13 @@ public class Application extends MessageCracker implements quickfix.Application,
newOrderSingle.set(new SecurityIDSource(SecurityIDSource.EXCHANGE_SYMBOL)); newOrderSingle.set(new SecurityIDSource(SecurityIDSource.EXCHANGE_SYMBOL));
newOrderSingle.set(new SecurityID(orderCurrency.getSecuritySymbol())); newOrderSingle.set(new SecurityID(orderCurrency.getSecuritySymbol()));
newOrderSingle.set(new ExDestination(orderCurrency.getMarket())); newOrderSingle.set(new ExDestination(orderCurrency.getMarket()));
newOrderSingle.set(new OrderQty(orderCurrency.getQuantity().doubleValue())); newOrderSingle.set(new OrderQty(orderCurrency.getQuantityLot().doubleValue()));
newOrderSingle.setField(new StringField(109, orderCurrency.getAccount())); // ClientID newOrderSingle.setField(new StringField(109, orderCurrency.getAccount())); // ClientID
newOrderSingle.set(new Text(orderCurrency.getComment())); newOrderSingle.set(new Text(orderCurrency.getComment()));
newOrderSingle.setField(new ContraBroker(orderCurrency.getCounterTradingCode())); newOrderSingle.setField(new ContraBroker(orderCurrency.getCounterTradingCode()));
newOrderSingle.set(new SettlType(orderCurrency.getSettleCode())); newOrderSingle.set(new SettlType(orderCurrency.getSettleCode()));
newOrderSingle.setField(new StringField(5018, orderCurrency.getTradingCode())); // FirmId newOrderSingle.setField(new StringField(5018, orderCurrency.getTradingCode())); // FirmId
newOrderSingle.set(new HandlInst(HandlInst.AUTOMATED_EXECUTION_ORDER_PRIVATE_NO_BROKER_INTERVENTION));
boolean result = Session.sendToTarget(newOrderSingle, fixSessionID); boolean result = Session.sendToTarget(newOrderSingle, fixSessionID);
} catch (SessionNotFound sessionNotFound) { } catch (SessionNotFound sessionNotFound) {
log.error(orderCurrency.toString(), sessionNotFound); log.error(orderCurrency.toString(), sessionNotFound);

View file

@ -31,7 +31,7 @@ public class RiskParameterMapStore extends TemplateMapStore<RiskParameter> {
public String[] getFields() { public String[] getFields() {
return new String[]{ return new String[]{
"ID", "VALUE", "SETTLEMENT_TYPE", "CURRENCY_PAIR", "CURRENCY_PAIR_ID", "CREATED_AT", "UPDATED_AT", "WORKFLOW_STATUS", "ID", "VALUE", "SETTLEMENT_TYPE", "CURRENCY_PAIR", "CURRENCY_PAIR_ID", "CREATED_AT", "UPDATED_AT", "WORKFLOW_STATUS",
"QUOTE_VALUE" "QUOTE_VALUE", "PENALTY_VALUE"
}; };
} }
@ -47,6 +47,7 @@ public class RiskParameterMapStore extends TemplateMapStore<RiskParameter> {
object.setUpdated(getInstantFromTimestamp(resultSet, "UPDATED_AT")); object.setUpdated(getInstantFromTimestamp(resultSet, "UPDATED_AT"));
object.setWorkflowStatus(resultSet.getObject("WORKFLOW_STATUS", String.class)); object.setWorkflowStatus(resultSet.getObject("WORKFLOW_STATUS", String.class));
object.setQuoteValue(resultSet.getObject("QUOTE_VALUE", BigDecimal.class)); object.setQuoteValue(resultSet.getObject("QUOTE_VALUE", BigDecimal.class));
object.setPenaltyValue(resultSet.getObject("PENALTY_VALUE", BigDecimal.class));
return object; return object;
} }
@ -61,7 +62,8 @@ public class RiskParameterMapStore extends TemplateMapStore<RiskParameter> {
TimeUtil.toDateFromInstant(object.getCreated()), TimeUtil.toDateFromInstant(object.getCreated()),
TimeUtil.toDateFromInstant(object.getUpdated()), TimeUtil.toDateFromInstant(object.getUpdated()),
object.getWorkflowStatus(), object.getWorkflowStatus(),
object.getQuoteValue() object.getQuoteValue(),
object.getPenaltyValue()
}; };
return args; return args;
} }

View file

@ -42,6 +42,7 @@ public class RiskParameterFacade implements IClearingFacade {
riskParameter.setSettlementType(request.getSettlementType()); riskParameter.setSettlementType(request.getSettlementType());
riskParameter.setValue(request.getValue()); riskParameter.setValue(request.getValue());
riskParameter.setQuoteValue(request.getQuoteValue()); riskParameter.setQuoteValue(request.getQuoteValue());
riskParameter.setPenaltyValue(request.getPenaltyValue());
riskParameter.setWorkflowStatus(request.getWorkflowStatus()); riskParameter.setWorkflowStatus(request.getWorkflowStatus());
riskParameter.setCreated(Instant.now()); riskParameter.setCreated(Instant.now());
@ -55,6 +56,7 @@ public class RiskParameterFacade implements IClearingFacade {
riskParameterForUpdate.setValue(request.getValue()); riskParameterForUpdate.setValue(request.getValue());
riskParameterForUpdate.setQuoteValue(request.getQuoteValue()); riskParameterForUpdate.setQuoteValue(request.getQuoteValue());
riskParameterForUpdate.setPenaltyValue(request.getPenaltyValue());
riskParameterForUpdate.setWorkflowStatus(request.getWorkflowStatus()); riskParameterForUpdate.setWorkflowStatus(request.getWorkflowStatus());
riskParameterImdg.update(riskParameterForUpdate); riskParameterImdg.update(riskParameterForUpdate);

View file

@ -10,6 +10,8 @@ public class RiskParameterNewRequest {
@JsonProperty @JsonProperty
private BigDecimal quoteValue; private BigDecimal quoteValue;
@JsonProperty @JsonProperty
private BigDecimal penaltyValue;
@JsonProperty
private String settlementType; private String settlementType;
@JsonProperty @JsonProperty
private Long currencyPairId; private Long currencyPairId;
@ -55,4 +57,12 @@ public class RiskParameterNewRequest {
public void setWorkflowStatus(String status) { public void setWorkflowStatus(String status) {
this.workflowStatus = status; this.workflowStatus = status;
} }
public BigDecimal getPenaltyValue() {
return penaltyValue;
}
public void setPenaltyValue(BigDecimal penaltyValue) {
this.penaltyValue = penaltyValue;
}
} }

View file

@ -12,6 +12,8 @@ public class RiskParameterUpdateRequest {
@JsonProperty @JsonProperty
private BigDecimal quoteValue; private BigDecimal quoteValue;
@JsonProperty @JsonProperty
private BigDecimal penaltyValue;
@JsonProperty
private String workflowStatus; private String workflowStatus;
public Long getId() { public Long getId() {
@ -45,4 +47,12 @@ public class RiskParameterUpdateRequest {
public void setWorkflowStatus(String status) { public void setWorkflowStatus(String status) {
this.workflowStatus = status; this.workflowStatus = status;
} }
public BigDecimal getPenaltyValue() {
return penaltyValue;
}
public void setPenaltyValue(BigDecimal penaltyValue) {
this.penaltyValue = penaltyValue;
}
} }