Example #1
0
        private static void ProcessSecurity(int securityId, int currencyId)
        {
            bool didDataChange = false;

            try
            {
                // Lock the tables.
                Debug.Assert(!ServerMarketData.IsLocked);
                ServerMarketData.PriceLock.AcquireWriterLock(Timeout.Infinite);
                ServerMarketData.SecurityLock.AcquireReaderLock(Timeout.Infinite);


                // get the price row associated with this security
                ServerMarketData.PriceRow priceRow = ServerMarketData.Price.FindBySecurityId(securityId);

                // if the row does not exist add it
                if (priceRow == null)
                {
                    priceRow = ServerMarketData.Price.NewPriceRow();
                    //priceRow.RowVersion = ServerMarketData.RowVersion.Increment();
                    priceRow.SecurityId = securityId;
                    priceRow.CurrencyId = currencyId;
                    priceRow.LastPrice  = 1.0M;
                    priceRow.AskPrice   = 1.01M;
                    priceRow.BidPrice   = 0.99M;
                    priceRow.Volume     = 0.0M;
                    priceRow.VolumeWeightedAveragePrice = priceRow.LastPrice;
                    priceRow.HighPrice  = priceRow.LastPrice;
                    priceRow.LowPrice   = priceRow.LastPrice;
                    priceRow.OpenPrice  = priceRow.LastPrice;
                    priceRow.ClosePrice = priceRow.LastPrice;

                    ServerMarketData.Price.AddPriceRow(priceRow);

                    openingPriceMap.Add(priceRow.SecurityId, priceRow.LastPrice);
                }

                // if we got a row then process it
                if (priceRow != null)
                {
                    // get the opening price
                    decimal openingPrice = priceRow.LastPrice;
                    if (openingPriceMap.Contains(securityId))
                    {
                        openingPrice = (decimal)openingPriceMap[securityId];
                    }
                    if (openingPrice == 0)
                    {
                        openingPrice = 10;
                    }

                    // if we do not already have a volume or approx every 50th(ish) time update the volume
                    if (priceRow.Volume <= 0 || (random.Next(50) == 0))
                    {
                        // if this security ID is not already in the volume table pick a randon volume divergrance (-50% to 50%)
                        // and add it to the table
                        double volumeDivergence = 0.0;
                        if (volumeDivergenceMap.Contains(securityId))
                        {
                            volumeDivergence = (double)volumeDivergenceMap[securityId];
                        }
                        else
                        {
                            volumeDivergence = (double)random.Next(-50, 50);
                        }

                        // increase or decrease by up to 1%
                        int divergenceChangePercent = random.Next(-100, 100);

                        // don't go over 50% up or down
                        volumeDivergence = Math.Max(-50.0, Math.Min(50.0, volumeDivergence + ((double)divergenceChangePercent / 100.0)));

                        // update the volume divergence table
                        volumeDivergenceMap[securityId] = volumeDivergence;

                        // get the estimated volume for this time of day
                        decimal projectVolume = ProjectedVolume(DateTime.Now, priceRow.SecurityRow.AverageDailyVolume);

                        // adjust it by the divergence we are using and update the price table
                        priceRow.Volume = (int)(projectVolume - (int)((double)projectVolume * (volumeDivergence / 100.0)));
                        didDataChange   = true;
                    }

                    // base the frequency of price updates to the ADV of the security
                    int updateFrequency = 10;
                    if (priceRow.SecurityRow.AverageDailyVolume < 1000000)      /* UNDER 1M about every 75 loops*/
                    {
                        updateFrequency = 75;
                    }
                    else
                    if (priceRow.SecurityRow.AverageDailyVolume < 5000000)      /* 1M to 5M about every 30 loops */
                    {
                        updateFrequency = 30;
                    }
                    else
                    {
                        updateFrequency = 20;                                    /* OVER 5M about every 20 loops*/
                    }
                    // about once every X loops update the price
                    if (random.Next(updateFrequency) == 0)
                    {
                        // the anount of change will be based on stock price
                        // < $10 ==     always 0.01 (plus or minus)
                        // $10 - 25 ==  0.01 to 0.02 (plus or minus)
                        // $25 - 100 == 0.01 to 0.03 (plus or minus)
                        // > $100  == 0.01 to 0.05 (plus or minus)
                        double priceChange = 0;
                        if (priceRow.LastPrice < 10)
                        {
                            priceChange = 0.01 - ((double)random.Next(3) * 0.01);
                        }
                        else
                        if (priceRow.LastPrice < 25)
                        {
                            priceChange = 0.02 - ((double)random.Next(5) * 0.01);
                        }
                        else
                        if (priceRow.LastPrice < 100)
                        {
                            priceChange = 0.03 - ((double)random.Next(7) * 0.01);
                        }
                        else
                        {
                            priceChange = 0.05 - ((double)random.Next(11) * 0.01);
                        }

                        // change the last price
                        decimal newPrice          = priceRow.LastPrice + (decimal)priceChange;
                        decimal lastChange        = openingPrice - newPrice;
                        double  lastChangepercent = ((double)(openingPrice - lastChange)) / (double)openingPrice;

                        // don't let it go over 20% change per day
                        if (Math.Abs(lastChangepercent) < 20)
                        {
                            priceRow.LastPrice = newPrice;
                        }

                        // set the spread to be 1 to 5 cents
                        int     spreadInCents = random.Next(1, 5);
                        decimal spread        = (decimal)spreadInCents / 100m;

                        // set the bid to be 0 to (spread - 1) cents below the price
                        priceRow.BidPrice = priceRow.LastPrice - ((decimal)random.Next(spreadInCents) / 100m);

                        // set the ask based on the spread
                        priceRow.AskPrice = priceRow.BidPrice + spread;

                        // set the bid ask size
                        priceRow.BidSize = random.Next(1, 999) * 100;
                        priceRow.AskSize = random.Next(1, 999) * 100;

                        // check to see if we are at a new high or low for the day
                        if (priceRow.LastPrice > priceRow.HighPrice)
                        {
                            priceRow.HighPrice = priceRow.LastPrice;
                        }
                        if (priceRow.LastPrice < priceRow.LowPrice)
                        {
                            priceRow.LowPrice = priceRow.LastPrice;
                        }


                        // set the VWAP to be the average of the open and last
                        // however don't let it be more than 5% from the last
                        decimal newVwap           = (priceRow.LastPrice + priceRow.OpenPrice) / 2;
                        decimal fivePercentOfLast = priceRow.LastPrice * 0.05M;
                        priceRow.VolumeWeightedAveragePrice = Math.Max(Math.Min(newVwap, (priceRow.LastPrice + fivePercentOfLast)), (priceRow.LastPrice - fivePercentOfLast));
                        didDataChange = true;
                    }
                }

                // if something changeds update the data model
                if (didDataChange)
                {
                    priceRow.RowVersion = ServerMarketData.RowVersion.Increment();
                    priceRow.AcceptChanges();
                }
            }
            catch (Exception exception)
            {
                // Write the error and stack trace out to the debug listener
                MarkThree.EventLog.Error(String.Format("{0}, {1}", exception.Message, exception.StackTrace));
            }
            finally
            {
                // Release the global tables.
                if (ServerMarketData.PriceLock.IsWriterLockHeld)
                {
                    ServerMarketData.PriceLock.ReleaseWriterLock();
                }
                if (ServerMarketData.SecurityLock.IsReaderLockHeld)
                {
                    ServerMarketData.SecurityLock.ReleaseReaderLock();
                }
                Debug.Assert(!ServerMarketData.IsLocked);
            }
        }
