-
Notifications
You must be signed in to change notification settings - Fork 1
/
ordersOnlyCustomMessage.ipl
159 lines (134 loc) · 3.72 KB
/
ordersOnlyCustomMessage.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//
// Imandra Inc.
// Copyright (c) 2024
//
// Minimal FIX 4.4 model
//
//
// 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 myNewOrderSingleField
validate { state.live_order == false }
}
// can extend the message
extend message NewOrderSingle {
myNewOrderSingleField "mnosf" : string
}
//
// Import an outbound message we would send out
//
//
outbound message ExecutionReport {
req OrderID
req ExecID
req ExecType
req OrdStatus
req Side
req LeavesQty
req CumQty
req AvgPx
req myNewExecutionReportField
}
// can extend ExecutionReport
extend message ExecutionReport {
myNewExecutionReportField "mnerp" : OrdStatus
}
// can extend Enum also
extend enum OrdStatus {
newCase "n"
}
// Define our internal state
internal state {
// The following fields would be assigned to
assignable {
OrdStatus : OrdStatus = OrdStatus.New;
Side : Side = Side.Buy;
OrderID : string = "";
LeavesQty : Qty = 0.0;
CumQty : Qty = 0.0;
AvgPx : Price = 0.0;
}
live_order : bool = false;
// These are not required within the orders, etc...
OrdQty : Qty = 0.0;
current_time : UTCTimeOnly = UTCTimeOnly (8, 0, 0, None);
// 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 ) {
// Extract all relevant fields from within the message
assignFrom (msg, state)
state.live_order = true
send ExecutionReport {
state with
ExecID = "";
myNewExecutionReportField = AcceptedForBidding;
ExecType = ExecType.New;
}
}
// Handle rejections for 'NewOrderSingle'
reject ( msg : NewOrderSingle, rejectReason : string ) {
// A field is missing
missingfield : {
send ExecutionReport {
state with
ExecID = "";
myNewExecutionReportField = OrdStatus.Expired;
ExecType = ExecType.Rejected;
}
}
// A field value is
invalidfield : {
send ExecutionReport {
state with
ExecID = "";
myNewExecutionReportField = OrdStatus.PendingCancel;
ExecType = ExecType.Rejected;
}
}
// One or more 'validate' statements is
invalid : {
send ExecutionReport {
state with
ExecID = "";
myNewExecutionReportField = newCase;
ExecType = ExecType.Rejected;
}
}
}
// Define action 'time_change'
action time_change {
new_time : UTCTimeOnly
validate { this.new_time >= state.current_time && state.OrdStatus == OrdStatus.New }
}
// Define logic for handling 'time_change' action above
receive ( act : time_change ) {
// Save the new time into internal state
state.current_time = act.new_time
// If it's past closing time, then cancel the order and send
// out the ExecutionReport
if ( act.new_time >= state.closing_time) then {
state.OrdStatus = OrdStatus.Expired
state.live_order = false
send ExecutionReport {
state with
ExecID = "";
myNewExecutionReportField = newCase;
ExecType = ExecType.New;
}
}
}