public MarketInfo(DateTime objTime, Ticker ticker, MarketDepth depth, List <Trade> trades, bool deepCopy) { Id = ""; Label = ""; PrimaryName = ""; PrimaryCode = ""; SecondaryCode = ""; SecondaryName = ""; Time = objTime; if (ticker != null) { if (deepCopy) { Ticker = new Ticker(ticker); } else { Ticker = ticker; } } else { Ticker = new Ticker(); } MarketDepth = new MarketDepth(depth, deepCopy); if (trades != null) { if (deepCopy) { RecentTrades = new List <Trade>(trades); } else { RecentTrades = trades; } } else { RecentTrades = new List <Trade>(); } }
public MarketDepth(MarketDepth cloneDepth, bool deepCopy) { if (cloneDepth != null) { if (deepCopy) { BidOrders = new List <Order>(cloneDepth.BidOrders); AskOrders = new List <Order>(cloneDepth.AskOrders); } else { BidOrders = cloneDepth.BidOrders; AskOrders = cloneDepth.AskOrders; } } else { Init(); } }
public MarketInfo(DateTime objTime, Ticker ticker, MarketDepth depth, List <Trade> trades) : this(objTime, ticker, depth, trades, false) { }
public MarketInfo(Ticker ticker, MarketDepth depth) : this(DateAndTime.Now, ticker, depth, null, false) { }
public MarketDepth(MarketDepth cloneDepth) : this(cloneDepth, false) { }
/// <summary> /// Emulates the Market data at a given time, given the historical trades /// In order to optimise performances, it keeps previous emulated market and only performs updates /// It implies that the method is called sequentially at increasing timings. /// Note that the marketDepth is only broadly approximated from future trades found in history /// </summary> /// <param name="time">the time at which the market should be emulated</param> /// <returns>a MarketInfo object with emulated ticker, RecentTrades, and Marketdepth</returns> public MarketInfo GetMarket(DateTime time) { _currentMarket.Time = time; // First we move the current trade cursor according to the new time and update the ticker and recent trades accordingly Trade currentTrade; do { currentTrade = Trades[_currentTradeIdx]; _currentMarket.RecentTrades.Add(currentTrade); _currentMarket.Ticker.Volume += currentTrade.Amount; if (currentTrade.Price > _currentMarket.Ticker.High) { _currentMarket.Ticker.High = currentTrade.Price; } if (_currentMarket.Ticker.Low == 0m || currentTrade.Price < _currentMarket.Ticker.Low) { _currentMarket.Ticker.Low = currentTrade.Price; } _currentTradeIdx += 1; } while (currentTrade.Time <= time); _currentMarket.Ticker.Last = currentTrade.Price; // Then we move the previous 24h trades cursor and update the Ticker accordingly var last24hTime = time.AddHours(-24d); var last24HTrade = Trades[_currentLast24HTradeIdx]; while (last24HTrade.Time < last24hTime) { _currentMarket.Ticker.Volume -= last24HTrade.Amount; if (last24HTrade.Price == _currentMarket.Ticker.High) { _currentMarket.Ticker.High = 0m; } if (last24HTrade.Price == _currentMarket.Ticker.Low) { _currentMarket.Ticker.Low = 0m; } _currentLast24HTradeIdx += 1; last24HTrade = Trades[_currentLast24HTradeIdx]; } // if the ticker low or high were reset, recompute them if (_currentMarket.Ticker.Low == 0m || _currentMarket.Ticker.High == 0m) { for (int i = _currentLast24HTradeIdx; i < _currentTradeIdx; i++) { var tempTrade = Trades[i]; if (_currentMarket.Ticker.Low == 0m || tempTrade.Price < _currentMarket.Ticker.Low) { _currentMarket.Ticker.Low = tempTrade.Price; } if (tempTrade.Price > _currentMarket.Ticker.High) { _currentMarket.Ticker.High = tempTrade.Price; } } } // Finally, compute MarketDepth //Identifying executed orders segments to be removed from existing MarketDepth var newMinAskIdx = 0; var existingMinAsk = decimal.MaxValue; var newMaxBidIdx = 0; var existingMaxBid = 0m; if (_currentMarket.MarketDepth.AskOrders.Count > 0) { while (newMinAskIdx < _currentMarket.MarketDepth.AskOrders.Count && _currentMarket.MarketDepth.AskOrders[newMinAskIdx].Time < time) { newMinAskIdx++; } existingMinAsk = _currentMarket.MarketDepth.AskOrders[newMinAskIdx].Price; } if (_currentMarket.MarketDepth.BidOrders.Count > 0) { while (newMaxBidIdx < _currentMarket.MarketDepth.BidOrders.Count && _currentMarket.MarketDepth.BidOrders[newMaxBidIdx].Time < time) { newMaxBidIdx++; } existingMaxBid = _currentMarket.MarketDepth.BidOrders[newMaxBidIdx].Price; } //Computing new depth segments var exitAskCondition = false; var exitBidCondition = false; var newDepth = new MarketDepth(); for (int depthIdx = _currentTradeIdx + 1; depthIdx < Trades.Count && !(exitAskCondition && exitBidCondition); depthIdx++) { var depthTrade = Trades[depthIdx]; if (!exitAskCondition && (newDepth.AskOrders.Count > 0 && depthTrade.Price > newDepth.AskOrders.Last().Price) || (newDepth.AskOrders.Count == 0 && depthTrade.Price > currentTrade.Price)) { if (depthTrade.Price < existingMinAsk) { newDepth.AskOrders.Add(depthTrade.ToOrder(OrderType.Sell)); } else { exitAskCondition = true; } } else if (!exitBidCondition && (newDepth.BidOrders.Count > 0 && depthTrade.Price < newDepth.BidOrders.Last().Price) || (newDepth.BidOrders.Count == 0 && depthTrade.Price < currentTrade.Price)) { if (depthTrade.Price > existingMaxBid) { newDepth.BidOrders.Add(depthTrade.ToOrder(OrderType.Buy)); } else { exitBidCondition = true; } } } //joining former and new marketdepth segments newDepth.AskOrders.AddRange(_currentMarket.MarketDepth.AskOrders.Skip(newMinAskIdx)); newDepth.BidOrders.AddRange(_currentMarket.MarketDepth.BidOrders.Skip(newMaxBidIdx)); _currentMarket.MarketDepth = newDepth; return(_currentMarket); }