Forex Heatmap█ OVERVIEW
This indicator creates a dynamic grid display of currency pair cross rates (exchange rates) and percentage changes, emulating the Cross Rates and Heat Map widgets available on our Forex page. It provides a view of realtime exchange rates for all possible pairs derived from a user-specified list of currencies, allowing users to monitor the relative performance of several currencies directly on a TradingView chart.
█ CONCEPTS
Foreign exchange
The Foreign Exchange (Forex/FX) market is the largest, most liquid financial market globally, with an average daily trading volume of over 5 trillion USD. Open 24 hours a day, five days a week, it operates through a decentralized network of financial hubs in various major cities worldwide. In this market, participants trade currencies in pairs , where the listed price of a currency pair represents the exchange rate from a given base currency to a specific quote currency . For example, the "EURUSD" pair's price represents the amount of USD (quote currency) that equals one unit of EUR (base currency). Globally, the most traded currencies include the U.S. dollar (USD), Euro (EUR), Japanese yen (JPY), British pound (GBP), and Australian dollar (AUD), with USD involved in over 87% of all trades.
Understanding the Forex market is essential for traders and investors, even those who do not trade currency pairs directly, because exchange rates profoundly affect global markets. For instance, fluctuations in the value of USD can impact the demand for U.S. exports or the earnings of companies that handle multinational transactions, either of which can affect the prices of stocks, indices, and commodities. Additionally, since many factors influence exchange rates, including economic policies and interest rate changes, analyzing the exchange rates across currencies can provide insight into global economic health.
█ FEATURES
Requesting a list of currencies
This indicator requests data for every valid currency pair combination from the list of currencies defined by the "Currency list" input in the "Settings/Inputs" tab. The list can contain up to six unique currency codes separated by commas, resulting in a maximum of 30 requested currency pairs.
For example, if the specified "Currency list" input is "CAD, USD, EUR", the indicator requests and displays relevant data for six currency pair combinations: "CADUSD", "USDCAD", "CADEUR", "EURCAD", "USDEUR", "EURUSD". See the "Grid display" section below to understand how the script organizes the requested information.
Each item in the comma-separated list must represent a valid currency code. If the "Currency list" input contains an invalid currency code, the corresponding cells for that currency in the "Cross rates" or "Heat map" grid show "NaN" values. If the list contains empty items, e.g., "CAD, ,EUR, ", the indicator ignores them in its data requests and calculations.
NOTE: Some uncommon currency pair combinations might not have data feeds available. If no available symbols provide the exchange rates between two specified currencies, the corresponding table cells show "NaN" results.
Realtime data
The indicator retrieves realtime market prices, daily price changes, and minimum tick sizes for all the currency pairs derived from the "Currency list" input. It updates the retrieved information shown in its grid display after new ticks become available to reflect the latest known values.
NOTE: Pine scripts execute on realtime bars only when new ticks are available in the chart's data feed. If no new updates are available from the chart's realtime feed, it may cause a delay in the data the indicator receives.
Grid display
This indicator displays the requested data for each currency pair in a table with cells organized as a grid. Each row name corresponds to a pair's base currency , and each column name corresponds to a quote currency . The cell at the intersection of a specific row and column shows the value requested from the corresponding currency pair.
For example, the cell at the intersection of a "EUR" row and "USD" column shows the data retrieved for the "EURUSD" currency pair, and the cell at the "USD" row and "EUR" column shows data for the inverse pair ("USDEUR").
Note that the main diagonal cells in the table, where rows and columns with the same names intersect, are blank. The exchange rate from one currency to itself is always 1, and no Forex symbols such as "EUREUR" exist.
The dropdown input at the top of the "Settings/Inputs" tab determines the type of information displayed in the table. Two options are available: "Cross rates" and "Heat map" . Both modes color their cells for light and dark themes separately based on the inputs in the "Colors" section.
Cross rates
When a user selects the "Cross rates" display mode, the table's cells show the latest available exchange rate for each currency pair, emulating the behavior of the Cross Rates widget. Each cell's value represents the amount of the quote currency (column name) that equals one unit of the base currency (row name). This display allows users to compare cross rates across currency pairs, and their inverses.
The background color of each cell changes based on the most recent update to the exchange rate, allowing users to monitor the direction of short-term fluctuations as they occur. By default, the background turns green (positive cell color) when the cross rate increases from the last recorded update and red (negative cell color) when the rate decreases. The background color disappears after no new updates are available for 200 milliseconds.
Heat map
When a user selects the "Heat map" display mode, the table's cells show the latest daily percentage change of each currency pair, emulating the behavior of the Heat Map widget.
In this mode, the background color of each cell depends on the corresponding currency pair's daily performance. Heat maps typically use colors that vary in intensity based on the calculated values. This indicator uses the following color coding by default:
• Green (Positive cell color): Percentage change > +0.1%
• No color: Percentage change between 0.0% and +0.1%
• Bright red (Negative cell color): Percentage change < -0.1%
• Lighter/darker red (Minor negative cell color): Percentage change between 0.0% and -0.1%
█ FOR Pine Script™ CODERS
• This script utilizes dynamic requests to iteratively fetch information from multiple contexts using a single request.security() instance in the code. Previously, `request.*()` functions were not allowed within the local scopes of loops or conditional structures, and most `request.*()` function parameters, excluding `expression`, required arguments of a simple or weaker qualified type. The new `dynamic_requests` parameter in script declaration statements enables more flexibility in how scripts can use `request.*()` calls. When its value is `true`, all `request.*()` functions can accept series arguments for the parameters that define their requested contexts, and `request.*()` functions can execute within local scopes. See the Dynamic requests section of the Pine Script™ User Manual to learn more.
• Scripts can execute up to 40 unique `request.*()` function calls. A `request.*()` call is unique only if the script does not already call the same function with the same arguments. See this section of the User Manual's Limitations page for more information.
• Typically, when requesting higher-timeframe data with request.security() using barmerge.lookahead_on as the `lookahead` argument, the `expression` argument should use the history-referencing operator to offset the series, preventing lookahead bias on historical bars. However, the request.security() call in this script uses barmerge.lookahead_on without offsetting the `expression` because the script only displays results for the latest historical bar and all realtime bars, where there is no future information to leak into the past. Instead, using this call on those bars ensures each request fetches the most recent data available from each context.
• The request.security() instance in this script includes a `calc_bars_count` argument to specify that each request retrieves only a minimal number of bars from the end of each symbol's historical data feed. The script does not need to request all the historical data for each symbol because it only shows results on the last chart bar that do not depend on the entire time series. In this case, reducing the retrieved bars in each request helps minimize resource usage without impacting the calculated results.
Look first. Then leap.
Requestsecurity
Ticker Tape█ OVERVIEW
This indicator creates a dynamic, scrolling display of multiple securities' latest prices and daily changes, similar to the ticker tapes on financial news channels and the Ticker Tape Widget . It shows realtime market information for a user-specified list of symbols along the bottom of the main chart pane.
█ CONCEPTS
Ticker tape
Traditionally, a ticker tape was a continuous, narrow strip of paper that displayed stock prices, trade volumes, and other financial and security information. Invented by Edward A. Calahan in 1867, ticker tapes were the earliest method for electronically transmitting live stock market data.
A machine known as a "stock ticker" received stock information via telegraph, printing abbreviated company names, transaction prices, and other information in a linear sequence on the paper as new data came in. The term "ticker" in the name comes from the "tick" sound the machine made as it printed stock information. The printed tape provided a running record of trading activity, allowing market participants to stay informed on recent market conditions without needing to be on the exchange floor.
In modern times, electronic displays have replaced physical ticker tapes. However, the term "ticker" remains persistent in today's financial lexicon. Nowadays, ticker symbols and digital tickers appear on financial news networks, trading platforms, and brokerage/exchange websites, offering live updates on market information. Modern electronic displays, thankfully, do not rely on telegraph updates to operate.
█ FEATURES
Requesting a list of securities
The "Symbol list" text box in the indicator's "Settings/Inputs" tab allows users to list up to 40 symbols or ticker Identifiers. The indicator dynamically requests and displays information for each one. To add symbols to the list, enter their names separated by commas . For example: "BITSTAMP:BTCUSD, TSLA, MSFT".
Each item in the comma-separated list must represent a valid symbol or ticker ID. If the list includes an invalid symbol, the script will raise a runtime error.
To specify a broker/exchange for a symbol, include its name as a prefix with a colon in the "EXCHANGE:SYMBOL" format. If a symbol in the list does not specify an exchange prefix, the indicator selects the most commonly used exchange when requesting the data.
Realtime updates
This indicator requests symbol descriptions, current market prices, daily price changes, and daily change percentages for each ticker from the user-specified list of symbols or ticker identifiers. It receives updated information for each security after new realtime ticks on the current chart.
After a new realtime price update, the indicator updates the values shown in the tape display and their colors.
The color of the percentages in the tape depends on the change in price from the previous day . The text is green when the daily change is positive, red when the value is negative, and gray when the value is 0.
The color of each displayed price depends on the change in value from the last recorded update, not the change over a daily period. For example, if a security's price increases in the latest update, the ticker tape shows that price with green text, even if the current price is below the previous day's closing price. This behavior allows users to monitor realtime directional changes in the requested securities.
NOTE: Pine scripts execute on realtime bars when new ticks are available in the chart's data feed. If no new updates are available from the chart's realtime feed, it may cause a delay in the data the indicator receives.
Ticker motion
This indicator's tape display shows a list of security information that incrementally scrolls horizontally from right to left after new chart updates, providing a dynamic visual stream of current market data. The scrolling effect works by using a counter that increments across successive intervals after realtime ticks to control the offset of each listed security. Users can set the initial scroll offset with the "Offset" input in the "Settings/Inputs" tab.
The scrolling rate of the ticker tape display depends on the realtime ticks available from the chart's data feed. Using the indicator on a chart with frequent realtime updates results in smoother scrolling. If no new realtime ticks are available in the chart's feed, the ticker tape does not move. Users can also deactivate the scrolling feature by toggling the "Running" input in the indicator's settings.
█ FOR Pine Script™ CODERS
• This script utilizes dynamic requests to iteratively fetch information from multiple contexts using a single request.security() instance in the code. Previously, `request.*()` functions were not allowed within the local scopes of loops or conditional structures, and most `request.*()` function parameters, excluding `expression`, required arguments of a simple or weaker qualified type. The new `dynamic_requests` parameter in script declaration statements enables more flexibility in how scripts can use `request.*()` calls. When its value is `true`, all `request.*()` functions can accept series arguments for the parameters that define their requested contexts, and `request.*()` functions can execute within local scopes. See the Dynamic requests section of the Pine Script™ User Manual to learn more.
• Scripts can execute up to 40 unique `request.*()` function calls. A `request.*()` call is unique only if the script does not already call the same function with the same arguments. See this section of the User Manual's Limitations page for more information.
• This script converts a comma-separated "string" list of symbols or ticker IDs into an array . It then loops through this array, dynamically requesting data from each symbol's context and storing the results within a collection of custom `Tape` objects . Each `Tape` instance holds information about a symbol, which the script uses to populate the table that displays the ticker tape.
• This script uses the varip keyword to declare variables and `Tape` fields that update across ticks on unconfirmed bars without rolling back. This behavior allows the script to color the tape's text based on the latest price movements and change the locations of the table cells after realtime updates without reverting. See the `varip` section of the User Manual to learn more about using this keyword.
• Typically, when requesting higher-timeframe data with request.security() using barmerge.lookahead_on as the `lookahead` argument, the `expression` argument should use the history-referencing operator to offset the series, preventing lookahead bias on historical bars. However, the request.security() call in this script uses barmerge.lookahead_on without offsetting the `expression` because the script only displays results for the latest historical bar and all realtime bars, where there is no future information to leak into the past. Instead, using this call on those bars ensures each request fetches the most recent data available from each context.
• The request.security() instance in this script includes a `calc_bars_count` argument to specify that each request retrieves only a minimal number of bars from the end of each symbol's historical data feed. The script does not need to request all the historical data for each symbol because it only shows results on the last chart bar that do not depend on the entire time series. In this case, reducing the retrieved bars in each request helps minimize resource usage without impacting the calculated results.
Look first. Then leap.
Higher-timeframe requests█ OVERVIEW
This publication focuses on enhancing awareness of the best practices for accessing higher-timeframe (HTF) data via the request.security() function. Some "traditional" approaches, such as what we explored in our previous `security()` revisited publication, have shown limitations in their ability to retrieve non-repainting HTF data. The fundamental technique outlined in this script is currently the most effective in preventing repainting when requesting data from a higher timeframe. For detailed information about why it works, see this section in the Pine Script™ User Manual .
█ CONCEPTS
Understanding repainting
Repainting is a behavior that occurs when a script's calculations or outputs behave differently after restarting it. There are several types of repainting behavior, not all of which are inherently useless or misleading. The most prevalent form of repainting occurs when a script's calculations or outputs exhibit different behaviors on historical and realtime bars.
When a script calculates across historical data, it only needs to execute once per bar, as those values are confirmed and not subject to change. After each historical execution, the script commits the states of its calculations for later access.
On a realtime, unconfirmed bar, values are fluid . They are subject to change on each new tick from the data provider until the bar closes. A script's code can execute on each tick in a realtime bar, meaning its calculations and outputs are subject to realtime fluctuations, just like the underlying data it uses. Each time a script executes on an unconfirmed bar, it first reverts applicable values to their last committed states, a process referred to as rollback . It only commits the new values from a realtime bar after the bar closes. See the User Manual's Execution model page to learn more.
In essence, a script can repaint when it calculates on realtime bars due to fluctuations before a bar's confirmation, which it cannot reproduce on historical data. A common strategy to avoid repainting when necessary involves forcing only confirmed values on realtime bars, which remain unchanged until each bar's conclusion.
Repainting in higher-timeframe (HTF) requests
When working with a script that retrieves data from higher timeframes with request.security() , it's crucial to understand the differences in how such requests behave on historical and realtime bars .
The request.security() function executes all code required by its `expression` argument using data from the specified context (symbol, timeframe, or modifiers) rather than on the chart's data. As when executing code in the chart's context, request.security() only returns new historical values when a bar closes in the requested context. However, the values it returns on realtime HTF bars can also update before confirmation, akin to the rollback and recalculation process that scripts perform in the chart's context on the open bar. Similar to how scripts operate in the chart's context, request.security() only confirms new values after a realtime bar closes in its specified context.
Once a script's execution cycle restarts, what were previously realtime bars become historical bars, meaning the request.security() call will only return confirmed values from the HTF on those bars. Therefore, if the requested data fluctuates across an open HTF bar, the script will repaint those values after it restarts.
This behavior is not a bug; it's simply the default behavior of request.security() . In some cases, having the latest information from an unconfirmed HTF bar is precisely what a script needs. However, in many other cases, traders will require confirmed, stable values that do not fluctuate across an open HTF bar. Below, we explain the most reliable approach to achieve such a result.
Achieving consistent timing on all bars
One can retrieve non-fluctuating values with consistent timing across historical and realtime feeds by exclusively using request.security() to fetch the data from confirmed HTF bars. The best way to achieve this result is offsetting the `expression` argument by at least one bar (e.g., `close [1 ]`) and using barmerge.lookahead_on as the `lookahead` argument.
We discourage the use of barmerge.lookahead_on alone since it prompts the function to look toward future values of HTF bars across historical data, which is heavily misleading. However, when paired with a requested `expression` that includes a one-bar historical offset, the "future" data the function retrieves is not from the future. Instead, it represents the last confirmed bar's values at the start of each HTF bar, thus preventing the results on realtime bars from fluctuating before confirmation from the timeframe.
For example, this line of code uses a request.security() call with barmerge.lookahead_on to request the close price from the "1D" timeframe, offset by one bar with the history-referencing operator [ ] . This line will return the daily price with consistent timing across all bars:
float htfClose = request.security(syminfo.tickerid, "1D", close , lookahead = barmerge.lookahead_on)
Note that:
• This technique only works as intended for higher-timeframe requests .
• When designing a script to work specifically with HTFs, we recommend including conditions to prevent request.security() from accessing timeframes equal to or lower than the chart's timeframe, especially if you intend to publish it. In this script, we included an if structure that raises a runtime error when the requested timeframe is too small.
• A necessary trade-off with this approach is that the script must wait for an HTF bar's confirmation to retrieve new data on realtime bars, thus delaying its availability until the open of the subsequent HTF bar. The time elapsed during such a delay varies with each market, but it's typically relatively small.
👉 Failing to offset the function's `expression` argument while using barmerge.lookahead_on will produce historical results with lookahead bias , as it will look to the future states of historical HTF bars, retrieving values before the times at which they're available in the feed. See the `lookahead` and Future leak with `request.security()` sections in the Pine Script™ User Manual for more information.
Evolving practices
The fundamental technique outlined in this publication is currently the only reliable approach to requesting non-repainting HTF data with request.security() . It is the superior approach because it avoids the pitfalls of other methods, such as the one introduced in the `security()` revisited publication. That publication proposed using a custom `f_security()` function, which applied offsets to the `expression` and the requested result based on historical and realtime bar states. At that time, we explored techniques that didn't carry the risk of lookahead bias if misused (i.e., removing the historical offset on the `expression` while using lookahead), as requests that look ahead to the future on historical bars exhibit dangerously misleading behavior.
Despite these efforts, we've unfortunately found that the bar state method employed by `f_security()` can produce inaccurate results with inconsistent timing in some scenarios, undermining its credibility as a universal non-repainting technique. As such, we've deprecated that approach, and the Pine Script™ User Manual no longer recommends it.
█ METHOD VARIANTS
In this script, all non-repainting requests employ the same underlying technique to avoid repainting. However, we've applied variants to cater to specific use cases, as outlined below:
Variant 1
Variant 1, which the script displays using a lime plot, demonstrates a non-repainting HTF request in its simplest form, aligning with the concept explained in the "Achieving consistent timing" section above. It uses barmerge.lookahead_on and offsets the `expression` argument in request.security() by one bar to retrieve the value from the last confirmed HTF bar. For detailed information about why this works, see the Avoiding Repainting section of the User Manual's Other timeframes and data page.
Variant 2
Variant 2 ( fuchsia ) introduces a custom function, `htfSecurity()`, which wraps the request.security() function to facilitate convenient repainting control. By specifying a value for its `repaint` parameter, users can determine whether to allow repainting HTF data. When the `repaint` value is `false`, the function applies lookahead and a one-bar offset to request the last confirmed value from the specified `timeframe`. When the value is `true`, the function requests the `expression` using the default behavior of request.security() , meaning the results can fluctuate across chart bars within realtime HTF bars and repaint when the script restarts.
Note that:
• This function exclusively handles HTF requests. If the requested timeframe is not higher than the chart's, it will raise a runtime error .
• We prefer this approach since it provides optional repainting control. Sometimes, a script's calculations need to respond immediately to realtime HTF changes, which `repaint = true` allows. In other cases, such as when issuing alerts, triggering strategy commands, and more, one will typically need stable values that do not repaint, in which case `repaint = false` will produce the desired behavior.
Variant 3
Variant 3 ( white ) builds upon the same fundamental non-repainting approach used by the first two. The difference in this variant is that it applies repainting control to tuples , which one cannot pass as the `expression` argument in our `htfSecurity()` function. Tuples are handy for consolidating `request.*()` calls when a script requires several values from the same context, as one can request a single tuple from the context rather than executing multiple separate request.security() calls.
This variant applies the internal logic of our `htfSecurity()` function in the script's global scope to request a tuple containing open and `srcInput` values from a higher timeframe with repainting control. Historically, Pine Script™ did not allow the history-referencing operator [ ] when requesting tuples unless the tuple came from a function call, which limited this technique. However, updates to Pine over time have lifted this restriction, allowing us to pass tuples with historical offsets directly as the `expression` in request.security() . By offsetting all items in a tuple `expression` by one bar and using barmerge.lookahead_on , we effectively retrieve a tuple of stable, non-repainting HTF values.
Since we cannot encapsulate this method within the `htfSecurity()` function and must execute the calculations in the global scope, the script's "Repainting" input directly controls the global `offset` and `lookahead` values to ensure it behaves as intended.
Variant 4 (Control)
Variant 4, which the script displays as a translucent orange plot, uses a default request.security() call, providing a reference point to compare the difference between a repainting request and the non-repainting variants outlined above. Whenever the script restarts its execution cycle, realtime bars become historical bars, and the request.security() call here will repaint the results on those bars.
█ Inputs
Repainting
The "Repainting" input (`repaintInput` variable) controls whether Variant 2 and Variant 3 are allowed to use fluctuating values from an unconfirmed HTF bar. If its value is `false` (default), these requests will only retrieve stable values from the last confirmed HTF bar.
Source
The "Source" input (`srcInput` variable) determines the series the script will use in the `expression` for all HTF data requests. Its default value is close .
HTF Selection
This script features two ways to specify the higher timeframe for all its data requests, which users can control with the "HTF Selection" input (`tfTypeInput` variable):
1) If its value is "Fixed TF", the script uses the timeframe value specified by the "Fixed Higher Timeframe" input (`fixedTfInput` variable). The script will raise a runtime error if the selected timeframe is not larger than the chart's.
2) If the input's value is "Multiple of chart TF", the script multiplies the value of the "Timeframe Multiple" input (`tfMultInput` variable) by the chart's timeframe.in_seconds() value, then converts the result to a valid timeframe string via timeframe.from_seconds() .
Timeframe Display
This script features the option to display an "information box", i.e., a single-cell table that shows the higher timeframe the script is currently using. Users can toggle the display and determine the table's size, location, and color scheme via the inputs in the "Timeframe Display" group.
█ Outputs
This script produces the following outputs:
• It plots the results from all four of the above variants for visual comparison.
• It highlights the chart's background gray whenever a new bar starts on the higher timeframe, signifying when confirmations occur in the requested context.
• To demarcate which bars the script considers historical or realtime bars, it plots squares with contrasting colors corresponding to bar states at the bottom of the chart pane.
• It displays the higher timeframe string in a single-cell table with a user-specified size, location, and color scheme.
Look first. Then leap.