Fair Value Gap (FVG) Algo-Trading with Smart Money Concepts (SMC)

Advanced Technical Analysis using SMC FVG Trading Signals in Python — ORCL Stock in Focus

In partnership with

Wall Street has Bloomberg. You have Stocks & Income.

Why spend $25K on a Bloomberg Terminal when 5 minutes reading Stocks & Income gives you institutional-quality insights?

We deliver breaking market news, key data, AI-driven stock picks, and actionable trends—for free.

Subscribe for free and take the first step towards growing your passive income streams and your net worth today.

Stocks & Income is for informational purposes only and is not intended to be used as investment advice. Do your own research.

🚀 Your Investing Journey Just Got Better: Premium Subscriptions Are Here! 🚀

It’s been 4 months since we launched our premium subscription plans at GuruFinance Insights, and the results have been phenomenal! Now, we’re making it even better for you to take your investing game to the next level. Whether you’re just starting out or you’re a seasoned trader, our updated plans are designed to give you the tools, insights, and support you need to succeed.

Here’s what you’ll get as a premium member:

  • Exclusive Trading Strategies: Unlock proven methods to maximize your returns.

  • In-Depth Research Analysis: Stay ahead with insights from the latest market trends.

  • Ad-Free Experience: Focus on what matters most—your investments.

  • Monthly AMA Sessions: Get your questions answered by top industry experts.

  • Coding Tutorials: Learn how to automate your trading strategies like a pro.

  • Masterclasses & One-on-One Consultations: Elevate your skills with personalized guidance.

Our three tailored plans—Starter Investor, Pro Trader, and Elite Investor—are designed to fit your unique needs and goals. Whether you’re looking for foundational tools or advanced strategies, we’ve got you covered.

Don’t wait any longer to transform your investment strategy. The last 4 months have shown just how powerful these tools can be—now it’s your turn to experience the difference.

Let’s break down the mechanics of SMC trading strategies based on the KISS (Keep It Simple, Stupid!) principle.

Modified Canva Image Design Template by @red-hawk-eye

  • Nowadays the use of algorithmic (aka algo-) trading [1, 2] has become more predominant in major financial markets.

  • According to Fortune Business Insights, the global algo-trading market size was valued at USD 2.36 billion in 2024 and is projected to grow from USD 2.53 billion in 2025 to USD 4.06 billion by 2032, exhibiting a CAGR of 7.0% during the forecast period.

  • Most technical analysis-based algo-trading strategies involve the technical indicators [1]. Each indicator is designed to serve a certain purpose by choosing among long-term investments, short-term intraday, swings, derivatives, or commodities.

  • However, most popular technical indicators [1] are lagging in that they all respond to what has occurred and not what’s going to occur. These indicators often create a false confidence and therefore are terrible in choppy or fast-moving markets [3].

  • The Inner Circle Trader (ICT) Trading Strategy developed by Michael J. Huddleston attempts to address the these shortcomings of lagging indicators based on the actions of institutional traders in the market (e.g. central banks in forex trading) [3].

  • ICT focuses on recognizing the footprints left behind by banks, hedge funds, and other big players. These show up through things like order blocks, liquidity grabs, fair value gaps, and shifts in market structure.

  • A crucial insight that the ICT method provides is the identification of the precise candle where the order flow starts.

  • Michael distilled his trading insights into the Smart Money Concept (SMC) [4]. Instead of relying solely on indicators that lag price and basic chart patterns, SMC practitioners [4] analyze key market structures and patterns that signal institutional activity, viz.

  1. Order Blocks: Areas where institutions place large orders that drive future price movement

  2. Liquidity: Concentrations of stop losses and pending orders that institutions target

  3. Market Structure: The hierarchical pattern of higher highs/lows or lower highs/lows

  4. Fair Value Gaps (FVG): Quick moves that leave imbalances in price, creating future reversal zones

  5. Breaker Blocks: Order blocks that have been broken through and now serve as strong support/resistance.

Run ads IRL with AdQuick

With AdQuick, you can now easily plan, deploy and measure campaigns just as easily as digital ads, making them a no-brainer to add to your team’s toolbox.

You can learn more at www.AdQuick.com

  • In this post, we’ll look at the FVG trading signals available through smartmoneyconcepts in Python [5]

!pip install smartmoneyconcepts
  • Typically, a FVG is formed when the low of a candle is higher than the high of the next candle (for bearish FVGs) or when the high of a candle is lower than the low of the next candle (for bullish FVGs). It’s essentially a gap in the normal flow of price action, as shown below.

