Exemplo n.º 1
0
        /// <summary>
        /// Converts the tradier order quantity into a qc quantity
        /// </summary>
        /// <remarks>
        /// Tradier quantities are always positive and use the direction to denote +/-, where as qc
        /// order quantities determine the direction
        /// </remarks>
        protected int ConvertQuantity(Anonymous8 order)
        {
            switch (order.Type)
            {
            case Type2.Buy:
                return((int)order.Quantity);

            case Type2.Sell:
                return(-(int)order.Quantity);

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Exemplo n.º 2
0
        /*
         * private bool IsUnknownOrderID(KeyValuePair<long, TradierOrder> x)
         * {
         *  // we don't have it in our local cache
         *  return !_cachedOpenOrdersByTradierOrderID.ContainsKey(x.Key)
         *      // the transaction happened after we initialized, make sure they're in the same time zone
         *      && x.Value.TransactionDate.ToUniversalTime() > _initializationDateTime.ToUniversalTime()
         *      // we don't have a record of it in our last 10k filled orders
         *      && !_filledTradierOrderIDs.Contains(x.Key);
         * }
         *
         * private void ProcessPotentiallyUpdatedOrder(TradierCachedOpenOrder cachedOrder, TradierOrder updatedOrder)
         * {
         *  // check for fills or status changes, for either fire a fill event
         *  if (updatedOrder.RemainingQuantity != cachedOrder.Order.RemainingQuantity
         || ConvertStatus(updatedOrder.Status) != ConvertStatus(cachedOrder.Order.Status))
         || {
         ||     var qcOrder = _orderProvider.GetOrderByBrokerageId(updatedOrder.Id);
         ||     qcOrder.PriceCurrency = "USD";
         ||     const int orderFee = 0;
         ||     var fill = new OrderEvent(qcOrder, DateTime.UtcNow, orderFee, "Tradier Fill Event")
         ||     {
         ||         Status = ConvertStatus(updatedOrder.Status),
         ||         // this is guaranteed to be wrong in the event we have multiple fills within our polling interval,
         ||         // we're able to partially cope with the fill quantity by diffing the previous info vs current info
         ||         // but the fill price will always be the most recent fill, so if we have two fills with 1/10 of a second
         ||         // we'll get the latter fill price, so for large orders this can lead to inconsistent state
         ||         FillPrice = updatedOrder.LastFillPrice,
         ||         FillQuantity = (int)(updatedOrder.QuantityExecuted - cachedOrder.Order.QuantityExecuted)
         ||     };
         ||
         ||     // flip the quantity on sell actions
         ||     if (IsShort(updatedOrder.Direction))
         ||     {
         ||         fill.FillQuantity *= -1;
         ||     }
         ||
         ||     if (!cachedOrder.EmittedOrderFee)
         ||     {
         ||         cachedOrder.EmittedOrderFee = true;
         ||         var security = _securityProvider.GetSecurity(qcOrder.Symbol);
         ||         fill.OrderFee = security.FeeModel.GetOrderFee(security, qcOrder);
         ||     }
         ||
         ||     // if we filled the order and have another contingent order waiting, submit it
         ||     ContingentOrderQueue contingent;
         ||     if (fill.Status == OrderStatus.Filled && _contingentOrdersByQCOrderID.TryGetValue(qcOrder.Id, out contingent))
         ||     {
         ||         // prevent submitting the contingent order multiple times
         ||         if (_contingentReentranceGuardByQCOrderID.Add(qcOrder.Id))
         ||         {
         ||             var order = contingent.Next();
         ||             if (order == null || contingent.Contingents.Count == 0)
         ||             {
         ||                 // we've finished with this contingent order
         ||                 _contingentOrdersByQCOrderID.TryRemove(qcOrder.Id, out contingent);
         ||             }
         ||             // fire this off in a task so we don't block this thread
         ||             if (order != null)
         ||             {
         ||                 // if we have a contingent that needs to be submitted then we can't respect the 'Filled' state from the order
         ||                 // because the QC order hasn't been technically filled yet, so mark it as 'PartiallyFilled'
         ||                 fill.Status = OrderStatus.PartiallyFilled;
         ||
         ||                 Task.Run(() =>
         ||                 {
         ||                     try
         ||                     {
         ||                         Log.Trace("TradierBrokerage.SubmitContingentOrder(): Submitting contingent order for QC id: " + qcOrder.Id);
         ||
         ||                         var response = TradierPlaceOrder(order);
         ||                         if (response.Errors.Errors.IsNullOrEmpty())
         ||                         {
         ||                             // add the new brokerage id for retrieval later
         ||                             qcOrder.BrokerId.Add(response.Order.Id.ToString());
         ||                         }
         ||                         else
         ||                         {
         ||                             // if we failed to place this order I don't know what to do, we've filled the first part
         ||                             // and failed to place the second... strange. Should we invalidate the rest of the order??
         ||                             Log.Error("TradierBrokerage.SubmitContingentOrder(): Failed to submit contingent order.");
         ||                             var message = string.Format("{0} Failed submitting contingent order for QC id: {1} Filled Tradier Order id: {2}", qcOrder.Symbol, qcOrder.Id, updatedOrder.Id);
         ||                             OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Warning, "ContingentOrderFailed", message));
         ||                             OnOrderEvent(new OrderEvent(qcOrder, DateTime.UtcNow, orderFee) { Status = OrderStatus.Canceled });
         ||                         }
         ||                     }
         ||                     catch (Exception err)
         ||                     {
         ||                         Log.Error(err);
         ||                         OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Warning, "ContingentOrderError", "An error ocurred while trying to submit an Tradier contingent order: " + err));
         ||                         OnOrderEvent(new OrderEvent(qcOrder, DateTime.UtcNow, orderFee) { Status = OrderStatus.Canceled });
         ||                     }
         ||                     finally
         ||                     {
         ||                         _contingentReentranceGuardByQCOrderID.Remove(qcOrder.Id);
         ||                     }
         ||                 });
         ||             }
         ||         }
         ||     }
         ||
         ||     OnOrderEvent(fill);
         || }
         ||
         || // remove from open orders since it's now closed
         || if (OrderIsClosed(updatedOrder))
         || {
         ||     _filledTradierOrderIDs.Add(updatedOrder.Id);
         ||     _cachedOpenOrdersByTradierOrderID.TryRemove(updatedOrder.Id, out cachedOrder);
         || }
         ||}
         ||
         ||private void UpdateCachedOpenOrder(long key, TradierOrder updatedOrder)
         ||{
         || TradierCachedOpenOrder cachedOpenOrder;
         || if (_cachedOpenOrdersByTradierOrderID.TryGetValue(key, out cachedOpenOrder))
         || {
         ||     cachedOpenOrder.Order = updatedOrder;
         || }
         || else
         || {
         ||     _cachedOpenOrdersByTradierOrderID[key] = new TradierCachedOpenOrder(updatedOrder);
         || }
         ||}
         */

        #endregion

        #region Conversion routines

        /// <summary>
        /// Converts the specified tradier 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>
        protected Order ConvertOrder(Anonymous8 order)
        {
            Order qcOrder;

            qcOrder = new LimitOrder()
            {
                LimitPrice = (decimal)order.LimitPrice
            };
            //TODO

            /*
             * switch (order.OrderType)
             * {
             *  case Type2
             *      qcOrder = new LimitOrder { LimitPrice = order.Price };
             *      break;
             *  case TradierOrderType.Market:
             *      qcOrder = new MarketOrder();
             *      break;
             *  case TradierOrderType.StopMarket:
             *      qcOrder = new StopMarketOrder { StopPrice = GetOrder(order.Id).StopPrice };
             *      break;
             *  case TradierOrderType.StopLimit:
             *      qcOrder = new StopLimitOrder { LimitPrice = order.Price, StopPrice = GetOrder(order.Id).StopPrice };
             *      break;
             *
             *  //case TradierOrderType.Credit:
             *  //case TradierOrderType.Debit:
             *  //case TradierOrderType.Even:
             *  default:
             *      throw new NotImplementedException("The Tradier order type " + order.Type + " is not implemented.");
             * }
             */
            qcOrder.Symbol   = _symbolMapper.GetLeanSymbol(order.Symbol, order.AssetType);// Symbol.Create(order.Symbol, SecurityType.Equity, Market.USA);
            qcOrder.Quantity = ConvertQuantity(order);
            qcOrder.Status   = ConvertStatus(order.Status);
            qcOrder.Id       = Int32.Parse(order.OrderID.ToString());
            //qcOrder.BrokerId.Add(order.OrderID.ToString());
            //qcOrder.ContingentId =
            qcOrder.Properties.TimeInForce = ConvertDuration(order.Duration);

            /*var orderByBrokerageId = _orderProvider.GetOrderByBrokerageId(order.OrderID.ToString());
             * if (orderByBrokerageId != null)
             * {
             *  qcOrder.Id = orderByBrokerageId.Id;
             * }
             */
            qcOrder.Time = DateTime.Parse(order.TimeStamp); //TransactionDate;
            return(qcOrder);
        }