/// <summary> /// Adds the quant fund. /// </summary> /// <param name="assembly"></param> /// <param name="message"></param> public IQuantFund AddFund(Assembly assembly, AddFundMessage message) { //Check if we have initialized the result tracker of this fund if (Results.QuantFund.InitialCapital == 0) { Results = new Result(BrokerAccount.Balance, _porfolioBenchmark); } //Get the benchmark instance if (!DynamicLoader.Instance.TryGetInstance(Config.GlobalConfig.Benchmark, out Benchmark benchmark)) { _log.Error($"Could not load instance of benchmark, {Config.GlobalConfig.Benchmark}. Cannot initialize quant fund {message.FundName}!"); return(null); } //Get quant fund var quantfund = new QuantFund(this, benchmark, message.FundId, message.AllocatedFunds, message.ForceTick, message.FundName); //Initialize the quant fund try { quantfund.Initialize(assembly, message); } catch (Exception exc) { _userlog.Error(exc, $"Could not initialize quant fund with id {quantfund.FundId}, please check the error"); throw exc; } //Add the quant fund _quantfunds.Add(quantfund); return(quantfund); }
/// <summary> /// Initializes a new instance of the <see cref="PortfolioManager"/> class for running a backtest. /// </summary> /// <param name="portfolioimplementations">The portfolioimplementations.</param> /// <param name="simulation">The backtest.</param> public PortfolioManager(PortfolioImplementations portfolioimplementations, SimulationMessage simulation) : this(portfolioimplementations) { //Set initial message _initialMessageInstance = simulation; //Since this is a backtest request RunMode = RunMode.Backtester; //World clock is depended on data received var clock = new WorldClock(() => PortfolioImplementations.DataFeed.LastDataReceivedUtc == DateTime.MinValue ? simulation.StartDateTime : portfolioimplementations.DataFeed.LastDataReceivedUtc); //Get additional information if (!Enum.TryParse(simulation.AccountType, out AccountType accounttype)) { throw new Exception($"Cannot initialize backtest account type {simulation.AccountType}"); } if (!Enum.TryParse(simulation.BrokerType, out BrokerType brokertype)) { throw new Exception($"Cannot initialize backtest broker type {simulation.BrokerType}"); } if (!Enum.TryParse(simulation.BaseCurrency, out CurrencyType basecurrency)) { throw new Exception($"Cannot initialize backtest base currency type {simulation.BaseCurrency}"); } //Get latest currency rates, so we are up to date (trough forced reload) _log.Debug($"Initializing currency implementation: {PortfolioImplementations.Currency.GetType().FullName}"); Config.LoadConfigFile <CurrencyRatesConfig[]>(Config.GlobalConfig.CurrencyRatesConfigFile, true); PortfolioImplementations.Currency.Initialize(clock, true); //Get broker model var brokermodel = BrokerModelFactory.GetBroker(accounttype, brokertype); //Check if the currency selected matches the currency of this broker (for instance when using crypto currencies) decimal allocatedfunds = simulation.QuantFund.AllocatedFunds; brokermodel.GetCompatibleInitialCapital(portfolioimplementations.Currency, ref basecurrency, ref allocatedfunds); simulation.QuantFund.AllocatedFunds = allocatedfunds; //Create portfolio _portfolio = CreatePortfolio(simulation.PortfolioId, Guid.NewGuid().ToString(), brokermodel, simulation.Leverage, basecurrency, basecurrency, clock, simulation.ExtendedMarketHours); //Set initial funds _portfolio.CashManager.AddCash(basecurrency, allocatedfunds); //Set initial fund message _initialFundMessage = simulation.QuantFund; }
/// <summary> /// Initializes the specified assembly. /// </summary> /// <param name="assembly">The assembly.</param> /// <param name="fundinfo">The fundinfo.</param> public void Initialize(Assembly assembly, AddFundMessage fundinfo) { try { //Set state State = FundState.Initializing; //Set fund universe Universe = Universe.Create(fundinfo.UniverseName, Portfolio.BrokerAccount.Securities, fundinfo.Universe); //Set fund modules foreach (var modulename in fundinfo.ModuleNames) { //Try and get the module instance if (!DynamicLoader.TryGetInstance(assembly, modulename, out IModule instance)) { throw new Exception($"Could not find module {modulename} in provided assembly. Did you add the export attribute?"); } //Set quantfund instance.SetQuantFund(this); //Set parameters fundinfo.Parameters.Where(x => x.ModuleName == modulename) .ForEach(parm => instance.SetParameter(parm.Name, parm.Value)); //Add to modules _modules.Add(instance); } //Set universe to position tracker Positions.SetUniverse(Universe.Securities.Select(x => x.Ticker).ToArray()); //Set benchmark Benchmark.OnCalc(x => Universe.Sum(s => s.Price * Universe.GetWeight(s))); //Subscribe to all ticker symbols by default Universe.ForEach(x => Portfolio.Subscription.AddSubscription(this, x, new TickQuoteBarAggregator(TimeSpan.FromMinutes(1)), fundinfo.ForceTick)); //Initialize all modules _modules.ForEach(m => m.Initialize()); } catch (Exception exc) { _log.Error(exc, $"Could not initialize quant fund with name {Name} due to error: {exc.Message}"); Portfolio.ExceptionHandler.HandleException(exc, FundId); State = FundState.DeployError; } }
/// <summary> /// Initializes a new instance of the <see cref="PortfolioManager"/> class for running a live trading instance. /// </summary> /// <param name="portfolioImplementations">The portfolio implementations.</param> /// <param name="livetrading">The livetrading.</param> public PortfolioManager(PortfolioImplementations portfolioImplementations, LiveTradingMessage livetrading) : this(portfolioImplementations) { //Set initial message _initialMessageInstance = livetrading; //Since this is a live trading request RunMode = RunMode.LiveTrading; //World clock is current time var clock = new WorldClock(() => DateTime.UtcNow); //Get additional information if (!Enum.TryParse(livetrading.AccountType, out AccountType accounttype)) { throw new Exception($"Cannot initialize backtest account type {livetrading.AccountType}"); } if (!Enum.TryParse(livetrading.BrokerType, out BrokerType brokertype)) { throw new Exception($"Cannot initialize backtest broker type {livetrading.BrokerType}"); } if (!Enum.TryParse(livetrading.BaseCurrency, out CurrencyType basecurrency)) { throw new Exception($"Cannot initialize backtest base currency type {livetrading.BaseCurrency}"); } if (!Enum.TryParse(livetrading.DisplayCurrency, out CurrencyType displaycurrency)) { throw new Exception($"Cannot initialize backtest base currency type {livetrading.DisplayCurrency}"); } //Get latest currency rates, so we are up to date (trough forced reload) _log.Debug($"Initializing currency implementation: {PortfolioImplementations.Currency.GetType().FullName}"); Config.LoadConfigFile <CurrencyRatesConfig[]>(Config.GlobalConfig.CurrencyRatesConfigFile, true); PortfolioImplementations.Currency.Initialize(clock, true); //Get broker model var brokermodel = BrokerModelFactory.GetBroker(accounttype, brokertype); //Create portfolio _portfolio = CreatePortfolio(livetrading.PortfolioId, livetrading.AccountId, brokermodel, livetrading.Leverage, basecurrency, displaycurrency, clock, livetrading.ExtendedMarketHours); //Set initial fund message _initialFundMessage = livetrading.QuantFund; }
/// <summary> /// Creates the fund message instance. /// </summary> /// <param name="config">The configuration.</param> /// <param name="assembly"></param> /// <returns></returns> private AddFundMessage CreateFund(QuantFundConfig config, string assembly) { var toreturn = new AddFundMessage { Universe = config.StaticUniverse.ToDictionary(x => x.Ticker, x => x.Weight), AllocatedFunds = config.AllocatedFunds, Base64Assembly = assembly, ForceTick = config.ForceTick, FundId = string.IsNullOrWhiteSpace(config.Id) ? Guid.NewGuid().ToString() : config.Id, UniqueId = Guid.NewGuid().ToString(), MessageType = MessageType.AddFund, SendUtc = DateTime.UtcNow, FrameworkVersion = Framework.CurrentVersion, IsResult = false, FundName = config.Name, Parameters = config.Parameters.Select(x => new ModuleParameter { Name = x.Name, ModuleName = x.ModuleName, Value = x.Value }).ToList(), UniverseName = config.UniverseName, ModuleNames = config.Modules }; //Check universe weights if (toreturn.Universe.Sum(x => x.Value) != 1) { _log.Error( $"Sum of universe attached to quant fund with name {config.Name} and universe name {config.UniverseName} does not sum to 1, cannot use a universe that does not sum to 1. Exiting..."); throw new Exception($"Universe weights of universe {config.UniverseName} does not sum to 1"); } //Return what we have return(toreturn); }