Exemple #1
0
 /// <summary>
 /// Estimate the trades per day of the strategy.
 /// </summary>
 /// <param name="name">Name of the widget</param>
 /// <param name="key">Location of injection</param>
 /// <param name="backtest">Backtest result object</param>
 /// <param name="live">Live result object</param>
 public TradesPerDayReportElement(string name, string key, BacktestResult backtest, LiveResult live)
 {
     _live     = live;
     _backtest = backtest;
     Name      = name;
     Key       = key;
 }
Exemple #2
0
        private IBot _AddBotForMode(BotMode mode, BacktestResult backtestResult = null, PBot pBot = null, TBot tBot = null, IBot bot = null)
        {
            IAccount account;

            switch (mode)
            {
            case BotMode.Live:
                account = LiveAccount;
                break;

            case BotMode.Demo:
                account = DemoAccount;
                break;

            case BotMode.Scanner:
                account = ScannerAccount;
                break;

            case BotMode.Paper:
                account = PaperAccount;
                break;

            default:
                throw new ArgumentException(nameof(mode) + " unknown or is set to more than one mode.");
            }
            if (account == null)
            {
                Debug.WriteLine($"WARNING - _AddBotForMode({mode}) assigned no account");
            }
            return(_AddBot(mode, account: account, backtestResult: backtestResult, pBot: pBot, tBot: tBot, bot: bot));
        }
Exemple #3
0
 /// <summary>
 /// Create a new plot of the rolling sharpe ratio
 /// </summary>
 /// <param name="name">Name of the widget</param>
 /// <param name="key">Location of injection</param>
 /// <param name="backtest">Backtest result object</param>
 /// <param name="live">Live result object</param>
 public RollingSharpeReportElement(string name, string key, BacktestResult backtest, LiveResult live)
 {
     _live     = live;
     _backtest = backtest;
     Name      = name;
     Key       = key;
 }
Exemple #4
0
        public static void GetAverageDaysPerTrade(this BacktestResult results, GetFitnessArgs args)
        {
            double sum           = 0;
            int    trades        = 0;
            double winSum        = 0;
            int    winningTrades = 0;

            double lossSum      = 0;
            int    losingTrades = 0;

            foreach (var trade in args.History)
            {
                if (double.IsNaN(trade.ClosingPrice))
                {
                    continue;
                }
                sum += (trade.ClosingTime - trade.EntryTime).TotalDays;
                trades++;

                if (trade.NetProfit >= 0)
                {
                    winSum += (trade.ClosingTime - trade.EntryTime).TotalDays;
                    winningTrades++;
                }
                else
                {
                    lossSum += (trade.ClosingTime - trade.EntryTime).TotalDays;
                    losingTrades++;
                }
            }

            results.AverageDaysPerTrade        = sum / trades;
            results.AverageDaysPerWinningTrade = winSum / winningTrades;
            results.AverageDaysPerLosingTrade  = lossSum / losingTrades;
        }
Exemple #5
0
 /// <summary>
 /// Estimate the max drawdown of the strategy.
 /// </summary>
 /// <param name="name">Name of the widget</param>
 /// <param name="key">Location of injection</param>
 /// <param name="backtest">Backtest result object</param>
 /// <param name="live">Live result object</param>
 public MaxDrawdownReportElement(string name, string key, BacktestResult backtest, LiveResult live)
 {
     _live     = live;
     _backtest = backtest;
     Name      = name;
     Key       = key;
 }
