Basic Model
In our first complete example, we’ll create a simple model that accepts incoming NewOrderSingle messages (as defined in FIX 4.4) and acknowledges them using an Execution Report. We will learn how to specify correct behaviour of the model, introducing validity constraints which will check that an incoming message is valid for example. If the constraints are satisfied then the message is handled as described in Receiving Valid Messages below. If the constraints are not satisfied then a rejection message can be specified as described in Rejecting invalid messages below.
Setting the stage
We start by importing the correct FIX version.
Declaring incoming messages
In this simple model, we will just import the NewOrderSingle
incoming message. In order to specify the fields we expect to receive and those we send out we use the req
, opt
or ign
directives.
For example, let us specify the following for NewOrderSingle
which determines the fields which are required to be present. We can additionally import fields which are optional (opt
) and ignored (ign
):
see the section on Importing Messages for a description of req
, opt
and ign
.
Imposing validity constraints on individual fields
For individual fields we can introduce validity constraints which will check the values of incoming fields. For example on a particular message field we can write
where Limit, Market
are valid values from the OrdType
Enum. This states that the value of the OrdType
must be one of the values specified, and if not the message is rejected. See the section on Expressions for how to write more complex validation conditions.
It is not possible to write a validation condition on an ignored
field.
Imposing general message validity constraints
It is possible to impose general validity constraints on a message. For example we may write the statement
which states that for a market order, the Price
is not present. The this
keyword here refers to the containing message – in this case NewOrderSingle
. Also we could write that for a limit order the Price
must be present and a valid value:
It is not possible to refer to an ignored field – in this case writing this.Account
would result in an error.
Declaring outgoing messages
In order to declare a message used for sending we declare an outbound message
, similarly to how we declare an inbound message:
In this case we do not declare any validation statements as the correct output is determined by the logic used to send out such messages. We can declare optionality of the fields using req
, opt
and ign
as for incoming messages.
Handling incoming messages
An incoming message can be valid, in which case it is processed using the receive
logic. Alternatively, the message can be invalid, in which case it is handled by the reject
logic.
Receiving valid messages
When a message is received we can specify the desired behaviour. In this example we send out an execution report with certain fields set as desired. We have already declared an outbound message ExecutionReport
which we will use to send an acknowledgment receipt of the message. We can write a receive block as follows:
Rejecting invalid messages
In the case of received messages which are invalid with respect to the logic defined in their declaration, there are three possible rejection cases:
- Missing Field - where a required field (annotated with
req
) is not present in the incoming message. In this case it is not possible to reference the incoming message parameter (msg below) as it is not a well-formed message. - Invalid Field - where a received field contravenes one of the validation constraints for that field;
- Invalid - where the combination of fields received contravens one of the general message validity constraints
In this example, let us just handle the case where we want to report back with an Execution Report if a field is missing or a field is invalid:
Errors and Warnings
Even in this very simple model it is possible to get errors and warnings. In general these should be interpreted as follows:
- Errors: if these occur in the model, then there is a logical inconsistency which means an executable simulator cannot be created.
- Warnings: these are advisory pieces of information usually questioning an unusual behaviour.
Examples of errors in this model, are if not all required fields of a sent message are present in a send statement. For example the receive block:
would error with the message:
Not all required fields of the message ExecutionReport
have been assigned - for example - Side
Examples of a warning would be if we defined ExecutionReport
as
would produce the warning:
The field ExecID is required in the FIX specs, but you are marking it as optional.
Are you sure this is the intended behaviour?
Full Model – Imandra Analysis
Click on the image below for an interactive analysis of this model performed by imandra.
Full Model - IPL Code
The full text of this model for this tutorial section is:
Generated Documentation
Click here to view the generated documentation for this model.