static void Main(string[] args) { CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; var(sec, thresholds) = ParseArgs(args); var date = DateTime.Now; Console.WriteLine($"Now: {date:s}"); date = date.Date.AddDays(date < date.Date.AddHours(20) ? -1 : 0); //date = new DateTime(2018, 10, 1); Console.WriteLine($"Trade date: {date:s}"); var history = MoexApi.DownloadHistory(sec, date.AddDays(-60), date).ToArray(); if (history.Last().Date != date) { if (MoexApi.HasCandles(sec, date)) { throw new Exception($"No history entry for {date:yyyy-MM-dd}"); } Console.WriteLine($"No trades on {date:yyyy-MM-dd}"); return; } var indicator = RocEma.Calculate(history); var candidate = new TurnCandidate(indicator, indicator.Count - 2); Console.WriteLine(candidate); if (candidate.IsDip(thresholds.Low)) { Notify($"📈 '{sec.ID}' DIP on {date:yyyy-MM-dd}"); } if (candidate.IsPeak(thresholds.High)) { Notify($"📉 '{sec.ID}' PEAK on {date:yyyy-MM-dd}"); } Console.WriteLine(); }
static void Main(string[] args) { var sec = new Sec("shares", "TQTF", "FXUS"); var history = RocEma.Calculate(HistoryCache.Read(sec)); //RunExperiment(history, new Thresholds(-1.1m, 2.2m), Console.WriteLine); //Environment.Exit(1); var tasks = SliceHistory(history) .Select(slice => Task.Run(() => BruteThresholds(slice))) .ToArray(); Task.WaitAll(tasks); Console.Error.WriteLine(); var groups = tasks .SelectMany(t => t.Result) .GroupBy(r => r.Thresholds) .Select(g => new { Thresholds = g.Key, Count = g.Count(), AvgXIrr = g.Average(i => i.XIrr), SdXIrr = g.StandardDeviation(i => i.XIrr), AvgTradeCount = g.Average(i => i.TradeCount), AvgSlipCount = g.Average(i => i.SlipCount) }) .ToArray(); var countTolerance = groups.Max(g => g.Count) * 95 / 100; groups = groups .Where(g => g.Count >= countTolerance) .OrderBy(g => g.SdXIrr) .ThenByDescending(g => g.AvgXIrr) .ThenBy(g => g.Thresholds.High) .ThenByDescending(g => g.Thresholds.Low) .ToArray(); var sdXIrrCents = Enumerable.Range(0, 100) .Select(i => groups[groups.Length * i / 100].SdXIrr) .ToArray(); Console.WriteLine(String.Join("\t", "t_lo", "t_hi", "count", "m_xirr", "sd_xirr", "m_trade", "m_slip")); var bestAvgXIrr = -1d; foreach (var g in groups) { if (g.AvgXIrr <= bestAvgXIrr) { continue; } else { bestAvgXIrr = g.AvgXIrr; } var sdXIrrCent = sdXIrrCents.TakeWhile(i => g.SdXIrr >= i).Count(); Console.WriteLine(String.Join("\t", g.Thresholds.Low, g.Thresholds.High, g.Count, Math.Round(100 * g.AvgXIrr, 2), ("p" + sdXIrrCent).Pastel(CentToColor(sdXIrrCent)), Math.Round(g.AvgTradeCount, 1), Math.Round(g.AvgSlipCount, 1) )); } }