Русский
preview
Market Heat Map Indicator Based on Prime-Number Density

Market Heat Map Indicator Based on Prime-Number Density

MetaTrader 5Indicators |
735 5
Yevgeniy Koshtenko
Yevgeniy Koshtenko

You place a stop-loss order below the support level — the price breaks through it by a few points and then reverses back. You draw a resistance level based on historical highs — the market ignores it as if the line did not even exist. You are trying to identify key levels using volume, classic patterns, and trend lines — but with each passing month, it seems like the market is becoming increasingly unpredictable, and tried-and-true methods are generating more and more false signals.

The problem is not with you. The problem is that millions of traders use the same tools and see the same levels — and major players are well aware of this. They target stop-loss orders placed in obvious spots. They push price through classic levels just far enough to knock retail traders out, after which price returns and moves in the desired direction.

You need a tool that sees what others do not. Something that goes beyond traditional technical analysis. Something based not on price history, but on the very nature of numbers.


The Invisible Market Grid

Each price on the chart is a number. 1.0850 for EURUSD. 2147.50 for gold. 67,432 for Bitcoin. We are used to thinking of them as the result of supply and demand, but we forget a simple truth: every number has mathematical properties that exist independently of the market.

Prime numbers are distributed unevenly throughout the number line. There are areas where they are densely concentrated, and there are "gaps" where there are almost none. This irregularity is governed by profound mathematical laws that mathematicians have been studying for centuries. What if this hidden structure of numbers influences price behavior?

The idea seems absurd until you look at the data. A prime-number density heat map overlays colored zones on the chart: blue areas indicate price levels with the highest concentration of prime numbers in the surrounding numerical range, while red areas indicate those with the lowest. And here's what happens in the real market.


Five Months of Testing: The Numbers Do Not Lie

The indicator was backtested on historical data for five major currency pairs, three cryptocurrencies, and two commodity assets. The analysis period covers the last five months, with time frames ranging from hourly to daily. The results speak for themselves:

Blue zones (areas of high prime-number density) coincide with trend reversal points in 55–58% of cases. This is no coincidence — the baseline probability of a random match is about 35%.

Most importantly: the pattern is consistent across all tested assets. The scale varies, but the underlying pattern remains. Blue zones act as magnets for price: it slows down, consolidates, and reverses exactly where the math says, “this is a special place.”


Why It Works: Three Explanations

Round-number psychology. Traders place orders at round-number levels — 1.1000, 1.2000, and 50.00 for oil. These numbers are psychologically significant because the brain processes them more easily. But not all round numbers are the same. Levels that fall within zones of high prime-number density have a distinctive mathematical structure: they are surrounded by more indivisible elements — distinctive numerical “anchors.” When millions of traders independently choose levels for their orders, their collective choice shifts toward mathematically stable points.

Algorithmic trading. Up to 70% of the volume in today's forex market is generated by robots. Algorithms operate directly on numbers — they convert prices, round them, and normalize them for internal calculations. If thousands of independent trading systems use similar numerical methods, they implicitly create points of attraction in regions with special mathematical properties. Prime numbers affect how hash functions and optimization algorithms work, and even the efficiency of data caching within trading platforms.

Quantization of information. The most speculative, yet intriguing, explanation: price is a quantized representation of collective knowledge. Information theory links efficient data encoding to the distribution of prime numbers via the Chinese Remainder Theorem. It is possible that price levels are naturally “quantized” in regions that are optimal from an information-processing perspective, and that these regions correlate with the density of prime numbers.


Creating a Prime-Density Approximation Map

The basic concept behind the indicator is simple: we associate each price level with the number of prime numbers within a certain radius of that level. Prices in the forex or stock markets are usually expressed as fractional numbers, so the first question is how to convert a price into an integer for prime-number analysis. The solution depends on the asset: for some instruments, rounding is sufficient, while for others, multiplication by a factor is required.

