예제 #1
0
        /// <summary>
        /// Gets the user's unique identifier.
        /// </summary>
        /// <returns>The user's unique identifier.</returns>
        public static Guid GetUserId()
        {
            // Get the current transaction and the user's identity principal.
            DataModelTransaction  dataModelTransaction  = DataModel.CurrentTransaction;
            OrganizationPrincipal organizationPrincipal = Thread.CurrentPrincipal as OrganizationPrincipal;

            // Try to find the user in the user tables.
            DataModel.UserRow userRow = DataModel.User.UserKeyDistinguishedName.Find(organizationPrincipal.DistinguishedName);
            if (userRow == null)
            {
                Log.Error(String.Format("Invalid Login request for {0}", organizationPrincipal.DistinguishedName));
                throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("User", new Object[] { organizationPrincipal.DistinguishedName }));
            }

            // If a record is found in the User table that matches the thread's identity, then lock it for the duration of the transaction and insure that it wasn't
            // deleted between the time it was found and the time it was locked.
            userRow.AcquireReaderLock(dataModelTransaction);
            dataModelTransaction.AddLock(userRow);
            if (userRow.RowState == DataRowState.Detached)
            {
                throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("User", new Object[] { organizationPrincipal.DistinguishedName }));
            }

            // This is the user's internal identity to the data model.
            return(userRow.UserId);
        }
예제 #2
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);
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Truncates the Execution table.
        /// </summary>
        internal static void Truncate()
        {
            // We need a transaction in order to scan the Execution table.
            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

            // We can't modify a list while iterating through it, so we need to collect all the Execution records in this list.  Then when we start to
            // destroy them, we won't disturb the iterator.
            List <DestroyInfo> destroyInfoList = new List <DestroyInfo>();

            try
            {
                // A reader lock is required to protect the table iterators while we collect all the Executions.
                DataModel.DataLock.EnterReadLock();

                // This will collect all the Executions.
                foreach (DataModel.ExecutionRow executionRow in DataModel.Execution)
                {
                    executionRow.AcquireReaderLock(dataModelTransaction);
                    dataModelTransaction.AddLock(executionRow);
                    destroyInfoList.Add(new DestroyInfo(new Object[] { executionRow.ExecutionId }, executionRow.RowVersion));
                }
            }
            finally
            {
                // We don't need to protect the Execution table iterators any longer.
                DataModel.DataLock.ExitReadLock();
            }

            // At this point we've collected all the Executions in the table.  This will call the internal method to destroy them.
            foreach (DestroyInfo destroyInfo in destroyInfoList)
            {
                DataModel.TenantDataModel.DestroyExecution(destroyInfo.Key, destroyInfo.RowVersion);
            }
        }
예제 #4
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);
                }
            }
        }
예제 #5
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);
                }
            }
        }
예제 #6
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();
                    }
                }
            }
        }
예제 #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();
                    }
                }
            }
        }
