コード例 #1
0
        private static RangeBarModel[] LoadBars(BacktestConfig config, string file)
        {
            CsvReader csv = null;

            if (file.Contains(".gz", StringComparison.OrdinalIgnoreCase))
            {
                var fStream  = new FileStream(file, FileMode.Open);
                var gzStream = new GZipStream(fStream, CompressionMode.Decompress);
                var reader   = new StreamReader(gzStream);
                csv = new CsvReader(reader, CultureInfo.InvariantCulture);
            }
            else
            {
                var reader = new StreamReader(file);
                csv = new CsvReader(reader, CultureInfo.InvariantCulture);
            }

            csv.Configuration.PrepareHeaderForMatch = (header, index) => header.ToLower();
            csv.Configuration.HeaderValidated       = null;
            csv.Configuration.MissingFieldFound     = null;
            var bars = csv.GetRecords <RangeBarModel>().ToArray();

            FixTimestamp(config, bars);
            var ordered = bars.OrderBy(x => x.TimestampDate).ToArray();

            csv.Dispose();

            return(ordered);
        }
コード例 #2
0
        private static void FixTimestamp(BacktestConfig config, RangeBarModel[] bars)
        {
            if (string.IsNullOrWhiteSpace(config.TimestampType) ||
                config.TimestampType == "unix-sec" ||
                config.TimestampType == "date")
            {
                // default valid timestamp format, do nothing
                return;
            }

            foreach (var bar in bars)
            {
                var t         = bar.TimestampUnix;
                var d         = config.TimestampDecimals ?? 0;
                var converted = t;

                switch (config.TimestampType)
                {
                case "unix-ms":
                case "ms":
                    converted = t / (Math.Pow(10, d));
                    break;
                }

                bar.TimestampUnix = converted;
            }
        }
コード例 #3
0
 public ProfitComputer(IStrategy strategy, BacktestConfig config, int?maxLimitInventory)
 {
     _orderSize         = config.Amount ?? 1;
     _strategy          = strategy;
     _feePercentage     = config.FeePercentage ?? 0;
     _quoteSymbol       = config.QuoteSymbol;
     _baseSymbol        = config.BaseSymbol;
     _config            = config;
     _maxLimitInventory = maxLimitInventory;
 }
コード例 #4
0
        private static void SaveTextReport(string report, BacktestConfig backtest, IStrategy strategy)
        {
            var filename     = Path.GetFileName(backtest.DirectoryPath);
            var strategyName = strategy.GetType().Name;
            var pattern      = ExtractFromPattern(backtest);

            pattern = string.IsNullOrWhiteSpace(pattern) ? filename : pattern;
            var targetFile = Path.Combine(GetPathToReportDir(backtest), $"{pattern}__{strategyName}.txt");

            File.WriteAllText(targetFile, report);
        }
コード例 #5
0
        private static RangeBarModel[] LoadBars(BacktestConfig config, string file)
        {
            using var reader = new StreamReader(file);
            using var csv    = new CsvReader(reader, CultureInfo.InvariantCulture);
            csv.Configuration.PrepareHeaderForMatch = (header, index) => header.ToLower();
            csv.Configuration.HeaderValidated       = null;
            csv.Configuration.MissingFieldFound     = null;
            var bars = csv.GetRecords <RangeBarModel>().ToArray();

            FixTimestamp(config, bars);
            var ordered = bars.OrderBy(x => x.TimestampDate).ToArray();

            return(ordered);
        }
コード例 #6
0
        private static string ExtractFromPattern(BacktestConfig backtest)
        {
            var pattern = backtest.FilePattern ?? string.Empty;
            var split   = pattern.Split("*");

            if (split.Length > 1)
            {
                return(split[0]
                       .Trim('_')
                       .Trim('_')
                       .Trim('/')
                       .Trim('\\')
                       .Trim());
            }
            return(pattern);
        }