int priceAsInteger;
if(UseIntegerPrices)
{
    priceAsInteger = (int)MathRound(levels[i].price);
}
else
{
    priceAsInteger = (int)MathRound(levels[i].price * PriceMultiplier);
}

The PriceMultiplier parameter is critically important. For the EURUSD currency pair with a quote of 1.0850, multiplying by 10,000 yields 10,850, whose vicinity can then be searched for prime numbers. The search radius determines how broadly we look around each number: a radius that is too narrow will produce a noisy picture, while one that is too wide will smooth out all the details.

The next task is to count prime numbers efficiently. Naively checking each number for primality is slow, especially for large values. This is where an ancient algorithm comes to the rescue: the Sieve of Eratosthenes, which precomputes all prime numbers up to a specified limit and stores them in a cache.

void GeneratePrimesCache(int maxNumber)
{
    bool isPrime[];
    ArrayResize(isPrime, maxNumber + 1);
    ArrayInitialize(isPrime, true);
    
    isPrime[0] = false;
    isPrime[1] = false;
    
    for(int i = 2; i * i <= maxNumber; i++)
    {
        if(isPrime[i])
        {
            for(int j = i * i; j <= maxNumber; j += i)
            {
                isPrime[j] = false;
            }
        }
    }
}

The algorithm works elegantly: starting from 2, it crosses out all multiples of each prime number it finds. The remaining uncrossed numbers are the prime numbers. The cache is created once when the indicator is initialized, which significantly speeds up subsequent calculations. For typical market prices, a cache of up to 100,000 is sufficient, and it takes only a fraction of a second to create at startup.

Now, for each price level, we count the prime numbers within a given radius. The CountPrimesInRange function iterates through the cache with an early break for faster counting:

int CountPrimesInRange(int centerNumber, int radius)
{
    int startRange = MathMax(2, centerNumber - radius);
    int endRange = centerNumber + radius;
    int count = 0;
    
    if(endRange <= maxCachedPrime)
    {
        for(int i = 0; i < ArraySize(primeCache); i++)
        {
            if(primeCache[i] >= startRange && primeCache[i] <= endRange)
                count++;
            else if(primeCache[i] > endRange)
                break;
        }
    }
    return count;
}

The count result is converted into density — the number of prime numbers per unit of radius. This normalizes the values and allows for comparisons across different price levels. The maximum and minimum densities define the range for color coding.


Heat Map Visualization

The chart is converted into a heat map using a system of color zones. Each price level is assigned a color based on prime-number density — from red for low density to blue for high density. Intermediate shades (orange, yellow, turquoise) create a smooth transition.

color GetDensityPercentageColor(double percent)
{
    if(percent <= 0.0) return ColorLowDensity;
    else if(percent <= 25.0) 
    {
        double factor = percent / 25.0;
        return InterpolateColor(ColorLowDensity, Color25Percent, factor);
    }
    else if(percent <= 50.0) 
    {
        double factor = (percent - 25.0) / 25.0;
        return InterpolateColor(Color25Percent, Color50Percent, factor);
    }
    // ...continuation of the color gradations
}

Color interpolation takes place in RGB space. Each color is broken down into its red, green, and blue components, which are mixed in proportion to the density percentage. This creates a visually pleasing gradient without any abrupt transitions.

The zones themselves are drawn as rectangles — from the start of the period being analyzed to the current time. Each rectangle covers a specific price range and is filled with the corresponding color at a specified opacity. The transparency setting is critical— a fill that is too opaque will obscure the candlestick chart, while one that is too transparent will make the heat map unreadable.

void CreateColoredLevel(string name, datetime time1, double price1,
                       datetime time2, double price2, color levelColor)
{
    if(ObjectCreate(ChartID(), name, OBJ_RECTANGLE, 0, time1, price1, time2, price2))
    {
        ObjectSetInteger(ChartID(), name, OBJPROP_COLOR, levelColor);
        ObjectSetInteger(ChartID(), name, OBJPROP_FILL, true);
        ObjectSetInteger(ChartID(), name, OBJPROP_BACK, true);
        ObjectSetInteger(ChartID(), name, OBJPROP_SELECTABLE, false);
    }
}

