Indicator · Pine Script v6 · On the chart

Market Monitor - 15m

by chris-c-thomas

Market Monitor - 15m is a directional bias chart overlay designed for 15-minute intraday chart analysis.

View on GitHub

GitHub stars14on the repository
Pine versionv6current
Lines of code334
Settings19inputs
LicenceMIT
Last update6 months ago8 Apr 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

334 lines of Pine Script v6 from scripts/market-monitor/market-monitor-15min.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

market-monitor-15min.pine
// ============================================================================
// Market Monitor — 15-Minute Optimized
// Timeframe: 15-minute (primary)
// Version: 1.0.0
// Author: Chris Thomas
// ============================================================================
// Directional-bias overlay purpose-built for 15-minute chart monitoring in
// multi-chart watchlist workflows. Serves as the reconnaissance bridge
// between the 15m 0DTE Scalper and the 15m Trend Compass.
//
// Enhancements tuned for the 26-bar RTH session:
//   - Weighted bias scoring (structural 2x, confirmation 1x)
//   - 1H Anchor EMA for immediate higher-timeframe institutional alignment
//   - Session phase detection (Open Drive / Morning / Midday / Power Hour / Close)
//   - NYSE TICK Index integration for market breadth
//   - TTM Squeeze detection (20-bar default)
//   - ATR regime classification with 260-bar lookback (~10 trading days)
//   - 30-minute Opening Range (first 2 bars of the session)
// ============================================================================

// ============================================================================
// TradingView Pine Script v6
// ============================================================================
//@version=6
indicator(
     title      = "Market Monitor - 15m",
     shorttitle = "MM-15m",
     overlay    = true,
     max_labels_count  = 100,
     max_lines_count   = 200,
     max_boxes_count   = 50,
     max_bars_back     = 5000
 )

// ============================================================================
// CONSTANTS & COLORS
// ============================================================================
var string GP_EMA      = "EMA Ribbon"
var string GP_VWAP     = "VWAP & Levels"
var string GP_HTF      = "Higher Timeframe"
var string GP_MOM      = "Momentum & Volatility"
var string GP_SCORE    = "Scoring Engine"
var string GP_DASH     = "Dashboard"

