Skip to main content
Glama

calculate_trailing_stop

Automate trailing stop loss calculations for Bybit trades, enabling breakeven and profit protection based on market price, entry price, and specified triggers.

Instructions

Calculate trailing stop loss with breakeven and profit protection

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
breakevenTriggerNoPrice distance from entry to activate breakeven protection (optional)
categoryYesCategory (linear, inverse)
currentPriceYesCurrent market price
entryPriceYesEntry price of the position
initialStopLossYesInitial stop loss price
profitProtectionTriggerNoPrice distance from entry to activate profit protection (optional)
sideYesPosition side (Buy for long, Sell for short)
symbolYesSymbol (e.g., ETHUSDT)
trailingDistanceYesTrailing distance in price units

Implementation Reference

  • Core handler function implementing trailing stop calculation logic with breakeven and profit protection features, unrealized PnL computation, risk warnings, and tick-size compliant price rounding.
    async calculateTrailingStop( category: string, symbol: string, entryPrice: number, currentPrice: number, side: 'Buy' | 'Sell', initialStopLoss: number, trailingDistance: number, breakevenTrigger?: number, profitProtectionTrigger?: number ): Promise<{ newStopLoss: number; trailingActivated: boolean; breakevenProtection: boolean; profitProtected: number; unrealizedPnL: number; unrealizedPnLPercentage: number; recommendations: { shouldUpdateStop: boolean; newStopPrice: number; protectionLevel: 'none' | 'breakeven' | 'profit'; reasoning: string; }; calculations: { priceMovement: number; priceMovementPercentage: number; stopLossMovement: number; maxDrawdownProtection: number; profitLocked: number; }; warnings: string[]; error?: string; }> { try { const warnings: string[] = []; const isLong = side === 'Buy'; // Validate inputs if (trailingDistance <= 0) { return { newStopLoss: initialStopLoss, trailingActivated: false, breakevenProtection: false, profitProtected: 0, unrealizedPnL: 0, unrealizedPnLPercentage: 0, recommendations: { shouldUpdateStop: false, newStopPrice: initialStopLoss, protectionLevel: 'none', reasoning: 'Invalid trailing distance' }, calculations: { priceMovement: 0, priceMovementPercentage: 0, stopLossMovement: 0, maxDrawdownProtection: 0, profitLocked: 0 }, warnings: ['Trailing distance must be greater than 0'], error: 'Invalid trailing distance' }; } // Calculate price movements const priceMovement = isLong ? currentPrice - entryPrice : entryPrice - currentPrice; const priceMovementPercentage = (priceMovement / entryPrice) * 100; // Calculate unrealized PnL const unrealizedPnL = priceMovement; const unrealizedPnLPercentage = priceMovementPercentage; // Set default triggers if not provided const breakevenTriggerDistance = breakevenTrigger || (Math.abs(entryPrice - initialStopLoss) * 1.5); const profitProtectionTriggerDistance = profitProtectionTrigger || (Math.abs(entryPrice - initialStopLoss) * 2.0); let newStopLoss = initialStopLoss; let trailingActivated = false; let breakevenProtection = false; let profitProtected = 0; let protectionLevel: 'none' | 'breakeven' | 'profit' = 'none'; let reasoning = 'No trailing conditions met'; // Check if price has moved favorably enough to activate trailing const favorableMovement = isLong ? currentPrice > entryPrice : currentPrice < entryPrice; if (favorableMovement) { // Calculate potential new stop loss based on trailing distance const potentialNewStop = isLong ? currentPrice - trailingDistance : currentPrice + trailingDistance; // Only move stop loss if it's better than current stop const shouldMoveStop = isLong ? potentialNewStop > initialStopLoss : potentialNewStop < initialStopLoss; if (shouldMoveStop) { newStopLoss = potentialNewStop; trailingActivated = true; // Check for breakeven protection const breakevenReached = isLong ? currentPrice >= entryPrice + breakevenTriggerDistance : currentPrice <= entryPrice - breakevenTriggerDistance; if (breakevenReached) { const breakevenStop = entryPrice; // Move stop to breakeven if (isLong ? breakevenStop > newStopLoss : breakevenStop < newStopLoss) { newStopLoss = breakevenStop; breakevenProtection = true; protectionLevel = 'breakeven'; reasoning = 'Breakeven protection activated - stop moved to entry price'; } } // Check for profit protection const profitProtectionReached = isLong ? currentPrice >= entryPrice + profitProtectionTriggerDistance : currentPrice <= entryPrice - profitProtectionTriggerDistance; if (profitProtectionReached) { const profitProtectionStop = isLong ? entryPrice + (profitProtectionTriggerDistance * 0.5) // Lock in 50% of the trigger distance as profit : entryPrice - (profitProtectionTriggerDistance * 0.5); if (isLong ? profitProtectionStop > newStopLoss : profitProtectionStop < newStopLoss) { newStopLoss = profitProtectionStop; profitProtected = Math.abs(profitProtectionStop - entryPrice); protectionLevel = 'profit'; reasoning = `Profit protection activated - locking in ${profitProtected.toFixed(2)} profit`; } } if (protectionLevel === 'none') { reasoning = `Trailing stop activated - following price with ${trailingDistance} distance`; } } else { reasoning = 'Price moved favorably but not enough to improve stop loss'; } } else { reasoning = 'Price has not moved favorably - maintaining original stop loss'; } // Calculate additional metrics const stopLossMovement = Math.abs(newStopLoss - initialStopLoss); const maxDrawdownProtection = Math.abs(currentPrice - newStopLoss); const profitLocked = Math.max(0, isLong ? newStopLoss - entryPrice : entryPrice - newStopLoss); // Add warnings for risk management if (unrealizedPnLPercentage < -5) { warnings.push('Position is down more than 5% - consider reviewing strategy'); } if (trailingDistance > Math.abs(entryPrice - initialStopLoss) * 2) { warnings.push('Trailing distance is very large compared to initial risk - may give back too much profit'); } if (Math.abs(unrealizedPnLPercentage) > 20) { warnings.push('Large unrealized PnL - consider taking partial profits'); } // Get instrument info for price formatting const instrumentInfo = await this.getInstrumentsInfo(category, symbol); if ('result' in instrumentInfo) { const priceFilter = instrumentInfo.result.list[0].priceFilter; const tickSize = parseFloat(priceFilter.tickSize); const decimalPlaces = tickSize.toString().split('.')[1]?.length || 0; // Round new stop loss to valid tick size newStopLoss = Math.round(newStopLoss / tickSize) * tickSize; newStopLoss = parseFloat(newStopLoss.toFixed(decimalPlaces)); } return { newStopLoss, trailingActivated, breakevenProtection, profitProtected, unrealizedPnL, unrealizedPnLPercentage, recommendations: { shouldUpdateStop: newStopLoss !== initialStopLoss, newStopPrice: newStopLoss, protectionLevel, reasoning }, calculations: { priceMovement, priceMovementPercentage, stopLossMovement, maxDrawdownProtection, profitLocked }, warnings }; } catch (error: any) { return { newStopLoss: initialStopLoss, trailingActivated: false, breakevenProtection: false, profitProtected: 0, unrealizedPnL: 0, unrealizedPnLPercentage: 0, recommendations: { shouldUpdateStop: false, newStopPrice: initialStopLoss, protectionLevel: 'none', reasoning: 'Error calculating trailing stop' }, calculations: { priceMovement: 0, priceMovementPercentage: 0, stopLossMovement: 0, maxDrawdownProtection: 0, profitLocked: 0 }, warnings: [], error: error.message }; } }
  • src/index.ts:591-636 (registration)
    MCP tool registration defining the 'calculate_trailing_stop' tool name, description, and input schema for validation.
    { name: 'calculate_trailing_stop', description: 'Calculate trailing stop loss with breakeven and profit protection', inputSchema: { type: 'object', properties: { category: { type: 'string', description: 'Category (linear, inverse)', }, symbol: { type: 'string', description: 'Symbol (e.g., ETHUSDT)', }, entryPrice: { type: 'number', description: 'Entry price of the position', }, currentPrice: { type: 'number', description: 'Current market price', }, side: { type: 'string', description: 'Position side (Buy for long, Sell for short)', }, initialStopLoss: { type: 'number', description: 'Initial stop loss price', }, trailingDistance: { type: 'number', description: 'Trailing distance in price units', }, breakevenTrigger: { type: 'number', description: 'Price distance from entry to activate breakeven protection (optional)', }, profitProtectionTrigger: { type: 'number', description: 'Price distance from entry to activate profit protection (optional)', }, }, required: ['category', 'symbol', 'entryPrice', 'currentPrice', 'side', 'initialStopLoss', 'trailingDistance'], }, },
  • Tool dispatch handler in main MCP server that extracts parameters from request and calls the BybitService.calculateTrailingStop method.
    case 'calculate_trailing_stop': { const result = await this.bybitService.calculateTrailingStop( typedArgs.category, typedArgs.symbol, typedArgs.entryPrice, typedArgs.currentPrice, typedArgs.side, typedArgs.initialStopLoss, typedArgs.trailingDistance, typedArgs.breakevenTrigger, typedArgs.profitProtectionTrigger ); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kondisettyravi/mcp-bybit-node'

If you have feedback or need assistance with the MCP directory API, please join our Discord server