/// <summary> /// Converts a Ruby date string into a DateTime. /// </summary> /// <param name="date">The string to convert.</param> /// <returns>The converted data.</returns> public static DateTime DateTimeFromRubyString(string date) { DateTimeFormatInfo dateFormat = new DateTimeFormatInfo(); dateFormat.SetAllDateTimePatterns(new string[] { "yyyy-MM-dd HH:mm:ss zzz" }, 'Y'); return DateTime.Parse(date, dateFormat); }
void client_ExecDetails(object sender, ExecDetailsEventArgs e) { lock (_lockObject) { Symbol symbol = TWSAssetArgs.SymbolFromContract(e.Contract); string msg = "IB ExecDetails: " + e.Execution.Time + " " + e.Execution.Side + " " + symbol + " Order ID: " + e.Execution.OrderId + " Size: " + e.Execution.Shares + " Price: " + e.Execution.Price; Trace.WriteLine(msg); //Console.WriteLine(msg); bool bIgnore = false; if (!string.IsNullOrEmpty(accountCode) && e.Execution.AccountNumber != accountCode) { Trace.WriteLine("### Execution ignored - Wrong Account"); bIgnore = true; } else if (e.Execution.Shares < 0) { Trace.WriteLine("### Execution Ignored - Negative Fill"); bIgnore = true; } if (!bIgnore) { string datePattern = "yyyyMMdd hh:mm:ss"; DateTimeFormatInfo dateFormat = new DateTimeFormatInfo(); dateFormat.SetAllDateTimePatterns(new[] { "yyyyMMdd" }, 'd'); dateFormat.SetAllDateTimePatterns(new[] { "HH:mm:ss" }, 't'); string[] dateSplit = e.Execution.Time.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); DateTime execDateTime = DateTime.ParseExact(dateSplit[0], "d", dateFormat).Date; TimeSpan execTime = DateTime.ParseExact(dateSplit[1], "t", dateFormat).TimeOfDay; execDateTime += execTime; BrokerOrder openOrder; if (openOrders.TryGetValue(e.OrderId.ToString(), out openOrder)) { // If we are reconnecting after a disconnect, we may get execDetails for partial fills that // we already know about. So loop through the fills through this order and see if // we already know about this execution. bool alreadyReported = false; foreach (Fill fill in openOrder.Fills) { string fillTimeString = fill.FillDateTime.ToString(datePattern); if (fillTimeString == e.Execution.Time && fill.Price.SymbolPrice == e.Execution.Price && fill.Quantity == e.Execution.Shares) { alreadyReported = true; } } if (!alreadyReported) { string information = ""; Fill fill = new Fill(); fill.FillDateTime = execDateTime; fill.Price = new Price(e.Execution.Price, e.Execution.Price); fill.Quantity = e.Execution.Shares; // Apparently IB doesn't send commissions fill.Commission = 0; openOrder.Fills.Add(fill); int totalFilled = 0; foreach (Fill f in openOrder.Fills) { totalFilled += f.Quantity; } if (totalFilled < openOrder.Shares) { openOrder.OrderState = BrokerOrderState.PartiallyFilled; information = "Partial fill"; } else { openOrder.OrderState = BrokerOrderState.Filled; openOrders.Remove(openOrder.OrderId); // Only remove from the potentially cancelled orders if it was completely filled // It may have been partially filled while disconnected and then cancelled if (_gettingReconnectData) { if (_potentiallyCancelledOrders.ContainsKey(openOrder.OrderId)) { _potentiallyCancelledOrders.Remove(openOrder.OrderId); } } } _filledOrders.RecordFill(openOrder.OrderId, fill.FillDateTime); //var callback = OutOfBandCallback; //if (callback != null) //{ // callback(this, EventArgs.Empty); //} OrderUpdatedDelegate tmp = OrderUpdated; if (tmp != null) { tmp(openOrder, fill, information); } } } } } }