In partnership with

Business news as it should be.

Join 4M+ professionals who start their day with Morning Brew—the free newsletter that makes business news quick, clear, and actually enjoyable.

Each morning, it breaks down the biggest stories in business, tech, and finance with a touch of wit to keep things smart and interesting.

🚀 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.

  • “Most quants lose money not because they can’t find patterns, but because they find too many that aren’t real.”
    David Leinweber, author of Nerds on Wall Street

  • We believe that a key success factor of SMC trading is the ability to avoid knee-jerk decisions due to market noise.

  • The crucial point of SMC is that financial markets often exhibit repetitive patterns influenced by institutional participants (aka smart money). Recognizing these patterns can bring to light the hidden phases of accumulation, trend progression, and reversals.

SMC + EODHD Backtesting in a Nutshell (Modified Canva Template).

  • In this post, we’ll walk through backtesting (lookahead bias avoided) SMC Swing Highs & Lows as compared to the bullish/bearish Fair Value Gap (FVG) trading signals [1].

  • Core Library: smartmoneyconcepts 0.0.26 inspired by Inner Circle Trader (ICT) concepts like Order blocks, Liquidity, Fair Value Gap, Swing Highs and Lows, Break of Structure, Change of Character, and more.

!pip install smartmoneyconcepts
  • Challenge [3]: Implement and (back)test robust algorithmic trading strategies that can help traders identify and manage false signals effectively, including fake reversals, breakouts, etc.

  • Objective: Backtest the following two SMC methods of the class smc with input_=”ohlc”:

  1. swing_highs_lows (cls, ohlc: DataFrame, swing_length: int = 50)

Swing Highs and Lows
A swing high is when the current high is the highest high out of the swing_length amount of candles before and after.
A swing low is when the current low is the lowest low out of the swing_length amount of candles before and after.

Find your customers on Roku this Black Friday

As with any digital ad campaign, the important thing is to reach streaming audiences who will convert. To that end, Roku’s self-service Ads Manager stands ready with powerful segmentation and targeting options. After all, you know your customers, and we know our streaming audience.

Worried it’s too late to spin up new Black Friday creative? With Roku Ads Manager, you can easily import and augment existing creative assets from your social channels. We also have AI-assisted upscaling, so every ad is primed for CTV.

Once you’ve done this, then you can easily set up A/B tests to flight different creative variants and Black Friday offers. If you’re a Shopify brand, you can even run shoppable ads directly on-screen so viewers can purchase with just a click of their Roku remote.

Bonus: we’re gifting you $5K in ad credits when you spend your first $5K on Roku Ads Manager. Just sign up and use code GET5K. Terms apply.

Parameters:
swing_length: int — the amount of candles to look back and forward to determine the swing high or low.

Returns:
HighLow = 1 if swing high, -1 if swing low
Level = the level of the swing high or low

2. fvg (cls, ohlc: DataFrame, join_consecutive=False)

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
Top = the top of the fair value gap
Bottom = the bottom of the fair value gap
MitigatedIndex = the index of the candle that mitigated the fair value gap.

  • The remainder of this paper is organized into three main steps:

  1. Loading Stock Historical Data from EODHD API

Use real-time and historical stock data from reliable sources like EODHD API for producing realistic and trustworthy performance results with improved timing on breakout entries [3]. Recall that poor/incomplete data and subsequent data cleaning can unintentionally bias results [4].

2. Fair Value Gap (FVG) Trading Strategy

Identify price inefficiencies where the squares of the candlestick chart do not entirely overlap, thus producing zones with a high probability for trading.

3. Swing Highs & Lows Trading Strategy

Our main framework is to unveil swing highs and lows:

  • A swing high happens when a candle has two lower highs on either side.

  • A swing low is the opposite — one low candle with two higher lows on each side.

  • Once we’ve marked these two swings, we can figure out whether we’re in an uptrend (higher highs, higher lows) or a downtrend (lower highs, lower lows). That tells us whether to look for long (buy) or short (sell) setups.

  • This is to be benchmarked against the FVG.

Let’s break down the specifics of these steps.

