diff --git a/docs/B3-ENTRYPOINT-COMPLIANCE.md b/docs/B3-ENTRYPOINT-COMPLIANCE.md
index 02a1396..658b013 100644
--- a/docs/B3-ENTRYPOINT-COMPLIANCE.md
+++ b/docs/B3-ENTRYPOINT-COMPLIANCE.md
@@ -173,7 +173,7 @@ contract supervision is a post-trade analytics concern.
| GAP-27 | 15.4 | Self-Trading Prevention (STPC) | missing | medium (in-scope per ADR 0012) | covered by [#14](https://github.com/pedrosakuma/B3MatchingPlatform/issues/14) |
| GAP-28 | 15.5 | Market Protections (price collars / fat-finger / max value) | partial | medium (in-scope per ADR 0012) | Engine-side static per-instrument price bands, auction-phase TOP collars, per-instrument max order quantity, and per-instrument max order value are implemented with existing ER reject reasons. The gateway dynamic last-trade-relative `priceBandPercent` remains as an outer decode-time guardrail. Outstanding: EntryPoint `protectionPrice` semantics for market orders are deferred. Tracked by [#500](https://github.com/pedrosakuma/B3MatchingPlatform/issues/500). |
| GAP-29 | 15.1 | User-Defined Spreads (UDS) — synthetic multi-leg instruments | missing | low (boundary case; borderline between exchange-side and broker-side) | — |
-| GAP-30 | 16.6 | Sweep & Cross | partial | low (in-scope per ADR 0012) | Matching semantics for `CrossType=AgainstBook` are implemented (#218), and sweep-phase UMDF `Trade_53.trdSubType` now emits `SWEEP_TRADE` (109). Remaining wire refinements: residual-cancel `ExecRestatementReason=210` is intentionally out of scope while residuals rest, and EntryPoint ER `crossType` / `crossPrioritization` echo remains pending. |
+| GAP-30 | 16.6 | Sweep & Cross | partial | low (in-scope per ADR 0012) | Matching semantics for `CrossType=AgainstBook` are implemented (#218), sweep-phase UMDF `Trade_53.trdSubType` emits `SWEEP_TRADE` (109), and EntryPoint `ExecutionReport_New` / `ExecutionReport_Trade` now echo `crossType` + `crossPrioritization` for cross-generated ERs (#529). Remaining wire refinement: residual-cancel `ExecRestatementReason=210` is intentionally out of scope while residuals rest. |
| GAP-31 | 7.1.19 / UMDF v2.2.0 `SecurityDefinition_12` | `SecurityDefinition_12` does not emit option fields (`strikePrice`, `putOrCall`, `exerciseStyle`, `contractMultiplier`, `noUnderlyings`, `optPayoutType`, `maturityMonthYear`). | missing | high | tracked via [RFC 0002](rfc/0002-equity-options-support.md) issue OPT-02 |
| GAP-32 | 8.3 / lifecycle | Expiring option series are not automatically moved to `Close` based on `ExpirationDate`. | missing | medium | tracked via [RFC 0002](rfc/0002-equity-options-support.md) issue OPT-03 |
diff --git a/src/B3.Exchange.Core/ChannelDispatcher.Loop.cs b/src/B3.Exchange.Core/ChannelDispatcher.Loop.cs
index 3654d62..9c7213a 100644
--- a/src/B3.Exchange.Core/ChannelDispatcher.Loop.cs
+++ b/src/B3.Exchange.Core/ChannelDispatcher.Loop.cs
@@ -378,11 +378,11 @@ internal void ProcessOne(in WorkItem item)
_metrics?.IncOrdersIn();
_currentClOrdId = prioClOrd;
BeginAggressor(prioLeg.Quantity);
- _engine.Submit(prioLeg);
+ _engine.SubmitCrossLeg(prioLeg, cross.CrossType, cross.CrossPrioritization);
_metrics?.IncOrdersIn();
_currentClOrdId = otherClOrd;
BeginAggressor(otherLeg.Quantity);
- _engine.Submit(otherLeg);
+ _engine.SubmitCrossLeg(otherLeg, cross.CrossType, cross.CrossPrioritization);
break;
}
@@ -407,7 +407,7 @@ internal void ProcessOne(in WorkItem item)
try
{
BeginAggressor(sweepLeg.Quantity);
- _engine.SubmitCrossSweep(sweepLeg);
+ _engine.SubmitCrossSweep(sweepLeg, cross.CrossType, cross.CrossPrioritization);
swept = _crossSweepFilledQty.GetValueOrDefault();
}
finally
@@ -425,7 +425,7 @@ internal void ProcessOne(in WorkItem item)
_metrics?.IncOrdersIn();
_currentClOrdId = prioClOrd;
BeginAggressor(residual);
- _engine.Submit(prioLeg with { Quantity = residual });
+ _engine.SubmitCrossLeg(prioLeg with { Quantity = residual }, cross.CrossType, cross.CrossPrioritization);
}
// Phase 3: the other leg at full OrderQty —
@@ -435,7 +435,7 @@ internal void ProcessOne(in WorkItem item)
_metrics?.IncOrdersIn();
_currentClOrdId = otherClOrd;
BeginAggressor(otherLeg.Quantity);
- _engine.Submit(otherLeg);
+ _engine.SubmitCrossLeg(otherLeg, cross.CrossType, cross.CrossPrioritization);
}
else
{
@@ -446,11 +446,11 @@ internal void ProcessOne(in WorkItem item)
_metrics?.IncOrdersIn();
_currentClOrdId = prioClOrd;
BeginAggressor(prioLeg.Quantity);
- _engine.Submit(prioLeg);
+ _engine.SubmitCrossLeg(prioLeg, cross.CrossType, cross.CrossPrioritization);
_metrics?.IncOrdersIn();
_currentClOrdId = otherClOrd;
BeginAggressor(otherLeg.Quantity);
- _engine.Submit(otherLeg);
+ _engine.SubmitCrossLeg(otherLeg, cross.CrossType, cross.CrossPrioritization);
}
break;
}
diff --git a/src/B3.Exchange.Gateway/ExecutionReportEncoder.cs b/src/B3.Exchange.Gateway/ExecutionReportEncoder.cs
index 6b2f3e1..4824a4d 100644
--- a/src/B3.Exchange.Gateway/ExecutionReportEncoder.cs
+++ b/src/B3.Exchange.Gateway/ExecutionReportEncoder.cs
@@ -129,6 +129,11 @@ private static int WriteMemoTrailer(Span dst, int blockLength, ReadOnlySpa
_ => 0,
};
+ private static byte EncodeCrossType(Matching.CrossType? value) => value.HasValue ? (byte)value.Value : (byte)255;
+
+ private static byte EncodeCrossPrioritization(Matching.CrossPrioritization? value)
+ => value.HasValue ? (byte)value.Value : (byte)255;
+
private static void WriteBusinessHeader(Span body, uint sessionId, uint msgSeqNum, ulong sendingTimeNanos)
{
// OutboundBusinessHeader (sequential, Pack=1):
@@ -145,7 +150,8 @@ public static int EncodeExecReportNew(Span dst,
uint sessionId, uint msgSeqNum, ulong sendingTimeNanos,
Matching.Side side, ulong clOrdIdValue, long secondaryOrderId, long securityId, long orderId,
ulong execId, ulong transactTimeNanos, Matching.OrderType ordType, Matching.TimeInForce tif,
- long orderQty, long? priceMantissa, ReadOnlySpan memo = default, ulong receivedTimeNanos = UTCTimestampNullValue)
+ long orderQty, long? priceMantissa, ReadOnlySpan memo = default, ulong receivedTimeNanos = UTCTimestampNullValue,
+ Matching.CrossType? crossType = null, Matching.CrossPrioritization? crossPrioritization = null)
{
int total = TotalSize(ExecReportNewBlock, memo.Length);
if (dst.Length < total) throw new ArgumentException("buffer too small for ER_New", nameof(dst));
@@ -175,8 +181,8 @@ public static int EncodeExecReportNew(Span dst,
// V3 trailing fields: receivedTime + non-zero null sentinels.
MemoryMarshal.Write(body.Slice(144, 8), in receivedTimeNanos); // ReceivedTime (tag 35544)
// ordTagID@155 null=0 already, investorID@156 null=zeros already, strategyID@168 null=0 already.
- body[162] = 255; // CrossType null
- body[163] = 255; // CrossPrioritization null
+ body[162] = EncodeCrossType(crossType); // CrossType
+ body[163] = EncodeCrossPrioritization(crossPrioritization); // CrossPrioritization
body[164] = 255; // MmProtectionReset null
// V6 trailing field: tradingSubAccount@172 (uint, null=0) — covered
// by body.Clear() above. strategyID@168 (int, null=0) ditto.
@@ -374,7 +380,8 @@ public static int EncodeExecReportTrade(Span dst,
Matching.Side side, ulong clOrdIdValue, long secondaryOrderId,
long securityId, long orderId, long lastQty, long lastPxMantissa,
ulong execId, ulong transactTimeNanos, long leavesQty, long cumQty,
- bool aggressor, uint tradeId, uint contraBroker, ushort tradeDate, long orderQty, ReadOnlySpan memo = default)
+ bool aggressor, uint tradeId, uint contraBroker, ushort tradeDate, long orderQty, ReadOnlySpan memo = default,
+ Matching.CrossType? crossType = null, Matching.CrossPrioritization? crossPrioritization = null)
{
int total = TotalSize(ExecReportTradeBlock, memo.Length);
if (dst.Length < total) throw new ArgumentException("buffer too small for ER_Trade", nameof(dst));
@@ -408,8 +415,8 @@ public static int EncodeExecReportTrade(Span dst,
body[154] = 255; // TradingSessionID null
body[155] = 255; // TradingSessionSubID null
body[156] = 255; // SecurityTradingStatus null
- body[157] = 255; // CrossType null
- body[158] = 255; // CrossPrioritization null
+ body[157] = EncodeCrossType(crossType); // CrossType
+ body[158] = EncodeCrossPrioritization(crossPrioritization); // CrossPrioritization
// strategyID@160 (int, null=0), impliedEventID@164 (6 bytes; eventID
// and noRelatedTrades both null=0) and tradingSubAccount@170 (uint,
// null=0) are covered by body.Clear() above.
diff --git a/src/B3.Exchange.Gateway/FixpOutboundEncoder.cs b/src/B3.Exchange.Gateway/FixpOutboundEncoder.cs
index 403126e..dcd49fa 100644
--- a/src/B3.Exchange.Gateway/FixpOutboundEncoder.cs
+++ b/src/B3.Exchange.Gateway/FixpOutboundEncoder.cs
@@ -84,7 +84,7 @@ public bool WriteExecutionReportNew(in OrderAcceptedEvent e, ulong receivedTimeN
(ulong)e.RptSeq, e.InsertTimestampNanos,
OrderType.Limit, TimeInForce.Day,
e.RemainingQuantity, e.PriceMantissa,
- memo.Span, receivedTimeNanos);
+ memo.Span, receivedTimeNanos, e.CrossType, e.CrossPrioritization);
return AppendAndEnqueueLocked(exact, durability);
}
}
@@ -112,7 +112,7 @@ public bool WriteExecutionReportTrade(in TradeEvent e, bool isAggressor, long ow
isAggressor, e.TradeId,
isAggressor ? e.RestingFirm : e.AggressorFirm,
tradeDate: 0,
- orderQty: leavesQty + cumQty, memo.Span);
+ orderQty: leavesQty + cumQty, memo.Span, e.CrossType, e.CrossPrioritization);
return AppendAndEnqueueLocked(exact, durability);
}
}
diff --git a/src/B3.Exchange.Matching/Events.cs b/src/B3.Exchange.Matching/Events.cs
index 500188b..e80444f 100644
--- a/src/B3.Exchange.Matching/Events.cs
+++ b/src/B3.Exchange.Matching/Events.cs
@@ -20,7 +20,9 @@ public readonly record struct OrderAcceptedEvent(
uint EnteringFirm,
ulong InsertTimestampNanos,
uint RptSeq,
- byte[]? Memo = null);
+ byte[]? Memo = null,
+ CrossType? CrossType = null,
+ CrossPrioritization? CrossPrioritization = null);
///
/// Fired when a resting order's remaining quantity is reduced as a passive maker
@@ -89,7 +91,9 @@ public readonly record struct TradeEvent(
ulong TransactTimeNanos,
uint RptSeq,
byte[]? AggressorMemo = null,
- byte[]? RestingMemo = null);
+ byte[]? RestingMemo = null,
+ CrossType? CrossType = null,
+ CrossPrioritization? CrossPrioritization = null);
public readonly record struct RejectEvent(
string ClOrdId,
diff --git a/src/B3.Exchange.Matching/MatchingEngine.cs b/src/B3.Exchange.Matching/MatchingEngine.cs
index 20d59a7..48f4228 100644
--- a/src/B3.Exchange.Matching/MatchingEngine.cs
+++ b/src/B3.Exchange.Matching/MatchingEngine.cs
@@ -777,7 +777,14 @@ private void FinalizeUncrossSide(LimitOrderBook book, RestingOrder o, long lastT
///
public void SubmitCrossSweep(NewOrderCommand cmd) => SubmitImpl(cmd, emitUnmatchedIocClose: false);
- private void SubmitImpl(NewOrderCommand cmd, bool emitUnmatchedIocClose)
+ public void SubmitCrossSweep(NewOrderCommand cmd, CrossType crossType, CrossPrioritization crossPrioritization)
+ => SubmitImpl(cmd, emitUnmatchedIocClose: false, crossType, crossPrioritization);
+
+ public void SubmitCrossLeg(NewOrderCommand cmd, CrossType crossType, CrossPrioritization crossPrioritization)
+ => SubmitImpl(cmd, emitUnmatchedIocClose: true, crossType, crossPrioritization);
+
+ private void SubmitImpl(NewOrderCommand cmd, bool emitUnmatchedIocClose,
+ CrossType? crossType = null, CrossPrioritization? crossPrioritization = null)
{
_currentMemo = cmd.Memo;
EnterDispatch();
@@ -985,10 +992,10 @@ private void SubmitImpl(NewOrderCommand cmd, bool emitUnmatchedIocClose)
// rest cmd directly with cmd.PriceMantissa.
if (phase == TradingPhase.Reserved || phase == TradingPhase.FinalClosingCall)
{
- RestForAuction(cmd, rules, book);
+ RestForAuction(cmd, rules, book, crossType, crossPrioritization);
return;
}
- ExecuteAggressor(cmd, rules, book, emitUnmatchedIocClose);
+ ExecuteAggressor(cmd, rules, book, emitUnmatchedIocClose, crossType, crossPrioritization);
}
finally { ExitDispatch(); }
}
@@ -1574,8 +1581,9 @@ public void Replace(ReplaceOrderCommand cmd)
}
private void ExecuteAggressor(NewOrderCommand cmd, InstrumentTradingRules rules, LimitOrderBook book,
- bool emitUnmatchedIocClose)
- => ExecuteAggressorWithOrderId(cmd, rules, book, _nextOrderId++, emitUnmatchedIocClose);
+ bool emitUnmatchedIocClose, CrossType? crossType = null, CrossPrioritization? crossPrioritization = null)
+ => ExecuteAggressorWithOrderId(cmd, rules, book, _nextOrderId++, emitUnmatchedIocClose,
+ crossType, crossPrioritization);
///
/// Issue #228 (Onda M · M1): rest the order on the book without any
@@ -1588,7 +1596,8 @@ private void ExecuteAggressor(NewOrderCommand cmd, InstrumentTradingRules rules,
/// () is honored so the visible
/// slice on the book matches the continuous-Open semantics from #211.
///
- private void RestForAuction(NewOrderCommand cmd, InstrumentTradingRules rules, LimitOrderBook book)
+ private void RestForAuction(NewOrderCommand cmd, InstrumentTradingRules rules, LimitOrderBook book,
+ CrossType? crossType = null, CrossPrioritization? crossPrioritization = null)
{
long visible = cmd.Quantity;
long hidden = 0;
@@ -1624,7 +1633,9 @@ private void RestForAuction(NewOrderCommand cmd, InstrumentTradingRules rules, L
RemainingQuantity: resting.RemainingQuantity,
EnteringFirm: resting.EnteringFirm,
InsertTimestampNanos: resting.InsertTimestampNanos,
- RptSeq: NextRptSeq()));
+ RptSeq: NextRptSeq(),
+ CrossType: crossType,
+ CrossPrioritization: crossPrioritization));
RecomputeAuctionTopIfApplicable(book.SecurityId, cmd.EnteredAtNanos);
}
@@ -1813,7 +1824,8 @@ private static bool IsMarketLike(OrderType t)
=> t == OrderType.Market || t == OrderType.MarketWithLeftover;
private void ExecuteAggressorWithOrderId(NewOrderCommand cmd, InstrumentTradingRules rules,
- LimitOrderBook book, long aggressorOrderIdForTrades, bool emitUnmatchedIocClose)
+ LimitOrderBook book, long aggressorOrderIdForTrades, bool emitUnmatchedIocClose,
+ CrossType? crossType = null, CrossPrioritization? crossPrioritization = null)
{
long aggressorRemaining = cmd.Quantity;
bool isMarket = IsMarketLike(cmd.Type);
@@ -1883,7 +1895,9 @@ private void ExecuteAggressorWithOrderId(NewOrderCommand cmd, InstrumentTradingR
TransactTimeNanos: cmd.EnteredAtNanos,
RptSeq: NextRptSeq(),
AggressorMemo: cmd.Memo,
- RestingMemo: maker.Memo));
+ RestingMemo: maker.Memo,
+ CrossType: crossType,
+ CrossPrioritization: crossPrioritization));
aggressorRemaining -= tradeQty;
maker.RemainingQuantity -= tradeQty;
@@ -2083,7 +2097,9 @@ private void ExecuteAggressorWithOrderId(NewOrderCommand cmd, InstrumentTradingR
EnteringFirm: resting.EnteringFirm,
InsertTimestampNanos: resting.InsertTimestampNanos,
RptSeq: NextRptSeq(),
- Memo: resting.Memo));
+ Memo: resting.Memo,
+ CrossType: crossType,
+ CrossPrioritization: crossPrioritization));
}
finally
{
diff --git a/tests/B3.Exchange.Core.Tests/CrossOrderSemanticsTests.cs b/tests/B3.Exchange.Core.Tests/CrossOrderSemanticsTests.cs
index e6b2c3f..dcd6729 100644
--- a/tests/B3.Exchange.Core.Tests/CrossOrderSemanticsTests.cs
+++ b/tests/B3.Exchange.Core.Tests/CrossOrderSemanticsTests.cs
@@ -400,6 +400,59 @@ public void AgainstBook_MaxSweepQtyZero_StillBehavesLikeAon()
Assert.Equal(100, s.Trades[0].Quantity);
}
+ [Fact]
+ public void AgainstBook_ExecutionReportsEchoSubmittedCrossAttributes()
+ {
+ var (disp, _, outbound) = NewDispatcher();
+ var external = new FakeSession(outbound);
+ var crosser = new FakeSession(outbound);
+
+ disp.EnqueueNewOrder(
+ new NewOrderCommand("EXT", Petr, Side.Sell, OrderType.Limit, TimeInForce.Day, Px(9.99m), 100, external.EnteringFirm, 1_000UL),
+ external.Id, external.EnteringFirm, clOrdIdValue: 1UL);
+ DrainInbound(disp);
+
+ Assert.Single(external.News);
+ Assert.Null(external.News[0].CrossType);
+ Assert.Null(external.News[0].CrossPrioritization);
+
+ var cross = new CrossOrderCommand(Buy(200, 10m, 10UL), Sell(200, 10m, 11UL), 10UL, 11UL, 999UL)
+ {
+ CrossType = CrossType.AgainstBook,
+ CrossPrioritization = CrossPrioritization.BuyPrioritized,
+ MaxSweepQty = 100,
+ };
+ disp.EnqueueCross(cross, crosser.Id, crosser.EnteringFirm);
+ DrainInbound(disp);
+
+ Assert.NotEmpty(crosser.News);
+ Assert.All(crosser.News, e =>
+ {
+ Assert.Equal(CrossType.AgainstBook, e.CrossType);
+ Assert.Equal(CrossPrioritization.BuyPrioritized, e.CrossPrioritization);
+ });
+ Assert.NotEmpty(crosser.Trades);
+ Assert.All(crosser.Trades, e =>
+ {
+ Assert.Equal(CrossType.AgainstBook, e.CrossType);
+ Assert.Equal(CrossPrioritization.BuyPrioritized, e.CrossPrioritization);
+ });
+ }
+
+ [Fact]
+ public void LimitOrder_ExecutionReportNewLeavesCrossAttributesNull()
+ {
+ var (disp, _, outbound) = NewDispatcher();
+ var session = new FakeSession(outbound);
+
+ disp.EnqueueNewOrder(Buy(100, 10m, 1UL), session.Id, session.EnteringFirm, clOrdIdValue: 1UL);
+ DrainInbound(disp);
+
+ Assert.Single(session.News);
+ Assert.Null(session.News[0].CrossType);
+ Assert.Null(session.News[0].CrossPrioritization);
+ }
+
[Fact]
public void MaxOpenOrdersPerFirm_CrossAtCapMinusOneIsRejectedForWorstCaseResidual()
{
diff --git a/tests/B3.Exchange.Gateway.Tests/ExecutionReportEncoderTests.cs b/tests/B3.Exchange.Gateway.Tests/ExecutionReportEncoderTests.cs
index e3dd3cb..5bd8f0b 100644
--- a/tests/B3.Exchange.Gateway.Tests/ExecutionReportEncoderTests.cs
+++ b/tests/B3.Exchange.Gateway.Tests/ExecutionReportEncoderTests.cs
@@ -45,8 +45,27 @@ public void EncodeNew_WritesHeaderAndCoreFields()
Assert.Equal(10L, MemoryMarshal.Read(body.Slice(96, 8))); // OrderQty
Assert.Equal(12_3450L, MemoryMarshal.Read(body.Slice(104, 8))); // Price
Assert.Equal(long.MinValue, MemoryMarshal.Read(body.Slice(112, 8))); // StopPx null
+ Assert.Equal((byte)255, body[162]); // CrossType null
+ Assert.Equal((byte)255, body[163]); // CrossPrioritization null
}
+ [Fact]
+ public void EncodeNew_CrossEchoesCrossTypeAndPrioritization()
+ {
+ var buf = new byte[ExecutionReportEncoder.ExecReportNewTotal];
+
+ ExecutionReportEncoder.EncodeExecReportNew(buf,
+ sessionId: 42, msgSeqNum: 1, sendingTimeNanos: 1_000_000_000UL,
+ side: Side.Buy, clOrdIdValue: 99, secondaryOrderId: 555,
+ securityId: 1122, orderId: 7777, execId: 100UL, transactTimeNanos: 1_000_000_001UL,
+ ordType: OrderType.Limit, tif: TimeInForce.Day,
+ orderQty: 10, priceMantissa: 12_3450L,
+ crossType: CrossType.AgainstBook, crossPrioritization: CrossPrioritization.BuyPrioritized);
+
+ var body = buf.AsSpan(EntryPointFrameReader.WireHeaderSize);
+ Assert.Equal((byte)CrossType.AgainstBook, body[162]);
+ Assert.Equal((byte)CrossPrioritization.BuyPrioritized, body[163]);
+ }
[Fact]
public void EncodeNew_WritesMemoVarData()
@@ -96,6 +115,29 @@ public void EncodeTrade_WritesCoreFields()
Assert.Equal((ushort)19000, MemoryMarshal.Read(body.Slice(116, 2))); // TradeDate
Assert.Equal((ushort)65535, MemoryMarshal.Read(body.Slice(144, 2))); // CrossedIndicator null
Assert.Equal(5L, MemoryMarshal.Read(body.Slice(146, 8))); // OrderQty
+ Assert.Equal((byte)255, body[157]); // CrossType null
+ Assert.Equal((byte)255, body[158]); // CrossPrioritization null
+ }
+
+ [Fact]
+ public void EncodeTrade_CrossEchoesCrossTypeAndPrioritization()
+ {
+ var buf = new byte[ExecutionReportEncoder.ExecReportTradeTotal];
+
+ ExecutionReportEncoder.EncodeExecReportTrade(buf,
+ sessionId: 1, msgSeqNum: 2, sendingTimeNanos: 0UL,
+ side: Side.Sell, clOrdIdValue: 77, secondaryOrderId: 0,
+ securityId: 999, orderId: 1234,
+ lastQty: 5, lastPxMantissa: 50_0000L,
+ execId: 10UL, transactTimeNanos: 0UL,
+ leavesQty: 0, cumQty: 5,
+ aggressor: true, tradeId: 4242, contraBroker: 8,
+ tradeDate: 19000, orderQty: 5,
+ crossType: CrossType.AgainstBook, crossPrioritization: CrossPrioritization.SellPrioritized);
+
+ var body = buf.AsSpan(EntryPointFrameReader.WireHeaderSize);
+ Assert.Equal((byte)CrossType.AgainstBook, body[157]);
+ Assert.Equal((byte)CrossPrioritization.SellPrioritized, body[158]);
}
[Fact]