Exemple #6
0
        protected virtual void DoLogBacktest(GetFitnessArgs args, BacktestResult backtestResult)
        {
            double   fitness        = backtestResult.Fitness;
            double   initialBalance = backtestResult.InitialBalance;
            TimeSpan timeSpan       = backtestResult.Duration;
            double   aroi           = backtestResult.Aroi;

            if (!double.IsNaN(Template.LogBacktestThreshold) && fitness > Template.LogBacktestThreshold)
            {
                BacktestLogger = this.GetLogger(this.ToString().Replace(' ', '.') + ".Backtest");

                try
                {
                    string resultJson = "";
                    resultJson = Newtonsoft.Json.JsonConvert.SerializeObject(backtestResult);

                    var profit = args.Equity / initialBalance;

                    this.BacktestLogger.LogInformation($"${args.Equity} ({profit.ToString("N1")}x) #{args.History.Count} {args.MaxEquityDrawdownPercentages.ToString("N2")}%dd [from ${initialBalance.ToString("N2")} to ${args.Equity.ToString("N2")}] [fit {fitness.ToString("N1")}] {Environment.NewLine} result = {resultJson} ");
                    var id = Template.Id;


                    backtestResult.GetAverageDaysPerTrade(args);



                    SaveResult(args, backtestResult, fitness, resultJson, id, timeSpan);
                }
                catch (Exception ex)
                {
                    this.BacktestLogger.LogError(ex.ToString());
                    throw;
                }
            }
        }
 /// <summary>
 /// Estimate the kelly estimate of the strategy.
 /// </summary>
 /// <param name="name">Name of the widget</param>
 /// <param name="key">Location of injection</param>
 /// <param name="backtest">Backtest result object</param>
 /// <param name="live">Live result object</param>
 public KellyEstimateReportElement(string name, string key, BacktestResult backtest, LiveResult live)
 {
     _live     = live;
     _backtest = backtest;
     Name      = name;
     Key       = key;
 }
 /// <summary>
 /// Create a new plot of the daily returns in bar chart format
 /// </summary>
 /// <param name="name">Name of the widget</param>
 /// <param name="key">Location of injection</param>
 /// <param name="backtest">Backtest result object</param>
 /// <param name="live">Live result object</param>
 public DailyReturnsReportElement(string name, string key, BacktestResult backtest, LiveResult live)
 {
     _live     = live;
     _backtest = backtest;
     Name      = name;
     Key       = key;
 }
 /// <summary>
 /// Estimate the information ratio of the strategy.
 /// </summary>
 /// <param name="name">Name of the widget</param>
 /// <param name="key">Location of injection</param>
 /// <param name="backtest">Backtest result object</param>
 /// <param name="live">Live result object</param>
 public InformationRatioReportElement(string name, string key, BacktestResult backtest, LiveResult live)
 {
     _live     = live;
     _backtest = backtest;
     Name      = name;
     Key       = key;
 }
 /// <summary>
 /// Create a new array of crisis event plots
 /// </summary>
 /// <param name="name">Name of the widget</param>
 /// <param name="key">Location of injection</param>
 /// <param name="backtest">Backtest result object</param>
 /// <param name="live">Live result object</param>
 public CrisisReportElement(string name, string key, BacktestResult backtest, LiveResult live)
 {
     _live     = live;
     _backtest = backtest;
     _template = File.ReadAllText("template.crisis.html");
     Name      = name;
     Key       = key;
 }
Exemple #11
0
        public virtual IBacktestResult GetResult()
        {
            var tradeEngine = Robot.Trade;
            var trades      = tradeEngine.Trades.ToList();

            var result = new BacktestResult
            {
                TotalTradesNumber = trades.Count,
                LongTradesNumber  = trades.Where(iTrade => iTrade.Order.TradeType == TradeType.Buy).Count(),
                ShortTradesNumber = trades.Where(iTrade => iTrade.Order.TradeType == TradeType.Sell).Count(),
                NetProfit         = trades.Select(iTrade => iTrade.Order.NetProfit).Sum(),
                WinningRate       = trades.Count > 0 ? trades.Where(iTrade => iTrade.Order.NetProfit > 0).Count() / (double)trades.Count * 100 : 0,
            };

            var grossProfit = trades.Where(iTrade => iTrade.Order.GrossProfit > 0).Sum(iTrade => iTrade.Order.GrossProfit);

            var grossLoss = trades.Where(iTrade => iTrade.Order.GrossProfit < 0).Sum(iTrade => Math.Abs(iTrade.Order.GrossProfit));

            result.ProfitFactor = grossLoss > 0 ? grossProfit / grossLoss : grossProfit;

            result.MaxEquityDrawdown  = MaxDrawdownCalculator.GetMaxDrawdown(Robot.Account.EquityChanges);
            result.MaxBalanceDrawdown = MaxDrawdownCalculator.GetMaxDrawdown(Robot.Account.BalanceChanges);

            result.Commission = trades.Sum(iTrade => iTrade.Order.Commission);

            if (Robot.Account.CurrentBalance > 0)
            {
                var depositTransaction = Robot.Account.Transactions.FirstOrDefault(iTransaction => iTransaction.Amount > 0);

                if (depositTransaction != null && trades.Any())
                {
                    var initialDeposit = depositTransaction.Amount;

                    var tradeData = trades.Select(iTrade => iTrade.Order.NetProfit);

                    result.SharpeRatio  = SharpeRatioCalculator.GetSharpeRatio(tradeData);
                    result.SortinoRatio = SortinoRatioCalculator.GetSortinoRatio(tradeData);
                }
            }

            var winningTrades = trades.Where(iTrade => iTrade.Order.NetProfit > 0);
            var losingTrades  = trades.Where(iTrade => iTrade.Order.NetProfit < 0);

            result.AverageProfit = winningTrades.Count() > 0 ? winningTrades.Average(iTrade => iTrade.Order.NetProfit) : 0;
            result.AverageLoss   = losingTrades.Count() > 0 ? losingTrades.Average(iTrade => iTrade.Order.NetProfit) : 0;
            result.AverageReturn = trades.Count > 0 ? trades.Average(iTrade => iTrade.Order.NetProfit) : 0;

            if (trades.Any())
            {
                var durationAverageInHours = trades.Select(iTrade => iTrade.Duration.TotalHours).Average();

                result.AverageTradeDuration = TimeSpan.FromHours(durationAverageInHours);

                result.AverageBarsPeriod = trades.Select(iTrade => iTrade.BarsPeriod).Average();
            }

            return(result);
        }