Loading Stock Historical Data from EODHD API

  • Fetching the AAPL.US 2025 stock data from 2025–01–02 to 2025–10–08 using the EODHD API with your unique API code

!pip install eodhd
from eodhd import APIClient
import pandas as pd

api = APIClient("YOUR API CODE")

resp = api.get_eod_historical_stock_market_data(symbol = 'AAPL.US', period='d', from_date = '2025-01-01', to_date = '2025-10-09', order='a')

df = pd.DataFrame(resp)
df.tail()

     date      open          high         low         close       adjusted_close volume
187 2025-10-02 256.58000000 258.18000000 254.15000000 257.13000000 257.13000000 42630200
188 2025-10-03 254.67000000 259.24000000 253.95000000 258.02000000 258.02000000 49155600
189 2025-10-06 257.99000000 259.07000000 255.05000000 256.69000000 256.69000000 44664100
190 2025-10-07 256.81000000 257.40000000 255.43000000 256.48000000 256.48000000 31955800
191 2025-10-08 256.52000000 258.52000000 256.11000000 258.06000000 258.06000000 36465000
  • Examining the overall structure of this dataset

df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 192 entries, 0 to 191
Data columns (total 7 columns):
 #   Column          Non-Null Count  Dtype  
---  ------          --------------  -----  
 0   date            192 non-null    object 
 1   open            192 non-null    float64
 2   high            192 non-null    float64
 3   low             192 non-null    float64
 4   close           192 non-null    float64
 5   adjusted_close  192 non-null    float64
 6   volume          192 non-null    int64  
dtypes: float64(5), int64(1), object(1)
memory usage: 10.6+ KB
  • Visualizing OHLC & Volume with Plotly

import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots

# Create subplots and mention plot grid size
fig = make_subplots(rows=2, cols=1, shared_xaxes=True, 
               vertical_spacing=0.03, subplot_titles=('OHLC AAPL.US', 'Volume'), 
               row_width=[0.2, 0.7])

# Plot OHLC on 1st row
fig.add_trace(go.Candlestick(x=df["date"], open=df["open"], high=df["high"],
                low=df["low"], close=df["close"], name="OHLC"), 
                row=1, col=1
)

# Bar trace for volumes on 2nd row without legend
fig.add_trace(go.Bar(x=df['date'], y=df['volume'], showlegend=False), row=2, col=1)

# Do not show OHLC's rangeslider plot 
fig.update(layout_xaxis_rangeslider_visible=False)
fig.show()

OHLC & Volume AAPL.US 2025

200+ AI Side Hustles to Start Right Now

From prompt engineering to AI apps, there are countless ways to profit from AI now. Our guide reveals 200+ actionable AI business models, from no-code solutions to advanced applications. Learn how people are earning $500-$10,000 monthly with tools that didn't exist last year. Sign up for The Hustle to get the guide and daily insights.

  • Using the column “date” to set the time series index

df_ind = df.set_index(['date'])
ohlc=df_ind.copy()

Fair Value Gap (FVG) Trading Strategy

  • Applying the smc.fvg method [1] to our data

myfvg=smc.fvg(ohlc, join_consecutive=False)

myfvg.columns

Index(['FVG', 'Top', 'Bottom', 'MitigatedIndex'], dtype='object')
  • Creating a DF with the FVG column

df = pd.DataFrame(index=(ohlc.index))
mylist=myfvg["FVG"]
se = pd.Series(mylist)
df['FVG']=se.values
  • Computing the bullish and bearish FVG entry signals

bullsignals = ohlc['close'][df["FVG"] == 1]
bearsignals = ohlc['close'][df["FVG"] == -1]
  • Visualizing these trading signals [2]

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

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



plt.title('AAPL.US FVG Bullish (Green) / Bearish (Red) Signals')
plt.ylabel('Price USD')
listOf_Xticks = np.arange(0, 192, 35)
plt.xticks(listOf_Xticks)   
plt.show()

AAPL.US FVG Bullish (Green) / Bearish (Red) Signals

  • Backtesting the FVG strategy by creating position

position = []

df["FVG"]=df["FVG"].shift(1)
for i in range(len(ohlc['close'])):
        position.append(0)
        