예제 #11
0
        /// <summary>
        /// Simulation of brokers executing destination orders.
        /// </summary>
        private static void SimulateBroker()
        {
            // This will seed the random number generator.
            Random random = new Random(DateTime.Now.Millisecond);

            // An instance of the data model is required to update it.
            DataModel dataModel = new DataModel();

            // This set of claims gives the current thread the authority to update the price table.
            List <Claim> listClaims = new List <Claim>();

            listClaims.Add(new Claim(Teraque.ClaimTypes.Create, Teraque.Resources.Application, Rights.PossessProperty));
            listClaims.Add(new Claim(Teraque.ClaimTypes.Update, Teraque.Resources.Application, Rights.PossessProperty));
            listClaims.Add(new Claim(Teraque.ClaimTypes.Read, Teraque.Resources.Application, Rights.PossessProperty));
            ClaimSet adminClaims = new DefaultClaimSet(null, listClaims);
//			Thread.CurrentPrincipal = new ClaimsPrincipal(new GenericIdentity("Broker Service"), adminClaims);

            // Every execution requires a user identifier (the user who created the execution) and the broker who executed the
            // trade.  These values are hard coded at the moment but should be more intelligently assigned in the future.
            Guid userId   = Guid.Empty;
            Guid brokerId = Guid.Empty;

            // Operating values are required for the simulation that come from the data model.
            using (TransactionScope transactionScope = new TransactionScope())
            {
                // The middle tier context allows ADO operations to participate in the transaction.
                DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

                // The broker for all the executions is hard coded.
                DataModel.EntityRow brokerRow = DataModel.Entity.EntityKeyExternalId0.Find(new object[] { "ZODIAC SECURITIES" });
                brokerRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                dataModelTransaction.AddLock(brokerRow);
                brokerId = brokerRow.EntityId;

                // The user who creates these executions is hard coded.
                DataModel.EntityRow userRow = DataModel.Entity.EntityKeyExternalId0.Find(new object[] { "ADMINISTRATOR" });
                userRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                dataModelTransaction.AddLock(userRow);
                userId = userRow.EntityId;

                // The data model doesn't need to be locked any more.
                transactionScope.Complete();
            }

            // This thread will run until an external thread sets this property to 'false'.
            while (MarketSimulator.IsBrokerSimulatorThreadRunning)
            {
                // Wait for orders to show up in the simulated order book.
                MarketSimulator.orderEvent.WaitOne();

                // The simulator parameters need to be locked for each batch of simulated price changes.
                try
                {
                    Monitor.Enter(MarketSimulator.syncRoot);

                    // This will select a random price in the table and change the price by a random amount.
                    if (MarketSimulator.dataSetMarket.Order.Rows.Count > 0)
                    {
                        // Select a random row from the order book.
                        int orderIndex = random.Next(MarketSimulator.dataSetMarket.Order.Rows.Count);
                        DataSetMarket.OrderRow orderRow = MarketSimulator.dataSetMarket.Order[orderIndex];
                        if (orderRow.IsBusy)
                        {
                            Thread.Sleep(0);
                            continue;
                        }
                        orderRow.IsBusy = true;

                        // This transaction is required to add the new execution.
                        using (TransactionScope transactionScope = new TransactionScope())
                        {
                            // The middle tier context allows ADO operations to participate in the transaction.
                            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;

                            // This will simulate a random selection of a price change is quoted. The 'quoteColumn' variable can be
                            // used to reference the selected quote from any price row.  Below, a random row will be selected for
                            // the price change.
                            int actionTypeIndex = random.Next(Enum.GetValues(typeof(ActionType)).Length);
                            switch ((ActionType)Enum.GetValues(typeof(ActionType)).GetValue(actionTypeIndex))
                            {
                            case ActionType.Execute:

                                // This creates a random execution of the remaining shares on the order.
                                DateTime dateTime         = DateTime.Now;
                                Guid     blotterId        = orderRow.BlotterId;
                                Decimal  quantityLeaves   = orderRow.QuantityOrdered - orderRow.QuantityExecuted;
                                Decimal  quantityExecuted = quantityLeaves <= 100 ?
                                                            quantityLeaves :
                                                            Convert.ToDecimal(random.Next(1, Convert.ToInt32(quantityLeaves / 100.0M))) * 100.0M;
                                DataSetMarket.PriceRow priceRow =
                                    MarketSimulator.dataSetMarket.Price.FindByConfigurationIdSymbol("US TICKER", orderRow.Symbol);
                                Decimal executionPrice = 0.0M;
                                if (priceRow != null)
                                {
                                    executionPrice = orderRow.SideCode == SideCode.Buy || orderRow.SideCode == SideCode.BuyCover ?
                                                     priceRow.BidPrice :
                                                     priceRow.AskPrice;
                                }
                                Guid executionId        = Guid.NewGuid();
                                Guid destinationOrderId = orderRow.DestinationOrderId;

                                // When the order is completed, it is removed from the order book.  When the order book is empty, the thread goes to sleep
                                // until another thread puts something in the order queue.
                                orderRow.QuantityExecuted += quantityExecuted;
                                if (orderRow.QuantityOrdered == orderRow.QuantityExecuted)
                                {
                                    MarketSimulator.dataSetMarket.Order.RemoveOrderRow(orderRow);
                                    if (MarketSimulator.dataSetMarket.Order.Count == 0)
                                    {
                                        MarketSimulator.orderEvent.Reset();
                                    }
                                }

                                if (quantityExecuted > 0)
                                {
                                    Monitor.Exit(MarketSimulator.syncRoot);

                                    dataModel.CreateExecution(
                                        0.0M,
                                        blotterId,
                                        null,
                                        brokerId,
                                        0.0M,
                                        dateTime,
                                        userId,
                                        destinationOrderId,
                                        StateMap.FromCode(StateCode.Acknowledged),
                                        executionId,
                                        executionPrice,
                                        quantityExecuted,
                                        null,
                                        null,
                                        false,
                                        dateTime,
                                        userId,
                                        null,
                                        null,
                                        null,
                                        null,
                                        StateMap.FromCode(StateCode.Acknowledged),
                                        0.0M,
                                        0.0M,
                                        0.0M,
                                        0.0M);
                                    Monitor.Enter(MarketSimulator.syncRoot);
                                }

                                break;
                            }

                            // This will commit the changes to the order book.
                            transactionScope.Complete();
                        }

                        // This allows another thread to work the order.
                        orderRow.IsBusy = false;
                    }
                }
                finally
                {
                    Monitor.Exit(MarketSimulator.syncRoot);
                }

                // This allows other threads the chance to run.
                Thread.Sleep(0);
            }
        }
