Automating 8 Retail Trading Mistakes
Overview
This system is designed to solve the biggest retail trading execution mistakes
automatically using Python + Zerodha Kite Connect.
The focus is NOT strategy generation. The focus is:
•Risk control
•Emotional protection
•Trade discipline
•Automated enforcement
•Rule-based exits
FEATURES INCLUDED
1. Risking Too Much on One Trade
● Maximum 10% capital allocation per trade
● Rejects oversized positions automatically
2.No SL for a Trade
● Every open position MUST have an SL
● System auto-checks after 1 minute
● Auto-creates SL if missing
3.Revenge Trading After Losses
● Daily max loss limit
● Trading blocked after hitting limit
● Any new order auto-cancelled
● Cooldown lock
● OTP unlock after market hours
4.Booking Profits Too Early
● Dynamic trailing stop logic
● Adjustable parameters
● Locks profits automatically
5.Overtrading
● Maximum trades per day
● Additional trades blocked automatically
6.Holding Losers Emotionally
● Hard 10% SL enforcement
● Auto square-off if SL breached
7.Buying Options That Never Moved Enough
● Compares expected move vs required move
● Exits low probability trades.
8. Loosing money in Overnight Trades
● Converts all Trades to MIS from NRML
● Closes all trades at 3:15 pm
Professional Python-based risk management and emotional discipline
automation framework for Zerodha Kite traders.
INSTALLATION
pip install kiteconnect pandas schedule python-dotenv
PROJECT STRUCTURE
.ENV FILE
CONFIG FILE
MAX_CAPITAL_PER_TRADE_PERCENT = 10
HARD_STOP_LOSS_PERCENT = 10
MAX_DAILY_LOSS = -5000
MAX_TRADES_PER_DAY = 5
TRAIL_START_PERCENT = 2
TRAIL_SL_MOVE_PERCENT = 0.5
KITE INITIALIZE
LOGGER
from datetime import datetime
def log(message):
timestamp = [Link]().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] {message}")
1. Risking Too Much on One Trade
Automatically blocks oversized trades beyond defined capital allocation.
Maximum 10% capital allocation per trade & Rejects oversized positions automatically
def validate_position_size(balance, quantity,
price): MAX_RISK_PERCENT = 10
max_allowed = balance * (
MAX_RISK_PERCENT / 100
)
trade_value = quantity * price
if trade_value > max_allowed:
print("ORDER REJECTED")
return False
print("POSITION SIZE APPROVED")
return True
2. No SL for a Trade
Ensures every open position has a stop loss order.
Every open position MUST have an SL,System auto-checks after 1 minute, Auto-creates
SL if missing
def ensure_sl_exists(kite):
positions = [Link]()["net"]
orders = [Link]()
for position in positions:
if position["quantity"] == 0:
continue
symbol = position["tradingsymbol"]
sl_exists = any(
order["tradingsymbol"] == symbol and
order["order_type"] in ["SL", "SL-M"] and
order["status"] in [
"OPEN",
"TRIGGER PENDING"
]
for order in orders
)
if not sl_exists:
trigger_price = round(
position["average_price"] * 0.90, 1
)
kite.place_order(
variety="regular",
exchange=position["exchange"],
tradingsymbol=symbol,
transaction_type="SELL",
quantity=position["quantity"],
order_type="SL-M",
trigger_price=trigger_price,
product=position["product"] )
print(f"SL CREATED FOR {symbol}")
3. Revenge Trading After Losses
Locks trading after daily loss threshold and auto closes positions.
Daily max loss limit, Trading blocked after hitting limit, Any new order auto-cancelled,
Cooldown lock, OTP unlock after market hours
MAX_DAILY_LOSS = -5000
def revenge_guard(kite):
positions = [Link]()["day"]
total_pnl = sum(
position["pnl"]
for position in positions
)
if total_pnl <= MAX_DAILY_LOSS:
print("TRADING BLOCKED")
live_positions = [Link]()["net"] for
position in live_positions:
if position["quantity"] == 0:
continue
kite.place_order(
variety="regular",
exchange=position["exchange"],
tradingsymbol=position["tradingsymbol"],
transaction_type="SELL",
quantity=abs(position["quantity"]),
order_type="MARKET",
product=position["product"]
)
print("ALL POSITIONS CLOSED")
4. Booking Profits Too Early
Applies trailing stop logic automatically to lock profits.
Dynamic trailing stop logic , Adjustable parameters , Locks profits automatically
TRAIL_START = 2
TRAIL_SL_MOVE = 0.5
def trail_profit(entry_price, current_price):
profit_percent = (
(current_price - entry_price)
/ entry_price
) * 100
if profit_percent >= TRAIL_START:
new_sl = round(
current_price * (
1 - TRAIL_SL_MOVE / 100 ),
1
)
print(
f"TRAILING SL UPDATED: {new_sl}" )
5. Overtrading
Limits total number of trades per day.
Maximum trades per day, Additional trades blocked automatically
MAX_TRADES_PER_DAY = 5
def check_trade_limit(kite):
orders = [Link]()
completed_orders = [
order for order in orders
if order["status"] == "COMPLETE" ]
total_trades = len(completed_orders) if
total_trades >= MAX_TRADES_PER_DAY:
print("TRADE LIMIT REACHED") return False
return True
6. Holding Losers Emotionally
Forces hard exits and recreates missing stop
losses.
Hard 10% SL enforcement, Auto square-off if SL breached
HARD_SL_PERCENT = 10
def emotional_loss_protection(kite):
positions = [Link]()["net"]
for position in positions:
if position["quantity"] == 0:
continue
entry_price = (
position["average_price"]
)
hard_sl = (
entry_price * (
1 - HARD_SL_PERCENT / 100 )
)
symbol = position["tradingsymbol"]
ltp = [Link](
f"NSE:{symbol}"
)[f"NSE:{symbol}"]["last_price"] if
ltp <= hard_sl:
kite.place_order(
variety="regular",
exchange=position["exchange"],
tradingsymbol=symbol,
transaction_type="SELL",
quantity=position["quantity"],
order_type="MARKET",
product=position["product"] )
print(
f"HARD SL EXIT EXECUTED: {symbol}" )
7. Buying Options That Never Moved Enough
Compares expected move vs required move and exits low probability
trades.
from math import sqrt
def expected_move_validation(
spot_price,
implied_volatility,
days_to_expiry,
option_entry_price,
option_target_price,
option_delta
):
expected_move = (
spot_price *
implied_volatility *
sqrt(days_to_expiry / 365)
)
required_move = (
option_target_price -
option_entry_price
) / option_delta
print(
f"EXPECTED MOVE: {expected_move}"
)
print(
f"REQUIRED MOVE: {required_move}"
)
if expected_move >= required_move:
print("TRADE VALID")
else:
print("LOW PROBABILITY TRADE")
print("POSITION SHOULD BE CLOSED")
8. Loosing money in Overnight Trades
● Converts all Trades to MIS from NRML
● Closes all trades at 3:15 pm
# Zerodha Kite Connect - Convert NRML position to MIS
# Install:
# pip install kiteconnect
from kiteconnect import KiteConnect
# -----------------------------
# Your Zerodha API Credentials
# -----------------------------
api_key = "YOUR_API_KEY"
access_token = "YOUR_ACCESS_TOKEN"
kite = KiteConnect(api_key=api_key)
kite.set_access_token(access_token)
# -----------------------------
# Position Details
# -----------------------------
exchange = "NFO" # NSE / NFO / CDS / MCX
tradingsymbol = "BANKNIFTY25MAY56000CE"
transaction_type = "SELL" # SELL to square-off long NRML
quantity = 15
try:
# Convert NRML -> MIS
order_id = kite.place_order(
variety=kite.VARIETY_REGULAR,
exchange=exchange,
tradingsymbol=tradingsymbol,
transaction_type=transaction_type,
quantity=quantity,
product=kite.PRODUCT_MIS,
order_type=kite.ORDER_TYPE_MARKET,
validity=kite.VALIDITY_DAY
)
print(f"Order placed successfully: {order_id}")
except Exception as e:
print("Error:", e)