public void Replace(CandleSample sample) { TimeSpanMs = sample.TimeSpanMs; LowPrice = sample.LowPrice; HighPrice = sample.HighPrice; OpenPrice = sample.OpenPrice; ClosePrice = sample.ClosePrice; BuyVolume = sample.BuyVolume; SellVolume = sample.SellVolume; Count = sample.Count; }
public void AggregateSample(CandleSample sample) { if (sample == null) { return; } this.TimeSpanMs += sample.TimeSpanMs; if (sample.LowPrice < this.LowPrice) { this.LowPrice = sample.LowPrice; } if (sample.HighPrice > this.HighPrice) { this.HighPrice = sample.HighPrice; } this.BuyVolume += sample.BuyVolume; this.SellVolume += sample.SellVolume; this.Count += sample.Count; this.ClosePrice = sample.ClosePrice; }
/// <summary> /// Generates random market candle stream /// </summary> public static CandleSample[] GenerateRandom(int count, DateTime startDate, int msInterval, int msIntervalDeviation, int priceDirChangeEvery, int priceChangeAccel, float currentMidPrice) { if (count <= 0) { count = 1; } if (msInterval == 0) { msInterval = 1000; } if (priceDirChangeEvery <= 0) { priceDirChangeEvery = 11; } if (priceChangeAccel == 0) { priceChangeAccel = 8; } var result = new CandleSample[count]; var dt = startDate; var deltaT = msInterval; var priceVelocity = -1.0f + (2.0f * (float)rnd.NextRandomDouble); var priceSteps = 0; var price = currentMidPrice; for (var i = 0; i < count; i++) { var sample = new CandleSample(dt); dt = dt.AddMilliseconds(deltaT); if (msIntervalDeviation != 0) { deltaT += rnd.NextScaledRandomInteger(-msIntervalDeviation, msIntervalDeviation); if (deltaT == 0) { deltaT = msInterval; } if (i % 8 == 0) { deltaT = msInterval; } } priceSteps++; if (priceSteps >= rnd.NextScaledRandomInteger( priceDirChangeEvery - 4, priceDirChangeEvery + 4)) { var accel = (float)rnd.NextScaledRandomInteger(1, priceChangeAccel); priceVelocity = -accel + (2.0f * accel * (float)rnd.NextRandomDouble); priceSteps = 0; } price += priceVelocity; var pSample = i > 0 ? result[i - 1] : null; sample.OpenPrice = pSample != null ? pSample.ClosePrice : price; sample.ClosePrice = price + (float)rnd.NextScaledRandomDouble(-0.08f * currentMidPrice, +0.08f * currentMidPrice); sample.LowPrice = Math.Min(sample.OpenPrice, sample.ClosePrice) - (float)rnd.NextScaledRandomDouble(0, +0.05f * currentMidPrice); sample.HighPrice = Math.Max(sample.OpenPrice, sample.ClosePrice) + (float)rnd.NextScaledRandomDouble(0, +0.05f * currentMidPrice); sample.Count = 1; result[i] = sample; } return(result); }
/// <summary> /// Synthesizes a stream of candle samples from Quote and Trade samples coming from the market (i.e SecDB file) /// </summary> /// <param name="source">Source of market data</param> /// <param name="secSamplingPeriod">The output sampling period</param> /// <param name="funcQuote">Aggregation func for Quote, if null default is used which aggregates best bid</param> /// <param name="funcTrade">Aggregation func for Quote, if null default is used which aggregates buy and sell volumes</param> /// <returns>Synthesized candle stream</returns> public static IEnumerable <CandleSample> SynthesizeCandles(this IEnumerable <ITimeSeriesSample> source, uint secSamplingPeriod, Action <CandleSample, SecDBFileReader.QuoteSample, int> funcQuote = null, Action <CandleSample, SecDBFileReader.TradeSample, int> funcTrade = null) { if (source == null) { yield break; } if (funcQuote == null) { funcQuote = (cs, qs, i) => { var bestBid = qs.Bids.LastOrDefault(); if (Math.Abs(bestBid.Price) < float.Epsilon) { return; } if (i == 0) { cs.OpenPrice = bestBid.Price; } cs.HighPrice = Math.Max(cs.HighPrice, bestBid.Price); cs.LowPrice = Math.Abs(cs.LowPrice) > float.Epsilon ? Math.Min(cs.LowPrice, bestBid.Price) : bestBid.Price; cs.ClosePrice = bestBid.Price; }; } if (funcTrade == null) { funcTrade = (cs, ts, i) => { if (!ts.IsQty) { return; } if (ts.Side == SecDBFileReader.TradeSample.SideType.Buy) { cs.BuyVolume += ts.Qty; } else { cs.SellVolume += ts.Qty; } }; } CandleSample emit = null; var filteredSamples = source.Where(s => s is SecDBFileReader.QuoteSample || s is SecDBFileReader.TradeSample); var aggregateCount = 0; foreach (var sample in filteredSamples) { if (emit != null && (sample.TimeStamp - emit.TimeStamp).TotalSeconds > secSamplingPeriod) { emit.TimeSpanMs = (long)(sample.TimeStamp - emit.TimeStamp).TotalMilliseconds; yield return(emit); emit = null; } if (emit == null) { emit = new CandleSample(sample.TimeStamp); aggregateCount = 0; } var qts = sample as SecDBFileReader.QuoteSample; if (qts != null) { funcQuote(emit, qts, aggregateCount); } var tds = sample as SecDBFileReader.TradeSample; if (tds != null) { funcTrade(emit, tds, aggregateCount); } aggregateCount++; } if (emit != null) { yield return(emit); } }