Example #2
0
        public static void OnUpdateSymbolDM(object wrapper, DMUpdateSymbolArgs args)
        {
            // StockInfo object holding the new symbol data for this update
            StockInfo stockInfo = args.stockInfo;

            try
            {
                // Lock the tables.
                Debug.Assert(!ServerMarketData.IsLocked);
                ServerMarketData.EquityLock.AcquireReaderLock(Timeout.Infinite);
                ServerMarketData.PriceLock.AcquireWriterLock(Timeout.Infinite);
                ServerMarketData.SecurityLock.AcquireReaderLock(Timeout.Infinite);

                // make sure the symbol is in the hash table - and that we added it to the data manager
                if (!symbolToSecurityIdTable.ContainsKey(stockInfo.Symbol))
                {
                    throw new Exception("Received update for unknown symbol: " + stockInfo.Symbol);
                }

                // get the security id of the symbol
                int securityID = (int)symbolToSecurityIdTable[stockInfo.Symbol];

                // get the security row
                ServerMarketData.SecurityRow securityRow = ServerMarketData.Security.FindBySecurityId(securityID);
                if (securityRow == null)
                {
                    throw new Exception("Warning: Could not find security row for symbol: " + stockInfo.Symbol);
                }

                //int equityId = Security.FindRequiredKey(configurationId, "equityId", externalEquityId);
                // Only Equities are priced by this simulator.  All others are ignored.
                ServerMarketData.EquityRow equityRow = ServerMarketData.Equity.FindByEquityId(securityRow.SecurityId);
                if (equityRow != null)
                {
                    // Find a price that matches the equity's default settlement.  This is the price record that will be updated
                    // with the simulated market conditions.
                    ServerMarketData.PriceRow priceRow = ServerMarketData.Price.FindBySecurityId(securityRow.SecurityId);
                    if (priceRow == null)
                    {
                        priceRow = ServerMarketData.Price.NewPriceRow();
                        //priceRow.RowVersion = ServerMarketData.RowVersion.Increment();
                        priceRow.SecurityId = equityRow.EquityId;
                        priceRow.CurrencyId = equityRow.SettlementId;
                        priceRow.LastPrice  = 0.0M;
                        priceRow.AskPrice   = 0.0M;
                        priceRow.BidPrice   = 0.0M;
                        priceRow.Volume     = 0.0M;
                        priceRow.ClosePrice = 0.0M;
                        priceRow.VolumeWeightedAveragePrice = 0.0M;
                        priceRow.HighPrice = 0.0M;
                        priceRow.LowPrice  = 0.0M;
                        ServerMarketData.Price.AddPriceRow(priceRow);
                    }

                    // set the new values from the real time event into the price row
                    priceRow.BidSize   = stockInfo.BidSize;
                    priceRow.BidPrice  = Convert.ToDecimal(stockInfo.BidPrice);
                    priceRow.AskPrice  = Convert.ToDecimal(stockInfo.AskPrice);
                    priceRow.AskSize   = Convert.ToDecimal(stockInfo.AskSize);
                    priceRow.LastPrice = Convert.ToDecimal(stockInfo.LastPrice);
                    priceRow.LastSize  = stockInfo.TradeVolume;
                    priceRow.Volume    = Convert.ToDecimal(stockInfo.TotalVolume);
                    priceRow.VolumeWeightedAveragePrice = (Convert.ToDecimal(stockInfo.LastPrice) + Convert.ToDecimal(stockInfo.OpenPrice)) / 2;
                    priceRow.OpenPrice  = Convert.ToDecimal(stockInfo.OpenPrice);
                    priceRow.LowPrice   = Convert.ToDecimal(stockInfo.LowPrice);
                    priceRow.HighPrice  = Convert.ToDecimal(stockInfo.HighPrice);
                    priceRow.ClosePrice = Convert.ToDecimal(stockInfo.PreviousPrice);

                    // increment the RowVersion so the client notices!!!
                    priceRow.RowVersion = ServerMarketData.RowVersion.Increment();

                    // commit the changes
                    priceRow.AcceptChanges();
                }
            }
            catch (Exception exception)
            {
                String msg = String.Format("{0}, {1}", exception.Message, exception.StackTrace);

                // Write the error and stack trace out to the debug listener
                //Debug.WriteLine(msg);
                MarkThree.EventLog.Warning(msg);
            }
            finally
            {
                // Release the global tables.
                if (ServerMarketData.EquityLock.IsReaderLockHeld)
                {
                    ServerMarketData.EquityLock.ReleaseReaderLock();
                }
                if (ServerMarketData.PriceLock.IsWriterLockHeld)
                {
                    ServerMarketData.PriceLock.ReleaseWriterLock();
                }
                if (ServerMarketData.SecurityLock.IsReaderLockHeld)
                {
                    ServerMarketData.SecurityLock.ReleaseReaderLock();
                }
                Debug.Assert(!ServerMarketData.IsLocked);
            }
        }