diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100755 index 000000000..e454a5258 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,178 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/pom.xml b/pom.xml index c8907869b..f9a88b2f6 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ 2.2.0 0.2.6 1.5.0 - 3.0.5 + 3.2.10 6.0.12 0.4.8 3.2.0 @@ -56,6 +56,7 @@ 2.0.0-M6 2.0.0-M6 5.0.0 + 5.3 @@ -167,17 +168,23 @@ net.finmath finmath-lib + + com.itextpdf + itextpdf + - org.apache.httpcomponents - httpclient + org.apache.httpcomponents.client5 + httpclient5 + ${httpcore.version} - org.apache.httpcomponents - httpcore + org.apache.httpcomponents.core5 + httpcore5 + ${httpcore.version} @@ -310,18 +317,23 @@ ${commons-cli.version} - - + + org.slf4j slf4j-api 2.0.7 + + + com.google.code.gson + gson + 2.11.0 + diff --git a/src/main/java/net/finmath/smartcontract/demo/VisualiserSDC.java b/src/main/java/net/finmath/smartcontract/demo/VisualiserSDC.java index 9ec195552..732d9dd3e 100644 --- a/src/main/java/net/finmath/smartcontract/demo/VisualiserSDC.java +++ b/src/main/java/net/finmath/smartcontract/demo/VisualiserSDC.java @@ -8,11 +8,11 @@ import javafx.scene.layout.FlowPane; import net.finmath.marketdata.products.Swap; import net.finmath.plots.*; +import net.finmath.smartcontract.product.IRSwapGenerator; import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataset; import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationParserDataItems; import net.finmath.smartcontract.valuation.oracle.SmartDerivativeContractSettlementOracle; import net.finmath.smartcontract.valuation.oracle.interestrates.ValuationOraclePlainSwap; -import net.finmath.smartcontract.product.IRSwapGenerator; import javax.swing.*; import java.awt.*; @@ -23,6 +23,7 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; /** @@ -68,9 +69,9 @@ public static void main(final String[] args) throws Exception { datapoint.getSpec().getProductName().equals("Swap-Rate") && datapoint.getSpec().getMaturity().equals("5Y")).mapToDouble(e -> e.getQuote()).findAny().getAsDouble(); - final Swap swap = IRSwapGenerator.generateAnalyticSwapObject(productStartDate, maturityKey, fixRate, false, forwardCurveKey, discountCurveKey); + final Swap swap = IRSwapGenerator.generateAnalyticSwapObject(productStartDate, maturityKey, notional, fixRate, false, forwardCurveKey, discountCurveKey); - final ValuationOraclePlainSwap oracle = new ValuationOraclePlainSwap(swap, notional, scenarioList); + final ValuationOraclePlainSwap oracle = new ValuationOraclePlainSwap(Map.of("value",swap), scenarioList); final SmartDerivativeContractSettlementOracle margin = new SmartDerivativeContractSettlementOracle(oracle); final List scenarioDates = scenarioList.stream().map(scenario -> scenario.getDate()).sorted().collect(Collectors.toList()); @@ -83,7 +84,7 @@ public static void main(final String[] args) throws Exception { sdcVisual.updateWithValue(scenarioDates.get(0), marginBuffer, 0, null, 0); Thread.sleep(1000); for (int i = 0; i < scenarioDates.size(); i++) { - final double marginCall = i > 0 ? margin.getMargin(scenarioDates.get(i - 1), scenarioDates.get(i)) : 0.0; + final double marginCall = i > 0 ? margin.getMargin(scenarioDates.get(i - 1), scenarioDates.get(i)).get("value").doubleValue() : 0.0; // double marginCall = i==0. ? oracle.getValue(scenarioDates.get(0)) : oracle.getValue(scenarioDates.get(i)) - oracle.getValue(scenarioDates.get(i-1));//90*(new Random()).nextDouble()-45; System.out.println(i + "\t" + DateTimeFormatter.ofPattern("dd.MM.yyyy").format(scenarioDates.get(i)) + "\t" + marginCall); marketValue += marginCall; diff --git a/src/main/java/net/finmath/smartcontract/model/ExceptionId.java b/src/main/java/net/finmath/smartcontract/model/ExceptionId.java index 8314f6115..8c68533f4 100644 --- a/src/main/java/net/finmath/smartcontract/model/ExceptionId.java +++ b/src/main/java/net/finmath/smartcontract/model/ExceptionId.java @@ -12,6 +12,8 @@ public enum ExceptionId { SDC_JAXB_ERROR, SDC_INVALID_TRADE_DATA, SDC_MARGIN_CALCULATION_ERROR, + SDC_VALUE_CALCULATION_ERROR, + SDC_VALUATION_HTTP_ERROR, SDC_CALIBRATION_ERROR, SDC_CERTIFICATE_ERROR, SDC_FABRIC_GETALLPAYMENTS_ERROR, diff --git a/src/main/java/net/finmath/smartcontract/product/IRSwapGenerator.java b/src/main/java/net/finmath/smartcontract/product/IRSwapGenerator.java index db908575a..918e581d6 100644 --- a/src/main/java/net/finmath/smartcontract/product/IRSwapGenerator.java +++ b/src/main/java/net/finmath/smartcontract/product/IRSwapGenerator.java @@ -9,10 +9,12 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.util.Arrays; import java.util.Optional; /** - * Scenario Generator provides static method for generating an analytic swap object + * Generates an interest rate swap. This is used for testing and visualization. + * Alternative way to generate the swap is via the parser. * * @author Peter Kohl-Landgraf * @author Christian Fries @@ -21,17 +23,31 @@ public class IRSwapGenerator { private IRSwapGenerator(){} - public static Swap generateAnalyticSwapObject(final LocalDate startDate, final String maturityLabel, final double fixRate, final boolean isReceiveFix, final String forwardCurveName, final String discountCurveName) { + public static Swap generateAnalyticSwapObject(final LocalDate startDate, final String maturityLabel, final double notional, final double fixRate, final boolean isReceiveFix, final String forwardCurveName, final String discountCurveName) { final String frequencyLabel = forwardCurveName.contains("3M") ? "quarterly" : forwardCurveName.contains("6M") ? "semiannual" : forwardCurveName.contains("1M") ? "monthly" : "annual"; + // Schedules final Schedule scheduleFloat = ScheduleGenerator.createScheduleFromConventions(startDate, 2, "0D", maturityLabel, frequencyLabel, "act/360", "first", "following", new BusinessdayCalendarExcludingTARGETHolidays(), 0, 0); final Schedule scheduleFix = ScheduleGenerator.createScheduleFromConventions(startDate, 2, "0D", maturityLabel, "annual", "E30/360", "first", "following", new BusinessdayCalendarExcludingTARGETHolidays(), 0, 0); - final SwapLeg floatLeg = new SwapLeg(Optional.of(LocalDateTime.of(startDate, LocalTime.of(0, 0))), scheduleFloat, forwardCurveName, 0.0, discountCurveName); + + // TODO Remove hardcoded effective date + // TODO Test effective date from parser + LocalDateTime cashFlowEffectiveDate = LocalDateTime.of(startDate, LocalTime.of(0, 0)); + boolean isNotionalExchanged = false; + + final double[] notionalsFloat = new double[scheduleFloat.getNumberOfPeriods()]; + final double[] spreadsFloat = new double[scheduleFloat.getNumberOfPeriods()]; + Arrays.fill(notionalsFloat, notional); + Arrays.fill(spreadsFloat, 0.0); + final SwapLeg floatLeg = new SwapLeg(Optional.of(cashFlowEffectiveDate), scheduleFloat, forwardCurveName, notionalsFloat, spreadsFloat, discountCurveName, isNotionalExchanged); + + final double[] notionalsFix = new double[scheduleFix.getNumberOfPeriods()]; + final double[] spreadsFix = new double[scheduleFix.getNumberOfPeriods()]; + Arrays.fill(notionalsFix, notional); + Arrays.fill(spreadsFix, fixRate); final SwapLeg fixLeg = new SwapLeg(Optional.of(LocalDateTime.of(startDate, LocalTime.of(0, 0))), scheduleFix, "", fixRate, discountCurveName); return isReceiveFix ? new Swap(fixLeg, floatLeg) : new Swap(floatLeg, fixLeg); } - - } diff --git a/src/main/java/net/finmath/smartcontract/product/SmartDerivativeContractDescriptor.java b/src/main/java/net/finmath/smartcontract/product/SmartDerivativeContractDescriptor.java index d81964d0b..efad7c0ec 100644 --- a/src/main/java/net/finmath/smartcontract/product/SmartDerivativeContractDescriptor.java +++ b/src/main/java/net/finmath/smartcontract/product/SmartDerivativeContractDescriptor.java @@ -28,6 +28,8 @@ public class SmartDerivativeContractDescriptor { private final List marketdataItemList; private final String currency; private final String marketDataProvider; + private final String tradeType; + private final String initialSettlementDate; /** * Descriptor for a smart derivative contract counterparty. Unified access to a party definition in an XML. @@ -73,7 +75,8 @@ public String toString() { } } - public SmartDerivativeContractDescriptor(String dltTradeId, String dltAddress, String uniqueTradeIdentifier, LocalDateTime tradeDate, List counterparties, Map marginAccountInitialByPartyID, Map penaltyFeeInitialByPartyID, String recervicePartyID, Node underlying, List marketdataItems, String currency, String marketDataProvider) { + //TODO convert constructor into builder pattern or something comparable + public SmartDerivativeContractDescriptor(String dltTradeId, String dltAddress, String uniqueTradeIdentifier, LocalDateTime tradeDate, List counterparties, Map marginAccountInitialByPartyID, Map penaltyFeeInitialByPartyID, String recervicePartyID, Node underlying, List marketdataItems, String currency, String marketDataProvider, String tradeType, String initialSettlementDate) { this.dltTradeId = dltTradeId; this.dltAddress = dltAddress; this.uniqueTradeIdentifier = uniqueTradeIdentifier; @@ -86,6 +89,8 @@ public SmartDerivativeContractDescriptor(String dltTradeId, String dltAddress, S this.underlying = underlying; this.currency = currency; this.marketDataProvider = marketDataProvider; + this.tradeType = tradeType; + this.initialSettlementDate = initialSettlementDate; Validate.isTrue(counterparties.size() == 2, "Number of counterparties must be 2."); Validate.isTrue(marginAccountInitialByPartyID.size() == 2, "Number of margin accounts values must be 2."); @@ -154,4 +159,12 @@ public String getCurrency() { public String getMarketDataProvider() { return marketDataProvider; } + + public String getTradeType() { + return tradeType; + } + + public String getInitialSettlementDate() { + return initialSettlementDate; + } } diff --git a/src/main/java/net/finmath/smartcontract/product/xml/PlainSwapEditorHandler.java b/src/main/java/net/finmath/smartcontract/product/xml/PlainSwapEditorHandler.java index 6828b7b12..98397a570 100644 --- a/src/main/java/net/finmath/smartcontract/product/xml/PlainSwapEditorHandler.java +++ b/src/main/java/net/finmath/smartcontract/product/xml/PlainSwapEditorHandler.java @@ -617,8 +617,8 @@ private AnalyticModel getAnalyticModel(String marketData, Schedule schedule, Str List marketDataSets; try { marketDataSets = CalibrationParserDataItems.getScenariosFromJsonString(marketData); - } catch (IOException e) { - logger.error("Failed to load market data."); + } catch (IllegalArgumentException e) { + logger.error("Failed to load market data.", e); throw e; } Validate.isTrue(marketDataSets.size() == 1, "Parameter marketData should be only a single market data set"); diff --git a/src/main/java/net/finmath/smartcontract/product/xml/SDCXMLParser.java b/src/main/java/net/finmath/smartcontract/product/xml/SDCXMLParser.java index f8d2e5818..0a2aa2f3a 100644 --- a/src/main/java/net/finmath/smartcontract/product/xml/SDCXMLParser.java +++ b/src/main/java/net/finmath/smartcontract/product/xml/SDCXMLParser.java @@ -1,10 +1,13 @@ package net.finmath.smartcontract.product.xml; -import jakarta.xml.bind.*; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Marshaller; +import jakarta.xml.bind.Unmarshaller; import net.finmath.smartcontract.model.ExceptionId; import net.finmath.smartcontract.model.SDCException; -import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; import net.finmath.smartcontract.product.SmartDerivativeContractDescriptor; +import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -13,7 +16,11 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.util.ArrayList; @@ -28,100 +35,123 @@ */ public class SDCXMLParser { - private static final Logger logger = LoggerFactory.getLogger(SDCXMLParser.class); + private static final Logger logger = LoggerFactory.getLogger(SDCXMLParser.class); - private SDCXMLParser() { - } + private SDCXMLParser() { + } - public static SmartDerivativeContractDescriptor parse(String sdcxml) throws ParserConfigurationException, IOException, SAXException { + public static SmartDerivativeContractDescriptor parse(String sdcxml) throws ParserConfigurationException, IOException, SAXException { - Smartderivativecontract sdc = unmarshalXml(sdcxml, Smartderivativecontract.class); + Smartderivativecontract sdc = unmarshalXml(sdcxml, Smartderivativecontract.class); - LocalDateTime settlementDateInitial = LocalDateTime.parse(sdc.getSettlement().settlementDateInitial.trim()); + LocalDateTime settlementDateInitial = LocalDateTime.parse(sdc.getSettlement().settlementDateInitial.trim()); - String uniqueTradeIdentifier = sdc.getUniqueTradeIdentifier().trim(); - String dltAddress = sdc.getDltAddress() == null ? "" : sdc.getDltAddress().trim(); - String dltTradeId = sdc.getDltTradeId() == null ? "" : sdc.getDltTradeId().trim(); + String uniqueTradeIdentifier = sdc.getUniqueTradeIdentifier().trim(); + String dltAddress = sdc.getDltAddress() == null ? "" : sdc.getDltAddress().trim(); + String dltTradeId = sdc.getDltTradeId() == null ? "" : sdc.getDltTradeId().trim(); /* Market Data */ - List marketdataItems = new ArrayList<>(); - for(Smartderivativecontract.Settlement.Marketdata.Marketdataitems.Item item : sdc.getSettlement().getMarketdata().getMarketdataitems().getItem()){ - String symbol = item.getSymbol().get(0).trim(); - String curve = item.getCurve().get(0).trim(); - String type = item.getType().get(0).trim(); - String tenor = item.getTenor().get(0).trim(); - CalibrationDataItem.Spec spec = new CalibrationDataItem.Spec(symbol, curve, type, tenor); - marketdataItems.add(spec); - } - - /* - * Counterparties - */ - List parties = new ArrayList<>(); - Map marginAccountInitialByPartyID = new HashMap<>(); - Map penaltyFeeInitialByPartyID = new HashMap<>(); - - for(Smartderivativecontract.Parties.Party p : sdc.getParties().getParty()){ - SmartDerivativeContractDescriptor.Party party = new SmartDerivativeContractDescriptor.Party( - p.getId().trim(), - p.getName().trim(), - null, - p.getAddress().trim() - ); - parties.add(party); - marginAccountInitialByPartyID.put(party.getId(), p.getMarginAccount().getValue()); - penaltyFeeInitialByPartyID.put(party.getId(), p.getPenaltyFee().getValue()); - } - - // Receiver party ID - String receiverPartyID = sdc.getReceiverPartyID().trim(); - - // TODO The parser needs to check that the field receiverPartyID of the SDC matched the field in the FPML - - // TODO Support multiple underlyings - - Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(sdcxml.getBytes(StandardCharsets.UTF_8))); - document.getDocumentElement().normalize(); - - Node underlying = document - .getElementsByTagName("underlying") - .item(0) - .getFirstChild(); - if (!underlying.getNodeName().equals("dataDocument")) { - underlying = underlying.getNextSibling(); - } - Swap swap = (Swap) sdc.getUnderlyings().getUnderlying().getDataDocument().getTrade().get(0).getProduct().getValue(); - String currency = swap.getSwapStream().get(0).getCalculationPeriodAmount().getCalculation().getNotionalSchedule().getNotionalStepSchedule().getCurrency().getValue().trim(); - - String marketDataProvider = sdc.getSettlement().getMarketdata().getProvider().trim(); - - return new SmartDerivativeContractDescriptor(dltTradeId, dltAddress, uniqueTradeIdentifier, settlementDateInitial, parties, marginAccountInitialByPartyID, penaltyFeeInitialByPartyID, receiverPartyID, underlying, marketdataItems, currency, marketDataProvider); - } - - public static T unmarshalXml(String xml, Class t) { - try { - StringReader reader = new StringReader(xml); - JAXBContext jaxbContext = JAXBContext.newInstance(t); - Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); - return (T) unmarshaller.unmarshal(reader); - } catch (JAXBException e) { - logger.error("unmarshalXml: jaxb error, ", e); - throw new SDCException(ExceptionId.SDC_JAXB_ERROR, e.getMessage(), 400); - } - } - - public static String marshalClassToXMLString(T t) { - try { - JAXBContext jaxbContextSettlement = JAXBContext.newInstance(t.getClass()); - Marshaller jaxbMarshaller = jaxbContextSettlement.createMarshaller(); - StringWriter writer = new StringWriter(); - jaxbMarshaller.marshal(t, writer); - return writer.toString(); - } catch (JAXBException e) { - logger.error("marshalClassToXMLString: jaxb error, ", e); - throw new SDCException(ExceptionId.SDC_JAXB_ERROR, e.getMessage(), 400); - } - } + List marketdataItems = new ArrayList<>(); + for (Smartderivativecontract.Settlement.Marketdata.Marketdataitems.Item item : sdc.getSettlement().getMarketdata().getMarketdataitems().getItem()) { + String symbol = item.getSymbol().get(0).trim(); + String curve = item.getCurve().get(0).trim(); + String type = item.getType().get(0).trim(); + String tenor = item.getTenor().get(0).trim(); + CalibrationDataItem.Spec spec = new CalibrationDataItem.Spec(symbol, curve, type, tenor); + marketdataItems.add(spec); + } + + /* + * Counterparties + */ + List parties = new ArrayList<>(); + Map marginAccountInitialByPartyID = new HashMap<>(); + Map penaltyFeeInitialByPartyID = new HashMap<>(); + + for (Smartderivativecontract.Parties.Party p : sdc.getParties().getParty()) { + SmartDerivativeContractDescriptor.Party party = new SmartDerivativeContractDescriptor.Party( + p.getId().trim(), + p.getName().trim(), + null, + p.getAddress().trim() + ); + parties.add(party); + marginAccountInitialByPartyID.put(party.getId(), p.getMarginAccount().getValue()); + penaltyFeeInitialByPartyID.put(party.getId(), p.getPenaltyFee().getValue()); + } + + // Receiver party ID + String receiverPartyID = sdc.getReceiverPartyID().trim(); + + // TODO The parser needs to check that the field receiverPartyID of the SDC matched the field in the FPML + + // TODO Support multiple underlyings + + Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(sdcxml.getBytes(StandardCharsets.UTF_8))); + document.getDocumentElement().normalize(); + + Node underlying = document + .getElementsByTagName("underlying") + .item(0) + .getFirstChild(); + if (!underlying.getNodeName().contains("dataDocument")) { + underlying = underlying.getNextSibling(); + } + + String currency = sdc.getSettlementCurrency(); + + String marketDataProvider = sdc.getSettlement().getMarketdata().getProvider().trim(); + + String tradeType = sdc.getTradeType(); + String initialSettlementDate = sdc.getSettlement().getSettlementDateInitial().trim(); + + return new SmartDerivativeContractDescriptor(dltTradeId, dltAddress, uniqueTradeIdentifier, settlementDateInitial, parties, marginAccountInitialByPartyID, penaltyFeeInitialByPartyID, receiverPartyID, underlying, marketdataItems, currency, marketDataProvider, tradeType, initialSettlementDate); + } + + public static T unmarshalXml(String xml, Class t) { + try { + StringReader reader = new StringReader(xml); + JAXBContext jaxbContext = JAXBContext.newInstance(t, BigDecimal.class); + Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + return (T) unmarshaller.unmarshal(reader); + } catch (JAXBException e) { + logger.error("unmarshalXml: jaxb error, ", e); + throw new SDCException(ExceptionId.SDC_JAXB_ERROR, e.getMessage(), 400); + } + } + + /** + * Generic object-to-XML-string converter for all annotated classes + * @param t object to be converted to an XML string + * @return XML formatted String + * @param generic Type, which has the correct XML bind annotations + */ + public static String marshalClassToXMLString(T t) { + try { + JAXBContext jaxbContextSettlement = JAXBContext.newInstance(t.getClass()); + Marshaller jaxbMarshaller = jaxbContextSettlement.createMarshaller(); + if (t instanceof Smartderivativecontract) + jaxbMarshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "uri:sdc smartderivativecontract.xsd"); + StringWriter writer = new StringWriter(); + jaxbMarshaller.marshal(t, writer); + return writer.toString(); + } catch (JAXBException e) { + logger.error("marshalClassToXMLString: jaxb error, ", e); + throw new SDCException(ExceptionId.SDC_JAXB_ERROR, e.getMessage(), 400); + } + } + + /** + * this version of an SDC-object-to-XML-string conversion includes text replacements to get rid of XML namespace tags like "fpml:dataDocument" + * @param smartderivativecontract SDC product data object which will be transformed into an XML string + * @return formatted xml string + */ + public static String marshalSDCToXMLString(Smartderivativecontract smartderivativecontract) { + //TODO took over an old implementation, please review + return marshalClassToXMLString(smartderivativecontract) + .replaceAll("", "") + .replaceAll("fpml:", ""); + } } diff --git a/src/main/java/net/finmath/smartcontract/settlement/BigDecimalAdapter.java b/src/main/java/net/finmath/smartcontract/settlement/BigDecimalAdapter.java new file mode 100644 index 000000000..93fe7f591 --- /dev/null +++ b/src/main/java/net/finmath/smartcontract/settlement/BigDecimalAdapter.java @@ -0,0 +1,24 @@ +package net.finmath.smartcontract.settlement; + +import jakarta.xml.bind.annotation.adapters.XmlAdapter; + +import java.math.BigDecimal; + +public class BigDecimalAdapter extends XmlAdapter { + + @Override + public String marshal(BigDecimal value) throws Exception + { + if (value!= null) + { + return value.toString(); + } + return null; + } + + @Override + public BigDecimal unmarshal(String s) throws Exception + { + return new BigDecimal(s); + } +} \ No newline at end of file diff --git a/src/main/java/net/finmath/smartcontract/settlement/Settlement.java b/src/main/java/net/finmath/smartcontract/settlement/Settlement.java index 6774a027c..4ddb13a07 100644 --- a/src/main/java/net/finmath/smartcontract/settlement/Settlement.java +++ b/src/main/java/net/finmath/smartcontract/settlement/Settlement.java @@ -1,5 +1,7 @@ package net.finmath.smartcontract.settlement; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElementWrapper; import jakarta.xml.bind.annotation.XmlRootElement; import jakarta.xml.bind.annotation.XmlType; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @@ -20,15 +22,13 @@ * * @author Christian Fries */ +//@XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement @XmlType(propOrder = {"tradeId", "settlementType", "currency", "marginValue", - "marginLimits", "settlementTime", "settlementValue", "settlementValuePrevious", - "settlementTimeNext", "settlementValueNext", "marketData"}) + "marginLimits", "settlementTime", "settlementNPV", "settlementNPVPrevious", + "settlementTimeNext", "settlementNPVNext", "marketData", "settlementInfos"}) public class Settlement { - public Settlement() { - } - public enum SettlementType { INITIAL, REGULAR, @@ -49,24 +49,25 @@ public enum SettlementType { private ZonedDateTime settlementTime; - - private BigDecimal settlementValue; + private BigDecimal settlementNPV; /// V(T1,M0) - - private BigDecimal settlementValuePrevious; + private BigDecimal settlementNPVPrevious; /// V(T2,M1) - indicative private ZonedDateTime settlementTimeNext; - private BigDecimal settlementValueNext; + private BigDecimal settlementNPVNext; private MarketDataList marketData; - // Custom additional information (e.g. risk figures or szenario values) + /// Custom additional information (e.g. risk figures or szenario values) + private List settlementInfos; - //private Map info; + /* + * Getter and setters + */ public String getTradeId() { return tradeId; @@ -117,59 +118,54 @@ public void setSettlementTime(ZonedDateTime settlementTime) { this.settlementTime = settlementTime; } - public MarketDataList getMarketData() { - return marketData; + public BigDecimal getSettlementNPV() { + return settlementNPV; } - public void setMarketData(MarketDataList marketData) { - this.marketData = marketData; + public void setSettlementNPV(BigDecimal settlementNPV) { + this.settlementNPV = settlementNPV; } - public BigDecimal getSettlementValue() { - return settlementValue; + public BigDecimal getSettlementNPVPrevious() { + return settlementNPVPrevious; } - public void setSettlementValue(BigDecimal settlementValue) { - this.settlementValue = settlementValue; + public void setSettlementNPVPrevious(BigDecimal settlementNPVPrevious) { + this.settlementNPVPrevious = settlementNPVPrevious; } - public BigDecimal getSettlementValuePrevious() { - return settlementValuePrevious; + @XmlJavaTypeAdapter(ZonedDateTimeAdapter.class) + public ZonedDateTime getSettlementTimeNext() { + return settlementTimeNext; } - public void setSettlementValuePrevious(BigDecimal settlementValuePrevious) { - this.settlementValuePrevious = settlementValuePrevious; + public void setSettlementTimeNext(ZonedDateTime settlementTimeNext) { + this.settlementTimeNext = settlementTimeNext; } - public Settlement(String tradeId, SettlementType settlementType, String currency, BigDecimal marginValue, List marginLimits, ZonedDateTime settlementTime, MarketDataList marketData, BigDecimal settlementValue, BigDecimal settlementValuePrevious, ZonedDateTime settlementTimeNext, BigDecimal settlementValueNext) { - this.tradeId = tradeId; - this.settlementType = settlementType; - this.currency = currency; - this.marginValue = marginValue; - this.marginLimits = marginLimits; - this.settlementTime = settlementTime; - this.marketData = marketData; - this.settlementValue = settlementValue; - this.settlementValuePrevious = settlementValuePrevious; - this.settlementTimeNext = settlementTimeNext; - this.settlementValueNext = settlementValueNext; + public BigDecimal getSettlementNPVNext() { + return settlementNPVNext; } - @XmlJavaTypeAdapter(ZonedDateTimeAdapter.class) - public ZonedDateTime getSettlementTimeNext() { - return settlementTimeNext; + public void setSettlementNPVNext(BigDecimal settlementNPVNext) { + this.settlementNPVNext = settlementNPVNext; + } + public MarketDataList getMarketData() { + return marketData; } - public void setSettlementTimeNext(ZonedDateTime settlementTimeNext) { - this.settlementTimeNext = settlementTimeNext; + public void setMarketData(MarketDataList marketData) { + this.marketData = marketData; } - public BigDecimal getSettlementValueNext() { - return settlementValueNext; + @XmlElementWrapper(name="settlementInfos") + @XmlElement(name = "settlementInfo") + public List getSettlementInfos() { + return settlementInfos; } - public void setSettlementValueNext(BigDecimal settlementValueNext) { - this.settlementValueNext = settlementValueNext; + public void setSettlementInfos(List settlementInfos) { + this.settlementInfos = settlementInfos; } } diff --git a/src/main/java/net/finmath/smartcontract/settlement/SettlementGenerator.java b/src/main/java/net/finmath/smartcontract/settlement/SettlementGenerator.java index 2b7d9d676..6be5b41cb 100644 --- a/src/main/java/net/finmath/smartcontract/settlement/SettlementGenerator.java +++ b/src/main/java/net/finmath/smartcontract/settlement/SettlementGenerator.java @@ -13,6 +13,7 @@ import java.time.ZonedDateTime; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Objects; public class SettlementGenerator { @@ -23,7 +24,7 @@ public class SettlementGenerator { public SettlementGenerator generateInitialSettlementXml(String marketDataXml, SmartDerivativeContractDescriptor sdc){ generateSettlement(marketDataXml, Settlement.SettlementType.INITIAL, sdc, BigDecimal.ZERO); - return this.settlementValuePrevious(BigDecimal.ZERO); + return this.settlementNPVPrevious(BigDecimal.ZERO); } public SettlementGenerator generateRegularSettlementXml(String marketDataXml, SmartDerivativeContractDescriptor sdc, BigDecimal marginValue){ @@ -48,13 +49,13 @@ public SettlementGenerator marginLimits(List marginLimits){ return this; } - public SettlementGenerator settlementValue(BigDecimal settlementValue){ - settlement.setSettlementValue(settlementValue); + public SettlementGenerator settlementNPV(BigDecimal settlementNPV){ + settlement.setSettlementNPV(settlementNPV); return this; } - public SettlementGenerator settlementValuePrevious(BigDecimal settlementValuePrevious){ - settlement.setSettlementValuePrevious(settlementValuePrevious); + public SettlementGenerator settlementNPVPrevious(BigDecimal settlementNPVPrevious){ + settlement.setSettlementNPVPrevious(settlementNPVPrevious); return this; } @@ -63,8 +64,13 @@ public SettlementGenerator settlementTimeNext(ZonedDateTime settlementTimeNext){ return this; } - public SettlementGenerator settlementValueNext(BigDecimal settlementValueNext){ - settlement.setSettlementValueNext(settlementValueNext); + public SettlementGenerator settlementNPVNext(BigDecimal settlementNPVNext){ + settlement.setSettlementNPVNext(settlementNPVNext); + return this; + } + + public SettlementGenerator settlementInfo(Map info){ + settlement.setSettlementInfos(info.entrySet().stream().map(e -> new SettlementInfo(e.getKey(), e.getValue())).toList()); return this; } diff --git a/src/main/java/net/finmath/smartcontract/settlement/SettlementInfo.java b/src/main/java/net/finmath/smartcontract/settlement/SettlementInfo.java new file mode 100644 index 000000000..da152bd02 --- /dev/null +++ b/src/main/java/net/finmath/smartcontract/settlement/SettlementInfo.java @@ -0,0 +1,41 @@ +package net.finmath.smartcontract.settlement; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlValue; +import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import java.math.BigDecimal; + +@XmlRootElement(name="settlementInfo") +public class SettlementInfo { + + private String key; + private BigDecimal value; + + public SettlementInfo() { } + + public SettlementInfo(String key, BigDecimal value) { + this.key = key; + this.value = value; + } + + @XmlAttribute + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + @XmlValue + @XmlJavaTypeAdapter(BigDecimalAdapter.class) + public BigDecimal getValue() { + return value; + } + + public void setValue(BigDecimal value) { + this.value = value; + } +} \ No newline at end of file diff --git a/src/main/java/net/finmath/smartcontract/settlement/ZonedDateTimeAdapter.java b/src/main/java/net/finmath/smartcontract/settlement/ZonedDateTimeAdapter.java index 007476ef9..50416cf19 100644 --- a/src/main/java/net/finmath/smartcontract/settlement/ZonedDateTimeAdapter.java +++ b/src/main/java/net/finmath/smartcontract/settlement/ZonedDateTimeAdapter.java @@ -2,7 +2,6 @@ import jakarta.xml.bind.annotation.adapters.XmlAdapter; -import java.text.ParseException; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -19,7 +18,6 @@ public String marshal(ZonedDateTime v) { public ZonedDateTime unmarshal(String str) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss"); LocalDateTime ldt = LocalDateTime.parse(str, formatter); - //return ZonedDateTime.parse(str, formatter); return ZonedDateTime.of(ldt, ZoneId.systemDefault()); } } \ No newline at end of file diff --git a/src/main/java/net/finmath/smartcontract/valuation/implementation/MarginCalculator.java b/src/main/java/net/finmath/smartcontract/valuation/implementation/MarginCalculator.java index 4e8d42235..c63c7a57e 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/implementation/MarginCalculator.java +++ b/src/main/java/net/finmath/smartcontract/valuation/implementation/MarginCalculator.java @@ -1,5 +1,6 @@ package net.finmath.smartcontract.valuation.implementation; +import net.finmath.marketdata.products.AnalyticProduct; import net.finmath.marketdata.products.Swap; import net.finmath.marketdata.products.SwapLeg; import net.finmath.modelling.DescribedProduct; @@ -8,7 +9,11 @@ import net.finmath.modelling.descriptor.InterestRateSwapProductDescriptor; import net.finmath.modelling.descriptor.xmlparser.FPMLParser; import net.finmath.modelling.productfactory.InterestRateAnalyticProductFactory; -import net.finmath.smartcontract.model.*; +import net.finmath.smartcontract.model.MarginResult; +import net.finmath.smartcontract.model.MarketDataList; +import net.finmath.smartcontract.model.ValueResult; +import net.finmath.smartcontract.product.SmartDerivativeContractDescriptor; +import net.finmath.smartcontract.product.xml.SDCXMLParser; import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataset; import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationParserDataItems; @@ -16,9 +21,9 @@ import net.finmath.smartcontract.valuation.marketdata.data.MarketDataPoint; import net.finmath.smartcontract.valuation.oracle.SmartDerivativeContractSettlementOracle; import net.finmath.smartcontract.valuation.oracle.interestrates.ValuationOraclePlainSwap; -import net.finmath.smartcontract.product.SmartDerivativeContractDescriptor; -import net.finmath.smartcontract.product.xml.SDCXMLParser; import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.math.BigDecimal; import java.time.LocalDate; @@ -39,6 +44,7 @@ */ public class MarginCalculator { + private static final Logger logger = LoggerFactory.getLogger(MarginCalculator.class); private final DoubleUnaryOperator rounding; private static final String FORWARD_EUR_6M = "forward-EUR-6M"; private static final String DISCOUNT_EUR_OIS = Calibrator.DISCOUNT_EUR_OIS; @@ -58,10 +64,9 @@ public MarginCalculator() { * @return the margin (MarginResult). * @throws Exception Exception */ - public MarginResult getValue(String marketDataStart, String marketDataEnd, String productData) throws Exception { + public Map getValues(String marketDataStart, String marketDataEnd, String productData) throws Exception { SmartDerivativeContractDescriptor productDescriptor = SDCXMLParser.parse(productData); - CalibrationDataset setStart = null; CalibrationDataset setEnd = null; try { @@ -82,15 +87,21 @@ public MarginResult getValue(String marketDataStart, String marketDataEnd, Strin LocalDateTime startDate = setStart.getDate(); LocalDateTime endDate = setEnd.getDate(); - double value = calculateMargin(List.of(setStart, setEnd), startDate, endDate, productDescriptor, underlying); + Map values = calculateMargin(List.of(setStart, setEnd), startDate, endDate, productDescriptor, underlying); + return values; + } + + public MarginResult getValue(String marketDataStart, String marketDataEnd, String productData) throws Exception { + BigDecimal value = getValues(marketDataStart, marketDataEnd, productData).get("value"); + // TODO Fix hardcoded currency String currency = "EUR"; + // TODO This needs to be replaced by the actual valuation date (can be different from now) LocalDateTime valuationDate = LocalDateTime.now(); - return new MarginResult().value(BigDecimal.valueOf(rounding.applyAsDouble(value))).currency(currency).valuationDate(valuationDate.toString()); + return new MarginResult().value(value).currency(currency).valuationDate(valuationDate.toString()); } - - public MarginResult getValue(MarketDataList marketDataStart, MarketDataList marketDataEnd, String productData) throws Exception { + public Map getValues(MarketDataList marketDataStart, MarketDataList marketDataEnd, String productData) throws Exception { SmartDerivativeContractDescriptor productDescriptor = SDCXMLParser.parse(productData); List marketdataItemList = productDescriptor.getMarketdataItemList(); @@ -129,12 +140,18 @@ public MarginResult getValue(MarketDataList marketDataStart, MarketDataList mark LocalDateTime startDate = marketDataListStart.get(0).getDate(); LocalDateTime endDate = marketDataListEnd.get(0).getDate(); - double value = calculateMargin(List.of(marketDataListStart.get(0), marketDataListEnd.get(0)), startDate, endDate, productDescriptor, underlying); + Map values = calculateMargin(List.of(marketDataListStart.get(0), marketDataListEnd.get(0)), startDate, endDate, productDescriptor, underlying); + + return values; + } + + public MarginResult getValue(MarketDataList marketDataStart, MarketDataList marketDataEnd, String productData) throws Exception { + Map values = getValues(marketDataStart, marketDataEnd, productData); String currency = "EUR"; LocalDateTime valuationDate = LocalDateTime.now(); - return new MarginResult().value(BigDecimal.valueOf(rounding.applyAsDouble(value))).currency(currency).valuationDate(valuationDate.toString()); + return new MarginResult().value(values.get("values")).currency(currency).valuationDate(valuationDate.toString()); } public ValueResult getValue(String marketData, String productData) throws Exception { @@ -145,27 +162,30 @@ public ValueResult getValue(String marketData, String productData) throws Except CalibrationDataset set = CalibrationParserDataItems.getCalibrationDataSetFromXML(marketData,productDescriptor.getMarketdataItemList()); - double value = calculateMargin(List.of(set), null, set.getDate(), productDescriptor, underlying); + BigDecimal value = calculateMargin(List.of(set), null, set.getDate(), productDescriptor, underlying).get("value"); String currency = "EUR"; LocalDateTime valuationDate = LocalDateTime.now(); - return new ValueResult().value(BigDecimal.valueOf(value)).currency(currency).valuationDate(valuationDate.toString()); + return new ValueResult().value(value).currency(currency).valuationDate(valuationDate.toString()); } public ValueResult getValueAtEvaluationTime(String marketData, String productData, LocalDateTime evaluationTime) throws Exception { SmartDerivativeContractDescriptor productDescriptor = SDCXMLParser.parse(productData); String ownerPartyID = productDescriptor.getUnderlyingReceiverPartyID(); + // TODO Remove fixed forward and discount curve InterestRateSwapProductDescriptor underlying = (InterestRateSwapProductDescriptor) new FPMLParser(ownerPartyID, FORWARD_EUR_6M, DISCOUNT_EUR_OIS).getProductDescriptor(productDescriptor.getUnderlying()); - CalibrationDataset set = CalibrationParserDataItems.getCalibrationDataSetFromXML(marketData,productDescriptor.getMarketdataItemList()); - double value = calculateValueAtTime(List.of(set),evaluationTime,set.getDate(),productDescriptor,underlying); + BigDecimal valueAtTime = calculateValueAtTime(List.of(set),evaluationTime,set.getDate(),productDescriptor,underlying); + // TODO Remove hardcoded currency String currency = "EUR"; - return new ValueResult().value(BigDecimal.valueOf(value)).currency(currency).valuationDate(evaluationTime.toString()); + logger.info("calculated value at time: {}", valueAtTime); + + return new ValueResult().value(valueAtTime).currency(currency).valuationDate(evaluationTime.toString()); } public ValueResult getValue(MarketDataList marketData, String productData) throws Exception { @@ -191,11 +211,11 @@ public ValueResult getValue(MarketDataList marketData, String productData) throw InterestRateSwapProductDescriptor underlying = (InterestRateSwapProductDescriptor) new FPMLParser(ownerPartyID, FORWARD_EUR_6M, DISCOUNT_EUR_OIS).getProductDescriptor(productDescriptor.getUnderlying()); LocalDateTime endDate = marketDataList.get(0).getDate(); - double value = calculateMargin(marketDataList, null, endDate, productDescriptor, underlying); + BigDecimal value = calculateMargin(marketDataList, null, endDate, productDescriptor, underlying).get("value"); String currency = "EUR"; - return new ValueResult().value(BigDecimal.valueOf(value)).currency(currency).valuationDate(marketData.getRequestTimeStamp().toString()); + return new ValueResult().value(value).currency(currency).valuationDate(marketData.getRequestTimeStamp().toString()); } /** @@ -206,7 +226,7 @@ public ValueResult getValue(MarketDataList marketData, String productData) throw * @param underlying The underlying descriptor (wrapper to the underlying XML) * @return The margin */ - private double calculateMargin(List marketDataList, LocalDateTime startDate, LocalDateTime endState, SmartDerivativeContractDescriptor productDescriptor, InterestRateSwapProductDescriptor underlying) { + private Map calculateMargin(List marketDataList, LocalDateTime startDate, LocalDateTime endState, SmartDerivativeContractDescriptor productDescriptor, InterestRateSwapProductDescriptor underlying) { // Build product LocalDate referenceDate = productDescriptor.getTradeDate().toLocalDate(); @@ -216,20 +236,31 @@ private double calculateMargin(List marketDataList, LocalDat DescribedProduct legReceiverProduct = productFactory.getProductFromDescriptor(legReceiver); DescribedProduct legPayerProduct = productFactory.getProductFromDescriptor(legPayer); + // Swap will be calculated outside Swap swap = new Swap((SwapLeg) legReceiverProduct, (SwapLeg) legPayerProduct); + Map products = Map.of( + "value", swap, + "value.receiverLeg", (SwapLeg)legReceiverProduct +// , "value.payerLeg", (SwapLeg)legPayerProduct + ); + // Build valuation oracle with given market data. - final ValuationOraclePlainSwap oracle = new ValuationOraclePlainSwap(swap, 1.0, marketDataList); + final ValuationOraclePlainSwap oracle = new ValuationOraclePlainSwap(products, marketDataList); final SmartDerivativeContractSettlementOracle margin = new SmartDerivativeContractSettlementOracle(oracle); - double marginCall = 0.0; - + Map marginCall; if (Objects.isNull(startDate)) { - marginCall = oracle.getValue(endState, endState); + marginCall = oracle.getValues(endState, endState); } else { marginCall = margin.getMargin(startDate, endState); } + // Recalculate payer leg to ensure rounding consistency. + marginCall.put("value.payerLeg", marginCall.get("value.receiverLeg").subtract(marginCall.get("value"))); + + logger.info("margin call: {}", marginCall); + return marginCall; } @@ -242,9 +273,9 @@ private double calculateMargin(List marketDataList, LocalDat * @param productDescriptor The product descriptor (wrapper to the product XML) * @param underlying The underlying descriptor (wrapper to the underlying XML) */ - private double calculateValueAtTime(List marketDataList, LocalDateTime evaluationTime, LocalDateTime marketDataTime, SmartDerivativeContractDescriptor productDescriptor, InterestRateSwapProductDescriptor underlying) { + private BigDecimal calculateValueAtTime(List marketDataList, LocalDateTime evaluationTime, LocalDateTime marketDataTime, SmartDerivativeContractDescriptor productDescriptor, InterestRateSwapProductDescriptor underlying) { - // Build product + // Build product - we only support interest rtes swaps here LocalDate referenceDate = productDescriptor.getTradeDate().toLocalDate(); InterestRateSwapLegProductDescriptor legReceiver = (InterestRateSwapLegProductDescriptor) underlying.getLegReceiver(); InterestRateSwapLegProductDescriptor legPayer = (InterestRateSwapLegProductDescriptor) underlying.getLegPayer(); @@ -254,10 +285,17 @@ private double calculateValueAtTime(List marketDataList, Loc Swap swap = new Swap((SwapLeg) legReceiverProduct, (SwapLeg) legPayerProduct); + Map products = Map.of( + "value", swap, + "value.receiverLeg", (SwapLeg)legReceiverProduct, + "value.payerLeg", (SwapLeg)legPayerProduct + ); + + // Build valuation oracle with given market data. - final ValuationOraclePlainSwap oracle = new ValuationOraclePlainSwap(swap, 1.0, marketDataList); + final ValuationOraclePlainSwap oracle = new ValuationOraclePlainSwap(products, marketDataList); - double value = oracle.getValue(evaluationTime,marketDataTime); + BigDecimal value = oracle.getValue(evaluationTime,marketDataTime); return value; } diff --git a/src/main/java/net/finmath/smartcontract/valuation/implementation/reactive/ConditionalSettlementCalculator.java b/src/main/java/net/finmath/smartcontract/valuation/implementation/reactive/ConditionalSettlementCalculator.java index 4c2089324..885457cf2 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/implementation/reactive/ConditionalSettlementCalculator.java +++ b/src/main/java/net/finmath/smartcontract/valuation/implementation/reactive/ConditionalSettlementCalculator.java @@ -1,8 +1,8 @@ package net.finmath.smartcontract.valuation.implementation.reactive; -import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataset; import net.finmath.smartcontract.model.ValueResult; import net.finmath.smartcontract.valuation.implementation.MarginCalculator; +import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataset; import java.io.Serializable; import java.math.BigDecimal; @@ -11,8 +11,8 @@ //TODO check if needed, not used public class ConditionalSettlementCalculator implements Function, Serializable { - private BigDecimal resultTriggerValue; - private String sdcXML; + private final BigDecimal resultTriggerValue; + private final String sdcXML; private String previousmarketdata = null; private final MarginCalculator calculator = new MarginCalculator(); diff --git a/src/main/java/net/finmath/smartcontract/valuation/marketdata/LaunchAGenerator.java b/src/main/java/net/finmath/smartcontract/valuation/marketdata/LaunchAGenerator.java index 4475c11ec..96511e0cb 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/marketdata/LaunchAGenerator.java +++ b/src/main/java/net/finmath/smartcontract/valuation/marketdata/LaunchAGenerator.java @@ -6,15 +6,17 @@ import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.Marshaller; import net.finmath.smartcontract.model.MarketDataList; -import net.finmath.smartcontract.valuation.marketdata.generators.*; -import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; import net.finmath.smartcontract.product.SmartDerivativeContractDescriptor; import net.finmath.smartcontract.product.xml.SDCXMLParser; +import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; +import net.finmath.smartcontract.valuation.marketdata.generators.MarketDataGeneratorWebsocket; +import net.finmath.smartcontract.valuation.marketdata.generators.WebSocketConnector; import java.io.File; import java.io.FileInputStream; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.List; +import java.util.Properties; public class LaunchAGenerator { diff --git a/src/main/java/net/finmath/smartcontract/valuation/marketdata/curvecalibration/CalibrationParserDataItems.java b/src/main/java/net/finmath/smartcontract/valuation/marketdata/curvecalibration/CalibrationParserDataItems.java index 2bcd404a0..a93a09522 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/marketdata/curvecalibration/CalibrationParserDataItems.java +++ b/src/main/java/net/finmath/smartcontract/valuation/marketdata/curvecalibration/CalibrationParserDataItems.java @@ -1,12 +1,13 @@ package net.finmath.smartcontract.valuation.marketdata.curvecalibration; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import net.finmath.smartcontract.model.ExceptionId; import net.finmath.smartcontract.model.MarketDataList; import net.finmath.smartcontract.model.SDCException; import net.finmath.smartcontract.product.xml.SDCXMLParser; -import org.slf4j.LoggerFactory; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; @@ -84,24 +85,7 @@ public static List getScenariosFromJsonFile(final String fil throw e; } - return getScenariosFromJsonContent(content); - - } - - - /** - * Static method which parses a json file from its string content and converts it to a list of market data scenarios - * - * @param jsonString Content of the json. - * @return List of IRMarketDataScenario - * @throws IOException File not found - * @throws UnsupportedEncodingException UnsupportedEncodingException - */ - public static List getScenariosFromJsonString(final String jsonString) throws IOException { - final String content; - - content = jsonString; - return getScenariosFromJsonContent(content); + return getScenariosFromJsonString(content); } @@ -137,13 +121,19 @@ public static List getScenariosFromCSVFile(final String file /** * Static method which parses a json file from its string content and converts it to a list of market data scenarios * + * @param content Content of the json. * @return List of IRMarketDataScenario - * @throws IOException File not found - * @throws UnsupportedEncodingException UnsupportedEncodingException + * @throws IllegalArgumentException If the JSON format is incorrect. */ - private static final List getScenariosFromJsonContent(final String content) throws IOException { - final ObjectMapper mapper = new ObjectMapper(); - final Map>>>> timeSeriesDatamap = mapper.readValue(content, new LinkedHashMap>>>>().getClass()); + public static final List getScenariosFromJsonString(final String content) { + final Map>>>> timeSeriesDatamap; + try { + final ObjectMapper mapper = new ObjectMapper(); + timeSeriesDatamap = mapper.readValue(content, new LinkedHashMap>>>>().getClass()); + } + catch(JsonProcessingException e) { + throw new IllegalArgumentException("Bad format.", e); + } return timeSeriesDatamap.entrySet().stream() .map( diff --git a/src/main/java/net/finmath/smartcontract/valuation/marketdata/data/MarketDataPoint.java b/src/main/java/net/finmath/smartcontract/valuation/marketdata/data/MarketDataPoint.java index fd4daf504..b0d42c715 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/marketdata/data/MarketDataPoint.java +++ b/src/main/java/net/finmath/smartcontract/valuation/marketdata/data/MarketDataPoint.java @@ -1,7 +1,8 @@ package net.finmath.smartcontract.valuation.marketdata.data; import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import jakarta.xml.bind.annotation.*; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlType; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import java.time.LocalDateTime; diff --git a/src/main/java/net/finmath/smartcontract/valuation/marketdata/database/DatabaseConnector.java b/src/main/java/net/finmath/smartcontract/valuation/marketdata/database/DatabaseConnector.java index b9ddefd68..de405feeb 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/marketdata/database/DatabaseConnector.java +++ b/src/main/java/net/finmath/smartcontract/valuation/marketdata/database/DatabaseConnector.java @@ -4,7 +4,6 @@ import net.finmath.smartcontract.valuation.service.utils.ResourceGovernor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; @@ -121,7 +120,7 @@ public void updateDatabase() throws SQLException, IOException { try ( Statement importTableCreationStatement = connection.createStatement(); Statement importStatement = connection.createStatement(); - Statement clearAfterUpdateStatement = connection.createStatement();) { + Statement clearAfterUpdateStatement = connection.createStatement()) { String importfileLocation = resourceGovernor.getImportCandidateAsResourceInReadMode().getFile().getAbsolutePath(); diff --git a/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/MarketDataGeneratorRandomFeed.java b/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/MarketDataGeneratorRandomFeed.java index 66ba01d89..a290e8bf9 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/MarketDataGeneratorRandomFeed.java +++ b/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/MarketDataGeneratorRandomFeed.java @@ -2,10 +2,10 @@ import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.ObservableOnSubscribe; +import net.finmath.smartcontract.model.MarketDataList; import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataset; import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationParserDataItems; -import net.finmath.smartcontract.model.MarketDataList; import java.time.LocalDateTime; import java.time.Period; diff --git a/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/MarketDataGeneratorWebsocket.java b/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/MarketDataGeneratorWebsocket.java index 49036edd0..26df9092e 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/MarketDataGeneratorWebsocket.java +++ b/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/MarketDataGeneratorWebsocket.java @@ -8,8 +8,8 @@ import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; import net.finmath.smartcontract.model.MarketDataList; -import net.finmath.smartcontract.valuation.marketdata.data.MarketDataPoint; import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; +import net.finmath.smartcontract.valuation.marketdata.data.MarketDataPoint; import net.finmath.time.businessdaycalendar.BusinessdayCalendarExcludingTARGETHolidays; import org.json.JSONObject; import org.slf4j.Logger; @@ -91,6 +91,7 @@ public void closeStreamsAndLogoff(WebSocket webSocket) { } + @Deprecated(forRemoval = true) public void writeDataset(String importDir, MarketDataList s, boolean isOvernightFixing) throws IOException { throw new RuntimeException("Not implemented"); /*String json = s.serializeToJson(); @@ -103,7 +104,7 @@ public void writeDataset(String importDir, MarketDataList s, boolean isOvernight @Override public void onTextMessage(WebSocket websocket, String message) throws Exception { - logger.info("message: {}", message); + logger.debug("message: {}", message); JsonNode responseJson = null; if (!message.isEmpty()) { @@ -146,17 +147,14 @@ public void onTextMessage(WebSocket websocket, String message) throws Exception } - if (this.allQuotesRetrieved()) { logger.info("all quotes retrieved"); - logger.info(marketDataList.toString()); + logger.debug(marketDataList.toString()); this.publishSubject.onNext(marketDataList); //this.sink.tryEmitNext(marketDataList); this.reset(); requestSent = false; } - - } private void reset() { diff --git a/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/WebSocketConnector.java b/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/WebSocketConnector.java index 9f86cabf4..4afc9662b 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/WebSocketConnector.java +++ b/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/WebSocketConnector.java @@ -6,24 +6,25 @@ //|----------------------------------------------------------------------------- import com.neovisionaries.ws.client.*; - -import org.apache.http.Header; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.ssl.SSLContextBuilder; -import org.apache.http.util.EntityUtils; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.message.BasicNameValuePair; import org.json.JSONObject; import javax.net.ssl.SSLParameters; import java.io.IOException; import java.net.Inet4Address; +import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; @@ -48,12 +49,9 @@ * providing the updated token to the Real-Time endpoint before token expiration. */ public class WebSocketConnector { - - Properties connectionProperties; public JSONObject authJson; - public String position; public String scope = ""; public String server = ""; @@ -63,8 +61,6 @@ public class WebSocketConnector { public WebSocketConnector(Properties connectionProperties) throws Exception { this.connectionProperties = connectionProperties; this.position = Inet4Address.getLocalHost().getHostAddress(); - - } public WebSocket getWebSocket() throws Exception{ @@ -84,10 +80,8 @@ public String getPosition(){ public WebSocketConnector initAuthJson() { try { - // Connect to Live Market Data Platform and authenticate (using our username and password) this.authJson = getAuthenticationInfo(null, connectionProperties.get("AUTHURL").toString()); - } catch (Exception e) { e.printStackTrace(); } @@ -134,9 +128,12 @@ public WebSocket initWebSocketConnection() throws IOException, WebSocketExceptio public JSONObject getAuthenticationInfo(JSONObject previousAuthResponseJson, String url) { try { - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(new SSLContextBuilder().build()); + PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(SSLConnectionSocketFactoryBuilder.create().build()) + .build(); - HttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); + HttpClient httpclient = HttpClientBuilder.create() + .setConnectionManager(connectionManager).build(); HttpPost httppost = new HttpPost(url); /* HttpParams httpParams = new BasicHttpParams(); @@ -144,7 +141,7 @@ public JSONObject getAuthenticationInfo(JSONObject previousAuthResponseJson, Str httpParams.setParameter(ClientPNames.HANDLE_REDIRECTS, false);*/ // Set request parameters. - List params = new ArrayList(2); + List params = new ArrayList<>(2); params.add(new BasicNameValuePair("client_id", connectionProperties.get("CLIENTID").toString())); params.add(new BasicNameValuePair("username", connectionProperties.get("USER").toString())); @@ -164,12 +161,12 @@ public JSONObject getAuthenticationInfo(JSONObject previousAuthResponseJson, Str } //httppost.setParams(httpParams); - httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); + httppost.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8)); //Execute and get the response. - HttpResponse response = httpclient.execute(httppost); + ClassicHttpResponse response = httpclient.executeOpen(null, httppost, null); - int statusCode = response.getStatusLine().getStatusCode(); + int statusCode = response.getCode(); switch ( statusCode ) { case HttpStatus.SC_OK: // 200 @@ -198,7 +195,7 @@ public JSONObject getAuthenticationInfo(JSONObject previousAuthResponseJson, Str case HttpStatus.SC_BAD_REQUEST: // 400 case HttpStatus.SC_UNAUTHORIZED: // 401 // Retry with username and password - System.out.println("Refinitiv Data Platform authentication HTTP code: " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase()); + System.out.println("Refinitiv Data Platform authentication HTTP code: " + response.getCode() + " " + response.getReasonPhrase()); if (previousAuthResponseJson != null) { System.out.println("Retry with username and password"); return getAuthenticationInfo(null, connectionProperties.get("AUTHURL").toString()); @@ -209,12 +206,12 @@ public JSONObject getAuthenticationInfo(JSONObject previousAuthResponseJson, Str case HttpStatus.SC_GONE: // 410 case 451: // 451 Unavailable For Legal Reasons // Stop retrying with the request - System.out.println("Refinitiv Data Platform authentication HTTP code: " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase()); + System.out.println("Refinitiv Data Platform authentication HTTP code: " + response.getCode() + " " + response.getReasonPhrase()); System.out.println("Stop retrying with the request"); return null; default: // Retry the request to Refinitiv Data Platform - System.out.println("Refinitiv Data Platform authentication HTTP code: " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase()); + System.out.println("Refinitiv Data Platform authentication HTTP code: " + response.getCode() + " " + response.getReasonPhrase()); Thread.sleep(5000); // CAUTION: This is sample code with infinite retries. System.out.println("Retry the request to Refinitiv Data Platform"); diff --git a/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/legacy/ReactiveMarketDataUpdater.java b/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/legacy/ReactiveMarketDataUpdater.java index 5335ada70..a9f162f1a 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/legacy/ReactiveMarketDataUpdater.java +++ b/src/main/java/net/finmath/smartcontract/valuation/marketdata/generators/legacy/ReactiveMarketDataUpdater.java @@ -9,8 +9,8 @@ import com.neovisionaries.ws.client.WebSocket; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; -import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; import net.finmath.smartcontract.model.*; +import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; import net.finmath.time.businessdaycalendar.BusinessdayCalendarExcludingTARGETHolidays; import org.json.JSONObject; import org.slf4j.Logger; diff --git a/src/main/java/net/finmath/smartcontract/valuation/oracle/SmartDerivativeContractSettlementOracle.java b/src/main/java/net/finmath/smartcontract/valuation/oracle/SmartDerivativeContractSettlementOracle.java index 3a5f50362..d1ecf9b78 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/oracle/SmartDerivativeContractSettlementOracle.java +++ b/src/main/java/net/finmath/smartcontract/valuation/oracle/SmartDerivativeContractSettlementOracle.java @@ -6,7 +6,10 @@ package net.finmath.smartcontract.valuation.oracle; +import java.math.BigDecimal; import java.time.LocalDateTime; +import java.util.Map; +import java.util.stream.Collectors; /** * The margin agreement of a smart derivative contract. @@ -37,10 +40,16 @@ public SmartDerivativeContractSettlementOracle(final ValuationOracle derivativeV * @param marginPeriodEnd Period end time of the margin period. * @return The margin. */ - public Double getMargin(final LocalDateTime marginPeriodStart, final LocalDateTime marginPeriodEnd) { - final double valueDerivativeCurrent = derivativeValuationOracle.getValue(marginPeriodEnd, marginPeriodEnd); - final double valueDerivativePrevious = derivativeValuationOracle.getValue(marginPeriodEnd, marginPeriodStart); + public Map getMargin(final LocalDateTime marginPeriodStart, final LocalDateTime marginPeriodEnd) { + final Map valueDerivativeCurrent = derivativeValuationOracle.getValues(marginPeriodEnd, marginPeriodEnd); + final Map valueDerivativePrevious = derivativeValuationOracle.getValues(marginPeriodEnd, marginPeriodStart); - return valueDerivativeCurrent - valueDerivativePrevious; + // + Map margin = valueDerivativeCurrent.keySet().stream().collect(Collectors.toMap( + key -> key, + key -> valueDerivativeCurrent.get(key).subtract(valueDerivativePrevious.get(key)) + )); + + return margin; } } diff --git a/src/main/java/net/finmath/smartcontract/valuation/oracle/ValuationOracle.java b/src/main/java/net/finmath/smartcontract/valuation/oracle/ValuationOracle.java index 85ceb5404..ebe6e1919 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/oracle/ValuationOracle.java +++ b/src/main/java/net/finmath/smartcontract/valuation/oracle/ValuationOracle.java @@ -7,7 +7,9 @@ package net.finmath.smartcontract.valuation.oracle; import javax.money.MonetaryAmount; +import java.math.BigDecimal; import java.time.LocalDateTime; +import java.util.Map; /** * Interface for Oracles providing a valuation at a given time. @@ -25,7 +27,9 @@ public interface ValuationOracle { * @param marketDataTime The market data time. * @return The value. */ - Double getValue(LocalDateTime evaluationTime, LocalDateTime marketDataTime); + BigDecimal getValue(LocalDateTime evaluationTime, LocalDateTime marketDataTime); + + Map getValues(LocalDateTime evaluationTime, LocalDateTime marketDataTime); /** * Provides the value of the Oracle at a given evaluation time. diff --git a/src/main/java/net/finmath/smartcontract/valuation/oracle/ValuationOracleSamplePath.java b/src/main/java/net/finmath/smartcontract/valuation/oracle/ValuationOracleSamplePath.java index e7363d01e..39cde725b 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/oracle/ValuationOracleSamplePath.java +++ b/src/main/java/net/finmath/smartcontract/valuation/oracle/ValuationOracleSamplePath.java @@ -11,7 +11,9 @@ import javax.money.CurrencyUnit; import javax.money.Monetary; import javax.money.MonetaryAmount; +import java.math.BigDecimal; import java.time.LocalDateTime; +import java.util.Map; /** * A valuation oracle constructed from a simulation providing a stochastic valuation oracle @@ -38,8 +40,13 @@ public ValuationOracleSamplePath(final StochasticValuationOracle stochasticValua } @Override - public Double getValue(final LocalDateTime evaluationTime, final LocalDateTime marketDataTime) { - return stochasticValuationOracle.getValue(evaluationTime, marketDataTime).get(path); + public BigDecimal getValue(final LocalDateTime evaluationTime, final LocalDateTime marketDataTime) { + return BigDecimal.valueOf(stochasticValuationOracle.getValue(evaluationTime, marketDataTime).get(path)); + } + + @Override + public Map getValues(LocalDateTime evaluationTime, LocalDateTime marketDataTime) { + return Map.of("value", getValue(evaluationTime, marketDataTime)); } @Override diff --git a/src/main/java/net/finmath/smartcontract/valuation/oracle/ValuationType.java b/src/main/java/net/finmath/smartcontract/valuation/oracle/ValuationType.java new file mode 100644 index 000000000..cfb54d710 --- /dev/null +++ b/src/main/java/net/finmath/smartcontract/valuation/oracle/ValuationType.java @@ -0,0 +1,4 @@ +package net.finmath.smartcontract.valuation.oracle; + +public interface ValuationType { +} diff --git a/src/main/java/net/finmath/smartcontract/valuation/oracle/interestrates/ValuationOraclePlainSwap.java b/src/main/java/net/finmath/smartcontract/valuation/oracle/interestrates/ValuationOraclePlainSwap.java index be473e790..17924f2ee 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/oracle/interestrates/ValuationOraclePlainSwap.java +++ b/src/main/java/net/finmath/smartcontract/valuation/oracle/interestrates/ValuationOraclePlainSwap.java @@ -1,23 +1,25 @@ package net.finmath.smartcontract.valuation.oracle.interestrates; import net.finmath.marketdata.model.AnalyticModel; -import net.finmath.marketdata.products.Swap; +import net.finmath.marketdata.products.AnalyticProduct; import net.finmath.smartcontract.model.ExceptionId; import net.finmath.smartcontract.model.SDCException; import net.finmath.smartcontract.valuation.marketdata.curvecalibration.*; import net.finmath.smartcontract.valuation.oracle.ValuationOracle; +import net.finmath.smartcontract.valuation.oracle.ValuationType; import net.finmath.time.FloatingpointDate; import org.javamoney.moneta.Money; import javax.money.CurrencyUnit; import javax.money.Monetary; import javax.money.MonetaryAmount; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.DoubleUnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -30,36 +32,38 @@ public class ValuationOraclePlainSwap implements ValuationOracle { + public enum ValuationTypeSwap implements ValuationType { + VALUE, + VALUE_RECEIVER_LEG, + VALUE_PAYER_LEG + } + private final CurrencyUnit currency = Monetary.getCurrency("EUR"); private final List scenarioList; - private final Swap product; - private final double notionalAmount; - private final DoubleUnaryOperator rounding; + private final Map products; + private final int scale; /** * Oracle will be instantiated based on a Swap product an market data scenario list * - * @param product The underlying swap product. - * @param notionalAmount The notional of the product. + * @param products The underlying products. * @param scenarioList The list of market data scenarios to be used for valuation. - * @param rounding An operator implementing the rounding. + * @param scale Specification of the rounding. */ - public ValuationOraclePlainSwap(final Swap product, final double notionalAmount, final List scenarioList, DoubleUnaryOperator rounding) { - this.notionalAmount = notionalAmount; - this.product = product; + public ValuationOraclePlainSwap(final Map products, final List scenarioList, int scale) { + this.products = products; this.scenarioList = scenarioList; - this.rounding = rounding; + this.scale = scale; } /** * Oracle will be instantiated based on a Swap product and market data scenario list * - * @param product The underlying swap product. - * @param notionalAmount The notional of the product. + * @param products A list of products to valuate. * @param scenarioList The list of market data scenarios to be used for valuation. */ - public ValuationOraclePlainSwap(final Swap product, final double notionalAmount, final List scenarioList) { - this(product, notionalAmount, scenarioList, x -> Math.round(x * 100) / 100.0); + public ValuationOraclePlainSwap(final Map products, final List scenarioList) { + this(products, scenarioList,2); } @Override @@ -68,7 +72,11 @@ public MonetaryAmount getAmount(final LocalDateTime evaluationTime, final LocalD } @Override - public Double getValue(final LocalDateTime evaluationDate, final LocalDateTime marketDataTime) { + public BigDecimal getValue(final LocalDateTime evaluationDate, final LocalDateTime marketDataTime) { + return getValues(evaluationDate, marketDataTime).get("value"); + } + + public Map getValues(final LocalDateTime evaluationDate, final LocalDateTime marketDataTime) { final Optional optionalScenario = scenarioList.stream().filter(scenario -> scenario.getDate().equals(marketDataTime)).findAny(); if (optionalScenario.isPresent()) { @@ -93,9 +101,16 @@ public Double getValue(final LocalDateTime evaluationDate, final LocalDateTime m final double evaluationTime = FloatingpointDate.getFloatingPointDateFromDate( referenceDate.atStartOfDay(), marketDataTime); - final double valueWithCurves = product.getValue(evaluationTime, calibratedModel) * notionalAmount; - - return rounding.applyAsDouble(valueWithCurves); + + Map values = ( + products.entrySet().stream().collect(Collectors.toMap( + e -> e.getKey(), + e -> BigDecimal.valueOf(e.getValue().getValue(evaluationTime, calibratedModel)).setScale(scale,RoundingMode.HALF_UP)))); + +// final double valueWithCurves = product.getValue(evaluationTime, calibratedModel) * notionalAmount; + + return values; +// return rounding.applyAsDouble(valueWithCurves); } catch (final Exception e) { throw new SDCException(ExceptionId.SDC_CALIBRATION_ERROR, e.getMessage()); } diff --git a/src/main/java/net/finmath/smartcontract/valuation/service/config/BasicAuthWebSecurityConfiguration.java b/src/main/java/net/finmath/smartcontract/valuation/service/config/BasicAuthWebSecurityConfiguration.java index bf43df577..65d913620 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/service/config/BasicAuthWebSecurityConfiguration.java +++ b/src/main/java/net/finmath/smartcontract/valuation/service/config/BasicAuthWebSecurityConfiguration.java @@ -6,7 +6,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -24,7 +23,7 @@ @Configuration @EnableWebSecurity -@EnableConfigurationProperties(value = ApplicationProperties.class) +//@EnableConfigurationProperties(value = ApplicationProperties.class) public class BasicAuthWebSecurityConfiguration { Logger logger = LoggerFactory.getLogger(BasicAuthWebSecurityConfiguration.class); diff --git a/src/main/java/net/finmath/smartcontract/valuation/service/config/RefinitivConfig.java b/src/main/java/net/finmath/smartcontract/valuation/service/config/RefinitivConfig.java new file mode 100644 index 000000000..c2ce6143d --- /dev/null +++ b/src/main/java/net/finmath/smartcontract/valuation/service/config/RefinitivConfig.java @@ -0,0 +1,109 @@ +package net.finmath.smartcontract.valuation.service.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + + +@Configuration +@ConfigurationProperties(prefix = "refinitiv") +public class RefinitivConfig { + private String user; + private String password; + private String clientId; + private String hostName; + private int port; + private String authUrl; + private String useProxy; + private String proxyHost; + private int proxyPort; + private String proxyUser; + private String proxyPassword; + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getHostName() { + return hostName; + } + + public void setHostName(String hostName) { + this.hostName = hostName; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getAuthUrl() { + return authUrl; + } + + public void setAuthUrl(String authUrl) { + this.authUrl = authUrl; + } + + public String getUseProxy() { + return useProxy; + } + + public void setUseProxy(String useProxy) { + this.useProxy = useProxy; + } + + public String getProxyHost() { + return proxyHost; + } + + public void setProxyHost(String proxyHost) { + this.proxyHost = proxyHost; + } + + public int getProxyPort() { + return proxyPort; + } + + public void setProxyPort(int proxyPort) { + this.proxyPort = proxyPort; + } + + public String getProxyUser() { + return proxyUser; + } + + public void setProxyUser(String proxyUser) { + this.proxyUser = proxyUser; + } + + public String getProxyPassword() { + return proxyPassword; + } + + public void setProxyPassword(String proxyPassword) { + this.proxyPassword = proxyPassword; + } +} diff --git a/src/main/java/net/finmath/smartcontract/valuation/service/config/ValuationConfig.java b/src/main/java/net/finmath/smartcontract/valuation/service/config/ValuationConfig.java new file mode 100644 index 000000000..03d747bc5 --- /dev/null +++ b/src/main/java/net/finmath/smartcontract/valuation/service/config/ValuationConfig.java @@ -0,0 +1,55 @@ +package net.finmath.smartcontract.valuation.service.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + + +@Configuration +@ConfigurationProperties(prefix = "valuation") +public class ValuationConfig { + private boolean liveMarketData; + private String settlementCurrency; + private String liveMarketDataProvider; + private String internalMarketDataProvider; + private String productFixingType; + + public boolean isLiveMarketData() { + return liveMarketData; + } + + public void setLiveMarketData(boolean liveMarketData) { + this.liveMarketData = liveMarketData; + } + + public String getSettlementCurrency() { + return settlementCurrency; + } + + public void setSettlementCurrency(String settlementCurrency) { + this.settlementCurrency = settlementCurrency; + } + + public String getLiveMarketDataProvider() { + return liveMarketDataProvider; + } + + public void setLiveMarketDataProvider(String liveMarketDataProvider) { + this.liveMarketDataProvider = liveMarketDataProvider; + } + + public String getInternalMarketDataProvider() { + return internalMarketDataProvider; + } + + public void setInternalMarketDataProvider(String internalMarketDataProvider) { + this.internalMarketDataProvider = internalMarketDataProvider; + } + + public String getProductFixingType() { + return productFixingType; + } + + public void setProductFixingType(String productFixingType) { + this.productFixingType = productFixingType; + } +} diff --git a/src/main/java/net/finmath/smartcontract/valuation/service/controllers/PlainSwapEditorController.java b/src/main/java/net/finmath/smartcontract/valuation/service/controllers/PlainSwapEditorController.java index 4bb926170..8dbf5873e 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/service/controllers/PlainSwapEditorController.java +++ b/src/main/java/net/finmath/smartcontract/valuation/service/controllers/PlainSwapEditorController.java @@ -7,17 +7,17 @@ import jakarta.xml.bind.JAXBException; import net.finmath.rootfinder.BisectionSearch; import net.finmath.smartcontract.api.PlainSwapEditorApi; -import net.finmath.smartcontract.valuation.marketdata.generators.legacy.LiveFeedAdapter; -import net.finmath.smartcontract.valuation.marketdata.generators.legacy.ReactiveMarketDataUpdater; -import net.finmath.smartcontract.valuation.marketdata.generators.WebSocketConnector; -import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; -import net.finmath.smartcontract.valuation.marketdata.database.DatabaseConnector; import net.finmath.smartcontract.model.*; import net.finmath.smartcontract.product.SmartDerivativeContractDescriptor; import net.finmath.smartcontract.product.xml.PlainSwapEditorHandler; import net.finmath.smartcontract.product.xml.SDCXMLParser; -import net.finmath.smartcontract.valuation.service.utils.ResourceGovernor; import net.finmath.smartcontract.valuation.implementation.MarginCalculator; +import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; +import net.finmath.smartcontract.valuation.marketdata.database.DatabaseConnector; +import net.finmath.smartcontract.valuation.marketdata.generators.WebSocketConnector; +import net.finmath.smartcontract.valuation.marketdata.generators.legacy.LiveFeedAdapter; +import net.finmath.smartcontract.valuation.marketdata.generators.legacy.ReactiveMarketDataUpdater; +import net.finmath.smartcontract.valuation.service.utils.ResourceGovernor; import net.finmath.util.TriFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/net/finmath/smartcontract/valuation/service/controllers/SettlementController.java b/src/main/java/net/finmath/smartcontract/valuation/service/controllers/SettlementController.java new file mode 100644 index 000000000..b618e07f2 --- /dev/null +++ b/src/main/java/net/finmath/smartcontract/valuation/service/controllers/SettlementController.java @@ -0,0 +1,35 @@ +package net.finmath.smartcontract.valuation.service.controllers; + +import net.finmath.smartcontract.api.SettlementApi; +import net.finmath.smartcontract.model.InitialSettlementRequest; +import net.finmath.smartcontract.model.InitialSettlementResult; +import net.finmath.smartcontract.model.RegularSettlementRequest; +import net.finmath.smartcontract.model.RegularSettlementResult; +import net.finmath.smartcontract.valuation.service.utils.SettlementService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class SettlementController implements SettlementApi { + + private static final Logger logger = LoggerFactory.getLogger(SettlementController.class); + private final SettlementService settlementService; + + public SettlementController(SettlementService settlementService) {this.settlementService = settlementService;} + + @Override + public ResponseEntity generateRegularSettlementResult(RegularSettlementRequest regularSettlementRequest) { + logger.info("Generating regular settlement result, generateRegularSettlementResult"); + RegularSettlementResult regularSettlementResult = settlementService.generateRegularSettlementResult(regularSettlementRequest); + return ResponseEntity.ok(regularSettlementResult); + } + + @Override + public ResponseEntity generateInitialSettlementResult(InitialSettlementRequest initialSettlementRequest) { + logger.info("Generating initial settlement result, generateInitialSettlementResult"); + InitialSettlementResult initialSettlementResult = settlementService.generateInitialSettlementResult(initialSettlementRequest); + return ResponseEntity.ok(initialSettlementResult); + } +} diff --git a/src/main/java/net/finmath/smartcontract/valuation/service/controllers/ValuationController.java b/src/main/java/net/finmath/smartcontract/valuation/service/controllers/ValuationController.java index a58e57e30..7c290675e 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/service/controllers/ValuationController.java +++ b/src/main/java/net/finmath/smartcontract/valuation/service/controllers/ValuationController.java @@ -8,8 +8,8 @@ package net.finmath.smartcontract.valuation.service.controllers; import net.finmath.smartcontract.api.ValuationApi; -import net.finmath.smartcontract.valuation.client.ValuationClient; import net.finmath.smartcontract.model.*; +import net.finmath.smartcontract.valuation.client.ValuationClient; import net.finmath.smartcontract.valuation.implementation.MarginCalculator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/net/finmath/smartcontract/valuation/service/utils/SDCAbstractRounding.java b/src/main/java/net/finmath/smartcontract/valuation/service/utils/SDCAbstractRounding.java new file mode 100644 index 000000000..266f13b7e --- /dev/null +++ b/src/main/java/net/finmath/smartcontract/valuation/service/utils/SDCAbstractRounding.java @@ -0,0 +1,77 @@ +/** + * SDC Project + * + * @author Dietmar Schnabel + * + * This class implements some number rounding according to business conventions. + * + */ + package net.finmath.smartcontract.valuation.service.utils; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * The Class SDCAbstractRounding + *

+ * Contains general rounding methods, as well as converting to strings. + */ +public abstract class SDCAbstractRounding { + + protected int scale; + protected RoundingMode roundingMode; + + private BigDecimal round(double variable) { + String s = Double.toString(variable); + return new BigDecimal(s).setScale(scale, roundingMode); + } + + /** + * Round double. + * + * @param variable the double var + * @return the rounded double + */ + public double roundDouble(double variable) { + return round(variable).doubleValue(); + } + + private String getAsIntString(BigDecimal variable) { + String margin = variable.toString(); + return margin.replace(".",""); + } + + /** + * Returns an integer value, the double left shifted + * + * @param variable the double var + * @return the double as integer string + */ + public String getRoundedValueAsIntegerString(double variable) { + BigDecimal x = round(variable); + return getAsIntString(x); + } + + /** + * Gets the double from the left shifted integer String + * + * @param s the integer string + * @return the double + */ + public double getDoubleFromIntegerString(String s) { + String sf = null; + + if (s.length()==1) { + sf = "0.0" + s; //TODO introduce scale + } else if (s.length()==2) { + sf = "0." + s; + } else { + int i1 = s.length() - scale -1; + int i2 = s.length() -1; + sf = s.substring(0,i1+1) + "." + s.substring(i1+1,i2+1); + } + + double x = Double.parseDouble(sf); + return roundDouble(x); + } +} diff --git a/src/main/java/net/finmath/smartcontract/valuation/service/utils/SDCRounding.java b/src/main/java/net/finmath/smartcontract/valuation/service/utils/SDCRounding.java new file mode 100644 index 000000000..ec368895c --- /dev/null +++ b/src/main/java/net/finmath/smartcontract/valuation/service/utils/SDCRounding.java @@ -0,0 +1,19 @@ +package net.finmath.smartcontract.valuation.service.utils; + +import java.math.RoundingMode; +/** + * The Class SDCRounding. + *

+ * Concrete implementation of the SDCAbstractRounding class. + * Will be currency dependent. + * */ +public class SDCRounding extends SDCAbstractRounding { + + private SDCRounding() { } + + public SDCRounding(int sc, RoundingMode rc) { + scale = sc; + roundingMode = rc; + } + +} diff --git a/src/main/java/net/finmath/smartcontract/valuation/service/utils/SettlementService.java b/src/main/java/net/finmath/smartcontract/valuation/service/utils/SettlementService.java new file mode 100644 index 000000000..5341ca489 --- /dev/null +++ b/src/main/java/net/finmath/smartcontract/valuation/service/utils/SettlementService.java @@ -0,0 +1,229 @@ +package net.finmath.smartcontract.valuation.service.utils; + +import net.finmath.smartcontract.model.*; +import net.finmath.smartcontract.product.SmartDerivativeContractDescriptor; +import net.finmath.smartcontract.product.xml.SDCXMLParser; +import net.finmath.smartcontract.product.xml.Smartderivativecontract; +import net.finmath.smartcontract.settlement.Settlement; +import net.finmath.smartcontract.settlement.SettlementGenerator; +import net.finmath.smartcontract.valuation.implementation.MarginCalculator; +import net.finmath.smartcontract.valuation.marketdata.data.MarketDataPoint; +import net.finmath.smartcontract.valuation.marketdata.generators.MarketDataGeneratorLauncher; +import net.finmath.smartcontract.valuation.marketdata.generators.MarketDataGeneratorScenarioList; +import net.finmath.smartcontract.valuation.service.config.RefinitivConfig; +import net.finmath.smartcontract.valuation.service.config.ValuationConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.xml.sax.SAXException; + +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +@Service +public class SettlementService { + private static final Logger logger = LoggerFactory.getLogger(SettlementService.class); + + private final MarginCalculator marginCalculator = new MarginCalculator(); + + private final RefinitivConfig refinitivConfig; + private final ValuationConfig valuationConfig; + private final MarketDataGeneratorScenarioList marketDataServiceScenarioList; + + public SettlementService(RefinitivConfig refinitivConfig, ValuationConfig valuationConfig) { + this.refinitivConfig = refinitivConfig; + this.valuationConfig = valuationConfig; + this.marketDataServiceScenarioList = new MarketDataGeneratorScenarioList(); + } + + public RegularSettlementResult generateRegularSettlementResult(RegularSettlementRequest regularSettlementRequest) { + logger.info("Generating regular settlement result, liveData: {}, now parsing trade data", valuationConfig.isLiveMarketData()); + SmartDerivativeContractDescriptor sdc = parseProductData(regularSettlementRequest.getTradeData()); + logger.info("generateRegularSettlementResult - sdc trade id: {}, product marketdata provider: {}, valuation service marketdata provider: {}", sdc.getDltTradeId(), sdc.getMarketDataProvider(), valuationConfig.getLiveMarketDataProvider()); + MarketDataList newMarketDataList = retrieveMarketData(sdc); + includeFixingsOfLastSettlement(regularSettlementRequest, newMarketDataList); + String newMarketDataString = SDCXMLParser.marshalClassToXMLString(newMarketDataList); + Settlement settlementLast = SDCXMLParser.unmarshalXml(regularSettlementRequest.getSettlementLast(), Settlement.class); + String marketDataLastString = SDCXMLParser.marshalClassToXMLString(settlementLast.getMarketData()); + logger.info("generateRegularSettlementResult - newMarketDataString: {}", newMarketDataString); + + // TODO Using now here is a bit strange in the unit test. Results will vary. + ZonedDateTime settlementTimeNext = ZonedDateTime.now().plusDays(1); + + ValueResult settlementValueNext = getValuationValueAtTime( + newMarketDataString, regularSettlementRequest.getTradeData(), settlementTimeNext.toLocalDateTime()); + + Map marginValues = getMargin(marketDataLastString, newMarketDataString, regularSettlementRequest.getTradeData()); + BigDecimal margin = marginValues.get("value"); + + String newSettlement = new SettlementGenerator() + .generateRegularSettlementXml( + newMarketDataString, + sdc, + margin) + .marginLimits(settlementLast.getMarginLimits()) + .settlementNPV(getValue(newMarketDataString, regularSettlementRequest.getTradeData())) + .settlementNPVPrevious(settlementLast.getSettlementNPV()) + .settlementTimeNext(settlementTimeNext) + .settlementNPVNext(settlementValueNext.getValue()) + .settlementInfo(marginValues) + .build(); + + return new RegularSettlementResult() + .generatedRegularSettlement(newSettlement) + .currency(valuationConfig.getSettlementCurrency()) + .marginValue(margin) + .valuationDate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss"))); + } + + public InitialSettlementResult generateInitialSettlementResult(InitialSettlementRequest initialSettlementRequest) { + logger.info("Generating initial settlement result, liveData: {}, now parsing trade data", valuationConfig.isLiveMarketData()); + SmartDerivativeContractDescriptor sdc = parseProductData(initialSettlementRequest.getTradeData()); + logger.info("generateInitialSettlementResult- sdc trade id: {}, product marketdata provider: {}, valuation service marketdata provider: {}", sdc.getDltTradeId(), sdc.getMarketDataProvider(), valuationConfig.getLiveMarketDataProvider()); + MarketDataList newMarketDataList = retrieveMarketData(sdc); + String newMarketDataString = SDCXMLParser.marshalClassToXMLString(newMarketDataList); + logger.debug("generateInitialSettlementResult- newMarketDataString: {}", newMarketDataString); + + ZonedDateTime settlementTimeNext = ZonedDateTime.now().plusDays(1); + + ValueResult settlementValueNext = getValuationValueAtTime( + newMarketDataString, initialSettlementRequest.getTradeData(), settlementTimeNext.toLocalDateTime()); + + List marginLimits = new ArrayList<>(); + sdc.getCounterparties().forEach(party -> marginLimits.add(BigDecimal.valueOf(sdc.getMarginAccount(party.getId())))); + + String newSettlement = new SettlementGenerator() + .generateInitialSettlementXml(newMarketDataString, sdc) + .marginLimits(marginLimits) + .settlementNPV(getValue(newMarketDataString, initialSettlementRequest.getTradeData())) + //.settlementValuePrevious(BigDecimal.ZERO) + .settlementTimeNext(settlementTimeNext) + .settlementNPVNext(settlementValueNext.getValue()) + .settlementInfo(Map.of()) + .build(); + + return new InitialSettlementResult() + .generatedInitialSettlement(newSettlement) + .currency(valuationConfig.getSettlementCurrency()) + .marginValue(BigDecimal.ZERO) + .valuationDate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss"))); + } + + + private static SmartDerivativeContractDescriptor parseProductData(String tradeData) { + try { + return SDCXMLParser.parse(tradeData); + } catch (ParserConfigurationException | IOException | SAXException e) { + logger.error("error parsing product data ", e); + throw new SDCException(ExceptionId.SDC_XML_PARSE_ERROR, "product data format incorrect, could not parse xml", 400); + } + } + + private MarketDataList retrieveMarketData(SmartDerivativeContractDescriptor sdc) { + AtomicReference marketDataList = new AtomicReference<>(new MarketDataList()); + logger.info("retrieveMarketData started for trade: {}", sdc.getDltTradeId()); + + if (sdc.getMarketDataProvider().equals(valuationConfig.getLiveMarketDataProvider()) && valuationConfig.isLiveMarketData()) { + logger.info("using live market data provider"); + marketDataList.set(MarketDataGeneratorLauncher.instantiateMarketDataGeneratorWebsocket(initConnectionProperties(), sdc)); + } else if (sdc.getMarketDataProvider().equals(valuationConfig.getInternalMarketDataProvider())) { + logger.info("using internal market data provider"); + //includes provider internal or no liveMarketData activated + final io.reactivex.rxjava3.functions.Consumer marketDataWriter = marketDataList::set; + marketDataServiceScenarioList.asObservable().subscribe(marketDataWriter, //onNext + throwable -> logger.error("unable to generate marketData from files ", throwable), //onError + () -> logger.info("on complete, simulated marketData generated from files")); //onComplete + } else { + logger.error("unable to retrieve marketData for {}", sdc.getDltTradeId()); + throw new SDCException(ExceptionId.SDC_WRONG_INPUT, + "Product data XML is not compatible with valuation service configuration, see logs for further investigation", 400); + } + return marketDataList.get(); + } + + private Properties initConnectionProperties() { + try { + Properties connectionProperties = new Properties(); + connectionProperties.put("USER", refinitivConfig.getUser()); + connectionProperties.put("PASSWORD", refinitivConfig.getPassword()); + connectionProperties.put("CLIENTID", refinitivConfig.getClientId()); + connectionProperties.put("HOSTNAME", refinitivConfig.getHostName()); + connectionProperties.put("PORT", refinitivConfig.getPort()); + connectionProperties.put("AUTHURL", refinitivConfig.getAuthUrl()); + connectionProperties.put("USEPROXY", refinitivConfig.getUseProxy()); + connectionProperties.put("PROXYHOST", refinitivConfig.getProxyHost()); + connectionProperties.put("PROXYPORT", refinitivConfig.getProxyPort()); + connectionProperties.put("PROXYUSER", refinitivConfig.getProxyUser()); + connectionProperties.put("PROXYPASS", refinitivConfig.getProxyPassword()); + + return connectionProperties; + } catch (NullPointerException e) { + logger.error("refinitiv connection properties not set", e); + throw new SDCException(ExceptionId.SDC_NO_DATA_FOUND, "missing connection properties", 400); + } + } + + private ValueResult getValuationValueAtTime(String marketData, String tradeData, LocalDateTime valuationDate) { + try { + return marginCalculator.getValueAtEvaluationTime(marketData, tradeData, valuationDate); + } catch (Exception e) { + logger.error("unable to get valueAtTime for market data ", e); + throw new SDCException(ExceptionId.SDC_VALUE_CALCULATION_ERROR, "error in MarginCalculator getValueAtTime"); + } + } + + private BigDecimal getValue(String marketData, String tradeData) { + try { + return marginCalculator.getValue(marketData, tradeData).getValue(); + } catch (Exception e) { + logger.error("unable to get value for market data ", e); + throw new SDCException(ExceptionId.SDC_VALUE_CALCULATION_ERROR, "error in MarginCalculator getValue"); + } + } + + private Map getMargin(String marketDataStart, String marketDataEnd, String tradeData) { + try { + return marginCalculator.getValues(marketDataStart, marketDataEnd, tradeData); + } catch (Exception e) { + logger.error("unable to get margin for market data ", e); + throw new SDCException(ExceptionId.SDC_VALUE_CALCULATION_ERROR, "error in MarginCalculator getMargin"); + } + } + + private void includeFixingsOfLastSettlement(RegularSettlementRequest regularSettlementRequest, MarketDataList newMarketDataList) { + //searching for Fixings in the sdc product data XML + Smartderivativecontract sdc = SDCXMLParser.unmarshalXml(regularSettlementRequest.getTradeData(), Smartderivativecontract.class); + Optional symbolsOptional = sdc.getSettlement().getMarketdata() + .getMarketdataitems().getItem().stream().filter( + item -> item.getType().get(0).equalsIgnoreCase(valuationConfig.getProductFixingType())) + .findAny(); + List symbols; + + if(symbolsOptional.isPresent()) {symbols = symbolsOptional.get().getSymbol();} + else { + logger.warn("no Fixings found in SDC product data XML, marketDataList not changed"); + return; + } + logger.info("found symbols in product data XML: {}", symbols); + + //matching symbols from product data xml to last settlement xml marketdataPoints + Settlement settlementLast = SDCXMLParser.unmarshalXml(regularSettlementRequest.getSettlementLast(), Settlement.class); + List fixingsLastSettlement = new ArrayList<>(); + symbols.forEach(s -> settlementLast.getMarketData().getPoints().forEach(marketDataPoint -> { + if (marketDataPoint.getId().equalsIgnoreCase(s)) + fixingsLastSettlement.add(marketDataPoint); + })); + + //add matching marketdataPoints to the new marketdata + logger.info("add matching marketdataPoints to product symbols: {}", fixingsLastSettlement); + for (MarketDataPoint marketDataPoint : fixingsLastSettlement) { + newMarketDataList.add(marketDataPoint); + } + } +} diff --git a/src/main/java/net/finmath/smartcontract/valuation/service/websocket/handler/ValuationHandler.java b/src/main/java/net/finmath/smartcontract/valuation/service/websocket/handler/ValuationHandler.java index 0dc42a6f3..84bef150b 100644 --- a/src/main/java/net/finmath/smartcontract/valuation/service/websocket/handler/ValuationHandler.java +++ b/src/main/java/net/finmath/smartcontract/valuation/service/websocket/handler/ValuationHandler.java @@ -2,13 +2,13 @@ import com.neovisionaries.ws.client.WebSocket; import io.reactivex.rxjava3.core.Observable; -import net.finmath.smartcontract.valuation.marketdata.generators.MarketDataGeneratorWebsocket; -import net.finmath.smartcontract.valuation.marketdata.generators.WebSocketConnector; -import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; import net.finmath.smartcontract.model.ValueResult; import net.finmath.smartcontract.product.SmartDerivativeContractDescriptor; import net.finmath.smartcontract.product.xml.SDCXMLParser; import net.finmath.smartcontract.valuation.implementation.MarginCalculator; +import net.finmath.smartcontract.valuation.marketdata.curvecalibration.CalibrationDataItem; +import net.finmath.smartcontract.valuation.marketdata.generators.MarketDataGeneratorWebsocket; +import net.finmath.smartcontract.valuation.marketdata.generators.WebSocketConnector; import org.springframework.web.socket.*; import java.io.FileInputStream; diff --git a/src/main/resources/SettlementExample.xml b/src/main/resources/SettlementExample.xml new file mode 100644 index 000000000..d8bdda95a --- /dev/null +++ b/src/main/resources/SettlementExample.xml @@ -0,0 +1,337 @@ + + + ID-historical123 + REGULAR + EUR + 49044.15 + -50000 + 50000 + 20241118-152508 + -752.94 + 18937.55 + 20241119-152506 + -752.94 + + 20080502-170000 + + EUB6FIX6M + 0.0484 + 20080502-170000 + + + ESTRSWP3W + 0.04 + 20080502-170000 + + + ESTRSWP1W + 0.0398 + 20080502-170000 + + + ESTRSWP2W + 0.04 + 20080502-170000 + + + ESTRSWP1M + 0.0404 + 20080502-170000 + + + ESTRSWP2M + 0.0407 + 20080502-170000 + + + ESTRSWP3M + 0.0401 + 20080502-170000 + + + ESTRSWP4M + 0.0407 + 20080502-170000 + + + ESTRSWP5M + 0.0406 + 20080502-170000 + + + ESTRSWP6M + 0.0403 + 20080502-170000 + + + ESTRSWP7M + 0.0407 + 20080502-170000 + + + ESTRSWP8M + 0.0404 + 20080502-170000 + + + ESTRSWP9M + 0.0401 + 20080502-170000 + + + ESTRSWP10M + 0.0406 + 20080502-170000 + + + ESTRSWP11M + 0.04 + 20080502-170000 + + + EUB6SWP1Y + 0.0483 + 20080502-170000 + + + ESTRSWP12M + 0.0408 + 20080502-170000 + + + ESTRSWP15M + 0.0402 + 20080502-170000 + + + ESTRSWP18M + 0.0396 + 20080502-170000 + + + EUB6SWP2Y + 0.0457 + 20080502-170000 + + + ESTRSWP2Y + 0.0398 + 20080502-170000 + + + EUB6SWP3Y + 0.0445 + 20080502-170000 + + + ESTRSWP3Y + 0.0399 + 20080502-170000 + + + EUB6SWP4Y + 0.0442 + 20080502-170000 + + + ESTRSWP4Y + 0.0406 + 20080502-170000 + + + EUB6SWP5Y + 0.0442 + 20080502-170000 + + + ESTRSWP5Y + 0.0406 + 20080502-170000 + + + EUB6SWP6Y + 0.0446 + 20080502-170000 + + + ESTRSWP6Y + 0.0407 + 20080502-170000 + + + EUB6SWP7Y + 0.0453 + 20080502-170000 + + + ESTRSWP7Y + 0.0414 + 20080502-170000 + + + EUB6SWP8Y + 0.0451 + 20080502-170000 + + + ESTRSWP8Y + 0.0419 + 20080502-170000 + + + EUB6SWP9Y + 0.0462 + 20080502-170000 + + + ESTRSWP9Y + 0.0422 + 20080502-170000 + + + EUB6SWP10Y + 0.0466 + 20080502-170000 + + + ESTRSWP10Y + 0.0427 + 20080502-170000 + + + EUB6SWP11Y + 0.0472 + 20080502-170000 + + + EUB6SWP12Y + 0.047 + 20080502-170000 + + + EUB6SWP13Y + 0.0481 + 20080502-170000 + + + EUB6SWP14Y + 0.0481 + 20080502-170000 + + + EUB6SWP15Y + 0.048 + 20080502-170000 + + + EUB6SWP16Y + 0.0483 + 20080502-170000 + + + EUB6SWP17Y + 0.0483 + 20080502-170000 + + + EUB6SWP18Y + 0.0483 + 20080502-170000 + + + EUB6SWP19Y + 0.0493 + 20080502-170000 + + + EUB6SWP20Y + 0.0489 + 20080502-170000 + + + EUB6SWP21Y + 0.0489 + 20080502-170000 + + + EUB6SWP22Y + 0.0488 + 20080502-170000 + + + EUB6SWP23Y + 0.0485 + 20080502-170000 + + + EUB6SWP24Y + 0.0487 + 20080502-170000 + + + EUB6SWP25Y + 0.0493 + 20080502-170000 + + + EUB6SWP26Y + 0.0491 + 20080502-170000 + + + EUB6SWP27Y + 0.0483 + 20080502-170000 + + + EUB6SWP28Y + 0.049 + 20080502-170000 + + + EUB6SWP29Y + 0.0485 + 20080502-170000 + + + EUB6SWP30Y + 0.0483 + 20080502-170000 + + + EUB6SWP35Y + 0.0485 + 20080502-170000 + + + EUB6SWP40Y + 0.0477 + 20080502-170000 + + + EUB6SWP45Y + 0.0474 + 20080502-170000 + + + EUB6SWP50Y + 0.0481 + 20080502-170000 + + + EUB6SWP60Y + 0.047 + 20080502-170000 + + + EUB6FIX6M + 0.0521 + 20080917-170000 + + + + -111894.26 + -62850.11 + 49044.15 + + diff --git a/src/main/resources/api.yml b/src/main/resources/api.yml index 0cb03b656..a13c78214 100644 --- a/src/main/resources/api.yml +++ b/src/main/resources/api.yml @@ -504,12 +504,62 @@ paths: schema: $ref: "#/components/schemas/Error" + + /settlement/generate-regular-settlement: + post: + summary: generate a regular settlement xml based on given settlement and product xml + operationId: generateRegularSettlementResult + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/RegularSettlementRequest" + responses: + "200": + description: regular settlement xml was created + content: + application/json: + schema: + $ref: "#/components/schemas/RegularSettlementResult" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + + /settlement/generate-initial-settlement: + post: + summary: generate an initial settlement xml based on given product xml + operationId: generateInitialSettlementResult + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/InitialSettlementRequest" + responses: + "200": + description: initial settlement xml was created + content: + application/json: + schema: + $ref: "#/components/schemas/InitialSettlementResult" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" components: schemas: ValueResult: $ref: "schemas/openapi-schemas/ValueResult.yml" MarginResult: $ref: "schemas/openapi-schemas/MarginResult.yml" + RegularSettlementResult: + $ref: "schemas/openapi-schemas/RegularSettlementResult.yml" + InitialSettlementResult: + $ref: "schemas/openapi-schemas/InitialSettlementResult.yml" Error: $ref: "schemas/openapi-schemas/Error.yml" PlainSwapOperationResponse: @@ -518,6 +568,10 @@ components: $ref: "schemas/openapi-schemas/ValueRequest.yml" MarginRequest: $ref: "schemas/openapi-schemas/MarginRequest.yml" + RegularSettlementRequest: + $ref: "schemas/openapi-schemas/RegularSettlementRequest.yml" + InitialSettlementRequest: + $ref: "schemas/openapi-schemas/InitialSettlementRequest.yml" PlainSwapOperationRequest: $ref: "schemas/openapi-schemas/PlainSwapOperationRequest.yml" CashflowPeriod: diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index fcccd0706..7e4791379 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -52,3 +52,22 @@ storage: marketDataProviderConnectionPropertiesFile: '/config/market_data_connect.properties' databaseConnectionPropertiesFile: '/config/database_connect.properties' +valuation: + live-market-data: false + live-market-data-provider: "refinitiv" + internal-market-data-provider: "internal" + settlement-currency: "EUR" + product-fixing-type: "Fixing" + +refinitiv: + user: ${REFINITIV_USER} + password: ${REFINITIV_PASSWORD} + client-id: ${REFINITIV_CLIENT_ID} + host-name: ${REFINITIV_HOST_NAME} + port: 443 + auth-url: "https://api.refinitiv.com:443/auth/oauth2/v1/token" + use-proxy: "FALSE" + proxy-host: "" + proxy-port: 9400 + proxy-user: "" + proxy-password: "" \ No newline at end of file diff --git a/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract.xml b/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract.xml index 49023694b..8fb83fdb8 100644 --- a/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract.xml +++ b/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract.xml @@ -4,6 +4,8 @@ ID-Test123 0x000000001 UTI12345 + EUR + SDCPledgedBalance net.finmath @@ -490,9 +492,9 @@ - + diff --git a/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract.xsd b/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract.xsd index 79d66e2b8..3c623aacb 100644 --- a/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract.xsd +++ b/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract.xsd @@ -11,6 +11,15 @@ + + + + + + + + + diff --git a/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract_simulated_historical_marketdata.xml b/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract_simulated_historical_marketdata.xml index 1d42e096d..ac136ab78 100644 --- a/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract_simulated_historical_marketdata.xml +++ b/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract_simulated_historical_marketdata.xml @@ -4,6 +4,8 @@ ID-historical123 0x000000002 UTI12345 + EUR + SDCNoPrefunding net.finmath @@ -430,9 +432,9 @@ - + diff --git a/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract_with_rics.xml b/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract_with_rics.xml index abbfd4b6a..f5c6be6b1 100644 --- a/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract_with_rics.xml +++ b/src/main/resources/net.finmath.smartcontract.product.xml/smartderivativecontract_with_rics.xml @@ -1,7 +1,11 @@ + ID-rics567 + 0x000000006 UTI12345 + EUR + SDCPledgedBalance net.finmath @@ -488,9 +492,9 @@ - + diff --git a/src/main/resources/net/finmath/smartcontract/valuation/client/settlement_testset_initial.xml b/src/main/resources/net/finmath/smartcontract/valuation/client/settlement_testset_initial.xml index d19c957e9..a53f21a1a 100644 --- a/src/main/resources/net/finmath/smartcontract/valuation/client/settlement_testset_initial.xml +++ b/src/main/resources/net/finmath/smartcontract/valuation/client/settlement_testset_initial.xml @@ -4,6 +4,13 @@ -50000 50000 -5000 + SDCTestTrade1 + INITIAL + 20220908-170110 + 12.25 + 0 + 20220909-170000 + 17.11 20220908-170110 @@ -357,11 +364,4 @@ 20220908-170110 - 20240314-170000 - 20240315-170000 - INITIAL - 20000 - 20001 - 25000 - SDCTestTrade1 \ No newline at end of file diff --git a/src/main/resources/net/finmath/smartcontract/valuation/client/settlement_testset_initial_historical.xml b/src/main/resources/net/finmath/smartcontract/valuation/client/settlement_testset_initial_historical.xml new file mode 100644 index 000000000..a854d548a --- /dev/null +++ b/src/main/resources/net/finmath/smartcontract/valuation/client/settlement_testset_initial_historical.xml @@ -0,0 +1,357 @@ + + + EUR + -50000 + 50000 + -5000 + SDCTestTrade1 + INITIAL + 20240314-170000 + 18937.55 + 0 + 20240315-170000 + 18940.22 + + 20080917-170000 + + EUB6FIX6M + 0.0521 + 20080917-170000 + + + ESTRSWP3W + 0.0424 + 20080917-170000 + + + ESTRSWP1W + 0.0426 + 20080917-170000 + + + ESTRSWP2W + 0.0424 + 20080917-170000 + + + ESTRSWP1M + 0.0422 + 20080917-170000 + + + ESTRSWP2M + 0.0426 + 20080917-170000 + + + ESTRSWP3M + 0.0429 + 20080917-170000 + + + ESTRSWP4M + 0.0421 + 20080917-170000 + + + ESTRSWP5M + 0.0422 + 20080917-170000 + + + ESTRSWP6M + 0.0425 + 20080917-170000 + + + ESTRSWP7M + 0.0415 + 20080917-170000 + + + ESTRSWP8M + 0.0416 + 20080917-170000 + + + ESTRSWP9M + 0.0416 + 20080917-170000 + + + ESTRSWP10M + 0.041 + 20080917-170000 + + + ESTRSWP11M + 0.0412 + 20080917-170000 + + + EUB6SWP1Y + 0.0513 + 20080917-170000 + + + ESTRSWP12M + 0.0412 + 20080917-170000 + + + ESTRSWP15M + 0.0402 + 20080917-170000 + + + ESTRSWP18M + 0.0394 + 20080917-170000 + + + EUB6SWP2Y + 0.0481 + 20080917-170000 + + + ESTRSWP2Y + 0.0393 + 20080917-170000 + + + EUB6SWP3Y + 0.0468 + 20080917-170000 + + + ESTRSWP3Y + 0.0391 + 20080917-170000 + + + EUB6SWP4Y + 0.0469 + 20080917-170000 + + + ESTRSWP4Y + 0.0403 + 20080917-170000 + + + EUB6SWP5Y + 0.047 + 20080917-170000 + + + ESTRSWP5Y + 0.0406 + 20080917-170000 + + + EUB6SWP6Y + 0.0466 + 20080917-170000 + + + ESTRSWP6Y + 0.0408 + 20080917-170000 + + + EUB6SWP7Y + 0.0474 + 20080917-170000 + + + ESTRSWP7Y + 0.0416 + 20080917-170000 + + + EUB6SWP8Y + 0.0473 + 20080917-170000 + + + ESTRSWP8Y + 0.0415 + 20080917-170000 + + + EUB6SWP9Y + 0.0473 + 20080917-170000 + + + ESTRSWP9Y + 0.0423 + 20080917-170000 + + + EUB6SWP10Y + 0.0474 + 20080917-170000 + + + ESTRSWP10Y + 0.0422 + 20080917-170000 + + + EUB6SWP11Y + 0.048 + 20080917-170000 + + + ESTRSWP11Y + 0.0424 + 20080917-170000 + + + EUB6SWP12Y + 0.0478 + 20080917-170000 + + + ESTRSWP12Y + 0.0435 + 20080917-170000 + + + EUB6SWP13Y + 0.0483 + 20080917-170000 + + + EUB6SWP14Y + 0.0486 + 20080917-170000 + + + EUB6SWP15Y + 0.0488 + 20080917-170000 + + + ESTRSWP15Y + 0.0443 + 20080917-170000 + + + EUB6SWP16Y + 0.0488 + 20080917-170000 + + + EUB6SWP17Y + 0.0491 + 20080917-170000 + + + EUB6SWP18Y + 0.0483 + 20080917-170000 + + + EUB6SWP19Y + 0.0487 + 20080917-170000 + + + EUB6SWP20Y + 0.0491 + 20080917-170000 + + + ESTRSWP20Y + 0.0447 + 20080917-170000 + + + EUB6SWP21Y + 0.0484 + 20080917-170000 + + + EUB6SWP22Y + 0.0488 + 20080917-170000 + + + EUB6SWP23Y + 0.048 + 20080917-170000 + + + EUB6SWP24Y + 0.0488 + 20080917-170000 + + + EUB6SWP25Y + 0.0481 + 20080917-170000 + + + ESTRSWP25Y + 0.0437 + 20080917-170000 + + + EUB6SWP26Y + 0.0482 + 20080917-170000 + + + EUB6SWP27Y + 0.0478 + 20080917-170000 + + + EUB6SWP28Y + 0.0479 + 20080917-170000 + + + EUB6SWP29Y + 0.0478 + 20080917-170000 + + + EUB6SWP30Y + 0.0473 + 20080917-170000 + + + ESTRSWP30Y + 0.0435 + 20080917-170000 + + + EUB6SWP35Y + 0.0473 + 20080917-170000 + + + EUB6SWP40Y + 0.0472 + 20080917-170000 + + + EUB6SWP45Y + 0.0471 + 20080917-170000 + + + EUB6SWP50Y + 0.0461 + 20080917-170000 + + + EUB6SWP60Y + 0.0458 + 20080917-170000 + + + \ No newline at end of file diff --git a/src/main/resources/patches/TradeIdentifier.java b/src/main/resources/patches/TradeIdentifier.java index 8a4aa4f1f..6478f93e3 100644 --- a/src/main/resources/patches/TradeIdentifier.java +++ b/src/main/resources/patches/TradeIdentifier.java @@ -1,20 +1,12 @@ package net.finmath.smartcontract.product.xml; -import java.util.ArrayList; -import java.util.List; - -import jakarta.xml.bind.annotation.XmlAccessType; -import jakarta.xml.bind.annotation.XmlAccessorType; -import jakarta.xml.bind.annotation.XmlAttribute; -import jakarta.xml.bind.annotation.XmlElement; -import jakarta.xml.bind.annotation.XmlElements; -import jakarta.xml.bind.annotation.XmlID; -import jakarta.xml.bind.annotation.XmlSchemaType; -import jakarta.xml.bind.annotation.XmlSeeAlso; -import jakarta.xml.bind.annotation.XmlType; +import jakarta.xml.bind.annotation.*; import jakarta.xml.bind.annotation.adapters.CollapsedStringAdapter; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.util.ArrayList; +import java.util.List; + /** I WAS HERE * A type defining a trade identifier issued by the indicated party. diff --git a/src/main/resources/schemas/openapi-schemas/InitialSettlementRequest.yml b/src/main/resources/schemas/openapi-schemas/InitialSettlementRequest.yml new file mode 100644 index 000000000..e2f283768 --- /dev/null +++ b/src/main/resources/schemas/openapi-schemas/InitialSettlementRequest.yml @@ -0,0 +1,6 @@ +type: object +required: + - tradeData +properties: + tradeData: + type: string \ No newline at end of file diff --git a/src/main/resources/schemas/openapi-schemas/InitialSettlementResult.yml b/src/main/resources/schemas/openapi-schemas/InitialSettlementResult.yml new file mode 100644 index 000000000..62bb74a81 --- /dev/null +++ b/src/main/resources/schemas/openapi-schemas/InitialSettlementResult.yml @@ -0,0 +1,15 @@ +type: object +required: + - marginValue + - currency + - valuationDate + - generatedInitialSettlement +properties: + marginValue: + type: number + currency: + type: string + valuationDate: + type: string + generatedInitialSettlement: + type: string \ No newline at end of file diff --git a/src/main/resources/schemas/openapi-schemas/RegularSettlementRequest.yml b/src/main/resources/schemas/openapi-schemas/RegularSettlementRequest.yml new file mode 100644 index 000000000..d2424f820 --- /dev/null +++ b/src/main/resources/schemas/openapi-schemas/RegularSettlementRequest.yml @@ -0,0 +1,9 @@ +type: object +required: + - settlementLast + - tradeData +properties: + settlementLast: + type: string + tradeData: + type: string \ No newline at end of file diff --git a/src/main/resources/schemas/openapi-schemas/RegularSettlementResult.yml b/src/main/resources/schemas/openapi-schemas/RegularSettlementResult.yml new file mode 100644 index 000000000..eda885a25 --- /dev/null +++ b/src/main/resources/schemas/openapi-schemas/RegularSettlementResult.yml @@ -0,0 +1,15 @@ +type: object +required: + - marginValue + - currency + - valuationDate + - generatedRegularSettlement +properties: + marginValue: + type: number + currency: + type: string + valuationDate: + type: string + generatedRegularSettlement: + type: string \ No newline at end of file diff --git a/src/main/resources/static/generate-initial-settlement.html b/src/main/resources/static/generate-initial-settlement.html new file mode 100644 index 000000000..2d6e1d5e5 --- /dev/null +++ b/src/main/resources/static/generate-initial-settlement.html @@ -0,0 +1,133 @@ + + + + + + + + + + + +

+

finmath Valuation Oracle: Margin Calculator

+ +

+ Perform a valuation of the settlement (margin) based on product data and two market data sets. +

+ +
+
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index 2b7c7124c..94ae89133 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -45,6 +45,16 @@

Product XML Check

+
+
+

Generate Initial Settlement XML

+

+ generate an initial settlement XML based on product data +

+ +
+
+