Exemple #12
0
        /// <summary>
        /// Create a new capacity estimate
        /// </summary>
        /// <param name="name">Name of the widget</param>
        /// <param name="key">Location of injection</param>
        /// <param name="backtest">Backtest result object</param>
        /// <param name="live">Live result object</param>
        public EstimatedCapacityReportElement(string name, string key, BacktestResult backtest, LiveResult live)
        {
            _live     = live;
            _backtest = backtest;
            Name      = name;
            Key       = key;

            _capacityEstimator = new StrategyCapacity();
        }
 public BacktestTradesLog(BacktestResult result)
 {
     InitializeComponent();
     Title = $"Backtest trade log - {result.Stock.Properties["name"]} ({result.Stock.Symbol})";
     foreach (TradeInfo trade in result.Trades)
     {
         grid.Items.Add(trade);
     }
 }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            BacktestResult result = ((FrameworkElement)sender).DataContext as BacktestResult;

            Debug.WriteLine(result.Stock.Symbol);
            BacktestTradesLog log = new BacktestTradesLog(result);

            log.Show();
        }
Exemple #15
0
        public void MoveAheadNoTarget()
        {
            var target = new Target("Profit", new Maximization(), null);

            Assert.IsTrue(target.MoveAhead(BacktestResult.Create(profit: 10m).ToJson()));
            Assert.AreEqual(10m, target.Current);
            Assert.IsFalse(target.MoveAhead(BacktestResult.Create(profit: 5m).ToJson()));
            Assert.AreEqual(10m, target.Current);
            Assert.IsTrue(target.MoveAhead(BacktestResult.Create(profit: 15m).ToJson()));
            Assert.AreEqual(15m, target.Current);
        }
