diff --git a/project-templates/python/custom-indicator/main.py b/project-templates/python/custom-indicator/main.py
index 140da03788..fac808ba2f 100644
--- a/project-templates/python/custom-indicator/main.py
+++ b/project-templates/python/custom-indicator/main.py
@@ -9,7 +9,7 @@ def initialize(self) -> None:
self.set_start_date(2024, 9, 1)
self.set_end_date(2024, 12, 31)
# Request daily SPY data to feed the indicators to generate trade signals and trade.
- self._spy = self.add_equity("SPY", data_normalization_mode=DataNormalizationMode.RAW)
+ self._spy = self.add_equity("SPY")
# Create a custom money flow index to generate a trade signal.
self._custom_mfi = CustomMoneyFlowIndex(20)
# Warm up for immediate usage of indicators.
diff --git a/project-templates/python/custom-indicator/research.ipynb b/project-templates/python/custom-indicator/research.ipynb
new file mode 100644
index 0000000000..df5a7f959e
--- /dev/null
+++ b/project-templates/python/custom-indicator/research.ipynb
@@ -0,0 +1,199 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "ci-logo",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
\n",
+ "\n",
+ "## Custom Indicator Research\n",
+ "\n",
+ "This notebook implements a custom Money Flow Index and builds value and signal series from daily SPY history."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ci-setup-md",
+ "metadata": {},
+ "source": [
+ "### Set Up QuantBook\n",
+ "\n",
+ "Create a daily SPY subscription for the custom indicator updates."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "ci-setup",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "qb = QuantBook()\n",
+ "qb.set_start_date(2024, 12, 31)\n",
+ "qb.settings.seed_initial_prices = True\n",
+ "equity = qb.add_equity(\"SPY\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ci-class-md",
+ "metadata": {},
+ "source": [
+ "### Define Indicator\n",
+ "\n",
+ "Implement a [custom Money Flow Index Indicator](https://www.quantconnect.com/docs/v2/writing-algorithms/indicators/custom-indicators)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "ci-class",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class CustomMoneyFlowIndex(PythonIndicator):\n",
+ "\n",
+ " def __init__(self, period: int) -> None:\n",
+ " super().__init__()\n",
+ " self.value = 0\n",
+ " self._previous_typical_price = 0\n",
+ " self._negative_money_flow: RollingWindow[float] = RollingWindow(period)\n",
+ " self._positive_money_flow: RollingWindow[float] = RollingWindow(period)\n",
+ "\n",
+ " def update(self, input: TradeBar) -> bool:\n",
+ " # Estimate the money flow by averaging the price multiplied by volume.\n",
+ " typical_price = (input.high + input.low + input.close) / 3\n",
+ " money_flow = typical_price * input.volume\n",
+ " # Classify the flow as positive or negative relative to the previous bar.\n",
+ " self._negative_money_flow.add(money_flow if typical_price < self._previous_typical_price else 0)\n",
+ " self._positive_money_flow.add(money_flow if typical_price > self._previous_typical_price else 0)\n",
+ " self._previous_typical_price = typical_price\n",
+ " positive_money_flow_sum = sum(self._positive_money_flow)\n",
+ " total_money_flow = positive_money_flow_sum + sum(self._negative_money_flow)\n",
+ " # Set the value to the positive money flow ratio.\n",
+ " self.value = 100\n",
+ " if total_money_flow != 0:\n",
+ " self.value *= positive_money_flow_sum / total_money_flow\n",
+ " return self._positive_money_flow.is_ready"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ci-build-md",
+ "metadata": {},
+ "source": [
+ "### Build Time Series\n",
+ "\n",
+ "Feed daily TradeBar history through the indicator and store its value for each bar."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "ci-build",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "2024-01-31 16:00:00 67.098719\n",
+ "2024-02-01 16:00:00 66.933356\n",
+ "2024-02-02 16:00:00 72.315045\n",
+ "2024-02-05 16:00:00 72.500965\n",
+ "2024-02-06 16:00:00 72.214645\n",
+ " ... \n",
+ "2024-12-23 16:00:00 56.324222\n",
+ "2024-12-24 13:00:00 55.565956\n",
+ "2024-12-26 16:00:00 55.006566\n",
+ "2024-12-27 16:00:00 53.274876\n",
+ "2024-12-30 16:00:00 48.933252\n",
+ "Name: mfi, Length: 231, dtype: float64"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "mfi = CustomMoneyFlowIndex(20)\n",
+ "mfi_by_date = {\n",
+ " bar.end_time: mfi.value\n",
+ " for bar in qb.history[TradeBar](equity, 250, Resolution.DAILY)\n",
+ " if mfi.update(bar)\n",
+ "}\n",
+ "\n",
+ "indicator_values = pd.Series(mfi_by_date, name=\"mfi\")\n",
+ "indicator_values"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ci-signal-md",
+ "metadata": {},
+ "source": [
+ "### Signal Series\n",
+ "\n",
+ "Derive long and short signals based on the money flow indicator."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "ci-signal",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "2024-01-31 16:00:00 1\n",
+ "2024-02-01 16:00:00 1\n",
+ "2024-02-02 16:00:00 1\n",
+ "2024-02-05 16:00:00 1\n",
+ "2024-02-06 16:00:00 1\n",
+ " ..\n",
+ "2024-12-23 16:00:00 1\n",
+ "2024-12-24 13:00:00 1\n",
+ "2024-12-26 16:00:00 1\n",
+ "2024-12-27 16:00:00 1\n",
+ "2024-12-30 16:00:00 -1\n",
+ "Name: signal, Length: 231, dtype: int64"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Go long when demand outweighs supply, otherwise go short.\n",
+ "signal = pd.Series(-1, index=indicator_values.index, name=\"signal\")\n",
+ "signal[indicator_values > 50] = 1\n",
+ "signal"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Foundation-Py-Default",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.14"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}