Automation¶
🌀 async set_trailing_stop(ticket, *, distance_pips, step_pips=None)¶
What it does: Enables a trailing stop for the given position. The SL trails price by distance_pips and (optionally) updates in discrete step_pips increments.
Used in:
- Letting winners run while automatically protecting gains.
- Hands‑off trend following and breakout strategies.
- Scalping strategies to lock in quick profits.
- Swing trading to maximize trend movements.
Parameters:
ticket- Order ticket number to traildistance_pips- Distance in pips between price and trailing stopstep_pips- (Optional) Minimum price movement in pips before updating SL. If not specified, updates on every price tick.
How it works:
- Monitors the position in real-time
- As price moves favorably, moves SL to maintain
distance_pipsdistance - If
step_pipsis specified, only updates SL when price moves by that amount - Returns a subscription ID that can be used to disable trailing later
- Stops automatically when position is closed
Related to: order_modify.md, opened_orders_tickets.md
Example 1: Basic trailing stop
# Open a buy position
ticket = await sugar.buy_market("EURUSD", lots=0.1, sl_pips=20)
# Trail 20 pips behind price; update every 2 pips
trail_id = await sugar.set_trailing_stop(
ticket=ticket,
distance_pips=20,
step_pips=2
)
Example 2: Aggressive trailing for scalping
# Scalp trade with tight trailing
ticket = await sugar.buy_market("EURUSD", lots=0.2, sl_pips=10, tp_pips=15)
# Trail very closely behind price (5 pips), update every pip
trail_id = await sugar.set_trailing_stop(
ticket=ticket,
distance_pips=5,
step_pips=1 # Update frequently
)
Example 3: Wide trailing for swing trading
# Swing trade - let it breathe
ticket = await sugar.buy_market("GBPUSD", lots=0.1, sl_pips=50)
# Trail 30 pips behind, update every 5 pips (reduce API calls)
trail_id = await sugar.set_trailing_stop(
ticket=ticket,
distance_pips=30,
step_pips=5 # Less frequent updates
)
Example 4: Conditional trailing activation
# Open position
ticket = await sugar.buy_market("EURUSD", lots=0.1, sl_pips=20, tp_pips=60)
# Wait for 20 pips profit before activating trailing
await sugar.auto_breakeven(ticket=ticket, trigger_pips=20)
# Now enable trailing stop
trail_id = await sugar.set_trailing_stop(
ticket=ticket,
distance_pips=15,
step_pips=2
)
Example 5: Multiple positions with different trailing strategies
# Conservative position - wide trail
ticket1 = await sugar.buy_market("EURUSD", lots=0.1)
trail_id1 = await sugar.set_trailing_stop(
ticket=ticket1,
distance_pips=30,
step_pips=5
)
# Aggressive position - tight trail
ticket2 = await sugar.buy_market("EURUSD", lots=0.1)
trail_id2 = await sugar.set_trailing_stop(
ticket=ticket2,
distance_pips=10,
step_pips=1
)
# Store trail IDs for later management
trailing_positions = {
ticket1: trail_id1,
ticket2: trail_id2
}
🧹 async unset_trailing_stop(subscription_id)¶
What it does: Disables a previously set trailing stop by its subscription/handler id.
Used in:
- Pausing automation around news events or switching strategy regime.
- Disabling trailing when profit target is reached.
- Manual intervention to take control of position management.
- Switching from automated to manual trailing strategy.
Parameters:
subscription_id- The ID returned byset_trailing_stop()
Important notes:
- Trailing stops automatically when position is closed
- Current SL level remains in place after unsubscribing
- Can be called multiple times safely (idempotent)
- Does not close or modify the position itself
Related to: order_modify.md
Example 1: Basic unsubscribe
# Enable trailing
trail_id = await sugar.set_trailing_stop(ticket=123456, distance_pips=20, step_pips=2)
# Later: disable trailing
await sugar.unset_trailing_stop(subscription_id=trail_id)
Example 2: Pause trailing during news events
import datetime
# Enable trailing
ticket = await sugar.buy_market("EURUSD", lots=0.1)
trail_id = await sugar.set_trailing_stop(ticket=ticket, distance_pips=20)
# Check for upcoming news
if is_news_time():
logger.info("News event upcoming - pausing trailing stop")
await sugar.unset_trailing_stop(trail_id)
# Wait for news to pass
await asyncio.sleep(300) # 5 minutes
# Resume trailing
trail_id = await sugar.set_trailing_stop(ticket=ticket, distance_pips=20)
Example 3: Disable trailing when profit target reached
# Open position with trailing
ticket = await sugar.buy_market("EURUSD", lots=0.1, sl_pips=20)
trail_id = await sugar.set_trailing_stop(ticket=ticket, distance_pips=15, step_pips=2)
# Monitor profit
while True:
orders = await sugar._svc.opened_orders()
position = next((o for o in orders if o.ticket == ticket), None)
if position and position.profit >= 100.0: # $100 profit
logger.info("Profit target reached - locking in gains")
# Disable trailing
await sugar.unset_trailing_stop(trail_id)
# Set tight manual SL
current_price = await sugar.last_quote("EURUSD")
tight_sl = current_price["bid"] - await sugar.pips_to_price("EURUSD", 5)
await sugar.modify_sl_tp_by_price(ticket=ticket, sl_price=tight_sl)
break
await asyncio.sleep(5)
Example 4: Manage multiple trailing stops
# Track all active trailing stops
active_trails = {}
# Enable trailing for multiple positions
for ticket in [111111, 222222, 333333]:
trail_id = await sugar.set_trailing_stop(
ticket=ticket,
distance_pips=20,
step_pips=2
)
active_trails[ticket] = trail_id
# Later: disable all trailing stops
for ticket, trail_id in active_trails.items():
logger.info(f"Disabling trailing for ticket {ticket}")
await sugar.unset_trailing_stop(trail_id)
active_trails.clear()
Example 5: Conditional trailing management
# Enable trailing
ticket = await sugar.buy_market("EURUSD", lots=0.1)
trail_id = await sugar.set_trailing_stop(ticket=ticket, distance_pips=20)
# Monitor market volatility
while True:
spread = await sugar.spread_pips("EURUSD")
if spread > 5.0:
# High spread - pause trailing
logger.warning("High spread detected - pausing trailing")
await sugar.unset_trailing_stop(trail_id)
trail_id = None
elif spread < 2.0 and trail_id is None:
# Normal spread - resume trailing
logger.info("Spread normalized - resuming trailing")
trail_id = await sugar.set_trailing_stop(ticket=ticket, distance_pips=20)
await asyncio.sleep(10)