Bullish & Bearish FVGs.

  • Our objective is twofold: (1) the automatic identification of FVGs with the smc.fvg method [5]; (2) Profitability analysis of FVG trading signals as compared to the Buy&Hold strategy for the same period of time.

  • Below we’ll download the Oracle (NYSE: ORCL) daily stock prices from 2025–01–01 to 2025–09–12. According to TradingView, the market views Oracle as a frontrunner in the expanding AI infrastructure space, driving a surge in investor confidence and buying activity.

Let’s get into specifics!

  • Importing the necessary Python libraries and fetching the ORCL stock data with TwelveData API [1]

import pandas as pd
import numpy as np
import requests
import matplotlib.pyplot as plt
from smartmoneyconcepts import smc
import plotly.graph_objects as go

def get_historical_data(symbol, start_date):
    api_key = 'YOUR API KEY'
    api_url = f'https://api.twelvedata.com/time_series?symbol={symbol}&interval=1day&outputsize=5000&apikey={api_key}'
    raw_df = requests.get(api_url).json()
    df = pd.DataFrame(raw_df['values']).iloc[::-1].set_index('datetime').astype(float)
    df = df[df.index >= start_date]
    df.index = pd.to_datetime(df.index)
    return df

ohlc = get_historical_data('ORCL', '2025-01-01')

ohlc.tail()

           open    high      low        close     volume
datetime     
2025-09-08 239.890 242.42000 235.310000 238.48000 18803000.0
2025-09-09 239.940 243.49001 234.560000 241.50999 41178700.0
2025-09-10 319.190 345.72000 312.089996 328.32999 131618100.0
2025-09-11 330.340 331.00000 304.600010 307.85999 69857800.0
2025-09-12 306.035 307.73500 291.750000 293.97000 1909846.0
  • Using Plotly to visualize the ORCL OHLC chart

fig = go.Figure(data=go.Ohlc(x=ohlc.index,
                             open=ohlc.open,
                             high=ohlc.high,
                             low=ohlc.low,
                             close=ohlc.close),

                layout=go.Layout(
        title=go.layout.Title(text="ORCL OHLC 2025"))
               )
fig.update_xaxes(title_text="Date")
fig.update_yaxes(title_text="Price USD")
# show the figure
fig.show()

ORCL OHLC 2025

  • Calculating the FVG indicator [5]

myfvg=smc.fvg(ohlc, join_consecutive=False)
  • The output of smc.fvg consists of the following four columns

df = pd.DataFrame(index=(ohlc.index))
mylist=myfvg["FVG"]
se = pd.Series(mylist)
df['FVG']=se.values

mylist=myfvg["Top"]
se = pd.Series(mylist)
df['Top']=se.values

mylist=myfvg["Bottom"]
se = pd.Series(mylist)
df['Bottom']=se.values

mylist=myfvg["MitigatedIndex"]
se = pd.Series(mylist)
df['MitigatedIndex']=se.values

df.tail()

           FVG Top        Bottom    MitigatedIndex
datetime    
2025-09-08 NaN NaN        NaN       NaN
2025-09-09 1.0 312.089996 242.42000 172.0
2025-09-10 1.0 304.600010 243.49001 173.0
2025-09-11 -1.0 312.089996 307.97000 0.0
2025-09-12 NaN  NaN       NaN       NaN
  • In principle, we can restrict ourselves to the simplified FVG method

    def fvgonly(cls, ohlc: DataFrame, join_consecutive=False) -> Series:
        """
        FVG - Fair Value Gap
        A fair value gap is when the previous high is lower than the next low if the current candle is bullish.
        Or when the previous low is higher than the next high if the current candle is bearish.

        parameters:
        join_consecutive: bool - if there are multiple FVG in a row then they will be merged into one using the highest top and the lowest bottom

        returns:
        FVG = 1 if bullish fair value gap, -1 if bearish fair value gap
        """

        fvg = np.where(
            (
                (ohlc["high"].shift(1) < ohlc["low"].shift(-1))
                & (ohlc["close"] > ohlc["open"])
            )
            | (
                (ohlc["low"].shift(1) > ohlc["high"].shift(-1))
                & (ohlc["close"] < ohlc["open"])
            ),
            np.where(ohlc["close"] > ohlc["open"], 1, -1),
            np.nan,
        )

        return pd.concat(
            [
                pd.Series(fvg, name="FVG"),
            ],
            axis=1,
        )

myfvgonly=smc.fvgonly(ohlc, join_consecutive=False)

print(myfvgonly)

FVG
0    NaN
1    NaN
2    NaN
3   -1.0
4    NaN
..   ...
169  NaN
170  1.0
171  1.0
172 -1.0
173  NaN

