-
Notifications
You must be signed in to change notification settings - Fork 1
/
msg_server_market_data.go
357 lines (290 loc) · 15 KB
/
msg_server_market_data.go
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
package keeper
import (
"context"
"fmt"
"strconv"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/jim380/Re/utils/constants"
"github.com/jim380/Re/x/fix/types"
)
// MarketDataRequest creates Market Data Request
func (k msgServer) MarketDataRequest(goCtx context.Context, msg *types.MsgMarketDataRequest) (*types.MsgMarketDataRequestResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// Validate the message creator
_, err := sdk.AccAddressFromBech32(msg.Creator)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Creator)
}
// check for if the provided session ID existss
session, found := k.GetSessions(ctx, msg.SessionID)
if !found {
return nil, sdkerrors.Wrapf(types.ErrEmptySession, "Session Name: %s", msg.SessionID)
}
// check that logon is established between both parties and that logon status equals to "loggedIn"
if session.Status != constants.LoggedInStatus {
return nil, sdkerrors.Wrapf(types.ErrSessionIsNotLoggedIn, "Status of Session: %s", msg.SessionID)
}
// check that the parties involved in a session are the ones using the sessionID and are able to create Market Data Request
if session.LogonInitiator.Header.SenderCompID != msg.Creator && session.LogonAcceptor.Header.SenderCompID != msg.Creator {
return nil, sdkerrors.Wrapf(types.ErrNotAccountCreator, "Session Creator: %s", msg.Creator)
}
// check that mandatory Market Data Request fields are not empty
if _, err := strconv.ParseInt(fmt.Sprint(msg.SubscriptionRequestType), 10, 64); err != nil {
return nil, sdkerrors.Wrapf(types.ErrSubscriptionRequestTypeIsEmpty, "SubscriptionRequestType: %v", msg.SubscriptionRequestType)
}
if _, err := strconv.ParseInt(fmt.Sprint(msg.MarketDepth), 10, 64); err != nil {
return nil, sdkerrors.Wrapf(types.ErrMarketDepthIsEmpty, "MarketDepth: %v", msg.MarketDepth)
}
if _, err := strconv.ParseInt(fmt.Sprint(msg.MdUpdateType), 10, 64); err != nil {
return nil, sdkerrors.Wrapf(types.ErrMdUpdateTypeIsEmpty, "MdUpdateType: %v", msg.MdUpdateType)
}
if _, err := strconv.ParseInt(fmt.Sprint(msg.NoRelatedSym), 10, 64); err != nil {
return nil, sdkerrors.Wrapf(types.ErrNoRelatedSymIsEmpty, "NoRelatedSym: %v", msg.NoRelatedSym)
}
if msg.Symbol == "" {
return nil, sdkerrors.Wrapf(types.ErrSymbolIsEmpty, "Symbol: %s", msg.Symbol)
}
// market data request
marketDataRequest := types.MarketData{
SessionID: msg.SessionID,
MarketDataRequest: &types.MarketDataRequest{
MdReqID: msg.MdReqID,
SubscriptionRequestType: msg.SubscriptionRequestType,
MarketDepth: msg.MarketDepth,
MdUpdateType: msg.MdUpdateType,
NoRelatedSym: msg.NoRelatedSym,
Symbol: msg.Symbol,
},
}
// fetch Header from existing session
// In the FIX Protocol, Market Data Request message can be sent by either the initiator or the acceptor of the FIX session.
// Determine whether we are the initiator or acceptor
var header *types.Header
if session.LogonInitiator.Header.SenderCompID == msg.Creator {
header = session.LogonInitiator.Header
} else {
header = session.LogonAcceptor.Header
}
// set the header and make changes to the header
// calculate and include all changes to the header
// Message type, V is the message type for Market Data Request
// BodyLength should be calculated using the BodyLength function
// set sending time to current time at creating market data request
marketDataRequest.MarketDataRequest.Header = header
marketDataRequest.MarketDataRequest.Header.MsgType = "V"
marketDataRequest.MarketDataRequest.Header.SendingTime = constants.SendingTime
// fetch Trailer from existing session
// for now copy trailer from session, it should be re-calculated
var trailer *types.Trailer
if session.LogonInitiator.Header.SenderCompID == msg.Creator {
trailer = session.LogonInitiator.Trailer
} else {
trailer = session.LogonAcceptor.Trailer
}
// set the Trailer and make changes to the trailer
// checksum in the trailer can be recalculated using CalculateChecksum function
marketDataRequest.MarketDataRequest.Trailer = trailer
// set new market data request to store
k.SetMarketData(ctx, msg.MdReqID, marketDataRequest)
// emit event
err = ctx.EventManager().EmitTypedEvent(msg)
return &types.MsgMarketDataRequestResponse{}, err
}
// MarketDataSnapshotFullRefresh creates Market Data Snapshot Full Refresh
func (k msgServer) MarketDataSnapshotFullRefresh(goCtx context.Context, msg *types.MsgMarketDataSnapshotFullRefresh) (*types.MsgMarketDataSnapshotFullRefreshResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// Validate the message creator
_, err := sdk.AccAddressFromBech32(msg.Creator)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Creator)
}
// check for if the provided session ID exists
session, found := k.GetSessions(ctx, msg.SessionID)
if !found {
return nil, sdkerrors.Wrapf(types.ErrEmptySession, "Session Name: %s", msg.SessionID)
}
// check that the sessionID provided is active between both parties
if session.SessionID != msg.SessionID {
return nil, sdkerrors.Wrapf(types.ErrMarketDataSession, "SessionID: %s", msg.SessionID)
}
// check that the user responding is the recipient of the market data request
if session.LogonInitiator.Header.SenderCompID != msg.Creator && session.LogonAcceptor.Header.SenderCompID != msg.Creator {
return nil, sdkerrors.Wrapf(types.ErrNotAccountCreator, "Market Data Snap Shot Full Refresh Creator: %s", msg.Creator)
}
// get the existing Market Data Request
marketDataRequest, found := k.GetMarketData(ctx, msg.MdReqID)
if !found {
return nil, sdkerrors.Wrapf(types.ErrMdReqIDIsNotFound, "MdReqID: %s", msg.MdReqID)
}
// check that Market Data Request creator address is not same responding to the Market Data Request
if marketDataRequest.MarketDataRequest.Header.SenderCompID == msg.Creator {
return nil, sdkerrors.Wrapf(types.ErrMarketDataSnapShotFullRefreshCreatorIsWrong, "Market Data Snapshot Full Refresh: %s", msg.Creator)
}
// check that this Market Data Request to be acknowledged has not been rejected
// if MarketDataRequestReject is not nil, then market data snap shot full refresh should be rejected
if marketDataRequest.MarketDataRequestReject != nil {
return nil, sdkerrors.Wrapf(types.ErrMarketDataRequestIsRejected, "Market Data Request: %s", marketDataRequest.MarketDataRequestReject)
}
// check that this Market Data Request is not acknowledged already
if marketDataRequest.MarketDataSnapShotFullRefresh != nil {
return nil, sdkerrors.Wrapf(types.ErrMarketDataRequestIsAcknowlodged, "Market Data Request: %s", marketDataRequest.MarketDataSnapShotFullRefresh)
}
// check that mandatory Market Data Snap Shot Full Refresh fields are not empty
if msg.MdReqID == "" {
return nil, sdkerrors.Wrapf(types.ErrMdReqIDIsEmpty, "MdReqID: %s", msg.MdReqID)
}
if msg.Symbol == "" {
return nil, sdkerrors.Wrapf(types.ErrSymbolIsEmpty, "Symbol: %s", msg.Symbol)
}
if _, err := strconv.ParseInt(fmt.Sprint(msg.NoMDEntries), 10, 64); err != nil {
return nil, sdkerrors.Wrapf(types.ErrMarketDepthIsEmpty, "NoMDEntries: %v", msg.NoMDEntries)
}
for _, md := range msg.MdEntries {
if _, err := strconv.ParseInt(fmt.Sprint(md.MdUpdateAction), 10, 64); err != nil {
return nil, sdkerrors.Wrapf(types.ErrMdUpdateActionIsEmpty, "MdUpdateAction: %v", md.MdUpdateAction)
}
if _, err := strconv.ParseInt(fmt.Sprint(md.MdEntryType), 10, 64); err != nil {
return nil, sdkerrors.Wrapf(types.ErrMdEntryTypeIsEmpty, "MdEntryType: %v", md.MdEntryType)
}
if md.MdEntryPx == "" {
return nil, sdkerrors.Wrapf(types.ErrMdEntryPxIsEmpty, "MdEntryPx: %s", md.MdEntryPx)
}
if md.MdEntrySize == "" {
return nil, sdkerrors.Wrapf(types.ErrMdEntrySizeIsEmpty, "MdEntrySize: %s", md.MdEntrySize)
}
}
// market data snap shot full refresh
marketDataSnapShotFullRefresh := types.MarketData{
SessionID: msg.SessionID,
MarketDataRequest: marketDataRequest.MarketDataRequest,
MarketDataSnapShotFullRefresh: &types.MarketDataSnapShotFullRefresh{
MdReqID: msg.MdReqID,
Symbol: msg.Symbol,
NoMDEntries: msg.NoMDEntries,
MdEntries: msg.MdEntries,
},
}
// set header from the existing Market Data Request
marketDataSnapShotFullRefresh.MarketDataSnapShotFullRefresh.Header = marketDataRequest.MarketDataRequest.Header
// create a copy of the Header
newHeader := new(types.Header)
*newHeader = *marketDataSnapShotFullRefresh.MarketDataSnapShotFullRefresh.Header
// set bodyLength
// TODO
// Recalculate the bodyLength in the header
newHeader.BodyLength = marketDataRequest.MarketDataRequest.Header.BodyLength
// set msgSeqNum
newHeader.MsgSeqNum = marketDataRequest.MarketDataRequest.Header.MsgSeqNum
// set the msgType to Market Data Snapshot/Full Refresh
newHeader.MsgType = "W"
// switch senderCompID and targetCompID between Market Data Request and MArket Data Snapshot Full Refresh
// set senderCompID of Market Data Snapshot Full Refresh to the targetCompID of Market Data Request in the header
newHeader.SenderCompID = marketDataRequest.MarketDataRequest.Header.TargetCompID
// set targetCompID of Market Data Snapshot Full Refresh to the senderCompID of Market Data Request in the header
newHeader.TargetCompID = marketDataRequest.MarketDataRequest.Header.SenderCompID
// set sending time
newHeader.SendingTime = constants.SendingTime
// pass all the edited values to the newHeader
marketDataSnapShotFullRefresh.MarketDataSnapShotFullRefresh.Header = newHeader
// set Trailer from the existing Market Data Request
marketDataSnapShotFullRefresh.MarketDataSnapShotFullRefresh.Trailer = marketDataRequest.MarketDataRequest.Trailer
// set new market data snapshot full refresh to store
k.SetMarketData(ctx, msg.MdReqID, marketDataSnapShotFullRefresh)
// emit event
err = ctx.EventManager().EmitTypedEvent(msg)
return &types.MsgMarketDataSnapshotFullRefreshResponse{}, err
}
// MarketDataIncremental creates Market Data Incremental
func (k msgServer) MarketDataIncremental(goCtx context.Context, msg *types.MsgMarketDataIncremental) (*types.MsgMarketDataIncrementalResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// TODO: Handling the message
_ = ctx
return &types.MsgMarketDataIncrementalResponse{}, nil
}
// MarketDataRequestReject creates Market Data Request Reject
func (k msgServer) MarketDataRequestReject(goCtx context.Context, msg *types.MsgMarketDataRequestReject) (*types.MsgMarketDataRequestRejectResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// Validate the message creator
_, err := sdk.AccAddressFromBech32(msg.Creator)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Creator)
}
// check for if the provided session ID exists
session, found := k.GetSessions(ctx, msg.SessionID)
if !found {
return nil, sdkerrors.Wrapf(types.ErrEmptySession, "Session Name: %s", msg.SessionID)
}
// check that the sessionID provided is active between botth parties
if session.SessionID != msg.SessionID {
return nil, sdkerrors.Wrapf(types.ErrMarketDataSession, "SessionID: %s", msg.SessionID)
}
// check that the user responding is the recipient of the market data request
if session.LogonInitiator.Header.SenderCompID != msg.Creator && session.LogonAcceptor.Header.SenderCompID != msg.Creator {
return nil, sdkerrors.Wrapf(types.ErrNotAccountCreator, "Market Data Request Creator: %s", msg.Creator)
}
// get the existing Market Data Request
marketDataRequest, found := k.GetMarketData(ctx, msg.MdReqID)
if !found {
return nil, sdkerrors.Wrapf(types.ErrMdReqIDIsNotFound, "MdReqID: %s", msg.MdReqID)
}
// check that Market Data Request creator address is not same responding to the Market Data Request Reject
if marketDataRequest.MarketDataRequest.Header.SenderCompID == msg.Creator {
return nil, sdkerrors.Wrapf(types.ErrMarketDataRequestRejectCreatorIsWrong, "Market Data Request Reject: %s", msg.Creator)
}
// check that this Market Data Request to be rejected has not been acknowledged
// if market data snap shot full refresh is not nil, then it means market data request has been acknowledged, hence market data request reject cannot be executed
if marketDataRequest.MarketDataSnapShotFullRefresh != nil {
return nil, sdkerrors.Wrapf(types.ErrMarketDataRequestIsAcknowlodged, "Market Data Request Reject: %s", marketDataRequest.MarketDataSnapShotFullRefresh)
}
// check that this Market Data Request is not rejected already
if marketDataRequest.MarketDataRequestReject != nil {
return nil, sdkerrors.Wrapf(types.ErrMarketDataRequestIsRejected, "Market Data Request: %s", marketDataRequest.MarketDataRequestReject)
}
// check that mandatory Market Data Request Reject field is not empty
if _, err := strconv.ParseInt(fmt.Sprint(msg.MdReqRejReason), 10, 64); err != nil {
return nil, sdkerrors.Wrapf(types.ErrMdReqRejReasonIsEmpty, "MdReqRejReason: %v", msg.MdReqRejReason)
}
// market data request reject
marketDataRequestReject := types.MarketData{
SessionID: msg.SessionID,
MarketDataRequest: marketDataRequest.MarketDataRequest,
MarketDataSnapShotFullRefresh: marketDataRequest.MarketDataSnapShotFullRefresh,
MarketDataIncremental: marketDataRequest.MarketDataIncremental,
MarketDataRequestReject: &types.MarketDataRequestReject{
MdReqID: msg.MdReqID,
MdReqRejReason: msg.MdReqRejReason,
Text: msg.Text,
},
}
// set header from the existing Market Data Request
marketDataRequestReject.MarketDataRequestReject.Header = marketDataRequest.MarketDataRequest.Header
// create a copy of the Header
newHeader := new(types.Header)
*newHeader = *marketDataRequestReject.MarketDataRequestReject.Header
// set bodyLength
// TODO
// Recalculate the bodyLength in the header
newHeader.BodyLength = marketDataRequest.MarketDataRequest.Header.BodyLength
// set msgSeqNum
newHeader.MsgSeqNum = marketDataRequest.MarketDataRequest.Header.MsgSeqNum
// set the msgType to Market Data Request Reject
newHeader.MsgType = "Y"
// switch senderCompID and targetCompID between Market Data Request and Market Data Request Reject
// set senderCompID of Market Data Request Reject to the targetCompID of Market Data Request in the header
newHeader.SenderCompID = marketDataRequest.MarketDataRequest.Header.TargetCompID
// set targetCompID of Market Data Request Reject to the senderCompID of Market Data Request in the header
newHeader.TargetCompID = marketDataRequest.MarketDataRequest.Header.SenderCompID
// set sending time
newHeader.SendingTime = constants.SendingTime
// pass all the edited values to the newHeader
marketDataRequestReject.MarketDataRequestReject.Header = newHeader
// set Trailer from the existing Market Data Request
// then calcualate the checksum
marketDataRequestReject.MarketDataRequestReject.Trailer = marketDataRequest.MarketDataRequest.Trailer
// set new market data request reject to store
k.SetMarketData(ctx, msg.MdReqID, marketDataRequestReject)
// emit event
err = ctx.EventManager().EmitTypedEvent(msg)
return &types.MsgMarketDataRequestRejectResponse{}, err
}