Hello! Welcome back to your deep dive into ICT and algorithmic trading.
In the last lesson, you built a Python function, calculate_ote, to programmatically identify the Optimal Trade Entry (OTE) zone. This gave you a powerful tool to pinpoint where a high-probability reversal might occur after a significant price swing.
Today, we will add another crucial layer of confirmation to that analysis. Our goal is to combine automated Fair Value Gap (FVG) detection with your OTE levels to generate potential entry signals. An FVG appearing within an OTE zone is a classic ICT confluence that signals a potent area of institutional interest. By the end of this lesson, you'll have a script that can automatically flag these high-probability setups.
The Power of Confluence: OTE + FVG
Why is this combination so effective? Let's break it down:
- Optimal Trade Entry (OTE) identifies a deep retracement into a premium or discount zone. It tells you that price has pulled back to a statistically significant level where a reversal is likely. It answers the question: "Is the price cheap enough to buy or expensive enough to sell?"
- Fair Value Gap (FVG) identifies an imbalance or inefficiency in price delivery. It's a footprint left by aggressive, one-sided order flow. A return to an FVG often signals that the market is coming back to "rebalance" price before continuing its move. It answers the question: "Is there a specific point of interest where institutions might re-engage?"
When you find an FVG inside an OTE zone, you have a confluence of signals. The market has returned to a favorable price (OTE) and is simultaneously testing a precise area of inefficiency (FVG). This is the kind of A+ setup traders look for.
These charts illustrate the concept perfectly.


