fixparser
Version:
FIX.Latest / 5.0 SP2 Parser / AI Agent Trading
409 lines (408 loc) • 18.4 kB
TypeScript
import { Field } from '../fields/Field.ts';
import type { RefType, Structure } from '../messagetype/MessageType.ts';
import type { ISpecEnums } from '../spec/SpecEnums.ts';
import type { ISpecFields } from '../spec/SpecFields.ts';
import { type FIXValue } from '../util/util.ts';
type FieldValues = {
[tag: string]: any;
};
/**
* The MessageError object is used by FIXParser validation to
* represent detailed error information when validation fails,
* including the field, tag, value, expected value, and a
* descriptive error message.
*
* @public
*/
export type MessageError = {
field: RefType | ISpecFields | undefined;
name: string | undefined;
tag: number;
value: FIXValue;
expectedValue?: FIXValue;
error: string;
};
/**
* Represents a complete FIX (Financial Information eXchange) message structure.
* The message is divided into three main parts: Header, Body, and Trailer.
*
* @typedef {Object} FIXJSON
* @property {Record<string, FIXValue | FIXValue[]>} Header - The header section of the FIX message, which includes metadata such as the sender, target, and timestamp.
* @property {Record<string, FIXValue | FIXValue[] | Record<string, FIXValue | FIXValue[]>[]}> Body - The body section of the FIX message, which contains the actual transaction or data being conveyed. It can contain nested groups.
* @property {Record<string, FIXValue | FIXValue[]>} Trailer - The trailer section of the FIX message, which typically contains checksum or other closing information.
*/
type FIXJSON = {
Header: Record<string, FIXValue | FIXValue[]>;
Body: Record<string, FIXValue | FIXValue[] | Record<string, FIXValue | FIXValue[]>[]>;
Trailer: Record<string, FIXValue | FIXValue[]>;
};
/**
* A FIX message is a standardized electronic communication used in
* financial markets to exchange information such as orders,
* executions, and market data between trading participants,
* following the FIX protocol's predefined structure and rules.
*
* @public
*/
export declare class Message {
#private;
/** The fix version associated with the message. */
fixVersion: string;
/** The data fields associated with the message. */
data: Field[];
/** The FIX string representation of the message. */
messageString: string;
/** The description of the message. */
description: string;
/** The type of the message. */
messageType: string;
/** A description of the message type. */
messageTypeDescription: string;
/** The sequence number of the message. */
messageSequence: number;
/** The structure of the message, can be null if not defined. */
structure: Structure[] | undefined;
/** Flag indicating whether the body length is valid. */
bodyLengthValid: boolean;
/** Flag indicating whether the checksum is valid. */
checksumValid: boolean;
/** The specified checksum value of the message, can be null if not available. */
checksumValue: string | undefined;
/** The actual checksum value of the message, can be null if not provided. */
checksumExpected: string | undefined;
/** The specified body length of the message, can be null if not available. */
bodyLengthValue: number | undefined;
/** The actual body length of the message, can be null if not provided. */
bodyLengthExpected: number | undefined;
/**
* Creates a new FIX Message instance.
*
* The constructor initializes the FIX Message with the specified FIX version and optional
* custom fields. It processes the fields to set specific FIX tags such as `BeginString`,
* `MsgSeqNum`, and `MsgType`, and updates the message accordingly.
*
* @param {string} [fixVersion=DEFAULT_FIX_VERSION] - The FIX protocol version. Defaults to `DEFAULT_FIX_VERSION`.
* @param {...Field} fields - A variable number of `Field` objects that represent individual tags in the FIX message.
* Each field object must contain a `tag` and a `value`, where `tag` indicates the field type (e.g., `BeginString`, `MsgSeqNum`, etc.).
*
* @throws {Error} If the field contains an invalid tag or value type.
*
* @example
* const message = new Message('FIXT.1.1', new Field(FieldType.MsgType, Messages.NewOrderSingle), new Field(Fields.OrderQty, 10000));
*
*/
constructor(fixVersion?: string, ...fields: Field[]);
/**
* Adds a single `Field` object to the message data.
*
* @param {Field} field - The `Field` object to be added.
*/
addField(field: Field): void;
/**
* Adds multiple `Field` objects to the message data.
* If the field's tag is `MsgType`, it will be added at the beginning of the `data` array.
* Otherwise, it will be appended to the end.
*
* @param {...Field} fields - One or more `Field` objects to be added.
*/
addFields(...fields: Field[]): void;
/**
* Removes a field from the message data by its `tag`.
*
* @param {number} tag - The tag of the field to be removed.
*/
removeFieldByTag(tag: number): void;
/**
* Retrieves a single field from the message data by its `tag`.
*
* @param {number} tag - The tag of the field to be retrieved.
* @returns {Field | undefined} The `Field` object if found, otherwise `undefined`.
*/
getField(tag: number): Field | undefined;
/**
* Retrieves all fields from the message data that have the specified `tag`.
*
* @param {number} tag - The tag of the fields to be retrieved.
* @returns {Field[]} An array of `Field` objects that match the specified `tag`, or an empty array if no fields match.
*/
getFields(tag: number): Field[] | undefined;
/**
* Returns an object containing the name-explain pairs of all fields in the message.
* The `name` of each field is used as the key, and the enumeration of the (`value`) is assigned to it.
* For example, `MsgType: 'D'` gets assigned `MsgType: 'NewOrderSingle'`,
*
* @returns {FieldValues} An object where the keys are field names and the values are the explained field values.
* @example
* console.log(message.getFieldExplains());
* {
* '47': 'A',
* BeginString: 'FIX42',
* BodyLength: 146,
* MsgType: 'NewOrderSingle',
* MsgSeqNum: 4,
* SenderCompID: 'ABC_DEFG01',
* SendingTime: '20090323-15:40:29',
* TargetCompID: 'CCG',
* OnBehalfOfCompID: 'XYZ',
* ClOrdID: 'NF 0542/03232009',
* Side: 'Buy',
* OrderQty: 100,
* Symbol: 'CVS',
* OrdType: 'Market',
* TimeInForce: 'Day',
* TransactTime: '20090323-15:40:29',
* HandlInst: 'AutomatedExecutionNoIntervention',
* SecurityExchange: 'N',
* CheckSum: '195'
* }
*/
getFieldExplains(): FieldValues;
/**
* Returns an object containing the name-value pairs of all fields in the message.
* The `name` of each field is used as the key, and the `value` is assigned to it.
*
* @returns {FieldValues} An object where the keys are field names and the values are field values.
* @example
* console.log(message.getFieldNameValues());
* {
* '47': 'A',
* BeginString: 'FIX.4.2',
* BodyLength: 146,
* MsgType: 'D',
* MsgSeqNum: 4,
* SenderCompID: 'ABC_DEFG01',
* SendingTime: '20090323-15:40:29',
* TargetCompID: 'CCG',
* OnBehalfOfCompID: 'XYZ',
* ClOrdID: 'NF 0542/03232009',
* Side: '1',
* OrderQty: 100,
* Symbol: 'CVS',
* OrdType: '1',
* TimeInForce: '0',
* TransactTime: '20090323-15:40:29',
* HandlInst: '1',
* SecurityExchange: 'N',
* CheckSum: '195'
* }
*/
getFieldNameValues(): FieldValues;
/**
* Returns an object containing the values of all fields in the message, indexed by their `tag`.
* If a tag has multiple fields, the values will be stored in an array.
*
* @returns {FieldValues} An object where the keys are field tags and the values are field values (or arrays of values).
* @example
* console.log(message.getFieldValues());
* {
* '8': 'FIX.4.2',
* '9': 146,
* '10': '195',
* '11': 'NF 0542/03232009',
* '21': '1',
* '34': 4,
* '35': 'D',
* '38': 100,
* '40': '1',
* '47': 'A',
* '49': 'ABC_DEFG01',
* '52': '20090323-15:40:29',
* '54': '1',
* '55': 'CVS',
* '56': 'CCG',
* '59': '0',
* '60': '20090323-15:40:29',
* '115': 'XYZ',
* '207': 'N'
* }
*/
getFieldValues(): FieldValues;
/**
* Updates a field in the message data based on its `tag`.
* If a field with the same tag exists, it will be replaced with the new `Field` object.
*
* @param {Field} field - The `Field` object to update in the data.
*/
setField(field: Field): void;
/**
* Retrieves the enumeration for a given `tag` and `value` based on the message's `MsgType`.
* This method ensures that the `MsgType` field is present and has a value before attempting
* to retrieve the corresponding enumeration.
*
* @param {number} tag - The tag of the field for which the enum is to be retrieved.
* @param {FIXValue} value - The value of the field for which the enum is to be retrieved.
* @returns {ISpecEnums | undefined} The corresponding enumeration if found, or `undefined` if the `MsgType` field is missing
* or has no value, or if no matching enum is found.
*
* @example
* const enumValue = message.getEnum(35, 'D');
* console.log(`Enum: ${enumValue}`);
*/
getEnum(tag: number, value: FIXValue): ISpecEnums | undefined;
/**
* Generates a brief Bloomberg-style description of the current message based on its fields, such as `Side`, `OrderQty`, `Symbol`, `Price`, etc.
* The description is typically used for a quick summary of an order or trade message, formatted with key field values.
*
* Depending on the available fields, the method formats and returns a string summarizing the message's main details,
* such as quantity, price, symbol, and order type. If certain fields (like `LeavesQty`, `OrderQty`, `Price`, etc.) are not present,
* it adjusts the description accordingly.
*
* @returns {string | null} A brief string description summarizing the message. If no description can be formed, `null` is returned.
*
* @example
* const description = message.getBriefDescription();
* console.log(description); // "100 AAPL LMT @123.45 GTC"
*/
getBriefDescription(): string | undefined;
/**
* Validates the body length of the FIX message by comparing the provided value to the actual body length.
* The body length is calculated as the difference between the positions of the `MsgType` tag and the `Checksum` tag.
*
* @param {string} value - The body length value to validate against the calculated body length.
* @returns {boolean} `true` if the provided body length matches the calculated body length, otherwise `false`.
*
* @example
* const isValid = message.validateBodyLength('123');
* console.log(isValid); // true if the body length is correct, false otherwise
*/
validateBodyLength(value: string): boolean;
/**
* Validates the checksum of the FIX message by comparing the provided checksum value to the calculated checksum.
* The checksum is calculated based on the substring of the message string before the `Checksum` tag.
*
* @param {string} value - The checksum value to validate against the calculated checksum.
* @returns {boolean} `true` if the provided checksum matches the calculated checksum, otherwise `false`.
*
* @example
* const isValid = message.validateChecksum('123456');
* console.log(isValid); // true if the checksum is valid, false otherwise
*/
validateChecksum(value: string): boolean;
/**
* Recalculates and updates the body length and checksum of the FIX message.
* This method is useful when message fields have been modified and the message
* needs to be updated with correct length and checksum values.
*
* The method will:
* 1. Calculate the new body length based on the message content
* 2. Calculate the new checksum based on the entire message
* 3. Update the message's internal state with the new values
*
* @returns {Object} An object containing the new body length and checksum values
* @property {number} bodyLength - The newly calculated body length
* @property {string} checksum - The newly calculated checksum
*
* @example
* const message = new Message('FIX.4.4');
* message.addField(new Field(FieldType.OrderQty, 100));
* const { bodyLength, checksum } = message.recalculateMessageLengths();
* console.log(`New body length: ${bodyLength}, New checksum: ${checksum}`);
*/
recalculateMessageLengths(): {
bodyLength: number;
checksum: string;
};
/**
* Validates the structure and content of a given FIX message.
*
* This method checks the fields in the provided `message` for correct data format, required fields,
* and field references (such as `fieldRef`, `groupRef`, `componentRef`). It also validates specific fields
* like `BodyLength` and `CheckSum` against expected values.
*
* The validation process can be constrained to only required fields, based on the `requiredFieldsOnly` flag.
*
* @param {boolean} [requiredFieldsOnly=true] - If `true`, only required fields (as specified in the message structure) are validated.
* Defaults to `true`.
*
* @returns {MessageError[]} - An array of validation errors. Each error includes details about the field that caused the error,
* such as the field's `tag`, `name`, `value`, the error message, and any expected value (if applicable).
*
* @throws {Error} If any internal validation process fails or an invalid message is encountered.
*
* @example
* const validationErrors = message.validate();
*
* if (validationErrors.length > 0) {
* validationErrors.forEach(error => {
* console.error(`Field ${error.name} (Tag ${error.tag}) has error: ${error.error}`);
* });
* }
*/
validate(requiredFieldsOnly?: boolean): MessageError[];
/**
* Encodes the FIX message into a string format based on the current message data, including its header, body, and trailer.
* This method first validates the license, then constructs the message by adding fields such as `BeginString`, `BodyLength`,
* and `CheckSum`. It also calculates the body length and checksum dynamically, ensuring the message is correctly formatted
* according to the FIX protocol.
*
* @param {string} [separator=SOH] - The separator used to separate fields in the encoded FIX message. Defaults to `SOH` (Start of Header).
* @returns {string} The encoded FIX message string, including calculated body length and checksum.
* @throws {Error} If the license is invalid, it throws an error with a message indicating no valid license.
*
* @example
* const fixMessage = message.encode();
* console.log(fixMessage); // "8=FIX.4.4|35=D|49=SenderCompID|56=TargetCompID|34=1|10=123"
*/
encode(separator?: string): string;
/**
* Converts the current FIX message to a JSON-like structure (FIX JSON), representing the message in a format that mirrors the FIX protocol.
* The structure includes three main sections: `Header`, `Body`, and `Trailer`. Each section contains fields and, where applicable,
* groups of repeating fields. The method processes the fields in the `data` array and organizes them into these sections, handling
* groups, references, and field types appropriately.
*
* @returns {FIXJSON} The FIX message converted into a structured JSON-like format with `Header`, `Body`, and `Trailer` sections.
*
* @throws {Error} If the license is invalid, an error is thrown with a message indicating that no valid license is available.
*
* @example
* const fixJson = message.toFIXJSON();
* console.log(fixJson);
* // {
* // "Header": {
* // "BeginString": "FIXT.1.1",
* // "MsgType": "NewOrderSingle",
* // "SenderCompID": "ABC",
* // "TargetCompID": "XYZ"
* // },
* // "Body": {
* // "OrderQty": 1000,
* // "Price": 50.25,
* // "Symbol": "AAPL",
* // "Side": "Buy"
* // },
* // "Trailer": {
* // "CheckSum": "123"
* // }
* // }
*/
toFIXJSON(): FIXJSON;
/**
* Creates and returns a new instance of the `Message` class, which is a deep clone of the current `Message` instance.
* The cloned instance has the same `fixVersion`, `messageSequence`, and `messageType`, but the `data` array is also cloned to avoid references to the original fields.
*
* @returns {Message} A new `Message` instance that is a clone of the current one.
*
* @example
* const originalMessage = new Message('FIXT.1.1', field1, field2, field3);
* const clonedMessage = originalMessage.clone();
* console.log(clonedMessage); // A new Message instance with the same data as the original
*/
clone(): Message;
/**
* Resets the internal state of the `Message` instance to its initial, empty state.
* This includes clearing all data fields, resetting various properties to their default values,
* and ensuring the message is in a clean state ready for processing.
*
* This method is typically used when you want to clear the state of the current `Message` object
* and prepare it for new data, e.g., when parsing or constructing a new FIX message.
*
* @private
* @returns {void} This method does not return any value.
*
* @example
* const message = new Message('FIX.4.4', field1, field2);
* message.reset(); // Clears all properties and prepares the message for a new state
*/
private reset;
}
export {};