Пример #1
0
        }//CancelAllOrders()

        //
        //
        // *********************************************
        // ****     ProcessSyntheticOrder()         ****
        // *********************************************
        /// <summary>
        /// This function returns the "new" strategy-level synthetic fills.
        /// </summary>
        /// <param name="syntheticOrder"></param>
        /// <param name="syntheticFills"></param>
        /// <returns></returns>
        public bool ProcessSyntheticOrder(SyntheticOrder syntheticOrder, ref List <Fill> syntheticFills)
        {
            bool           newFillsFound = false;
            SyntheticOrder prevOrder     = null;

            if (m_FilledOrders.TryGetValue(syntheticOrder.OrderId, out prevOrder))
            { // we have seen this order before, so lets just find the new fills and save them
                int n = 0;
                if (prevOrder.m_SyntheticFills != null)
                {
                    n = prevOrder.m_SyntheticFills.Count;
                }
                for (int i = n; i < syntheticOrder.m_SyntheticFills.Count; ++i)
                {
                    syntheticFills.Add(syntheticOrder.m_SyntheticFills[i]);
                }
                m_FilledOrders[syntheticOrder.OrderId] = syntheticOrder.Copy();  // save the newest order update
                newFillsFound = n != syntheticOrder.m_SyntheticFills.Count;
            }
            else
            {                                                                      // We have never seen this order order before, add it to the dictionary.
                m_FilledOrders.Add(syntheticOrder.OrderId, syntheticOrder.Copy()); // this has to be a copy for us to be able to compare.
                foreach (SyntheticFill newSynthFill in syntheticOrder.m_SyntheticFills)
                {
                    syntheticFills.Add(newSynthFill);
                }
                newFillsFound = syntheticOrder.m_SyntheticFills.Count > 0;
            }
            return(newFillsFound);
        }// ProcessSyntheticOrder()
Пример #2
0
        }// ProcessParameterChangeRequest()

        //
        //
        // *****************************************
        // ****  ProcessSyntheticOrderRequest   ****
        // *****************************************
        /// <summary>
        /// A request for submission of a synthetic order.
        /// </summary>
        /// <param name="engineEventArg"></param>
        private void ProcessSyntheticOrderRequest(EngineEventArgs engineEventArg)
        {
            SyntheticOrder  syntheticOrder = (SyntheticOrder)engineEventArg.DataObjectList[0];
            ThreadContainer strategy       = null;
            int             strategyID     = engineEventArg.EngineContainerID;

            if (strategyID < 0)
            {   // This request is for all strategies
                Log.NewEntry(LogLevel.Error, "ProcessEngineEvent: Negative EngineContainerId not allowed in {0}.", syntheticOrder);
                engineEventArg.EngineHubName = this.ServiceName;
                engineEventArg.Status        = EngineEventArgs.EventStatus.Failed;
                OnEngineChanged(engineEventArg);
            }
            else if (m_ExecutionContainers[DefaultHubName].TryGetValue(strategyID, out strategy))
            {   // Found the strategy, pass it the request now.
                // He is on another thread, so give him a thread safe copy.
                strategy.ProcessEvent(engineEventArg.Copy());
            }
            else
            {   // Unknown strategy
                Log.NewEntry(LogLevel.Error, "ProcessEngineEvent: Unknown EngineContainerId {0}", syntheticOrder);
                engineEventArg.EngineHubName = this.ServiceName;
                engineEventArg.Status        = EngineEventArgs.EventStatus.Failed;
                OnEngineChanged(engineEventArg);
            }
        }
