What it does
A currency pair only shows how one currency moves against another. A strength meter tries to separate the two by looking at many pairs at once. This indicator measures each of the eight major currencies (USD, EUR, GBP, JPY, CHF, CAD, AUD, NZD) against the other seven and ranks them. It plots the strength of the two currencies in your chart symbol and shows a table of all eight.
How it works
- For each of the 28 pairs formed by the eight majors, the script takes the percentage change over the lookback: % change = (close − close N bars earlier) ÷ close N bars earlier × 100. Only closed bars are used, with lookahead off.
- Each currency appears in seven pairs. When it is the base currency, the pair's change counts as is. When it is the quote currency, the sign is flipped, because a falling EUR/USD means a rising USD.
- The currency's strength is the average of those seven signed changes. For example, EUR strength = (EUR/USD + EUR/GBP + EUR/JPY + EUR/CHF + EUR/AUD + EUR/NZD + EUR/CAD) ÷ 7, using each pair's % change.
- The eight scores add up to zero, so the meter shows relative strength, not absolute.
- The chart pair's base and quote currencies are read from the symbol and plotted as two thick lines.
The script uses 28 data requests, one per pair, which is within TradingView's per-script limit.
How to use it
- Pairs made of a strong currency against a weak one have shown the clearest relative moves over the lookback. Some traders use the table as a shortlist and then apply their own analysis.
- When the base currency line crosses above the quote currency line, the base has become the stronger of the two over the lookback; an alert is available for this and for the opposite cross.
- Short lookbacks (5 to 10 bars) react quickly but are noisy. Longer ones (50 to 100) describe the broader picture.
- Background on how pairs move together is in the lesson on currency correlation.
Settings
| Input | Default | What it changes |
|---|---|---|
| Data feed prefix | OANDA | Source of the 28 pair prices |
| Timeframe | Chart | Timeframe of the calculation |
| Lookback (bars) | 20 | Period of the % change |
| Plot all eight currencies | Off | Extra lines for every currency |
| Show ranking table | On | Strongest-to-weakest table |
| Table position | Top right | Placement |
| Chart base / quote colors | Blue / orange | Appearance only |
Limitations
Strength is derived from past percentage changes, so it describes what has already happened and does not predict the next move. If the chosen feed does not list a pair, that pair is treated as unchanged, which distorts the scores, so pick a prefix that carries all 28 majors and crosses. Pairs trade on slightly different sessions and holidays, which can create small mismatches. The chart lines only appear when the chart symbol is a pair of two majors; for other symbols, use the table.
Pine Script source
In TradingView open Pine Editor, paste the code, click Save and then Add to chart.
FXP_CurrencyStrengthMeter.pine
128 lines
// © FXPIPS ONLINE — https://fxpips.online/tradingview-indicators/currency-strength-meter/
// License: MIT. Educational tool — not financial advice. Trading involves substantial risk.
//@version=6
// Measures the relative strength of the eight major currencies (USD, EUR, GBP, JPY, CHF,
// CAD, AUD, NZD) from the percentage change of the 28 pairs they form over N closed bars.
// Each currency's score is the average of its seven pair changes (signed so that a rise
// in the currency counts as positive). Uses 28 request.security() calls, within Pine's
// limit, with lookahead off and closed-bar values only.
indicator("FXP Currency Strength Meter", shorttitle = "FXP CSM", overlay = false, precision = 3)
// ── Inputs ─────────────────────────────────────────────────────────────
grpData = "Data"
exch = input.string("OANDA", "Data feed prefix", group = grpData, tooltip = "Exchange prefix used for all 28 pairs, e.g. OANDA, FX, FX_IDC, FOREXCOM. Pick one that lists every major cross.")
tfIn = input.timeframe("", "Timeframe", group = grpData, tooltip = "Empty = chart timeframe.")
lenN = input.int(20, "Lookback (bars)", minval = 1, maxval = 500, group = grpData)
grpDisp = "Display"
showAll = input.bool(false, "Plot all eight currencies", group = grpDisp)
showTbl = input.bool(true, "Show ranking table", group = grpDisp)
posIn = input.string("Top right", "Table position", options = ["Top right", "Top left", "Bottom right", "Bottom left"], group = grpDisp)
colBase = input.color(#2962ff, "Chart base currency", group = grpDisp)
colQuote = input.color(#ff9800, "Chart quote currency", group = grpDisp)
// ── Pair changes ───────────────────────────────────────────────────────
pct(string pair) =>
float v = request.security(exch + ":" + pair, tfIn, ta.roc(close, lenN)[1], lookahead = barmerge.lookahead_off, ignore_invalid_symbol = true)
nz(v)
EURUSD = pct("EURUSD")
GBPUSD = pct("GBPUSD")
AUDUSD = pct("AUDUSD")
NZDUSD = pct("NZDUSD")
USDJPY = pct("USDJPY")
USDCHF = pct("USDCHF")
USDCAD = pct("USDCAD")
EURGBP = pct("EURGBP")
EURJPY = pct("EURJPY")
EURCHF = pct("EURCHF")
EURAUD = pct("EURAUD")
EURNZD = pct("EURNZD")
EURCAD = pct("EURCAD")
GBPJPY = pct("GBPJPY")
GBPCHF = pct("GBPCHF")
GBPAUD = pct("GBPAUD")
GBPNZD = pct("GBPNZD")
GBPCAD = pct("GBPCAD")
AUDJPY = pct("AUDJPY")
AUDCHF = pct("AUDCHF")
AUDNZD = pct("AUDNZD")
AUDCAD = pct("AUDCAD")
NZDJPY = pct("NZDJPY")
NZDCHF = pct("NZDCHF")
NZDCAD = pct("NZDCAD")
CADJPY = pct("CADJPY")
CADCHF = pct("CADCHF")
CHFJPY = pct("CHFJPY")
// ── Currency scores (average of seven signed pair changes) ─────────────
float sUSD = (-EURUSD - GBPUSD - AUDUSD - NZDUSD + USDJPY + USDCHF + USDCAD) / 7
float sEUR = ( EURUSD + EURGBP + EURJPY + EURCHF + EURAUD + EURNZD + EURCAD) / 7
float sGBP = ( GBPUSD - EURGBP + GBPJPY + GBPCHF + GBPAUD + GBPNZD + GBPCAD) / 7
float sJPY = (-USDJPY - EURJPY - GBPJPY - AUDJPY - NZDJPY - CADJPY - CHFJPY) / 7
float sCHF = (-USDCHF - EURCHF - GBPCHF - AUDCHF - NZDCHF - CADCHF + CHFJPY) / 7
float sCAD = (-USDCAD - EURCAD - GBPCAD - AUDCAD - NZDCAD + CADJPY + CADCHF) / 7
float sAUD = ( AUDUSD - EURAUD - GBPAUD + AUDJPY + AUDCHF + AUDNZD + AUDCAD) / 7
float sNZD = ( NZDUSD - EURNZD - GBPNZD - AUDNZD + NZDJPY + NZDCHF + NZDCAD) / 7
strengthOf(string cur) =>
switch cur
"USD" => sUSD
"EUR" => sEUR
"GBP" => sGBP
"JPY" => sJPY
"CHF" => sCHF
"CAD" => sCAD
"AUD" => sAUD
"NZD" => sNZD
=> float(na)
string baseCur = syminfo.basecurrency
string quoteCur = syminfo.currency
float sBase = strengthOf(baseCur)
float sQuote = strengthOf(quoteCur)
// ── Plots ──────────────────────────────────────────────────────────────
hline(0, "Zero", color = color.new(color.gray, 60), linestyle = hline.style_dashed)
plot(sBase, "Base currency strength", color = colBase, linewidth = 2)
plot(sQuote, "Quote currency strength", color = colQuote, linewidth = 2)
plot(showAll ? sUSD : na, "USD", color = color.new(#4caf50, 30))
plot(showAll ? sEUR : na, "EUR", color = color.new(#2196f3, 30))
plot(showAll ? sGBP : na, "GBP", color = color.new(#9c27b0, 30))
plot(showAll ? sJPY : na, "JPY", color = color.new(#f44336, 30))
plot(showAll ? sCHF : na, "CHF", color = color.new(#795548, 30))
plot(showAll ? sCAD : na, "CAD", color = color.new(#e91e63, 30))
plot(showAll ? sAUD : na, "AUD", color = color.new(#ffc107, 30))
plot(showAll ? sNZD : na, "NZD", color = color.new(#00bcd4, 30))
// ── Ranking table ──────────────────────────────────────────────────────
tablePos = switch posIn
"Top left" => position.top_left
"Bottom right" => position.bottom_right
"Bottom left" => position.bottom_left
=> position.top_right
var table tbl = table.new(tablePos, 2, 9, bgcolor = color.new(color.black, 20), frame_color = color.new(color.gray, 60), frame_width = 1, border_color = color.new(color.gray, 80), border_width = 1)
if showTbl and barstate.islast
array<string> names = array.from("USD", "EUR", "GBP", "JPY", "CHF", "CAD", "AUD", "NZD")
array<float> vals = array.from(sUSD, sEUR, sGBP, sJPY, sCHF, sCAD, sAUD, sNZD)
array<int> rank = vals.sort_indices(order.descending)
table.cell(tbl, 0, 0, "Currency", text_color = color.gray, text_size = size.small)
table.cell(tbl, 1, 0, "% (" + str.tostring(lenN) + " bars)", text_color = color.gray, text_size = size.small)
for i = 0 to 7
int k = rank.get(i)
string nm = names.get(k)
float v = vals.get(k)
bool hl = nm == baseCur or nm == quoteCur
color bg = v >= 0 ? color.new(#26a69a, 60) : color.new(#ef5350, 60)
table.cell(tbl, 0, i + 1, nm, text_color = hl ? color.yellow : color.white, text_size = size.small)
table.cell(tbl, 1, i + 1, str.tostring(v, "#.###"), text_color = color.white, bgcolor = bg, text_size = size.small)
// ── Alerts ─────────────────────────────────────────────────────────────
bool baseAbove = barstate.isconfirmed and sBase > sQuote and sBase[1] <= sQuote[1]
bool baseBelow = barstate.isconfirmed and sBase < sQuote and sBase[1] >= sQuote[1]
alertcondition(baseAbove, "Base currency turns stronger", "{{ticker}}: base currency strength crossed above quote currency strength")
alertcondition(baseBelow, "Base currency turns weaker", "{{ticker}}: base currency strength crossed below quote currency strength")