コード例 #7
0
        private static void Visualize(BacktestConfig backtest, ProfitComputer computer, IStrategy strategy,
                                      int maxInv, ProfitInfo report, ProfitInfo[] days, ProfitInfo[] months)
        {
            if (computer == null || backtest.Visualize == null || !backtest.Visualize.Value)
            {
                return;
            }

            PrepareWebVisualization(backtest, computer, strategy, maxInv, report, report, days, months);

            var chart        = new ChartVisualizer();
            var filename     = Path.GetFileName(backtest.DirectoryPath);
            var strategyName = strategy.GetType().Name.ToLower();
            var pnl          = report.Pnl;
            var name         = $"{pnl:#.00} {backtest.QuoteSymbol} (max inv: {maxInv}) ";
            var nameWithFee  = $"{report.PnlWithFee:#.00} {backtest.QuoteSymbol} (max inv: {maxInv}) ";

            var dir        = GetPathToReportDir(backtest);
            var pattern    = ExtractFromPattern(backtest);
            var targetFile = Path.Combine(dir, $"{pattern}__{strategyName}__{maxInv}__{pnl:0}");

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            var bars      = computer.Bars;
            var totalBars = bars.Length;

            if (backtest.VisualizeSkipBars.HasValue)
            {
                bars = bars.Skip(backtest.VisualizeSkipBars.Value).ToArray();
            }
            if (backtest.VisualizeLimitBars.HasValue)
            {
                bars = bars.Take(backtest.VisualizeLimitBars.Value).ToArray();
            }

            var minIndex = bars.Min(x => x.Index);
            var maxIndex = bars.Max(x => x.Index);

            var trades = computer.Trades
                         .Where(x => x.BarIndex >= minIndex && x.BarIndex <= maxIndex)
                         .ToArray();

            chart.Plot(name, nameWithFee, targetFile, totalBars, bars, trades, days, months);
        }
