Ejemplo n.º 1
0
        public void OnDayClose(DateTime todaysDate, decimal totalCapitalToday)
        {
            //update the status of each trade
            foreach (TradeTracker t in TradeTrackers.Values)
            {
                t.Update(todaysDate, _data, _fxData);
            }

            //update position stats
            foreach (var kvp in Positions)
            {
                int id = kvp.Key;

                Position p         = kvp.Value;
                decimal  fxRate    = p.Currency == null || p.Currency.ID == 1 ? 1 : _fxData[p.Currency.ID][0].Close;
                decimal? lastPrice = !_data.ContainsKey(id) || _data[id].CurrentBar < 0 ? (decimal?)null : _data[id][0].Close;
                p.GetPnL(lastPrice, fxRate);
            }

            //Capital usage and profit/loss for the day
            Capital.AddLong(Positions.Sum(x => x.Value.Capital.Long.Last()));
            Capital.AddShort(Positions.Sum(x => x.Value.Capital.Short.Last()));
            decimal todaysPnl = TradeTrackers.Sum(x => x.Value.TodaysPnL);

            _logger.Log(LogLevel.Trace, string.Format("Portfolio {0} @ {1}: Capital used: {2:0.00} P/L: {3:0.00}",
                                                      Name,
                                                      todaysDate,
                                                      Capital.TodaysCapitalGross,
                                                      todaysPnl));

            //P/L curves
            ProfitLossEquityCurve.AddChange((double)todaysPnl, todaysDate);
            ProfitLossLongEquityCurve.AddValue((double)TradeTrackers.Sum(x => x.Value.TotalPnlLong), todaysDate);
            ProfitLossShortEquityCurve.AddValue((double)TradeTrackers.Sum(x => x.Value.TotalPnlShort), todaysDate);

            //ROAC
            if (Capital.TodaysCapitalGross == 0)
            {
                _deferredPnL += todaysPnl;
                RoacEquityCurve.AddReturn(0, todaysDate);
            }
            else
            {
                RoacEquityCurve.AddReturn((double)((_deferredPnL + todaysPnl) / Capital.TodaysCapitalGross), todaysDate);
                _deferredPnL = 0;
            }

            //ROTC
            if (totalCapitalToday == 0)
            {
                RotcEquityCurve.AddReturn(0, todaysDate);
            }
            else
            {
                RotcEquityCurve.AddReturn((double)(todaysPnl / totalCapitalToday), todaysDate);
            }

            Capital.EndOfDay();
        }