예제 #12
0
        /// <summary>
        /// Updates prices using a United States ticker.
        /// </summary>
        /// <param name="symbolIndex">The index to use to find the symbol.</param>
        /// <param name="symbolKey">The symbol key.</param>
        /// <param name="currencyIndex">The index to use to find the currency.</param>
        /// <param name="currencyKey">The currency key.</param>
        /// <param name="quote">The quote used to update the price.</param>
        static void UpdatePriceBySymbolCurrency(
            DataModel.IEntityIndex symbolIndex,
            Object[] symbolKey,
            DataModel.IEntityIndex currencyIndex,
            Object[] currencyKey,
            Quote quote)
        {
            // The current transaction and the target data model is extracted from the thread.
            DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction;
            TenantDataModel      tenantDataSet        = dataModelTransaction.TenantDataModel;

            // This will find the currency of the quote.
            DataModel.EntityRow currencyEntityRow = currencyIndex.Find(currencyKey);
            if (currencyEntityRow == null)
            {
                throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("Entity", currencyKey));
            }
            currencyEntityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
            dataModelTransaction.AddLock(currencyEntityRow);
            if (currencyEntityRow.RowState == System.Data.DataRowState.Detached)
            {
                throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("Entity", currencyKey));
            }
            Guid currencyId = currencyEntityRow.EntityId;

            // This will find the security using the external identifier.
            DataModel.EntityRow securityEntityRow = symbolIndex.Find(symbolKey);
            if (securityEntityRow == null)
            {
                throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("Entity", symbolKey));
            }
            securityEntityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
            dataModelTransaction.AddLock(securityEntityRow);
            if (securityEntityRow.RowState == System.Data.DataRowState.Detached)
            {
                throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("Entity", symbolKey));
            }
            Guid securityId = securityEntityRow.EntityId;

            // If the price record exists, then update it.  If it doesn't exist then create it.
            Object[]           priceKey = new Object[] { securityId, currencyId };
            DataModel.PriceRow priceRow = DataModel.Price.PriceKey.Find(priceKey);
            if (priceRow == null)
            {
                tenantDataSet.CreatePrice(
                    quote.AskPrice,
                    quote.AskSize,
                    quote.BidPrice,
                    quote.BidSize,
                    null,
                    currencyId,
                    null,
                    quote.LastPrice,
                    quote.LastSize,
                    null,
                    null,
                    null,
                    securityId,
                    null,
                    null);
            }
            else
            {
                priceRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                dataModelTransaction.AddLock(priceRow);
                if (priceRow.RowState == System.Data.DataRowState.Detached)
                {
                    throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("Price", priceKey));
                }
                tenantDataSet.UpdatePrice(
                    quote.AskPrice,
                    quote.AskSize,
                    quote.BidPrice,
                    quote.BidSize,
                    null,
                    currencyId,
                    null,
                    quote.LastPrice,
                    quote.LastSize,
                    null,
                    null,
                    null,
                    priceKey,
                    priceRow.RowVersion,
                    securityId,
                    null,
                    null);
            }
        }