How to Customize Wick Colors in Pine Script?

Visualizing market data effectively is crucial for any trader. While standard candlestick charts provide fundamental information, customizing their appearance can offer deeper insights or highlight specific conditions. One powerful way to enhance chart visualization in TradingView, particularly using Pine Script, is by customizing the color of candlestick wicks.

Understanding Candlestick Components: Body, Wicks, and Tails

A candlestick represents price movement over a specific period. It consists of three main parts:

  • Body: This shows the range between the open and close prices.
    • A green (or unfilled) body indicates a bullish period where the close was higher than the open.
    • A red (or filled) body indicates a bearish period where the close was lower than the open.
  • Wicks (or Tails): These are the thin lines extending above and below the body.
    • The upper wick represents the high price reached during the period.
    • The lower wick represents the low price reached during the period.

Wicks capture the price volatility and range beyond the open and close, providing essential context about supply and demand dynamics within that timeframe.

Why Customize Wick Colors?

Customizing wick colors isn’t just for aesthetics; it serves a practical purpose in technical analysis. By coloring wicks based on specific conditions, you can visually detect patterns, strength, or weakness that might not be immediately obvious from standard coloring.

For example, you might color wicks differently based on:

  • Whether the wick relates to a bullish or bearish candle body.
  • The length of the wick relative to the body or the candle’s total range.
  • Volume associated with the period.
  • Proximity to key support or resistance levels.

This visual cue can help in quicker analysis and decision-making by making relevant information pop out from the chart noise.

Basic Syntax for Color Modification in Pine Script

