private void ProcessOrder(OrderRecord order, bool bRequest) { if (order != null) { if (order.Type == "UserSubmitStagedOrder") { string sDetails = order.GetDetails(); if (!bRequest) // don't want to spam the console at startup... { Console.WriteLine("Received Order Update: " + sDetails); } OrderRecord oldOrder = null; if (_book.ContainsKey(order.OrderID)) { oldOrder = _book[order.OrderID]; } OrderStats stats = GetOrCreateStats(order.Portfolio); stats.ReplaceOrder(order, oldOrder); // it's ok if oldOrder is null _book[order.OrderID] = order; // I don't like this... if (stats._statsRecalcNeeded) { RecalculateStats(order.Portfolio); } // Fire event to publish the result if (!bRequest) // only do this here for realtime updates. Otherwise, do it outside of loop. { StatsChanged?.Invoke(order.Portfolio, stats); } if (!bRequest) { if (_rand.Next(10) == 0) { var IDs = new List <string>(); IDs.Add(order.OrderID); AppendMagicDataToOrders(IDs); } } } else if (order.Type == "UserSubmitOrder") { _child_book[order.OrderID] = order; } } }
// Called when there is a realtime update to an order public bool ReplaceOrder(OrderRecord newOrder, OrderRecord oldOrder) { bool AnythingInterestingChanged = false; if (oldOrder == null) { AnythingInterestingChanged = true; } else { if (newOrder.Status != oldOrder.Status) { AnythingInterestingChanged = true; } else if (newOrder.lWorking != oldOrder.lWorking) { AnythingInterestingChanged = true; } else if (newOrder.lQtyTraded != oldOrder.lQtyTraded) { AnythingInterestingChanged = true; } else if (newOrder.lQty != oldOrder.lQty) { AnythingInterestingChanged = true; } } if (AnythingInterestingChanged) { if (oldOrder != null) { UpdateOrderStats(oldOrder, false); // remove old order's contribution to stats } UpdateOrderStats(newOrder, true); } return(AnythingInterestingChanged); }
private List <string> BuildListOfChildOrderIDs(string algoName, bool bLiveOnly = true) { List <string> IDs = new List <string>(); foreach (KeyValuePair <string, OrderRecord> entry in _child_book) { string TicketID = entry.Value.TicketID; if (TicketID != null && TicketID.Length > 0) { // look up the parent and see if it is associated with the desired Algo OrderRecord parent = _book[entry.Value.TicketID]; if (parent != null && parent.Portfolio == algoName) { if (!bLiveOnly || entry.Value.IsLive()) { IDs.Add(entry.Value.OrderID); } } } } return(IDs); }
private void ProcessDataBlock(IDataBlock block, bool bRequest) { foreach (Row row in block) { OrderRecord order = new OrderRecord(); foreach (Field f in row) { if (f.FieldInfo.Name == "TYPE") { order.Type = f.StringValue; } else if (f.FieldInfo.Name == "ORDER_ID") { order.OrderID = f.StringValue; } else if (f.FieldInfo.Name == "CURRENT_STATUS") { order.Status = f.StringValue; } else if (f.FieldInfo.Name == "DISP_NAME") { order.Symbol = f.StringValue; } else if (f.FieldInfo.Name == "VOLUME") { order.lQty = f.IntValue; } else if (f.FieldInfo.Name == "VOLUME_TRADED") { order.lQtyTraded = f.IntValue; } else if (f.FieldInfo.Name == "BUYORSELL") { order.Side = f.StringValue; } else if (f.FieldInfo.Name == "AVG_PRICE") { order.dPrice = f.DoubleValue; } else if (f.FieldInfo.Name == "WORKING_QTY") { order.lWorking = f.LongValue; } else if (f.FieldInfo.Name == "ORDER_TAG") { order.OrderTag = f.StringValue; } else if (f.FieldInfo.Name == "PORTFOLIO_NAME") { order.Portfolio = f.StringValue; } else if (f.FieldInfo.Name == "TRDPRC_1") { order.ArrivalPrice = f.PriceValue; } else if (f.FieldInfo.Name == "TS3_CONVERSION_RULE_FLAGS") { order.ConversionRuleFlags = (ulong)f.LongValue; } else if (f.FieldInfo.Name == "TICKET_ID") { order.TicketID = f.StringValue; } } ProcessOrder(order, bRequest); } if (bRequest) // when we get a data refesh, re-publish all stats { foreach (KeyValuePair <string, OrderStats> s in Stats) { OrderStats stats = s.Value; // Fire event to publish the result StatsChanged?.Invoke(s.Key, stats); } } }
// either add an order to stats, or remove it. public void UpdateOrderStats(OrderRecord order, bool bAdd = true) { int inc = bAdd ? 1 : -1; Total += inc; switch (order.Status) { case "PENDING": Pending += inc; break; case "LIVE": { if (order.lWorking > 0) { Working += inc; } else { Staged += inc; } break; } case "COMPLETED": Completed += inc; break; case "DELETED": Deleted += inc; break; } long OrderTargetQty = order.IsLive() ? order.lQty : order.lQtyTraded; long OrderResidual = OrderTargetQty - order.lQtyTraded; if (OrderResidual < 0) { OrderResidual = 0; } double OrderCompletedValue = (double)(order.lQtyTraded * order.dPrice); double OrderResidualValue = (double)(OrderResidual * order.ArrivalPrice.DecimalValue); double OrderTargetValue = OrderCompletedValue + OrderResidualValue; if (OrderTargetValue < OrderCompletedValue) { // this shouldn't happen, but it seems like it does occasionally... OrderTargetValue = OrderCompletedValue; } double OrderBenchmarkValue = (double)(OrderTargetQty * order.ArrivalPrice.DecimalValue); // Ex: bought at 5, benchmark 7 -> P&L = 2. Flip the sign for sells (SideMult) double OrderPL = (OrderBenchmarkValue - OrderTargetValue) * order.SideMult(); TotalQty += (OrderTargetQty * inc); CompletedQty += (order.lQtyTraded * inc); CompletedValue += (OrderCompletedValue * inc); TotalValue += (OrderTargetValue * inc); BenchmarkValue += (OrderBenchmarkValue * inc); BenchmarkPL += (OrderPL * inc); CompletedPct = 1000 * GetValueCompletionRate(); CompletedPct = Math.Truncate(CompletedPct) / 10; if (order.Status != "DELETED" && order.Status != "PENDING") { const ulong CRF_SUBMITTED_BY_RULES = 0x00000001; // sorry for this magic if ((order.ConversionRuleFlags & CRF_SUBMITTED_BY_RULES) != 0) { AutoRouted += inc; } else if (order.lWorking > 0 || order.lQtyTraded > 0) { Manual += inc; } } }
public void AddOrder(OrderRecord order) { UpdateOrderStats(order, true); }