예제 #1
0
 /// <summary>
 /// Updates the status of the Destination Order.
 /// </summary>
 /// <param name="destinationOrderRow">The Working Order to be modified.</param>
 /// <param name="statusCode">The new status of the Working Order.</param>
 internal static void UpdateDestinationOrderStatus(DataModel.DestinationOrderRow destinationOrderRow, StatusCode statusCode)
 {
     // This will update only the status of the given destination order.
     DataModel.TenantDataModel.UpdateDestinationOrder(
         null,
         null,
         null,
         null,
         null,
         null,
         new Object[] { destinationOrderRow.DestinationOrderId },
         null,
         null,
         null,
         null,
         null,
         null,
         null,
         null,
         destinationOrderRow.RowVersion,
         null,
         null,
         null,
         null,
         null,
         statusCode,
         null,
         null,
         null,
         null,
         null);
 }
예제 #2
0
        /// <summary>
        /// Handler for validating Destination Order records.
        /// </summary>
        /// <param name="sender">The object that originated the event.</param>
        /// <param name="e">The event arguments.</param>
        static void OnDestinationOrderAdd(DataModel.DestinationOrderRow destinationOrderRow)
        {
            // A transaction is needed to handle the change.
            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

            DataModel.WorkingOrderRow workingOrderRow = destinationOrderRow.WorkingOrderRow;
            workingOrderRow.AcquireReaderLock(dataModelTransaction);

            Decimal sourceOrderQuantity      = WorkingOrderService.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow);
            Decimal destinationOrderQuantity = WorkingOrderService.GetDestinationOrderQuantity(dataModelTransaction, workingOrderRow);

            if (sourceOrderQuantity < destinationOrderQuantity)
            {
                throw new FaultException <DestinationQuantityFault>(
                          new DestinationQuantityFault(workingOrderRow.WorkingOrderId, sourceOrderQuantity, destinationOrderQuantity));
            }
        }
예제 #3
0
        /// <summary>
        /// Handler for validating Destination Order records.
        /// </summary>
        /// <param name="sender">The object that originated the event.</param>
        /// <param name="e">The event arguments.</param>
        static void OnDestinationOrderDelete(DataModel.DestinationOrderRow destinationOrderRow)
        {
            // A transaction is needed to handle the change.
            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

            // If the StatusCode of the destination order has changed then find the right handler for the state change and go execute the business logic for this
            // change.  The 'statusChangeMap' is a two dimensional Dictionary (hash table) using the previous and current states to find the right handler.  Note
            // that on a deletion, we don't have easy access to the original working order, so we need to extract it from the deleted record.
            StatusCode previousStatusCode = (StatusCode)destinationOrderRow[DataModel.DestinationOrder.StatusCodeColumn, DataRowVersion.Original];
            StatusCode currentStatusCode  = StatusCode.Deleted;
            Guid       workingOrderId     = (Guid)destinationOrderRow[DataModel.DestinationOrder.WorkingOrderIdColumn, DataRowVersion.Original];

            DataModel.WorkingOrderRow workingOrderRow = DataModel.WorkingOrder.WorkingOrderKey.Find(new Object[] { workingOrderId });
            if (workingOrderRow != null)
            {
                statusChangeMap[previousStatusCode][currentStatusCode](workingOrderRow);
            }
        }
예제 #4
0
        /// <summary>
        /// Handles a change to the DestinationOrder table.
        /// </summary>
        /// <param name="sender">The object that originated the event.</param>
        /// <param name="e">The event data.</param>
        static void OnDestinationOrderRowChanged(object sender, DataModel.DestinationOrderRowChangeEventArgs e)
        {
            // This will turn new DestinationOrder records into orders that can be sent to a destination for execution.
            if (e.Action == DataRowAction.Add)
            {
                // The current transaction is going to be needed to lock records.
                DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

                // Create a new message for the order we're going to build from the DestinationOrder.
                Message message = new Message();

                // The market execution engine will need to know the source firm so it knows how to route the order back.
                OrganizationPrincipal organizationPrincipal = Thread.CurrentPrincipal as OrganizationPrincipal;
                message.SenderCompID = organizationPrincipal.Organization;

                // Copy the basic properties of the DestinationOrder into the message.
                DataModel.DestinationOrderRow destinationOrderRow = e.Row;
                message.ClOrdID         = destinationOrderRow.DestinationOrderId.ToString();
                message.OrderQty        = destinationOrderRow.OrderedQuantity;
                message.OrdType         = destinationOrderRow.OrderTypeCode;
                message.SideCode        = destinationOrderRow.SideCode;
                message.TimeInForceCode = destinationOrderRow.TimeInForceCode;

                // Get the symbol to use as a security identifier.
                DataModel.SecurityRow securityRow = destinationOrderRow.SecurityRowByFK_Security_DestinationOrder_SecurityId;
                securityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                dataModelTransaction.AddLock(securityRow);
                if (securityRow.RowState == DataRowState.Detached)
                {
                    throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("Security", new Object[] { destinationOrderRow.SecurityId }));
                }
                message.Symbol = securityRow.Symbol;

                // This will put the new order in a queue.  The DestinatonThread will pull it out, batch it up and send it to the destination to be executed.
                lock (MarketEngine.syncRoot)
                {
                    MarketEngine.messageQueue.Enqueue(message);
                    if (messageQueue.Count == 1)
                    {
                        MarketEngine.orderEvent.Set();
                    }
                }
            }
        }
예제 #5
0
 /// <summary>
 /// Handles the deletion of a Execution row.
 /// </summary>
 /// <param name="sender">The object that originated the event.</param>
 /// <param name="executionRowChangeEventArgs">The event arguments.</param>
 void OnExecutionRowDeleted(Object sender, DataModel.ExecutionRowChangeEventArgs executionRowChangeEventArgs)
 {
     // We're only interested in deletes that affect the WorkingOrder records in this blotter.
     if (executionRowChangeEventArgs.Action == DataRowAction.Delete)
     {
         // Filtering requires a little more work with a deleted record.  We need to first find the original record and then look up the destination and
         // working order to which it belonged.  We don't need to check for the existence of the destination order or working order as we know that this
         // execution was just deleted and, for it to have existed in the first place, there must have been a parent destination and working order.
         DataModel.ExecutionRow executionRow = executionRowChangeEventArgs.Row;
         Guid destinationOrderId             = (Guid)executionRow[DataModel.Execution.DestinationOrderIdColumn, DataRowVersion.Original];
         DataModel.DestinationOrderRow destinationOrderRow = DataModel.DestinationOrder.DestinationOrderKey.Find(destinationOrderId);
         DataModel.WorkingOrderRow     workingOrderRow     = destinationOrderRow.WorkingOrderRow;
         if (this.blotterIdSet.Contains(workingOrderRow.BlotterId))
         {
             // Once the quantity has been removed from the totals, the percent executed can be updated.
             this.ExecutionQuantity -= (Decimal)executionRow[DataModel.Execution.ExecutionQuantityColumn, DataRowVersion.Original];
             this.ExecutedPercent    = this.DestinationOrderQuantity == 0.0m ? 0.0 : Convert.ToDouble(this.ExecutionQuantity / this.DestinationOrderQuantity);
         }
     }
 }
예제 #6
0
 /// <summary>
 /// Handles a change to the Execution row.
 /// </summary>
 /// <param name="sender">The object that originated the event.</param>
 /// <param name="executionRowChangeEventArgs">The event arguments.</param>
 void OnExecutionRowChanged(Object sender, DataModel.ExecutionRowChangeEventArgs executionRowChangeEventArgs)
 {
     // We're only interested in additions and changes that affect the WorkingOrder records in this blotter.
     if (executionRowChangeEventArgs.Action == DataRowAction.Add || executionRowChangeEventArgs.Action == DataRowAction.Change)
     {
         // This is designed to filter out all events that don't pertain to this blotter.
         DataModel.ExecutionRow        executionRow        = executionRowChangeEventArgs.Row;
         DataModel.DestinationOrderRow destinationOrderRow = executionRow.DestinationOrderRow;
         DataModel.WorkingOrderRow     workingOrderRow     = destinationOrderRow.WorkingOrderRow;
         if (this.blotterIdSet.Contains(workingOrderRow.BlotterId))
         {
             // Once the previous execution is subtracted and the current execution added to the totals we can calculate the percent executed.
             if (executionRow.HasVersion(DataRowVersion.Original))
             {
                 this.executionQuantityField -= (Decimal)executionRow[DataModel.Execution.ExecutionQuantityColumn, DataRowVersion.Original];
             }
             this.ExecutionQuantity += executionRow.ExecutionQuantity;
             this.ExecutedPercent    = this.DestinationOrderQuantity == 0.0m ? 0.0 : Convert.ToDouble(this.ExecutionQuantity / this.DestinationOrderQuantity);
         }
     }
 }
예제 #7
0
        /// <summary>
        /// Handler for validating Destination Order records.
        /// </summary>
        /// <param name="sender">The object that originated the event.</param>
        /// <param name="e">The event arguments.</param>
        static void OnDestinationOrderChange(DataModel.DestinationOrderRow destinationOrderRow)
        {
            // A transaction is needed to handle the change.
            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

            // If the quantity has changed then we need to make sure that the quantity sent to a destination (broker, exchange, etc.) is not less than the amount
            // ordered.  That is, we can't accept a change that leaves us overcommited with a destination.
            Decimal originalQuantity = (Decimal)destinationOrderRow[DataModel.DestinationOrder.OrderedQuantityColumn, DataRowVersion.Original];
            Decimal currentQuantity  = (Decimal)destinationOrderRow[DataModel.DestinationOrder.OrderedQuantityColumn, DataRowVersion.Current];

            if (originalQuantity < currentQuantity)
            {
                // We need to aggregate at the working order, so we need to lock the working order while we do our sums.
                DataModel.WorkingOrderRow workingOrderRow = destinationOrderRow.WorkingOrderRow;
                workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                dataModelTransaction.AddLock(workingOrderRow);

                // This will aggregate the source and destination orders and throw an exception if this transaction would leave us overcommitted with the
                // destination.
                Decimal sourceOrderQuantity      = WorkingOrderService.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow);
                Decimal destinationOrderQuantity = WorkingOrderService.GetDestinationOrderQuantity(dataModelTransaction, workingOrderRow);
                if (sourceOrderQuantity < destinationOrderQuantity)
                {
                    throw new FaultException <DestinationQuantityFault>(
                              new DestinationQuantityFault(workingOrderRow.WorkingOrderId, sourceOrderQuantity, destinationOrderQuantity));
                }
            }

            // If the StatusCode of the destination order has changed then find the right handler for the state change and go execute the business logic for this
            // change.  The 'statusChangeMap' is a two dimensional Dictionary (hash table) using the previous and current states to find the right handler.
            StatusCode previousStatusCode = (StatusCode)destinationOrderRow[DataModel.DestinationOrder.StatusCodeColumn, DataRowVersion.Original];
            StatusCode currentStatusCode  = destinationOrderRow.StatusCode;

            if (previousStatusCode != currentStatusCode)
            {
                statusChangeMap[previousStatusCode][currentStatusCode](destinationOrderRow.WorkingOrderRow);
            }
        }
