Description
Two related gaps exist around FIX message header/trailer handling:
1. Header fields (e.g. OnBehalfOfCompID) are only configurable at the session/profile level, not per Favourite
Currently, header fields like OnBehalfOfCompID (tag 115) are configured globally via the Header Fields section in GeneralInfo.tsx → FixHeaderForm. These values are stored in session.profile.headerFields and applied uniformly to every outgoing message in encodeToFix(). There is no way to save different header field values per Favourite.
In real trading workflows, different orders are often placed on behalf of different clients. A trader managing orders for Client A and Client B needs OnBehalfOfCompID to vary per order, not be locked to one value for the entire session. Today, the only workaround is to manually change the global header config before sending each message — error-prone and slow.
2. Header and trailer fields are not visible in the structured Message Viewer or in-session Message Diff
When viewing received/sent messages, the structured table view (MessageView) only shows body fields via getValue(). Header fields like SenderCompID, TargetCompID, OnBehalfOfCompID, SendingTime, etc. are invisible in the structured view (only visible in the raw message string). The same gap applies to the in-session diff comparison.
Current Behavior
Favourites — header fields not saved:
In FavoriteManagementService.ts (line 32), only body data is persisted:
await this.fileManager.writeFile(`${saveDirPath}/${name}___${messageDef.name}.json`, JSON.stringify({ msg: messageDef.name, data }));
And in FixForm.tsx (lines 214–220), getMessageData() extracts only body fields:
private onAddToFavorites = (name: string) => {
const { session, message } = this.props;
const data = this.formRef.current?.getFieldsValue();
const ret = this.getMessageData(data);
this.setState({ saving: true })
GlobalServiceRegistry.favoriteManager.addToFavorites((session as FixSession).profile, message, name, ret).then(() => {
When a Favourite is loaded and sent, it goes through encodeToFix() which only applies profile-level headers:
public encodeToFix = (header: FixMsgHeader, msgDef: FixMessageDef, parameters?: Parameters, additionalHeaders?: any): string => {
let newHeaders: any = {};
if (this.profile.headerFields) {
newHeaders = { ...this.profile.headerFields }
}
if (additionalHeaders) {
newHeaders = { ...newHeaders, ...additionalHeaders }
}
return this.parser.encodeToFix(msgDef, msgDef.getValue(), header, parameters, newHeaders)
}
MessageView — body only:
In MessageView.tsx (line 166), the structured view renders only getValue() (body fields):
{!this.isEmpty(selectedMsg.def.getValue()) ? <div id={`search-node-msg-view${this.componentKey}`}>{this.renderValues(selectedMsg.def.getValue())}</div>
: <div className="no-data">{getIntlMessage("no_data")}</div>}
In-session Diff — body only:
In SessoinMessageStream.tsx (line 177), when selecting two messages for diff, the raw JSON is constructed from body-only data:
this.setState({
selectedRows: rows.map((row: any) => ({
def: row.msg,
rawMsg: JSON.stringify(row.msg.getValue(), null, 2),
session: this.props.session
})), diffModeEnabled: true
This feeds into MessageDiffViewer → ReactDiffViewer, so the diff comparison only covers body fields.
Note: The standalone Message Diff Viewer tab (MessageDiffViewerManagement.tsx line 117) does use getValueWithHeaders() for its comparison, so it includes header fields. But the side-by-side mode there still uses MessageView, which falls back to body-only.
Expected Behavior
1. Per-Favourite header field overrides:
- When editing/saving a Favourite, allow the user to optionally specify header field overrides (e.g.
OnBehalfOfCompID = "ClientA").
- The
FavoriteInstance structure should support an optional headerOverrides field:
export interface FavoriteInstance {
msg: string,
data: any,
headerOverrides?: any // optional per-favourite header fields
}
- When sending a Favourite, its
headerOverrides should be merged on top of profile.headerFields (with Favourite values taking precedence), before passing to encodeToFix().
- The Favourite form (or a collapsible section within it) should expose the relevant header fields for override.
2. Header/trailer visibility in MessageView:
MessageView should display header fields (and optionally trailer fields) in the structured table, perhaps in a collapsible "Header" section above the body and a "Trailer" section below, using getValueWithHeaders() or a new method that separates header/body/trailer.
- This should apply everywhere
MessageView is used: the session message viewer panel, the MessageViewer tab, and the side-by-side diff.
3. In-session diff should include headers:
- In
SessoinMessageStream.tsx, the rawMsg for diff should use getValueWithHeaders() (or equivalent) instead of getValue() so that header differences are visible in the diff view.
Files to Modify
| File |
Change |
src/services/favorite-management/FavoriteManagementService.ts |
Extend FavoriteInstance with optional headerOverrides; save/load them |
src/main-layout/SessionWindow/SessionTab/SessionManagement/FixForm.tsx |
Add UI for editing header overrides when saving a Favourite; pass headerOverrides through to encodeToFix() on send |
src/services/fix/FixSession.ts |
encodeToFix() — accept and merge per-message header overrides (Favourite-level) between profile headers and additional headers |
src/services/fix/FixDefs.ts |
Potentially add a method to separate header, body, and trailer data for structured display |
src/common/MessageView/MessageView.tsx |
Use getValueWithHeaders() (or a structured variant) to render header/trailer sections in the table view |
src/main-layout/SessionWindow/SessionTab/SessoinMessageStream/SessoinMessageStream.tsx |
Use getValueWithHeaders() instead of getValue() when constructing diff JSON (line 177) |
src/main-layout/SessionWindow/SessionTab/SessoinMessageStream/MessageDiffViewer.tsx |
Ensure the side-by-side mode also shows header/trailer |
src/services/profile/ProfileDefs.ts |
No structural change needed — headerFields remains the session-level default |
Additional Context
-
Current summary of header/trailer visibility across the app:
| Component |
Shows Headers? |
Shows Trailers? |
Data Source |
| FixForm (message editor) |
No |
No |
Body only |
| FixHeaderForm (global config) |
Yes |
No |
Profile-level headerFields |
| MessageView (structured view) |
No |
No |
getValue() — body only |
| In-session Diff |
No |
No |
getValue() — body only |
| Standalone Diff tab (JSON diff) |
Yes |
Partially |
getValueWithHeaders() |
| Standalone Diff tab (side-by-side) |
No |
No |
Falls back to MessageView |
| Raw message display |
Yes |
Yes |
Full raw FIX string |
-
The decodeInternals() method in FixDefinitionParser.ts already populates dataWithHeaders (with fieldName[tagNumber] format) alongside the body-only data. The infrastructure to expose header fields is partially there — it just needs to be surfaced in the UI components.
-
This feature is particularly important for institutional trading desks where a single session handles orders for multiple underlying clients, making OnBehalfOfCompID a per-order concern rather than a session-level setting.
Description
Two related gaps exist around FIX message header/trailer handling:
1. Header fields (e.g.
OnBehalfOfCompID) are only configurable at the session/profile level, not per FavouriteCurrently, header fields like
OnBehalfOfCompID(tag 115) are configured globally via the Header Fields section inGeneralInfo.tsx→FixHeaderForm. These values are stored insession.profile.headerFieldsand applied uniformly to every outgoing message inencodeToFix(). There is no way to save different header field values per Favourite.In real trading workflows, different orders are often placed on behalf of different clients. A trader managing orders for Client A and Client B needs
OnBehalfOfCompIDto vary per order, not be locked to one value for the entire session. Today, the only workaround is to manually change the global header config before sending each message — error-prone and slow.2. Header and trailer fields are not visible in the structured Message Viewer or in-session Message Diff
When viewing received/sent messages, the structured table view (
MessageView) only shows body fields viagetValue(). Header fields likeSenderCompID,TargetCompID,OnBehalfOfCompID,SendingTime, etc. are invisible in the structured view (only visible in the raw message string). The same gap applies to the in-session diff comparison.Current Behavior
Favourites — header fields not saved:
In
FavoriteManagementService.ts(line 32), only body data is persisted:And in
FixForm.tsx(lines 214–220),getMessageData()extracts only body fields:When a Favourite is loaded and sent, it goes through
encodeToFix()which only applies profile-level headers:MessageView — body only:
In
MessageView.tsx(line 166), the structured view renders onlygetValue()(body fields):In-session Diff — body only:
In
SessoinMessageStream.tsx(line 177), when selecting two messages for diff, the raw JSON is constructed from body-only data:This feeds into
MessageDiffViewer→ReactDiffViewer, so the diff comparison only covers body fields.Note: The standalone Message Diff Viewer tab (
MessageDiffViewerManagement.tsxline 117) does usegetValueWithHeaders()for its comparison, so it includes header fields. But the side-by-side mode there still usesMessageView, which falls back to body-only.Expected Behavior
1. Per-Favourite header field overrides:
OnBehalfOfCompID = "ClientA").FavoriteInstancestructure should support an optionalheaderOverridesfield:headerOverridesshould be merged on top ofprofile.headerFields(with Favourite values taking precedence), before passing toencodeToFix().2. Header/trailer visibility in MessageView:
MessageViewshould display header fields (and optionally trailer fields) in the structured table, perhaps in a collapsible "Header" section above the body and a "Trailer" section below, usinggetValueWithHeaders()or a new method that separates header/body/trailer.MessageViewis used: the session message viewer panel, the MessageViewer tab, and the side-by-side diff.3. In-session diff should include headers:
SessoinMessageStream.tsx, therawMsgfor diff should usegetValueWithHeaders()(or equivalent) instead ofgetValue()so that header differences are visible in the diff view.Files to Modify
src/services/favorite-management/FavoriteManagementService.tsFavoriteInstancewith optionalheaderOverrides; save/load themsrc/main-layout/SessionWindow/SessionTab/SessionManagement/FixForm.tsxheaderOverridesthrough toencodeToFix()on sendsrc/services/fix/FixSession.tsencodeToFix()— accept and merge per-message header overrides (Favourite-level) between profile headers and additional headerssrc/services/fix/FixDefs.tssrc/common/MessageView/MessageView.tsxgetValueWithHeaders()(or a structured variant) to render header/trailer sections in the table viewsrc/main-layout/SessionWindow/SessionTab/SessoinMessageStream/SessoinMessageStream.tsxgetValueWithHeaders()instead ofgetValue()when constructing diff JSON (line 177)src/main-layout/SessionWindow/SessionTab/SessoinMessageStream/MessageDiffViewer.tsxsrc/services/profile/ProfileDefs.tsheaderFieldsremains the session-level defaultAdditional Context
Current summary of header/trailer visibility across the app:
headerFieldsgetValue()— body onlygetValue()— body onlygetValueWithHeaders()MessageViewThe
decodeInternals()method inFixDefinitionParser.tsalready populatesdataWithHeaders(withfieldName[tagNumber]format) alongside the body-onlydata. The infrastructure to expose header fields is partially there — it just needs to be surfaced in the UI components.This feature is particularly important for institutional trading desks where a single session handles orders for multiple underlying clients, making
OnBehalfOfCompIDa per-order concern rather than a session-level setting.