Skip to main content

fix-antenna-net-core

This skill should be used when the user asks to "create a FIX session", "build a FIX acceptor", "build a FIX initiator", "send a NewOrderSingle", "handle ExecutionReport", "set up drop copy", "configure fixengine.properties", "implement FIX session recovery", "add a FIX repeating group", or mentions Epam.FixAntenna.NetCore, IFixSession, IFixSessionListener, IFixMessageListener, FixServer, FixMessage, SessionParametersBuilder, ForceSeqNumReset, or FIXT 1.1 in a .NET / C# context. Skip for QuickFIX/n or other FIX libraries — APIs differ.

Zur Installation springen

Quellinformationen

Repository
epam/fix-antenna-net-core
Letzte Quellaktivität
23. Juni 2026 um 15:59
Erkannte Sprache von SKILL.md
Englisch
Sterne
49
Forks
19

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
18 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
FIX Antenna .NET Core
description
This skill should be used when the user asks to "create a FIX session", "build a FIX acceptor", "build a FIX initiator", "send a NewOrderSingle", "handle ExecutionReport", "set up drop copy", "configure fixengine.properties", "implement FIX session recovery", "add a FIX repeating group", or mentions Epam.FixAntenna.NetCore, IFixSession, IFixSessionListener, IFixMessageListener, FixServer, FixMessage, SessionParametersBuilder, ForceSeqNumReset, or FIXT 1.1 in a .NET / C# context. Skip for QuickFIX/n or other FIX libraries — APIs differ.
version
0.2.0
# FIX Antenna .NET Core Guidance for coding agents working in projects that depend on **`Epam.FixAntenna.NetCore`**. This skill is verified against version **1.2.3**. ## What FIX Antenna .NET Core is A high-performance FIX protocol engine for .NET Standard 2.0+, maintained by EPAM / B2Bits, open-sourced under Apache 2.0. It implements **FIX 4.0 – 5.0** and **FIXT 1.1** session and application layers. - Repository: `https://github.com/epam/fix-antenna-net-core` - NuGet: `Epam.FixAntenna.NetCore` - Official docs: <https://github.com/epam/fix-antenna-net-core/tree/main/Docs> — indexed and cross-mapped in `references/official-docs.md`. **Consult the bundled `references/` first; fetch upstream pages only when the topic isn't covered there** (see "When in doubt"). ### What it is NOT - **Not QuickFIX/n.** APIs differ. Do not translate QuickFIX/n samples and rename types — the session model, message construction, and config keys are different. - **Not a broker connectivity SDK.** It speaks FIX. It does not normalize venue quirks or ship pre-built drop-in connectors per venue. - **Not an OMS or EMS.** It gives session, message, persistence, recovery. Order state machine and business logic are out of scope. ## Mental model Four concepts. Master these or every generation will be wrong. ``` Configuration ──► Session ──► IFixSessionListener (one class, two callbacks) (file/code) │ ├─ OnSessionStateChange(SessionState) │ └─ OnNewMessage(FixMessage) ← inherited from IFixMessageListener │ └────► Storage (durable seq + log, engine-managed) ``` | Concept | Type(s) | Role | |---|---|---| | **Configuration** | `Config`, `SessionParameters`, `fixengine.properties` | Where session params, storage, TLS live. Prefer file-based for production. | | **Server / acceptor host** | `FixServer`, `IFixServerListener` | Listens for inbound connections. Per-session `NewFixSession(IFixSession)` callback decides accept/reject. | | **Session** | `IFixSession` | One FIX session. Owns sequence numbers, heartbeats, logon/logout, resend. | | **Session listener** | `IFixSessionListener : IFixMessageListener` | **Implements BOTH** `OnSessionStateChange(SessionState)` (declared on `IFixSessionListener`) AND `OnNewMessage(FixMessage)` (inherited from `IFixMessageListener`). Register via `session.SetFixSessionListener(...)`. Receives **application messages only** — admin messages (35=A,0,1,2,3,4,5) never reach it. | | **Admin-message observers** (optional) | `IFixMessageListener` | Session-level (admin) messages are consumed by the engine and NOT passed to the main listener. To observe inbound admin traffic (log Logons, watch 35=3 rejects, recovery flows), register via `session.AddInSessionLevelMessageListener(...)`. | | **Message** | `FixMessage : ITagList` | Add tags with `AddTag(int, value)`, read with `GetTagValueAsString(int)` etc. | | **Tags (constants)** | `Epam.FixAntenna.Constants.Fix44.Tags` | Static class of tag-number `const int` fields per FIX version. | > ⚠️ **Inheritance trap.** `IFixSessionListener` *extends* `IFixMessageListener`. The compiler will demand that any class implementing `IFixSessionListener` provide BOTH methods (`OnSessionStateChange` and `OnNewMessage`). Implement both on the same class. This is true in 1.2.3 and in 2.x master — same shape, different declaration site. ## Hard rules — DO and DON'T These are non-negotiable for production-quality code. Agents repeatedly violate these; this section exists to stop that. ### DO 1. **Use the dictionary.** Validate every inbound message against the FIX dictionary. Reject malformed messages at session layer; do not attempt business processing on a structurally invalid message. 2. **Treat FIX as binary-typed, not text.** Read with `FixMessage.GetTagValueAsLong(Fix44.Tags.OrderQty)`, not `int.Parse(message.ToString().Split('|')...)`. 3. **Separate session handling from business logic.** `OnNewMessage` should dispatch to a business handler that does NOT know about FIX wire format. The listener is a boundary. 4. **Use a persistent storage factory in production.** Set `storageFactory = Epam.FixAntenna.NetCore.FixEngine.Storage.FilesystemStorageFactory` (default, durable) or `MmfStorageFactory` (memory-mapped, higher throughput). Never `InMemoryStorageFactory` for a live session — it's for tests. Persistent storage is what makes gap fill / resend / restart recovery work. 5. **Acknowledge state transitions explicitly.** `OnSessionStateChange` will be called many times per session lifecycle (`WaitingForLogon` → `LogonReceived` → `Connected` → `Disconnected` → `Reconnecting`, etc.). Branch via `SessionState.IsDisconnected(state)`, not on string compares. 6. **Dispose sessions.** Always `session.Dispose()` after disconnect. 7. **Know the difference between `AddTag` and `Set`.** `AddTag(tag, value)` *appends* a new occurrence — calling it twice for the same tag on the same message yields a malformed (duplicate-tag) outbound. `Set(tag, value)` (inherited from `ExtendedIndexedStorage`, available on every `FixMessage`) *updates the tag in place and adds it if absent* — every `Set` overload delegates to `UpdateValue(..., IndexedStorage.MissingTagHandling.AddIfNotExists)`, so `Set` is already the "replace if present, add if missing" call. Reach for `UpdateValue(tag, value, IndexedStorage.MissingTagHandling.DontAddIfNotExists)` only when you want the opposite — update *only* if the tag already exists, otherwise leave the message untouched (the call returns `-1`). (The enum is nested in `IndexedStorage` — fully-qualify it, or `using static Epam.FixAntenna.NetCore.Message.IndexedStorage;`.) Use `AddTag` for fresh outbound construction; use `Set` when mutating an existing message (e.g., echoing an inbound back with one field changed). 8. **Engine fills the header and trailer.** BeginString (8), BodyLength (9), MsgSeqNum (34), MsgType (35), SenderCompID (49), SendingTime (52), TargetCompID (56), CheckSum (10) are engine-managed. ### DON'T 1. **Don't hardcode sequence numbers.** Never write `session.OutSeqNum = 1` on every start, never use `SetSequenceNumbers(...)` from app code unless explicitly implementing manual recovery tooling. The engine and persistent storage manage this; touching it breaks recovery and triggers session-level rejects. 2. **Don't ignore Resend Requests.** If a counterparty asks for messages N–M, the engine handles replay automatically *if* persistent storage is configured. Don't write custom resend logic. 3. **Don't parse FIX wire format with `Split('|')` or `Split('')`.** Use `FixMessage`'s tag-typed accessors. 4. **Don't treat ExecutionReport as fire-and-forget.** `ExecType` (150) and `OrdStatus` (39) define a state machine. 5. **Don't swallow session-level rejects (msg type 3).** Means the previous outbound was malformed. Log loudly. 6. **Don't bypass admin messages.** Logon (A), Logout (5), Heartbeat (0), TestRequest (1), ResendRequest (2), SequenceReset (4), Reject (3) are handled by the engine. Don't construct them from app code. 7. **Don't catch and continue on listener exceptions silently.** Log loudly, then either rethrow or disconnect. 8. **Don't invent enum values.** `ForceSeqNumReset` has exactly three values: `Always`, `OneTime`, `Never`. There is no `OnLogon`. 9. **Don't reference `SessionState.LoggedOn`.** It does not exist in 1.2.3. The fully-logged-on state is `SessionState.Connected` (verify with `SessionState.IsConnected(state)`). ## API surface The full verified API surface lives in `references/api-reference.md`: namespaces, session construction (acceptor/initiator/listener), `FixMessage` read/write, `SessionState` and `ForceSeqNumReset` enums, useful `SessionParameters` properties, the "Other IFixSession methods worth knowing" table, and repeating-group iteration. Load that reference before generating non-trivial FIX Antenna code. The signatures there were verified by reflection against 1.2.3. ### Critical pitfalls captured in `references/api-reference.md` - **Single-arg `SendMessage(content)` is NOT interchangeable with two-arg `SendMessage(msgType, content)`** on a raw `new FixMessage()`. With no MsgType (35) it throws `ArgumentException: Message type(35 tag) cannot be null` at serialization; with 35 set but no header it serializes without 8/9/34/49/52/56 (header updates use `DontAddIfNotExists`) and crashes at the storage layer with `"Tag 34 is missing or has invalid value"`. Use the two-arg overload for fresh construction, or `PrepareMessage(...)`. - **`IFixSession.Connect()` is polymorphic by role**: opens TCP + sends Logon on an initiator; *accepts* a pending inbound on an acceptor (inside `IFixServerListener.NewFixSession`). - **`IFixSessionListener` inherits `IFixMessageListener`** — implement BOTH `OnSessionStateChange` and `OnNewMessage` on the same class. - **`SessionState.LoggedOn` does not exist.** Use `SessionState.Connected` / `SessionState.IsConnected(state)`. - **`ForceSeqNumReset` values: only `Always`, `OneTime`, `Never`.** No `OnLogon`. - **CompID property casing: `SenderCompId` / `TargetCompId`** (lowercase `d`) — the properties-file key, in contrast, is `senderCompID` / `targetCompID` (uppercase). - **`AddTag` appends; `Set` replaces-or-adds.** Two `AddTag(sameTag, ...)` calls = malformed outbound. `Set(tag, value)` updates in place and adds the tag if absent (every overload delegates to `UpdateValue(..., MissingTagHandling.AddIfNotExists)`), so `Set` *is* the "replace if present, add if missing" call — don't reach for `UpdateValue` just to get that behavior. Use `UpdateValue(tag, value, IndexedStorage.MissingTagHandling.DontAddIfNotExists)` only for update-only-if-present (returns `-1`, no-op when absent). The enum is nested in `IndexedStorage` (namespace `Epam.FixAntenna.NetCore.Message`). - **Repeating groups on a fresh `FixMessage`** require `RawFixUtil.IndexRepeatingGroup(msg, FixVersion.Fix44, "<msgType>")` before `AddRepeatingGroup(leadingTag)`, otherwise it throws "no info about FIX version in message". ### Namespaces (quick) ```csharp using Epam.FixAntenna.NetCore.Configuration; // Config using Epam.FixAntenna.NetCore.FixEngine; // FixServer, IFixSession, IFixSessionListener, // IFixMessageListener, IFixServerListener, // SessionParameters, SessionState, ForceSeqNumReset using Epam.FixAntenna.NetCore.FixEngine.Session.Util; // SessionParametersBuilder using Epam.FixAntenna.NetCore.Message; // FixMessage, ITagList using Epam.FixAntenna.Constants.Fix44; // Tags ← FIX 4.4 tag numbers // Other FIX versions: Epam.FixAntenna.Constants.{Fix40,Fix41,Fix42,Fix43,Fix44,Fix50,Fix50sp1,Fix50sp2,Fixt11,Fixt11ep} ``` ## Configuration: `fixengine.properties` > The keys documented in this section and in `references/12-perf-profiles.md` cover the common cases — use them as-is, no lookup needed. For any other key, do not invent it: the **complete 1.2.3 key index** (every recognized key, default, scope) is bundled in `references/config-keys.md`. The upstream [`Docs/Configuration.md`](https://github.com/epam/fix-antenna-net-core/blob/main/Docs/Configuration.md) is only needed for long-form prose on a key already found in the index. The shipped `Epam.FixAntenna.NetCore` NuGet's `SessionParametersBuilder` reads a specific property-file layout (verified against `epam/fix-antenna-net-core/Samples/ConnectToGateway/fixengine.properties`): - **List sessions** with the key `sessionIDs` (comma-separated). - **Per-session properties** are prefixed `sessions.<id>.<key>`. - **Shared defaults** can live under `sessions.default.<key>`. - The session-type key is **`sessionType`** with values `initiator` | `acceptor` — NOT `connectionType`. ```properties # Process-wide settings (no session prefix) storageFactory = Epam.FixAntenna.NetCore.FixEngine.Storage.FilesystemStorageFactory storageDirectory = ./logs # Autoreconnect is controlled SOLELY by autoreconnectAttempts. # There is NO `enableAutoreconnect` property — agents commonly invent this # (the engine ignores it silently). Values for autoreconnectAttempts: # -1 = no autoreconnect (Config.NoAutoreconnect) # 0 = infinite (Config.InfinityAutoreconnect) # N = N attempts autoreconnectAttempts = 0 autoreconnectDelayInMs = 2000 # Session list sessionIDs = session1 # Defaults shared across all sessions sessions.default.fixVersion = FIX.4.4 # FIX.4.0..FIX.5.0SP2 or FIXT.1.1+appVersion sessions.default.heartbeatInterval = 30 # Per-session sessions.session1.sessionType = initiator # initiator | acceptor sessions.session1.senderCompID = BUYSIDE sessions.session1.targetCompID = VENUE sessions.session1.host = fix.example.com # initiator only sessions.session1.port = 9876 sessions.session1.forceSeqNumReset = Never # Always | OneTime | Never # Optional Logon credentials (tags 553/554) sessions.session1.username = TRADER sessions.session1.password = pass ``` > ⚠️ **Silent failure trap.** The engine accepts unknown property keys with no warning. A typo (`sessions=` instead of `sessionIDs=`, or `connectionType` instead of `sessionType`) yields an empty session list at runtime, not a config error. Use the exact keys above. > ⚠️ For an **acceptor**, `FixServer` reads the process-wide `port` at the top of the properties file (no per-session host/port required since sessions are created dynamically as counterparties connect). Verified in `Samples/EchoServer/fixengine.properties`: > ```properties > # default listening port > port = 4000 > ``` > ⚠️ **CompID mirroring.** A FIX session pair must have inverse CompIDs — each side's `senderCompID` equals the other's `targetCompID`: > ``` > Side A (initiator): senderCompID = BUYSIDE, targetCompID = VENUE > Side B (acceptor): senderCompID = VENUE, targetCompID = BUYSIDE > ``` > If the pairing doesn't mirror, Logon is refused — and the engine doesn't surface this as a config error. It surfaces as a refused connection or a session-level reject (35=3) at runtime. When writing a gateway against a counterparty whose config is fixed (e.g., the engine's shipped `Samples/EchoServer`), copy *their* CompIDs and swap them. > ⚠️ The `Config` class exposes 141 string constants for property keys — see `Config.StorageFactory`, `Config.TradePeriodBegin`, `Config.SslCertificate`, etc. Use these in code for compiler-checked key names. **But not every recognised property key has a `Config.X` constant.** Common per-session keys parsed by literal string in `SessionParameters.cs` — `senderCompID`, `targetCompID`, `host`, `fixVersion`, `appVersion`, `heartbeatInterval`, `username`, `password`, `sessionType` (which lives on `SessionParametersBuilder.SessionTypeProp`, not `Config`) — have **no** corresponding `Config.X` constant in 1.2.3. Reaching for `Config.SenderCompID` or `Config.Username` from code is a compile error. Use the literal string for those, or write a small `Keys` static class in the project. ## Mini-glossary (terms agents confuse) | Term | Meaning | Common mistake | |---|---|---| | **Admin message** | Session-layer: Logon (A), Logout (5), Heartbeat (0), TestRequest (1), ResendRequest (2), SequenceReset (4), Reject (3). | Treating admin messages as app messages. The engine handles them. | | **Application message** | Business-layer: NewOrderSingle (D), ExecutionReport (8), MarketDataRequest (V), etc. | Generating admin messages from app code. | | **Session-level reject** (3) | Peer couldn't parse/validate the outbound message. | Treating as a business reject. Means the local engine sent malformed FIX. | | **Business reject** (j) | Outbound parsed; peer business logic refused it. | Same as above in reverse. | | **Gap fill** | A `SequenceReset (4)` with `GapFillFlag (123) = Y`, used to fill admin-message slots during a resend. | Sending gap fill for app messages — replay them instead. | | **Sequence reset** | A `SequenceReset (4)` with `GapFillFlag = N`. Force-resets the counterparty's expected next seq num. Operational. | Using as a routine recovery tool. | | **Resend Request** (2) | Counterparty asking for retransmission of messages N..M. | Ignoring it. Engine handles it if storage is persistent. |
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen