コード例 #1
0
        /// <summary>
        /// Handles a change to a filled state.
        /// </summary>
        /// <param name="workingOrderRow">The parent working order.</param>
        static void OnFilledAction(DataModel.WorkingOrderRow workingOrderRow)
        {
            // A transaction is needed to handle the change.
            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

            // This will lock the WorkingOrderRow while we examine it.
            workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
            dataModelTransaction.AddLock(workingOrderRow);
            if (workingOrderRow.RowState == DataRowState.Detached)
            {
                return;
            }

            // This will mark the working order as filled when the quantity executed is the same as the quantity ordered.  The only exception to this is when ng
            // the workiorder is in an error state.
            if (workingOrderRow.StatusCode != StatusCode.Error)
            {
                Decimal quantityOrdered  = WorkingOrderService.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow);
                Decimal quantityExecuted = WorkingOrderService.GetExecutionQuantity(dataModelTransaction, workingOrderRow);
                if (quantityOrdered == quantityExecuted)
                {
                    WorkingOrderService.UpdateWorkingOrderStatus(workingOrderRow, StatusCode.Filled);
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Handles a change to a cancelled state.
        /// </summary>
        /// <param name="workingOrderRow">The parent working order.</param>
        static void OnCanceledAction(DataModel.WorkingOrderRow workingOrderRow)
        {
            // A transaction is needed to handle the change.
            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

            // This will lock the WorkingOrderRow while we examine it.
            workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
            dataModelTransaction.AddLock(workingOrderRow);
            if (workingOrderRow.RowState == DataRowState.Detached)
            {
                return;
            }

            // When a destination order is canceled we will return the order to its previous state (as determined by aggregating the executed and destination
            // quantities).  The only exception to this is when the working order is in the error state.
            if (workingOrderRow.StatusCode != StatusCode.Error)
            {
                Decimal quantityExecuted = WorkingOrderService.GetExecutionQuantity(dataModelTransaction, workingOrderRow);
                Decimal quantityOrdered  = WorkingOrderService.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow);
                if (quantityExecuted == 0.0M && workingOrderRow.StatusCode != StatusCode.New)
                {
                    WorkingOrderService.UpdateWorkingOrderStatus(workingOrderRow, StatusCode.New);
                }
                if (0.0M < quantityExecuted && quantityExecuted < quantityOrdered && workingOrderRow.StatusCode != StatusCode.PartiallyFilled)
                {
                    WorkingOrderService.UpdateWorkingOrderStatus(workingOrderRow, StatusCode.PartiallyFilled);
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Validates the source order row when it is deleted.
        /// </summary>
        /// <param name="sourceOrderRow">The source order row that was deleted.</param>
        static void OnSourceOrderDelete(DataModel.SourceOrderRow sourceOrderRow)
        {
            // We'll need to add several rows to the transaction as we validate the source order deletion.
            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

            // There is no implicit locking mechanism for deleted rows, so we need to lock the record manually as we access the parent working order of the deleted
            // source order.
            DataModel.WorkingOrderRow workingOrderRow = null;
            try
            {
                DataModel.DataLock.EnterReadLock();
                workingOrderRow = ((DataModel.WorkingOrderRow)(sourceOrderRow.GetParentRow(DataModel.SourceOrder.WorkingOrderSourceOrderRelation, DataRowVersion.Original)));
            }
            finally
            {
                DataModel.DataLock.ExitReadLock();
            }
            workingOrderRow.AcquireReaderLock(dataModelTransaction);

            // This will insure that the quantity ordered doesn't fall below the quantity placed with brokers and exchanges.
            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));
            }
        }
コード例 #4
0
        /// <summary>
        /// Validates the source order row when it changes.
        /// </summary>
        /// <param name="sourceOrderRow">The source order row that was changed.</param>
        static void OnSourceOrderChange(DataModel.SourceOrderRow sourceOrderRow)
        {
            // We can't allow the quantity of source order shares to drop below the quantity of destination order shares.  We only need to check for this condition
            // when the quantity of the source order record has changed.
            Decimal originalQuantity = (Decimal)sourceOrderRow[DataModel.SourceOrder.OrderedQuantityColumn, DataRowVersion.Original];
            Decimal currentQuantity  = (Decimal)sourceOrderRow[DataModel.SourceOrder.OrderedQuantityColumn, DataRowVersion.Current];

            if (originalQuantity < currentQuantity)
            {
                // We'll need to lock several records in order to check source order and destination order totals.
                DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

                // Get the working order associated with this source order and lock it.
                DataModel.WorkingOrderRow workingOrderRow = sourceOrderRow.WorkingOrderRow;
                workingOrderRow.AcquireReaderLock(dataModelTransaction);

                // Now aggregate the source order quantities and the destination order quantities.  Throw an exception if the source orders are less than the
                // destination orders (we can't have less quantity ordered than we've placed with brokers and exchanges).
                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));
                }
            }
        }
コード例 #5
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));
            }
        }
コード例 #6
0
        /// <summary>
        /// Handles a change to a error state.
        /// </summary>
        /// <param name="workingOrderRow">The parent working order.</param>
        static void OnClearErrorAction(DataModel.WorkingOrderRow workingOrderRow)
        {
            // A transaction is needed to handle the change.
            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

            // This will lock the WorkingOrderRow while we examine it.
            workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
            dataModelTransaction.AddLock(workingOrderRow);
            if (workingOrderRow.RowState == DataRowState.Detached)
            {
                return;
            }

            // The error status is cleared only when none of the sibling destination orders has an error.
            Boolean isErrorStatus = false;

            foreach (DataModel.DestinationOrderRow siblingOrderRow in workingOrderRow.GetDestinationOrderRows())
            {
                siblingOrderRow.AcquireReaderLock(dataModelTransaction);
                if (siblingOrderRow.StatusCode == StatusCode.Error)
                {
                    isErrorStatus = true;
                    break;
                }
            }

            // If none of the siblings has an error, the we're going to set the working order's status to what it was before the error occurred.
            if (!isErrorStatus)
            {
                Decimal quantityExecuted = WorkingOrderService.GetExecutionQuantity(dataModelTransaction, workingOrderRow);
                Decimal quantityOrdered  = WorkingOrderService.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow);
                if (quantityExecuted == 0.0M && workingOrderRow.StatusCode != StatusCode.New)
                {
                    WorkingOrderService.UpdateWorkingOrderStatus(workingOrderRow, StatusCode.New);
                }
                if (0.0M < quantityExecuted && quantityExecuted < quantityOrdered && workingOrderRow.StatusCode != StatusCode.PartiallyFilled)
                {
                    WorkingOrderService.UpdateWorkingOrderStatus(workingOrderRow, StatusCode.PartiallyFilled);
                }
                if (quantityExecuted == quantityOrdered && workingOrderRow.StatusCode != StatusCode.Filled)
                {
                    WorkingOrderService.UpdateWorkingOrderStatus(workingOrderRow, StatusCode.Filled);
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// Handles a change to a error state.
        /// </summary>
        /// <param name="workingOrderRow">The parent working order.</param>
        static void OnSetErrorAction(DataModel.WorkingOrderRow workingOrderRow)
        {
            // A transaction is needed to handle the change.
            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

            // This will lock the WorkingOrderRow while we examine it.
            workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
            dataModelTransaction.AddLock(workingOrderRow);
            if (workingOrderRow.RowState == DataRowState.Detached)
            {
                return;
            }

            // This logic is simple enough, set to an error state if we're not already there.
            if (workingOrderRow.StatusCode != StatusCode.Error)
            {
                WorkingOrderService.UpdateWorkingOrderStatus(workingOrderRow, StatusCode.Error);
            }
        }
コード例 #8
0
        /// <summary>
        /// Handles a change to a partially executed state.
        /// </summary>
        /// <param name="workingOrderRow">The parent working order.</param>
        static void OnPartialAction(DataModel.WorkingOrderRow workingOrderRow)
        {
            // A transaction is needed to handle the change.
            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

            // This will lock the WorkingOrderRow while we examine it.
            workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
            dataModelTransaction.AddLock(workingOrderRow);
            if (workingOrderRow.RowState == DataRowState.Detached)
            {
                return;
            }

            // The working order is considered partially filled if any of its destination orders are partially filled.  The only exception to this is when the
            // working order is in an error state.
            if (workingOrderRow.StatusCode != StatusCode.Error && workingOrderRow.StatusCode != StatusCode.PartiallyFilled)
            {
                WorkingOrderService.UpdateWorkingOrderStatus(workingOrderRow, StatusCode.PartiallyFilled);
            }
        }
コード例 #9
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);
            }
        }
コード例 #10
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();
                    }
                }
            }
        }