Exemple #1
0
        /// <summary>
        /// Generates random Price movements.
        /// </summary>
        private static void ExecutionThread(params object[] argument)
        {
            // Extract the thread arguments.  The simulator will execute orders placed with this broker.
            int brokerId = (int)argument[0];

            // Continually execute trades from the local order book when they exist.
            while (true)
            {
                // Wait until there is something in the order book to execute.
                Broker.orderBookEvent.WaitOne();

                // These parameters are used to create the filled execution.
                int      blockOrderId   = 0;
                decimal  quantity       = 0.0M;
                decimal  price          = 0.0M;
                DateTime tradeDate      = DateTime.MinValue;
                DateTime settlementDate = DateTime.MinValue;

                // This will insure that we survive any single error on a random execution.
                try
                {
                    // Lock the Order Book.
                    Broker.orderBookLock.AcquireWriterLock(CommonTimeout.LockWait);

                    // Lock the tables.
                    Debug.Assert(!ServerMarketData.AreLocksHeld);
                    ServerMarketData.DebtLock.AcquireReaderLock(Timeout.Infinite);
                    ServerMarketData.ExecutionLock.AcquireWriterLock(Timeout.Infinite);
                    ServerMarketData.EquityLock.AcquireReaderLock(Timeout.Infinite);
                    ServerMarketData.HolidayLock.AcquireReaderLock(Timeout.Infinite);
                    ServerMarketData.PriceLock.AcquireReaderLock(Timeout.Infinite);
                    ServerMarketData.SecurityLock.AcquireReaderLock(Timeout.Infinite);

                    // Now that the tables are locked, the trade and settlement dates can be calcualted.
                    tradeDate      = Trading.TradeDate(0, 0, DateTime.Now);
                    settlementDate = Trading.SettlementDate(0, 0, tradeDate);

                    // Pick a random order to fill.
                    if (Broker.orderBook.Order.Rows.Count > 0)
                    {
                        int orderIndex = Random.Next(0, Broker.orderBook.Order.Rows.Count);
                        OrderBook.OrderRow orderRow = Broker.orderBook.Order[orderIndex];
                        blockOrderId = orderRow.BlockOrderId;

                        // Find the security associated with this placement.
                        ServerMarketData.SecurityRow securityRow = ServerMarketData.Security.FindBySecurityId(orderRow.SecurityId);
                        if (securityRow == null)
                        {
                            continue;
                        }

                        // A settlement Price is required to find the Price of a security.  For many issues, the default can
                        // be found from the defaults.  If a settlement currency isn't available, this issue can't be executed.
                        object settlementId = null;
                        foreach (ServerMarketData.DebtRow debtsRow in securityRow.GetDebtRowsByFKSecurityDebtDebtId())
                        {
                            settlementId = debtsRow.SettlementId;
                        }
                        foreach (ServerMarketData.EquityRow equityRow in securityRow.GetEquityRowsByFKSecurityEquityEquityId())
                        {
                            settlementId = equityRow.SettlementId;
                        }
                        if (settlementId == null)
                        {
                            continue;
                        }

                        // Simulate an executed quantity for this order.
                        decimal quantityLeaves = orderRow.QuantityOrdered - orderRow.QuantityExecuted;
                        if (quantityLeaves >= 100.0M)
                        {
                            quantity = Random.Next(100, Convert.ToInt32((quantityLeaves > maxExecution) ? maxExecution : quantityLeaves));
                            quantity = Math.Round(quantity / 100.0M) * 100.0M;
                        }

                        // When the quantity is zero, the order has been filled and can be removed from the local order book.  When
                        // the book is empty, then this thread can be paused until a new order is generated from a new placement.
                        // In either event, when there are no shares in the order book, there can be no executions.  When there's
                        // nothing to execute, delete the order and go look for another order to fill.
                        if (quantity == 0.0M)
                        {
                            orderRow.Delete();
                            orderRow.AcceptChanges();
                            if (orderBook.Order.Rows.Count == 0)
                            {
                                Broker.orderBookEvent.Reset();
                            }
                            continue;
                        }

                        // Update the amount executed on this order.
                        orderRow.QuantityExecuted += quantity;

                        // Select a Price for the execution.
                        ServerMarketData.PriceRow priceRow = ServerMarketData.Price.FindBySecurityIdCurrencyId(securityRow.SecurityId,
                                                                                                               (int)settlementId);
                        if (priceRow != null)
                        {
                            price = priceRow.LastPrice;
                        }
                    }
                }
                catch (Exception exception)
                {
                    // Display the error.
                    Debug.WriteLine(exception.Message);
                }
                finally
                {
                    // Release the order book.
                    if (Broker.orderBookLock.IsWriterLockHeld)
                    {
                        Broker.orderBookLock.ReleaseWriterLock();
                    }

                    // Release the tables.
                    if (ServerMarketData.DebtLock.IsReaderLockHeld)
                    {
                        ServerMarketData.DebtLock.ReleaseReaderLock();
                    }
                    if (ServerMarketData.EquityLock.IsReaderLockHeld)
                    {
                        ServerMarketData.EquityLock.ReleaseReaderLock();
                    }
                    if (ServerMarketData.ExecutionLock.IsWriterLockHeld)
                    {
                        ServerMarketData.ExecutionLock.ReleaseWriterLock();
                    }
                    if (ServerMarketData.HolidayLock.IsReaderLockHeld)
                    {
                        ServerMarketData.HolidayLock.ReleaseReaderLock();
                    }
                    if (ServerMarketData.PriceLock.IsReaderLockHeld)
                    {
                        ServerMarketData.PriceLock.ReleaseReaderLock();
                    }
                    if (ServerMarketData.SecurityLock.IsReaderLockHeld)
                    {
                        ServerMarketData.SecurityLock.ReleaseReaderLock();
                    }
                    Debug.Assert(!ServerMarketData.AreLocksHeld);
                }

                // Create an execution record for this fill.
                Transaction transaction = new Transaction();
                Shadows.WebService.Trading.Execution.Insert(transaction);
                transaction.BeginTransaction();
                try
                {
                    long rowVersion = 0L;
                    Shadows.WebService.Trading.Execution.Insert(transaction, blockOrderId, brokerId, ref rowVersion, quantity, price, null,
                                                                null, null, null, null, null, tradeDate, settlementDate);
                    transaction.Commit();
                }
                catch
                {
                    transaction.Rollback();
                }
                transaction.EndTransaction();

                // Sleep for a random amount of time between execution.
                Thread.Sleep(Random.Next(50, 300));
            }
        }
