private EquityCurve EcFromEquitySummaries(List <EquitySummary> summaries, Dictionary <DateTime, decimal> depositsWithdrawals)
        {
            if (summaries.Count == 0)
            {
                return(new EquityCurve());
            }

            var     ec        = new EquityCurve();
            decimal lastTotal = summaries[0].Total;

            for (int i = 1; i < summaries.Count; i++)
            {
                var     es = summaries[i];
                decimal externalCashFlow = depositsWithdrawals.ContainsKey(es.Date) ? depositsWithdrawals[es.Date] : 0;

                if (lastTotal != 0)
                //make sure we avoid division by zero...equity can't change if we have 0 to start with anyway
                {
                    double ret = (double)(((es.Total - externalCashFlow) - lastTotal) / lastTotal);
                    ec.AddReturn(ret, es.Date);
                }
                lastTotal = es.Total;
            }
            ec.CalcFinalValues(summaries.Last().Date);
            return(ec);
        }
        private EquityCurve EcFromEquitySummaries(Dictionary <DateTime, decimal> summaries, Dictionary <DateTime, decimal> depositsWithdrawals)
        {
            if (summaries.Count == 0)
            {
                return(new EquityCurve(100, summaries.First().Key));
            }

            var     ec        = new EquityCurve(100, summaries.First().Key);
            decimal lastTotal = summaries.First().Value;
            bool    first     = true;

            foreach (var kvp in summaries)
            {
                if (first)
                {
                    first = false;
                    continue;
                }
                DateTime date             = kvp.Key;
                decimal  total            = kvp.Value;
                decimal  externalCashFlow = depositsWithdrawals.ContainsKey(date) ? depositsWithdrawals[date] : 0;

                if (lastTotal != 0)
                //make sure we avoid division by zero...equity can't change if we have 0 to start with anyway
                {
                    double ret = (double)(((total - externalCashFlow) - lastTotal) / lastTotal);
                    ec.AddReturn(ret, date);
                }
                lastTotal = total;
            }
            ec.CalcFinalValues(summaries.Last().Key);
            return(ec);
        }