Exemple #16
0
        /// <summary>
        /// Create beautiful HTML and PDF Reports based on backtest and live data.
        /// </summary>
        /// <param name="name">Name of the strategy</param>
        /// <param name="description">Description of the strategy</param>
        /// <param name="version">Version number of the strategy</param>
        /// <param name="backtest">Backtest result object</param>
        /// <param name="live">Live result object</param>
        public Report(string name, string description, string version, BacktestResult backtest, LiveResult live)
        {
            var backtestCurve = new Series <DateTime, double>(ResultsUtil.EquityPoints(backtest));
            var liveCurve     = new Series <DateTime, double>(ResultsUtil.EquityPoints(live));

            var backtestOrders = backtest?.Orders?.Values.ToList() ?? new List <Order>();
            var liveOrders     = live?.Orders?.Values.ToList() ?? new List <Order>();

            Log.Trace($"QuantConnect.Report.Report(): Processing backtesting orders");
            var backtestPortfolioInTime = PortfolioLooper.FromOrders(backtestCurve, backtestOrders).ToList();

            Log.Trace($"QuantConnect.Report.Report(): Processing live orders");
            var livePortfolioInTime = PortfolioLooper.FromOrders(liveCurve, liveOrders, liveSeries: true).ToList();

            _elements = new List <IReportElement>
            {
                //Basics
                new TextReportElement("strategy name", ReportKey.StrategyName, name),
                new TextReportElement("description", ReportKey.StrategyDescription, description),
                new TextReportElement("version", ReportKey.StrategyVersion, version),
                new TextReportElement("stylesheet", ReportKey.Stylesheet, File.ReadAllText("css/report.css")),
                new TextReportElement("live marker key", ReportKey.LiveMarker, live == null ? string.Empty : "Live "),

                //KPI's Backtest:
                new DaysLiveReportElement("days live kpi", ReportKey.DaysLive, live),
                new CAGRReportElement("cagr kpi", ReportKey.CAGR, backtest, live),
                new TurnoverReportElement("turnover kpi", ReportKey.Turnover, backtest, live),
                new MaxDrawdownReportElement("max drawdown kpi", ReportKey.MaxDrawdown, backtest, live),
                new KellyEstimateReportElement("kelly estimate kpi", ReportKey.KellyEstimate, backtest, live),
                new SharpeRatioReportElement("sharpe kpi", ReportKey.SharpeRatio, backtest, live),
                new PSRReportElement("psr kpi", ReportKey.PSR, backtest, live),
                new InformationRatioReportElement("ir kpi", ReportKey.InformationRatio, backtest, live),
                new MarketsReportElement("markets kpi", ReportKey.Markets, backtest, live),
                new TradesPerDayReportElement("trades per day kpi", ReportKey.TradesPerDay, backtest, live),

                // Generate and insert plots MonthlyReturnsReportElement
                new MonthlyReturnsReportElement("monthly return plot", ReportKey.MonthlyReturns, backtest, live),
                new CumulativeReturnsReportElement("cumulative returns", ReportKey.CumulativeReturns, backtest, live),
                new AnnualReturnsReportElement("annual returns", ReportKey.AnnualReturns, backtest, live),
                new ReturnsPerTradeReportElement("returns per trade", ReportKey.ReturnsPerTrade, backtest, live),
                new AssetAllocationReportElement("asset allocation over time pie chart", ReportKey.AssetAllocation, backtest, live, backtestPortfolioInTime, livePortfolioInTime),
                new DrawdownReportElement("drawdown plot", ReportKey.Drawdown, backtest, live),
                //new DailyReturnsReportElement("daily returns plot", ReportKey.DailyReturns, backtest, live),
                //new RollingPortfolioBetaReportElement("rolling beta to equities plot", ReportKey.RollingBeta, backtest, live),
                //new RollingSharpeReportElement("rolling sharpe ratio plot", ReportKey.RollingSharpe, backtest, live),
                //new LeverageUtilizationReportElement("leverage plot", ReportKey.LeverageUtilization, backtest, live, backtestPortfolioInTime, livePortfolioInTime),
                //new ExposureReportElement("exposure plot", ReportKey.Exposure, backtest, live, backtestPortfolioInTime, livePortfolioInTime),

                // Array of Crisis Plots:
                new CrisisReportElement("crisis page", ReportKey.CrisisPageStyle, backtest, live),
                new CrisisReportElement("crisis plots", ReportKey.CrisisPlots, backtest, live)
            };
        }
Exemple #17
0
 public Result FromBacktestResult(BacktestResult backtestResult)
 {
     return(new Result
     {
         ResultType = ResultType.Backtest,
         Charts = new Dictionary <string, Chart>(backtestResult.Charts),
         Orders = new Dictionary <int, Order>(backtestResult.Orders),
         ProfitLoss = new Dictionary <DateTime, decimal>(backtestResult.ProfitLoss),
         Statistics = new Dictionary <string, string>(backtestResult.Statistics),
         RuntimeStatistics = new Dictionary <string, string>(backtestResult.RuntimeStatistics),
         RollingWindow = new Dictionary <string, AlgorithmPerformance>(backtestResult.RollingWindow)
     });
 }
        /// <summary>
        /// Save the snapshot of the total results to storage.
        /// </summary>
        /// <param name="packet">Packet to store.</param>
        /// <param name="async">Store the packet asyncronously to speed up the thread.</param>
        /// <remarks>Async creates crashes in Mono 3.10 if the thread disappears before the upload is complete so it is disabled for now.</remarks>
        public void StoreResult(Packet packet, bool async = false)
        {
            try
            {
                // Make sure this is the right type of packet:
                if (packet.Type != PacketType.BacktestResult)
                {
                    return;
                }

                // Port to packet format:
                var result = packet as BacktestResultPacket;

                if (result != null)
                {
                    // Get Storage Location:
                    var key = _job.BacktestId + ".json";

                    BacktestResult results;
                    lock (_chartLock)
                    {
                        results = new BacktestResult(
                            result.Results.IsFrameworkAlgorithm,
                            result.Results.Charts.ToDictionary(x => x.Key, x => x.Value.Clone()),
                            result.Results.Orders,
                            result.Results.ProfitLoss,
                            result.Results.Statistics,
                            result.Results.RuntimeStatistics,
                            result.Results.RollingWindow,
                            result.Results.TotalPerformance
                            )
                                  // Set Alpha Runtime Statistics
                        {
                            AlphaRuntimeStatistics = result.Results.AlphaRuntimeStatistics
                        };
                    }
                    // Save results
                    SaveResults(key, results);
                }
                else
                {
                    Log.Error("BacktestingResultHandler.StoreResult(): Result Null.");
                }
            }
            catch (Exception err)
            {
                Log.Error(err);
            }
        }
 /// <summary>
 /// Create a new plot of the asset allocation over time
 /// </summary>
 /// <param name="name">Name of the widget</param>
 /// <param name="key">Location of injection</param>
 /// <param name="backtest">Backtest result object</param>
 /// <param name="live">Live result object</param>
 /// <param name="backtestPortfolios">Backtest point in time portfolios</param>
 /// <param name="livePortfolios">Live point in time portfolios</param>
 public AssetAllocationReportElement(
     string name,
     string key,
     BacktestResult backtest,
     LiveResult live,
     List <PointInTimePortfolio> backtestPortfolios,
     List <PointInTimePortfolio> livePortfolios)
 {
     _backtest           = backtest;
     _backtestPortfolios = backtestPortfolios;
     _live           = live;
     _livePortfolios = livePortfolios;
     Name            = name;
     Key             = key;
 }