コード例 #8
0
 private static void PrepareWebVisualization(BacktestConfig backtest, ProfitComputer computer, IStrategy strategy, in int maxInv,
コード例 #9
0
        private static void RunBacktest(BacktestConfig backtest, Func <IStrategy> strategyFactory)
        {
            var files = LoadAllFiles(backtest.DirectoryPath, backtest.FilePattern);

            if (backtest.SkipFiles.HasValue)
            {
                files = files.Skip(backtest.SkipFiles.Value).ToArray();
            }
            if (backtest.LimitFiles.HasValue)
            {
                files = files.Take(backtest.LimitFiles.Value).ToArray();
            }

            if (!files.Any())
            {
                return;
            }

            Console.WriteLine();
            Console.WriteLine("=====================================================================");
            Console.WriteLine($"    Running for {files.Length} files from dir '{backtest.DirectoryPath}' and pattern: '{backtest.FilePattern}'");

            var builderTop = new StringBuilder();
            var builder    = new StringBuilder();

            foreach (var maxInventory in backtest.MaxInventory)
            {
                RangeBarModel lastBar  = null;
                var           strategy = strategyFactory();
                var           computer = new ProfitComputer(strategy, backtest, maxInventory);
                foreach (var file in files)
                {
                    var bars = LoadBars(backtest, file);
                    computer.ProcessBars(bars);
                    lastBar = bars.LastOrDefault();
                }

                if (lastBar != null)
                {
                    computer.ProcessLastBar(lastBar);
                }

                var report = computer.GetReport();

                builderTop.AppendLine(report.ToString());

                builder.AppendLine(
                    $"==== MAX INV: {maxInventory} {new string('=', 133)}");
                builder.AppendLine();
                builder.AppendLine(report.ToString());
                Console.WriteLine($"    {report}");

                var reportDays = new List <ProfitInfo>();
                var perMonth   = computer.GetReportByMonth();
                foreach (var month in perMonth)
                {
                    builder.AppendLine($"    {month.Report}");
                    if (month.Month == null)
                    {
                        builderTop.AppendLine($"{month.Report}");
                        continue;
                    }
                    var perDay = computer.GetReportPerDays(month.Year.Value, month.Month.Value);
                    reportDays.AddRange(perDay.Where(x => x.Day != null));
                    foreach (var day in perDay)
                    {
                        builder.AppendLine($"        {day.Report}");
                    }
                }

                //var totalReportAllDays = computer.GetTotalReport(reportDays.ToArray());
                //builderTop.AppendLine($"{totalReportAllDays.Report}");

                //builderTop.AppendLine();
                builder.AppendLine();
                builder.AppendLine();

                Visualize(backtest, computer, strategy, maxInventory, report,
                          reportDays.ToArray(),
                          perMonth.Where(x => x.Month.HasValue).ToArray());
            }

            var mergedReport = $"{builderTop}{Environment.NewLine}{builder}";

            SaveTextReport(mergedReport, backtest, strategyFactory());

            Console.WriteLine();
        }
コード例 #10
0
 private static string GetPathToReportDir(BacktestConfig backtest)
 {
     return(Path.Combine(Path.GetDirectoryName(backtest.DirectoryPath), "reports"));
 }
コード例 #11
0
        private static void RunBacktest(BacktestConfig backtest, Func <IStrategy> strategyFactory)
        {
            var files = LoadAllFiles(backtest.DirectoryPath, backtest.FilePattern);

            if (backtest.SkipFiles.HasValue)
            {
                files = files.Skip(backtest.SkipFiles.Value).ToArray();
            }
            if (backtest.LimitFiles.HasValue)
            {
                files = files.Take(backtest.LimitFiles.Value).ToArray();
            }

            if (!files.Any())
            {
                return;
            }

            Console.WriteLine();
            Console.WriteLine("=====================================================================");
            Console.WriteLine($"    Running for {files.Length} files from dir '{backtest.DirectoryPath}' and pattern: '{backtest.FilePattern}'");

            var builderTop = new StringBuilder();
            var builder    = new StringBuilder();

            foreach (var maxInventory in backtest.MaxInventory)
            {
                RangeBarModel lastBar  = null;
                var           strategy = strategyFactory();
                var           computer = new ProfitComputer(strategy, backtest, maxInventory);
                foreach (var file in files)
                {
                    var bars = LoadBars(backtest, file);
                    computer.ProcessBars(bars);
                    lastBar = bars.LastOrDefault();
                }

                if (lastBar != null)
                {
                    computer.ProcessLastBar(lastBar);
                }

                var primaryReport = computer.GetReport();

                var perMonth    = computer.GetReportByMonth();
                var reportDays  = new List <ProfitInfo>();
                var maxTotalPnl = maxInventory * computer.InitialPrice;
                var minTotalPnl = maxTotalPnl;
                var totalPnl    = maxTotalPnl;

                foreach (var month in perMonth)
                {
                    if (month.Month == null)
                    {
                        continue;
                    }

                    var perDay = computer.GetReportPerDays(month.Year.Value, month.Month.Value, ref maxTotalPnl, ref minTotalPnl, ref totalPnl);
                    reportDays.AddRange(perDay.Where(x => x.Day != null));
                    month.MaxDrawdownPercentage = perDay.Min(x => x.MaxDrawdownPercentage);
                    month.SubProfits            = perDay;
                }

                primaryReport.MaxDrawdownPercentage = perMonth.Min(x => x.MaxDrawdownPercentage);

                builderTop.AppendLine(primaryReport.ToString());

                builder.AppendLine(
                    $"==== MAX INV: {maxInventory} {new string('=', 133)}");
                builder.AppendLine();
                builder.AppendLine(primaryReport.ToString());

                var consoleDefaultColor = Console.ForegroundColor;
                var reportColor         = Console.ForegroundColor;

                var pnl = backtest.DisplayFee != null && backtest.DisplayFee.Value ? primaryReport.PnlWithFee : primaryReport.Pnl;

                if (pnl < 0)
                {
                    reportColor = ConsoleColor.DarkRed;
                }
                else if (pnl > 0 && primaryReport.MaxDrawdownPercentage >= -0.03)
                {
                    reportColor = ConsoleColor.Green;
                }
                else if (pnl > 0)
                {
                    reportColor = ConsoleColor.DarkGreen;
                }

                Console.ForegroundColor = reportColor;
                Console.WriteLine($"    {primaryReport}");
                Console.ForegroundColor = consoleDefaultColor;

                foreach (var month in perMonth)
                {
                    if (month.Month == null)
                    {
                        builder.AppendLine($"    {month.Report}");
                        builderTop.AppendLine($"{month.Report}");
                        continue;
                    }

                    builder.AppendLine($"    {month.Report}");
                    foreach (var day in month.SubProfits)
                    {
                        builder.AppendLine($"        {day.Report}");
                    }
                }

                //var totalReportAllDays = computer.GetTotalReport(reportDays.ToArray());
                //builderTop.AppendLine($"{totalReportAllDays.Report}");

                //builderTop.AppendLine();
                builder.AppendLine();
                builder.AppendLine();

                Visualize(backtest, computer, strategy, maxInventory, primaryReport,
                          reportDays.ToArray(),
                          perMonth.Where(x => x.Month.HasValue).ToArray());
            }

            var mergedReport = $"{builderTop}{Environment.NewLine}{builder}";

            SaveTextReport(mergedReport, backtest, strategyFactory());

            Console.WriteLine();
        }