Ever noticed how some stocks just keep going up after breaking a level? Or suddenly crash after crossing a support?
That’s momentum – when prices move in a certain direction with force. Algo traders love to ride this wave.
In simple words:
“Buy high, sell higher.” “Sell low, cover lower.”
Momentum strategies don’t wait for dips — they jump in when prices show strong strength (up or down), assuming the trend will continue.
Here are common signals used:
When a short-term MA (say 10-day) crosses above a long-term MA (say 50-day), it indicates upward momentum.
Your algo can buy here and exit when the crossover reverses.
import pandas as pd import talib
close_prices = df['Close'] # <-- Add this line before SMA short_ma = talib.SMA(close_prices, timeperiod=10) long_ma = talib.SMA(close_prices, timeperiod=50)
#Buy signal when short MA > long MA if short_ma[-1] > long_ma[-1] and short_ma[-2] <= long_ma[-2]: print("Buy Signal: Moving Average Crossover")
Note:
This code uses the TA-Lib library to detect a moving average crossover — a common trading signal.
short_ma & long_ma: Calculated using TA-Lib’s SMA() function. Here, the short-term moving average uses a 10-period window, and the long-term moving average uses a 50-period window. Both are based on close_prices, which is assumed to be a Pandas Series of closing prices.
Signal logic:
o short_ma[-1] > long_ma[-1] → In the most recent candle, the short-term MA is above the long-term MA (bullish).
o short_ma[-2] <= long_ma[-2] → In the previous candle, the short-term MA was at or below the long-term MA.
o Together, these conditions detect the exact moment when the short MA crosses above the long MA — a “golden cross” indicating a potential buy.
o print(): Outputs the signal text to confirm the crossover event.
This structure ensures you only trigger a buy signal on the crossover itself, not on every bar where the short MA remains above the long MA.
Price breaks a previous high after consolidation = breakout.
Your algo enters long as soon as breakout candle closes above resistance.
resistance = max(close_prices[-20:-1]) #Highest price in last 20 candles
if close_prices[-1] > resistance:
print("Buy Signal: Breakout from Resistance")
Note: Finds the highest close in the last 20 candles. If today’s close is higher, it’s a breakout buy signal.
import talib
rsi = talib.RSI(df['Close'], timeperiod=14)
if rsi[-1] > 60 and rsi[-2] <= 60:
print("Buy Signal: RSI Crossing 60")
elif rsi[-1] > 70 and rsi[-2] <= 70:
print("Strong Buy Signal: RSI Crossing 70")
Note:
Let’s say you define:
You run this strategy on NIFTY stocks every day. Your algo scans all 50 stocks at 9:30 AM, checks signals, and enters trades.
This way, your code is always hunting for momentum breakouts, automatically.
import yfinance as yf
#Define universe stocks = ["RELIANCE.NS", "TCS.NS", "INFY.NS", "HDFCBANK.NS", "ICICIBANK.NS"]
#Store signals as (symbol, side) signals = []
for s in stocks: #Download last 1 month daily data df = yf.download(s, period="1mo", interval="1d")
#Skip if data is missing or too short
if df is None or df.empty or len(df) < 21:
continue
last_close = df['Close'].iloc[-1]
#Highest High of last 20 days (excluding current bar)
prev_20_high = df['High'].iloc[-21:-1].max()
#Lowest Low of last 10 days (excluding current bar)
prev_10_low = df['Low'].iloc[-11:-1].min()
#Momentum BUY condition
if last_close > prev_20_high:
signals.append((s, "BUY"))
#Momentum SELL condition
elif last_close < prev_10_low:
signals.append((s, "SELL"))
#Print signals print("Momentum Signals:") for sym, side in signals: print(f"{sym}: {side}")
#--- Order placement (placeholder) --- #Replace with your broker API call def place_market_order(api_client, symbol, qty, side): """ Example placeholder for broker order placement. Modify according to your broker API. """ print(f"Placing {side} order for {qty} shares of {symbol}")
#Example loop to place trades api_client = None #<-- initialize with your broker client for sym, side in signals: symbol_for_broker = sym.replace(".NS", "") # adjust if your broker needs NSE suffix dropped place_market_order(api_client, symbol_for_broker, qty=1, side=side)
Note:
stocks → List of stock tickers (symbols) the algo will scan. Example: Reliance, TCS.
df = yf.download(...) → Downloads price data from Yahoo Finance.
a. period="1mo" → Gets 1 month of past data.
b. interval="1d" → Each data point is 1 day (daily candles).
df['Close'].iloc[-1] → last_close → The most recent closing price (yesterday’s close if you run in morning).
df['High'].iloc[-21:-1].max() → prev_20_high
a. Looks back at the last 20 days (excluding the latest day).
b. Finds the highest price in that period.
c. Used to detect breakout above recent highs.
df['Low'].iloc[-11:-1].min() → prev_10_low
a. Looks back at the last 10 days (excluding the latest day).
b. Finds the lowest price in that period.
c. Used to detect breakdown below recent lows.
signals.append((s, "BUY")) → Stores a buy signal if last_close > prev_20_high.
signals.append((s, "SELL")) → Stores a sell signal if last_close < prev_10_low.
print("Momentum Signals:") → Prints which stocks got buy/sell signals.
place_market_order(api_client, symbol, qty, side) →
Placeholder function that would send the order to your broker API.
a. api_client → The broker connection (to be initialized with your broker).
b. symbol → Stock ticker, formatted for your broker.
c. qty → Number of shares to buy/sell (currently fixed at 1).
d. side → BUY or SELL, depending on the signal.
#Assume you have already authenticated with your broker's API
#and have an 'api_client' object ready for placing orders.
def place_market_order(api_client, symbol, qty, side="BUY", exchange="NSE", product="CNC"):
"""
Places a market order for the given symbol.
Parameters:
api_client : object - Your broker API client instance
symbol : str - Trading symbol (e.g., 'RELIANCE' or 'RELIANCE.NS')
qty : int - Quantity to buy/sell
side : str - "BUY" or "SELL"
exchange : str - Market exchange (default NSE)
product : str - Product type ("CNC" for delivery, "MIS" for intraday)
"""
try:
response = api_client.place_order(
tradingsymbol=symbol,
exchange=exchange,
transaction_type=side,
quantity=qty,
order_type="MARKET",
product=product #<- changed from product_type to product </br>
)
print(f"Order placed for {symbol}: {response}")
except Exception as e: </br>
print(f"Error placing order for {symbol}: {repr(e)}") </br>
#Example usage: Place buy orders for all breakout stocks
for stock in breakout_stocks:
#keep .NS if broker expects it, strip only if necessary
broker_symbol = stock.replace(".NS", "")
place_market_order(api_client, broker_symbol, qty=1, side="BUY")
Note:
This function is just a shortcut to send market orders using your broker’s Python client.
You pass the details:
o symbol → stock name (e.g., "RELIANCE")
o qty → how many shares
o side → "BUY" or "SELL"
o exchange → default "NSE"
o product → "CNC" for delivery, change to "MIS" for intraday
api_client.place_order(...) is only a placeholder — replace the field names to match your broker’s SDK.
try/except makes sure the code doesn’t crash if an order fails; it prints the error instead.
stock.replace(".NS","") removes the Yahoo suffix so "RELIANCE.NS" becomes "RELIANCE" (what brokers usually accept).
Orders here are market orders (instant at market price). If you want price control, use limit orders.
Safety tips before going live:
o Make sure qty > 0
o Run only during market hours
o Test on paper/sandbox mode first
In short: Momentum algos try to ride the wave, not fight it.
In the next chapter, we’ll look at the opposite of momentum — Mean Reversion Strategies.
Disclaimer: This article is for informational purposes only and does not constitute financial advice. It is not produced by the desk of the Kotak Securities Research Team, nor is it a report published by the Kotak Securities Research Team. The information presented is compiled from several secondary sources available on the internet and may change over time. Investors should conduct their own research and consult with financial professionals before making any investment decisions. Read the full disclaimer here.
Investments in securities market are subject to market risks, read all the related documents carefully before investing. Brokerage will not exceed SEBI prescribed limit. The securities are quoted as an example and not as a recommendation. SEBI Registration No-INZ000200137 Member Id NSE-08081; BSE-673; MSE-1024, MCX-56285, NCDEX-1262.
Disclaimer: This article is for informational purposes only and does not constitute financial advice. It is not produced by the desk of the Kotak Securities Research Team, nor is it a report published by the Kotak Securities Research Team. The information presented is compiled from several secondary sources available on the internet and may change over time. Investors should conduct their own research and consult with financial professionals before making any investment decisions. Read the full disclaimer here.
Investments in securities market are subject to market risks, read all the related documents carefully before investing. Brokerage will not exceed SEBI prescribed limit. The securities are quoted as an example and not as a recommendation. SEBI Registration No-INZ000200137 Member Id NSE-08081; BSE-673; MSE-1024, MCX-56285, NCDEX-1262.
Explore our comprehensive video library that blends expert market insights with Kotak's innovative financial solutions to support your goals.