private IDisposable GenerateTradesAndMaintainCache() { //bit of code to generate trades var random = new Random(); //initally load some trades _tradesSource.AddOrUpdate(_tradeGenerator.Generate(10000, true)); Func <TimeSpan> randomInterval = () => { var ms = random.Next(150, 5000); return(TimeSpan.FromMilliseconds(ms)); }; // create a random number of trades at a random interval var tradeGenerator = _schedulerProvider.TaskPool .ScheduleRecurringAction(randomInterval, () => { var number = random.Next(1, 7); _logger.Info("Adding {0} trades", number); var trades = _tradeGenerator.Generate(number); _tradesSource.AddOrUpdate(trades); }); // close a random number of trades at a random interval var tradeCloser = _schedulerProvider.TaskPool .ScheduleRecurringAction(randomInterval, () => { var number = random.Next(1, 8); _logger.Info("Closing {0} trades", number); _tradesSource.BatchUpdate(updater => { var trades = updater.Items .Where(trade => trade.Status == TradeStatus.Live) .OrderBy(t => Guid.NewGuid()).Take(number).ToArray(); var toClose = trades .Select(trade => new Trade(trade, TradeStatus.Closed)); _tradesSource.AddOrUpdate(toClose); }); }); return(new CompositeDisposable(tradeGenerator, tradeCloser)); }
private IObservable <IChangeSet <Trade, long> > GenerateTradesAndMaintainCache() { //construct an cache datasource specifying that the primary key is Trade.Id return(ObservableChangeSet.Create <Trade, long>(cache => { /* * The following code emulates an external trade provider. * Alternatively you can use "new SourceCacheTrade, long>(t=>t.Id)" and manually maintain the cache. * * For examples of creating a observable change sets, see https://github.com/RolandPheasant/DynamicData.Snippets */ //bit of code to generate trades var random = new Random(); //initally load some trades cache.AddOrUpdate(_tradeGenerator.Generate(5_000, true)); TimeSpan RandomInterval() => TimeSpan.FromMilliseconds(random.Next(2500, 5000)); // create a random number of trades at a random interval var tradeGenerator = _schedulerProvider.Background .ScheduleRecurringAction(RandomInterval, () => { var number = random.Next(1, 5); var trades = _tradeGenerator.Generate(number); cache.AddOrUpdate(trades); }); // close a random number of trades at a random interval var tradeCloser = _schedulerProvider.Background .ScheduleRecurringAction(RandomInterval, () => { var number = random.Next(1, 2); cache.Edit(innerCache => { var trades = innerCache.Items .Where(trade => trade.Status == TradeStatus.Live) .OrderBy(t => Guid.NewGuid()).Take(number).ToArray(); var toClose = trades.Select(trade => new Trade(trade, TradeStatus.Closed)); cache.AddOrUpdate(toClose); }); }); //expire closed items from the cache to avoid unbounded data var expirer = cache .ExpireAfter(t => t.Status == TradeStatus.Closed ? TimeSpan.FromMinutes(1) : (TimeSpan?)null, TimeSpan.FromMinutes(1), _schedulerProvider.Background) .Subscribe(x => _logger.Info("{0} filled trades have been removed from memory", x.Count())); return new CompositeDisposable(tradeGenerator, tradeCloser, expirer); }, trade => trade.Id)); }
private IDisposable GenerateTradesAndMaintainCache() { //bit of code to generate trades var random = new Random(); //initally load some trades _tradesSource.AddOrUpdate(_tradeGenerator.Generate(5000, true)); TimeSpan RandomInterval() => TimeSpan.FromMilliseconds(random.Next(1000, 2500)); // create a random number of trades at a random interval var tradeGenerator = _schedulerProvider.Background .ScheduleRecurringAction(RandomInterval, () => { var number = random.Next(1, 5); var trades = _tradeGenerator.Generate(number); _tradesSource.AddOrUpdate(trades); }); // close a random number of trades at a random interval var tradeCloser = _schedulerProvider.Background .ScheduleRecurringAction(RandomInterval, () => { var number = random.Next(1, 2); _tradesSource.Edit(updater => { var trades = updater.Items .Where(trade => trade.Status == TradeStatus.Live) .OrderBy(t => Guid.NewGuid()).Take(number).ToArray(); var toClose = trades.Select(trade => new Trade(trade, TradeStatus.Closed)); _tradesSource.AddOrUpdate(toClose); }); }); return(new CompositeDisposable(tradeGenerator, tradeCloser)); }
public TradeService(ILogger logger, TradeGenerator tradeGenerator, OcDispatcher backgroundOcDispatcher) { _logger = logger; _tradeGenerator = tradeGenerator; _backgroundOcDispatcher = backgroundOcDispatcher; All = new ObservableCollection <Trade>(_tradeGenerator.Generate(5_000, true)); Live = All.Filtering(t => t.Status == TradeStatus.Live).For(_consumer); var random = new Random(); TimeSpan RandomInterval() => TimeSpan.FromMilliseconds(random.Next(2500, 5000)); // create a random number of trades at a random interval RecurringAction tradeEmitter = new RecurringAction(() => { var number = random.Next(1, 5); var trades = _tradeGenerator.Generate(number); foreach (Trade trade in trades) { _backgroundOcDispatcher.Invoke(() => All.Add(trade)); } }, RandomInterval); List <Trade> closedTrades = new List <Trade>(); //close a random number of trades at a random interval RecurringAction tradeCloser = new RecurringAction(() => { var number = random.Next(1, 2); for (int i = 1; i <= number; i++) { _backgroundOcDispatcher.Invoke(() => { Trade trade = All[random.Next(0, All.Count - 1)]; trade.Status = TradeStatus.Closed; trade.CloseTimestamp = DateTime.Now; closedTrades.Add(trade); }); } }, RandomInterval); //expire closed items from the cache to avoid unbounded data RecurringAction tradeRemover = new RecurringAction(() => { _backgroundOcDispatcher.Invoke(() => { for (var index = closedTrades.Count - 1; index >= 0; index--) { Trade closedTrade = closedTrades[index]; if ((DateTime.Now - closedTrade.CloseTimestamp).Minutes >= 1) { All.Remove(closedTrade); closedTrades.RemoveAt(index); } } }); }, () => TimeSpan.FromMinutes(1)); //log changes OcDispatcher logPropertyChangedOcDispatcher = new OcDispatcher(); LogChanges(logPropertyChangedOcDispatcher); _cleanup = new CompositeDisposable( _consumer, tradeEmitter, tradeCloser, logPropertyChangedOcDispatcher, tradeRemover); }