Пример #3
0
 // *****************************************************************
 // ****                 Public Methods                          ****
 // *****************************************************************
 //
 //
 public override void ProcessEvent(EventArgs e)
 {
     base.ProcessEvent(e);
     if (e is EngineEventArgs)
     {
         EngineEventArgs engineEventArg = (EngineEventArgs)e;
         if (engineEventArg.MsgType == EngineEventArgs.EventType.SyntheticOrder)
         {
             SyntheticOrder syntheticOrder = (SyntheticOrder)engineEventArg.DataObjectList[0];
             if (m_OpenSyntheticOrders[syntheticOrder.Side] == null)
             { // this is the first time we have seen this order
                 m_OpenSyntheticOrders[syntheticOrder.Side] = syntheticOrder;
                 Quote(syntheticOrder.Side, syntheticOrder.Price, syntheticOrder.Qty);
             }
             else
             { // we have seen this order before, check what do do...currently not implementing much
                 // todo: how to save, check what user is requesting to change, etc
                 m_OpenSyntheticOrders[syntheticOrder.Side].Qty         = syntheticOrder.Qty;
                 m_OpenSyntheticOrders[syntheticOrder.Side].Price       = syntheticOrder.Price;
                 m_OpenSyntheticOrders[syntheticOrder.Side].TradeReason = syntheticOrder.TradeReason;
                 Quote(syntheticOrder.Side, syntheticOrder.Price, syntheticOrder.Qty);
             }
         }
     }
 }
Пример #4
0
        //
        // *****************************************************
        // ****         ProcessSyntheticOrder()             ****
        // *****************************************************
        /// <summary>
        /// Called by the strategy hub to process a synthetic order for strategy.
        /// </summary>
        /// <param name="syntheticOrder"></param>
        /// <returns></returns>
        public bool ProcessSyntheticOrder(SyntheticOrder syntheticOrder)
        {
            bool isUpdateRequired = false;

            if (m_OrderEngine == null)
            {   // This is an error.  We need this engine!
                return(isUpdateRequired);
            }
            List <Fill> newFills = new List <Fill>();

            m_OrderEngine.ProcessSyntheticOrder(syntheticOrder, ref newFills);


            if (m_QuoteEngine != null)
            {
                isUpdateRequired = m_QuoteEngine.ProcessSyntheticOrder(syntheticOrder, newFills);
                if (isUpdateRequired)
                {
                    m_QuoteEngine.UpdateQuotes(true);
                }
            }



            /*
             * m_PricingEngine.Filled(syntheticOrder);                         // pass pricing engine raw event arg.
             * // Inform the pricing engine if there is a new
             * // synthetic fill.
             * if (m_PricingEngine != null && newFills != null)
             * {
             *  // Prepare to write to fill database. Pre-fill snapshot.
             *  string attributeString = string.Empty;
             *  DateTime localTime = StrategyHub.GetLocalTime();
             *  UV.Lib.DatabaseReaderWriters.Queries.FillsQuery query = new Lib.DatabaseReaderWriters.Queries.FillsQuery();
             *  if (m_ModelSnapshots.TryGetValue(syntheticOrder.OrderId, out attributeString) == false)
             *      attributeString = m_PricingEngine.GetFillAttributeString();     // get internal state of the pricing engine if it wants to send info with this fill.
             *  query.AddItemToWrite(this.SqlId, -1, localTime, m_Services.User, attributeString, 0, 0);
             *
             *  // Inform pricing engine
             *  foreach (Fill f in newFills)
             *  {
             *      m_PricingEngine.Filled(f);                // pass pricing engine synthetic fill.
             *      attributeString = m_PricingEngine.GetFillAttributeString();
             *      if(syntheticOrder.TradeReason != null && syntheticOrder.TradeReason != string.Empty)
             *          attributeString = String.Format("{0} TradeReason={1}", attributeString, syntheticOrder.TradeReason);
             *      query.AddItemToWrite(this.SqlId, -1, localTime, m_Services.User, attributeString, f.Qty, f.Price);    // here -1 means "strategy fill"
             *  }
             *  // Prepare a post-trade snapshot.
             *  StrategyHub.RequestDatabaseWrite(query);            // submit all the queries
             * }
             */
            // Exit
            return(isUpdateRequired);
        }// ProcessTradeEventArg
