I’m trying to make a simple indicator for delta divergence. I can’t figure out how to get the bid/ask data in the indicator. How do I implement historic bid/ask so I can make an accurate delta calculation. Essentially I’m trying to replicate the delta number that you can find in the volumetric chart. I have tick data enabled.
I’ve implemented my own cumulative delta indicator using bid/ask, price and volume. In order to get it working correctly I had to add a 1 tick data series using:
AddDataSeries(BarsPeriodType.Tick, 1);
Then during OnBarUpdate (for the tick series) you can get bid, ask, price, and volume using:
This should be all you need to get started calculating delta during both historic and live states. No need to use the OnMarketData event. I can provide more detail on the calculation itself if you need it.
Downloading one as Maverick mentioned is definitely a viable option. If you still want to roll your own, here’s the core functions of my version. Note that I have some options not in the NT version, such as calculating the delta momentum (momo). You can just ignore those parts for the basic delta calculation.
private long _currentMomentum = 0;
private int lastBar = -1;
private long lastVolume = 0;
private int tickNumber = 1;
private int totalTickVolume = 0;
//private bool _haveFirstReatimeTick = false;
protected override void OnBarUpdate()
{
if (BarsInProgress == _barsIdx)
{
DeltaOpen[0] = _deltaOpen;
DeltaHigh[0] = _deltaHigh;
DeltaLow[0] = _deltaLow;
if (CalculateAsMomo)
{
if (State == State.Historical)
{
if (CurrentBar != lastBar) { tickNumber = 1; }
else tickNumber++;
lastBar = CurrentBar;
if (DoPrintLogging) Print($"CD HISTORY BarIdx{CurrentBar} Tick{tickNumber}: Volume{Volume[0]} DC{_deltaClose} CM{_currentMomentum}");
if (((_deltaClose < 0 && _currentMomentum < 0) ||
(_deltaClose > 0 && _currentMomentum > 0))
)
{
if (DoPrintLogging) Print($"CD BarIdx{CurrentBar}: Setting DeltaClose to DC{_deltaClose} + CM{_currentMomentum}");
DeltaClose[0] = _deltaClose + _currentMomentum;
}
else
{
if (DoPrintLogging) Print($"CD BarIdx{CurrentBar}: Setting DeltaClose to DC{_deltaClose}");
DeltaClose[0] = _deltaClose;
}
}
else
{
double prevDeltaClose = 0;
if (DeltaClose.IsValidDataPoint(1)) prevDeltaClose = DeltaClose[1];
if (CurrentBar != lastBar) { tickNumber = 1; lastVolume = 0; }
else tickNumber++;
lastBar = CurrentBar;
long tickVolume = Bars.GetVolume(CurrentBar) - lastVolume;
lastVolume = Bars.GetVolume(CurrentBar);
if (DoPrintLogging) Print($"CD LIVE BarIdx{CurrentBar} Tick{tickNumber}: Volume{Volume[0]} TickVolume{tickVolume} DC{_deltaClose} CM{_currentMomentum}");
//<-- CalcDelta?? if (Calculate==Calculate.OnEachTick)??
//CalcDelta(BarsArray[_barsIdx], tickVolume);
if (((_deltaClose < 0 && prevDeltaClose < 0) ||
(_deltaClose > 0 && prevDeltaClose > 0))
)
{
//if (DoPrintLogging) Print($"CD BarIdx{CurrentBar}: Setting DeltaClose to DC{_deltaClose} + PD{prevDeltaClose}");
DeltaClose[0] = _deltaClose + prevDeltaClose;
}
else
{
//if (DoPrintLogging) Print($"CD BarIdx{CurrentBar}: Setting DeltaClose to DC{_deltaClose}");
DeltaClose[0] = _deltaClose;
}
}
}
else
DeltaClose[0] = _deltaClose;
//set color for the close plot, this will change the hightlight color in the databox
if (Values[CloseValueIndex][0] > 0) { PlotBrushes[CloseValueIndex][0] = CandleUpBrush; }
else { PlotBrushes[CloseValueIndex][0] = CandleDownBrush; }
}
if (BarsInProgress == _sessionIdx)
{
if (BarsArray[_sessionIdx].IsFirstBarOfSession)
{
clearDelta();
}
}
if (BarsInProgress == _tickIdx) //&& (State == History ||(State==Live && Calculate!=Calculate.OnEachTick)) ??
{
int currentPrimaryBarIndex = CurrentBars[_barsIdx];
if (currentPrimaryBarIndex < 0) return;
if (currentPrimaryBarIndex != _currentBarIndex)
{//new bar...
totalTickVolume = (int)Volume[0];
if (Period == DeltaPeriod.Bar)
{
long currentDelta = _deltaClose;
clearDelta();
if (CalculateAsMomo)
{
double lastDeltaClose = 0;
if (currentPrimaryBarIndex > 1)
lastDeltaClose = DeltaClose.GetValueAt(currentPrimaryBarIndex - 1);
if (currentDelta > 0)
{
if (lastDeltaClose > 0) _currentMomentum += currentDelta;
else _currentMomentum = currentDelta;
}
else if (currentDelta < 0)
{
if (lastDeltaClose < 0) _currentMomentum += currentDelta;
else _currentMomentum = currentDelta;
}
else _currentMomentum = 0;
}
}
else if (Period == DeltaPeriod.Session)
{
_deltaOpen = _deltaClose;
_deltaHigh = _deltaClose;
_deltaLow = _deltaClose;
_lastMarketEventPressure = 0;
}
_currentBarIndex = currentPrimaryBarIndex;
}
else
totalTickVolume += (int)Volume[0];
if (DoPrintLogging) Print($"CD TICK TickIdx{CurrentBar} BarIdx{currentPrimaryBarIndex}: Volume{Volume[0]} TotalTickVolume{totalTickVolume} DC{_deltaClose} CM{_currentMomentum}");
CalcDelta(BarsArray[_tickIdx], BarsArray[_tickIdx].GetVolume(CurrentBar));
}
}
private void CalcDelta(Bars bars, long vol)
{
double bid = bars.GetBid(CurrentBar);
double ask = bars.GetAsk(CurrentBar);
double price = bars.GetClose(CurrentBar);
if (vol >= SizeFilter)
addDelta(price, bid, ask, vol);
if (_deltaClose > _deltaHigh) _deltaHigh = _deltaClose;
if (_deltaClose < _deltaLow) _deltaLow = _deltaClose;
}
private void addDelta(double price, double bid, double ask, long vol)
{
if (price >= ask)
{
_deltaClose += vol;
_lastMarketEventPressure = 1;
}
else if (price <= bid)
{
_deltaClose -= vol;
_lastMarketEventPressure = -1;
}
else
{
if (_lastMarketEventPressure == 1) _deltaClose += vol;
else if (_lastMarketEventPressure == -1) _deltaClose -= vol;
}
}
Thanks for sharing. Human written code looks much different from AI so It’s a nice reference.
Have you considered or tried using onmarketdata bid and ask for realtime?
I’ve used OnMarketReplay in a few indicators I’ve written like:
AudiblePriceAction (similar to tick strike or bookmap’s market pulse) and Spread (shows the latest price spread). It’s also been useful for non-bid/ask events like capturing the settlement price. In general though I try to avoid it given the computational overhead and historical data limitations. Not to mention with a 1-Tick historical series, or realtime with calculate set to “on each tick”, OnBarUpdate is called before OnMarketData allowing a slightly faster reaction to the event in either state.
I’ve found the doc page on developing for tick replay to be invaluable as well. It’s a bit deep and (for me) required several readings, but it does an excellent job breaking down the event delivery timing in various scenarios (live vs history, tick replay vs no tick replay)