[174 rows x 1 columns]
  • Plotting the ORCL FVG Top/Bottom (output of smc.fvg)

plt.plot(df.index,ohlc['close'],color='y',alpha=0.5,label='Close')
plt.scatter(df.index,myfvg["Top"],color = 'green',alpha=0.99,label='Top')
plt.scatter(df.index,myfvg["Bottom"],color = 'red',alpha=0.99,label='Bottom')
plt.legend()
plt.xlabel('Date')
plt.ylabel('Price USD')
plt.title('ORCL FVG Top/Bottom')
plt.show()

ORCL FVG Top/Bottom

bullsignals = ohlc['close'][df["FVG"] == 1]
bearsignals = ohlc['close'][df["FVG"] == -1]

plt.plot(ohlc['close'],alpha=0.4,label='Close')
for idx in bullsignals.index.tolist():
  plt.plot(
      idx,
      ohlc.loc[idx]["close"],
      "g*",
      markersize=25, 
  )

for idx in bearsignals.index.tolist():
  plt.plot(
      idx,
      ohlc.loc[idx]["close"],
      "r*",
      markersize=25,
  )

plt.legend()
plt.title('ORCL FVG Trading Signals')
plt.xlabel('Date')
plt.ylabel('Price USD')

plt.show()

ORCL FVG Buy & Sell Trading Signals (Green & Red Star Symbols, respectively).

  • Creating positions (shift signals to avoid look-ahead bias) [2]

data=df.copy()
data['Position'] = data['FVG'].shift(1)
  • Calculating and plotting the daily and cumulative returns (backtesting)

# Calculate daily percentage change in stock prices
data['Daily Return'] = ohlc['close'].pct_change()

# Calculate returns based on the strategy
data['Strategy Return'] = data['Position'] * data['Daily Return']

# Calculate cumulative returns
data['Cumulative Market Return'] = (1 + data['Daily Return']).cumprod()
data['Cumulative Strategy Return'] = (1 + data['Strategy Return']).cumprod()

plt.style.use('fivethirtyeight')
plt.rcParams['figure.figsize'] = (10,5)

rets = ohlc.close.pct_change()[1:]
strat_rets = data['Position'][1:] * rets

plt.title('ORCL Daily Returns')
rets.plot(color = 'blue', alpha = 0.3, linewidth = 7,label='Buy&Hold')
strat_rets.plot(color = 'r', linewidth = 1,linestyle='dashed', marker='s',label='FVG')
plt.legend()
plt.show()

rets_cum = (1 + rets).cumprod() - 1 
strat_cum = (1 + strat_rets).cumprod() - 1

plt.title('ORCL Cumulative Returns')
rets_cum.plot(color = 'blue', alpha = 0.3, linewidth = 7,label='Buy&Hold')
strat_cum.plot(color = 'r', linewidth = 2,linestyle='dashed', marker='s',label='FVG')
plt.legend()
plt.show()

ORCL Daily Returns: FVG vs Buy&Hold.

ORCL Cumulative Returns: FVG vs Buy&Hold.

Conclusions

  • We have implemented and (back)tested the FVG trading strategy using smartmoneyconcepts in Python.

  • In terms of the cumulative return, this strategy is shown to significantly outperform the buy & hold approach for the Oracle stock in Q1-Q3 2025.

  • However, these are strictly backtesting findings. Like any strategy, there is no guarantee of future performance, and this strategy should not be taken as financial advice.

    How 433 Investors Unlocked 400X Return Potential

    Institutional investors back startups to unlock outsized returns. Regular investors have to wait. But not anymore. Thanks to regulatory updates, some companies are doing things differently.

    Take Revolut. In 2016, 433 regular people invested an average of $2,730. Today? They got a 400X buyout offer from the company, as Revolut’s valuation increased 89,900% in the same timeframe.

    No wonder 10K+ everyday people are taking the chance on Pacaso.

    Founded by a former Zillow exec, Pacaso’s co-ownership tech reshapes the $1.3T vacation home market. They’ve earned $110M+ in gross profit to date, including 41% YoY growth in 2024 alone. They even reserved the Nasdaq ticker PCSO.

    The same institutional investors behind Uber, Venmo, and eBay backed Pacaso. And you can join them. But not for long. Pacaso’s investment opportunity ends September 18.

    Invest While You Still Can

    Paid advertisement for Pacaso’s Regulation A offering. Read the offering circular at invest.pacaso.com. Reserving a ticker symbol is not a guarantee that the company will go public. Listing on the NASDAQ is subject to approvals.