public void Initialize(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IMapFileProvider mapFileProvider) { if (algorithm.SubscriptionManager.Subscriptions.Count == 0 && algorithm.Universes.IsNullOrEmpty()) { throw new Exception("No subscriptions registered and no universe defined."); } _algorithm = algorithm; _resultHandler = resultHandler; _mapFileProvider = mapFileProvider; _subscriptions = new ConcurrentDictionary<Symbol, Subscription>(); _cancellationTokenSource = new CancellationTokenSource(); IsActive = true; Bridge = new BusyBlockingCollection<TimeSlice>(100); var ffres = Time.OneSecond; _fillForwardResolution = Ref.Create(() => ffres, res => ffres = res); // find the minimum resolution, ignoring ticks ffres = ResolveFillForwardResolution(algorithm); // add each universe selection subscription to the feed foreach (var universe in _algorithm.Universes) { var startTimeUtc = _algorithm.StartDate.ConvertToUtc(_algorithm.TimeZone); var endTimeUtc = _algorithm.EndDate.ConvertToUtc(_algorithm.TimeZone); AddUniverseSubscription(universe, startTimeUtc, endTimeUtc); } }
private void LaunchLean() { Config.Set ("environment", "desktop"); string algorithm = "EMATest"; Config.Set("algorithm-type-name", algorithm); _jobQueue = new JobQueue (); _notify = new Messaging (); _api = new Api(); _resultshandler = new DesktopResultHandler (); _dataFeed = new FileSystemDataFeed (); _setup = new ConsoleSetupHandler (); _realTime = new BacktestingRealTimeHandler (); _historyProvider = new SubscriptionDataReaderHistoryProvider (); _transactions = new BacktestingTransactionHandler (); var systemHandlers = new LeanEngineSystemHandlers (_jobQueue, _api, _notify); systemHandlers.Initialize (); var algorithmHandlers = new LeanEngineAlgorithmHandlers (_resultshandler, _setup, _dataFeed, _transactions, _realTime, _historyProvider); var _engine = new Engine (systemHandlers, algorithmHandlers, Config.GetBool ("live-mode")); string algorithmPath; var job = systemHandlers.JobQueue.NextJob(out algorithmPath); _engine.Run(job, algorithmPath); }
/// <summary> /// Creates a new <see cref="ScheduledEvent"/> that will fire before market close by the specified time /// </summary> /// <param name="algorithm">The algorithm instance the event is fo</param> /// <param name="resultHandler">The result handler, used to communicate run time errors</param> /// <param name="start">The date to start the events</param> /// <param name="end">The date to end the events</param> /// <param name="endOfDayDelta">The time difference between the market close and the event, positive time will fire before market close</param> /// <param name="currentUtcTime">Specfies the current time in UTC, before which, no events will be scheduled. Specify null to skip this filter.</param> /// <returns>The new <see cref="ScheduledEvent"/> that will fire near market close each tradeable dat</returns> public static ScheduledEvent EveryAlgorithmEndOfDay(IAlgorithm algorithm, IResultHandler resultHandler, DateTime start, DateTime end, TimeSpan endOfDayDelta, DateTime? currentUtcTime = null) { if (endOfDayDelta >= Time.OneDay) { throw new ArgumentException("Delta must be less than a day", "endOfDayDelta"); } // set up an event to fire every tradeable date for the algorithm as a whole var eodEventTime = Time.OneDay.Subtract(endOfDayDelta); // create enumerable of end of day in algorithm's time zone var times = // for every date any exchange is open in the algorithm from date in Time.EachTradeableDay(algorithm.Securities.Values, start, end) // define the time of day we want the event to fire, a little before midnight let eventTime = date + eodEventTime // convert the event time into UTC let eventUtcTime = eventTime.ConvertToUtc(algorithm.TimeZone) // perform filter to verify it's not before the current time where !currentUtcTime.HasValue || eventUtcTime > currentUtcTime.Value select eventUtcTime; return new ScheduledEvent(CreateEventName("Algorithm", "EndOfDay"), times, (name, triggerTime) => { try { algorithm.OnEndOfDay(); } catch (Exception err) { resultHandler.RuntimeError(String.Format("Runtime error in {0} event: {1}", name, err.Message), err.StackTrace); Log.Error(err, string.Format("ScheduledEvent.{0}:", name)); } }); }
/// <summary> /// Launch the Lean Engine Primary Form: /// </summary> /// <param name="engine">Accept the engine instance we just launched</param> public LeanEngineWinForm(Engine engine) { _engine = engine; //Setup the State: _resultsHandler = engine.AlgorithmHandlers.Results; //Create Form: Text = "QuantConnect Lean Algorithmic Trading Engine: v" + Constants.Version; Size = new Size(1024,768); MinimumSize = new Size(1024, 768); CenterToScreen(); WindowState = FormWindowState.Maximized; Icon = new Icon("../../../lean.ico"); //Setup Console Log Area: _console = new RichTextBox(); _console.Parent = this; _console.ReadOnly = true; _console.Multiline = true; _console.Location = new Point(0, 0); _console.Dock = DockStyle.Fill; _console.KeyUp += ConsoleOnKeyUp; //Form Events: Closed += OnClosed; //Setup Polling Events: _polling = new Timer(); _polling.Interval = 1000; _polling.Tick += PollingOnTick; _polling.Start(); }
public Ping(AlgorithmManager algorithmManager, IApi api, IResultHandler resultHandler) { _api = api; _resultHandler = resultHandler; _algorithmManager = algorithmManager; _exitEvent = new ManualResetEventSlim(false); }
/// <summary> /// Handles a given message /// </summary> /// <param name="client"> /// The client. /// </param> /// <param name="collectionManager"> /// The collection manager. /// </param> /// <param name="resultHandler"> /// The result handler. /// </param> /// <param name="messageText"> /// The message text. /// </param> /// <returns> /// The <see cref="Task"/>. /// </returns> public async Task HandleMessage( IDdpConnectionSender client, ICollectionManager collectionManager, IResultHandler resultHandler, string messageText) { JObject message = JObject.Parse(messageText); if (message["msg"] != null) { var msg = message["msg"]; if (msg != null) { var messageType = (string)msg; foreach (var handler in this.handlers) { if (handler.CanHandle(messageType)) { await handler.HandleMessage(client, collectionManager, resultHandler, messageText); } } } } }
public void Run(string configuration, IResultHandler resultHandler) { Console.WriteLine("Doing work for: " + configuration); var t = new System.Threading.Tasks.Task(() => { resultHandler.OnSuccess(); }); t.Start(); }
public DbResultContext(IDbExecuteContext ctx, Type resultType, object resultInstance, IResultHandler resultHandler, IDictionary items) : base(items) { this.ExecuteContext = ctx; this.ResultType = resultType; this.ResultInstance = resultInstance; this.ResultHandler = resultHandler; }
public void Run(string configuration, IResultHandler resultHandler) { TaskRunCount++; Payloads.Add(configuration); resultHandler.OnSuccess(); }
public Ping(AlgorithmManager algorithmManager, IApi api, IResultHandler resultHandler, IMessagingHandler messagingHandler, AlgorithmNodePacket job) { _api = api; _job = job; _resultHandler = resultHandler; _messagingHandler = messagingHandler; _algorithmManager = algorithmManager; _exitEvent = new ManualResetEventSlim(false); }
/******************************************************** * PUBLIC CONSTRUCTOR *********************************************************/ /// <summary> /// Initialize the realtime event handler with all information required for triggering daily events. /// </summary> public LiveTradingRealTimeHandler(IAlgorithm algorithm, IDataFeed feed, IResultHandler results, IBrokerage brokerage, AlgorithmNodePacket job) { //Initialize: _algorithm = algorithm; _events = new List<RealTimeEvent>(); _today = new Dictionary<SecurityType, MarketToday>(); _feed = feed; _results = results; }
public void Run(string configuration, IResultHandler resultHandler) { TaskRunCount++; if (TaskRunCount.Equals(_failAtTask)) resultHandler.OnFailure(); else resultHandler.OnSuccess(); }
/// <summary> /// Initializes the data feed for the specified job and algorithm /// </summary> public void Initialize(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IMapFileProvider mapFileProvider, IFactorFileProvider factorFileProvider) { _algorithm = algorithm; _resultHandler = resultHandler; _mapFileProvider = mapFileProvider; _factorFileProvider = factorFileProvider; _subscriptions = new SubscriptionCollection(); _universeSelection = new UniverseSelection(this, algorithm, job.Controls); _cancellationTokenSource = new CancellationTokenSource(); IsActive = true; var threadCount = Math.Max(1, Math.Min(4, Environment.ProcessorCount - 3)); _controller = new ParallelRunnerController(threadCount); _controller.Start(_cancellationTokenSource.Token); var ffres = Time.OneMinute; _fillForwardResolution = Ref.Create(() => ffres, res => ffres = res); // wire ourselves up to receive notifications when universes are added/removed algorithm.UniverseManager.CollectionChanged += (sender, args) => { switch (args.Action) { case NotifyCollectionChangedAction.Add: foreach (var universe in args.NewItems.OfType<Universe>()) { var config = universe.Configuration; var start = _frontierUtc != DateTime.MinValue ? _frontierUtc : _algorithm.StartDate.ConvertToUtc(_algorithm.TimeZone); var marketHoursDatabase = MarketHoursDatabase.FromDataFolder(); var exchangeHours = marketHoursDatabase.GetExchangeHours(config); Security security; if (!_algorithm.Securities.TryGetValue(config.Symbol, out security)) { // create a canonical security object if it doesn't exist security = new Security(exchangeHours, config, _algorithm.Portfolio.CashBook[CashBook.AccountCurrency], SymbolProperties.GetDefault(CashBook.AccountCurrency)); } var end = _algorithm.EndDate.ConvertToUtc(_algorithm.TimeZone); AddSubscription(new SubscriptionRequest(true, universe, security, config, start, end)); } break; case NotifyCollectionChangedAction.Remove: foreach (var universe in args.OldItems.OfType<Universe>()) { RemoveSubscription(universe.Configuration); } break; default: throw new NotImplementedException("The specified action is not implemented: " + args.Action); } }; }
public ConsoleApplication(ICommandParser commandParser, IResultHandler resultHandler, IInput input, IExceptionHandler exceptionHandler) { _commandParser = commandParser; _resultHandler = resultHandler; _input = input; _exceptionHandler = exceptionHandler; }
/// <summary> /// Initializes a new instance of the <see cref="DefaultBrokerageMessageHandler"/> class /// </summary> /// <param name="algorithm">The running algorithm</param> /// <param name="job">The job that produced the algorithm</param> /// <param name="results">The result handler for the algorithm</param> /// <param name="api">The api for the algorithm</param> /// <param name="initialDelay"></param> /// <param name="openThreshold">Defines how long before market open to re-check for brokerage reconnect message</param> public DefaultBrokerageMessageHandler(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler results, IApi api, TimeSpan? initialDelay = null, TimeSpan? openThreshold = null) { _api = api; _job = job; _results = results; _algorithm = algorithm; _connected = true; _openThreshold = openThreshold ?? DefaultOpenThreshold; _initialDelay = initialDelay ?? DefaultInitialDelay; }
/// <summary> /// Creates a new BacktestingTransactionHandler using the BacktestingBrokerage /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="brokerage">The BacktestingBrokerage</param> /// <param name="resultHandler"></param> public override void Initialize(IAlgorithm algorithm, IBrokerage brokerage, IResultHandler resultHandler) { if (!(brokerage is BacktestingBrokerage)) { throw new ArgumentException("Brokerage must be of type BacktestingBrokerage for use wth the BacktestingTransactionHandler"); } _brokerage = (BacktestingBrokerage) brokerage; base.Initialize(algorithm, brokerage, resultHandler); }
public UserStatusChecker( IResultHandler resultHandler, IUserInfo infoProvider, IUserRepository repository, IErrorLogger errorLogger) { _resultHandler = resultHandler; _infoProvider = infoProvider; _repository = repository; _errorLogger = errorLogger; }
/// <summary> /// Processes the changed message /// </summary> /// <param name="client"> /// The connection to send replies to the server /// </param> /// <param name="collectionManager"> /// The CollectionManager /// </param> /// <param name="resultHandler"> /// The ResultHandler /// </param> /// <param name="message"> /// The message to process /// </param> /// <returns> /// Task to process the message /// </returns> public override Task HandleMessage( IDdpConnectionSender client, ICollectionManager collectionManager, IResultHandler resultHandler, string message) { var changedMessage = JsonConvert.DeserializeObject<Changed>(message); collectionManager.Changed(changedMessage); return Task.FromResult(true); }
/// <summary> /// Processes the ping message /// </summary> /// <param name="client"> /// The connection to send replies to the server /// </param> /// <param name="collectionManager"> /// The CollectionManager /// </param> /// <param name="resultHandler"> /// The ResultHandler /// </param> /// <param name="message"> /// The message to process /// </param> /// <returns> /// Task to process the message /// </returns> public override Task HandleMessage( IDdpConnectionSender client, ICollectionManager collectionManager, IResultHandler resultHandler, string message) { var pingMessage = JsonConvert.DeserializeObject<Ping>(message); var pongReply = new Pong() { Id = pingMessage.Id }; return client.SendObject(pongReply); }
public UserMailInfoChecker( IResultHandler<MailRepository.MailInfo> resultHandler, IUserInfo infoProvider, IMailRepository repository, IErrorLogger errorLogger) { _resultHandler = resultHandler; _repository = repository; _errorLogger = errorLogger; _infoProvider = infoProvider; }
public WrappedHandler(object handler) { DebugCheck.NotNull(handler); var handlerBase = handler as HandlerBase ?? new ForwardingProxy<HandlerBase>(handler).GetTransparentProxy(); _resultHandler = handler as IResultHandler ?? (handlerBase.ImplementsContract(typeof(IResultHandler).FullName) ? new ForwardingProxy<IResultHandler>(handler).GetTransparentProxy() : null); }
/// <summary> /// Processes the reply message /// </summary> /// <param name="client"> /// The connection to send replies to the server /// </param> /// <param name="collectionManager"> /// The CollectionManager /// </param> /// <param name="resultHandler"> /// The ResultHandler /// </param> /// <param name="message"> /// The message to process /// </param> /// <returns> /// Task to process the message /// </returns> public Task HandleMessage( IDdpConnectionSender client, ICollectionManager collectionManager, IResultHandler resultHandler, string message) { JObject parsedObject = JObject.Parse(message); var result = new ReturnedObject((string)parsedObject["msg"], parsedObject, message); resultHandler.AddResult(result); return Task.FromResult(true); }
/// <summary> /// Initializes a new instance of the <see cref="LeanEngineAlgorithmHandlers"/> class from the specified handlers /// </summary> /// <param name="results">The result handler for communicating results from the algorithm</param> /// <param name="setup">The setup handler used to initialize algorithm state</param> /// <param name="dataFeed">The data feed handler used to pump data to the algorithm</param> /// <param name="transactions">The transaction handler used to process orders from the algorithm</param> /// <param name="realTime">The real time handler used to process real time events</param> /// <param name="historyProvider">The history provider used to process historical data requests</param> /// <param name="commandQueue">The command queue handler used to receive external commands for the algorithm</param> /// <param name="mapFileProvider">The map file provider used to retrieve map files for the data feed</param> public LeanEngineAlgorithmHandlers(IResultHandler results, ISetupHandler setup, IDataFeed dataFeed, ITransactionHandler transactions, IRealTimeHandler realTime, IHistoryProvider historyProvider, ICommandQueueHandler commandQueue, IMapFileProvider mapFileProvider ) { if (results == null) { throw new ArgumentNullException("results"); } if (setup == null) { throw new ArgumentNullException("setup"); } if (dataFeed == null) { throw new ArgumentNullException("dataFeed"); } if (transactions == null) { throw new ArgumentNullException("transactions"); } if (realTime == null) { throw new ArgumentNullException("realTime"); } if (historyProvider == null) { throw new ArgumentNullException("realTime"); } if (commandQueue == null) { throw new ArgumentNullException("commandQueue"); } if (mapFileProvider == null) { throw new ArgumentNullException("mapFileProvider"); } _results = results; _setup = setup; _dataFeed = dataFeed; _transactions = transactions; _realTime = realTime; _historyProvider = historyProvider; _commandQueue = commandQueue; _mapFileProvider = mapFileProvider; }
/// <summary> /// Initializes the data feed for the specified job and algorithm /// </summary> public void Initialize(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IMapFileProvider mapFileProvider, IFactorFileProvider factorFileProvider) { _algorithm = algorithm; _resultHandler = resultHandler; _mapFileProvider = mapFileProvider; _factorFileProvider = factorFileProvider; _subscriptions = new ConcurrentDictionary<Symbol, Subscription>(); _universeSelection = new UniverseSelection(this, algorithm, job.Controls); _cancellationTokenSource = new CancellationTokenSource(); IsActive = true; var threadCount = Math.Max(1, Math.Min(4, Environment.ProcessorCount - 3)); _controller = new ParallelRunnerController(threadCount); _controller.Start(_cancellationTokenSource.Token); var ffres = Time.OneSecond; _fillForwardResolution = Ref.Create(() => ffres, res => ffres = res); // find the minimum resolution, ignoring ticks ffres = ResolveFillForwardResolution(algorithm); // wire ourselves up to receive notifications when universes are added/removed algorithm.UniverseManager.CollectionChanged += (sender, args) => { switch (args.Action) { case NotifyCollectionChangedAction.Add: foreach (var universe in args.NewItems.OfType<Universe>()) { var start = _frontierUtc != DateTime.MinValue ? _frontierUtc : _algorithm.StartDate.ConvertToUtc(_algorithm.TimeZone); AddUniverseSubscription(universe, start, _algorithm.EndDate.ConvertToUtc(_algorithm.TimeZone)); } break; case NotifyCollectionChangedAction.Remove: foreach (var universe in args.OldItems.OfType<Universe>()) { Subscription subscription; if (_subscriptions.TryGetValue(universe.Configuration.Symbol, out subscription)) { RemoveSubscription(subscription); } } break; default: throw new NotImplementedException("The specified action is not implemented: " + args.Action); } }; }
public void Run(string configuration, IResultHandler resultHandler) { Gate.Set(); var result = WaitHandle.WaitAny(new WaitHandle[] { Abort, LetRun }); switch(result) { case 0: return; case 1: resultHandler.OnSuccess(); break; }; }
/// <summary> /// Initializes a new instance of the <see cref="SubscriptionDataReaderSubscriptionEnumeratorFactory"/> class /// </summary> /// <param name="resultHandler">The result handler for the algorithm</param> /// <param name="mapFileResolver">The map file resolver</param> /// <param name="factorFileProvider">The factory file provider</param> /// <param name="isLiveMode">True if runnig live algorithm, false otherwise</param> /// <param name="includeAuxiliaryData">True to check for auxiliary data, false otherwise</param> /// <param name="tradableDaysProvider">Function used to provide the tradable dates to be enumerator. /// Specify null to default to <see cref="SubscriptionRequest.TradableDays"/></param> public SubscriptionDataReaderSubscriptionEnumeratorFactory(IResultHandler resultHandler, MapFileResolver mapFileResolver, IFactorFileProvider factorFileProvider, bool isLiveMode, bool includeAuxiliaryData, Func<SubscriptionRequest, IEnumerable<DateTime>> tradableDaysProvider = null ) { _resultHandler = resultHandler; _mapFileResolver = mapFileResolver; _factorFileProvider = factorFileProvider; _isLiveMode = isLiveMode; _includeAuxiliaryData = includeAuxiliaryData; _tradableDaysProvider = tradableDaysProvider ?? (request => request.TradableDays); }
/// <summary> /// Intializes the real time handler for the specified algorithm and job /// </summary> public void Setup(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IApi api) { //Initialize: _api = api; _algorithm = algorithm; _resultHandler = resultHandler; _cancellationTokenSource = new CancellationTokenSource(); var todayInAlgorithmTimeZone = DateTime.UtcNow.ConvertFromUtc(_algorithm.TimeZone).Date; // refresh the market hours for today explicitly, and then set up an event to refresh them each day at midnight RefreshMarketHoursToday(todayInAlgorithmTimeZone); // every day at midnight from tomorrow until the end of time var times = from date in Time.EachDay(todayInAlgorithmTimeZone.AddDays(1), Time.EndOfTime) select date.ConvertToUtc(_algorithm.TimeZone); Add(new ScheduledEvent("RefreshMarketHours", times, (name, triggerTime) => { // refresh market hours from api every day RefreshMarketHoursToday(triggerTime.ConvertFromUtc(_algorithm.TimeZone).Date); })); // add end of day events for each tradeable day Add(ScheduledEventFactory.EveryAlgorithmEndOfDay(_algorithm, _resultHandler, todayInAlgorithmTimeZone, Time.EndOfTime, ScheduledEvent.AlgorithmEndOfDayDelta, DateTime.UtcNow)); // add end of trading day events for each security foreach (var security in _algorithm.Securities.Values.Where(x => !x.SubscriptionDataConfig.IsInternalFeed)) { // assumes security.Exchange has been updated with today's hours via RefreshMarketHoursToday Add(ScheduledEventFactory.EverySecurityEndOfDay(_algorithm, _resultHandler, security, todayInAlgorithmTimeZone, Time.EndOfTime, ScheduledEvent.SecurityEndOfDayDelta, DateTime.UtcNow)); } foreach (var scheduledEvent in _scheduledEvents) { // zoom past old events scheduledEvent.Value.SkipEventsUntil(algorithm.UtcTime); // set logging accordingly scheduledEvent.Value.IsLoggingEnabled = Log.DebuggingEnabled; } }
/// <summary> /// Intializes the real time handler for the specified algorithm and job /// </summary> public void Initialize(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IApi api) { //Initialize: _api = api; _algorithm = algorithm; _resultHandler = resultHandler; _events = new ConcurrentDictionary<string, ScheduledEvent>(); _cancellationTokenSource = new CancellationTokenSource(); var todayInAlgorithmTimeZone = DateTime.UtcNow.ConvertFromUtc(_algorithm.TimeZone).Date; // refresh the market hours for today explicitly, and then set up an event to refresh them each day at midnight RefreshMarketHoursToday(todayInAlgorithmTimeZone); // every day at midnight from tomorrow until the end of time var times = from date in Time.EachDay(todayInAlgorithmTimeZone.AddDays(1), Time.EndOfTime) select date.ConvertToUtc(_algorithm.TimeZone); AddEvent(new ScheduledEvent("RefreshMarketHours", times, (name, triggerTime) => { // refresh market hours from api every day RefreshMarketHoursToday(triggerTime); })); // add end of day events for each tradeable day AddEvent(ScheduledEvent.EveryAlgorithmEndOfDay(_algorithm, _resultHandler, todayInAlgorithmTimeZone, Time.EndOfTime, ScheduledEvent.AlgorithmEndOfDayDelta, DateTime.UtcNow)); // add end of trading day events for each security foreach (var security in _algorithm.Securities.Values) { // assumes security.Exchange has been updated with today's hours via RefreshMarketHoursToday AddEvent(ScheduledEvent.EverySecurityEndOfDay(_algorithm, _resultHandler, security, todayInAlgorithmTimeZone, Time.EndOfTime, ScheduledEvent.SecurityEndOfDayDelta, DateTime.UtcNow)); } foreach (var scheduledEvent in _events.Values) { scheduledEvent.IsLoggingEnabled = true; } }
/// <summary> /// Intializes the real time handler for the specified algorithm and job /// </summary> public void Setup(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IApi api) { //Initialize: _algorithm = algorithm; _resultHandler = resultHandler; // create events for algorithm's end of tradeable dates Add(ScheduledEventFactory.EveryAlgorithmEndOfDay(_algorithm, _resultHandler, _algorithm.StartDate, _algorithm.EndDate, ScheduledEvent.AlgorithmEndOfDayDelta)); // set up the events for each security to fire every tradeable date before market close foreach (var security in _algorithm.Securities.Values.Where(x => !x.SubscriptionDataConfig.IsInternalFeed)) { Add(ScheduledEventFactory.EverySecurityEndOfDay(_algorithm, _resultHandler, security, algorithm.StartDate, _algorithm.EndDate, ScheduledEvent.SecurityEndOfDayDelta)); } foreach (var scheduledEvent in _scheduledEvents) { // zoom past old events scheduledEvent.Value.SkipEventsUntil(algorithm.UtcTime); // set logging accordingly scheduledEvent.Value.IsLoggingEnabled = Log.DebuggingEnabled; } }
/// <summary> /// Intializes the real time handler for the specified algorithm and job /// </summary> public void Initialize(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IApi api) { //Initialize: _algorithm = algorithm; _resultHandler = resultHandler; _scheduledEvents = new ConcurrentDictionary<string, ScheduledEvent>(); // create events for algorithm's end of tradeable dates AddEvent(ScheduledEvent.EveryAlgorithmEndOfDay(_algorithm, _resultHandler, _algorithm.StartDate, _algorithm.EndDate, ScheduledEvent.AlgorithmEndOfDayDelta)); // set up the events for each security to fire every tradeable date before market close foreach (var security in _algorithm.Securities.Values) { AddEvent(ScheduledEvent.EverySecurityEndOfDay(_algorithm, _resultHandler, security, algorithm.StartDate, _algorithm.EndDate, ScheduledEvent.SecurityEndOfDayDelta)); } if (Log.DebuggingEnabled) { foreach (var scheduledEvent in _scheduledEvents) { scheduledEvent.Value.IsLoggingEnabled = true; } } }
/// <summary> /// Post请求处理 /// </summary> /// <param name="resultHandler">返回的响应处理方法</param> /// <typeparam name="TR">接收的类型</typeparam> /// <typeparam name="T">转换类型</typeparam> /// <returns>转换后的结果类型</returns> public async Task <Result <T> > PostAsync <TR, T> (Dictionary <string, string> data, IResultHandler <TR, T> resultHandler, string url, string charset = null) { // 指定编码格式 data.Add(YunPianFields.ApiKey, _options.ApiKey); var encoding = Encoding.GetEncoding(charset ?? _options.Charset); // 对返回的结果进行处理 var response = resultHandler.Response(await(await _httpClient.PostAsync(url, new StringContent(UrlEncode(data, encoding), encoding, "application/x-www-form-urlencoded") )).Content.ReadAsStringAsync()); // 对发送成功/失败/异常的返回结果进行处理 try { return(resultHandler.Code == YunPianFields.Ok ? resultHandler.Success(response) : resultHandler.Fail(response)); } catch (Exception ex) { return(resultHandler.CatchException(ex)); } }
/// <summary> /// Initializes the data feed for the specified job and algorithm /// </summary> public void Initialize(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IMapFileProvider mapFileProvider, IFactorFileProvider factorFileProvider, IDataProvider dataProvider) { if (!(job is LiveNodePacket)) { throw new ArgumentException("The LiveTradingDataFeed requires a LiveNodePacket."); } _cancellationTokenSource = new CancellationTokenSource(); _algorithm = algorithm; _job = (LiveNodePacket)job; _resultHandler = resultHandler; _timeProvider = GetTimeProvider(); _dataQueueHandler = GetDataQueueHandler(); _dataProvider = dataProvider; _dataCacheProvider = new SingleEntryDataCacheProvider(dataProvider); _frontierTimeProvider = new ManualTimeProvider(_timeProvider.GetUtcNow()); _customExchange = new BaseDataExchange("CustomDataExchange") { SleepInterval = 10 }; // sleep is controlled on this exchange via the GetNextTicksEnumerator _exchange = new BaseDataExchange("DataQueueExchange") { SleepInterval = 0 }; _exchange.AddEnumerator(DataQueueHandlerSymbol, GetNextTicksEnumerator()); _subscriptions = new SubscriptionCollection(); _bridge = new BusyBlockingCollection <TimeSlice>(); _universeSelection = new UniverseSelection(this, algorithm); // run the exchanges Task.Run(() => _exchange.Start(_cancellationTokenSource.Token)); Task.Run(() => _customExchange.Start(_cancellationTokenSource.Token)); // this value will be modified via calls to AddSubscription/RemoveSubscription var ffres = Time.OneMinute; _fillForwardResolution = Ref.Create(() => ffres, v => ffres = v); // wire ourselves up to receive notifications when universes are added/removed var start = _timeProvider.GetUtcNow(); algorithm.UniverseManager.CollectionChanged += (sender, args) => { switch (args.Action) { case NotifyCollectionChangedAction.Add: foreach (var universe in args.NewItems.OfType <Universe>()) { var config = universe.Configuration; var marketHoursDatabase = MarketHoursDatabase.FromDataFolder(); var exchangeHours = marketHoursDatabase.GetExchangeHours(config); Security security; if (!_algorithm.Securities.TryGetValue(config.Symbol, out security)) { // create a canonical security object security = new Security(exchangeHours, config, _algorithm.Portfolio.CashBook[CashBook.AccountCurrency], SymbolProperties.GetDefault(CashBook.AccountCurrency)); } AddSubscription(new SubscriptionRequest(true, universe, security, config, start, Time.EndOfTime)); // Not sure if this is needed but left here because of this: // https://github.com/QuantConnect/Lean/commit/029d70bde6ca83a1eb0c667bb5cc4444bea05678 UpdateFillForwardResolution(); } break; case NotifyCollectionChangedAction.Remove: foreach (var universe in args.OldItems.OfType <Universe>()) { RemoveSubscription(universe.Configuration); } break; default: throw new NotImplementedException("The specified action is not implemented: " + args.Action); } }; }
/// <summary> /// Setup the algorithm cash, dates and portfolio as desired. /// </summary> /// <param name="algorithm">Existing algorithm instance</param> /// <param name="brokerage">New brokerage instance</param> /// <param name="baseJob">Backtesting job</param> /// <param name="resultHandler">The configured result handler</param> /// <param name="transactionHandler">The configuration transaction handler</param> /// <param name="realTimeHandler">The configured real time handler</param> /// <returns>Boolean true on successfully setting up the console.</returns> public bool Setup(IAlgorithm algorithm, IBrokerage brokerage, AlgorithmNodePacket baseJob, IResultHandler resultHandler, ITransactionHandler transactionHandler, IRealTimeHandler realTimeHandler) { var initializeComplete = false; try { //Set common variables for console programs: if (baseJob.Type == PacketType.BacktestNode) { var backtestJob = baseJob as BacktestNodePacket; algorithm.SetMaximumOrders(int.MaxValue); // set our parameters algorithm.SetParameters(baseJob.Parameters); algorithm.SetLiveMode(false); algorithm.SetAvailableDataTypes(GetConfiguredDataFeeds()); //Set the source impl for the event scheduling algorithm.Schedule.SetEventSchedule(realTimeHandler); // set the option chain provider algorithm.SetOptionChainProvider(new CachingOptionChainProvider(new BacktestingOptionChainProvider())); // set the future chain provider algorithm.SetFutureChainProvider(new CachingFutureChainProvider(new BacktestingFutureChainProvider())); //Setup Base Algorithm: algorithm.Initialize(); //Set the time frontier of the algorithm algorithm.SetDateTime(algorithm.StartDate.ConvertToUtc(algorithm.TimeZone)); //Construct the backtest job packet: backtestJob.PeriodStart = algorithm.StartDate; backtestJob.PeriodFinish = algorithm.EndDate; backtestJob.BacktestId = algorithm.GetType().Name; backtestJob.Type = PacketType.BacktestNode; backtestJob.UserId = baseJob.UserId; backtestJob.Channel = baseJob.Channel; //Backtest Specific Parameters: StartingDate = backtestJob.PeriodStart; StartingPortfolioValue = algorithm.Portfolio.Cash; } else { throw new Exception("The ConsoleSetupHandler is for backtests only. Use the BrokerageSetupHandler."); } } catch (Exception err) { Log.Error(err); Errors.Add("Failed to initialize algorithm: Initialize(): " + err); } if (Errors.Count == 0) { initializeComplete = true; } algorithm.PostInitialize(); return(initializeComplete); }
/// <summary> /// Initializes the data feed for the specified job and algorithm /// </summary> public void Initialize(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IMapFileProvider mapFileProvider, IFactorFileProvider factorFileProvider, IDataProvider dataProvider, IDataFeedSubscriptionManager subscriptionManager) { if (!(job is LiveNodePacket)) { throw new ArgumentException("The LiveTradingDataFeed requires a LiveNodePacket."); } _cancellationTokenSource = new CancellationTokenSource(); _algorithm = algorithm; _job = (LiveNodePacket)job; _resultHandler = resultHandler; _timeProvider = GetTimeProvider(); _dataQueueHandler = GetDataQueueHandler(); _dataProvider = dataProvider; _dataCacheProvider = new SingleEntryDataCacheProvider(dataProvider); _frontierTimeProvider = new ManualTimeProvider(_timeProvider.GetUtcNow()); _customExchange = new BaseDataExchange("CustomDataExchange") { SleepInterval = 10 }; // sleep is controlled on this exchange via the GetNextTicksEnumerator _exchange = new BaseDataExchange("DataQueueExchange") { SleepInterval = 0 }; _exchange.AddEnumerator(DataQueueHandlerSymbol, GetNextTicksEnumerator()); _subscriptions = subscriptionManager.DataFeedSubscriptions; _universeSelection = subscriptionManager.UniverseSelection; // run the exchanges Task.Run(() => _exchange.Start(_cancellationTokenSource.Token)); Task.Run(() => _customExchange.Start(_cancellationTokenSource.Token)); IsActive = true; // wire ourselves up to receive notifications when universes are added/removed var start = _timeProvider.GetUtcNow(); algorithm.UniverseManager.CollectionChanged += (sender, args) => { switch (args.Action) { case NotifyCollectionChangedAction.Add: foreach (var universe in args.NewItems.OfType <Universe>()) { var config = universe.Configuration; var marketHoursDatabase = MarketHoursDatabase.FromDataFolder(); var exchangeHours = marketHoursDatabase.GetExchangeHours(config); Security security; if (!_algorithm.Securities.TryGetValue(config.Symbol, out security)) { // create a canonical security object security = new Security( exchangeHours, config, _algorithm.Portfolio.CashBook[CashBook.AccountCurrency], SymbolProperties.GetDefault(CashBook.AccountCurrency), _algorithm.Portfolio.CashBook ); } AddSubscription(new SubscriptionRequest(true, universe, security, config, start, Time.EndOfTime)); } break; case NotifyCollectionChangedAction.Remove: foreach (var universe in args.OldItems.OfType <Universe>()) { RemoveSubscription(universe.Configuration); } break; default: throw new NotImplementedException("The specified action is not implemented: " + args.Action); } }; }
public void Setup(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IApi api, IIsolatorLimitResultProvider isolatorLimitProvider) { }
/// <summary> /// Setup the algorithm cash, dates and data subscriptions as desired. /// </summary> /// <param name="algorithm">Algorithm instance</param> /// <param name="brokerage">Brokerage instance</param> /// <param name="baseJob">Algorithm job</param> /// <param name="resultHandler">The configured result handler</param> /// <param name="transactionHandler">The configurated transaction handler</param> /// <param name="realTimeHandler">The configured real time handler</param> /// <returns>Boolean true on successfully initializing the algorithm</returns> public bool Setup(IAlgorithm algorithm, out IBrokerage brokerage, AlgorithmNodePacket baseJob, IResultHandler resultHandler, ITransactionHandler transactionHandler, IRealTimeHandler realTimeHandler) { var job = baseJob as BacktestNodePacket; if (job == null) { throw new ArgumentException("Expected BacktestNodePacket but received " + baseJob.GetType().Name); } Log.Trace(string.Format("BacktestingSetupHandler.Setup(): Setting up job: Plan: {0}, UID: {1}, PID: {2}, Version: {3}, Source: {4}", job.UserPlan, job.UserId, job.ProjectId, job.Version, job.RequestSource)); brokerage = null; if (algorithm == null) { Errors.Add("Could not create instance of algorithm"); return(false); } //Make sure the algorithm start date ok. if (job.PeriodStart == default(DateTime)) { Errors.Add("Algorithm start date was never set"); return(false); } var isolator = new Isolator(); var initializeComplete = isolator.ExecuteWithTimeLimit(TimeSpan.FromMinutes(5), () => { try { //Algorithm is backtesting, not live: algorithm.SetLiveMode(false); //Set the backtest level asset ram allocation limits algorithm.SetAssetLimits(500, 100, 30); //Set the algorithm time before we even initialize: algorithm.SetDateTime(job.PeriodStart.ConvertToUtc(algorithm.TimeZone)); //Set the source impl for the event scheduling algorithm.Schedule.SetEventSchedule(realTimeHandler); //Initialise the algorithm, get the required data: algorithm.Initialize(); //Add currency data feeds that weren't explicity added in Initialize algorithm.Portfolio.CashBook.EnsureCurrencyDataFeeds(algorithm.Securities, algorithm.SubscriptionManager, SecurityExchangeHoursProvider.FromDataFolder()); } catch (Exception err) { Errors.Add("Failed to initialize algorithm: Initialize(): " + err.Message); } }); //Before continuing, detect if this is ready: if (!initializeComplete) { return(false); } // this needs to be done after algorithm initialization brokerage = new BacktestingBrokerage(algorithm); // set the transaction and settlement models based on the brokerage properties SetupHandler.UpdateModels(algorithm, algorithm.BrokerageModel); algorithm.Transactions.SetOrderProcessor(transactionHandler); algorithm.PostInitialize(); //Calculate the max runtime for the strategy _maxRuntime = GetMaximumRuntime(job.PeriodStart, job.PeriodFinish, algorithm.SubscriptionManager.Count); //Get starting capital: _startingCaptial = algorithm.Portfolio.Cash; //Max Orders: 10k per backtest: if (job.UserPlan == UserPlan.Free) { _maxOrders = 10000; } else { _maxOrders = int.MaxValue; _maxRuntime += _maxRuntime; } //Set back to the algorithm, algorithm.SetMaximumOrders(_maxOrders); //Starting date of the algorithm: _startingDate = job.PeriodStart; //Put into log for debugging: Log.Trace("SetUp Backtesting: User: "******" ProjectId: " + job.ProjectId + " AlgoId: " + job.AlgorithmId); Log.Trace("Dates: Start: " + job.PeriodStart.ToShortDateString() + " End: " + job.PeriodFinish.ToShortDateString() + " Cash: " + _startingCaptial.ToString("C")); if (Errors.Count > 0) { initializeComplete = false; } return(initializeComplete); }
public void Setup(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IApi api) { }
public void Initialize(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler) { _cancellationTokenSource = new CancellationTokenSource(); Subscriptions = algorithm.SubscriptionManager.Subscriptions; _subscriptions = Subscriptions.Count; //Public Properties: IsActive = true; _endOfBridge = new bool[_subscriptions]; SubscriptionReaders = new IEnumerator <BaseData> [_subscriptions]; FillForwardFrontiers = new DateTime[_subscriptions]; RealtimePrices = new List <decimal>(_subscriptions); //Class Privates: _algorithm = algorithm; // find the minimum resolution, ignoring ticks var fillForwardResolution = Subscriptions .Where(x => x.Resolution != Resolution.Tick) .Select(x => x.Resolution.ToTimeSpan()) .DefaultIfEmpty(TimeSpan.FromSeconds(1)) .Min(); // figure out how many subscriptions are at the minimum resolution var subscriptionsAtMinimumResolution = (from sub in Subscriptions where sub.Resolution == Subscriptions.Min(x => x.Resolution) select sub).Count(); Bridge = new BlockingCollection <TimeSlice>(Math.Min(1000, 50000 / subscriptionsAtMinimumResolution)); for (var i = 0; i < _subscriptions; i++) { _endOfBridge[i] = false; var config = Subscriptions[i]; var start = algorithm.StartDate; var end = algorithm.EndDate; var security = _algorithm.Securities[Subscriptions[i].Symbol]; var tradeableDates = Time.EachTradeableDay(security, start.Date, end.Date); IEnumerator <BaseData> enumerator = new SubscriptionDataReader(config, security, DataFeedEndpoint.FileSystem, start, end, resultHandler, tradeableDates); // optionally apply fill forward logic, but never for tick data if (config.FillDataForward && config.Resolution != Resolution.Tick) { enumerator = new FillForwardEnumerator(enumerator, security.Exchange, fillForwardResolution, security.IsExtendedMarketHours, end, config.Resolution.ToTimeSpan()); } // finally apply exchange/user filters SubscriptionReaders[i] = SubscriptionFilterEnumerator.WrapForDataFeed(resultHandler, enumerator, security, end); FillForwardFrontiers[i] = new DateTime(); // prime the pump for iteration in Run _endOfBridge[i] = !SubscriptionReaders[i].MoveNext(); if (_endOfBridge[i]) { Log.Trace("FileSystemDataFeed.Run(): Failed to load subscription: " + Subscriptions[i].Symbol); } } }
/// <summary> /// Launch the algorithm manager to run this strategy /// </summary> /// <param name="job">Algorithm job</param> /// <param name="algorithm">Algorithm instance</param> /// <param name="feed">Datafeed object</param> /// <param name="transactions">Transaction manager object</param> /// <param name="results">Result handler object</param> /// <param name="realtime">Realtime processing object</param> /// <param name="token">Cancellation token</param> /// <remarks>Modify with caution</remarks> public void Run(AlgorithmNodePacket job, IAlgorithm algorithm, IDataFeed feed, ITransactionHandler transactions, IResultHandler results, IRealTimeHandler realtime, CancellationToken token) { //Initialize: _dataPointCount = 0; var startingPortfolioValue = algorithm.Portfolio.TotalPortfolioValue; var backtestMode = (job.Type == PacketType.BacktestNode); var methodInvokers = new Dictionary <Type, MethodInvoker>(); var marginCallFrequency = TimeSpan.FromMinutes(5); var nextMarginCallTime = DateTime.MinValue; var delistingTickets = new List <OrderTicket>(); //Initialize Properties: _algorithmId = job.AlgorithmId; _algorithmState = AlgorithmStatus.Running; _previousTime = algorithm.StartDate.Date; //Create the method accessors to push generic types into algorithm: Find all OnData events: // Algorithm 2.0 data accessors var hasOnDataTradeBars = AddMethodInvoker <TradeBars>(algorithm, methodInvokers); var hasOnDataTicks = AddMethodInvoker <Ticks>(algorithm, methodInvokers); // dividend and split events var hasOnDataDividends = AddMethodInvoker <Dividends>(algorithm, methodInvokers); var hasOnDataSplits = AddMethodInvoker <Splits>(algorithm, methodInvokers); var hasOnDataDelistings = AddMethodInvoker <Delistings>(algorithm, methodInvokers); // Algorithm 3.0 data accessors var hasOnDataSlice = algorithm.GetType().GetMethods() .Where(x => x.Name == "OnData" && x.GetParameters().Length == 1 && x.GetParameters()[0].ParameterType == typeof(Slice)) .FirstOrDefault(x => x.DeclaringType == algorithm.GetType()) != null; //Go through the subscription types and create invokers to trigger the event handlers for each custom type: foreach (var config in feed.Subscriptions) { //If type is a tradebar, combine tradebars and ticks into unified array: if (config.Type.Name != "TradeBar" && config.Type.Name != "Tick") { //Get the matching method for this event handler - e.g. public void OnData(Quandl data) { .. } var genericMethod = (algorithm.GetType()).GetMethod("OnData", new[] { config.Type }); //If we already have this Type-handler then don't add it to invokers again. if (methodInvokers.ContainsKey(config.Type)) { continue; } //If we couldnt find the event handler, let the user know we can't fire that event. if (genericMethod == null && !hasOnDataSlice) { algorithm.RunTimeError = new Exception("Data event handler not found, please create a function matching this template: public void OnData(" + config.Type.Name + " data) { }"); _algorithmState = AlgorithmStatus.RuntimeError; return; } if (genericMethod != null) { methodInvokers.Add(config.Type, genericMethod.DelegateForCallMethod()); } } } //Loop over the queues: get a data collection, then pass them all into relevent methods in the algorithm. Log.Trace("AlgorithmManager.Run(): Begin DataStream - Start: " + algorithm.StartDate + " Stop: " + algorithm.EndDate); foreach (var timeSlice in feed.Bridge.GetConsumingEnumerable(token)) { // reset our timer on each loop _currentTimeStepTime = DateTime.UtcNow; //Check this backtest is still running: if (_algorithmState != AlgorithmStatus.Running) { Log.Error(string.Format("AlgorithmManager.Run(): Algorthm state changed to {0} at {1}", _algorithmState, timeSlice.Time)); break; } //Execute with TimeLimit Monitor: if (token.IsCancellationRequested) { Log.Error("AlgorithmManager.Run(): CancellationRequestion at " + timeSlice.Time); return; } var time = timeSlice.Time; var newData = timeSlice.Data; //If we're in backtest mode we need to capture the daily performance. We do this here directly //before updating the algorithm state with the new data from this time step, otherwise we'll //produce incorrect samples (they'll take into account this time step's new price values) if (backtestMode) { //On day-change sample equity and daily performance for statistics calculations if (_previousTime.Date != time.Date) { //Sample the portfolio value over time for chart. results.SampleEquity(_previousTime, Math.Round(algorithm.Portfolio.TotalPortfolioValue, 4)); //Check for divide by zero if (startingPortfolioValue == 0m) { results.SamplePerformance(_previousTime.Date, 0); } else { results.SamplePerformance(_previousTime.Date, Math.Round((algorithm.Portfolio.TotalPortfolioValue - startingPortfolioValue) * 100 / startingPortfolioValue, 10)); } startingPortfolioValue = algorithm.Portfolio.TotalPortfolioValue; } } //Update algorithm state after capturing performance from previous day //Set the algorithm and real time handler's time algorithm.SetDateTime(time); realtime.SetTime(algorithm.Time); //On each time step push the real time prices to the cashbook so we can have updated conversion rates algorithm.Portfolio.CashBook.Update(newData); //Update the securities properties: first before calling user code to avoid issues with data algorithm.Securities.Update(time, newData); // process fill models on the updated data before entering algorithm, applies to all non-market orders transactions.ProcessSynchronousEvents(); if (delistingTickets.Count != 0) { for (int i = 0; i < delistingTickets.Count; i++) { var ticket = delistingTickets[i]; if (ticket.Status == OrderStatus.Filled) { algorithm.Securities.Remove(ticket.Symbol); delistingTickets.RemoveAt(i--); Log.Trace("AlgorithmManager.Run(): Security removed: " + ticket.Symbol); } } } //Check if the user's signalled Quit: loop over data until day changes. if (algorithm.GetQuit()) { _algorithmState = AlgorithmStatus.Quit; Log.Trace("AlgorithmManager.Run(): Algorithm quit requested."); break; } if (algorithm.RunTimeError != null) { _algorithmState = AlgorithmStatus.RuntimeError; Log.Trace(string.Format("AlgorithmManager.Run(): Algorithm encountered a runtime error at {0}. Error: {1}", timeSlice.Time, algorithm.RunTimeError)); break; } // perform margin calls, in live mode we can also use realtime to emit these if (time >= nextMarginCallTime || (_liveMode && nextMarginCallTime > DateTime.Now)) { // determine if there are possible margin call orders to be executed bool issueMarginCallWarning; var marginCallOrders = algorithm.Portfolio.ScanForMarginCall(out issueMarginCallWarning); if (marginCallOrders.Count != 0) { try { // tell the algorithm we're about to issue the margin call algorithm.OnMarginCall(marginCallOrders); } catch (Exception err) { algorithm.RunTimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: OnMarginCall: " + err.Message + " STACK >>> " + err.StackTrace); return; } // execute the margin call orders var executedTickets = algorithm.Portfolio.MarginCallModel.ExecuteMarginCall(marginCallOrders); foreach (var ticket in executedTickets) { algorithm.Error(string.Format("{0} - Executed MarginCallOrder: {1} - Quantity: {2} @ {3}", algorithm.Time, ticket.Symbol, ticket.Quantity, ticket.OrderEvents.Last().FillPrice)); } } // we didn't perform a margin call, but got the warning flag back, so issue the warning to the algorithm else if (issueMarginCallWarning) { try { algorithm.OnMarginCallWarning(); } catch (Exception err) { algorithm.RunTimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: OnMarginCallWarning: " + err.Message + " STACK >>> " + err.StackTrace); } } nextMarginCallTime = time + marginCallFrequency; } //Trigger the data events: Invoke the types we have data for: var newBars = new TradeBars(algorithm.Time); var newTicks = new Ticks(algorithm.Time); var newDividends = new Dividends(algorithm.Time); var newSplits = new Splits(algorithm.Time); var newDelistings = new Delistings(algorithm.Time); //Invoke all non-tradebars, non-ticks methods and build up the TradeBars and Ticks dictionaries // --> i == Subscription Configuration Index, so we don't need to compare types. foreach (var i in newData.Keys) { //Data point and config of this point: var dataPoints = newData[i]; var config = feed.Subscriptions[i]; //Keep track of how many data points we've processed _dataPointCount += dataPoints.Count; //We don't want to pump data that we added just for currency conversions if (config.IsInternalFeed) { continue; } //Create TradeBars Unified Data --> OR --> invoke generic data event. One loop. // Aggregate Dividends and Splits -- invoke portfolio application methods foreach (var dataPoint in dataPoints) { var dividend = dataPoint as Dividend; if (dividend != null) { Log.Trace("AlgorithmManager.Run(): Applying Dividend for " + dividend.Symbol); // if this is a dividend apply to portfolio algorithm.Portfolio.ApplyDividend(dividend); if (hasOnDataDividends) { // and add to our data dictionary to pump into OnData(Dividends data) newDividends.Add(dividend); } continue; } var split = dataPoint as Split; if (split != null) { Log.Trace("AlgorithmManager.Run(): Applying Split for " + split.Symbol); // if this is a split apply to portfolio algorithm.Portfolio.ApplySplit(split); if (hasOnDataSplits) { // and add to our data dictionary to pump into OnData(Splits data) newSplits.Add(split); } continue; } var delisting = dataPoint as Delisting; if (delisting != null) { if (hasOnDataDelistings) { // add to out data dictonary to pump into OnData(Delistings data) newDelistings.Add(delisting); } } //Update registered consolidators for this symbol index try { for (var j = 0; j < config.Consolidators.Count; j++) { config.Consolidators[j].Update(dataPoint); } } catch (Exception err) { algorithm.RunTimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: Consolidators update: " + err.Message); return; } // TRADEBAR -- add to our dictionary if (dataPoint.DataType == MarketDataType.TradeBar) { var bar = dataPoint as TradeBar; if (bar != null) { newBars[bar.Symbol] = bar; continue; } } // TICK -- add to our dictionary if (dataPoint.DataType == MarketDataType.Tick) { var tick = dataPoint as Tick; if (tick != null) { List <Tick> ticks; if (!newTicks.TryGetValue(tick.Symbol, out ticks)) { ticks = new List <Tick>(3); newTicks.Add(tick.Symbol, ticks); } ticks.Add(tick); continue; } } // if it was nothing else then it must be custom data // CUSTOM DATA -- invoke on data method //Send data into the generic algorithm event handlers try { MethodInvoker methodInvoker; if (methodInvokers.TryGetValue(config.Type, out methodInvoker)) { methodInvoker(algorithm, dataPoint); } } catch (Exception err) { algorithm.RunTimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: Custom Data: " + err.Message + " STACK >>> " + err.StackTrace); return; } } } try { // fire off the dividend and split events before pricing events if (hasOnDataDividends && newDividends.Count != 0) { methodInvokers[typeof(Dividends)](algorithm, newDividends); } if (hasOnDataSplits && newSplits.Count != 0) { methodInvokers[typeof(Splits)](algorithm, newSplits); } if (hasOnDataDelistings && newDelistings.Count != 0) { methodInvokers[typeof(Delistings)](algorithm, newDelistings); } } catch (Exception err) { algorithm.RunTimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: Dividends/Splits/Delistings: " + err.Message + " STACK >>> " + err.StackTrace); return; } // run the delisting logic after firing delisting events HandleDelistedSymbols(algorithm, newDelistings, delistingTickets); //After we've fired all other events in this second, fire the pricing events: try { if (hasOnDataTradeBars && newBars.Count > 0) { methodInvokers[typeof(TradeBars)](algorithm, newBars); } if (hasOnDataTicks && newTicks.Count > 0) { methodInvokers[typeof(Ticks)](algorithm, newTicks); } } catch (Exception err) { algorithm.RunTimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: New Style Mode: " + err.Message + " STACK >>> " + err.StackTrace); return; } // EVENT HANDLER v3.0 -- all data in a single event var slice = new Slice(algorithm.Time, newData.Values.SelectMany(x => x), newBars.Count == 0 ? null : newBars, newTicks.Count == 0 ? null : newTicks, newSplits.Count == 0 ? null : newSplits, newDividends.Count == 0 ? null : newDividends, newDelistings.Count == 0 ? null : newDelistings ); try { algorithm.OnData(slice); } catch (Exception err) { algorithm.RunTimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: Slice: " + err.Message + " STACK >>> " + err.StackTrace); return; } //If its the historical/paper trading models, wait until market orders have been "filled" // Manually trigger the event handler to prevent thread switch. transactions.ProcessSynchronousEvents(); //Save the previous time for the sample calculations _previousTime = time; // Process any required events of the results handler such as sampling assets, equity, or stock prices. results.ProcessSynchronousEvents(); } // End of ForEach feed.Bridge.GetConsumingEnumerable // stop timing the loops _currentTimeStepTime = DateTime.MinValue; //Stream over:: Send the final packet and fire final events: Log.Trace("AlgorithmManager.Run(): Firing On End Of Algorithm..."); try { algorithm.OnEndOfAlgorithm(); } catch (Exception err) { _algorithmState = AlgorithmStatus.RuntimeError; algorithm.RunTimeError = new Exception("Error running OnEndOfAlgorithm(): " + err.Message, err.InnerException); Log.Error("AlgorithmManager.OnEndOfAlgorithm(): " + err.Message + " STACK >>> " + err.StackTrace); return; } // Process any required events of the results handler such as sampling assets, equity, or stock prices. results.ProcessSynchronousEvents(forceProcess: true); //Liquidate Holdings for Calculations: if (_algorithmState == AlgorithmStatus.Liquidated && _liveMode) { Log.Trace("AlgorithmManager.Run(): Liquidating algorithm holdings..."); algorithm.Liquidate(); results.LogMessage("Algorithm Liquidated"); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Liquidated); } //Manually stopped the algorithm if (_algorithmState == AlgorithmStatus.Stopped) { Log.Trace("AlgorithmManager.Run(): Stopping algorithm..."); results.LogMessage("Algorithm Stopped"); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Stopped); } //Backtest deleted. if (_algorithmState == AlgorithmStatus.Deleted) { Log.Trace("AlgorithmManager.Run(): Deleting algorithm..."); results.DebugMessage("Algorithm Id:(" + job.AlgorithmId + ") Deleted by request."); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Deleted); } //Algorithm finished, send regardless of commands: results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Completed); //Take final samples: results.SampleRange(algorithm.GetChartUpdates()); results.SampleEquity(_previousTime, Math.Round(algorithm.Portfolio.TotalPortfolioValue, 4)); results.SamplePerformance(_previousTime, Math.Round((algorithm.Portfolio.TotalPortfolioValue - startingPortfolioValue) * 100 / startingPortfolioValue, 10)); } // End of Run();
/// <summary> /// Error handlers in event of a brokerage error. /// </summary> /// <param name="results">Result handler for sending results on error.</param> /// <param name="brokerage">Brokerage instance</param> /// <remarks>Not used for local setup.</remarks> /// <returns>Boolean true on successfully setting up local algorithm</returns> public bool SetupErrorHandler(IResultHandler results, IBrokerage brokerage) { return(true); }
/******************************************************** * CLASS METHODS *********************************************************/ /// <summary> /// Primary Analysis Thread: /// </summary> public static void Main(string[] args) { //Initialize: var algorithmPath = ""; string mode = "RELEASE"; AlgorithmNodePacket job = null; var algorithm = default(IAlgorithm); var startTime = DateTime.Now; Log.LogHandler = Composer.Instance.GetExportedValueByTypeName <ILogHandler>(Config.Get("log-handler", "CompositeLogHandler")); _version = DateTime.ParseExact(Config.Get("version", DateTime.Now.ToString(DateFormat.UI)), DateFormat.UI, CultureInfo.InvariantCulture); #if DEBUG mode = "DEBUG"; #endif //Name thread for the profiler: Thread.CurrentThread.Name = "Algorithm Analysis Thread"; Log.Trace("Engine.Main(): LEAN ALGORITHMIC TRADING ENGINE v" + _version + " Mode: " + mode); Log.Trace("Engine.Main(): Started " + DateTime.Now.ToShortTimeString()); Log.Trace("Engine.Main(): Memory " + OS.ApplicationMemoryUsed + "Mb-App " + +OS.TotalPhysicalMemoryUsed + "Mb-Used " + OS.TotalPhysicalMemory + "Mb-Total"); //Import external libraries specific to physical server location (cloud/local) try { // grab the right export based on configuration Api = Composer.Instance.GetExportedValueByTypeName <IApi>(Config.Get("api-handler")); Notify = Composer.Instance.GetExportedValueByTypeName <IMessagingHandler>(Config.Get("messaging-handler")); JobQueue = Composer.Instance.GetExportedValueByTypeName <IJobQueueHandler>(Config.Get("job-queue-handler")); } catch (CompositionException compositionException) { Log.Error("Engine.Main(): Failed to load library: " + compositionException); } //Setup packeting, queue and controls system: These don't do much locally. Api.Initialize(); Notify.Initialize(); JobQueue.Initialize(); //Start monitoring the backtest active status: var statusPingThread = new Thread(StateCheck.Ping.Run); statusPingThread.Start(); do { try { //Reset algo manager internal variables preparing for a new algorithm. AlgorithmManager.ResetManager(); //Reset thread holders. var initializeComplete = false; Thread threadFeed = null; Thread threadTransactions = null; Thread threadResults = null; Thread threadRealTime = null; do { //-> Pull job from QuantConnect job queue, or, pull local build: job = JobQueue.NextJob(out algorithmPath); // Blocking. if (!IsLocal && LiveMode && (job.Version < Version || (job.Version == Version && job.Redelivered))) { //Tiny chance there was an uncontrolled collapse of a server, resulting in an old user task circulating. //In this event kill the old algorithm and leave a message so the user can later review. JobQueue.AcknowledgeJob(job); Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmStatus.RuntimeError, _collapseMessage); Notify.SetChannel(job.Channel); Notify.RuntimeError(job.AlgorithmId, _collapseMessage); job = null; } } while (job == null); //-> Initialize messaging system Notify.SetChannel(job.Channel); //-> Create SetupHandler to configure internal algorithm state: SetupHandler = GetSetupHandler(job.SetupEndpoint); //-> Set the result handler type for this algorithm job, and launch the associated result thread. ResultHandler = GetResultHandler(job); threadResults = new Thread(ResultHandler.Run, 0) { Name = "Result Thread" }; threadResults.Start(); try { // Save algorithm to cache, load algorithm instance: algorithm = SetupHandler.CreateAlgorithmInstance(algorithmPath); //Initialize the internal state of algorithm and job: executes the algorithm.Initialize() method. initializeComplete = SetupHandler.Setup(algorithm, out _brokerage, job); //If there are any reasons it failed, pass these back to the IDE. if (!initializeComplete || algorithm.ErrorMessages.Count > 0 || SetupHandler.Errors.Count > 0) { initializeComplete = false; //Get all the error messages: internal in algorithm and external in setup handler. var errorMessage = String.Join(",", algorithm.ErrorMessages); errorMessage += String.Join(",", SetupHandler.Errors); throw new Exception(errorMessage); } } catch (Exception err) { var runtimeMessage = "Algorithm.Initialize() Error: " + err.Message + " Stack Trace: " + err.StackTrace; ResultHandler.RuntimeError(runtimeMessage, err.StackTrace); Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmStatus.RuntimeError, runtimeMessage); } //-> Using the job + initialization: load the designated handlers: if (initializeComplete) { //-> Reset the backtest stopwatch; we're now running the algorithm. startTime = DateTime.Now; //Set algorithm as locked; set it to live mode if we're trading live, and set it to locked for no further updates. algorithm.SetAlgorithmId(job.AlgorithmId); algorithm.SetLiveMode(LiveMode); algorithm.SetLocked(); //Load the associated handlers for data, transaction and realtime events: ResultHandler.SetAlgorithm(algorithm); DataFeed = GetDataFeedHandler(algorithm, job); TransactionHandler = GetTransactionHandler(algorithm, _brokerage, ResultHandler, job); RealTimeHandler = GetRealTimeHandler(algorithm, _brokerage, DataFeed, ResultHandler, job); //Set the error handlers for the brokerage asynchronous errors. SetupHandler.SetupErrorHandler(ResultHandler, _brokerage); //Send status to user the algorithm is now executing. ResultHandler.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Running); //Launch the data, transaction and realtime handlers into dedicated threads threadFeed = new Thread(DataFeed.Run, 0) { Name = "DataFeed Thread" }; threadTransactions = new Thread(TransactionHandler.Run, 0) { Name = "Transaction Thread" }; threadRealTime = new Thread(RealTimeHandler.Run, 0) { Name = "RealTime Thread" }; //Launch the data feed, result sending, and transaction models/handlers in separate threads. threadFeed.Start(); // Data feed pushing data packets into thread bridge; threadTransactions.Start(); // Transaction modeller scanning new order requests threadRealTime.Start(); // RealTime scan time for time based events: // Result manager scanning message queue: (started earlier) try { // Execute the Algorithm Code: var complete = Isolator.ExecuteWithTimeLimit(SetupHandler.MaximumRuntime, () => { try { //Run Algorithm Job: // -> Using this Data Feed, // -> Send Orders to this TransactionHandler, // -> Send Results to ResultHandler. AlgorithmManager.Run(job, algorithm, DataFeed, TransactionHandler, ResultHandler, SetupHandler, RealTimeHandler); } catch (Exception err) { //Debugging at this level is difficult, stack trace needed. Log.Error("Engine.Run(): Error in Algo Manager: " + err.Message + " ST >> " + err.StackTrace); } Log.Trace("Engine.Run(): Exiting Algorithm Manager"); }, MaximumRamAllocation); if (!complete) { Log.Error("Engine.Main(): Failed to complete in time: " + SetupHandler.MaximumRuntime.ToString("F")); throw new Exception("Failed to complete algorithm within " + SetupHandler.MaximumRuntime.ToString("F") + " seconds. Please make it run faster."); } // Algorithm runtime error: if (algorithm.RunTimeError != null) { throw algorithm.RunTimeError; } } catch (Exception err) { //Error running the user algorithm: purge datafeed, send error messages, set algorithm status to failed. Log.Error("Engine.Run(): Breaking out of parent try-catch: " + err.Message + " " + err.StackTrace); if (DataFeed != null) { DataFeed.Exit(); } if (ResultHandler != null) { var message = "Runtime Error: " + err.Message; Log.Trace("Engine.Run(): Sending runtime error to user..."); ResultHandler.LogMessage(message); ResultHandler.RuntimeError(message, err.StackTrace); Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmStatus.RuntimeError, message + " Stack Trace: " + err.StackTrace); } } //Send result data back: this entire code block could be rewritten. // todo: - Split up statistics class, its enormous. // todo: - Make a dedicated Statistics.Benchmark class. // todo: - Move all creation and transmission of statistics out of primary engine loop. // todo: - Statistics.Generate(algorithm, resulthandler, transactionhandler); try { var charts = new Dictionary <string, Chart>(ResultHandler.Charts); var orders = new Dictionary <int, Order>(algorithm.Transactions.Orders); var holdings = new Dictionary <string, Holding>(); var statistics = new Dictionary <string, string>(); var banner = new Dictionary <string, string>(); try { //Generates error when things don't exist (no charting logged, runtime errors in main algo execution) const string strategyEquityKey = "Strategy Equity"; const string equityKey = "Equity"; const string dailyPerformanceKey = "Daily Performance"; // make sure we've taken samples for these series before just blindly requesting them if (charts.ContainsKey(strategyEquityKey) && charts[strategyEquityKey].Series.ContainsKey(equityKey) && charts[strategyEquityKey].Series.ContainsKey(dailyPerformanceKey)) { var equity = charts[strategyEquityKey].Series[equityKey].Values; var performance = charts[strategyEquityKey].Series[dailyPerformanceKey].Values; var profitLoss = new SortedDictionary <DateTime, decimal>(algorithm.Transactions.TransactionRecord); statistics = Statistics.Statistics.Generate(equity, profitLoss, performance, SetupHandler.StartingCapital, 252); } } catch (Exception err) { Log.Error("Algorithm.Node.Engine(): Error generating statistics packet: " + err.Message); } //Diagnostics Completed, Send Result Packet: var totalSeconds = (DateTime.Now - startTime).TotalSeconds; ResultHandler.DebugMessage(string.Format("Algorithm Id:({0}) completed in {1} seconds at {2}k data points per second. Processing total of {3} data points.", job.AlgorithmId, totalSeconds.ToString("F2"), ((AlgorithmManager.DataPoints / (double)1000) / totalSeconds).ToString("F0"), AlgorithmManager.DataPoints.ToString("N0"))); ResultHandler.SendFinalResult(job, orders, algorithm.Transactions.TransactionRecord, holdings, statistics, banner); } catch (Exception err) { Log.Error("Engine.Main(): Error sending analysis result: " + err.Message + " ST >> " + err.StackTrace); } //Before we return, send terminate commands to close up the threads TransactionHandler.Exit(); DataFeed.Exit(); RealTimeHandler.Exit(); } //Close result handler: ResultHandler.Exit(); //Wait for the threads to complete: var ts = Stopwatch.StartNew(); while ((ResultHandler.IsActive || (TransactionHandler != null && TransactionHandler.IsActive) || (DataFeed != null && DataFeed.IsActive)) && ts.ElapsedMilliseconds < 30 * 1000) { Thread.Sleep(100); Log.Trace("Waiting for threads to exit..."); } if (threadFeed != null && threadFeed.IsAlive) { threadFeed.Abort(); } if (threadTransactions != null && threadTransactions.IsAlive) { threadTransactions.Abort(); } if (threadResults != null && threadResults.IsAlive) { threadResults.Abort(); } Log.Trace("Engine.Main(): Analysis Completed and Results Posted."); } catch (Exception err) { Log.Error("Engine.Main(): Error running algorithm: " + err.Message + " >> " + err.StackTrace); } finally { //Delete the message from the job queue: JobQueue.AcknowledgeJob(job); Log.Trace("Engine.Main(): Packet removed from queue: " + job.AlgorithmId); //No matter what for live mode; make sure we've set algorithm status in the API for "not running" conditions: if (LiveMode && AlgorithmManager.State != AlgorithmStatus.Running && AlgorithmManager.State != AlgorithmStatus.RuntimeError) { Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmManager.State); } //Attempt to clean up ram usage: GC.Collect(); } //If we're running locally will execute just once. } while (!IsLocal); // Send the exit signal and then kill the thread StateCheck.Ping.Exit(); // Make the console window pause so we can read log output before exiting and killing the application completely Console.Read(); //Finally if ping thread still not complete, kill. if (statusPingThread != null && statusPingThread.IsAlive) { statusPingThread.Abort(); } if (Log.LogHandler != null) { Log.LogHandler.Dispose(); } }
/// <summary> /// Setup the algorithm cash, dates and portfolio as desired. /// </summary> /// <param name="algorithm">Existing algorithm instance</param> /// <param name="brokerage">New brokerage instance</param> /// <param name="baseJob">Backtesting job</param> /// <param name="resultHandler">The configured result handler</param> /// <param name="transactionHandler">The configuration transaction handler</param> /// <returns>Boolean true on successfully setting up the console.</returns> public bool Setup(IAlgorithm algorithm, out IBrokerage brokerage, AlgorithmNodePacket baseJob, IResultHandler resultHandler, ITransactionHandler transactionHandler) { var initializeComplete = false; try { //Set common variables for console programs: if (baseJob.Type == PacketType.BacktestNode) { var backtestJob = baseJob as BacktestNodePacket; //Set the limits on the algorithm assets (for local no limits) algorithm.SetAssetLimits(999, 999, 999); algorithm.SetMaximumOrders(int.MaxValue); //Setup Base Algorithm: algorithm.Initialize(); //Add currency data feeds that weren't explicity added in Initialize algorithm.Portfolio.CashBook.EnsureCurrencyDataFeeds(algorithm.Securities, algorithm.SubscriptionManager, SecurityExchangeHoursProvider.FromDataFolder()); //Construct the backtest job packet: backtestJob.PeriodStart = algorithm.StartDate; backtestJob.PeriodFinish = algorithm.EndDate; backtestJob.BacktestId = "LOCALHOST"; backtestJob.UserId = 1001; backtestJob.Type = PacketType.BacktestNode; //Backtest Specific Parameters: StartingDate = backtestJob.PeriodStart; StartingPortfolioValue = algorithm.Portfolio.Cash; } else { throw new Exception("The ConsoleSetupHandler is for backtests only. Use the BrokerageSetupHandler."); } } catch (Exception err) { Log.Error("ConsoleSetupHandler().Setup(): " + err.Message); Errors.Add("Failed to initialize algorithm: Initialize(): " + err.Message); } if (Errors.Count == 0) { initializeComplete = true; } // we need to do this after algorithm initialization brokerage = new BacktestingBrokerage(algorithm); // set the transaction models base on the requested brokerage properties SetupHandler.UpdateTransactionModels(algorithm, algorithm.BrokerageModel); algorithm.Transactions.SetOrderProcessor(transactionHandler); return(initializeComplete); }
public static void _AddActionResultHandler(ClientObject clientObj, Action action, IResultHandler resultHandler) { clientObj.Context._PendingRequest.AddActionResultHandler(action, resultHandler); }
/// <summary> /// Setup the algorithm cash, dates and data subscriptions as desired. /// </summary> /// <param name="algorithm">Algorithm instance</param> /// <param name="brokerage">Brokerage instance</param> /// <param name="baseJob">Algorithm job</param> /// <param name="resultHandler">The configured result handler</param> /// <param name="transactionHandler">The configurated transaction handler</param> /// <param name="realTimeHandler">The configured real time handler</param> /// <returns>Boolean true on successfully initializing the algorithm</returns> public bool Setup(IAlgorithm algorithm, IBrokerage brokerage, AlgorithmNodePacket baseJob, IResultHandler resultHandler, ITransactionHandler transactionHandler, IRealTimeHandler realTimeHandler) { var job = baseJob as BacktestNodePacket; if (job == null) { throw new ArgumentException("Expected BacktestNodePacket but received " + baseJob.GetType().Name); } Log.Trace(string.Format("BacktestingSetupHandler.Setup(): Setting up job: Plan: {0}, UID: {1}, PID: {2}, Version: {3}, Source: {4}", job.UserPlan, job.UserId, job.ProjectId, job.Version, job.RequestSource)); if (algorithm == null) { Errors.Add("Could not create instance of algorithm"); return(false); } algorithm.Name = job.GetAlgorithmName(); //Make sure the algorithm start date ok. if (job.PeriodStart == default(DateTime)) { Errors.Add("Algorithm start date was never set"); return(false); } var controls = job.Controls; var isolator = new Isolator(); var initializeComplete = isolator.ExecuteWithTimeLimit(TimeSpan.FromMinutes(5), () => { try { resultHandler.SendStatusUpdate(AlgorithmStatus.Initializing, "Initializing algorithm..."); //Set our parameters algorithm.SetParameters(job.Parameters); //Algorithm is backtesting, not live: algorithm.SetLiveMode(false); //Set the source impl for the event scheduling algorithm.Schedule.SetEventSchedule(realTimeHandler); // set the option chain provider algorithm.SetOptionChainProvider(new CachingOptionChainProvider(new BacktestingOptionChainProvider())); //Initialise the algorithm, get the required data: algorithm.Initialize(); } catch (Exception err) { Log.Error(err); Errors.Add("Failed to initialize algorithm: Initialize(): " + err); } }, controls.RamAllocation); //Before continuing, detect if this is ready: if (!initializeComplete) { return(false); } // TODO: Refactor the BacktestResultHandler to use algorithm not job to set times job.PeriodStart = algorithm.StartDate; job.PeriodFinish = algorithm.EndDate; algorithm.PostInitialize(); //Calculate the max runtime for the strategy _maxRuntime = GetMaximumRuntime(job.PeriodStart, job.PeriodFinish, algorithm.SubscriptionManager, algorithm.UniverseManager, baseJob.Controls); // Python takes forever; lets give it 10x longer to finish. if (job.Language == Language.Python) { _maxRuntime = _maxRuntime.Add(TimeSpan.FromSeconds(_maxRuntime.TotalSeconds * 9)); } //Get starting capital: _startingCaptial = algorithm.Portfolio.Cash; //Max Orders: 10k per backtest: if (job.UserPlan == UserPlan.Free) { _maxOrders = 10000; } else { _maxOrders = int.MaxValue; _maxRuntime += _maxRuntime; } //Set back to the algorithm, algorithm.SetMaximumOrders(_maxOrders); //Starting date of the algorithm: _startingDate = job.PeriodStart; //Put into log for debugging: Log.Trace("SetUp Backtesting: User: "******" ProjectId: " + job.ProjectId + " AlgoId: " + job.AlgorithmId); Log.Trace("Dates: Start: " + job.PeriodStart.ToShortDateString() + " End: " + job.PeriodFinish.ToShortDateString() + " Cash: " + _startingCaptial.ToString("C")); if (Errors.Count > 0) { initializeComplete = false; } return(initializeComplete); }
public void SetUp() { _resultHandler = new TestResultHandler(Console.WriteLine); }
/// <summary> /// Subscription data reader takes a subscription request, loads the type, accepts the data source and enumerate on the results. /// </summary> /// <param name="config">Subscription configuration object</param> /// <param name="security">Security asset</param> /// <param name="periodStart">Start date for the data request/backtest</param> /// <param name="periodFinish">Finish date for the data request/backtest</param> /// <param name="resultHandler"></param> /// <param name="tradeableDates">Defines the dates for which we'll request data, in order</param> /// <param name="isLiveMode">True if we're in live mode, false otherwise</param> /// <param name="symbolResolutionDate">The date used to resolve the correct symbol</param> public SubscriptionDataReader(SubscriptionDataConfig config, Security security, DateTime periodStart, DateTime periodFinish, IResultHandler resultHandler, IEnumerable <DateTime> tradeableDates, bool isLiveMode, DateTime?symbolResolutionDate ) { //Save configuration of data-subscription: _config = config; _auxiliaryData = new Queue <BaseData>(); //Save Start and End Dates: _periodStart = periodStart; _periodFinish = periodFinish; //Save access to securities _security = security; _isDynamicallyLoadedData = security.IsDynamicallyLoadedData; _isLiveMode = isLiveMode; //Save the type of data we'll be getting from the source. //Create the dynamic type-activators: var objectActivator = ObjectActivator.GetActivator(config.Type); _resultHandler = resultHandler; _tradeableDates = tradeableDates.GetEnumerator(); if (objectActivator == null) { _resultHandler.ErrorMessage("Custom data type '" + config.Type.Name + "' missing parameterless constructor E.g. public " + config.Type.Name + "() { }"); _endOfStream = true; return; } //Create an instance of the "Type": var userObj = objectActivator.Invoke(new object[] { }); _dataFactory = userObj as BaseData; //If its quandl set the access token in data factory: var quandl = _dataFactory as Quandl; if (quandl != null) { if (!Quandl.IsAuthCodeSet) { Quandl.SetAuthCode(Config.Get("quandl-auth-token")); } } //Load the entire factor and symbol mapping tables into memory, we'll start with some defaults _factorFile = new FactorFile(config.Symbol, new List <FactorFileRow>()); _mapFile = new MapFile(config.Symbol, new List <MapFileRow>()); try { // do we have map/factor tables? -- only applies to equities if (!security.IsDynamicallyLoadedData && security.Type == SecurityType.Equity) { // resolve the correct map file as of the date _mapFile = MapFile.ResolveMapFile(config.Symbol, config.Market, symbolResolutionDate); _hasScaleFactors = FactorFile.HasScalingFactors(_mapFile.EntitySymbol, config.Market); if (_hasScaleFactors) { _factorFile = FactorFile.Read(config.Symbol, config.Market); } } } catch (Exception err) { Log.Error("SubscriptionDataReader(): Fetching Price/Map Factors: " + err.Message); } _subscriptionFactoryEnumerator = ResolveDataEnumerator(true); }
/// <summary> /// Primary entry point to setup a new algorithm /// </summary> /// <param name="algorithm">Algorithm instance</param> /// <param name="brokerage">New brokerage output instance</param> /// <param name="job">Algorithm job task</param> /// <param name="resultHandler">The configured result handler</param> /// <param name="transactionHandler">The configurated transaction handler</param> /// <param name="realTimeHandler">The configured real time handler</param> /// <returns>True on successfully setting up the algorithm state, or false on error.</returns> public bool Setup(IAlgorithm algorithm, IBrokerage brokerage, AlgorithmNodePacket job, IResultHandler resultHandler, ITransactionHandler transactionHandler, IRealTimeHandler realTimeHandler) { _algorithm = algorithm; // verify we were given the correct job packet type var liveJob = job as LiveNodePacket; if (liveJob == null) { AddInitializationError("BrokerageSetupHandler requires a LiveNodePacket"); return(false); } // verify the brokerage was specified if (string.IsNullOrWhiteSpace(liveJob.Brokerage)) { AddInitializationError("A brokerage must be specified"); return(false); } // attach to the message event to relay brokerage specific initialization messages EventHandler <BrokerageMessageEvent> brokerageOnMessage = (sender, args) => { if (args.Type == BrokerageMessageType.Error) { AddInitializationError(string.Format("Brokerage Error Code: {0} - {1}", args.Code, args.Message)); } }; try { Log.Trace("BrokerageSetupHandler.Setup(): Initializing algorithm..."); resultHandler.SendStatusUpdate(AlgorithmStatus.Initializing, "Initializing algorithm..."); //Execute the initialize code: var controls = job.Controls; var isolator = new Isolator(); var initializeComplete = isolator.ExecuteWithTimeLimit(TimeSpan.FromSeconds(300), () => { try { //Set the default brokerage model before initialize algorithm.SetBrokerageModel(_factory.BrokerageModel); //Set our default markets algorithm.SetDefaultMarkets(_factory.DefaultMarkets.ToDictionary()); //Set our parameters algorithm.SetParameters(job.Parameters); //Algorithm is live, not backtesting: algorithm.SetLiveMode(true); //Initialize the algorithm's starting date algorithm.SetDateTime(DateTime.UtcNow); //Set the source impl for the event scheduling algorithm.Schedule.SetEventSchedule(realTimeHandler); //Initialise the algorithm, get the required data: algorithm.Initialize(); if (liveJob.Brokerage != "PaperBrokerage") { //Zero the CashBook - we'll populate directly from brokerage foreach (var kvp in algorithm.Portfolio.CashBook) { kvp.Value.SetAmount(0); } } } catch (Exception err) { AddInitializationError(err.Message); } }); if (!initializeComplete) { AddInitializationError("Initialization timed out."); return(false); } // let the world know what we're doing since logging in can take a minute resultHandler.SendStatusUpdate(AlgorithmStatus.LoggingIn, "Logging into brokerage..."); brokerage.Message += brokerageOnMessage; // set the transaction and settlement models based on the brokerage properties algorithm.UpdateModels(algorithm.BrokerageModel); algorithm.Transactions.SetOrderProcessor(transactionHandler); algorithm.PostInitialize(); Log.Trace("BrokerageSetupHandler.Setup(): Connecting to brokerage..."); try { // this can fail for various reasons, such as already being logged in somewhere else brokerage.Connect(); } catch (Exception err) { Log.Error(err); AddInitializationError(string.Format("Error connecting to brokerage: {0}. " + "This may be caused by incorrect login credentials or an unsupported account type.", err.Message)); return(false); } if (!brokerage.IsConnected) { // if we're reporting that we're not connected, bail AddInitializationError("Unable to connect to brokerage."); return(false); } Log.Trace("BrokerageSetupHandler.Setup(): Fetching cash balance from brokerage..."); try { // set the algorithm's cash balance for each currency var cashBalance = brokerage.GetCashBalance(); foreach (var cash in cashBalance) { Log.Trace("BrokerageSetupHandler.Setup(): Setting " + cash.Symbol + " cash to " + cash.Amount); algorithm.Portfolio.SetCash(cash.Symbol, cash.Amount, cash.ConversionRate); } } catch (Exception err) { Log.Error(err); AddInitializationError("Error getting cash balance from brokerage: " + err.Message); return(false); } Log.Trace("BrokerageSetupHandler.Setup(): Fetching open orders from brokerage..."); try { // populate the algorithm with the account's outstanding orders var openOrders = brokerage.GetOpenOrders(); foreach (var order in openOrders) { // be sure to assign order IDs such that we increment from the SecurityTransactionManager to avoid ID collisions Log.Trace("BrokerageSetupHandler.Setup(): Has open order: " + order.Symbol.ToString() + " - " + order.Quantity); order.Id = algorithm.Transactions.GetIncrementOrderId(); transactionHandler.Orders.AddOrUpdate(order.Id, order, (i, o) => order); } } catch (Exception err) { Log.Error(err); AddInitializationError("Error getting open orders from brokerage: " + err.Message); return(false); } Log.Trace("BrokerageSetupHandler.Setup(): Fetching holdings from brokerage..."); try { // populate the algorithm with the account's current holdings var holdings = brokerage.GetAccountHoldings(); var supportedSecurityTypes = new HashSet <SecurityType> { SecurityType.Equity, SecurityType.Forex }; var minResolution = new Lazy <Resolution>(() => algorithm.Securities.Select(x => x.Value.Resolution).DefaultIfEmpty(Resolution.Second).Min()); foreach (var holding in holdings) { Log.Trace("BrokerageSetupHandler.Setup(): Has existing holding: " + holding); // verify existing holding security type if (!supportedSecurityTypes.Contains(holding.Type)) { Log.Error("BrokerageSetupHandler.Setup(): Unsupported security type: " + holding.Type + "-" + holding.Symbol.Value); AddInitializationError("Found unsupported security type in existing brokerage holdings: " + holding.Type + ". " + "QuantConnect currently supports the following security types: " + string.Join(",", supportedSecurityTypes)); // keep aggregating these errors continue; } if (!algorithm.Portfolio.ContainsKey(holding.Symbol)) { Log.Trace("BrokerageSetupHandler.Setup(): Adding unrequested security: " + holding.Symbol.ToString()); // for items not directly requested set leverage to 1 and at the min resolution algorithm.AddSecurity(holding.Type, holding.Symbol.Value, minResolution.Value, null, true, 1.0m, false); } algorithm.Portfolio[holding.Symbol].SetHoldings(holding.AveragePrice, (int)holding.Quantity); algorithm.Securities[holding.Symbol].SetMarketPrice(new TradeBar { Time = DateTime.Now, Open = holding.MarketPrice, High = holding.MarketPrice, Low = holding.MarketPrice, Close = holding.MarketPrice, Volume = 0, Symbol = holding.Symbol, DataType = MarketDataType.TradeBar }); } } catch (Exception err) { Log.Error(err); AddInitializationError("Error getting account holdings from brokerage: " + err.Message); return(false); } //Set the starting portfolio value for the strategy to calculate performance: StartingPortfolioValue = algorithm.Portfolio.TotalPortfolioValue; StartingDate = DateTime.Now; } catch (Exception err) { AddInitializationError(err.Message); } finally { if (brokerage != null) { brokerage.Message -= brokerageOnMessage; } } return(Errors.Count == 0); }
/// <summary> /// Initializes the data feed for the specified job and algorithm /// </summary> public void Initialize(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IMapFileProvider mapFileProvider, IFactorFileProvider factorFileProvider) { if (!(job is LiveNodePacket)) { throw new ArgumentException("The LiveTradingDataFeed requires a LiveNodePacket."); } _cancellationTokenSource = new CancellationTokenSource(); _algorithm = algorithm; _job = (LiveNodePacket)job; _resultHandler = resultHandler; _timeProvider = GetTimeProvider(); _dataQueueHandler = GetDataQueueHandler(); _frontierTimeProvider = new ManualTimeProvider(_timeProvider.GetUtcNow()); _customExchange = new BaseDataExchange("CustomDataExchange") { SleepInterval = 10 }; // sleep is controlled on this exchange via the GetNextTicksEnumerator _exchange = new BaseDataExchange("DataQueueExchange") { SleepInterval = 0 }; _exchange.AddEnumerator(DataQueueHandlerSymbol, GetNextTicksEnumerator()); _subscriptions = new ConcurrentDictionary <Symbol, List <Subscription> >(); _bridge = new BusyBlockingCollection <TimeSlice>(); _universeSelection = new UniverseSelection(this, algorithm, job.Controls); // run the exchanges Task.Run(() => _exchange.Start(_cancellationTokenSource.Token)); Task.Run(() => _customExchange.Start(_cancellationTokenSource.Token)); // this value will be modified via calls to AddSubscription/RemoveSubscription var ffres = Time.OneMinute; _fillForwardResolution = Ref.Create(() => ffres, v => ffres = v); // wire ourselves up to receive notifications when universes are added/removed var start = _timeProvider.GetUtcNow(); algorithm.UniverseManager.CollectionChanged += (sender, args) => { switch (args.Action) { case NotifyCollectionChangedAction.Add: foreach (var universe in args.NewItems.OfType <Universe>()) { _subscriptions.Add(universe.Configuration.Symbol, CreateUniverseSubscription(universe, start, Time.EndOfTime)); UpdateFillForwardResolution(); } break; case NotifyCollectionChangedAction.Remove: foreach (var universe in args.OldItems.OfType <Universe>()) { RemoveSubscription(universe.Configuration.Symbol); } break; default: throw new NotImplementedException("The specified action is not implemented: " + args.Action); } }; }
public void Initialize(IAlgorithm algorithm, IBrokerage brokerage, IResultHandler resultHandler) { }
private IEnumerable <TimeSlice> Stream(AlgorithmNodePacket job, IAlgorithm algorithm, IDataFeed feed, IResultHandler results, CancellationToken cancellationToken) { bool setStartTime = false; var timeZone = algorithm.TimeZone; var history = algorithm.HistoryProvider; // get the required history job from the algorithm DateTime?lastHistoryTimeUtc = null; var historyRequests = algorithm.GetWarmupHistoryRequests().ToList(); // initialize variables for progress computation var start = DateTime.UtcNow.Ticks; var nextStatusTime = DateTime.UtcNow.AddSeconds(1); var minimumIncrement = algorithm.Securities.Min(x => x.Value.SubscriptionDataConfig.Increment); minimumIncrement = (minimumIncrement == TimeSpan.Zero ? Time.OneSecond : minimumIncrement); if (historyRequests.Count != 0) { // rewrite internal feed requests var minResolution = algorithm.SubscriptionManager.Subscriptions.Where(x => !x.IsInternalFeed).Min(x => x.Resolution); foreach (var request in historyRequests) { Security security; if (algorithm.Securities.TryGetValue(request.Symbol, out security) && security.SubscriptionDataConfig.IsInternalFeed) { if (request.Resolution < minResolution) { request.Resolution = minResolution; request.FillForwardResolution = request.FillForwardResolution.HasValue ? minResolution : (Resolution?)null; } } } // rewrite all to share the same fill forward resolution if (historyRequests.Any(x => x.FillForwardResolution.HasValue)) { minResolution = historyRequests.Where(x => x.FillForwardResolution.HasValue).Min(x => x.FillForwardResolution.Value); foreach (var request in historyRequests.Where(x => x.FillForwardResolution.HasValue)) { request.FillForwardResolution = minResolution; } } foreach (var request in historyRequests) { start = Math.Min(request.StartTimeUtc.Ticks, start); Log.Trace(string.Format("AlgorithmManager.Stream(): WarmupHistoryRequest: {0}: Start: {1} End: {2} Resolution: {3}", request.Symbol, request.StartTimeUtc, request.EndTimeUtc, request.Resolution)); } // make the history request and build time slices foreach (var slice in history.GetHistory(historyRequests, timeZone)) { TimeSlice timeSlice; try { // we need to recombine this slice into a time slice var paired = new List <KeyValuePair <Security, List <BaseData> > >(); foreach (var symbol in slice.Keys) { var security = algorithm.Securities[symbol]; var data = slice[symbol]; var list = new List <BaseData>(); var ticks = data as List <Tick>; if (ticks != null) { list.AddRange(ticks); } else { list.Add(data); } paired.Add(new KeyValuePair <Security, List <BaseData> >(security, list)); } timeSlice = TimeSlice.Create(slice.Time.ConvertToUtc(timeZone), timeZone, algorithm.Portfolio.CashBook, paired, SecurityChanges.None); } catch (Exception err) { Log.Error(err); algorithm.RunTimeError = err; yield break; } if (timeSlice != null) { if (!setStartTime) { setStartTime = true; _previousTime = timeSlice.Time; algorithm.Debug("Algorithm warming up..."); } if (DateTime.UtcNow > nextStatusTime) { // send some status to the user letting them know we're done history, but still warming up, // catching up to real time data nextStatusTime = DateTime.UtcNow.AddSeconds(1); var percent = (int)(100 * (timeSlice.Time.Ticks - start) / (double)(DateTime.UtcNow.Ticks - start)); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.History, string.Format("Catching up to realtime {0}%...", percent)); } yield return(timeSlice); lastHistoryTimeUtc = timeSlice.Time; } } } // if we're not live or didn't event request warmup, then set us as not warming up if (!algorithm.LiveMode || historyRequests.Count == 0) { algorithm.SetFinishedWarmingUp(); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Running); if (historyRequests.Count != 0) { algorithm.Debug("Algorithm finished warming up."); Log.Trace("AlgorithmManager.Stream(): Finished warmup"); } } foreach (var timeSlice in feed.Bridge.GetConsumingEnumerable(cancellationToken)) { if (!setStartTime) { setStartTime = true; _previousTime = timeSlice.Time; } if (algorithm.LiveMode && algorithm.IsWarmingUp) { // this is hand-over logic, we spin up the data feed first and then request // the history for warmup, so there will be some overlap between the data if (lastHistoryTimeUtc.HasValue) { // make sure there's no historical data, this only matters for the handover var hasHistoricalData = false; foreach (var data in timeSlice.Slice.Ticks.Values.SelectMany(x => x).Concat <BaseData>(timeSlice.Slice.Bars.Values)) { // check if any ticks in the list are on or after our last warmup point, if so, skip this data if (data.EndTime.ConvertToUtc(algorithm.Securities[data.Symbol].Exchange.TimeZone) >= lastHistoryTimeUtc) { hasHistoricalData = true; break; } } if (hasHistoricalData) { continue; } // prevent us from doing these checks every loop lastHistoryTimeUtc = null; } // in live mode wait to mark us as finished warming up when // the data feed has caught up to now within the min increment if (timeSlice.Time > DateTime.UtcNow.Subtract(minimumIncrement)) { algorithm.SetFinishedWarmingUp(); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Running); algorithm.Debug("Algorithm finished warming up."); Log.Trace("AlgorithmManager.Stream(): Finished warmup"); } else if (DateTime.UtcNow > nextStatusTime) { // send some status to the user letting them know we're done history, but still warming up, // catching up to real time data nextStatusTime = DateTime.UtcNow.AddSeconds(1); var percent = (int)(100 * (timeSlice.Time.Ticks - start) / (double)(DateTime.UtcNow.Ticks - start)); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.History, string.Format("Catching up to realtime {0}%...", percent)); } } yield return(timeSlice); } }
/// <summary> /// Select the realtime event handler set in the job. /// </summary> private static IRealTimeHandler GetRealTimeHandler(IAlgorithm algorithm, IBrokerage brokerage, IDataFeed feed, IResultHandler results, AlgorithmNodePacket job) { var rth = default(IRealTimeHandler); switch (job.RealTimeEndpoint) { //Don't fire based on system time but virtualized backtesting time. case RealTimeEndpoint.Backtesting: Log.Trace("Engine.GetRealTimeHandler(): Selected Backtesting RealTimeEvent Handler"); rth = new BacktestingRealTimeHandler(algorithm, job); break; // Fire events based on real system clock time. case RealTimeEndpoint.LiveTrading: Log.Trace("Engine.GetRealTimeHandler(): Selected LiveTrading RealTimeEvent Handler"); rth = new LiveTradingRealTimeHandler(algorithm, feed, results); break; } return(rth); }
public void Initialize(IAlgorithm algorithm, AlgorithmNodePacket job, IResultHandler resultHandler, IMapFileProvider mapFileProvider, IFactorFileProvider factorFileProvider, IDataProvider dataProvider, IDataFeedSubscriptionManager subscriptionManager, IDataFeedTimeProvider dataFeedTimeProvider) { }
/// <summary> /// Subscription data reader takes a subscription request, loads the type, accepts the data source and enumerate on the results. /// </summary> /// <param name="config">Subscription configuration object</param> /// <param name="periodStart">Start date for the data request/backtest</param> /// <param name="periodFinish">Finish date for the data request/backtest</param> /// <param name="resultHandler">Result handler used to push error messages and perform sampling on skipped days</param> /// <param name="mapFileResolver">Used for resolving the correct map files</param> /// <param name="factorFileProvider">Used for getting factor files</param> /// <param name="dataProvider">Used for getting files not present on disk</param> /// <param name="dataCacheProvider">Used for caching files</param> /// <param name="tradeableDates">Defines the dates for which we'll request data, in order, in the security's exchange time zone</param> /// <param name="isLiveMode">True if we're in live mode, false otherwise</param> /// <param name="includeAuxilliaryData">True if we want to emit aux data, false to only emit price data</param> public SubscriptionDataReader(SubscriptionDataConfig config, DateTime periodStart, DateTime periodFinish, IResultHandler resultHandler, MapFileResolver mapFileResolver, IFactorFileProvider factorFileProvider, IDataProvider dataProvider, IEnumerable <DateTime> tradeableDates, bool isLiveMode, IDataCacheProvider dataCacheProvider, bool includeAuxilliaryData = true) { //Save configuration of data-subscription: _config = config; _auxiliaryData = new Queue <BaseData>(); //Save Start and End Dates: _periodStart = periodStart; _periodFinish = periodFinish; _dataProvider = dataProvider; _dataCacheProvider = dataCacheProvider; //Save access to securities _isLiveMode = isLiveMode; _includeAuxilliaryData = includeAuxilliaryData; //Save the type of data we'll be getting from the source. //Create the dynamic type-activators: var objectActivator = ObjectActivator.GetActivator(config.Type); _resultHandler = resultHandler; _tradeableDates = tradeableDates.GetEnumerator(); if (objectActivator == null) { _resultHandler.ErrorMessage("Custom data type '" + config.Type.Name + "' missing parameterless constructor E.g. public " + config.Type.Name + "() { }"); _endOfStream = true; return; } //Create an instance of the "Type": var userObj = objectActivator.Invoke(new object[] { config.Type }); _dataFactory = userObj as BaseData; //If its quandl set the access token in data factory: var quandl = _dataFactory as Quandl; if (quandl != null) { if (!Quandl.IsAuthCodeSet) { Quandl.SetAuthCode(Config.Get("quandl-auth-token")); } } _factorFile = new FactorFile(config.Symbol.Value, new List <FactorFileRow>()); _mapFile = new MapFile(config.Symbol.Value, new List <MapFileRow>()); // load up the map and factor files for equities if (!config.IsCustomData && config.SecurityType == SecurityType.Equity) { try { var mapFile = mapFileResolver.ResolveMapFile(config.Symbol.ID.Symbol, config.Symbol.ID.Date); // only take the resolved map file if it has data, otherwise we'll use the empty one we defined above if (mapFile.Any()) { _mapFile = mapFile; } var factorFile = factorFileProvider.Get(_config.Symbol); _hasScaleFactors = factorFile != null; if (_hasScaleFactors) { _factorFile = factorFile; // if factor file has minimum date, update start period if before minimum date if (!_isLiveMode && _factorFile != null && _factorFile.FactorFileMinimumDate.HasValue) { if (_periodStart < _factorFile.FactorFileMinimumDate.Value) { _periodStart = _factorFile.FactorFileMinimumDate.Value; _resultHandler.DebugMessage( string.Format("Data for symbol {0} has been limited due to numerical precision issues in the factor file. The starting date has been set to {1}.", config.Symbol.Value, _factorFile.FactorFileMinimumDate.Value.ToShortDateString())); } } } } catch (Exception err) { Log.Error(err, "Fetching Price/Map Factors: " + config.Symbol.ID + ": "); } } // load up the map and factor files for underlying of equity option if (!config.IsCustomData && config.SecurityType == SecurityType.Option) { try { var mapFile = mapFileResolver.ResolveMapFile(config.Symbol.Underlying.ID.Symbol, config.Symbol.Underlying.ID.Date); // only take the resolved map file if it has data, otherwise we'll use the empty one we defined above if (mapFile.Any()) { _mapFile = mapFile; } } catch (Exception err) { Log.Error(err, "Map Factors: " + config.Symbol.ID + ": "); } } _subscriptionFactoryEnumerator = ResolveDataEnumerator(true); }
public void Run(string configuration, IResultHandler resultHandler) { resultHandler.OnSuccess(); }
public OptimizerResultHandler() { _shadow = new BacktestingResultHandler(); }
/// <summary> /// Launch the algorithm manager to run this strategy /// </summary> /// <param name="job">Algorithm job</param> /// <param name="algorithm">Algorithm instance</param> /// <param name="feed">Datafeed object</param> /// <param name="transactions">Transaction manager object</param> /// <param name="results">Result handler object</param> /// <param name="realtime">Realtime processing object</param> /// <param name="commands">The command queue for relaying extenal commands to the algorithm</param> /// <param name="token">Cancellation token</param> /// <remarks>Modify with caution</remarks> public void Run(AlgorithmNodePacket job, IAlgorithm algorithm, IDataFeed feed, ITransactionHandler transactions, IResultHandler results, IRealTimeHandler realtime, ICommandQueueHandler commands, CancellationToken token) { //Initialize: _dataPointCount = 0; _algorithm = algorithm; var portfolioValue = algorithm.Portfolio.TotalPortfolioValue; var backtestMode = (job.Type == PacketType.BacktestNode); var methodInvokers = new Dictionary <Type, MethodInvoker>(); var marginCallFrequency = TimeSpan.FromMinutes(5); var nextMarginCallTime = DateTime.MinValue; var settlementScanFrequency = TimeSpan.FromMinutes(30); var nextSettlementScanTime = DateTime.MinValue; var delistingTickets = new List <OrderTicket>(); //Initialize Properties: _algorithmId = job.AlgorithmId; _algorithm.Status = AlgorithmStatus.Running; _previousTime = algorithm.StartDate.Date; //Create the method accessors to push generic types into algorithm: Find all OnData events: // Algorithm 2.0 data accessors var hasOnDataTradeBars = AddMethodInvoker <TradeBars>(algorithm, methodInvokers); var hasOnDataTicks = AddMethodInvoker <Ticks>(algorithm, methodInvokers); // dividend and split events var hasOnDataDividends = AddMethodInvoker <Dividends>(algorithm, methodInvokers); var hasOnDataSplits = AddMethodInvoker <Splits>(algorithm, methodInvokers); var hasOnDataDelistings = AddMethodInvoker <Delistings>(algorithm, methodInvokers); var hasOnDataSymbolChangedEvents = AddMethodInvoker <SymbolChangedEvents>(algorithm, methodInvokers); // Algorithm 3.0 data accessors var hasOnDataSlice = algorithm.GetType().GetMethods() .Where(x => x.Name == "OnData" && x.GetParameters().Length == 1 && x.GetParameters()[0].ParameterType == typeof(Slice)) .FirstOrDefault(x => x.DeclaringType == algorithm.GetType()) != null; //Go through the subscription types and create invokers to trigger the event handlers for each custom type: foreach (var config in feed.Subscriptions.Select(x => x.Configuration)) { //If type is a tradebar, combine tradebars and ticks into unified array: if (config.Type.Name != "TradeBar" && config.Type.Name != "Tick" && !config.IsInternalFeed) { //Get the matching method for this event handler - e.g. public void OnData(Quandl data) { .. } var genericMethod = (algorithm.GetType()).GetMethod("OnData", new[] { config.Type }); //If we already have this Type-handler then don't add it to invokers again. if (methodInvokers.ContainsKey(config.Type)) { continue; } //If we couldnt find the event handler, let the user know we can't fire that event. if (genericMethod == null && !hasOnDataSlice) { algorithm.RunTimeError = new Exception("Data event handler not found, please create a function matching this template: public void OnData(" + config.Type.Name + " data) { }"); _algorithm.Status = AlgorithmStatus.RuntimeError; return; } if (genericMethod != null) { methodInvokers.Add(config.Type, genericMethod.DelegateForCallMethod()); } } } //Loop over the queues: get a data collection, then pass them all into relevent methods in the algorithm. Log.Trace("AlgorithmManager.Run(): Begin DataStream - Start: " + algorithm.StartDate + " Stop: " + algorithm.EndDate); foreach (var timeSlice in Stream(job, algorithm, feed, results, token)) { // reset our timer on each loop _currentTimeStepTime = DateTime.UtcNow; //Check this backtest is still running: if (_algorithm.Status != AlgorithmStatus.Running) { Log.Error(string.Format("AlgorithmManager.Run(): Algorthm state changed to {0} at {1}", _algorithm.Status, timeSlice.Time)); break; } //Execute with TimeLimit Monitor: if (token.IsCancellationRequested) { Log.Error("AlgorithmManager.Run(): CancellationRequestion at " + timeSlice.Time); return; } // before doing anything, check our command queue foreach (var command in commands.GetCommands()) { if (command == null) { continue; } Log.Trace("AlgorithmManager.Run(): Executing {0}", command); command.Run(algorithm); } var time = timeSlice.Time; _dataPointCount += timeSlice.DataPointCount; //If we're in backtest mode we need to capture the daily performance. We do this here directly //before updating the algorithm state with the new data from this time step, otherwise we'll //produce incorrect samples (they'll take into account this time step's new price values) if (backtestMode) { //On day-change sample equity and daily performance for statistics calculations if (_previousTime.Date != time.Date) { SampleBenchmark(algorithm, results, _previousTime.Date); //Sample the portfolio value over time for chart. results.SampleEquity(_previousTime, Math.Round(algorithm.Portfolio.TotalPortfolioValue, 4)); //Check for divide by zero if (portfolioValue == 0m) { results.SamplePerformance(_previousTime.Date, 0); } else { results.SamplePerformance(_previousTime.Date, Math.Round((algorithm.Portfolio.TotalPortfolioValue - portfolioValue) * 100 / portfolioValue, 10)); } portfolioValue = algorithm.Portfolio.TotalPortfolioValue; } } else { // live mode continously sample the benchmark SampleBenchmark(algorithm, results, time); } //Update algorithm state after capturing performance from previous day //Set the algorithm and real time handler's time algorithm.SetDateTime(time); if (timeSlice.Slice.SymbolChangedEvents.Count != 0) { if (hasOnDataSymbolChangedEvents) { methodInvokers[typeof(SymbolChangedEvents)](algorithm, timeSlice.Slice.SymbolChangedEvents); } foreach (var symbol in timeSlice.Slice.SymbolChangedEvents.Keys) { // cancel all orders for the old symbol foreach (var ticket in transactions.GetOrderTickets(x => x.Status.IsOpen() && x.Symbol == symbol)) { ticket.Cancel("Open order cancelled on symbol changed event"); } } } if (timeSlice.SecurityChanges != SecurityChanges.None) { foreach (var security in timeSlice.SecurityChanges.AddedSecurities) { if (!algorithm.Securities.ContainsKey(security.Symbol)) { // add the new security algorithm.Securities.Add(security); } } } //On each time step push the real time prices to the cashbook so we can have updated conversion rates foreach (var kvp in timeSlice.CashBookUpdateData) { kvp.Key.Update(kvp.Value); } //Update the securities properties: first before calling user code to avoid issues with data foreach (var kvp in timeSlice.SecuritiesUpdateData) { kvp.Key.SetMarketPrice(kvp.Value); // Send market price updates to the TradeBuilder if (kvp.Value != null) { algorithm.TradeBuilder.SetMarketPrice(kvp.Key.Symbol, kvp.Value.Price); } } // fire real time events after we've updated based on the new data realtime.SetTime(timeSlice.Time); // process fill models on the updated data before entering algorithm, applies to all non-market orders transactions.ProcessSynchronousEvents(); if (delistingTickets.Count != 0) { for (int i = 0; i < delistingTickets.Count; i++) { var ticket = delistingTickets[i]; if (ticket.Status == OrderStatus.Filled) { algorithm.Securities.Remove(ticket.Symbol); delistingTickets.RemoveAt(i--); Log.Trace("AlgorithmManager.Run(): Delisted Security removed: " + ticket.Symbol.Permtick); } } } //Check if the user's signalled Quit: loop over data until day changes. if (algorithm.Status == AlgorithmStatus.Stopped) { Log.Trace("AlgorithmManager.Run(): Algorithm quit requested."); break; } if (algorithm.RunTimeError != null) { _algorithm.Status = AlgorithmStatus.RuntimeError; Log.Trace(string.Format("AlgorithmManager.Run(): Algorithm encountered a runtime error at {0}. Error: {1}", timeSlice.Time, algorithm.RunTimeError)); break; } // perform margin calls, in live mode we can also use realtime to emit these if (time >= nextMarginCallTime || (_liveMode && nextMarginCallTime > DateTime.Now)) { // determine if there are possible margin call orders to be executed bool issueMarginCallWarning; var marginCallOrders = algorithm.Portfolio.ScanForMarginCall(out issueMarginCallWarning); if (marginCallOrders.Count != 0) { var executingMarginCall = false; try { // tell the algorithm we're about to issue the margin call algorithm.OnMarginCall(marginCallOrders); executingMarginCall = true; // execute the margin call orders var executedTickets = algorithm.Portfolio.MarginCallModel.ExecuteMarginCall(marginCallOrders); foreach (var ticket in executedTickets) { algorithm.Error(string.Format("{0} - Executed MarginCallOrder: {1} - Quantity: {2} @ {3}", algorithm.Time, ticket.Symbol, ticket.Quantity, ticket.AverageFillPrice)); } } catch (Exception err) { algorithm.RunTimeError = err; _algorithm.Status = AlgorithmStatus.RuntimeError; var locator = executingMarginCall ? "Portfolio.MarginCallModel.ExecuteMarginCall" : "OnMarginCall"; Log.Error(string.Format("AlgorithmManager.Run(): RuntimeError: {0}: ", locator) + err.Message + " STACK >>> " + err.StackTrace); return; } } // we didn't perform a margin call, but got the warning flag back, so issue the warning to the algorithm else if (issueMarginCallWarning) { try { algorithm.OnMarginCallWarning(); } catch (Exception err) { algorithm.RunTimeError = err; _algorithm.Status = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: OnMarginCallWarning: " + err.Message + " STACK >>> " + err.StackTrace); return; } } nextMarginCallTime = time + marginCallFrequency; } // perform check for settlement of unsettled funds if (time >= nextSettlementScanTime || (_liveMode && nextSettlementScanTime > DateTime.Now)) { algorithm.Portfolio.ScanForCashSettlement(algorithm.UtcTime); nextSettlementScanTime = time + settlementScanFrequency; } // before we call any events, let the algorithm know about universe changes if (timeSlice.SecurityChanges != SecurityChanges.None) { try { algorithm.OnSecuritiesChanged(timeSlice.SecurityChanges); } catch (Exception err) { algorithm.RunTimeError = err; _algorithm.Status = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: OnSecuritiesChanged event: " + err.Message); return; } } // apply dividends foreach (var dividend in timeSlice.Slice.Dividends.Values) { Log.Trace("AlgorithmManager.Run(): Applying Dividend for " + dividend.Symbol, true); algorithm.Portfolio.ApplyDividend(dividend); } // apply splits foreach (var split in timeSlice.Slice.Splits.Values) { try { Log.Trace("AlgorithmManager.Run(): Applying Split for " + split.Symbol, true); algorithm.Portfolio.ApplySplit(split); // apply the split to open orders as well in raw mode, all other modes are split adjusted if (_liveMode || algorithm.Securities[split.Symbol].SubscriptionDataConfig.DataNormalizationMode == DataNormalizationMode.Raw) { // in live mode we always want to have our order match the order at the brokerage, so apply the split to the orders var openOrders = transactions.GetOrderTickets(ticket => ticket.Status.IsOpen() && ticket.Symbol == split.Symbol); algorithm.BrokerageModel.ApplySplit(openOrders.ToList(), split); } } catch (Exception err) { algorithm.RunTimeError = err; _algorithm.Status = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: Split event: " + err.Message); return; } } //Update registered consolidators for this symbol index try { foreach (var kvp in timeSlice.ConsolidatorUpdateData) { var consolidators = kvp.Key.Consolidators; foreach (var dataPoint in kvp.Value) { foreach (var consolidator in consolidators) { consolidator.Update(dataPoint); } } } } catch (Exception err) { algorithm.RunTimeError = err; _algorithm.Status = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: Consolidators update: " + err.Message); return; } // fire custom event handlers foreach (var kvp in timeSlice.CustomData) { MethodInvoker methodInvoker; var type = kvp.Key.SubscriptionDataConfig.Type; if (!methodInvokers.TryGetValue(type, out methodInvoker)) { continue; } try { foreach (var dataPoint in kvp.Value) { if (type.IsInstanceOfType(dataPoint)) { methodInvoker(algorithm, dataPoint); } } } catch (Exception err) { algorithm.RunTimeError = err; _algorithm.Status = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: Custom Data: " + err.Message + " STACK >>> " + err.StackTrace); return; } } try { // fire off the dividend and split events before pricing events if (hasOnDataDividends && timeSlice.Slice.Dividends.Count != 0) { methodInvokers[typeof(Dividends)](algorithm, timeSlice.Slice.Dividends); } if (hasOnDataSplits && timeSlice.Slice.Splits.Count != 0) { methodInvokers[typeof(Splits)](algorithm, timeSlice.Slice.Splits); } if (hasOnDataDelistings && timeSlice.Slice.Delistings.Count != 0) { methodInvokers[typeof(Delistings)](algorithm, timeSlice.Slice.Delistings); } } catch (Exception err) { algorithm.RunTimeError = err; _algorithm.Status = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: Dividends/Splits/Delistings: " + err.Message + " STACK >>> " + err.StackTrace); return; } // run the delisting logic after firing delisting events HandleDelistedSymbols(algorithm, timeSlice.Slice.Delistings, delistingTickets); //After we've fired all other events in this second, fire the pricing events: try { if (hasOnDataTradeBars && timeSlice.Slice.Bars.Count > 0) { methodInvokers[typeof(TradeBars)](algorithm, timeSlice.Slice.Bars); } if (hasOnDataTicks && timeSlice.Slice.Ticks.Count > 0) { methodInvokers[typeof(Ticks)](algorithm, timeSlice.Slice.Ticks); } } catch (Exception err) { algorithm.RunTimeError = err; _algorithm.Status = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: New Style Mode: " + err.Message + " STACK >>> " + err.StackTrace); return; } try { if (timeSlice.Slice.Count != 0) { // EVENT HANDLER v3.0 -- all data in a single event algorithm.OnData(timeSlice.Slice); } } catch (Exception err) { algorithm.RunTimeError = err; _algorithm.Status = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: Slice: " + err.Message + " STACK >>> " + err.StackTrace); return; } //If its the historical/paper trading models, wait until market orders have been "filled" // Manually trigger the event handler to prevent thread switch. transactions.ProcessSynchronousEvents(); //Save the previous time for the sample calculations _previousTime = time; // Process any required events of the results handler such as sampling assets, equity, or stock prices. results.ProcessSynchronousEvents(); } // End of ForEach feed.Bridge.GetConsumingEnumerable // stop timing the loops _currentTimeStepTime = DateTime.MinValue; //Stream over:: Send the final packet and fire final events: Log.Trace("AlgorithmManager.Run(): Firing On End Of Algorithm..."); try { algorithm.OnEndOfAlgorithm(); } catch (Exception err) { _algorithm.Status = AlgorithmStatus.RuntimeError; algorithm.RunTimeError = new Exception("Error running OnEndOfAlgorithm(): " + err.Message, err.InnerException); Log.Error("AlgorithmManager.OnEndOfAlgorithm(): " + err.Message + " STACK >>> " + err.StackTrace); return; } // Process any required events of the results handler such as sampling assets, equity, or stock prices. results.ProcessSynchronousEvents(forceProcess: true); //Liquidate Holdings for Calculations: if (_algorithm.Status == AlgorithmStatus.Liquidated && _liveMode) { Log.Trace("AlgorithmManager.Run(): Liquidating algorithm holdings..."); algorithm.Liquidate(); results.LogMessage("Algorithm Liquidated"); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Liquidated); } //Manually stopped the algorithm if (_algorithm.Status == AlgorithmStatus.Stopped) { Log.Trace("AlgorithmManager.Run(): Stopping algorithm..."); results.LogMessage("Algorithm Stopped"); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Stopped); } //Backtest deleted. if (_algorithm.Status == AlgorithmStatus.Deleted) { Log.Trace("AlgorithmManager.Run(): Deleting algorithm..."); results.DebugMessage("Algorithm Id:(" + job.AlgorithmId + ") Deleted by request."); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Deleted); } //Algorithm finished, send regardless of commands: results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Completed); //Take final samples: results.SampleRange(algorithm.GetChartUpdates()); results.SampleEquity(_previousTime, Math.Round(algorithm.Portfolio.TotalPortfolioValue, 4)); SampleBenchmark(algorithm, results, _previousTime); results.SamplePerformance(_previousTime, Math.Round((algorithm.Portfolio.TotalPortfolioValue - portfolioValue) * 100 / portfolioValue, 10)); } // End of Run();
/******************************************************** * CLASS METHODS *********************************************************/ /// <summary> /// Launch the algorithm manager to run this strategy /// </summary> /// <param name="job">Algorithm job</param> /// <param name="algorithm">Algorithm instance</param> /// <param name="feed">Datafeed object</param> /// <param name="transactions">Transaction manager object</param> /// <param name="results">Result handler object</param> /// <param name="setup">Setup handler object</param> /// <param name="realtime">Realtime processing object</param> /// <remarks>Modify with caution</remarks> public static void Run(AlgorithmNodePacket job, IAlgorithm algorithm, IDataFeed feed, ITransactionHandler transactions, IResultHandler results, ISetupHandler setup, IRealTimeHandler realtime) { //Initialize: _dataPointCount = 0; var backwardsCompatibilityMode = false; var tradebarsType = typeof(TradeBars); var ticksType = typeof(Ticks); var startingPortfolioValue = setup.StartingCapital; var backtestMode = (job.Type == PacketType.BacktestNode); var methodInvokers = new Dictionary <Type, MethodInvoker>(); var marginCallFrequency = TimeSpan.FromMinutes(5); var nextMarginCallTime = DateTime.MinValue; //Initialize Properties: _frontier = setup.StartingDate; _algorithmId = job.AlgorithmId; _algorithmState = AlgorithmStatus.Running; _previousTime = setup.StartingDate.Date; //Create the method accessors to push generic types into algorithm: Find all OnData events: //Algorithm 1.0 Data Accessors. //If the users defined these methods, add them in manually. This allows keeping backwards compatibility to algorithm 1.0. var oldTradeBarsMethodInfo = (algorithm.GetType()).GetMethod("OnTradeBar", new[] { typeof(Dictionary <string, TradeBar>) }); var oldTicksMethodInfo = (algorithm.GetType()).GetMethod("OnTick", new[] { typeof(Dictionary <string, List <Tick> >) }); //Algorithm 2.0 Data Generics Accessors. //New hidden access to tradebars with custom type. var newTradeBarsMethodInfo = (algorithm.GetType()).GetMethod("OnData", new[] { tradebarsType }); var newTicksMethodInfo = (algorithm.GetType()).GetMethod("OnData", new[] { ticksType }); if (newTradeBarsMethodInfo == null && newTicksMethodInfo == null) { backwardsCompatibilityMode = true; if (oldTradeBarsMethodInfo != null) { methodInvokers.Add(tradebarsType, oldTradeBarsMethodInfo.DelegateForCallMethod()); } if (oldTradeBarsMethodInfo != null) { methodInvokers.Add(ticksType, oldTicksMethodInfo.DelegateForCallMethod()); } } else { backwardsCompatibilityMode = false; if (newTradeBarsMethodInfo != null) { methodInvokers.Add(tradebarsType, newTradeBarsMethodInfo.DelegateForCallMethod()); } if (newTicksMethodInfo != null) { methodInvokers.Add(ticksType, newTicksMethodInfo.DelegateForCallMethod()); } } //Go through the subscription types and create invokers to trigger the event handlers for each custom type: foreach (var config in feed.Subscriptions) { //If type is a tradebar, combine tradebars and ticks into unified array: if (config.Type.Name != "TradeBar" && config.Type.Name != "Tick") { //Get the matching method for this event handler - e.g. public void OnData(Quandl data) { .. } var genericMethod = (algorithm.GetType()).GetMethod("OnData", new[] { config.Type }); //If we already have this Type-handler then don't add it to invokers again. if (methodInvokers.ContainsKey(config.Type)) { continue; } //If we couldnt find the event handler, let the user know we can't fire that event. if (genericMethod == null) { algorithm.RunTimeError = new Exception("Data event handler not found, please create a function matching this template: public void OnData(" + config.Type.Name + " data) { }"); _algorithmState = AlgorithmStatus.RuntimeError; return; } methodInvokers.Add(config.Type, genericMethod.DelegateForCallMethod()); } } //Loop over the queues: get a data collection, then pass them all into relevent methods in the algorithm. Log.Debug("AlgorithmManager.Run(): Algorithm initialized, launching time loop."); foreach (var newData in DataStream.GetData(feed, setup.StartingDate)) { //Check this backtest is still running: if (_algorithmState != AlgorithmStatus.Running) { break; } //Go over each time stamp we've collected, pass it into the algorithm in order: foreach (var time in newData.Keys) { //Set the time frontier: _frontier = time; //Execute with TimeLimit Monitor: if (Isolator.IsCancellationRequested) { return; } //If we're in backtest mode we need to capture the daily performance. We do this here directly //before updating the algorithm state with the new data from this time step, otherwise we'll //produce incorrect samples (they'll take into account this time step's new price values) if (backtestMode) { //Refresh the realtime event monitor: //in backtest mode use the algorithms clock as realtime. realtime.SetTime(time); //On day-change sample equity and daily performance for statistics calculations if (_previousTime.Date != time.Date) { //Sample the portfolio value over time for chart. results.SampleEquity(_previousTime, Math.Round(algorithm.Portfolio.TotalPortfolioValue, 4)); //Check for divide by zero if (startingPortfolioValue == 0m) { results.SamplePerformance(_previousTime.Date, 0); } else { results.SamplePerformance(_previousTime.Date, Math.Round((algorithm.Portfolio.TotalPortfolioValue - startingPortfolioValue) * 100 / startingPortfolioValue, 10)); } startingPortfolioValue = algorithm.Portfolio.TotalPortfolioValue; } } //Update algorithm state after capturing performance from previous day //On each time step push the real time prices to the cashbook so we can have updated conversion rates algorithm.Portfolio.CashBook.Update(newData[time]); //Update the securities properties: first before calling user code to avoid issues with data algorithm.Securities.Update(time, newData[time]); // perform margin calls if (time >= nextMarginCallTime) { // determine if there are possible margin call orders to be executed var marginCallOrders = algorithm.Portfolio.ScanForMarginCall(); if (marginCallOrders.Count != 0) { // execute the margin call orders var executedOrders = algorithm.Portfolio.MarginCallModel.ExecuteMarginCall(marginCallOrders); foreach (var order in executedOrders) { algorithm.Error(string.Format("Executed MarginCallOrder: {0} - Quantity: {1} @ {2}", order.Symbol, order.Quantity, order.Price)); } } nextMarginCallTime = time + marginCallFrequency; } //Check if the user's signalled Quit: loop over data until day changes. if (algorithm.GetQuit()) { _algorithmState = AlgorithmStatus.Quit; break; } //Pass in the new time first: algorithm.SetDateTime(time); //Trigger the data events: Invoke the types we have data for: var oldBars = new Dictionary <string, TradeBar>(); var oldTicks = new Dictionary <string, List <Tick> >(); var newBars = new TradeBars(time); var newTicks = new Ticks(time); //Invoke all non-tradebars, non-ticks methods and build up the TradeBars and Ticks dictionaries // --> i == Subscription Configuration Index, so we don't need to compare types. foreach (var i in newData[time].Keys) { //Data point and config of this point: var dataPoints = newData[time][i]; var config = feed.Subscriptions[i]; //Keep track of how many data points we've processed _dataPointCount += dataPoints.Count; //We don't want to pump data that we added just for currency conversions if (config.IsInternalFeed) { continue; } //Create TradeBars Unified Data --> OR --> invoke generic data event. One loop. foreach (var dataPoint in dataPoints) { //Update registered consolidators for this symbol index try { for (var j = 0; j < config.Consolidators.Count; j++) { config.Consolidators[j].Update(dataPoint); } } catch (Exception err) { algorithm.RunTimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Error("AlgorithmManager.Run(): RuntimeError: Consolidators update: " + err.Message); return; } switch (config.Type.Name) { case "TradeBar": var bar = dataPoint as TradeBar; try { if (bar != null) { if (backwardsCompatibilityMode) { if (!oldBars.ContainsKey(bar.Symbol)) { oldBars.Add(bar.Symbol, bar); } } else { if (!newBars.ContainsKey(bar.Symbol)) { newBars.Add(bar.Symbol, bar); } } } } catch (Exception err) { Log.Error(time.ToLongTimeString() + " >> " + bar.Time.ToLongTimeString() + " >> " + bar.Symbol + " >> " + bar.Value.ToString("C")); Log.Error("AlgorithmManager.Run(): Failed to add TradeBar (" + bar.Symbol + ") Time: (" + time.ToLongTimeString() + ") Count:(" + newBars.Count + ") " + err.Message); } break; case "Tick": var tick = dataPoint as Tick; if (tick != null) { if (backwardsCompatibilityMode) { if (!oldTicks.ContainsKey(tick.Symbol)) { oldTicks.Add(tick.Symbol, new List <Tick>()); } oldTicks[tick.Symbol].Add(tick); } else { if (!newTicks.ContainsKey(tick.Symbol)) { newTicks.Add(tick.Symbol, new List <Tick>()); } newTicks[tick.Symbol].Add(tick); } } break; default: //Send data into the generic algorithm event handlers try { methodInvokers[config.Type](algorithm, dataPoint); } catch (Exception err) { algorithm.RunTimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Debug("AlgorithmManager.Run(): RuntimeError: Custom Data: " + err.Message + " STACK >>> " + err.StackTrace); return; } break; } } } //After we've fired all other events in this second, fire the pricing events: if (backwardsCompatibilityMode) { //Log.Debug("AlgorithmManager.Run(): Invoking v1.0 Event Handlers..."); try { if (oldTradeBarsMethodInfo != null && oldBars.Count > 0) { methodInvokers[tradebarsType](algorithm, oldBars); } if (oldTicksMethodInfo != null && oldTicks.Count > 0) { methodInvokers[ticksType](algorithm, oldTicks); } } catch (Exception err) { algorithm.RunTimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Debug("AlgorithmManager.Run(): RuntimeError: Backwards Compatibility Mode: " + err.Message + " STACK >>> " + err.StackTrace); return; } } else { //Log.Debug("AlgorithmManager.Run(): Invoking v2.0 Event Handlers..."); try { if (newTradeBarsMethodInfo != null && newBars.Count > 0) { methodInvokers[tradebarsType](algorithm, newBars); } if (newTicksMethodInfo != null && newTicks.Count > 0) { methodInvokers[ticksType](algorithm, newTicks); } } catch (Exception err) { algorithm.RunTimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Debug("AlgorithmManager.Run(): RuntimeError: New Style Mode: " + err.Message + " STACK >>> " + err.StackTrace); return; } } //If its the historical/paper trading models, wait until market orders have been "filled" // Manually trigger the event handler to prevent thread switch. transactions.ProcessSynchronousEvents(); //Save the previous time for the sample calculations _previousTime = time; // Process any required events of the results handler such as sampling assets, equity, or stock prices. results.ProcessSynchronousEvents(); } // End of Time Loop } // End of ForEach DataStream //Stream over:: Send the final packet and fire final events: Log.Trace("AlgorithmManager.Run(): Firing On End Of Algorithm..."); try { algorithm.OnEndOfAlgorithm(); } catch (Exception err) { _algorithmState = AlgorithmStatus.RuntimeError; algorithm.RunTimeError = new Exception("Error running OnEndOfAlgorithm(): " + err.Message, err.InnerException); Log.Debug("AlgorithmManager.OnEndOfAlgorithm(): " + err.Message + " STACK >>> " + err.StackTrace); return; } // Process any required events of the results handler such as sampling assets, equity, or stock prices. results.ProcessSynchronousEvents(forceProcess: true); //Liquidate Holdings for Calculations: if (_algorithmState == AlgorithmStatus.Liquidated || !Engine.LiveMode) { Log.Trace("AlgorithmManager.Run(): Liquidating algorithm holdings..."); algorithm.Liquidate(); results.LogMessage("Algorithm Liquidated"); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Liquidated); } //Manually stopped the algorithm if (_algorithmState == AlgorithmStatus.Stopped) { Log.Trace("AlgorithmManager.Run(): Stopping algorithm..."); results.LogMessage("Algorithm Stopped"); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Stopped); } //Backtest deleted. if (_algorithmState == AlgorithmStatus.Deleted) { Log.Trace("AlgorithmManager.Run(): Deleting algorithm..."); results.DebugMessage("Algorithm Id:(" + job.AlgorithmId + ") Deleted by request."); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Deleted); } //Algorithm finished, send regardless of commands: results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Completed); //Take final samples: results.SampleRange(algorithm.GetChartUpdates()); results.SampleEquity(_frontier, Math.Round(algorithm.Portfolio.TotalPortfolioValue, 4)); results.SamplePerformance(_frontier, Math.Round((algorithm.Portfolio.TotalPortfolioValue - startingPortfolioValue) * 100 / startingPortfolioValue, 10)); } // End of Run();
/// <summary> /// Get an instance of the transaction handler set by the task. /// </summary> /// <param name="algorithm">Algorithm instance</param> /// <param name="job">Algorithm job packet</param> /// <param name="brokerage">Brokerage instance to avoid access token duplication</param> /// <param name="results">Results array for sending order events.</param> /// <returns>Class matching ITransactionHandler interface</returns> private static ITransactionHandler GetTransactionHandler(IAlgorithm algorithm, IBrokerage brokerage, IResultHandler results, AlgorithmNodePacket job) { ITransactionHandler th; switch (job.TransactionEndpoint) { case TransactionHandlerEndpoint.Brokerage: th = new BrokerageTransactionHandler(algorithm, brokerage); Log.Trace("Engine.GetTransactionHandler(): Selected Brokerage Transaction Models."); break; //Operation from local files: default: th = new BacktestingTransactionHandler(algorithm, brokerage as BacktestingBrokerage); Log.Trace("Engine.GetTransactionHandler(): Selected Backtesting Transaction Models."); break; } return(th); }
/// <summary> /// Primary entry point to setup a new algorithm /// </summary> /// <param name="algorithm">Algorithm instance</param> /// <param name="brokerage">New brokerage output instance</param> /// <param name="job">Algorithm job task</param> /// <param name="resultHandler">The configured result handler</param> /// <param name="transactionHandler">The configurated transaction handler</param> /// <param name="realTimeHandler">The configured real time handler</param> /// <returns>True on successfully setting up the algorithm state, or false on error.</returns> public bool Setup(IAlgorithm algorithm, IBrokerage brokerage, AlgorithmNodePacket job, IResultHandler resultHandler, ITransactionHandler transactionHandler, IRealTimeHandler realTimeHandler) { // verify we were given the correct job packet type var liveJob = job as LiveNodePacket; if (liveJob == null) { AddInitializationError("BrokerageSetupHandler requires a LiveNodePacket"); return(false); } algorithm.Name = liveJob.GetAlgorithmName(); // verify the brokerage was specified if (string.IsNullOrWhiteSpace(liveJob.Brokerage)) { AddInitializationError("A brokerage must be specified"); return(false); } // attach to the message event to relay brokerage specific initialization messages EventHandler <BrokerageMessageEvent> brokerageOnMessage = (sender, args) => { if (args.Type == BrokerageMessageType.Error) { AddInitializationError(string.Format("Brokerage Error Code: {0} - {1}", args.Code, args.Message)); } }; try { Log.Trace("BrokerageSetupHandler.Setup(): Initializing algorithm..."); resultHandler.SendStatusUpdate(AlgorithmStatus.Initializing, "Initializing algorithm..."); //Execute the initialize code: var controls = job.Controls; var isolator = new Isolator(); var initializeComplete = isolator.ExecuteWithTimeLimit(TimeSpan.FromSeconds(300), () => { try { //Set the default brokerage model before initialize algorithm.SetBrokerageModel(_factory.BrokerageModel); //Margin calls are disabled by default in live mode algorithm.Portfolio.MarginCallModel = MarginCallModel.Null; //Set our parameters algorithm.SetParameters(job.Parameters); algorithm.SetAvailableDataTypes(GetConfiguredDataFeeds()); //Algorithm is live, not backtesting: algorithm.SetLiveMode(true); //Initialize the algorithm's starting date algorithm.SetDateTime(DateTime.UtcNow); //Set the source impl for the event scheduling algorithm.Schedule.SetEventSchedule(realTimeHandler); // set the option chain provider algorithm.SetOptionChainProvider(new CachingOptionChainProvider(new LiveOptionChainProvider())); // set the future chain provider algorithm.SetFutureChainProvider(new CachingFutureChainProvider(new LiveFutureChainProvider())); // If we're going to receive market data from IB, // set the default subscription limit to 100, // algorithms can override this setting in the Initialize method if (brokerage is InteractiveBrokersBrokerage && liveJob.DataQueueHandler.EndsWith("InteractiveBrokersBrokerage")) { algorithm.Settings.DataSubscriptionLimit = 100; } //Initialise the algorithm, get the required data: algorithm.Initialize(); //Finalize Initialization algorithm.PostInitialize(); if (liveJob.Brokerage != "PaperBrokerage") { //Zero the CashBook - we'll populate directly from brokerage foreach (var kvp in algorithm.Portfolio.CashBook) { kvp.Value.SetAmount(0); } } } catch (Exception err) { AddInitializationError(err.ToString(), err); } }, controls.RamAllocation); if (!initializeComplete) { AddInitializationError("Initialization timed out."); return(false); } // let the world know what we're doing since logging in can take a minute resultHandler.SendStatusUpdate(AlgorithmStatus.LoggingIn, "Logging into brokerage..."); brokerage.Message += brokerageOnMessage; Log.Trace("BrokerageSetupHandler.Setup(): Connecting to brokerage..."); try { // this can fail for various reasons, such as already being logged in somewhere else brokerage.Connect(); } catch (Exception err) { Log.Error(err); AddInitializationError(string.Format("Error connecting to brokerage: {0}. " + "This may be caused by incorrect login credentials or an unsupported account type.", err.Message), err); return(false); } if (!brokerage.IsConnected) { // if we're reporting that we're not connected, bail AddInitializationError("Unable to connect to brokerage."); return(false); } Log.Trace("BrokerageSetupHandler.Setup(): Fetching cash balance from brokerage..."); try { // set the algorithm's cash balance for each currency var cashBalance = brokerage.GetCashBalance(); foreach (var cash in cashBalance) { Log.Trace("BrokerageSetupHandler.Setup(): Setting " + cash.Symbol + " cash to " + cash.Amount); algorithm.Portfolio.SetCash(cash.Symbol, cash.Amount, cash.ConversionRate); } } catch (Exception err) { Log.Error(err); AddInitializationError("Error getting cash balance from brokerage: " + err.Message, err); return(false); } Log.Trace("BrokerageSetupHandler.Setup(): Fetching open orders from brokerage..."); try { GetOpenOrders(algorithm, resultHandler, transactionHandler, brokerage); } catch (Exception err) { Log.Error(err); AddInitializationError("Error getting open orders from brokerage: " + err.Message, err); return(false); } Log.Trace("BrokerageSetupHandler.Setup(): Fetching holdings from brokerage..."); try { // populate the algorithm with the account's current holdings var holdings = brokerage.GetAccountHoldings(); var supportedSecurityTypes = new HashSet <SecurityType> { SecurityType.Equity, SecurityType.Forex, SecurityType.Cfd, SecurityType.Option, SecurityType.Future, SecurityType.Crypto }; var minResolution = new Lazy <Resolution>(() => algorithm.Securities.Select(x => x.Value.Resolution).DefaultIfEmpty(Resolution.Second).Min()); foreach (var holding in holdings) { Log.Trace("BrokerageSetupHandler.Setup(): Has existing holding: " + holding); // verify existing holding security type if (!supportedSecurityTypes.Contains(holding.Type)) { Log.Error("BrokerageSetupHandler.Setup(): Unsupported security type: " + holding.Type + "-" + holding.Symbol.Value); AddInitializationError("Found unsupported security type in existing brokerage holdings: " + holding.Type + ". " + "QuantConnect currently supports the following security types: " + string.Join(",", supportedSecurityTypes)); // keep aggregating these errors continue; } if (!algorithm.Portfolio.ContainsKey(holding.Symbol)) { Log.Trace("BrokerageSetupHandler.Setup(): Adding unrequested security: " + holding.Symbol.Value); if (holding.Type == SecurityType.Option) { // add current option contract to the system algorithm.AddOptionContract(holding.Symbol, minResolution.Value, true, 1.0m); } else if (holding.Type == SecurityType.Future) { // add current future contract to the system algorithm.AddFutureContract(holding.Symbol, minResolution.Value, true, 1.0m); } else { // for items not directly requested set leverage to 1 and at the min resolution algorithm.AddSecurity(holding.Type, holding.Symbol.Value, minResolution.Value, null, true, 1.0m, false); } } algorithm.Portfolio[holding.Symbol].SetHoldings(holding.AveragePrice, holding.Quantity); algorithm.Securities[holding.Symbol].SetMarketPrice(new TradeBar { Time = DateTime.Now, Open = holding.MarketPrice, High = holding.MarketPrice, Low = holding.MarketPrice, Close = holding.MarketPrice, Volume = 0, Symbol = holding.Symbol, DataType = MarketDataType.TradeBar }); } } catch (Exception err) { Log.Error(err); AddInitializationError("Error getting account holdings from brokerage: " + err.Message, err); return(false); } //Set the starting portfolio value for the strategy to calculate performance: StartingPortfolioValue = algorithm.Portfolio.TotalPortfolioValue; StartingDate = DateTime.Now; } catch (Exception err) { AddInitializationError(err.ToString(), err); } finally { if (brokerage != null) { brokerage.Message -= brokerageOnMessage; } } return(Errors.Count == 0); }
public void PublicGetOpenOrders(IAlgorithm algorithm, IResultHandler resultHandler, ITransactionHandler transactionHandler, IBrokerage brokerage) { GetOpenOrders(algorithm, resultHandler, transactionHandler, brokerage, _supportedSecurityTypes, Resolution.Second); }