3.2.0
Note we are receiving increasing numbers of production style support questions normally which resolve to missing fields within the dictionary file. This is particularly problematic when these fields belong to components such as Instrument as the message cannot be parsed correctly. Please check carefully before raising such issues as they take considerable time to check and fix. In particular a good start point is to fetch tokens such as below from the fix log and see if any fields are unknown. All missing fields have to be added into the correct messages and defined properly else you will experience problems which may seem like bugs in this library. If you are working against a commercial vendor check the specification they provide carefully and ensure missing fields are all present. see the jspf-cserver example for a bespoke set of messages working with this library.
We will not provide support unless it is clear these basic checks have been done and that full examples are available to demonstrate the problem along with the corresponding dictionary file being used.
example demo applications written with this library
description | link |
---|---|
a good start point showing FIX 4 and 5 market data request/snapshot and custom generated types. | jspf-md-demo |
simple example with a custom dictionary that targets cserver | jspf-cserver |
example trade capture applicaton | jspf-demo |
change summary
- #62 the quickfix parser has been improved to cope with forward referenced components where previously groups wthin those components would not be included. This particularly impacts the FIX 5 SP2 specification. If you are using FIX 5 and quickfix notation you must move to this release.
- fewer memory allocations.
- include types for quickfix and repo based FIX5 SP2 - see the jspf-md-demo for both FIX.50SP2 and FIX.4.4 examples and an easy start point for a jspurefix based application.
- more unit tests added covering FIX 5 specifically.
- started documenting apis via doc notation, this is a work in progress.
- each message / component definition has a helper method allowing to reach recursively in and pull out a sub definition
getSecListGrp (): (ContainedFieldSet | null) {
return this.definitions.getSet('SecurityList.SecListGrp')
}
getNumRelatedSym (): (ContainedFieldSet | null) {
return return this.definitions.getSet('SecurityList.SecListGrp.NoRelatedSym')
}
getNoTickRules (): (ContainedFieldSet | null) {
return return this.definitions.getSet('SecurityList.SecListGrp.NoRelatedSym.SecurityTradingRules.BaseTradingRules.TickRules.NoTickRules')
}
- linting against standard
- note the existing helper command can be useful when parsing logs. See jspf-demo package.json and examples below.
- add admin messages into FIX5 xml for quickfix and generate associated types.
- update to latest npm dependencies e.g. tsc compiler.
- new cserver example with generated types for this venue jspf-cserver
- repo unzipped as part of npm install
example command line usage parse FIX log
fetch trade capure messages from a log and display in object notation
node node_modules/jspurefix/dist/jsfix-cmd --fix=../../jsfix.test_client.txt --delimiter="|" --session=../../data/session/test-initiator.json --type=AE --objects
AE [TradeCaptureReport] = {
"StandardHeader": {
"BeginString": "FIX4.4",
"BodyLength": 194,
"MsgType": "AE",
"SenderCompID": "accept-comp",
"TargetCompID": "init-comp",
"MsgSeqNum": 11,
"TargetSubID": "fix",
"SendingTime": "2023-11-11T14:45:19.705Z"
},
"TradeReportID": "100007",
"TradeReportTransType": 0,
"TradeReportType": 0,
"TrdType": 0,
"ExecID": "600007",
"OrdStatus": "2",
"PreviouslyReported": false,
"Instrument": {
"Symbol": "Gold",
"SecurityID": "Gold.INC"
},
"LastQty": 118,
"LastPx": 4.07,
"TradeDate": "2023-11-11T00:00:00.000Z",
"TransactTime": "2023-11-11T14:45:19.705Z",
"StandardTrailer": {
"CheckSum": "016"
}
}
see tokenised output from log
node .\node_modules\jspurefix\dist\jsfix-cmd --fix=..\..\jsfix.test_client.txt --delimiter="|" --type=AE --session=..\..\data\session\test-initiator.json --tokens
[0] 8 (BeginString) = FIX4.4, [1] 9 (BodyLength) = 0000193
[2] 35 (MsgType) = AE[TradeCaptureReport], [3] 49 (SenderCompID) = accept-comp
[4] 56 (TargetCompID) = init-comp, [5] 34 (MsgSeqNum) = 3
[6] 57 (TargetSubID) = fix, [7] 52 (SendingTime) = 20231111-14:44:59.672
[8] 571 (TradeReportID) = 100000, [9] 487 (TradeReportTransType) = 0
[10] 856 (TradeReportType) = 0[Submit], [11] 828 (TrdType) = 0[RegularTrade]
[12] 17 (ExecID) = 600000, [13] 39 (OrdStatus) = 2[Filled]
[14] 570 (PreviouslyReported) = N[NotReportedToCounterparty], [15] 55 (Symbol) = Gold
[16] 48 (SecurityID) = Gold.INC, [17] 32 (LastQty) = 171
[18] 31 (LastPx) = 6.28, [19] 75 (TradeDate) = 20231111
[20] 60 (TransactTime) = 20231111-14:44:59.672, [21] 10 (CheckSum) = 226
FIX 5 message types generated for quickfix and repo based definitions as below.
export interface ILogon {
StandardHeader: IStandardHeader// [1] BeginString.8, BodyLength.9 .. HopRefID.630
EncryptMethod: number// [2] 98 (Int)
HeartBtInt: number// [3] 108 (Int)
RawDataLength?: number// [4] 95 (Length)
RawData?: Buffer// [5] 96 (RawData)
ResetSeqNumFlag?: boolean// [6] 141 (Boolean)
NextExpectedMsgSeqNum?: number// [7] 789 (Int)
MaxMessageSize?: number// [8] 383 (Length)
NoMsgTypes?: ILogonNoMsgTypes[]// [9] RefMsgType.372, MsgDirection.385
TestMessageIndicator?: boolean// [10] 464 (Boolean)
Username?: string// [11] 553 (String)
Password?: string// [12] 554 (String)
NewPassword?: string// [13] 925 (String)
EncryptedPasswordMethod?: number// [14] 1400 (Int)
EncryptedPasswordLen?: number// [15] 1401 (Length)
EncryptedPassword?: Buffer// [16] 1402 (RawData)
EncryptedNewPasswordLen?: number// [17] 1403 (Length)
EncryptedNewPassword?: Buffer// [18] 1404 (RawData)
SessionStatus?: number// [19] 1409 (Int)
DefaultApplVerID?: string// [20] 1137 (String)
DefaultApplExtID?: number// [21] 1407 (Int)
DefaultCstmApplVerID?: string// [22] 1408 (String)
Text?: string// [23] 58 (String)
EncodedTextLen?: number// [24] 354 (Length)
EncodedText?: Buffer// [25] 355 (RawData)
StandardTrailer: IStandardTrailer// [26] SignatureLength.93, Signature.89, CheckSum.10
}
you can benchmark the library with something like
npm run qf50sp2-bench-md
> jspurefix@3.2.0 qf50sp2-bench-md
> node dist/jsfix-cmd --dict=qf50sp2 --fix=data/examples/FIX.5.0SP2/quickfix/md-data-snapshot/fix.txt --benchmark --delimiter="|" --repeats=80000
{
"content": "8=FIX.5.0SP2|9=0000430|35=W|49=init-comp|56=accept-comp|115=DTS|34=3187|57=fix|145=NCFX1_FIX50|52=20231031-20:51:03.893|122=20231030-10:18:33.507|262=EURJPY10Y=TDS|48=EURJPY10Y=TDS|22=8|167=FXFWD|762=NONE|15=EUR|20460=EUZZ02X3F8ZYPHZZZZ|268=3|269=0|278=2971|270=-3657.05|271=0|272=20231030|273=10:18:33.507|336=1|269=1|278=2972|270=-3590.35|271=0|272=20231030|273=10:18:33.507|336=1|269=H|278=2973|270=-3623.7|272=20231030|273=10:18:33.507|336=1|10=052|",
"view": "[0] 8 (BeginString) = FIX.5.0SP2[FIX.5.0SP2], [1] 9 (BodyLength) = 0000430\r\n[2] 35 (MsgType) = W[MarketDataSnapshotFullRefresh], [3] 49 (SenderCompID) = init-comp\r\n[4] 56 (TargetCompID) = accept-comp, [5] 115 (OnBehalfOfCompID) = DTS\r\n[6] 34 (MsgSeqNum) = 3187, [7] 57 (TargetSubID) = fix\r\n[8] 145 (DeliverToLocationID) = NCFX1_FIX50, [9] 52 (SendingTime) = 20231031-20:51:03.893\r\n[10] 122 (OrigSendingTime) = 20231030-10:18:33.507, [11] 262 (MDReqID) = EURJPY10Y=TDS\r\n[12] 48 (SecurityID) = EURJPY10Y=TDS, [13] 22 (SecurityIDSource) = 8[ExchangeSymbol]\r\n[14] 167 (SecurityType) = FXFWD[FxForward], [15] 762 (SecuritySubType) = NONE\r\n[16] 15 (Currency) = EUR, [17] 20460 (InstrumentCustom) = EUZZ02X3F8ZYPHZZZZ\r\n[18] 268 (NoMDEntries) = 3, [19] 269 (MDEntryType) = 0[Bid]\r\n[20] 278 (MDEntryID) = 2971, [21] 270 (MDEntryPx) = -3657.05\r\n[22] 271 (MDEntrySize) = 0, [23] 272 (MDEntryDate) = 20231030\r\n[24] 273 (MDEntryTime) = 10:18:33.507, [25] 336 (TradingSessionID) = 1[Day]\r\n[26] 269 (MDEntryType) = 1[Offer], [27] 278 (MDEntryID) = 2972\r\n[28] 270 (MDEntryPx) = -3590.35, [29] 271 (MDEntrySize) = 0\r\n[30] 272 (MDEntryDate) = 20231030, [31] 273 (MDEntryTime) = 10:18:33.507\r\n[32] 336 (TradingSessionID) = 1[Day], [33] 269 (MDEntryType) = H[MidPrice]\r\n[34] 278 (MDEntryID) = 2973, [35] 270 (MDEntryPx) = -3623.7\r\n[36] 272 (MDEntryDate) = 20231030, [37] 273 (MDEntryTime) = 10:18:33.507\r\n[38] 336 (TradingSessionID) = 1[Day], [39] 10 (CheckSum) = 052",
"msg_type": "W",
"iterations": 80000,
"elapsed_ms": 590,
"fields": 40,
"content_length": 453,
"micros_per_msg": 7.375,
"chars_per_second": 61423729,
"fields_per_second": 5423729
}
What's Changed
- Tsc5 by @TimelordUK in #71
- Fix52 by @TimelordUK in #76
Full Changelog: 3.0.0...3.2.0