public void SimulateTradingReturnsExpectedSimulationResult(List <Company> testCompanies)
        {
            // Arrange

            var tested           = Tested;
            var flattenedQuotes  = testCompanies.SelectMany(x => x.Quotes).OrderBy(x => x.DateParsed).ToList();
            var simulationConfig = new TradingSimulationConfig
            {
                FromDate     = new DateTime(2020, 01, 01),
                ToDate       = new DateTime(2021, 01, 01),
                StartingCash = 1000,
                TopN         = 10
            };

            var allQuotesPrefiltered = flattenedQuotes.Where(z =>
                                                             !new Regex(@".*\d{3,}|WIG.*|RC.*|INTL.*|INTS.*|WIG.*|.*PP\d.*|.*BAHOLDING.*|CFI.*").IsMatch(z.Ticker) &&
                                                             z.DateParsed.InOpenRange(simulationConfig.FromDate.AddDays(-30),
                                                                                      simulationConfig.ToDate))
                                       .ToList();
            // Act

            var result = tested.Simulate(allQuotesPrefiltered, simulationConfig);

            // Assert
            Assert.Equal(102.65, result.FinalBalance, 2);
            Assert.Equal(-89.73, result.ReturnOnInvestment, 2);
            Assert.Equal(0.33, result.ROC.Accuracy, 2);
            Assert.Equal(2394, result.ROC.All);
            Assert.True(result.TransactionsLedger.All(x => x.Date.InOpenRange(simulationConfig.FromDate, simulationConfig.ToDate)));
            Assert.Equal(result.ROC.All * 2, result.TransactionsLedger.Count);
            Assert.Equal(result.ROC.All, result.TransactionsLedger.Count(x => x.TransactionType == StockTransactionType.Sell));
            Assert.Equal(result.ROC.All, result.TransactionsLedger.Count(x => x.TransactionType == StockTransactionType.Buy));
        }
        protected override List <StockQuote> GetTopN(TradingSimulationConfig tradingSimulationConfig, List <StockQuote> allQuotesPrefilterd, DateTime date)
        {
            var allQuotesBeforeTradeDay  = allQuotesPrefilterd.Where(x => x.DateParsed.Date < date.Date).ToList();
            var nMinusOneDay             = allQuotesBeforeTradeDay.Select(x => x.DateParsed).Max();
            var allQuotesFromMinusOneDay = allQuotesPrefilterd.Where(x => x.DateParsed.Date.Equals(nMinusOneDay.Date)).ToList();

            var topN = allQuotesFromMinusOneDay
                       .Where(x => (!tradingSimulationConfig.ExcludePennyStocks || x.AveragePrice > tradingSimulationConfig.ExcludePennyStocksThreshold) &&
                              (!ProjectSettings.ExcludeBlacklisted || !ProjectSettings.BlackListPattern.IsMatch(x.Ticker)))
                       .OrderByDescending(x => x.AveragePriceChange)
                       .Take(tradingSimulationConfig.TopN)
                       .ToList();

            return(topN);
        }
