Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 59

Building an OTE Retracement Function

Recommended resources

Hello! Welcome back to our journey into ICT and algorithmic trading.

In our last lesson, you built a powerful script to programmatically detect Smart Money Technique (SMT) divergence. That was a significant step, as it gave you a tool for confirmation—a way to spot when a supposed trend might be losing momentum and a reversal is likely.

Today, we're building the logical next piece of the puzzle. If SMT divergence signals a potential reversal, the next question is: where do we enter? This lesson answers that question. Our goal is to develop a function to identify an Optimal Trade Entry (OTE) retracement level programmatically. You will learn to translate one of ICT's core entry models into a reusable Python function.

What is Optimal Trade Entry (OTE)?

Before we write any code, let's solidify our understanding of what OTE is and why it's such a cornerstone of ICT.

An OTE is not just a random set of Fibonacci levels; it's a specific zone where price is most likely to reverse after a significant move, offering a high-probability entry with a favorable risk-to-reward ratio. It represents a deep retracement into either a discount zone (for buy setups) or a premium zone (for sell setups).

This infographic provides an excellent overview of the entire OTE framework. Pay close attention to the concepts of market structure, premium/discount, and the specific Fibonacci levels highlighted.

ICT Optimal Trade Entry (OTE) Infographic
This infographic shows how OTE fits into a broader trading model, combining market structure with specific entry zones.

The core of the OTE lies in three key Fibonacci retracement levels, measured from the start to the end of a major price swing:

  • 62% (0.62)
  • 70.5% (0.705) - Often considered the "sweet spot".
  • 79% (0.79)

This simple illustration cleanly shows these levels within a price swing.

Optimal Trade Entry (OTE) Retracement Illustration
A clear visual of the OTE retracement levels (0.62, 0.705, and 0.79) within a price swing. This is the zone we want to identify with our Python function.

The Logic of Calculating Retracement Levels

To translate this concept into code, we need a clear, mathematical formula. The calculation depends on whether you are looking for a buy setup (a retracement down into a discount zone) or a sell setup (a retracement up into a premium zone).

The following resource explains the universal formulas for this.

Fibonacci Sequence in Trading with Python | by EODHD APIs

The article 'Fibonacci Sequence in Trading with Python' by EODHD APIs clearly outlines the formulas for calculating retracement levels in both uptrends and downtrends. This is the exact logic we will implement.

Read the section 'Calculating Fibonacci levels in Python for trading'. Focus on the formulas provided for 'Uptrend Retracement' and 'Downtrend Retracement'. We will use these as the foundation for our OTE function.

As the article shows, the formulas are:

  • For a Buy Setup (after an uptrend swing): We expect price to retrace down. The level is calculated as:
  • For a Sell Setup (after a downtrend swing): We expect price to retrace up. The level is calculated as:

Our task is to build a Python function that applies these formulas using the specific OTE percentages (0.62, 0.705, 0.79).


Developing the OTE Function in Python

Now, let's get to the code. We will create a single, reusable function that can calculate the OTE zone for either a buy or a sell setup.

The video below demonstrates how to create a Python function to calculate standard Fibonacci levels. While it uses slightly different levels and a different method for finding the swing high/low, the core principle of creating a function to perform the calculation is the same.

How to Code Fibonacci Retracement in Python

The video 'How to Code Fibonacci Retracement in Python' by YouDomo shows the process of creating a function to calculate Fibonacci levels. We will adapt this approach for our specific OTE levels.

Watch the section from 07:26 to 08:16. Pay attention to how the function takes the data, finds the min/max prices within a range, and then calculates each retracement level.

Drawing on that concept, here is a Python function designed specifically for calculating ICT Optimal Trade Entry levels.

def calculate_ote(swing_high: float, swing_low: float, is_buy_setup: bool) -> dict:
    """
    Calculates the ICT Optimal Trade Entry (OTE) levels for a given price swing.

    Args:
        swing_high (float): The high price of the swing that defines the trading range.
        swing_low (float): The low price of the swing that defines the trading range.
        is_buy_setup (bool):
            - Set to True for a bullish OTE (buy setup). The primary swing was UP,
              and we are calculating the retracement DOWN into a discount zone.
            - Set to False for a bearish OTE (sell setup). The primary swing was DOWN,
              and we are calculating the retracement UP into a premium zone.

    Returns:
        dict: A dictionary containing the OTE price levels and the 50% equilibrium level.
    """
    price_range = swing_high - swing_low
    
    ote_levels = {}
    ote_fib_levels = [0.62, 0.705, 0.79]

    if is_buy_setup:
        # For a buy setup, the OTE levels are in the discount zone (lower part of the range).
        # We calculate them by subtracting a portion of the range from the swing high.
        for level in ote_fib_levels:
            # The key is formatted to be readable, e.g., 'ote_62.0'
            ote_levels[f'ote_{level*100:.1f}'] = swing_high - (price_range * level)
        ote_levels['equilibrium'] = swing_high - (price_range * 0.5)
    else: # This is a sell setup
        # For a sell setup, the OTE levels are in the premium zone (upper part of the range).
        # We calculate them by adding a portion of the range to the swing low.
        for level in ote_fib_levels:
            ote_levels[f'ote_{level*100:.1f}'] = swing_low + (price_range * level)
        ote_levels['equilibrium'] = swing_low + (price_range * 0.5)
            
    return ote_levels


