private static RenkoCandleMessage CreateCandle(MarketDataMessage message, DataType buildFrom, ref VolumeProfileBuilder volumeProfile, Unit boxSize, decimal openPrice, decimal renkoStep, decimal price, decimal?volume, Sides?side, DateTimeOffset time, decimal?oi) { var candle = new RenkoCandleMessage { SecurityId = message.SecurityId, BoxSize = boxSize, BuildFrom = buildFrom, OpenPrice = openPrice, ClosePrice = openPrice + renkoStep, //HighPrice = openPrice + renkoStep, //LowPrice = openPrice, OpenVolume = volume, CloseVolume = volume, HighVolume = volume, LowVolume = volume, OpenTime = time, CloseTime = time, HighTime = time, LowTime = time, RelativeVolume = side == null ? null : (side == Sides.Buy ? volume : -volume), TotalTicks = 1, State = CandleStates.Active, OpenInterest = oi, }; if (volume != null) { candle.TotalPrice += price * volume.Value; candle.TotalVolume += volume.Value; } if (renkoStep > 0) { candle.HighPrice = candle.ClosePrice; candle.LowPrice = candle.OpenPrice; } else { candle.HighPrice = candle.OpenPrice; candle.LowPrice = candle.ClosePrice; } if (message.IsCalcVolumeProfile) { var levels = new List <CandlePriceLevel>(); volumeProfile = new VolumeProfileBuilder(levels); volumeProfile.Update(price, volume, side); candle.PriceLevels = levels; } return(candle); }
private static void UpdateCandle(PnFCandleMessage currentPnFCandle, decimal price, decimal?volume, DateTimeOffset time, Sides?side, decimal?oi, VolumeProfileBuilder volumeProfile) { currentPnFCandle.TotalTicks = currentPnFCandle.TotalTicks ?? 0 + 1; if (volume != null) { var v = volume.Value; currentPnFCandle.TotalVolume += v; currentPnFCandle.TotalPrice += v * price; currentPnFCandle.RelativeVolume = currentPnFCandle.RelativeVolume ?? 0 + (side == Sides.Buy ? v : -v); } currentPnFCandle.CloseVolume = volume; currentPnFCandle.CloseTime = time; volumeProfile?.Update(price, volume, side); currentPnFCandle.OpenInterest = oi; }
/// <inheritdoc /> public override void Process(MarketDataMessage message, CandleMessage currentCandle, ICandleBuilderValueTransform transform, ref VolumeProfileBuilder volumeProfile, IList <CandleMessage> changes) { var currentRenkoCandle = (RenkoCandleMessage)currentCandle; var price = transform.Price; var volume = transform.Volume; var time = transform.Time; var side = transform.Side; var oi = transform.OpenInterest; var boxSize = message.GetArg <Unit>(); var renkoStep = (decimal)(1 * boxSize); if (currentRenkoCandle == null) { var openPrice = price.Floor(renkoStep); changes.Add(CreateCandle(message, ref volumeProfile, boxSize, openPrice, renkoStep, price, volume, side, time, oi)); } else { if (currentRenkoCandle.LowPrice <= price && price <= currentRenkoCandle.HighPrice) { currentRenkoCandle.TotalTicks++; if (volume != null) { currentRenkoCandle.TotalVolume += volume.Value; currentRenkoCandle.TotalPrice += volume.Value * price; currentRenkoCandle.RelativeVolume += side == Sides.Buy ? volume : -volume; } currentRenkoCandle.CloseVolume = volume; currentRenkoCandle.CloseTime = time; volumeProfile?.Update(price, volume, side); currentRenkoCandle.OpenInterest = oi; changes.Add(currentRenkoCandle); } else { currentRenkoCandle.State = CandleStates.Finished; changes.Add(currentRenkoCandle); int times; bool isUp; decimal openPrice; if (price < currentRenkoCandle.LowPrice) { times = (int)((currentRenkoCandle.LowPrice - price) / renkoStep) + 1; isUp = false; openPrice = currentRenkoCandle.LowPrice; } else { times = (int)((price - currentRenkoCandle.HighPrice) / renkoStep) + 1; isUp = true; openPrice = currentRenkoCandle.HighPrice; } for (var i = 0; i < times; i++) { if (isUp) { currentRenkoCandle = CreateCandle(message, ref volumeProfile, boxSize, openPrice, renkoStep, price, volume, side, time, oi); changes.Add(currentRenkoCandle); openPrice += renkoStep; } else { currentRenkoCandle = CreateCandle(message, ref volumeProfile, boxSize, openPrice, -renkoStep, price, volume, side, time, oi); changes.Add(currentRenkoCandle); openPrice -= renkoStep; } currentRenkoCandle.State = CandleStates.Finished; } currentRenkoCandle.State = CandleStates.Active; } } }