예제 #8
0
 /// <summary>
 /// Do nothing.
 /// </summary>
 /// <param name="workingOrderRow">The source order row that was changed.</param>
 static void OnDoNothing(DataModel.DestinationOrderRow destinationOrderRow)
 {
 }
예제 #9
0
        /// <summary>
        /// Creates orders in the simulated order book.
        /// </summary>
        private static void OrderHandler()
        {
            // This thread will create orders in the simulated order book from destination orders placed in the queue.  This thread
            // is necessary due to the locking architecture that prevents accessing the data model during a commit operation (which
            // is where the event indicating a new or changed destination order originates).
            while (MarketSimulator.IsBrokerSimulatorThreadRunning)
            {
                // This thread will wait here until a destination order is available in the queue.
                DataModel.DestinationOrderRow destinationOrderRow = MarketSimulator.orderQueue.Dequeue();

                // The code that adds an order to the simulated book must have exclusive access to the simulated data model.
                lock (MarketSimulator.syncRoot)
                {
                    // The primary data model needs to be accessed also for ancillary data associated with the new order.
                    using (TransactionScope transactionScope = new TransactionScope())
                    {
                        try
                        {
                            // This context is used to keep track of the locks aquired for the ancillary data.
                            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

                            // Lock the destination order.
                            destinationOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                            dataModelTransaction.AddLock(destinationOrderRow);

                            // Lock the Security.
                            DataModel.SecurityRow securityRow = destinationOrderRow.SecurityRowByFK_Security_DestinationOrder_SecurityId;
                            securityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                            dataModelTransaction.AddLock(securityRow);

                            // The working order row must be locked to examine the flags
                            DataModel.WorkingOrderRow workingOrderRow = destinationOrderRow.WorkingOrderRow;
                            workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                            dataModelTransaction.AddLock(workingOrderRow);

                            // Lock the Entity.
                            DataModel.EntityRow entityRow = securityRow.EntityRow;
                            entityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                            dataModelTransaction.AddLock(entityRow);

                            // Calculate the quantity executed on this order (some orders are created with executions, such as crossed orders.)
                            Decimal quantityExecuted = 0.0M;
                            foreach (DataModel.ExecutionRow executionRow in destinationOrderRow.GetExecutionRows())
                            {
                                executionRow.AcquireReaderLock(dataModelTransaction);
                                dataModelTransaction.AddLock(executionRow);
                                quantityExecuted += executionRow.ExecutionQuantity;
                            }

                            // The simulated order is added to the book.  This collects all the information required to simulate the execution of this order.
                            DataSetMarket.OrderRow orderRow = MarketSimulator.dataSetMarket.Order.NewOrderRow();
                            orderRow.BlotterId          = destinationOrderRow.BlotterId;
                            orderRow.DestinationOrderId = destinationOrderRow.DestinationOrderId;
                            orderRow.OrderTypeCode      = OrderTypeMap.FromId(destinationOrderRow.OrderTypeId);
                            orderRow.QuantityOrdered    = destinationOrderRow.OrderedQuantity;
                            orderRow.QuantityExecuted   = quantityExecuted;
                            orderRow.SideCode           = SideMap.FromId(destinationOrderRow.SideId);
                            orderRow.Symbol             = securityRow.Symbol;
                            orderRow.TimeInForceCode    = TimeInForceMap.FromId(destinationOrderRow.TimeInForceId);
                            MarketSimulator.dataSetMarket.Order.AddOrderRow(orderRow);

                            // Adding the first order to the simulated order book will enable the simulation thread to begin processing the orders.  The order
                            // simulation thread will continue until the book is filled.
                            if (MarketSimulator.dataSetMarket.Order.Count == 1)
                            {
                                MarketSimulator.orderEvent.Set();
                            }
                        }
                        catch { }

                        // The locks are no longer required.
                        transactionScope.Complete();
                    }
                }
            }
        }