Fix protocol financial trading
Skill hamzabellouch/agent-skills/Financial and Fintech Engineering/fix-protocol-financial-trading
Comprehensive collection of 380+ production-ready Agent Skills (26 domains) conforming to the Agent Skills Standard, featuring native auto-discovery for Antigravity, Gemini CLI, Claude Code, Cursor, and Codex.
npx -y skills add hamzabellouch/agent-skills --skill fix-protocol-financial-tradingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 19 days oldThe repository was created 19 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Master high-frequency FIX (Financial Information eXchange) protocol messaging (FIX 4.2/4.4/5.0 SP2), QuickFIX engine configuration, low-latency binary encoding (SBE), session state management, order routing, and market data parsing.
SKILL.md
12.0 KB, ~3.0k tokens by cl100k_base, as published. Nobody here has run it
FIX Protocol Financial Trading & Messaging Architecture
This skill package defines enterprise standards for high-frequency financial trading systems, order management systems (OMS), and execution management systems (EMS) utilizing FIX (Financial Information eXchange) protocol versions 4.2, 4.4, and 5.0 SP2 (FIXML / SBE).
1. Core Session & Application Architecture
Session Layer Management & Resend Recovery
- Session State Persistence: Maintain strictly synchronized sequence numbers (
MsgSeqNum, Tag 34) for incoming and outgoing messages. Store session state in memory-mapped files (MMAP) or persistent low-latency disk storage. - Sequence Gap Handling & Recovery:
- When an incoming
MsgSeqNumis greater than expected, immediately issue aResendRequest(MsgType2, Tag 35=2). - Respond to incoming
ResendRequestmessages by re-sending administrative messages asSequenceReset-GapFill(MsgType4, Tag 35=4, Tag 123GapFillFlag=Y) and re-sending application messages withPossDupFlag=Y(Tag 43).
- When an incoming
- Heartbeat & Test Request Loop: Send
Heartbeat(Tag 35=0) at specifiedHeartBtInt(Tag 108) intervals. If no activity is received withinHeartBtInt + Margin, issue aTestRequest(Tag 35=1) with a uniqueTestReqID(Tag 112). Drop session if response is absent.
Low-Latency Messaging Engineering
- Zero-GC & Zero-Copy Memory Management: Eliminate object allocations on hot execution paths. Utilize ring buffers (e.g., LMAX Disruptor pattern) and pre-allocated byte buffers for message serialization.
- Encoding Formats: Use SBE (Simple Binary Encoding) or FAST (FIX Adapted for STreaming) for ultra-low latency market data feeds over UDP multicast, replacing legacy tag-value pairs.
- Transport Security & Network Topologies: Enforce mTLS 1.3 or IPsec VPN tunnels across dedicated cross-connects (Equinix NY4, LD4, TY3). Enable
TCP_NODELAY(disable Nagle's algorithm) and pin thread CPU affinity.
2. Key FIX Tag Reference Matrix
| Tag # | Field Name | Required / Enum | Description |
|---|---|---|---|
| 8 | BeginString | FIX.4.2 / FIX.4.4 / FIXT.1.1 | Protocol version identifier |
| 9 | BodyLength | Integer | Length of message body between Tag 9 and Tag 10 |
| 35 | MsgType | D (New Order), 8 (ExecReport), 2 (ResendReq) | Message type code |
| 49 | SenderCompID | String | Submitting institution identifier |
| 56 | TargetCompID | String | Receiving counterparty/exchange identifier |
| 34 | MsgSeqNum | Integer (1-based counter) | Message sequence counter |
| 11 | ClOrdID | Unique String | Client assigned unique identifier for order |
| 55 | Symbol | String | Financial instrument ticker (e.g., AAPL, EUR/USD) |
| 54 | Side | 1=Buy, 2=Sell, 5=Sell Short | Order side specification |
| 40 | OrdType | 1=Market, 2=Limit, 3=Stop, P=Pegged | Order type execution style |
| 38 | OrderQty | Quantity / Decimal | Total quantity of shares/contracts |
| 44 | Price | Currency Price | Limit price per unit |
| 10 | CheckSum | 3-digit zero-padded String | Modulo 256 sum of all characters up to 10= |
3. Production Code Implementations
Python Implementation: Production QuickFIX Initiator for Order Routing
import sys
import time
import logging
import quickfix as fix
import quickfix44 as fix44
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
class FIXOrderRoutingApplication(fix.Application):
def __init__(self):
super().__init__()
self.session_id = None
def onCreate(self, sessionID: fix.SessionID):
logging.info(f"Session Created: {sessionID}")
def onLogon(self, sessionID: fix.SessionID):
logging.info(f"Logon Successful: {sessionID}")
self.session_id = sessionID
def onLogout(self, sessionID: fix.SessionID):
logging.warning(f"Session Logged Out: {sessionID}")
self.session_id = None
def toAdmin(self, message: fix.Message, sessionID: fix.SessionID):
msg_type = fix.MsgType()
message.getHeader().getField(msg_type)
if msg_type.getValue() == fix.MsgType_Logon:
# Add Username/Password credentials for authentication
message.setField(fix.RawData("SuperSecretAuthToken"))
message.setField(fix.RawDataLength(len("SuperSecretAuthToken")))
def fromAdmin(self, message: fix.Message, sessionID: fix.SessionID):
pass
def toApp(self, message: fix.Message, sessionID: fix.SessionID):
logging.info(f"Sending Outbound App Message: {message}")
def fromApp(self, message: fix.Message, sessionID: fix.SessionID):
self._route_app_message(message, sessionID)
def send_limit_order(self, cl_ord_id: str, symbol: str, side: str, qty: float, price: float):
"""
Constructs and sends a FIX 4.4 NewOrderSingle (MsgType D)
"""
if not self.session_id:
raise RuntimeError("Cannot send order: FIX Session not active")
order = fix44.NewOrderSingle()
order.setField(fix.ClOrdID(cl_ord_id))
# Side: 1=Buy, 2=Sell
side_val = fix.Side_BUY if side.upper() == "BUY" else fix.Side_SELL
order.setField(fix.Side(side_val))
order.setField(fix.TransactTime())
order.setField(fix.OrdType(fix.OrdType_LIMIT))
order.setField(fix.Symbol(symbol))
order.setField(fix.OrderQty(qty))
order.setField(fix.Price(price))
order.setField(fix.TimeInForce(fix.TimeInForce_DAY))
# Send order asynchronously via QuickFIX engine
success = fix.Session.sendToTarget(order, self.session_id)
if not success:
logging.error(f"Failed to submit ClOrdID: {cl_ord_id}")
else:
logging.info(f"Submitted Limit Order {cl_ord_id} for {symbol}")
def _route_app_message(self, message: fix.Message, sessionID: fix.SessionID):
msg_type = fix.MsgType()
message.getHeader().getField(msg_type)
if msg_type.getValue() == fix.MsgType_ExecutionReport:
exec_id = fix.ExecID()
cl_ord_id = fix.ClOrdID()
ord_status = fix.OrdStatus()
symbol = fix.Symbol()
cum_qty = fix.CumQty()
avg_px = fix.AvgPx()
message.getField(exec_id)
message.getField(cl_ord_id)
message.getField(ord_status)
message.getField(symbol)
message.getField(cum_qty)
message.getField(avg_px)
logging.info(
f"ExecutionReport Received | ExecID: {exec_id.getValue()} | "
f"ClOrdID: {cl_ord_id.getValue()} | Status: {ord_status.getValue()} | "
f"Symbol: {symbol.getValue()} | CumQty: {cum_qty.getValue()} | AvgPx: {avg_px.getValue()}"
)
def main():
settings = fix.SessionSettings("fix_initiator.cfg")
application = FIXOrderRoutingApplication()
store_factory = fix.FileStoreFactory(settings)
log_factory = fix.FileLogFactory(settings)
initiator = fix.SocketInitiator(application, store_factory, settings, log_factory)
logging.info("Starting FIX Socket Initiator...")
initiator.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
logging.info("Stopping FIX Initiator...")
initiator.stop()
if __name__ == "__main__":
main()
TypeScript Implementation: High-Throughput Zero-Allocation FIX Parser
export class FastFixParser {
private static readonly SOH = 0x01; // SOH (Start of Header \x01)
/**
* Fast zero-copy zero-allocation parser for Tag-Value FIX buffers
*/
public parse(buffer: Buffer): Map<number, string> {
const fields = new Map<number, string>();
let cursor = 0;
const len = buffer.length;
while (cursor < len) {
const tagStart = cursor;
while (cursor < len && buffer[cursor] !== 0x3d /* '=' */) {
cursor++;
}
if (cursor >= len) break;
const tag = parseInt(buffer.toString('ascii', tagStart, cursor), 10);
cursor++; // Skip '='
const valStart = cursor;
while (cursor < len && buffer[cursor] !== FastFixParser.SOH) {
cursor++;
}
const value = buffer.toString('utf8', valStart, cursor);
fields.set(tag, value);
cursor++; // Skip SOH
}
this.validateChecksum(buffer, fields.get(10));
return fields;
}
/**
* Computes checksum modulo 256 over all bytes up to tag 10=
*/
private validateChecksum(buffer: Buffer, expectedChecksum?: string): void {
if (!expectedChecksum) return;
const sohIndex = buffer.lastIndexOf('\x0110=');
if (sohIndex === -1) return;
let sum = 0;
for (let i = 0; i <= sohIndex; i++) {
sum += buffer[i];
}
const computed = (sum % 256).toString().padStart(3, '0');
if (computed !== expectedChecksum) {
throw new Error(`FIX Checksum Error: Computed=${computed}, Expected=${expectedChecksum}`);
}
}
/**
* Formats a raw key-value map into a raw FIX wire protocol Buffer
*/
public serialize(msgType: string, senderCompId: string, targetCompId: string, seqNum: number, tags: Map<number, string>): Buffer {
let bodyStr = `35=${msgType}\x0149=${senderCompId}\x0156=${targetCompId}\x0134=${seqNum}\x01`;
for (const [tag, val] of tags.entries()) {
if ([8, 9, 35, 49, 56, 34, 10].includes(tag)) continue;
bodyStr += `${tag}=${val}\x01`;
}
const bodyLength = Buffer.byteLength(bodyStr, 'ascii');
const headerStr = `8=FIX.4.4\x019=${bodyLength}\x01`;
const fullMsgWithoutChecksum = headerStr + bodyStr;
let sum = 0;
const msgBuffer = Buffer.from(fullMsgWithoutChecksum, 'ascii');
for (let i = 0; i < msgBuffer.length; i++) {
sum += msgBuffer[i];
}
const checksumStr = `10=${(sum % 256).toString().padStart(3, '0')}\x01`;
return Buffer.concat([msgBuffer, Buffer.from(checksumStr, 'ascii')]);
}
}
4. Anti-Patterns & Critical Mistakes
-
Dynamic Memory Allocation in the Hot Path
- Impact: Garbage collection pauses (GC stalls) cause execution latencies to spike from microseconds to hundreds of milliseconds, triggering slippage or rejected limit orders.
- Remediation: Pre-allocate object pools, fix ring buffer sizes, and use off-heap memory.
-
Incorrect Gap Fill Processing (
SequenceReset-GapFill)- Impact: Exchange disconnects the session or rejects subsequent valid orders due to unsynchronized sequence numbers.
- Remediation: Ensure admin messages (Logon, Heartbeat, TestRequest) are skipped using
GapFillFlag=Ywhile incrementingNewSeqNo(Tag 36) appropriately.
-
Synchronous Disk I/O on Session Persistence
- Impact: Blocking file appends stall the event loop thread during market volatility bursts.
- Remediation: Perform async I/O or flush memory-mapped files off the critical path using dedicated background writer threads.
-
Ignoring Sub-Millisecond Timestamp Precision
- Impact: Regulatory non-compliance under MiFID II (RTS 25) requiring clock synchronization accuracy within 100 microseconds for high-frequency trading.
- Remediation: Format
SendingTime(Tag 52) andTransactTime(Tag 60) with microsecond (YYYYMMDD-HH:MM:SS.uuuuuu) or nanosecond resolution against PTP (Precision Time Protocol / IEEE 1588) synchronized clocks.
5. Verification & Testing Playbook
- Mock Acceptor Integration: Connect Initiator against QuickFIX Acceptor harness or TT/FIX Simulator.
- Sequence Number Gap Injection Test: Force gap by sending
MsgSeqNum = N + 5and verify incomingResendRequestgeneration and properSequenceResethandling. - Latency Profiling: Measure end-to-end wire-to-cancel throughput using
perfand low-overhead tick counters (RDTSC).