Page 1 of 2

cTrader Hotkey Profiles: Mapping Buy, Sell, Close-All and Reverse

Posted: Fri Oct 09, 2026 6:40 am
by FXS Prop Desk
cTrader allows custom hotkeys for most trading actions, which makes it popular with manual scalpers. A well-planned mapping can save seconds and reduce mis-clicks.

Common actions to map:
  • Buy and sell market with the default volume.
  • Close all positions on the current symbol.
  • Close all positions on the account.
  • Reverse the current position.
  • Move stop to break-even.
  • Cancel all pending orders.
Good practice:
  • Keep buy and sell keys apart to avoid confusion.
  • Map destructive actions (close all, reverse) to key combinations, not single keys.
  • Set default volume carefully, ideally to your standard risk.
  • Practise on demo until the mapping is automatic.
MT4/MT5 have fewer native hotkeys, but third-party panels add similar features.

Do you use hotkeys for trading, and which actions are mapped?

Re: cTrader Hotkey Profiles: Mapping Buy, Sell, Close-All and Reverse

Posted: Fri Oct 09, 2026 8:54 am
by FTtrader
FXS Prop Desk wrote: Fri Oct 09, 2026 6:40 am cTrader allows custom hotkeys for most trading actions, which makes it popular with manual scalpers. A well-planned mapping can save seconds and reduce mis-clicks.

Common actions to map:
  • Buy and sell market with the default volume.
  • Close all positions on the current symbol.
  • Close all positions on the account.
  • Reverse the current position.
  • Move stop to break-even.
  • Cancel all pending orders.
Good practice:
  • Keep buy and sell keys apart to avoid confusion.
  • Map destructive actions (close all, reverse) to key combinations, not single keys.
  • Set default volume carefully, ideally to your standard risk.
  • Practise on demo until the mapping is automatic.
MT4/MT5 have fewer native hotkeys, but third-party panels add similar features.

Do you use hotkeys for trading, and which actions are mapped?
Hello,

For a price action scalper operating on the 1-minute and 5-minute charts, where order book liquidity sweeps happen in milliseconds, standard mouse clicks are a structural disadvantage. A well-architected hotkey setup doesn't just save time; it eliminates the cognitive load of navigating UIs during high-volatility moves.

Re: cTrader Hotkey Profiles: Mapping Buy, Sell, Close-All and Reverse

Posted: Fri Oct 09, 2026 8:54 am
by FTtrader
Here is how an advanced, extended mapping strategy looks when elevating native platform features with custom script logic:

The Tactical Hotkey Architecture

Instead of strictly mapping static "Buy" and "Sell" buttons, advanced setups map keys by intent, risk, and trade management.

Bridging the MT4/MT5 Gap

While cTrader natively supports much of this out of the box, MetaTrader requires a programmatic approach to achieve the same execution speed. Because native hotkeys in MT4 and MT5 are largely restricted to chart navigation and launching indicators, the standard solution is to write custom Expert Advisors using the OnChartEvent function.

By programming a script to listen for specific CHARTEVENT_KEYDOWN keystrokes in MQL5, you bypass the MetaTrader graphical interface entirely. When you press a designated key, the script catches the event and sends the execution command directly to the broker server, effectively replicating cTrader's native speed on the MetaTrader backend.

Re: cTrader Hotkey Profiles: Mapping Buy, Sell, Close-All and Reverse

Posted: Fri Oct 09, 2026 8:56 am
by FTtrader
But on another hand i know at least two full time scalpers, who trade just from mobile phone.
Because they like, that you can be out and trade everywhere, because one of very important component in trading is to have cool mind.

Re: cTrader Hotkey Profiles: Mapping Buy, Sell, Close-All and Reverse

Posted: Fri Oct 09, 2026 8:56 am
by FTtrader
Here is the MQL5 Expert Advisor script using the standard CTrade library. It listens for specific ASCII key codes via OnChartEvent to trigger immediate execution.

For this implementation:

B (Key Code 66): Executes a Market Buy.

S (Key Code 83): Executes a Market Sell.

C (Key Code 67): Closes all active positions for the current chart symbol.

Re: cTrader Hotkey Profiles: Mapping Buy, Sell, Close-All and Reverse

Posted: Fri Oct 09, 2026 8:56 am
by FTtrader
Code snippet

Code: Select all

//+------------------------------------------------------------------+
//|                                                HotkeyScalper.mq5 |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Custom MQL5 Script"
#property version   "1.00"

#include <Trade\Trade.mqh>