Пример #5
0
        //
        //
        //
        //
        #endregion//Properties


        #region Public Methods
        // *****************************************************************
        // ****                     Public Methods                      ****
        // *****************************************************************
        //
        //
        // *****************************************
        // ****             Quote()             ****
        // *****************************************
        /// <summary>
        /// Method to request that an order be sent to the Execution hub at
        /// a particular price and qty.
        /// </summary>
        /// <param name="orderSide"></param>
        /// <param name="price"></param>
        /// <param name="qty"></param>
        /// <param name="quoteReason"></param>
        /// <returns>TradeId</returns>
        public int Quote(int orderSide, double price, int qty, string quoteReason)
        {
            m_EngineEventArgsForOrders[orderSide].DataObjectList.Clear();  //clear before each use!

            // Locate TradeEventArg to update.
            SyntheticOrder syntheticOrder = null;

            if (m_ActiveOrders[orderSide] == null)
            {   // There is currently no active trade, so create one.
                syntheticOrder             = SyntheticOrder.RequestNewOrder(++m_LastOrderId);
                syntheticOrder.Side        = orderSide;
                syntheticOrder.TradeReason = quoteReason;
                m_ActiveOrders[orderSide]  = syntheticOrder;          // store it as active trade
            }
            else
            {   // There is already an active trade, grab it.
                syntheticOrder = m_ActiveOrders[orderSide];
            }
            // Update quatities if they have changed.
            // TODO: implement various round-off schemes.
            int  tradeSign         = QTMath.MktSideToMktSign(orderSide);
            int  iPrice            = tradeSign * (int)System.Math.Floor(tradeSign * price / m_QuoteTickSize); // integerized price!
            bool isChangedFromPrev = qty != m_QuoteQtyPrev[orderSide] || (iPrice != m_QuoteIPricePrev[orderSide]) || quoteReason != m_QuoteReasonPrev[orderSide];

            if (isChangedFromPrev)
            {
                m_QuoteQtyPrev[orderSide]    = qty;
                m_QuoteIPricePrev[orderSide] = iPrice;
                m_QuoteReasonPrev[orderSide] = quoteReason;
                syntheticOrder.Price         = iPrice * m_QuoteTickSize;
                syntheticOrder.Qty           = qty;
                syntheticOrder.TradeReason   = quoteReason;

                m_EngineEventArgsForOrders[orderSide].DataObjectList.Add(syntheticOrder);       // add to event arg that is already set up.
                m_ExecutionHub.HubEventEnqueue(m_EngineEventArgsForOrders[orderSide].Copy());   // send off to remote exeuction
                m_StrategyHub.Log.NewEntry(Lib.Hubs.LogLevel.Major, "TradeEngine: {0} sent {1} ", m_Strategy.Name, syntheticOrder);
            }
            // Exit
            if (syntheticOrder == null)
            {
                return(-1);
            }
            else
            {
                return(syntheticOrder.OrderId);
            }
        }// Quote()
