Ejemplo n.º 1
0
        }//RequestStop()

        //
        //
        //
        //***********************************************
        // ****       RequestProductsToRecord()      ****
        //***********************************************
        //
        /// <summary>
        /// Threadsafe call to request products to recorded.
        ///
        /// Warning this need to be improved to take into account illiquid months!
        /// </summary>
        /// <param name="productRequest"></param>
        /// <returns></returns>
        public bool RequestProductsToRecord(ProductRequest productRequest)
        {
            DataHubRequest request = m_RequestFactory.Get();

            request.Request = RequestCode.RequestProductsToRecord;
            request.Data.Add(productRequest);
            return(this.HubEventEnqueue(request));
        }
Ejemplo n.º 2
0
        //
        //
        /// <summary>
        /// Given a ttOrder try and create a UV style order attempting to use
        /// a recycle order each time.
        /// </summary>
        /// <param name="ttOrder"></param>
        /// <param name="orderRecycler"></param>
        /// <param name="uvOrder"></param>
        /// <returns></returns>
        public static bool TryConvert(Order ttOrder, RecycleFactory <UVOrder> orderRecycler, out UVOrder uvOrder)
        {
            bool isSuccess = true;

            try
            {
                uvOrder = orderRecycler.Get();                      // try and use a recycled order
                if (ttOrder.BuySell == BuySell.Buy)
                {
                    uvOrder.OriginalQtyConfirmed = ttOrder.OrderQuantity;
                    uvOrder.ExecutedQty          = ttOrder.FillQuantity;
                    uvOrder.Side = UVOrder.BuySide;
                }
                else
                {
                    uvOrder.OriginalQtyConfirmed = ttOrder.OrderQuantity * -1;
                    uvOrder.ExecutedQty          = ttOrder.FillQuantity * -1;
                    uvOrder.Side = UVOrder.SellSide;
                }
                uvOrder.OrderTIF            = ToUVTimeinForce(ttOrder.TimeInForce);
                uvOrder.IPriceConfirmed     = ttOrder.LimitPrice.ToTicks() / ttOrder.InstrumentDetails.SmallestTickIncrement;
                uvOrder.TickSize            = ToUVTickSize(ttOrder.InstrumentDetails);
                uvOrder.OrderStateConfirmed = ToUVOrderState(ttOrder.TradeState);
            }
            catch (Exception)
            {
                isSuccess = false;
                uvOrder   = null;
            }
            return(isSuccess);
        }
Ejemplo n.º 3
0
        }//TryCreateNewBook()

        //
        //
        // *************************************************************
        // ****                     GetRequest()                    ****
        // *************************************************************
        /// <summary>
        /// This utility method uses the RequestFactory for request to create
        /// and clear a request for new use.
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        protected MarketHubRequest GetRequest(MarketHubRequest.RequestType request)
        {
            MarketHubRequest eventArg = m_RequestFactory.Get();

            eventArg.Request = request;
            eventArg.Data.Clear();
            return(eventArg);
        }//GetRequest()
Ejemplo n.º 4
0
        //
        //
        //
        //
        //
        //
        #endregion//Public Methods


        #region Private Utility Methods
        // *****************************************************************
        // ****                     Private Methods                     ****
        // *****************************************************************
        //
        //
        /// <summary>
        /// This method gives the caller a eventarg object to use.  It may be new
        /// or recycled from previous usage.
        /// </summary>
        /// <param name="requestType"></param>
        /// <returns></returns>
        private DropQueueWriterEventArgs GetRequest(DropQueueWriterRequestType requestType)
        {
            DropQueueWriterEventArgs eventArgs = m_Factory.Get();

            eventArgs.Clear();
            eventArgs.Request = requestType;
            return(eventArgs);
        }
Ejemplo n.º 5
0
        //
        //
        //
        #endregion//Private Methods


        #region Private Methods
        // *****************************************************************
        // ****                     Private Methods                     ****
        // *****************************************************************
        //
        //
        //
        //
        // ****             GetMessage()            ****
        //
        protected Message GetMessage(MessageType type, MessageState state, params object[] args)
        {
            Message response = m_Messages.Get();

            response.MessageType = type;
            response.State       = state;
            if (args != null)
            {
                foreach (object o in args)
                {
                    if (o is IStringifiable)
                    {
                        response.Data.Add((IStringifiable)o);
                    }
                    else if (o is List <IStringifiable> )
                    {
                        response.Data.AddRange((List <IStringifiable>)o);
                    }
                }
            }
            return(response);
        }//GetMessage()
Ejemplo n.º 6
0
        //
        //
        #endregion//Constructors

        #region no Properties
        // *****************************************************************
        // ****                     Properties                          ****
        // *****************************************************************
        //
        //
        #endregion//Properties

        #region Public Methods
        // *****************************************************************
        // ****                     Public Methods                      ****
        // *****************************************************************
        //
        //
        // *************************************************
        // ****             Try Add()                   ****
        // *************************************************
        /// <summary>
        /// Adds a copy of newOrder into this OrderPage.
        /// </summary>
        /// <param name="newOrder"></param>
        /// <returns>true, if successful.</returns>
        public bool TryAdd(Order newOrder)
        {
            bool isSuccess = true;

            lock (m_Lock)
            {
                // Validate newOrder
                if (m_OrdersById.ContainsKey(newOrder.Id))                      // Check that we don't already have entry for this orderId
                {
                    isSuccess = false;
                }
                if (this.OrderSide != newOrder.Side)                            // Check side of mkt is same as this book.
                {
                    isSuccess = false;
                }

                // Accept order
                if (isSuccess)
                {
                    Order myOrder = m_OrderRecycleFactory.Get();
                    newOrder.CopyTo(myOrder);
                    int iPriceLevel = -this.OrderSign * myOrder.IPricePending;    // Puts lowest (highest) priced sell (buy) orders at lowest price level
                    if (!m_OrdersByPendingPrice.ContainsKey(iPriceLevel))
                    {
                        if (m_RecyclingList.Count > 0)
                        {
                            List <int> recycledList = m_RecyclingList.Dequeue();
                            recycledList.Clear();
                            m_OrdersByPendingPrice.Add(iPriceLevel, recycledList);
                        }
                        else
                        {
                            m_OrdersByPendingPrice.Add(iPriceLevel, new List <int>());
                        }
                    }
                    newOrder.OrderStatePending = OrderState.Submitted;          // set pending state to submitted.
                    myOrder.OrderStatePending  = OrderState.Submitted;
                    m_OrdersByPendingPrice[iPriceLevel].Add(myOrder.Id);        // add to price-list
                    m_OrdersById.Add(myOrder.Id, myOrder);                      // add to id-list.
                }
            }
            // Exit
            return(isSuccess);
        }//Add().
Ejemplo n.º 7
0
        }//CreateOrderBook()

        //
        //
        // *****************************************
        // ****         TryCreateOrder          ****
        // *****************************************
        /// <summary>
        /// The caller wants to create an order.  After creation, the order must be submitted
        /// to the specific OrderBook to be managed.
        /// </summary>
        /// <param name="instrumentName"></param>
        /// <returns></returns>
        public virtual bool TryCreateOrder(InstrumentName instrumentName, int tradeSide, int iPrice, int qty, out Order newOrder)
        {
            newOrder = null;
            if ((UV.Lib.Utilities.QTMath.MktSideToMktSign(tradeSide) * qty) < 0)
            {   // this means our signs are incorrect!
                Log.NewEntry(LogLevel.Error, "Attempt to Create Order For Instrument {0} Failed, Mismatched Sides and Qtys", instrumentName);
                return(false);
            }
            OrderInstrument orderInstrument;

            if (m_OrderInstruments.TryGetValue(instrumentName, out orderInstrument))
            {
                newOrder                    = m_OrderRecycleFactory.Get();
                newOrder.Instrument         = instrumentName;
                newOrder.Id                 = Order.GetNextId();
                newOrder.Side               = tradeSide;
                newOrder.OriginalQtyPending = qty;
                newOrder.IPricePending      = iPrice;
                newOrder.TickSize           = orderInstrument.Details.TickSize;
                newOrder.OrderType          = OrderType.LimitOrder;
            }
            // Exit.
            return(newOrder != null);
        }//CreateOrderBook()
Ejemplo n.º 8
0
        }// ProcessSyntheticOrder()

        //
        //
        //
        //
        //
        #endregion//Public Methods


        #region Private Methods
        // *****************************************************************
        // ****                     Private Methods                     ****
        // *****************************************************************
        //
        //
        //
        //
        //
        // *********************************************************************
        // ****                 DistributeFillsToQuoters()                  ****
        // *********************************************************************
        /// <summary>
        /// This distibutes fills in the list to those quotes provided in the list quotes.
        /// In the process of distrubuting, the fills are removed from the first list, and the
        /// quote quantities are reduced.  PricingEngines that will receive the fills are
        /// added to the "distributedFills" dictionary.  Also, the net position[] array is updated and
        /// fill messages are added to the query.
        /// </summary>
        /// <param name="fillsToDistribute">fills that will be distributed</param>
        /// <param name="quotes">quotes that will be distributed to.</param>
        /// <param name="query"></param>
        /// <param name="distributedFills"></param>
        /// <param name="position"></param>
        protected void DistributeFillsToQuoters(ref List <Fill> fillsToDistribute, ref List <Quote> quotes,
                                                ref FillsQuery query, ref Dictionary <Quote, List <Fill> > distributedFills, ref int[] position)
        {
            DateTime localTime = ParentStrategy.StrategyHub.GetLocalTime();
            int      quoter    = 0;

            while (quoter < quotes.Count && fillsToDistribute.Count > 0)// loop thru each quoter until fills gone.
            {
                Quote quote = quotes[quoter];
                Log.AppendEntry(" [{0}]", quote);
                Fill fill = fillsToDistribute[0]; // consider first fill.
                if (fill.Qty == 0)
                {                                 // this should never happen.
                    Log.AppendEntry(" Removed empty fill {0}.", fill);
                    fillsToDistribute.Remove(fill);
                    continue;
                }
                int tradeSign = Math.Sign(fill.Qty);
                int tradeSide = QTMath.MktSignToMktSide(tradeSign);

                //
                // Determine how much to allocate to this quoter.
                //
                Fill allocatedFill = null;     // fill to allocate to quoter.
                int  remainingQty  = fill.Qty; // qty to be added back to fills list.
                if (quote.Side != tradeSide)
                {                              // This is an error.  Never allocate a fill to a quote for the other side of mkt!
                    Log.AppendEntry(" wrong-side {0}.", QTMath.MktSideToLongString(quote.Side));
                }
                //else if (forceFillAbsQty != 0)
                //{   // Here, we are forcing fills to be allocated even to quoters who have qty = 0.
                //    remainingQty = tradeSign * Math.Max(0, Math.Abs(fill.Qty) - forceFillAbsQty); // force up to full qty.
                //}
                else if (quote.Reason != QuoteReason.Entry && quote.Qty != 0)
                {   // Normal non-entry request. Try to fill this quote as much as possible completely.
                    remainingQty = tradeSign * Math.Max(0, (fill.Qty - quote.Qty) * tradeSign);
                    Log.AppendEntry(" taking {0}, remaining {1},", quote.Qty, remainingQty);
                }
                else if (quote.Reason == QuoteReason.Entry && quote.Qty != 0)
                {   // Normal entry request.  Don't allow entries to violet position limit!
                    int allowedEntryQty = tradeSign * Math.Max(0, m_MaxPosition - Math.Abs(position[tradeSide]));
                    //remainingQty = tradeSign * Math.Max(0, (allowedEntryQty - quote.Qty) * tradeSign);
                    int qtyWeCanTake = Math.Min(Math.Abs(allowedEntryQty), Math.Abs(quote.Qty)) * tradeSign;
                    remainingQty = tradeSign * Math.Max(0, (fill.Qty - qtyWeCanTake) * tradeSign);
                    Log.AppendEntry(" taking {0}, remaining {1},", qtyWeCanTake, remainingQty);
                }

                //
                // Allocate the fill
                //
                if (remainingQty == 0)
                {                                   // This fill is completely consumed by the quoter.
                    fillsToDistribute.Remove(fill); // remove fill from list.
                    allocatedFill = fill;
                }
                else if (remainingQty == fill.Qty)
                {   // No qty was consumed at all!?!
                    allocatedFill = null;
                }
                else
                {                                   // This fill is only partially consumed.
                    fillsToDistribute.Remove(fill); // remove original fill from list.
                    Fill remainingFill = Fill.Create(fill);
                    remainingFill.Qty = remainingQty;
                    fillsToDistribute.Insert(0, remainingFill);         // First, replace the unused portion back onto list.

                    allocatedFill     = Fill.Create(fill);
                    allocatedFill.Qty = fill.Qty - remainingQty;        // Allocate the consumed portion.
                }
                if (allocatedFill != null && allocatedFill.Qty != 0)
                {
                    Log.AppendEntry(" filled {1}.", quote.PricingEngine.EngineName, allocatedFill);
                    List <Fill> fills;
                    if (distributedFills.TryGetValue(quote, out fills) == false)
                    {   // No fills had be distributed to this quote previously.
                        fills = m_FillListRecycling.Get();
                        fills.Clear();
                        distributedFills.Add(quote, fills);
                    }
                    fills.Add(allocatedFill);
                    position[quote.Side] += allocatedFill.Qty;
                    quote.Qty             = tradeSign * Math.Max(0, tradeSign * (quote.Qty - allocatedFill.Qty));
                    string msgStr = quote.FillAttribution();
                    query.AddItemToWrite(ParentStrategy.SqlId, -1, localTime, m_Services.User, quote.PricingEngine.EngineName, msgStr, allocatedFill.Qty, allocatedFill.Price);
                }
                else
                {
                    Log.AppendEntry(" skipped.");
                }
                quoter++;                  // otherwise move to next quoter
            }// next quoter
        }//DistributeFillsToQuoters()
Ejemplo n.º 9
0
        //
        #endregion//Properties


        #region Public Methods
        // *****************************************************************
        // ****                     Public Methods                      ****
        // *****************************************************************
        //
        //
        //
        //
        // *****************************************
        // ****             Quote()             ****
        // *****************************************
        /// <summary>
        /// Method called by PricingEngine to request a change in quoting
        /// for a particular, side, price and qty.
        /// Sending a quote with only tradeSide will remove quote from price list.
        ///
        /// Generally,s pricingEngines that don't want to quote a qty should still quote their target price.
        /// This allows overfills to be distributed to the pricing engine that can best use it.
        /// </summary>
        /// <param name="pricingEngine"></param>
        /// <param name="tradeSide"></param>
        /// <param name="price"></param>
        /// <param name="qty">signed integer</param>
        /// <param name="quoteReason">user chosen quote reason.</param>
        public virtual void Quote(PricingEngine pricingEngine, int tradeSide, double price = double.NaN, int qty = 0,
                                  QuoteReason quoteReason = QuoteReason.None)
        {
            // Compute quote variables.
            int  tradeSign     = UV.Lib.Utilities.QTMath.MktSideToMktSign(tradeSide);
            bool isPriceListed = (double.IsNaN(price) == false && double.IsInfinity(price) == false);
            int  iPriceNew     = 0;

            if (isPriceListed)
            {
                iPriceNew = tradeSign * (int)System.Math.Floor(tradeSign * price / m_QuoteTickSize);    // integerized price!
            }
            // Get this engines quote object from our master list.
            Quote quote = null;

            if (!m_Quotes[tradeSide].TryGetValue(pricingEngine, out quote)) // we store quotes for each side of mkt.
            {                                                               // Apparently this is the first quote call from this engine.
                quote = new Quote();
                m_Quotes[tradeSide].Add(pricingEngine, quote);
                quote.PricingEngine = pricingEngine;                                // set constant vars.
                quote.Side          = tradeSide;
                if (m_FirstPriceEngine == null)
                {
                    m_FirstPriceEngine = pricingEngine;
                }
            }
            bool isPriceListedPrev = quote.IsPriceListed;
            int  iPricePrev        = quote.IPrice;
            int  qtyPrev           = quote.Qty;

            // Test validity of qty value
            if (tradeSign * qty < 0)
            {
                qty = 0;
            }

            // Determine if this quote has changed.
            //      isPriceChanged = should contain all reasons the quotes location in book might change.
            bool isPriceChanged = (isPriceListed != isPriceListedPrev) || (iPriceNew != iPricePrev) || (quote.Reason != quoteReason);
            bool doesThisChangeRequireQuoteUpdating = (qty != qtyPrev) || (isPriceChanged);

            m_IsQuoteSideUpdateRequired[tradeSide] = m_IsQuoteSideUpdateRequired[tradeSide] || doesThisChangeRequireQuoteUpdating; // true if ANY PricingEngines quotes have changed since last update.

            // If the price has changed, and it should have been in our price list,
            // we need to remove it from its old location in price list.
            if (isPriceChanged && isPriceListedPrev)
            {
                RemoveQuoteFromListing(tradeSide, quote);
            }

            // Update the quote with the new price/qty
            quote.IsPriceListed = isPriceListed;
            quote.IPrice        = iPriceNew;
            quote.RawPrice      = price;
            quote.Qty           = qty;
            quote.Reason        = quoteReason;
            quote.FillAttributeStr.Clear();
            quote.FillAttributeStr.Append(pricingEngine.GetFillAttributeString());

            // Now add quote to new price location, if necessary.
            if (isPriceChanged && isPriceListed)
            {   // We need to add it since its price has changed, and it price is valid now.
                List <Quote> quoteList = null;
                int          priceKey  = -tradeSign * iPriceNew;
                if (!m_QuotesByPrice[tradeSide].TryGetValue(priceKey, out quoteList)) // get all quotes at this price
                {                                                                     // There are no previous quotes at this price, create new list.
                    quoteList = m_QuoteListRecycling.Get();
                    quoteList.Clear();
                    m_QuotesByPrice[tradeSide].Add(priceKey, quoteList);
                }
                // Add quote to list at this price.
                if (quote.Reason == QuoteReason.Exit || quote.Reason == QuoteReason.Stop)
                {
                    quoteList.Insert(0, quote);                  // put these in the front of the list.
                }
                else
                {
                    quoteList.Add(quote);                       // add these to end of list.
                }
            }
        }//Quote()
Ejemplo n.º 10
0
        //
        //
        //
        //
        //
        // *********************************************************
        //  ****                 CreateBar()                   ****
        // *********************************************************
        /// <summary>
        /// This is called each time a bar must be created from a snapshot of the current market.
        /// New bars are pushed into the BarEventArg.BarList queue and handed to the QueryBuilder
        /// for query creation and writing.
        /// Called by internal hub thread.
        /// </summary>
        private void CreateBar(DateTime barTime)
        {
            //Log.NewEntry(LogLevel.Minor, "DataHub: CreateBar - Bar Creation Started");
            BarEventArgs eArg = m_BarEventFactory.Get();                                      // new version GetBarEventArg();

            eArg.unixTime = (int)Utilities.QTMath.DateTimeToEpoch(barTime.ToUniversalTime()); //round this to the floor.
            Log.NewEntry(LogLevel.Minor, "CreateBar: Attempting to create bar for timestamp {0} - miliseconds = {1}", eArg.unixTime, barTime.Millisecond);


            if ((eArg.unixTime - m_LastBarTimeStamp) > 1)
            { // we have stepped through time in some interval greater than a second....create email alert for debugging purposes
                DatabaseWriterEventArgs emailEvent = new DatabaseWriterEventArgs();
                emailEvent.Request = DatabaseWriterRequests.SendEmail;
                emailEvent.QueryBase.AppendFormat("Data Hub Missed Timestamp.  Current timestamp={0} and last timestamp={1} difference is {2} seconds", eArg.unixTime, m_LastBarTimeStamp, eArg.unixTime - m_LastBarTimeStamp);
                m_DatabaseWriterHub.HubEventEnqueue(emailEvent);
            }
            m_LastBarTimeStamp = eArg.unixTime;


            //
            // Get markets now.
            //
            UV.Lib.BookHubs.Book aBook;
            if (m_Market.TryEnterReadBook(out aBook))
            {
                foreach (KeyValuePair <int, UV.Lib.BookHubs.Market> aBookMarket in aBook.Instruments)
                {
                    int mySQLID = -1;
                    if (m_InstrumentsRequested.Contains(aBookMarket.Value.Name) && m_InstrToMySQLID.TryGetValue(aBookMarket.Value.Name, out mySQLID))
                    { // we would like to record data for this instrument
                        if (aBookMarket.Value.Qty[(int)UV.Lib.Utilities.QTMath.BidSide][0] == 0 ||
                            aBookMarket.Value.Qty[(int)UV.Lib.Utilities.QTMath.AskSide][0] == 0)
                        {// we have bad data this can happen sometimes in between sessions..
                            //Log.NewEntry(LogLevel.Major, "CreateBar: Bid Or Ask qty for {0} is equal To zero, skipping bar", aBookMarket.Value.Name);
                            continue;
                        }
                        Bar aBar = m_BarFactory.Get();                                                          // grab a bar!
                        aBar.mysqlID        = mySQLID;                                                          // set instrument id
                        aBar.bidPrice       = aBookMarket.Value.Price[(int)UV.Lib.Utilities.QTMath.BidSide][0]; // set best bid
                        aBar.askPrice       = aBookMarket.Value.Price[(int)UV.Lib.Utilities.QTMath.AskSide][0]; // set best ask
                        aBar.bidQty         = aBookMarket.Value.Qty[(int)UV.Lib.Utilities.QTMath.BidSide][0];   // set best bidqty
                        aBar.askQty         = aBookMarket.Value.Qty[(int)UV.Lib.Utilities.QTMath.AskSide][0];   // set best askqty
                        aBar.lastTradePrice = aBookMarket.Value.LastPrice;
                        aBar.sessionVolume  = aBookMarket.Value.Volume[(int)UV.Lib.Utilities.QTMath.LastSide];
                        aBar.longVolume     = aBookMarket.Value.Volume[(int)UV.Lib.Utilities.QTMath.BidSide];
                        aBar.shortVolume    = aBookMarket.Value.Volume[(int)UV.Lib.Utilities.QTMath.AskSide];
                        aBar.totalVolume    = aBar.longVolume + aBar.shortVolume + aBookMarket.Value.Volume[(int)UV.Lib.Utilities.QTMath.UnknownSide];
                        aBar.sessionCode    = Convert.ToInt32(aBookMarket.Value.IsMarketGood);              // flag for trading ==1 or not trading==0
                        eArg.BarList.Enqueue(aBar);
                    }
                }
                m_Market.ExitReadBook(aBook);
            }
            else
            { // something went wrong here!
                Log.NewEntry(LogLevel.Error, "  *********  CreateBar: FAILED TO OBTAIN READ FOR BOOK!  *********");
            }

            if (eArg.BarList.Count > 0 && !m_IsDebugMode) // do not write to db in debug mode.
            {
                m_QueryBuilderHub.HubEventEnqueue(eArg);
            }
        }//CreateBar().