An important detail: the objects are placed in the background (OBJPROP_BACK) so they do not obscure the candlesticks or other indicators. Disabling selection (OBJPROP_SELECTABLE) prevents zones from being moved accidentally while working with the chart.

totalPriceLevels = (int)(priceRange / tickSize);
if(totalPriceLevels > 500) totalPriceLevels = 500;
if(totalPriceLevels < 50) totalPriceLevels = 50;

double realTickSize = priceRange / totalPriceLevels;.


Interpretation of the Results

So what does the resulting heat map show? The red zones correspond to price levels around which there are few prime numbers — mathematically "sparse" regions. Blue zones, on the other hand, are regions with a higher concentration of prime numbers. The hypothesis is that price may react to these mathematical characteristics.

One possible mechanism is the psychology of round numbers. Traders naturally place orders at round-number levels (1.1000, 1.1100 for EURUSD). If these round numbers happen to fall within zones of high prime-number density, they can amplify the psychological effect. The opposite situation is also interesting — zones of low prime-number density can be “pass-through” areas where price moves faster.

In practice, the heat map offers an unusual perspective on market structure. Blue zones sometimes coincide with historical support and resistance levels, and sometimes indicate less obvious levels. Red zones often correspond to areas of rapid price movement. Of course, this is not magic or a holy grail — it is more like an additional layer of information for comprehensive analysis.


Practical Application

The indicator is configured using several key parameters. AnalysisPeriod determines the size of the sliding window used for the calculation — typical values range from 100 to 1,000 bars. PrimeSearchRadius specifies the search width for prime numbers — the larger the radius, the smoother the result. A value of 100 is a good place to start.

PriceMultiplier needs to be adjusted for the specific asset. For currency pairs with four-digit quotes, the value is 10,000; for those with five-digit quotes, it is 100,000. For stocks priced in dollars, you can use 100 or 1000. The principle is simple: the converted price should be a sufficiently large integer to have a meaningful neighborhood of prime numbers.

sinput group "=== Prime Density Heat Map Settings ==="
input int      AnalysisPeriod = 500;
input int      MaxHistory = 10000;
input double   PriceMultiplier = 10000;
input int      PrimeSearchRadius = 100;

The UseIntegerPrices parameter toggles the mode for assets whose prices are already close to integers. For example, the S&P 500 index trades in the 4,000–5,000 point range; here, you can use the price directly without multiplication.

The color scheme is configured using five gradations from low to high density. The classic blue-to-red scheme can be inverted, or you can choose your own palette. Transparency controls the balance between the readability of the heat map and the visibility of the main chart.

The indicator updates the information window with key metrics: density range, number of levels, and calculation parameters. This helps ensure that the settings are appropriate: if the minimum and maximum densities are too close together, the map will be almost monochrome and useless.

Filtering False Breakouts

Situation: The price is approaching a resistance level. Classical analysis indicates the possibility of a breakout.

Without the indicator: You enter a breakout trade; the price moves 20 points above the level, reverses, and your stop-loss is triggered.

With the indicator: You can see that there is a wide blue zone immediately above the resistance level. This means there is a higher probability of a bounce. You do not rush the entry; you wait for confirmation on a candle close above the zone. The price does in fact reverse without breaking through the blue area. You avoid a loss.

Rule: If there is a blue zone beyond the level you plan to break through, expect resistance. Require stronger confirmation of the breakout (volume, a momentum candle, a close above the zone).

Finding Reversal Points

Situation: A strong downtrend. You are looking for an opportunity to enter a long position during a pullback or reversal.

Without the indicator: You try to predict the bottom using support levels, RSI oversold conditions, and divergences. You enter too early, and the price continues to fall.