Applying the Function

Let's see this function in action. In a full trading script, you would first identify a significant swing high and swing low (for example, using the pivotid function from our last lesson) that establishes a new trading range. Then, you would pass those values to our calculate_ote function.

Example 1: Bullish OTE (Buy Setup)
Imagine the price of EUR/USD moves from a swing low at 1.07200 up to a swing high at 1.08500. We now anticipate a retracement down into a discount zone to look for a buy.

# --- Bullish OTE Example ---
bullish_swing_low = 1.07200
bullish_swing_high = 1.08500

# We set is_buy_setup to True because we are looking for a discount entry
buy_ote_zone = calculate_ote(
    swing_high=bullish_swing_high, 
    swing_low=bullish_swing_low, 
    is_buy_setup=True
)

print("--- Bullish OTE Zone (Buy Setup) ---")
# Print the results formatted to 5 decimal places for forex
for level, price in buy_ote_zone.items():
    print(f"{level}: {price:.5f}")

Expected Output:

--- Bullish OTE Zone (Buy Setup) ---
ote_62.0: 1.07694
ote_70.5: 1.07604
ote_79.0: 1.07473
equilibrium: 1.07850

This tells us that the key area to watch for a long entry is between 1.07694 and 1.07473.

Example 2: Bearish OTE (Sell Setup)
Now, let's say GBP/USD moves from a swing high at 1.27000 down to a swing low at 1.25500. We anticipate a retracement up into a premium zone to look for a sell.

# --- Bearish OTE Example ---
bearish_swing_high = 1.27000
bearish_swing_low = 1.25500

# We set is_buy_setup to False because we are looking for a premium entry
sell_ote_zone = calculate_ote(
    swing_high=bearish_swing_high, 
    swing_low=bearish_swing_low, 
    is_buy_setup=False
)

print("\n--- Bearish OTE Zone (Sell Setup) ---")
for level, price in sell_ote_zone.items():
    print(f"{level}: {price:.5f}")

Expected Output:

--- Bearish OTE Zone (Sell Setup) ---
ote_62.0: 1.26430
ote_70.5: 1.26558
ote_79.0: 1.26685
equilibrium: 1.26250

Here, our function identifies the premium sell zone between 1.26430 and 1.26685.

Test your understanding!

After a strong downtrend, you observe a bullish SMT divergence on the 1-hour chart for USD/CAD. Price then creates a bullish Break of Structure (BOS), defining a new potential trading range. The swing low that initiated the move is at 1.36100 and the swing high that broke structure is at 1.37300.

You are now anticipating a retracement to enter a long position. Use the calculate_ote function to determine the price levels of your OTE zone. Which prices would you be monitoring?

Show answer

You would be looking for a buy setup. Therefore, you would call the function like this:

swing_low = 1.36100
swing_high = 1.37300

ote_zone = calculate_ote(swing_high, swing_low, is_buy_setup=True)

print("--- USD/CAD Buy Setup OTE Zone ---")
for level, price in ote_zone.items():
    print(f"{level}: {price:.5f}")

Output:

--- USD/CAD Buy Setup OTE Zone ---
ote_62.0: 1.36556
ote_70.5: 1.36454
ote_79.0: 1.36352
equilibrium: 1.36700

You would be closely monitoring the price zone between 1.36556 and 1.36352 for a potential long entry.


Conclusion

Excellent work! You have successfully created a function to programmatically identify one of ICT's most reliable entry models. This is a crucial building block in your journey towards automating your trading analysis.

Key Takeaways:

  • The Optimal Trade Entry (OTE) is a specific zone, defined by the 62%, 70.5%, and 79% Fibonacci retracement levels, located within a premium or discount market.
  • The mathematical formula for calculating the retracement levels depends on the direction of the setup (buy vs. sell).
  • We have encapsulated this logic into a clean, reusable Python function, calculate_ote, that takes a swing_high, swing_low, and the setup direction (is_buy_setup) as inputs.

Preview for the Next Lesson:
Finding an OTE zone is powerful. Finding an OTE zone that aligns with another institutional price pattern is even more powerful. In our next lesson, we will combine automated FVG detection with OTE levels to generate potential entry signals. You'll write a script that looks for the potent confluence of price retracing into an OTE zone that also contains a Fair Value Gap (FVG), creating a very high-probability automated alert for your review.