Automating FVG Detection with a Library
In Module 6, you learned the logic to detect FVGs. As you move toward building more complex automated systems, it's efficient to use specialized libraries that have pre-built, optimized functions for these tasks.
For this lesson, we will use the smartmoneyconcepts library, a Python tool specifically designed for ICT concepts. This will allow you to detect FVGs with a single line of code.
joshyattridge/smart-money-concepts
The smartmoneyconcepts library is a powerful tool for any ICT-based algorithmic trader. This GitHub repository serves as its documentation. We will focus on its fvg indicator function.
First, read the 'Installation' section to see how to install the library. Then, review the section for the 'Fair Value Gap (FVG)' indicator. Pay close attention to the parameters it takes and the columns it returns (FVG, Top, Bottom). This is the function we will use.
To get started, open your terminal or command prompt and install the library:
pip install smartmoneyconcepts
Once installed, you can import it and use the fvg function on your pandas DataFrame. A key requirement is that your DataFrame columns must be lowercase: ['open', 'high', 'low', 'close'].
Here’s how you would apply it:
import pandas as pd
from smartmoneyconcepts import smc
# Assume 'ohlc_df' is your DataFrame with OHLC data
# Ensure columns are lowercase
ohlc_df.columns = ['open', 'high', 'low', 'close']
# Detect FVGs
fvg_data = smc.fvg(ohlc_df)
# Merge the FVG data back into your main DataFrame
df = pd.concat([ohlc_df, fvg_data], axis=1)
# The 'df' now contains new columns: 'FVG', 'Top', 'Bottom', 'MitigatedIndex'
The smc.fvg() function will add four new columns:
FVG:1for a bullish FVG,-1for a bearish FVG, and0orNaNotherwise.Top: The top price level of the FVG.Bottom: The bottom price level of the FVG.MitigatedIndex: The candle index that fills or "mitigates" the FVG.
The Logic: Finding the FVG in the OTE Zone
Now we have the two main components:
- Our
calculate_otefunction from the last lesson. - A DataFrame enriched with FVG data from the
smartmoneyconceptslibrary.
The final step is to create a function that checks for the overlap. The logic is as follows:
- Define a price swing (
swing_high,swing_low). - Calculate the OTE zone for that swing.
- Iterate through the price data.
- At each candle, if a relevant FVG exists (e.g., a bullish FVG for a buy setup), check if its price range intersects with the OTE zone.
- An intersection occurs if the FVG range and the OTE range overlap. For a bullish setup, this means checking if the FVG is at least partially inside the discount OTE zone.
Here is a Python function that implements this logic. It takes the OTE dictionary and a row from your DataFrame (which represents a single candle with its FVG data) and checks for the confluence.
def check_fvg_ote_confluence(ote_zone: dict, fvg_row, is_buy_setup: bool) -> bool:
"""
Checks if a given Fair Value Gap (FVG) is located within the Optimal Trade Entry (OTE) zone.
Args:
ote_zone (dict): The dictionary returned by the calculate_ote function.
Contains 'ote_62.0', 'ote_79.0', etc.
fvg_row: A row from a pandas DataFrame containing FVG data ('FVG', 'Top', 'Bottom').
is_buy_setup (bool): True for a buy setup, False for a sell setup.
Returns:
bool: True if there is a confluence, False otherwise.
"""
fvg_type = fvg_row['FVG']
fvg_top = fvg_row['Top']
fvg_bottom = fvg_row['Bottom']
# If there's no FVG on this row, return False immediately
if pd.isna(fvg_type) or fvg_type == 0:
return False
if is_buy_setup:
# For a buy setup, we look for a bullish FVG (-1 is bearish, 1 is bullish)
if fvg_type != 1:
return False
# OTE zone for a buy setup is between ote_62.0 (higher price) and ote_79.0 (lower price)
ote_top_price = ote_zone['ote_62.0']
ote_bottom_price = ote_zone['ote_79.0']
# Check for overlap: The FVG bottom must be below the OTE top,
# and the FVG top must be above the OTE bottom.
# This confirms the two zones intersect.
if fvg_bottom < ote_top_price and fvg_top > ote_bottom_price:
return True
else: # This is a sell setup
# For a sell setup, we look for a bearish FVG
if fvg_type != -1:
return False
# OTE zone for a sell setup is between ote_79.0 (higher price) and ote_62.0 (lower price)
ote_top_price = ote_zone['ote_79.0']
ote_bottom_price = ote_zone['ote_62.0']
# Check for overlap
if fvg_bottom < ote_top_price and fvg_top > ote_bottom_price:
return True
return False
Note: The function calculate_ote is assumed to be available from the previous lesson. We'll include it here for completeness.
def calculate_ote(swing_high: float, swing_low: float, is_buy_setup: bool) -> dict:
price_range = swing_high - swing_low
ote_levels = {}
ote_fib_levels = [0.62, 0.705, 0.79]
if is_buy_setup:
for level in ote_fib_levels:
ote_levels[f'ote_{level*100:.1f}'] = swing_high - (price_range * level)
else:
for level in ote_fib_levels:
ote_levels[f'ote_{level*100:.1f}'] = swing_low + (price_range * level)
return ote_levels
Putting It All Together: A Full Example
Let's now use these functions in a complete script. We will simulate a scenario where we have a defined price swing and want to find an OTE+FVG entry signal.
Scenario: Bullish Setup (Buy)
import pandas as pd
from smartmoneyconcepts import smc
# --- 1. Sample Data and Swing Definition ---
# Let's create some sample data representing a retracement
data = {
'open': [1.0820, 1.0790, 1.0770, 1.0780, 1.0800],
'high': [1.0830, 1.0795, 1.0775, 1.0785, 1.0810],
'low': [1.0785, 1.0765, 1.0750, 1.0770, 1.0790],
'close': [1.0790, 1.0770, 1.0760, 1.0782, 1.0805]
}
df = pd.DataFrame(data)
df.columns = ['open', 'high', 'low', 'close'] # Ensure lowercase column names
# Define the major swing that created our trading range
swing_low = 1.0720
swing_high = 1.0850
is_buy_setup = True
# --- 2. Calculate OTE Zone ---
buy_ote_zone = calculate_ote(swing_high, swing_low, is_buy_setup)
print("--- Bullish OTE Zone (Buy Setup) ---")
print(f"OTE Top (62%): {buy_ote_zone['ote_62.0']:.4f}")
print(f"OTE Bottom (79%): {buy_ote_zone['ote_79.0']:.4f}\n")
# --- 3. Detect FVGs ---
fvg_data = smc.fvg(df)
df = pd.concat([df, fvg_data], axis=1)
# --- 4. Find Confluence ---
print("--- Searching for FVG + OTE Confluence ---")
for index, row in df.iterrows():
# We need to look at the FVG formed by the candle at `index-1`
# The smc library marks the FVG on the third candle of the pattern.
# To be practical, let's check the FVG associated with the *previous* candle.
if index > 0:
fvg_row = df.loc[index-1]
if check_fvg_ote_confluence(buy_ote_zone, fvg_row, is_buy_setup):
print(f"Signal Found at index {index-1}!")
print(f" -> Bullish FVG detected from {fvg_row['Bottom']:.4f} to {fvg_row['Top']:.4f}")
print(f" -> This FVG is inside the OTE zone.\n")
In a real-world scenario, you would be feeding live or historical data into this script, and the swing_high/swing_low would be programmatically identified (e.g., using the pivot functions we've explored). The print statement could be replaced with an alert (email, Discord message) or an automated order execution command.
Test your understanding!
Imagine you have a sell setup where a price swing is defined by a swing_high of 1.2750 and a swing_low of 1.2600.
Your script detects a bearish FVG on a specific candle with a Top price of 1.2705 and a Bottom price of 1.2690.
Would your check_fvg_ote_confluence function return True or False for this FVG? Explain why.
Show answer
First, let's calculate the OTE zone for the sell setup:sell_ote_zone = calculate_ote(1.2750, 1.2600, is_buy_setup=False)
This would give us:
ote_62.0: 1.2600 + (1.2750 - 1.2600) * 0.62 = 1.2693ote_79.0: 1.2600 + (1.2750 - 1.2600) * 0.79 = 1.27185
So, the premium OTE zone for selling is between 1.2693 and 1.27185.
The detected bearish FVG spans from 1.2690 to 1.2705.
The function would return True.
Why? The FVG's range (1.2690 - 1.2705) overlaps with the OTE zone's range (1.2693 - 1.27185). The top of the FVG (1.2705) is within the OTE zone, creating the confluence we are looking for.
Conclusion
Congratulations! You have now successfully combined two of ICT's most powerful concepts into a single, automated signal. This is a significant step forward in building a robust algorithmic trading toolkit.
Key Takeaways:
- The confluence of an OTE and an FVG provides a high-probability entry signal by aligning a statistically favorable price zone with a specific point of market inefficiency.
- Using specialized libraries like
smartmoneyconceptsdramatically speeds up development by providing ready-to-use functions for complex patterns like FVGs. - We created a core logic function,
check_fvg_ote_confluence, that programmatically verifies if an FVG overlaps with a calculated OTE zone, forming the basis of an automated alert system.
Preview for the Next Lesson:
We've layered price patterns on top of each other. The next step is to add the dimension of time. In the next lesson, you will learn to build a Python script that alerts when Silver Bullet conditions are met. The Silver Bullet is a time-based setup that requires an FVG to be taken within a specific 1-hour window during the London or New York sessions. Your work today has laid the perfect foundation for tackling this exciting strategy.