public void DoTick(string label = "Unlabelled") { TickTime = Time.time; Ticks.Add(new Tick { Context = Context, Label = label, Time = TickTime }); }
/// <summary> /// Adds the specified <see cref="BaseData"/> instance to the appropriate <see cref="DataDictionary{T}"/> /// </summary> private static void PopulateDataDictionaries(BaseData baseData, Ticks ticks, TradeBars tradeBars, QuoteBars quoteBars, OptionChains optionChains, FuturesChains futuresChains) { var symbol = baseData.Symbol; // populate data dictionaries switch (baseData.DataType) { case MarketDataType.Tick: ticks.Add(symbol, (Tick)baseData); break; case MarketDataType.TradeBar: tradeBars[symbol] = (TradeBar)baseData; break; case MarketDataType.QuoteBar: quoteBars[symbol] = (QuoteBar)baseData; break; case MarketDataType.OptionChain: optionChains[symbol] = (OptionChain)baseData; break; case MarketDataType.FuturesChain: futuresChains[symbol] = (FuturesChain)baseData; break; } }
private void Cast(Actor caster, Actor target) { //Deal damage var damagePerTick = new Damage(_tickDamage, DamageType.Magical, DamageFlags.Ability); var damage = new SourcedDamage(caster, damagePerTick); var damageable = target.GetModule <IDamageable>(); void InternalTick() { damageable.TakeDamage(damage); } var tickWrapper = new TickAction { Callback = InternalTick, TickCount = _tickCount, TickInterval = _tickInterval }; if (target.TryGetModule <IKillable>(out var killable)) { killable.Died += RemoveTick; } void RemoveTick(object sender, DeathEventArgs args) { killable.Died -= RemoveTick; Ticks.Remove(tickWrapper); } Ticks.Add(tickWrapper); ApplyFX(target.transform, _tickInterval * _tickCount); }
private async Task <bool> ExecuteLoadTickDataAsync(object parameter) { IsBusy = true; StatusText = "Loading..."; if (parameter != null) { _lastLoadedDuration = (DurationEnum)Enum.Parse(typeof(DurationEnum), parameter.ToString()); } Duration = _lastLoadedDuration.ToString(); var ticks = await _xtbWrapper.LoadData(Name, _lastLoadedDuration); Ticks.Clear(); foreach (var tick in ticks) { Ticks.Add(tick); } UpdatePlot(_lastLoadedDuration); StatusText = "Ready"; IsBusy = false; IsLoaded = true; return(true); }
public void Recalculate(double min, double max, double fixedSpacingMajor, double fixedSpacingMinor) { Ticks.Clear(); double firstMajorTickPosition = min - (min % fixedSpacingMajor); if (min > 0) { firstMajorTickPosition += fixedSpacingMajor; } for (double i = firstMajorTickPosition; i <= max; i += fixedSpacingMajor) { Ticks.Add(new Tick(i, Math.Round(i, 8).ToString(), true)); } double[] majorTickPositions = Ticks.Select(x => x.Position).ToArray(); double firstMinorTickPosition = min - (min % fixedSpacingMinor); if (min > 0) { firstMinorTickPosition += fixedSpacingMinor; } for (double i = firstMinorTickPosition; i <= max; i += fixedSpacingMinor) { if (!majorTickPositions.Contains(i)) { Ticks.Add(new Tick(i)); } } }
/// <summary> /// Poll for new tick to refresh conversion rate of non-USD denomination /// </summary> /// <param name="symbol"></param> public void PollTick(Symbol symbol) { int delay = 36000000; var token = _canceller.Token; var listener = Task.Factory.StartNew(() => { OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Information, -1, $"GDAXBrokerage.PollLatestTick: started polling for ticks: {symbol.Value.ToString()}")); while (true) { var rate = GetConversionRate(symbol.Value.Replace("USD", "")); lock (TickLocker) { var latest = new Tick { Value = rate, Time = DateTime.UtcNow, Symbol = symbol }; Ticks.Add(latest); } Thread.Sleep(delay); if (token.IsCancellationRequested) { break; } } OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Information, -1, $"PollLatestTick: stopped polling for ticks: {symbol.Value.ToString()}")); }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default); }
/// <summary> /// /// </summary> /// <param name="symbol"></param> /// <param name="entries"></param> private void EmitTradeTick(Symbol symbol, string[] entries) { try { var time = Time.UnixTimeStampToDateTime(double.Parse(entries[0], NumberStyles.Float, CultureInfo.InvariantCulture)); var price = decimal.Parse(entries[1], NumberStyles.Float, CultureInfo.InvariantCulture); var amout = decimal.Parse(entries[2], NumberStyles.Float, CultureInfo.InvariantCulture); lock (TickLocker) { Ticks.Add(new Tick { Value = price, Time = time, Symbol = symbol, TickType = TickType.Trade, Quantity = Math.Abs(amout) }); } } catch (Exception e) { Log.Error(e); throw; } }
// [[1, 250, 'Unscheduled'], [2, 54, 'Sprint 1'], [3, 20, 'Sprint Banana'], [4, 0, 'Sprint Cross Reference'], [5, 8, 'Sprint Sammy']] private List <object> CreateTaskHoursPerSprintJsonList(Product product, int currentSprintId) { List <object> taskHoursPerSprintJsonList = new List <object>(); ScrumTimeEntities scrumTimeEntities = new ScrumTimeEntities(); TaskService taskService = new TaskService(scrumTimeEntities); decimal unassignedTaskHours = taskService.GetUnassignedTaskHours(product.ProductId); CheckSetYAxisMax(unassignedTaskHours); List <object> unassignedHoursList = new List <object>(); unassignedHoursList.Add(1); unassignedHoursList.Add(unassignedTaskHours); unassignedHoursList.Add("Unassigned"); taskHoursPerSprintJsonList.Add(unassignedHoursList); Ticks.Add(" "); SprintService sprintService = new SprintService(scrumTimeEntities); List <Sprint> mostRecentSprints = sprintService.GetMostRecentSprints(product.ProductId, currentSprintId, 4); int index = 2; foreach (Sprint recentSprint in mostRecentSprints) { List <object> sprintHoursList = new List <object>(); sprintHoursList.Add(index); sprintHoursList.Add(CalculateHoursForSprint(recentSprint)); sprintHoursList.Add(recentSprint.Name); taskHoursPerSprintJsonList.Add(sprintHoursList); Ticks.Add(" "); index++; } return(taskHoursPerSprintJsonList); }
/// <summary> /// Poll for new tick to refresh conversion rate of non-USD denomination /// </summary> /// <param name="symbol"></param> /// <param name="client"></param> public void PollTick(Symbol symbol) { int delay = 36000000; var token = _canceller.Token; var listener = Task.Factory.StartNew(() => { Log.Trace("PollLatestTick: " + "Started polling for ticks: " + symbol.Value.ToString()); while (true) { var rate = GetConversionRate(symbol.Value.Replace("USD", "")); lock (_tickLocker) { var latest = new Tick { Value = rate, Time = DateTime.UtcNow, Symbol = symbol }; Ticks.Add(latest); } Thread.Sleep(delay); if (token.IsCancellationRequested) { break; } } Log.Trace("PollLatestTick: " + "Stopped polling for ticks: " + symbol.Value.ToString()); }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default); }
public void DateTimeConversion() { UT_INIT(); Log.SetVerbosity(new ConsoleLogger(), Verbosity.Verbose, "/"); Log.MapThreadName("UnitTest"); Log.SetDomain("TickWatch", Scope.Method); Log.Info("DateTime.MinValue(): " + (DateTime.MinValue.ToString())); Log.Info("DateTime.MaxValue(): " + (DateTime.MaxValue.ToString())); Ticks ticksNow = new Ticks(); // roundtrip 1 long millisEpochNow = ticksNow.InEpochMillis(); ticksNow.SetFromEpochMillis(millisEpochNow); long ticksNowFromEpoch = ticksNow.Raw(); UT_TRUE(Math.Abs(ticksNow.Raw() - ticksNowFromEpoch) < 50000); // roundtrip 2 long millis5_1_70_3_51 = 0 + (4L * 24L * 60L * 60L * 1000L) + (3L * 60L * 60L * 1000L) + (51L * 60L * 1000L); long millis5_1_71_3_51 = millis5_1_70_3_51 + (365L * 24L * 60L * 60L * 1000L); Ticks ticks5_1_70_3_51 = new Ticks(); ticks5_1_70_3_51.SetFromEpochMillis(millis5_1_70_3_51); Ticks ticks5_1_71_3_51 = new Ticks(); ticks5_1_71_3_51.SetFromEpochMillis(millis5_1_71_3_51); UT_TRUE(ticks5_1_70_3_51.Raw() < ticks5_1_71_3_51.Raw()); long millis5_1_70_3_51_back = ticks5_1_70_3_51.InEpochMillis(); long millis5_1_71_3_51_back = ticks5_1_71_3_51.InEpochMillis(); UT_TRUE(millis5_1_70_3_51_back == millis5_1_70_3_51); UT_TRUE(millis5_1_71_3_51_back == millis5_1_71_3_51); // add 1 day, 2h, 3min and 4sec days: Ticks tomorrow = new Ticks(ticksNow); Ticks span = new Ticks(); span.FromMillis((long)(new TimeSpan(1, 2, 3, 4)).TotalMilliseconds); tomorrow.Add(span); Log.Info("Today: is: " + (DateTime.Now.ToString())); Log.Info("Today: is: " + (ticksNow.InDotNetDateTime().ToString())); Log.Info("Today: is: " + ((new Ticks(ticksNowFromEpoch)).InDotNetDateTime().ToString())); Log.Info("+1d, 2h,3m,4s: " + (tomorrow.InDotNetDateTime().ToString())); Log.Info("5.1.70 3:51:00: " + (ticks5_1_70_3_51.InDotNetDateTime().ToString())); Log.Info("5.1.71 3:51:00: " + (ticks5_1_71_3_51.InDotNetDateTime().ToString())); }
internal HistoricalTicks(ResponseReader r) { RequestId = r.ReadInt(); int n = r.ReadInt(); for (int i = 0; i < n; i++) { Ticks.Add(new HistoricalTick(r)); } Done = r.ReadBool(); }
private void HandleBadProductId() { List <object> taskHoursPerSprintJsonList = new List <object>(); taskHoursPerSprintJsonList.Add(0); taskHoursPerSprintJsonList.Add(0); taskHoursPerSprintJsonList.Add("None"); Data.Add(taskHoursPerSprintJsonList); Ticks.Add(" "); YAxisMax = 10; }
public HistoricalTicks(ResponseComposer c) { RequestId = c.ReadInt(); var n = c.ReadInt(); for (int i = 0; i < n; i++) { Ticks.Add(new HistoricalTick(c)); } Done = c.ReadBool(); }
public void InitializeTicks() { logger.Trace("InitializeTicks()..."); for (int j = 0; j < 10; j = j + 1) { DiaryTimeTick dtt = new DiaryTimeTick(this); dtt.Top = j * 80; Ticks.Add(dtt); } logger.Trace("InitializeTicks()...Done"); }
public override void Initialize(LinkedNavigationEvent linkedNavigationEvent) { var ticks = IoC.Get <IBacktestRepository>().GetBacktestTicks(linkedNavigationEvent.Key); Ticks.Clear(); foreach (var tick in ticks) { Ticks.Add(tick); } TickView = CollectionViewSource.GetDefaultView(Ticks); base.Initialize(linkedNavigationEvent); }
public void AddTest() { IDataManager data = new OpenWealth.Data.Data(); //data.Init(); сейчас всё делается в конструкторе, но в будущем может понадобится ISymbol symbol = data.GetSymbol("AddTest"); IScale scale = data.GetScale(ScaleEnum.tick, 1); Ticks ticks = new Ticks(symbol, scale); Assert.AreEqual(ticks.Count, 0); IBar bar0 = new Bar(DateTime.Now, 10, 1, 1, 1, 1, 1); ticks.Add(null, bar0); Assert.AreEqual(ticks.Count, 1); Assert.AreEqual(ticks[0], bar0); IBar bar1 = new Bar(DateTime.Now, 20, 1, 1, 1, 1, 1); ticks.Add(null, bar1); Assert.AreEqual(ticks.Count, 2); Assert.AreEqual(ticks[1], bar1); IBar bar2 = new Bar(DateTime.Now, 15, 1, 1, 1, 1, 1); ticks.Add(null, bar2); Assert.AreEqual(ticks.Count, 3); Assert.AreEqual(ticks[0], bar0); Assert.AreEqual(ticks[1], bar2); Assert.AreEqual(ticks[2], bar1); IBar bar3 = new Bar(DateTime.Now, 15, 1, 1, 1, 1, 2); ticks.Add(null, bar2); Assert.AreEqual(ticks.Count, 3); Assert.AreEqual(ticks[0], bar0); Assert.AreEqual(ticks[1], bar2); Assert.AreEqual(ticks[2], bar1); }
public void BarExistsTest() { IDataManager data = new OpenWealth.Data.Data(); //data.Init(); сейчас всё делается в конструкторе, но в будущем может понадобится ISymbol symbol = data.GetSymbol("BarExistsTest"); IScale scale = data.GetScale(ScaleEnum.tick, 1); Ticks ticks = new Ticks(symbol, scale); int index; Assert.AreEqual(ticks.BarExists(777, out index), false); Assert.AreEqual(0, index); ticks.Add(null, new Bar(DateTime.Now, 10, 1, 1, 1, 1, 1)); Assert.AreEqual(ticks.BarExists(5, out index), false); Assert.AreEqual(0, index); Assert.AreEqual(ticks.BarExists(10, out index), true); Assert.AreEqual(0, index); Assert.AreEqual(ticks.BarExists(20, out index), false); Assert.AreEqual(1, index); ticks.Add(null, new Bar(DateTime.Now, 20, 1, 1, 1, 1, 1)); Assert.AreEqual(ticks.BarExists(5, out index), false); Assert.AreEqual(0, index); Assert.AreEqual(ticks.BarExists(10, out index), true); Assert.AreEqual(0, index); Assert.AreEqual(ticks.BarExists(15, out index), false); Assert.AreEqual(1, index); Assert.AreEqual(ticks.BarExists(20, out index), true); Assert.AreEqual(1, index); Assert.AreEqual(ticks.BarExists(25, out index), false); Assert.AreEqual(2, index); }
/// <summary> /// Emits a new trade tick from a match message /// </summary> private void EmitTradeTick(Messages.Matched message) { var symbol = ConvertProductId(message.ProductId); lock (TickLocker) { Ticks.Add(new Tick { Value = message.Price, Time = DateTime.UtcNow, Symbol = symbol, TickType = TickType.Trade, Quantity = message.Size }); } }
private void EmitQuoteTick(Symbol symbol, decimal bidPrice, decimal bidSize, decimal askPrice, decimal askSize) { lock (TickLocker) { Ticks.Add(new Tick { AskPrice = askPrice, BidPrice = bidPrice, Value = (askPrice + bidPrice) / 2m, Time = DateTime.UtcNow, Symbol = symbol, TickType = TickType.Quote, AskSize = Math.Abs(askSize), BidSize = Math.Abs(bidSize) }); } }
public void Add(TTick item) { var periodInstance = Period.CreateInstance(); if (Ticks.Any()) { var tickEndTime = periodInstance.NextTimestamp(Ticks.Last().DateTime); if (item.DateTime < tickEndTime) { throw new InvalidTimeFrameException(item.DateTime); } if (_maxTickCount.HasValue && Ticks.Count >= _maxTickCount.Value) { Ticks = Ticks.Skip(Ticks.Count - _maxTickCount.Value + 1).Take(_maxTickCount.Value).ToList(); } } Ticks.Add(item); }
/// <summary> /// Converts a ticker message and emits data as a new quote tick /// </summary> /// <param name="data"></param> private void EmitQuoteTick(string data) { var message = JsonConvert.DeserializeObject <Messages.Ticker>(data, JsonSettings); var symbol = ConvertProductId(message.ProductId); lock (_tickLocker) { Ticks.Add(new Tick { AskPrice = message.BestAsk, BidPrice = message.BestBid, Value = (message.BestAsk + message.BestBid) / 2m, Time = DateTime.UtcNow, Symbol = symbol, TickType = TickType.Quote //todo: tick volume }); } }
/// <summary> /// Event handler for streaming ticks /// </summary> /// <param name="json">The data object containing the received tick</param> private void OnPricingDataReceived(string json) { var obj = (JObject)JsonConvert.DeserializeObject(json); var type = obj["type"].ToString(); switch (type) { case "HEARTBEAT": lock (LockerConnectionMonitor) { LastHeartbeatUtcTime = DateTime.UtcNow; } break; case "PRICE": var data = obj.ToObject <Price>(); var securityType = SymbolMapper.GetBrokerageSecurityType(data.Instrument); var symbol = SymbolMapper.GetLeanSymbol(data.Instrument, securityType, Market.Oanda); var time = GetTickDateTimeFromString(data.Time); // live ticks timestamps must be in exchange time zone DateTimeZone exchangeTimeZone; if (!_symbolExchangeTimeZones.TryGetValue(symbol, out exchangeTimeZone)) { exchangeTimeZone = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.Oanda, symbol, securityType).TimeZone; _symbolExchangeTimeZones.Add(symbol, exchangeTimeZone); } time = time.ConvertFromUtc(exchangeTimeZone); var bidPrice = Convert.ToDecimal(data.Bids.Last().Price); var askPrice = Convert.ToDecimal(data.Asks.Last().Price); var tick = new Tick(time, symbol, bidPrice, askPrice); lock (Ticks) { Ticks.Add(tick); } break; } }
private void LedDeviceThreadProc() { var lastSentBytes = new byte[0]; while (!_isClosing) { Thread.Sleep(5); Color[] colors; lock (this) colors = _colors.ToArray(); try { var fade = CurrentFade; var bytes = colors.SelectMany(color => new[] { (byte)Math.Round(color.R * fade), (byte)Math.Round(color.G * fade), (byte)Math.Round(color.B * fade) }).ToArray(); if (!lastSentBytes.SequenceEqual(bytes)) { _port?.Write("LEDS"); WriteByte((byte)colors.Length); Write(bytes); ReadResponse(); lastSentBytes = bytes; Ticks.Add(); LastUpdated = DateTime.Now; Updated?.Invoke(); } } catch (Exception exception) { Error = exception; _port?.Dispose(); return; } } _port?.Dispose(); }
/// <summary> /// Event handler for streaming ticks /// </summary> /// <param name="data">The data object containing the received tick</param> private void OnDataReceived(RateStreamResponse data) { if (data.IsHeartbeat()) { lock (LockerConnectionMonitor) { LastHeartbeatUtcTime = DateTime.UtcNow; } return; } if (data.tick == null) { return; } var securityType = SymbolMapper.GetBrokerageSecurityType(data.tick.instrument); var symbol = SymbolMapper.GetLeanSymbol(data.tick.instrument, securityType, Market.Oanda); var time = OandaBrokerage.GetDateTimeFromString(data.tick.time); // live ticks timestamps must be in exchange time zone DateTimeZone exchangeTimeZone; if (!_symbolExchangeTimeZones.TryGetValue(symbol, out exchangeTimeZone)) { exchangeTimeZone = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.Oanda, symbol, securityType).TimeZone; _symbolExchangeTimeZones.Add(symbol, exchangeTimeZone); } time = time.ConvertFromUtc(exchangeTimeZone); var bidPrice = Convert.ToDecimal(data.tick.bid); var askPrice = Convert.ToDecimal(data.tick.ask); var tick = new Tick(time, symbol, bidPrice, askPrice); lock (Ticks) { Ticks.Add(tick); } }
private void ReCalculateTimelineTicks() { // for now Ticks.Clear(); // do a tick for each hour var hours = (int)(TickEndDateTime - TickStartDateTime).TotalHours; // round up to the nearest hour // need to get the tick based rounding code DateTime baseHourTick = TickStartDateTime.AddHours(1).AddMinutes(TickStartDateTime.Minute * -1); for (int i = 0; i < hours; i++) { Ticks.Add( new TimelineTick() { Time = baseHourTick.AddHours(i) } ); } }
/// <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();
public void AddTick() { Ticks.Add(MockUtilities.GenerateTicks("backtestidToImplement", 1)[0]); }
/******************************************************** * 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: var backwardsCompatibilityMode = false; var tradebarsType = typeof(TradeBars); var ticksType = typeof(Ticks); var startingPerformance = setup.StartingCapital; var backtestMode = (job.Type == PacketType.BacktestNode); var methodInvokers = new Dictionary <Type, MethodInvoker>(); //Initialize Properties: _frontier = setup.StartingDate; _runtimeError = null; _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 }); //Is 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) { _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; } //Refresh the realtime event monitor: realtime.SetTime(time); //Fire EOD if the time packet we just processed is greater if (backtestMode && _previousTime.Date != time.Date) { //Sample the portfolio value over time for chart. results.SampleEquity(_previousTime, Math.Round(algorithm.Portfolio.TotalPortfolioValue, 4)); if (startingPerformance == 0) { results.SamplePerformance(_previousTime.Date, 0); } else { results.SamplePerformance(_previousTime.Date, Math.Round((algorithm.Portfolio.TotalPortfolioValue - startingPerformance) * 100 / startingPerformance, 10)); } startingPerformance = algorithm.Portfolio.TotalPortfolioValue; } //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: // --> 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]; //Create TradeBars Unified Data --> OR --> invoke generic data event. One loop. foreach (var dataPoint in dataPoints) { //Update the securities properties: first before calling user code to avoid issues with data algorithm.Securities.Update(time, dataPoint); //Update registered consolidators for this symbol index for (var j = 0; j < config.Consolidators.Count; j++) { config.Consolidators[j].Update(dataPoint); } 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) { _runtimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Error("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) { _runtimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Error("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) { _runtimeError = err; _algorithmState = AlgorithmStatus.RuntimeError; Log.Error("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; } // End of Time Loop // Process any required events of the results handler such as sampling assets, equity, or stock prices. results.ProcessSynchronousEvents(); } // 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) { _runtimeError = new Exception("Error running OnEndOfAlgorithm(): " + err.Message, err.InnerException); _algorithmState = AlgorithmStatus.RuntimeError; return; } // Process any required events of the results handler such as sampling assets, equity, or stock prices. results.ProcessSynchronousEvents(); //Liquidate Holdings for Calculations: if (_algorithmState == AlgorithmStatus.Liquidated || !Engine.LiveMode) { Log.Trace("AlgorithmManager.Run(): Liquidating algorithm holdings..."); algorithm.Liquidate(); results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Liquidated); } //Manually stopped the algorithm if (_algorithmState == AlgorithmStatus.Stopped) { Log.Trace("AlgorithmManager.Run(): Stopping algorithm..."); 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 - startingPerformance) * 100 / startingPerformance, 10)); } // End of Run();
public static TimeSpan Add(TimeSpan timeout1, TimeSpan timeout2) { return(Ticks.ToTimeSpan(Ticks.Add(Ticks.FromTimeSpan(timeout1), Ticks.FromTimeSpan(timeout2)))); }
protected override void AddTrade(TradeEvent tradeEvent) { Ticks.Add(tradeEvent.Tick); }
/******************************************************** * 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: var backwardsCompatibilityMode = false; var tradebarsType = typeof (TradeBars); var ticksType = typeof(Ticks); var startingPerformance = setup.StartingCapital; var backtestMode = (job.Type == PacketType.BacktestNode); var methodInvokers = new Dictionary<Type, MethodInvoker>(); //Initialize Properties: _frontier = setup.StartingDate; _runtimeError = null; _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 }); //Is 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) { _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; //Refresh the realtime event monitor: realtime.SetTime(time); //Fire EOD if the time packet we just processed is greater if (backtestMode && _previousTime.Date != time.Date) { //Sample the portfolio value over time for chart. results.SampleEquity(_previousTime, Math.Round(algorithm.Portfolio.TotalPortfolioValue, 4)); if (startingPerformance == 0) { results.SamplePerformance(_previousTime.Date, 0); } else { results.SamplePerformance(_previousTime.Date, Math.Round((algorithm.Portfolio.TotalPortfolioValue - startingPerformance) * 100 / startingPerformance, 10)); } startingPerformance = algorithm.Portfolio.TotalPortfolioValue; } //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: // --> 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]; //Create TradeBars Unified Data --> OR --> invoke generic data event. One loop. foreach (var dataPoint in dataPoints) { //Update the securities properties: first before calling user code to avoid issues with data algorithm.Securities.Update(time, dataPoint); //Update registered consolidators for this symbol index for (var j = 0; j < config.Consolidators.Count; j++) { config.Consolidators[j].Update(dataPoint); } 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) { _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) { _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) { _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; } // End of Time Loop // Process any required events of the results handler such as sampling assets, equity, or stock prices. results.ProcessSynchronousEvents(); } // 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; _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 - startingPerformance) * 100 / startingPerformance, 10)); }
/// <summary> /// Adds the specified <see cref="BaseData"/> instance to the appropriate <see cref="DataDictionary{T}"/> /// </summary> private static void PopulateDataDictionaries(BaseData baseData, Ticks ticks, TradeBars tradeBars, QuoteBars quoteBars, OptionChains optionChains) { var symbol = baseData.Symbol; // populate data dictionaries switch (baseData.DataType) { case MarketDataType.Tick: ticks.Add(symbol, (Tick)baseData); break; case MarketDataType.TradeBar: tradeBars[symbol] = (TradeBar) baseData; break; case MarketDataType.QuoteBar: quoteBars[symbol] = (QuoteBar) baseData; break; case MarketDataType.OptionChain: optionChains[symbol] = (OptionChain) baseData; break; } }