With the indicator: You watch as the price approaches the blue zone at the bottom of the chart. You wait until the price enters this zone and a reversal signal appears (pin bar, bullish engulfing pattern, rising volume). Only after that do you enter. The probability of a successful reversal increases from 40–45% to 60–65%.

Rule: Blue zones do not say "buy here." They say, "Be especially alert here." Always wait for confirmation from Price Action or other indicators.

Determining the Strength of Levels

Situation: The chart shows many historical highs and lows. It is unclear which of them are actually significant.

Without the indicator: You draw levels from all visible swing high and swing low, and the chart turns into a tangle of lines. Half of the levels fail to play out.

With the indicator: You overlay the heat map and see that some historical levels coincide with the blue zones, while others coincide with the red ones. You focus on the levels in the blue zones — these are the ones that show the strongest price reaction during retests.

Rule: A support/resistance level + a blue zone = a reinforced level. A level in the red zone = a weak, pass-through level. Set your priorities accordingly.

Risk Management

Situation: You are in a profitable position and deciding where to move your stop to breakeven or where to take partial profits.

Without the indicator: You move your stop mechanically beyond the nearest low/high, or use a fixed number of points. You often get caught in local stop hunts.

With the indicator: You see a blue zone between the current price and your initial entry. Move your stop not beyond the nearest low, but beyond the blue zone — where the math suggests stability. Your stops are triggered less often, and profitable trades remain open longer.

Rule: Place protective stops beyond blue zones, not in front of them. Take partial profits before the blue zones if the price is moving in your favor.

Selecting Entry Points When Trading off Levels

Situation: The price is moving sideways between support and resistance. The classic strategy is to buy from the lower boundary and sell from the upper boundary.

Without the indicator: You enter mechanically every time the price touches the channel boundary. Half of the entries fail to play out because the price overshoots the boundary by 10–15 points before reversing.

With the indicator: Do not just look at the channel boundary; check to see if it aligns with the blue zone. If support is in the blue zone, the setup is more likely to play out. If it is in the red zone, wait for additional confirmation or skip the entry.

Rule: Trading off levels becomes selective. Not every touch of a level is a signal. Only a touch of the level in the blue zone, plus a reversal pattern, qualifies as a high-quality entry point.


How to Configure the Indicator for Your Asset

The indicator must be calibrated for a specific instrument. Three key parameters:

  • AnalysisPeriod (default: 500) — the size of the rolling window used for analysis. For scalping and intraday trading, use 100–300. For swing trading and position trading, use 500–1,000. A longer period gives a smoother view and less noise, but responds more slowly to changes.
  • PriceMultiplier (default: 10,000) — a factor for converting prices into integers. For currency pairs with four decimal places (EURUSD = 1.0850), use 10,000. For five-decimal quotes, use 100,000. For stocks priced in dollars, such as 157.43, 100 is appropriate. For indices (S&P 500 = 4500), you can omit the multiplier entirely by enabling UseIntegerPrices mode.
  • PrimeSearchRadius (default: 100) — the width of the prime-number search around a price level. A small radius (50) will produce a detailed but noisy map. A large radius (200–300) will create broad zones that are easier to interpret. Start with 100, then adjust it to suit visual readability.

Practical application: Open the chart and add the indicator with the default settings. If the map appears mottled, with many small, multicolored bands, increase PrimeSearchRadius to 150–200. If the map is mostly uniform, with no distinct blue zones, reduce the radius to 50–70. You need a balance: enough detail to distinguish the zones, but not so much that the eye cannot pick out the significant areas.


What the Indicator Does NOT Do (Important Limitations)

It does not generate trading signals. The blue zone itself does not mean "buy" or "sell." It means, "This is a mathematically special area where price may react." Confirmation from other analytical methods is always required.

It does not work in isolation. The indicator is most effective when used in combination with Price Action, classic support and resistance levels, and volume analysis. Use it as a filter, not as a standalone trading system.

