fixparser
Version:
FIX.Latest / 5.0 SP2 Parser / AI Agent Trading
166 lines (155 loc) • 6.27 kB
text/typescript
/**
* This example will connect to the C++ QuickFIX engine.
* Clone https://github.com/quickfix/quickfix
* build and run ./bin/run_executor_cpp.sh.
*
* FIX session flow:
* Initiator (us) connects over TCP to port 5001 on the QuickFIX server.
* Upon connection, we send a Logon message. QuickFIX responds to the Logon message.
* Next, we send several NewOrderSingle at random intervals. QuickFIX responds with ExecutionReports.
* This demonstrates a continuous connection with random order intervals and session management messages.
*/
import {
EncryptMethod,
FIXParser,
Field,
Fields,
HandlInst,
LicenseManager,
type Message,
Messages,
MsgType,
type Options,
OrdType,
ResetSeqNumFlag,
Side,
TimeInForce,
} from 'fixparser';
let randomIterator = 0;
const timeBasedRandom = (min: number, max: number): number => {
const timeNow = Date.now() % 1000;
randomIterator++;
let x = timeNow ^ randomIterator;
x ^= x << 21;
x ^= x >>> 35;
x ^= x << 4;
const timeBasedRandom = Math.abs(x % (max - min + 1));
return min + timeBasedRandom;
};
const getRandomNumber = (min = 0, max = 65535): number => {
return timeBasedRandom(min, max);
};
const getRandomEnumValue = <T>(enumObj: T): T[keyof T] => {
const enumValues = Object.values(enumObj);
const randomIndex = timeBasedRandom(0, enumValues.length - 1);
return enumValues[randomIndex];
};
const initializeConnection = async () => {
// NOTE: This feature requires a FIXParser Pro license
await LicenseManager.setLicenseKey(process.env.FIXPARSER_LICENSE_KEY);
let sentOrders = 0;
let orderInterval: NodeJS.Timeout;
const fixParser = new FIXParser();
const SENDER = 'CLIENT2';
const TARGET = 'EXECUTOR';
const CONNECT_PARAMS: Options = {
host: 'localhost',
port: 5001,
protocol: 'tcp',
sender: SENDER,
target: TARGET,
fixVersion: 'FIX.4.4',
logging: false,
logOptions: {
name: SENDER,
level: 'info',
format: 'json',
},
onOpen: () => {
console.log('Open');
sendLogon();
},
onMessage: (message: Message) => {
switch (message.messageType) {
case MsgType.Reject: {
console.log(
`\x1b[31mReceived ${message.description}: ${message.getField(58)?.value} (referencing tag ${message.getField(371)?.value})\x1b[0m`,
);
break;
}
case MsgType.Logon: {
console.log(`\x1b[34mReceived ${message.description}\x1b[0m`);
const startInterval = () => {
const numOrders = getRandomNumber(3, 50);
const pauseMs = getRandomNumber(100, 15000);
orderInterval = setInterval(() => {
const randomOrderId = getRandomNumber();
sendOrder(randomOrderId);
if (sentOrders % numOrders === 0) {
clearInterval(orderInterval);
console.log(
`-----------------> pausing for ${pauseMs / 1000} s (sent ${numOrders} orders)...`,
);
setTimeout(() => {
console.log('-----------------> restarting...');
sentOrders = 0;
startInterval();
}, pauseMs);
}
}, 5);
};
startInterval();
break;
}
case MsgType.ExecutionReport: {
console.log(
`\x1b[32mReceived ${message.description}: ${JSON.stringify(message.toFIXJSON(), null, 4)})\x1b[0m`,
);
break;
}
default: {
console.log(`\x1b[36mReceived unhandled message: ${message.description}\x1b[0m`);
}
}
},
onClose: () => {
console.log('Disconnected');
},
};
const sendLogon = () => {
const logon = fixParser.createMessage(
new Field(Fields.MsgType, Messages.Logon),
new Field(Fields.MsgSeqNum, fixParser.getNextTargetMsgSeqNum()),
new Field(Fields.SenderCompID, SENDER),
new Field(Fields.SendingTime, fixParser.getTimestamp()),
new Field(Fields.TargetCompID, TARGET),
new Field(Fields.ResetSeqNumFlag, ResetSeqNumFlag.Yes),
new Field(Fields.EncryptMethod, EncryptMethod.None),
new Field(Fields.HeartBtInt, 10),
);
fixParser.send(logon);
};
const sendOrder = (orderId: number) => {
const newOrderSingle = fixParser.createMessage(
new Field(Fields.MsgType, Messages.NewOrderSingle),
new Field(Fields.MsgSeqNum, fixParser.getNextTargetMsgSeqNum()),
new Field(Fields.SenderCompID, SENDER),
new Field(Fields.TargetCompID, TARGET),
new Field(Fields.SendingTime, fixParser.getTimestamp()),
new Field(Fields.ClOrdID, String(orderId).padStart(4, '0')),
new Field(Fields.Side, getRandomEnumValue(Side)),
new Field(Fields.Symbol, 'MSFT'),
new Field(Fields.OrderQty, getRandomNumber(1, 100000)),
new Field(Fields.Price, getRandomNumber(100, 500)),
new Field(Fields.OrdType, OrdType.Limit),
new Field(Fields.HandlInst, getRandomEnumValue(HandlInst)),
new Field(Fields.TimeInForce, getRandomEnumValue(TimeInForce)),
new Field(Fields.Text, `New Order ${orderId}`),
new Field(Fields.TransactTime, fixParser.getTimestamp()),
);
fixParser.send(newOrderSingle);
sentOrders++;
};
fixParser.connect(CONNECT_PARAMS);
};
initializeConnection().catch((err) => console.error('Error initializing connection:', err));