// // // // #endregion//Public Methods #region Private Methods // ***************************************************************** // **** Private Methods **** // ***************************************************************** // // // ***************************************************************** // **** RunHedgeLogic() **** // ***************************************************************** /// <summary> /// Called after Instrument_TickChanged to update hedge prices of /// orders under active management by the HedgeRuleManager. /// </summary> private void RunHedgeLogic() { double endingPrice; // price we end up with after our rules are applied. double userDefinedWorstPrice; // price the user has defined as the worst possible price if (m_OrderBook.Count() == 0) { // we have no orders to manage m_isManagerActive = false; m_QuoterLeg.m_Market.MarketChanged -= new EventHandler(Market_MarketChanged); // subscribe to orders state changes for this leg. m_Log.NewEntry(LogLevel.Minor, "HedgeRuleManager : {0} has no orders to manage, Unsunbscribing from market", m_QuoterLeg.InstrumentDetails.InstrumentName); return; } else // we have orders and need to manage them { for (int mktSide = 0; mktSide < 2; ++mktSide) { // each side of market if (m_OrderBook.Count(mktSide) != 0) { //we have orders on this side of the market m_ActiveOrders.Clear(); // these can not be recycled since the hedger could still be holding an order. m_OrderBook.GetOrdersBySide(mktSide, ref m_ActiveOrders); // populate all orders for this side of the market foreach (int id in m_ActiveOrders.Keys) { if (m_ActiveOrders.TryGetValue(id, out tmpOrder)) { // we can find the order int orderSign = QTMath.MktSideToMktSign(tmpOrder.Side); if (!m_OrderIdToUserDefinedWorstPrice.ContainsKey(id)) { userDefinedWorstPrice = tmpOrder.PricePending + (orderSign * tmpOrder.TickSize * m_MaxPayUpTicks); m_OrderIdToUserDefinedWorstPrice.Add(id, userDefinedWorstPrice); } else { userDefinedWorstPrice = m_OrderIdToUserDefinedWorstPrice[tmpOrder.Id]; } endingPrice = tmpOrder.PricePending; // assume we have no change to start. foreach (IHedgeRule rule in m_HedgeRules) { // apply our hedge rules bool isContinue = rule.ApplyHedgeRule(endingPrice, tmpOrder.Side, out endingPrice); // hand the function the ending price and let it update it if (!isContinue) // we want to execute our rule immediately { break; } } if ((endingPrice * orderSign) > userDefinedWorstPrice * orderSign) // if our ending price is worse than worse price, reassing it. { endingPrice = userDefinedWorstPrice; } if (!QTMath.IsPriceEqual(endingPrice, tmpOrder.PricePending, tmpOrder.TickSize)) { // our price has been changed m_Hedger.UpdateHedgerOrderPrice(tmpOrder, endingPrice); // call the hedger to change the order } } } // end foreach } // end if } // end mktside } // end else } // RunHedgeLogic()
// // ************************************************************* // **** Quote() ***** // ************************************************************* // /// <summary> /// This sets the inner market price and qty for the trade. /// For now it assumes the strategy has only one OrderInstrument, which is always /// the case when we have an "ExecutionStrategy" deployed; eg, an autospreader. /// /// qty must be signed, negative for sell qty's /// /// This will validate all prices prior to setting them. /// </summary> /// <param name="tradeSide"></param> /// <param name="price"></param> /// <param name="qty">Signed qty</param> public void Quote(int tradeSide, double price, int qty) { if (qty != 0 && tradeSide != QTMath.MktSignToMktSide(qty)) { // mismatch qty and sides Log.NewEntry(LogLevel.Warning, "Quote: tradeSide and side implied by qty sign do not match, rejecting quote update"); return; } if (!m_IsLegSetUpComplete) { // we cant't even validate prices yet. Log.NewEntry(LogLevel.Major, "Quote: Market has not been intialized yet. Order's will not be sent until market is intialized"); return; } price = price / m_PriceLeg.PriceMultiplier; // convert from strat price to instrument price qty = (int)(qty * Math.Abs(m_PriceLeg.Weight)); // convert from strat qty to instrument qty if (!QTMath.IsPriceEqual(m_StrategyWorkingPrice[tradeSide], price, m_InstrumentDetails.TickSize) || m_TotalDesiredQty[tradeSide] != qty) { // price is different. if (m_RiskManager.ValidatePrices(price, tradeSide, m_PriceLeg.InstrumentName) || qty == 0) { // our prices are valid so we can save variables m_StrategyWorkingPrice[tradeSide] = price; m_TotalDesiredQty[tradeSide] = qty; Log.NewEntry(LogLevel.Major, "Quote:{4} Working {1} {0} @ {2} in {3}", // while this may be silly to log first, it is here for readability m_OpenSyntheticOrders[tradeSide].TradeReason, // 0 qty, // 1 price, // 2 m_InstrumentDetails.InstrumentName, //3 m_ExecutionContainer.EngineContainerID); //4 Quote(); // go ahead an update our orders } } }//Quote()
// ***************************************************************** // **** Private Methods **** // ***************************************************************** // // // //********************************************************** //**** Update Market Prices() **** //********************************************************** /// <summary> /// Called whenever the mkt changes. Updates m_Prices[][] and m_Qtys[][]. /// returns True if inside market has changed prices /// </summary> /// TODO: THIS NEEDS TO BE FIXED private bool UpdateMarketPrices(UV.Lib.BookHubs.Market market, List <int>[] MarketDepthChangedList) { bool isChanged = false; for (int side = 0; side < 2; ++side) { if (MarketDepthChangedList[side].Count == 0 || MarketDepthChangedList[side][0] > m_LeanableDepth[side] || MarketDepthChangedList[side][0] > m_OrderBookDepthMax) { // if no change on this side || top change is past our leanable depth || top change is past the depth we care about //nothing to do here! } else { // this is a price or qty change that we need to consider if (MarketDepthChangedList[side][0] == 0 && !QTMath.IsPriceEqual(m_Market.Price[side][MarketDepthChangedList[side][0]], market.Price[side][0], InstrumentDetails.TickSize)) { // if this is a top of book price change! isChanged = true; } foreach (int level in MarketDepthChangedList[side]) { // Set new internal market from the depth changed back if (level < m_OrderBookDepthMax) { // we care about updates at this level m_Market.Price[side][level] = market.Price[side][level]; m_Market.Qty[side][level] = market.Qty[side][level]; } } } } return(isChanged); }
}// AddBook() // // // ************************************************************* // **** Quote() **** // ************************************************************* // // /// <summary> /// This sets the inner market price and qty for the trade. /// For now it assumes the strategy has only one OrderInstrument, which is always /// the case when we have an "ExecutionStrategy" deployed; eg, an autospreader. /// /// qty must be signed, negative for sell qty's /// /// This will validate all prices prior to setting them. /// </summary> /// <param name="tradeSide"></param> /// <param name="price"></param> /// <param name="qty">Signed qty</param> /// <param name="aBook"></param> public void Quote(int tradeSide, double price, int qty, UV.Lib.BookHubs.Book aBook) { if (qty != 0 && tradeSide != QTMath.MktSignToMktSide(qty)) { // mismatch qty and sides Log.NewEntry(LogLevel.Warning, "Quote: tradeSide and side implied by qty sign do not match, rejecting quote update"); return; } if (!m_IsMarketReady) { // we cant't even validate prices yet. Log.NewEntry(LogLevel.Major, "Quote: Market has not been intialized yet. Order's will not be sent until market is intialized"); return; } if (!QTMath.IsPriceEqual(m_StrategyWorkingPrice[tradeSide], price, m_InstrumentDetails.TickSize)) { // price is different. if (m_RiskManager.ValidatePrices(price, tradeSide, m_Instrument, aBook)) { // our prices are valid so we can save variables m_StrategyWorkingPrice[tradeSide] = price; m_TotalDesiredQty[tradeSide] = qty; } } else { // price hasn't changed so if it was already set m_TotalDesiredQty[tradeSide] = qty; } Quote(); // go ahead an update our orders }//Quote()
}//Quote() // // #endregion//Public Methods #region Private Methods // ***************************************************************** // **** Private Methods **** // ***************************************************************** // // // ************************************************************* // **** Quote() **** // ************************************************************* /// <summary> /// This private method can be called on any state change to update our orders /// in the market once all our internal prices, flags, and states are set. /// </summary> private void Quote() { bool isAllowedToWorkOrder; int marketSign; int qtyToWork; for (int side = 0; side < 2; side++) { marketSign = QTMath.MktSideToMktSign(side); isAllowedToWorkOrder = (Math.Abs(m_StrategyPosition[side]) < Math.Abs(m_TotalDesiredQty[side])) && m_IsRiskCheckPassed && m_DripQty > 0; // find our working order. m_OrderWorkSpace.Clear(); m_OrderBook.GetOrdersByRank(side, 0, ref m_OrderWorkSpace); Order quoteOrder = null; int nthOrder = 0; while (nthOrder < m_OrderWorkSpace.Count && quoteOrder == null) // loop until we find a living quoteOrder { if (m_OrderWorkSpace[nthOrder].OrderStateConfirmed != OrderState.Dead) { quoteOrder = m_OrderWorkSpace[nthOrder]; } nthOrder++; } if (isAllowedToWorkOrder) { qtyToWork = QTMath.CalculateDripQty(m_DripQty, m_TotalDesiredQty[side], m_StrategyPosition[side]); int iPrice = (int)(m_StrategyWorkingPrice[side] / m_InstrumentDetails.TickSize); if (quoteOrder == null && qtyToWork != 0) { // we aren't working an order, but would like to be Order order; if (m_OrderHub.TryCreateOrder(m_Instrument, side, iPrice, qtyToWork, out order)) { if (m_UseGTC) { order.OrderTIF = OrderTIF.GTC; } m_OrderHub.TrySubmitOrder(m_OrderBook.BookID, order); m_RiskManager.m_NumberOfQuotesThisSecond++; } } else if (!QTMath.IsPriceEqual(quoteOrder.PricePending, m_StrategyWorkingPrice[side], m_InstrumentDetails.TickSize) || quoteOrder.WorkingQtyPending != qtyToWork) { // we need to change price, qty, or both if (m_OrderHub.TryChangeOrderPriceAndQty(quoteOrder, qtyToWork, iPrice)) // this will handle everthing for us! { m_RiskManager.m_NumberOfQuotesThisSecond += 2; // cancel and replace = 2? } else { Log.NewEntry(LogLevel.Warning, "Quote: Failed To Modify order {0}", quoteOrder); // do we want to do anything more here? } } } else if (quoteOrder != null) { // we are working an order, but don't want to be! if (!m_OrderHub.TryDeleteOrder(quoteOrder)) { Log.NewEntry(LogLevel.Warning, "Quote: Failed to canel order {0}", quoteOrder); } } } }//Quote()