Exemple #20
0
        /// <summary>
        /// Save the snapshot of the total results to storage.
        /// </summary>
        /// <param name="packet">Packet to store.</param>
        protected override void StoreResult(Packet packet)
        {
            try
            {
                // Make sure this is the right type of packet:
                if (packet.Type != PacketType.BacktestResult)
                {
                    return;
                }

                // Port to packet format:
                var result = packet as BacktestResultPacket;

                if (result != null)
                {
                    // Get Storage Location:
                    var key = $"{AlgorithmId}.json";

                    BacktestResult results;
                    lock (ChartLock)
                    {
                        results = new BacktestResult(new BacktestResultParameters(
                                                         result.Results.Charts.ToDictionary(x => x.Key, x => x.Value.Clone()),
                                                         result.Results.Orders,
                                                         result.Results.ProfitLoss,
                                                         result.Results.Statistics,
                                                         result.Results.RuntimeStatistics,
                                                         result.Results.RollingWindow,
                                                         null, // null order events, we store them separately
                                                         result.Results.TotalPerformance,
                                                         result.Results.AlphaRuntimeStatistics));
                    }
                    // Save results
                    SaveResults(key, results);

                    // Store Order Events in a separate file
                    StoreOrderEvents(Algorithm.UtcTime, result.Results.OrderEvents);
                }
                else
                {
                    Log.Error("BacktestingResultHandler.StoreResult(): Result Null.");
                }
            }
            catch (Exception err)
            {
                Log.Error(err);
            }
        }
Exemple #21
0
        /// <summary>
        /// Normalizes the Series used to calculate the drawdown plots and charts
        /// </summary>
        /// <param name="backtestResult">Backtest result packet</param>
        /// <param name="liveResult">Live result packet</param>
        /// <returns></returns>
        public static Series <DateTime, double> NormalizeResults(BacktestResult backtestResult, LiveResult liveResult)
        {
            var backtestPoints = ResultsUtil.EquityPoints(backtestResult);
            var livePoints     = ResultsUtil.EquityPoints(liveResult);

            if (backtestPoints.Count == 0 && livePoints.Count == 0)
            {
                return(new Series <DateTime, double>(new DateTime[] { }, new double[] { }));
            }

            var startingEquity = backtestPoints.Count == 0 ? livePoints.First().Value : backtestPoints.First().Value;
            var backtestSeries = new Series <DateTime, double>(backtestPoints)
                                 .PercentChange()
                                 .Where(kvp => kvp.Value != 0)
                                 .CumulativeSum();

            var liveSeries = new Series <DateTime, double>(livePoints)
                             .PercentChange()
                             .CumulativeSum();

            // Get the last key of the backtest series if our series is empty to avoid issues with empty frames
            var firstLiveKey = liveSeries.IsEmpty ? backtestSeries.LastKey().AddDays(1) : liveSeries.FirstKey();

            // Add the final non-overlapping point of the backtest equity curve to the entire live series to keep continuity.
            if (!backtestSeries.IsEmpty)
            {
                var filtered = backtestSeries.Where(kvp => kvp.Key < firstLiveKey);
                liveSeries = filtered.IsEmpty ? liveSeries : liveSeries + filtered.LastValue();
            }

            // Prefer the live values as we don't care about backtest once we've deployed into live.
            // All in all, this is a normalized equity curve, though it's been normalized
            // so that there are no discontinuous jumps in equity value if we only used equity cash
            // to add the last value of the backtest series to the live series.
            //
            // Pandas equivalent:
            //
            // ```
            // pd.concat([backtestSeries, liveSeries], axis=1).fillna(method='ffill').dropna().diff().add(1).cumprod().mul(startingEquity)
            // ```
            return(backtestSeries.Merge(liveSeries, UnionBehavior.PreferRight)
                   .FillMissing(Direction.Forward)
                   .DropMissing()
                   .Diff(1)
                   .SelectValues(x => x + 1)
                   .CumulativeProduct()
                   .SelectValues(x => x * startingEquity));
        }
