public void SetAttributes(Dictionary <string, string> attributes)
        {
            InstrumentKey instrumentKey;
            bool          boolValue = false;

            foreach (string key in attributes.Keys)
            {
                if (key.Equals("Name"))
                {
                    Name = attributes[key];
                }
                else if (key.Equals("FilterInstrumentKey") && TTConvert.TryCreateInstrumentKey(attributes[key], out instrumentKey))
                {
                    this.FilterByInstrument(instrumentKey);
                    this.m_FilterType = FilterType.Instrument;
                }
                else if (key.Equals("FilterAccount"))
                {
                    this.FilterByAccount(attributes[key]);
                    this.m_FilterType = FilterType.Account;
                }
                else if (key.Equals("LogAllFills") && bool.TryParse(attributes[key], out boolValue))
                {
                    this.m_LogAllFillPropertiesFromTT = boolValue;
                }
            }
        }
        }//ProcessMarketCatalogUpdate()

        //
        // *****************************************************************
        // ****             ProcessProductCatalogUpdate()               ****
        // *****************************************************************
        /// <summary>
        /// TT sent us a ProductCatalogUpdate event. Update our list of internal products.
        /// Called by hub thread.
        /// </summary>
        /// <param name="eventArg"></param>
        private void ProcessProductCatalogUpdate(ProductCatalogUpdatedEventArgs eventArg)
        {
            List <Misty.Lib.Products.Product> productList = new List <MistyProds.Product>();

            foreach (Product ttProduct in eventArg.Added)                    // loop thru each ttProduct found in event.
            {
                Misty.Lib.Products.Product ourProduct;
                if (TTConvert.TryConvert(ttProduct, out ourProduct)) // Create one of our product objects for each.
                {                                                    // Success!
                    productList.Add(ourProduct);
                    Log.NewEntry(LogLevel.Minor, "ProcessProductCatalogUpdate: Found product {0} -> {1}. ", ttProduct.Name, ourProduct);
                    if (!m_Products.ContainsKey(ttProduct.Key))
                    {
                        m_Products.Add(ttProduct.Key, ttProduct);           // store the actual TT product.
                        lock (m_ProductMapLock)
                        {
                            m_ProductMap.Add(ourProduct, ttProduct.Key);    // my product -->  productKey map
                            m_ProductMapKey.Add(ttProduct.Key, ourProduct); // product key --> my product map
                        }
                    }
                    else
                    {
                        Log.NewEntry(LogLevel.Warning, "ProcessProductCatalogUpdate: Received duplicate product! Received {0} <--> {1}", ttProduct.Name, ourProduct);
                    }
                }
                else
                {   // Since products include server name, there should never be two duplicates!
                    Log.NewEntry(LogLevel.Minor, "ProcessProductCatalogUpdate: Unknown product type {0}. ", ttProduct.Name);
                }
            }
            // Fire the event to our subscribers.
            OnMarketFoundResource(productList);                      // TODO: Send all products, all for this server, or just the new ones?
        }//ProcessProductCatalogUpdate()
Exemple #3
0
        }     //InstrumentCatalog_InstrumentsUpdated()

        //
        //
        private void InstrumentLookup_InstrumentUpdated(object sender, InstrumentLookupSubscriptionEventArgs eventArgs)
        {
            if (eventArgs.Instrument != null && eventArgs.Error == null)
            {
                MistyProd.InstrumentName instrName;
                Instrument ttInstrument = eventArgs.Instrument;
                if (TTConvert.TryConvert(ttInstrument, out instrName))
                {   // Success in converting to our internal naming scheme.
                    InstrumentDetails details;
                    if (m_InstrumentDetails.TryGetValue(instrName, out details))
                    {   // This instrument was already added!
                        if (!ttInstrument.Key.Equals(details.Key))
                        {
                            Log.NewEntry(LogLevel.Warning, "{0}: Instrument {1} found before with non-unique key {2}!", this.Name, instrName.FullName, instrName.SeriesName);
                        }
                        else
                        {
                            Log.NewEntry(LogLevel.Warning, "{0}: Instrument {1} found before and keys match! Good.", this.Name, instrName.FullName);
                        }
                    }
                    else
                    {
                        m_KeyToInstruments.Add(ttInstrument.Key, instrName);
                        m_InstrumentDetails.Add(instrName, ttInstrument.InstrumentDetails);
                        Log.NewEntry(LogLevel.Minor, "{0}: Instruments found {1} <---> {2}.", this.Name, instrName, ttInstrument.Key.ToString());
                    }
                }
                else
                {   // Failed to convert TT instrument to a Misty Instrument.
                    // This happens because either their name is too confusing to know what it is.
                    // Or, more likely, we are set to ignore the product type (options, equity, swaps).
                    Log.NewEntry(LogLevel.Warning, "{0}: Instrument creation failed for {1}.", this.Name, ttInstrument.Key.ToString());
                }
                OnInstrumentsFound();
            }
            else if (eventArgs.IsFinal)
            {   // Instrument was not found and TTAPI has given up on looking.
                if (eventArgs.Instrument != null)
                {
                    Log.NewEntry(LogLevel.Warning, "{0}: TTAPI gave up looking for {1}.", this.Name, eventArgs.Instrument.Key.ToString());
                }
                else
                {
                    Log.NewEntry(LogLevel.Warning, "{0}: TTAPI gave up looking for something. ", this.Name, eventArgs.RequestInfo.ToString());
                }
            }
        }//InstrumentLookup_Callback()