for i in range(len(ohlc['close'])):
    if df["FVG"][i] == 1:
        position[i] = 1
    elif df["FVG"][i] == -1:
        position[i] = 0
    else:
        position[i] = position[i-1]
  • Calculating and plotting daily/cumulative returns of the FVG strategy

rets = ohlc.close.pct_change()[1:]
strat_rets = position[1:] * rets

plt.title('Daily Returns')
rets.plot(color = 'blue', alpha = 0.3, linewidth = 7,label='Buy&Hold')
strat_rets.plot(color = 'r', linewidth = 1,label='FVG')
plt.legend()
plt.show()
rets_cum = (1 + rets).cumprod() - 1 
strat_cum = (1 + strat_rets).cumprod() - 1
plt.title('Cumulative Returns')
rets_cum.plot(color = 'blue', alpha = 0.3, linewidth = 7,label='Buy&Hold')
strat_cum.plot(color = 'r', linewidth = 2,label='FVG')
plt.legend()
plt.show()

FVG Strategy Daily Returns

FVG Strategy Cumulative Returns

Swing Highs & Lows Trading Strategy

  • Applying the smc.swing_highs_lows method [1] with weekly swings to our data

myswing=smc.swing_highs_lows(ohlc, swing_length = 5)

myswing.columns

Index(['HighLow', 'Level'], dtype='object')
  • Creating a DF with the HighLow column

dfs = pd.DataFrame(index=(ohlc.index))
mylist=myswing["HighLow"]
se = pd.Series(mylist)
dfs['HighLow']=se.values
  • Detecting Swing-5 Highs and Lows

highsignals = ohlc['close'][dfs["HighLow"] == 1]
lowsignals = ohlc['close'][dfs["HighLow"] == -1]
  • Visualizing these Highs and Lows [2]

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

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

plt.xticks([])



plt.title('AAPL.US FVG Swing-5 Highs (Green) & Lows (Red) Signals')
plt.ylabel('Price USD')
listOf_Xticks = np.arange(0, 192, 35)
plt.xticks(listOf_Xticks)  



plt.show()

AAPL.US FVG Swing-5 Highs (Green) & Lows (Red) Signals

  • Compared to the FVG, the present strategy provides more distinct and interpretable trading signals, facilitating more reliable decision-making. These signals are better aligned with true market movements than those of the FVG.

  • Backtesting the Swing-5 Highs and Lows by creating position

dfs["HighLow"]=dfs["HighLow"].shift(1)

position = []

for i in range(len(ohlc['close'])):
        position.append(0)

        
for i in range(len(ohlc['close'])):
    if dfs["HighLow"][i] == -1:
        position[i] = 1
    elif dfs["HighLow"][i] == 1:
        position[i] = 0
    else:
        position[i] = position[i-1]
  • Calculating and plotting daily/cumulative returns of Swing-5 Highs and Lows

rets = ohlc.close.pct_change()[1:]
strat_rets = position[1:] * rets

plt.title('Daily Returns')
rets.plot(color = 'blue', alpha = 0.3, linewidth = 7,label='Buy&Hold')
strat_rets.plot(color = 'r', linewidth = 1,label='Swing Highs & Lows')
plt.legend()
plt.show()

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

plt.title('Cumulative Returns')
rets_cum.plot(color = 'blue', alpha = 0.3, linewidth = 7,label='Buy&Hold')
strat_cum.plot(color = 'r', linewidth = 2,label='Swing Highs & Lows')
plt.legend()
plt.show()

Swing-5 Highs and Lows Daily Returns

Swing-5 Highs and Lows Cumulative Returns

  • Observe that the above strategy delivers cumulative returns roughly 9× higher than the FVG and 35× higher than Buy & Hold during the testing period.

Conclusions

  • This paper demonstrates the effectiveness of the SMC Swing Highs & Lows strategy compared with FVG and Buy & Hold benchmarks.

  • Expected returns were calculated using a look-ahead bias-free backtesting analysis of AAPL.US stock data from 2025–01–02 to 2025–10–08.

  • If you’re a swing trader aiming to avoid liquidity sweeps and market manipulation traps, it’s essential to understand this approach.

Keep Reading

No posts found