Exemple #22
0
        public void MoveAheadReachFirst()
        {
            var  target  = new Target("Profit", new Minimization(), 100);
            bool reached = false;

            target.Reached += (s, e) =>
            {
                reached = true;
            };

            Assert.IsTrue(target.MoveAhead(BacktestResult.Create(profit: 10m).ToJson()));
            target.CheckCompliance();

            Assert.AreEqual(10m, target.Current);
            Assert.IsTrue(reached);
        }
Exemple #23
0
        public void MoveAheadReachLast()
        {
            var  target  = new Target("Profit", new Minimization(), 100);
            bool reached = false;

            target.Reached += (s, e) =>
            {
                reached = true;
            };

            for (var profit = 500m; profit > 0; profit -= 50)
            {
                Assert.IsTrue(target.MoveAhead(BacktestResult.Create(profit: profit).ToJson()));
                Assert.AreEqual(profit, target.Current);
                target.CheckCompliance();
            }

            Assert.IsTrue(reached);
        }
Exemple #24
0
 public IEnumerable <IBot> AddBotForModes(BacktestResult backtestResult, BotMode modes)
 {
     if (modes.HasFlag(BotMode.Live))
     {
         yield return(_AddBotForMode(BotMode.Live, backtestResult: backtestResult));
     }
     if (modes.HasFlag(BotMode.Demo))
     {
         yield return(_AddBotForMode(BotMode.Demo, backtestResult: backtestResult));
     }
     if (modes.HasFlag(BotMode.Scanner))
     {
         yield return(_AddBotForMode(BotMode.Scanner, backtestResult: backtestResult));
     }
     if (modes.HasFlag(BotMode.Paper))
     {
         yield return(_AddBotForMode(BotMode.Paper, backtestResult: backtestResult));
     }
 }