Exemple #4
0
        public void SetAttributes(Dictionary <string, string> attributes)
        {
            InstrumentName name;
            InstrumentKey  ttkey;

            foreach (string key in attributes.Keys)
            {
                if (key.Equals("Name") && InstrumentName.TryDeserialize(attributes["Name"], out name))
                {
                    this.Name = name;
                }
                else if (key.Equals("Key") && TTConvert.TryCreateInstrumentKey(attributes["Key"], out ttkey))
                {
                    this.Key = ttkey;
                }
            }
        }
Exemple #5
0
        }     //ProcessAJob()

        //

        //
        #endregion// private methods



        #region TT Callback Event Handlers
        // *****************************************************************************
        // ****                     TT Callback Event Handlers                      ****
        // *****************************************************************************
        /// <summary>
        /// Using TT's dispatcher model, the thread in these methods is my local thread.
        /// </summary>
        private void InstrumentCatalog_InstrumentsUpdated(object sender, InstrumentCatalogUpdatedEventArgs eventArgs)
        {
            if (m_isDisposing)
            {
                return;
            }
            if (eventArgs.Error != null)
            {
                Log.NewEntry(LogLevel.Warning, "{0}: Error in instrument catalog {1}.", this.Name, eventArgs.Error.Message);
                return;
            }
            //
            foreach (Instrument ttInstrument in eventArgs.Added)
            {
                MistyProd.InstrumentName instrName;
                if (TTConvert.TryConvert(ttInstrument, out instrName))
                {   // Success in converting to our internal type.
                    InstrumentDetails details;
                    if (m_InstrumentDetails.TryGetValue(instrName, out details))
                    {                                                               // This instrument was already added!
                        if (!ttInstrument.Key.Equals(details.Key))
                        {
                            Log.NewEntry(LogLevel.Warning, "{0}: Instrument {1} found before with non-unique key {2}!", this.Name, instrName.FullName, instrName.SeriesName);
                        }
                        else
                        {
                            Log.NewEntry(LogLevel.Warning, "{0}: Instrument {1} found before and keys match! Good.", this.Name, instrName.FullName);
                        }
                    }
                    else
                    {
                        m_KeyToInstruments.Add(ttInstrument.Key, instrName);
                        m_InstrumentDetails.Add(instrName, ttInstrument.InstrumentDetails);
                        Log.NewEntry(LogLevel.Minor, "{0}: Instruments found {1} <---> {2}.", this.Name, instrName, ttInstrument.Key.ToString());
                    }
                }
                else
                {   // Failed to convert TT instrument to a Misty Instrument.
                    // This happens because either their name is too confusing to know what it is.
                    // Or, more likely, we are set to ignore the product type (options, equity, swaps).
                    Log.NewEntry(LogLevel.Warning, "{0}: Instrument creation failed for {1}.", ttInstrument.Key.ToString());
                }
            } // next instr added
            OnInstrumentsFound();                                                       // Trigger event for subscribers
        }     //InstrumentCatalog_InstrumentsUpdated()
        /// <summary>
        /// Creates a fill event from the pair-wise info in drop.
        /// Allowed keys:
        ///     Time - the time the drop was made.
        ///     LocalFillTime - local time fill was received.
        /// </summary>
        /// <param name="pairs"></param>
        /// <returns></returns>
        private FillEventArgs CreateFillEvent(Dictionary <string, string> pairs)
        {
            string sQty;
            string sPrice;

            if (pairs.TryGetValue("Qty", out sQty) && pairs.TryGetValue("Price", out sPrice))
            {
                UV.Lib.OrderHubs.Fill aFill = UV.Lib.OrderHubs.Fill.Create();
                aFill.Qty   = Convert.ToInt32(sQty);
                aFill.Price = Convert.ToDouble(sPrice);

                // Extract fill times.
                if (pairs.ContainsKey("LocalFillTime"))
                {
                    aFill.LocalTime = Convert.ToDateTime(pairs["LocalFillTime"]);                    // use fill time, if available.
                }
                else
                {
                    aFill.LocalTime = Convert.ToDateTime(pairs["Time"]);                             // else use last drop time- legacy approach
                }
                // Extract TT's instrument key.
                InstrumentKey key;
                string        sForeignKey;
                if (pairs.TryGetValue("ForeignKey", out sForeignKey) && TTConvert.TryCreateInstrumentKey(sForeignKey, out key))
                {
                    FillEventArgs e = new FillEventArgs(key, FillType.InitialPosition, aFill);
                    return(e);   // success!
                }
                else
                {
                    Log.NewEntry(LogLevel.Error, "Failed to recreate instrument key from {0}.", sForeignKey);
                    return(null);
                }
            }
            else
            {
                Log.NewEntry(LogLevel.Error, "Failed to create a fill event");
                return(null);
            }
        }// CreateFillEvent()
        public void SetAttributes(Dictionary <string, string> attributes)
        {
            this.Fill = new UV.Lib.OrderHubs.Fill();
            ((IStringifiable)this.Fill).SetAttributes(attributes);

            FillType type;

            TradingTechnologies.TTAPI.InstrumentKey ttInstrumentKey;
            foreach (string key in attributes.Keys)
            {
                if (key == "Type" && Enum.TryParse <FillType>(attributes[key], out type))
                {
                    this.Type = type;
                }
                else if (key == "InstrumentKey" && TTConvert.TryCreateInstrumentKey(attributes[key], out ttInstrumentKey))
                {
                    this.TTInstrumentKey = ttInstrumentKey;
                }
                else if (key == "FillKey")
                {
                    this.FillKey = attributes[key];
                }
            }
        }
Exemple #8
0
        // *****************************************************************
        // ****                     Properties                          ****
        // *****************************************************************
        //
        //
        #endregion//Properties


        #region Public Methods
        // *****************************************************************
        // ****                     Public Methods                      ****
        // *****************************************************************
        //
        //
        //
        //
        //
        //
        /// <summary>
        /// This function reads all lines in the audit trail file, generating fill event args and store them.
        /// In addition to that, it also collect the last most recent fill information and update the position for the next step.
        /// </summary>
        /// <param name="startDateTime"></param>
        /// <param name="endDateTime"></param>
        /// <returns></returns>
        public bool TryReadAuditTrailFills(DateTime startDateTime, DateTime endDateTime, AuditTrailFillHub auditTrailFillHub)
        {
            // This method will load the audit trail fills from TT given start and end date time automatically.
            // The results will be added to the audit trail fills dictionary.
            // It will also construct the fill hub name by user dictionary.

            // Get the target audit trail files to read. The file name format is AuditLog_yyyy-mm-dd_N.
            DateTime startDate;
            DateTime endDate;

            startDate = startDateTime.Subtract(startDateTime.TimeOfDay);
            while (startDate.DayOfWeek == DayOfWeek.Saturday || startDate.DayOfWeek == DayOfWeek.Sunday)
            {
                startDate = startDate.AddDays(-1);
            }
            endDate = endDateTime.Subtract(endDateTime.TimeOfDay).AddDays(1);
            while (endDate.DayOfWeek == DayOfWeek.Saturday || endDate.DayOfWeek == DayOfWeek.Sunday)
            {
                endDate = endDate.AddDays(1);
            }
            if (!System.IO.Directory.Exists(m_AuditTrailPath))
            {
                System.IO.Directory.CreateDirectory(m_AuditTrailPath);
            }
            string          pattern         = "AuditLog*.mdb";
            List <string>   fileList        = new List <string>();
            List <string>   targetFileList  = new List <string>();
            List <string>   targetTableList = new List <string>();
            List <DateTime> targetDateList  = new List <DateTime>();

            fileList.AddRange(System.IO.Directory.GetFiles(m_AuditTrailPath, pattern));
            int      dateDelimiterStart;
            int      dateDelimiterEnd;
            DateTime fileDate = DateTime.MinValue;
            string   fileDateString;

            // Loop through the file collection and choose the desired files.
            foreach (string fileName in fileList)
            {
                dateDelimiterEnd   = fileName.LastIndexOf("_");
                dateDelimiterStart = fileName.LastIndexOf("_", dateDelimiterEnd - 1);

                if (dateDelimiterStart < fileName.Length && dateDelimiterEnd < fileName.Length)
                {
                    fileDateString = fileName.Substring(dateDelimiterStart + 1, dateDelimiterEnd - dateDelimiterStart - 1);
                    if (DateTime.TryParseExact(fileDateString, "yyyy-MM-dd", null, System.Globalization.DateTimeStyles.None, out fileDate))
                    {
                        if (startDate <= fileDate && fileDate <= endDate)
                        {
                            Log.NewEntry(LogLevel.Minor, "Include the file name:{0}.", fileName);
                            targetFileList.Add(fileName);
                            targetTableList.Add(fileDate.ToString("MMMdd"));
                            targetDateList.Add(fileDate);
                        }
                        else
                        {
                            Log.NewEntry(LogLevel.Major, "Exclude the file name:{0}.", fileName);
                            continue;
                        }
                    }
                    else
                    {
                        Log.NewEntry(LogLevel.Major, "There is problem in parsing file date string:{0}.", fileDateString);
                        continue;
                    }
                }
                else
                {
                    Log.NewEntry(LogLevel.Major, "There is problem in parsing file name:{0}.", fileName);
                    continue;
                }
            }

            // Build the connections and load data from the file collection.
            m_FillEventArgsList.Clear();
            bool isBadRow;
            List <InstrumentKey> instrumentKeyList = new List <InstrumentKey>();
            bool readAllFillAccounts = false;

            if (auditTrailFillHub.HubName == string.Empty)
            {
                readAllFillAccounts = true;
            }
            for (int fileIndex = 0; fileIndex < targetFileList.Count; ++fileIndex)
            {
                // Read from the audit file.
                List <List <object> > dataCollections = new List <List <object> >();
                if (AccessReader.TryReadAccessFile(targetFileList[fileIndex], targetTableList[fileIndex], out dataCollections))
                {
                    // Get the information from the output. All the values are in object type.
                    int rowNumber = dataCollections.Count;
                    for (int rowIndex = 0; rowIndex < rowNumber; ++rowIndex)
                    {
                        isBadRow = false;

                        // The valid data types are explored in detail by test program.
                        string localTimeStamp = (string)dataCollections[rowIndex][ObjectListSchema.LocalTimeStamp];
                        string exchangeName   = (string)dataCollections[rowIndex][ObjectListSchema.ExchangeName];
                        string orderStatus    = (string)dataCollections[rowIndex][ObjectListSchema.OrderStatus];
                        string orderAction    = (string)dataCollections[rowIndex][ObjectListSchema.OrderAction];
                        string orderSide      = (string)dataCollections[rowIndex][ObjectListSchema.OrderSide];
                        int    orderQty       = (int)dataCollections[rowIndex][ObjectListSchema.OrderQty];
                        string product        = (string)dataCollections[rowIndex][ObjectListSchema.Product];
                        string contract       = (string)dataCollections[rowIndex][ObjectListSchema.Contract];
                        string orderPrice     = (string)dataCollections[rowIndex][ObjectListSchema.OrderPrice];
                        string accountName    = (string)dataCollections[rowIndex][ObjectListSchema.AccountName];
                        string userName       = (string)dataCollections[rowIndex][ObjectListSchema.UserName];
                        string exchangeTime   = (string)dataCollections[rowIndex][ObjectListSchema.ExchangeTime];
                        string exchangeDate   = (string)dataCollections[rowIndex][ObjectListSchema.ExchangeDate];
                        string tradeSource    = (string)dataCollections[rowIndex][ObjectListSchema.TradeSource];
                        string ttOrderKey     = (string)dataCollections[rowIndex][ObjectListSchema.TTOrderKey];
                        string ttSeriesKey    = (string)dataCollections[rowIndex][ObjectListSchema.TTSeriesKey];

                        // Check whether the account is desired.
                        if (!readAllFillAccounts && !accountName.Equals(m_FillHubName))
                        {
                            continue;
                        }

                        // Check whether the exchange name includes AlgoSE sub string.
                        if (exchangeName.Contains(m_ExchangeName_AlgoSE))
                        {
                            continue;
                        }

                        // Check whether it is a fill event.
                        if (!orderAction.Equals(m_Action_Fill) && !orderAction.Equals(m_Action_PartialFill))
                        {
                            continue;
                        }

                        // Check whether it is a OK status.
                        if (!orderStatus.Equals(m_OrderStatus_OK))
                        {
                            continue;
                        }

                        // Check whether the product type is future.
                        if (product.Equals(m_Product_AutoSpreader))
                        {
                            continue;
                        }

                        // Check whether the contract string contains Calendar string to avoid duplicate fills.
                        foreach (string specialString in m_Contract_Special)
                        {
                            if (contract.Contains(specialString))
                            {
                                isBadRow = true;
                                if (exchangeName.Contains("TOCOM") && specialString.Equals("/") && isBadRow)
                                {
                                    isBadRow = false;
                                }
                                break;
                            }
                        }
                        if (isBadRow)
                        {
                            continue;
                        }

                        // Try parse some necessary variables.
                        DateTime localDateTimeValid = DateTime.MinValue;
                        DateTime exchangeTimeValid  = DateTime.MinValue;
                        DateTime exchangeDateValid  = DateTime.MinValue;
                        double   fillPrice          = double.NaN;
                        if (!DateTime.TryParseExact(localTimeStamp, "HH:mm:ss.fff", null, System.Globalization.DateTimeStyles.None, out localDateTimeValid))
                        {
                            Log.NewEntry(LogLevel.Major, "Failed to parse the utc time of {0}.", localTimeStamp);
                            continue;
                        }
                        if (!DateTime.TryParseExact(exchangeTime, "HH:mm:ss.fff", null, System.Globalization.DateTimeStyles.None, out exchangeTimeValid))
                        {
                            Log.NewEntry(LogLevel.Major, "Failed to parse the exchange time of {0}.", exchangeTime);
                            continue;
                        }
                        if (!DateTime.TryParseExact(exchangeDate, "ddMMMyy", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out exchangeDateValid))
                        {
                            Log.NewEntry(LogLevel.Major, "Failed to parse the exchange time of {0}.", exchangeDate);
                            continue;
                        }
                        if (!double.TryParse(orderPrice, out fillPrice))
                        {
                            Log.NewEntry(LogLevel.Major, "Failed to parse the order price of {0}.", orderPrice);
                            continue;
                        }
                        localDateTimeValid = targetDateList[fileIndex].Add(localDateTimeValid.TimeOfDay);
                        exchangeTimeValid  = exchangeDateValid.Add(exchangeTimeValid.TimeOfDay);

                        // Edit the market.
                        int validEndIndex = exchangeName.LastIndexOf("-");
                        if (validEndIndex >= 0)
                        {
                            exchangeName = exchangeName.Substring(0, validEndIndex);
                        }

                        // Create fill.
                        Fill fill = new Fill();
                        fill.ExchangeTime = exchangeTimeValid;
                        //TimeZoneInfo localTimeZone = TimeZoneInfo.FindSystemTimeZoneById(m_LocalTimeZoneString);
                        //DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(localDateTimeValid, localTimeZone);
                        fill.LocalTime = localDateTimeValid;
                        fill.Price     = fillPrice;
                        fill.Qty       = orderSide.Equals(m_OrderSide_Buy) ? orderQty : (orderSide.Equals(m_OrderSide_Sell) ? -orderQty : 0);

                        // Create fill event args.
                        InstrumentKey instrumentKey = new InstrumentKey(exchangeName, TradingTechnologies.TTAPI.ProductType.Future, product, ttSeriesKey);
                        FillEventArgs fillEventArgs = new FillEventArgs();
                        fillEventArgs.Fill      = fill;
                        fillEventArgs.AccountID = accountName;
                        //fillEventArgs.FillKey = ttOrderKey;
                        fillEventArgs.Type            = FillType.Historic;
                        fillEventArgs.TTInstrumentKey = instrumentKey;

                        // Add the instrument key to the list.
                        if (startDateTime.AddSeconds(-3) <= localDateTimeValid && localDateTimeValid <= endDateTime.AddSeconds(3))
                        {
                            if (!TTConvert.CheckExistenceOfInstrumentKey(instrumentKeyList, instrumentKey))
                            {
                                instrumentKeyList.Add(instrumentKey);
                            }

                            // Add the fill event args to the list.
                            string rowInfo = string.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}.", localTimeStamp, exchangeName, orderStatus, orderAction, orderSide, orderQty, product, contract, orderPrice, accountName, userName, exchangeTime, exchangeDate, tradeSource, ttOrderKey, ttSeriesKey);
                            Log.NewEntry(LogLevel.Minor, "Record:{0}", rowInfo);
                            m_FillEventArgsList.Add(fillEventArgs);
                        }
                    }
                }
                else
                {
                    Log.NewEntry(LogLevel.Major, "Failed to read access file with name:{0}.", targetFileList[fileIndex]);
                    continue;
                }

                Log.NewEntry(LogLevel.Minor, "Complete reading access file with name:{0}.", targetFileList[fileIndex]);
            }

            // Get the last local time of fill for each instrument in initial fill hub.
            m_NeededBookInstrumentList.Clear();
            //foreach (InstrumentKey ttKeyInWaitList in auditTrailFillHub.InitialWaitDictionary.Keys)
            //{
            //    // These fills that do not have books will be requested to create new books if possible. To ensure they have books, create them if necessary here.
            //    if (!auditTrailFillHub.TryCheckExistenceOfInstrumentKey(ttKeyInWaitList) && !TTConvert.CheckExistenceOfInstrumentKey(neededBookInstrumentList, ttKeyInWaitList))
            //    {
            //        neededBookInstrumentList.Add(ttKeyInWaitList);
            //    }
            //}

            // For the fills from the audit trail files, also get instruments that need books.
            foreach (InstrumentKey instrumentKeyInAuditTrail in instrumentKeyList)
            {
                if (!auditTrailFillHub.TryCheckExistenceOfInstrumentKey(instrumentKeyInAuditTrail) && !TTConvert.CheckExistenceOfInstrumentKey(m_NeededBookInstrumentList, instrumentKeyInAuditTrail))
                {
                    m_NeededBookInstrumentList.Add(instrumentKeyInAuditTrail);
                }
            }

            // Clear all trades in the waiting list because they are all included in the audit trail files.
            auditTrailFillHub.InitialWaitDictionary.Clear();

            // Create books if necessary.
            // The instrument that need book creation is those got from FillEventArgs from drop file and the new fills listened in the audit trail file.
            // It is crucial to get all the books ready before updating positions.
            foreach (InstrumentKey key in m_NeededBookInstrumentList)
            {
                OrderHubRequest creatFillBookRequest = new OrderHubRequest(OrderHubRequest.RequestType.RequestCreateFillBook);
                creatFillBookRequest.Data    = new object[1];
                creatFillBookRequest.Data[0] = key;
                auditTrailFillHub.HubEventEnqueue(creatFillBookRequest);
            }

            Log.NewEntry(LogLevel.Minor, "Complete loading audit trail fills.");
            return(true);
        }
Exemple #9
0
        }//StoreOrder()

        //
        //
        //
        #endregion // order update handlers


        #region Private Methods
        // *****************************************************************
        // ****                     Private Methods                     ****
        // *****************************************************************
        //
        //
        //
        //
        // *****************************************************
        // ****             Try Create New Book()           ****
        // *****************************************************
        private bool TryCreateNewBook(TT.InstrumentKey ttKey, out OrderBookTT book)
        {
            book = null;
            InstrumentName name;

            TT.InstrumentDetails details;
            if (m_Market.TryLookupInstrument(ttKey, out name) && m_Market.TryLookupInstrumentDetails(name, out details))
            {                                       // Market knows this instrument already.
                Log.BeginEntry(LogLevel.Minor, "TryCreateNewBook: Creating book.");
                book = new OrderBookTT(this, name); // Create book.
                double minTickSize = Convert.ToDouble(details.TickSize.Numerator) / Convert.ToDouble(details.TickSize.Denominator);
                book.MinimumPriceTick = minTickSize;
                if (m_Books.TryAdd(book.m_InstrumentName, book))
                {
                    m_TTKey2Name.TryAdd(ttKey, book.m_InstrumentName);

                    Log.AppendEntry(" New book created {0}.", book);
                    Log.EndEntry();
                    return(true);
                }
                else
                {
                    Log.AppendEntry(" Failed to add book to Books.");
                    Log.EndEntry();
                    return(false);
                }
            }
            else
            {                                       // Market doesnt know this instrument yet.
                Log.NewEntry(LogLevel.Minor, "TryCreateNewBook: Market instrument unknown.  Requesting details from market for {0}.", TTConvert.ToString(ttKey));
                m_Market.RequestInstruments(ttKey); // request to look it up.
                return(false);
            }
        }//TryCreateNewBook()