Trailing stop-loss
A trailing stop moves in the profitable direction as price advances, locking in gains, but never moves backward. Chapter 54 introduced the core modify logic and its critical one-directional guard — this chapter builds the full loop that drives it off live prices.
class TrailingStop:
def __init__(self, kite, order_manager, sl_order_id, side, trail_distance, tick_size):
self.kite = kite
self.om = order_manager
self.sl_order_id = sl_order_id
self.side = side # "BUY" or "SELL" — the ORIGINAL position side
self.trail_distance = trail_distance
self.tick_size = tick_size
self.best_trigger = None
def update(self, current_price: float):
if self.side == "BUY":
new_trigger = round_to_tick(current_price - self.trail_distance, self.tick_size)
if self.best_trigger is None or new_trigger > self.best_trigger:
self._apply(new_trigger)
else: # short position, stop trails downward as price falls
new_trigger = round_to_tick(current_price + self.trail_distance, self.tick_size)
if self.best_trigger is None or new_trigger < self.best_trigger:
self._apply(new_trigger)
def _apply(self, new_trigger: float):
try:
self.kite.modify_order(variety="regular", order_id=self.sl_order_id, trigger_price=new_trigger)
self.best_trigger = new_trigger
logging.info(f"Trailed stop to {new_trigger}")
except OrderException as e:
logging.warning(f"Trail modify failed (order may have filled): {e}")
Drive it from your live price cache (chapter 42), not a tight polling loop against the REST API:
def run_trailing_stop(trailing_stop: TrailingStop, price_cache: PriceCache, token: int):
while True:
price = price_cache.get_price(token)
if price is not None:
trailing_stop.update(price)
time.sleep(1) # trail check frequency — no need to check every tick
ATR-based trailing distance — adapts to volatility like chapter 72's sizing
def atr_trailing_distance(atr: float, multiplier: float = 1.5) -> float:
return atr * multiplier
A fixed-point trail distance suffers the same problem chapter 72 raised for stops: too tight and normal noise stops you out on every pullback, too wide and you give back too much profit before it kicks in.
Modify frequency — don't hammer the API on every tiny tick
Trailing on every single tick both wastes API calls and can cause excessive stop movement chasing noise. Update on a fixed interval (e.g. every few seconds) or only when price has moved a meaningful increment since the last trail update — whichever fits your strategy's timeframe.