Exemple #2
0
        /// <summary>
        /// This thread takes placements off the queue and creates orders in the local order book for them.
        /// </summary>
        private static void PlacementHandler()
        {
            while (true)
            {
                // Wait here for the next tick to come in.
                Broker.placementQueue.WaitOne();

                // Get the next placement from the queue.
                int placementId = Broker.placementQueue.Dequeue();

                try
                {
                    // Lock the Order Book.
                    Broker.orderBookLock.AcquireWriterLock(CommonTimeout.LockWait);

                    // Lock the tables.
                    Debug.Assert(!ServerMarketData.AreLocksHeld);
                    ServerMarketData.BlockOrderLock.AcquireReaderLock(Timeout.Infinite);
                    ServerMarketData.PlacementLock.AcquireReaderLock(Timeout.Infinite);

                    // Find the placement row.
                    ServerMarketData.PlacementRow placementRow = ServerMarketData.Placement.FindByPlacementId(placementId);
                    if (placementRow == null)
                    {
                        return;
                    }

                    // Information about the security is found in the block.  It isn't part of the placement so a BlockOrder
                    // record is needed to get some of the ancillary data.
                    ServerMarketData.BlockOrderRow blockOrderRow = placementRow.BlockOrderRow;

                    // The execution quantity needs to be calculated to prevent over execution when the simulator is
                    // restarted.  Count up the quantity executed against this placement.  While this calcuation isn't
                    // perfect -- it will miss when there are multiple placements to the same broker -- it is good enough for
                    // the simulator to restart itself.
                    decimal quantityExecuted = 0.0M;
                    foreach (ServerMarketData.ExecutionRow executionRow in blockOrderRow.GetExecutionRows())
                    {
                        if (executionRow.BrokerId == placementRow.BrokerId)
                        {
                            quantityExecuted += executionRow.Quantity;
                        }
                    }

                    // Create a new order book record and copy the data from the placement into the order.
                    OrderBook.OrderRow orderRow = Broker.orderBook.Order.NewOrderRow();
                    orderRow.BlockOrderId     = placementRow.BlockOrderId;
                    orderRow.BrokerId         = placementRow.BrokerId;
                    orderRow.SecurityId       = blockOrderRow.SecurityId;
                    orderRow.QuantityOrdered  = placementRow.Quantity;
                    orderRow.QuantityExecuted = quantityExecuted;
                    orderRow.TimeInForceCode  = placementRow.TimeInForceCode;
                    orderRow.OrderTypeCode    = placementRow.OrderTypeCode;
                    if (!placementRow.IsPrice1Null())
                    {
                        orderRow.Price1 = placementRow.Price1;
                    }
                    if (!placementRow.IsPrice2Null())
                    {
                        orderRow.Price2 = placementRow.Price2;
                    }

                    // Add the new record to the book and accept the changes.
                    Broker.orderBook.Order.AddOrderRow(orderRow);
                    orderRow.AcceptChanges();

                    // Signal to the execution thread that there are orders in the local book to be filled.
                    Broker.orderBookEvent.Set();
                }
                catch (Exception exception)
                {
                    // Write the error and stack trace out to the debug listener
                    Debug.WriteLine(String.Format("{0}, {1}", exception.Message, exception.StackTrace));
                }
                finally
                {
                    // Release the order book.
                    if (Broker.orderBookLock.IsWriterLockHeld)
                    {
                        Broker.orderBookLock.ReleaseWriterLock();
                    }

                    // Release the global tables.
                    if (ServerMarketData.BlockOrderLock.IsReaderLockHeld)
                    {
                        ServerMarketData.BlockOrderLock.ReleaseReaderLock();
                    }
                    if (ServerMarketData.PlacementLock.IsReaderLockHeld)
                    {
                        ServerMarketData.PlacementLock.ReleaseReaderLock();
                    }
                    Debug.Assert(!ServerMarketData.AreLocksHeld);
                }
            }
        }