EMA Crossover Strategy with Stoploss and Target
Strategy Name
EMA_Crossover_RELIANCE
Strategy Type
Positional Strategy – This strategy does not impose any intraday entry/exit time limits. Positions may remain open across multiple trading sessions until stoploss or target conditions are met.
Instrument Configuration
Parameter | Value |
---|---|
Symbol | RELIANCE |
Exchange | NSE |
Quantity | 1 |
Order Type | MARKET |
Product Type | MIS |
Note: Even though MIS is used, positional behavior is controlled through logic, not by broker product type. This can be switched to CNC for true positional holding if desired.
Indicators Used
- EMA 5: Exponential Moving Average over the last 5 closing prices (short-term trend).
- EMA 10: Exponential Moving Average over the last 10 closing prices (medium-term trend).
Entry Conditions
- Fetch 1-minute historical candle data every 5 seconds.
- Calculate EMA-5 and EMA-10.
- Identify confirmed crossover using the last two closed candles (i.e., not the current forming candle).
- Buy Signal: Previous candle EMA-5 < EMA-10 and last closed candle EMA-5 > EMA-10.
- Sell Signal: Previous candle EMA-5 > EMA-10 and last closed candle EMA-5 < EMA-10.
- When a signal is confirmed:
- Place a MARKET order (
BUY
orSELL
). - Capture entry price and calculate:
- Stoploss = Entry Price − 10.0
- Target = Entry Price + 20.0
- Place a MARKET order (
Exit Conditions
- Use WebSocket streaming to receive live LTP updates.
- Continuously monitor whether LTP hits stoploss or target levels.
- When triggered, exit the position by placing a MARKET order in the opposite direction.
Strategy Architecture
- Two dedicated threads:
- WebSocket Thread: Listens to real-time LTP and checks SL/Target.
- Strategy Thread: Periodically fetches historical data, calculates EMA signals, and initiates trades.
- Uses
threading.Event()
to handle graceful shutdown viaCTRL+C
.
Shutdown Behavior
- On receiving a keyboard interrupt, both threads are safely stopped.
- WebSocket subscription is removed, and connection is closed.
- The strategy exits cleanly and logs the shutdown.
Complete Code
import threading
import time
import signal
import pandas as pd
import pandas_ta as ta
from datetime import datetime, timedelta
from openalgo import api
# Initialize OpenAlgo client
client = api(
api_key="openalgo-api-key",
host="http://127.0.0.1:5000",
ws_url="ws://127.0.0.1:8765"
)
# Configuration
STRATEGY_NAME = "EMA_Crossover_RELIANCE"
SYMBOL = "RELIANCE"
EXCHANGE = "NSE"
QUANTITY = 1
PRODUCT = "MIS"
PRICE_TYPE = "MARKET"
STOPLOSS_BUFFER = 10.0
TARGET_BUFFER = 20.0
instrument = [{"exchange": EXCHANGE, "symbol": SYMBOL}]
# State Variables
ltp = None
in_position = False
entry_price = None
stoploss_price = None
target_price = None
current_position = None
exit_signal = False
stop_event = threading.Event()
# WebSocket LTP Handler
def on_data_received(data):
global ltp, exit_signal
if data.get("type") == "market_data" and data.get("symbol") == SYMBOL:
ltp = float(data["data"]["ltp"])
print(f"LTP Update {EXCHANGE}:{SYMBOL} => ₹{ltp}")
if in_position and not exit_signal:
if ltp <= stoploss_price or ltp >= target_price:
print(f"Exit Triggered: LTP ₹{ltp} hit stoploss or target.")
exit_signal = True
# WebSocket Thread
def websocket_thread():
try:
client.connect()
client.subscribe_ltp(instrument, on_data_received=on_data_received)
print("WebSocket LTP thread started.")
while not stop_event.is_set():
time.sleep(1)
finally:
print("Shutting down WebSocket...")
client.unsubscribe_ltp(instrument)
client.disconnect()
print("WebSocket connection closed.")
# EMA Signal Logic
def get_latest_signals():
end_date = datetime.now()
start_date = end_date - timedelta(days=3)
df = client.history(
symbol=SYMBOL,
exchange=EXCHANGE,
interval="5m",
start_date=start_date.strftime("%Y-%m-%d"),
end_date=end_date.strftime("%Y-%m-%d")
)
df.ta.ema(length=5, append=True)
df.ta.ema(length=10, append=True)
if len(df) < 3:
print("Waiting for sufficient data...")
return None
prev = df.iloc[-3]
last = df.iloc[-2]
print(f"{datetime.now().strftime('%H:%M:%S')} | EMA5: {last['EMA_5']:.2f}, EMA10: {last['EMA_10']:.2f}")
if prev['EMA_5'] < prev['EMA_10'] and last['EMA_5'] > last['EMA_10']:
print("Confirmed BUY crossover.")
return "BUY"
elif prev['EMA_5'] > prev['EMA_10'] and last['EMA_5'] < last['EMA_10']:
print("Confirmed SELL crossover.")
return "SELL"
return None
# Place Order
def place_order(action):
global in_position, entry_price, stoploss_price, target_price, current_position
print(f"Placing {action} order for {SYMBOL}")
resp = client.placeorder(
strategy=STRATEGY_NAME,
symbol=SYMBOL,
exchange=EXCHANGE,
action=action,
price_type=PRICE_TYPE,
product=PRODUCT,
quantity=QUANTITY
)
print("Order Response:", resp)
if resp.get("status") == "success":
order_id = resp.get("orderid")
time.sleep(1)
status = client.orderstatus(order_id=order_id, strategy=STRATEGY_NAME)
data = status.get("data", {})
if data.get("order_status", "").lower() == "complete":
entry_price = float(data["price"])
stoploss_price = round(entry_price - STOPLOSS_BUFFER, 2)
target_price = round(entry_price + TARGET_BUFFER, 2)
current_position = action
in_position = True
print(f"Entry @ ₹{entry_price} | SL ₹{stoploss_price} | Target ₹{target_price}")
# Exit Order
def exit_trade():
global in_position, exit_signal
action = "SELL" if current_position == "BUY" else "BUY"
print(f"Exiting trade with {action}")
client.placeorder(
strategy=STRATEGY_NAME,
symbol=SYMBOL,
exchange=EXCHANGE,
action=action,
price_type=PRICE_TYPE,
product=PRODUCT,
quantity=QUANTITY
)
in_position = False
exit_signal = False
# Strategy Thread
def strategy_thread():
global exit_signal
while not stop_event.is_set():
if not in_position:
signal = get_latest_signals()
if signal:
place_order(signal)
elif exit_signal:
exit_trade()
time.sleep(5)
# Main Execution
def main():
print("EMA Crossover Strategy is running...")
ws_thread = threading.Thread(target=websocket_thread)
strat_thread = threading.Thread(target=strategy_thread)
ws_thread.start()
strat_thread.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("KeyboardInterrupt received. Shutting down...")
stop_event.set()
ws_thread.join()
strat_thread.join()
print("Strategy shutdown complete.")
if __name__ == "__main__":
main()