/// <summary> /// Creates one or more destination orders. /// </summary> /// <param name="destinationOrders"></param> internal static void CreateDestinationOrders(DestinationOrderInfo[] destinationOrders) { // An instance of the shared data model is required to use its methods. DataModel dataModel = new DataModel(); // Business logic: provide the current time and the user identifier for the new destination order. DateTime dateTime = DateTime.UtcNow; Guid userId = TradingSupport.UserId; DataModelTransaction dataModelTransaction = DataModelTransaction.Current; StatusRow statusNewRow = DataModel.Status.StatusKeyStatusCode.Find(Status.New); statusNewRow.AcquireReaderLock(dataModelTransaction); StateRow stateIntialRow = DataModel.State.StateKeyStateCode.Find(State.Initial); stateIntialRow.AcquireReaderLock(dataModelTransaction); // The entire collection of destination orders is added or rejected as a single transaction. foreach (DestinationOrderInfo destinationOrderInfo in destinationOrders) { Guid destinationOrderId = Guid.NewGuid(); dataModel.CreateDestinationOrder( destinationOrderInfo.BlotterId, 0.0M, null, dateTime, userId, destinationOrderInfo.DestinationId, destinationOrderId, null, null, false, false, null, dateTime, userId, destinationOrderInfo.OrderedQuantity, destinationOrderInfo.OrderTypeId, destinationOrderInfo.SecurityId, dateTime, destinationOrderInfo.SettlementId, destinationOrderInfo.SideCodeId, stateIntialRow.StateId, statusNewRow.StatusId, null, destinationOrderInfo.TimeInForceCodeId, dateTime, null, destinationOrderInfo.WorkingOrderId); } }
internal static void Accept(Guid matchId, Int64 rowVersion) { DataModel dataModel = new DataModel(); try { DataModel.DataLock.EnterReadLock(); MatchRow matchRow = DataModel.Match.MatchKey.Find(matchId); if (matchRow != null) { // Time stamps and user stamps Guid createdUserId = TradingSupport.UserId; DateTime createdTime = DateTime.UtcNow; Guid modifiedUserId = createdUserId; DateTime modifiedTime = createdTime; // Call the internal method to complete the operation. dataModel.UpdateMatch(null, null, null, null, null, null, null, new Object[] { matchRow.MatchId }, rowVersion, StatusMap.FromCode(Status.Accepted), null); // This is the working order associated with the match. WorkingOrderRow workingOrderRow = matchRow.WorkingOrderRow; // This will find the contra order. MatchRow contraMatchRow = DataModel.Match.MatchKeyWorkingOrderIdContraOrderId.Find( matchRow.ContraOrderId, matchRow.WorkingOrderId); if (contraMatchRow == null) { throw new Exception(string.Format("Corruption: the match record for {0}, {1} can't be found", matchRow.ContraOrderId, matchRow.WorkingOrderId)); } // When both sides have agreed to the match, the Destination Orders are generated. if (contraMatchRow.StatusId != StatusMap.FromCode(Status.Accepted)) { return; } // At this point, both sides have agreed to a trade. This is the working order of the contra side of the trade. WorkingOrderRow contraOrderRow = contraMatchRow.WorkingOrderRow; // The quantity of this transaction is the lesser of the two sides of the trade. decimal quantity = workingOrderRow.SubmittedQuantity < contraOrderRow.SubmittedQuantity ? workingOrderRow.SubmittedQuantity : contraOrderRow.SubmittedQuantity; PriceRow priceRow = DataModel.Price.PriceKey.Find(workingOrderRow.SecurityId, workingOrderRow.SettlementId); if (priceRow == null) { throw new Exception("The price of this trade can't be determined."); } Guid destinationOrderId = Guid.NewGuid(); dataModel.CreateDestinationOrder( workingOrderRow.BlotterId, null, null, createdTime, createdUserId, Match.destinationId, destinationOrderId, null, null, false, false, workingOrderRow[DataModel.WorkingOrder.LimitPriceColumn], modifiedTime, modifiedUserId, quantity, workingOrderRow.OrderTypeId, workingOrderRow.SecurityId, createdTime, workingOrderRow.SettlementId, workingOrderRow.SideId, StateMap.FromCode(State.Acknowledged), StatusMap.FromCode(Status.New), workingOrderRow[DataModel.WorkingOrder.StopPriceColumn], workingOrderRow.TimeInForceId, createdTime, createdUserId, workingOrderRow.WorkingOrderId); Guid executionId = Guid.NewGuid(); dataModel.CreateExecution( 0.0m, workingOrderRow.BlotterId, null, null, 0.0m, createdTime, createdUserId, destinationOrderId, StateMap.FromCode(State.Acknowledged), executionId, priceRow.LastPrice, quantity, null, null, false, modifiedTime, modifiedUserId, null, null, null, null, StateMap.FromCode(State.Sent), null, null, null, null); dataModel.UpdateMatch(null, null, null, null, null, null, null, new Object[] { matchId }, matchRow.RowVersion, StatusMap.FromCode(Status.Accepted), null); Guid contraDestinationOrderId = Guid.NewGuid(); dataModel.CreateDestinationOrder( contraOrderRow.BlotterId, 0.0m, null, createdTime, createdUserId, Match.destinationId, contraDestinationOrderId, null, null, false, false, contraOrderRow[DataModel.WorkingOrder.LimitPriceColumn], modifiedTime, modifiedUserId, quantity, contraOrderRow.OrderTypeId, contraOrderRow.SecurityId, createdTime, contraOrderRow.SettlementId, contraOrderRow.SideId, StateMap.FromCode(State.Acknowledged), StatusMap.FromCode(Status.New), contraOrderRow[DataModel.WorkingOrder.StopPriceColumn], contraOrderRow.TimeInForceId, createdTime, createdUserId, contraOrderRow.WorkingOrderId); Guid contraExecutionId = Guid.NewGuid(); dataModel.CreateExecution( 0.0m, contraOrderRow.BlotterId, null, null, 0.0m, createdTime, createdUserId, contraDestinationOrderId, StateMap.FromCode(State.Acknowledged), contraExecutionId, priceRow.LastPrice, quantity, null, null, false, modifiedTime, modifiedUserId, null, null, null, null, StateMap.FromCode(State.Sent), 0.0m, 0.0m, 0.0m, 0.0m); } } finally { // Release the tables. DataModel.DataLock.ExitReadLock(); } }
/// <summary>Inserts a Negotiation record using Metadata Parameters.</summary> internal static void Offer(Guid matchId, Decimal quantity) { Guid negotiationId = Guid.Empty; DataModel dataModel = new DataModel(); try { DataModel.DataLock.EnterReadLock(); MatchRow matchRow = DataModel.Match.MatchKey.Find(matchId); if (matchRow != null) { // Rule #1: Insure that there are no pending offers. foreach (NegotiationRow innerNegotiationRow in matchRow.GetNegotiationRows()) { if (innerNegotiationRow.StatusId == StatusMap.FromCode(Status.Pending)) { throw new Exception("There is already an offer pending."); } if (innerNegotiationRow.StatusId == StatusMap.FromCode(Status.Declined)) { throw new Exception("This offer has previously been declined."); } } // Time stamps and user stamps Guid createdUserId = TradingSupport.UserId; DateTime createdTime = DateTime.UtcNow; Guid modifiedUserId = TradingSupport.UserId; DateTime modifiedTime = createdTime; // This will find the contra matching record. MatchRow contraMatchRow = DataModel.Match.MatchKeyWorkingOrderIdContraOrderId.Find( new Object[] { matchRow.ContraOrderId, matchRow.WorkingOrderId }); if (contraMatchRow == null) { throw new Exception( string.Format("Corruption: the match record for {0}, {1} can't be found", matchRow.ContraOrderId, matchRow.WorkingOrderId)); } // This is the order on the other side of the match. WorkingOrderRow contraWorkingOrderRow = contraMatchRow.WorkingOrderRow; // When both sides have agreed to the Negotiation, the Destination Orders are generated. NegotiationRow contraNegotiationRow = null; foreach (NegotiationRow innerNegotiationRow in contraMatchRow.GetNegotiationRows()) { if (innerNegotiationRow.StatusId == StatusMap.FromCode(Status.Pending)) { contraNegotiationRow = innerNegotiationRow; break; } } // This means that there's an offer on the other side. if (contraNegotiationRow == null) { // There is no opposite side of this transaction yet. It will be placed in the negotation table and wait there // until it times out, or the other side accepts the offer. negotiationId = Guid.NewGuid(); dataModel.CreateNegotiation( contraWorkingOrderRow.BlotterId, null, false, contraMatchRow.MatchId, negotiationId, quantity, StatusMap.FromCode(Status.Pending)); } else { // At this point, there is an offer on both sides of the match for a follow-on order. We'll create orders and // executions for both sides of the trade for the minimum agreed upon quantity. WorkingOrderRow workingOrderRow = matchRow.WorkingOrderRow; WorkingOrderRow contraOrderRow = contraNegotiationRow.MatchRow.WorkingOrderRow; // The quantity of this negotiation will be the minimum of the two offers. decimal matchedQuantity = quantity < contraNegotiationRow.Quantity ? quantity : contraNegotiationRow.Quantity; // Create the order on this side of the trade. Guid destinationOrderId = Guid.NewGuid(); dataModel.CreateDestinationOrder( workingOrderRow.BlotterId, null, null, createdTime, createdUserId, destinationId, destinationOrderId, null, null, null, null, workingOrderRow[DataModel.WorkingOrder.LimitPriceColumn], modifiedTime, modifiedUserId, matchedQuantity, workingOrderRow.OrderTypeId, workingOrderRow.SecurityId, modifiedTime, workingOrderRow.SettlementId, workingOrderRow.SideId, StateMap.FromCode(State.Acknowledged), StatusMap.FromCode(Status.New), workingOrderRow[DataModel.WorkingOrder.StopPriceColumn], workingOrderRow.TimeInForceId, modifiedTime, null, workingOrderRow.WorkingOrderId); // The the trade is executed at the current price. PriceRow priceRow = DataModel.Price.PriceKey.Find(workingOrderRow.SecurityId, workingOrderRow.SettlementId); // Create the Execution for this side of the trade. Guid executionId = Guid.NewGuid(); dataModel.CreateExecution( null, workingOrderRow.BlotterId, null, null, null, createdTime, createdUserId, destinationOrderId, StateMap.FromCode(State.Acknowledged), executionId, priceRow.LastPrice, matchedQuantity, null, null, null, modifiedTime, modifiedUserId, null, null, null, null, StateMap.FromCode(State.Sent), null, null, null, null); // There is no opposite side of this transaction yet. It will be placed in the negotation table and wait there // until it times out, or the other side accepts the offer. negotiationId = Guid.NewGuid(); dataModel.CreateNegotiation( workingOrderRow.BlotterId, executionId, false, matchId, negotiationId, quantity, StatusMap.FromCode(Status.Accepted)); // Create an order for the agreed upon quantity. // Create the order on this side of the trade. Guid contraDestinationOrderId = Guid.NewGuid(); dataModel.CreateDestinationOrder( contraWorkingOrderRow.BlotterId, null, null, createdTime, createdUserId, destinationId, contraDestinationOrderId, null, null, null, null, contraWorkingOrderRow[DataModel.WorkingOrder.LimitPriceColumn], modifiedTime, modifiedUserId, matchedQuantity, contraWorkingOrderRow.OrderTypeId, contraWorkingOrderRow.SecurityId, modifiedTime, contraWorkingOrderRow.SettlementId, contraWorkingOrderRow.SideId, StateMap.FromCode(State.Acknowledged), StatusMap.FromCode(Status.New), contraWorkingOrderRow[DataModel.WorkingOrder.StopPriceColumn], contraWorkingOrderRow.TimeInForceId, modifiedTime, null, contraWorkingOrderRow.WorkingOrderId); // Create the Execution for this side of the trade. Guid contraExecutionId = Guid.NewGuid(); dataModel.CreateExecution( null, contraWorkingOrderRow.BlotterId, null, null, null, createdTime, createdUserId, contraDestinationOrderId, StateMap.FromCode(State.Acknowledged), contraExecutionId, priceRow.LastPrice, matchedQuantity, null, null, null, modifiedTime, modifiedUserId, null, null, null, null, StateMap.FromCode(State.Sent), null, null, null, null); // Update the contra offer. dataModel.UpdateNegotiation( contraWorkingOrderRow.BlotterId, contraExecutionId, false, null, null, new Object[] { contraNegotiationRow.NegotiationId }, null, contraNegotiationRow.RowVersion, StatusMap.FromCode(Status.Accepted)); } } } finally { // Release the tables. DataModel.DataLock.ExitReadLock(); } }