Пример #6
0
        }//UpdateQuotes().

        //
        //
        // *****************************************************
        // ****         Process Synthetic Order()           ****
        // *****************************************************
        /// <summary>
        /// Process fills from Strategy to PricingEngines.
        /// </summary>
        /// <param name="syntheticOrder"></param>
        /// <param name="newFills"></param>
        /// <returns>True if update required</returns>
        public override bool ProcessSyntheticOrder(SyntheticOrder syntheticOrder, List <Fill> newFills)
        {
            if (newFills == null || newFills.Count == 0)
            {
                return(false);
            }

            // Collect all fills into work spaces.
            Log.BeginEntry(LogLevel.Major, "Quote.ProcessSynthOrder: {0}  Fills=", ParentStrategy.Name);
            w_NewFills[0].Clear();
            w_NewFills[1].Clear();
            foreach (Fill fill in newFills)
            {
                int tradeSide = QTMath.MktSignToMktSide(fill.Qty);
                w_NewFills[tradeSide].Add(fill);
                m_BuySellQty[tradeSide] += fill.Qty;                // this records the raw fills as they come in.
                Log.AppendEntry(" [{0}]", fill);
            }
            int[] position = new int[2];                            // this will be updated during allocation of fills.
            base.m_Position.CopyTo(position, 0);
            Log.AppendEntry(". ");


            // Try to cancel fills with undistributed fills.
            // TODO: Cancel undistributed fills, if any.

            /*
             * if ( m_UndistributedFills[0].Count + m_UndistributedFills[1].Count > 0)
             * {
             *  for (int tradeSide = 0; tradeSide < 2; ++tradeSide)
             *  {
             *      int otherSide = QTMath.MktSideToOtherSide(tradeSide);
             *      if (w_NewFills[tradeSide].Count > 0 && m_UndistributedFills[otherSide].Count > 0 )
             *      {
             *          Log.AppendEntry(" Canceling with undistributed fills: Not implemented!");
             *      }
             *  }
             * }
             */

            // Prepare entry for database write.
            DateTime localTime = ParentStrategy.StrategyHub.GetLocalTime();

            UV.Lib.DatabaseReaderWriters.Queries.FillsQuery query = new Lib.DatabaseReaderWriters.Queries.FillsQuery();

            // -----------------------------------------------------
            // Pass: distribute fills to stops
            // -----------------------------------------------------
            for (int tradeSide = 0; tradeSide < 2; ++tradeSide)
            {
                int exitingSide = QTMath.MktSideToActiveMktSide(tradeSide);
                if (w_NewFills[tradeSide].Count == 0 || base.m_FillQty[exitingSide].Count == 0)
                {
                    continue;
                }
                List <Quote> exitList = m_QuoteListRecycling.Get();      // get empty list.
                exitList.Clear();
                foreach (KeyValuePair <PricingEngine, int> kv in base.m_FillQty[exitingSide])
                {
                    Quote quote;
                    if (m_Quotes[tradeSide].TryGetValue(kv.Key, out quote) && quote.Reason == QuoteReason.Stop && quote.Qty != 0)
                    {
                        exitList.Add(quote);
                    }
                }
                if (exitList.Count > 0)
                {
                    Log.AppendEntry(" Distribute to {0} stop quoters:", exitList.Count);
                    DistributeFillsToQuoters(ref w_NewFills[tradeSide], ref exitList, ref query, ref w_DistributedFills, ref position);
                    Log.AppendEntry(". ");
                }
                exitList.Clear();
                m_QuoteListRecycling.Recycle(exitList);
            }//next tradeSide

            // -----------------------------------------------------
            // Pass: distribute fills to quoters who want them.
            // -----------------------------------------------------
            for (int tradeSide = 0; tradeSide < 2; ++tradeSide)
            {
                if (w_NewFills[tradeSide].Count == 0)
                {
                    continue;
                }
                int          exitingSide = QTMath.MktSideToOtherSide(tradeSide);
                int          tradeSign   = QTMath.MktSideToMktSign(tradeSide);
                List <Quote> exitList    = m_QuoteListRecycling.Get();  // get empty lists for entry quotes.
                List <Quote> entryList   = m_QuoteListRecycling.Get();  // and for exit quoters...

                Log.AppendEntry(" Distribute to working quoters");
                List <int> iPriceKeys = new List <int>(m_QuotesByPrice[tradeSide].Keys);
                int        priceLevel = 0;
                while (w_NewFills[tradeSide].Count > 0 && priceLevel < iPriceKeys.Count)
                {
                    // On each interation, update our "pos" so we know the remaining qty.
                    int allowedEntryQty = tradeSign * Math.Max(0, m_MaxPosition - Math.Abs(position[tradeSide]));

                    // Load entry/exit quoters for this price level.
                    Log.AppendEntry(" lvl={0}/{1}:", priceLevel, iPriceKeys.Count);
                    entryList.Clear();
                    exitList.Clear();
                    List <Quote> quotes = null;
                    if (m_QuotesByPrice[tradeSide].TryGetValue(iPriceKeys[priceLevel], out quotes))
                    {
                        foreach (Quote quote in quotes)
                        {
                            if (allowedEntryQty != 0 && quote.Reason == QuoteReason.Entry && quote.Qty != 0)
                            {
                                entryList.Add(quote);
                            }
                            else if (base.m_FillQty[exitingSide].ContainsKey(quote.PricingEngine) && quote.Reason == QuoteReason.Exit && quote.Qty != 0)
                            {
                                exitList.Add(quote);
                            }
                        }
                    }

                    if (exitList.Count > 0)
                    {
                        Log.AppendEntry(" Exits ({0}):", exitList.Count);
                        DistributeFillsToQuoters(ref w_NewFills[tradeSide], ref exitList, ref query, ref w_DistributedFills, ref position);
                    }
                    if (entryList.Count > 0)
                    {
                        entryList.Sort(this.QuoteComparerByEngineId);  // To better match our backtest, consider sorting entryList by engine names...
                        Log.AppendEntry(" Entries ({0}):", entryList.Count);
                        DistributeFillsToQuoters(ref w_NewFills[tradeSide], ref entryList, ref query, ref w_DistributedFills, ref position);
                    }
                    //
                    priceLevel++;
                }// next price level
                // Clean up.
                entryList.Clear();
                exitList.Clear();
                m_QuoteListRecycling.Recycle(entryList);
                m_QuoteListRecycling.Recycle(exitList);
                Log.AppendEntry(" Finished.");
                if (w_NewFills[tradeSide].Count > 0)
                {
                    Log.AppendEntry(" {0} fills remaining.", w_NewFills[tradeSide].Count);
                }
                else
                {
                    Log.AppendEntry(" No fills remain.");
                }
            }//tradeSide

            // -----------------------------------------------------
            // Start emergency processing!
            // -----------------------------------------------------
            if (w_NewFills[0].Count > 0 || w_NewFills[1].Count > 0)
            {
                Log.AppendEntry(" Process unwanted fills!");
                ProcessUnwantedFills(ref w_NewFills, ref w_DistributedFills);
            }

            Log.EndEntry();                                             // end logging for us now, before we call other methods.
            // -----------------------------------------------------
            // Distribute these fills now.
            // -----------------------------------------------------
            if (query != null && query.Count != 0)
            {
                ParentStrategy.StrategyHub.RequestDatabaseWrite(query); // submit all the queries
            }
            foreach (KeyValuePair <Quote, List <Fill> > kv in w_DistributedFills)
            {
                int    fillQty   = 0;
                double fillPrice = 0;
                foreach (Fill fill in kv.Value)
                {
                    fillQty  += fill.Qty;
                    fillPrice = fill.Price;                             // TODO: this should be ave fill price
                }
                int tradeSide = QTMath.MktSignToMktSide(fillQty);
                int exitSide  = QTMath.MktSideToOtherSide(tradeSide);
                if (fillQty == 0)
                {
                    continue;
                }
                // Update our position counting.
                int openPos = 0;
                if (base.m_FillQty[exitSide].TryGetValue(kv.Key.PricingEngine, out openPos))
                {   // This is an exit (since this PricingEngine has open position on other side of mkt).
                    openPos += fillQty;

                    // update quoter's graph
                    if (m_IsGraphEnabled)
                    {
                        if (exitSide == 0)
                        {   // exit long position.
                            m_GraphEngine.AddPoint(m_GraphID, "Long Exit", fillPrice);
                            m_GraphEngine.AddText(m_GraphID, string.Format("{0}", kv.Key.PricingEngine.EngineName), fillPrice + m_TextOffsetTicks * m_QuoteTickSize);
                        }
                        else
                        {   // exit short position.
                            m_GraphEngine.AddPoint(m_GraphID, "Short Exit", fillPrice);
                            m_GraphEngine.AddText(m_GraphID, string.Format("{0}", kv.Key.PricingEngine.EngineName), fillPrice - m_TextOffsetTicks * m_QuoteTickSize);
                        }
                    }

                    // Update real position table.
                    if (openPos * fillQty <= 0)
                    {
                        base.m_FillQty[exitSide].Remove(kv.Key.PricingEngine);// complete exit, possibly a side flip
                    }
                    if (openPos != 0)
                    {   // There is a new position (on other side of mkt).
                        int posSide = QTMath.MktSignToMktSide(openPos);
                        base.m_FillQty[posSide][kv.Key.PricingEngine] = openPos;
                    }
                }
                else
                {   // This is an entry!
                    if (m_IsGraphEnabled)
                    {
                        if (tradeSide == 0)
                        {
                            m_GraphEngine.AddPoint(m_GraphID, "Long Entry", fillPrice);
                            m_GraphEngine.AddText(m_GraphID, string.Format("{0}", kv.Key.PricingEngine.EngineName), fillPrice - m_TextOffsetTicks * m_QuoteTickSize);
                        }
                        else
                        {
                            m_GraphEngine.AddPoint(m_GraphID, "Short Entry", fillPrice);
                            m_GraphEngine.AddText(m_GraphID, string.Format("{0}", kv.Key.PricingEngine.EngineName), fillPrice + m_TextOffsetTicks * m_QuoteTickSize);
                        }
                    }
                    // Update real position table.
                    if (base.m_FillQty[tradeSide].ContainsKey(kv.Key.PricingEngine))
                    {
                        base.m_FillQty[tradeSide][kv.Key.PricingEngine] += fillQty;  // add to this engines position.
                    }
                    else
                    {
                        base.m_FillQty[tradeSide].Add(kv.Key.PricingEngine, fillQty); // store this engines position.
                    }
                }
                // Trigger the pricing engine filled event!
                foreach (Fill fill in kv.Value)
                {
                    kv.Key.PricingEngine.Filled(fill);
                }
            }// next filled Quote.
            // Update total sum
            Log.BeginEntry(LogLevel.Major, "Quote.ProcessSynthOrder {0} Summary: ", ParentStrategy.Name);
            for (int tradeSide = 0; tradeSide < 2; tradeSide++)
            {
                // Add up the current position.
                int pos = 0;
                foreach (KeyValuePair <PricingEngine, int> kv in base.m_FillQty[tradeSide])
                {
                    pos += kv.Value;
                }
                base.m_Position[tradeSide] = pos;

                // Write some logging.
                Log.AppendEntry(" {0}-side:", QTMath.MktSideToLongString(tradeSide));
                Log.AppendEntry(" Pos={0:+0;-0;0}", base.m_Position[tradeSide]);
                foreach (KeyValuePair <PricingEngine, int> kv in base.m_FillQty[tradeSide])
                {
                    Log.AppendEntry(" [{1:+0;-0;0} {0}]", kv.Key.EngineName, kv.Value);
                }
                Log.AppendEntry(" TotalQty={0}", m_BuySellQty[tradeSide]);
                // Log undistributed fills too.
                if (m_UndistributedFills[tradeSide].Count > 0)
                {
                    Log.AppendEntry(" Undistributed {0}-fills:", QTMath.MktSideToLongString(tradeSide));
                    foreach (Fill fill in m_UndistributedFills[tradeSide])
                    {
                        Log.AppendEntry(" {0}", fill);
                    }
                }
            }// next tradeSide
            Log.AppendEntry(" |MaxPos|={0}.", m_MaxPosition);
            Log.EndEntry();

            //
            // Clean up work spaces
            //
            foreach (KeyValuePair <Quote, List <Fill> > kv in w_DistributedFills)
            {
                kv.Value.Clear();
                m_FillListRecycling.Recycle(kv.Value);
            }
            w_DistributedFills.Clear();                                 // Quoters and their fills to distribute.

            return(true);
        }// ProcessSyntheticOrder()
Пример #7
0
 //
 //
 // *********************************************
 // ****      SendSyntheticOrderToRemote()   ****
 // *********************************************
 /// <summary>
 /// Called by an order engine who would like to send back to the strategy hub
 /// a synthetic order that has been updated. - This should probably be renamed.
 /// but just going with this for now.
 /// </summary>
 /// <param name="syntheticOrder"></param>
 public void SendSyntheticOrderToRemote(SyntheticOrder syntheticOrder)
 {
     m_ConfirmSynthOrderEventArg.DataObjectList.Clear(); // clear before each reuse.
     m_ConfirmSynthOrderEventArg.DataObjectList.Add(syntheticOrder);
     this.RemoteEngineHub.HubEventEnqueue(m_ConfirmSynthOrderEventArg.Copy());
 }