/// <summary> /// Event handler for streaming events /// </summary> /// <param name="data">The event object</param> private void OnEventReceived(Event data) { if (data.IsHeartbeat()) { lock (LockerConnectionMonitor) { LastHeartbeatUtcTime = DateTime.UtcNow; } return; } if (data.transaction != null) { if (data.transaction.type == "ORDER_FILLED") { var qcOrder = OrderProvider.GetOrderByBrokerageId(data.transaction.orderId); qcOrder.PriceCurrency = SecurityProvider.GetSecurity(qcOrder.Symbol).SymbolProperties.QuoteCurrency; const int orderFee = 0; var fill = new OrderEvent(qcOrder, DateTime.UtcNow, orderFee, "Oanda Fill Event") { Status = OrderStatus.Filled, FillPrice = (decimal)data.transaction.price, FillQuantity = data.transaction.units }; // flip the quantity on sell actions if (qcOrder.Direction == OrderDirection.Sell) { fill.FillQuantity *= -1; } OnOrderEvent(fill); } } }
/// <summary> /// Event handler for streaming events /// </summary> /// <param name="json">The event object</param> private void OnTransactionDataReceived(string json) { var obj = (JObject)JsonConvert.DeserializeObject(json); var type = obj["type"].ToString(); switch (type) { case "HEARTBEAT": lock (LockerConnectionMonitor) { LastHeartbeatUtcTime = DateTime.UtcNow; } break; case "ORDER_FILL": var transaction = obj.ToObject <OrderFillTransaction>(); var order = OrderProvider.GetOrderByBrokerageId(transaction.OrderID); if (order != null) { order.PriceCurrency = SecurityProvider.GetSecurity(order.Symbol).SymbolProperties.QuoteCurrency; const int orderFee = 0; OnOrderEvent(new OrderEvent(order, DateTime.UtcNow, orderFee, "Oanda Fill Event") { Status = OrderStatus.Filled, FillPrice = transaction.Price.ToDecimal(), FillQuantity = Convert.ToInt32(transaction.Units) }); } break; } }
/// <summary> /// Event handler for streaming events /// </summary> /// <param name="data">The event object</param> private void OnEventReceived(Event data) { if (data.IsHeartbeat()) { lock (LockerConnectionMonitor) { LastHeartbeatUtcTime = DateTime.UtcNow; } return; } if (data.transaction != null) { if (data.transaction.type == "ORDER_FILLED") { Order order; lock (Locker) { order = OrderProvider.GetOrderByBrokerageId(data.transaction.orderId); } if (order != null) { OrderStatus status; // Market orders are special: if the order was not in 'PartiallyFilledMarketOrders', means // we already sent the fill event with OrderStatus.Filled, else it means we already informed the user // of a partiall fill, or didn't inform the user, so we need to do it now if (order.Type != OrderType.Market || PendingFilledMarketOrders.TryRemove(order.Id, out status)) { order.PriceCurrency = SecurityProvider.GetSecurity(order.Symbol).SymbolProperties.QuoteCurrency; const int orderFee = 0; var fill = new OrderEvent(order, DateTime.UtcNow, orderFee, "Oanda Fill Event") { Status = OrderStatus.Filled, FillPrice = (decimal)data.transaction.price, FillQuantity = data.transaction.units }; // flip the quantity on sell actions if (order.Direction == OrderDirection.Sell) { fill.FillQuantity *= -1; } OnOrderEvent(fill); } } else { Log.Error($"OandaBrokerage.OnEventReceived(): order id not found: {data.transaction.orderId}"); } } } }
/// <summary> /// Event handler for streaming events /// </summary> /// <param name="json">The event object</param> private void OnTransactionDataReceived(string json) { var obj = (JObject)JsonConvert.DeserializeObject(json); var type = obj["type"].ToString(); switch (type) { case "HEARTBEAT": lock (LockerConnectionMonitor) { LastHeartbeatUtcTime = DateTime.UtcNow; } break; case "ORDER_FILL": var transaction = obj.ToObject <OrderFillTransaction>(); Order order; lock (Locker) { order = OrderProvider.GetOrderByBrokerageId(transaction.OrderID); } if (order != null) { OrderStatus status; // Market orders are special: if the order was not in 'PartiallyFilledMarketOrders', means // we already sent the fill event with OrderStatus.Filled, else it means we already informed the user // of a partiall fill, or didn't inform the user, so we need to do it now if (order.Type != OrderType.Market || PendingFilledMarketOrders.TryRemove(order.Id, out status)) { order.PriceCurrency = SecurityProvider.GetSecurity(order.Symbol).SymbolProperties.QuoteCurrency; const int orderFee = 0; OnOrderEvent(new OrderEvent(order, DateTime.UtcNow, orderFee, "Oanda Fill Event") { Status = OrderStatus.Filled, FillPrice = transaction.Price.ToDecimal(), FillQuantity = Convert.ToInt32(transaction.Units) }); } } else { Log.Error($"OandaBrokerage.OnTransactionDataReceived(): order id not found: {transaction.OrderID}"); } break; } }
/// <summary> /// Event handler for streaming events /// </summary> /// <param name="json">The event object</param> private void OnTransactionDataReceived(string json) { var obj = (JObject)JsonConvert.DeserializeObject(json); var type = obj["type"].ToString(); switch (type) { case "HEARTBEAT": TransactionsConnectionHandler.KeepAlive(DateTime.UtcNow); break; case "ORDER_FILL": var transaction = obj.ToObject <OrderFillTransaction>(); Order order; lock (Locker) { order = OrderProvider.GetOrderByBrokerageId(transaction.OrderID); } if (order != null) { OrderStatus status; // Market orders are special: if the order was not in 'PartiallyFilledMarketOrders', means // we already sent the fill event with OrderStatus.Filled, else it means we already informed the user // of a partiall fill, or didn't inform the user, so we need to do it now if (order.Type != OrderType.Market || PendingFilledMarketOrders.TryRemove(order.Id, out status)) { OnOrderEvent(new OrderEvent(order, DateTime.UtcNow, OrderFee.Zero, "Oanda Fill Event") { Status = OrderStatus.Filled, FillPrice = transaction.Price.ToDecimal(), FillQuantity = transaction.Units.ConvertInvariant <decimal>() }); } } else { Log.Error($"OandaBrokerage.OnTransactionDataReceived(): order id not found: {transaction.OrderID}"); } break; } }
/// <summary> /// Converts an Oanda order into a LEAN order. /// </summary> private Order ConvertOrder(JToken order) { var type = order["type"].ToString(); Order qcOrder; switch (type) { case "MARKET_IF_TOUCHED": var stopOrder = order.ToObject <MarketIfTouchedOrder>(); qcOrder = new StopMarketOrder { StopPrice = stopOrder.Price.ToDecimal() }; break; case "LIMIT": var limitOrder = order.ToObject <OandaLimitOrder>(); qcOrder = new LimitOrder { LimitPrice = limitOrder.Price.ToDecimal() }; break; case "STOP": var stopLimitOrder = order.ToObject <StopOrder>(); qcOrder = new StopLimitOrder { Price = stopLimitOrder.Price.ConvertInvariant <decimal>(), LimitPrice = stopLimitOrder.PriceBound.ConvertInvariant <decimal>() }; break; case "MARKET": qcOrder = new MarketOrder(); break; default: throw new NotSupportedException( "An existing " + type + " working order was found and is currently unsupported. Please manually cancel the order before restarting the algorithm."); } var instrument = order["instrument"].ToString(); var id = order["id"].ToString(); var units = order["units"].ConvertInvariant <int>(); var createTime = order["createTime"].ToString(); var securityType = SymbolMapper.GetBrokerageSecurityType(instrument); qcOrder.Symbol = SymbolMapper.GetLeanSymbol(instrument, securityType, Market.Oanda); qcOrder.Time = GetTickDateTimeFromString(createTime); qcOrder.Quantity = units; qcOrder.Status = OrderStatus.None; qcOrder.BrokerId.Add(id); var orderByBrokerageId = OrderProvider.GetOrderByBrokerageId(id); if (orderByBrokerageId != null) { qcOrder.Id = orderByBrokerageId.Id; } var gtdTime = order["gtdTime"]; if (gtdTime != null) { var expiry = GetTickDateTimeFromString(gtdTime.ToString()); qcOrder.Properties.TimeInForce = TimeInForce.GoodTilDate(expiry); } return(qcOrder); }
/// <summary> /// Converts the specified Oanda order into a qc order. /// The 'task' will have a value if we needed to issue a rest call for the stop price, otherwise it will be null /// </summary> private Order ConvertOrder(RestV1.DataType.Order order) { Order qcOrder; switch (order.type) { case "limit": qcOrder = new LimitOrder(); if (order.side == "buy") { ((LimitOrder)qcOrder).LimitPrice = Convert.ToDecimal(order.lowerBound); } if (order.side == "sell") { ((LimitOrder)qcOrder).LimitPrice = Convert.ToDecimal(order.upperBound); } break; case "stop": qcOrder = new StopLimitOrder(); if (order.side == "buy") { ((StopLimitOrder)qcOrder).LimitPrice = Convert.ToDecimal(order.lowerBound); } if (order.side == "sell") { ((StopLimitOrder)qcOrder).LimitPrice = Convert.ToDecimal(order.upperBound); } break; case "marketIfTouched": //when market reaches the price sell at market. qcOrder = new StopMarketOrder { Price = Convert.ToDecimal(order.price), StopPrice = Convert.ToDecimal(order.price) }; break; case "market": qcOrder = new MarketOrder(); break; default: throw new NotSupportedException("The Oanda order type " + order.type + " is not supported."); } var securityType = SymbolMapper.GetBrokerageSecurityType(order.instrument); qcOrder.Symbol = SymbolMapper.GetLeanSymbol(order.instrument, securityType, Market.Oanda); qcOrder.Quantity = ConvertQuantity(order); qcOrder.Status = OrderStatus.None; qcOrder.BrokerId.Add(order.id.ToString()); var orderByBrokerageId = OrderProvider.GetOrderByBrokerageId(order.id); if (orderByBrokerageId != null) { qcOrder.Id = orderByBrokerageId.Id; } var expiry = XmlConvert.ToDateTime(order.expiry, XmlDateTimeSerializationMode.Utc); qcOrder.Properties.TimeInForce = TimeInForce.GoodTilDate(expiry); qcOrder.Time = XmlConvert.ToDateTime(order.time, XmlDateTimeSerializationMode.Utc); return(qcOrder); }
/// <summary> /// Converts an Oanda order into a LEAN order. /// </summary> private Order ConvertOrder(JToken order) { var type = order["type"].ToString(); var instrument = order["instrument"].ToString(); var id = order["id"].ToString(); var units = Convert.ToInt32(order["units"]); var createTime = order["createTime"].ToString(); Order qcOrder; switch (type) { case "MARKET_IF_TOUCHED": var stopOrder = order.ToObject <MarketIfTouchedOrder>(); qcOrder = new StopMarketOrder { StopPrice = stopOrder.Price.ToDecimal() }; break; case "LIMIT": var limitOrder = order.ToObject <OandaLimitOrder>(); qcOrder = new LimitOrder { LimitPrice = limitOrder.Price.ToDecimal() }; break; case "STOP": var stopLimitOrder = order.ToObject <StopOrder>(); qcOrder = new StopLimitOrder { Price = Convert.ToDecimal(stopLimitOrder.Price), LimitPrice = Convert.ToDecimal(stopLimitOrder.PriceBound) }; break; case "MARKET": qcOrder = new MarketOrder(); break; default: throw new NotSupportedException("The Oanda order type " + type + " is not supported."); } var securityType = SymbolMapper.GetBrokerageSecurityType(instrument); qcOrder.Symbol = SymbolMapper.GetLeanSymbol(instrument, securityType, Market.Oanda); qcOrder.Time = GetTickDateTimeFromString(createTime); qcOrder.Quantity = units; qcOrder.Status = OrderStatus.None; qcOrder.BrokerId.Add(id); var orderByBrokerageId = OrderProvider.GetOrderByBrokerageId(id); if (orderByBrokerageId != null) { qcOrder.Id = orderByBrokerageId.Id; } var gtdTime = order["gtdTime"]; if (gtdTime != null) { qcOrder.Duration = OrderDuration.Custom; qcOrder.DurationValue = GetTickDateTimeFromString(gtdTime.ToString()); } return(qcOrder); }