Example #3
0
        /// <summary>
        /// Returns false is parsing failed.
        /// </summary>
        /// <returns></returns>
        public bool Import()
        {
            var dates        = new List <DateTime>();
            var equityValues = new List <double>();

            int count = 0;

            foreach (var kvp in RawSplitData)
            {
                DateTime date;
                if (!DateTime.TryParseExact(kvp.Key, DateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
                {
                    _dialogService.ShowMessageAsync("Parsing error.",
                                                    string.Format("Failed to date value at line {0}: {1}", count, kvp.Key));
                    return(false);
                }
                dates.Add(date);

                double equity;
                if (!double.TryParse(kvp.Value, out equity))
                {
                    _dialogService.ShowMessageAsync("Parsing error.",
                                                    string.Format("Failed to parse equity value at line {0}: {1}", count, kvp.Value));
                    return(false);
                }
                equityValues.Add(equity);

                count++;
            }

            //Make sure there's sufficient data
            if (dates.Count <= 1)
            {
                _dialogService.ShowMessageAsync("Parsing error.", "Parsed backtest data too short.");
                EquityCurve = null;
                return(false);
            }

            //Then generate an EquityCurve using the data
            EquityCurve = new EquityCurve(100, dates[0]);
            for (int i = 1; i < dates.Count; i++)
            {
                EquityCurve.AddReturn(equityValues[i] / equityValues[i - 1] - 1, dates[i]);
            }
            return(true);
        }
Example #4
0
        public PortfolioTracker(Dictionary <int, TimeSeries> data, Dictionary <int, TimeSeries> fxData, List <Trade> trades, string name)
        {
            _data   = data;
            _fxData = fxData;
            Name    = name;

            Trades = trades;

            TradeTrackers = trades.ToDictionary(t => t.ID, t => new TradeTracker(t));

            ProfitLossEquityCurve      = new EquityCurve(0);
            ProfitLossLongEquityCurve  = new EquityCurve(0);
            ProfitLossShortEquityCurve = new EquityCurve(0);

            RoacEquityCurve = new EquityCurve(1);
            RotcEquityCurve = new EquityCurve(1);

            Capital = new AllocatedCapital();

            Positions = new Dictionary <int, Position>
            {
                //dummy position used for cash transactions without a related instrument
                { NullInstrumentId, new Position(new Instrument()) }
            };

            //group cash transactions by date so they're easily accessible
            _cashTransactionsByDate =
                trades
                .Where(x => x.CashTransactions != null)
                .SelectMany(x => x.CashTransactions)
                .Where(x => x.Type != "Deposits & Withdrawals")
                .GroupBy(x => x.TransactionDate.Date)
                .ToDictionary(x => x.Key, x => x.ToList());

            //group fx transactions
            _fxTransactionsByDate =
                trades
                .Where(x => x.FXTransactions != null)
                .SelectMany(x => x.FXTransactions)
                .GroupBy(x => x.DateTime.Date)
                .ToDictionary(x => x.Key, x => x.ToList());

            _allOrders = Trades.Where(x => x.Orders != null).SelectMany(x => x.Orders).ToList();
        }
Example #5
0
        public PortfolioTracker(Dictionary<int, TimeSeries> data, Dictionary<int, TimeSeries> fxData, List<Trade> trades, string name, DateTime firstDate, decimal optionsCapitalUsageMultiplier)
        {
            _data = data;
            _fxData = fxData;
            Name = name;
            _optionsCapitalUsageMultiplier = optionsCapitalUsageMultiplier;
            Trades = trades;

            TradeTrackers = trades.ToDictionary(t => t.ID, t => new TradeTracker(t, optionsCapitalUsageMultiplier));

            ProfitLossEquityCurve = new EquityCurve(0, firstDate);
            ProfitLossLongEquityCurve = new EquityCurve(0, firstDate);
            ProfitLossShortEquityCurve = new EquityCurve(0, firstDate);

            RoacEquityCurve = new EquityCurve(1, firstDate);
            RotcEquityCurve = new EquityCurve(1, firstDate);

            Capital = new AllocatedCapital();

            Positions = new Dictionary<int, Position>
            {
                //dummy position used for cash transactions without a related instrument
                { NullInstrumentId, new Position(new Instrument(), _optionsCapitalUsageMultiplier)} 
            };

            //group cash transactions by date so they're easily accessible
            _cashTransactionsByDate =
                trades
                .Where(x => x.CashTransactions != null)
                .SelectMany(x => x.CashTransactions)
                .Where(x => x.Type != "Deposits & Withdrawals")
                .GroupBy(x => x.TransactionDate.Date)
                .ToDictionary(x => x.Key, x => x.ToList());

            //group fx transactions
            _fxTransactionsByDate =
                trades
                .Where(x => x.FXTransactions != null)
                .SelectMany(x => x.FXTransactions)
                .GroupBy(x => x.DateTime.Date)
                .ToDictionary(x => x.Key, x => x.ToList());

            _allOrders = Trades.Where(x => x.Orders != null).SelectMany(x => x.Orders).ToList();
        }
Example #6
0
        /// <summary>
        /// Returns false is parsing failed.
        /// </summary>
        /// <returns></returns>
        public bool Import()
        {
            var dates = new List<DateTime>();
            var equityValues = new List<double>();

            int count = 0;
            foreach(var kvp in RawSplitData)
            {
                DateTime date;
                if(!DateTime.TryParseExact(kvp.Key, DateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
                {
                    _dialogService.ShowMessageAsync(this, "Parsing error.",
                        string.Format("Failed to date value at line {0}: {1}", count, kvp.Key));
                    return false;
                }
                dates.Add(date);

                double equity;
                if(!double.TryParse(kvp.Value, out equity))
                {
                    _dialogService.ShowMessageAsync(this, "Parsing error.",
                        string.Format("Failed to parse equity value at line {0}: {1}", count, kvp.Value));
                    return false;
                }
                equityValues.Add(equity);

                count++;
            }

            //Make sure there's sufficient data
            if (dates.Count <= 1)
            {
                _dialogService.ShowMessageAsync(this, "Parsing error.", "Parsed backtest data too short.");
                EquityCurve = null;
                return false;
            }

            //Then generate an EquityCurve using the data
            EquityCurve = new EquityCurve(100, dates[0]);
            for (int i = 1; i < dates.Count; i++)
            {
                EquityCurve.AddReturn(equityValues[i] / equityValues[i - 1] - 1, dates[i]);
            }
            return true;
        }
Example #7
0
        /// <summary>
        /// generate EC and other curves for a benchmark
        /// </summary>
        public static EquityCurve GetBenchmarkReturns(
            int benchmarkID, 
            DBContext context, 
            List<DateTime> datesInPeriod, 
            IDataSourcer dataSourcer, 
            out Dictionary<DateTime, double> benchmarkSeries,
            out List<double> benchmarkReturns)
        {
            Logger logger = LogManager.GetCurrentClassLogger();

            List<BenchmarkComponent> components = context.BenchmarkComponents.Where(x => x.BenchmarkID == benchmarkID).ToList();

            DateTime earliestDate = datesInPeriod[0].Date;
            DateTime latestDate = datesInPeriod.Last();

            Dictionary<int, TimeSeries> data =
                components
                .ToDictionary(
                    component => component.QDMSInstrumentID,
                    component => new TimeSeries(
                        dataSourcer.GetExternalData(component.QDMSInstrumentID, earliestDate, latestDate)));

            Dictionary<int, decimal> weights = components.ToDictionary(x => x.QDMSInstrumentID, x => (decimal)x.Weight);

            benchmarkSeries = new Dictionary<DateTime, double>();
            benchmarkReturns = new List<double>();
            var benchmarkEC = new EquityCurve(1, null);

            decimal equity = 1;

            bool first = true;

            foreach (DateTime today in datesInPeriod)
            {
                decimal ret = 0;
                foreach (var kvp in data)
                {
                    var ts = kvp.Value;
                    ts.ProgressTo(today);
                    if (ts.CurrentBar > 0)
                    {
                        decimal todayClose = ts[0].AdjClose.HasValue ? ts[0].AdjClose.Value : ts[0].Close;
                        decimal lastClose = ts[1].AdjClose.HasValue ? ts[1].AdjClose.Value : ts[1].Close;
                        ret += weights[kvp.Key] * (todayClose / lastClose - 1);
#if DEBUG
                        logger.Log(LogLevel.Trace, "Benchmark component: Date: {0} Close: {1} PrevClose: {2} Ret: {3}", today, todayClose, lastClose, ret);
#endif
                    }
                }

                benchmarkEC.AddReturn((double)ret, today);

                if (first)
                {
                    first = false;
                    benchmarkReturns.Add((double)(1 + ret));
                    benchmarkSeries.Add(today, (double)equity);

                    continue;
                }

                equity *= 1 + ret;
                benchmarkReturns.Add((double)(1 + ret));
                benchmarkSeries.Add(today, (double)equity);
            }

            return benchmarkEC;
        }
Example #8
0
        /// <summary>
        /// generate EC and other curves for a benchmark
        /// </summary>
        public static EquityCurve GetBenchmarkReturns(
            int benchmarkID,
            DBContext context,
            List <DateTime> datesInPeriod,
            IDataSourcer dataSourcer,
            out Dictionary <DateTime, double> benchmarkSeries,
            out List <double> benchmarkReturns)
        {
            Logger logger = LogManager.GetCurrentClassLogger();

            List <BenchmarkComponent> components = context.BenchmarkComponents.Where(x => x.BenchmarkID == benchmarkID).ToList();

            DateTime earliestDate = datesInPeriod[0].Date;
            DateTime latestDate   = datesInPeriod.Last();

            Dictionary <int, TimeSeries> data =
                components
                .ToDictionary(
                    component => component.QDMSInstrumentID,
                    component => new TimeSeries(
                        dataSourcer.GetExternalData(component.QDMSInstrumentID, earliestDate, latestDate)));

            Dictionary <int, decimal> weights = components.ToDictionary(x => x.QDMSInstrumentID, x => (decimal)x.Weight);

            benchmarkSeries  = new Dictionary <DateTime, double>();
            benchmarkReturns = new List <double>();
            var benchmarkEC = new EquityCurve(1);

            decimal equity = 1;

            bool first = true;

            foreach (DateTime today in datesInPeriod)
            {
                decimal ret = 0;
                foreach (var kvp in data)
                {
                    var ts = kvp.Value;
                    ts.ProgressTo(today);
                    if (ts.CurrentBar > 0)
                    {
                        decimal todayClose = ts[0].AdjClose.HasValue ? ts[0].AdjClose.Value : ts[0].Close;
                        decimal lastClose  = ts[1].AdjClose.HasValue ? ts[1].AdjClose.Value : ts[1].Close;
                        ret += weights[kvp.Key] * (todayClose / lastClose - 1);
#if DEBUG
                        logger.Log(LogLevel.Trace, "Benchmark component: Date: {0} Close: {1} PrevClose: {2} Ret: {3}", today, todayClose, lastClose, ret);
#endif
                    }
                }

                benchmarkEC.AddReturn((double)ret, today);

                if (first)
                {
                    first = false;
                    benchmarkReturns.Add((double)(1 + ret));
                    benchmarkSeries.Add(today, (double)equity);

                    continue;
                }

                equity *= 1 + ret;
                benchmarkReturns.Add((double)(1 + ret));
                benchmarkSeries.Add(today, (double)equity);
            }

            return(benchmarkEC);
        }
Example #9
0
 public static void GetRatios(EquityCurve ec, int daysInPeriod, out double sharpeRatio, out double marRatio, out double kRatio)
 {
     GetRatios(ec.Equity, ec.DrawdownPct, daysInPeriod, out sharpeRatio, out marRatio, out kRatio);
 }
Example #10
0
        public static Dictionary <string, string> EquityCurveStats(EquityCurve ec, int calendarDaysInPeriod)
        {
            if (ec.Returns.Count <= 1)
            {
                return(new Dictionary <string, string>());
            }

            var stats = new Dictionary <string, string>();
            var ds    = new DescriptiveStatistics(ec.Returns);

            stats.Add("Average Return", ds.Mean.ToString("p3"));
            stats.Add("Total Period Return", ((ec.Equity.Last() / ec.Equity.First()) - 1).ToString("p2"));
            double cagr = Math.Pow(ec.Equity.Last() / ec.Equity.First(), 365.0 / calendarDaysInPeriod) - 1;

            stats.Add("CAGR", cagr.ToString("p2"));
            stats.Add("Standard Deviation (Daily)", ds.StandardDeviation.ToString("p2"));
            stats.Add("Standard Deviation (Annualized)", (ds.StandardDeviation * Math.Sqrt(252)).ToString("p2"));
            stats.Add("Skewness", ds.Skewness.ToString("0.00"));
            stats.Add("Best day", ds.Maximum.ToString("p2"));
            stats.Add("Worst day", ds.Minimum.ToString("p2"));
            stats.Add("Average Up Day", ec.Returns.Any(x => x > 0) ? ec.Returns.Where(x => x > 0).Average().ToString("p2") : "-");
            stats.Add("Average Down Day", ec.Returns.Any(x => x < 0) ? ec.Returns.Where(x => x < 0).Average().ToString("p2") : "-");



            if (ec.Returns.Any(x => x > 0) && ec.Returns.Any(x => x < 0))
            {
                stats.Add("Risk:Reward", (ec.Returns.Where(x => x > 0).Average() / -ec.Returns.Where(x => x < 0).Average()).ToString("0.00"));
            }
            else
            {
                stats.Add("Risk:Reward", "-");
            }

            double zeroLimit = 0.0000001;

            stats.Add("% Up Days", ((double)ec.Returns.Count(x => x > zeroLimit) / ec.Returns.Count).ToString("p1"));
            stats.Add("% Down Days", ((double)ec.Returns.Count(x => x < -zeroLimit) / ec.Returns.Count).ToString("p1"));
            stats.Add("% Flat Days", ((double)ec.Returns.Count(x => Math.Abs(x) < zeroLimit) / ec.Returns.Count).ToString("p1"));

            double grossWin = ec.Returns.Where(x => x > 0).Sum();

            stats.Add("Gross Win", grossWin.ToString("p2"));
            double grossLoss = ec.Returns.Where(x => x < 0).Sum();

            stats.Add("Gross Loss", grossLoss.ToString("p2"));

            stats.Add("Profit Factor", grossLoss != 0 ? (grossWin / -grossLoss).ToString("0.00") : "-");

            double downsideDeviation = ec.Returns.DownsideDeviation(0);
            double upsideDeviation   = ec.Returns.Where(x => x > 0).StandardDeviation();

            stats.Add("Volatility Skewness", (upsideDeviation / downsideDeviation).ToString("0.00"));

            stats.Add("Max Drawdown", ec.DrawdownPct.Min().ToString("p2"));
            stats.Add("Average Drawdown", ec.DrawdownPct.Average().ToString("p2"));
            if (ec.DrawdownLengths.Count > 0)
            {
                stats.Add("Longest Drawdown", ec.DrawdownLengths.Max().TotalDays.ToString("0.0") + " days");
            }
            else
            {
                stats.Add("Longest Drawdown", "N/A");
            }

            string avgDDLengthStat = "N/A";

            if (ec.DrawdownLengths.Count > 0)
            {
                avgDDLengthStat = ec.DrawdownLengths.Select(x => x.TotalDays).Average().ToString("0.00") + " days";
            }
            stats.Add("Average Drawdown Length", avgDDLengthStat);

            double sharpe, mar, kratio;

            GetRatios(ec, calendarDaysInPeriod, out sharpe, out mar, out kratio);
            stats.Add("Sharpe ratio", sharpe.ToString("0.00"));
            double sortino = (cagr - Properties.Settings.Default.assumedInterestRate) / (downsideDeviation * Math.Sqrt(252));

            stats.Add("Sortino ratio", sortino.ToString("0.00"));
            stats.Add("MAR Ratio", mar.ToString("0.00"));
            stats.Add("K Ratio", kratio.ToString("0.00"));
            double ulcerIndex = Math.Sqrt(ec.DrawdownPct.Sum(x => x * x) / ec.DrawdownPct.Count);

            stats.Add("Ulcer Index", (ulcerIndex * 100).ToString("0.00"));
            stats.Add("UPI/Martin Ratio", ((cagr - Properties.Settings.Default.assumedInterestRate) / ulcerIndex).ToString("0.00"));

            return(stats);
        }
Example #11
0
 public static void GetRatios(EquityCurve ec, int daysInPeriod, out double sharpeRatio, out double marRatio, out double kRatio)
 {
     GetRatios(ec.Equity, ec.DrawdownPct, daysInPeriod, out sharpeRatio, out marRatio, out kRatio);
 }
Example #12
0
        public static Dictionary<string, string> EquityCurveStats(EquityCurve ec, int calendarDaysInPeriod)
        {
            if (ec.Returns.Count <= 1) return new Dictionary<string, string>();

            var stats = new Dictionary<string, string>();
            var ds = new DescriptiveStatistics(ec.Returns);

            stats.Add("Average Return", ds.Mean.ToString("p3"));
            stats.Add("Total Period Return", ((ec.Equity.Last() / ec.Equity.First()) - 1).ToString("p2"));
            double cagr = Math.Pow(ec.Equity.Last() / ec.Equity.First(), 365.0 / calendarDaysInPeriod) - 1;
            stats.Add("CAGR", cagr.ToString("p2"));
            stats.Add("Standard Deviation (Daily)", ds.StandardDeviation.ToString("p2"));
            stats.Add("Standard Deviation (Annualized)", (ds.StandardDeviation * Math.Sqrt(252)).ToString("p2"));
            stats.Add("Skewness", ds.Skewness.ToString("0.00"));
            stats.Add("Best day", ds.Maximum.ToString("p2"));
            stats.Add("Worst day", ds.Minimum.ToString("p2"));
            stats.Add("Average Up Day", ec.Returns.Any(x => x > 0) ? ec.Returns.Where(x => x > 0).Average().ToString("p2") : "-");
            stats.Add("Average Down Day", ec.Returns.Any(x => x < 0) ? ec.Returns.Where(x => x < 0).Average().ToString("p2") : "-");



            if (ec.Returns.Any(x => x > 0) && ec.Returns.Any(x => x < 0))
            {
                stats.Add("Risk:Reward", (ec.Returns.Where(x => x > 0).Average() / -ec.Returns.Where(x => x < 0).Average()).ToString("0.00"));
            }
            else
            {
                stats.Add("Risk:Reward", "-");
            }

            double zeroLimit = 0.0000001;
            stats.Add("% Up Days", ((double)ec.Returns.Count(x => x > zeroLimit) / ec.Returns.Count).ToString("p1"));
            stats.Add("% Down Days", ((double)ec.Returns.Count(x => x < -zeroLimit) / ec.Returns.Count).ToString("p1"));
            stats.Add("% Flat Days", ((double)ec.Returns.Count(x => Math.Abs(x) < zeroLimit) / ec.Returns.Count).ToString("p1"));

            double grossWin = ec.Returns.Where(x => x > 0).Sum();
            stats.Add("Gross Win", grossWin.ToString("p2"));
            double grossLoss = ec.Returns.Where(x => x < 0).Sum();
            stats.Add("Gross Loss", grossLoss.ToString("p2"));

            stats.Add("Profit Factor", grossLoss != 0 ? (grossWin / -grossLoss).ToString("0.00") : "-");

            double downsideDeviation = ec.Returns.DownsideDeviation(0);
            double upsideDeviation = ec.Returns.Where(x => x > 0).StandardDeviation();
            stats.Add("Volatility Skewness", (upsideDeviation / downsideDeviation).ToString("0.00"));

            stats.Add("Max Drawdown", ec.DrawdownPct.Min().ToString("p2"));
            stats.Add("Average Drawdown", ec.DrawdownPct.Average().ToString("p2"));
            if(ec.DrawdownLengths.Count > 0)
                stats.Add("Longest Drawdown", ec.DrawdownLengths.Max().TotalDays.ToString("0.0") + " days");
            else
                stats.Add("Longest Drawdown", "N/A");

            string avgDDLengthStat = "N/A";
            if (ec.DrawdownLengths.Count > 0)
            {
                avgDDLengthStat = ec.DrawdownLengths.Select(x => x.TotalDays).Average().ToString("0.00") + " days";
            }
            stats.Add("Average Drawdown Length", avgDDLengthStat);
            
            double sharpe, mar, kratio;
            GetRatios(ec, calendarDaysInPeriod, out sharpe, out mar, out kratio);
            stats.Add("Sharpe ratio", sharpe.ToString("0.00"));
            double sortino = (cagr - Properties.Settings.Default.assumedInterestRate) / (downsideDeviation * Math.Sqrt(252));
            stats.Add("Sortino ratio", sortino.ToString("0.00"));
            stats.Add("MAR Ratio", mar.ToString("0.00"));
            stats.Add("K Ratio", kratio.ToString("0.00"));
            double ulcerIndex = Math.Sqrt(ec.DrawdownPct.Sum(x => x * x) / ec.DrawdownPct.Count);
            stats.Add("Ulcer Index", (ulcerIndex * 100).ToString("0.00"));
            stats.Add("UPI/Martin Ratio", ((cagr - Properties.Settings.Default.assumedInterestRate) / ulcerIndex).ToString("0.00"));

            return stats;
        }
        private EquityCurve EcFromEquitySummaries(Dictionary<DateTime, decimal> summaries, Dictionary<DateTime, decimal> depositsWithdrawals)
        {
            if (summaries.Count == 0) return new EquityCurve(100, DateTime.Now);

            var ec = new EquityCurve(100, summaries.First().Key);
            decimal lastTotal = summaries.First().Value;
            bool first = true;
            foreach(var kvp in summaries)
            {
                if (first)
                {
                    first = false;
                    continue;
                }
                DateTime date = kvp.Key;
                decimal total = kvp.Value;
                decimal externalCashFlow = depositsWithdrawals.ContainsKey(date) ? depositsWithdrawals[date] : 0;

                if (lastTotal != 0)
                //make sure we avoid division by zero...equity can't change if we have 0 to start with anyway
                {
                    double ret = (double)(((total - externalCashFlow) - lastTotal) / lastTotal);
                    ec.AddReturn(ret, date);
                }
                lastTotal = total;
            }
            ec.CalcFinalValues(summaries.Last().Key);
            return ec;
        }