//--- Input parameters
input double InpLotSize = 0.1;       // Default Volume (Lots)
input ulong  InpMagic = 123456;      // Magic Number
input ulong  InpSlippage = 3;        // Max Slippage (Points)

CTrade trade;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   trade.SetExpertMagicNumber(InpMagic);
   trade.SetDeviationInPoints(InpSlippage);
   
   Print("Hotkey EA Initialized. Press 'B' for Buy, 'S' for Sell, 'C' to Close All.");
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   // Check if the event is a key press
   if(id == CHARTEVENT_KEYDOWN)
     {
      // lparam contains the ASCII code of the key pressed
      switch((int)lparam)
        {
         case 66: // 'B' key
            ExecuteBuy();
            break;
            
         case 83: // 'S' key
            ExecuteSell();
            break;
            
         case 67: // 'C' key
            CloseAllCurrentSymbol();
            break;
        }
     }
  }

//+------------------------------------------------------------------+
//| Execution Functions                                              |
//+------------------------------------------------------------------+
void ExecuteBuy()
  {
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   if(trade.Buy(InpLotSize, _Symbol, ask, 0, 0, "Hotkey Buy"))
      Print("Buy order executed at ", ask);
   else
      Print("Buy failed. Error: ", GetLastError());
  }

void ExecuteSell()
  {
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   if(trade.Sell(InpLotSize, _Symbol, bid, 0, 0, "Hotkey Sell"))
      Print("Sell order executed at ", bid);
   else
      Print("Sell failed. Error: ", GetLastError());
  }

void CloseAllCurrentSymbol()
  {
   // Loop backwards when closing positions to avoid index shifting
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      string position_symbol = PositionGetSymbol(i);
      
      if(position_symbol == _Symbol)
        {
         ulong ticket = PositionGetInteger(POSITION_TICKET);
         if(trade.PositionClose(ticket))
            Print("Position ", ticket, " closed successfully.");
         else
            Print("Failed to close position ", ticket, ". Error: ", GetLastError());
        }
     }
  }

Re: cTrader Hotkey Profiles: Mapping Buy, Sell, Close-All and Reverse

Posted: Fri Oct 09, 2026 8:57 am
by FTtrader
Key Implementation Details

CHARTEVENT_KEYDOWN: This is the core event listener. MetaTrader passes the physical key's ASCII integer value into the lparam argument.

Reverse Iteration on Close: The CloseAllCurrentSymbol() function loops backward (i = PositionsTotal() - 1; i >= 0; i--). Because closing a position dynamically shrinks the total position count, looping forward would cause index out-of-bounds errors or skipped orders.

Focus Requirements: The MetaTrader chart running the EA must be the active, focused window for OnChartEvent to register the keystrokes.

Auto Trading: This must be compiled as an Expert Advisor, not an Indicator. The "Algo Trading" button in the MT5 terminal must be enabled, and the EA properties must have "Allow Algo Trading" checked.

Re: cTrader Hotkey Profiles: Mapping Buy, Sell, Close-All and Reverse

Posted: Fri Oct 09, 2026 8:57 am
by FTtrader
This implementation introduces dynamic position sizing by calculating the exact lot size required to risk 1% of the account balance based on the current ATR distance.

It handles the necessary conversions using the symbol's tick value and tick size, ensuring the math works across forex, metals, and equities. The ATR is sampled from the last closed candle (index 1) to prevent the stop-loss distance from fluctuating wildly mid-tick when the hotkey is pressed.

Re: cTrader Hotkey Profiles: Mapping Buy, Sell, Close-All and Reverse

Posted: Fri Oct 09, 2026 8:57 am
by FTtrader
MQL5 code

Code: Select all

//+------------------------------------------------------------------+
//|                                     DynamicRiskHotkeyScalper.mq5 |
//+------------------------------------------------------------------+
#property copyright "Custom MQL5 Script"
#property version   "1.10"

#include <Trade\Trade.mqh>

//--- Input parameters
input double InpRiskPercent   = 1.0;     // Account Risk per Trade (%)
input int    InpAtrPeriod     = 14;      // ATR Period
input double InpAtrMultiplier = 1.0;     // ATR Multiplier for Stop Loss
input ulong  InpMagic         = 123456;  // Magic Number
input ulong  InpSlippage      = 3;       // Max Slippage (Points)

CTrade trade;
int    atrHandle;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   trade.SetExpertMagicNumber(InpMagic);
   trade.SetDeviationInPoints(InpSlippage);
   
   // Initialize the ATR indicator handle
   atrHandle = iATR(_Symbol, PERIOD_CURRENT, InpAtrPeriod);
   if(atrHandle == INVALID_HANDLE)
     {
      Print("Failed to create ATR indicator handle.");
      return(INIT_FAILED);
     }
   
   Print("Dynamic Risk Hotkeys Initialized. 'B'=Buy, 'S'=Sell, 'C'=Close All.");
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   if(id == CHARTEVENT_KEYDOWN)
     {
      switch((int)lparam)
        {
         case 66: // 'B' key
            ExecuteBuy();
            break;
            
         case 83: // 'S' key
            ExecuteSell();
            break;
            
         case 67: // 'C' key
            CloseAllCurrentSymbol();
            break;
        }
     }
  }

//+------------------------------------------------------------------+
//| Lot Size Calculation                                             |
//+------------------------------------------------------------------+
double CalculateLotSize(double slDistanceInPrice)
  {
   double balance = AccountInfoDouble(ACCOUNT_BALANCE);
   double riskAmount = balance * (InpRiskPercent / 100.0);
   
   double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double tickSize  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   
   if(tickSize == 0 || tickValue == 0 || slDistanceInPrice == 0) 
      return 0.0;
   
   // Calculate the monetary risk for 1 standard lot
   double riskPerLot = (slDistanceInPrice / tickSize) * tickValue;
   
   // Calculate raw lot size
   double rawLot = riskAmount / riskPerLot;
   
   // Normalize against broker constraints
   double minLot  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double stepLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   
   // Round down to the nearest volume step
   double finalLot = MathFloor(rawLot / stepLot) * stepLot;
   
   if(finalLot < minLot) finalLot = minLot;
   if(finalLot > maxLot) finalLot = maxLot;
   
   return finalLot;
  }

//+------------------------------------------------------------------+
//| Execution Functions                                              |
//+------------------------------------------------------------------+
void ExecuteBuy()
  {
   double atrArray[];
   ArraySetAsSeries(atrArray, true);
   
   // Get ATR from the last closed candle (index 1) to avoid tick fluctuations
   if(CopyBuffer(atrHandle, 0, 1, 1, atrArray) <= 0)
     {
      Print("Error getting ATR data.");
      return;
     }
     
   double currentAtr = atrArray[0];
   double slDistance = currentAtr * InpAtrMultiplier;
   
   double volume = CalculateLotSize(slDistance);
   if(volume <= 0) return;
   
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double sl  = ask - slDistance;
   
   if(trade.Buy(volume, _Symbol, ask, sl, 0, "ATR Risk Buy"))
      PrintFormat("Buy executed. Vol: %.2f, SL: %.5f", volume, sl);
   else
      Print("Buy failed. Error: ", GetLastError());
  }

void ExecuteSell()
  {
   double atrArray[];
   ArraySetAsSeries(atrArray, true);
   
   if(CopyBuffer(atrHandle, 0, 1, 1, atrArray) <= 0)
     {
      Print("Error getting ATR data.");
      return;
     }
     
   double currentAtr = atrArray[0];
   double slDistance = currentAtr * InpAtrMultiplier;
   
   double volume = CalculateLotSize(slDistance);
   if(volume <= 0) return;
   
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double sl  = bid + slDistance;
   
   if(trade.Sell(volume, _Symbol, bid, sl, 0, "ATR Risk Sell"))
      PrintFormat("Sell executed. Vol: %.2f, SL: %.5f", volume, sl);
   else
      Print("Sell failed. Error: ", GetLastError());
  }

void CloseAllCurrentSymbol()
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      string position_symbol = PositionGetSymbol(i);
      if(position_symbol == _Symbol)
        {
         ulong ticket = PositionGetInteger(POSITION_TICKET);
         trade.PositionClose(ticket);
        }
     }
  }

Re: cTrader Hotkey Profiles: Mapping Buy, Sell, Close-All and Reverse

Posted: Fri Oct 09, 2026 8:58 am
by FTtrader
Key Mechanical Additions

Risk per Lot Calculation: The formula (slDistanceInPrice / tickSize) * tickValue translates the physical price distance of the ATR into the exact monetary risk that a single standard lot would incur. This prevents sizing errors when transitioning between pairs with different quote currencies or moving from FX to indices.

Step Lot Normalization: MathFloor(rawLot / stepLot) * stepLot ensures the calculated lot size adheres to broker limits (e.g., preventing an order of 0.125 lots if the broker only accepts 0.01 increments).

Integrated Stop Loss: Because risk is defined by the ATR distance, the script now automatically places a hard Stop Loss at Entry ± (ATR * Multiplier). Without this hard stop, the 1% risk calculation would be theoretical rather than enforced.