Exemple #3
0
        public async Task Execute(params string[] args)
        {
            _projectSettings.EnsureAllDirectoriesExist();
            var command  = args[0];
            var fromDate = default(DateTime?);
            var toDate   = default(DateTime?);
            var tradingSimulationConfig = TradingSimulationConfig.CreateFrom(_configuration);

            switch (command)
            {
            case "h":
            case "help":
                _logger.LogInfo(HelpMessage);
                break;

            case "getDir":
                _logger.LogInfo($"Working directory: {_projectSettings.WorkingDirectory.FullName}");
                break;

            case "openDir":
                ProcessStartInfo startInfo = new ProcessStartInfo("explorer.exe", _projectSettings.WorkingDirectory.FullName);
                startInfo.Verb = "runas";
                Process.Start(startInfo);
                break;

            case "printUnzipped":
                _logger.LogInfo(string.Join(Environment.NewLine, _projectSettings.GetFilesListInDirectory(_projectSettings.UnzippedFilesDirectory)));
                break;


            case "cleanDir":
                _projectSettings.CleanOutputDirectory();
                _logger.LogInfo($"Cleaned directory {_projectSettings.UnzippedFilesDirectory.FullName}");
                break;

            case "cleanLogs":
                _projectSettings.CleanLogs();
                _logger.LogInfo($"Cleaned logs in {_projectSettings.LogDirectory.FullName}");
                break;

            case "dropDb":
                await _databaseManagementService.EnsureDbDoesNotExist(_projectSettings);

                break;

            case "download":
                await _stockQuotesDownloadService.Download(_projectSettings);

                break;

            case "unzip":
                await _stockQuotesMigrationFromCsv.Unzip(_projectSettings);

                break;

            case "migrate":
                await _stockQuotesMigrationFromCsv.Migrate(_projectSettings, TargetLocation.Directory);

                _logger.LogInfo("Successfully migrated data to database.");
                break;

            case "dbVersion":
                var latestDateInDb = await _stockQuoteRepository.GetLatestSessionInDbDateAsync();

                _logger.LogInfo(latestDateInDb.ToShortDateString());
                break;

            case "update":
                await _stockUpdateService.PerformUpdateTillToday();

                break;

            case "print":
                if (args.Length >= 2)
                {
                    var found = _companyRepository.GetById(args[1]);
                    if (found == null)
                    {
                        _logger.LogWarning($"{args[1]} not found.");
                    }
                    else
                    {
                        _logger.LogInfo(string.Join(Environment.NewLine, found.Quotes.Select(x => x.Summary())));
                    }
                }
                else
                {
                    var summary = _companyRepository.Summary();
                    _logger.LogInfo($"{Environment.NewLine}{summary.Count} companies.{string.Join(Environment.NewLine, summary)}");
                }
                break;

            case "simulate":
                if (args.Length >= 3)
                {
                    fromDate = TryParseDateTime(args[1]);
                    toDate   = TryParseDateTime(args[2]);
                    if (fromDate.HasValue && toDate.HasValue)
                    {
                        tradingSimulationConfig.FromDate = fromDate.Value;
                        tradingSimulationConfig.ToDate   = toDate.Value;
                    }
                }

                var allQuotesPrefilterd = _stockQuoteRepository
                                          .GetAll(x => !_projectSettings.BlackListPattern.IsMatch(x.Ticker) &&
                                                  x.DateParsed.InOpenRange(tradingSimulationConfig.FromDate.AddDays(-30), tradingSimulationConfig.ToDate))
                                          .ToList();

                var simulationResult = _tradingSimulator.Simulate(allQuotesPrefilterd, tradingSimulationConfig, _progressReporter);

                _logger.LogInfo(simulationResult.ToString());
                break;

            case "predict":
                if (args.Length >= 2)
                {
                    var date = TryParseDateTime(args[1]);
                    if (date.HasValue)
                    {
                        var prediction = _tradingSimulator.GetSignals(tradingSimulationConfig, date.Value);
                        _logger.LogInfo($"Stonks to buy: {string.Join(", ", prediction.Select(x => x.Ticker).OrderBy(x => x))}. Used prediction made with data from session {prediction.Select(x => x.DateParsed).First()} and config = {tradingSimulationConfig}");
                    }
                    else
                    {
                        _logger.LogError($"{args[1]} is not a valid date. Enter date in format YYYY-MM-DD");
                    }
                }
                else
                {
                    _logger.LogError($"Enter date in format YYYY-MM-DD as second argument after empty space. Example: predict 2020-01-01");
                }
                break;

            default:
                _logger.LogWarning(@$ "{command} not recognized as valid command. {HelpMessage}");
                break;
            }
        }
