-
Notifications
You must be signed in to change notification settings - Fork 1
/
ambiguousOptionalityComplex.ipl
123 lines (99 loc) · 3.18 KB
/
ambiguousOptionalityComplex.ipl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//
// Imandra Inc.
// Copyright (c) 2024
//
// Minimal FIX 4.4 model complex treatment
// of ambiguous type fields
//
// For further info see https://docs.imandra.ai
//
//
import FIX_4_4
// Import inbound NewOrderSingle message
message NewOrderSingle {
req ClOrdID
req Side
req TransactTime
req OrdType valid when it in [ OrdType.Limit, OrdType.Market ]
req OrderQtyData.OrderQty
req Price
opt Account valid when present(it) valid when (case(it){None:""}{Some x: x}) == "acct_01"
opt AccountType valid when it == (Some AccountType.CarriedCustomerSide) && state.CumQty == 0.0
validate { state.live_order == false }
validate { state.OrdStatus in [ OrdStatus.New ] }
}
// Import an outbound message ExecutionReport
outbound message ExecutionReport {
req OrderID
req ExecID
req ExecType
req OrdStatus
req Side
req LeavesQty
req CumQty
req AvgPx
opt Price
opt DayAvgPx
}
// Define the interface state
internal state {
// The following fields would be assigned to
assignable {
OrdStatus : OrdStatus = OrdStatus.New;
Side : Side
OrderID : string
LeavesQty : Qty
CumQty : Qty
AvgPx : Price
Price :* Price = 0.0;
OrdType : OrdType
DayAvgPx :? Price
}
live_order : bool = false;
// These are not required within the orders, etc...
OrdQty : Qty = 0.0;
filledQty : Qty = 0.0;
current_time : UTCTimeOnly = UTCTimeOnly (8, 0, 0, None);
temp_Price : Price = 0.0;
// Define the opening and closing times
opening_time : UTCTimeOnly = UTCTimeOnly (8, 0, 0, None);
closing_time : UTCTimeOnly = UTCTimeOnly (16, 0, 0, None);
}
// Define how the model should process a validated
// incoming NewOrderSingle message
receive ( msg : NewOrderSingle ) {
let tP = state.AvgPx // a non-optional state value
let tPopt = state.DayAvgPx // an optional state value
let tPambig = state.Price // an ambiguous state value
// these are allowed - type checking determines which optionality
// of tpAmbig to check
if (tP == tPambig) then {
tP = tPambig
tPambig = tP
}
if (tPopt == tPambig) then {
tPopt = tPambig
//this is not allowed as you cannot assign an ambiguous type to an optional value
//tPambig = tPopt
//this is allowed and also sets the optional part
tPambig = case(tPopt){None:tPambig}{Some x: x}
}
// this is not allowed - the optionality is different
// if (tp == tPopt) then return
// Extract all relevant fields from within the message
assignFrom (msg, state)
state.live_order = true
// reset the DayAvgPx if below a certain figure
state.temp_Price = case (state.DayAvgPx) {Some x : x} {None : 0.0}
state.DayAvgPx = if state.temp_Price > 10.0
then Some state.temp_Price
else None
// here we override the existing Price assignment in the assignable
// section of state with one from our local ambiguous variable
send ExecutionReport {
state with
ExecID = "";
ExecType = ExecType.New;
Price = tPambig;
}
}