示例#1
0
        /// <summary>
        /// Processes a new fill, eventually creating new trades
        /// </summary>
        /// <param name="fill">The new fill order event</param>
        /// <param name="conversionRate">The current security market conversion rate into the account currency</param>
        /// <param name="feeInAccountCurrency">The current order fee in the account currency</param>
        /// <param name="multiplier">The contract multiplier</param>
        public void ProcessFill(OrderEvent fill,
                                decimal conversionRate,
                                decimal feeInAccountCurrency,
                                decimal multiplier = 1.0m)
        {
            // If we have multiple fills per order, we assign the order fee only to its first fill
            // to avoid counting the same order fee multiple times.
            var orderFee = 0m;

            if (!_ordersWithFeesAssigned.Contains(fill.OrderId))
            {
                orderFee = feeInAccountCurrency;
                _ordersWithFeesAssigned.Add(fill.OrderId);
            }

            switch (_groupingMethod)
            {
            case FillGroupingMethod.FillToFill:
                ProcessFillUsingFillToFill(fill.Clone(), orderFee, conversionRate, multiplier);
                break;

            case FillGroupingMethod.FlatToFlat:
                ProcessFillUsingFlatToFlat(fill.Clone(), orderFee, conversionRate, multiplier);
                break;

            case FillGroupingMethod.FlatToReduced:
                ProcessFillUsingFlatToReduced(fill.Clone(), orderFee, conversionRate, multiplier);
                break;
            }
        }
        /// <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)
        {
            Log.Trace("TradeStation.PlaceOrder(): " + order);

            if (_cancelledQcOrderIDs.Contains(order.Id))
            {
                Log.Trace("TradeStation.PlaceOrder(): Cancelled Order: " + order.Id + " - " + order);
                return(false);
            }

            var tsOrder = new OrderRequestDefinition();

            tsOrder.Symbol = _symbolMapper.GetBrokerageSymbol(order.Symbol);
            if (order.Symbol.SecurityType == SecurityType.Option)
            {
                tsOrder.AssetType = OrderRequestDefinitionAssetType.OP;
            }
            else
            {
                tsOrder.AssetType = OrderRequestDefinitionAssetType.EQ;
            }
            tsOrder.AccountKey = _accountKeys[0];
            tsOrder.Quantity   = order.AbsoluteQuantity.ToString();
            if (order.Direction == OrderDirection.Buy)
            {
                tsOrder.TradeAction = OrderRequestDefinitionTradeAction.BUY;
            }
            else
            {
                tsOrder.TradeAction = OrderRequestDefinitionTradeAction.SELL;
            }
            tsOrder.OrderConfirmId = Guid.NewGuid().ToString();
            if (order.TimeInForce == TimeInForce.Day)
            {
                tsOrder.Duration = OrderRequestDefinitionDuration.DAY;
            }
            else
            {
                tsOrder.Duration = OrderRequestDefinitionDuration.GTC;
            }

            switch (order.Type)
            {
            case Orders.OrderType.Limit:
                tsOrder.LimitPrice = ((LimitOrder)order).LimitPrice.ToString();
                tsOrder.OrderType  = OrderRequestDefinitionOrderType.Limit;
                //TODO: support more order types
                tsOrder.TradeAction = tsOrder.TradeAction == OrderRequestDefinitionTradeAction.BUY ? OrderRequestDefinitionTradeAction.BUYTOOPEN : OrderRequestDefinitionTradeAction.SELLTOCLOSE;
                break;

            case Orders.OrderType.Market:
                tsOrder.OrderType = OrderRequestDefinitionOrderType.Market;
                break;

            default:
                throw new Exception("Order type not supported!");
            }

            var response = _tradeStationClient.PostOrderAsync(_accessToken, tsOrder).Result;

            Log.Trace("TradeStation.PlaceOrder(): " + response.Message);

            return(response.OrderStatus == OrderResponseDefinitionOrderStatus.Ok);

            /*
             *
             * // before doing anything, verify only one outstanding order per symbol
             * var cachedOpenOrder = _cachedOpenOrdersByTradierOrderID.FirstOrDefault(x => x.Value.Order.Symbol == order.Symbol.Value).Value;
             * if (cachedOpenOrder != null)
             * {
             *  var qcOrder = _orderProvider.GetOrderByBrokerageId(cachedOpenOrder.Order.Id);
             *  if (qcOrder == null)
             *  {
             *      // clean up our mess, this should never be encountered.
             *      TradierCachedOpenOrder tradierOrder;
             *      Log.Error("TradierBrokerage.PlaceOrder(): Unable to locate existing QC Order when verifying single outstanding order per symbol.");
             *      _cachedOpenOrdersByTradierOrderID.TryRemove(cachedOpenOrder.Order.Id, out tradierOrder);
             *  }
             *  // if the qc order is still listed as open, then we have an issue, attempt to cancel it before placing this new order
             *  else if (qcOrder.Status.IsOpen())
             *  {
             *      // let the world know what we're doing
             *      OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Warning, "OneOrderPerSymbol",
             *          "Tradier Brokerage currently only supports one outstanding order per symbol. Canceled old order: " + qcOrder.Id)
             *          );
             *
             *      // cancel the open order and clear out any contingents
             *      ContingentOrderQueue contingent;
             *      _contingentOrdersByQCOrderID.TryRemove(qcOrder.Id, out contingent);
             *      // don't worry about the response here, if it couldn't be canceled it was
             *      // more than likely already filled, either way we'll trust we're clean to proceed
             *      // with this new order
             *      CancelOrder(qcOrder);
             *  }
             * }
             *
             * var holdingQuantity = _securityProvider.GetHoldingsQuantity(order.Symbol);
             *
             * var orderRequest = new TradierPlaceOrderRequest(order, TradierOrderClass.Equity, holdingQuantity);
             *
             * // do we need to split the order into two pieces?
             * bool crossesZero = OrderCrossesZero(order);
             * if (crossesZero)
             * {
             *  // first we need an order to close out the current position
             *  var firstOrderQuantity = -holdingQuantity;
             *  var secondOrderQuantity = order.Quantity - firstOrderQuantity;
             *
             *  orderRequest.Quantity = Math.Abs(firstOrderQuantity);
             *
             *  // we actually can't place this order until the closingOrder is filled
             *  // create another order for the rest, but we'll convert the order type to not be a stop
             *  // but a market or a limit order
             *  var restOfOrder = new TradierPlaceOrderRequest(order, TradierOrderClass.Equity, 0) { Quantity = Math.Abs(secondOrderQuantity) };
             *  restOfOrder.ConvertStopOrderTypes();
             *
             *  _contingentOrdersByQCOrderID.AddOrUpdate(order.Id, new ContingentOrderQueue(order, restOfOrder));
             *
             *  // issue the first order to close the position
             *  var response = TradierPlaceOrder(orderRequest);
             *  bool success = response.Errors.Errors.IsNullOrEmpty();
             *  if (!success)
             *  {
             *      // remove the contingent order if we weren't succesful in placing the first
             *      ContingentOrderQueue contingent;
             *      _contingentOrdersByQCOrderID.TryRemove(order.Id, out contingent);
             *      return false;
             *  }
             *
             *  var closingOrderID = response.Order.Id;
             *  order.BrokerId.Add(closingOrderID.ToString());
             *  return true;
             * }
             * else
             * {
             *  var response = TradierPlaceOrder(orderRequest);
             *  if (!response.Errors.Errors.IsNullOrEmpty())
             *  {
             *      return false;
             *  }
             *  order.BrokerId.Add(response.Order.Id.ToString());
             *  return true;
             * }
             */
        }