Exemple #4
0
        public virtual SimulationResult Simulate(List <StockQuote> allQuotesPrefilterd,
                                                 TradingSimulationConfig tradingSimulationConfig,
                                                 IProgressReportable progress = null)
        {
            var ledger = new TransactionsLedger(tradingSimulationConfig.StartingCash);
            var result = new SimulationResult {
                TradingSimulationConfig = tradingSimulationConfig
            };

            var filteredQuotes = allQuotesPrefilterd.Where(x =>
                                                           x.DateParsed.InOpenRange(tradingSimulationConfig.FromDate, tradingSimulationConfig.ToDate)).ToList();

            var tradingStartingDate = filteredQuotes.Min(x => x.DateParsed);
            var tradingEndDate      = filteredQuotes.Max(x => x.DateParsed);
            var datesToTrade        = filteredQuotes
                                      .Where(x => x.DateParsed.InOpenRange(tradingStartingDate, tradingEndDate))
                                      .Select(x => x.DateParsed)
                                      .Distinct()
                                      .OrderBy(x => x)
                                      .ToList();


            progress?.Restart(datesToTrade.Count);
            foreach (var date in datesToTrade)
            {
                var topN = GetTopN(tradingSimulationConfig, allQuotesPrefilterd, date);

                var topNTickers = Enumerable.ToHashSet(topN.Select(quote => quote.Ticker));
                var tradingDayQuotesForMostRising = allQuotesPrefilterd
                                                    .Where(x => x.DateParsed.Date.Equals(date.Date) && topNTickers.Contains(x.Ticker) && x.IsValid());

                foreach (var stockQuoteForToday in tradingDayQuotesForMostRising)
                {
                    var volume         = (ledger.Balance / tradingSimulationConfig.TopN) / (stockQuoteForToday.Open);
                    var buyOrderStatus = ledger.PlaceBuyOrder(stockQuoteForToday, stockQuoteForToday.Open, volume);

                    switch (buyOrderStatus)
                    {
                    case OrderStatusType.Accepted:
                        var sellOrderStatus = ledger.ClosePosition(stockQuoteForToday, stockQuoteForToday.Close);
                        if (sellOrderStatus != OrderStatusType.Accepted)
                        {
                            Logger.LogWarning($"Could not perform closing sell on {stockQuoteForToday.Ticker} {stockQuoteForToday.DateParsed}. Selling the trade for buy price...");
                            ledger.ClosePosition(stockQuoteForToday, stockQuoteForToday.Open);
                        }

                        switch (sellOrderStatus)
                        {
                        case OrderStatusType.DeniedNoOpenPosition:
                            Logger.LogError($"Sell order of {volume} stocks denied due to lack of open position on {stockQuoteForToday.Ticker}.");
                            break;

                        case OrderStatusType.DeniedOutOfRange:
                            Logger.LogWarning($"Sell order for of {volume} stocks denied due to price being out of range of today's {stockQuoteForToday.Ticker} prices ({stockQuoteForToday.Low} - {stockQuoteForToday.High})." +
                                              "Selling the trade for buy price...");
                            ledger.ClosePosition(stockQuoteForToday, stockQuoteForToday.Open);
                            break;
                        }
                        break;

                    case OrderStatusType.DeniedInsufficientFunds:
                        Logger.LogWarning($"Buy order for {stockQuoteForToday.Ticker} price = {stockQuoteForToday.Open} vol = {volume} denied due to insufficient funds ({ledger.Balance}).");
                        break;

                    case OrderStatusType.DeniedOutOfRange:
                        Logger.LogWarning($"Buy order for {stockQuoteForToday.Open * volume} denied due to price being out of range of today's {stockQuoteForToday.Ticker} prices ({stockQuoteForToday.Low} - {stockQuoteForToday.High}.");
                        break;
                    }
                    result.ROC.Activate(true, stockQuoteForToday.Close > stockQuoteForToday.Open);
                }
                progress?.ReportProgress();
            }

            result.TransactionsLedger        = ledger.TheLedger;
            result.FinalBalance              = ledger.Balance;
            result.CompaniesUsedInSimulation = filteredQuotes.DistinctBy(x => x.Ticker).Count();
            result.SimulatorName             = this.GetType().Name;

            return(result);
        }
Exemple #5
0
 protected abstract List <StockQuote> GetTopN(TradingSimulationConfig tradingSimulationConfig, List <StockQuote> allQuotesPrefilterd, DateTime date);
Exemple #6
0
        public virtual List <StockQuote> GetSignals(TradingSimulationConfig tradingSimulationConfig, DateTime date)
        {
            var allQuotesFromLastSession = StockQuoteRepository.GetAllQuotesFromPreviousSession(date);

            return(GetTopN(tradingSimulationConfig, allQuotesFromLastSession, date));
        }
        public override SimulationResult Simulate(List <StockQuote> allQuotesPrefilterd, TradingSimulationConfig tradingSimulationConfig,
                                                  IProgressReportable progress = null)
        {
            var result = base.Simulate(allQuotesPrefilterd, tradingSimulationConfig, progress);

            return(result);
        }
Exemple #8
0
 protected override List <StockQuote> GetTopN(TradingSimulationConfig tradingSimulationConfig, List <StockQuote> allQuotesPrefilterd, DateTime date)
 {
     throw new NotImplementedException();
 }