private void ConfigureTimestampEdges(BacktestDaemonState state, StartBacktestCommandArguments args) { var(begin, end) = DatabaseUtilities.Instance.GetTimeStampEdges(_configuration.TradingPairs); if (args.BeginEpoch != 0) { if (args.BeginEpoch < 0) { throw new InvalidCommandException( $"Cannot set begin epoch to {DateTimeOffset.FromUnixTimeMilliseconds(args.BeginEpoch)}, " + $"the database starts at {DateTimeOffset.FromUnixTimeMilliseconds(begin)}"); } if (args.BeginEpoch < begin) { throw new InvalidCommandException("begin_epoch was smaller than database start."); } if (args.BeginEpoch < begin + TimeSpan.FromDays(14).TotalMilliseconds) { Console.WriteLine($"WARNING: Custom Begin Epoch is close to the beginning of the data, be careful" + $"not to read to far into the past."); } state.BeginTimeStamp = args.BeginEpoch; } else { state.BeginTimeStamp = begin + (long)TimeSpan.FromDays(14).TotalMilliseconds; } if (args.EndEpoch != 0) { if (args.EndEpoch > end) { throw new InvalidCommandException( $"Cannot set end epoch to {DateTimeOffset.FromUnixTimeMilliseconds(args.EndEpoch)}, " + $"the database stops at {DateTimeOffset.FromUnixTimeMilliseconds(end)}"); } end = args.EndEpoch; } state.EndTimeStamp = end; }
/// <summary> /// Initializes a new instance of the <see cref="StartBacktestCommand"/> class. /// </summary> /// <param name="inputs">inputs.</param> public StartBacktestCommand(string[] inputs) : base(inputs) { Parser parser = new Parser(x => x.HelpWriter = null); parser.ParseArguments <StartBacktestCommandArguments>(inputs) .WithNotParsed(_ => throw new InvalidCommandException("invalid arguments, use help to get more info")) .WithParsed(x => _args = x); // Check if the input type is a valid algorithm _algo = Reflections.GetAllImplementations(typeof(IBaseAlgorithm)) .FirstOrDefault(x => x.Name == _args.AlgorithmName) ?? throw new InvalidCommandException($"{_args.AlgorithmName} is not a known algorithm"); // Retrieve the settings type var settingsType = Reflections.GetAllSubtypes(typeof(AlgorithmConfiguration)) .FirstOrDefault(s => Reflections.AlgorithmMatchesConfiguration(_algo, s)) ?? throw new InvalidCommandException( $"{_args.AlgorithmName} does not have a configuration object and cannot be started."); // Optionally load with custom path. if (!_args.Inline) { _args.ConfigurationPath = _args.ConfigurationPath ?? _args.AlgorithmName + ".yaml"; try { _configuration = ConfigurationLoader.LoadConfiguration(settingsType, _args.ConfigurationPath); } catch (Exception e) { throw new InvalidCommandException(e.Message); } } else { _configuration = BacktestDaemonService.GetConfigurationFromUser(settingsType); } DatabaseUtilities.Instance.ValidateCandleWidth(_configuration.TradingPairs, Configuration.Configuration.Instance.CandleWidth); ConfigureTimestampEdges(BacktestDaemonService.Instance.State, _args); Program.CommandLineArgs.BacktestOutputPath = _args.OutputPath; }