Exemple #25
0
        private async void SaveResult(GetFitnessArgs args, BacktestResult backtestResult, double fitness, string json, string id, TimeSpan timeSpan)
        {
            //var filename = DateTime.Now.ToString("yyyy.MM.dd HH-mm-ss.fff ") + this.GetType().Name + " " + Symbol.Code + " " + id;
            var sym =
#if cAlgo
                MarketSeries.SymbolCode;
#else
                Template.Symbol;
#endif

            var tf =
#if cAlgo
                TimeFrame.ToShortString();
#else
                (this as IHasSingleSeries)?.MarketSeries?.TimeFrame?.Name;
#endif



            var tradesPerMonth = (args.TotalTrades / (timeSpan.TotalDays / 31)).ToString("F1");
            var filename       = fitness.ToString("00.0") + $"ad {tradesPerMonth}tpm {timeSpan.TotalDays.ToString("F0")}d  {backtestResult.AverageDaysPerWinningTrade.ToString("F2")}adwt bot={this.GetType().Name} sym={sym} tf={tf} id={id}";
            var ext            = ".json";
            int i    = 0;
            var dir  = BacktestResultSaveDir;
            var path = Path.Combine(dir, filename + ext);
            if (CreateResultsDirIfMissing && !Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            for (; File.Exists(path); i++, path = Path.Combine(dir, filename + $" ({i})" + ext))
            {
                ;
            }
            using (var sw = new StreamWriter(new FileStream(path, FileMode.Create)))
            {
                await sw.WriteAsync(json).ConfigureAwait(false);
            }
        }
        public void NoDrawdown(bool hasEquityPoint)
        {
            var strategyEquityChart = new Chart("Strategy Equity");
            var equitySeries        = new Series("Equity");

            strategyEquityChart.AddSeries(equitySeries);

            if (hasEquityPoint)
            {
                equitySeries.AddPoint(new DateTime(2020, 1, 1), 100000);
            }

            var backtest = new BacktestResult
            {
                Charts = new Dictionary <string, Chart> {
                    [strategyEquityChart.Name] = strategyEquityChart
                }
            };

            var normalizedResults = DrawdownCollection.NormalizeResults(backtest, null);

            Assert.AreEqual(0, normalizedResults.KeyCount);
            Assert.AreEqual(0, normalizedResults.ValueCount);
        }
Exemple #27
0
 public PortfolioComponent(string backtestResultId, BacktestResult backtestResult = null) : this()
 {
     BacktestResultId    = backtestResultId;
     this.BacktestResult = backtestResult;
 }
        } // End Run();

        /// <summary>
        /// Send a backtest update to the browser taking a latest snapshot of the charting data.
        /// </summary>
        public void ProcessSeriesUpdate()
        {
            try
            {
                //Sometimes don't run the update, if not ready or we're ending.
                if (Algorithm == null || Algorithm.Transactions == null || _processingFinalPacket)
                {
                    return;
                }

                if (DateTime.Now <= _nextUpdate || !(_daysProcessed > (_lastDaysProcessed + 1)))
                {
                    return;
                }

                //Debugging..
                //Logging.Log.Debug("BacktestingResultHandler.ProcessSeriesUpdate(): Sending Update (" + _lastDaysProcessed + ") : " + DateTime.Now.ToLongTimeString());

                //Extract the orders since last update
                var deltaOrders = new Dictionary <int, Order>();

                try
                {
                    deltaOrders = (from order in Algorithm.Transactions.Orders
                                   where order.Value.Time.Date >= _lastUpdate && order.Value.Status == OrderStatus.Filled
                                   select order).ToDictionary(t => t.Key, t => t.Value);
                }
                catch (Exception err)
                {
                    Log.Error("BacktestingResultHandler().ProcessSeriesUpdate(): Transactions: " + err.Message);
                }

                //Limit length of orders we pass back dynamically to avoid flooding.
                if (deltaOrders.Count > 50)
                {
                    deltaOrders.Clear();
                }

                //Reset loop variables:
                try
                {
                    _lastUpdate        = AlgorithmManager.Frontier.Date;
                    _lastDaysProcessed = _daysProcessed;
                    _nextUpdate        = DateTime.Now.AddSeconds(0.5);
                }
                catch (Exception err)
                {
                    Log.Error("BacktestingResultHandler.ProcessSeriesUpdate(): Can't update variables: " + err.Message);
                }

                var deltaCharts = new Dictionary <string, Chart>();
                lock (_chartLock)
                {
                    //Get the updates since the last chart
                    foreach (var chart in Charts.Values)
                    {
                        deltaCharts.Add(chart.Name, chart.GetUpdates());
                    }
                }

                //Profit Loss Changes:
                var deltaProfitLoss = new Dictionary <DateTime, decimal>();
                var deltaStatistics = new Dictionary <string, string>();
                var progress        = Convert.ToDecimal(_daysProcessed / _jobDays);
                if (progress > 0.999m)
                {
                    progress = 0.999m;
                }

                //1. Cloud Upload -> Upload the whole packet to S3  Immediately:
                var completeResult = new BacktestResult(Charts, Algorithm.Transactions.Orders, Algorithm.Transactions.TransactionRecord, new Dictionary <string, string>());
                var complete       = new BacktestResultPacket(_job, completeResult, progress);

                if (DateTime.Now > _nextS3Update)
                {
                    _nextS3Update = DateTime.Now.AddSeconds(30);
                    StoreResult(complete, false);
                }

                //2. Backtest Update -> Send the truncated packet to the backtester:
                var packet = new BacktestResultPacket(_job, new BacktestResult(deltaCharts, deltaOrders, deltaProfitLoss, deltaStatistics), progress);
                packet.DateRequested = _timeRequested;
                Engine.Notify.BacktestResult(packet);
            }
            catch (Exception err)
            {
                Log.Error("BacktestingResultHandler().ProcessSeriesUpdate(): " + err.Message + " >> " + err.StackTrace);
            }
        }
        } // End Run();

        /// <summary>
        /// Send a backtest update to the browser taking a latest snapshot of the charting data.
        /// </summary>
        public void Update()
        {
            try
            {
                //Sometimes don't run the update, if not ready or we're ending.
                if (Algorithm?.Transactions == null || _processingFinalPacket)
                {
                    return;
                }

                if (DateTime.UtcNow <= _nextUpdate || !(_daysProcessed > (_lastDaysProcessed + 1)))
                {
                    return;
                }

                //Extract the orders since last update
                var deltaOrders = new Dictionary <int, Order>();

                try
                {
                    deltaOrders = (from order in _transactionHandler.Orders
                                   where order.Value.Time.Date >= _lastUpdate && order.Value.Status == OrderStatus.Filled
                                   select order).ToDictionary(t => t.Key, t => t.Value);
                }
                catch (Exception err)
                {
                    Log.Error(err, "Transactions");
                }

                //Limit length of orders we pass back dynamically to avoid flooding.
                if (deltaOrders.Count > 50)
                {
                    deltaOrders.Clear();
                }

                //Reset loop variables:
                try
                {
                    _lastUpdate        = Algorithm.UtcTime.Date;
                    _lastDaysProcessed = _daysProcessed;
                    _nextUpdate        = DateTime.UtcNow.AddSeconds(2);
                }
                catch (Exception err)
                {
                    Log.Error(err, "Can't update variables");
                }

                var deltaCharts = new Dictionary <string, Chart>();
                lock (_chartLock)
                {
                    //Get the updates since the last chart
                    foreach (var kvp in Charts)
                    {
                        var chart = kvp.Value;

                        deltaCharts.Add(chart.Name, chart.GetUpdates());
                    }
                }

                //Get the runtime statistics from the user algorithm:
                var runtimeStatistics = new Dictionary <string, string>();
                lock (_runtimeLock)
                {
                    foreach (var pair in _runtimeStatistics)
                    {
                        runtimeStatistics.Add(pair.Key, pair.Value);
                    }
                }
                runtimeStatistics.Add("Unrealized", "$" + Algorithm.Portfolio.TotalUnrealizedProfit.ToString("N2"));
                runtimeStatistics.Add("Fees", "-$" + Algorithm.Portfolio.TotalFees.ToString("N2"));
                runtimeStatistics.Add("Net Profit", "$" + (Algorithm.Portfolio.TotalProfit - Algorithm.Portfolio.TotalFees).ToString("N2"));
                runtimeStatistics.Add("Return", ((Algorithm.Portfolio.TotalPortfolioValue - _setupHandler.StartingPortfolioValue) / _setupHandler.StartingPortfolioValue).ToString("P"));
                runtimeStatistics.Add("Equity", "$" + Algorithm.Portfolio.TotalPortfolioValue.ToString("N2"));

                //Profit Loss Changes:
                var progress = Convert.ToDecimal(_daysProcessed / _jobDays);
                if (progress > 0.999m)
                {
                    progress = 0.999m;
                }

                //1. Cloud Upload -> Upload the whole packet to S3  Immediately:
                if (DateTime.UtcNow > _nextS3Update)
                {
                    // For intermediate backtesting results, we truncate the order list to include only the last 100 orders
                    // The final packet will contain the full list of orders.
                    const int maxOrders  = 100;
                    var       orderCount = _transactionHandler.Orders.Count;

                    var completeResult = new BacktestResult(
                        Algorithm.IsFrameworkAlgorithm,
                        Charts,
                        orderCount > maxOrders ? _transactionHandler.Orders.Skip(orderCount - maxOrders).ToDictionary() : _transactionHandler.Orders.ToDictionary(),
                        Algorithm.Transactions.TransactionRecord,
                        new Dictionary <string, string>(),
                        runtimeStatistics,
                        new Dictionary <string, AlgorithmPerformance>());

                    StoreResult(new BacktestResultPacket(_job, completeResult, progress));

                    _nextS3Update = DateTime.UtcNow.AddSeconds(30);
                }

                //2. Backtest Update -> Send the truncated packet to the backtester:
                var splitPackets = SplitPackets(deltaCharts, deltaOrders, runtimeStatistics, progress);

                foreach (var backtestingPacket in splitPackets)
                {
                    _messagingHandler.Send(backtestingPacket);
                }
            }
            catch (Exception err)
            {
                Log.Error(err);
            }
        }
 /// <summary>
 /// Generate a new instance of DrawdownCollection from backtest and live <see cref="Result"/> derived instances
 /// </summary>
 /// <param name="backtestResult">Backtest result packet</param>
 /// <param name="liveResult">Live result packet</param>
 /// <param name="periods">Top N drawdown periods to get</param>
 /// <returns>DrawdownCollection instance</returns>
 public static DrawdownCollection FromResult(BacktestResult backtestResult = null, LiveResult liveResult = null, int periods = 5)
 {
     return(new DrawdownCollection(NormalizeResults(backtestResult, liveResult), periods));
 }