MetaTrader has no built-in Ultimate Oscillator, so this is a worthwhile custom build — buying pressure and true range summed over three windows and blended. See the explainer.
What you’ll need
- MetaTrader 5 with MetaEditor
- Save as
AlgoGen.UO.mq5underMQL5/Indicators/
The source
//+------------------------------------------------------------------+
//| AlgoGen.UO.mq5 |
//| Copyright 2026, AlgoGen |
//| https://www.algogen.io |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, AlgoGen"
#property link "https://www.algogen.io"
#property version "1.00"
#property indicator_separate_window
#property indicator_minimum 0
#property indicator_maximum 100
#property indicator_buffers 3
#property indicator_plots 1
#property indicator_label1 "UO"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDodgerBlue
#property indicator_width1 2
#property indicator_level1 30.0
#property indicator_level2 70.0
input int InpS1 = 7;
input int InpS2 = 14;
input int InpS3 = 28;
double UOBuffer[], BP[], TR[];
int OnInit()
{
SetIndexBuffer(0, UOBuffer, INDICATOR_DATA);
SetIndexBuffer(1, BP, INDICATOR_CALCULATIONS);
SetIndexBuffer(2, TR, INDICATOR_CALCULATIONS);
IndicatorSetString(INDICATOR_SHORTNAME, "AlgoGen UO");
return(INIT_SUCCEEDED);
}
double SumOf(const double &buf[], int i, int period)
{ double s = 0.0; for(int j = 0; j < period; j++) s += buf[i - j]; return s; }
int OnCalculate(const int rates_total, const int prev_calculated,
const datetime &time[], const double &open[],
const double &high[], const double &low[],
const double &close[], const long &tick_volume[],
const long &volume[], const int &spread[])
{
if(rates_total < InpS3 + 1) return(0);
int bpStart = (prev_calculated > 1) ? prev_calculated - 1 : 1;
for(int i = bpStart; i < rates_total; i++)
{
double pc = close[i - 1];
double trueLow = MathMin(low[i], pc);
BP[i] = close[i] - trueLow;
TR[i] = MathMax(high[i], pc) - trueLow;
}
int start = (prev_calculated > InpS3) ? prev_calculated - 1 : InpS3;
for(int i = start; i < rates_total; i++)
{
double a1 = SumOf(BP, i, InpS1) / SumOf(TR, i, InpS1);
double a2 = SumOf(BP, i, InpS2) / SumOf(TR, i, InpS2);
double a3 = SumOf(BP, i, InpS3) / SumOf(TR, i, InpS3);
UOBuffer[i] = 100.0 * (4 * a1 + 2 * a2 + a3) / 7.0;
}
return(rates_total);
}
//+------------------------------------------------------------------+
Install & compile
- Drop it in
MQL5/Indicators/, press F7. - Drag onto a chart — a separate window shows the UO between 0 and 100 with the 30/70 levels, matching the output chart.
Gotchas
- Buying pressure & true range use the prior close.
MathMin(low, pc)/MathMax(high, pc)are the true-range endpoints — the same idea as ATR. - Sum over each window, then divide.
SumOf(BP)/SumOf(TR)per timeframe; don’t average per-bar ratios. - Fixed 0–100 scale. The
indicator_minimum/maximumpins the pane so the 30/70 levels sit correctly. MQL4 ports directly by swapping theOnCalculatesignature.
Same indicator elsewhere: Python, Pine Script, EasyLanguage, NinjaScript. Then test a UO rule in AlgoGen.
This post is educational, not financial advice. Indicators describe the past; they don’t predict the future. Backtest anything before you risk real money on it.
Sources and further reading
- Technical indicator functions (MetaQuotes)
