/// <summary> /// Cancels the order with the specified ID /// </summary> /// <param name="order">The order to cancel</param> /// <returns>True if the request was made for the order to be canceled, false otherwise</returns> public override bool CancelOrder(Order order) { Log.Trace("OandaBrokerage.CancelOrder(): " + order); if (!order.BrokerId.Any()) { Log.Trace("OandaBrokerage.CancelOrder(): Unable to cancel order without BrokerId."); return(false); } foreach (var orderId in order.BrokerId) { CancelOrder(long.Parse(orderId)); OnOrderEvent(new OrderEvent(order, DateTime.UtcNow, 0, "Oanda Cancel Order Event") { Status = OrderStatus.Canceled }); } return(true); }
/// <summary> /// Updates the order with the same id /// </summary> /// <param name="order">The new order information</param> /// <returns>True if the request was made for the order to be updated, false otherwise</returns> public override bool UpdateOrder(Order order) { Log.Trace("OandaBrokerage.UpdateOrder(): " + order); if (!order.BrokerId.Any()) { // we need the brokerage order id in order to perform an update Log.Trace("OandaBrokerage.UpdateOrder(): Unable to update order without BrokerId."); return(false); } var requestParams = new Dictionary <string, string> { { "instrument", _symbolMapper.GetBrokerageSymbol(order.Symbol) }, { "units", Convert.ToInt32(order.AbsoluteQuantity).ToString() }, }; // we need the brokerage order id in order to perform an update PopulateOrderRequestParameters(order, requestParams); UpdateOrder(long.Parse(order.BrokerId.First()), requestParams); return(true); }
/// <summary> /// Places a new order and assigns a new broker ID to the order /// </summary> /// <param name="order">The order to be placed</param> /// <returns>True if the request for a new order has been placed, false otherwise</returns> public override bool PlaceOrder(Order order) { var requestParams = new Dictionary <string, string> { { "instrument", _symbolMapper.GetBrokerageSymbol(order.Symbol) }, { "units", Convert.ToInt32(order.AbsoluteQuantity).ToString() } }; PopulateOrderRequestParameters(order, requestParams); var postOrderResponse = PostOrderAsync(requestParams); if (postOrderResponse == null) { return(false); } // if market order, find fill quantity and price var marketOrderFillPrice = 0m; if (order.Type == OrderType.Market) { marketOrderFillPrice = Convert.ToDecimal(postOrderResponse.price); } var marketOrderFillQuantity = 0; if (postOrderResponse.tradeOpened != null && postOrderResponse.tradeOpened.id > 0) { if (order.Type == OrderType.Market) { marketOrderFillQuantity = postOrderResponse.tradeOpened.units; } else { order.BrokerId.Add(postOrderResponse.tradeOpened.id.ToString()); } } if (postOrderResponse.tradeReduced != null && postOrderResponse.tradeReduced.id > 0) { if (order.Type == OrderType.Market) { marketOrderFillQuantity = postOrderResponse.tradeReduced.units; } else { order.BrokerId.Add(postOrderResponse.tradeReduced.id.ToString()); } } if (postOrderResponse.orderOpened != null && postOrderResponse.orderOpened.id > 0) { if (order.Type != OrderType.Market) { order.BrokerId.Add(postOrderResponse.orderOpened.id.ToString()); } } if (postOrderResponse.tradesClosed != null && postOrderResponse.tradesClosed.Count > 0) { marketOrderFillQuantity += postOrderResponse.tradesClosed .Where(trade => order.Type == OrderType.Market) .Sum(trade => trade.units); } // send Submitted order event const int orderFee = 0; order.PriceCurrency = _securityProvider.GetSecurity(order.Symbol).SymbolProperties.QuoteCurrency; OnOrderEvent(new OrderEvent(order, DateTime.UtcNow, orderFee) { Status = OrderStatus.Submitted }); if (order.Type == OrderType.Market) { // if market order, also send Filled order event OnOrderEvent(new OrderEvent(order, DateTime.UtcNow, orderFee) { Status = OrderStatus.Filled, FillPrice = marketOrderFillPrice, FillQuantity = marketOrderFillQuantity * Math.Sign(order.Quantity) }); } return(true); }
private static void PopulateOrderRequestParameters(Order order, Dictionary <string, string> requestParams) { if (order.Direction != OrderDirection.Buy && order.Direction != OrderDirection.Sell) { throw new Exception("Invalid Order Direction"); } requestParams.Add("side", order.Direction == OrderDirection.Buy ? "buy" : "sell"); if (order.Type == OrderType.Market) { requestParams.Add("type", "market"); } if (order.Type == OrderType.Limit) { requestParams.Add("type", "limit"); requestParams.Add("price", ((LimitOrder)order).LimitPrice.ToString(CultureInfo.InvariantCulture)); switch (order.Direction) { case OrderDirection.Buy: //Limit Order Does not like Lower Bound Values == Limit Price value //Don't set bounds when placing limit orders. //Orders can be submitted with lower and upper bounds. If the market price on execution falls outside these bounds, it is considered a "Bounds Violation" and the order is cancelled. break; case OrderDirection.Sell: //Limit Order Does not like Lower Bound Values == Limit Price value //Don't set bounds when placing limit orders. //Orders can be submitted with lower and upper bounds. If the market price on execution falls outside these bounds, it is considered a "Bounds Violation" and the order is cancelled. break; } //3 months is the max expiry for Oanda, and OrderDuration.GTC is only currently available requestParams.Add("expiry", XmlConvert.ToString(DateTime.Now.AddMonths(3), XmlDateTimeSerializationMode.Utc)); } //this type should contain a stop and a limit to that stop. if (order.Type == OrderType.StopLimit) { requestParams.Add("type", "stop"); requestParams.Add("price", ((StopLimitOrder)order).StopPrice.ToString(CultureInfo.InvariantCulture)); switch (order.Direction) { case OrderDirection.Buy: requestParams.Add("upperBound", ((StopLimitOrder)order).LimitPrice.ToString(CultureInfo.InvariantCulture)); break; case OrderDirection.Sell: requestParams.Add("lowerBound", ((StopLimitOrder)order).LimitPrice.ToString(CultureInfo.InvariantCulture)); break; } //3 months is the max expiry for Oanda, and OrderDuration.GTC is only currently available requestParams.Add("expiry", XmlConvert.ToString(DateTime.Now.AddMonths(3), XmlDateTimeSerializationMode.Utc)); } if (order.Type == OrderType.StopMarket) { requestParams.Add("type", "marketIfTouched"); requestParams.Add("price", ((StopMarketOrder)order).StopPrice.ToString(CultureInfo.InvariantCulture)); //3 months is the max expiry for Oanda, and OrderDuration.GTC is only currently available requestParams.Add("expiry", XmlConvert.ToString(DateTime.Now.AddMonths(3), XmlDateTimeSerializationMode.Utc)); } }