Ejemplo n.º 2
0
        private decimal CalculateCapitalUsage(Order order)
        {
            decimal capitalUsage = 0;
            //If the order is toward the end of the day, we don't want to count it for the day's capital usage
            var timeLimit = new TimeSpan(15, 40, 00);

            if (order.TradeDate.TimeOfDay < timeLimit)
            {
                capitalUsage = GetCapitalUsage(order);
            }
            else
            {
                //Unless! It's an intraday trade which we entered and exited after the cutoff,
                //in which case we want to count it
                if (Quantity == 0 || Math.Sign(Quantity) == Math.Sign(order.Quantity))
                {
                    //Adding to a position
                    //We just want to keep track of this, no reason to add capital usage yet
                    _avgPriceEnteredAfterEodCutoff =
                        (Math.Abs(order.Quantity) * GetCapitalUsagePriceBasis(order.Price, order.FXRateToBase) + Math.Abs(_quantityEnteredAfterEodCutoff) * _avgPriceEnteredAfterEodCutoff)
                        / Math.Abs(order.Quantity + _quantityEnteredAfterEodCutoff);
                    _quantityEnteredAfterEodCutoff += order.Quantity;
                }
                else if (_quantityEnteredAfterEodCutoff != 0)
                {
                    //Exiting a position opened after the cutoff
                    decimal originalQuantityEntered = _quantityEnteredAfterEodCutoff;
                    if (order.Quantity > 0)
                    {
                        //exiting a short
                        capitalUsage = Math.Min(order.Quantity, -_quantityEnteredAfterEodCutoff) * _avgPriceEnteredAfterEodCutoff;
                        Capital.AddShort(capitalUsage);
                        _quantityEnteredAfterEodCutoff -= Math.Min(order.Quantity, -_quantityEnteredAfterEodCutoff);
                    }
                    else
                    {
                        //exiting a long
                        capitalUsage = Math.Min(-order.Quantity, _quantityEnteredAfterEodCutoff) * _avgPriceEnteredAfterEodCutoff;
                        Capital.AddLong(capitalUsage);
                        _quantityEnteredAfterEodCutoff -= Math.Min(-order.Quantity, _quantityEnteredAfterEodCutoff);
                    }

                    //Did we actually reverse the position?
                    if (Math.Abs(order.Quantity) > Math.Abs(originalQuantityEntered))
                    {
                        _quantityEnteredAfterEodCutoff = Math.Sign(order.Quantity) * (Math.Abs(order.Quantity) - Math.Abs(originalQuantityEntered));
                        _avgPriceEnteredAfterEodCutoff = GetCapitalUsagePriceBasis(order.Price, order.FXRateToBase);
                    }
                }
            }

            return(capitalUsage);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Update the capital usage given a new order
        /// </summary>
        private decimal GetCapitalUsage(Order order)
        {
            decimal capitalUsage = 0;

            if (Math.Sign(order.Quantity) == Math.Sign(Quantity) || Math.Abs(order.Quantity) > Math.Abs(Quantity))
            {
                //if reversing
                if ((order.Quantity < 0 && Quantity > 0) ||
                    (order.Quantity > 0 && Quantity < 0))
                {
                    capitalUsage = GetCapitalUsage(Math.Abs(Math.Abs(order.Quantity) - Math.Abs(Quantity)), order.Price, order.FXRateToBase);

                    if (order.Quantity > 0)
                    {
                        Capital.AddLong(Math.Abs(Math.Abs(order.Quantity) - Math.Abs(Quantity)) * order.Price * order.FXRateToBase * Instrument.Multiplier * GetCapitalUsageMultiplier(Instrument.AssetCategory));
                    }
                    else
                    {
                        Capital.AddShort(Math.Abs(Math.Abs(order.Quantity) - Math.Abs(Quantity)) * order.Price * order.FXRateToBase * Instrument.Multiplier * GetCapitalUsageMultiplier(Instrument.AssetCategory));
                    }
                }
                else //if adding
                {
                    capitalUsage = GetCapitalUsage(order.Quantity, order.Price, order.FXRateToBase);

                    if (order.Quantity > 0)
                    {
                        Capital.AddLong(Math.Abs(order.Quantity * order.Price) * order.FXRateToBase * Instrument.Multiplier * GetCapitalUsageMultiplier(Instrument.AssetCategory));
                    }
                    else
                    {
                        Capital.AddShort(Math.Abs(order.Quantity * order.Price) * order.FXRateToBase * Instrument.Multiplier * GetCapitalUsageMultiplier(Instrument.AssetCategory));
                    }
                }
            }

            return(capitalUsage);
        }
Ejemplo n.º 4
0
        public void Update(DateTime currentDate, Dictionary <int, TimeSeries> data, Dictionary <int, TimeSeries> fxData)
        {
            TodaysPnL = 0;
            if (!Open)
            {
                return;
            }

            //Update positions
            foreach (var kvp in Positions)
            {
                int id = kvp.Key;

                Position p      = kvp.Value;
                decimal  fxRate = p.Currency == null || p.Currency.ID <= 1 ? 1 : fxData[p.Currency.ID][0].Close;
                TodaysPnL += p.GetPnL(data[id].CurrentBar < 0 ? (decimal?)null : data[id][0].Close, fxRate);
            }

            //Update currency positions
            foreach (var kvp in CurrencyPositions)
            {
                int id = kvp.Key;
                if (fxData[id].CurrentBar < 0)
                {
                    continue;
                }

                CurrencyPosition p      = kvp.Value;
                decimal          fxRate = fxData[id][0].Close;
                TodaysPnL += p.Update(fxRate);
            }

            if (Positions.Any(x => x.Value.Capital.Gross.Count > 0))
            {
                Capital.AddLong(Positions.Sum(x => x.Value.Capital.Long.Last()));
                Capital.AddShort(Positions.Sum(x => x.Value.Capital.Short.Last()));
            }

            if (Capital.TodaysCapitalGross != 0)
            {
                _currentEquity *= (double)(1 + TodaysPnL / Capital.TodaysCapitalGross);
            }
#if DEBUG
            _logger.Log(LogLevel.Trace, string.Format("Trade tracker ID {0} @ {1}, todays capital usage {2:0.00}, P/L: {3:0.00}",
                                                      Trade.ID,
                                                      currentDate,
                                                      Capital.TodaysCapitalGross,
                                                      TodaysPnL));
#endif

            Capital.EndOfDay();

            _totalPnL += TodaysPnL;

            CumulativeReturns.Add(currentDate, _currentEquity);
            CumulativePnL.Add(currentDate, _totalPnL);

            Open = Positions.Values.Sum(x => x.Quantity) != 0 ||
                   CurrencyPositions.Values.Sum(x => x.Quantity) != 0 ||
                   (_ordersRemaining > 0 && _ordersRemaining < Trade.Orders.Count);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Calculates profit/loss given a new price and FX rate. Also updates ROAC.
        /// </summary>
        /// <returns>The profit/loss since the last GetPnL() call.</returns>
        public decimal GetPnL(decimal?newPrice, decimal newFXRate)
        {
            //Null: this happens if there is no data on this anywhere.
            //Can happen when there is no prior position on an instrument.
            decimal updatePrice = newPrice ?? PriorPeriodCostBasis;

            var capitalUsage = GetCapitalUsage(_priorPeriodQuantity, PriorPeriodCostBasis, PriorPeriodFXRateBasis);

            if (_priorPeriodQuantity > 0)
            {
                Capital.AddLong(capitalUsage);
            }
            else
            {
                Capital.AddShort(capitalUsage);
            }

            //the change in value from the previous day
            if (Quantity > 0)
            {
                _unrecognizedPnLLong += Instrument.Multiplier * Quantity * (updatePrice * newFXRate - PriorPeriodCostBasis * PriorPeriodFXRateBasis);
            }
            else
            {
                _unrecognizedPnLShort += Instrument.Multiplier * Quantity * (updatePrice * newFXRate - PriorPeriodCostBasis * PriorPeriodFXRateBasis);
            }

            //calculate ROAC
            if (Capital.TodaysCapitalGross > 0)
            {
                ROAC         = ROAC * (double)(1 + (_unrecognizedPnLLong + _unrecognizedPnLShort + _deferredPnL) / Capital.TodaysCapitalGross);
                _deferredPnL = 0;
            }
            else
            {
                //if no capital is deployed, ROAC calculation is impossible
                //so we just defer the profit/loss until some capital usage exists to calculate ROAC on
                //This happens when position is zero, but we get a cash transaction for example.
                _deferredPnL += _unrecognizedPnLLong + _unrecognizedPnLShort;
            }

            LastPrice = updatePrice;

            _priorPeriodQuantity = Quantity;

            //prior period cost basis is updated to reflect the latest prices
            PriorPeriodCostBasis   = updatePrice;
            PriorPeriodFXRateBasis = newFXRate;

            //Total p/l is updated with today's profit/loss
            PnLLong  += _unrecognizedPnLLong;
            PnLShort += _unrecognizedPnLShort;

            decimal toReturn = _unrecognizedPnLLong + _unrecognizedPnLShort;

            _unrecognizedPnLLong           = 0;
            _unrecognizedPnLShort          = 0;
            _quantityEnteredAfterEodCutoff = 0;
            _avgPriceEnteredAfterEodCutoff = 0;

            Capital.EndOfDay();

            return(toReturn);
        }