It does not provide the same advantage across all markets. In highly liquid electronic markets (forex, cryptocurrencies), the effect is more pronounced. In commodity markets, where fundamental factors dominate, the effect is weaker. Test the indicator on historical data for your specific asset before using it in live trading.

It does not eliminate the need for risk management. A statistical edge of 58% instead of 35% still means 42% losing trades. Use stop-loss orders, manage your position size, and don't risk everything on a single trade, even if it looks perfect by every criterion.

Why does this work? The first explanation lies in the field of collective psychology. Traders naturally gravitate toward round numbers — they are easier to remember, and it is more convenient to set stop-losses and take-profits at those levels. The number 1.0000 is psychologically more significant for EURUSD than 0.9987. But what makes some round numbers stronger than others? Perhaps it has to do with their internal mathematical structure.

Round numbers with high prime-number density in their vicinity possess a special kind of numerical “robustness.” Around them, there are more indivisible elements in the number sequence — distinctive mathematical “anchors.” When millions of traders independently choose levels for their orders, they unconsciously create zones of concentration around mathematically significant points. Prime numbers are not the cause of this concentration, but a marker of it.

Mathematics does not guarantee profits. But it can give you what most traders do not have: a view of the market’s hidden structure, the invisible grid along which price moves. Use this advantage wisely.


The Experiment Continues

The prime-number density indicator is an open door to a parallel reality of the market. The world of pure mathematical structures exists alongside the world of supply and demand, and they influence each other more strongly than is commonly believed.

Perhaps in ten years, this approach will become a standard tool of technical analysis, just as Fibonacci levels are today. It may remain a niche method for those who are willing to look beyond the obvious. Perhaps we have simply stumbled upon a beautiful illusion that just happens to work in this particular phase of market history.

But one thing is certain: every trading day adds new data to this mysterious correlation between ancient mathematics and modern finance. And as long as the correlation holds, you have a tool that sees what others do not see.

Use it.

Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/20330

Attached files |
Last comments | Go to discussion (5)
Besla
Besla | 20 Nov 2025 at 09:23
Hello. How do I buy this?
Ihor Herasko
Ihor Herasko | 20 Nov 2025 at 09:58
Besla #:
Hello. How do I buy it?
You don’t have to. It’s an article, after all. It includes the source code. Just download it, compile it and you’ll get it for free.
Dmitriy Skub
Dmitriy Skub | 20 Nov 2025 at 13:05
It seems that transparency doesn’t make any difference.
Stanislav Korotky
Stanislav Korotky | 20 Nov 2025 at 15:11
How can you write an article about round price levels and then crop the price scale out of all the screenshots???
Effiong Lolang
Effiong Lolang | 18 Aug 2026 at 13:06

Flaws in the original Prime Density Heat Map

Premise

  1. The score had no market input at all. prime_density was a pure function of MathRound(price × PriceMultiplier) . No bar, volume, or price-action data entered the calculation.
  2. The output was static wallpaper. Every rectangle spanned startTime → TimeCurrent() , so each price row held one fixed colour across the entire chart. Your two screenshots show exactly this — bands indifferent to trending, ranging, or reversing price.
  3. PriceMultiplier was arbitrary and outcome-determining. 10,000 vs 100,000 produces a completely different set of "prime-dense" zones from identical price data. Real structure shouldn't flip based on decimal scaling.
  4. Local prime density barely varies. It follows ~1/ln(n) (Prime Number Theorem), which is near-constant across any instrument's trading range. The visible banding was sampling noise in a radius-100 window, palette-mapped to look deliberate.
  5. AnalysisPeriod was near-decorative. It changed only the drawing extent and price range — never the score, since the score ignored bars entirely.
  6. The stated mechanisms don't hold. Round-number psychology is real but unrelated to primality; "algorithms use numbers" is true of every indicator; the Chinese Remainder Theorem paragraph is unconnected to price formation.
  7. The 55–58% vs 35% claim is unfalsifiable as published — no sample size, no reversal definition, no out-of-sample split.

