UNPKG

fixparser

Version:

FIX.Latest / 5.0 SP2 Parser / AI Agent Trading

164 lines (152 loc) 6.33 kB
import { randomInt } from 'node:crypto'; import { LicenseManager as clientLicense, FIXParser } from 'fixparser'; import { EncryptMethod, ExecType, FIXServer, Field, Fields, HandlInst, type Message, Messages, OrdStatus, OrdType, ResetSeqNumFlag, Side, LicenseManager as serverLicense, TimeInForce, } from 'fixparser/FIXServer'; const RANDOMIZED_PORT = randomInt(9900, 12000); let fixServer: FIXServer; let fixParser: FIXParser; const testTimeout: NodeJS.Timeout | null = setTimeout(() => { console.log('Test timeout... exiting with error code 1'); if (fixParser) { fixParser.close(); } if (fixServer) { fixServer.close(); } process.exit(1); }, 10000); const clientSendLogon = () => { const logon: Message = fixParser.createMessage( new Field(Fields.MsgType, Messages.Logon), new Field(Fields.MsgSeqNum, fixParser.getNextTargetMsgSeqNum()), new Field(Fields.SenderCompID, 'CLIENT'), new Field(Fields.SendingTime, fixParser.getTimestamp()), new Field(Fields.TargetCompID, 'SERVER'), new Field(Fields.ResetSeqNumFlag, ResetSeqNumFlag.Yes), new Field(Fields.EncryptMethod, EncryptMethod.None), new Field(Fields.HeartBtInt, 10), ); const messages = fixParser.parse(logon.encode()); console.log('CLIENT sending message', messages[0].description, messages[0].messageString); fixParser.send(logon); }; const clientSendOrder = () => { const order: Message = fixParser.createMessage( new Field(Fields.MsgType, Messages.NewOrderSingle), new Field(Fields.MsgSeqNum, fixParser.getNextTargetMsgSeqNum()), new Field(Fields.SenderCompID, 'CLIENT'), new Field(Fields.SendingTime, fixParser.getTimestamp()), new Field(Fields.TargetCompID, 'SERVER'), new Field(Fields.ClOrdID, '11223344'), new Field(Fields.HandlInst, HandlInst.AutomatedExecutionNoIntervention), new Field(Fields.OrderQty, '123'), new Field(Fields.TransactTime, fixParser.getTimestamp()), new Field(Fields.OrdType, OrdType.Market), new Field(Fields.Side, Side.Buy), new Field(Fields.Symbol, '700.HK'), new Field(Fields.TimeInForce, TimeInForce.Day), ); const messages = fixParser.parse(order.encode()); console.log('CLIENT sending message', messages[0].description, messages[0].messageString.replace(/\x01/g, '|')); fixParser.send(order); }; const serverSendExecutionReport = (message: Message) => { const executionReport: Message = fixServer.createMessage( new Field(Fields.MsgType, Messages.ExecutionReport), new Field(Fields.MsgSeqNum, fixServer.getNextTargetMsgSeqNum()), new Field(Fields.SenderCompID, 'SERVER'), new Field(Fields.SendingTime, fixServer.getTimestamp()), new Field(Fields.TargetCompID, 'CLIENT'), new Field(Fields.AvgPx, message.getField(Fields.Price) ? message.getField(Fields.Price)?.value : 0), new Field(Fields.ClOrdID, message.getField(Fields.ClOrdID) ? message.getField(Fields.ClOrdID)?.value : 'N/A'), new Field(Fields.CumQty, message.getField(Fields.OrderQty) ? message.getField(Fields.OrderQty)?.value : 0), new Field(Fields.Symbol, message.getField(Fields.Symbol) ? message.getField(Fields.Symbol)?.value : 'N/A'), new Field(Fields.LastPx, message.getField(Fields.Price) ? message.getField(Fields.Price)?.value : 0), new Field(Fields.OrderID, 55), new Field(Fields.OrderQty, message.getField(Fields.OrderQty) ? message.getField(Fields.OrderQty)?.value : 0), new Field(Fields.OrdStatus, OrdStatus.Filled), new Field(Fields.Side, Side.Buy), new Field(Fields.ExecType, ExecType.Trade), new Field(Fields.LeavesQty, 0), ); const messages = fixServer.parse(executionReport.encode()); console.log('SERVER sending message', messages[0].description, messages[0].messageString.replace(/\x01/g, '|')); fixServer.send(executionReport); }; const setupServer = async () => { return new Promise<void>((resolve, reject) => { void reject; // Reject unused for now fixServer = new FIXServer({ logging: false }); fixServer.createServer({ host: '0.0.0.0', port: RANDOMIZED_PORT, sender: 'SERVER', target: 'CLIENT', onMessage: (message: Message) => { if (message.messageType === Messages.NewOrderSingle) { serverSendExecutionReport(message); } }, onReady: () => { console.log('SERVER READY'); resolve(); }, }); }); }; const setupClient = async () => { return new Promise<void>((resolve, _reject) => { fixParser = new FIXParser({ logging: false }); fixParser.connect({ host: 'localhost', port: RANDOMIZED_PORT, protocol: 'tcp', sender: 'CLIENT', target: 'SERVER', fixVersion: 'FIXT.1.1', onOpen: () => { clientSendLogon(); }, onMessage: (message: Message) => { if (message.messageType === Messages.Logon) { console.log('CLIENT received a Logon Acknowledge', message.messageString); clientSendOrder(); } else if (message.messageType === Messages.ExecutionReport) { console.log('CLIENT received a Execution Report', message.messageString); resolve(); } }, onClose: () => console.log('Disconnected'), }); }); }; const runE2E = async () => { try { // NOTE: This feature requires a FIXParser Pro license await serverLicense.setLicenseKey(process.env.FIXPARSER_LICENSE_KEY); await clientLicense.setLicenseKey(process.env.FIXPARSER_LICENSE_KEY); await setupServer(); await setupClient(); console.log('FIXServer E2E test was successfully completed.'); clearTimeout(testTimeout); process.exit(0); } catch (error) { console.error('Error during server setup:', error); process.exit(1); } }; void runE2E();