// // **** Serialize() **** // private void Serialize() { // Create some books. StringBuilder msg = new StringBuilder(); System.Random rand = new Random(); for (int i = 0; i < 2; ++i) { InstrumentName name = new InstrumentName(new Product("CME", "ED", ProductTypes.Spread), string.Format("#{0}", i + 1)); double minTick = 0.5; FillBookLifo book = new FillBookLifo(minTick, 12.50, name); for (int j = 0; j < 2; ++j) { Fill aFill = Fill.Create(); aFill.Price = rand.Next(20) * minTick; aFill.Qty = rand.Next(10) + 2; aFill.LocalTime = DateTime.Now.AddSeconds(-rand.NextDouble() * 100); aFill.ExchangeTime = aFill.LocalTime; book.Add(aFill); } m_FillBooks.Add(name, book); msg.AppendFormat("{0}", Stringifiable.Stringify(book)); }// next i textBox1.Text = msg.ToString(); this.Select(); }// Serialize().
// #endregion//Properties #region Public Methods // ***************************************************************** // **** Public Methods **** // ***************************************************************** // // // // **** Add() **** // /// <summary> /// Method: /// if (qty*NetPosition) >= 0 we are simply added to position. /// else /// while (qty!=0 and Fills.Count > 0) /// if (LastFill.Qty+qty)*qty >= 0 we cancel this entire fill, remove it, /// and have left over qty += LastFill.Qty (qty may be exactly zero). /// else LastFill.Qty += qty, and LastFill.Qty is not zero, qty=0. /// if (qty!=0) we have completely flipped our position to other side. Add new fill. /// </summary> /// <param name="aFill">A ref to the Fill is kept here.</param> public virtual void Add(Fill aFill) { int remainingQty = aFill.Qty; if (remainingQty == 0) { return; // do nothing in this case. } // Store the fill. if (aFill.LocalTime.CompareTo(LocalTimeLast) > 0) { LocalTimeLast = aFill.LocalTime; } if (aFill.ExchangeTime.CompareTo(ExchangeTimeLast) > 0) { ExchangeTimeLast = aFill.ExchangeTime; } m_FillTrail.Add(aFill); // Update total volume m_Volume += Math.Abs(remainingQty); // // Allocate fill against our open posiion. // if (m_FillsOpen.Count == 0 || remainingQty * m_FillsOpen[0].Qty >= 0) { // adding to our position, or new position. Fill newFill = Fill.Create(aFill); m_FillsOpen.Add(newFill); } else { // cancelling positions. double realPnL = 0.0; while (remainingQty != 0 && m_FillsOpen.Count > 0) { Fill oldFill = m_FillsOpen[m_FillsOpen.Count - 1]; if ((oldFill.Qty + remainingQty) * remainingQty >= 0) { // Incoming qty kills old fill qty "Q0" entirely; so the transacting amount is Q0 realPnL += -oldFill.Qty * oldFill.Price + oldFill.Qty * aFill.Price; // -Q0*P0 - (-Q0)*P remainingQty += m_FillsOpen[m_FillsOpen.Count - 1].Qty; // Q = Q + Q0 m_FillsOpen.RemoveAt(m_FillsOpen.Count - 1); // remove entire old fill [P0,Q0] } else { // Old fill completely absorbs new fill qty "Q"; transacting amount is Q realPnL += remainingQty * oldFill.Price - remainingQty * aFill.Price; // -pnl = -(-Q)*P1 - Q*P oldFill.Qty += remainingQty; // reduce oldQty by amount transacted. remainingQty = 0; // there is no quantity left. } } if (remainingQty != 0) { // After cancelling out all levels of old fills, we still have some left! Fill newFill = Fill.Create(aFill); newFill.Qty = remainingQty; // overwrite the quantity with remaining qty. m_FillsOpen.Add(newFill); } m_RealizedGain += realPnL; } UpdatePositionInfo(); }//Add()
private void Test1() { InstrumentName name = new InstrumentName(new Product("CME", "GE", ProductTypes.Spread), "H2M2"); FillBookLifo book = new FillBookLifo(0.5, 12.50, name); List <Fill> aList = new List <Fill>(); for (int i = 0; i < 2; ++i) { Fill aFill = Fill.Create(); aFill.Qty = i + 2; aFill.Price = 1.0 + 0.5 * i; aFill.LocalTime = DateTime.Now.AddHours(i * .25); aFill.ExchangeTime = aFill.LocalTime; aList.Add(aFill); //string s = SerializeToString(aFill).Replace('\n',' '); //textBox1.Text = textBox1.Text + s; book.Add(aFill); } textBox1.Text = SerializeToString(book); }
public static Tensor <T> Const <T>(Scalar <T> content, params Dim[] shape) => Fill <T> .Create(content, shape);
}//DistributeFillsToQuoters() // // // ************************************************************* // **** Process Unwanted Fills() **** // ************************************************************* protected void ProcessUnwantedFills(ref List <Fill>[] newFills, ref Dictionary <Quote, List <Fill> > distributedFills) { // // Cancel off-setting fills. // if (newFills[0].Count > 0 && newFills[1].Count > 0) { Log.AppendEntry(" Remove offsetting fills:"); while (newFills[0].Count > 0 && newFills[1].Count > 0) { Fill fillLong = newFills[0][0]; newFills[0].RemoveAt(0); Fill fillShort = newFills[1][0]; newFills[1].RemoveAt(0); int netQty = fillLong.Qty + fillShort.Qty; // cancel the first fill in each list. int cancelledQty = Math.Min(Math.Abs(fillLong.Qty), Math.Abs(fillShort.Qty)); Log.AppendEntry(" PnL={0}", cancelledQty * (fillShort.Price - fillLong.Price)); if (netQty > 0) { // Long side will survive somewhat. Fill remainder = Fill.Create(fillLong); remainder.Qty = netQty; newFills[0].Insert(0, remainder); } else if (netQty < 0) { Fill remainder = Fill.Create(fillShort); remainder.Qty = netQty; newFills[1].Insert(0, remainder); } } } // // Pass: distribute fills to anyone with position: "forced exit" // if (newFills[0].Count > 0 || newFills[1].Count > 0) { for (int tradeSide = 0; tradeSide < 2; ++tradeSide) { int exitSide = QTMath.MktSideToOtherSide(tradeSide); if (newFills[tradeSide].Count == 0 || m_FillQty[exitSide].Count == 0) { continue; } int tradeSign = QTMath.MktSideToMktSign(tradeSide); foreach (KeyValuePair <PricingEngine, int> kv in m_FillQty[exitSide]) { Quote quote; List <Fill> fills; int qtyToForce = 0; if (m_Quotes[tradeSide].TryGetValue(kv.Key, out quote) && distributedFills.TryGetValue(quote, out fills)) { // This strategy already has some fills. int fillQty = 0; foreach (Fill fill in fills) { fillQty += fill.Qty; } int finalQty = (kv.Value + fillQty); qtyToForce = Math.Min(0, tradeSign * finalQty); // qty for fill he can still take. } else { qtyToForce = -kv.Value; } if (qtyToForce != 0) { // Pass to him extra fills foreach (Fill fill in newFills[tradeSide]) { } } } }// next side } // // Pass: distribute fills to anyone with a quote! // if (newFills[0].Count > 0 || newFills[1].Count > 0) { for (int tradeSide = 0; tradeSide < 2; ++tradeSide) { if (newFills[tradeSide].Count == 0) { continue; } Log.AppendEntry(" Forcing fills:"); int tradeSign = QTMath.MktSideToMktSign(tradeSide); // Collect all the quotes List <Quote> quotes = m_QuoteListRecycling.Get(); quotes.Clear(); foreach (KeyValuePair <int, List <Quote> > kv in m_QuotesByPrice[tradeSide]) { quotes.AddRange(kv.Value); } int quoteID = 0; int qtyToForce = 1; // TODO: This can be dynamic // Force fills now while (newFills[tradeSide].Count > 0 && quotes.Count > 0) { Quote quote = quotes[quoteID]; Fill origFill = newFills[tradeSide][0]; newFills[tradeSide].RemoveAt(0); Fill fillToDistribute = null; int fillQty = tradeSign * Math.Min(qtyToForce, Math.Abs(origFill.Qty)); if ((origFill.Qty - fillQty) == 0) { // Entire fill is consumed. fillToDistribute = origFill; } else { fillToDistribute = Fill.Create(origFill); fillToDistribute.Qty = fillQty; Fill remainingFill = Fill.Create(origFill); remainingFill.Qty = origFill.Qty - fillQty; newFills[tradeSide].Insert(0, remainingFill); } List <Fill> fills; if (!distributedFills.TryGetValue(quote, out fills)) { // This is this quotes first fill, so create a fill list. fills = new List <Fill>(); distributedFills.Add(quote, fills); } fills.Add(fillToDistribute); Log.AppendEntry(" {0} filled {1}.", quote.PricingEngine.EngineName, fillToDistribute); // increment the while loop! quoteID = (quoteID + 1) % quotes.Count; }//wend // Cleanup. quotes.Clear(); m_QuoteListRecycling.Recycle(quotes); } // next side } // if fills to distribute. // // Failed to distribute fills. // if (newFills[0].Count > 0 || newFills[1].Count > 0) { Log.AppendEntry(" FAILED to distribute fills:"); for (int tradeSide = 0; tradeSide < 2; ++tradeSide) { foreach (Fill fill in newFills[tradeSide]) { m_UndistributedFills[tradeSide].Add(fill); Log.AppendEntry(" {0}", fill); } } } }// ProcessUnwantedFills()
}// 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()