public void ChangeAlgorithmConfiguration(Type algorithm, AlgorithmConfiguration config) { Guard.Argument(algorithm).Require(Reflections.IsAlgorithm, x => $"{x} is not an algorithm"); if (!Reflections.AlgorithmMatchesConfiguration(algorithm, config.GetType())) { throw new InvalidOperationException($"Cannot set algorithm to {algorithm} with config {config} because they are not compatible."); } __algorithm = algorithm.Name; _enabledAlgorithmConstructor.Invalidate(); AlgorithmConfiguration = config; }
/// <summary> /// Builds container by evaluation the Trading command line argument. /// </summary> /// <param name="algorithmConfiguration">The configuration of the algorithm.</param> /// <typeparam name="T">The type of the algorithm.</typeparam> /// <returns>Binance container with providers.</returns> public ExchangeProvidersContainer BuildContainer <T>(AlgorithmConfiguration algorithmConfiguration) where T : IBaseAlgorithm { if (!Reflections.AlgorithmMatchesConfiguration(typeof(T), algorithmConfiguration.GetType())) { throw new InvalidOperationException( $"Cannot build container for {typeof(T).Name} using a {algorithmConfiguration.GetType().Name} object"); } return(Program.CommandLineArgs.Trading ? BuildBinanceContainer <T>(algorithmConfiguration) : BuildBacktestingContainer <T>(algorithmConfiguration)); }
/// <summary> /// Starts the algorithm using a custom configuration object. /// </summary> /// <param name="algorithm">Algorithm to start.</param> /// <param name="configuration">Configuration object.</param> /// <returns>If the algorithm was started successfully.</returns> public ResponseObject StartAlgorithm(Type algorithm, AlgorithmConfiguration configuration) { if (!Reflections.AlgorithmMatchesConfiguration(algorithm, configuration.GetType())) { return(new ResponseObject(ResponseCode.Error, $"Provided settings object is of type {configuration.GetType()} and does not match {algorithm}")); } // Call StartAlgorithm<T> to start the algorithm return(GetType() .GetMethod( nameof(StartAlgorithm), BindingFlags.Instance | BindingFlags.NonPublic, Type.DefaultBinder, new[] { typeof(AlgorithmConfiguration) }, null) .MakeGenericMethod(algorithm) .Invoke(this, new object[] { configuration }) as ResponseObject); }
/// <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; }