/// <summary>
        /// Performs application of an OrderEvent to the portfolio
        /// </summary>
        /// <param name="portfolio">The algorithm's portfolio</param>
        /// <param name="security">The fill's security</param>
        /// <param name="fill">The order event fill object to be applied</param>
        public virtual void ProcessFill(SecurityPortfolioManager portfolio, Security security, OrderEvent fill)
        {
            var quoteCash = security.QuoteCurrency;

            //Get the required information from the vehicle this order will affect
            var isLong         = security.Holdings.IsLong;
            var isShort        = security.Holdings.IsShort;
            var closedPosition = false;
            //Make local decimals to avoid any rounding errors from int multiplication
            var quantityHoldings         = (decimal)security.Holdings.Quantity;
            var absoluteHoldingsQuantity = security.Holdings.AbsoluteQuantity;
            var averageHoldingsPrice     = security.Holdings.AveragePrice;

            try
            {
                // apply sales value to holdings in the account currency
                if (security.Type == SecurityType.Future)
                {
                    // for futures, we measure volume of sales, not notionals
                    var saleValueInQuoteCurrency = fill.FillPrice * Convert.ToDecimal(fill.AbsoluteFillQuantity);
                    var saleValue = saleValueInQuoteCurrency * quoteCash.ConversionRate;
                    security.Holdings.AddNewSale(saleValue);
                }
                else
                {
                    var saleValueInQuoteCurrency = fill.FillPrice * Convert.ToDecimal(fill.AbsoluteFillQuantity) * security.SymbolProperties.ContractMultiplier;
                    var saleValue = saleValueInQuoteCurrency * quoteCash.ConversionRate;
                    security.Holdings.AddNewSale(saleValue);
                }

                // subtract transaction fees from the portfolio (assumes in account currency)
                var feeThisOrder = Math.Abs(fill.OrderFee);
                security.Holdings.AddNewFee(feeThisOrder);
                portfolio.CashBook[CashBook.AccountCurrency].AddAmount(-feeThisOrder);

                // apply the funds using the current settlement model
                // we dont adjust funds for futures: it is zero upfront payment derivative (margin applies though)
                if (security.Type != SecurityType.Future)
                {
                    security.SettlementModel.ApplyFunds(portfolio, security, fill.UtcTime, quoteCash.Symbol, -fill.FillQuantity * fill.FillPrice * security.SymbolProperties.ContractMultiplier);
                }
                if (security.Type == SecurityType.Forex || security.Type == SecurityType.Crypto)
                {
                    // model forex fills as currency swaps
                    var forex = (IBaseCurrencySymbol)security;
                    security.SettlementModel.ApplyFunds(portfolio, security, fill.UtcTime, forex.BaseCurrencySymbol, fill.FillQuantity);
                }

                // did we close or open a position further?
                closedPosition = isLong && fill.Direction == OrderDirection.Sell ||
                                 isShort && fill.Direction == OrderDirection.Buy;

                // calculate the last trade profit
                if (closedPosition)
                {
                    // profit = (closed sale value - cost)*conversion to account currency
                    // closed sale value = quantity closed * fill price       BUYs are deemed negative cash flow
                    // cost = quantity closed * average holdings price        SELLS are deemed positive cash flow
                    var absoluteQuantityClosed         = Math.Min(fill.AbsoluteFillQuantity, absoluteHoldingsQuantity);
                    var closedSaleValueInQuoteCurrency = Math.Sign(-fill.FillQuantity) * fill.FillPrice * absoluteQuantityClosed;
                    var closedCost      = Math.Sign(-fill.FillQuantity) * absoluteQuantityClosed * averageHoldingsPrice;
                    var lastTradeProfit = (closedSaleValueInQuoteCurrency - closedCost)
                                          * security.SymbolProperties.ContractMultiplier;
                    var lastTradeProfitInAccountCurrency = lastTradeProfit * security.QuoteCurrency.ConversionRate;

                    // Reflect account cash adjustment for futures position
                    if (security.Type == SecurityType.Future)
                    {
                        security.SettlementModel.ApplyFunds(portfolio, security, fill.UtcTime, quoteCash.Symbol, lastTradeProfit);
                    }

                    //Update Vehicle Profit Tracking:
                    security.Holdings.AddNewProfit(lastTradeProfitInAccountCurrency);
                    security.Holdings.SetLastTradeProfit(lastTradeProfitInAccountCurrency);
                    portfolio.AddTransactionRecord(security.LocalTime.ConvertToUtc(
                                                       security.Exchange.TimeZone),
                                                   lastTradeProfitInAccountCurrency - 2 * feeThisOrder);
                }

                //UPDATE HOLDINGS QUANTITY, AVG PRICE:
                //Currently NO holdings. The order is ALL our holdings.
                if (quantityHoldings == 0)
                {
                    //First transaction just subtract order from cash and set our holdings:
                    averageHoldingsPrice = fill.FillPrice;
                    quantityHoldings     = fill.FillQuantity;
                }
                else if (isLong)
                {
                    //If we're currently LONG on the stock.
                    switch (fill.Direction)
                    {
                    case OrderDirection.Buy:
                        //Update the Holding Average Price: Total Value / Total Quantity:
                        averageHoldingsPrice = ((averageHoldingsPrice * quantityHoldings) + (fill.FillQuantity * fill.FillPrice)) / (quantityHoldings + fill.FillQuantity);
                        //Add the new quantity:
                        quantityHoldings += fill.FillQuantity;
                        break;

                    case OrderDirection.Sell:
                        quantityHoldings += fill.FillQuantity;     //+ a short = a subtraction
                        if (quantityHoldings < 0)
                        {
                            //If we've now passed through zero from selling stock: new avg price:
                            averageHoldingsPrice = fill.FillPrice;
                        }
                        else if (quantityHoldings == 0)
                        {
                            averageHoldingsPrice = 0;
                        }
                        break;
                    }
                }
                else if (isShort)
                {
                    //We're currently SHORTING the stock: What is the new position now?
                    switch (fill.Direction)
                    {
                    case OrderDirection.Buy:
                        //Buying when we're shorting moves to close position:
                        quantityHoldings += fill.FillQuantity;
                        if (quantityHoldings > 0)
                        {
                            //If we were short but passed through zero, new average price is what we paid. The short position was closed.
                            averageHoldingsPrice = fill.FillPrice;
                        }
                        else if (quantityHoldings == 0)
                        {
                            averageHoldingsPrice = 0;
                        }
                        break;

                    case OrderDirection.Sell:
                        //We are increasing a Short position:
                        //E.g.  -100 @ $5, adding -100 @ $10: Avg: $7.5
                        //      dAvg = (-500 + -1000) / -200 = 7.5
                        averageHoldingsPrice = ((averageHoldingsPrice * quantityHoldings) + (fill.FillQuantity * fill.FillPrice)) / (quantityHoldings + fill.FillQuantity);
                        quantityHoldings    += fill.FillQuantity;
                        break;
                    }
                }
            }
            catch (Exception err)
            {
                Log.Error(err);
            }

            //Set the results back to the vehicle.
            security.Holdings.SetHoldings(averageHoldingsPrice, quantityHoldings);
        }
        /// <summary>
        /// Performs application of an OrderEvent to the portfolio
        /// </summary>
        /// <param name="portfolio">The algorithm's portfolio</param>
        /// <param name="security">The fill's security</param>
        /// <param name="fill">The order event fill object to be applied</param>
        public virtual void ProcessFill(SecurityPortfolioManager portfolio, Security security, OrderEvent fill)
        {
            //Get the required information from the vehicle this order will affect
            var isLong         = security.Holdings.IsLong;
            var isShort        = security.Holdings.IsShort;
            var closedPosition = false;
            //Make local decimals to avoid any rounding errors from int multiplication
            var quantityHoldings         = (decimal)security.Holdings.Quantity;
            var absoluteHoldingsQuantity = security.Holdings.AbsoluteQuantity;
            var averageHoldingsPrice     = security.Holdings.AveragePrice;

            var lastTradeProfit = 0m;

            try
            {
                //Update the Vehicle approximate total sales volume.
                security.Holdings.AddNewSale(fill.FillPrice * Convert.ToDecimal(fill.AbsoluteFillQuantity));

                //Get the Fee for this Order - Update the Portfolio Cash Balance: Remove Transacion Fees.
                var feeThisOrder = Math.Abs(fill.OrderFee);
                security.Holdings.AddNewFee(feeThisOrder);
                portfolio.CashBook[CashBook.AccountCurrency].AddAmount(-feeThisOrder);


                //Calculate & Update the Last Trade Profit
                if (isLong && fill.Direction == OrderDirection.Sell)
                {
                    //Closing up a long position
                    if (quantityHoldings >= fill.AbsoluteFillQuantity)
                    {
                        //Closing up towards Zero.
                        lastTradeProfit = (fill.FillPrice - averageHoldingsPrice) * fill.AbsoluteFillQuantity;
                    }
                    else
                    {
                        //Closing up to Neg/Short Position (selling more than we have) - Only calc profit on the stock we have to sell.
                        lastTradeProfit = (fill.FillPrice - averageHoldingsPrice) * quantityHoldings;
                    }
                    closedPosition = true;
                }
                else if (isShort && fill.Direction == OrderDirection.Buy)
                {
                    //Closing up a short position.
                    if (absoluteHoldingsQuantity >= fill.FillQuantity)
                    {
                        //Reducing the stock we have, and enough stock on hand to process order.
                        lastTradeProfit = (averageHoldingsPrice - fill.FillPrice) * fill.AbsoluteFillQuantity;
                    }
                    else
                    {
                        //Increasing stock holdings, short to positive through zero, but only calc profit on stock we Buy.
                        lastTradeProfit = (averageHoldingsPrice - fill.FillPrice) * absoluteHoldingsQuantity;
                    }
                    closedPosition = true;
                }


                if (closedPosition)
                {
                    //Update Vehicle Profit Tracking:
                    security.Holdings.AddNewProfit(lastTradeProfit);
                    security.Holdings.SetLastTradeProfit(lastTradeProfit);
                    portfolio.AddTransactionRecord(security.LocalTime.ConvertToUtc(security.Exchange.TimeZone), lastTradeProfit - 2 * feeThisOrder);
                }

                // Apply the funds using the current settlement model
                var amount = fill.FillPrice * Convert.ToDecimal(fill.FillQuantity);
                security.SettlementModel.ApplyFunds(portfolio, security, fill.UtcTime, CashBook.AccountCurrency, -amount);

                //UPDATE HOLDINGS QUANTITY, AVG PRICE:
                //Currently NO holdings. The order is ALL our holdings.
                if (quantityHoldings == 0)
                {
                    //First transaction just subtract order from cash and set our holdings:
                    averageHoldingsPrice = fill.FillPrice;
                    quantityHoldings     = fill.FillQuantity;
                }
                else if (isLong)
                {
                    //If we're currently LONG on the stock.
                    switch (fill.Direction)
                    {
                    case OrderDirection.Buy:
                        //Update the Holding Average Price: Total Value / Total Quantity:
                        averageHoldingsPrice = ((averageHoldingsPrice * quantityHoldings) + (fill.FillQuantity * fill.FillPrice)) / (quantityHoldings + (decimal)fill.FillQuantity);
                        //Add the new quantity:
                        quantityHoldings += fill.FillQuantity;
                        //Subtract this order from cash:
                        break;

                    case OrderDirection.Sell:
                        quantityHoldings += fill.FillQuantity;     //+ a short = a subtraction
                        if (quantityHoldings < 0)
                        {
                            //If we've now passed through zero from selling stock: new avg price:
                            averageHoldingsPrice = fill.FillPrice;
                        }
                        else if (quantityHoldings == 0)
                        {
                            averageHoldingsPrice = 0;
                        }
                        break;
                    }
                }
                else if (isShort)
                {
                    //We're currently SHORTING the stock: What is the new position now?
                    switch (fill.Direction)
                    {
                    case OrderDirection.Buy:
                        //Buying when we're shorting moves to close position:
                        quantityHoldings += fill.FillQuantity;
                        if (quantityHoldings > 0)
                        {
                            //If we were short but passed through zero, new average price is what we paid. The short position was closed.
                            averageHoldingsPrice = fill.FillPrice;
                        }
                        else if (quantityHoldings == 0)
                        {
                            averageHoldingsPrice = 0;
                        }
                        break;

                    case OrderDirection.Sell:
                        //We are increasing a Short position:
                        //E.g.  -100 @ $5, adding -100 @ $10: Avg: $7.5
                        //      dAvg = (-500 + -1000) / -200 = 7.5
                        averageHoldingsPrice = ((averageHoldingsPrice * quantityHoldings) + (Convert.ToDecimal(fill.FillQuantity) * fill.FillPrice)) / (quantityHoldings + (decimal)fill.FillQuantity);
                        quantityHoldings    += fill.FillQuantity;
                        break;
                    }
                }
            }
            catch (Exception err)
            {
                Log.Error(err);
            }

            //Set the results back to the vehicle.
            security.Holdings.SetHoldings(averageHoldingsPrice, Convert.ToInt32(quantityHoldings));
        }