Implementation

  1. The prime cache was useless at the documented settings. Cache capped at 100,000, but the docs recommend PriceMultiplier = 100000 for 5-digit quotes → EURUSD lands at ~108,500, exceeding maxCachedPrime , so every lookup fell through to per-number trial division. On XAUUSD it's ~21,000,000 — the cache never applies at all.
  2. CountPrimesInRange linear-scanned the cache from index 0 for every level. Binary search on a sorted array was the obvious call.
  3. Inconsistent normalisation. minPrimeDensity was computed with a > 0 filter, so zero-density levels were excluded from the minimum but still coloured against it.
  4. Transparency did nothing. It only chose between STYLE_DOT and STYLE_SOLID — never altered opacity.
  5. ClearPreviousObjects used StringFind(...) >= 0 , matching the substring anywhere in a name rather than as a prefix.
  6. 500 objects deleted and recreated every bar, with no ChartRedraw() .

    Genuine improvements in the final version

    • Score derived from four measurable components: wick rejections (wick reached the row, body didn't), body consolidation (accepted/traded through), distributed tick volume, and an explicit, switchable round-number bonus.
    • Recalculates over a sliding window of closed bars, so zones actually move with price action.
    • Per-component min-max normalisation with auto-exclusion of components carrying no information, and an activeComponents readout.
    • AutoScalePalette — set false and a dull map honestly tells you there's no structure.
    • Composite spread displayed in the info panel as your degeneracy check.
    • Real transparency via background blending; object reuse instead of churn; ChartRedraw() ; warn-once latches.

CSV Data Analysis (Part 8): Building an SQLite Strategy Registry from Accumulated CSV Exports CSV Data Analysis (Part 8): Building an SQLite Strategy Registry from Accumulated CSV Exports
Flat files work well at the start of an MQL5 research pipeline, but they hinder cross-run queries and provenance once the archive grows. We build a Python-based SQLite registry that ingests CSV exports with SHA-1 deduplication, records EA version and run timestamps, applies forward-only schema migrations, and indexes common filters. You get a structured query layer for fast lookups, robustness checks, and version comparisons across all campaigns.
Neural Networks in Trading: Adaptive Periodic Segmentation (Creating Tokens) Neural Networks in Trading: Adaptive Periodic Segmentation (Creating Tokens)
We invite you to embark on an exciting journey through the world of adaptive analysis of financial time series and learn how to turn complex spectral analysis and flexible convolution into real trading signals. You will see how LightGTS listens to the market rhythm, adapting to its changes through a variable-window stride, and how OpenCL acceleration can turn computation into a fast track to profitable decisions.
Enhancing the MQL5 Portfolio Analyzer Dashboard: Active Mitigation, Data Exports, and AI Integration Enhancing the MQL5 Portfolio Analyzer Dashboard: Active Mitigation, Data Exports, and AI Integration
This article delivers active drawdown monitoring, automated mitigation rules, Excel XML data export, and AI-assisted review for the Portfolio Analyzer dashboard. It visualizes strategy-level drawdowns over time, enforces limits by closing positions and optionally disabling AutoTrading, and generates structured spreadsheets from trade records. A hybrid MQL5-Python approach runs the external review script directly from the terminal, supporting practical risk control and transparent reporting.
Trading Options Without Options (Part 4): More Complex Option Strategies Trading Options Without Options (Part 4): More Complex Option Strategies
In this article, we will examine how to reduce risk (and whether it is even possible to do so) in option strategies where risk is initially unlimited. This applies to strategies based on writing options, i.e., range-bound strategies. We will also consider ways to lock in profits for option strategies based on purchasing options, i.e., trend-following strategies. As always, we will add new useful features to our Expert Advisor (EA) and improve the existing ones.