Giter Site home page Giter Site logo

rosetta-dsl's Introduction

title date description draft weight
Rune DSL Overview
2022-02-09 00:38:25 +0900
Rune is a Domain-Specific Language (DSL) that supports the modelling of operational processes for the financial markets' industry. Its purpose is to promote consistency and inter-operability between the various implementations of these processes.
false
1

Rune DSL

FINOS - Incubating

Continuous Integration: Maven Central

Rune DSL is a Domain-Specific Language (DSL) that supports the modelling of operational processes for the financial markets' industry. Its purpose is to promote consistency and inter-operability between the various implementations of these processes.

{{< notice info "Note" >}} In software engineering, a domain model is a conceptual model of a business domain that incorporates both data and logic (i.e. rules and processes). {{< /notice >}}

The key idea behind the Rune DSL is that, whilst financial markets' operational infrastructure is largely electronified, many of its underlying IT systems tend to operate in silos.

For instance, the same data are often represented differently between different applications - usually a reasonable choice when considering the respective purpose of each application. But without any formalised translation between them, data cannot easily flow from one application to another and the overall architecture looses cohesiveness. Applications also tend to mix the specification of their business logic with its technical implementation. Once buried in code, an application's logic is hard to extract and must usually be documented separately, with no guarantee of consistency.

The Rune DSL allows to represent data and business logic in a system- and technology-agnostic way into a cohesive domain model. By supporting a shared, formalised understanding of the financial markets' domain, it enables different technology implementations to "talk" to each other in the same native language.

A model expressed in the Rune DSL provides more than a technical specification: it automatically generates executable code, to be used directly in an implementation. Both the Rune DSL and associated code generators are available in open source.

One important application of the Rune DSL concerns regulatory reporting. While many financial institutions share the same reporting obligations, they usually implement their logic in slightly different ways because of siloed technology approaches. This exposes firms to non-compliance risk and fines and degrades the quality and comparability of the data that regulators collect.

Instead, Rune empowers many users within firms to take part in interpreting and codifying reporting rules, without the risk of loss-in-translation once they get implemented in IT systems. The language itself is designed to be human-readable, so that domain experts without programming experience (e.g. operations or compliance professionals) can write fully functional regulatory logic directly – a bit like in Excel.

Rosetta

A complete end to end development environment called Rosetta is provided to help industry participants to create, edit or extend models using the Rune DSL. Rosetta also provides integration tools designed to facilitate firms' adoption and implementation of models within their own technology architecture.

Much like how software engineers use programming languages and tools to build and test software, it is useful to think of Rosetta as a platform with a set of tools to build and test a domain model using the Rune DSL. The Rosetta products documentation details the various tools and products that are available in the Rosetta platform.

In order to facilitate the use of the Rune DSL by industry members, a Community Edition of Rosetta that already features many of the platform's functionalities is available as a free web application. Through Rosetta, users can also access a number of open-source modelling projects that are based on the Rune DSL, allowing them to use, edit or extend those models.

Rune DSL Components

The Rune DSL comprises 2 components, both open-source:

  • Syntax - defines the language and rules for editing a model using the Rune DSL, also known as a grammar
  • Code generators - from a model expressed in the Rune DSL, automatically generates executable code in other programming languages

Syntax

The Rune DSL repository contains the definition of the language. It is based on the Eclipe Modelling Framework.

The language components available in the Rune DSL and their syntax are detailed in the Rune Modelling Components section of the documentation.

A demonstration model, also available in open source, provides a set of working examples of those modelling components. Snippets extracted from this model are being used to support the DSL documentation.

Code Generator

Code generators remove the need for software developers to translate the model specifications into executable code while ensuring the inter-operability of different implementations. The Rune DSL repository provides one default code generator, for Java.

To make models agnostic to the technology platform in which they are being implemented, other code generators have been provided in a variety of languages. A separate code generator repository, also open source, allows the community to create and share code generators in potentially any software language.

The Code Generator documentation details the available code generators, the code generation mechanism and how to write and test one.

Development setup

Setup for developers

This guide is meant for everyone who wants to contribute to the Rune DSL and needs to get things up and running.

If this guide does not work for you, be sure to raise an issue. This way we can help you figure out what the problem is and update this guide to prevent the same problem for future users.

1. Building with Maven

Start by cloning the project: git clone https://github.com/finos/rune-dsl

Our project runs with Java 17. Make sure that your Maven also uses this version of Java by running mvn -v.

To build the project, run mvn clean install.

2. Setting things up in Eclipse

Install Eclipse IDE for Java and DSL Developers

Install the latest version of the "Eclipse IDE for Java and DSL Developers" using the Eclipse Installer.

Install the Checkstyle plugin

We use Checkstyle for enforcing good coding practices. The Eclipse plugin for Checkstyle can be found here: https://checkstyle.org/eclipse-cs/#!/.

Install the Xsemantics plugin

We use the Xsemantics DSL to define the type system of Rune. To enable language support for it in Eclipse, follow these steps:

  1. Find out which version of Xsemantics you need by looking in the pom.xml file of the parent project. There should be a property called xsemantics.version.
  2. Go to Help > Install New Software...
  3. In 'Work with' fill in https://download.eclipse.org/xsemantics/milestones/.
  4. Install the appropriate version of XSemantics.

Setup the project

  1. Open the project in Eclipse: File > Open Projects from File System..., select the right folder, click Finish.
  2. Update Maven dependencies: right click on the com.regnosys.rosetta.parent project > Maven > Update project... and finish.
Troubleshooting

Make sure you have successfully run mvn clean install. (see section 1 of this guide)

If you're seeing 1000+ errors in the "Problems" window of Eclipse, try the following.

  1. Disable auto-building. (Project > Build automatically)
  2. Close Eclipse and open it again.
  3. Update Maven dependencies again.
  4. Re-enable auto-building.

3. Setting things up in Intellij

Support for developing Xtext projects in Intellij is limited. It has no support for

  • editing Xtend files
  • editing the Xtext file
  • editing the Xsemantics file
  • running GenerateRosetta.mwe2.

You can however let Maven take care of that, and still edit regular Java files, run tests, etc.

Unfortunately, there is an issue in Intellij that lets the Maven build fail, see

In the stacktrace, you'll see a reference to a file called plexus-classworlds.license. It is safe to delete this file. Once you do this, the build should succeed.

Roadmap

Coming soon...

Contributing

For any questions, bugs or feature requests please open an issue For anything else please send an email to {project mailing list}.

To submit a contribution:

  1. Fork it (https://github.com/finos/rune-dsl/fork)
  2. Create your feature branch (git checkout -b feature/fooBar)
  3. Read our contribution guidelines and Community Code of Conduct
  4. Commit your changes (git commit -am 'Add some fooBar')
  5. Push to the branch (git push origin feature/fooBar)
  6. Create a new Pull Request

NOTE: Commits and pull requests to FINOS repositories will only be accepted from those contributors with an active, executed Individual Contributor License Agreement (ICLA) with FINOS OR who are covered under an existing and active Corporate Contribution License Agreement (CCLA) executed with FINOS. Commits from individuals not covered under an ICLA or CCLA will be flagged and blocked by the FINOS Clabot tool (or EasyCLA). Please note that some CCLAs require individuals/employees to be explicitly named on the CCLA.

Get in touch with the Rune Team

Get in touch with the Rune team by creating a GitHub issue and labelling it with "help wanted".

We encourage the community to get in touch via the FINOS Slack.

License

Copyright 2019 REGnosys

Distributed under the Apache License, Version 2.0.

SPDX-License-Identifier: Apache-2.0

rosetta-dsl's People

Contributors

adamturski avatar davidalk avatar dependabot[bot] avatar dhuebner avatar gopazoth avatar hugohills avatar hugohills-regnosys avatar ja6a-regnosys avatar jasonkrohn-regnosys avatar jayasrir avatar jim-h-wang avatar lolabeis avatar minesh-s-patel avatar nigelcobb avatar nikos-sotiropoulos avatar payalkhanna avatar renovate[bot] avatar simoncockx avatar tomclforwood avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rosetta-dsl's Issues

Consolidate grammar for Synonyms on Attributes and Enums

enum DayCountFractionEnum <"The enumerated values to specify the day count fraction.">
	[synonym FpML_5_10, CME_SubmissionIRS_1_0, DTCC_11_0, DTCC_9_0, CME_ClearedConfirm_1_17 value dayCountFractionScheme_2_2]
{
	ACT_360 displayName "ACT/360" <"Per 2006 ISDA Definitions...">
		[synonym FpML_5_10, CME_SubmissionIRS_1_0, DTCC_11_0, DTCC_9_0, CME_ClearedConfirm_1_17 value "ACT/360"],
class Contract key <"A class ...">
		[synonym FpML_5_10, CME_SubmissionIRS_1_0, CME_ClearedConfirm_1_17 meta id path "trade"]
		[synonym FpML_5_10, CME_SubmissionIRS_1_0, CME_ClearedConfirm_1_17, Rosetta_Workbench meta id]
{
	contractIdentifier Identifier (1..*) <"The identifier...">;
		[synonym FpML_5_10, CME_SubmissionIRS_1_0 value partyTradeIdentifier path "trade.tradeHeader"]
		[synonym FpML_5_10, CME_SubmissionIRS_1_0 value partyTradeIdentifier path "tradeHeader"]
		[synonym CME_ClearedConfirm_1_17 value partyTradeIdentifier path "trade.tradeHeader"]
  1. the value on enums are in double-quotes whilst on attributes are not in quotes. Should make consistent and should prefer no quotes where possible.
  2. for attribute synonyms, the path is in quotes whilst the value is not. Should make consistent and should prefer no quotes where possible.
  3. the dot . delimiter on the path is inconsistent with the arrow -> on rosetta attribute paths, I think we should use -> for all paths if possible

All functions to generated abstract java classes

A follow on from #43.

funcs annotated with calculation should generate concrete implementations whilst all other funcs should generate abstract classes. The abstract classes should represent the logic as defined in the func and should delegate to a concrete implementation that throws an UnsupportedOperationException that signals to the users that they should provide their own implementations.

Generated code to support adding values to lists

The below model code will generate java code that does not compile. This is because in order to assign a value to a list (using the current api), we must know which index of that list to assign.

assign-output reset -> after -> updatedContract -> contractualProduct -> economicTerms -> payout -> equityPayout -> rateOfReturn : <"...">
		RateOfReturn( equityPayout )

The default behaviour should be to assign to index 0, however we should also support in the syntax a way to assign to an arbitrary index i, i.e. in the below.

assign-output reset -> after -> updatedContract -> contractualProduct -> economicTerms -> payout -> equityPayout[1] -> rateOfReturn : <"...">
		RateOfReturn( equityPayout )

Validate direct assignment of an alias

In assign-output when using an alias there should be at least one path segment for an assigment setter/adder:

alias EquityPayout_before: <"">
		reset -> before -> updatedContract -> contractualProduct -> economicTerms -> payout -> equityPayout only-element
	
assign-output EquityPayout_before:   // <--- error here 
		<"">
		equityPayout
	

Solution refactoring:

alias Payout_before: <"">
		reset -> before -> updatedContract -> contractualProduct -> economicTerms -> payout only-element
	
assign-output  Payout_before -> equityPayout :   
		<"">
		equityPayout
	

Expand 'func' features to fully support 'calculation'

  • func should add support for alias and assign-output

  • add support for 'dispatch' functions where the exact implementation of the function depends on an Enum Value

  • 'func' code generators to generate concrete implementations

Reduce warnings in generated Java

Even after switching to new FuncGenerator and Using new DataGenerator we still have around 6k compile warnings in generated Java. Most of them are wrong imports. As we now use the new ExpressionGenerator that supports autoimport we can switch existing generators to use that feature.

Scoping: Add Enumerations to Attribute Path scope

The below is valid Rosetta, however the content assist does not suggest QuantityNotationEnum.

assign-output updatedContract -> contractualQuantity -> quantityNotation -> notationTag :
		<"Set the notional amount on the Updated Contract.">  
		QuantityNotationEnum.Notional

Navigate from Dispatch Functions to the parent

When reading a dispatch function, I want to know what are the inputs and outputs attributes that are being referenced. Can we create content assist to to display such information or provide an ability to click and navigate to the parent function?

Find a better name for toOne

We have a possibility to convert a Multi type (List) to a single value.
In fact the MapperC.get() function is used where if the list is of size 1 the first element will be retuned null otherwise.
Language feature is called toOne we are looking for a better name.

Support 'empty' type

func NewEquitySwapProduct makes use of EmptyEquitySwapMasterConfirmation2018(), which returns a null or empty object. We need to be able to support passing in a generic empty object into functions.

func NewEquitySwapProduct: <"Function specification to create an Equity Swap according to the 2018 ISDA CDM Equity Confirmation Template, based on a minimum set of inputs which can (optionally) include a Master Confirmation Agreement. The inputs represent the minimum set of inputs required to create an Equity Swap, either based on an existing Master Confirmation Agreement or as a stand-alone Equity Swap">
	inputs: 
		underlier Equity (1..1) <"The underlying Equity asset for the swap.">
		masterConfirmation EquitySwapMasterConfirmation2018 (0..1) <"An (optional) pointer to the Master Confirmation Agreement, if any, that holds further inputs to the Equity Swap">
		
	output:
		product Product (1..1)
		
	post-condition: <"Equity and interest rate payouts must be set-up according to their corresponding payout specifications, and other payout types must be absent.">
		if masterConfirmation exists then
			product -> contractualProduct -> economicTerms -> payout -> equityPayout = NewSingleNameEquityPayout( underlier, masterConfirmation ) and
			product -> contractualProduct -> economicTerms -> payout -> interestRatePayout = NewFloatingPayout( masterConfirmation )
		else
			product -> contractualProduct -> economicTerms -> payout -> equityPayout = NewSingleNameEquityPayout( underlier, EmptyEquitySwapMasterConfirmation2018() );
		product -> contractualProduct -> economicTerms -> payout -> cashflow is absent;
		product -> contractualProduct -> economicTerms -> payout -> creditDefaultPayout is absent;
		product -> contractualProduct -> economicTerms -> payout -> forwardPayout is absent;
		product -> contractualProduct -> economicTerms -> payout -> optionPayout is absent;	
		
	post-condition: <"Non-contractual product types must be absent.">
		product -> foreignExchange is absent;
		product -> index is absent;
		product -> loan is absent;
		product -> security is absent;

The resulting syntax will be easier to read and will be more usable as it avoid the need to create function to produce empty objects.

product -> contractualProduct -> economicTerms -> payout -> equityPayout = NewSingleNameEquityPayout( underlier, empty );

Add support for assigning 'key's to 'reference'

In the below extract from the FormContract Function:

func FormContract : <"...">
	inputs:
		executionEvent Event (1..1)
		legalAgreement LegalAgreement (0..1)
		
	output:
		contractFormationEvent Event (1..1)
	
	...
	
	assign-output contractFormationEvent -> lineage -> eventReference : <"Construct the lineage making reference to the input event">
		executionEvent
		
	...

Add support so that the key on executionEvent can be assigned to the reference on eventReference. This can be done via a language level keyword that then generates the correct java code underneath.

	assign-output contractFormationEvent -> lineage -> eventReference : <"Construct the lineage making reference to the input event">
		executionEvent as-key

Support 'this' or 'it'

There are sometime situations where we need to pass a special kind of parameter. Example:

func ForwardFX:
	inputs: forwardPayout ForwardPayout(1..1)
	output: result ForeignExchange (1..1)
	assign-output result: forwardPayout -> doSmartThings...

data ForwardPayout: 
    condition FxForward_settlementDate: <"...">
		if ForwardFX(<NEED ForwardPayout HERE>) exists

Would be nice instead of an implicit first parameter handling to have this or it as type inside a data element. Another option would be to re-write forwardFX to have underlier as input

see also #38

Update versions of Xtend and Xtext

The versions of Xtext and Xtend currently being used (2.15.0) only supports up to Java 8.
We need to be able to move to a fully supported version of Java.

Use the same starting point in all conditions

For all conditions the first expression should be either an attribute or a function call.
Currently for datarules we use:

data Foo: 
    attr1:  int
    attr2: string
    condition Foo_rule_1:
		if Foo -> attr1 exists
		then Foo -> attr2 exists;

Merge JavaQualifiedTypeProvider and JavaNames

Only one class should survive
com.regnosys.rosetta.generator.java.function.JavaQualifiedTypeProvider
com.regnosys.rosetta.generator.java.util.JavaNames

Same for:
RosettaExpressionJavaGenerator.xtend
RosettaExpressionJavaGeneratorForFunctions.xtend

Handle cardinality transformation in function invocation

In the below function, we must explicitly extract out elements from a Rosetta Path that yields a list. We should support an implicit "get only element" when such invocations are made.

The Rosetta Path: contract -> contractualProduct -> economicTerms -> payout -> equityPayout yields a list of values as there can be multiple equityPayouts. Function Equity Reset requires only a single Equity Payout.

func EquityReset: 
	inputs:
		equityPayout EquityPayout (1..)
		observation number (1..1)
		date date (1..1)
        ...

func EquityResetEvent: 
	inputs:
		contract Contract (1..1)
		observation Event (1..1)
		
	output:
		reset Event (1..1)

	...

 	post-condition: <"Event must contain a reset primitive that is calculated based on the observation, and no other primitive.">
		reset -> primitive -> reset = EquityReset( 
				ExtractSingleEquityPayout( contract -> contractualProduct -> economicTerms -> payout -> equityPayout ), 
				ExtractSingleNumber( observation -> primitive -> observation -> observation ), 
				ExtractSingleDate( observation -> primitive -> observation -> date ) );
		reset -> primitive -> reset only exists;

The desired syntax:

 	post-condition: <"Event must contain a reset primitive that is calculated based on the observation, and no other primitive.">
		reset -> primitive -> reset = EquityReset( 
			contract -> contractualProduct -> economicTerms -> payout -> equityPayout, 
			observation -> primitive -> observation -> observation, 
			observation -> primitive -> observation -> date );
		reset -> primitive -> reset only exists;

Validation should still check Type compatibility and the number of arguments.

Issue with count in condition

The function

	func Allocate: <"Function specification to create the fully-formed business event of allocating an 	execution based on allocation instructions.">
	

	inputs:
		execution Execution (1..1) <"Block trade to be allocated.">
		allocationInstructions AllocationInstructions (1..1) <"Allocation instructions to be applied.">
		previousEvent Event (1..1) <"Previous event for lineage purposes.">

	output:
		allocationEvent Event (1..1) <"Allocation event containing both the original block trade (with the status set to Allocated) and the set of allocated trades.">

	condition: 
		allocationInstructions -> breakdowns count > 0

fails to generate code with the server side error
INFO [2019-10-16 10:43:21,771] [] com.regnosys.rosetta.generator.RosettaGenerator: Unexpected calling standard generate for rosetta
! java.lang.IllegalArgumentException: RosettaCountOperation is not covered yet.
! at com.regnosys.rosetta.generator.java.function.RosettaFunctionDependencyProvider.functionDependencies(RosettaFunctionDependencyProvider.java:141)
! at com.regnosys.rosetta.generator.java.function.FuncGenerator.lambda$3(FuncGenerator.java:156)

ValidatorHelper::doIf should support missing else statement

    public static <T> Mapper<T> doIf(ComparisonResult test, Mapper<T> ifthen) {
        return test.get() ? ifthen : null;
    }

The doIf is called as follows: doIf( xyz, trueValue ).get()

If the test result is false, null is returned and the calling code will throw a null pointer exception

Add cardinality checks

  1. Bar( strings ) should error as strings has multiple cardinality when single cardinality is expected.
  2. assign-output fooOut : Bar( strings ) should error as the return type of Bar has multiple cardinality when single cardinality is expected.
func Foo:
	inputs: strings string (1..*)
	output: fooOut number (1..1)
	assign-output fooOut : Bar( strings )
		
func Bar:
	inputs: string string (1..1)
	output: numbers number (1..*)

Bug in ValidatorHelper

com.rosetta.model.lib.validation.ValidatorHelper

public static <T> ComparisonResult contains(Mapper<T> o1, Mapper<T> o2) {
    boolean result =  o2.getMulti().containsAll(o2.getMulti());
    if (result) { ...

should be:
o1.getMulti().containsAll(o2.getMulti())

Add support for List literal

post-condition: <"Ensuring that the execution attributes are correctly populated on the output.">
	if execution -> after -> execution -> party exists then
		execution -> after -> execution -> party count = 2 and
		execution -> after -> execution -> party contains partyA and
		execution -> after -> execution -> party contains partyB
	else True;

In the above example, we are testing whether execution -> after -> execution -> party contains both partyA and partyB. It would be nicer to specify the below:

	if execution -> after -> execution -> party exists then
		execution -> after -> execution -> party count = 2 and
		execution -> after -> execution -> party contains [ partyA, partyB ]

Generated java code should handle values of multiple cardinality

For . model :

	assign-output execution -> after -> execution -> party:
		[ partyA, partyB ]

The below java code is generated

executionHolder
	.getOrCreateAfter().getOrCreateExecution()
	.addPartyRef(MapperC.of(MapperS.of(partyA), MapperS.of(partyB)).get());
;

But should use MapperC::getMulti:

executionHolder
	.getOrCreateAfter().getOrCreateExecution()
	.addPartyRef(MapperC.of(MapperS.of(partyA), MapperS.of(partyB)).getMulti());
;

Add Scoping and Validation features to 'func'

  • Validate parameter types on the caller side
  • Validate alias path do not use a Type as entry point (only inputs or output?)
  • Validate same enum type is used in enum dispatch
  • Validate no duplicate enum values are used
  • one of can only be defined one per Data object
  • Dispatch func may only refer to an enum typed attr
  • warn if not all the enum values implemented
  • statements within func should only references alias, inputs, output and other funcs
  • Additionally, conditions within func should only reference inputs, alias's that reference only inputs and other funcs
  • constraints are not allowed inside a func conditions

Choice rule syntax

  • support one of and Choices only in condition blocks.
  • condition blocks can have either be a single one of, multiple Choices or multiple Expressions
Condition:
    'condition' RosettaNamed? ':' Definable?
        Annotations?
        (constraints += Constraint)+ | (expressions+=RosettaCalcExpression ';')+
;

Constraint:
    Choice | OneOf
;

Choice:
    ('optioinal' | required ?= 'required') 'choice' 'between' attributes += [Attribute | ValidID] ',' attributes += [Attribute | ValidID] (',' attributes += [Attribute | ValidID])*
;

OneOf:
    'one' 'of'
;

Make RosettaConditionalExpression else condition optional

To make Rosetta more concise (especially for functions) can we make the "else" condition of RosettaConditionalExpression optional, and in the code generation default it to true.

func FooFunc:
inputs: a A (1..1)
output: b B (1..1)
post-condition:
if a.name = "Foo"
then b.foo exists
else True; // else condition should be optional and generated code will default to true

Generated code for functions to all follow same structure

func RateOfReturn utilises code generators that were used for (the now deprecated) calculations. We should aim to have a consistent structure and api for all generated code that relate to Rosetta Functions.

Additionally, This causes incompatibility in the java code when new-style functions reference old-style functions. In the below example, func EquityReset was modified to call func RateOfReturn, which yielded the below error in the generated code for EquityReset.

image

Enum consistency

  1. So that enums can be syntactically more similar to types, remove the comma separating each enum value.
  2. So that referencing enum values is more consistent with referencing types: use the arrow syntax i.e. DayCountFractionEnum -> _30_360 not DayCountFractionEnum._30_360

Generate default impl for abstract function

Guice needs a default implementation to inject a class. But we can't use generate once approach or wait until user implements a class.

@ImplementedBy(AddOne.AddOneDummy.class)
public abstract class AddOne implements RosettaFunction {

	/**
	 * @param arg
	 * @param d
	 * @return out
	 */
	public FooDat evaluate(FooDat arg, Date d) {

		FooDat out = doEvaluate(arg, d).build();

		return out;
	}

	protected abstract FooDat.FooDatBuilder doEvaluate(FooDat arg, Date d);


	private static final class AddOneDummy extends AddOne {
		@Override
		protected FooDatBuilder doEvaluate(FooDat arg, Date d) {
			throw new UnsupportedOperationException();
		}
	}
}

Generated code fails to compile

If the line EquityPerformance( equityPayout, observation -> observation, periodEndDate ) is updated to EquityPerformance( updatedEquityPayout, observation -> observation, periodEndDate ), then the generated code does not compile

func ResolveEquityContract: <"Specifies how the updated contract should be constructed in a Equity Reset event.">
	inputs:
		contractState ContractState (1..1)
		observation ObservationPrimitive (1..1)
		date date (1..1)
		
	output:
		updatedContract Contract (1..1)
		
        alias equityPayout:
		contractState -> contract -> contractualProduct -> economicTerms -> payout -> equityPayout only-element
	
	alias updatedEquityPayout :
		updatedContract -> contractualProduct -> economicTerms -> payout -> equityPayout only-element

        ...
		
	alias equityPerformance :
		EquityPerformance( equityPayout, observation -> observation, periodEndDate )

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.