Example #1
0
        /// <summary>
        /// Immediate fill logic, fill the order
        /// can be reused on other fill models for filling and checking
        /// </summary>
        /// <param name="broker"></param>
        /// <param name="datapoint"></param>
        /// <param name="pendingorder"></param>
        /// <param name="highliquidfill"></param>
        /// <returns></returns>
        protected Fill ImmediateFill(BrokerModel broker, DataPoint datapoint, PendingOrder pendingorder, bool highliquidfill)
        {
            //Get order
            Order    order    = pendingorder.Order;
            Security security = pendingorder.Security;

            //Check market conditions
            if (order.State == OrderState.Cancelled || order.State == OrderState.Error)
            {
                return(Fill.Cancelled(order.InternalId));                                        //Order has already been cancelled or has an error
            }
            else if (order.State == OrderState.Invalid)
            {
                return(Fill.Invalid(order.InternalId, "Invalid Order received"));                //Order has already been made invalid
            }
            else if (order.State != OrderState.Submitted)
            {
                return(Fill.Error(order.InternalId, $"Unexpected order state {order.State}"));   //Something else has gone wrong
            }
            else if (!IsExchangeOpen(pendingorder.Security, datapoint))
            {
                return(Fill.NoFill());                                                           //Exchange is not opened for trading
            }
            else if (IsOrderExpired(order, datapoint))
            {
                return(Fill.Cancelled(order.InternalId, "Order expired"));                       //Check if order has been expired
            }
            //Check latency for processing this order
            try
            {
                if (pendingorder.CreatedUtc.Add(broker.GetLatencyModel(security).GetLatency(order)) > datapoint.Occured)
                {
                    return(Fill.NoFill());                                                           //We are not suppose to see this order yet, due to added latency
                }
            }
            catch (Exception exc)
            {
                _log.Error(exc, $"Could not execute broker latency model function for get latency.");
                throw;
            }

            //Check possible fill price
            var     prices    = datapoint.OrderPrice(order.Security, order.Direction);
            decimal fillprice = prices.Current;

            //Check order type and logic
            if (order is LimitOrder limitorder)
            {
                //Check if limit order price is triggered
                if (!limitorder.IsTriggered(prices, out fillprice))
                {
                    return(Fill.NoFill());
                }
            }
            else if (order is StopLimitOrder stoplimitorder)
            {
                //Check if stop limit order price is triggered
                if (!stoplimitorder.IsTriggered(prices, out fillprice))
                {
                    return(Fill.NoFill());
                }
            }
            else if (order is StopMarketOrder stopmarketorder)
            {
                //Check if stop order price is triggered
                if (!stopmarketorder.IsTriggered(prices, out fillprice))
                {
                    return(Fill.NoFill());
                }
            }
            else if (order is MarketOnCloseOrder marketoncloseorder)
            {
                //Check if market on close order is triggered
                if (!marketoncloseorder.IsTriggered())
                {
                    return(Fill.NoFill());
                }
            }
            else if (order is MarketOnOpenOrder marketonopenorder)
            {
                //Check if market on open order is triggered
                if (!marketonopenorder.IsTriggered())
                {
                    return(Fill.NoFill());
                }
            }

            //Check slippage model
            try
            {
                fillprice += broker.GetSlippageModel(security).GetSlippage(order);
            }
            catch (Exception exc)
            {
                _log.Error(exc, $"Could not execute broker slippage model function for get slippage.");
                throw;
            }

            //Check additional spread
            try
            {
                fillprice += broker.GetSpreadModel(security).GetAdditionalSpread(order);
            }
            catch (Exception exc)
            {
                _log.Error(exc, $"Could not execute broker spread model function for get additional spread.");
                throw;
            }

            //Check fill amount (based on liquidity)
            if (!highliquidfill)
            {
                //Check fill size possible, according to tick
                var filled = datapoint.OrderSize(order.Direction);

                //Needed to fill (in case we partially already filled some of the order)
                decimal neededfill = order.UnsignedQuantity - pendingorder.OrderFilledQuantity;

                //Check for partial fills (will not include fees)
                if (filled < neededfill)
                {
                    return(Fill.PartialFill(order, pendingorder.Security.Exchange.Name, fillprice, 0m, filled));
                }
                else
                {
                    //Process needed fill (will include fees)
                    try
                    {
                        return(Fill.FullFill(order, pendingorder.Security.Exchange.Name, fillprice, Math.Abs(broker.GetFeeModel(pendingorder.Security).GetCommissionAndFees(pendingorder)), neededfill));
                    }
                    catch (Exception exc)
                    {
                        _log.Error(exc, $"Could not process full fill, due to broker feemodel implementation.");
                        throw;
                    }
                }
            }
            else
            {
                //Process full fill (will include fees)
                try
                {
                    return(Fill.FullFill(order, pendingorder.Security.Exchange.Name, fillprice, Math.Abs(broker.GetFeeModel(pendingorder.Security).GetCommissionAndFees(pendingorder)), order.UnsignedQuantity));
                }
                catch (Exception exc)
                {
                    _log.Error(exc, $"Could not process full fill, due to broker feemodel implementation.");
                    throw;
                }
            }
        }