Pine Script offers various ways to apply colors. The most common way to specify colors is using the color type built-in variables (e.g., color.red, color.green, color.blue), hexadecimal color codes (e.g., #FF0000 for red), or the color.rgb() and color.new() functions for more control, including transparency.

When plotting candles, colors are typically applied using the color argument within plotting functions. For wicks specifically, this control is usually handled within the main candle plotting function, as we’ll see.

Methods for Changing Wick Colors

Pine Script provides dedicated functions to plot candles and control their appearance, including wick colors.

Using plotcandle() Function for Direct Color Control

The primary function for plotting customizable candles in Pine Script is plotcandle(). This function allows specifying colors for the body, borders, and wicks separately. Its signature includes arguments for these specific color controls:

plotcandle(
     open,
     high,
     low,
     close,
     title,
     color,
     bordercolor,
     wickcolor,
     showcolors,
     editable,
     display)

The key argument here is wickcolor. You can pass a simple color variable or a conditional expression that resolves to a color value.

// Example: Plotting standard candles with specific wick color
plotcandle(open, high, low, close, 
           color=color.blue, 
           bordercolor=color.black,
           wickcolor=color.orange)

This basic usage sets a static color for all wicks. The power comes when you make the wickcolor dynamic.

Employing Conditional Statements for Dynamic Wick Colors

The wickcolor argument accepts a series color. This means you can use conditional logic (if, else if, else structure or ternary operator ? :) to determine the color of each wick based on the data of that specific bar.

The ternary operator is particularly clean for this purpose:

condition ? color_if_true : color_if_false

Or for multiple conditions:

condition1 ? color1 : condition2 ? color2 : default_color

This allows you to set wick colors based on price movements, indicator values, or any other series data available for the bar.

Utilizing the color.new() Function to Create Custom Color Palettes

While built-in colors are convenient, color.new(color, transparency) (or the older color(color, transparency)) is essential for defining custom colors or, more importantly, controlling transparency. Transparency is specified as a value from 0 (fully opaque) to 100 (fully transparent). Using transparency can be useful for subtle highlighting or making certain wicks less prominent.

// Define a semi-transparent red color
semiTransparentRed = color.new(color.red, 50)

// Use it conditionally for wicks
wickColor = close > open ? color.green : semiTransparentRed

plotcandle(open, high, low, close, wickcolor=wickColor)

color.new() is the modern and preferred way to handle transparency compared to the older color() function.

Advanced Wick Color Customization Techniques

Moving beyond simple static coloring, conditional logic allows for sophisticated visualizations.

Coloring Wicks Based on Price Action (e.g., Bullish/Bearish)

A common technique is to color wicks based on whether the candle body is bullish or bearish. While plotcandle‘s main color argument often handles this for the body, you might want the wicks to match the body color or use a different color to contrast or complement the body.

// Wick color matches body color
bodyColor = close > open ? color.green : color.red
plotcandle(open, high, low, close, color=bodyColor, wickcolor=bodyColor)

// Wick color contrasts body color (e.g., gray for both)
wickColor = color.gray // Static wick color regardless of body
plotcandle(open, high, low, close, color=bodyColor, wickcolor=wickColor)

More advanced price action checks could involve identifying dojis (small bodies, long wicks) and coloring their wicks specifically.

Highlighting Wicks Based on Length or Size

Long wicks often indicate potential rejection of higher or lower prices. Highlighting these wicks can draw attention to supply/demand battles. You can color wicks based on their absolute length (abs(high - low) - abs(close - open)) or their length relative to the candle’s total range or body size.

// Calculate wick lengths
upperWickLength = high - math.max(open, close)
lowerWickLength = math.min(open, close) - low
totalRange = high - low

// Define a threshold (e.g., wick is > 50% of total range)
longWickThreshold = 0.5

// Determine wick color
wickColor = color.black
if (upperWickLength / totalRange > longWickThreshold)
    wickColor := color.purple // Highlight long upper wicks
if (lowerWickLength / totalRange > longWickThreshold)
    wickColor := color.blue   // Highlight long lower wicks

plotcandle(open, high, low, close, color=close>open ? color.green : color.red, wickcolor=wickColor)

This requires calculating the lengths first and then applying conditional coloring.

Implementing Wick Color Changes Based on Volume

High volume accompanying a candle with long wicks can signify strong conviction behind the price rejection. You can incorporate volume data into your wick coloring logic. Access volume using the built-in volume variable.

// Calculate average volume for comparison
avgVolume = ta.sma(volume, 20)

// Check for long wicks and high volume
isLongUpperWick = (high - math.max(open, close)) / (high - low) > 0.6
isLongLowerWick = (math.min(open, close) - low) / (high - low) > 0.6
isHighVolume = volume > avgVolume * 1.5

// Determine wick color based on conditions
wickColor = color.gray // Default color
if (isLongUpperWick and isHighVolume)
    wickColor := color.fuchsia // Long upper wick with high volume
else if (isLongLowerWick and isHighVolume)
    wickColor := color.teal   // Long lower wick with high volume

plotcandle(open, high, low, close, color=close>open ? color.green : color.red, wickcolor=wickColor)

This example highlights wicks only when they are both relatively long and volume is significantly higher than average.

Combining Multiple Conditions for Nuanced Wick Coloring

Complex trading ideas often require combining several conditions. You can build intricate if/else if/else structures or chain ternary operators to apply highly specific wick colors based on combinations of price action, volume, indicator states, or other criteria.

Consider coloring wicks differently based on bullish/bearish bodies and whether the wick extends into a specific indicator level (e.g., Bollinger Band or moving average). This requires calculating the indicator value for the bar and then checking if high or low crossed it within the wick’s range.

Practical Examples and Code Snippets

Let’s put these concepts into full script examples.

Example 1: Simple Bullish/Bearish Wick Coloring

This script colors wicks based on the direction of the candle body. Wicks of bullish candles are green, and wicks of bearish candles are red.

//@version=5
indicator("Bull/Bear Wick Color", overlay=true)

// Determine candle body color
bodyColor = close > open ? color.green : color.red

// Set wick color to match body color
wickColor = bodyColor

// Plot the candles with custom wick color
plotcandle(open, high, low, close, 
           title="Candles",
           color=bodyColor,
           bordercolor=color.black,
           wickcolor=wickColor)

This is a straightforward implementation using the ternary operator within the color assignment, then passing that color to the wickcolor argument of plotcandle.

Example 2: Wick Coloring Based on a Custom Indicator

Suppose you have a simple 20-period SMA. You want to color wicks blue if the low of the wick touched or crossed below the SMA, and orange if the high of the wick touched or crossed above the SMA. Otherwise, wicks are gray.

//@version=5
indicator("Wick Color Based on SMA Touch", overlay=true)

// Calculate a simple moving average
smaLength = input.int(20, "SMA Length")
smaValue = ta.sma(close, smaLength)

// Determine wick color based on SMA interaction
wickColor = color.gray // Default color

// Check if low touched or crossed below SMA
if (low <= smaValue and low[1] > smaValue[1]) // Crossed below
    wickColor := color.blue
else if (low <= smaValue) // Touched or stayed below
    wickColor := color.blue

// Check if high touched or crossed above SMA
if (high >= smaValue and high[1] < smaValue[1]) // Crossed above
    wickColor := color.orange
else if (high >= smaValue) // Touched or stayed above
    wickColor := color.orange


// Use a different color if both conditions were met (e.g., volatile bar around SMA)
// This part is optional, depending on desired behavior when wick crosses both ways
// For simplicity, the current logic prioritizes crossing above if it happens later
// A more robust check would use `ta.cross()` or check high vs low relative to SMA
// Let's refine the logic slightly for clearer separation:

wickColor = color.gray // Reset for new logic

bool lowTouchedSMA = low <= smaValue
bool highTouchedSMA = high >= smaValue

if (lowTouchedSMA and not highTouchedSMA)
    wickColor := color.blue // Only low touched/crossed below
else if (highTouchedSMA and not lowTouchedSMA)
    wickColor := color.orange // Only high touched/crossed above
else if (lowTouchedSMA and highTouchedSMA)
    wickColor := color.fuchsia // Both touched/crossed - potentially a piercing candle on SMA


// Plot the candles
plotcandle(open, high, low, close, 
           title="Candles",
           color=close>open ? color.green : color.red, 
           bordercolor=color.black,
           wickcolor=wickColor)

// Optionally plot the SMA
plot(smaValue, color=color.blue, title="SMA")

This example demonstrates using if/else if statements to build more complex conditional logic based on an indicator’s value.

Example 3: Highlighting Long Wicks with a Specific Color

This script highlights wicks that are significantly long relative to the total candle range.

//@version=5
indicator("Highlight Long Wicks", overlay=true)

// Input for the long wick ratio threshold
longWickRatioThreshold = input.float(0.4, "Long Wick Ratio Threshold (vs Total Range)", minval=0.1, maxval=0.9, step=0.05)

// Calculate candle components
totalRange = high - low
bodySize = math.abs(close - open)

// Handle cases with zero range to avoid division by zero
float upperWickLength = totalRange > 0 ? (high - math.max(open, close)) : 0
float lowerWickLength = totalRange > 0 ? (math.min(open, close) - low) : 0

// Determine if upper or lower wick is 'long'
bool isLongUpperWick = totalRange > 0 ? (upperWickLength / totalRange >= longWickRatioThreshold) : false
bool isLongLowerWick = totalRange > 0 ? (lowerWickLength / totalRange >= longWickRatioThreshold) : false

// Determine wick color
wickColor = color.gray // Default color
if (isLongUpperWick)
    wickColor := color.teal // Highlight long upper wicks
else if (isLongLowerWick)
    wickColor := color.purple // Highlight long lower wicks

// Plot the candles
plotcandle(open, high, low, close,
           title="Candles",
           color=close>open ? color.green : color.red,
           bordercolor=color.black,
           wickcolor=wickColor)

This code calculates wick lengths, normalizes them by the total range, and uses the input threshold to decide whether to apply a special color. It also includes a check (totalRange > 0) to prevent division by zero errors on zero-range bars (like dojis where high=low=open=close), which is a good practice for robustness.

Best Practices and Considerations

Implementing custom wick colors effectively involves more than just writing the conditional logic. Consider these points:

Ensuring Code Readability and Maintainability

  • Use meaningful variable names: isLongUpperWick is clearer than cond1. longWickRatioThreshold explains its purpose better than thr..
  • Break down complex logic: Instead of one massive ternary operation, calculate intermediate boolean variables (isLongUpperWick, isHighVolume) first and then combine them in the final color assignment. This makes the logic flow easier to follow.
  • Add comments: Explain why a certain color condition is used, not just what the code does line-by-line (unless the logic itself is complex).
  • Consistent formatting: Indent properly and use consistent spacing.

Optimizing Performance with Efficient Color Logic

  • Avoid redundant calculations: Calculate values like totalRange, bodySize, or indicator values only once per bar if they are needed for multiple conditions.
  • Simplify conditions: Complex boolean expressions can sometimes be simplified. Test your logic on different bar types (standard, doji, high wave) to ensure it behaves as expected without unnecessary computation.
  • Prefer built-ins: Use built-in functions like math.max, math.abs, ta.sma where appropriate, as they are highly optimized.

For wick coloring specifically, since plotcandle is applied bar by bar, the performance bottleneck is usually not the color logic itself unless it involves iterating through historical bars within the color calculation (which is generally bad practice for plotting functions). The key is efficient calculation of the conditions that determine the color.

Avoiding Common Pitfalls in Wick Color Coding

  • Division by Zero: As shown in Example 3, dividing by totalRange or bodySize can cause errors if they are zero. Always add checks (if totalRange > 0) or use functions like math.max(1e-10, totalRange) to ensure the denominator is never zero.
  • Repainting: Ensure that the conditions determining the wick color only use data from the current bar (open, high, low, close, volume, time) or past bars (using history reference [1], [2], etc., or functions like ta.sma which are non-repainting). Using future data explicitly or implicitly via certain functions without proper handling will lead to repainting, where historical wick colors change on subsequent bar updates, rendering them unreliable for backtesting or real-time signals.
  • Over-coloring: Too many different wick colors or overly bright/transparent colors can make the chart look cluttered and difficult to interpret. Choose your colors and conditions thoughtfully to highlight only the most significant information.
  • Misunderstanding plotcandle arguments: Ensure you are passing the color to the wickcolor argument and not accidentally to the main color argument (which affects the body) or bordercolor.

By understanding the structure of candlesticks, the capabilities of plotcandle, and applying conditional logic effectively while keeping best practices in mind, you can create powerful and insightful visualizations through customized wick colors in your Pine Script indicators and strategies.


Leave a Reply