var color C_BULL       = #00E676
var color C_BEAR       = #FF1744
var color C_NEUTRAL    = #B0BEC5
var color C_YELLOW     = #FFD600
var color C_ORANGE     = #FF9100
var color C_CYAN       = #00BCD4
var color C_PURPLE     = #7C4DFF
var color C_DASH_BG    = color.new(#1A1A2E, 5)
var color C_DASH_TEXT  = #E0E0E0
var color C_DASH_HEADER = #7C4DFF
var color C_CLOUD_BULL = color.new(#00E676, 85)
var color C_CLOUD_BEAR = color.new(#FF1744, 85)
var color C_CLOUD_MIX  = color.new(#FFD600, 90)
var color C_BG_BULL    = color.new(#00E676, 95)
var color C_BG_BEAR    = color.new(#FF1744, 95)

// ============================================================================
// INPUTS
// ============================================================================
// --- EMA Ribbon ---
int    i_emaFastLen  = input.int(9,   "Fast EMA",        minval=2, group=GP_EMA)
int    i_emaMidLen   = input.int(21,  "Mid EMA",         minval=2, group=GP_EMA)
int    i_emaSlowLen  = input.int(50,  "Slow EMA",        minval=2, group=GP_EMA)
bool   i_showCloud   = input.bool(true, "Show EMA Cloud",          group=GP_EMA)

// --- VWAP & Levels ---
bool   i_useVwap     = input.bool(true,  "Use Session VWAP",       group=GP_VWAP)
float  i_vwapMult    = input.float(1.5,  "VWAP Band Multiplier",   minval=0.5, step=0.1, group=GP_VWAP)
bool   i_showPrior   = input.bool(true,  "Show Prior Day Levels",  group=GP_VWAP)

// --- Higher Timeframe ---
bool   i_useHTF      = input.bool(true,  "Use 1H Anchor EMA",      group=GP_HTF)
int    i_htfEmaLen   = input.int(50,     "1H Anchor EMA Length",   minval=10, group=GP_HTF)

// --- Momentum & Volatility ---
int    i_rsiLen      = input.int(14,  "RSI Length",      minval=2, group=GP_MOM)
int    i_adxLen      = input.int(14,  "ADX Length",      minval=2, group=GP_MOM)
int    i_volSmaLen   = input.int(20,  "Volume SMA",      minval=5, group=GP_MOM)
int    i_atrPctlLB   = input.int(260, "ATR Pctl Lookback", minval=50, group=GP_MOM, tooltip="260 bars = 10 days on 15m")
bool   i_useTick     = input.bool(true, "Use NYSE TICK",           group=GP_MOM)

// --- Scoring Engine ---
bool   i_useWeighted = input.bool(true, "Use Weighted Scoring (2x/1x)", group=GP_SCORE)
bool   i_bgTint      = input.bool(true, "Color Background on High Score", group=GP_SCORE)

// --- Dashboard ---
bool   i_showDash    = input.bool(true,  "Show Dashboard",         group=GP_DASH)
string i_dashPos     = input.string("Bottom Right", "Position", options=["Top Right", "Top Left", "Bottom Right", "Bottom Left"], group=GP_DASH)
string i_dashSize    = input.string("Small", "Size", options=["Tiny", "Small", "Normal", "Large"], group=GP_DASH)

// ============================================================================
// HELPER FUNCTIONS
// ============================================================================
f1(float v) => str.tostring(v, "#.#")
f2(float v) => str.tostring(v, "#.##")

// ============================================================================
// TIME & SESSION PHASE
// ============================================================================
bool isRTH = time(timeframe.period, "0930-1600:1234567") != 0
var int sessionBar = 0
if isRTH and not isRTH[1]
    sessionBar := 1
else if isRTH
    sessionBar += 1

string sessionPhase = "PRE/POST"
if isRTH
    if sessionBar <= 2
        sessionPhase := "OPEN DRIVE"
    else if sessionBar <= 8
        sessionPhase := "MORNING"
    else if sessionBar <= 18
        sessionPhase := "MIDDAY"
    else if sessionBar <= 25
        sessionPhase := "POWER HOUR"
    else
        sessionPhase := "CLOSE"

// ============================================================================
// PRICE & EMA STRUCTURE
// ============================================================================
float emaFast = ta.ema(close, i_emaFastLen)
float emaMid  = ta.ema(close, i_emaMidLen)
float emaSlow = ta.ema(close, i_emaSlowLen)

bool emaBull = emaFast > emaMid and emaMid > emaSlow
bool emaBear = emaFast < emaMid and emaMid < emaSlow

string emaStr = emaBull ? "FULL BULL" : emaBear ? "FULL BEAR" : emaFast > emaSlow ? "MIXED BULL" : "MIXED BEAR"
color  emaClr = emaBull ? C_BULL : emaBear ? C_BEAR : C_YELLOW

// ============================================================================
// VWAP & ORB
// ============================================================================
var float vwapValue = na
var float vwapUpper = na
var float vwapLower = na

if i_useVwap and timeframe.isintraday
    [v, u, l] = ta.vwap(close, i_vwapMult)
    vwapValue := v
    vwapUpper := u
    vwapLower := l

float priceRef = i_useVwap and timeframe.isintraday ? vwapValue : emaSlow
string vwapPos = close > priceRef ? (close > vwapUpper ? "ABOVE BAND" : "ABOVE VWAP") : close < priceRef ? (close < vwapLower ? "BELOW BAND" : "BELOW VWAP") : "ON VWAP"
color  vwapClr = close > vwapUpper ? C_ORANGE : close > priceRef ? C_BULL : close < vwapLower ? C_ORANGE : close < priceRef ? C_BEAR : C_NEUTRAL

// Opening Range (First 2 bars = 30 mins)
var float orHigh = na
var float orLow  = na
if isRTH and not isRTH[1]
    orHigh := high
    orLow  := low
else if isRTH and sessionBar == 2
    orHigh := math.max(orHigh, high)
    orLow  := math.min(orLow, low)

// ============================================================================
// HIGHER TIMEFRAME (1H ANCHOR)
// ============================================================================
float htfEma = request.security(syminfo.tickerid, "60", ta.ema(close, i_htfEmaLen), lookahead=barmerge.lookahead_off)
string htfStr = close > htfEma ? "BULLISH" : close < htfEma ? "BEARISH" : "NEUTRAL"
color  htfClr = close > htfEma ? C_BULL : close < htfEma ? C_BEAR : C_NEUTRAL

// ============================================================================
// MOMENTUM, VOLUME & SQUEEZE
// ============================================================================
float rsiVal = ta.rsi(close, i_rsiLen)
string rsiStr = rsiVal > 65 ? "OVERBOUGHT" : rsiVal > 55 ? "BULLISH" : rsiVal < 35 ? "OVERSOLD" : rsiVal < 45 ? "BEARISH" : "NEUTRAL"
color  rsiClr = rsiVal > 65 ? C_ORANGE : rsiVal > 55 ? C_BULL : rsiVal < 35 ? C_ORANGE : rsiVal < 45 ? C_BEAR : C_NEUTRAL

[diPlus, diMinus, adxVal] = ta.dmi(i_adxLen, i_adxLen)
bool adxTrend = adxVal > 20
string dmiStr = adxTrend ? (diPlus > diMinus ? "BULL TREND" : "BEAR TREND") : "NO TREND"
color  dmiClr = adxTrend ? (diPlus > diMinus ? C_BULL : C_BEAR) : C_NEUTRAL

float avgVol = ta.sma(volume, i_volSmaLen)
float relVol = avgVol != 0 ? volume / avgVol : 0.0
string volStr = relVol > 2.0 ? "SPIKE" : relVol > 1.2 ? "HIGH" : relVol > 0.8 ? "NORMAL" : "LOW"
color  volClr = relVol > 2.0 ? C_ORANGE : relVol > 1.2 ? C_BULL : relVol > 0.8 ? C_NEUTRAL : C_YELLOW

// TTM Squeeze Logic (20, 2.0 BB, 1.5 KC)
float sqzLength = 20
[bbMid, bbUp, bbLow] = ta.bb(close, sqzLength, 2.0)
[kcMid, kcUp, kcLow] = ta.kc(close, sqzLength, 1.5)
bool squeezeOn = (bbUp < kcUp) and (bbLow > kcLow)
bool sqzFired  = squeezeOn[1] and not squeezeOn
float sqzMom   = ta.linreg(close - math.avg(math.avg(ta.highest(high, 20), ta.lowest(low, 20)), ta.sma(close, 20)), 20, 0)
string sqzStr  = squeezeOn ? "COMPRESSED" : sqzFired ? "FIRED" : "EXPANDED"
color  sqzClr  = squeezeOn ? C_YELLOW : sqzFired ? (sqzMom > 0 ? C_BULL : C_BEAR) : C_NEUTRAL

// ATR Regime
float atrVal = ta.atr(14)
int atrRank = 0
for i = 1 to i_atrPctlLB
    if atrVal > nz(atrVal[i])
        atrRank += 1
float atrPctl = i_atrPctlLB > 0 ? atrRank / i_atrPctlLB * 100 : 50.0
string atrRegime = atrPctl >= 90 ? "EXTREME" : atrPctl >= 70 ? "HIGH" : atrPctl >= 30 ? "NORMAL" : "LOW"
color  atrClr    = atrPctl >= 90 ? C_ORANGE : atrPctl >= 70 ? C_YELLOW : atrPctl >= 30 ? C_NEUTRAL : C_CYAN

// NYSE TICK
float tickValue = i_useTick ? request.security("USI:TICK", timeframe.period, close) : na
string tickStr = na(tickValue) ? "N/A" : tickValue > 800 ? "EXT BULL" : tickValue > 400 ? "BULLISH" : tickValue < -800 ? "EXT BEAR" : tickValue < -400 ? "BEARISH" : "NEUTRAL"
color  tickClr = na(tickValue) ? C_NEUTRAL : tickValue > 800 ? C_BULL : tickValue > 400 ? color.new(C_BULL, 40) : tickValue < -800 ? C_BEAR : tickValue < -400 ? color.new(C_BEAR, 40) : C_NEUTRAL

// ============================================================================
// SCORING ENGINE
// ============================================================================
int wStruct  = i_useWeighted ? 2 : 1
int wConfirm = 1
int bias     = 0

// Structural (Max +6 / -6)
bias += emaBull ? wStruct : emaBear ? -wStruct : 0
bias += close > priceRef ? wStruct : close < priceRef ? -wStruct : 0
if i_useHTF and not na(htfEma)
    bias += close > htfEma ? wStruct : close < htfEma ? -wStruct : 0

// Confirmation (Max +5 / -5)
bias += rsiVal > 55 ? wConfirm : rsiVal < 45 ? -wConfirm : 0
if adxTrend
    bias += diPlus > diMinus ? wConfirm : diMinus > diPlus ? -wConfirm : 0
bias += sqzMom > 0 ? wConfirm : sqzMom < 0 ? -wConfirm : 0
bias += close > emaFast ? wConfirm : close < emaFast ? -wConfirm : 0
if i_useTick and not na(tickValue)
    bias += tickValue > 200 ? wConfirm : tickValue < -200 ? -wConfirm : 0

int maxBias = (3 * wStruct) + (5 * wConfirm)
float biasAvg = ta.sma(bias, 3)
string biasTrend = bias > biasAvg + 0.5 ? "IMPROVING" : bias < biasAvg - 0.5 ? "FADING" : "STABLE"

color biasClr = bias > 0 ? (bias >= (maxBias*0.6) ? C_BULL : color.new(C_BULL, 30)) : bias < 0 ? (bias <= -(maxBias*0.6) ? C_BEAR : color.new(C_BEAR, 30)) : C_NEUTRAL

if i_bgTint
    bgcolor(bias >= (maxBias*0.7) ? C_BG_BULL : bias <= -(maxBias*0.7) ? C_BG_BEAR : na, title="Bias Background")

// ============================================================================
// DASHBOARD
// ============================================================================
if i_showDash and barstate.islast
    string tblPos = switch i_dashPos
        "Top Right" => position.top_right
        "Top Left" => position.top_left
        "Bottom Right" => position.bottom_right
        "Bottom Left" => position.bottom_left
        => position.top_right

    string cellSize = switch i_dashSize
        "Tiny" => size.tiny
        "Small" => size.small
        "Normal" => size.normal
        "Large" => size.large
        => size.small

    var table dash = table.new(tblPos, 3, 19,
         bgcolor      = C_DASH_BG,
         border_width = 0,
         border_color = color.new(#FFFFFF, 85),
         frame_width  = 1,
         frame_color  = color.new(#FFFFFF, 80))

    // === Row 0: Header ===
    table.cell(dash, 0, 0, "  Market Monitor - 15m  ", text_color=#FFFFFF,
         bgcolor=C_DASH_HEADER, text_size=cellSize, text_halign=text.align_center)
    table.cell(dash, 1, 0, "", bgcolor=C_DASH_HEADER, text_size=cellSize)
    table.cell(dash, 2, 0, "", bgcolor=C_DASH_HEADER, text_size=cellSize)
    table.merge_cells(dash, 0, 0, 2, 0)

    table.cell(dash, 0, 1, "Phase", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
    table.cell(dash, 1, 1, sessionPhase, text_color=C_WHITE, text_size=cellSize, text_halign=text.align_right)

    string biasValStr = (bias > 0 ? "+" : "") + str.tostring(bias)
    table.cell(dash, 0, 2, "Bias Score", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
    table.cell(dash, 1, 2, biasValStr, text_color=biasClr, text_size=cellSize, text_halign=text.align_right)
    table.cell(dash, 2, 2, biasTrend, text_color=biasClr, text_size=cellSize, text_halign=text.align_right)

    table.cell(dash, 0, 3, "EMA Array", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
    table.cell(dash, 1, 3, emaStr, text_color=emaClr, text_size=cellSize, text_halign=text.align_right)

    table.cell(dash, 0, 4, "VWAP", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
    table.cell(dash, 1, 4, vwapPos, text_color=vwapClr, text_size=cellSize, text_halign=text.align_right)

    table.cell(dash, 0, 5, "1H Anchor", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
    table.cell(dash, 1, 5, htfStr, text_color=htfClr, text_size=cellSize, text_halign=text.align_right)

    table.cell(dash, 0, 6, "Squeeze", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
    table.cell(dash, 1, 6, sqzStr, text_color=sqzClr, text_size=cellSize, text_halign=text.align_right)

    table.cell(dash, 0, 7, "TICK", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
    table.cell(dash, 1, 7, tickStr, text_color=tickClr, text_size=cellSize, text_halign=text.align_right)

    table.cell(dash, 0, 8, "RSI", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
    table.cell(dash, 1, 8, f1(rsiVal), text_color=rsiClr, text_size=cellSize, text_halign=text.align_right)

    table.cell(dash, 0, 9, "DMI", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
    table.cell(dash, 1, 9, dmiStr, text_color=dmiClr, text_size=cellSize, text_halign=text.align_right)

    table.cell(dash, 0, 10, "Rel Vol", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
    table.cell(dash, 1, 10, f2(relVol) + "x", text_color=volClr, text_size=cellSize, text_halign=text.align_right)

    table.cell(dash, 0, 11, "ATR State", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
    table.cell(dash, 1, 11, atrRegime, text_color=atrClr, text_size=cellSize, text_halign=text.align_right)
    
// ============================================================================
// PLOTS
// ============================================================================
plot(i_showCloud ? emaFast : na, "Fast EMA", color=C_BULL, linewidth=1)
plot(i_showCloud ? emaMid  : na, "Mid EMA",  color=C_YELLOW, linewidth=1)
plot(i_showCloud ? emaSlow : na, "Slow EMA", color=C_BEAR, linewidth=1)

p1 = plot(i_showCloud ? emaFast : na, color=color(na))
p2 = plot(i_showCloud ? emaSlow : na, color=color(na))
fill(p1, p2, color=emaBull ? C_CLOUD_BULL : emaBear ? C_CLOUD_BEAR : C_CLOUD_MIX)

plot(i_useVwap ? vwapValue : na, "VWAP", color=C_PURPLE, linewidth=2)
plot(i_useVwap ? vwapUpper : na, "VWAP Upper", color=color.new(C_PURPLE, 50), style=plot.style_circles)
plot(i_useVwap ? vwapLower : na, "VWAP Lower", color=color.new(C_PURPLE, 50), style=plot.style_circles)

// ============================================================================
// ALERTS
// ============================================================================
int strongThresh = i_useWeighted ? 7 : 5
alertcondition(bias >= strongThresh,    "Strong Bullish Bias",     "{{ticker}} bias score >= +7 on {{interval}}")
alertcondition(bias <= -strongThresh,   "Strong Bearish Bias",     "{{ticker}} bias score <= -7 on {{interval}}")
alertcondition(ta.cross(bias, 0),       "Bias Crossed Neutral",    "{{ticker}} bias crossed zero on {{interval}}")
alertcondition(relVol > 2.0,            "Volume Spike (>2x)",      "{{ticker}} relative volume > 2x on {{interval}}")
alertcondition(sqzFired,                "Squeeze Fired",           "{{ticker}} TTM Squeeze fired on {{interval}}")

Overview

Market Monitor - 15m calculates a triple exponential moving average ribbon with EMA cloud shading, session VWAP with multiplier bands, prior day levels, a 30-minute opening range, and an optional 1-hour anchor EMA. It integrates momentum and volatility tools including RSI, ADX, ATR percentile regimes, and TTM squeeze detection to generate a weighted directional bias score. An on-screen table displays session phases and scoring metrics, while optional background coloring highlights high-conviction states. Inputs allow customizing indicator lengths, visual layers, and dashboard layout.

Details

Published by

chris-c-thomas on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Trend, Moving averages, Sessions & time, Screeners & dashboards

Markets

Stocks, Indices

Timeframes

M15-H1

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Topics

financeoptionspinescriptpinescript-indicatorspinescript-strategiestradingtradingvewtradingview-chart-analysischarting

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Fast EMAint9i_emaFastLen
Mid EMAint21i_emaMidLen
Slow EMAint50i_emaSlowLen
Show EMA Cloudbooltruei_showCloud
Use Session VWAPbooltruei_useVwap
VWAP Band Multiplierfloat1.5i_vwapMult
Show Prior Day Levelsbooltruei_showPrior
Use 1H Anchor EMAbooltruei_useHTF
1H Anchor EMA Lengthint50i_htfEmaLen
RSI Lengthint14i_rsiLen
ADX Lengthint14i_adxLen
Volume SMAint20i_volSmaLen
Show all 19 settings
SettingTypeDefaultVariable
ATR Pctl Lookbackint260i_atrPctlLB
Use NYSE TICKbooltruei_useTick
Use Weighted Scoring (2x/1x)booltruei_useWeighted
Color Background on High Scorebooltruei_bgTint
Show Dashboardbooltruei_showDash
PositionstringBottom Righti_dashPos
SizestringSmalli_dashSize
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

257 stars

Donald SPX - Options Trading is an overlay indicator designed for intraday SPX analysis. It plots a 200-period Weighted Moving Average (WMA) on the price chart while evaluating multi-timeframe market structure across Daily, 15-minute, 5-minute, and 2-minute ba

Indicator v5 Moving averagesTrend Repaints
Updated 6 weeks ago · None stated GitHub repository of Donald SPX - Options Trading
218 stars

TradersPost Trading Checklist is an overlay indicator that evaluates a suite of popular technical conditions for long and short trade setups. It checks session-anchored VWAP, fast and slow EMA alignments and crosses, 200 SMA, RSI overbought or oversold conditi

Indicator v6 Screeners & dashboardsTrend
Updated 3 months ago · None stated GitHub repository of TradersPost Trading Checklist
92 stars

This indicator classifies the market into gamma regime types (negative gamma trend, positive gamma mean-reversion, or transition) by calculating a composite score based on daily ATR ratios, session VWAP crossover frequencies, and opening range displacement. It

Indicator v5 Volatility & bandsTrend
Updated 8 weeks ago · Custom licence GitHub repository of Moon Dev GEX Regime & Trap

EMA Ribbon Overlay

by iamrichardD
57 stars

Calculates exponential moving averages for fast, pivot, and slow lengths along with optional 50, 100, and 200 simple moving average context lines. It visualizes bullish and bearish ribbon fills on the main price chart alongside MACD calculations to generate ea

Indicator v6 TrendMoving averages
Updated 1 year ago · Apache-2.0 GitHub repository of EMA Ribbon Overlay
53 stars

This indicator analyzes historical candle direction and price range over a configurable lookback window to gauge market trend. It categorizes trend direction using candle count, price range sum, or both. Signals are filtered using a Simple Moving Average to en

Indicator v6 TrendOscillators & momentum
Updated 2 months ago · MPL-2.0 GitHub repository of Candle Counter + MA + RSI + Mode

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers